190 lines
4.1 KiB
C#
190 lines
4.1 KiB
C#
using System.Numerics;
|
|
using Voile.Rendering;
|
|
using Voile.Resources;
|
|
|
|
namespace Voile.UI.Widgets;
|
|
|
|
/// <summary>
|
|
/// A clickable button with a label.
|
|
/// </summary>
|
|
public class Button : Widget
|
|
{
|
|
public enum ButtonState
|
|
{
|
|
Disabled,
|
|
Hovered,
|
|
Pressed,
|
|
Focused,
|
|
Normal
|
|
}
|
|
|
|
public string Text
|
|
{
|
|
get => _text; set
|
|
{
|
|
_text = value;
|
|
MarkDirty(DirtyFlags.Content);
|
|
}
|
|
}
|
|
|
|
public ButtonState CurrentState { get; private set; } = ButtonState.Normal;
|
|
|
|
public override Rect MinimumSize => Padding + _textSize;
|
|
|
|
/// <summary>
|
|
/// <see cref="FontSet"/> to use with this button.
|
|
/// </summary>
|
|
public FontSet FontSet { get; set; } = new();
|
|
public Size Padding
|
|
{
|
|
get => _padding; set
|
|
{
|
|
_padding = value;
|
|
}
|
|
}
|
|
|
|
public override string? StyleElementName => nameof(Button);
|
|
public override string[]? StyleModifiers =>
|
|
[
|
|
CurrentState.ToString()
|
|
];
|
|
|
|
public Button(string text, ResourceRef<Font> fontOverride, Action pressedAction)
|
|
{
|
|
_text = text;
|
|
_pressedAction = pressedAction;
|
|
|
|
FontSet.AddFont(fontOverride);
|
|
|
|
MarkDirty();
|
|
}
|
|
|
|
public Button(string text, FontSet fontSet)
|
|
{
|
|
_text = text;
|
|
|
|
FontSet = fontSet;
|
|
|
|
MarkDirty();
|
|
}
|
|
|
|
public Button(string text, FontSet fontSet, Action pressedAction)
|
|
{
|
|
_text = text;
|
|
_pressedAction = pressedAction;
|
|
|
|
FontSet = fontSet;
|
|
|
|
MarkDirty();
|
|
}
|
|
|
|
protected override void OnRender(RenderSystem renderer, Style style)
|
|
{
|
|
_padding = style.Padding ?? Voile.Size.Zero;
|
|
|
|
var color = style.TextColor ?? Color.Black;
|
|
|
|
var pos = new Vector2(
|
|
GlobalPosition.X + _padding.Left,
|
|
GlobalPosition.Y + _padding.Top);
|
|
|
|
renderer.SetTransform(pos, Vector2.Zero);
|
|
|
|
if (_font.HasValue)
|
|
{
|
|
renderer.DrawText(_font, _text, color);
|
|
}
|
|
}
|
|
|
|
protected virtual void Pressed() { }
|
|
|
|
protected override void OnInput(UIInputContext action)
|
|
{
|
|
bool isHovering = ContainsPoint(action.MousePosition);
|
|
|
|
if (action.MousePressed && isHovering)
|
|
{
|
|
_isHeldDown = true;
|
|
CurrentState = ButtonState.Pressed;
|
|
}
|
|
else if (action.MouseReleased)
|
|
{
|
|
if (_isHeldDown && isHovering)
|
|
{
|
|
_pressedAction?.Invoke();
|
|
Pressed();
|
|
}
|
|
|
|
_isHeldDown = false;
|
|
CurrentState = isHovering ? ButtonState.Hovered : ButtonState.Normal;
|
|
}
|
|
else
|
|
{
|
|
if (_isHeldDown)
|
|
{
|
|
CurrentState = ButtonState.Pressed; // keep showing as pressed
|
|
}
|
|
else if (isHovering)
|
|
{
|
|
CurrentState = ButtonState.Hovered;
|
|
}
|
|
else
|
|
{
|
|
CurrentState = ButtonState.Normal;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void OnUpdate(LayoutContext layoutContext)
|
|
{
|
|
ResolveFont();
|
|
|
|
if (!_font.HasValue)
|
|
return;
|
|
|
|
var font = _font.Value;
|
|
|
|
var newSize = font.Measure(_text);
|
|
_textSize = newSize;
|
|
|
|
var final = _textSize + _padding;
|
|
|
|
if (_cachedSize.Width == final.Width &&
|
|
_cachedSize.Height == final.Height)
|
|
return;
|
|
|
|
_cachedSize = final;
|
|
|
|
Size = final;
|
|
|
|
MarkDirty(DirtyFlags.Layout);
|
|
}
|
|
|
|
private void ResolveFont()
|
|
{
|
|
if (_font.HasValue)
|
|
return;
|
|
|
|
var text = _text;
|
|
|
|
for (int i = 0; i < text.Length; i++)
|
|
{
|
|
if (FontSet.TryGetFontFor(text[i], out var f))
|
|
{
|
|
_font = f;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private Action? _pressedAction;
|
|
private Rect _cachedSize = Rect.Zero;
|
|
private string _text = "Hello, World!";
|
|
private Rect _textSize = Rect.Zero;
|
|
|
|
private ResourceRef<Font> _font = ResourceRef<Font>.Empty();
|
|
|
|
private Size _padding;
|
|
|
|
private bool _isHeldDown;
|
|
} |