Extract editor edit action router

This commit is contained in:
2026-03-26 22:31:22 +08:00
parent 8bdb1f34c7
commit f87bc53875
15 changed files with 227 additions and 125 deletions

View File

@@ -15,6 +15,10 @@ inline void ObserveFocusedActionRoute(IEditorContext& context, EditorActionRoute
}
}
inline void ObserveInactiveActionRoute(IEditorContext& context) {
ObserveFocusedActionRoute(context, EditorActionRoute::None);
}
inline bool IsActionRouteActive(const IEditorContext& context, EditorActionRoute route) {
return context.GetActiveActionRoute() == route;
}

View File

@@ -0,0 +1,144 @@
#pragma once
#include "ActionBinding.h"
#include "EditorActions.h"
#include "Commands/EntityCommands.h"
#include "Commands/ProjectCommands.h"
#include "Core/EventBus.h"
#include "Core/EditorEvents.h"
#include "Core/IEditorContext.h"
#include "UI/UI.h"
namespace XCEngine {
namespace Editor {
namespace Actions {
struct EditActionTarget {
EditorActionRoute route = EditorActionRoute::None;
::XCEngine::Components::GameObject* selectedGameObject = nullptr;
AssetItemPtr selectedAssetItem;
};
inline EditActionTarget ResolveEditActionTarget(IEditorContext& context) {
EditActionTarget target;
target.route = context.GetActiveActionRoute();
target.selectedGameObject = GetSelectedGameObject(context);
target.selectedAssetItem = GetSelectedAssetItem(context);
return target;
}
inline ActionBinding MakeDisabledPasteAction() {
return MakeAction("Paste", "Ctrl+V", false, false);
}
inline void HandleProjectEditShortcuts(
IEditorContext& context,
const EditActionTarget& target,
const ShortcutContext& shortcutContext) {
auto& projectManager = context.GetProjectManager();
HandleShortcut(MakeNavigateBackAction(projectManager.CanNavigateBack()), shortcutContext, [&]() {
projectManager.NavigateBack();
});
HandleShortcut(MakeOpenAssetAction(Commands::CanOpenAsset(target.selectedAssetItem)), shortcutContext, [&]() {
Commands::OpenAsset(context, target.selectedAssetItem);
});
HandleShortcut(MakeDeleteAssetAction(target.selectedAssetItem != nullptr), shortcutContext, [&]() {
Commands::DeleteAsset(projectManager, projectManager.GetSelectedIndex());
});
}
inline void HandleHierarchyEditShortcuts(
IEditorContext& context,
const EditActionTarget& target,
const ShortcutContext& shortcutContext) {
HandleShortcut(MakeDeleteEntityAction(target.selectedGameObject), shortcutContext, [&]() {
Commands::DeleteEntity(context, target.selectedGameObject->GetID());
});
HandleShortcut(MakeRenameEntityAction(target.selectedGameObject), shortcutContext, [&]() {
context.GetEventBus().Publish(EntityRenameRequestedEvent{ target.selectedGameObject->GetID() });
});
HandleShortcut(MakeCopyEntityAction(target.selectedGameObject), shortcutContext, [&]() {
Commands::CopyEntity(context, target.selectedGameObject->GetID());
});
HandleShortcut(MakePasteEntityAction(context), shortcutContext, [&]() {
Commands::PasteEntity(context, target.selectedGameObject ? target.selectedGameObject->GetID() : 0);
});
HandleShortcut(MakeDuplicateEntityAction(target.selectedGameObject), shortcutContext, [&]() {
Commands::DuplicateEntity(context, target.selectedGameObject->GetID());
});
}
inline void HandleEditShortcuts(IEditorContext& context, const ShortcutContext& shortcutContext) {
const EditActionTarget target = ResolveEditActionTarget(context);
switch (target.route) {
case EditorActionRoute::Project:
HandleProjectEditShortcuts(context, target, shortcutContext);
return;
case EditorActionRoute::Hierarchy:
HandleHierarchyEditShortcuts(context, target, shortcutContext);
return;
case EditorActionRoute::None:
return;
}
}
inline void DrawProjectEditActions(IEditorContext& context, const EditActionTarget& target) {
auto& projectManager = context.GetProjectManager();
DrawMenuAction(MakeOpenAssetAction(Commands::CanOpenAsset(target.selectedAssetItem)), [&]() {
Commands::OpenAsset(context, target.selectedAssetItem);
});
DrawMenuAction(MakeDeleteAssetAction(target.selectedAssetItem != nullptr), [&]() {
Commands::DeleteAsset(projectManager, projectManager.GetSelectedIndex());
});
DrawMenuSeparator();
DrawMenuAction(MakeNavigateBackAction(projectManager.CanNavigateBack()), [&]() {
projectManager.NavigateBack();
});
}
inline void DrawHierarchyEditActions(IEditorContext& context, const EditActionTarget& target) {
const bool hierarchyRouteActive = target.route == EditorActionRoute::Hierarchy;
const ::XCEngine::Components::GameObject* activeObject =
hierarchyRouteActive ? target.selectedGameObject : nullptr;
DrawMenuAction(MakeCutAction(false), []() {});
DrawMenuAction(MakeCopyEntityAction(const_cast<::XCEngine::Components::GameObject*>(activeObject)), [&]() {
Commands::CopyEntity(context, target.selectedGameObject->GetID());
});
DrawMenuAction(
hierarchyRouteActive ? MakePasteEntityAction(context) : MakeDisabledPasteAction(),
[&]() {
Commands::PasteEntity(context, target.selectedGameObject ? target.selectedGameObject->GetID() : 0);
});
DrawMenuAction(MakeDuplicateEntityAction(const_cast<::XCEngine::Components::GameObject*>(activeObject)), [&]() {
Commands::DuplicateEntity(context, target.selectedGameObject->GetID());
});
DrawMenuAction(MakeDeleteEntityAction(const_cast<::XCEngine::Components::GameObject*>(activeObject)), [&]() {
Commands::DeleteEntity(context, target.selectedGameObject->GetID());
});
DrawMenuAction(MakeRenameEntityAction(const_cast<::XCEngine::Components::GameObject*>(activeObject)), [&]() {
context.GetEventBus().Publish(EntityRenameRequestedEvent{ target.selectedGameObject->GetID() });
});
}
inline void DrawEditActions(IEditorContext& context) {
const EditActionTarget target = ResolveEditActionTarget(context);
DrawMenuAction(MakeUndoAction(context), [&]() { context.GetUndoManager().Undo(); });
DrawMenuAction(MakeRedoAction(context), [&]() { context.GetUndoManager().Redo(); });
DrawMenuSeparator();
if (target.route == EditorActionRoute::Project) {
DrawProjectEditActions(context, target);
return;
}
DrawHierarchyEditActions(context, target);
}
} // namespace Actions
} // namespace Editor
} // namespace XCEngine

