Refactor XCUI editor module layout

This commit is contained in:
2026-04-10 00:41:28 +08:00
parent 4b47764f26
commit 02a0e626fe
263 changed files with 12396 additions and 7592 deletions

View File

@@ -2,12 +2,12 @@
#define NOMINMAX
#endif
#include <XCEditor/Core/UIEditorCommandDispatcher.h>
#include <XCEditor/Core/UIEditorMenuModel.h>
#include <XCEditor/Core/UIEditorMenuSession.h>
#include <XCEditor/Core/UIEditorShortcutManager.h>
#include <XCEditor/Widgets/UIEditorMenuBar.h>
#include <XCEditor/Widgets/UIEditorMenuPopup.h>
#include <XCEditor/Foundation/UIEditorCommandDispatcher.h>
#include <XCEditor/Shell/UIEditorMenuModel.h>
#include <XCEditor/Shell/UIEditorMenuSession.h>
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
#include <XCEditor/Shell/UIEditorMenuBar.h>
#include <XCEditor/Shell/UIEditorMenuPopup.h>
#include "Host/AutoScreenshot.h"
#include "Host/NativeRenderer.h"
@@ -866,9 +866,9 @@ void ScenarioApp::ResetScenario() {
m_menuPopups.clear();
m_menuItems.clear();
SetCustomResult(
"等待操作",
"绛夊緟鎿嶄綔",
"Pending",
"先点 File / Window / Layout,确认一次只会打开一个菜单;再点菜单外区域或按 Escape 关闭。");
"鍏堢偣 File / Window / Layout锛岀‘璁や竴娆″彧浼氭墦寮€涓€涓彍鍗曪紱鍐嶇偣鑿滃崟澶栧尯鍩熸垨鎸?Escape 鍏抽棴銆?);
#endif
}
@@ -1004,7 +1004,7 @@ void ScenarioApp::HandleMouseMove(float x, float y) {
SetCustomResult(
"Hover 切换顶层菜单",
"Changed",
"已切换到顶层菜单 `" + hoveredButton->label + "`。重点检查:旧 root popup 被替换,新 root popup 立即出现。");
"已切换到顶层菜单 `" + hoveredButton->label + "`。重点检查:旧 root popup 被替换,新 root popup 是否立即出现。");
dirty = true;
}
} else {
@@ -1014,7 +1014,7 @@ void ScenarioApp::HandleMouseMove(float x, float y) {
SetCustomResult(
"Hover 收起子菜单",
"Dismissed",
"鼠标回到顶层按钮后,旧的 child popup 已收起。closed: " +
"鼠标回到顶层按钮后,旧的 child popup 已收起。Closed: " +
JoinClosedPopupIds(mutation));
dirty = true;
}
@@ -1040,7 +1040,7 @@ void ScenarioApp::HandleMouseMove(float x, float y) {
SetCustomResult(
"Hover 收起子菜单",
"Dismissed",
"鼠标移到普通菜单项后,旧的 child popup 已收起。closed: " +
"鼠标移到普通菜单项后,旧的 child popup 已收起。Closed: " +
JoinClosedPopupIds(mutation));
dirty = true;
}
@@ -1052,7 +1052,7 @@ void ScenarioApp::HandleMouseMove(float x, float y) {
SetCustomResult(
"Hover popup 空白区",
"Dismissed",
"鼠标停留在 popup 空白区后,子菜单链已回收到当前 popup。closed: " +
"鼠标停留在 popup 空白区后,子菜单链已回收到当前 popup。Closed: " +
JoinClosedPopupIds(mutation));
dirty = true;
}
@@ -1075,7 +1075,7 @@ void ScenarioApp::HandleClick(float x, float y) {
"点击关闭顶层菜单",
mutation.changed ? "Dismissed" : "NoOp",
mutation.changed
? "再次点击当前顶层按钮后,整条菜单链已关闭。closed: " +
? "再次点击当前顶层按钮后,整条菜单链已关闭。Closed: " +
JoinClosedPopupIds(mutation)
: "当前顶层菜单没有发生变化。");
} else {
@@ -1108,8 +1108,8 @@ void ScenarioApp::HandleClick(float x, float y) {
mutation.changed ? "Changed" : "NoOp",
mutation.changed
? "已展开 `" + hoveredItem->label +
"` 子菜单。这个场景正常行为是 hover 也会直接展开。"
: "子菜单已经处于开状态。");
"` 子菜单。这个场景正常行为是 hover 也会直接展开。"
: "子菜单已经处于开状态。");
InvalidateRect(m_hwnd, nullptr, FALSE);
return;
}
@@ -1140,7 +1140,7 @@ void ScenarioApp::HandleClick(float x, float y) {
SetCustomResult(
"点击 popup 空白区",
"Dismissed",
"点击当前 popup 空白区后,仅更深层子菜单被关闭。closed: " +
"点击当前 popup 空白区后,仅更深层子菜单被关闭。Closed: " +
JoinClosedPopupIds(mutation));
ClearHoverWhenMenuClosed();
InvalidateRect(m_hwnd, nullptr, FALSE);
@@ -1155,7 +1155,7 @@ void ScenarioApp::HandleClick(float x, float y) {
"点击菜单外区域",
mutation.changed ? "Dismissed" : "NoOp",
mutation.changed
? "点击外部区域后,整条菜单链已关闭。closed: " +
? "点击外部区域后,整条菜单链已关闭。Closed: " +
JoinClosedPopupIds(mutation)
: "菜单链没有变化。");
ClearHoverWhenMenuClosed();
@@ -1172,14 +1172,14 @@ void ScenarioApp::HandleClick(float x, float y) {
if (m_openMenuId == button.menuId) {
m_openMenuId.clear();
m_hoveredItemId.clear();
SetCustomResult("关闭菜单", "NoOp", "再次点击当前菜单按钮,菜单已关闭。");
SetCustomResult("鍏抽棴鑿滃崟", "NoOp", "鍐嶆鐐瑰嚮褰撳墠鑿滃崟鎸夐挳锛岃彍鍗曞凡鍏抽棴銆?);
} else {
m_openMenuId = button.menuId;
m_hoveredItemId.clear();
SetCustomResult(
"打开菜单",
"鎵撳紑鑿滃崟",
"Changed",
"当前激活菜单: " + button.label + "。确认同一时刻只存在一个下拉菜单。");
"褰撳墠婵€娲昏彍鍗? " + button.label + "銆傜‘璁ゅ悓涓€鏃跺埢鍙瓨鍦ㄤ竴涓笅鎷夎彍鍗曘€?);
}
InvalidateRect(m_hwnd, nullptr, FALSE);
return;
@@ -1197,9 +1197,9 @@ void ScenarioApp::HandleClick(float x, float y) {
if (!item.enabled) {
SetCustomResult(
"菜单项不可执行",
"鑿滃崟椤逛笉鍙墽琛?,
"Disabled",
"当前工作区状态下 `" + item.label + "` 不可执行。");
"褰撳墠宸ヤ綔鍖虹姸鎬佷笅 `" + item.label + "` 涓嶅彲鎵ц銆?);
InvalidateRect(m_hwnd, nullptr, FALSE);
return;
}
@@ -1216,7 +1216,7 @@ void ScenarioApp::HandleClick(float x, float y) {
if (!m_openMenuId.empty()) {
m_openMenuId.clear();
m_hoveredItemId.clear();
SetCustomResult("菜单失焦", "Dismissed", "点击菜单外区域,菜单已关闭。");
SetCustomResult("鑿滃崟澶辩劍", "Dismissed", "鐐瑰嚮鑿滃崟澶栧尯鍩燂紝鑿滃崟宸插叧闂€?);
InvalidateRect(m_hwnd, nullptr, FALSE);
}
#endif
@@ -1255,13 +1255,13 @@ void ScenarioApp::HandleKeyDown(UINT keyCode) {
if (!m_openMenuId.empty()) {
m_openMenuId.clear();
m_hoveredItemId.clear();
SetCustomResult("Esc 关闭菜单", "Dismissed", "按下 Escape 后,菜单已关闭。");
SetCustomResult("Esc 鍏抽棴鑿滃崟", "Dismissed", "鎸変笅 Escape 鍚庯紝鑿滃崟宸插叧闂€?);
InvalidateRect(m_hwnd, nullptr, FALSE);
}
break;
case 'R':
SetDispatchResult(
"键盘 Reset Workspace",
"閿洏 Reset Workspace",
m_commandDispatcher.Dispatch("workspace.reset", m_controller));
InvalidateRect(m_hwnd, nullptr, FALSE);
break;
@@ -1446,13 +1446,13 @@ void ScenarioApp::BuildDrawData(UIDrawData& drawData, float width, float height)
DrawCard(
drawList,
headerRect,
"测试内容Editor Menu 会话状态层",
"这个测试验证什么功能?",
"本场景只验证顶层菜单切换、child popup hover、Esc / outside dismiss、命令派发不验证业务面板。");
drawList.AddText(UIPoint(headerRect.x + 18.0f, headerRect.y + 70.0f), "1. 点击 File 打开 root popup再 hover `Workspace Tools`,右侧 child popup 应立即弹出。", kTextPrimary, 13.0f);
drawList.AddText(UIPoint(headerRect.x + 18.0f, headerRect.y + 92.0f), "2. root popup 打开时,把鼠标移到 Window / Layout 顶层按钮,旧 popup 应直接被新的 root popup 替换。", kTextPrimary, 13.0f);
drawList.AddText(UIPoint(headerRect.x + 18.0f, headerRect.y + 114.0f), "3. 点击 Window -> Activate Details再点 Window -> Hide Active检查右侧 details visible / active 是否按状态变化。", kTextPrimary, 13.0f);
drawList.AddText(UIPoint(headerRect.x + 18.0f, headerRect.y + 136.0f), "4. 如果 child popup 已打开,按一次 Esc 只关 topmost再按一次 Esc 关闭整条菜单链。点击外部空白区也必须整条关闭。", kTextPrimary, 13.0f);
drawList.AddText(UIPoint(headerRect.x + 18.0f, headerRect.y + 158.0f), "5. F12 保存截图R 可直接触发 Reset Workspace方便确认命令派发仍正常。", kTextPrimary, 13.0f);
drawList.AddText(UIPoint(headerRect.x + 18.0f, headerRect.y + 158.0f), "5. F12 保存截图R 可直接触发 Reset Workspace方便确认命令派发仍正常。", kTextPrimary, 13.0f);
DrawCard(drawList, shellRect, "操作区", "这里只保留 MenuBar 和当前 popup overlay。");
DrawCard(drawList, stateRect, "状态摘要", "重点看 menu session 当前链路和 Details 状态,不放无关杂项。");
@@ -1464,15 +1464,15 @@ void ScenarioApp::BuildDrawData(UIDrawData& drawData, float width, float height)
const UIRect shellInfoRect(shellRect.x + 18.0f, shellRect.y + 144.0f, shellRect.width - 36.0f, 190.0f);
drawList.AddFilledRect(shellInfoRect, kIndicatorBg, 8.0f);
drawList.AddRectOutline(shellInfoRect, kCardBorder, 1.0f, 8.0f);
drawList.AddText(UIPoint(shellInfoRect.x + 14.0f, shellInfoRect.y + 14.0f), "Open root menu", kTextMuted, 12.0f);
drawList.AddText(UIPoint(shellInfoRect.x + 14.0f, shellInfoRect.y + 14.0f), "已打开 root menu", kTextMuted, 12.0f);
drawList.AddText(UIPoint(shellInfoRect.x + 14.0f, shellInfoRect.y + 34.0f), m_menuSession.HasOpenMenu() ? std::string(m_menuSession.GetOpenRootMenuId()) : "(none)", kTextPrimary, 14.0f);
drawList.AddText(UIPoint(shellInfoRect.x + 14.0f, shellInfoRect.y + 62.0f), "Popup chain", kTextMuted, 12.0f);
drawList.AddText(UIPoint(shellInfoRect.x + 14.0f, shellInfoRect.y + 62.0f), "Popup ", kTextMuted, 12.0f);
drawList.AddText(UIPoint(shellInfoRect.x + 14.0f, shellInfoRect.y + 82.0f), JoinPopupChainIds(m_menuSession), kTextPrimary, 14.0f);
drawList.AddText(UIPoint(shellInfoRect.x + 14.0f, shellInfoRect.y + 110.0f), "Submenu path", kTextMuted, 12.0f);
drawList.AddText(UIPoint(shellInfoRect.x + 14.0f, shellInfoRect.y + 110.0f), "Submenu 路径", kTextMuted, 12.0f);
drawList.AddText(UIPoint(shellInfoRect.x + 14.0f, shellInfoRect.y + 130.0f), JoinSubmenuPathIds(m_menuSession), kTextPrimary, 14.0f);
drawList.AddText(UIPoint(shellInfoRect.x + 14.0f, shellInfoRect.y + 158.0f), "提示popup overlay 必须压在右侧状态面板上方,这一轮会专门检查这个层级关系。", kTextMuted, 12.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 72.0f), "Hover summary", kAccent, 15.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 72.0f), "Hover 摘要", kAccent, 15.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 100.0f), "hover menu", kTextMuted, 12.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 120.0f), m_hoveredMenuId.empty() ? "(none)" : m_hoveredMenuId, kTextPrimary, 14.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 150.0f), "hover popup", kTextMuted, 12.0f);
@@ -1480,19 +1480,19 @@ void ScenarioApp::BuildDrawData(UIDrawData& drawData, float width, float height)
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 200.0f), "hover item", kTextMuted, 12.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 220.0f), m_hoveredItemId.empty() ? "(none)" : m_hoveredItemId, kTextPrimary, 14.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 262.0f), "Workspace summary", kAccent, 15.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 290.0f), "active panel", kTextMuted, 12.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 262.0f), "Workspace 摘要", kAccent, 15.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 290.0f), "当前激活面板", kTextMuted, 12.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 310.0f), workspace.activePanelId.empty() ? "(none)" : workspace.activePanelId, kTextPrimary, 14.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 338.0f), "visible panels", kTextMuted, 12.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 338.0f), "可见面板", kTextMuted, 12.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 358.0f), JoinVisiblePanelIds(workspace, session), kTextPrimary, 14.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 386.0f), "details visible", kTextMuted, 12.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 386.0f), "Details 可见", kTextMuted, 12.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 406.0f), detailsState != nullptr && detailsState->visible ? "true" : "false", detailsState != nullptr && detailsState->visible ? kSuccess : kWarning, 14.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 434.0f), "details active", kTextMuted, 12.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 434.0f), "Details 激活", kTextMuted, 12.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 454.0f), workspace.activePanelId == "details" ? "true" : "false", workspace.activePanelId == "details" ? kSuccess : kTextMuted, 14.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 482.0f), "menu model validation", kTextMuted, 12.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 482.0f), "菜单模型验证", kTextMuted, 12.0f);
drawList.AddText(UIPoint(stateRect.x + 18.0f, stateRect.y + 502.0f), menuValidation.IsValid() ? "OK" : menuValidation.message, menuValidation.IsValid() ? kSuccess : kDanger, 12.0f);
drawList.AddText(UIPoint(footerRect.x + 18.0f, footerRect.y + 56.0f), "Last interaction: " + m_lastActionName + " | Result: " + m_lastStatusLabel, m_lastStatusColor, 13.0f);
drawList.AddText(UIPoint(footerRect.x + 18.0f, footerRect.y + 56.0f), "最近交互: " + m_lastActionName + " | Result: " + m_lastStatusLabel, m_lastStatusColor, 13.0f);
drawList.AddText(UIPoint(footerRect.x + 18.0f, footerRect.y + 74.0f), m_lastMessage, kTextPrimary, 12.0f);
const std::string captureSummary =
@@ -1630,7 +1630,7 @@ void ScenarioApp::BuildDrawData(UIDrawData& drawData, float width, float height)
DrawCard(
drawList,
headerRect,
"测试内容Editor Menu 基础壳层验证",
"这个测试验证什么功能?",
"只验证 MenuBar / 下拉展开 / hover / 菜单关闭 / command dispatch不验证业务面板不验证完整编辑器菜单体系。");
drawList.AddText(UIPoint(headerRect.x + 18.0f, headerRect.y + 70.0f), "1. 点击 File / Window / Layout确认同一时刻只会有一个菜单展开。", kTextPrimary, 13.0f);
drawList.AddText(UIPoint(headerRect.x + 18.0f, headerRect.y + 92.0f), "2. 展开菜单后移动鼠标,确认 hover 高亮稳定disabled 项不会误显示成可点击。", kTextPrimary, 13.0f);