Compare commits

...

3 Commits

16 changed files with 168 additions and 31 deletions

View File

@@ -115,7 +115,7 @@ public class TestGame : Game
{ {
if (Input.IsActionPressed("reload")) if (Input.IsActionPressed("reload"))
{ {
ResourceManager.Reload(); // ResourceManager.Reload();
// _particleSystem!.RestartEmitter(_emitterId); // _particleSystem!.RestartEmitter(_emitterId);
} }
} }

View File

@@ -7,15 +7,23 @@ namespace Voile;
public class GridSet<T> public class GridSet<T>
{ {
public float GridSize { get; } /// <summary>
public GridSet(float gridSize = 32.0f) /// The size of a cell of this <see cref="GridSet"/>.
/// </summary>
public float CellSize { get; }
public GridSet(float cellSize = 32.0f)
{ {
GridSize = gridSize; CellSize = cellSize;
} }
/// <summary>
/// Add an element to this <see cref="GridSet"/>.
/// </summary>
/// <param name="position">Position of the element in this <see cref="GridSet"/>.</param>
/// <param name="child">Element to add.</param>
public void Add(Vector2 position, T child) public void Add(Vector2 position, T child)
{ {
var snap = Vector2.One * GridSize; var snap = Vector2.One * CellSize;
position = position.Snapped(snap); position = position.Snapped(snap);
if (_values.TryGetValue(position, out var list)) if (_values.TryGetValue(position, out var list))
@@ -28,10 +36,11 @@ public class GridSet<T>
} }
} }
public void Remove(T child) /// <summary>
{ /// Removes an element from this <see cref="GridSet"/>.
/// </summary>
} /// <param name="child">Element to remove.</param>
public void Remove(T child) => throw new NotImplementedException();
private Dictionary<Vector2, List<T>> _values = new(); private Dictionary<Vector2, List<T>> _values = new();
} }

View File

@@ -65,6 +65,9 @@ namespace Voile.Resources.DataReaders
/// <param name="defaultValue">Default value in case this getter fails to get data.</param> /// <param name="defaultValue">Default value in case this getter fails to get data.</param>
/// <returns></returns> /// <returns></returns>
double GetDouble(string key, double defaultValue = 0.0); double GetDouble(string key, double defaultValue = 0.0);
string GetString(string key, string defaultValue);
/// <summary> /// <summary>
/// Get a Voile.Color from this data getter. /// Get a Voile.Color from this data getter.
/// </summary> /// </summary>

View File

@@ -105,6 +105,21 @@ public class TomlDataReader : IStreamDataReader, IDataValidator, IStreamKeyValue
public double GetDouble(string key, double defaultValue = 0) public double GetDouble(string key, double defaultValue = 0)
=> TryGetNode(key, out var node) && node.IsFloat ? node.AsFloat : defaultValue; => TryGetNode(key, out var node) && node.IsFloat ? node.AsFloat : defaultValue;
public string GetString(string key, string defaultValue)
{
if (!TryGetNode(key, out var node))
{
return defaultValue;
}
if (node.IsString)
{
return node.AsString;
}
return defaultValue;
}
public Color GetColor(string key, Color defaultValue) public Color GetColor(string key, Color defaultValue)
{ {
if (!TryGetNode(key, out var node)) if (!TryGetNode(key, out var node))
@@ -225,7 +240,6 @@ public class TomlDataReader : IStreamDataReader, IDataValidator, IStreamKeyValue
return false; return false;
} }
private TomlTable? _table; private TomlTable? _table;
private bool _valid; private bool _valid;

View File

@@ -269,7 +269,6 @@ namespace Voile.Resources
| NotifyFilters.CreationTime | NotifyFilters.CreationTime
| NotifyFilters.DirectoryName | NotifyFilters.DirectoryName
| NotifyFilters.FileName | NotifyFilters.FileName
| NotifyFilters.LastAccess
| NotifyFilters.LastWrite | NotifyFilters.LastWrite
| NotifyFilters.Security | NotifyFilters.Security
| NotifyFilters.Size; | NotifyFilters.Size;

View File

