Refine editor window host structure and utility chrome

This commit is contained in:
2026-04-25 18:20:17 +08:00
parent 41b912933d
commit 7335def3fd
31 changed files with 241 additions and 61 deletions

View File

@@ -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 stripframe stats。
当前用于控制 detached title bar tab stripframe 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`

View File

@@ -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}
)

View File

@@ -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"

View File

@@ -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;

View File

@@ -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 = {});

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;
};

View File

@@ -1,6 +1,6 @@
#pragma once
#include "Platform/Win32/Windowing/EditorWindowTransferRequests.h"
#include "Windowing/Frame/EditorWindowTransferRequests.h"
namespace XCEngine::UI::Editor::App {

View File

@@ -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>

View File

@@ -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"

View File

@@ -1,6 +1,6 @@
#pragma once
#include "Platform/Win32/Windowing/EditorWindowTransferRequests.h"
#include "Windowing/Frame/EditorWindowTransferRequests.h"
#include <string_view>

View File

@@ -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 = {};

View File

@@ -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"

View File

@@ -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"

View File

@@ -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;

View File

@@ -4,7 +4,7 @@
#define NOMINMAX
#endif
#include "Platform/Win32/Windowing/EditorWindowTransferRequests.h"
#include "Windowing/Frame/EditorWindowTransferRequests.h"
#include <windows.h>

View File

@@ -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>

View File

@@ -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 {

View File

@@ -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"

View File

@@ -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>

View File

@@ -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 = {

View File

@@ -1,4 +1,4 @@
#include "Platform/Win32/Content/EditorUtilityWindowContentController.h"
#include "Windowing/Content/EditorUtilityWindowContentController.h"
#include "UtilityWindows/EditorUtilityWindowPanel.h"
#include "UtilityWindows/EditorUtilityWindowRegistry.h"

View File

@@ -1,6 +1,6 @@
#pragma once
#include "Platform/Win32/Content/EditorWindowContentController.h"
#include "Windowing/Content/EditorWindowContentController.h"
#include <XCEditor/Shell/UIEditorShellInteraction.h>

View File

@@ -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>

View File

@@ -1,4 +1,4 @@
#include "Platform/Win32/Content/EditorWorkspaceWindowContentController.h"
#include "Windowing/Content/EditorWorkspaceWindowContentController.h"
#include <XCEditor/Workspace/UIEditorDetachedWindowPolicy.h>

View File

@@ -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>

View File

@@ -1,4 +1,4 @@
#include "Platform/Win32/Runtime/EditorWindowFrameOrchestrator.h"
#include "Windowing/Frame/EditorWindowFrameOrchestrator.h"
#include "Composition/EditorContext.h"
#include "Composition/EditorShellRuntime.h"

View File

@@ -1,6 +1,6 @@
#pragma once
#include "Platform/Win32/Windowing/EditorWindowTransferRequests.h"
#include "Windowing/Frame/EditorWindowTransferRequests.h"
#include <XCEngine/UI/Types.h>