ui: add typed editor field foundations

This commit is contained in:
2026-04-08 02:52:28 +08:00
parent 805e07bf90
commit 0a392e1311
69 changed files with 11676 additions and 1169 deletions

View File

@@ -0,0 +1,218 @@
#pragma once
#include <XCEngine/Core/Containers/String.h>
#include <XCEngine/Core/Math/Color.h>
#include <XCEngine/Resources/UI/UIDocumentCompiler.h>
#include <XCEngine/UI/DrawData.h>
#include <XCEngine/UI/Style/DocumentStyleCompiler.h>
#include <XCEngine/UI/Style/Theme.h>
#include <filesystem>
#include <initializer_list>
#include <string>
#include <string_view>
namespace XCEngine::Tests::EditorUI {
struct EditorValidationThemeLoadResult {
::XCEngine::UI::Style::UITheme theme = {};
std::string error = {};
bool succeeded = false;
};
struct EditorValidationShellPalette {
::XCEngine::UI::UIColor windowBackground = ::XCEngine::UI::UIColor(0.13f, 0.13f, 0.13f, 1.0f);
::XCEngine::UI::UIColor cardBackground = ::XCEngine::UI::UIColor(0.18f, 0.18f, 0.18f, 1.0f);
::XCEngine::UI::UIColor cardBorder = ::XCEngine::UI::UIColor(0.29f, 0.29f, 0.29f, 1.0f);
::XCEngine::UI::UIColor textPrimary = ::XCEngine::UI::UIColor(0.94f, 0.94f, 0.94f, 1.0f);
::XCEngine::UI::UIColor textMuted = ::XCEngine::UI::UIColor(0.72f, 0.72f, 0.72f, 1.0f);
::XCEngine::UI::UIColor textWeak = ::XCEngine::UI::UIColor(0.56f, 0.56f, 0.56f, 1.0f);
::XCEngine::UI::UIColor textSuccess = ::XCEngine::UI::UIColor(0.63f, 0.76f, 0.63f, 1.0f);
::XCEngine::UI::UIColor buttonBackground = ::XCEngine::UI::UIColor(0.25f, 0.25f, 0.25f, 1.0f);
::XCEngine::UI::UIColor buttonHoverBackground = ::XCEngine::UI::UIColor(0.32f, 0.32f, 0.32f, 1.0f);
};
struct EditorValidationShellMetrics {
float margin = 20.0f;
float gap = 16.0f;
float cardRadius = 10.0f;
float buttonRadius = 8.0f;
float titleFontSize = 17.0f;
float bodyFontSize = 12.0f;
};
inline ::XCEngine::UI::UIColor ToUIColor(const ::XCEngine::Math::Color& color) {
return ::XCEngine::UI::UIColor(color.r, color.g, color.b, color.a);
}
inline bool TryResolveThemeFloat(
const ::XCEngine::UI::Style::UITheme& theme,
std::string_view tokenName,
float& outValue) {
const auto resolution =
theme.ResolveToken(std::string(tokenName), ::XCEngine::UI::Style::UIStyleValueType::Float);
if (resolution.status != ::XCEngine::UI::Style::UITokenResolveStatus::Resolved) {
return false;
}
const float* value = resolution.value.TryGetFloat();
if (value == nullptr) {
return false;
}
outValue = *value;
return true;
}
inline bool TryResolveThemeColor(
const ::XCEngine::UI::Style::UITheme& theme,
std::string_view tokenName,
::XCEngine::UI::UIColor& outColor) {
const auto resolution =
theme.ResolveToken(std::string(tokenName), ::XCEngine::UI::Style::UIStyleValueType::Color);
if (resolution.status != ::XCEngine::UI::Style::UITokenResolveStatus::Resolved) {
return false;
}
const ::XCEngine::Math::Color* value = resolution.value.TryGetColor();
if (value == nullptr) {
return false;
}
outColor = ToUIColor(*value);
return true;
}
inline float ResolveThemeFloatAliases(
const ::XCEngine::UI::Style::UITheme& theme,
std::initializer_list<std::string_view> tokenNames,
float fallbackValue) {
float resolvedValue = fallbackValue;
for (std::string_view tokenName : tokenNames) {
if (TryResolveThemeFloat(theme, tokenName, resolvedValue)) {
return resolvedValue;
}
}
return fallbackValue;
}
inline ::XCEngine::UI::UIColor ResolveThemeColorAliases(
const ::XCEngine::UI::Style::UITheme& theme,
std::initializer_list<std::string_view> tokenNames,
const ::XCEngine::UI::UIColor& fallbackValue) {
::XCEngine::UI::UIColor resolvedValue = fallbackValue;
for (std::string_view tokenName : tokenNames) {
if (TryResolveThemeColor(theme, tokenName, resolvedValue)) {
return resolvedValue;
}
}
return fallbackValue;
}
inline EditorValidationThemeLoadResult LoadEditorValidationTheme(
const std::filesystem::path& themePath) {
EditorValidationThemeLoadResult result = {};
::XCEngine::Resources::UIDocumentCompileResult compileResult = {};
const ::XCEngine::Containers::String pathString(themePath.generic_string().c_str());
if (!::XCEngine::Resources::CompileUIDocument(
::XCEngine::Resources::UIDocumentCompileRequest {
::XCEngine::Resources::UIDocumentKind::Theme,
pathString,
::XCEngine::Resources::GetUIDocumentDefaultRootTag(
::XCEngine::Resources::UIDocumentKind::Theme)
},
compileResult)) {
result.error = compileResult.errorMessage.Empty()
? std::string("Failed to compile editor validation theme document.")
: std::string(compileResult.errorMessage.CStr());
return result;
}
const auto styleCompileResult =
::XCEngine::UI::Style::CompileDocumentStyle(compileResult.document);
if (!styleCompileResult.succeeded) {
result.error = styleCompileResult.errorMessage;
return result;
}
result.theme = styleCompileResult.theme;
result.succeeded = true;
return result;
}
inline EditorValidationShellPalette ResolveEditorValidationShellPalette(
const ::XCEngine::UI::Style::UITheme& theme) {
EditorValidationShellPalette palette = {};
palette.windowBackground = ResolveThemeColorAliases(
theme,
{ "editor.color.validation.window", "color.bg.workspace" },
palette.windowBackground);
palette.cardBackground = ResolveThemeColorAliases(
theme,
{ "editor.color.validation.card", "color.bg.panel" },
palette.cardBackground);
palette.cardBorder = ResolveThemeColorAliases(
theme,
{ "editor.color.validation.card_border", "editor.color.menu_popup.border" },
palette.cardBorder);
palette.textPrimary = ResolveThemeColorAliases(
theme,
{ "editor.color.validation.text_primary", "color.text.primary" },
palette.textPrimary);
palette.textMuted = ResolveThemeColorAliases(
theme,
{ "editor.color.validation.text_muted", "color.text.muted" },
palette.textMuted);
palette.textWeak = ResolveThemeColorAliases(
theme,
{ "editor.color.validation.text_weak", "color.text.muted" },
palette.textWeak);
palette.textSuccess = ResolveThemeColorAliases(
theme,
{ "editor.color.validation.text_success" },
palette.textSuccess);
palette.buttonBackground = ResolveThemeColorAliases(
theme,
{ "editor.color.validation.button", "color.bg.selection" },
palette.buttonBackground);
palette.buttonHoverBackground = ResolveThemeColorAliases(
theme,
{ "editor.color.validation.button_hover", "editor.color.validation.button", "color.bg.selection" },
palette.buttonHoverBackground);
return palette;
}
inline EditorValidationShellMetrics ResolveEditorValidationShellMetrics(
const ::XCEngine::UI::Style::UITheme& theme) {
EditorValidationShellMetrics metrics = {};
metrics.margin = ResolveThemeFloatAliases(
theme,
{ "editor.space.validation.margin", "space.shell" },
metrics.margin);
metrics.gap = ResolveThemeFloatAliases(
theme,
{ "editor.space.validation.gap" },
metrics.gap);
metrics.cardRadius = ResolveThemeFloatAliases(
theme,
{ "editor.radius.validation.card", "radius.panel" },
metrics.cardRadius);
metrics.buttonRadius = ResolveThemeFloatAliases(
theme,
{ "editor.radius.validation.button", "radius.control" },
metrics.buttonRadius);
metrics.titleFontSize = ResolveThemeFloatAliases(
theme,
{ "editor.font.validation.title" },
metrics.titleFontSize);
metrics.bodyFontSize = ResolveThemeFloatAliases(
theme,
{ "editor.font.validation.body", "editor.font.field.value" },
metrics.bodyFontSize);
return metrics;
}
} // namespace XCEngine::Tests::EditorUI