Unify dock leaves around single-tab stacks
This commit is contained in:
@@ -40,7 +40,7 @@ UIEditorWorkspaceModel BuildWorkspace() {
|
||||
"workspace-top",
|
||||
UIEditorWorkspaceSplitAxis::Horizontal,
|
||||
0.15f,
|
||||
BuildUIEditorWorkspacePanel(
|
||||
BuildUIEditorWorkspaceSingleTabStack(
|
||||
"hierarchy-panel",
|
||||
"hierarchy",
|
||||
"Hierarchy",
|
||||
@@ -64,7 +64,7 @@ UIEditorWorkspaceModel BuildWorkspace() {
|
||||
false)
|
||||
},
|
||||
0u),
|
||||
BuildUIEditorWorkspacePanel(
|
||||
BuildUIEditorWorkspaceSingleTabStack(
|
||||
"inspector-panel",
|
||||
"inspector",
|
||||
"Inspector",
|
||||
|
||||
@@ -96,15 +96,6 @@ struct UIEditorDockHostSplitterLayout {
|
||||
bool active = false;
|
||||
};
|
||||
|
||||
struct UIEditorDockHostPanelLayout {
|
||||
std::string nodeId = {};
|
||||
std::string panelId = {};
|
||||
std::string title = {};
|
||||
bool active = false;
|
||||
UIEditorPanelFrameState frameState = {};
|
||||
UIEditorPanelFrameLayout frameLayout = {};
|
||||
};
|
||||
|
||||
struct UIEditorDockHostTabStackLayout {
|
||||
std::string nodeId = {};
|
||||
std::string selectedPanelId = {};
|
||||
@@ -119,7 +110,6 @@ struct UIEditorDockHostTabStackLayout {
|
||||
struct UIEditorDockHostLayout {
|
||||
::XCEngine::UI::UIRect bounds = {};
|
||||
std::vector<UIEditorDockHostSplitterLayout> splitters = {};
|
||||
std::vector<UIEditorDockHostPanelLayout> panels = {};
|
||||
std::vector<UIEditorDockHostTabStackLayout> tabStacks = {};
|
||||
};
|
||||
|
||||
|
||||
@@ -78,6 +78,12 @@ UIEditorWorkspaceNode BuildUIEditorWorkspacePanel(
|
||||
std::string title,
|
||||
bool placeholder = false);
|
||||
|
||||
UIEditorWorkspaceNode BuildUIEditorWorkspaceSingleTabStack(
|
||||
std::string nodeId,
|
||||
std::string panelId,
|
||||
std::string title,
|
||||
bool placeholder = false);
|
||||
|
||||
UIEditorWorkspaceNode BuildUIEditorWorkspaceTabStack(
|
||||
std::string nodeId,
|
||||
std::vector<UIEditorWorkspaceNode> panels,
|
||||
@@ -93,6 +99,9 @@ UIEditorWorkspaceNode BuildUIEditorWorkspaceSplit(
|
||||
UIEditorWorkspaceValidationResult ValidateUIEditorWorkspace(
|
||||
const UIEditorWorkspaceModel& workspace);
|
||||
|
||||
UIEditorWorkspaceModel CanonicalizeUIEditorWorkspaceModel(
|
||||
UIEditorWorkspaceModel workspace);
|
||||
|
||||
std::vector<UIEditorWorkspaceVisiblePanel> CollectUIEditorWorkspaceVisiblePanels(
|
||||
const UIEditorWorkspaceModel& workspace);
|
||||
|
||||
|
||||
@@ -23,9 +23,6 @@ using ::XCEngine::UI::Layout::UITabStripMeasureItem;
|
||||
using ::XCEngine::UI::Layout::UILayoutAxis;
|
||||
using ::XCEngine::UI::Widgets::ExpandUISplitterHandleHitRect;
|
||||
|
||||
constexpr std::string_view kStandalonePanelActiveFooter = "";
|
||||
constexpr std::string_view kStandalonePanelInactiveFooter = "";
|
||||
|
||||
struct DockMeasureResult {
|
||||
bool visible = false;
|
||||
UISize minimumSize = {};
|
||||
@@ -102,17 +99,6 @@ UIEditorPanelFrameMetrics BuildTabContentFrameMetrics(
|
||||
return frameMetrics;
|
||||
}
|
||||
|
||||
UISize MeasurePanelMinimumSize(
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
const UIEditorPanelFrameMetrics& frameMetrics = metrics.panelFrameMetrics;
|
||||
return UISize(
|
||||
metrics.minimumStandalonePanelBodySize.width +
|
||||
ClampNonNegative(frameMetrics.contentPadding) * 2.0f,
|
||||
ClampNonNegative(frameMetrics.headerHeight) +
|
||||
metrics.minimumStandalonePanelBodySize.height +
|
||||
ClampNonNegative(frameMetrics.contentPadding) * 2.0f);
|
||||
}
|
||||
|
||||
UISize MeasureTabContentMinimumSize(
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
const UIEditorPanelFrameMetrics frameMetrics = BuildTabContentFrameMetrics(metrics);
|
||||
@@ -205,14 +191,8 @@ DockMeasureResult MeasureNodeRecursive(
|
||||
const UIEditorWorkspaceSession& session,
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
switch (node.kind) {
|
||||
case UIEditorWorkspaceNodeKind::Panel: {
|
||||
DockMeasureResult result = {};
|
||||
result.visible = IsPanelOpenAndVisible(session, node.panel.panelId);
|
||||
if (result.visible) {
|
||||
result.minimumSize = MeasurePanelMinimumSize(metrics);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
case UIEditorWorkspaceNodeKind::Panel:
|
||||
return {};
|
||||
case UIEditorWorkspaceNodeKind::TabStack:
|
||||
return MeasureTabStackNode(node, panelRegistry, session, metrics);
|
||||
case UIEditorWorkspaceNodeKind::Split:
|
||||
@@ -269,38 +249,6 @@ UIEditorTabStripState BuildTabStripState(
|
||||
return tabState;
|
||||
}
|
||||
|
||||
UIEditorPanelFrameState BuildStandalonePanelFrameState(
|
||||
const UIEditorDockHostState& state,
|
||||
const UIEditorWorkspaceModel& workspace,
|
||||
const UIEditorPanelDescriptor* descriptor,
|
||||
const UIEditorWorkspaceNode& node) {
|
||||
UIEditorPanelFrameState frameState = {};
|
||||
frameState.active = workspace.activePanelId == node.panel.panelId;
|
||||
frameState.focused = state.focused && frameState.active;
|
||||
frameState.closable = descriptor != nullptr ? descriptor->canClose : true;
|
||||
frameState.pinnable = false;
|
||||
frameState.showFooter = true;
|
||||
|
||||
if (state.hoveredTarget.panelId != node.panel.panelId) {
|
||||
return frameState;
|
||||
}
|
||||
|
||||
switch (state.hoveredTarget.kind) {
|
||||
case UIEditorDockHostHitTargetKind::PanelHeader:
|
||||
case UIEditorDockHostHitTargetKind::PanelBody:
|
||||
case UIEditorDockHostHitTargetKind::PanelFooter:
|
||||
case UIEditorDockHostHitTargetKind::PanelCloseButton:
|
||||
frameState.hovered = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
frameState.closeHovered =
|
||||
state.hoveredTarget.kind == UIEditorDockHostHitTargetKind::PanelCloseButton;
|
||||
return frameState;
|
||||
}
|
||||
|
||||
UIEditorPanelFrameState BuildTabContentFrameState(
|
||||
const UIEditorDockHostState& state,
|
||||
const UIEditorWorkspaceModel& workspace,
|
||||
@@ -338,29 +286,6 @@ void LayoutNodeRecursive(
|
||||
const UIEditorDockHostMetrics& metrics,
|
||||
UIEditorDockHostLayout& layout);
|
||||
|
||||
void LayoutPanelNode(
|
||||
const UIEditorWorkspaceNode& node,
|
||||
const UIRect& bounds,
|
||||
const UIEditorPanelRegistry& panelRegistry,
|
||||
const UIEditorWorkspaceModel& workspace,
|
||||
const UIEditorDockHostState& state,
|
||||
const UIEditorDockHostMetrics& metrics,
|
||||
UIEditorDockHostLayout& layout) {
|
||||
const UIEditorPanelDescriptor* descriptor =
|
||||
FindPanelDescriptor(panelRegistry, node.panel.panelId);
|
||||
|
||||
UIEditorDockHostPanelLayout panelLayout = {};
|
||||
panelLayout.nodeId = node.nodeId;
|
||||
panelLayout.panelId = node.panel.panelId;
|
||||
panelLayout.title = node.panel.title;
|
||||
panelLayout.active = workspace.activePanelId == node.panel.panelId;
|
||||
panelLayout.frameState =
|
||||
BuildStandalonePanelFrameState(state, workspace, descriptor, node);
|
||||
panelLayout.frameLayout =
|
||||
BuildUIEditorPanelFrameLayout(bounds, panelLayout.frameState, metrics.panelFrameMetrics);
|
||||
layout.panels.push_back(std::move(panelLayout));
|
||||
}
|
||||
|
||||
void LayoutTabStackNode(
|
||||
const UIEditorWorkspaceNode& node,
|
||||
const UIRect& bounds,
|
||||
@@ -525,9 +450,6 @@ void LayoutNodeRecursive(
|
||||
UIEditorDockHostLayout& layout) {
|
||||
switch (node.kind) {
|
||||
case UIEditorWorkspaceNodeKind::Panel:
|
||||
if (IsPanelOpenAndVisible(session, node.panel.panelId)) {
|
||||
LayoutPanelNode(node, bounds, panelRegistry, workspace, state, metrics, layout);
|
||||
}
|
||||
return;
|
||||
case UIEditorWorkspaceNodeKind::TabStack:
|
||||
LayoutTabStackNode(node, bounds, panelRegistry, workspace, session, state, metrics, layout);
|
||||
@@ -606,11 +528,13 @@ UIEditorDockHostLayout BuildUIEditorDockHostLayout(
|
||||
bounds.y,
|
||||
ClampNonNegative(bounds.width),
|
||||
ClampNonNegative(bounds.height));
|
||||
const UIEditorWorkspaceModel canonicalWorkspace =
|
||||
CanonicalizeUIEditorWorkspaceModel(workspace);
|
||||
LayoutNodeRecursive(
|
||||
workspace.root,
|
||||
canonicalWorkspace.root,
|
||||
layout.bounds,
|
||||
panelRegistry,
|
||||
workspace,
|
||||
canonicalWorkspace,
|
||||
session,
|
||||
state,
|
||||
metrics,
|
||||
@@ -675,17 +599,6 @@ UIEditorDockHostHitTarget HitTestUIEditorDockHost(
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t index = layout.panels.size(); index > 0u; --index) {
|
||||
const UIEditorDockHostPanelLayout& panel = layout.panels[index - 1u];
|
||||
const UIEditorPanelFrameHitTarget hitTarget = HitTestUIEditorPanelFrame(
|
||||
panel.frameLayout,
|
||||
panel.frameState,
|
||||
point);
|
||||
if (hitTarget != UIEditorPanelFrameHitTarget::None) {
|
||||
return MapPanelFrameHitTarget(hitTarget, panel.nodeId, panel.panelId);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -694,15 +607,6 @@ void AppendUIEditorDockHostBackground(
|
||||
const UIEditorDockHostLayout& layout,
|
||||
const UIEditorDockHostPalette& palette,
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
for (const UIEditorDockHostPanelLayout& panel : layout.panels) {
|
||||
AppendUIEditorPanelFrameBackground(
|
||||
drawList,
|
||||
panel.frameLayout,
|
||||
panel.frameState,
|
||||
palette.panelFramePalette,
|
||||
metrics.panelFrameMetrics);
|
||||
}
|
||||
|
||||
const UIEditorPanelFrameMetrics tabContentFrameMetrics =
|
||||
BuildTabContentFrameMetrics(metrics);
|
||||
for (const UIEditorDockHostTabStackLayout& tabStack : layout.tabStacks) {
|
||||
@@ -744,23 +648,6 @@ void AppendUIEditorDockHostForeground(
|
||||
const UIEditorDockHostForegroundOptions& options,
|
||||
const UIEditorDockHostPalette& palette,
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
for (const UIEditorDockHostPanelLayout& panel : layout.panels) {
|
||||
AppendUIEditorPanelFrameForeground(
|
||||
drawList,
|
||||
panel.frameLayout,
|
||||
panel.frameState,
|
||||
UIEditorPanelFrameText{
|
||||
panel.title,
|
||||
{},
|
||||
panel.active ? kStandalonePanelActiveFooter : kStandalonePanelInactiveFooter
|
||||
},
|
||||
palette.panelFramePalette,
|
||||
metrics.panelFrameMetrics);
|
||||
if (UsesExternalBodyPresentation(options, panel.panelId)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const UIEditorPanelFrameMetrics tabContentFrameMetrics =
|
||||
BuildTabContentFrameMetrics(metrics);
|
||||
for (const UIEditorDockHostTabStackLayout& tabStack : layout.tabStacks) {
|
||||
|
||||
@@ -12,12 +12,6 @@ namespace {
|
||||
const ::XCEngine::UI::UIRect* FindVisiblePanelBodyRect(
|
||||
const Widgets::UIEditorDockHostLayout& layout,
|
||||
std::string_view panelId) {
|
||||
for (const Widgets::UIEditorDockHostPanelLayout& panel : layout.panels) {
|
||||
if (panel.panelId == panelId) {
|
||||
return &panel.frameLayout.bodyRect;
|
||||
}
|
||||
}
|
||||
|
||||
for (const Widgets::UIEditorDockHostTabStackLayout& tabStack : layout.tabStacks) {
|
||||
if (tabStack.selectedPanelId == panelId) {
|
||||
return &tabStack.contentFrameLayout.bodyRect;
|
||||
|
||||
@@ -75,9 +75,9 @@ UIEditorWorkspaceController::UIEditorWorkspaceController(
|
||||
UIEditorWorkspaceModel workspace,
|
||||
UIEditorWorkspaceSession session)
|
||||
: m_panelRegistry(std::move(panelRegistry))
|
||||
, m_baselineWorkspace(workspace)
|
||||
, m_baselineWorkspace(CanonicalizeUIEditorWorkspaceModel(workspace))
|
||||
, m_baselineSession(session)
|
||||
, m_workspace(std::move(workspace))
|
||||
, m_workspace(m_baselineWorkspace)
|
||||
, m_session(std::move(session)) {
|
||||
}
|
||||
|
||||
@@ -178,6 +178,10 @@ const UIEditorPanelDescriptor* UIEditorWorkspaceController::FindPanelDescriptor(
|
||||
|
||||
UIEditorWorkspaceLayoutOperationResult UIEditorWorkspaceController::RestoreLayoutSnapshot(
|
||||
const UIEditorWorkspaceLayoutSnapshot& snapshot) {
|
||||
UIEditorWorkspaceLayoutSnapshot canonicalSnapshot = snapshot;
|
||||
canonicalSnapshot.workspace =
|
||||
CanonicalizeUIEditorWorkspaceModel(std::move(canonicalSnapshot.workspace));
|
||||
|
||||
const UIEditorPanelRegistryValidationResult registryValidation =
|
||||
ValidateUIEditorPanelRegistry(m_panelRegistry);
|
||||
if (!registryValidation.IsValid()) {
|
||||
@@ -187,7 +191,7 @@ UIEditorWorkspaceLayoutOperationResult UIEditorWorkspaceController::RestoreLayou
|
||||
}
|
||||
|
||||
const UIEditorWorkspaceValidationResult workspaceValidation =
|
||||
ValidateUIEditorWorkspace(snapshot.workspace);
|
||||
ValidateUIEditorWorkspace(canonicalSnapshot.workspace);
|
||||
if (!workspaceValidation.IsValid()) {
|
||||
return BuildLayoutOperationResult(
|
||||
UIEditorWorkspaceLayoutOperationStatus::Rejected,
|
||||
@@ -195,15 +199,18 @@ UIEditorWorkspaceLayoutOperationResult UIEditorWorkspaceController::RestoreLayou
|
||||
}
|
||||
|
||||
const UIEditorWorkspaceSessionValidationResult sessionValidation =
|
||||
ValidateUIEditorWorkspaceSession(m_panelRegistry, snapshot.workspace, snapshot.session);
|
||||
ValidateUIEditorWorkspaceSession(
|
||||
m_panelRegistry,
|
||||
canonicalSnapshot.workspace,
|
||||
canonicalSnapshot.session);
|
||||
if (!sessionValidation.IsValid()) {
|
||||
return BuildLayoutOperationResult(
|
||||
UIEditorWorkspaceLayoutOperationStatus::Rejected,
|
||||
"Layout session invalid: " + sessionValidation.message);
|
||||
}
|
||||
|
||||
if (AreUIEditorWorkspaceModelsEquivalent(m_workspace, snapshot.workspace) &&
|
||||
AreUIEditorWorkspaceSessionsEquivalent(m_session, snapshot.session)) {
|
||||
if (AreUIEditorWorkspaceModelsEquivalent(m_workspace, canonicalSnapshot.workspace) &&
|
||||
AreUIEditorWorkspaceSessionsEquivalent(m_session, canonicalSnapshot.session)) {
|
||||
return BuildLayoutOperationResult(
|
||||
UIEditorWorkspaceLayoutOperationStatus::NoOp,
|
||||
"Current state already matches the requested layout snapshot.");
|
||||
@@ -211,8 +218,8 @@ UIEditorWorkspaceLayoutOperationResult UIEditorWorkspaceController::RestoreLayou
|
||||
|
||||
const UIEditorWorkspaceModel previousWorkspace = m_workspace;
|
||||
const UIEditorWorkspaceSession previousSession = m_session;
|
||||
m_workspace = snapshot.workspace;
|
||||
m_session = snapshot.session;
|
||||
m_workspace = canonicalSnapshot.workspace;
|
||||
m_session = canonicalSnapshot.session;
|
||||
|
||||
const UIEditorWorkspaceControllerValidationResult validation = ValidateState();
|
||||
if (!validation.IsValid()) {
|
||||
@@ -441,10 +448,12 @@ UIEditorWorkspaceCommandResult UIEditorWorkspaceController::Dispatch(
|
||||
UIEditorWorkspaceController BuildDefaultUIEditorWorkspaceController(
|
||||
const UIEditorPanelRegistry& panelRegistry,
|
||||
const UIEditorWorkspaceModel& workspace) {
|
||||
const UIEditorWorkspaceModel canonicalWorkspace =
|
||||
CanonicalizeUIEditorWorkspaceModel(workspace);
|
||||
return UIEditorWorkspaceController(
|
||||
panelRegistry,
|
||||
workspace,
|
||||
BuildDefaultUIEditorWorkspaceSession(panelRegistry, workspace));
|
||||
canonicalWorkspace,
|
||||
BuildDefaultUIEditorWorkspaceSession(panelRegistry, canonicalWorkspace));
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor
|
||||
|
||||
@@ -391,7 +391,7 @@ UIEditorWorkspaceLayoutSnapshot BuildUIEditorWorkspaceLayoutSnapshot(
|
||||
const UIEditorWorkspaceModel& workspace,
|
||||
const UIEditorWorkspaceSession& session) {
|
||||
UIEditorWorkspaceLayoutSnapshot snapshot = {};
|
||||
snapshot.workspace = workspace;
|
||||
snapshot.workspace = CanonicalizeUIEditorWorkspaceModel(workspace);
|
||||
snapshot.session = session;
|
||||
return snapshot;
|
||||
}
|
||||
@@ -461,6 +461,8 @@ UIEditorWorkspaceLayoutLoadResult DeserializeUIEditorWorkspaceLayoutSnapshot(
|
||||
return rootResult;
|
||||
}
|
||||
|
||||
snapshot.workspace = CanonicalizeUIEditorWorkspaceModel(std::move(snapshot.workspace));
|
||||
|
||||
snapshot.session.panelStates.clear();
|
||||
while (index < lines.size()) {
|
||||
UIEditorPanelSessionState state = {};
|
||||
|
||||
@@ -22,6 +22,55 @@ bool IsValidSplitRatio(float value) {
|
||||
return std::isfinite(value) && value > 0.0f && value < 1.0f;
|
||||
}
|
||||
|
||||
std::string BuildSingleTabPanelNodeId(std::string_view stackNodeId) {
|
||||
if (stackNodeId.empty()) {
|
||||
return "single-tab-panel";
|
||||
}
|
||||
|
||||
return std::string(stackNodeId) + "__panel";
|
||||
}
|
||||
|
||||
UIEditorWorkspaceNode WrapStandalonePanelAsTabStack(UIEditorWorkspaceNode panelNode) {
|
||||
UIEditorWorkspaceNode panelChild = std::move(panelNode);
|
||||
const std::string stackNodeId = panelChild.nodeId;
|
||||
panelChild.nodeId = BuildSingleTabPanelNodeId(stackNodeId);
|
||||
|
||||
UIEditorWorkspaceNode tabStack = {};
|
||||
tabStack.kind = UIEditorWorkspaceNodeKind::TabStack;
|
||||
tabStack.nodeId = stackNodeId;
|
||||
tabStack.selectedTabIndex = 0u;
|
||||
tabStack.children.push_back(std::move(panelChild));
|
||||
return tabStack;
|
||||
}
|
||||
|
||||
void CanonicalizeNodeRecursive(
|
||||
UIEditorWorkspaceNode& node,
|
||||
bool allowStandalonePanelLeaf) {
|
||||
if (node.kind == UIEditorWorkspaceNodeKind::Panel) {
|
||||
if (!allowStandalonePanelLeaf) {
|
||||
node = WrapStandalonePanelAsTabStack(std::move(node));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (UIEditorWorkspaceNode& child : node.children) {
|
||||
CanonicalizeNodeRecursive(
|
||||
child,
|
||||
node.kind == UIEditorWorkspaceNodeKind::TabStack);
|
||||
}
|
||||
|
||||
if (node.kind == UIEditorWorkspaceNodeKind::TabStack &&
|
||||
!node.children.empty() &&
|
||||
node.selectedTabIndex >= node.children.size()) {
|
||||
node.selectedTabIndex = node.children.size() - 1u;
|
||||
}
|
||||
|
||||
if (node.kind == UIEditorWorkspaceNodeKind::Split &&
|
||||
node.children.size() == 1u) {
|
||||
node = std::move(node.children.front());
|
||||
}
|
||||
}
|
||||
|
||||
const UIEditorPanelDescriptor& RequirePanelDescriptor(
|
||||
const UIEditorPanelRegistry& registry,
|
||||
std::string_view panelId) {
|
||||
@@ -274,7 +323,7 @@ UIEditorWorkspaceModel BuildDefaultEditorShellWorkspaceModel() {
|
||||
RequirePanelDescriptor(registry, "editor-foundation-root");
|
||||
|
||||
UIEditorWorkspaceModel workspace = {};
|
||||
workspace.root = BuildUIEditorWorkspacePanel(
|
||||
workspace.root = BuildUIEditorWorkspaceSingleTabStack(
|
||||
"editor-foundation-root-node",
|
||||
rootPanel.panelId,
|
||||
rootPanel.defaultTitle,
|
||||
@@ -297,6 +346,22 @@ UIEditorWorkspaceNode BuildUIEditorWorkspacePanel(
|
||||
return node;
|
||||
}
|
||||
|
||||
UIEditorWorkspaceNode BuildUIEditorWorkspaceSingleTabStack(
|
||||
std::string nodeId,
|
||||
std::string panelId,
|
||||
std::string title,
|
||||
bool placeholder) {
|
||||
UIEditorWorkspaceNode panel = BuildUIEditorWorkspacePanel(
|
||||
BuildSingleTabPanelNodeId(nodeId),
|
||||
std::move(panelId),
|
||||
std::move(title),
|
||||
placeholder);
|
||||
return BuildUIEditorWorkspaceTabStack(
|
||||
std::move(nodeId),
|
||||
{ std::move(panel) },
|
||||
0u);
|
||||
}
|
||||
|
||||
UIEditorWorkspaceNode BuildUIEditorWorkspaceTabStack(
|
||||
std::string nodeId,
|
||||
std::vector<UIEditorWorkspaceNode> panels,
|
||||
@@ -345,6 +410,12 @@ UIEditorWorkspaceValidationResult ValidateUIEditorWorkspace(
|
||||
return {};
|
||||
}
|
||||
|
||||
UIEditorWorkspaceModel CanonicalizeUIEditorWorkspaceModel(
|
||||
UIEditorWorkspaceModel workspace) {
|
||||
CanonicalizeNodeRecursive(workspace.root, false);
|
||||
return workspace;
|
||||
}
|
||||
|
||||
std::vector<UIEditorWorkspaceVisiblePanel> CollectUIEditorWorkspaceVisiblePanels(
|
||||
const UIEditorWorkspaceModel& workspace) {
|
||||
std::vector<UIEditorWorkspaceVisiblePanel> visiblePanels = {};
|
||||
|
||||
Reference in New Issue
Block a user