246 lines
9.3 KiB
C++
246 lines
9.3 KiB
C++
#include "Composition/EditorShellRuntimeInternal.h"
|
|
|
|
#include "Features/PanelInputContext.h"
|
|
#include "Composition/EditorContext.h"
|
|
|
|
#include "Composition/EditorPanelIds.h"
|
|
#include <XCEditor/Foundation/UIEditorTheme.h>
|
|
|
|
namespace XCEngine::UI::Editor::App::Internal {
|
|
|
|
namespace {
|
|
|
|
using ::XCEngine::UI::UIInputEvent;
|
|
using ::XCEngine::UI::UIInputEventType;
|
|
using Widgets::UIEditorDockHostHitTargetKind;
|
|
|
|
bool IsPointerInputEventType(UIInputEventType type) {
|
|
switch (type) {
|
|
case UIInputEventType::PointerMove:
|
|
case UIInputEventType::PointerEnter:
|
|
case UIInputEventType::PointerLeave:
|
|
case UIInputEventType::PointerButtonDown:
|
|
case UIInputEventType::PointerButtonUp:
|
|
case UIInputEventType::PointerWheel:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
PanelInputContext BuildHostedPanelInputContext(
|
|
const UIEditorWorkspaceInteractionFrame& workspaceFrame,
|
|
bool allowInteraction,
|
|
std::string_view panelId) {
|
|
PanelInputContext inputContext = {};
|
|
inputContext.allowInteraction = allowInteraction;
|
|
inputContext.hasInputFocus =
|
|
IsUIEditorWorkspaceHostedPanelInputOwner(workspaceFrame.inputOwner, panelId);
|
|
inputContext.focusGained =
|
|
!IsUIEditorWorkspaceHostedPanelInputOwner(workspaceFrame.previousInputOwner, panelId) &&
|
|
inputContext.hasInputFocus;
|
|
inputContext.focusLost =
|
|
IsUIEditorWorkspaceHostedPanelInputOwner(workspaceFrame.previousInputOwner, panelId) &&
|
|
!inputContext.hasInputFocus;
|
|
return inputContext;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
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;
|
|
}
|
|
|
|
bool ShouldHostedContentYieldPointerStream(
|
|
const UIEditorShellInteractionFrame& shellFrame,
|
|
bool shellInteractiveCaptureActive) {
|
|
if (shellInteractiveCaptureActive ||
|
|
shellFrame.result.requestPointerCapture ||
|
|
shellFrame.result.releasePointerCapture) {
|
|
return true;
|
|
}
|
|
|
|
return shellFrame.result.workspaceResult.dockHostResult.hitTarget.kind ==
|
|
UIEditorDockHostHitTargetKind::SplitterHandle;
|
|
}
|
|
|
|
std::vector<UIInputEvent> FilterHostedContentInputEventsForShellOwnership(
|
|
const std::vector<UIInputEvent>& inputEvents,
|
|
bool shellOwnsPointerStream) {
|
|
if (!shellOwnsPointerStream) {
|
|
return inputEvents;
|
|
}
|
|
|
|
std::vector<UIInputEvent> filteredEvents = {};
|
|
filteredEvents.reserve(inputEvents.size() + 1u);
|
|
|
|
bool strippedPointerInput = false;
|
|
UIInputEvent lastPointerEvent = {};
|
|
for (const UIInputEvent& event : inputEvents) {
|
|
if (IsPointerInputEventType(event.type)) {
|
|
strippedPointerInput = true;
|
|
lastPointerEvent = event;
|
|
continue;
|
|
}
|
|
|
|
filteredEvents.push_back(event);
|
|
}
|
|
|
|
if (strippedPointerInput) {
|
|
UIInputEvent leaveEvent = {};
|
|
leaveEvent.type = UIInputEventType::PointerLeave;
|
|
leaveEvent.position = lastPointerEvent.position;
|
|
leaveEvent.modifiers = lastPointerEvent.modifiers;
|
|
filteredEvents.push_back(leaveEvent);
|
|
}
|
|
|
|
return filteredEvents;
|
|
}
|
|
|
|
} // namespace XCEngine::UI::Editor::App::Internal
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
|
|
using namespace Internal;
|
|
|
|
void EditorShellRuntime::Update(
|
|
EditorContext& context,
|
|
UIEditorWorkspaceController& workspaceController,
|
|
const ::XCEngine::UI::UIRect& bounds,
|
|
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
|
std::string_view captureText,
|
|
EditorShellVariant shellVariant,
|
|
bool useDetachedTitleBarTabStrip,
|
|
float detachedTitleBarTabHeight) {
|
|
UIEditorShellInteractionMetrics metrics = ResolveUIEditorShellInteractionMetrics();
|
|
if (useDetachedTitleBarTabStrip && detachedTitleBarTabHeight > 0.0f) {
|
|
metrics.shellMetrics.dockHostMetrics.tabStripMetrics.layoutMetrics.headerHeight =
|
|
detachedTitleBarTabHeight;
|
|
}
|
|
|
|
const UIEditorWorkspaceLayoutSnapshot preUpdateSnapshot =
|
|
workspaceController.CaptureLayoutSnapshot();
|
|
const Widgets::UIEditorDockHostLayout preUpdateDockLayout =
|
|
m_shellFrame.workspaceInteractionFrame.dockHostFrame.layout;
|
|
|
|
m_hierarchyPanel.SetSceneRuntime(&context.GetSceneRuntime());
|
|
m_hierarchyPanel.SetCommandFocusService(&context.GetCommandFocusService());
|
|
m_sceneEditCommandRoute.BindSceneRuntime(&context.GetSceneRuntime());
|
|
m_sceneViewportFeature.SetCommandFocusService(&context.GetCommandFocusService());
|
|
// Keep the previous render request available for readback-based picking during
|
|
// this update, then refresh it again after camera/navigation state changes.
|
|
m_sceneViewportFeature.SyncRenderRequest(context.GetSceneRuntime());
|
|
context.BindEditCommandRoutes(
|
|
&m_hierarchyPanel,
|
|
&m_projectPanel,
|
|
&m_sceneEditCommandRoute,
|
|
&m_inspectorPanel);
|
|
context.SyncSessionFromWorkspace(workspaceController);
|
|
UIEditorShellInteractionDefinition definition =
|
|
context.BuildShellDefinition(workspaceController, captureText, shellVariant);
|
|
m_viewportHostService.BeginFrame();
|
|
const std::vector<::XCEngine::UI::UIInputEvent> shellEvents =
|
|
HasHostedContentCapture()
|
|
? FilterShellInputEventsForHostedContentCapture(inputEvents)
|
|
: inputEvents;
|
|
|
|
m_shellFrame = UpdateUIEditorShellInteraction(
|
|
m_shellInteractionState,
|
|
workspaceController,
|
|
bounds,
|
|
definition,
|
|
shellEvents,
|
|
context.GetShellServices(),
|
|
metrics);
|
|
|
|
if (TryApplyUIEditorWorkspaceSplitterDragCorrection(
|
|
m_splitterDragCorrectionState,
|
|
m_shellInteractionState.workspaceInteractionState.dockHostInteractionState,
|
|
preUpdateSnapshot,
|
|
preUpdateDockLayout,
|
|
workspaceController,
|
|
metrics.shellMetrics.dockHostMetrics)) {
|
|
context.SyncSessionFromWorkspace(workspaceController);
|
|
definition =
|
|
context.BuildShellDefinition(workspaceController, captureText, shellVariant);
|
|
m_shellFrame = UpdateUIEditorShellInteraction(
|
|
m_shellInteractionState,
|
|
workspaceController,
|
|
bounds,
|
|
definition,
|
|
{},
|
|
context.GetShellServices(),
|
|
metrics);
|
|
}
|
|
|
|
const bool shellOwnsHostedContentPointerStream =
|
|
ShouldHostedContentYieldPointerStream(m_shellFrame, HasShellInteractiveCapture());
|
|
const std::vector<::XCEngine::UI::UIInputEvent> hostedContentEvents =
|
|
FilterHostedContentInputEventsForShellOwnership(
|
|
inputEvents,
|
|
shellOwnsHostedContentPointerStream);
|
|
m_sceneViewportFeature.Update(
|
|
context.GetSceneRuntime(),
|
|
m_shellInteractionState.workspaceInteractionState.composeState,
|
|
m_shellFrame.workspaceInteractionFrame.composeFrame);
|
|
ApplyViewportFramesToShellFrame(m_shellFrame, m_viewportHostService);
|
|
context.SyncSessionFromWorkspace(workspaceController);
|
|
context.UpdateStatusFromShellResult(workspaceController, m_shellFrame.result);
|
|
|
|
const bool allowHostedInteraction = !m_shellFrame.result.workspaceInputSuppressed;
|
|
const PanelInputContext hierarchyInputContext = BuildHostedPanelInputContext(
|
|
m_shellFrame.workspaceInteractionFrame,
|
|
allowHostedInteraction,
|
|
kHierarchyPanelId);
|
|
const PanelInputContext projectInputContext = BuildHostedPanelInputContext(
|
|
m_shellFrame.workspaceInteractionFrame,
|
|
allowHostedInteraction,
|
|
kProjectPanelId);
|
|
const PanelInputContext inspectorInputContext = BuildHostedPanelInputContext(
|
|
m_shellFrame.workspaceInteractionFrame,
|
|
allowHostedInteraction,
|
|
kInspectorPanelId);
|
|
m_projectPanel.SetProjectRuntime(&context.GetProjectRuntime());
|
|
m_projectPanel.SetCommandFocusService(&context.GetCommandFocusService());
|
|
m_projectPanel.SetSystemInteractionHost(context.GetSystemInteractionHost());
|
|
m_inspectorPanel.SetCommandFocusService(&context.GetCommandFocusService());
|
|
m_hierarchyPanel.Update(
|
|
m_shellFrame.workspaceInteractionFrame.composeFrame.contentHostFrame,
|
|
hostedContentEvents,
|
|
hierarchyInputContext);
|
|
m_projectPanel.Update(
|
|
m_shellFrame.workspaceInteractionFrame.composeFrame.contentHostFrame,
|
|
hostedContentEvents,
|
|
projectInputContext);
|
|
m_traceEntries = SyncWorkspaceEvents(context, *this);
|
|
m_inspectorPanel.Update(
|
|
context.GetSession(),
|
|
context.GetSceneRuntime(),
|
|
m_shellFrame.workspaceInteractionFrame.composeFrame.contentHostFrame,
|
|
hostedContentEvents,
|
|
inspectorInputContext);
|
|
context.SyncSessionFromCommandFocusService();
|
|
m_consolePanel.Update(
|
|
context.GetSession(),
|
|
m_shellFrame.workspaceInteractionFrame.composeFrame.contentHostFrame);
|
|
}
|
|
|
|
} // namespace XCEngine::UI::Editor::App
|