Add XCUI style theme token system

This commit is contained in:
2026-04-04 19:34:29 +08:00
parent 75ded6f630
commit 95c4a50186
12 changed files with 1100 additions and 1 deletions

View File

@@ -0,0 +1,61 @@
#pragma once
#include "StyleSet.h"
#include "Theme.h"
#include <map>
namespace XCEngine {
namespace UI {
namespace Style {
enum class UIStyleLayer : std::uint8_t {
None = 0,
Default,
Type,
Named,
Local
};
struct UIStylePropertyResolution {
bool resolved = false;
UIStyleLayer layer = UIStyleLayer::None;
UIStyleValue value = {};
};
class UIResolvedStyle {
public:
void SetProperty(UIStylePropertyId propertyId, const UIStylePropertyResolution& resolution) {
m_properties[propertyId] = resolution;
}
const UIStylePropertyResolution* FindProperty(UIStylePropertyId propertyId) const {
const auto it = m_properties.find(propertyId);
return it != m_properties.end() ? &it->second : nullptr;
}
const std::map<UIStylePropertyId, UIStylePropertyResolution>& GetProperties() const {
return m_properties;
}
private:
std::map<UIStylePropertyId, UIStylePropertyResolution> m_properties = {};
};
struct UIStyleResolveContext {
const UITheme* theme = nullptr;
const UIStyleSheet* styleSheet = nullptr;
UIStyleSelector selector = {};
const UIStyleSet* localStyle = nullptr;
};
UIStylePropertyResolution ResolveStyleProperty(
UIStylePropertyId propertyId,
const UIStyleResolveContext& context);
UIResolvedStyle ResolveStyle(const UIStyleResolveContext& context);
const char* ToString(UIStyleLayer layer);
} // namespace Style
} // namespace UI
} // namespace XCEngine

View File

@@ -0,0 +1,80 @@
#pragma once
#include "StyleTypes.h"
#include <map>
#include <string>
namespace XCEngine {
namespace UI {
namespace Style {
class UIStyleSet {
public:
void SetProperty(UIStylePropertyId propertyId, const UIStyleValue& value) {
m_properties[propertyId] = value;
}
bool RemoveProperty(UIStylePropertyId propertyId) {
return m_properties.erase(propertyId) > 0u;
}
bool HasProperty(UIStylePropertyId propertyId) const {
return m_properties.find(propertyId) != m_properties.end();
}
const UIStyleValue* FindProperty(UIStylePropertyId propertyId) const {
const auto it = m_properties.find(propertyId);
return it != m_properties.end() ? &it->second : nullptr;
}
const std::map<UIStylePropertyId, UIStyleValue>& GetProperties() const {
return m_properties;
}
private:
std::map<UIStylePropertyId, UIStyleValue> m_properties = {};
};
struct UIStyleSelector {
std::string typeName;
std::string styleName;
};
class UIStyleSheet {
public:
UIStyleSet& DefaultStyle() {
return m_defaultStyle;
}
const UIStyleSet& DefaultStyle() const {
return m_defaultStyle;
}
UIStyleSet& GetOrCreateTypeStyle(const std::string& typeName) {
return m_typeStyles[typeName];
}
UIStyleSet& GetOrCreateNamedStyle(const std::string& styleName) {
return m_namedStyles[styleName];
}
const UIStyleSet* FindTypeStyle(const std::string& typeName) const {
const auto it = m_typeStyles.find(typeName);
return it != m_typeStyles.end() ? &it->second : nullptr;
}
const UIStyleSet* FindNamedStyle(const std::string& styleName) const {
const auto it = m_namedStyles.find(styleName);
return it != m_namedStyles.end() ? &it->second : nullptr;
}
private:
UIStyleSet m_defaultStyle = {};
std::map<std::string, UIStyleSet> m_typeStyles = {};
std::map<std::string, UIStyleSet> m_namedStyles = {};
};
} // namespace Style
} // namespace UI
} // namespace XCEngine

View File

