#pragma once #ifndef NOMINMAX #define NOMINMAX #endif #include "State/EditorContext.h" #include "Platform/Win32/EditorWindowState.h" #include #include #include #include #include #include #include namespace XCEngine::UI::Editor::App { struct EditorWindowPendingTabDragStart { std::string nodeId = {}; std::string panelId = {}; POINT screenPoint = {}; }; struct EditorWindowPendingDetachRequest { std::string nodeId = {}; std::string panelId = {}; POINT screenPoint = {}; }; class EditorWindow { public: EditorWindow( std::string windowId, std::wstring title, bool primary, UIEditorWorkspaceController workspaceController); EditorWindow(const EditorWindow&) = delete; EditorWindow& operator=(const EditorWindow&) = delete; EditorWindow(EditorWindow&&) = delete; EditorWindow& operator=(EditorWindow&&) = delete; std::string_view GetWindowId() const; HWND GetHwnd() const; bool HasHwnd() const; bool IsPrimary() const; bool IsRenderReady() const; bool IsTrackingMouseLeave() const; bool HasHoveredBorderlessResizeEdge() const; const std::wstring& GetTitle() const; const UIEditorWorkspaceController& GetWorkspaceController() const; UIEditorWorkspaceController& GetWorkspaceController(); const EditorShellRuntime& GetShellRuntime() const; EditorShellRuntime& GetShellRuntime(); const UIEditorShellInteractionFrame& GetShellFrame() const; const UIEditorShellInteractionState& GetShellInteractionState() const; ::XCEngine::UI::UIPoint ConvertScreenPixelsToClientDips(const POINT& screenPoint) const; void InvalidateHostWindow() const; void AttachHwnd(HWND hwnd); void MarkDestroyed(); void SetTrackingMouseLeave(bool trackingMouseLeave); void SetTitle(std::wstring title); void ReplaceWorkspaceController(UIEditorWorkspaceController workspaceController); bool Initialize( const std::filesystem::path& repoRoot, EditorContext& editorContext, const std::filesystem::path& captureRoot, bool autoCaptureOnStartup); void Shutdown(); void ResetInteractionState(); std::optional ConsumePendingTabDragStart(); std::optional ConsumeDetachRequest(); void RenderFrame( EditorContext& editorContext, bool globalTabDragActive); void OnPaintMessage( EditorContext& editorContext, bool globalTabDragActive); void OnResize(UINT width, UINT height); void OnEnterSizeMove(); void OnExitSizeMove(); void OnDpiChanged(UINT dpi, const RECT& suggestedRect); bool IsBorderlessWindowEnabled() const; bool IsBorderlessWindowMaximized() const; bool HandleBorderlessWindowSystemCommand( EditorContext& editorContext, bool globalTabDragActive, WPARAM wParam); bool HandleBorderlessWindowGetMinMaxInfo(LPARAM lParam) const; LRESULT HandleBorderlessWindowNcCalcSize(WPARAM wParam, LPARAM lParam) const; bool ApplyCurrentCursor() const; bool UpdateBorderlessWindowResizeHover(LPARAM lParam); bool HandleBorderlessWindowResizeButtonDown(LPARAM lParam); bool HandleBorderlessWindowResizeButtonUp(); bool HandleBorderlessWindowResizePointerMove( EditorContext& editorContext, bool globalTabDragActive); void ClearBorderlessWindowResizeState(); void ForceClearBorderlessWindowResizeState(); Host::BorderlessWindowChromeHitTarget HitTestBorderlessWindowChrome(LPARAM lParam) const; bool UpdateBorderlessWindowChromeHover(LPARAM lParam); bool HandleBorderlessWindowChromeButtonDown(LPARAM lParam); bool HandleBorderlessWindowChromeButtonUp( EditorContext& editorContext, bool globalTabDragActive, LPARAM lParam); bool HandleBorderlessWindowChromeDoubleClick( EditorContext& editorContext, bool globalTabDragActive, LPARAM lParam); bool HandleBorderlessWindowChromeDragRestorePointerMove( EditorContext& editorContext, bool globalTabDragActive); void ClearBorderlessWindowChromeDragRestoreState(); void ClearBorderlessWindowChromeState(); bool HasInteractiveCaptureState() const; void QueuePointerEvent( ::XCEngine::UI::UIInputEventType type, ::XCEngine::UI::UIPointerButton button, WPARAM wParam, LPARAM lParam); void QueuePointerLeaveEvent(); void QueuePointerWheelEvent(short wheelDelta, WPARAM wParam, LPARAM lParam); void QueueKeyEvent(::XCEngine::UI::UIInputEventType type, WPARAM wParam, LPARAM lParam); void QueueCharacterEvent(WPARAM wParam, LPARAM lParam); void QueueWindowFocusEvent(::XCEngine::UI::UIInputEventType type); void SyncInputModifiersFromSystemState(); void ResetInputModifiers(); void RequestManualScreenshot(); private: bool ApplyWindowResize(UINT width, UINT height); bool QueryCurrentClientPixelSize(UINT& outWidth, UINT& outHeight) const; bool ResolveRenderClientPixelSize(UINT& outWidth, UINT& outHeight) const; ::XCEngine::UI::UIRect ResolveWorkspaceBounds( float clientWidthDips, float clientHeightDips) const; void RenderRuntimeFrame( EditorContext& editorContext, bool globalTabDragActive, const ::XCEngine::UI::UIRect& workspaceBounds, ::XCEngine::UI::UIDrawList& drawList); void RenderInvalidFrame( EditorContext& editorContext, ::XCEngine::UI::UIDrawList& drawList) const; void LogFrameInteractionTrace( EditorContext& editorContext, const std::vector<::XCEngine::UI::UIInputEvent>& frameEvents, const UIEditorShellInteractionFrame& shellFrame) const; void QueueShellTransferRequests( bool globalTabDragActive, const UIEditorDockHostInteractionState& dockHostInteractionState, const UIEditorShellInteractionFrame& shellFrame); bool IsPointerInsideClientArea() const; LPCWSTR ResolveCurrentCursorResource() const; float GetDpiScale() const; float PixelsToDips(float pixels) const; ::XCEngine::UI::UIPoint ConvertClientPixelsToDips(LONG x, LONG y) const; std::string BuildCaptureStatusText() const; void ApplyHostCaptureRequests(const UIEditorShellInteractionResult& result); void ApplyHostedContentCaptureRequests(); std::string DescribeInputEvents( const std::vector<::XCEngine::UI::UIInputEvent>& events) const; Host::BorderlessWindowResizeEdge HitTestBorderlessWindowResizeEdge(LPARAM lParam) const; void ApplyBorderlessWindowResizeCursorHoverPriority(); Host::BorderlessWindowChromeLayout ResolveBorderlessWindowChromeLayout( float clientWidthDips) const; bool QueryCurrentWindowRect(RECT& outRect) const; bool QueryBorderlessWindowWorkAreaRect(RECT& outRect) const; bool ApplyPredictedWindowRectTransition( EditorContext& editorContext, bool globalTabDragActive, const RECT& targetRect); bool ShouldUseDetachedTitleBarTabStrip() const; void ToggleBorderlessWindowMaximizeRestore( EditorContext& editorContext, bool globalTabDragActive); void AppendBorderlessWindowChrome( ::XCEngine::UI::UIDrawList& drawList, float clientWidthDips) const; void ExecuteBorderlessWindowChromeAction( EditorContext& editorContext, bool globalTabDragActive, Host::BorderlessWindowChromeHitTarget target); void QueuePendingTabDragStart(std::string_view nodeId, std::string_view panelId); void QueuePendingDetachRequest(std::string_view nodeId, std::string_view panelId); void UpdateCachedTitleText(); static bool IsVerboseRuntimeTraceEnabled(); EditorWindowWindowState m_window = {}; EditorWindowRenderState m_render = {}; EditorWindowInputState m_input = {}; EditorWindowCompositionState m_composition = {}; EditorWindowChromeRuntimeState m_chrome = {}; EditorWindowPanelTransferState m_pendingDetachRequest = {}; EditorWindowPanelTransferState m_pendingTabDragStart = {}; }; } // namespace XCEngine::UI::Editor::App