Refine editor window host structure and utility chrome
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
|
||||
## 2. 分层边界
|
||||
|
||||
推荐按下面四层理解和修改:
|
||||
推荐按下面五层理解和修改:
|
||||
|
||||
1. `editor/src` / `editor/include/XCEditor`
|
||||
XCEditor UI framework。这里应保持通用,不依赖具体项目、场景、Win32 宿主或 D3D12 实现。
|
||||
@@ -29,20 +29,43 @@
|
||||
2. `editor/app/Composition`、`Features`、`Project`、`Scene`、`State`、`Commands`
|
||||
Editor app core。这里装配 panel、项目运行时、场景运行时、选择状态、命令路由和 shell frame。
|
||||
|
||||
3. `editor/app/Platform/Win32`
|
||||
Win32 host。这里负责原生窗口、消息分发、窗口生命周期、输入收集、窗口内容装载和 title bar / chrome。
|
||||
3. `editor/app/Windowing`
|
||||
Editor host seam。这里放平台无关的窗口内容 contract、workspace/utility content assembly、frame orchestration 和 host-facing transfer request。
|
||||
|
||||
4. `editor/app/Rendering`
|
||||
4. `editor/app/Platform/Win32`
|
||||
Win32 host。这里负责原生窗口、消息分发、窗口生命周期、输入收集、title bar / chrome 和 surface/presenter。
|
||||
|
||||
5. `editor/app/Rendering`
|
||||
Editor rendering host。这里负责 D3D12 UI 渲染、窗口 swapchain、viewport 离屏资源、editor 图标纹理和 scene viewport pass。
|
||||
|
||||
依赖方向尽量保持:
|
||||
|
||||
```text
|
||||
app/platform + app/rendering -> app/core -> XCEditor framework -> engine UI primitives
|
||||
app/platform + app/rendering -> app/windowing -> app/core -> XCEditor framework -> engine UI primitives
|
||||
```
|
||||
|
||||
不要让 `editor/src` 反向依赖 `editor/app`。
|
||||
|
||||
### 2.1 长期目标:把语义分层落成真实模块边界
|
||||
|
||||
当前 `editor/` 已经有语义上的四层划分,但还没有真正的编译/依赖边界。窗口相关代码最重要的长期目标,不是继续细拆 `Win32` 目录里的类,而是把下面这条关系变成代码和构建系统都能强制执行的事实:
|
||||
|
||||
```text
|
||||
XCEditor framework
|
||||
<- editor app core
|
||||
<- editor host seam / app/Windowing
|
||||
<- Win32 host + D3D12 host
|
||||
```
|
||||
|
||||
收敛要求:
|
||||
|
||||
- `editor/app/Platform/Win32` 只负责 native window、message pump、input translation、chrome、lifecycle 和 surface/presenter 等宿主职责。
|
||||
- workspace mutation、utility window routing、shell composition、window content assembly 这类产品语义应逐步收敛到平台无关层,而不是继续堆进 Win32 host。
|
||||
- `editor/src` / `editor/include/XCEditor` 不允许反向依赖 `editor/app`;公开头文件不应暴露 `App::*` 类型。
|
||||
- 最终要通过独立 CMake target 和受限 include dirs 落实,而不是只靠目录约定。
|
||||
|
||||
后续凡是修改窗口系统,优先朝“缩小 `Platform/Win32` 对 `Composition`、`Features`、`UtilityWindows`、`Rendering` 的直接依赖面”这个方向收敛。如果一个新需求只能通过继续把业务语义塞进 Win32 host 才能完成,应先停下来评估是否缺少平台无关的 host seam。
|
||||
|
||||
## 3. 顶层启动流程
|
||||
|
||||
入口:
|
||||
@@ -128,7 +151,7 @@ utility window 的内容控制器是 `EditorUtilityWindowContentController`,
|
||||
窗口外观/宿主策略当前最少包括:
|
||||
|
||||
- `EditorWindowChromePolicy`
|
||||
当前用于控制 detached title bar tab strip 和 frame stats。
|
||||
当前用于控制 detached title bar tab strip、frame stats,以及 utility window 的 topmost pin 按钮/默认置顶策略。
|
||||
- `EditorWindowNativeStylePolicy`
|
||||
当前用于控制扩展窗口样式和是否复用 host 默认 style。
|
||||
|
||||
@@ -137,6 +160,7 @@ utility window 的内容控制器是 `EditorUtilityWindowContentController`,
|
||||
- workspace window 允许 detached title bar tab strip。
|
||||
- utility window 不允许 detached title bar tab strip。
|
||||
- utility window 不显示 frame stats。
|
||||
- utility window 顶栏显示 topmost pin 按钮,且默认置顶。
|
||||
- utility window 使用 `WS_EX_TOOLWINDOW`。
|
||||
|
||||
## 6. Workspace / Utility 协调器边界
|
||||
@@ -218,11 +242,12 @@ Application::Run
|
||||
|
||||
## 9. 修改规范
|
||||
|
||||
- 先判断改动属于 framework、app core、Win32 host 还是 rendering host。
|
||||
- 先判断改动属于 framework、app core、windowing seam、Win32 host 还是 rendering host。
|
||||
- 小改动优先贴近现有模式,不顺手做跨层重构。
|
||||
- 新增通用 widget 放 `editor/src` / `editor/include/XCEditor`。
|
||||
- 新增具体 editor 功能放 `editor/app/Features/<FeatureName>`,再由 composition 装配。
|
||||
- 新增窗口行为放 `editor/app/Platform/Win32`,通过 content/controller/policy/binding 与 app core 通信。
|
||||
- 新增 host-facing window content、frame request、content assembly 放 `editor/app/Windowing`。
|
||||
- 新增 Win32 宿主行为放 `editor/app/Platform/Win32`,通过 seam/controller/policy 与 app core 通信。
|
||||
- 新增 viewport 渲染资源或 pass 放 `editor/app/Rendering/Viewport` 或 `editor/resources/shaders/scene-viewport`。
|
||||
- draw append 只负责绘制,不修改 editor runtime 或 scene/project state。
|
||||
- D3D12 host、Win32 host、panel 之间避免双向强耦合。
|
||||
@@ -231,11 +256,11 @@ Application::Run
|
||||
|
||||
这轮重构完成后,仍有以下债务:
|
||||
|
||||
- `editor/CMakeLists.txt` 还没有把 framework、app core、Win32 host、D3D12 host 拆成独立 target。
|
||||
- `editor/CMakeLists.txt` 还没有把 framework、app core、windowing seam、Win32 host、D3D12 host 拆成独立 target。
|
||||
- `EditorContext` 仍然过重,混合了全局状态、service locator、command bridge、session sync 和状态输出。
|
||||
- `EditorShellRuntime` 仍然过重,既持有 panel,又持有 viewport host、shell frame、draw composer 和 interaction coordinator。
|
||||
- panel 仍缺少统一 feature 接口,`HierarchyPanel`、`ProjectPanel`、`InspectorPanel` 只是模式相似。
|
||||
- Win32 host 和 utility host 还没有拆到独立目录层级,例如 `Windowing/Core`、`Windowing/Workspace`、`Windowing/Utility`。
|
||||
- `app/Windowing` 目前只是首刀 ownership 调整,workspace / utility window orchestration 仍主要停留在 Win32 coordinator。
|
||||
|
||||
这些债务后续要分步处理,不要一次性重写整个窗口系统。
|
||||
|
||||
@@ -257,11 +282,11 @@ Application::Run
|
||||
- `editor/app/Bootstrap/Application.*`
|
||||
- `editor/app/Composition/EditorContext.*`
|
||||
- `editor/app/Composition/EditorShellRuntime.*`
|
||||
- `editor/app/Platform/Win32/Content/EditorWindowContentController.h`
|
||||
- `editor/app/Windowing/Content/EditorWindowContentController.h`
|
||||
- `editor/app/Windowing/Frame/EditorWindowFrameOrchestrator.*`
|
||||
- `editor/app/Platform/Win32/Windowing/EditorWindow.*`
|
||||
- `editor/app/Platform/Win32/Windowing/EditorWindowWorkspaceCoordinator.*`
|
||||
- `editor/app/Platform/Win32/Windowing/EditorUtilityWindowCoordinator.*`
|
||||
- `editor/app/UtilityWindows/EditorUtilityWindowRegistry.*`
|
||||
- `editor/include/XCEditor/Workspace/UIEditorWorkspaceController.h`
|
||||
- `editor/include/XCEditor/Shell/UIEditorShellInteraction.h`
|
||||
|
||||
|
||||
@@ -239,17 +239,20 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP)
|
||||
app/Scene/EditorSceneBridge.cpp
|
||||
)
|
||||
|
||||
set(XCUI_EDITOR_APP_WINDOWING_SOURCES
|
||||
app/Windowing/Content/EditorUtilityWindowContentController.cpp
|
||||
app/Windowing/Content/EditorWorkspaceWindowContentController.cpp
|
||||
app/Windowing/Frame/EditorWindowFrameOrchestrator.cpp
|
||||
)
|
||||
|
||||
set(XCUI_EDITOR_APP_PLATFORM_SOURCES
|
||||
app/Platform/Win32/Windowing/EditorWindow.cpp
|
||||
app/Platform/Win32/Windowing/EditorFloatingWindowPlacement.cpp
|
||||
app/Platform/Win32/Windowing/EditorWindowSession.cpp
|
||||
app/Platform/Win32/Content/EditorUtilityWindowContentController.cpp
|
||||
app/Platform/Win32/Chrome/EditorWindowChromeController.cpp
|
||||
app/Platform/Win32/Runtime/EditorWindowFrameDriver.cpp
|
||||
app/Platform/Win32/Runtime/EditorWindowFrameOrchestrator.cpp
|
||||
app/Platform/Win32/Runtime/EditorWindowInputController.cpp
|
||||
app/Platform/Win32/Runtime/EditorWindowRuntimeController.cpp
|
||||
app/Platform/Win32/Content/EditorWorkspaceWindowContentController.cpp
|
||||
app/Platform/Win32/System/Win32SystemInteractionHost.cpp
|
||||
app/Platform/Win32/Windowing/EditorWindowHostRuntime.cpp
|
||||
app/Platform/Win32/Windowing/EditorWindowLifecycleCoordinator.cpp
|
||||
@@ -273,6 +276,7 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP)
|
||||
${XCUI_EDITOR_HOST_PLATFORM_SOURCES}
|
||||
${XCUI_EDITOR_HOST_RENDERING_SOURCES}
|
||||
${XCUI_EDITOR_APP_CORE_SOURCES}
|
||||
${XCUI_EDITOR_APP_WINDOWING_SOURCES}
|
||||
${XCUI_EDITOR_APP_PLATFORM_SOURCES}
|
||||
)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "Composition/EditorContext.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowManager.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindow.h"
|
||||
#include "Platform/Win32/Content/EditorWorkspaceWindowContentController.h"
|
||||
#include "Windowing/Content/EditorWorkspaceWindowContentController.h"
|
||||
#include "Platform/Win32/System/Win32SystemInteractionHost.h"
|
||||
#include "Support/EnvironmentFlags.h"
|
||||
#include "Support/ExecutablePath.h"
|
||||
|
||||
@@ -24,6 +24,7 @@ bool IsPointInsideRect(const UIRect& rect, const UIPoint& point) {
|
||||
BorderlessWindowChromeLayout BuildBorderlessWindowChromeLayout(
|
||||
const UIRect& titleBarRect,
|
||||
float leadingOccupiedRight,
|
||||
bool includePinButton,
|
||||
const BorderlessWindowChromeMetrics& metrics) {
|
||||
BorderlessWindowChromeLayout layout = {};
|
||||
layout.titleBarRect = titleBarRect;
|
||||
@@ -32,18 +33,30 @@ BorderlessWindowChromeLayout BuildBorderlessWindowChromeLayout(
|
||||
}
|
||||
|
||||
const float buttonWidth = (std::max)(metrics.buttonWidth, 0.0f);
|
||||
const float buttonX3 = titleBarRect.x + titleBarRect.width - metrics.buttonInsetX - buttonWidth;
|
||||
const float buttonX2 = buttonX3 - buttonWidth;
|
||||
const float buttonX1 = buttonX2 - buttonWidth;
|
||||
const float rightEdge = titleBarRect.x + titleBarRect.width - metrics.buttonInsetX;
|
||||
const float closeButtonX = rightEdge - buttonWidth;
|
||||
const float maximizeButtonX = closeButtonX - buttonWidth;
|
||||
const float minimizeButtonX = maximizeButtonX - buttonWidth;
|
||||
const float pinButtonX = minimizeButtonX - buttonWidth;
|
||||
|
||||
layout.minimizeButtonRect = UIRect(buttonX1, titleBarRect.y, buttonWidth, titleBarRect.height);
|
||||
layout.maximizeRestoreButtonRect = UIRect(buttonX2, titleBarRect.y, buttonWidth, titleBarRect.height);
|
||||
layout.closeButtonRect = UIRect(buttonX3, titleBarRect.y, buttonWidth, titleBarRect.height);
|
||||
if (includePinButton) {
|
||||
layout.pinButtonRect = UIRect(pinButtonX, titleBarRect.y, buttonWidth, titleBarRect.height);
|
||||
}
|
||||
layout.minimizeButtonRect =
|
||||
UIRect(minimizeButtonX, titleBarRect.y, buttonWidth, titleBarRect.height);
|
||||
layout.maximizeRestoreButtonRect =
|
||||
UIRect(maximizeButtonX, titleBarRect.y, buttonWidth, titleBarRect.height);
|
||||
layout.closeButtonRect =
|
||||
UIRect(closeButtonX, titleBarRect.y, buttonWidth, titleBarRect.height);
|
||||
|
||||
const float dragLeft =
|
||||
(std::max)(titleBarRect.x, leadingOccupiedRight + metrics.dragPaddingLeft);
|
||||
const float buttonClusterLeft =
|
||||
includePinButton
|
||||
? layout.pinButtonRect.x
|
||||
: layout.minimizeButtonRect.x;
|
||||
const float dragRight =
|
||||
(std::max)(dragLeft, layout.minimizeButtonRect.x - metrics.dragPaddingRight);
|
||||
(std::max)(dragLeft, buttonClusterLeft - metrics.dragPaddingRight);
|
||||
layout.dragRect = UIRect(
|
||||
dragLeft,
|
||||
titleBarRect.y,
|
||||
@@ -64,6 +77,9 @@ BorderlessWindowChromeHitTarget HitTestBorderlessWindowChrome(
|
||||
if (IsPointInsideRect(layout.minimizeButtonRect, point)) {
|
||||
return BorderlessWindowChromeHitTarget::MinimizeButton;
|
||||
}
|
||||
if (IsPointInsideRect(layout.pinButtonRect, point)) {
|
||||
return BorderlessWindowChromeHitTarget::PinButton;
|
||||
}
|
||||
if (IsPointInsideRect(layout.dragRect, point)) {
|
||||
return BorderlessWindowChromeHitTarget::DragRegion;
|
||||
}
|
||||
@@ -175,10 +191,45 @@ void AppendCloseGlyph(
|
||||
thickness);
|
||||
}
|
||||
|
||||
void AppendPinGlyph(
|
||||
UIDrawList& drawList,
|
||||
const UIRect& rect,
|
||||
const UIColor& color,
|
||||
float thickness) {
|
||||
const float centerX = rect.x + rect.width * 0.5f;
|
||||
const float centerY = rect.y + rect.height * 0.5f;
|
||||
const float iconSize = ResolveGlyphBoxSize(rect, 0.34f, 10.0f);
|
||||
const float headRadius = iconSize * 0.18f;
|
||||
const float headCenterY = centerY - iconSize * 0.30f;
|
||||
const float collarTopY = headCenterY + headRadius;
|
||||
const float collarBottomY = collarTopY + iconSize * 0.12f;
|
||||
const float shoulderHalfWidth = iconSize * 0.34f;
|
||||
const float bodyBottomY = centerY + iconSize * 0.06f;
|
||||
const float needleBottomY = centerY + iconSize * 0.44f;
|
||||
|
||||
drawList.AddFilledCircle(UIPoint(centerX, headCenterY), headRadius, color);
|
||||
drawList.AddLine(
|
||||
UIPoint(centerX, collarTopY),
|
||||
UIPoint(centerX, collarBottomY),
|
||||
color,
|
||||
thickness);
|
||||
drawList.AddFilledTriangle(
|
||||
UIPoint(centerX - shoulderHalfWidth, collarBottomY),
|
||||
UIPoint(centerX + shoulderHalfWidth, collarBottomY),
|
||||
UIPoint(centerX, bodyBottomY),
|
||||
color);
|
||||
drawList.AddLine(
|
||||
UIPoint(centerX, bodyBottomY),
|
||||
UIPoint(centerX, needleBottomY),
|
||||
color,
|
||||
thickness);
|
||||
}
|
||||
|
||||
UIColor ResolveButtonFillColor(
|
||||
BorderlessWindowChromeHitTarget target,
|
||||
const BorderlessWindowChromeState& state,
|
||||
const BorderlessWindowChromePalette& palette) {
|
||||
const BorderlessWindowChromePalette& palette,
|
||||
bool topmostPinned) {
|
||||
const bool hovered = state.hoveredTarget == target;
|
||||
const bool pressed = state.pressedTarget == target;
|
||||
if (target == BorderlessWindowChromeHitTarget::CloseButton) {
|
||||
@@ -191,6 +242,11 @@ UIColor ResolveButtonFillColor(
|
||||
return kTransparentColor;
|
||||
}
|
||||
|
||||
if (target == BorderlessWindowChromeHitTarget::PinButton && topmostPinned &&
|
||||
!hovered && !pressed) {
|
||||
return palette.buttonActiveColor;
|
||||
}
|
||||
|
||||
if (pressed) {
|
||||
return palette.buttonPressedColor;
|
||||
}
|
||||
@@ -203,12 +259,17 @@ UIColor ResolveButtonFillColor(
|
||||
UIColor ResolveIconColor(
|
||||
BorderlessWindowChromeHitTarget target,
|
||||
const BorderlessWindowChromeState& state,
|
||||
const BorderlessWindowChromePalette& palette) {
|
||||
const BorderlessWindowChromePalette& palette,
|
||||
bool topmostPinned) {
|
||||
if (target == BorderlessWindowChromeHitTarget::CloseButton &&
|
||||
(state.hoveredTarget == target || state.pressedTarget == target)) {
|
||||
return palette.closeIconHoverColor;
|
||||
}
|
||||
|
||||
if (target == BorderlessWindowChromeHitTarget::PinButton && topmostPinned) {
|
||||
return palette.iconActiveColor;
|
||||
}
|
||||
|
||||
return palette.iconColor;
|
||||
}
|
||||
|
||||
@@ -219,25 +280,34 @@ void AppendBorderlessWindowChrome(
|
||||
const BorderlessWindowChromeLayout& layout,
|
||||
const BorderlessWindowChromeState& state,
|
||||
bool maximized,
|
||||
bool topmostPinned,
|
||||
const BorderlessWindowChromePalette& palette,
|
||||
const BorderlessWindowChromeMetrics& metrics) {
|
||||
const struct ButtonEntry {
|
||||
BorderlessWindowChromeHitTarget target;
|
||||
UIRect rect;
|
||||
} buttons[] = {
|
||||
{ BorderlessWindowChromeHitTarget::PinButton, layout.pinButtonRect },
|
||||
{ BorderlessWindowChromeHitTarget::MinimizeButton, layout.minimizeButtonRect },
|
||||
{ BorderlessWindowChromeHitTarget::MaximizeRestoreButton, layout.maximizeRestoreButtonRect },
|
||||
{ BorderlessWindowChromeHitTarget::CloseButton, layout.closeButtonRect }
|
||||
};
|
||||
|
||||
for (const ButtonEntry& button : buttons) {
|
||||
const UIColor fill = ResolveButtonFillColor(button.target, state, palette);
|
||||
if (button.rect.width <= 0.0f || button.rect.height <= 0.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const UIColor fill = ResolveButtonFillColor(button.target, state, palette, topmostPinned);
|
||||
if (fill.a > 0.0f) {
|
||||
drawList.AddFilledRect(button.rect, fill);
|
||||
}
|
||||
|
||||
const UIColor iconColor = ResolveIconColor(button.target, state, palette);
|
||||
const UIColor iconColor = ResolveIconColor(button.target, state, palette, topmostPinned);
|
||||
switch (button.target) {
|
||||
case BorderlessWindowChromeHitTarget::PinButton:
|
||||
AppendPinGlyph(drawList, button.rect, iconColor, metrics.iconThickness);
|
||||
break;
|
||||
case BorderlessWindowChromeHitTarget::MinimizeButton:
|
||||
AppendMinimizeGlyph(drawList, button.rect, iconColor, metrics.iconThickness);
|
||||
break;
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace XCEngine::UI::Editor::Host {
|
||||
enum class BorderlessWindowChromeHitTarget : std::uint8_t {
|
||||
None = 0,
|
||||
DragRegion,
|
||||
PinButton,
|
||||
MinimizeButton,
|
||||
MaximizeRestoreButton,
|
||||
CloseButton
|
||||
@@ -31,12 +32,16 @@ struct BorderlessWindowChromePalette {
|
||||
::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
|
||||
::XCEngine::UI::UIColor buttonPressedColor =
|
||||
::XCEngine::UI::UIColor(0.17f, 0.17f, 0.17f, 1.0f);
|
||||
::XCEngine::UI::UIColor buttonActiveColor =
|
||||
::XCEngine::UI::UIColor(0.20f, 0.20f, 0.20f, 1.0f);
|
||||
::XCEngine::UI::UIColor closeButtonHoverColor =
|
||||
::XCEngine::UI::UIColor(0.84f, 0.28f, 0.22f, 1.0f);
|
||||
::XCEngine::UI::UIColor closeButtonPressedColor =
|
||||
::XCEngine::UI::UIColor(0.72f, 0.20f, 0.16f, 1.0f);
|
||||
::XCEngine::UI::UIColor iconColor =
|
||||
::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
|
||||
::XCEngine::UI::UIColor iconActiveColor =
|
||||
::XCEngine::UI::UIColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
::XCEngine::UI::UIColor closeIconHoverColor =
|
||||
::XCEngine::UI::UIColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
};
|
||||
@@ -49,6 +54,7 @@ struct BorderlessWindowChromeState {
|
||||
struct BorderlessWindowChromeLayout {
|
||||
::XCEngine::UI::UIRect titleBarRect = {};
|
||||
::XCEngine::UI::UIRect dragRect = {};
|
||||
::XCEngine::UI::UIRect pinButtonRect = {};
|
||||
::XCEngine::UI::UIRect minimizeButtonRect = {};
|
||||
::XCEngine::UI::UIRect maximizeRestoreButtonRect = {};
|
||||
::XCEngine::UI::UIRect closeButtonRect = {};
|
||||
@@ -57,6 +63,7 @@ struct BorderlessWindowChromeLayout {
|
||||
BorderlessWindowChromeLayout BuildBorderlessWindowChromeLayout(
|
||||
const ::XCEngine::UI::UIRect& titleBarRect,
|
||||
float leadingOccupiedRight,
|
||||
bool includePinButton = false,
|
||||
const BorderlessWindowChromeMetrics& metrics = {});
|
||||
|
||||
BorderlessWindowChromeHitTarget HitTestBorderlessWindowChrome(
|
||||
@@ -68,6 +75,7 @@ void AppendBorderlessWindowChrome(
|
||||
const BorderlessWindowChromeLayout& layout,
|
||||
const BorderlessWindowChromeState& state,
|
||||
bool maximized,
|
||||
bool topmostPinned = false,
|
||||
const BorderlessWindowChromePalette& palette = {},
|
||||
const BorderlessWindowChromeMetrics& metrics = {});
|
||||
|
||||
|
||||
@@ -38,6 +38,20 @@ bool IsVerboseResizeTraceEnabled() {
|
||||
return s_enabled;
|
||||
}
|
||||
|
||||
bool IsChromeButtonTarget(Host::BorderlessWindowChromeHitTarget target) {
|
||||
return target == Host::BorderlessWindowChromeHitTarget::PinButton ||
|
||||
target == Host::BorderlessWindowChromeHitTarget::MinimizeButton ||
|
||||
target == Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton ||
|
||||
target == Host::BorderlessWindowChromeHitTarget::CloseButton;
|
||||
}
|
||||
|
||||
float ResolveLeadingChromeButtonLeft(
|
||||
const Host::BorderlessWindowChromeLayout& layout) {
|
||||
return layout.pinButtonRect.width > 0.0f
|
||||
? layout.pinButtonRect.x
|
||||
: layout.minimizeButtonRect.x;
|
||||
}
|
||||
|
||||
float ResolveDetachedTabWidth(
|
||||
std::string_view text,
|
||||
const UIEditorTextMeasurer* textMeasurer) {
|
||||
@@ -54,7 +68,7 @@ float ResolveDetachedTabWidth(
|
||||
|
||||
UIRect BuildDetachedTitleLogoRect(const Host::BorderlessWindowChromeLayout& layout) {
|
||||
const float availableLeft = layout.titleBarRect.x;
|
||||
const float availableRight = layout.minimizeButtonRect.x;
|
||||
const float availableRight = ResolveLeadingChromeButtonLeft(layout);
|
||||
const float centeredX = std::floor(
|
||||
layout.titleBarRect.x + layout.titleBarRect.width * 0.5f - kTitleBarLogoExtent * 0.5f);
|
||||
const float clampedX = (std::max)(
|
||||
@@ -227,6 +241,15 @@ const Host::BorderlessWindowChromeState& EditorWindowChromeController::GetChrome
|
||||
return m_chromeState;
|
||||
}
|
||||
|
||||
void EditorWindowChromeController::InitializeWindowChrome(EditorWindow& window) {
|
||||
if (!window.GetChromePolicy().topmostByDefault) {
|
||||
SetWindowTopmost(false);
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyWindowTopmost(window, true);
|
||||
}
|
||||
|
||||
bool EditorWindowChromeController::HandleSystemCommand(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
@@ -463,10 +486,7 @@ bool EditorWindowChromeController::UpdateChromeHover(EditorWindow& window, LPARA
|
||||
}
|
||||
|
||||
const Host::BorderlessWindowChromeHitTarget hitTarget = HitTestChrome(window, lParam);
|
||||
const Host::BorderlessWindowChromeHitTarget buttonTarget =
|
||||
hitTarget == Host::BorderlessWindowChromeHitTarget::MinimizeButton ||
|
||||
hitTarget == Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton ||
|
||||
hitTarget == Host::BorderlessWindowChromeHitTarget::CloseButton
|
||||
const Host::BorderlessWindowChromeHitTarget buttonTarget = IsChromeButtonTarget(hitTarget)
|
||||
? hitTarget
|
||||
: Host::BorderlessWindowChromeHitTarget::None;
|
||||
if (GetHoveredChromeTarget() == buttonTarget) {
|
||||
@@ -486,6 +506,7 @@ bool EditorWindowChromeController::HandleChromeButtonDown(EditorWindow& window,
|
||||
const HWND hwnd = window.GetHwnd();
|
||||
const Host::BorderlessWindowChromeHitTarget hitTarget = HitTestChrome(window, lParam);
|
||||
switch (hitTarget) {
|
||||
case Host::BorderlessWindowChromeHitTarget::PinButton:
|
||||
case Host::BorderlessWindowChromeHitTarget::MinimizeButton:
|
||||
case Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton:
|
||||
case Host::BorderlessWindowChromeHitTarget::CloseButton:
|
||||
@@ -525,9 +546,7 @@ bool EditorWindowChromeController::HandleChromeButtonUp(
|
||||
}
|
||||
|
||||
const Host::BorderlessWindowChromeHitTarget pressedTarget = GetPressedChromeTarget();
|
||||
if (pressedTarget != Host::BorderlessWindowChromeHitTarget::MinimizeButton &&
|
||||
pressedTarget != Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton &&
|
||||
pressedTarget != Host::BorderlessWindowChromeHitTarget::CloseButton) {
|
||||
if (!IsChromeButtonTarget(pressedTarget)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -692,7 +711,8 @@ Host::BorderlessWindowChromeLayout EditorWindowChromeController::ResolveChromeLa
|
||||
|
||||
return Host::BuildBorderlessWindowChromeLayout(
|
||||
UIRect(0.0f, 0.0f, clientWidthDips, kBorderlessTitleBarHeightDips),
|
||||
leadingOccupiedRight);
|
||||
leadingOccupiedRight,
|
||||
window.GetChromePolicy().showTopmostButton);
|
||||
}
|
||||
|
||||
bool EditorWindowChromeController::ShouldUseDetachedTitleBarTabStrip(
|
||||
@@ -828,7 +848,8 @@ void EditorWindowChromeController::AppendChrome(
|
||||
drawList,
|
||||
layout,
|
||||
GetChromeState(),
|
||||
IsBorderlessWindowMaximized());
|
||||
IsBorderlessWindowMaximized(),
|
||||
IsWindowTopmost());
|
||||
}
|
||||
|
||||
void EditorWindowChromeController::ApplyResizeCursorHoverPriority() {
|
||||
@@ -907,6 +928,35 @@ bool EditorWindowChromeController::ApplyPredictedWindowRectTransition(
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditorWindowChromeController::SetWindowTopmost(bool topmost) {
|
||||
m_runtimeState.SetWindowTopmost(topmost);
|
||||
}
|
||||
|
||||
bool EditorWindowChromeController::IsWindowTopmost() const {
|
||||
return m_runtimeState.IsWindowTopmost();
|
||||
}
|
||||
|
||||
bool EditorWindowChromeController::ApplyWindowTopmost(EditorWindow& window, bool topmost) {
|
||||
const HWND hwnd = window.GetHwnd();
|
||||
if (hwnd == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetWindowPos(
|
||||
hwnd,
|
||||
topmost ? HWND_TOPMOST : HWND_NOTOPMOST,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SetWindowTopmost(topmost);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditorWindowChromeController::ToggleMaximizeRestore(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
@@ -949,6 +999,9 @@ void EditorWindowChromeController::ExecuteChromeAction(
|
||||
}
|
||||
|
||||
switch (target) {
|
||||
case Host::BorderlessWindowChromeHitTarget::PinButton:
|
||||
ApplyWindowTopmost(window, !IsWindowTopmost());
|
||||
break;
|
||||
case Host::BorderlessWindowChromeHitTarget::MinimizeButton:
|
||||
ShowWindow(hwnd, SW_MINIMIZE);
|
||||
break;
|
||||
|
||||
@@ -74,6 +74,7 @@ public:
|
||||
void ResetChromeState();
|
||||
bool IsChromeStateClear() const;
|
||||
const Host::BorderlessWindowChromeState& GetChromeState() const;
|
||||
void InitializeWindowChrome(EditorWindow& window);
|
||||
|
||||
bool HandleSystemCommand(
|
||||
EditorWindow& window,
|
||||
@@ -133,6 +134,9 @@ public:
|
||||
EditorContext& editorContext,
|
||||
bool globalTabDragActive,
|
||||
const RECT& targetRect);
|
||||
void SetWindowTopmost(bool topmost);
|
||||
bool IsWindowTopmost() const;
|
||||
bool ApplyWindowTopmost(EditorWindow& window, bool topmost);
|
||||
void ToggleMaximizeRestore(
|
||||
EditorWindow& window,
|
||||
EditorContext& editorContext,
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
m_predictedClientPixelSize = {};
|
||||
m_borderlessWindowPlacementState = {};
|
||||
m_borderlessWindowDragRestoreState = {};
|
||||
m_windowTopmost = false;
|
||||
m_skipNextSteadyStateFrame = false;
|
||||
}
|
||||
|
||||
@@ -213,6 +214,14 @@ public:
|
||||
return m_borderlessWindowDragRestoreState.initialScreenPoint;
|
||||
}
|
||||
|
||||
void SetWindowTopmost(bool topmost) {
|
||||
m_windowTopmost = topmost;
|
||||
}
|
||||
|
||||
bool IsWindowTopmost() const {
|
||||
return m_windowTopmost;
|
||||
}
|
||||
|
||||
private:
|
||||
UINT m_windowDpi = 96u;
|
||||
bool m_inInteractiveResize = false;
|
||||
@@ -220,6 +229,7 @@ private:
|
||||
PredictedClientPixelSize m_predictedClientPixelSize = {};
|
||||
BorderlessWindowPlacementState m_borderlessWindowPlacementState = {};
|
||||
BorderlessWindowDragRestoreState m_borderlessWindowDragRestoreState = {};
|
||||
bool m_windowTopmost = false;
|
||||
bool m_skipNextSteadyStateFrame = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Platform/Win32/Windowing/EditorWindowTransferRequests.h"
|
||||
#include "Windowing/Frame/EditorWindowTransferRequests.h"
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include "Platform/Win32/Content/EditorWindowContentController.h"
|
||||
#include "Windowing/Content/EditorWindowContentController.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowScreenshotController.h"
|
||||
|
||||
#include <Rendering/D3D12/D3D12UiRenderer.h>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include "UtilityWindows/EditorUtilityWindowRegistry.h"
|
||||
#include "Platform/Win32/Windowing/EditorFloatingWindowPlacement.h"
|
||||
#include "Platform/Win32/Content/EditorUtilityWindowContentController.h"
|
||||
#include "Windowing/Content/EditorUtilityWindowContentController.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindow.h"
|
||||
#include "Platform/Win32/Content/EditorWindowContentController.h"
|
||||
#include "Windowing/Content/EditorWindowContentController.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowHostRuntime.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowLifecycleCoordinator.h"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Platform/Win32/Windowing/EditorWindowTransferRequests.h"
|
||||
#include "Windowing/Frame/EditorWindowTransferRequests.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "Platform/Win32/Windowing/EditorWindow.h"
|
||||
#include "Bootstrap/EditorResources.h"
|
||||
#include "Platform/Win32/Chrome/EditorWindowChromeController.h"
|
||||
#include "Platform/Win32/Content/EditorWindowContentController.h"
|
||||
#include "Windowing/Content/EditorWindowContentController.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowFrameDriver.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowSession.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowSupport.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowFrameOrchestrator.h"
|
||||
#include "Windowing/Frame/EditorWindowFrameOrchestrator.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowInputController.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowRuntimeController.h"
|
||||
#include "Composition/EditorContext.h"
|
||||
@@ -219,6 +219,7 @@ bool EditorWindow::Initialize(
|
||||
Host::RefreshBorderlessWindowDwmDecorations(m_session->GetHwnd());
|
||||
m_chromeController->Reset();
|
||||
m_chromeController->SetWindowDpi(QueryWindowDpi(m_session->GetHwnd()));
|
||||
m_chromeController->InitializeWindowChrome(*this);
|
||||
m_runtime->SetDpiScale(GetDpiScale());
|
||||
|
||||
std::ostringstream dpiTrace = {};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "Composition/EditorContext.h"
|
||||
#include "Platform/Win32/Chrome/EditorWindowChromeController.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindow.h"
|
||||
#include "Platform/Win32/Content/EditorWindowContentController.h"
|
||||
#include "Windowing/Content/EditorWindowContentController.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowFrameDriver.h"
|
||||
#include "Platform/Win32/Windowing/EditorUtilityWindowCoordinator.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowLifecycleCoordinator.h"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "Platform/Win32/Windowing/EditorWindowManager.h"
|
||||
|
||||
#include "Platform/Win32/Windowing/EditorWindow.h"
|
||||
#include "Platform/Win32/Content/EditorWindowContentController.h"
|
||||
#include "Windowing/Content/EditorWindowContentController.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowHostRuntime.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowLifecycleCoordinator.h"
|
||||
#include "Platform/Win32/Windowing/EditorUtilityWindowCoordinator.h"
|
||||
|
||||
@@ -160,7 +160,8 @@ bool EditorWindowMessageDispatcher::TryHandleChromeHoverConsumption(
|
||||
|
||||
const Host::BorderlessWindowChromeHitTarget chromeHitTarget =
|
||||
chromeController.HitTestChrome(context.window, lParam);
|
||||
if (chromeHitTarget == Host::BorderlessWindowChromeHitTarget::MinimizeButton ||
|
||||
if (chromeHitTarget == Host::BorderlessWindowChromeHitTarget::PinButton ||
|
||||
chromeHitTarget == Host::BorderlessWindowChromeHitTarget::MinimizeButton ||
|
||||
chromeHitTarget == Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton ||
|
||||
chromeHitTarget == Host::BorderlessWindowChromeHitTarget::CloseButton) {
|
||||
outResult = 0;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include "Platform/Win32/Windowing/EditorWindowTransferRequests.h"
|
||||
#include "Windowing/Frame/EditorWindowTransferRequests.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Platform/Win32/Windowing/EditorWindowState.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowTransferRequests.h"
|
||||
#include "Windowing/Frame/EditorWindowTransferRequests.h"
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
@@ -41,6 +41,8 @@ inline std::string_view GetEditorWindowCategoryName(
|
||||
struct EditorWindowChromePolicy {
|
||||
bool allowDetachedTitleBarTabStrip = true;
|
||||
bool showFrameStats = true;
|
||||
bool showTopmostButton = false;
|
||||
bool topmostByDefault = false;
|
||||
};
|
||||
|
||||
struct EditorWindowNativeStylePolicy {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "Composition/EditorContext.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindow.h"
|
||||
#include "Platform/Win32/Windowing/EditorFloatingWindowPlacement.h"
|
||||
#include "Platform/Win32/Content/EditorWorkspaceWindowContentController.h"
|
||||
#include "Windowing/Content/EditorWorkspaceWindowContentController.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowRuntimeController.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowHostRuntime.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowLifecycleCoordinator.h"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#endif
|
||||
|
||||
#include "Composition/EditorWindowWorkspaceStore.h"
|
||||
#include "Platform/Win32/Windowing/EditorWindowTransferRequests.h"
|
||||
#include "Windowing/Frame/EditorWindowTransferRequests.h"
|
||||
|
||||
#include <XCEditor/Workspace/UIEditorWorkspaceController.h>
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ using ::XCEngine::UI::UISize;
|
||||
constexpr EditorWindowChromePolicy kUtilityWindowChromePolicy = {
|
||||
.allowDetachedTitleBarTabStrip = false,
|
||||
.showFrameStats = false,
|
||||
.showTopmostButton = true,
|
||||
.topmostByDefault = true,
|
||||
};
|
||||
|
||||
constexpr EditorWindowNativeStylePolicy kUtilityWindowNativeStylePolicy = {
|
||||
@@ -26,8 +28,8 @@ constexpr EditorUtilityWindowDescriptor kColorPickerUtilityWindowDescriptor = {
|
||||
.title = L"Color Picker",
|
||||
.chromePolicy = kUtilityWindowChromePolicy,
|
||||
.nativeStylePolicy = kUtilityWindowNativeStylePolicy,
|
||||
.preferredOuterSize = UISize(352.0f, 500.0f),
|
||||
.minimumOuterSize = UISize(320.0f, 460.0f),
|
||||
.preferredOuterSize = UISize(400.0f, 620.0f),
|
||||
.minimumOuterSize = UISize(360.0f, 560.0f),
|
||||
};
|
||||
|
||||
constexpr EditorUtilityWindowDescriptor kAddComponentUtilityWindowDescriptor = {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "Platform/Win32/Content/EditorUtilityWindowContentController.h"
|
||||
#include "Windowing/Content/EditorUtilityWindowContentController.h"
|
||||
|
||||
#include "UtilityWindows/EditorUtilityWindowPanel.h"
|
||||
#include "UtilityWindows/EditorUtilityWindowRegistry.h"
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Platform/Win32/Content/EditorWindowContentController.h"
|
||||
#include "Windowing/Content/EditorWindowContentController.h"
|
||||
|
||||
#include <XCEditor/Shell/UIEditorShellInteraction.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Platform/Win32/Windowing/EditorWindowTransferRequests.h"
|
||||
#include "Windowing/Frame/EditorWindowTransferRequests.h"
|
||||
|
||||
#include <XCEditor/Docking/UIEditorDockHostTransfer.h>
|
||||
#include <XCEditor/Foundation/UIEditorTextMeasurement.h>
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "Platform/Win32/Content/EditorWorkspaceWindowContentController.h"
|
||||
#include "Windowing/Content/EditorWorkspaceWindowContentController.h"
|
||||
|
||||
#include <XCEditor/Workspace/UIEditorDetachedWindowPolicy.h>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "Composition/EditorShellRuntime.h"
|
||||
#include "Platform/Win32/Content/EditorWindowContentController.h"
|
||||
#include "Platform/Win32/Runtime/EditorWindowFrameOrchestrator.h"
|
||||
#include "Windowing/Content/EditorWindowContentController.h"
|
||||
#include "Windowing/Frame/EditorWindowFrameOrchestrator.h"
|
||||
|
||||
#include <XCEditor/Workspace/UIEditorWorkspaceController.h>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "Platform/Win32/Runtime/EditorWindowFrameOrchestrator.h"
|
||||
#include "Windowing/Frame/EditorWindowFrameOrchestrator.h"
|
||||
|
||||
#include "Composition/EditorContext.h"
|
||||
#include "Composition/EditorShellRuntime.h"
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Platform/Win32/Windowing/EditorWindowTransferRequests.h"
|
||||
#include "Windowing/Frame/EditorWindowTransferRequests.h"
|
||||
|
||||
#include <XCEngine/UI/Types.h>
|
||||
|
||||
Reference in New Issue
Block a user