View File

@@ -0,0 +1,47 @@
#pragma once
#include <XCEngine/Debug/LogLevel.h>
namespace XCEngine {
namespace Editor {
namespace UI {
class ConsoleFilterState {
public:
bool& ShowInfo() {
return m_showInfo;
}
bool& ShowWarning() {
return m_showWarning;
}
bool& ShowError() {
return m_showError;
}
bool Allows(::XCEngine::Debug::LogLevel level) const {
switch (level) {
case ::XCEngine::Debug::LogLevel::Verbose:
case ::XCEngine::Debug::LogLevel::Debug:
case ::XCEngine::Debug::LogLevel::Info:
return m_showInfo;
case ::XCEngine::Debug::LogLevel::Warning:
return m_showWarning;
case ::XCEngine::Debug::LogLevel::Error:
case ::XCEngine::Debug::LogLevel::Fatal:
return m_showError;
}
return false;
}
private:
bool m_showInfo = true;
bool m_showWarning = true;
bool m_showError = true;
};
} // namespace UI
} // namespace Editor
} // namespace XCEngine

View File

@@ -1,6 +1,7 @@
#pragma once
#include "BaseTheme.h"
#include "ConsoleFilterState.h"
#include "Core.h"
#include "DockHostStyle.h"
#include "PanelChrome.h"

View File

