refactor(new_editor/docking): split dock host rendering and hit testing
This commit is contained in:
@@ -67,6 +67,8 @@ set(XCUI_EDITOR_COLLECTION_SOURCES
|
||||
|
||||
set(XCUI_EDITOR_DOCKING_SOURCES
|
||||
src/Docking/UIEditorDockHost.cpp
|
||||
src/Docking/UIEditorDockHostHitTest.cpp
|
||||
src/Docking/UIEditorDockHostRendering.cpp
|
||||
src/Docking/UIEditorDockHostInteraction.cpp
|
||||
)
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <XCEngine/UI/Widgets/UISplitterInteraction.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -11,9 +10,6 @@ namespace XCEngine::UI::Editor::Widgets {
|
||||
|
||||
namespace {
|
||||
|
||||
using ::XCEngine::UI::UIColor;
|
||||
using ::XCEngine::UI::UIDrawList;
|
||||
using ::XCEngine::UI::UIPoint;
|
||||
using ::XCEngine::UI::UIRect;
|
||||
using ::XCEngine::UI::UISize;
|
||||
using ::XCEngine::UI::Layout::ArrangeUISplitter;
|
||||
@@ -42,36 +38,6 @@ float GetMainExtent(const UISize& size, UIEditorWorkspaceSplitAxis axis) {
|
||||
return axis == UIEditorWorkspaceSplitAxis::Horizontal ? size.width : size.height;
|
||||
}
|
||||
|
||||
bool IsPointInsideRect(
|
||||
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 UsesExternalBodyPresentation(
|
||||
const UIEditorDockHostForegroundOptions& options,
|
||||
std::string_view panelId) {
|
||||
return std::find(
|
||||
options.externalBodyPanelIds.begin(),
|
||||
options.externalBodyPanelIds.end(),
|
||||
panelId) != options.externalBodyPanelIds.end();
|
||||
}
|
||||
|
||||
const UIEditorDockHostTabStripVisualState* FindTabStripVisualState(
|
||||
const UIEditorDockHostState& state,
|
||||
std::string_view nodeId) {
|
||||
for (const UIEditorDockHostTabStripVisualState& entry : state.tabStripStates) {
|
||||
if (entry.nodeId == nodeId) {
|
||||
return &entry;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool IsPanelOpenAndVisible(
|
||||
const UIEditorWorkspaceSession& session,
|
||||
std::string_view panelId) {
|
||||
@@ -146,7 +112,8 @@ DockMeasureResult MeasureTabStackNode(
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto measured = MeasureUITabStrip(measureItems, metrics.tabStripMetrics.layoutMetrics);
|
||||
const auto measured =
|
||||
MeasureUITabStrip(measureItems, metrics.tabStripMetrics.layoutMetrics);
|
||||
DockMeasureResult result = {};
|
||||
result.visible = true;
|
||||
result.minimumSize = measured.minimumSize;
|
||||
@@ -218,6 +185,18 @@ std::size_t ResolveSelectedVisibleTabIndex(
|
||||
return 0u;
|
||||
}
|
||||
|
||||
const UIEditorDockHostTabStripVisualState* FindTabStripVisualState(
|
||||
const UIEditorDockHostState& state,
|
||||
std::string_view nodeId) {
|
||||
for (const UIEditorDockHostTabStripVisualState& entry : state.tabStripStates) {
|
||||
if (entry.nodeId == nodeId) {
|
||||
return &entry;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UIEditorTabStripState BuildTabStripState(
|
||||
const UIEditorDockHostState& state,
|
||||
std::string_view nodeId,
|
||||
@@ -230,7 +209,8 @@ UIEditorTabStripState BuildTabStripState(
|
||||
}
|
||||
tabState.selectedIndex = selectedIndex;
|
||||
|
||||
if (FindTabStripVisualState(state, nodeId) != nullptr || state.hoveredTarget.nodeId != nodeId) {
|
||||
if (FindTabStripVisualState(state, nodeId) != nullptr ||
|
||||
state.hoveredTarget.nodeId != nodeId) {
|
||||
return tabState;
|
||||
}
|
||||
|
||||
@@ -338,10 +318,15 @@ void LayoutTabStackNode(
|
||||
tabStackLayout.items[selectedVisibleIndex].panelId;
|
||||
tabStackLayout.tabStripState =
|
||||
BuildTabStripState(state, node.nodeId, selectedVisibleIndex);
|
||||
tabStackLayout.tabStripLayout =
|
||||
BuildUIEditorTabStripLayout(bounds, tabStripItems, tabStackLayout.tabStripState, metrics.tabStripMetrics);
|
||||
tabStackLayout.contentFrameState =
|
||||
BuildTabContentFrameState(state, workspace, tabStackLayout.selectedPanelId);
|
||||
tabStackLayout.tabStripLayout = BuildUIEditorTabStripLayout(
|
||||
bounds,
|
||||
tabStripItems,
|
||||
tabStackLayout.tabStripState,
|
||||
metrics.tabStripMetrics);
|
||||
tabStackLayout.contentFrameState = BuildTabContentFrameState(
|
||||
state,
|
||||
workspace,
|
||||
tabStackLayout.selectedPanelId);
|
||||
tabStackLayout.contentFrameLayout = BuildUIEditorPanelFrameLayout(
|
||||
tabStackLayout.tabStripLayout.contentRect,
|
||||
tabStackLayout.contentFrameState,
|
||||
@@ -412,7 +397,10 @@ void LayoutSplitNode(
|
||||
splitterLayout.handleHitRect = ExpandUISplitterHandleHitRect(
|
||||
splitterLayout.splitterLayout.handleRect,
|
||||
ToLayoutAxis(node.splitAxis),
|
||||
(std::max)(0.0f, (splitterLayout.metrics.hitThickness - splitterLayout.metrics.thickness) * 0.5f));
|
||||
(std::max)(
|
||||
0.0f,
|
||||
(splitterLayout.metrics.hitThickness -
|
||||
splitterLayout.metrics.thickness) * 0.5f));
|
||||
splitterLayout.hovered =
|
||||
state.hoveredTarget.kind == UIEditorDockHostHitTargetKind::SplitterHandle &&
|
||||
state.hoveredTarget.nodeId == node.nodeId;
|
||||
@@ -452,55 +440,30 @@ void LayoutNodeRecursive(
|
||||
case UIEditorWorkspaceNodeKind::Panel:
|
||||
return;
|
||||
case UIEditorWorkspaceNodeKind::TabStack:
|
||||
LayoutTabStackNode(node, bounds, panelRegistry, workspace, session, state, metrics, layout);
|
||||
LayoutTabStackNode(
|
||||
node,
|
||||
bounds,
|
||||
panelRegistry,
|
||||
workspace,
|
||||
session,
|
||||
state,
|
||||
metrics,
|
||||
layout);
|
||||
return;
|
||||
case UIEditorWorkspaceNodeKind::Split:
|
||||
LayoutSplitNode(node, bounds, panelRegistry, workspace, session, state, metrics, layout);
|
||||
LayoutSplitNode(
|
||||
node,
|
||||
bounds,
|
||||
panelRegistry,
|
||||
workspace,
|
||||
session,
|
||||
state,
|
||||
metrics,
|
||||
layout);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
UIEditorDockHostHitTarget MakePanelHitTarget(
|
||||
UIEditorDockHostHitTargetKind kind,
|
||||
std::string_view nodeId,
|
||||
std::string_view panelId) {
|
||||
UIEditorDockHostHitTarget target = {};
|
||||
target.kind = kind;
|
||||
target.nodeId = std::string(nodeId);
|
||||
target.panelId = std::string(panelId);
|
||||
return target;
|
||||
}
|
||||
|
||||
UIEditorDockHostHitTarget MapPanelFrameHitTarget(
|
||||
UIEditorPanelFrameHitTarget hitTarget,
|
||||
std::string_view nodeId,
|
||||
std::string_view panelId) {
|
||||
switch (hitTarget) {
|
||||
case UIEditorPanelFrameHitTarget::Header:
|
||||
return MakePanelHitTarget(UIEditorDockHostHitTargetKind::PanelHeader, nodeId, panelId);
|
||||
case UIEditorPanelFrameHitTarget::Body:
|
||||
return MakePanelHitTarget(UIEditorDockHostHitTargetKind::PanelBody, nodeId, panelId);
|
||||
case UIEditorPanelFrameHitTarget::Footer:
|
||||
return MakePanelHitTarget(UIEditorDockHostHitTargetKind::PanelFooter, nodeId, panelId);
|
||||
case UIEditorPanelFrameHitTarget::CloseButton:
|
||||
return MakePanelHitTarget(UIEditorDockHostHitTargetKind::PanelCloseButton, nodeId, panelId);
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
UIColor ResolveSplitterColor(const UIEditorDockHostSplitterLayout& splitter, const UIEditorDockHostPalette& palette) {
|
||||
if (splitter.active) {
|
||||
return palette.splitterActiveColor;
|
||||
}
|
||||
|
||||
if (splitter.hovered) {
|
||||
return palette.splitterHoveredColor;
|
||||
}
|
||||
|
||||
return palette.splitterColor;
|
||||
}
|
||||
|
||||
const UIEditorDockHostTabStackLayout* FindTabStackLayoutByNodeId(
|
||||
const UIEditorDockHostLayout& layout,
|
||||
std::string_view nodeId) {
|
||||
@@ -530,11 +493,7 @@ UIRect ResolveDropPreviewRect(
|
||||
const UIRect bounds = tabStack.bounds;
|
||||
switch (placement) {
|
||||
case UIEditorWorkspaceDockPlacement::Left:
|
||||
return UIRect(
|
||||
bounds.x,
|
||||
bounds.y,
|
||||
bounds.width * 0.35f,
|
||||
bounds.height);
|
||||
return UIRect(bounds.x, bounds.y, bounds.width * 0.35f, bounds.height);
|
||||
case UIEditorWorkspaceDockPlacement::Right:
|
||||
return UIRect(
|
||||
bounds.x + bounds.width * 0.65f,
|
||||
@@ -542,11 +501,7 @@ UIRect ResolveDropPreviewRect(
|
||||
bounds.width * 0.35f,
|
||||
bounds.height);
|
||||
case UIEditorWorkspaceDockPlacement::Top:
|
||||
return UIRect(
|
||||
bounds.x,
|
||||
bounds.y,
|
||||
bounds.width,
|
||||
bounds.height * 0.35f);
|
||||
return UIRect(bounds.x, bounds.y, bounds.width, bounds.height * 0.35f);
|
||||
case UIEditorWorkspaceDockPlacement::Bottom:
|
||||
return UIRect(
|
||||
bounds.x,
|
||||
@@ -653,187 +608,4 @@ UIEditorDockHostLayout BuildUIEditorDockHostLayout(
|
||||
return layout;
|
||||
}
|
||||
|
||||
UIEditorDockHostHitTarget HitTestUIEditorDockHost(
|
||||
const UIEditorDockHostLayout& layout,
|
||||
const UIPoint& point) {
|
||||
for (std::size_t index = layout.splitters.size(); index > 0u; --index) {
|
||||
const UIEditorDockHostSplitterLayout& splitter = layout.splitters[index - 1u];
|
||||
if (IsPointInsideRect(splitter.handleHitRect, point)) {
|
||||
UIEditorDockHostHitTarget target = {};
|
||||
target.kind = UIEditorDockHostHitTargetKind::SplitterHandle;
|
||||
target.nodeId = splitter.nodeId;
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t index = layout.tabStacks.size(); index > 0u; --index) {
|
||||
const UIEditorDockHostTabStackLayout& tabStack = layout.tabStacks[index - 1u];
|
||||
const UIEditorTabStripHitTarget tabHit =
|
||||
HitTestUIEditorTabStrip(tabStack.tabStripLayout, tabStack.tabStripState, point);
|
||||
switch (tabHit.kind) {
|
||||
case UIEditorTabStripHitTargetKind::CloseButton: {
|
||||
UIEditorDockHostHitTarget target = {};
|
||||
target.kind = UIEditorDockHostHitTargetKind::TabCloseButton;
|
||||
target.nodeId = tabStack.nodeId;
|
||||
target.index = tabHit.index;
|
||||
if (tabHit.index < tabStack.items.size()) {
|
||||
target.panelId = tabStack.items[tabHit.index].panelId;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
case UIEditorTabStripHitTargetKind::Tab: {
|
||||
UIEditorDockHostHitTarget target = {};
|
||||
target.kind = UIEditorDockHostHitTargetKind::Tab;
|
||||
target.nodeId = tabStack.nodeId;
|
||||
target.index = tabHit.index;
|
||||
if (tabHit.index < tabStack.items.size()) {
|
||||
target.panelId = tabStack.items[tabHit.index].panelId;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
case UIEditorTabStripHitTargetKind::HeaderBackground: {
|
||||
UIEditorDockHostHitTarget target = {};
|
||||
target.kind = UIEditorDockHostHitTargetKind::TabStripBackground;
|
||||
target.nodeId = tabStack.nodeId;
|
||||
return target;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const UIEditorPanelFrameHitTarget panelHit = HitTestUIEditorPanelFrame(
|
||||
tabStack.contentFrameLayout,
|
||||
tabStack.contentFrameState,
|
||||
point);
|
||||
if (panelHit != UIEditorPanelFrameHitTarget::None) {
|
||||
return MapPanelFrameHitTarget(panelHit, tabStack.nodeId, tabStack.selectedPanelId);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void AppendUIEditorDockHostBackground(
|
||||
UIDrawList& drawList,
|
||||
const UIEditorDockHostLayout& layout,
|
||||
const UIEditorDockHostPalette& palette,
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
for (const UIEditorDockHostTabStackLayout& tabStack : layout.tabStacks) {
|
||||
std::vector<UIEditorTabStripItem> tabItems = {};
|
||||
tabItems.reserve(tabStack.items.size());
|
||||
for (const UIEditorDockHostTabItemLayout& item : tabStack.items) {
|
||||
UIEditorTabStripItem tabItem = {};
|
||||
tabItem.tabId = item.panelId;
|
||||
tabItem.title = item.title;
|
||||
tabItem.closable = item.closable;
|
||||
tabItems.push_back(std::move(tabItem));
|
||||
}
|
||||
|
||||
AppendUIEditorTabStripBackground(
|
||||
drawList,
|
||||
tabStack.tabStripLayout,
|
||||
tabStack.tabStripState,
|
||||
palette.tabStripPalette,
|
||||
metrics.tabStripMetrics);
|
||||
}
|
||||
|
||||
for (const UIEditorDockHostSplitterLayout& splitter : layout.splitters) {
|
||||
drawList.AddFilledRect(
|
||||
splitter.splitterLayout.handleRect,
|
||||
ResolveSplitterColor(splitter, palette),
|
||||
metrics.splitterHandleRounding);
|
||||
}
|
||||
}
|
||||
|
||||
void AppendUIEditorDockHostForeground(
|
||||
UIDrawList& drawList,
|
||||
const UIEditorDockHostLayout& layout,
|
||||
const UIEditorDockHostForegroundOptions& options,
|
||||
const UIEditorDockHostPalette& palette,
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
for (const UIEditorDockHostTabStackLayout& tabStack : layout.tabStacks) {
|
||||
std::vector<UIEditorTabStripItem> tabItems = {};
|
||||
tabItems.reserve(tabStack.items.size());
|
||||
for (const UIEditorDockHostTabItemLayout& item : tabStack.items) {
|
||||
UIEditorTabStripItem tabItem = {};
|
||||
tabItem.tabId = item.panelId;
|
||||
tabItem.title = item.title;
|
||||
tabItem.closable = item.closable;
|
||||
tabItems.push_back(std::move(tabItem));
|
||||
}
|
||||
|
||||
AppendUIEditorTabStripForeground(
|
||||
drawList,
|
||||
tabStack.tabStripLayout,
|
||||
tabItems,
|
||||
tabStack.tabStripState,
|
||||
palette.tabStripPalette,
|
||||
metrics.tabStripMetrics);
|
||||
|
||||
if (UsesExternalBodyPresentation(options, tabStack.selectedPanelId)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (layout.dropPreview.visible) {
|
||||
drawList.AddFilledRect(
|
||||
layout.dropPreview.previewRect,
|
||||
palette.dropPreviewFillColor);
|
||||
drawList.AddRectOutline(
|
||||
layout.dropPreview.previewRect,
|
||||
palette.dropPreviewBorderColor,
|
||||
1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void AppendUIEditorDockHostForeground(
|
||||
UIDrawList& drawList,
|
||||
const UIEditorDockHostLayout& layout,
|
||||
const UIEditorDockHostPalette& palette,
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
AppendUIEditorDockHostForeground(
|
||||
drawList,
|
||||
layout,
|
||||
UIEditorDockHostForegroundOptions{},
|
||||
palette,
|
||||
metrics);
|
||||
}
|
||||
|
||||
void AppendUIEditorDockHost(
|
||||
UIDrawList& drawList,
|
||||
const UIRect& bounds,
|
||||
const UIEditorPanelRegistry& panelRegistry,
|
||||
const UIEditorWorkspaceModel& workspace,
|
||||
const UIEditorWorkspaceSession& session,
|
||||
const UIEditorDockHostState& state,
|
||||
const UIEditorDockHostForegroundOptions& foregroundOptions,
|
||||
const UIEditorDockHostPalette& palette,
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
const UIEditorDockHostLayout layout =
|
||||
BuildUIEditorDockHostLayout(bounds, panelRegistry, workspace, session, state, metrics);
|
||||
AppendUIEditorDockHostBackground(drawList, layout, palette, metrics);
|
||||
AppendUIEditorDockHostForeground(drawList, layout, foregroundOptions, palette, metrics);
|
||||
}
|
||||
|
||||
void AppendUIEditorDockHost(
|
||||
UIDrawList& drawList,
|
||||
const UIRect& bounds,
|
||||
const UIEditorPanelRegistry& panelRegistry,
|
||||
const UIEditorWorkspaceModel& workspace,
|
||||
const UIEditorWorkspaceSession& session,
|
||||
const UIEditorDockHostState& state,
|
||||
const UIEditorDockHostPalette& palette,
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
AppendUIEditorDockHost(
|
||||
drawList,
|
||||
bounds,
|
||||
panelRegistry,
|
||||
workspace,
|
||||
session,
|
||||
state,
|
||||
UIEditorDockHostForegroundOptions{},
|
||||
palette,
|
||||
metrics);
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor::Widgets
|
||||
|
||||
116
new_editor/src/Docking/UIEditorDockHostHitTest.cpp
Normal file
116
new_editor/src/Docking/UIEditorDockHostHitTest.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
#include <XCEditor/Docking/UIEditorDockHost.h>
|
||||
|
||||
namespace XCEngine::UI::Editor::Widgets {
|
||||
|
||||
namespace {
|
||||
|
||||
using ::XCEngine::UI::UIPoint;
|
||||
using ::XCEngine::UI::UIRect;
|
||||
|
||||
bool IsPointInsideRect(
|
||||
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;
|
||||
}
|
||||
|
||||
UIEditorDockHostHitTarget MakePanelHitTarget(
|
||||
UIEditorDockHostHitTargetKind kind,
|
||||
std::string_view nodeId,
|
||||
std::string_view panelId) {
|
||||
UIEditorDockHostHitTarget target = {};
|
||||
target.kind = kind;
|
||||
target.nodeId = std::string(nodeId);
|
||||
target.panelId = std::string(panelId);
|
||||
return target;
|
||||
}
|
||||
|
||||
UIEditorDockHostHitTarget MapPanelFrameHitTarget(
|
||||
UIEditorPanelFrameHitTarget hitTarget,
|
||||
std::string_view nodeId,
|
||||
std::string_view panelId) {
|
||||
switch (hitTarget) {
|
||||
case UIEditorPanelFrameHitTarget::Header:
|
||||
return MakePanelHitTarget(UIEditorDockHostHitTargetKind::PanelHeader, nodeId, panelId);
|
||||
case UIEditorPanelFrameHitTarget::Body:
|
||||
return MakePanelHitTarget(UIEditorDockHostHitTargetKind::PanelBody, nodeId, panelId);
|
||||
case UIEditorPanelFrameHitTarget::Footer:
|
||||
return MakePanelHitTarget(UIEditorDockHostHitTargetKind::PanelFooter, nodeId, panelId);
|
||||
case UIEditorPanelFrameHitTarget::CloseButton:
|
||||
return MakePanelHitTarget(
|
||||
UIEditorDockHostHitTargetKind::PanelCloseButton,
|
||||
nodeId,
|
||||
panelId);
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
UIEditorDockHostHitTarget HitTestUIEditorDockHost(
|
||||
const UIEditorDockHostLayout& layout,
|
||||
const UIPoint& point) {
|
||||
for (std::size_t index = layout.splitters.size(); index > 0u; --index) {
|
||||
const UIEditorDockHostSplitterLayout& splitter = layout.splitters[index - 1u];
|
||||
if (IsPointInsideRect(splitter.handleHitRect, point)) {
|
||||
UIEditorDockHostHitTarget target = {};
|
||||
target.kind = UIEditorDockHostHitTargetKind::SplitterHandle;
|
||||
target.nodeId = splitter.nodeId;
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t index = layout.tabStacks.size(); index > 0u; --index) {
|
||||
const UIEditorDockHostTabStackLayout& tabStack = layout.tabStacks[index - 1u];
|
||||
const UIEditorTabStripHitTarget tabHit =
|
||||
HitTestUIEditorTabStrip(tabStack.tabStripLayout, tabStack.tabStripState, point);
|
||||
switch (tabHit.kind) {
|
||||
case UIEditorTabStripHitTargetKind::CloseButton: {
|
||||
UIEditorDockHostHitTarget target = {};
|
||||
target.kind = UIEditorDockHostHitTargetKind::TabCloseButton;
|
||||
target.nodeId = tabStack.nodeId;
|
||||
target.index = tabHit.index;
|
||||
if (tabHit.index < tabStack.items.size()) {
|
||||
target.panelId = tabStack.items[tabHit.index].panelId;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
case UIEditorTabStripHitTargetKind::Tab: {
|
||||
UIEditorDockHostHitTarget target = {};
|
||||
target.kind = UIEditorDockHostHitTargetKind::Tab;
|
||||
target.nodeId = tabStack.nodeId;
|
||||
target.index = tabHit.index;
|
||||
if (tabHit.index < tabStack.items.size()) {
|
||||
target.panelId = tabStack.items[tabHit.index].panelId;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
case UIEditorTabStripHitTargetKind::HeaderBackground: {
|
||||
UIEditorDockHostHitTarget target = {};
|
||||
target.kind = UIEditorDockHostHitTargetKind::TabStripBackground;
|
||||
target.nodeId = tabStack.nodeId;
|
||||
return target;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const UIEditorPanelFrameHitTarget panelHit = HitTestUIEditorPanelFrame(
|
||||
tabStack.contentFrameLayout,
|
||||
tabStack.contentFrameState,
|
||||
point);
|
||||
if (panelHit != UIEditorPanelFrameHitTarget::None) {
|
||||
return MapPanelFrameHitTarget(
|
||||
panelHit,
|
||||
tabStack.nodeId,
|
||||
tabStack.selectedPanelId);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor::Widgets
|
||||
161
new_editor/src/Docking/UIEditorDockHostRendering.cpp
Normal file
161
new_editor/src/Docking/UIEditorDockHostRendering.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
#include <XCEditor/Docking/UIEditorDockHost.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
namespace XCEngine::UI::Editor::Widgets {
|
||||
|
||||
namespace {
|
||||
|
||||
using ::XCEngine::UI::UIColor;
|
||||
using ::XCEngine::UI::UIDrawList;
|
||||
|
||||
bool UsesExternalBodyPresentation(
|
||||
const UIEditorDockHostForegroundOptions& options,
|
||||
std::string_view panelId) {
|
||||
return std::find(
|
||||
options.externalBodyPanelIds.begin(),
|
||||
options.externalBodyPanelIds.end(),
|
||||
panelId) != options.externalBodyPanelIds.end();
|
||||
}
|
||||
|
||||
UIColor ResolveSplitterColor(
|
||||
const UIEditorDockHostSplitterLayout& splitter,
|
||||
const UIEditorDockHostPalette& palette) {
|
||||
if (splitter.active) {
|
||||
return palette.splitterActiveColor;
|
||||
}
|
||||
|
||||
if (splitter.hovered) {
|
||||
return palette.splitterHoveredColor;
|
||||
}
|
||||
|
||||
return palette.splitterColor;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void AppendUIEditorDockHostBackground(
|
||||
UIDrawList& drawList,
|
||||
const UIEditorDockHostLayout& layout,
|
||||
const UIEditorDockHostPalette& palette,
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
for (const UIEditorDockHostTabStackLayout& tabStack : layout.tabStacks) {
|
||||
std::vector<UIEditorTabStripItem> tabItems = {};
|
||||
tabItems.reserve(tabStack.items.size());
|
||||
for (const UIEditorDockHostTabItemLayout& item : tabStack.items) {
|
||||
UIEditorTabStripItem tabItem = {};
|
||||
tabItem.tabId = item.panelId;
|
||||
tabItem.title = item.title;
|
||||
tabItem.closable = item.closable;
|
||||
tabItems.push_back(std::move(tabItem));
|
||||
}
|
||||
|
||||
AppendUIEditorTabStripBackground(
|
||||
drawList,
|
||||
tabStack.tabStripLayout,
|
||||
tabStack.tabStripState,
|
||||
palette.tabStripPalette,
|
||||
metrics.tabStripMetrics);
|
||||
}
|
||||
|
||||
for (const UIEditorDockHostSplitterLayout& splitter : layout.splitters) {
|
||||
drawList.AddFilledRect(
|
||||
splitter.splitterLayout.handleRect,
|
||||
ResolveSplitterColor(splitter, palette),
|
||||
metrics.splitterHandleRounding);
|
||||
}
|
||||
}
|
||||
|
||||
void AppendUIEditorDockHostForeground(
|
||||
UIDrawList& drawList,
|
||||
const UIEditorDockHostLayout& layout,
|
||||
const UIEditorDockHostForegroundOptions& options,
|
||||
const UIEditorDockHostPalette& palette,
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
for (const UIEditorDockHostTabStackLayout& tabStack : layout.tabStacks) {
|
||||
std::vector<UIEditorTabStripItem> tabItems = {};
|
||||
tabItems.reserve(tabStack.items.size());
|
||||
for (const UIEditorDockHostTabItemLayout& item : tabStack.items) {
|
||||
UIEditorTabStripItem tabItem = {};
|
||||
tabItem.tabId = item.panelId;
|
||||
tabItem.title = item.title;
|
||||
tabItem.closable = item.closable;
|
||||
tabItems.push_back(std::move(tabItem));
|
||||
}
|
||||
|
||||
AppendUIEditorTabStripForeground(
|
||||
drawList,
|
||||
tabStack.tabStripLayout,
|
||||
tabItems,
|
||||
tabStack.tabStripState,
|
||||
palette.tabStripPalette,
|
||||
metrics.tabStripMetrics);
|
||||
|
||||
if (UsesExternalBodyPresentation(options, tabStack.selectedPanelId)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (layout.dropPreview.visible) {
|
||||
drawList.AddFilledRect(
|
||||
layout.dropPreview.previewRect,
|
||||
palette.dropPreviewFillColor);
|
||||
drawList.AddRectOutline(
|
||||
layout.dropPreview.previewRect,
|
||||
palette.dropPreviewBorderColor,
|
||||
1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void AppendUIEditorDockHostForeground(
|
||||
UIDrawList& drawList,
|
||||
const UIEditorDockHostLayout& layout,
|
||||
const UIEditorDockHostPalette& palette,
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
AppendUIEditorDockHostForeground(
|
||||
drawList,
|
||||
layout,
|
||||
UIEditorDockHostForegroundOptions{},
|
||||
palette,
|
||||
metrics);
|
||||
}
|
||||
|
||||
void AppendUIEditorDockHost(
|
||||
UIDrawList& drawList,
|
||||
const ::XCEngine::UI::UIRect& bounds,
|
||||
const UIEditorPanelRegistry& panelRegistry,
|
||||
const UIEditorWorkspaceModel& workspace,
|
||||
const UIEditorWorkspaceSession& session,
|
||||
const UIEditorDockHostState& state,
|
||||
const UIEditorDockHostForegroundOptions& foregroundOptions,
|
||||
const UIEditorDockHostPalette& palette,
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
const UIEditorDockHostLayout layout =
|
||||
BuildUIEditorDockHostLayout(bounds, panelRegistry, workspace, session, state, metrics);
|
||||
AppendUIEditorDockHostBackground(drawList, layout, palette, metrics);
|
||||
AppendUIEditorDockHostForeground(drawList, layout, foregroundOptions, palette, metrics);
|
||||
}
|
||||
|
||||
void AppendUIEditorDockHost(
|
||||
UIDrawList& drawList,
|
||||
const ::XCEngine::UI::UIRect& bounds,
|
||||
const UIEditorPanelRegistry& panelRegistry,
|
||||
const UIEditorWorkspaceModel& workspace,
|
||||
const UIEditorWorkspaceSession& session,
|
||||
const UIEditorDockHostState& state,
|
||||
const UIEditorDockHostPalette& palette,
|
||||
const UIEditorDockHostMetrics& metrics) {
|
||||
AppendUIEditorDockHost(
|
||||
drawList,
|
||||
bounds,
|
||||
panelRegistry,
|
||||
workspace,
|
||||
session,
|
||||
state,
|
||||
UIEditorDockHostForegroundOptions{},
|
||||
palette,
|
||||
metrics);
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor::Widgets
|
||||
Reference in New Issue
Block a user