From 6ec5f05601e778be2cf6771ec8e431784efc04a0 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Fri, 27 Mar 2026 00:15:38 +0800 Subject: [PATCH] Refactor main menu action shell --- docs/plan/Editor重构3.26.md | 3 + editor/src/Actions/MainMenuActionRouter.h | 50 ++++++++++++++ editor/src/UI/AboutEditorDialog.h | 39 +++++++++++ editor/src/UI/SceneStatusWidget.h | 46 +++++++++++++ editor/src/UI/UI.h | 2 + editor/src/UI/Widgets.h | 1 + editor/src/panels/MenuBar.cpp | 83 ++--------------------- 7 files changed, 148 insertions(+), 76 deletions(-) create mode 100644 editor/src/Actions/MainMenuActionRouter.h create mode 100644 editor/src/UI/AboutEditorDialog.h create mode 100644 editor/src/UI/SceneStatusWidget.h diff --git a/docs/plan/Editor重构3.26.md b/docs/plan/Editor重构3.26.md index dfb0f6ab..e7c64ee9 100644 --- a/docs/plan/Editor重构3.26.md +++ b/docs/plan/Editor重构3.26.md @@ -107,6 +107,7 @@ - `Project` 右键菜单目标已不再依赖 panel 内裸索引字段,而是改成 targeted popup state - `Inspector / Console` 的局部 action 组装也开始继续下沉到 shared router - `Inspector` 的 component section header 菜单已开始改成 callback/router 驱动,而不是在 widget 层硬编码动作 +- `MenuBar` 的 File / View / Help / global shortcut 也开始继续下沉到 shared main-menu router ### 5. Dock / Layout 层 @@ -172,6 +173,8 @@ - `Exit` 已通过事件驱动关闭 editor - `Edit` 菜单已开始跟随 active action route 在 `Hierarchy / Project` 之间切换 - `Edit` 菜单与上下文快捷键开始共享同一套 edit action router +- `File / View / Help / global shortcut` 已开始继续从 panel 下沉到 shared main-menu router +- scene status 与 about dialog 已开始继续从 panel 下沉到共享 UI widget/dialog 仍待完成: diff --git a/editor/src/Actions/MainMenuActionRouter.h b/editor/src/Actions/MainMenuActionRouter.h new file mode 100644 index 00000000..bc147cc5 --- /dev/null +++ b/editor/src/Actions/MainMenuActionRouter.h @@ -0,0 +1,50 @@ +#pragma once + +#include "EditActionRouter.h" +#include "EditorActions.h" +#include "Commands/SceneCommands.h" +#include "Core/EditorEvents.h" +#include "Core/EventBus.h" +#include "Core/IEditorContext.h" +#include "UI/PopupState.h" + +namespace XCEngine { +namespace Editor { +namespace Actions { + +inline void HandleMainMenuShortcuts(IEditorContext& context, const ShortcutContext& shortcutContext) { + HandleShortcut(MakeNewSceneAction(), shortcutContext, [&]() { Commands::NewScene(context); }); + HandleShortcut(MakeOpenSceneAction(), shortcutContext, [&]() { Commands::OpenSceneWithDialog(context); }); + HandleShortcut(MakeSaveSceneAction(), shortcutContext, [&]() { Commands::SaveCurrentScene(context); }); + HandleShortcut(MakeSaveSceneAsAction(), shortcutContext, [&]() { Commands::SaveSceneAsWithDialog(context); }); + HandleShortcut(MakeUndoAction(context), shortcutContext, [&]() { context.GetUndoManager().Undo(); }); + HandleShortcut(MakeRedoAction(context), shortcutContext, [&]() { context.GetUndoManager().Redo(); }); + HandleEditShortcuts(context, shortcutContext); +} + +inline void DrawFileMenuActions(IEditorContext& context) { + DrawMenuAction(MakeNewSceneAction(), [&]() { Commands::NewScene(context); }); + DrawMenuAction(MakeOpenSceneAction(), [&]() { Commands::OpenSceneWithDialog(context); }); + DrawMenuAction(MakeSaveSceneAction(), [&]() { Commands::SaveCurrentScene(context); }); + DrawMenuAction(MakeSaveSceneAsAction(), [&]() { Commands::SaveSceneAsWithDialog(context); }); + DrawMenuSeparator(); + DrawMenuAction(MakeExitAction(), [&]() { + context.GetEventBus().Publish(EditorExitRequestedEvent{}); + }); +} + +inline void DrawViewMenuActions(IEditorContext& context) { + DrawMenuAction(MakeResetLayoutAction(), [&]() { + context.GetEventBus().Publish(DockLayoutResetRequestedEvent{}); + }); +} + +inline void DrawHelpMenuActions(UI::DeferredPopupState& aboutPopup) { + DrawMenuAction(MakeAboutAction(), [&]() { + aboutPopup.RequestOpen(); + }); +} + +} // namespace Actions +} // namespace Editor +} // namespace XCEngine diff --git a/editor/src/UI/AboutEditorDialog.h b/editor/src/UI/AboutEditorDialog.h new file mode 100644 index 00000000..d4a33921 --- /dev/null +++ b/editor/src/UI/AboutEditorDialog.h @@ -0,0 +1,39 @@ +#pragma once + +#include "PopupState.h" +#include "Widgets.h" + +#include "Core/IEditorContext.h" + +namespace XCEngine { +namespace Editor { +namespace UI { + +inline void DrawEditorAboutDialog(const IEditorContext* context, DeferredPopupState& popupState) { + popupState.ConsumeOpenRequest("About XCEngine Editor"); + + if (!BeginModalPopup("About XCEngine Editor")) { + return; + } + + ImGui::TextUnformatted("XCEngine Editor"); + ImGui::Separator(); + DrawHintText("Unity-like editor shell built on Dear ImGui."); + ImGui::Spacing(); + ImGui::Text("Date: 2026-03-27"); + ImGui::Text("UI Refactor: Actions / Commands / Layout in progress"); + if (context) { + ImGui::Text("Project: %s", context->GetProjectPath().c_str()); + } + ImGui::Spacing(); + + if (ImGui::Button("Close", DialogActionButtonSize())) { + ImGui::CloseCurrentPopup(); + } + + EndPopup(); +} + +} // namespace UI +} // namespace Editor +} // namespace XCEngine diff --git a/editor/src/UI/SceneStatusWidget.h b/editor/src/UI/SceneStatusWidget.h new file mode 100644 index 00000000..d8f774cb --- /dev/null +++ b/editor/src/UI/SceneStatusWidget.h @@ -0,0 +1,46 @@ +#pragma once + +#include "Widgets.h" + +#include "Core/IEditorContext.h" +#include "Core/ISceneManager.h" + +#include +#include + +namespace XCEngine { +namespace Editor { +namespace UI { + +inline void DrawSceneStatusWidget(IEditorContext& context) { + auto& sceneManager = context.GetSceneManager(); + std::string sceneLabel = sceneManager.HasActiveScene() ? sceneManager.GetCurrentSceneName() : "No Scene"; + if (sceneLabel.empty()) { + sceneLabel = "Untitled Scene"; + } + + const std::string fileLabel = sceneManager.GetCurrentScenePath().empty() + ? "Unsaved.xc" + : std::filesystem::path(sceneManager.GetCurrentScenePath()).filename().string(); + + const bool dirty = sceneManager.IsSceneDirty(); + const std::string statusText = dirty ? (std::string("* ") + fileLabel) : fileLabel; + DrawRightAlignedText( + statusText.c_str(), + dirty ? MenuBarStatusDirtyColor() : MenuBarStatusIdleColor()); + + if (ImGui::IsItemHovered()) { + BeginTitledTooltip("Scene"); + ImGui::Text("Name: %s", sceneLabel.c_str()); + ImGui::Text("File: %s", fileLabel.c_str()); + ImGui::Text("State: %s", dirty ? "Modified" : "Saved"); + ImGui::Text( + "Path: %s", + sceneManager.GetCurrentScenePath().empty() ? "(not saved yet)" : sceneManager.GetCurrentScenePath().c_str()); + EndTitledTooltip(); + } +} + +} // namespace UI +} // namespace Editor +} // namespace XCEngine diff --git a/editor/src/UI/UI.h b/editor/src/UI/UI.h index cd481fc9..1b84c73e 100644 --- a/editor/src/UI/UI.h +++ b/editor/src/UI/UI.h @@ -1,5 +1,6 @@ #pragma once +#include "AboutEditorDialog.h" #include "BaseTheme.h" #include "ConsoleFilterState.h" #include "ConsoleLogFormatter.h" @@ -9,6 +10,7 @@ #include "PopupState.h" #include "PropertyGrid.h" #include "ScalarControls.h" +#include "SceneStatusWidget.h" #include "StyleTokens.h" #include "VectorControls.h" #include "Widgets.h" diff --git a/editor/src/UI/Widgets.h b/editor/src/UI/Widgets.h index 61a9b9f3..d6258037 100644 --- a/editor/src/UI/Widgets.h +++ b/editor/src/UI/Widgets.h @@ -1,5 +1,6 @@ #pragma once +#include "Core.h" #include "StyleTokens.h" #include diff --git a/editor/src/panels/MenuBar.cpp b/editor/src/panels/MenuBar.cpp index 537e4e71..c06fb8e6 100644 --- a/editor/src/panels/MenuBar.cpp +++ b/editor/src/panels/MenuBar.cpp @@ -1,14 +1,9 @@ #include "Actions/ActionRouting.h" #include "Actions/EditActionRouter.h" -#include "Actions/EditorActions.h" -#include "Commands/SceneCommands.h" +#include "Actions/MainMenuActionRouter.h" #include "MenuBar.h" -#include "Core/EditorEvents.h" -#include "Core/EventBus.h" #include "Core/IEditorContext.h" -#include "Core/ISceneManager.h" #include "UI/UI.h" -#include #include namespace XCEngine { @@ -36,27 +31,12 @@ void MenuBar::HandleShortcuts() { return; } - 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(); }); - Actions::HandleEditShortcuts(*m_context, shortcutContext); + Actions::HandleMainMenuShortcuts(*m_context, Actions::GlobalShortcutContext()); } void MenuBar::ShowFileMenu() { UI::DrawMenuScope("File", [&]() { - Actions::DrawMenuAction(Actions::MakeNewSceneAction(), [&]() { Commands::NewScene(*m_context); }); - Actions::DrawMenuAction(Actions::MakeOpenSceneAction(), [&]() { Commands::OpenSceneWithDialog(*m_context); }); - Actions::DrawMenuAction(Actions::MakeSaveSceneAction(), [&]() { Commands::SaveCurrentScene(*m_context); }); - Actions::DrawMenuAction(Actions::MakeSaveSceneAsAction(), [&]() { Commands::SaveSceneAsWithDialog(*m_context); }); - Actions::DrawMenuSeparator(); - Actions::DrawMenuAction(Actions::MakeExitAction(), [&]() { - m_context->GetEventBus().Publish(EditorExitRequestedEvent{}); - }); + Actions::DrawFileMenuActions(*m_context); }); } @@ -68,74 +48,25 @@ void MenuBar::ShowEditMenu() { void MenuBar::ShowViewMenu() { UI::DrawMenuScope("View", [&]() { - Actions::DrawMenuAction(Actions::MakeResetLayoutAction(), [&]() { - m_context->GetEventBus().Publish(DockLayoutResetRequestedEvent{}); - }); + Actions::DrawViewMenuActions(*m_context); }); } void MenuBar::ShowHelpMenu() { UI::DrawMenuScope("Help", [&]() { - Actions::DrawMenuAction(Actions::MakeAboutAction(), [&]() { - m_aboutPopup.RequestOpen(); - }); + Actions::DrawHelpMenuActions(m_aboutPopup); }); } void MenuBar::RenderAboutPopup() { - m_aboutPopup.ConsumeOpenRequest("About XCEngine Editor"); - - if (!UI::BeginModalPopup("About XCEngine Editor")) { - return; - } - - ImGui::TextUnformatted("XCEngine Editor"); - ImGui::Separator(); - UI::DrawHintText("Unity-like editor shell built on Dear ImGui."); - ImGui::Spacing(); - ImGui::Text("Date: 2026-03-26"); - ImGui::Text("UI Refactor: Actions / Commands / Layout in progress"); - if (m_context) { - ImGui::Text("Project: %s", m_context->GetProjectPath().c_str()); - } - ImGui::Spacing(); - - if (Actions::DrawButtonAction(Actions::MakeAction("Close"), UI::DialogActionButtonSize())) { - ImGui::CloseCurrentPopup(); - } - - UI::EndPopup(); + UI::DrawEditorAboutDialog(m_context, m_aboutPopup); } void MenuBar::RenderSceneStatus() { if (!m_context) { return; } - - auto& sceneManager = m_context->GetSceneManager(); - std::string sceneLabel = sceneManager.HasActiveScene() ? sceneManager.GetCurrentSceneName() : "No Scene"; - if (sceneLabel.empty()) { - sceneLabel = "Untitled Scene"; - } - - std::string fileLabel = sceneManager.GetCurrentScenePath().empty() - ? "Unsaved.xc" - : std::filesystem::path(sceneManager.GetCurrentScenePath()).filename().string(); - - const bool dirty = sceneManager.IsSceneDirty(); - const std::string statusText = dirty ? (std::string("* ") + fileLabel) : fileLabel; - UI::DrawRightAlignedText( - statusText.c_str(), - dirty ? UI::MenuBarStatusDirtyColor() : UI::MenuBarStatusIdleColor()); - - if (ImGui::IsItemHovered()) { - UI::BeginTitledTooltip("Scene"); - ImGui::Text("Name: %s", sceneLabel.c_str()); - ImGui::Text("File: %s", fileLabel.c_str()); - ImGui::Text("State: %s", dirty ? "Modified" : "Saved"); - ImGui::Text("Path: %s", sceneManager.GetCurrentScenePath().empty() ? "(not saved yet)" : sceneManager.GetCurrentScenePath().c_str()); - UI::EndTitledTooltip(); - } + UI::DrawSceneStatusWidget(*m_context); } }