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]
BackgroundColor = "#0f62fe"
CornerRadius = 16.0
TextColor = "#ffffff"
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]
BackgroundColor = "#0353e9"

View File

@@ -11,7 +11,7 @@ namespace Voile.UI;
/// </summary>
public class Style
{
public enum AnimationType
public enum TransitionType
{
Linear,
EaseIn,
@@ -20,7 +20,7 @@ public class Style
}
public float TransitionDuration = 0f;
public AnimationType TransitionType = AnimationType.Linear;
public TransitionType Transition = TransitionType.Linear;
public Style() { }
@@ -35,17 +35,39 @@ public class Style
/// 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"/>.
/// </summary>
/// <param name="overrideStyle"></param>
/// <param name="other"></param>
/// <returns>A merged <see cref="Style"/>.</returns>
public Style Merge(Style overrideStyle)
public Style Merge(Style other)
{
return new Style
{
BackgroundColor = overrideStyle.BackgroundColor != default ? overrideStyle.BackgroundColor : BackgroundColor,
TextColor = overrideStyle.TextColor != default ? overrideStyle.TextColor : TextColor,
Padding = overrideStyle.Padding != default ? overrideStyle.Padding : Padding,
BorderSize = overrideStyle.BorderSize != default ? overrideStyle.BorderSize : BorderSize,
BorderColor = overrideStyle.BorderColor != default ? overrideStyle.BorderColor : BorderColor,
Padding =
other.Padding ?? Padding,
BackgroundColor =
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();
string easingName = reader.GetString("TransitionType", "Linear");
string transitionName = reader.GetString("TransitionType", "Linear");
if (!Enum.TryParse<Style.AnimationType>(easingName, true, out var easing))
easing = Style.AnimationType.Linear;
if (!Enum.TryParse<Style.TransitionType>(transitionName, true, out var transition))
throw new ArgumentException($"\"{transitionName}\" is not a valid TransitionType.");
style.TransitionType = easing;
style.Transition = transition;
if (reader.HasKey("BackgroundColor"))
@@ -147,9 +169,13 @@ public class StyleSheet : Resource
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>()
@@ -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();
}

View File

@@ -13,14 +13,14 @@ public class StyleAnimator
_elapsed = 0f;
}
public static float Ease(float t, Style.AnimationType type)
public static float Ease(float t, Style.TransitionType type)
{
return type switch
{
Style.AnimationType.Linear => t,
Style.AnimationType.EaseIn => t * t,
Style.AnimationType.EaseOut => t * (2 - t),
Style.AnimationType.EaseInOut => t < 0.5f
Style.TransitionType.Linear => t,
Style.TransitionType.EaseIn => t * t,
Style.TransitionType.EaseOut => t * (2 - t),
Style.TransitionType.EaseInOut => t < 0.5f
? 2 * t * t
: -1 + (4 - 2 * t) * t,
_ => t
@@ -31,7 +31,7 @@ public class StyleAnimator
{
_elapsed = MathF.Min(_elapsed + deltaTime, _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);
}
@@ -45,7 +45,7 @@ public class StyleAnimator
Padding = MathUtils.LerpSize(from.Padding ?? Size.Zero, to.Padding ?? Size.Zero, 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),
TransitionType = to.TransitionType
Transition = to.Transition
};
return result;