225 lines
8.8 KiB
C++
225 lines
8.8 KiB
C++
|
|
#include "Composition/EditorShellInteractionEngine.h"
|
||
|
|
|
||
|
|
#include "Composition/EditorPanelIds.h"
|
||
|
|
|
||
|
|
#include <XCEditor/Foundation/UIEditorTheme.h>
|
||
|
|
|
||
|
|
#include <algorithm>
|
||
|
|
|
||
|
|
namespace XCEngine::UI::Editor::App {
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
using ::XCEngine::UI::UIInputEvent;
|
||
|
|
using ::XCEngine::UI::UIInputEventType;
|
||
|
|
|
||
|
|
bool IsViewportPanel(std::string_view panelId) {
|
||
|
|
return IsEditorViewportPanelId(panelId);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ApplyViewportFrameToPresentation(
|
||
|
|
const ViewportFrame& viewportFrame,
|
||
|
|
UIEditorWorkspacePanelPresentationModel& presentation) {
|
||
|
|
presentation.viewportShellModel.frame.texture = viewportFrame.texture;
|
||
|
|
presentation.viewportShellModel.frame.requestedSize = viewportFrame.requestedSize;
|
||
|
|
presentation.viewportShellModel.frame.presentedSize = viewportFrame.renderSize;
|
||
|
|
presentation.viewportShellModel.frame.hasTexture = viewportFrame.hasTexture;
|
||
|
|
presentation.viewportShellModel.frame.statusText = viewportFrame.statusText;
|
||
|
|
}
|
||
|
|
|
||
|
|
void ApplyViewportFrameToShellModel(
|
||
|
|
const ViewportFrame& viewportFrame,
|
||
|
|
UIEditorViewportShellModel& shellModel) {
|
||
|
|
shellModel.frame.texture = viewportFrame.texture;
|
||
|
|
shellModel.frame.requestedSize = viewportFrame.requestedSize;
|
||
|
|
shellModel.frame.presentedSize = viewportFrame.renderSize;
|
||
|
|
shellModel.frame.hasTexture = viewportFrame.hasTexture;
|
||
|
|
shellModel.frame.statusText = viewportFrame.statusText;
|
||
|
|
}
|
||
|
|
|
||
|
|
UIEditorWorkspacePanelPresentationModel* FindMutableWorkspacePresentation(
|
||
|
|
std::vector<UIEditorWorkspacePanelPresentationModel>& presentations,
|
||
|
|
std::string_view panelId) {
|
||
|
|
for (UIEditorWorkspacePanelPresentationModel& presentation : presentations) {
|
||
|
|
if (presentation.panelId == panelId) {
|
||
|
|
return &presentation;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
void ApplyViewportFramesToShellFrame(
|
||
|
|
UIEditorShellInteractionFrame& shellFrame,
|
||
|
|
ViewportHostService& viewportHostService) {
|
||
|
|
auto applyToViewportFrames =
|
||
|
|
[&](std::vector<UIEditorWorkspaceViewportComposeFrame>& viewportFrames) {
|
||
|
|
for (UIEditorWorkspaceViewportComposeFrame& viewportComposeFrame : viewportFrames) {
|
||
|
|
if (!IsViewportPanel(viewportComposeFrame.panelId)) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
const ViewportFrame viewportFrame =
|
||
|
|
viewportHostService.RequestViewport(
|
||
|
|
viewportComposeFrame.panelId,
|
||
|
|
viewportComposeFrame.viewportShellFrame.requestedViewportSize);
|
||
|
|
ApplyViewportFrameToShellModel(
|
||
|
|
viewportFrame,
|
||
|
|
viewportComposeFrame.viewportShellModel);
|
||
|
|
if (UIEditorWorkspacePanelPresentationModel* presentation =
|
||
|
|
FindMutableWorkspacePresentation(
|
||
|
|
shellFrame.model.workspacePresentations,
|
||
|
|
viewportComposeFrame.panelId);
|
||
|
|
presentation != nullptr) {
|
||
|
|
ApplyViewportFrameToPresentation(viewportFrame, *presentation);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
applyToViewportFrames(shellFrame.workspaceInteractionFrame.composeFrame.viewportFrames);
|
||
|
|
}
|
||
|
|
|
||
|
|
const UIEditorPanelDescriptor* ResolveSingleVisibleToolWindowPanelDescriptor(
|
||
|
|
const UIEditorWorkspaceController& workspaceController) {
|
||
|
|
const UIEditorWorkspaceNode& root = workspaceController.GetWorkspace().root;
|
||
|
|
if (root.kind != UIEditorWorkspaceNodeKind::TabStack) {
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
const UIEditorWorkspaceSession& session = workspaceController.GetSession();
|
||
|
|
const UIEditorPanelRegistry& panelRegistry = workspaceController.GetPanelRegistry();
|
||
|
|
const UIEditorPanelDescriptor* visibleDescriptor = nullptr;
|
||
|
|
std::size_t visibleCount = 0u;
|
||
|
|
for (const UIEditorWorkspaceNode& child : root.children) {
|
||
|
|
if (child.kind != UIEditorWorkspaceNodeKind::Panel) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
const UIEditorPanelSessionState* panelState =
|
||
|
|
FindUIEditorPanelSessionState(session, child.panel.panelId);
|
||
|
|
if (panelState == nullptr || !panelState->open || !panelState->visible) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
const UIEditorPanelDescriptor* descriptor =
|
||
|
|
FindUIEditorPanelDescriptor(panelRegistry, child.panel.panelId);
|
||
|
|
if (descriptor == nullptr) {
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
++visibleCount;
|
||
|
|
visibleDescriptor = descriptor;
|
||
|
|
if (visibleCount > 1u) {
|
||
|
|
return nullptr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return visibleDescriptor != nullptr && visibleDescriptor->toolWindow
|
||
|
|
? visibleDescriptor
|
||
|
|
: nullptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
UIEditorShellInteractionMetrics ResolveInteractionMetrics(
|
||
|
|
const UIEditorWorkspaceController& workspaceController,
|
||
|
|
bool useDetachedTitleBarTabStrip,
|
||
|
|
float detachedTitleBarTabHeight,
|
||
|
|
float detachedWindowChromeHeight) {
|
||
|
|
UIEditorShellInteractionMetrics metrics = ResolveUIEditorShellInteractionMetrics();
|
||
|
|
if (const UIEditorPanelDescriptor* toolWindowDescriptor =
|
||
|
|
ResolveSingleVisibleToolWindowPanelDescriptor(workspaceController);
|
||
|
|
toolWindowDescriptor != nullptr) {
|
||
|
|
metrics.shellMetrics.dockHostMetrics.tabStripMetrics.layoutMetrics.headerHeight = 0.0f;
|
||
|
|
const float minimumContentWidth =
|
||
|
|
toolWindowDescriptor->minimumDetachedWindowSize.width > 0.0f
|
||
|
|
? toolWindowDescriptor->minimumDetachedWindowSize.width
|
||
|
|
: metrics.shellMetrics.dockHostMetrics.minimumStandalonePanelBodySize.width;
|
||
|
|
const float minimumContentHeight =
|
||
|
|
toolWindowDescriptor->minimumDetachedWindowSize.height > detachedWindowChromeHeight
|
||
|
|
? toolWindowDescriptor->minimumDetachedWindowSize.height -
|
||
|
|
detachedWindowChromeHeight
|
||
|
|
: metrics.shellMetrics.dockHostMetrics.minimumStandalonePanelBodySize.height;
|
||
|
|
metrics.shellMetrics.dockHostMetrics.minimumStandalonePanelBodySize =
|
||
|
|
::XCEngine::UI::UISize(minimumContentWidth, minimumContentHeight);
|
||
|
|
metrics.shellMetrics.dockHostMetrics.minimumTabContentBodySize =
|
||
|
|
metrics.shellMetrics.dockHostMetrics.minimumStandalonePanelBodySize;
|
||
|
|
}
|
||
|
|
if (useDetachedTitleBarTabStrip && detachedTitleBarTabHeight > 0.0f) {
|
||
|
|
metrics.shellMetrics.dockHostMetrics.tabStripMetrics.layoutMetrics.headerHeight =
|
||
|
|
detachedTitleBarTabHeight;
|
||
|
|
}
|
||
|
|
|
||
|
|
return metrics;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<UIInputEvent> FilterShellInputEventsForHostedContentCapture(
|
||
|
|
const std::vector<UIInputEvent>& inputEvents) {
|
||
|
|
std::vector<UIInputEvent> filteredEvents = {};
|
||
|
|
filteredEvents.reserve(inputEvents.size());
|
||
|
|
for (const UIInputEvent& event : inputEvents) {
|
||
|
|
switch (event.type) {
|
||
|
|
case UIInputEventType::PointerMove:
|
||
|
|
case UIInputEventType::PointerEnter:
|
||
|
|
case UIInputEventType::PointerLeave:
|
||
|
|
case UIInputEventType::PointerButtonDown:
|
||
|
|
case UIInputEventType::PointerButtonUp:
|
||
|
|
case UIInputEventType::PointerWheel:
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
filteredEvents.push_back(event);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return filteredEvents;
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
void EditorShellInteractionEngine::Update(
|
||
|
|
const EditorShellInteractionEngineContext& context) const {
|
||
|
|
const UIEditorShellInteractionMetrics metrics = ResolveInteractionMetrics(
|
||
|
|
context.workspaceController,
|
||
|
|
context.useDetachedTitleBarTabStrip,
|
||
|
|
context.detachedTitleBarTabHeight,
|
||
|
|
context.detachedWindowChromeHeight);
|
||
|
|
const UIEditorWorkspaceLayoutSnapshot preUpdateSnapshot =
|
||
|
|
context.workspaceController.CaptureLayoutSnapshot();
|
||
|
|
const Widgets::UIEditorDockHostLayout preUpdateDockLayout =
|
||
|
|
context.shellFrame.workspaceInteractionFrame.dockHostFrame.layout;
|
||
|
|
|
||
|
|
context.viewportHostService.BeginFrame();
|
||
|
|
const std::vector<UIInputEvent> shellEvents =
|
||
|
|
context.hostedContentCaptureActive
|
||
|
|
? FilterShellInputEventsForHostedContentCapture(context.inputEvents)
|
||
|
|
: context.inputEvents;
|
||
|
|
|
||
|
|
context.shellFrame = UpdateUIEditorShellInteraction(
|
||
|
|
context.shellInteractionState,
|
||
|
|
context.workspaceController,
|
||
|
|
context.bounds,
|
||
|
|
context.buildDefinition(),
|
||
|
|
shellEvents,
|
||
|
|
context.shellServices,
|
||
|
|
metrics);
|
||
|
|
|
||
|
|
if (TryApplyUIEditorWorkspaceSplitterDragCorrection(
|
||
|
|
context.splitterDragCorrectionState,
|
||
|
|
context.shellInteractionState.workspaceInteractionState.dockHostInteractionState,
|
||
|
|
preUpdateSnapshot,
|
||
|
|
preUpdateDockLayout,
|
||
|
|
context.workspaceController,
|
||
|
|
metrics.shellMetrics.dockHostMetrics)) {
|
||
|
|
context.shellFrame = UpdateUIEditorShellInteraction(
|
||
|
|
context.shellInteractionState,
|
||
|
|
context.workspaceController,
|
||
|
|
context.bounds,
|
||
|
|
context.buildDefinition(),
|
||
|
|
{},
|
||
|
|
context.shellServices,
|
||
|
|
metrics);
|
||
|
|
}
|
||
|
|
|
||
|
|
ApplyViewportFramesToShellFrame(context.shellFrame, context.viewportHostService);
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace XCEngine::UI::Editor::App
|