@@ -0,0 +1,104 @@
#pragma once
#include <XCEngine/Core/Math/Color.h>
#include <XCEngine/UI/Types.h>
#include <cstdint>
#include <string>
#include <variant>
namespace XCEngine {
namespace UI {
namespace Style {
struct UIThickness {
float left = 0.0f;
float top = 0.0f;
float right = 0.0f;
float bottom = 0.0f;
static UIThickness Uniform(float value);
bool IsUniform() const;
};
struct UICornerRadius {
float topLeft = 0.0f;
float topRight = 0.0f;
float bottomRight = 0.0f;
float bottomLeft = 0.0f;
static UICornerRadius Uniform(float value);
bool IsUniform() const;
};
struct UITokenReference {
std::string name;
bool IsValid() const;
};
enum class UIStyleValueType : std::uint8_t {
None = 0,
Float,
Color,
Thickness,
CornerRadius,
Size,
Point,
TokenReference
};
class UIStyleValue {
public:
using Storage =
std::variant<std::monostate, float, Math::Color, UIThickness, UICornerRadius, UISize, UIPoint, UITokenReference>;
UIStyleValue() = default;
explicit UIStyleValue(float value);
explicit UIStyleValue(const Math::Color& value);
explicit UIStyleValue(const UIThickness& value);
explicit UIStyleValue(const UICornerRadius& value);
explicit UIStyleValue(const UISize& value);
explicit UIStyleValue(const UIPoint& value);
static UIStyleValue Token(const std::string& tokenName);
bool IsSet() const;
bool IsTokenReference() const;
UIStyleValueType GetType() const;
const float* TryGetFloat() const;
const Math::Color* TryGetColor() const;
const UIThickness* TryGetThickness() const;
const UICornerRadius* TryGetCornerRadius() const;
const UISize* TryGetSize() const;
const UIPoint* TryGetPoint() const;
const UITokenReference* TryGetTokenReference() const;
bool operator==(const UIStyleValue& other) const;
bool operator!=(const UIStyleValue& other) const;
private:
explicit UIStyleValue(const UITokenReference& tokenReference);
Storage m_storage = {};
};
enum class UIStylePropertyId : std::uint8_t {
BackgroundColor = 0,
ForegroundColor,
BorderColor,
BorderWidth,
CornerRadius,
Padding,
Gap,
FontSize,
LineWidth
};
UIStyleValueType GetExpectedValueType(UIStylePropertyId propertyId);
const char* ToString(UIStylePropertyId propertyId);
} // namespace Style
} // namespace UI
} // namespace XCEngine

View File

@@ -0,0 +1,75 @@
#pragma once
#include "StyleTypes.h"
#include <map>
#include <string>
#include <vector>
namespace XCEngine {
namespace UI {
namespace Style {
enum class UITokenResolveStatus : std::uint8_t {
Unresolved = 0,
Resolved,
MissingToken,
CycleDetected,
TypeMismatch
};
struct UITokenResolveResult {
UITokenResolveStatus status = UITokenResolveStatus::Unresolved;
UIStyleValue value = {};
};
struct UIThemeDefinition {
std::string name;
std::map<std::string, UIStyleValue> tokens = {};
void SetToken(const std::string& tokenName, const UIStyleValue& value);
const UIStyleValue* FindToken(const std::string& tokenName) const;
};
enum class UIBuiltinThemeKind : std::uint8_t {
NeutralDark = 0,
NeutralLight
};
class UITheme {
public:
UITheme() = default;
explicit UITheme(const UIThemeDefinition& definition);
void SetName(const std::string& name);
const std::string& GetName() const;
void SetParent(const UITheme* parent);
const UITheme* GetParent() const;
void SetToken(const std::string& tokenName, const UIStyleValue& value);
bool RemoveToken(const std::string& tokenName);
const UIStyleValue* FindToken(const std::string& tokenName) const;
const std::map<std::string, UIStyleValue>& GetTokens() const;
UITokenResolveResult ResolveToken(
const std::string& tokenName,
UIStyleValueType expectedType = UIStyleValueType::None) const;
private:
UITokenResolveResult ResolveTokenRecursive(
const std::string& tokenName,
UIStyleValueType expectedType,
std::vector<std::string>& visiting) const;
std::string m_name;
const UITheme* m_parent = nullptr;
std::map<std::string, UIStyleValue> m_tokens = {};
};
UITheme BuildTheme(const UIThemeDefinition& definition, const UITheme* parent = nullptr);
UITheme BuildBuiltinTheme(UIBuiltinThemeKind themeKind);
} // namespace Style
} // namespace UI
} // namespace XCEngine