Unlink XCNewEditor default shell from ImGui compat slice

This commit is contained in:
2026-04-05 16:32:43 +08:00
parent 712cc79c44
commit 74b1280aa6
12 changed files with 1128 additions and 57 deletions

View File

@@ -0,0 +1,126 @@
#pragma once
#include <XCEngine/UI/DrawData.h>
#include <string>
#include <string_view>
namespace XCEngine {
namespace UI {
namespace Widgets {
struct UIEditorPanelChromeState {
bool active = false;
bool hovered = false;
};
struct UIEditorPanelChromeText {
std::string_view title = {};
std::string_view subtitle = {};
std::string_view footer = {};
};
struct UIEditorPanelChromeMetrics {
float cornerRounding = 18.0f;
float headerHeight = 42.0f;
float titleInsetX = 16.0f;
float titleInsetY = 12.0f;
float subtitleInsetY = 28.0f;
float footerInsetX = 16.0f;
float footerInsetBottom = 18.0f;
float activeBorderThickness = 2.0f;
float inactiveBorderThickness = 1.0f;
};
struct UIEditorPanelChromePalette {
UIColor surfaceColor = UIColor(9.0f / 255.0f, 13.0f / 255.0f, 18.0f / 255.0f, 212.0f / 255.0f);
UIColor borderColor = UIColor(53.0f / 255.0f, 72.0f / 255.0f, 96.0f / 255.0f, 1.0f);
UIColor accentColor = UIColor(84.0f / 255.0f, 176.0f / 255.0f, 244.0f / 255.0f, 1.0f);
UIColor hoveredAccentColor = UIColor(1.0f, 206.0f / 255.0f, 112.0f / 255.0f, 1.0f);
UIColor headerColor = UIColor(13.0f / 255.0f, 20.0f / 255.0f, 28.0f / 255.0f, 242.0f / 255.0f);
UIColor textPrimary = UIColor(232.0f / 255.0f, 238.0f / 255.0f, 246.0f / 255.0f, 1.0f);
UIColor textSecondary = UIColor(150.0f / 255.0f, 164.0f / 255.0f, 184.0f / 255.0f, 1.0f);
UIColor textMuted = UIColor(108.0f / 255.0f, 123.0f / 255.0f, 145.0f / 255.0f, 1.0f);
};
inline UIRect BuildUIEditorPanelChromeHeaderRect(
const UIRect& panelRect,
const UIEditorPanelChromeMetrics& metrics = {}) {
return UIRect(
panelRect.x,
panelRect.y,
panelRect.width,
metrics.headerHeight);
}
inline UIColor ResolveUIEditorPanelChromeBorderColor(
const UIEditorPanelChromeState& state,
const UIEditorPanelChromePalette& palette = {}) {
if (state.active) {
return palette.accentColor;
}
if (state.hovered) {
return palette.hoveredAccentColor;
}
return palette.borderColor;
}
inline float ResolveUIEditorPanelChromeBorderThickness(
const UIEditorPanelChromeState& state,
const UIEditorPanelChromeMetrics& metrics = {}) {
return state.active
? metrics.activeBorderThickness
: metrics.inactiveBorderThickness;
}
inline void AppendUIEditorPanelChromeBackground(
UIDrawList& drawList,
const UIRect& panelRect,
const UIEditorPanelChromeState& state,
const UIEditorPanelChromePalette& palette = {},
const UIEditorPanelChromeMetrics& metrics = {}) {
drawList.AddFilledRect(panelRect, palette.surfaceColor, metrics.cornerRounding);
drawList.AddRectOutline(
panelRect,
ResolveUIEditorPanelChromeBorderColor(state, palette),
ResolveUIEditorPanelChromeBorderThickness(state, metrics),
metrics.cornerRounding);
drawList.AddFilledRect(
BuildUIEditorPanelChromeHeaderRect(panelRect, metrics),
palette.headerColor,
metrics.cornerRounding);
}
inline void AppendUIEditorPanelChromeForeground(
UIDrawList& drawList,
const UIRect& panelRect,
const UIEditorPanelChromeText& text,
const UIEditorPanelChromePalette& palette = {},
const UIEditorPanelChromeMetrics& metrics = {}) {
if (!text.title.empty()) {
drawList.AddText(
UIPoint(panelRect.x + metrics.titleInsetX, panelRect.y + metrics.titleInsetY),
std::string(text.title),
palette.textPrimary);
}
if (!text.subtitle.empty()) {
drawList.AddText(
UIPoint(panelRect.x + metrics.titleInsetX, panelRect.y + metrics.subtitleInsetY),
std::string(text.subtitle),
palette.textSecondary);
}
if (!text.footer.empty()) {
drawList.AddText(
UIPoint(panelRect.x + metrics.footerInsetX, panelRect.y + panelRect.height - metrics.footerInsetBottom),
std::string(text.footer),
palette.textMuted);
}
}
} // namespace Widgets
} // namespace UI
} // namespace XCEngine

