256 lines
11 KiB
C++
256 lines
11 KiB
C++
#pragma once
|
|
|
|
#ifndef NOMINMAX
|
|
#define NOMINMAX
|
|
#endif
|
|
|
|
#include <Host/AutoScreenshot.h>
|
|
#include <Host/BorderlessWindowChrome.h>
|
|
#include <Host/BorderlessWindowFrame.h>
|
|
#include <Host/D3D12WindowRenderer.h>
|
|
#include <Host/D3D12WindowRenderLoop.h>
|
|
#include <Host/HostRuntimeState.h>
|
|
#include <Host/InputModifierTracker.h>
|
|
#include <Host/NativeRenderer.h>
|
|
|
|
#include "Core/ProductEditorContext.h"
|
|
#include "Workspace/ProductEditorWorkspace.h"
|
|
|
|
#include <XCEditor/Shell/UIEditorShellInteraction.h>
|
|
#include <XCEditor/Shell/UIEditorWindowWorkspaceController.h>
|
|
#include <XCEditor/Shell/UIEditorWorkspaceController.h>
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
|
|
#include <cstdint>
|
|
#include <filesystem>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
namespace XCEngine::UI::Editor::Host {
|
|
class WindowMessageDispatcher;
|
|
}
|
|
|
|
namespace XCEngine::UI::Editor {
|
|
|
|
class Application {
|
|
public:
|
|
Application();
|
|
~Application();
|
|
|
|
Application(const Application&) = delete;
|
|
Application& operator=(const Application&) = delete;
|
|
Application(Application&&) = delete;
|
|
Application& operator=(Application&&) = delete;
|
|
|
|
int Run(HINSTANCE hInstance, int nCmdShow);
|
|
|
|
private:
|
|
struct ManagedWindowState {
|
|
HWND hwnd = nullptr;
|
|
std::string windowId = {};
|
|
std::wstring title = {};
|
|
bool primary = false;
|
|
::XCEngine::UI::Editor::Host::NativeRenderer renderer = {};
|
|
::XCEngine::UI::Editor::Host::D3D12WindowRenderer windowRenderer = {};
|
|
::XCEngine::UI::Editor::Host::D3D12WindowRenderLoop windowRenderLoop = {};
|
|
::XCEngine::UI::Editor::Host::AutoScreenshotController autoScreenshot = {};
|
|
::XCEngine::UI::Editor::Host::InputModifierTracker inputModifierTracker = {};
|
|
UIEditorWorkspaceController workspaceController = {};
|
|
App::ProductEditorWorkspace editorWorkspace = {};
|
|
std::vector<::XCEngine::UI::UIInputEvent> pendingInputEvents = {};
|
|
bool trackingMouseLeave = false;
|
|
bool renderReady = false;
|
|
::XCEngine::UI::UITextureHandle titleBarLogoIcon = {};
|
|
::XCEngine::UI::Editor::Host::BorderlessWindowChromeState borderlessWindowChromeState = {};
|
|
::XCEngine::UI::Editor::Host::HostRuntimeState hostRuntime = {};
|
|
bool detachRequested = false;
|
|
std::string detachedNodeId = {};
|
|
std::string detachedPanelId = {};
|
|
POINT detachScreenPoint = {};
|
|
bool pendingGlobalTabDragStart = false;
|
|
std::string pendingGlobalTabDragNodeId = {};
|
|
std::string pendingGlobalTabDragPanelId = {};
|
|
POINT pendingGlobalTabDragScreenPoint = {};
|
|
POINT pendingGlobalTabDragWindowOffset = {};
|
|
};
|
|
struct GlobalTabDragSession {
|
|
bool active = false;
|
|
std::string panelWindowId = {};
|
|
std::string sourceNodeId = {};
|
|
std::string panelId = {};
|
|
POINT screenPoint = {};
|
|
POINT windowDragOffset = {};
|
|
};
|
|
struct ManagedWindowCreateParams {
|
|
std::string windowId = {};
|
|
std::wstring title = {};
|
|
int initialX = CW_USEDEFAULT;
|
|
int initialY = CW_USEDEFAULT;
|
|
int initialWidth = 1540;
|
|
int initialHeight = 940;
|
|
int showCommand = SW_SHOW;
|
|
bool primary = false;
|
|
bool autoCaptureOnStartup = false;
|
|
};
|
|
|
|
friend class ::XCEngine::UI::Editor::Host::WindowMessageDispatcher;
|
|
|
|
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
|
|
bool Initialize(HINSTANCE hInstance, int nCmdShow);
|
|
void Shutdown();
|
|
bool RegisterWindowClass();
|
|
ManagedWindowState* CreateManagedWindow(
|
|
UIEditorWorkspaceController workspaceController,
|
|
const ManagedWindowCreateParams& params);
|
|
void DestroyManagedWindow(ManagedWindowState& windowState);
|
|
void DestroyClosedWindows();
|
|
void RenderAllWindows();
|
|
void ProcessPendingGlobalTabDragStarts();
|
|
void ProcessPendingDetachRequests();
|
|
bool TryStartGlobalTabDrag(ManagedWindowState& sourceWindowState);
|
|
bool TryProcessDetachRequest(ManagedWindowState& sourceWindowState);
|
|
UIEditorWindowWorkspaceSet BuildWindowWorkspaceSet(std::string_view activeWindowId = {}) const;
|
|
bool SynchronizeManagedWindowsFromWindowSet(
|
|
const UIEditorWindowWorkspaceSet& windowSet,
|
|
std::string_view preferredNewWindowId,
|
|
const POINT& preferredScreenPoint);
|
|
UIEditorWorkspaceController BuildWorkspaceControllerForWindow(
|
|
const UIEditorWindowWorkspaceState& windowState) const;
|
|
std::wstring BuildManagedWindowTitle(const UIEditorWorkspaceController& workspaceController) const;
|
|
RECT BuildDetachedWindowRect(const POINT& screenPoint) const;
|
|
void ResetManagedWindowInteractionState(ManagedWindowState& windowState);
|
|
void HandleDestroyedWindow(HWND hwnd);
|
|
void BeginGlobalTabDragSession(
|
|
std::string_view panelWindowId,
|
|
std::string_view sourceNodeId,
|
|
std::string_view panelId,
|
|
const POINT& screenPoint,
|
|
const POINT& windowDragOffset);
|
|
void EndGlobalTabDragSession();
|
|
bool HandleGlobalTabDragPointerMove(HWND hwnd);
|
|
bool HandleGlobalTabDragPointerButtonUp(HWND hwnd);
|
|
ManagedWindowState* FindTopmostWindowStateAtScreenPoint(
|
|
const POINT& screenPoint,
|
|
std::string_view excludedWindowId = {});
|
|
const ManagedWindowState* FindTopmostWindowStateAtScreenPoint(
|
|
const POINT& screenPoint,
|
|
std::string_view excludedWindowId = {}) const;
|
|
ManagedWindowState* FindWindowState(HWND hwnd);
|
|
const ManagedWindowState* FindWindowState(HWND hwnd) const;
|
|
ManagedWindowState* FindWindowState(std::string_view windowId);
|
|
const ManagedWindowState* FindWindowState(std::string_view windowId) const;
|
|
ManagedWindowState* FindPrimaryWindowState();
|
|
const ManagedWindowState* FindPrimaryWindowState() const;
|
|
ManagedWindowState& RequireCurrentWindowState();
|
|
const ManagedWindowState& RequireCurrentWindowState() const;
|
|
|
|
void RenderFrame();
|
|
void OnPaintMessage();
|
|
void OnResize(UINT width, UINT height);
|
|
void OnEnterSizeMove();
|
|
void OnExitSizeMove();
|
|
void OnDpiChanged(UINT dpi, const RECT& suggestedRect);
|
|
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;
|
|
bool IsPointerInsideClientArea() const;
|
|
bool ApplyCurrentCursor() const;
|
|
LPCWSTR ResolveCurrentCursorResource() const;
|
|
float GetDpiScale() const;
|
|
float PixelsToDips(float pixels) const;
|
|
bool HasBorderlessWindowChrome() const;
|
|
::XCEngine::UI::UIPoint ConvertClientPixelsToDips(LONG x, LONG y) const;
|
|
::XCEngine::UI::UIPoint ConvertScreenPixelsToClientDips(
|
|
const ManagedWindowState& windowState,
|
|
const POINT& screenPoint) const;
|
|
POINT ConvertClientDipsToScreenPixels(
|
|
const ManagedWindowState& windowState,
|
|
const ::XCEngine::UI::UIPoint& point) const;
|
|
bool TryResolveDraggedTabScreenRect(
|
|
const ManagedWindowState& windowState,
|
|
std::string_view nodeId,
|
|
std::string_view panelId,
|
|
RECT& outRect) const;
|
|
POINT ResolveGlobalTabDragWindowOffset(
|
|
const ManagedWindowState& windowState,
|
|
std::string_view nodeId,
|
|
std::string_view panelId,
|
|
const POINT& screenPoint) const;
|
|
void MoveGlobalTabDragWindow(ManagedWindowState& windowState, const POINT& screenPoint) const;
|
|
void AppendGlobalTabDragDropPreview(::XCEngine::UI::UIDrawList& drawList) const;
|
|
std::string BuildCaptureStatusText() const;
|
|
void LogRuntimeTrace(std::string_view channel, std::string_view message) const;
|
|
void ApplyHostCaptureRequests(const UIEditorShellInteractionResult& result);
|
|
void ApplyHostedContentCaptureRequests();
|
|
bool HasInteractiveCaptureState() const;
|
|
std::string DescribeInputEvents(
|
|
const std::vector<::XCEngine::UI::UIInputEvent>& events) 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);
|
|
bool IsBorderlessWindowEnabled() const;
|
|
bool IsBorderlessWindowMaximized() const;
|
|
bool HandleBorderlessWindowSystemCommand(WPARAM wParam);
|
|
bool HandleBorderlessWindowGetMinMaxInfo(LPARAM lParam) const;
|
|
LRESULT HandleBorderlessWindowNcCalcSize(WPARAM wParam, LPARAM lParam) const;
|
|
Host::BorderlessWindowChromeHitTarget HitTestBorderlessWindowChrome(LPARAM lParam) const;
|
|
bool UpdateBorderlessWindowChromeHover(LPARAM lParam);
|
|
bool HandleBorderlessWindowChromeButtonDown(LPARAM lParam);
|
|
bool HandleBorderlessWindowChromeButtonUp(LPARAM lParam);
|
|
bool HandleBorderlessWindowChromeDoubleClick(LPARAM lParam);
|
|
bool HandleBorderlessWindowChromeDragRestorePointerMove();
|
|
void ClearBorderlessWindowChromeDragRestoreState();
|
|
void ClearBorderlessWindowChromeState();
|
|
Host::BorderlessWindowResizeEdge HitTestBorderlessWindowResizeEdge(LPARAM lParam) const;
|
|
bool UpdateBorderlessWindowResizeHover(LPARAM lParam);
|
|
bool HandleBorderlessWindowResizeButtonDown(LPARAM lParam);
|
|
bool HandleBorderlessWindowResizeButtonUp();
|
|
bool HandleBorderlessWindowResizePointerMove();
|
|
void ClearBorderlessWindowResizeState();
|
|
void ForceClearBorderlessWindowResizeState();
|
|
void ApplyBorderlessWindowResizeCursorHoverPriority();
|
|
bool QueryCurrentWindowRect(RECT& outRect) const;
|
|
bool QueryBorderlessWindowWorkAreaRect(RECT& outRect) const;
|
|
bool ApplyPredictedWindowRectTransition(const RECT& targetRect);
|
|
void ToggleBorderlessWindowMaximizeRestore();
|
|
void AppendBorderlessWindowChrome(
|
|
::XCEngine::UI::UIDrawList& drawList,
|
|
float clientWidthDips) const;
|
|
void ExecuteBorderlessWindowChromeAction(Host::BorderlessWindowChromeHitTarget target);
|
|
Host::BorderlessWindowChromeLayout ResolveBorderlessWindowChromeLayout(
|
|
float clientWidthDips) const;
|
|
void InvalidateHostWindow() const;
|
|
static std::filesystem::path ResolveRepoRootPath();
|
|
static LONG WINAPI HandleUnhandledException(EXCEPTION_POINTERS* exceptionInfo);
|
|
static bool IsVerboseRuntimeTraceEnabled();
|
|
|
|
HINSTANCE m_hInstance = nullptr;
|
|
ATOM m_windowClassAtom = 0;
|
|
std::filesystem::path m_repoRoot = {};
|
|
App::ProductEditorContext m_editorContext = {};
|
|
std::vector<std::unique_ptr<ManagedWindowState>> m_windows = {};
|
|
GlobalTabDragSession m_globalTabDragSession = {};
|
|
ManagedWindowState* m_currentWindowState = nullptr;
|
|
ManagedWindowState* m_pendingCreateWindowState = nullptr;
|
|
bool m_shutdownRequested = false;
|
|
};
|
|
|
|
int RunXCUIEditorApp(HINSTANCE hInstance, int nCmdShow);
|
|
|
|
} // namespace XCEngine::UI::Editor
|