Refactor new editor boundaries and test ownership

This commit is contained in:
2026-04-19 15:52:28 +08:00
parent dc13b56cf3
commit 93f06e84ed
279 changed files with 6349 additions and 3238 deletions

View File

@@ -200,7 +200,8 @@ UIEditorWorkspaceComposeFrame UpdateUIEditorWorkspaceCompose(
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
const Widgets::UIEditorDockHostState& dockHostState,
const Widgets::UIEditorDockHostMetrics& dockHostMetrics,
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics) {
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics,
const UIEditorWorkspaceInputOwner* inputOwner) {
UIEditorWorkspaceComposeFrame frame = {};
frame.dockHostLayout = BuildUIEditorDockHostLayout(
bounds,
@@ -238,12 +239,19 @@ UIEditorWorkspaceComposeFrame UpdateUIEditorWorkspaceCompose(
viewportFrame.panelId = presentation.panelId;
viewportFrame.bounds = contentHostPanelState->bounds;
viewportFrame.viewportShellModel = presentation.viewportShellModel;
UIEditorViewportInputBridgeRequest inputRequest = {};
if (inputOwner != nullptr) {
inputRequest.focusMode = UIEditorViewportInputBridgeFocusMode::External;
inputRequest.focused =
IsUIEditorWorkspaceViewportInputOwner(*inputOwner, presentation.panelId);
}
viewportFrame.viewportShellFrame = UpdateUIEditorViewportShell(
panelState.viewportShellState,
contentHostPanelState->bounds,
presentation.viewportShellModel,
inputEvents,
viewportMetrics);
viewportMetrics,
inputRequest);
frame.viewportFrames.push_back(std::move(viewportFrame));
}

View File

@@ -0,0 +1,143 @@
#include <XCEditor/Workspace/UIEditorWorkspaceInputOwner.h>
namespace XCEngine::UI::Editor {
namespace {
using ::XCEngine::UI::UIPoint;
using ::XCEngine::UI::UIRect;
using Widgets::HitTestUIEditorDockHost;
using Widgets::UIEditorDockHostHitTargetKind;
bool ContainsPoint(const UIRect& rect, const UIPoint& point) {
return point.x >= rect.x &&
point.x <= rect.x + rect.width &&
point.y >= rect.y &&
point.y <= rect.y + rect.height;
}
bool HasUsableBounds(const UIRect& rect) {
return rect.width > 0.0f && rect.height > 0.0f;
}
bool IsMountedContentPanelValid(
const UIEditorPanelContentHostPanelState& panelState) {
return panelState.mounted && HasUsableBounds(panelState.bounds);
}
} // namespace
std::string_view GetUIEditorWorkspaceInputOwnerKindName(
UIEditorWorkspaceInputOwnerKind kind) {
switch (kind) {
case UIEditorWorkspaceInputOwnerKind::None:
return "None";
case UIEditorWorkspaceInputOwnerKind::DockHost:
return "DockHost";
case UIEditorWorkspaceInputOwnerKind::HostedPanel:
return "HostedPanel";
case UIEditorWorkspaceInputOwnerKind::Viewport:
return "Viewport";
}
return "Unknown";
}
bool AreUIEditorWorkspaceInputOwnersEquivalent(
const UIEditorWorkspaceInputOwner& lhs,
const UIEditorWorkspaceInputOwner& rhs) {
return lhs.kind == rhs.kind && lhs.panelId == rhs.panelId;
}
bool IsUIEditorWorkspaceDockHostInputOwner(
const UIEditorWorkspaceInputOwner& owner) {
return owner.kind == UIEditorWorkspaceInputOwnerKind::DockHost;
}
bool IsUIEditorWorkspaceHostedPanelInputOwner(
const UIEditorWorkspaceInputOwner& owner,
std::string_view panelId) {
return owner.kind == UIEditorWorkspaceInputOwnerKind::HostedPanel &&
(panelId.empty() || owner.panelId == panelId);
}
bool IsUIEditorWorkspaceViewportInputOwner(
const UIEditorWorkspaceInputOwner& owner,
std::string_view panelId) {
return owner.kind == UIEditorWorkspaceInputOwnerKind::Viewport &&
(panelId.empty() || owner.panelId == panelId);
}
UIEditorWorkspaceInputOwner ResolveUIEditorWorkspacePointerInputOwner(
const Widgets::UIEditorDockHostLayout& dockHostLayout,
const UIEditorPanelContentHostFrame& contentHostFrame,
const UIPoint& pointerPosition) {
for (const UIEditorPanelContentHostPanelState& panelState :
contentHostFrame.panelStates) {
if (!IsMountedContentPanelValid(panelState) ||
!ContainsPoint(panelState.bounds, pointerPosition)) {
continue;
}
UIEditorWorkspaceInputOwner owner = {};
owner.panelId = panelState.panelId;
owner.kind = panelState.kind == UIEditorPanelPresentationKind::ViewportShell
? UIEditorWorkspaceInputOwnerKind::Viewport
: UIEditorWorkspaceInputOwnerKind::HostedPanel;
return owner;
}
const Widgets::UIEditorDockHostHitTarget hitTarget =
HitTestUIEditorDockHost(dockHostLayout, pointerPosition);
switch (hitTarget.kind) {
case UIEditorDockHostHitTargetKind::SplitterHandle:
case UIEditorDockHostHitTargetKind::TabStripBackground:
case UIEditorDockHostHitTargetKind::Tab:
case UIEditorDockHostHitTargetKind::PanelHeader:
case UIEditorDockHostHitTargetKind::PanelBody:
case UIEditorDockHostHitTargetKind::PanelFooter:
return { UIEditorWorkspaceInputOwnerKind::DockHost, {} };
case UIEditorDockHostHitTargetKind::None:
default:
return {};
}
}
UIEditorWorkspaceInputOwner NormalizeUIEditorWorkspaceInputOwner(
UIEditorWorkspaceInputOwner owner,
const Widgets::UIEditorDockHostLayout& dockHostLayout,
const UIEditorPanelContentHostFrame& contentHostFrame) {
switch (owner.kind) {
case UIEditorWorkspaceInputOwnerKind::None:
return {};
case UIEditorWorkspaceInputOwnerKind::DockHost:
return HasUsableBounds(dockHostLayout.bounds)
? owner
: UIEditorWorkspaceInputOwner {};
case UIEditorWorkspaceInputOwnerKind::HostedPanel:
case UIEditorWorkspaceInputOwnerKind::Viewport:
for (const UIEditorPanelContentHostPanelState& panelState :
contentHostFrame.panelStates) {
if (!IsMountedContentPanelValid(panelState) ||
panelState.panelId != owner.panelId) {
continue;
}
const UIEditorWorkspaceInputOwnerKind expectedKind =
panelState.kind == UIEditorPanelPresentationKind::ViewportShell
? UIEditorWorkspaceInputOwnerKind::Viewport
: UIEditorWorkspaceInputOwnerKind::HostedPanel;
return owner.kind == expectedKind
? owner
: UIEditorWorkspaceInputOwner {};
}
return {};
}
return {};
}
} // namespace XCEngine::UI::Editor

View File

@@ -20,6 +20,41 @@ bool HasMeaningfulViewportInputFrame(const UIEditorViewportInputBridgeFrame& fra
!frame.characters.empty();
}
UIEditorWorkspaceInputOwner ResolveNextInputOwner(
UIEditorWorkspaceInputOwner currentOwner,
const Widgets::UIEditorDockHostLayout& dockHostLayout,
const UIEditorPanelContentHostFrame& contentHostFrame,
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents) {
using ::XCEngine::UI::UIInputEventType;
currentOwner = NormalizeUIEditorWorkspaceInputOwner(
std::move(currentOwner),
dockHostLayout,
contentHostFrame);
for (const ::XCEngine::UI::UIInputEvent& event : inputEvents) {
switch (event.type) {
case UIInputEventType::FocusLost:
currentOwner = {};
break;
case UIInputEventType::PointerButtonDown:
currentOwner = ResolveUIEditorWorkspacePointerInputOwner(
dockHostLayout,
contentHostFrame,
event.position);
break;
default:
break;
}
}
return NormalizeUIEditorWorkspaceInputOwner(
std::move(currentOwner),
dockHostLayout,
contentHostFrame);
}
} // namespace
UIEditorWorkspaceInteractionFrame UpdateUIEditorWorkspaceInteraction(
@@ -31,12 +66,44 @@ UIEditorWorkspaceInteractionFrame UpdateUIEditorWorkspaceInteraction(
const Widgets::UIEditorDockHostMetrics& dockHostMetrics,
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics) {
UIEditorWorkspaceInteractionFrame frame = {};
frame.previousInputOwner = state.inputOwner;
frame.dockHostFrame = UpdateUIEditorDockHostInteraction(
state.dockHostInteractionState,
controller,
bounds,
inputEvents,
dockHostMetrics);
const UIEditorWorkspaceComposeFrame previewComposeFrame = UpdateUIEditorWorkspaceCompose(
state.composeState,
bounds,
controller.GetPanelRegistry(),
controller.GetWorkspace(),
controller.GetSession(),
model.workspacePresentations,
{},
state.dockHostInteractionState.dockHostState,
dockHostMetrics,
viewportMetrics);
state.inputOwner = ResolveNextInputOwner(
state.inputOwner,
previewComposeFrame.dockHostLayout,
previewComposeFrame.contentHostFrame,
inputEvents);
frame.inputOwner = state.inputOwner;
frame.inputOwnerChanged = !AreUIEditorWorkspaceInputOwnersEquivalent(
frame.previousInputOwner,
frame.inputOwner);
state.dockHostInteractionState.dockHostState.focused =
IsUIEditorWorkspaceDockHostInputOwner(frame.inputOwner);
frame.dockHostFrame.layout = Widgets::BuildUIEditorDockHostLayout(
bounds,
controller.GetPanelRegistry(),
controller.GetWorkspace(),
controller.GetSession(),
state.dockHostInteractionState.dockHostState,
dockHostMetrics);
frame.dockHostFrame.focused = state.dockHostInteractionState.dockHostState.focused;
frame.composeFrame = UpdateUIEditorWorkspaceCompose(
state.composeState,
bounds,
@@ -47,7 +114,8 @@ UIEditorWorkspaceInteractionFrame UpdateUIEditorWorkspaceInteraction(
inputEvents,
state.dockHostInteractionState.dockHostState,
dockHostMetrics,
viewportMetrics);
viewportMetrics,
&frame.inputOwner);
frame.result.dockHostResult = frame.dockHostFrame.result;
frame.result.consumed = frame.dockHostFrame.result.consumed;