Refactor XCUI editor module layout

This commit is contained in:
2026-04-10 00:41:28 +08:00
parent 4b47764f26
commit 02a0e626fe
263 changed files with 12396 additions and 7592 deletions

View File

@@ -11,6 +11,14 @@
#include <unordered_set>
#include <vector>
#ifndef XCENGINE_EDITOR_UI_TESTS_REPO_ROOT
#define XCENGINE_EDITOR_UI_TESTS_REPO_ROOT "."
#endif
#ifndef XCENGINE_EDITOR_UI_TESTS_BUILD_ROOT
#define XCENGINE_EDITOR_UI_TESTS_BUILD_ROOT "."
#endif
namespace XCEngine::Tests::EditorUI {
namespace {
@@ -41,6 +49,55 @@ Application* GetApplicationFromWindow(HWND hwnd) {
return reinterpret_cast<Application*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
}
std::filesystem::path GetRepoRootPath() {
std::string root = XCENGINE_EDITOR_UI_TESTS_REPO_ROOT;
if (root.size() >= 2u && root.front() == '"' && root.back() == '"') {
root = root.substr(1u, root.size() - 2u);
}
return std::filesystem::path(root).lexically_normal();
}
std::filesystem::path GetBuildRootPath() {
std::string root = XCENGINE_EDITOR_UI_TESTS_BUILD_ROOT;
if (root.size() >= 2u && root.front() == '"' && root.back() == '"') {
root = root.substr(1u, root.size() - 2u);
}
return std::filesystem::path(root).lexically_normal();
}
bool TryMakeRepoRelativePath(
const std::filesystem::path& absolutePath,
std::filesystem::path& outRelativePath) {
std::error_code errorCode = {};
outRelativePath = std::filesystem::relative(
absolutePath,
GetRepoRootPath(),
errorCode);
if (errorCode || outRelativePath.empty()) {
return false;
}
for (const auto& part : outRelativePath) {
if (part == "..") {
return false;
}
}
return true;
}
std::filesystem::path ResolveCaptureOutputRoot(
const std::filesystem::path& sourceCaptureRoot) {
const std::filesystem::path normalizedSourcePath =
sourceCaptureRoot.lexically_normal();
std::filesystem::path relativePath = {};
if (TryMakeRepoRelativePath(normalizedSourcePath, relativePath)) {
return (GetBuildRootPath() / relativePath).lexically_normal();
}
return (GetBuildRootPath() / "ui_test_captures" / normalizedSourcePath.filename())
.lexically_normal();
}
std::string TruncateText(const std::string& text, std::size_t maxLength) {
if (text.size() <= maxLength) {
return text;
@@ -230,7 +287,8 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
initialScenario = &GetDefaultEditorValidationScenario();
}
m_autoScreenshot.Initialize(initialScenario->captureRootPath);
m_autoScreenshot.Initialize(
ResolveCaptureOutputRoot(initialScenario->captureRootPath));
LoadStructuredScreen("startup");
return true;
}
@@ -406,7 +464,6 @@ bool Application::LoadStructuredScreen(const char* triggerReason) {
m_screenAsset = {};
m_screenAsset.screenId = scenario->id;
m_screenAsset.documentPath = scenario->documentPath.string();
m_screenAsset.themePath = scenario->themePath.string();
const bool loaded = m_screenPlayer.Load(m_screenAsset);
m_useStructuredScreen = loaded;
@@ -463,7 +520,6 @@ void Application::RebuildTrackedFileStates() {
};
appendTrackedPath(m_screenAsset.documentPath);
appendTrackedPath(m_screenAsset.themePath);
if (const auto* document = m_screenPlayer.GetDocument(); document != nullptr) {
for (const std::string& dependency : document->dependencies) {

View File

@@ -33,7 +33,6 @@ const std::array<EditorValidationScenario, 1>& GetEditorValidationScenarios() {
"shell",
"Editor 壳层 | 工作区组合",
RepoRelative("tests/UI/Editor/integration/shell/workspace_shell_compose/View.xcui"),
RepoRelative("tests/UI/Editor/integration/shared/themes/editor_validation.xctheme"),
RepoRelative("tests/UI/Editor/integration/shell/workspace_shell_compose/captures")
}
} };

View File

@@ -16,7 +16,6 @@ struct EditorValidationScenario {
std::string categoryId = {};
std::string displayName = {};
std::filesystem::path documentPath = {};
std::filesystem::path themePath = {};
std::filesystem::path captureRootPath = {};
};

View File

@@ -1,25 +1,9 @@
#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);
@@ -41,178 +25,12 @@ struct EditorValidationShellMetrics {
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 EditorValidationShellPalette GetEditorValidationShellPalette() {
return {};
}
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;
inline EditorValidationShellMetrics GetEditorValidationShellMetrics() {
return {};
}
} // namespace XCEngine::Tests::EditorUI