Add XCUI editor collection primitives and stack rollback

This commit is contained in:
2026-04-05 06:36:50 +08:00
parent 9525053624
commit 585575a738
7 changed files with 294 additions and 4 deletions

View File

@@ -0,0 +1,41 @@
#pragma once
#include <XCEngine/UI/Style/Theme.h>
#include <cstdint>
#include <string_view>
namespace XCEngine {
namespace UI {
namespace Widgets {
enum class UIEditorCollectionPrimitiveKind : std::uint8_t {
None = 0,
ScrollView,
TreeView,
TreeItem,
ListView,
ListItem,
PropertySection,
FieldRow
};
UIEditorCollectionPrimitiveKind ClassifyUIEditorCollectionPrimitive(std::string_view tagName);
bool IsUIEditorCollectionPrimitiveContainer(UIEditorCollectionPrimitiveKind kind);
bool UsesUIEditorCollectionPrimitiveColumnLayout(UIEditorCollectionPrimitiveKind kind);
bool IsUIEditorCollectionPrimitiveHoverable(UIEditorCollectionPrimitiveKind kind);
bool DoesUIEditorCollectionPrimitiveClipChildren(UIEditorCollectionPrimitiveKind kind);
float ResolveUIEditorCollectionPrimitivePadding(
UIEditorCollectionPrimitiveKind kind,
const Style::UITheme& theme);
float ResolveUIEditorCollectionPrimitiveDefaultHeight(
UIEditorCollectionPrimitiveKind kind,
const Style::UITheme& theme);
float ResolveUIEditorCollectionPrimitiveIndent(
UIEditorCollectionPrimitiveKind kind,
const Style::UITheme& theme,
float indentLevel);
} // namespace Widgets
} // namespace UI
} // namespace XCEngine

View File

@@ -82,11 +82,27 @@ bool UIScreenStackController::ReplaceTop(
return PushScreen(asset, options) != 0;
}
if (!Pop()) {
if (m_system == nullptr) {
return false;
}
return PushScreen(asset, options) != 0;
const UIScreenStackEntry previousTop = m_entries.back();
const UIScreenLayerId replacementLayerId = m_system->PushScreen(asset, options);
if (replacementLayerId == 0) {
return false;
}
if (!m_system->RemoveLayer(previousTop.layerId)) {
m_system->RemoveLayer(replacementLayerId);
return false;
}
UIScreenStackEntry replacementEntry = {};
replacementEntry.layerId = replacementLayerId;
replacementEntry.asset = asset;
replacementEntry.options = options;
m_entries.back() = std::move(replacementEntry);
return true;
}
bool UIScreenStackController::Pop() {

View File

@@ -0,0 +1,114 @@
#include <XCEngine/UI/Widgets/UIEditorCollectionPrimitives.h>
namespace XCEngine {
namespace UI {
namespace Widgets {
namespace {
float ResolveFloatToken(
const Style::UITheme& theme,
const char* tokenName,
float fallbackValue) {
const Style::UITokenResolveResult result =
theme.ResolveToken(tokenName, Style::UIStyleValueType::Float);
if (result.status != Style::UITokenResolveStatus::Resolved) {
return fallbackValue;
}
const float* value = result.value.TryGetFloat();
return value != nullptr ? *value : fallbackValue;
}
} // namespace
UIEditorCollectionPrimitiveKind ClassifyUIEditorCollectionPrimitive(std::string_view tagName) {
if (tagName == "ScrollView") {
return UIEditorCollectionPrimitiveKind::ScrollView;
}
if (tagName == "TreeView") {
return UIEditorCollectionPrimitiveKind::TreeView;
}
if (tagName == "TreeItem") {
return UIEditorCollectionPrimitiveKind::TreeItem;
}
if (tagName == "ListView") {
return UIEditorCollectionPrimitiveKind::ListView;
}
if (tagName == "ListItem") {
return UIEditorCollectionPrimitiveKind::ListItem;
}
if (tagName == "PropertySection") {
return UIEditorCollectionPrimitiveKind::PropertySection;
}
if (tagName == "FieldRow") {
return UIEditorCollectionPrimitiveKind::FieldRow;
}
return UIEditorCollectionPrimitiveKind::None;
}
bool IsUIEditorCollectionPrimitiveContainer(UIEditorCollectionPrimitiveKind kind) {
return kind == UIEditorCollectionPrimitiveKind::ScrollView ||
kind == UIEditorCollectionPrimitiveKind::TreeView ||
kind == UIEditorCollectionPrimitiveKind::ListView ||
kind == UIEditorCollectionPrimitiveKind::PropertySection;
}
bool UsesUIEditorCollectionPrimitiveColumnLayout(UIEditorCollectionPrimitiveKind kind) {
return kind == UIEditorCollectionPrimitiveKind::TreeView ||
kind == UIEditorCollectionPrimitiveKind::ListView ||
kind == UIEditorCollectionPrimitiveKind::PropertySection;
}
bool IsUIEditorCollectionPrimitiveHoverable(UIEditorCollectionPrimitiveKind kind) {
return kind == UIEditorCollectionPrimitiveKind::TreeItem ||
kind == UIEditorCollectionPrimitiveKind::ListItem ||
kind == UIEditorCollectionPrimitiveKind::FieldRow;
}
bool DoesUIEditorCollectionPrimitiveClipChildren(UIEditorCollectionPrimitiveKind kind) {
return kind == UIEditorCollectionPrimitiveKind::ScrollView ||
kind == UIEditorCollectionPrimitiveKind::TreeView ||
kind == UIEditorCollectionPrimitiveKind::ListView;
}
float ResolveUIEditorCollectionPrimitivePadding(
UIEditorCollectionPrimitiveKind kind,
const Style::UITheme& theme) {
return kind == UIEditorCollectionPrimitiveKind::TreeView ||
kind == UIEditorCollectionPrimitiveKind::ListView ||
kind == UIEditorCollectionPrimitiveKind::PropertySection
? ResolveFloatToken(theme, "space.cardInset", 12.0f)
: 0.0f;
}
float ResolveUIEditorCollectionPrimitiveDefaultHeight(
UIEditorCollectionPrimitiveKind kind,
const Style::UITheme& theme) {
switch (kind) {
case UIEditorCollectionPrimitiveKind::TreeItem:
return ResolveFloatToken(theme, "size.treeItemHeight", 28.0f);
case UIEditorCollectionPrimitiveKind::ListItem:
return ResolveFloatToken(theme, "size.listItemHeight", 60.0f);
case UIEditorCollectionPrimitiveKind::FieldRow:
return ResolveFloatToken(theme, "size.fieldRowHeight", 32.0f);
case UIEditorCollectionPrimitiveKind::PropertySection:
return ResolveFloatToken(theme, "size.propertySectionHeight", 148.0f);
default:
return 0.0f;
}
}
float ResolveUIEditorCollectionPrimitiveIndent(
UIEditorCollectionPrimitiveKind kind,
const Style::UITheme& theme,
float indentLevel) {
return kind == UIEditorCollectionPrimitiveKind::TreeItem
? indentLevel * ResolveFloatToken(theme, "size.treeIndent", 18.0f)
: 0.0f;
}
} // namespace Widgets
} // namespace UI
} // namespace XCEngine