2026-04-21 00:57:14 +08:00
|
|
|
|
#include "Composition/EditorShellRuntime.h"
|
2026-04-19 15:52:28 +08:00
|
|
|
|
#include "Ports/TexturePort.h"
|
|
|
|
|
|
#include "Ports/ViewportRenderPort.h"
|
|
|
|
|
|
#include "Composition/EditorContext.h"
|
2026-04-19 04:36:52 +08:00
|
|
|
|
#include "Composition/EditorPanelIds.h"
|
2026-04-15 22:47:42 +08:00
|
|
|
|
#include <XCEngine/Rendering/RenderContext.h>
|
2026-04-21 00:57:14 +08:00
|
|
|
|
#include <XCEditor/Foundation/UIEditorTheme.h>
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
#include "Features/PanelInputContext.h"
|
2026-04-15 22:47:42 +08:00
|
|
|
|
|
2026-04-15 08:24:06 +08:00
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
|
|
|
|
|
2026-04-21 00:57:14 +08:00
|
|
|
|
void ApplyViewportFramesToShellFrame(
|
|
|
|
|
|
UIEditorShellInteractionFrame& shellFrame,
|
|
|
|
|
|
ViewportHostService& viewportHostService);
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<::XCEngine::UI::UIInputEvent> FilterShellInputEventsForHostedContentCapture(
|
|
|
|
|
|
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents);
|
|
|
|
|
|
|
|
|
|
|
|
bool ShouldHostedContentYieldPointerStream(
|
|
|
|
|
|
const UIEditorShellInteractionFrame& shellFrame,
|
|
|
|
|
|
bool shellInteractiveCaptureActive);
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<::XCEngine::UI::UIInputEvent> FilterHostedContentInputEventsForShellOwnership(
|
|
|
|
|
|
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
|
|
|
|
|
bool shellOwnsPointerStream);
|
|
|
|
|
|
|
|
|
|
|
|
UIEditorShellComposeModel BuildShellComposeModelFromFrame(
|
|
|
|
|
|
const UIEditorShellInteractionFrame& frame);
|
|
|
|
|
|
|
|
|
|
|
|
void AppendShellPopups(
|
|
|
|
|
|
::XCEngine::UI::UIDrawList& drawList,
|
|
|
|
|
|
const UIEditorShellInteractionFrame& frame,
|
|
|
|
|
|
const UIEditorShellInteractionPalette& palette,
|
|
|
|
|
|
const UIEditorShellInteractionMetrics& metrics);
|
|
|
|
|
|
|
2026-04-15 08:24:06 +08:00
|
|
|
|
void EditorShellRuntime::Initialize(
|
|
|
|
|
|
const std::filesystem::path& repoRoot,
|
2026-04-19 15:52:28 +08:00
|
|
|
|
Ports::TexturePort& textureHost,
|
2026-04-19 02:48:41 +08:00
|
|
|
|
UIEditorTextMeasurer& textMeasurer) {
|
|
|
|
|
|
m_textureHost = &textureHost;
|
|
|
|
|
|
m_builtInIcons.Initialize(textureHost);
|
2026-04-21 00:57:14 +08:00
|
|
|
|
m_sceneViewportFeature.Initialize(
|
|
|
|
|
|
repoRoot,
|
|
|
|
|
|
textureHost,
|
|
|
|
|
|
&m_builtInIcons,
|
|
|
|
|
|
m_viewportHostService);
|
2026-04-15 08:24:06 +08:00
|
|
|
|
m_hierarchyPanel.SetBuiltInIcons(&m_builtInIcons);
|
|
|
|
|
|
m_projectPanel.SetBuiltInIcons(&m_builtInIcons);
|
2026-04-19 02:48:41 +08:00
|
|
|
|
m_projectPanel.SetTextMeasurer(&textMeasurer);
|
2026-04-15 08:24:06 +08:00
|
|
|
|
m_hierarchyPanel.Initialize();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-19 15:52:28 +08:00
|
|
|
|
void EditorShellRuntime::AttachViewportWindowRenderer(Ports::ViewportRenderPort& renderer) {
|
2026-04-15 08:24:06 +08:00
|
|
|
|
m_viewportHostService.AttachWindowRenderer(renderer);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void EditorShellRuntime::DetachViewportWindowRenderer() {
|
|
|
|
|
|
m_viewportHostService.DetachWindowRenderer();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void EditorShellRuntime::SetViewportSurfacePresentationEnabled(bool enabled) {
|
|
|
|
|
|
m_viewportHostService.SetSurfacePresentationEnabled(enabled);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void EditorShellRuntime::Shutdown() {
|
|
|
|
|
|
m_shellFrame = {};
|
|
|
|
|
|
m_shellInteractionState = {};
|
2026-04-15 19:30:58 +08:00
|
|
|
|
m_splitterDragCorrectionState = {};
|
2026-04-15 08:24:06 +08:00
|
|
|
|
m_traceEntries.clear();
|
2026-04-18 18:55:19 +08:00
|
|
|
|
m_sceneEditCommandRoute = {};
|
2026-04-19 02:48:41 +08:00
|
|
|
|
if (m_textureHost != nullptr) {
|
2026-04-19 15:52:28 +08:00
|
|
|
|
m_sceneViewportFeature.Shutdown(*m_textureHost, m_viewportHostService);
|
2026-04-18 18:55:19 +08:00
|
|
|
|
m_builtInIcons.Shutdown();
|
2026-04-19 02:48:41 +08:00
|
|
|
|
m_textureHost = nullptr;
|
2026-04-18 18:55:19 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
m_builtInIcons.Shutdown();
|
|
|
|
|
|
}
|
2026-04-15 08:24:06 +08:00
|
|
|
|
m_viewportHostService.Shutdown();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void EditorShellRuntime::ResetInteractionState() {
|
|
|
|
|
|
m_shellFrame = {};
|
|
|
|
|
|
m_shellInteractionState = {};
|
2026-04-15 19:30:58 +08:00
|
|
|
|
m_splitterDragCorrectionState = {};
|
2026-04-15 08:24:06 +08:00
|
|
|
|
m_traceEntries.clear();
|
2026-04-19 15:52:28 +08:00
|
|
|
|
m_sceneViewportFeature.ResetInteractionState();
|
2026-04-15 08:24:06 +08:00
|
|
|
|
m_hierarchyPanel.ResetInteractionState();
|
2026-04-21 00:57:14 +08:00
|
|
|
|
m_colorPickerPanel.ResetInteractionState();
|
2026-04-15 08:24:06 +08:00
|
|
|
|
m_projectPanel.ResetInteractionState();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const UIEditorShellInteractionFrame& EditorShellRuntime::GetShellFrame() const {
|
|
|
|
|
|
return m_shellFrame;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const UIEditorShellInteractionState& EditorShellRuntime::GetShellInteractionState() const {
|
|
|
|
|
|
return m_shellInteractionState;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const std::vector<WorkspaceTraceEntry>& EditorShellRuntime::GetTraceEntries() const {
|
|
|
|
|
|
return m_traceEntries;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const std::vector<HierarchyPanel::Event>& EditorShellRuntime::GetHierarchyPanelEvents() const {
|
|
|
|
|
|
return m_hierarchyPanel.GetFrameEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const std::vector<ProjectPanel::Event>& EditorShellRuntime::GetProjectPanelEvents() const {
|
|
|
|
|
|
return m_projectPanel.GetFrameEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const std::string& EditorShellRuntime::GetBuiltInIconError() const {
|
|
|
|
|
|
return m_builtInIcons.GetLastError();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 13:22:58 +08:00
|
|
|
|
void EditorShellRuntime::SetExternalDockHostDropPreview(
|
|
|
|
|
|
const Widgets::UIEditorDockHostDropPreviewState& preview) {
|
|
|
|
|
|
m_shellInteractionState.workspaceInteractionState.dockHostInteractionState
|
|
|
|
|
|
.dockHostState.dropPreview = preview;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void EditorShellRuntime::ClearExternalDockHostDropPreview() {
|
|
|
|
|
|
m_shellInteractionState.workspaceInteractionState.dockHostInteractionState
|
|
|
|
|
|
.dockHostState.dropPreview = {};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 08:24:06 +08:00
|
|
|
|
ProjectPanel::CursorKind EditorShellRuntime::GetHostedContentCursorKind() const {
|
|
|
|
|
|
return m_projectPanel.GetCursorKind();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Widgets::UIEditorDockHostCursorKind EditorShellRuntime::GetDockCursorKind() const {
|
|
|
|
|
|
return Widgets::ResolveUIEditorDockHostCursorKind(
|
|
|
|
|
|
m_shellFrame.workspaceInteractionFrame.dockHostFrame.layout);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-21 00:57:14 +08:00
|
|
|
|
bool EditorShellRuntime::TryResolveDockTabDragHotspot(
|
|
|
|
|
|
std::string_view nodeId,
|
|
|
|
|
|
std::string_view panelId,
|
|
|
|
|
|
const ::XCEngine::UI::UIPoint& point,
|
|
|
|
|
|
::XCEngine::UI::UIPoint& outHotspot) const {
|
|
|
|
|
|
return TryResolveUIEditorDockHostTabDragHotspot(
|
|
|
|
|
|
m_shellFrame.workspaceInteractionFrame.dockHostFrame.layout,
|
|
|
|
|
|
nodeId,
|
|
|
|
|
|
panelId,
|
|
|
|
|
|
point,
|
|
|
|
|
|
outHotspot);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UIEditorDockHostTabDropTarget EditorShellRuntime::ResolveDockTabDropTarget(
|
|
|
|
|
|
const ::XCEngine::UI::UIPoint& point) const {
|
|
|
|
|
|
return ResolveUIEditorDockHostTabDropTarget(
|
|
|
|
|
|
m_shellFrame.workspaceInteractionFrame.dockHostFrame.layout,
|
|
|
|
|
|
point);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-19 04:36:52 +08:00
|
|
|
|
EditorShellPointerOwner EditorShellRuntime::GetPointerOwner() const {
|
|
|
|
|
|
const auto& dockHostInteractionState =
|
|
|
|
|
|
m_shellInteractionState.workspaceInteractionState.dockHostInteractionState;
|
|
|
|
|
|
if (dockHostInteractionState.splitterDragState.active ||
|
|
|
|
|
|
!dockHostInteractionState.activeTabDragNodeId.empty()) {
|
|
|
|
|
|
return EditorShellPointerOwner::DockHost;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto& panelState :
|
|
|
|
|
|
m_shellInteractionState.workspaceInteractionState.composeState.panelStates) {
|
|
|
|
|
|
if (!panelState.viewportShellState.inputBridgeState.captured) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (panelState.panelId == kGamePanelId) {
|
|
|
|
|
|
return EditorShellPointerOwner::GameViewport;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return EditorShellPointerOwner::SceneViewport;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_hierarchyPanel.HasActivePointerCapture()) {
|
|
|
|
|
|
return EditorShellPointerOwner::HierarchyPanel;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_projectPanel.HasActivePointerCapture()) {
|
|
|
|
|
|
return EditorShellPointerOwner::ProjectPanel;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return EditorShellPointerOwner::None;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 08:24:06 +08:00
|
|
|
|
bool EditorShellRuntime::WantsHostPointerCapture() const {
|
2026-04-19 04:36:52 +08:00
|
|
|
|
return IsHostedContentPointerOwner(GetPointerOwner());
|
2026-04-15 08:24:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool EditorShellRuntime::WantsHostPointerRelease() const {
|
2026-04-19 04:36:52 +08:00
|
|
|
|
return !IsHostedContentPointerOwner(GetPointerOwner());
|
2026-04-15 08:24:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool EditorShellRuntime::HasHostedContentCapture() const {
|
2026-04-19 04:36:52 +08:00
|
|
|
|
return IsHostedContentPointerOwner(GetPointerOwner());
|
2026-04-15 08:24:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool EditorShellRuntime::HasShellInteractiveCapture() const {
|
2026-04-19 04:36:52 +08:00
|
|
|
|
return IsShellPointerOwner(GetPointerOwner());
|
2026-04-15 08:24:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool EditorShellRuntime::HasInteractiveCapture() const {
|
2026-04-19 04:36:52 +08:00
|
|
|
|
return GetPointerOwner() != EditorShellPointerOwner::None;
|
2026-04-15 08:24:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace XCEngine::UI::Editor::App
|
2026-04-21 00:57:14 +08:00
|
|
|
|
|
|
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
|
|
|
|
|
|
|
|
|
|
void EditorShellRuntime::RenderRequestedViewports(
|
|
|
|
|
|
const ::XCEngine::Rendering::RenderContext& renderContext) {
|
|
|
|
|
|
m_viewportHostService.RenderRequestedViewports(renderContext);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-22 14:53:24 +08:00
|
|
|
|
void EditorShellRuntime::Append(::XCEngine::UI::UIDrawData& drawData) const {
|
|
|
|
|
|
m_drawComposer.Append(
|
|
|
|
|
|
EditorShellDrawComposerContext{
|
|
|
|
|
|
.shellFrame = m_shellFrame,
|
|
|
|
|
|
.shellInteractionState = m_shellInteractionState,
|
|
|
|
|
|
.builtInIcons = m_builtInIcons,
|
|
|
|
|
|
.consolePanel = m_consolePanel,
|
|
|
|
|
|
.colorPickerPanel = m_colorPickerPanel,
|
|
|
|
|
|
.hierarchyPanel = m_hierarchyPanel,
|
|
|
|
|
|
.inspectorPanel = m_inspectorPanel,
|
|
|
|
|
|
.projectPanel = m_projectPanel,
|
|
|
|
|
|
.sceneViewportFeature = m_sceneViewportFeature,
|
|
|
|
|
|
},
|
|
|
|
|
|
drawData);
|
2026-04-21 00:57:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace XCEngine::UI::Editor::App
|
|
|
|
|
|
|
|
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace XCEngine::UI::Editor::App
|
|
|
|
|
|
|
|
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const UIEditorWorkspaceLayoutSnapshot preUpdateSnapshot =
|
|
|
|
|
|
workspaceController.CaptureLayoutSnapshot();
|
|
|
|
|
|
const Widgets::UIEditorDockHostLayout preUpdateDockLayout =
|
|
|
|
|
|
m_shellFrame.workspaceInteractionFrame.dockHostFrame.layout;
|
|
|
|
|
|
|
|
|
|
|
|
UIEditorShellInteractionDefinition definition =
|
2026-04-22 15:01:03 +08:00
|
|
|
|
m_sessionCoordinator.PrepareShellDefinition(
|
|
|
|
|
|
EditorShellSessionCoordinatorContext{
|
|
|
|
|
|
.context = context,
|
|
|
|
|
|
.workspaceController = workspaceController,
|
|
|
|
|
|
.captureText = captureText,
|
|
|
|
|
|
.shellVariant = shellVariant,
|
|
|
|
|
|
.hierarchyPanel = m_hierarchyPanel,
|
|
|
|
|
|
.inspectorPanel = m_inspectorPanel,
|
|
|
|
|
|
.projectPanel = m_projectPanel,
|
|
|
|
|
|
.sceneEditCommandRoute = m_sceneEditCommandRoute,
|
|
|
|
|
|
.sceneViewportFeature = m_sceneViewportFeature,
|
|
|
|
|
|
});
|
2026-04-21 00:57:14 +08:00
|
|
|
|
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)) {
|
|
|
|
|
|
definition =
|
2026-04-22 15:01:03 +08:00
|
|
|
|
m_sessionCoordinator.PrepareShellDefinition(
|
|
|
|
|
|
EditorShellSessionCoordinatorContext{
|
|
|
|
|
|
.context = context,
|
|
|
|
|
|
.workspaceController = workspaceController,
|
|
|
|
|
|
.captureText = captureText,
|
|
|
|
|
|
.shellVariant = shellVariant,
|
|
|
|
|
|
.hierarchyPanel = m_hierarchyPanel,
|
|
|
|
|
|
.inspectorPanel = m_inspectorPanel,
|
|
|
|
|
|
.projectPanel = m_projectPanel,
|
|
|
|
|
|
.sceneEditCommandRoute = m_sceneEditCommandRoute,
|
|
|
|
|
|
.sceneViewportFeature = m_sceneViewportFeature,
|
|
|
|
|
|
});
|
2026-04-21 00:57:14 +08:00
|
|
|
|
m_shellFrame = UpdateUIEditorShellInteraction(
|
|
|
|
|
|
m_shellInteractionState,
|
|
|
|
|
|
workspaceController,
|
|
|
|
|
|
bounds,
|
|
|
|
|
|
definition,
|
|
|
|
|
|
{},
|
|
|
|
|
|
context.GetShellServices(),
|
|
|
|
|
|
metrics);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ApplyViewportFramesToShellFrame(m_shellFrame, m_viewportHostService);
|
2026-04-22 15:01:03 +08:00
|
|
|
|
m_sessionCoordinator.FinalizeFrame(context, workspaceController, m_shellFrame.result);
|
|
|
|
|
|
|
|
|
|
|
|
m_hostedPanelCoordinator.Update(
|
|
|
|
|
|
EditorShellHostedPanelCoordinatorContext{
|
|
|
|
|
|
.context = context,
|
|
|
|
|
|
.shellFrame = m_shellFrame,
|
|
|
|
|
|
.shellInteractionState = m_shellInteractionState,
|
|
|
|
|
|
.inputEvents = inputEvents,
|
|
|
|
|
|
.shellInteractiveCaptureActive = HasShellInteractiveCapture(),
|
|
|
|
|
|
.consolePanel = m_consolePanel,
|
|
|
|
|
|
.colorPickerPanel = m_colorPickerPanel,
|
|
|
|
|
|
.hierarchyPanel = m_hierarchyPanel,
|
|
|
|
|
|
.inspectorPanel = m_inspectorPanel,
|
|
|
|
|
|
.projectPanel = m_projectPanel,
|
|
|
|
|
|
.sceneViewportFeature = m_sceneViewportFeature,
|
|
|
|
|
|
});
|
2026-04-21 00:57:14 +08:00
|
|
|
|
m_traceEntries = SyncWorkspaceEvents(context, *this);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace XCEngine::UI::Editor::App
|
|
|
|
|
|
|
|
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace XCEngine::UI::Editor::App
|
|
|
|
|
|
|
|
|
|
|
|
|