Route editor actions by active target
This commit is contained in:
@@ -17,6 +17,16 @@ struct ShortcutChord {
|
||||
bool alt = false;
|
||||
};
|
||||
|
||||
enum class ShortcutRoute {
|
||||
Global,
|
||||
FocusedWindow
|
||||
};
|
||||
|
||||
struct ShortcutContext {
|
||||
ShortcutRoute route = ShortcutRoute::Global;
|
||||
bool enabled = true;
|
||||
};
|
||||
|
||||
struct ActionBinding {
|
||||
std::string label;
|
||||
std::string shortcutLabel;
|
||||
@@ -31,6 +41,14 @@ inline ShortcutChord Shortcut(ImGuiKey key, bool ctrl = false, bool shift = fals
|
||||
return ShortcutChord{ key, ctrl, shift, alt };
|
||||
}
|
||||
|
||||
inline ShortcutContext GlobalShortcutContext() {
|
||||
return ShortcutContext{ ShortcutRoute::Global, true };
|
||||
}
|
||||
|
||||
inline ShortcutContext FocusedWindowShortcutContext() {
|
||||
return ShortcutContext{ ShortcutRoute::FocusedWindow, true };
|
||||
}
|
||||
|
||||
inline ActionBinding MakeAction(
|
||||
std::string label,
|
||||
const char* shortcutLabel = nullptr,
|
||||
@@ -118,11 +136,30 @@ inline bool IsShortcutPressed(const ShortcutChord& shortcut, const ImGuiIO& io)
|
||||
return ImGui::IsKeyPressed(shortcut.key, false);
|
||||
}
|
||||
|
||||
inline bool IsShortcutPressed(const ActionBinding& action) {
|
||||
inline bool IsShortcutContextActive(const ShortcutContext& context) {
|
||||
if (!context.enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (context.route) {
|
||||
case ShortcutRoute::Global:
|
||||
return true;
|
||||
case ShortcutRoute::FocusedWindow:
|
||||
return ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool IsShortcutPressed(const ActionBinding& action, const ShortcutContext& context) {
|
||||
if (!action.enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsShortcutContextActive(context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ImGuiIO& io = ImGui::GetIO();
|
||||
if (!action.allowWhenTextInput && io.WantTextInput) {
|
||||
return false;
|
||||
@@ -137,9 +174,13 @@ inline bool IsShortcutPressed(const ActionBinding& action) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool IsShortcutPressed(const ActionBinding& action) {
|
||||
return IsShortcutPressed(action, GlobalShortcutContext());
|
||||
}
|
||||
|
||||
template <typename ExecuteFn>
|
||||
inline bool HandleShortcut(const ActionBinding& action, ExecuteFn&& execute) {
|
||||
if (!IsShortcutPressed(action)) {
|
||||
inline bool HandleShortcut(const ActionBinding& action, const ShortcutContext& context, ExecuteFn&& execute) {
|
||||
if (!IsShortcutPressed(action, context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -147,6 +188,11 @@ inline bool HandleShortcut(const ActionBinding& action, ExecuteFn&& execute) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ExecuteFn>
|
||||
inline bool HandleShortcut(const ActionBinding& action, ExecuteFn&& execute) {
|
||||
return HandleShortcut(action, GlobalShortcutContext(), std::forward<ExecuteFn>(execute));
|
||||
}
|
||||
|
||||
} // namespace Actions
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
|
||||
24
editor/src/Actions/ActionRouting.h
Normal file
24
editor/src/Actions/ActionRouting.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/EditorActionRoute.h"
|
||||
#include "Core/IEditorContext.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
namespace Actions {
|
||||
|
||||
inline void ObserveFocusedActionRoute(IEditorContext& context, EditorActionRoute route) {
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)) {
|
||||
context.SetActiveActionRoute(route);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool IsActionRouteActive(const IEditorContext& context, EditorActionRoute route) {
|
||||
return context.GetActiveActionRoute() == route;
|
||||
}
|
||||
|
||||
} // namespace Actions
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
#include "ActionBinding.h"
|
||||
#include "Core/IEditorContext.h"
|
||||
#include "Core/IProjectManager.h"
|
||||
#include "Core/ISelectionManager.h"
|
||||
#include "Core/ISceneManager.h"
|
||||
#include "Core/IUndoManager.h"
|
||||
#include "Core/AssetItem.h"
|
||||
|
||||
#include <XCEngine/Components/GameObject.h>
|
||||
|
||||
@@ -128,15 +130,15 @@ inline ActionBinding MakeExitAction() {
|
||||
}
|
||||
|
||||
inline ActionBinding MakeNavigateBackAction(bool enabled) {
|
||||
return MakeAction("<", nullptr, false, enabled);
|
||||
return MakeAction("<", "Alt+Left", false, enabled, false, Shortcut(ImGuiKey_LeftArrow, false, false, true));
|
||||
}
|
||||
|
||||
inline ActionBinding MakeOpenAssetAction(bool enabled) {
|
||||
return MakeAction("Open", nullptr, false, enabled);
|
||||
return MakeAction("Open", "Enter", false, enabled, false, Shortcut(ImGuiKey_Enter), Shortcut(ImGuiKey_KeypadEnter));
|
||||
}
|
||||
|
||||
inline ActionBinding MakeDeleteAssetAction(bool enabled = true) {
|
||||
return MakeAction("Delete", nullptr, false, enabled);
|
||||
return MakeAction("Delete", "Delete", false, enabled, false, Shortcut(ImGuiKey_Delete));
|
||||
}
|
||||
|
||||
inline ActionBinding MakeCreateFolderAction(bool enabled = true) {
|
||||
@@ -179,6 +181,17 @@ inline ::XCEngine::Components::GameObject* GetSelectedGameObject(IEditorContext&
|
||||
return context.GetSceneManager().GetEntity(context.GetSelectionManager().GetSelectedEntity());
|
||||
}
|
||||
|
||||
inline AssetItemPtr GetSelectedAssetItem(IEditorContext& context) {
|
||||
auto& projectManager = context.GetProjectManager();
|
||||
const int selectedIndex = projectManager.GetSelectedIndex();
|
||||
auto& items = projectManager.GetCurrentItems();
|
||||
if (selectedIndex < 0 || selectedIndex >= static_cast<int>(items.size())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return items[selectedIndex];
|
||||
}
|
||||
|
||||
} // namespace Actions
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
|
||||
@@ -7,16 +7,12 @@
|
||||
#include <XCEngine/Debug/Logger.h>
|
||||
#include <XCEngine/Debug/FileLogSink.h>
|
||||
#include <XCEngine/Debug/ConsoleLogSink.h>
|
||||
#include <imgui_impl_win32.h>
|
||||
#include <imgui_impl_dx12.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <filesystem>
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
|
||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
namespace {
|
||||
|
||||
std::string WideToUtf8(const std::wstring& value) {
|
||||
@@ -66,10 +62,6 @@ std::string GetExecutableLogPath(const char* fileName) {
|
||||
return GetExecutableDirectoryUtf8() + "\\" + fileName;
|
||||
}
|
||||
|
||||
std::string BuildEditorConfigDirectory(const std::string& projectPath) {
|
||||
return (std::filesystem::path(projectPath) / ".xceditor").string();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
static LONG WINAPI GlobalExceptionFilter(EXCEPTION_POINTERS* exceptionPointers) {
|
||||
@@ -142,12 +134,9 @@ bool Application::Initialize(HWND hwnd) {
|
||||
PostMessageW(m_hwnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
});
|
||||
ConfigureImGui(m_editorContext->GetProjectPath());
|
||||
m_imguiSession.Initialize(m_editorContext->GetProjectPath());
|
||||
|
||||
ImGui_ImplWin32_Init(hwnd);
|
||||
ImGui_ImplDX12_Init(m_device, 3, DXGI_FORMAT_R8G8B8A8_UNORM, m_srvHeap,
|
||||
m_srvHeap->GetCPUDescriptorHandleForHeapStart(),
|
||||
m_srvHeap->GetGPUDescriptorHandleForHeapStart());
|
||||
m_imguiBackend.Initialize(hwnd, m_device, m_srvHeap);
|
||||
|
||||
m_editorLayer = new EditorLayer();
|
||||
m_editorLayer->SetContext(m_editorContext);
|
||||
@@ -159,16 +148,14 @@ bool Application::Initialize(HWND hwnd) {
|
||||
|
||||
void Application::Shutdown() {
|
||||
m_layerStack.onDetach();
|
||||
SaveImGuiSettings();
|
||||
|
||||
if (m_editorContext && m_exitRequestedHandlerId) {
|
||||
m_editorContext->GetEventBus().Unsubscribe<EditorExitRequestedEvent>(m_exitRequestedHandlerId);
|
||||
m_exitRequestedHandlerId = 0;
|
||||
}
|
||||
|
||||
ImGui_ImplDX12_Shutdown();
|
||||
ImGui_ImplWin32_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
m_imguiBackend.Shutdown();
|
||||
m_imguiSession.Shutdown();
|
||||
|
||||
CleanupRenderTarget();
|
||||
|
||||
@@ -183,9 +170,7 @@ void Application::Shutdown() {
|
||||
}
|
||||
|
||||
void Application::Render() {
|
||||
ImGui_ImplDX12_NewFrame();
|
||||
ImGui_ImplWin32_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
m_imguiBackend.BeginFrame();
|
||||
|
||||
m_layerStack.onImGuiRender();
|
||||
UpdateWindowTitle();
|
||||
@@ -214,7 +199,7 @@ void Application::Render() {
|
||||
ID3D12DescriptorHeap* heaps[] = { m_srvHeap };
|
||||
m_commandList->SetDescriptorHeaps(1, heaps);
|
||||
|
||||
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), m_commandList);
|
||||
m_imguiBackend.RenderDrawData(m_commandList);
|
||||
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||
@@ -233,45 +218,6 @@ void Application::Render() {
|
||||
}
|
||||
}
|
||||
|
||||
void Application::ConfigureImGui(const std::string& projectPath) {
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||
|
||||
ConfigureImGuiIniFile(projectPath, io);
|
||||
|
||||
if (ImFont* uiFont = io.Fonts->AddFontFromFileTTF("C:/Windows/Fonts/msyh.ttc", 15.0f)) {
|
||||
io.FontDefault = uiFont;
|
||||
} else {
|
||||
io.FontDefault = io.Fonts->AddFontDefault();
|
||||
}
|
||||
|
||||
unsigned char* pixels = nullptr;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||
|
||||
ApplyUnityDarkTheme();
|
||||
}
|
||||
|
||||
void Application::ConfigureImGuiIniFile(const std::string& projectPath, ImGuiIO& io) {
|
||||
const std::filesystem::path configDir = BuildEditorConfigDirectory(projectPath);
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(configDir, ec);
|
||||
|
||||
m_imguiIniPath = (configDir / "imgui_layout.ini").string();
|
||||
io.IniFilename = m_imguiIniPath.c_str();
|
||||
}
|
||||
|
||||
void Application::SaveImGuiSettings() {
|
||||
if (m_imguiIniPath.empty() || ImGui::GetCurrentContext() == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::SaveIniSettingsToDisk(m_imguiIniPath.c_str());
|
||||
}
|
||||
|
||||
void Application::UpdateWindowTitle() {
|
||||
if (!m_hwnd || !m_editorContext) {
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "UI/ImGuiBackendBridge.h"
|
||||
#include "UI/ImGuiSession.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <imgui.h>
|
||||
@@ -8,8 +11,6 @@
|
||||
|
||||
#include <XCEngine/Core/LayerStack.h>
|
||||
|
||||
#include "Theme.h"
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
|
||||
@@ -32,9 +33,6 @@ private:
|
||||
Application() = default;
|
||||
~Application() = default;
|
||||
|
||||
void ConfigureImGui(const std::string& projectPath);
|
||||
void ConfigureImGuiIniFile(const std::string& projectPath, ImGuiIO& io);
|
||||
void SaveImGuiSettings();
|
||||
bool CreateDevice();
|
||||
bool CreateRenderTarget();
|
||||
void CleanupRenderTarget();
|
||||
@@ -60,8 +58,9 @@ private:
|
||||
Core::LayerStack m_layerStack;
|
||||
EditorLayer* m_editorLayer = nullptr;
|
||||
std::shared_ptr<IEditorContext> m_editorContext;
|
||||
UI::ImGuiBackendBridge m_imguiBackend;
|
||||
UI::ImGuiSession m_imguiSession;
|
||||
uint64_t m_exitRequestedHandlerId = 0;
|
||||
std::string m_imguiIniPath;
|
||||
std::wstring m_lastWindowTitle;
|
||||
};
|
||||
|
||||
|
||||
13
editor/src/Core/EditorActionRoute.h
Normal file
13
editor/src/Core/EditorActionRoute.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
|
||||
enum class EditorActionRoute {
|
||||
None,
|
||||
Hierarchy,
|
||||
Project
|
||||
};
|
||||
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
@@ -55,6 +55,14 @@ public:
|
||||
IUndoManager& GetUndoManager() override {
|
||||
return *m_undoManager;
|
||||
}
|
||||
|
||||
void SetActiveActionRoute(EditorActionRoute route) override {
|
||||
m_activeActionRoute = route;
|
||||
}
|
||||
|
||||
EditorActionRoute GetActiveActionRoute() const override {
|
||||
return m_activeActionRoute;
|
||||
}
|
||||
|
||||
void SetProjectPath(const std::string& path) override {
|
||||
m_projectPath = path;
|
||||
@@ -70,6 +78,7 @@ private:
|
||||
std::unique_ptr<SceneManager> m_sceneManager;
|
||||
std::unique_ptr<UndoManager> m_undoManager;
|
||||
std::unique_ptr<ProjectManager> m_projectManager;
|
||||
EditorActionRoute m_activeActionRoute = EditorActionRoute::None;
|
||||
std::string m_projectPath;
|
||||
uint64_t m_entityDeletedHandlerId;
|
||||
};
|
||||
|
||||
@@ -25,6 +25,10 @@ struct EntityChangedEvent {
|
||||
GameObjectID entityId;
|
||||
};
|
||||
|
||||
struct EntityRenameRequestedEvent {
|
||||
GameObjectID entityId;
|
||||
};
|
||||
|
||||
struct EntityParentChangedEvent {
|
||||
GameObjectID entityId;
|
||||
GameObjectID oldParentId;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "EditorActionRoute.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
@@ -21,6 +23,8 @@ public:
|
||||
virtual ISceneManager& GetSceneManager() = 0;
|
||||
virtual IProjectManager& GetProjectManager() = 0;
|
||||
virtual IUndoManager& GetUndoManager() = 0;
|
||||
virtual void SetActiveActionRoute(EditorActionRoute route) = 0;
|
||||
virtual EditorActionRoute GetActiveActionRoute() const = 0;
|
||||
|
||||
virtual void SetProjectPath(const std::string& path) = 0;
|
||||
virtual const std::string& GetProjectPath() const = 0;
|
||||
|
||||
65
editor/src/UI/ImGuiBackendBridge.h
Normal file
65
editor/src/UI/ImGuiBackendBridge.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include <d3d12.h>
|
||||
#include <dxgi1_6.h>
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_dx12.h>
|
||||
#include <imgui_impl_win32.h>
|
||||
#include <windows.h>
|
||||
|
||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
namespace UI {
|
||||
|
||||
class ImGuiBackendBridge {
|
||||
public:
|
||||
void Initialize(
|
||||
HWND hwnd,
|
||||
ID3D12Device* device,
|
||||
ID3D12DescriptorHeap* srvHeap,
|
||||
int frameCount = 3,
|
||||
DXGI_FORMAT backBufferFormat = DXGI_FORMAT_R8G8B8A8_UNORM) {
|
||||
ImGui_ImplWin32_Init(hwnd);
|
||||
ImGui_ImplDX12_Init(
|
||||
device,
|
||||
frameCount,
|
||||
backBufferFormat,
|
||||
srvHeap,
|
||||
srvHeap->GetCPUDescriptorHandleForHeapStart(),
|
||||
srvHeap->GetGPUDescriptorHandleForHeapStart());
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
if (!m_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui_ImplDX12_Shutdown();
|
||||
ImGui_ImplWin32_Shutdown();
|
||||
m_initialized = false;
|
||||
}
|
||||
|
||||
void BeginFrame() const {
|
||||
ImGui_ImplDX12_NewFrame();
|
||||
ImGui_ImplWin32_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
void RenderDrawData(ID3D12GraphicsCommandList* commandList) const {
|
||||
ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), commandList);
|
||||
}
|
||||
|
||||
static bool HandleWindowMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
return ImGui_ImplWin32_WndProcHandler(hwnd, msg, wParam, lParam) != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_initialized = false;
|
||||
};
|
||||
|
||||
} // namespace UI
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
77
editor/src/UI/ImGuiSession.h
Normal file
77
editor/src/UI/ImGuiSession.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include "BaseTheme.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Editor {
|
||||
namespace UI {
|
||||
|
||||
class ImGuiSession {
|
||||
public:
|
||||
void Initialize(const std::string& projectPath) {
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||
|
||||
ConfigureIniFile(projectPath, io);
|
||||
ConfigureFonts(io);
|
||||
ApplyBaseTheme(ImGui::GetStyle());
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
SaveSettings();
|
||||
if (ImGui::GetCurrentContext() != nullptr) {
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
m_iniPath.clear();
|
||||
}
|
||||
|
||||
void SaveSettings() const {
|
||||
if (m_iniPath.empty() || ImGui::GetCurrentContext() == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::SaveIniSettingsToDisk(m_iniPath.c_str());
|
||||
}
|
||||
|
||||
const std::string& GetIniPath() const {
|
||||
return m_iniPath;
|
||||
}
|
||||
|
||||
private:
|
||||
void ConfigureIniFile(const std::string& projectPath, ImGuiIO& io) {
|
||||
const std::filesystem::path configDir = std::filesystem::path(projectPath) / ".xceditor";
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(configDir, ec);
|
||||
|
||||
m_iniPath = (configDir / "imgui_layout.ini").string();
|
||||
io.IniFilename = m_iniPath.c_str();
|
||||
}
|
||||
|
||||
void ConfigureFonts(ImGuiIO& io) const {
|
||||
if (ImFont* uiFont = io.Fonts->AddFontFromFileTTF("C:/Windows/Fonts/msyh.ttc", 15.0f)) {
|
||||
io.FontDefault = uiFont;
|
||||
} else {
|
||||
io.FontDefault = io.Fonts->AddFontDefault();
|
||||
}
|
||||
|
||||
unsigned char* pixels = nullptr;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||
}
|
||||
|
||||
std::string m_iniPath;
|
||||
};
|
||||
|
||||
} // namespace UI
|
||||
} // namespace Editor
|
||||
} // namespace XCEngine
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "Application.h"
|
||||
#include "UI/ImGuiBackendBridge.h"
|
||||
#include <imgui.h>
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
@@ -72,10 +73,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int nCmdShow) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
|
||||
if (XCEngine::Editor::UI::ImGuiBackendBridge::HandleWindowMessage(hWnd, msg, wParam, lParam))
|
||||
return true;
|
||||
|
||||
switch (msg) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "Actions/EditorActions.h"
|
||||
#include "Actions/ActionRouting.h"
|
||||
#include "Commands/EntityCommands.h"
|
||||
#include "HierarchyPanel.h"
|
||||
#include "Core/IEditorContext.h"
|
||||
@@ -20,6 +21,7 @@ HierarchyPanel::HierarchyPanel() : Panel("Hierarchy") {
|
||||
HierarchyPanel::~HierarchyPanel() {
|
||||
if (m_context) {
|
||||
m_context->GetEventBus().Unsubscribe<SelectionChangedEvent>(m_selectionHandlerId);
|
||||
m_context->GetEventBus().Unsubscribe<EntityRenameRequestedEvent>(m_renameRequestHandlerId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +31,11 @@ void HierarchyPanel::OnAttach() {
|
||||
OnSelectionChanged(event);
|
||||
}
|
||||
);
|
||||
m_renameRequestHandlerId = m_context->GetEventBus().Subscribe<EntityRenameRequestedEvent>(
|
||||
[this](const EntityRenameRequestedEvent& event) {
|
||||
OnRenameRequested(event);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void HierarchyPanel::OnSelectionChanged(const SelectionChangedEvent& event) {
|
||||
@@ -37,12 +44,24 @@ void HierarchyPanel::OnSelectionChanged(const SelectionChangedEvent& event) {
|
||||
}
|
||||
}
|
||||
|
||||
void HierarchyPanel::OnRenameRequested(const EntityRenameRequestedEvent& event) {
|
||||
if (!m_context || event.entityId == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto* gameObject = m_context->GetSceneManager().GetEntity(event.entityId)) {
|
||||
BeginRename(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
void HierarchyPanel::Render() {
|
||||
UI::PanelWindowScope panel(m_name.c_str());
|
||||
if (!panel.IsOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Actions::ObserveFocusedActionRoute(*m_context, EditorActionRoute::Hierarchy);
|
||||
|
||||
RenderSearchBar();
|
||||
|
||||
HandleKeyboardShortcuts();
|
||||
@@ -299,26 +318,24 @@ void HierarchyPanel::HandleDragDrop(::XCEngine::Components::GameObject* gameObje
|
||||
void HierarchyPanel::HandleKeyboardShortcuts() {
|
||||
auto& sceneManager = m_context->GetSceneManager();
|
||||
auto& selectionManager = m_context->GetSelectionManager();
|
||||
|
||||
::XCEngine::Components::GameObject* selectedGameObject = sceneManager.GetEntity(selectionManager.GetSelectedEntity());
|
||||
|
||||
if (ImGui::IsWindowFocused()) {
|
||||
Actions::HandleShortcut(Actions::MakeDeleteEntityAction(selectedGameObject), [&]() {
|
||||
Commands::DeleteEntity(*m_context, selectedGameObject->GetID());
|
||||
});
|
||||
Actions::HandleShortcut(Actions::MakeRenameEntityAction(selectedGameObject), [&]() {
|
||||
BeginRename(selectedGameObject);
|
||||
});
|
||||
Actions::HandleShortcut(Actions::MakeCopyEntityAction(selectedGameObject), [&]() {
|
||||
Commands::CopyEntity(*m_context, selectedGameObject->GetID());
|
||||
});
|
||||
Actions::HandleShortcut(Actions::MakePasteEntityAction(*m_context), [&]() {
|
||||
Commands::PasteEntity(*m_context, selectedGameObject ? selectedGameObject->GetID() : 0);
|
||||
});
|
||||
Actions::HandleShortcut(Actions::MakeDuplicateEntityAction(selectedGameObject), [&]() {
|
||||
Commands::DuplicateEntity(*m_context, selectedGameObject->GetID());
|
||||
});
|
||||
}
|
||||
const Actions::ShortcutContext shortcutContext = Actions::FocusedWindowShortcutContext();
|
||||
|
||||
Actions::HandleShortcut(Actions::MakeDeleteEntityAction(selectedGameObject), shortcutContext, [&]() {
|
||||
Commands::DeleteEntity(*m_context, selectedGameObject->GetID());
|
||||
});
|
||||
Actions::HandleShortcut(Actions::MakeRenameEntityAction(selectedGameObject), shortcutContext, [&]() {
|
||||
BeginRename(selectedGameObject);
|
||||
});
|
||||
Actions::HandleShortcut(Actions::MakeCopyEntityAction(selectedGameObject), shortcutContext, [&]() {
|
||||
Commands::CopyEntity(*m_context, selectedGameObject->GetID());
|
||||
});
|
||||
Actions::HandleShortcut(Actions::MakePasteEntityAction(*m_context), shortcutContext, [&]() {
|
||||
Commands::PasteEntity(*m_context, selectedGameObject ? selectedGameObject->GetID() : 0);
|
||||
});
|
||||
Actions::HandleShortcut(Actions::MakeDuplicateEntityAction(selectedGameObject), shortcutContext, [&]() {
|
||||
Commands::DuplicateEntity(*m_context, selectedGameObject->GetID());
|
||||
});
|
||||
}
|
||||
|
||||
bool HierarchyPanel::PassesFilter(::XCEngine::Components::GameObject* gameObject, const std::string& filter) {
|
||||
|
||||
@@ -20,6 +20,7 @@ public:
|
||||
|
||||
private:
|
||||
void OnSelectionChanged(const struct SelectionChangedEvent& event);
|
||||
void OnRenameRequested(const struct EntityRenameRequestedEvent& event);
|
||||
void RenderSearchBar();
|
||||
void RenderEntity(::XCEngine::Components::GameObject* gameObject, const std::string& filter);
|
||||
void RenderContextMenu(::XCEngine::Components::GameObject* gameObject);
|
||||
@@ -36,6 +37,7 @@ private:
|
||||
UI::InlineTextEditState<uint64_t, 256> m_renameState;
|
||||
SortMode m_sortMode = SortMode::Name;
|
||||
uint64_t m_selectionHandlerId = 0;
|
||||
uint64_t m_renameRequestHandlerId = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
#include "Actions/ActionRouting.h"
|
||||
#include "Actions/EditorActions.h"
|
||||
#include "Commands/EntityCommands.h"
|
||||
#include "Commands/ProjectCommands.h"
|
||||
#include "Commands/SceneCommands.h"
|
||||
#include "MenuBar.h"
|
||||
#include "Core/EditorEvents.h"
|
||||
#include "Core/EventBus.h"
|
||||
#include "Core/IEditorContext.h"
|
||||
#include "Core/IProjectManager.h"
|
||||
#include "Core/ISceneManager.h"
|
||||
#include "Core/IUndoManager.h"
|
||||
#include "Core/ISelectionManager.h"
|
||||
@@ -37,12 +40,14 @@ void MenuBar::HandleShortcuts() {
|
||||
return;
|
||||
}
|
||||
|
||||
Actions::HandleShortcut(Actions::MakeNewSceneAction(), [&]() { Commands::NewScene(*m_context); });
|
||||
Actions::HandleShortcut(Actions::MakeOpenSceneAction(), [&]() { Commands::OpenSceneWithDialog(*m_context); });
|
||||
Actions::HandleShortcut(Actions::MakeSaveSceneAction(), [&]() { Commands::SaveCurrentScene(*m_context); });
|
||||
Actions::HandleShortcut(Actions::MakeSaveSceneAsAction(), [&]() { Commands::SaveSceneAsWithDialog(*m_context); });
|
||||
Actions::HandleShortcut(Actions::MakeUndoAction(*m_context), [&]() { m_context->GetUndoManager().Undo(); });
|
||||
Actions::HandleShortcut(Actions::MakeRedoAction(*m_context), [&]() { m_context->GetUndoManager().Redo(); });
|
||||
const Actions::ShortcutContext shortcutContext = Actions::GlobalShortcutContext();
|
||||
|
||||
Actions::HandleShortcut(Actions::MakeNewSceneAction(), shortcutContext, [&]() { Commands::NewScene(*m_context); });
|
||||
Actions::HandleShortcut(Actions::MakeOpenSceneAction(), shortcutContext, [&]() { Commands::OpenSceneWithDialog(*m_context); });
|
||||
Actions::HandleShortcut(Actions::MakeSaveSceneAction(), shortcutContext, [&]() { Commands::SaveCurrentScene(*m_context); });
|
||||
Actions::HandleShortcut(Actions::MakeSaveSceneAsAction(), shortcutContext, [&]() { Commands::SaveSceneAsWithDialog(*m_context); });
|
||||
Actions::HandleShortcut(Actions::MakeUndoAction(*m_context), shortcutContext, [&]() { m_context->GetUndoManager().Undo(); });
|
||||
Actions::HandleShortcut(Actions::MakeRedoAction(*m_context), shortcutContext, [&]() { m_context->GetUndoManager().Redo(); });
|
||||
}
|
||||
|
||||
void MenuBar::ShowFileMenu() {
|
||||
@@ -60,11 +65,29 @@ void MenuBar::ShowFileMenu() {
|
||||
|
||||
void MenuBar::ShowEditMenu() {
|
||||
::XCEngine::Components::GameObject* selectedGameObject = Actions::GetSelectedGameObject(*m_context);
|
||||
const AssetItemPtr selectedAssetItem = Actions::GetSelectedAssetItem(*m_context);
|
||||
auto& projectManager = m_context->GetProjectManager();
|
||||
const EditorActionRoute actionRoute = m_context->GetActiveActionRoute();
|
||||
|
||||
UI::DrawMenuScope("Edit", [&]() {
|
||||
Actions::DrawMenuAction(Actions::MakeUndoAction(*m_context), [&]() { m_context->GetUndoManager().Undo(); });
|
||||
Actions::DrawMenuAction(Actions::MakeRedoAction(*m_context), [&]() { m_context->GetUndoManager().Redo(); });
|
||||
Actions::DrawMenuSeparator();
|
||||
|
||||
if (actionRoute == EditorActionRoute::Project) {
|
||||
Actions::DrawMenuAction(Actions::MakeOpenAssetAction(Commands::CanOpenAsset(selectedAssetItem)), [&]() {
|
||||
Commands::OpenAsset(*m_context, selectedAssetItem);
|
||||
});
|
||||
Actions::DrawMenuAction(Actions::MakeDeleteAssetAction(selectedAssetItem != nullptr), [&]() {
|
||||
Commands::DeleteAsset(projectManager, projectManager.GetSelectedIndex());
|
||||
});
|
||||
Actions::DrawMenuSeparator();
|
||||
Actions::DrawMenuAction(Actions::MakeNavigateBackAction(projectManager.CanNavigateBack()), [&]() {
|
||||
projectManager.NavigateBack();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Actions::DrawMenuAction(Actions::MakeCutAction(false), []() {});
|
||||
Actions::DrawMenuAction(Actions::MakeCopyEntityAction(selectedGameObject), [&]() {
|
||||
Commands::CopyEntity(*m_context, selectedGameObject->GetID());
|
||||
@@ -72,6 +95,15 @@ void MenuBar::ShowEditMenu() {
|
||||
Actions::DrawMenuAction(Actions::MakePasteEntityAction(*m_context), [&]() {
|
||||
Commands::PasteEntity(*m_context, selectedGameObject ? selectedGameObject->GetID() : 0);
|
||||
});
|
||||
Actions::DrawMenuAction(Actions::MakeDuplicateEntityAction(selectedGameObject), [&]() {
|
||||
Commands::DuplicateEntity(*m_context, selectedGameObject->GetID());
|
||||
});
|
||||
Actions::DrawMenuAction(Actions::MakeDeleteEntityAction(selectedGameObject), [&]() {
|
||||
Commands::DeleteEntity(*m_context, selectedGameObject->GetID());
|
||||
});
|
||||
Actions::DrawMenuAction(Actions::MakeRenameEntityAction(selectedGameObject), [&]() {
|
||||
m_context->GetEventBus().Publish(EntityRenameRequestedEvent{ selectedGameObject->GetID() });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "Actions/ActionRouting.h"
|
||||
#include "Actions/EditorActions.h"
|
||||
#include "Commands/ProjectCommands.h"
|
||||
#include "ProjectPanel.h"
|
||||
@@ -32,6 +33,9 @@ void ProjectPanel::Render() {
|
||||
if (!panel.IsOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Actions::ObserveFocusedActionRoute(*m_context, EditorActionRoute::Project);
|
||||
HandleKeyboardShortcuts();
|
||||
|
||||
auto& manager = m_context->GetProjectManager();
|
||||
|
||||
@@ -146,6 +150,30 @@ void ProjectPanel::Render() {
|
||||
}
|
||||
}
|
||||
|
||||
AssetItemPtr ProjectPanel::GetSelectedItem() const {
|
||||
return m_context ? Actions::GetSelectedAssetItem(*m_context) : nullptr;
|
||||
}
|
||||
|
||||
void ProjectPanel::HandleKeyboardShortcuts() {
|
||||
if (!m_context) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& manager = m_context->GetProjectManager();
|
||||
const AssetItemPtr selectedItem = GetSelectedItem();
|
||||
const Actions::ShortcutContext shortcutContext = Actions::FocusedWindowShortcutContext();
|
||||
|
||||
Actions::HandleShortcut(Actions::MakeNavigateBackAction(manager.CanNavigateBack()), shortcutContext, [&]() {
|
||||
manager.NavigateBack();
|
||||
});
|
||||
Actions::HandleShortcut(Actions::MakeOpenAssetAction(Commands::CanOpenAsset(selectedItem)), shortcutContext, [&]() {
|
||||
Commands::OpenAsset(*m_context, selectedItem);
|
||||
});
|
||||
Actions::HandleShortcut(Actions::MakeDeleteAssetAction(selectedItem != nullptr), shortcutContext, [&]() {
|
||||
Commands::DeleteAsset(manager, manager.GetSelectedIndex());
|
||||
});
|
||||
}
|
||||
|
||||
void ProjectPanel::RenderAssetItem(const AssetItemPtr& item, int index) {
|
||||
auto& manager = m_context->GetProjectManager();
|
||||
bool isSelected = (manager.GetSelectedIndex() == index);
|
||||
|
||||
@@ -14,6 +14,8 @@ public:
|
||||
void Initialize(const std::string& projectPath);
|
||||
|
||||
private:
|
||||
AssetItemPtr GetSelectedItem() const;
|
||||
void HandleKeyboardShortcuts();
|
||||
void RenderAssetItem(const AssetItemPtr& item, int index);
|
||||
|
||||
char m_searchBuffer[256] = "";
|
||||
|
||||
Reference in New Issue
Block a user