From 34c635ba226bc2586b9b33d6df6bf77cc86a8b81 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Wed, 22 Apr 2026 21:02:24 +0800 Subject: [PATCH] refactor(new_editor): split utility window semantics from workspace --- ...ilityWindowSemanticSplitPlan_2026-04-22.md | 30 +++- new_editor/CMakeLists.txt | 4 + new_editor/app/Composition/EditorPanelIds.h | 2 - .../Composition/EditorShellAssetBuilder.cpp | 26 +-- .../Composition/EditorShellDrawComposer.cpp | 5 - .../app/Composition/EditorShellDrawComposer.h | 2 - .../EditorShellHostedPanelCoordinator.cpp | 7 - .../EditorShellHostedPanelCoordinator.h | 2 - .../EditorShellInteractionEngine.cpp | 15 +- .../app/Composition/EditorShellRuntime.cpp | 3 - .../app/Composition/EditorShellRuntime.h | 2 - .../Features/ColorPicker/ColorPickerPanel.cpp | 22 +-- .../Features/ColorPicker/ColorPickerPanel.h | 12 +- ...orPickerUtilityWindowContentController.cpp | 165 ++++++++++++++++++ ...olorPickerUtilityWindowContentController.h | 75 ++++++++ .../Win32/EditorFloatingWindowPlacement.cpp | 46 +++++ .../Win32/EditorFloatingWindowPlacement.h | 18 ++ .../Platform/Win32/EditorUtilityWindowKind.h | 12 ++ .../Win32/EditorUtilityWindowRegistry.cpp | 50 ++++++ .../Win32/EditorUtilityWindowRegistry.h | 28 +++ .../Win32/EditorWindowFrameOrchestrator.cpp | 23 +-- .../app/Platform/Win32/EditorWindowManager.h | 2 + .../Win32/EditorWindowTransferRequests.h | 15 +- ...EditorWorkspaceWindowContentController.cpp | 9 +- .../EditorUtilityWindowCoordinator.cpp | 153 ++++++++++++++++ .../EditorUtilityWindowCoordinator.h | 36 ++++ .../WindowManager/EditorWindowHostRuntime.cpp | 10 +- .../WindowManager/EditorWindowHostRuntime.h | 4 +- .../WindowManager/EditorWindowManager.cpp | 9 +- .../EditorWindowMessageDispatcher.cpp | 23 ++- .../EditorWindowMessageDispatcher.h | 7 + .../EditorWindowWorkspaceCoordinator.cpp | 105 +---------- .../EditorWindowWorkspaceCoordinator.h | 13 +- .../app/State/EditorColorPickerToolState.cpp | 8 +- .../app/State/EditorColorPickerToolState.h | 4 +- .../XCEditor/Panels/UIEditorPanelRegistry.h | 2 - .../Workspace/UIEditorDetachedWindowPolicy.h | 13 -- .../UIEditorWindowWorkspaceController.h | 4 - .../UIEditorDetachedWindowPolicy.cpp | 47 ----- .../UIEditorWindowWorkspaceController.cpp | 93 ---------- 40 files changed, 715 insertions(+), 391 deletions(-) create mode 100644 new_editor/app/Platform/Win32/EditorColorPickerUtilityWindowContentController.cpp create mode 100644 new_editor/app/Platform/Win32/EditorColorPickerUtilityWindowContentController.h create mode 100644 new_editor/app/Platform/Win32/EditorFloatingWindowPlacement.cpp create mode 100644 new_editor/app/Platform/Win32/EditorFloatingWindowPlacement.h create mode 100644 new_editor/app/Platform/Win32/EditorUtilityWindowKind.h create mode 100644 new_editor/app/Platform/Win32/EditorUtilityWindowRegistry.cpp create mode 100644 new_editor/app/Platform/Win32/EditorUtilityWindowRegistry.h create mode 100644 new_editor/app/Platform/Win32/WindowManager/EditorUtilityWindowCoordinator.cpp create mode 100644 new_editor/app/Platform/Win32/WindowManager/EditorUtilityWindowCoordinator.h diff --git a/docs/plan/NewEditor_WorkspaceUtilityWindowSemanticSplitPlan_2026-04-22.md b/docs/plan/NewEditor_WorkspaceUtilityWindowSemanticSplitPlan_2026-04-22.md index 19edb976..35cda627 100644 --- a/docs/plan/NewEditor_WorkspaceUtilityWindowSemanticSplitPlan_2026-04-22.md +++ b/docs/plan/NewEditor_WorkspaceUtilityWindowSemanticSplitPlan_2026-04-22.md @@ -1,7 +1,7 @@ # NewEditor Workspace Utility Window Semantic Split Plan Date: 2026-04-22 -Status: In Progress +Status: Implementation Complete, Manual Verification Pending ## 0. Execution Progress @@ -29,6 +29,34 @@ What is intentionally not done yet: This means the root shell/content ownership boundary has been extracted first, while feature semantics remain unchanged for safety. +### Completed on 2026-04-22 + +Phase C, Phase D, and Phase E implementation are now in place. + +Completed changes: + +1. a first-class utility window domain now exists: + - `EditorUtilityWindowKind` + - `EditorWindowOpenUtilityWindowRequest` + - `EditorUtilityWindowCoordinator` + - `EditorUtilityWindowRegistry` +2. color picker open intent no longer routes through detached workspace mutation +3. the color picker now opens through utility-window coordination and utility content +4. color picker has been removed from: + - `UIEditorPanelRegistry` + - shell hosted-panel composition + - workspace detached-panel request plumbing +5. `openDetachedPanel` has been deleted from frame transfer routing +6. `UIEditorWindowWorkspaceController::OpenPanelInNewWindow(...)` has been deleted +7. `toolWindow` and related workspace utility inference have been deleted +8. detached floating-window placement logic is now shared instead of duplicated +9. `XCUIEditorApp` Debug build passes after this phase + +What is intentionally not claimed yet: + +1. manual GUI regression verification is still required for the matrix in section 10 +2. no drag/drop or panel movement was automated during this step + ## 1. Objective This plan solves the problem from the architectural root, not by adding another special case. diff --git a/new_editor/CMakeLists.txt b/new_editor/CMakeLists.txt index e55d469d..1c3ca7b9 100644 --- a/new_editor/CMakeLists.txt +++ b/new_editor/CMakeLists.txt @@ -279,17 +279,21 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP) set(XCUI_EDITOR_APP_PLATFORM_SOURCES app/Platform/Win32/EditorWindow.cpp + app/Platform/Win32/EditorColorPickerUtilityWindowContentController.cpp + app/Platform/Win32/EditorFloatingWindowPlacement.cpp app/Platform/Win32/EditorWindowChromeController.cpp app/Platform/Win32/EditorWindowFrameDriver.cpp app/Platform/Win32/EditorWindowFrameOrchestrator.cpp app/Platform/Win32/EditorWindowInputController.cpp app/Platform/Win32/EditorWindowRuntimeController.cpp + app/Platform/Win32/EditorUtilityWindowRegistry.cpp app/Platform/Win32/EditorWorkspaceWindowContentController.cpp app/Platform/Win32/Win32SystemInteractionHost.cpp app/Platform/Win32/WindowManager/EditorWindowHostRuntime.cpp app/Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.cpp app/Platform/Win32/WindowManager/EditorWindowManager.cpp app/Platform/Win32/WindowManager/EditorWindowMessageDispatcher.cpp + app/Platform/Win32/WindowManager/EditorUtilityWindowCoordinator.cpp app/Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.cpp ) diff --git a/new_editor/app/Composition/EditorPanelIds.h b/new_editor/app/Composition/EditorPanelIds.h index c54b9793..ca608769 100644 --- a/new_editor/app/Composition/EditorPanelIds.h +++ b/new_editor/app/Composition/EditorPanelIds.h @@ -10,7 +10,6 @@ inline constexpr std::string_view kGamePanelId = "game"; inline constexpr std::string_view kInspectorPanelId = "inspector"; inline constexpr std::string_view kConsolePanelId = "console"; inline constexpr std::string_view kProjectPanelId = "project"; -inline constexpr std::string_view kColorPickerPanelId = "color-picker"; inline constexpr std::string_view kHierarchyPanelTitle = "Hierarchy"; inline constexpr std::string_view kScenePanelTitle = "Scene"; @@ -18,7 +17,6 @@ inline constexpr std::string_view kGamePanelTitle = "Game"; inline constexpr std::string_view kInspectorPanelTitle = "Inspector"; inline constexpr std::string_view kConsolePanelTitle = "Console"; inline constexpr std::string_view kProjectPanelTitle = "Project"; -inline constexpr std::string_view kColorPickerPanelTitle = "Color Picker"; [[nodiscard]] constexpr bool IsEditorViewportPanelId(std::string_view panelId) { return panelId == kScenePanelId || panelId == kGamePanelId; diff --git a/new_editor/app/Composition/EditorShellAssetBuilder.cpp b/new_editor/app/Composition/EditorShellAssetBuilder.cpp index 154d0847..0d3a9f78 100644 --- a/new_editor/app/Composition/EditorShellAssetBuilder.cpp +++ b/new_editor/app/Composition/EditorShellAssetBuilder.cpp @@ -266,23 +266,6 @@ UIEditorPanelDescriptor BuildHostedContentPanelDescriptor( return descriptor; } -UIEditorPanelDescriptor BuildToolWindowHostedContentPanelDescriptor( - std::string_view panelId, - std::string_view title, - float preferredWidth, - float preferredHeight, - float minimumWidth, - float minimumHeight) { - UIEditorPanelDescriptor descriptor = - BuildHostedContentPanelDescriptor(panelId, title, false, true, true); - descriptor.toolWindow = true; - descriptor.preferredDetachedWindowSize = - ::XCEngine::UI::UISize(preferredWidth, preferredHeight); - descriptor.minimumDetachedWindowSize = - ::XCEngine::UI::UISize(minimumWidth, minimumHeight); - return descriptor; -} - UIEditorPanelDescriptor BuildViewportPanelDescriptor( std::string_view panelId, std::string_view title, @@ -326,14 +309,7 @@ UIEditorPanelRegistry BuildEditorPanelRegistry() { BuildViewportPanelDescriptor(kGamePanelId, kGamePanelTitle, false, false, false, false), BuildHostedContentPanelDescriptor(kInspectorPanelId, kInspectorPanelTitle, true, false, false), BuildHostedContentPanelDescriptor(kConsolePanelId, kConsolePanelTitle, true, false, false), - BuildHostedContentPanelDescriptor(kProjectPanelId, kProjectPanelTitle, false, false, false), - BuildToolWindowHostedContentPanelDescriptor( - kColorPickerPanelId, - kColorPickerPanelTitle, - 352.0f, - 500.0f, - 320.0f, - 460.0f) + BuildHostedContentPanelDescriptor(kProjectPanelId, kProjectPanelTitle, false, false, false) }; return registry; } diff --git a/new_editor/app/Composition/EditorShellDrawComposer.cpp b/new_editor/app/Composition/EditorShellDrawComposer.cpp index 55c9fa5f..23bf44ac 100644 --- a/new_editor/app/Composition/EditorShellDrawComposer.cpp +++ b/new_editor/app/Composition/EditorShellDrawComposer.cpp @@ -1,6 +1,5 @@ #include "Composition/EditorShellDrawComposer.h" -#include "Features/ColorPicker/ColorPickerPanel.h" #include "Features/Console/ConsolePanel.h" #include "Features/Hierarchy/HierarchyPanel.h" #include "Features/Inspector/InspectorPanel.h" @@ -136,10 +135,6 @@ void EditorShellDrawComposer::Append( drawData, "XCEditorPanel.Console", [&](UIDrawList& drawList) { context.consolePanel.Append(drawList); }); - AppendDrawPacket( - drawData, - "XCEditorPanel.ColorPicker", - [&](UIDrawList& drawList) { context.colorPickerPanel.Append(drawList); }); AppendDrawPacket( drawData, "XCEditorPanel.Hierarchy", diff --git a/new_editor/app/Composition/EditorShellDrawComposer.h b/new_editor/app/Composition/EditorShellDrawComposer.h index a3419fae..86f72da1 100644 --- a/new_editor/app/Composition/EditorShellDrawComposer.h +++ b/new_editor/app/Composition/EditorShellDrawComposer.h @@ -12,7 +12,6 @@ struct UIEditorShellInteractionState; namespace XCEngine::UI::Editor::App { class BuiltInIcons; -class ColorPickerPanel; class ConsolePanel; class HierarchyPanel; class InspectorPanel; @@ -24,7 +23,6 @@ struct EditorShellDrawComposerContext { const UIEditorShellInteractionState& shellInteractionState; const BuiltInIcons& builtInIcons; const ConsolePanel& consolePanel; - const ColorPickerPanel& colorPickerPanel; const HierarchyPanel& hierarchyPanel; const InspectorPanel& inspectorPanel; const ProjectPanel& projectPanel; diff --git a/new_editor/app/Composition/EditorShellHostedPanelCoordinator.cpp b/new_editor/app/Composition/EditorShellHostedPanelCoordinator.cpp index 2634a923..d5f26469 100644 --- a/new_editor/app/Composition/EditorShellHostedPanelCoordinator.cpp +++ b/new_editor/app/Composition/EditorShellHostedPanelCoordinator.cpp @@ -2,7 +2,6 @@ #include "Composition/EditorContext.h" #include "Composition/EditorPanelIds.h" -#include "Features/ColorPicker/ColorPickerPanel.h" #include "Features/Console/ConsolePanel.h" #include "Features/Hierarchy/HierarchyPanel.h" #include "Features/Inspector/InspectorPanel.h" @@ -51,8 +50,6 @@ void EditorShellHostedPanelCoordinator::Update( ResolveHostedPanelDispatchEntry(hostedPanelDispatchFrame, kProjectPanelId); const UIEditorHostedPanelDispatchEntry& inspectorDispatchEntry = ResolveHostedPanelDispatchEntry(hostedPanelDispatchFrame, kInspectorPanelId); - const UIEditorHostedPanelDispatchEntry& colorPickerDispatchEntry = - ResolveHostedPanelDispatchEntry(hostedPanelDispatchFrame, kColorPickerPanelId); const UIEditorHostedPanelDispatchEntry& consoleDispatchEntry = ResolveHostedPanelDispatchEntry(hostedPanelDispatchFrame, kConsolePanelId); @@ -70,10 +67,6 @@ void EditorShellHostedPanelCoordinator::Update( context.projectPanel.Update( projectDispatchEntry, hostedContentEvents); - context.colorPickerPanel.Update( - context.context, - colorPickerDispatchEntry, - hostedContentEvents); context.inspectorPanel.Update( context.context, inspectorDispatchEntry, diff --git a/new_editor/app/Composition/EditorShellHostedPanelCoordinator.h b/new_editor/app/Composition/EditorShellHostedPanelCoordinator.h index b9d6a643..03354c4c 100644 --- a/new_editor/app/Composition/EditorShellHostedPanelCoordinator.h +++ b/new_editor/app/Composition/EditorShellHostedPanelCoordinator.h @@ -17,7 +17,6 @@ struct UIEditorShellInteractionState; namespace XCEngine::UI::Editor::App { -class ColorPickerPanel; class ConsolePanel; class EditorContext; class HierarchyPanel; @@ -32,7 +31,6 @@ struct EditorShellHostedPanelCoordinatorContext { const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents; bool shellInteractiveCaptureActive = false; ConsolePanel& consolePanel; - ColorPickerPanel& colorPickerPanel; HierarchyPanel& hierarchyPanel; InspectorPanel& inspectorPanel; ProjectPanel& projectPanel; diff --git a/new_editor/app/Composition/EditorShellInteractionEngine.cpp b/new_editor/app/Composition/EditorShellInteractionEngine.cpp index e74805bd..a7924e49 100644 --- a/new_editor/app/Composition/EditorShellInteractionEngine.cpp +++ b/new_editor/app/Composition/EditorShellInteractionEngine.cpp @@ -3,7 +3,6 @@ #include "Composition/EditorPanelIds.h" #include -#include #include @@ -81,21 +80,11 @@ void ApplyViewportFramesToShellFrame( } UIEditorShellInteractionMetrics ResolveInteractionMetrics( - const UIEditorWorkspaceController& workspaceController, + const UIEditorWorkspaceController&, bool useDetachedTitleBarTabStrip, float detachedTitleBarTabHeight, - float detachedWindowChromeHeight) { + float) { UIEditorShellInteractionMetrics metrics = ResolveUIEditorShellInteractionMetrics(); - if (IsUIEditorDetachedWorkspaceToolWindow(workspaceController)) { - metrics.shellMetrics.dockHostMetrics.tabStripMetrics.layoutMetrics.headerHeight = 0.0f; - metrics.shellMetrics.dockHostMetrics.minimumStandalonePanelBodySize = - ResolveUIEditorDetachedToolWindowMinimumContentSize( - workspaceController, - metrics.shellMetrics.dockHostMetrics.minimumStandalonePanelBodySize, - detachedWindowChromeHeight); - metrics.shellMetrics.dockHostMetrics.minimumTabContentBodySize = - metrics.shellMetrics.dockHostMetrics.minimumStandalonePanelBodySize; - } if (useDetachedTitleBarTabStrip && detachedTitleBarTabHeight > 0.0f) { metrics.shellMetrics.dockHostMetrics.tabStripMetrics.layoutMetrics.headerHeight = detachedTitleBarTabHeight; diff --git a/new_editor/app/Composition/EditorShellRuntime.cpp b/new_editor/app/Composition/EditorShellRuntime.cpp index 6721e988..592f7d6f 100644 --- a/new_editor/app/Composition/EditorShellRuntime.cpp +++ b/new_editor/app/Composition/EditorShellRuntime.cpp @@ -60,7 +60,6 @@ void EditorShellRuntime::ResetInteractionState() { m_traceEntries.clear(); m_sceneViewportFeature.ResetInteractionState(); m_hierarchyPanel.ResetInteractionState(); - m_colorPickerPanel.ResetInteractionState(); m_projectPanel.ResetInteractionState(); } @@ -149,7 +148,6 @@ void EditorShellRuntime::Append(::XCEngine::UI::UIDrawData& drawData) const { .shellInteractionState = m_shellInteractionState, .builtInIcons = m_builtInIcons, .consolePanel = m_consolePanel, - .colorPickerPanel = m_colorPickerPanel, .hierarchyPanel = m_hierarchyPanel, .inspectorPanel = m_inspectorPanel, .projectPanel = m_projectPanel, @@ -212,7 +210,6 @@ void EditorShellRuntime::Update( .inputEvents = inputEvents, .shellInteractiveCaptureActive = HasShellInteractiveCapture(), .consolePanel = m_consolePanel, - .colorPickerPanel = m_colorPickerPanel, .hierarchyPanel = m_hierarchyPanel, .inspectorPanel = m_inspectorPanel, .projectPanel = m_projectPanel, diff --git a/new_editor/app/Composition/EditorShellRuntime.h b/new_editor/app/Composition/EditorShellRuntime.h index 5fdb12d3..53434a54 100644 --- a/new_editor/app/Composition/EditorShellRuntime.h +++ b/new_editor/app/Composition/EditorShellRuntime.h @@ -6,7 +6,6 @@ #include "Composition/EditorShellSessionCoordinator.h" #include "Composition/EditorShellVariant.h" #include "Features/Console/ConsolePanel.h" -#include "Features/ColorPicker/ColorPickerPanel.h" #include "Features/Hierarchy/HierarchyPanel.h" #include "Features/Inspector/InspectorPanel.h" #include "Features/Project/ProjectPanel.h" @@ -102,7 +101,6 @@ private: BuiltInIcons m_builtInIcons = {}; Ports::TexturePort* m_textureHost = nullptr; ConsolePanel m_consolePanel = {}; - ColorPickerPanel m_colorPickerPanel = {}; HierarchyPanel m_hierarchyPanel = {}; InspectorPanel m_inspectorPanel = {}; ProjectPanel m_projectPanel = {}; diff --git a/new_editor/app/Features/ColorPicker/ColorPickerPanel.cpp b/new_editor/app/Features/ColorPicker/ColorPickerPanel.cpp index c767d23d..46c318cf 100644 --- a/new_editor/app/Features/ColorPicker/ColorPickerPanel.cpp +++ b/new_editor/app/Features/ColorPicker/ColorPickerPanel.cpp @@ -89,15 +89,15 @@ void ColorPickerPanel::ResetInteractionState() { void ColorPickerPanel::Update( EditorContext& context, - const UIEditorHostedPanelDispatchEntry& dispatchEntry, + const ColorPickerPanelHostContext& hostContext, const std::vector& inputEvents) { - if (!dispatchEntry.mounted) { + if (!hostContext.mounted) { ResetPanelState(); return; } m_visible = true; - m_bounds = dispatchEntry.bounds; + m_bounds = hostContext.bounds; m_metrics = BuildColorPickerPanelMetrics(m_bounds); m_palette = BuildColorPickerPanelPalette(); @@ -136,18 +136,18 @@ void ColorPickerPanel::Update( m_bounds, inputEvents, UIEditorPanelInputFilterOptions{ - .allowPointerInBounds = dispatchEntry.allowInteraction, + .allowPointerInBounds = hostContext.allowInteraction, .allowPointerWhileCaptured = false, - .allowKeyboardInput = dispatchEntry.focused, + .allowKeyboardInput = hostContext.focused, .allowFocusEvents = - dispatchEntry.focused || - dispatchEntry.focusGained || - dispatchEntry.focusLost, + hostContext.focused || + hostContext.focusGained || + hostContext.focusLost, .includePointerLeave = - dispatchEntry.allowInteraction || dispatchEntry.focused + hostContext.allowInteraction || hostContext.focused }, - dispatchEntry.focusGained, - dispatchEntry.focusLost); + hostContext.focusGained, + hostContext.focusLost); const UIRect editorRect = BuildColorPickerEditorRect(m_bounds, m_metrics); m_frame = UpdateUIEditorColorFieldInteraction( diff --git a/new_editor/app/Features/ColorPicker/ColorPickerPanel.h b/new_editor/app/Features/ColorPicker/ColorPickerPanel.h index acc42868..2b99eb98 100644 --- a/new_editor/app/Features/ColorPicker/ColorPickerPanel.h +++ b/new_editor/app/Features/ColorPicker/ColorPickerPanel.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include @@ -12,12 +11,21 @@ namespace XCEngine::UI::Editor::App { class EditorContext; +struct ColorPickerPanelHostContext { + bool mounted = false; + ::XCEngine::UI::UIRect bounds = {}; + bool allowInteraction = false; + bool focused = false; + bool focusGained = false; + bool focusLost = false; +}; + class ColorPickerPanel { public: void ResetInteractionState(); void Update( EditorContext& context, - const UIEditorHostedPanelDispatchEntry& dispatchEntry, + const ColorPickerPanelHostContext& hostContext, const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents); void Append(::XCEngine::UI::UIDrawList& drawList) const; diff --git a/new_editor/app/Platform/Win32/EditorColorPickerUtilityWindowContentController.cpp b/new_editor/app/Platform/Win32/EditorColorPickerUtilityWindowContentController.cpp new file mode 100644 index 00000000..46c9e8cb --- /dev/null +++ b/new_editor/app/Platform/Win32/EditorColorPickerUtilityWindowContentController.cpp @@ -0,0 +1,165 @@ +#include "Platform/Win32/EditorColorPickerUtilityWindowContentController.h" + +#include + +#include + +namespace XCEngine::UI::Editor::App { + +using ::XCEngine::UI::UIInputEvent; +using ::XCEngine::UI::UIInputEventType; + +EditorColorPickerUtilityWindowContentController:: + EditorColorPickerUtilityWindowContentController( + const ::XCEngine::UI::UISize& minimumOuterSize) + : m_minimumOuterSize(minimumOuterSize) {} + +EditorColorPickerUtilityWindowContentController:: + ~EditorColorPickerUtilityWindowContentController() = default; + +const UIEditorWorkspaceController* +EditorColorPickerUtilityWindowContentController::TryGetWorkspaceController() const { + return nullptr; +} + +UIEditorWorkspaceController* +EditorColorPickerUtilityWindowContentController::TryGetMutableWorkspaceController() { + return nullptr; +} + +void EditorColorPickerUtilityWindowContentController::ReplaceWorkspaceController( + UIEditorWorkspaceController) {} + +void EditorColorPickerUtilityWindowContentController::Initialize( + const EditorWindowContentInitializationContext&) {} + +void EditorColorPickerUtilityWindowContentController::Shutdown() { + m_colorPickerPanel.ResetInteractionState(); + m_shellInteractionState = {}; + m_shellFrame = {}; + m_windowFocused = false; +} + +void EditorColorPickerUtilityWindowContentController::ResetInteractionState() { + m_colorPickerPanel.ResetInteractionState(); +} + +void EditorColorPickerUtilityWindowContentController::SetViewportSurfacePresentationEnabled(bool) {} + +EditorWindowFrameTransferRequests +EditorColorPickerUtilityWindowContentController::UpdateAndAppend( + const EditorWindowContentFrameContext& context, + ::XCEngine::UI::UIDrawData& drawData) { + bool focusGained = false; + bool focusLost = false; + for (const UIInputEvent& event : context.inputEvents) { + if (event.type == UIInputEventType::FocusGained) { + m_windowFocused = true; + focusGained = true; + } else if (event.type == UIInputEventType::FocusLost) { + m_windowFocused = false; + focusLost = true; + } + } + + m_shellInteractionState.focused = m_windowFocused; + m_shellFrame.focused = m_windowFocused; + m_colorPickerPanel.Update( + context.editorContext, + ColorPickerPanelHostContext{ + .mounted = true, + .bounds = context.bounds, + .allowInteraction = true, + .focused = m_windowFocused, + .focusGained = focusGained, + .focusLost = focusLost, + }, + context.inputEvents); + + ::XCEngine::UI::UIDrawList& drawList = + drawData.EmplaceDrawList("XCEditorUtility.ColorPicker"); + m_colorPickerPanel.Append(drawList); + return {}; +} + +void EditorColorPickerUtilityWindowContentController::RenderRequestedViewports( + const ::XCEngine::Rendering::RenderContext&) {} + +const UIEditorShellInteractionFrame& +EditorColorPickerUtilityWindowContentController::GetShellFrame() const { + return m_shellFrame; +} + +const UIEditorShellInteractionState& +EditorColorPickerUtilityWindowContentController::GetShellInteractionState() const { + return m_shellInteractionState; +} + +void EditorColorPickerUtilityWindowContentController::SetExternalDockHostDropPreview( + const Widgets::UIEditorDockHostDropPreviewState&) {} + +void EditorColorPickerUtilityWindowContentController::ClearExternalDockHostDropPreview() {} + +bool EditorColorPickerUtilityWindowContentController::TryResolveDockTabDragHotspot( + std::string_view, + std::string_view, + const ::XCEngine::UI::UIPoint&, + ::XCEngine::UI::UIPoint&) const { + return false; +} + +UIEditorDockHostTabDropTarget +EditorColorPickerUtilityWindowContentController::ResolveDockTabDropTarget( + const ::XCEngine::UI::UIPoint&) const { + return {}; +} + +bool EditorColorPickerUtilityWindowContentController::HasHostedContentCapture() const { + return false; +} + +bool EditorColorPickerUtilityWindowContentController::HasShellInteractiveCapture() const { + return false; +} + +bool EditorColorPickerUtilityWindowContentController::HasInteractiveCapture() const { + return false; +} + +EditorWindowContentCursorKind +EditorColorPickerUtilityWindowContentController::GetHostedContentCursorKind() const { + return EditorWindowContentCursorKind::Arrow; +} + +EditorWindowContentCursorKind +EditorColorPickerUtilityWindowContentController::GetDockCursorKind() const { + return EditorWindowContentCursorKind::Arrow; +} + +::XCEngine::UI::UISize +EditorColorPickerUtilityWindowContentController::ResolveMinimumOuterSize() const { + return m_minimumOuterSize; +} + +bool EditorColorPickerUtilityWindowContentController::ShouldUseDetachedTitleBarTabStrip() const { + return false; +} + +std::string EditorColorPickerUtilityWindowContentController::ResolveTabStripTitleText( + std::string_view fallbackTitle) const { + return std::string(fallbackTitle); +} + +std::string EditorColorPickerUtilityWindowContentController::ResolveDetachedWindowTitleText( + std::string_view fallbackWindowTitle) const { + return std::string(fallbackWindowTitle); +} + +std::unique_ptr +CreateEditorColorPickerUtilityWindowContentController( + const ::XCEngine::UI::UISize& minimumOuterSize) { + return std::make_unique( + minimumOuterSize); +} + +} // namespace XCEngine::UI::Editor::App diff --git a/new_editor/app/Platform/Win32/EditorColorPickerUtilityWindowContentController.h b/new_editor/app/Platform/Win32/EditorColorPickerUtilityWindowContentController.h new file mode 100644 index 00000000..0334e097 --- /dev/null +++ b/new_editor/app/Platform/Win32/EditorColorPickerUtilityWindowContentController.h @@ -0,0 +1,75 @@ +#pragma once + +#include "Features/ColorPicker/ColorPickerPanel.h" +#include "Platform/Win32/EditorWindowContentController.h" + +#include + +#include + +#include + +namespace XCEngine::UI::Editor::App { + +class EditorColorPickerUtilityWindowContentController final + : public EditorWindowContentController { +public: + explicit EditorColorPickerUtilityWindowContentController( + const ::XCEngine::UI::UISize& minimumOuterSize); + ~EditorColorPickerUtilityWindowContentController() override; + + const UIEditorWorkspaceController* TryGetWorkspaceController() const override; + UIEditorWorkspaceController* TryGetMutableWorkspaceController() override; + void ReplaceWorkspaceController(UIEditorWorkspaceController workspaceController) override; + + void Initialize(const EditorWindowContentInitializationContext& context) override; + void Shutdown() override; + void ResetInteractionState() override; + void SetViewportSurfacePresentationEnabled(bool enabled) override; + + EditorWindowFrameTransferRequests UpdateAndAppend( + const EditorWindowContentFrameContext& context, + ::XCEngine::UI::UIDrawData& drawData) override; + void RenderRequestedViewports( + const ::XCEngine::Rendering::RenderContext& renderContext) override; + + const UIEditorShellInteractionFrame& GetShellFrame() const override; + const UIEditorShellInteractionState& GetShellInteractionState() const override; + + void SetExternalDockHostDropPreview( + const Widgets::UIEditorDockHostDropPreviewState& preview) override; + void ClearExternalDockHostDropPreview() override; + + bool TryResolveDockTabDragHotspot( + std::string_view nodeId, + std::string_view panelId, + const ::XCEngine::UI::UIPoint& point, + ::XCEngine::UI::UIPoint& outHotspot) const override; + UIEditorDockHostTabDropTarget ResolveDockTabDropTarget( + const ::XCEngine::UI::UIPoint& point) const override; + + bool HasHostedContentCapture() const override; + bool HasShellInteractiveCapture() const override; + bool HasInteractiveCapture() const override; + EditorWindowContentCursorKind GetHostedContentCursorKind() const override; + EditorWindowContentCursorKind GetDockCursorKind() const override; + + ::XCEngine::UI::UISize ResolveMinimumOuterSize() const override; + bool ShouldUseDetachedTitleBarTabStrip() const override; + std::string ResolveTabStripTitleText(std::string_view fallbackTitle) const override; + std::string ResolveDetachedWindowTitleText( + std::string_view fallbackWindowTitle) const override; + +private: + ::XCEngine::UI::UISize m_minimumOuterSize = {}; + ColorPickerPanel m_colorPickerPanel = {}; + UIEditorShellInteractionState m_shellInteractionState = {}; + UIEditorShellInteractionFrame m_shellFrame = {}; + bool m_windowFocused = true; +}; + +std::unique_ptr +CreateEditorColorPickerUtilityWindowContentController( + const ::XCEngine::UI::UISize& minimumOuterSize); + +} // namespace XCEngine::UI::Editor::App diff --git a/new_editor/app/Platform/Win32/EditorFloatingWindowPlacement.cpp b/new_editor/app/Platform/Win32/EditorFloatingWindowPlacement.cpp new file mode 100644 index 00000000..475051c1 --- /dev/null +++ b/new_editor/app/Platform/Win32/EditorFloatingWindowPlacement.cpp @@ -0,0 +1,46 @@ +#include "Platform/Win32/EditorFloatingWindowPlacement.h" + +#include + +namespace XCEngine::UI::Editor::App { + +namespace { + +constexpr LONG kFloatingWindowTopOffset = 24; + +} + +RECT BuildEditorFloatingWindowRect( + const POINT& screenPoint, + LONG preferredWidth, + LONG preferredHeight, + LONG fallbackWidth, + LONG fallbackHeight) { + const LONG resolvedWidth = preferredWidth > 0 ? preferredWidth : fallbackWidth; + const LONG resolvedHeight = preferredHeight > 0 ? preferredHeight : fallbackHeight; + const LONG left = screenPoint.x - resolvedWidth / 2; + const LONG top = screenPoint.y - kFloatingWindowTopOffset; + RECT rect = { + left, + top, + left + resolvedWidth, + top + resolvedHeight + }; + + const HMONITOR monitor = MonitorFromPoint(screenPoint, MONITOR_DEFAULTTONEAREST); + MONITORINFO monitorInfo = {}; + monitorInfo.cbSize = sizeof(monitorInfo); + if (monitor != nullptr && GetMonitorInfoW(monitor, &monitorInfo)) { + const RECT& workArea = monitorInfo.rcWork; + const LONG width = rect.right - rect.left; + const LONG height = rect.bottom - rect.top; + rect.left = (std::max)(workArea.left, (std::min)(rect.left, workArea.right - width)); + rect.top = (std::max)(workArea.top, (std::min)(rect.top, workArea.bottom - height)); + rect.right = rect.left + width; + rect.bottom = rect.top + height; + } + + return rect; +} + +} // namespace XCEngine::UI::Editor::App diff --git a/new_editor/app/Platform/Win32/EditorFloatingWindowPlacement.h b/new_editor/app/Platform/Win32/EditorFloatingWindowPlacement.h new file mode 100644 index 00000000..ae113c72 --- /dev/null +++ b/new_editor/app/Platform/Win32/EditorFloatingWindowPlacement.h @@ -0,0 +1,18 @@ +#pragma once + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include + +namespace XCEngine::UI::Editor::App { + +RECT BuildEditorFloatingWindowRect( + const POINT& screenPoint, + LONG preferredWidth = 0, + LONG preferredHeight = 0, + LONG fallbackWidth = 960, + LONG fallbackHeight = 720); + +} // namespace XCEngine::UI::Editor::App diff --git a/new_editor/app/Platform/Win32/EditorUtilityWindowKind.h b/new_editor/app/Platform/Win32/EditorUtilityWindowKind.h new file mode 100644 index 00000000..a94033c8 --- /dev/null +++ b/new_editor/app/Platform/Win32/EditorUtilityWindowKind.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace XCEngine::UI::Editor::App { + +enum class EditorUtilityWindowKind : std::uint8_t { + None = 0, + ColorPicker, +}; + +} // namespace XCEngine::UI::Editor::App diff --git a/new_editor/app/Platform/Win32/EditorUtilityWindowRegistry.cpp b/new_editor/app/Platform/Win32/EditorUtilityWindowRegistry.cpp new file mode 100644 index 00000000..d557eb65 --- /dev/null +++ b/new_editor/app/Platform/Win32/EditorUtilityWindowRegistry.cpp @@ -0,0 +1,50 @@ +#include "Platform/Win32/EditorUtilityWindowRegistry.h" + +#include "Platform/Win32/EditorColorPickerUtilityWindowContentController.h" + +namespace XCEngine::UI::Editor::App { + +namespace { + +using ::XCEngine::UI::UISize; + +constexpr EditorUtilityWindowDescriptor kColorPickerUtilityWindowDescriptor = { + .kind = EditorUtilityWindowKind::ColorPicker, + .windowId = "utility.color-picker", + .title = L"Color Picker", + .preferredOuterSize = UISize(352.0f, 500.0f), + .minimumOuterSize = UISize(320.0f, 460.0f), +}; + +} + +const EditorUtilityWindowDescriptor* ResolveEditorUtilityWindowDescriptor( + EditorUtilityWindowKind kind) { + switch (kind) { + case EditorUtilityWindowKind::ColorPicker: + return &kColorPickerUtilityWindowDescriptor; + case EditorUtilityWindowKind::None: + default: + return nullptr; + } +} + +std::unique_ptr CreateEditorUtilityWindowContentController( + EditorUtilityWindowKind kind) { + const EditorUtilityWindowDescriptor* descriptor = + ResolveEditorUtilityWindowDescriptor(kind); + if (descriptor == nullptr) { + return nullptr; + } + + switch (kind) { + case EditorUtilityWindowKind::ColorPicker: + return CreateEditorColorPickerUtilityWindowContentController( + descriptor->minimumOuterSize); + case EditorUtilityWindowKind::None: + default: + return nullptr; + } +} + +} // namespace XCEngine::UI::Editor::App diff --git a/new_editor/app/Platform/Win32/EditorUtilityWindowRegistry.h b/new_editor/app/Platform/Win32/EditorUtilityWindowRegistry.h new file mode 100644 index 00000000..a65faf88 --- /dev/null +++ b/new_editor/app/Platform/Win32/EditorUtilityWindowRegistry.h @@ -0,0 +1,28 @@ +#pragma once + +#include "Platform/Win32/EditorUtilityWindowKind.h" + +#include + +#include +#include + +namespace XCEngine::UI::Editor::App { + +class EditorWindowContentController; + +struct EditorUtilityWindowDescriptor { + EditorUtilityWindowKind kind = EditorUtilityWindowKind::None; + std::string_view windowId = {}; + const wchar_t* title = L""; + ::XCEngine::UI::UISize preferredOuterSize = {}; + ::XCEngine::UI::UISize minimumOuterSize = {}; +}; + +const EditorUtilityWindowDescriptor* ResolveEditorUtilityWindowDescriptor( + EditorUtilityWindowKind kind); + +std::unique_ptr CreateEditorUtilityWindowContentController( + EditorUtilityWindowKind kind); + +} // namespace XCEngine::UI::Editor::App diff --git a/new_editor/app/Platform/Win32/EditorWindowFrameOrchestrator.cpp b/new_editor/app/Platform/Win32/EditorWindowFrameOrchestrator.cpp index 5b66588f..6f9d495e 100644 --- a/new_editor/app/Platform/Win32/EditorWindowFrameOrchestrator.cpp +++ b/new_editor/app/Platform/Win32/EditorWindowFrameOrchestrator.cpp @@ -1,12 +1,10 @@ #include "Platform/Win32/EditorWindowFrameOrchestrator.h" #include "Composition/EditorContext.h" -#include "Composition/EditorPanelIds.h" #include "Composition/EditorShellRuntime.h" #include "Composition/EditorShellVariant.h" #include "Platform/Win32/EditorWindowSupport.h" -#include #include #include @@ -82,20 +80,15 @@ EditorWindowFrameTransferRequests EditorWindowFrameOrchestrator::UpdateAndAppend EditorWindowFrameTransferRequests transferRequests = BuildShellTransferRequests(globalTabDragActive, dockHostInteractionState, shellFrame); POINT screenPoint = {}; - if (ConsumeEditorColorPickerOpenDetachedPanelRequest( - editorContext.GetColorPickerToolState()) && - GetCursorPos(&screenPoint) != FALSE) { - const ::XCEngine::UI::UISize preferredSize = - ResolveUIEditorDetachedPanelPreferredWindowSize( - editorContext.GetShellAsset().panelRegistry, - kColorPickerPanelId, - ::XCEngine::UI::UISize(360.0f, 520.0f)); - transferRequests.openDetachedPanel = EditorWindowOpenDetachedPanelRequest{ - std::string(kColorPickerPanelId), - screenPoint, - static_cast(preferredSize.width), - static_cast(preferredSize.height), + if (ConsumeEditorColorPickerOpenUtilityWindowRequest( + editorContext.GetColorPickerToolState())) { + transferRequests.openUtilityWindow = EditorWindowOpenUtilityWindowRequest{ + .kind = EditorUtilityWindowKind::ColorPicker, + .useCursorPlacement = GetCursorPos(&screenPoint) != FALSE, }; + if (transferRequests.openUtilityWindow->useCursorPlacement) { + transferRequests.openUtilityWindow->screenPoint = screenPoint; + } } for (const WorkspaceTraceEntry& entry : shellRuntime.GetTraceEntries()) { diff --git a/new_editor/app/Platform/Win32/EditorWindowManager.h b/new_editor/app/Platform/Win32/EditorWindowManager.h index 1d4c684c..eca85c52 100644 --- a/new_editor/app/Platform/Win32/EditorWindowManager.h +++ b/new_editor/app/Platform/Win32/EditorWindowManager.h @@ -29,6 +29,7 @@ class EditorWindow; class EditorWindowContentController; class EditorWindowHostRuntime; class EditorWindowLifecycleCoordinator; +class EditorUtilityWindowCoordinator; class EditorWindowWorkspaceCoordinator; struct EditorWindowPanelTransferRequest; struct EditorWindowFrameTransferRequests; @@ -92,6 +93,7 @@ public: private: std::unique_ptr m_hostRuntime = {}; std::unique_ptr m_lifecycleCoordinator = {}; + std::unique_ptr m_utilityCoordinator = {}; std::unique_ptr m_workspaceCoordinator = {}; }; diff --git a/new_editor/app/Platform/Win32/EditorWindowTransferRequests.h b/new_editor/app/Platform/Win32/EditorWindowTransferRequests.h index fc97453d..185685b5 100644 --- a/new_editor/app/Platform/Win32/EditorWindowTransferRequests.h +++ b/new_editor/app/Platform/Win32/EditorWindowTransferRequests.h @@ -4,6 +4,8 @@ #define NOMINMAX #endif +#include "Platform/Win32/EditorUtilityWindowKind.h" + #include #include @@ -21,26 +23,25 @@ struct EditorWindowPanelTransferRequest { } }; -struct EditorWindowOpenDetachedPanelRequest { - std::string panelId = {}; +struct EditorWindowOpenUtilityWindowRequest { + EditorUtilityWindowKind kind = EditorUtilityWindowKind::None; POINT screenPoint = {}; - LONG preferredWidth = 0; - LONG preferredHeight = 0; + bool useCursorPlacement = false; bool IsValid() const { - return !panelId.empty(); + return kind != EditorUtilityWindowKind::None; } }; struct EditorWindowFrameTransferRequests { std::optional beginGlobalTabDrag = {}; std::optional detachPanel = {}; - std::optional openDetachedPanel = {}; + std::optional openUtilityWindow = {}; bool HasPendingRequests() const { return beginGlobalTabDrag.has_value() || detachPanel.has_value() || - openDetachedPanel.has_value(); + openUtilityWindow.has_value(); } }; diff --git a/new_editor/app/Platform/Win32/EditorWorkspaceWindowContentController.cpp b/new_editor/app/Platform/Win32/EditorWorkspaceWindowContentController.cpp index c1fc560c..73e8ae91 100644 --- a/new_editor/app/Platform/Win32/EditorWorkspaceWindowContentController.cpp +++ b/new_editor/app/Platform/Win32/EditorWorkspaceWindowContentController.cpp @@ -153,8 +153,7 @@ EditorWindowContentCursorKind EditorWorkspaceWindowContentController::GetDockCur } bool EditorWorkspaceWindowContentController::ShouldUseDetachedTitleBarTabStrip() const { - return !IsUIEditorDetachedWorkspaceToolWindow(m_workspaceController) && - HasUIEditorSingleVisibleRootTab(m_workspaceController); + return HasUIEditorSingleVisibleRootTab(m_workspaceController); } std::string EditorWorkspaceWindowContentController::ResolveTabStripTitleText( @@ -164,12 +163,6 @@ std::string EditorWorkspaceWindowContentController::ResolveTabStripTitleText( std::string EditorWorkspaceWindowContentController::ResolveDetachedWindowTitleText( std::string_view fallbackWindowTitle) const { - if (IsUIEditorDetachedWorkspaceToolWindow(m_workspaceController)) { - return ResolveUIEditorDetachedWorkspaceTitle( - m_workspaceController, - fallbackWindowTitle); - } - return std::string(fallbackWindowTitle); } diff --git a/new_editor/app/Platform/Win32/WindowManager/EditorUtilityWindowCoordinator.cpp b/new_editor/app/Platform/Win32/WindowManager/EditorUtilityWindowCoordinator.cpp new file mode 100644 index 00000000..715e0e4b --- /dev/null +++ b/new_editor/app/Platform/Win32/WindowManager/EditorUtilityWindowCoordinator.cpp @@ -0,0 +1,153 @@ +#include "Platform/Win32/WindowManager/EditorUtilityWindowCoordinator.h" + +#include "Platform/Win32/EditorFloatingWindowPlacement.h" +#include "Platform/Win32/EditorUtilityWindowRegistry.h" +#include "Platform/Win32/EditorWindow.h" +#include "Platform/Win32/EditorWindowContentController.h" +#include "Platform/Win32/WindowManager/EditorWindowHostRuntime.h" +#include "Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.h" + +#include + +namespace XCEngine::UI::Editor::App { + +namespace { + +bool IsLiveWindow(const EditorWindow* window) { + return window != nullptr && + window->GetHwnd() != nullptr && + !window->IsClosing(); +} + +LONG ResolveOuterDimension(float value, LONG fallback) { + return value > 0.0f + ? static_cast(std::lround(value)) + : fallback; +} + +} + +EditorUtilityWindowCoordinator::EditorUtilityWindowCoordinator( + EditorWindowHostRuntime& hostRuntime) + : m_hostRuntime(hostRuntime) {} + +EditorUtilityWindowCoordinator::~EditorUtilityWindowCoordinator() = default; + +void EditorUtilityWindowCoordinator::BindLifecycleCoordinator( + EditorWindowLifecycleCoordinator& lifecycleCoordinator) { + m_lifecycleCoordinator = &lifecycleCoordinator; +} + +void EditorUtilityWindowCoordinator::RegisterExistingWindow(EditorWindow&) {} + +void EditorUtilityWindowCoordinator::RefreshWindowPresentation(EditorWindow&) const {} + +void EditorUtilityWindowCoordinator::HandleWindowFrameTransferRequests( + EditorWindow& sourceWindow, + const EditorWindowFrameTransferRequests& transferRequests) { + if (transferRequests.openUtilityWindow.has_value() && + transferRequests.openUtilityWindow->IsValid()) { + TryProcessOpenUtilityWindowRequest(sourceWindow, *transferRequests.openUtilityWindow); + } +} + +bool EditorUtilityWindowCoordinator::TryProcessOpenUtilityWindowRequest( + EditorWindow& sourceWindow, + const EditorWindowOpenUtilityWindowRequest& request) { + if (sourceWindow.IsClosing()) { + LogRuntimeTrace( + "utility", + "open utility window request rejected: source window is closing"); + return false; + } + + const EditorUtilityWindowDescriptor* descriptor = + ResolveEditorUtilityWindowDescriptor(request.kind); + if (descriptor == nullptr) { + LogRuntimeTrace("utility", "open utility window request rejected: unknown kind"); + return false; + } + + if (EditorWindow* existingWindow = m_hostRuntime.FindWindow(descriptor->windowId); + existingWindow != nullptr && existingWindow->GetHwnd() == nullptr && + m_lifecycleCoordinator != nullptr) { + m_lifecycleCoordinator->ReapDestroyedWindows(); + } + + if (EditorWindow* existingWindow = m_hostRuntime.FindWindow(descriptor->windowId); + IsLiveWindow(existingWindow)) { + FocusWindow(*existingWindow); + LogRuntimeTrace( + "utility", + "reused utility window '" + std::string(descriptor->windowId) + "'"); + return true; + } + + if (EditorWindow* existingWindow = m_hostRuntime.FindWindow(descriptor->windowId); + existingWindow != nullptr) { + LogRuntimeTrace( + "utility", + "open utility window request rejected: existing utility window is still closing"); + return false; + } + + std::unique_ptr contentController = + CreateEditorUtilityWindowContentController(request.kind); + if (contentController == nullptr) { + LogRuntimeTrace( + "utility", + "open utility window request rejected: content factory returned null"); + return false; + } + + EditorWindowHostRuntime::CreateParams createParams = {}; + createParams.windowId = std::string(descriptor->windowId); + createParams.title = descriptor->title; + createParams.primary = false; + createParams.initialWidth = ResolveOuterDimension( + descriptor->preferredOuterSize.width, + createParams.initialWidth); + createParams.initialHeight = ResolveOuterDimension( + descriptor->preferredOuterSize.height, + createParams.initialHeight); + if (request.useCursorPlacement) { + const RECT rect = BuildEditorFloatingWindowRect( + request.screenPoint, + createParams.initialWidth, + createParams.initialHeight); + createParams.initialX = rect.left; + createParams.initialY = rect.top; + createParams.initialWidth = rect.right - rect.left; + createParams.initialHeight = rect.bottom - rect.top; + } + + EditorWindow* utilityWindow = + m_hostRuntime.CreateEditorWindow(std::move(contentController), createParams); + if (utilityWindow == nullptr) { + LogRuntimeTrace("utility", "failed to create utility window"); + return false; + } + + FocusWindow(*utilityWindow); + LogRuntimeTrace( + "utility", + "opened utility window '" + std::string(descriptor->windowId) + "'"); + return true; +} + +void EditorUtilityWindowCoordinator::FocusWindow(EditorWindow& window) const { + if (!IsLiveWindow(&window)) { + return; + } + + ShowWindow(window.GetHwnd(), SW_RESTORE); + SetForegroundWindow(window.GetHwnd()); +} + +void EditorUtilityWindowCoordinator::LogRuntimeTrace( + std::string_view channel, + std::string_view message) const { + m_hostRuntime.LogRuntimeTrace(channel, message); +} + +} // namespace XCEngine::UI::Editor::App diff --git a/new_editor/app/Platform/Win32/WindowManager/EditorUtilityWindowCoordinator.h b/new_editor/app/Platform/Win32/WindowManager/EditorUtilityWindowCoordinator.h new file mode 100644 index 00000000..12252cf5 --- /dev/null +++ b/new_editor/app/Platform/Win32/WindowManager/EditorUtilityWindowCoordinator.h @@ -0,0 +1,36 @@ +#pragma once + +#include "Platform/Win32/EditorWindowTransferRequests.h" + +#include + +namespace XCEngine::UI::Editor::App { + +class EditorWindow; +class EditorWindowHostRuntime; +class EditorWindowLifecycleCoordinator; + +class EditorUtilityWindowCoordinator final { +public: + explicit EditorUtilityWindowCoordinator(EditorWindowHostRuntime& hostRuntime); + ~EditorUtilityWindowCoordinator(); + + void BindLifecycleCoordinator(EditorWindowLifecycleCoordinator& lifecycleCoordinator); + void RegisterExistingWindow(EditorWindow& window); + void RefreshWindowPresentation(EditorWindow& window) const; + void HandleWindowFrameTransferRequests( + EditorWindow& sourceWindow, + const EditorWindowFrameTransferRequests& transferRequests); + +private: + bool TryProcessOpenUtilityWindowRequest( + EditorWindow& sourceWindow, + const EditorWindowOpenUtilityWindowRequest& request); + void FocusWindow(EditorWindow& window) const; + void LogRuntimeTrace(std::string_view channel, std::string_view message) const; + + EditorWindowHostRuntime& m_hostRuntime; + EditorWindowLifecycleCoordinator* m_lifecycleCoordinator = nullptr; +}; + +} // namespace XCEngine::UI::Editor::App diff --git a/new_editor/app/Platform/Win32/WindowManager/EditorWindowHostRuntime.cpp b/new_editor/app/Platform/Win32/WindowManager/EditorWindowHostRuntime.cpp index bd3acf92..84c4a2bb 100644 --- a/new_editor/app/Platform/Win32/WindowManager/EditorWindowHostRuntime.cpp +++ b/new_editor/app/Platform/Win32/WindowManager/EditorWindowHostRuntime.cpp @@ -5,6 +5,7 @@ #include "Platform/Win32/EditorWindow.h" #include "Platform/Win32/EditorWindowContentController.h" #include "Platform/Win32/EditorWindowFrameDriver.h" +#include "Platform/Win32/WindowManager/EditorUtilityWindowCoordinator.h" #include "Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.h" #include "Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.h" @@ -168,7 +169,8 @@ bool EditorWindowHostRuntime::HasWindows() const { void EditorWindowHostRuntime::RenderAllWindows( bool globalTabDragActive, - EditorWindowWorkspaceCoordinator& workspaceCoordinator) { + EditorWindowWorkspaceCoordinator& workspaceCoordinator, + EditorUtilityWindowCoordinator& utilityCoordinator) { struct WindowFrameTransferBatch { EditorWindow* sourceWindow = nullptr; EditorWindowFrameTransferRequests requests = {}; @@ -190,6 +192,7 @@ void EditorWindowHostRuntime::RenderAllWindows( m_editorContext, globalTabDragActive); workspaceCoordinator.RefreshWindowPresentation(*window); + utilityCoordinator.RefreshWindowPresentation(*window); if (!transferRequests.HasPendingRequests()) { continue; } @@ -209,7 +212,10 @@ void EditorWindowHostRuntime::RenderAllWindows( workspaceCoordinator.HandleWindowFrameTransferRequests( *batch.sourceWindow, - std::move(batch.requests)); + batch.requests); + utilityCoordinator.HandleWindowFrameTransferRequests( + *batch.sourceWindow, + batch.requests); } } diff --git a/new_editor/app/Platform/Win32/WindowManager/EditorWindowHostRuntime.h b/new_editor/app/Platform/Win32/WindowManager/EditorWindowHostRuntime.h index fefd5131..ad8d52d2 100644 --- a/new_editor/app/Platform/Win32/WindowManager/EditorWindowHostRuntime.h +++ b/new_editor/app/Platform/Win32/WindowManager/EditorWindowHostRuntime.h @@ -15,6 +15,7 @@ class EditorContext; class EditorWindow; class EditorWindowContentController; class EditorWindowLifecycleCoordinator; +class EditorUtilityWindowCoordinator; class EditorWindowWorkspaceCoordinator; class EditorWindowHostRuntime final { @@ -43,7 +44,8 @@ public: bool HasWindows() const; void RenderAllWindows( bool globalTabDragActive, - EditorWindowWorkspaceCoordinator& workspaceCoordinator); + EditorWindowWorkspaceCoordinator& workspaceCoordinator, + EditorUtilityWindowCoordinator& utilityCoordinator); EditorContext& GetEditorContext() { return m_editorContext; diff --git a/new_editor/app/Platform/Win32/WindowManager/EditorWindowManager.cpp b/new_editor/app/Platform/Win32/WindowManager/EditorWindowManager.cpp index 0c97b74a..032b592d 100644 --- a/new_editor/app/Platform/Win32/WindowManager/EditorWindowManager.cpp +++ b/new_editor/app/Platform/Win32/WindowManager/EditorWindowManager.cpp @@ -4,6 +4,7 @@ #include "Platform/Win32/EditorWindowContentController.h" #include "Platform/Win32/WindowManager/EditorWindowHostRuntime.h" #include "Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.h" +#include "Platform/Win32/WindowManager/EditorUtilityWindowCoordinator.h" #include "Platform/Win32/WindowManager/EditorWindowMessageDispatcher.h" #include "Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.h" @@ -21,11 +22,14 @@ EditorWindowManager::EditorWindowManager( editorContext)) { m_workspaceCoordinator = std::make_unique(*m_hostRuntime); + m_utilityCoordinator = + std::make_unique(*m_hostRuntime); m_lifecycleCoordinator = std::make_unique( *m_hostRuntime, *m_workspaceCoordinator); m_hostRuntime->BindLifecycleCoordinator(*m_lifecycleCoordinator); m_workspaceCoordinator->BindLifecycleCoordinator(*m_lifecycleCoordinator); + m_utilityCoordinator->BindLifecycleCoordinator(*m_lifecycleCoordinator); } EditorWindowManager::~EditorWindowManager() = default; @@ -37,6 +41,7 @@ EditorWindow* EditorWindowManager::CreateEditorWindow( m_hostRuntime->CreateEditorWindow(std::move(contentController), params); if (window != nullptr) { m_workspaceCoordinator->RegisterExistingWindow(*window); + m_utilityCoordinator->RegisterExistingWindow(*window); } return window; } @@ -69,6 +74,7 @@ bool EditorWindowManager::TryDispatchWindowMessage( hwnd, *m_hostRuntime, *m_lifecycleCoordinator, + *m_utilityCoordinator, *m_workspaceCoordinator, *window, message, @@ -112,7 +118,8 @@ void EditorWindowManager::DestroyClosedWindows() { void EditorWindowManager::RenderAllWindows() { m_hostRuntime->RenderAllWindows( m_workspaceCoordinator->IsGlobalTabDragActive(), - *m_workspaceCoordinator); + *m_workspaceCoordinator, + *m_utilityCoordinator); } } // namespace XCEngine::UI::Editor::App diff --git a/new_editor/app/Platform/Win32/WindowManager/EditorWindowMessageDispatcher.cpp b/new_editor/app/Platform/Win32/WindowManager/EditorWindowMessageDispatcher.cpp index 13d85593..907b453b 100644 --- a/new_editor/app/Platform/Win32/WindowManager/EditorWindowMessageDispatcher.cpp +++ b/new_editor/app/Platform/Win32/WindowManager/EditorWindowMessageDispatcher.cpp @@ -6,6 +6,7 @@ #include "Platform/Win32/EditorWindowPointerCapture.h" #include "Platform/Win32/WindowManager/EditorWindowHostRuntime.h" #include "Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.h" +#include "Platform/Win32/WindowManager/EditorUtilityWindowCoordinator.h" #include "Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.h" #include @@ -57,19 +58,29 @@ struct EditorWindowMessageDispatcher::DispatchContext { HWND hwnd = nullptr; EditorWindowHostRuntime& hostRuntime; EditorWindowLifecycleCoordinator& lifecycleCoordinator; + EditorUtilityWindowCoordinator& utilityCoordinator; EditorWindowWorkspaceCoordinator& workspaceCoordinator; EditorWindow& window; }; +void EditorWindowMessageDispatcher::DispatchWindowFrameTransferRequests( + const DispatchContext& context, + const EditorWindowFrameTransferRequests& transferRequests) { + context.workspaceCoordinator.HandleWindowFrameTransferRequests( + context.window, + transferRequests); + context.utilityCoordinator.HandleWindowFrameTransferRequests( + context.window, + transferRequests); +} + void EditorWindowMessageDispatcher::RenderAndHandleWindowFrame(const DispatchContext& context) { EditorWindowFrameTransferRequests transferRequests = EditorWindowFrameDriver::DriveFrame( context.window, context.hostRuntime.GetEditorContext(), context.workspaceCoordinator.IsGlobalTabDragActive()); if (transferRequests.HasPendingRequests()) { - context.workspaceCoordinator.HandleWindowFrameTransferRequests( - context.window, - std::move(transferRequests)); + DispatchWindowFrameTransferRequests(context, transferRequests); } } @@ -425,9 +436,7 @@ bool EditorWindowMessageDispatcher::TryDispatchWindowLifecycleMessage( context.hostRuntime.GetEditorContext(), context.workspaceCoordinator.IsGlobalTabDragActive()); transferRequests.HasPendingRequests()) { - context.workspaceCoordinator.HandleWindowFrameTransferRequests( - context.window, - std::move(transferRequests)); + DispatchWindowFrameTransferRequests(context, transferRequests); } outResult = 0; return true; @@ -507,6 +516,7 @@ bool EditorWindowMessageDispatcher::TryDispatch( HWND hwnd, EditorWindowHostRuntime& hostRuntime, EditorWindowLifecycleCoordinator& lifecycleCoordinator, + EditorUtilityWindowCoordinator& utilityCoordinator, EditorWindowWorkspaceCoordinator& workspaceCoordinator, EditorWindow& window, UINT message, @@ -517,6 +527,7 @@ bool EditorWindowMessageDispatcher::TryDispatch( .hwnd = hwnd, .hostRuntime = hostRuntime, .lifecycleCoordinator = lifecycleCoordinator, + .utilityCoordinator = utilityCoordinator, .workspaceCoordinator = workspaceCoordinator, .window = window, }; diff --git a/new_editor/app/Platform/Win32/WindowManager/EditorWindowMessageDispatcher.h b/new_editor/app/Platform/Win32/WindowManager/EditorWindowMessageDispatcher.h index 1b5a943c..c7f005fa 100644 --- a/new_editor/app/Platform/Win32/WindowManager/EditorWindowMessageDispatcher.h +++ b/new_editor/app/Platform/Win32/WindowManager/EditorWindowMessageDispatcher.h @@ -4,6 +4,8 @@ #define NOMINMAX #endif +#include "Platform/Win32/EditorWindowTransferRequests.h" + #include namespace XCEngine::UI::Editor::App { @@ -14,6 +16,7 @@ namespace XCEngine::UI::Editor::App { class EditorWindowHostRuntime; class EditorWindowLifecycleCoordinator; +class EditorUtilityWindowCoordinator; class EditorWindowWorkspaceCoordinator; class EditorWindowMessageDispatcher final { @@ -22,6 +25,7 @@ public: HWND hwnd, EditorWindowHostRuntime& hostRuntime, EditorWindowLifecycleCoordinator& lifecycleCoordinator, + EditorUtilityWindowCoordinator& utilityCoordinator, EditorWindowWorkspaceCoordinator& workspaceCoordinator, EditorWindow& window, UINT message, @@ -33,6 +37,9 @@ private: struct DispatchContext; static void RenderAndHandleWindowFrame(const DispatchContext& context); + static void DispatchWindowFrameTransferRequests( + const DispatchContext& context, + const EditorWindowFrameTransferRequests& transferRequests); static bool EnsureTrackingMouseLeave(const DispatchContext& context); static bool TryHandleChromeHoverConsumption( const DispatchContext& context, diff --git a/new_editor/app/Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.cpp b/new_editor/app/Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.cpp index e3eba85b..4280b65d 100644 --- a/new_editor/app/Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.cpp +++ b/new_editor/app/Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.cpp @@ -2,6 +2,7 @@ #include "Composition/EditorContext.h" #include "Platform/Win32/EditorWindow.h" +#include "Platform/Win32/EditorFloatingWindowPlacement.h" #include "Platform/Win32/EditorWorkspaceWindowContentController.h" #include "Platform/Win32/WindowManager/EditorWindowHostRuntime.h" #include "Platform/Win32/WindowManager/EditorWindowLifecycleCoordinator.h" @@ -222,37 +223,6 @@ void EditorWindowWorkspaceCoordinator::RefreshWindowTitle(EditorWindow& window) } } -RECT EditorWindowWorkspaceCoordinator::BuildDetachedWindowRect( - const POINT& screenPoint, - LONG preferredWidth, - LONG preferredHeight) const { - const LONG resolvedWidth = preferredWidth > 0 ? preferredWidth : 960; - const LONG resolvedHeight = preferredHeight > 0 ? preferredHeight : 720; - const LONG left = screenPoint.x - resolvedWidth / 2; - const LONG top = screenPoint.y - 24; - RECT rect = { - left, - top, - left + resolvedWidth, - top + resolvedHeight - }; - - const HMONITOR monitor = MonitorFromPoint(screenPoint, MONITOR_DEFAULTTONEAREST); - MONITORINFO monitorInfo = {}; - monitorInfo.cbSize = sizeof(monitorInfo); - if (monitor != nullptr && GetMonitorInfoW(monitor, &monitorInfo)) { - const RECT& workArea = monitorInfo.rcWork; - const LONG width = rect.right - rect.left; - const LONG height = rect.bottom - rect.top; - rect.left = (std::max)(workArea.left, (std::min)(rect.left, workArea.right - width)); - rect.top = (std::max)(workArea.top, (std::min)(rect.top, workArea.bottom - height)); - rect.right = rect.left + width; - rect.bottom = rect.top + height; - } - - return rect; -} - bool EditorWindowWorkspaceCoordinator::SynchronizeWindowsFromWindowSet( const UIEditorWindowWorkspaceSet& windowSet, std::string_view preferredNewWindowId, @@ -330,7 +300,7 @@ bool EditorWindowWorkspaceCoordinator::SynchronizeWindowsFromWindowSet( : L"XCEngine Editor") : BuildWindowTitle(BuildWorkspaceControllerForWindow(entry)); if (entry.windowId == preferredNewWindowId) { - const RECT detachedRect = BuildDetachedWindowRect( + const RECT detachedRect = BuildEditorFloatingWindowRect( preferredScreenPoint, preferredWidth, preferredHeight); @@ -782,70 +752,9 @@ bool EditorWindowWorkspaceCoordinator::TryProcessDetachRequest( return true; } -bool EditorWindowWorkspaceCoordinator::TryProcessOpenDetachedPanelRequest( - EditorWindow& sourceWindow, - const EditorWindowOpenDetachedPanelRequest& request) { - if (sourceWindow.IsClosing()) { - LogRuntimeTrace( - "window", - "open detached panel request rejected: source window is closing"); - return false; - } - - UIEditorWindowWorkspaceController windowWorkspaceController = - BuildWorkspaceMutationController(); - const UIEditorWindowWorkspaceOperationResult result = - windowWorkspaceController.OpenPanelInNewWindow(request.panelId); - if (result.status == UIEditorWindowWorkspaceOperationStatus::NoOp && - !result.targetWindowId.empty()) { - if (EditorWindow* existingWindow = m_hostRuntime.FindWindow(result.targetWindowId); - existingWindow != nullptr && - existingWindow->GetHwnd() != nullptr && - !existingWindow->IsClosing()) { - SetForegroundWindow(existingWindow->GetHwnd()); - } - - LogRuntimeTrace( - "window", - "open detached panel request reused existing window '" + - result.targetWindowId + "' for panel '" + request.panelId + "'"); - return true; - } - - if (result.status != UIEditorWindowWorkspaceOperationStatus::Changed) { - LogRuntimeTrace( - "window", - "open detached panel request rejected: " + result.message); - return false; - } - - if (!CommitWindowWorkspaceMutation( - windowWorkspaceController, - result.targetWindowId, - request.screenPoint, - request.preferredWidth, - request.preferredHeight)) { - LogRuntimeTrace("window", "failed to synchronize detached panel window state"); - return false; - } - - if (EditorWindow* detachedWindow = m_hostRuntime.FindWindow(result.targetWindowId); - detachedWindow != nullptr && - detachedWindow->GetHwnd() != nullptr && - !detachedWindow->IsClosing()) { - SetForegroundWindow(detachedWindow->GetHwnd()); - } - - LogRuntimeTrace( - "window", - "opened detached panel '" + request.panelId + "' in window '" + - result.targetWindowId + "'"); - return true; -} - void EditorWindowWorkspaceCoordinator::HandleWindowFrameTransferRequests( EditorWindow& sourceWindow, - EditorWindowFrameTransferRequests&& transferRequests) { + const EditorWindowFrameTransferRequests& transferRequests) { if (!m_globalTabDragSession.active && transferRequests.beginGlobalTabDrag.has_value() && transferRequests.beginGlobalTabDrag->IsValid()) { @@ -857,14 +766,6 @@ void EditorWindowWorkspaceCoordinator::HandleWindowFrameTransferRequests( transferRequests.detachPanel->IsValid()) { TryProcessDetachRequest(sourceWindow, *transferRequests.detachPanel); } - - if (!m_globalTabDragSession.active && - transferRequests.openDetachedPanel.has_value() && - transferRequests.openDetachedPanel->IsValid()) { - TryProcessOpenDetachedPanelRequest( - sourceWindow, - *transferRequests.openDetachedPanel); - } } EditorWindow* EditorWindowWorkspaceCoordinator::FindTopmostWindowAtScreenPoint( diff --git a/new_editor/app/Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.h b/new_editor/app/Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.h index 303a2367..40f954f6 100644 --- a/new_editor/app/Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.h +++ b/new_editor/app/Platform/Win32/WindowManager/EditorWindowWorkspaceCoordinator.h @@ -7,6 +7,8 @@ #include "Composition/EditorWindowWorkspaceStore.h" #include "Platform/Win32/EditorWindowTransferRequests.h" +#include + #include #include @@ -25,7 +27,7 @@ public: void BindLifecycleCoordinator(EditorWindowLifecycleCoordinator& lifecycleCoordinator); void RegisterExistingWindow(EditorWindow& window); - void CommitWindowProjection(EditorWindow& window); + void RefreshWindowPresentation(EditorWindow& window) const; bool IsPrimaryWindowId(std::string_view windowId) const; std::string DescribeWindowSet() const; void RemoveWindowProjection(std::string_view windowId, bool primary); @@ -37,7 +39,7 @@ public: bool HandleGlobalTabDragPointerButtonUp(HWND hwnd); void HandleWindowFrameTransferRequests( EditorWindow& sourceWindow, - EditorWindowFrameTransferRequests&& transferRequests); + const EditorWindowFrameTransferRequests& transferRequests); private: struct GlobalTabDragSession { @@ -68,10 +70,6 @@ private: std::wstring BuildWindowTitle( const UIEditorWorkspaceController& workspaceController) const; void RefreshWindowTitle(EditorWindow& window) const; - RECT BuildDetachedWindowRect( - const POINT& screenPoint, - LONG preferredWidth = 0, - LONG preferredHeight = 0) const; void BeginGlobalTabDragSession( std::string_view panelWindowId, std::string_view sourceNodeId, @@ -99,9 +97,6 @@ private: bool TryProcessDetachRequest( EditorWindow& sourceWindow, const EditorWindowPanelTransferRequest& request); - bool TryProcessOpenDetachedPanelRequest( - EditorWindow& sourceWindow, - const EditorWindowOpenDetachedPanelRequest& request); void LogRuntimeTrace(std::string_view channel, std::string_view message) const; EditorWindowHostRuntime& m_hostRuntime; diff --git a/new_editor/app/State/EditorColorPickerToolState.cpp b/new_editor/app/State/EditorColorPickerToolState.cpp index a09bb904..03189bf0 100644 --- a/new_editor/app/State/EditorColorPickerToolState.cpp +++ b/new_editor/app/State/EditorColorPickerToolState.cpp @@ -29,17 +29,17 @@ void OpenEditorColorPickerToolForInspectorField( bool showAlpha) { state.active = true; state.showAlpha = showAlpha; - state.requestOpenDetachedPanel = true; + state.requestOpenUtilityWindow = true; state.color = color; state.inspectorTarget.subjectKey = std::string(subjectKey); state.inspectorTarget.fieldId = std::string(fieldId); ++state.revision; } -bool ConsumeEditorColorPickerOpenDetachedPanelRequest( +bool ConsumeEditorColorPickerOpenUtilityWindowRequest( EditorColorPickerToolState& state) { - const bool requested = state.requestOpenDetachedPanel; - state.requestOpenDetachedPanel = false; + const bool requested = state.requestOpenUtilityWindow; + state.requestOpenUtilityWindow = false; return requested; } diff --git a/new_editor/app/State/EditorColorPickerToolState.h b/new_editor/app/State/EditorColorPickerToolState.h index 07eb93cf..9f73d84f 100644 --- a/new_editor/app/State/EditorColorPickerToolState.h +++ b/new_editor/app/State/EditorColorPickerToolState.h @@ -16,7 +16,7 @@ struct EditorColorPickerInspectorTarget { struct EditorColorPickerToolState { bool active = false; bool showAlpha = true; - bool requestOpenDetachedPanel = false; + bool requestOpenUtilityWindow = false; ::XCEngine::UI::UIColor color = {}; EditorColorPickerInspectorTarget inspectorTarget = {}; std::uint64_t revision = 0u; @@ -29,7 +29,7 @@ void OpenEditorColorPickerToolForInspectorField( std::string_view fieldId, const ::XCEngine::UI::UIColor& color, bool showAlpha); -bool ConsumeEditorColorPickerOpenDetachedPanelRequest( +bool ConsumeEditorColorPickerOpenUtilityWindowRequest( EditorColorPickerToolState& state); bool UpdateEditorColorPickerToolColor( EditorColorPickerToolState& state, diff --git a/new_editor/include/XCEditor/Panels/UIEditorPanelRegistry.h b/new_editor/include/XCEditor/Panels/UIEditorPanelRegistry.h index 5e1bb647..83e9d6f2 100644 --- a/new_editor/include/XCEditor/Panels/UIEditorPanelRegistry.h +++ b/new_editor/include/XCEditor/Panels/UIEditorPanelRegistry.h @@ -23,8 +23,6 @@ struct UIEditorPanelDescriptor { bool placeholder = true; bool canHide = true; bool canClose = true; - bool toolWindow = false; - ::XCEngine::UI::UISize preferredDetachedWindowSize = {}; ::XCEngine::UI::UISize minimumDetachedWindowSize = {}; UIEditorViewportShellSpec viewportShellSpec = {}; }; diff --git a/new_editor/include/XCEditor/Workspace/UIEditorDetachedWindowPolicy.h b/new_editor/include/XCEditor/Workspace/UIEditorDetachedWindowPolicy.h index 7bafd0b2..8d7fc113 100644 --- a/new_editor/include/XCEditor/Workspace/UIEditorDetachedWindowPolicy.h +++ b/new_editor/include/XCEditor/Workspace/UIEditorDetachedWindowPolicy.h @@ -14,9 +14,6 @@ const UIEditorPanelDescriptor* ResolveUIEditorSingleVisibleRootPanelDescriptor( bool HasUIEditorSingleVisibleRootTab( const UIEditorWorkspaceController& controller); -bool IsUIEditorDetachedWorkspaceToolWindow( - const UIEditorWorkspaceController& controller); - std::string ResolveUIEditorDetachedWorkspaceTitle( const UIEditorWorkspaceController& controller, std::string_view fallbackTitle = {}); @@ -25,14 +22,4 @@ std::string ResolveUIEditorDetachedWorkspaceTitle( const UIEditorWorkspaceController& controller, const ::XCEngine::UI::UISize& fallbackSize = ::XCEngine::UI::UISize(640.0f, 360.0f)); -::XCEngine::UI::UISize ResolveUIEditorDetachedToolWindowMinimumContentSize( - const UIEditorWorkspaceController& controller, - const ::XCEngine::UI::UISize& fallbackContentSize, - float detachedWindowChromeHeight = 0.0f); - -::XCEngine::UI::UISize ResolveUIEditorDetachedPanelPreferredWindowSize( - const UIEditorPanelRegistry& panelRegistry, - std::string_view panelId, - const ::XCEngine::UI::UISize& fallbackSize = {}); - } // namespace XCEngine::UI::Editor diff --git a/new_editor/include/XCEditor/Workspace/UIEditorWindowWorkspaceController.h b/new_editor/include/XCEditor/Workspace/UIEditorWindowWorkspaceController.h index 7a807db6..70ae3014 100644 --- a/new_editor/include/XCEditor/Workspace/UIEditorWindowWorkspaceController.h +++ b/new_editor/include/XCEditor/Workspace/UIEditorWindowWorkspaceController.h @@ -52,10 +52,6 @@ public: std::string_view panelId, std::string_view preferredNewWindowId = {}); - UIEditorWindowWorkspaceOperationResult OpenPanelInNewWindow( - std::string_view panelId, - std::string_view preferredNewWindowId = {}); - UIEditorWindowWorkspaceOperationResult MovePanelToStack( std::string_view sourceWindowId, std::string_view sourceNodeId, diff --git a/new_editor/src/Workspace/UIEditorDetachedWindowPolicy.cpp b/new_editor/src/Workspace/UIEditorDetachedWindowPolicy.cpp index e9788eaa..12006a98 100644 --- a/new_editor/src/Workspace/UIEditorDetachedWindowPolicy.cpp +++ b/new_editor/src/Workspace/UIEditorDetachedWindowPolicy.cpp @@ -51,17 +51,6 @@ bool HasUIEditorSingleVisibleRootTab( return ResolveUIEditorSingleVisibleRootPanelDescriptor(controller) != nullptr; } -bool IsUIEditorDetachedWorkspaceToolWindow( - const UIEditorWorkspaceController& controller) { - if (const UIEditorPanelDescriptor* descriptor = - ResolveUIEditorSingleVisibleRootPanelDescriptor(controller); - descriptor != nullptr) { - return descriptor->toolWindow; - } - - return false; -} - std::string ResolveUIEditorDetachedWorkspaceTitle( const UIEditorWorkspaceController& controller, std::string_view fallbackTitle) { @@ -90,40 +79,4 @@ std::string ResolveUIEditorDetachedWorkspaceTitle( return fallbackSize; } -::XCEngine::UI::UISize ResolveUIEditorDetachedToolWindowMinimumContentSize( - const UIEditorWorkspaceController& controller, - const ::XCEngine::UI::UISize& fallbackContentSize, - float detachedWindowChromeHeight) { - if (const UIEditorPanelDescriptor* descriptor = - ResolveUIEditorSingleVisibleRootPanelDescriptor(controller); - descriptor != nullptr && descriptor->toolWindow) { - const float minimumContentWidth = - descriptor->minimumDetachedWindowSize.width > 0.0f - ? descriptor->minimumDetachedWindowSize.width - : fallbackContentSize.width; - const float minimumContentHeight = - descriptor->minimumDetachedWindowSize.height > detachedWindowChromeHeight - ? descriptor->minimumDetachedWindowSize.height - detachedWindowChromeHeight - : fallbackContentSize.height; - return ::XCEngine::UI::UISize(minimumContentWidth, minimumContentHeight); - } - - return fallbackContentSize; -} - -::XCEngine::UI::UISize ResolveUIEditorDetachedPanelPreferredWindowSize( - const UIEditorPanelRegistry& panelRegistry, - std::string_view panelId, - const ::XCEngine::UI::UISize& fallbackSize) { - const UIEditorPanelDescriptor* descriptor = - FindUIEditorPanelDescriptor(panelRegistry, panelId); - if (descriptor == nullptr || - descriptor->preferredDetachedWindowSize.width <= 0.0f || - descriptor->preferredDetachedWindowSize.height <= 0.0f) { - return fallbackSize; - } - - return descriptor->preferredDetachedWindowSize; -} - } // namespace XCEngine::UI::Editor diff --git a/new_editor/src/Workspace/UIEditorWindowWorkspaceController.cpp b/new_editor/src/Workspace/UIEditorWindowWorkspaceController.cpp index b89470b3..5c6b2395 100644 --- a/new_editor/src/Workspace/UIEditorWindowWorkspaceController.cpp +++ b/new_editor/src/Workspace/UIEditorWindowWorkspaceController.cpp @@ -63,18 +63,6 @@ bool TryExtractPanelFromWindow( extractedPanel); } -const UIEditorWindowWorkspaceState* FindWindowOwningPanel( - const UIEditorWindowWorkspaceSet& windowSet, - std::string_view panelId) { - for (const UIEditorWindowWorkspaceState& state : windowSet.windows) { - if (FindUIEditorPanelSessionState(state.session, panelId) != nullptr) { - return &state; - } - } - - return nullptr; -} - } // namespace std::string_view GetUIEditorWindowWorkspaceOperationStatusName( @@ -228,87 +216,6 @@ UIEditorWindowWorkspaceOperationResult UIEditorWindowWorkspaceController::Detach panelId); } -UIEditorWindowWorkspaceOperationResult UIEditorWindowWorkspaceController::OpenPanelInNewWindow( - std::string_view panelId, - std::string_view preferredNewWindowId) { - const UIEditorWindowWorkspaceValidationResult stateValidation = ValidateState(); - if (!stateValidation.IsValid()) { - return BuildOperationResult( - UIEditorWindowWorkspaceOperationStatus::Rejected, - "Window workspace state invalid: " + stateValidation.message, - {}, - {}, - panelId); - } - - const UIEditorPanelDescriptor* descriptor = - FindUIEditorPanelDescriptor(m_panelRegistry, panelId); - if (descriptor == nullptr) { - return BuildOperationResult( - UIEditorWindowWorkspaceOperationStatus::Rejected, - "Panel is missing from the panel registry.", - {}, - {}, - panelId); - } - - if (const UIEditorWindowWorkspaceState* existingWindow = - FindWindowOwningPanel(m_windowSet, panelId); - existingWindow != nullptr) { - return BuildOperationResult( - UIEditorWindowWorkspaceOperationStatus::NoOp, - "Panel is already open in a window.", - existingWindow->windowId, - existingWindow->windowId, - panelId); - } - - UIEditorWorkspaceExtractedPanel extractedPanel = {}; - extractedPanel.panelNode = BuildUIEditorWorkspacePanel( - std::string(panelId) + "-panel", - descriptor->panelId, - descriptor->defaultTitle, - descriptor->placeholder); - extractedPanel.sessionState.panelId = descriptor->panelId; - extractedPanel.sessionState.open = true; - extractedPanel.sessionState.visible = true; - - const std::string newWindowId = MakeUniqueWindowId( - preferredNewWindowId.empty() - ? std::string(panelId) + "-window" - : std::string(preferredNewWindowId)); - const std::string previousActiveWindowId = m_windowSet.activeWindowId; - UIEditorWindowWorkspaceState detachedWindow = {}; - detachedWindow.windowId = newWindowId; - detachedWindow.workspace = - BuildUIEditorDetachedWorkspaceFromExtractedPanel( - newWindowId + "-root", - extractedPanel); - detachedWindow.session = - BuildUIEditorDetachedWorkspaceSessionFromExtractedPanel(extractedPanel); - m_windowSet.windows.push_back(std::move(detachedWindow)); - m_windowSet.activeWindowId = newWindowId; - - const UIEditorWindowWorkspaceValidationResult validation = ValidateState(); - if (!validation.IsValid()) { - m_windowSet.windows.pop_back(); - m_windowSet.activeWindowId = previousActiveWindowId; - return BuildOperationResult( - UIEditorWindowWorkspaceOperationStatus::Rejected, - "OpenPanelInNewWindow produced invalid state: " + validation.message, - {}, - newWindowId, - panelId); - } - - return BuildOperationResult( - UIEditorWindowWorkspaceOperationStatus::Changed, - "Panel opened in a new detached window.", - {}, - newWindowId, - panelId); -} - UIEditorWindowWorkspaceOperationResult UIEditorWindowWorkspaceController::MovePanelToStack( std::string_view sourceWindowId, std::string_view sourceNodeId,