@@ -140,10 +140,8 @@ public abstract class Container : UIElement, IParentableElement
Update(); Update();
} }
public override void Render(RenderSystem renderer, Style style) protected override void OnRender(RenderSystem renderer, Style style)
{ {
RenderStyleBox(renderer, style);
foreach (var child in Children) foreach (var child in Children)
{ {
if (child is not IRenderableElement renderable) continue; if (child is not IRenderableElement renderable) continue;

View File

@@ -23,9 +23,9 @@ public class FillContainer : Container
} }
public override void Render(RenderSystem renderer, Style style) protected override void OnRender(RenderSystem renderer, Style style)
{ {
base.Render(renderer, style); base.OnRender(renderer, style);
Rect parentSize; Rect parentSize;

View File

@@ -63,7 +63,7 @@ public interface IUpdatableElement
/// <summary> /// <summary>
/// Update this element. /// Update this element.
/// </summary> /// </summary>
void Update(); void Update(float dt = 0.0f);
/// <summary> /// <summary>
/// Marks this element as changed, requiring an update. /// Marks this element as changed, requiring an update.
/// </summary> /// </summary>

View File

@@ -11,6 +11,16 @@ namespace Voile.UI;
/// </summary> /// </summary>
public class Style public class Style
{ {
public enum AnimationType
{
Linear,
EaseIn,
EaseOut,
EaseInOut
}
public float TransitionDuration = 0f;
public AnimationType TransitionType = AnimationType.Linear;
public Style() { } public Style() { }
@@ -78,6 +88,14 @@ public class StyleSheetLoader : ResourceLoader<StyleSheet>
{ {
var style = new Style(); var style = new Style();
string easingName = reader.GetString("TransitionType", "Linear");
if (!Enum.TryParse<Style.AnimationType>(easingName, true, out var easing))
easing = Style.AnimationType.Linear;
style.TransitionType = easing;
if (reader.HasKey("BackgroundColor")) if (reader.HasKey("BackgroundColor"))
style.BackgroundColor = reader.GetColor("BackgroundColor", Color.Transparent); style.BackgroundColor = reader.GetColor("BackgroundColor", Color.Transparent);

View File

@@ -0,0 +1,56 @@
namespace Voile.UI;
public class StyleAnimator
{
public bool IsComplete => _elapsed >= _duration;
public StyleAnimator(Style from, Style to, float duration)
{
_from = from;
_to = to;
_duration = duration;
_elapsed = 0f;
}
public static float Ease(float t, Style.AnimationType 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
? 2 * t * t
: -1 + (4 - 2 * t) * t,
_ => t
};
}
public Style Update(float deltaTime)
{
_elapsed = MathF.Min(_elapsed + deltaTime, _duration);
float t = _duration == 0 ? 1 : _elapsed / _duration;
float easedT = Ease(t, _to.TransitionType);
return LerpStyle(_from, _to, easedT);
}
private static Style LerpStyle(Style from, Style to, float t)
{
var result = new Style()
{
BackgroundColor = MathUtils.LerpColor(from.BackgroundColor ?? Color.Transparent, to.BackgroundColor ?? Color.Transparent, t),
TextColor = MathUtils.LerpColor(from.TextColor ?? Color.Black, to.TextColor ?? Color.Black, 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),
BorderSize = MathUtils.LerpSize(from.BorderSize ?? Size.Zero, to.BorderSize ?? Size.Zero, t),
TransitionType = to.TransitionType
};
return result;
}
private Style _from, _to;
private float _duration, _elapsed;
}

View File

@@ -91,7 +91,7 @@ public abstract class UIElement : IElement, IRenderableElement, IResizeableEleme
MarkDirty(); MarkDirty();
} }
public void Update() public void Update(float dt = 0.0f)
{ {
if (!_dirty) return; if (!_dirty) return;
_dirty = false; _dirty = false;
@@ -107,7 +107,13 @@ public abstract class UIElement : IElement, IRenderableElement, IResizeableEleme
} }
} }
public abstract void Render(RenderSystem renderer, Style style); public void Render(RenderSystem renderer, Style style)
{
RenderStyleBox(renderer, style);
OnRender(renderer, style);
}
protected abstract void OnRender(RenderSystem renderer, Style style);
protected abstract void OnUpdate(); protected abstract void OnUpdate();
/// <summary> /// <summary>

View File

@@ -3,19 +3,48 @@ using Voile.Input;
namespace Voile.UI; namespace Voile.UI;
/// <summary>
/// Input information for UI elements.
/// </summary>
public class UIInputContext public class UIInputContext
{ {
/// <summary>
/// Current action handled by this <see cref="UIElement"/>.
/// </summary>
public IInputAction Action { get; } public IInputAction Action { get; }
/// <summary>
/// Current mouse position.
/// </summary>
public Vector2 MousePosition { get; } public Vector2 MousePosition { get; }
/// <summary>
/// Determines if a mouse button was pressed.
/// </summary>
public bool MousePressed { get; set; } public bool MousePressed { get; set; }
/// <summary>
/// Determines if a mouse button was released.
/// </summary>
public bool MouseReleased { get; set; } public bool MouseReleased { get; set; }
/// <summary>
/// Determines if a mouse button is currently held.
/// </summary>
public bool MouseDown { get; set; } public bool MouseDown { get; set; }
/// <summary>
/// Name of the current <see cref="IInputAction"/>.
/// </summary>
public string ActionName { get; } public string ActionName { get; }
/// <summary>
/// Keycode of a currently pressed character.
/// </summary>
public int CharPressed { get; } public int CharPressed { get; }
/// <summary>
/// Determines if this <see cref="UIInputContext"/> registered any character input from keyboard.
/// </summary>
public bool HasCharInput => CharPressed != 0; public bool HasCharInput => CharPressed != 0;
/// <summary>
/// Determines if this context's input was already handled and no longer needs to be processed.
/// </summary>
public bool Handled => _handled; public bool Handled => _handled;
/// <summary> /// <summary>

View File

@@ -81,7 +81,7 @@ public class Button : Widget
Update(); Update();
} }
public override void Render(RenderSystem renderer, Style style) protected override void OnRender(RenderSystem renderer, Style style)
{ {
if (_padding != style.Padding) if (_padding != style.Padding)
{ {
@@ -91,11 +91,6 @@ public class Button : Widget
_padding = style.Padding ?? Voile.Size.Zero; _padding = style.Padding ?? Voile.Size.Zero;
var textColor = style.TextColor ?? Color.Black; var textColor = style.TextColor ?? Color.Black;
// renderer.SetTransform(GlobalPosition, Vector2.Zero);
// renderer.DrawRectangle(new Vector2(Size.Width, Size.Height), backgroundColor);
RenderStyleBox(renderer, style);
var textPosition = new Vector2(GlobalPosition.X + Padding.Left, GlobalPosition.Y + Padding.Top); var textPosition = new Vector2(GlobalPosition.X + Padding.Left, GlobalPosition.Y + Padding.Top);
renderer.SetTransform(textPosition, Vector2.Zero); renderer.SetTransform(textPosition, Vector2.Zero);
renderer.DrawText(_suitableFont, _text, textColor); renderer.DrawText(_suitableFont, _text, textColor);

View File

@@ -50,10 +50,8 @@ public class Label : Widget
} }
public override void Render(RenderSystem renderer, Style style) protected override void OnRender(RenderSystem renderer, Style style)
{ {
RenderStyleBox(renderer, style);
renderer.SetTransform(GlobalPosition, Vector2.Zero); renderer.SetTransform(GlobalPosition, Vector2.Zero);
renderer.DrawText(_suitableFont, _text, style.TextColor ?? Color.Black); renderer.DrawText(_suitableFont, _text, style.TextColor ?? Color.Black);
} }

View File

@@ -20,7 +20,7 @@ public class RectangleWidget : Widget
_hoverColor = color.Lightened(0.25f); _hoverColor = color.Lightened(0.25f);
} }
public override void Render(RenderSystem renderer, Style style) protected override void OnRender(RenderSystem renderer, Style style)
{ {
renderer.SetTransform(GlobalPosition, Vector2.Zero); renderer.SetTransform(GlobalPosition, Vector2.Zero);
renderer.DrawRectangle(new Vector2(Size.Width, Size.Height), Color); renderer.DrawRectangle(new Vector2(Size.Width, Size.Height), Color);

View File

@@ -15,6 +15,18 @@ namespace Voile
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static float Lerp(float a, float b, float t) => t <= 0f ? a : t >= 1f ? b : LerpUnclamped(a, b, t); public static float Lerp(float a, float b, float t) => t <= 0f ? a : t >= 1f ? b : LerpUnclamped(a, b, t);
public static Size LerpSize(Size a, Size b, float t)
{
t = Math.Clamp(t, 0f, 1f);
float left = Lerp(a.Left, b.Left, t);
float right = Lerp(a.Right, b.Right, t);
float top = Lerp(a.Top, b.Top, t);
float bottom = Lerp(a.Bottom, b.Bottom, t);
return new Size(left, right, top, bottom);
}
public static Color LerpColor(Color colorA, Color colorB, float t) public static Color LerpColor(Color colorA, Color colorB, float t)
{ {
t = Math.Clamp(t, 0f, 1f); t = Math.Clamp(t, 0f, 1f);