Files
XCEngine/new_editor/app/Platform/Win32/EditorWindowFrame.cpp

230 lines
7.4 KiB
C++

#include "Platform/Win32/EditorWindow.h"
#include "Platform/Win32/EditorWindowConstants.h"
#include "Platform/Win32/EditorWindowFrameOrchestrator.h"
#include "Platform/Win32/EditorWindowInputController.h"
#include "Platform/Win32/EditorWindowInternalState.h"
#include "Platform/Win32/EditorWindowRuntimeController.h"
#include "Platform/Win32/EditorWindowRuntimeInternal.h"
#include "Platform/Win32/EditorWindowStyle.h"
#include "Composition/EditorShellPointerInteraction.h"
#include "Composition/EditorContext.h"
#include <algorithm>
#include <XCEngine/UI/DrawData.h>
#include <cstdint>
#include <utility>
namespace XCEngine::UI::Editor::App {
using namespace EditorWindowInternal;
using ::XCEngine::UI::UIDrawData;
using ::XCEngine::UI::UIDrawList;
using ::XCEngine::UI::UIInputEvent;
using ::XCEngine::UI::UIInputModifiers;
using ::XCEngine::UI::UIPointerButton;
using ::XCEngine::UI::UIRect;
namespace {
std::uint8_t ButtonMask(UIPointerButton button) {
switch (button) {
case UIPointerButton::Left: return 1u << 0u;
case UIPointerButton::Right: return 1u << 1u;
case UIPointerButton::Middle: return 1u << 2u;
case UIPointerButton::X1: return 1u << 3u;
case UIPointerButton::X2: return 1u << 4u;
case UIPointerButton::None:
default:
return 0u;
}
}
std::uint8_t ButtonMaskFromModifiers(const UIInputModifiers& modifiers) {
std::uint8_t mask = 0u;
if (modifiers.leftMouse) {
mask |= ButtonMask(UIPointerButton::Left);
}
if (modifiers.rightMouse) {
mask |= ButtonMask(UIPointerButton::Right);
}
if (modifiers.middleMouse) {
mask |= ButtonMask(UIPointerButton::Middle);
}
if (modifiers.x1Mouse) {
mask |= ButtonMask(UIPointerButton::X1);
}
if (modifiers.x2Mouse) {
mask |= ButtonMask(UIPointerButton::X2);
}
return mask;
}
std::uint8_t ResolveExpectedShellCaptureButtons(
const EditorShellRuntime& shellRuntime) {
std::uint8_t expectedButtons = 0u;
const auto& shellState = shellRuntime.GetShellInteractionState();
const auto& dockHostState =
shellState.workspaceInteractionState.dockHostInteractionState;
if (dockHostState.splitterDragState.active ||
!dockHostState.activeTabDragNodeId.empty()) {
expectedButtons |= ButtonMask(UIPointerButton::Left);
}
for (const auto& panelState :
shellState.workspaceInteractionState.composeState.panelStates) {
const auto& inputBridgeState = panelState.viewportShellState.inputBridgeState;
if (inputBridgeState.captured) {
expectedButtons |= ButtonMask(inputBridgeState.captureButton);
}
}
return expectedButtons;
}
} // namespace
EditorWindowFrameTransferRequests EditorWindow::RenderFrame(
EditorContext& editorContext,
bool globalTabDragActive) {
if (!m_runtime->IsReady() || m_state->window.hwnd == nullptr) {
return {};
}
UINT pixelWidth = 0u;
UINT pixelHeight = 0u;
if (!ResolveRenderClientPixelSize(pixelWidth, pixelHeight)) {
return {};
}
const float width = PixelsToDips(static_cast<float>(pixelWidth));
const float height = PixelsToDips(static_cast<float>(pixelHeight));
const UIRect workspaceBounds = ResolveWorkspaceBounds(width, height);
UIDrawData drawData = {};
UIDrawList& drawList = drawData.EmplaceDrawList("XCEditorShell");
drawList.AddFilledRect(
UIRect(0.0f, 0.0f, width, height),
kShellSurfaceColor);
EditorWindowFrameTransferRequests transferRequests = {};
if (editorContext.IsValid()) {
transferRequests =
RenderRuntimeFrame(editorContext, globalTabDragActive, workspaceBounds, drawList);
} else {
m_frameOrchestrator->AppendInvalidFrame(editorContext, drawList);
}
AppendBorderlessWindowChrome(drawList, width);
const Host::D3D12WindowRenderLoopPresentResult presentResult = m_runtime->Present(drawData);
if (!presentResult.warning.empty()) {
LogRuntimeTrace("present", presentResult.warning);
}
m_runtime->CaptureIfRequested(
drawData,
pixelWidth,
pixelHeight,
presentResult.framePresented);
return transferRequests;
}
EditorWindowFrameTransferRequests EditorWindow::OnPaintMessage(
EditorContext& editorContext,
bool globalTabDragActive) {
if (!m_runtime->IsReady() || m_state->window.hwnd == nullptr) {
return {};
}
PAINTSTRUCT paintStruct = {};
BeginPaint(m_state->window.hwnd, &paintStruct);
const EditorWindowFrameTransferRequests transferRequests =
RenderFrame(editorContext, globalTabDragActive);
EndPaint(m_state->window.hwnd, &paintStruct);
return transferRequests;
}
UIRect EditorWindow::ResolveWorkspaceBounds(float clientWidthDips, float clientHeightDips) const {
if (!IsBorderlessWindowEnabled()) {
return UIRect(0.0f, 0.0f, clientWidthDips, clientHeightDips);
}
if (ShouldUseDetachedTitleBarTabStrip()) {
return UIRect(0.0f, 0.0f, clientWidthDips, clientHeightDips);
}
const float titleBarHeight = (std::min)(kBorderlessTitleBarHeightDips, clientHeightDips);
return UIRect(
0.0f,
titleBarHeight,
clientWidthDips,
(std::max)(0.0f, clientHeightDips - titleBarHeight));
}
EditorWindowFrameTransferRequests EditorWindow::RenderRuntimeFrame(
EditorContext& editorContext,
bool globalTabDragActive,
const UIRect& workspaceBounds,
UIDrawList& drawList) {
SyncShellCapturedPointerButtonsFromSystemState();
std::vector<UIInputEvent> frameEvents = m_inputController->TakePendingEvents();
const bool useDetachedTitleBarTabStrip = ShouldUseDetachedTitleBarTabStrip();
const EditorWindowFrameTransferRequests transferRequests =
m_frameOrchestrator->UpdateAndAppend(
editorContext,
*m_runtime,
workspaceBounds,
frameEvents,
m_runtime->BuildCaptureStatusText(),
m_state->window.primary,
globalTabDragActive,
useDetachedTitleBarTabStrip,
drawList);
ApplyShellRuntimePointerCapture();
ApplyCurrentCursor();
return transferRequests;
}
void EditorWindow::SyncShellCapturedPointerButtonsFromSystemState() {
m_inputController->SyncInputModifiersFromSystemState();
const std::uint8_t expectedButtons = ResolveExpectedShellCaptureButtons(
m_runtime->GetShellRuntime());
if (expectedButtons == 0u ||
m_inputController->HasPendingPointerStateReconciliationEvent()) {
return;
}
const UIInputModifiers modifiers = m_inputController->GetCurrentModifiers();
if ((ButtonMaskFromModifiers(modifiers) & expectedButtons) == expectedButtons) {
return;
}
QueueSyntheticPointerStateSyncEvent(modifiers);
}
void EditorWindow::ApplyShellRuntimePointerCapture() {
const EditorShellPointerOwner owner = m_runtime->GetShellRuntime().GetPointerOwner();
if (IsShellPointerOwner(owner)) {
AcquirePointerCapture(EditorWindowPointerCaptureOwner::Shell);
return;
}
if (IsHostedContentPointerOwner(owner)) {
AcquirePointerCapture(EditorWindowPointerCaptureOwner::HostedContent);
return;
}
if (OwnsPointerCapture(EditorWindowPointerCaptureOwner::Shell)) {
ReleasePointerCapture(EditorWindowPointerCaptureOwner::Shell);
}
if (OwnsPointerCapture(EditorWindowPointerCaptureOwner::HostedContent)) {
ReleasePointerCapture(EditorWindowPointerCaptureOwner::HostedContent);
}
}
} // namespace XCEngine::UI::Editor::App