Fix explicit definition of nested styles, resolve parent style if the style for the variant is not present in the stylesheet.

This commit is contained in:
2026-05-31 19:34:51 +02:00
parent 11423d86e5
commit b506b78c32
3 changed files with 73 additions and 26 deletions

View File

@@ -1,12 +1,9 @@
[Button] [Button]
BackgroundColor = "#0f62fe" BackgroundColor = "#0f62fe"
CornerRadius = 16.0
TextColor = "#ffffff" TextColor = "#ffffff"
Padding = 16.0 Padding = 16.0
# Creates an empty rule for Button.Normal.
# This will inherit style from Button, this is a temporary workaround.
[Button.Normal]
[Button.Hovered] [Button.Hovered]
BackgroundColor = "#0353e9" BackgroundColor = "#0353e9"

View File

@@ -11,7 +11,7 @@ namespace Voile.UI;
/// </summary> /// </summary>
public class Style public class Style
{ {
public enum AnimationType public enum TransitionType
{ {
Linear, Linear,
EaseIn, EaseIn,
@@ -20,7 +20,7 @@ public class Style
} }
public float TransitionDuration = 0f; public float TransitionDuration = 0f;
public AnimationType TransitionType = AnimationType.Linear; public TransitionType Transition = TransitionType.Linear;
public Style() { } public Style() { }
@@ -35,17 +35,39 @@ public class Style
/// Merges this <see cref="Style"/> with a different one.<br /> /// Merges this <see cref="Style"/> with a different one.<br />
/// Properties that are not set for this <see cref="Style"/> will be inherited from <paramref name="overrideStyle"/>. /// Properties that are not set for this <see cref="Style"/> will be inherited from <paramref name="overrideStyle"/>.
/// </summary> /// </summary>
/// <param name="overrideStyle"></param> /// <param name="other"></param>
/// <returns>A merged <see cref="Style"/>.</returns> /// <returns>A merged <see cref="Style"/>.</returns>
public Style Merge(Style overrideStyle) public Style Merge(Style other)
{ {
return new Style return new Style
{ {
BackgroundColor = overrideStyle.BackgroundColor != default ? overrideStyle.BackgroundColor : BackgroundColor, Padding =
TextColor = overrideStyle.TextColor != default ? overrideStyle.TextColor : TextColor, other.Padding ?? Padding,
Padding = overrideStyle.Padding != default ? overrideStyle.Padding : Padding,
BorderSize = overrideStyle.BorderSize != default ? overrideStyle.BorderSize : BorderSize, BackgroundColor =
BorderColor = overrideStyle.BorderColor != default ? overrideStyle.BorderColor : BorderColor, other.BackgroundColor ?? BackgroundColor,
BorderSize =
other.BorderSize ?? BorderSize,
BorderColor =
other.BorderColor ?? BorderColor,
TextColor =
other.TextColor ?? TextColor,
CornerRadius =
other.CornerRadius != default
? other.CornerRadius
: CornerRadius,
TransitionDuration =
other.TransitionDuration != default
? other.TransitionDuration
: TransitionDuration,
Transition =
other.Transition
}; };
} }
} }
@@ -88,12 +110,12 @@ public class StyleSheetLoader : ResourceLoader<StyleSheet>
{ {
var style = new Style(); var style = new Style();
string easingName = reader.GetString("TransitionType", "Linear"); string transitionName = reader.GetString("TransitionType", "Linear");
if (!Enum.TryParse<Style.AnimationType>(easingName, true, out var easing)) if (!Enum.TryParse<Style.TransitionType>(transitionName, true, out var transition))
easing = Style.AnimationType.Linear; throw new ArgumentException($"\"{transitionName}\" is not a valid TransitionType.");
style.TransitionType = easing; style.Transition = transition;
if (reader.HasKey("BackgroundColor")) if (reader.HasKey("BackgroundColor"))
@@ -147,9 +169,13 @@ public class StyleSheet : Resource
public void Add(string key, Style style) => _styles.Add(key, style); public void Add(string key, Style style) => _styles.Add(key, style);
public bool TryGet(string styleName, [NotNullWhen(true)] out Style? style) public bool TryGet(
string styleName,
[NotNullWhen(true)] out Style? style)
{ {
return _styles.TryGetValue(styleName, out style); style = Resolve(styleName);
return style != null;
} }
public static StyleSheet Default => new(new Dictionary<string, Style>() public static StyleSheet Default => new(new Dictionary<string, Style>()
@@ -226,5 +252,29 @@ public class StyleSheet : Resource
}}, }},
}); });
private Style? Resolve(string fullKey)
{
var parts = fullKey.Split('.');
Style? merged = null;
for (int i = 1; i <= parts.Length; i++)
{
var subKey = string.Join('.',
parts.Take(i));
if (_styles.TryGetValue(
subKey,
out var style))
{
merged ??= new Style();
merged = merged.Merge(style);
}
}
return merged;
}
private Dictionary<string, Style> _styles = new(); private Dictionary<string, Style> _styles = new();
} }

View File

@@ -13,14 +13,14 @@ public class StyleAnimator
_elapsed = 0f; _elapsed = 0f;
} }
public static float Ease(float t, Style.AnimationType type) public static float Ease(float t, Style.TransitionType type)
{ {
return type switch return type switch
{ {
Style.AnimationType.Linear => t, Style.TransitionType.Linear => t,
Style.AnimationType.EaseIn => t * t, Style.TransitionType.EaseIn => t * t,
Style.AnimationType.EaseOut => t * (2 - t), Style.TransitionType.EaseOut => t * (2 - t),
Style.AnimationType.EaseInOut => t < 0.5f Style.TransitionType.EaseInOut => t < 0.5f
? 2 * t * t ? 2 * t * t
: -1 + (4 - 2 * t) * t, : -1 + (4 - 2 * t) * t,
_ => t _ => t
@@ -31,7 +31,7 @@ public class StyleAnimator
{ {
_elapsed = MathF.Min(_elapsed + deltaTime, _duration); _elapsed = MathF.Min(_elapsed + deltaTime, _duration);
float t = _duration == 0 ? 1 : _elapsed / _duration; float t = _duration == 0 ? 1 : _elapsed / _duration;
float easedT = Ease(t, _to.TransitionType); float easedT = Ease(t, _to.Transition);
return LerpStyle(_from, _to, easedT); return LerpStyle(_from, _to, easedT);
} }
@@ -45,7 +45,7 @@ public class StyleAnimator
Padding = MathUtils.LerpSize(from.Padding ?? Size.Zero, to.Padding ?? Size.Zero, t), Padding = MathUtils.LerpSize(from.Padding ?? Size.Zero, to.Padding ?? Size.Zero, t),
BorderColor = MathUtils.LerpColor(from.BorderColor ?? Color.Transparent, to.BorderColor ?? Color.Transparent, t), BorderColor = MathUtils.LerpColor(from.BorderColor ?? Color.Transparent, to.BorderColor ?? Color.Transparent, t),
BorderSize = MathUtils.LerpSize(from.BorderSize ?? Size.Zero, to.BorderSize ?? Size.Zero, t), BorderSize = MathUtils.LerpSize(from.BorderSize ?? Size.Zero, to.BorderSize ?? Size.Zero, t),
TransitionType = to.TransitionType Transition = to.Transition
}; };
return result; return result;