View File

@@ -0,0 +1,167 @@
#pragma once
#include <cstddef>
#include <span>
#include <utility>
namespace XCEngine {
namespace UI {
namespace Widgets {
inline constexpr std::size_t kInvalidUIFlatHierarchyItemOffset = static_cast<std::size_t>(-1);
namespace Detail {
template <typename ResolveDepthFn>
float ResolveUIFlatHierarchyDepth(
std::span<const std::size_t> itemIndices,
std::size_t itemOffset,
ResolveDepthFn&& resolveDepth) {
if (itemOffset >= itemIndices.size()) {
return 0.0f;
}
const float depth = static_cast<float>(resolveDepth(itemIndices[itemOffset]));
return depth > 0.0f ? depth : 0.0f;
}
} // namespace Detail
template <typename ResolveDepthFn>
bool UIFlatHierarchyHasChildren(
std::span<const std::size_t> itemIndices,
std::size_t itemOffset,
ResolveDepthFn&& resolveDepth) {
if (itemOffset >= itemIndices.size()) {
return false;
}
const float itemDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
itemOffset,
std::forward<ResolveDepthFn>(resolveDepth));
for (std::size_t candidateOffset = itemOffset + 1u;
candidateOffset < itemIndices.size();
++candidateOffset) {
const float candidateDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
candidateOffset,
std::forward<ResolveDepthFn>(resolveDepth));
if (candidateDepth <= itemDepth) {
break;
}
return true;
}
return false;
}
template <typename ResolveDepthFn>
std::size_t UIFlatHierarchyFindParentOffset(
std::span<const std::size_t> itemIndices,
std::size_t itemOffset,
ResolveDepthFn&& resolveDepth) {
if (itemOffset >= itemIndices.size()) {
return kInvalidUIFlatHierarchyItemOffset;
}
const float itemDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
itemOffset,
std::forward<ResolveDepthFn>(resolveDepth));
if (itemDepth <= 0.0f) {
return kInvalidUIFlatHierarchyItemOffset;
}
for (std::size_t candidateOffset = itemOffset; candidateOffset > 0u; --candidateOffset) {
const std::size_t previousOffset = candidateOffset - 1u;
const float previousDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
previousOffset,
std::forward<ResolveDepthFn>(resolveDepth));
if (previousDepth < itemDepth) {
return previousOffset;
}
}
return kInvalidUIFlatHierarchyItemOffset;
}
template <typename ResolveDepthFn, typename IsExpandedFn>
bool UIFlatHierarchyIsVisible(
std::span<const std::size_t> itemIndices,
std::size_t itemOffset,
ResolveDepthFn&& resolveDepth,
IsExpandedFn&& isExpanded) {
if (itemOffset >= itemIndices.size()) {
return false;
}
float requiredAncestorDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
itemOffset,
std::forward<ResolveDepthFn>(resolveDepth));
if (requiredAncestorDepth <= 0.0f) {
return true;
}
for (std::size_t candidateOffset = itemOffset;
candidateOffset > 0u && requiredAncestorDepth > 0.0f;
--candidateOffset) {
const std::size_t previousOffset = candidateOffset - 1u;
const float previousDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
previousOffset,
std::forward<ResolveDepthFn>(resolveDepth));
if (previousDepth < requiredAncestorDepth) {
if (!isExpanded(itemIndices[previousOffset])) {
return false;
}
requiredAncestorDepth = previousDepth;
}
}
return true;
}
template <typename ResolveDepthFn, typename IsVisibleFn>
std::size_t UIFlatHierarchyFindFirstVisibleChildOffset(
std::span<const std::size_t> itemIndices,
std::size_t itemOffset,
ResolveDepthFn&& resolveDepth,
IsVisibleFn&& isVisible) {
if (!UIFlatHierarchyHasChildren(
itemIndices,
itemOffset,
std::forward<ResolveDepthFn>(resolveDepth))) {
return kInvalidUIFlatHierarchyItemOffset;
}
const float itemDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
itemOffset,
std::forward<ResolveDepthFn>(resolveDepth));
for (std::size_t candidateOffset = itemOffset + 1u;
candidateOffset < itemIndices.size();
++candidateOffset) {
const float candidateDepth = Detail::ResolveUIFlatHierarchyDepth(
itemIndices,
candidateOffset,
std::forward<ResolveDepthFn>(resolveDepth));
if (candidateDepth <= itemDepth) {
break;
}
if (isVisible(itemIndices[candidateOffset])) {
return candidateOffset;
}
}
return kInvalidUIFlatHierarchyItemOffset;
}
} // namespace Widgets
} // namespace UI
} // namespace XCEngine