@@ -1,3 +1,4 @@
#include "Actions/ActionRouting.h"
#include "Actions/EditorActions.h"
#include "ConsolePanel.h"
#include "Core/EditorConsoleSink.h"
@@ -18,6 +19,8 @@ void ConsolePanel::Render() {
return;
}
Actions::ObserveInactiveActionRoute(*m_context);
auto* sink = Debug::EditorConsoleSink::GetInstance();
{
@@ -30,11 +33,11 @@ void ConsolePanel::Render() {
UI::DrawToolbarLabel("Filter");
ImGui::SameLine();
Actions::DrawToolbarToggleAction(Actions::MakeConsoleInfoFilterAction(m_showInfo), m_showInfo);
Actions::DrawToolbarToggleAction(Actions::MakeConsoleInfoFilterAction(m_filterState.ShowInfo()), m_filterState.ShowInfo());
ImGui::SameLine();
Actions::DrawToolbarToggleAction(Actions::MakeConsoleWarningFilterAction(m_showWarning), m_showWarning);
Actions::DrawToolbarToggleAction(Actions::MakeConsoleWarningFilterAction(m_filterState.ShowWarning()), m_filterState.ShowWarning());
ImGui::SameLine();
Actions::DrawToolbarToggleAction(Actions::MakeConsoleErrorFilterAction(m_showError), m_showError);
Actions::DrawToolbarToggleAction(Actions::MakeConsoleErrorFilterAction(m_filterState.ShowError()), m_filterState.ShowError());
}
}
@@ -46,23 +49,7 @@ void ConsolePanel::Render() {
const auto logs = sink->GetLogs();
size_t logIndex = 0;
for (const auto& log : logs) {
bool shouldShow = false;
switch (log.level) {
case ::XCEngine::Debug::LogLevel::Info:
case ::XCEngine::Debug::LogLevel::Verbose:
case ::XCEngine::Debug::LogLevel::Debug:
shouldShow = m_showInfo;
break;
case ::XCEngine::Debug::LogLevel::Warning:
shouldShow = m_showWarning;
break;
case ::XCEngine::Debug::LogLevel::Error:
case ::XCEngine::Debug::LogLevel::Fatal:
shouldShow = m_showError;
break;
}
if (!shouldShow) {
if (!m_filterState.Allows(log.level)) {
continue;
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "Panel.h"
#include "UI/ConsoleFilterState.h"
namespace XCEngine {
namespace Editor {
@@ -11,11 +12,8 @@ public:
void Render() override;
private:
bool m_showInfo = true;
bool m_showWarning = true;
bool m_showError = true;
bool m_scrollToBottom = false;
UI::ConsoleFilterState m_filterState;
};
}
}
}

View File

@@ -1,3 +1,4 @@
#include "Actions/ActionRouting.h"
#include "GameViewPanel.h"
#include "UI/UI.h"
#include <imgui.h>
@@ -9,7 +10,11 @@ GameViewPanel::GameViewPanel() : Panel("Game") {}
void GameViewPanel::Render() {
UI::PanelWindowScope panel(m_name.c_str());
(void)panel;
if (!panel.IsOpen()) {
return;
}
Actions::ObserveInactiveActionRoute(*m_context);
}
}

View File

@@ -63,9 +63,6 @@ void HierarchyPanel::Render() {
Actions::ObserveFocusedActionRoute(*m_context, EditorActionRoute::Hierarchy);
RenderSearchBar();
HandleKeyboardShortcuts();
std::string filter = m_searchBuffer;
UI::PanelContentScope content("EntityList");
@@ -315,29 +312,6 @@ 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());
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) {
if (!gameObject) return false;

View File

@@ -29,7 +29,6 @@ private:
void CommitRename();
void CancelRename();
void HandleDragDrop(::XCEngine::Components::GameObject* gameObject);
void HandleKeyboardShortcuts();
bool PassesFilter(::XCEngine::Components::GameObject* gameObject, const std::string& filter);
void SortEntities(std::vector<::XCEngine::Components::GameObject*>& entities);

View File

@@ -1,3 +1,4 @@
#include "Actions/ActionRouting.h"
#include "Actions/EditorActions.h"
#include "Commands/ComponentCommands.h"
#include "InspectorPanel.h"
@@ -36,6 +37,8 @@ void InspectorPanel::Render() {
if (!panel.IsOpen()) {
return;
}
Actions::ObserveInactiveActionRoute(*m_context);
if (!m_selectionHandlerId && m_context) {
m_selectionHandlerId = m_context->GetEventBus().Subscribe<SelectionChangedEvent>(

View File

@@ -1,16 +1,12 @@
#include "Actions/ActionRouting.h"
#include "Actions/EditActionRouter.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"
#include "UI/UI.h"
#include <filesystem>
#include <imgui.h>
@@ -48,6 +44,7 @@ void MenuBar::HandleShortcuts() {
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(); });
Actions::HandleEditShortcuts(*m_context, shortcutContext);
}
void MenuBar::ShowFileMenu() {
@@ -64,46 +61,8 @@ 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());
});
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() });
});
Actions::DrawEditActions(*m_context);
});
}

View File

@@ -35,7 +35,6 @@ void ProjectPanel::Render() {
}
Actions::ObserveFocusedActionRoute(*m_context, EditorActionRoute::Project);
HandleKeyboardShortcuts();
auto& manager = m_context->GetProjectManager();
@@ -150,30 +149,6 @@ 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);

View File

@@ -14,8 +14,6 @@ public:
void Initialize(const std::string& projectPath);
private:
AssetItemPtr GetSelectedItem() const;
void HandleKeyboardShortcuts();
void RenderAssetItem(const AssetItemPtr& item, int index);
char m_searchBuffer[256] = "";

View File

@@ -1,3 +1,4 @@
#include "Actions/ActionRouting.h"
#include "SceneViewPanel.h"
#include "UI/UI.h"
#include <imgui.h>
@@ -9,7 +10,11 @@ SceneViewPanel::SceneViewPanel() : Panel("Scene") {}
void SceneViewPanel::Render() {
UI::PanelWindowScope panel(m_name.c_str());
(void)panel;
if (!panel.IsOpen()) {
return;
}
Actions::ObserveInactiveActionRoute(*m_context);
}
}