280 lines
7.9 KiB
C#
280 lines
7.9 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
using Voile.Resources;
|
|
using Voile.Resources.DataReaders;
|
|
using Voile.UI.Containers;
|
|
using Voile.VFS;
|
|
|
|
namespace Voile.UI;
|
|
|
|
/// <summary>
|
|
/// UI style settings.
|
|
/// </summary>
|
|
public class Style
|
|
{
|
|
public enum TransitionType
|
|
{
|
|
Linear,
|
|
EaseIn,
|
|
EaseOut,
|
|
EaseInOut
|
|
}
|
|
|
|
public float TransitionDuration = 0f;
|
|
public TransitionType Transition = TransitionType.Linear;
|
|
|
|
public Style() { }
|
|
|
|
public Size? Padding { get; set; }
|
|
public Color? BackgroundColor { get; set; }
|
|
public Size? BorderSize { get; set; }
|
|
public Color? BorderColor { get; set; }
|
|
public float CornerRadius { get; set; }
|
|
public Color? TextColor { get; set; }
|
|
|
|
/// <summary>
|
|
/// 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="other"></param>
|
|
/// <returns>A merged <see cref="Style"/>.</returns>
|
|
public Style Merge(Style other)
|
|
{
|
|
return new Style
|
|
{
|
|
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
|
|
};
|
|
}
|
|
}
|
|
|
|
public class StyleSheetLoader : ResourceLoader<StyleSheet>
|
|
{
|
|
public override IEnumerable<string> SupportedExtensions => [".toml"];
|
|
|
|
protected override StyleSheet LoadResource(string path)
|
|
{
|
|
var result = new StyleSheet(path);
|
|
var allStyles = new Dictionary<string, Style>();
|
|
|
|
using var stream = VirtualFileSystem.Read(path);
|
|
_reader.Read(stream);
|
|
|
|
foreach (var styleKey in _reader.GetSubKeysRecursive())
|
|
{
|
|
var subReader = _reader.GetSubReader(styleKey);
|
|
if (subReader == null || !subReader.Valid())
|
|
continue;
|
|
|
|
var style = ParseStyle(subReader, styleKey);
|
|
if (style != null)
|
|
{
|
|
allStyles[styleKey] = style;
|
|
}
|
|
}
|
|
|
|
foreach (var kvp in allStyles)
|
|
{
|
|
var finalStyle = GetMergedStyle(kvp.Key, allStyles);
|
|
result.Add(kvp.Key, finalStyle);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private Style ParseStyle(TomlDataReader reader, string input)
|
|
{
|
|
var style = new Style();
|
|
|
|
string transitionName = reader.GetString("TransitionType", "Linear");
|
|
|
|
if (!Enum.TryParse<Style.TransitionType>(transitionName, true, out var transition))
|
|
throw new ArgumentException($"\"{transitionName}\" is not a valid TransitionType.");
|
|
|
|
style.Transition = transition;
|
|
|
|
|
|
if (reader.HasKey("BackgroundColor"))
|
|
style.BackgroundColor = reader.GetColor("BackgroundColor", Color.Transparent);
|
|
|
|
if (reader.HasKey("TextColor"))
|
|
style.TextColor = reader.GetColor("TextColor", Color.Black);
|
|
|
|
if (reader.HasKey("Padding"))
|
|
style.Padding = reader.GetSize("Padding", Size.Zero);
|
|
|
|
if (reader.HasKey("BorderSize"))
|
|
style.BorderSize = reader.GetSize("BorderSize", Size.Zero);
|
|
|
|
if (reader.HasKey("BorderColor"))
|
|
style.BorderColor = reader.GetColor("BorderColor", Color.Transparent);
|
|
|
|
return style;
|
|
}
|
|
|
|
private Style GetMergedStyle(string fullKey, Dictionary<string, Style> allStyles)
|
|
{
|
|
var parts = fullKey.Split('.');
|
|
var merged = new Style();
|
|
|
|
for (int i = 1; i <= parts.Length; i++)
|
|
{
|
|
var subKey = string.Join('.', parts.Take(i));
|
|
if (allStyles.TryGetValue(subKey, out var parentStyle))
|
|
{
|
|
merged = merged.Merge(parentStyle);
|
|
}
|
|
}
|
|
|
|
return merged;
|
|
}
|
|
|
|
private readonly TomlDataReader _reader = new();
|
|
}
|
|
|
|
public class StyleSheet : Resource
|
|
{
|
|
public StyleSheet(string path) : base(path)
|
|
{
|
|
}
|
|
|
|
public StyleSheet(Dictionary<string, Style> styles) : base(string.Empty)
|
|
{
|
|
_styles = styles;
|
|
}
|
|
|
|
public void Add(string key, Style style) => _styles.Add(key, style);
|
|
|
|
public bool TryGet(
|
|
string styleName,
|
|
[NotNullWhen(true)] out Style? style)
|
|
{
|
|
style = Resolve(styleName);
|
|
|
|
return style != null;
|
|
}
|
|
|
|
public static StyleSheet Default => new(new Dictionary<string, Style>()
|
|
{
|
|
{"Label", new Style()
|
|
{
|
|
TextColor = Color.FromHexString("#161616"),
|
|
BackgroundColor = Color.DarkRed,
|
|
BorderSize = new Size(2.0f),
|
|
BorderColor = Color.Red
|
|
}},
|
|
{ "Button", new Style()
|
|
{
|
|
Padding = new Size(8.0f),
|
|
BackgroundColor = Color.FromHexString("#0f62fe"),
|
|
TextColor = Color.FromHexString("#ffffff"),
|
|
}},
|
|
{"Button.Normal", new Style()
|
|
{
|
|
Padding = new Size(8.0f),
|
|
BackgroundColor = Color.FromHexString("#0f62fe"),
|
|
TextColor = Color.FromHexString("#ffffff"),
|
|
}},
|
|
{"Button.Hovered", new Style()
|
|
{
|
|
Padding = new Size(8.0f),
|
|
BackgroundColor = Color.FromHexString("#0353e9"),
|
|
TextColor = Color.FromHexString("#ffffff"),
|
|
}},
|
|
{"Button.Pressed", new Style()
|
|
{
|
|
Padding = new Size(8.0f),
|
|
BackgroundColor = Color.FromHexString("#002d9c"),
|
|
TextColor = Color.FromHexString("#ffffff"),
|
|
}},
|
|
{"Button.Danger", new Style()
|
|
{
|
|
Padding = new Size(8.0f),
|
|
BackgroundColor = Color.FromHexString("#da1e28"),
|
|
TextColor = Color.FromHexString("#ffffff"),
|
|
}},
|
|
{"Button.Danger.Normal", new Style()
|
|
{
|
|
Padding = new Size(8.0f),
|
|
BackgroundColor = Color.FromHexString("#da1e28"),
|
|
TextColor = Color.FromHexString("#ffffff"),
|
|
}},
|
|
{"Button.Danger.Hovered", new Style()
|
|
{
|
|
Padding = new Size(8.0f),
|
|
BackgroundColor = Color.FromHexString("#ba1b23"),
|
|
TextColor = Color.FromHexString("#ffffff"),
|
|
}},
|
|
{"Button.Danger.Pressed", new Style()
|
|
{
|
|
Padding = new Size(8.0f),
|
|
BackgroundColor = Color.FromHexString("#750e13"),
|
|
TextColor = Color.FromHexString("#ffffff"),
|
|
}},
|
|
{"Container", new Style()
|
|
{
|
|
BackgroundColor = Color.FromHexString("#ffffff"),
|
|
TextColor = Color.FromHexString("#ffffff"),
|
|
}},
|
|
{"Container.Layer01", new Style()
|
|
{
|
|
BackgroundColor = Color.FromHexString("#f4f4f4"),
|
|
TextColor = Color.FromHexString("#ffffff"),
|
|
}},
|
|
{"Container.Layer02", new Style()
|
|
{
|
|
BackgroundColor = Color.FromHexString("#e8e8e8"),
|
|
TextColor = Color.FromHexString("#ffffff"),
|
|
}},
|
|
});
|
|
|
|
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();
|
|
} |