Compare commits
2 Commits
e75dcb7753
...
6f3a945f34
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f3a945f34 | |||
| c18adaeede |
6
TODO.md
6
TODO.md
@@ -94,8 +94,10 @@
|
|||||||
- Input propagation
|
- Input propagation
|
||||||
- ~~Pass input to widgets.~~
|
- ~~Pass input to widgets.~~
|
||||||
- Add element focus logic, make them focusable with action inputs.
|
- Add element focus logic, make them focusable with action inputs.
|
||||||
- Basic input elements (button, text field, toggle).
|
- Basic input elements (~~button~~, text field, toggle).
|
||||||
- Styling
|
- Styling
|
||||||
- Add style settings for UI panels (for buttons, labels, etc.).
|
- ~~Style sheet~~
|
||||||
|
- ~~Add style settings for UI panels (for buttons, labels, etc.).~~
|
||||||
|
- Animated styles
|
||||||
- Find a way to reference external assets in the style (fonts, textures).
|
- Find a way to reference external assets in the style (fonts, textures).
|
||||||
- Create a default style for widgets.
|
- Create a default style for widgets.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class TestGame : Game
|
|||||||
{
|
{
|
||||||
InitializeSystemsDefault();
|
InitializeSystemsDefault();
|
||||||
|
|
||||||
_uiSystem = new UISystem(Input, ResourceRef<Style>.Empty());
|
_uiSystem = new UISystem(Input, StyleSheet.Default);
|
||||||
// _uiSystem.RenderDebugRects = true;
|
// _uiSystem.RenderDebugRects = true;
|
||||||
|
|
||||||
_particleSystem = new ParticleSystem();
|
_particleSystem = new ParticleSystem();
|
||||||
@@ -64,7 +64,6 @@ public class TestGame : Game
|
|||||||
_emitterId = _particleSystem.CreateEmitter(Renderer.WindowSize / 2, _fireEffect);
|
_emitterId = _particleSystem.CreateEmitter(Renderer.WindowSize / 2, _fireEffect);
|
||||||
|
|
||||||
var addButton = new Button("Add element", _defaultFontSet, () => { _container.AddChild(new Label("Hello, World!", _defaultFontSet)); });
|
var addButton = new Button("Add element", _defaultFontSet, () => { _container.AddChild(new Label("Hello, World!", _defaultFontSet)); });
|
||||||
addButton.Padding = new Margin(8.0f);
|
|
||||||
|
|
||||||
var removeButton = new Button("Remove element", _defaultFontSet, () =>
|
var removeButton = new Button("Remove element", _defaultFontSet, () =>
|
||||||
{
|
{
|
||||||
@@ -73,21 +72,30 @@ public class TestGame : Game
|
|||||||
_container.RemoveChild(lastChild);
|
_container.RemoveChild(lastChild);
|
||||||
});
|
});
|
||||||
|
|
||||||
removeButton.Padding = new Margin(8.0f);
|
removeButton.StyleVariant = "Danger";
|
||||||
|
|
||||||
_buttonContainer.AddChild(addButton);
|
// _buttonContainer.AddChild(addButton);
|
||||||
_buttonContainer.AddChild(removeButton);
|
// _buttonContainer.AddChild(removeButton);
|
||||||
|
|
||||||
var c = new VerticalContainer();
|
var c = new HorizontalContainer()
|
||||||
|
{
|
||||||
|
StyleVariant = "Layer01",
|
||||||
|
ConfineToContents = true,
|
||||||
|
Anchor = Anchor.TopCenter
|
||||||
|
};
|
||||||
|
|
||||||
var m = new MarginContainer();
|
c.AddChild(addButton);
|
||||||
m.AddChild(_container);
|
c.AddChild(removeButton);
|
||||||
|
|
||||||
c.AddChild(_buttonContainer);
|
var vc = new VerticalContainer(0.0f);
|
||||||
c.AddChild(m);
|
vc.AddChild(c);
|
||||||
|
|
||||||
_rootFill.AddChild(c);
|
var f = new MarginContainer(new Margin(0.0f));
|
||||||
|
f.AddChild(_container);
|
||||||
|
|
||||||
|
vc.AddChild(f);
|
||||||
|
|
||||||
|
_rootFill.AddChild(vc);
|
||||||
_uiSystem.AddElement(_rootFill);
|
_uiSystem.AddElement(_rootFill);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +160,8 @@ public class TestGame : Game
|
|||||||
Justify = JustifyContent.Start,
|
Justify = JustifyContent.Start,
|
||||||
Align = AlignItems.Center,
|
Align = AlignItems.Center,
|
||||||
Wrap = true,
|
Wrap = true,
|
||||||
Gap = 8.0f
|
Gap = 8.0f,
|
||||||
|
StyleVariant = "Layer02",
|
||||||
};
|
};
|
||||||
|
|
||||||
[NotNull] private Label _label;
|
[NotNull] private Label _label;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace Voile.Input
|
|||||||
|
|
||||||
public bool IsPressed(InputSystem inputSystem)
|
public bool IsPressed(InputSystem inputSystem)
|
||||||
{
|
{
|
||||||
return inputSystem.IsMousePressed(MouseButton);
|
return inputSystem.IsMouseButtonPressed(MouseButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsDown(InputSystem inputSystem)
|
public bool IsDown(InputSystem inputSystem)
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ namespace Voile.Input
|
|||||||
|
|
||||||
public abstract int GetCharPressed();
|
public abstract int GetCharPressed();
|
||||||
|
|
||||||
public abstract bool IsMousePressed(MouseButton button);
|
public abstract bool IsMouseButtonPressed(MouseButton button);
|
||||||
public abstract bool IsMouseButtonDown(MouseButton button);
|
public abstract bool IsMouseButtonDown(MouseButton button);
|
||||||
public abstract bool IsMouseButtonReleased(MouseButton button);
|
public abstract bool IsMouseButtonReleased(MouseButton button);
|
||||||
public abstract float GetMouseWheelMovement();
|
public abstract float GetMouseWheelMovement();
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace Voile.Input
|
|||||||
public override bool KeyboardKeyJustPressed(KeyboardKey key) => _justPressedKeys.Contains(key);
|
public override bool KeyboardKeyJustPressed(KeyboardKey key) => _justPressedKeys.Contains(key);
|
||||||
public override bool KeyboardKeyJustReleased(KeyboardKey key) => _justReleasedKeys.Contains(key);
|
public override bool KeyboardKeyJustReleased(KeyboardKey key) => _justReleasedKeys.Contains(key);
|
||||||
|
|
||||||
public override bool IsMousePressed(MouseButton button) => _pressedMouseButtons.Contains(button);
|
public override bool IsMouseButtonPressed(MouseButton button) => _pressedMouseButtons.Contains(button);
|
||||||
public override bool IsMouseButtonReleased(MouseButton button) => _releasedMouseButtons.Contains(button);
|
public override bool IsMouseButtonReleased(MouseButton button) => _releasedMouseButtons.Contains(button);
|
||||||
public override bool IsMouseButtonDown(MouseButton button) => _downMouseButtons.Contains(button);
|
public override bool IsMouseButtonDown(MouseButton button) => _downMouseButtons.Contains(button);
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ public abstract class Container : UIElement, IParentableElement
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ConfineToContents { get; set; } = false;
|
public bool ConfineToContents { get; set; } = false;
|
||||||
|
|
||||||
|
public override string? StyleElementName => nameof(Container);
|
||||||
|
|
||||||
public override Rect MinimumSize => _minimumSize;
|
public override Rect MinimumSize => _minimumSize;
|
||||||
|
|
||||||
public Container()
|
public Container()
|
||||||
@@ -122,6 +124,7 @@ public abstract class Container : UIElement, IParentableElement
|
|||||||
|
|
||||||
public void AddChild(UIElement child)
|
public void AddChild(UIElement child)
|
||||||
{
|
{
|
||||||
|
// child.StyleSheetOverride = StyleSheet;
|
||||||
_children.Add(child);
|
_children.Add(child);
|
||||||
child.SetParent(this);
|
child.SetParent(this);
|
||||||
|
|
||||||
@@ -139,10 +142,18 @@ public abstract class Container : UIElement, IParentableElement
|
|||||||
|
|
||||||
public override void Render(RenderSystem renderer, Style style)
|
public override void Render(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;
|
||||||
renderable.Render(renderer, style);
|
|
||||||
|
if (!child.TryGetStyle(StyleSheet, out var childStyle))
|
||||||
|
{
|
||||||
|
childStyle = new Style();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderable.Render(renderer, childStyle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,11 @@ public class FillContainer : Container
|
|||||||
{
|
{
|
||||||
base.OnUpdate();
|
base.OnUpdate();
|
||||||
Size = _lastParentSize;
|
Size = _lastParentSize;
|
||||||
|
|
||||||
|
if (Children.Count != 0)
|
||||||
|
{
|
||||||
|
Children[0].Size = Size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Rect _lastParentSize = Rect.Zero;
|
private Rect _lastParentSize = Rect.Zero;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace Voile.UI.Containers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the margin offsets applied around an element.
|
/// Represents the margin offsets applied around an element.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct Margin
|
public struct Margin : IEquatable<Margin>
|
||||||
{
|
{
|
||||||
public float Left;
|
public float Left;
|
||||||
public float Right;
|
public float Right;
|
||||||
@@ -39,6 +39,25 @@ public struct Margin
|
|||||||
|
|
||||||
public static Rect operator +(Rect rect, Margin margin) =>
|
public static Rect operator +(Rect rect, Margin margin) =>
|
||||||
margin + rect;
|
margin + rect;
|
||||||
|
|
||||||
|
|
||||||
|
public static bool operator ==(Margin a, Margin b) =>
|
||||||
|
a.Equals(b);
|
||||||
|
|
||||||
|
public static bool operator !=(Margin a, Margin b) =>
|
||||||
|
!a.Equals(b);
|
||||||
|
|
||||||
|
public bool Equals(Margin other) =>
|
||||||
|
Left == other.Left &&
|
||||||
|
Right == other.Right &&
|
||||||
|
Top == other.Top &&
|
||||||
|
Bottom == other.Bottom;
|
||||||
|
|
||||||
|
public override bool Equals(object? obj) =>
|
||||||
|
obj is Margin other && Equals(other);
|
||||||
|
|
||||||
|
public override int GetHashCode() =>
|
||||||
|
HashCode.Combine(Left, Right, Top, Bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MarginContainer : Container
|
public class MarginContainer : Container
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Voile.Resources;
|
using Voile.Resources;
|
||||||
|
using Voile.UI.Containers;
|
||||||
|
|
||||||
namespace Voile.UI;
|
namespace Voile.UI;
|
||||||
|
|
||||||
@@ -10,4 +12,106 @@ public class Style : TextDataResource
|
|||||||
public Style(string path) : base(path)
|
public Style(string path) : base(path)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Style() : base(string.Empty) { }
|
||||||
|
|
||||||
|
public Margin Padding { get; set; }
|
||||||
|
public Color BackgroundColor { get; set; }
|
||||||
|
public Margin BorderSize { get; set; }
|
||||||
|
public Color BorderColor { get; set; }
|
||||||
|
public float CornerRadius { get; set; }
|
||||||
|
public Color TextColor { get; set; } = Color.White;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StyleSheet : TextDataResource
|
||||||
|
{
|
||||||
|
public StyleSheet(string path) : base(path)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public StyleSheet(Dictionary<string, Style> styles) : base(string.Empty)
|
||||||
|
{
|
||||||
|
_styles = styles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGet(string styleName, [NotNullWhen(true)] out Style? style)
|
||||||
|
{
|
||||||
|
return _styles.TryGetValue(styleName, out style);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StyleSheet Default => new(new Dictionary<string, Style>()
|
||||||
|
{
|
||||||
|
{"Label", new Style()
|
||||||
|
{
|
||||||
|
TextColor = Color.FromHexString("#161616"),
|
||||||
|
BackgroundColor = Color.DarkRed,
|
||||||
|
BorderSize = new Margin(2.0f),
|
||||||
|
BorderColor = Color.Red
|
||||||
|
}},
|
||||||
|
{ "Button", new Style()
|
||||||
|
{
|
||||||
|
Padding = new Margin(8.0f),
|
||||||
|
BackgroundColor = Color.FromHexString("#0f62fe"),
|
||||||
|
TextColor = Color.FromHexString("#ffffff"),
|
||||||
|
}},
|
||||||
|
{"Button.Normal", new Style()
|
||||||
|
{
|
||||||
|
Padding = new Margin(8.0f),
|
||||||
|
BackgroundColor = Color.FromHexString("#0f62fe"),
|
||||||
|
TextColor = Color.FromHexString("#ffffff"),
|
||||||
|
}},
|
||||||
|
{"Button.Hovered", new Style()
|
||||||
|
{
|
||||||
|
Padding = new Margin(8.0f),
|
||||||
|
BackgroundColor = Color.FromHexString("#0353e9"),
|
||||||
|
TextColor = Color.FromHexString("#ffffff"),
|
||||||
|
}},
|
||||||
|
{"Button.Pressed", new Style()
|
||||||
|
{
|
||||||
|
Padding = new Margin(8.0f),
|
||||||
|
BackgroundColor = Color.FromHexString("#002d9c"),
|
||||||
|
TextColor = Color.FromHexString("#ffffff"),
|
||||||
|
}},
|
||||||
|
{"Button.Danger", new Style()
|
||||||
|
{
|
||||||
|
Padding = new Margin(8.0f),
|
||||||
|
BackgroundColor = Color.FromHexString("#da1e28"),
|
||||||
|
TextColor = Color.FromHexString("#ffffff"),
|
||||||
|
}},
|
||||||
|
{"Button.Danger.Normal", new Style()
|
||||||
|
{
|
||||||
|
Padding = new Margin(8.0f),
|
||||||
|
BackgroundColor = Color.FromHexString("#da1e28"),
|
||||||
|
TextColor = Color.FromHexString("#ffffff"),
|
||||||
|
}},
|
||||||
|
{"Button.Danger.Hovered", new Style()
|
||||||
|
{
|
||||||
|
Padding = new Margin(8.0f),
|
||||||
|
BackgroundColor = Color.FromHexString("#ba1b23"),
|
||||||
|
TextColor = Color.FromHexString("#ffffff"),
|
||||||
|
}},
|
||||||
|
{"Button.Danger.Pressed", new Style()
|
||||||
|
{
|
||||||
|
Padding = new Margin(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 Dictionary<string, Style> _styles = new();
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
using Voile.Rendering;
|
using Voile.Rendering;
|
||||||
|
|
||||||
namespace Voile.UI;
|
namespace Voile.UI;
|
||||||
@@ -13,6 +15,23 @@ public abstract class UIElement : IElement, IRenderableElement, IResizeableEleme
|
|||||||
public Vector2 LocalPosition { get; set; } = Vector2.Zero;
|
public Vector2 LocalPosition { get; set; } = Vector2.Zero;
|
||||||
public Vector2 GlobalPosition => _parent?.GlobalPosition + LocalPosition ?? LocalPosition;
|
public Vector2 GlobalPosition => _parent?.GlobalPosition + LocalPosition ?? LocalPosition;
|
||||||
|
|
||||||
|
public string StyleName => $"{StyleElementName ?? "UIElement"}{GetStyleVariantString()}{ConstructStyleModifiers(StyleModifiers)}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An element name for style.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string? StyleElementName { get; }
|
||||||
|
|
||||||
|
public string StyleVariant { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of style modifiers for this <see cref="UIElement"/>.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string[]? StyleModifiers { get; }
|
||||||
|
|
||||||
|
public StyleSheet StyleSheet => Parent?.StyleSheet ?? StyleSheetOverride;
|
||||||
|
public StyleSheet StyleSheetOverride { get; set; } = new(string.Empty);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parent <see cref="UIElement"/> of this element.
|
/// Parent <see cref="UIElement"/> of this element.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -47,6 +66,11 @@ public abstract class UIElement : IElement, IRenderableElement, IResizeableEleme
|
|||||||
public abstract Rect MinimumSize { get; }
|
public abstract Rect MinimumSize { get; }
|
||||||
public bool Dirty => _dirty;
|
public bool Dirty => _dirty;
|
||||||
|
|
||||||
|
public bool TryGetStyle(StyleSheet styleSheet, [NotNullWhen(true)] out Style? style)
|
||||||
|
{
|
||||||
|
return styleSheet.TryGet(StyleName, out style);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void MarkDirty()
|
public virtual void MarkDirty()
|
||||||
{
|
{
|
||||||
if (Parent != null && !Parent.Dirty)
|
if (Parent != null && !Parent.Dirty)
|
||||||
@@ -86,6 +110,60 @@ public abstract class UIElement : IElement, IRenderableElement, IResizeableEleme
|
|||||||
public abstract void Render(RenderSystem renderer, Style style);
|
public abstract void Render(RenderSystem renderer, Style style);
|
||||||
protected abstract void OnUpdate();
|
protected abstract void OnUpdate();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Renders a stylebox from a given style.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderer"></param>
|
||||||
|
/// <param name="style"></param>
|
||||||
|
protected void RenderStyleBox(RenderSystem renderer, Style style)
|
||||||
|
{
|
||||||
|
var backgroundColor = style.BackgroundColor;
|
||||||
|
var borderColor = style.BorderColor;
|
||||||
|
var borderSize = style.BorderSize;
|
||||||
|
|
||||||
|
renderer.SetTransform(GlobalPosition, Vector2.Zero);
|
||||||
|
|
||||||
|
renderer.DrawRectangle(new Vector2(Size.Width, Size.Height), backgroundColor);
|
||||||
|
|
||||||
|
if (borderSize.Left > 0)
|
||||||
|
{
|
||||||
|
renderer.SetTransform(GlobalPosition, Vector2.Zero);
|
||||||
|
renderer.DrawRectangle(
|
||||||
|
new Vector2(borderSize.Left, Size.Height),
|
||||||
|
borderColor
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (borderSize.Top > 0)
|
||||||
|
{
|
||||||
|
renderer.SetTransform(GlobalPosition, Vector2.Zero);
|
||||||
|
renderer.DrawRectangle(
|
||||||
|
new Vector2(Size.Width, borderSize.Top),
|
||||||
|
borderColor
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (borderSize.Right > 0)
|
||||||
|
{
|
||||||
|
var rightX = GlobalPosition.X + Size.Width - borderSize.Right;
|
||||||
|
renderer.SetTransform(new Vector2(rightX, GlobalPosition.Y), Vector2.Zero);
|
||||||
|
renderer.DrawRectangle(
|
||||||
|
new Vector2(borderSize.Right, Size.Height),
|
||||||
|
borderColor
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (borderSize.Bottom > 0)
|
||||||
|
{
|
||||||
|
var bottomY = GlobalPosition.Y + Size.Height - borderSize.Bottom;
|
||||||
|
renderer.SetTransform(new Vector2(GlobalPosition.X, bottomY), Vector2.Zero);
|
||||||
|
renderer.DrawRectangle(
|
||||||
|
new Vector2(Size.Width, borderSize.Bottom),
|
||||||
|
borderColor
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void DrawSize(RenderSystem renderer)
|
public void DrawSize(RenderSystem renderer)
|
||||||
{
|
{
|
||||||
renderer.SetTransform(GlobalPosition, Vector2.Zero);
|
renderer.SetTransform(GlobalPosition, Vector2.Zero);
|
||||||
@@ -112,6 +190,30 @@ public abstract class UIElement : IElement, IRenderableElement, IResizeableEleme
|
|||||||
LocalPosition = Anchor.Calculate(parentPosition, parentRect, Size) + new Vector2(AnchorOffset.X, AnchorOffset.Y);
|
LocalPosition = Anchor.Calculate(parentPosition, parentRect, Size) + new Vector2(AnchorOffset.X, AnchorOffset.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string ConstructStyleModifiers(string[]? modifiers)
|
||||||
|
{
|
||||||
|
if (modifiers == null)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var modifier in modifiers)
|
||||||
|
{
|
||||||
|
sb.Append($".{modifier}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetStyleVariantString()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(StyleVariant))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
return $".{StyleVariant}";
|
||||||
|
}
|
||||||
|
|
||||||
private bool _dirty = true;
|
private bool _dirty = true;
|
||||||
private Rect _size = Rect.Zero;
|
private Rect _size = Rect.Zero;
|
||||||
|
|
||||||
|
|||||||
@@ -14,25 +14,26 @@ public class UISystem : IUpdatableSystem, IRenderableSystem
|
|||||||
|
|
||||||
public UISystem(InputSystem inputSystem)
|
public UISystem(InputSystem inputSystem)
|
||||||
{
|
{
|
||||||
_style = ResourceRef<Style>.Empty();
|
_styleSheet = StyleSheet.Default;
|
||||||
_input = inputSystem;
|
_input = inputSystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UISystem(InputSystem inputSystem, ResourceRef<Style> style)
|
public UISystem(InputSystem inputSystem, StyleSheet styleSheet)
|
||||||
{
|
{
|
||||||
_input = inputSystem;
|
_input = inputSystem;
|
||||||
_style = style;
|
_styleSheet = styleSheet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UISystem(InputSystem inputSystem, ResourceRef<Style> style, List<UIElement> elements)
|
public UISystem(InputSystem inputSystem, StyleSheet styleSheet, List<UIElement> elements)
|
||||||
{
|
{
|
||||||
_input = inputSystem;
|
_input = inputSystem;
|
||||||
_style = style;
|
_styleSheet = styleSheet;
|
||||||
_elements = elements;
|
_elements = elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddElement(UIElement element)
|
public void AddElement(UIElement element)
|
||||||
{
|
{
|
||||||
|
element.StyleSheetOverride = _styleSheet;
|
||||||
_elements.Add(element);
|
_elements.Add(element);
|
||||||
_inputElementIndices.Add(element.GlobalPosition, _elements.Count - 1);
|
_inputElementIndices.Add(element.GlobalPosition, _elements.Count - 1);
|
||||||
}
|
}
|
||||||
@@ -40,30 +41,33 @@ public class UISystem : IUpdatableSystem, IRenderableSystem
|
|||||||
|
|
||||||
public void Update(double deltaTime)
|
public void Update(double deltaTime)
|
||||||
{
|
{
|
||||||
HandleInput();
|
// HandleInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Render(RenderSystem renderer)
|
public void Render(RenderSystem renderer)
|
||||||
{
|
{
|
||||||
// Update elements each time UI system is rendered.
|
// Update elements each time UI system is rendered.
|
||||||
|
HandleInput();
|
||||||
|
|
||||||
foreach (var element in _elements)
|
foreach (var element in _elements)
|
||||||
{
|
{
|
||||||
if (element is not IUpdatableElement updatable) continue;
|
if (element is not IUpdatableElement updatable) continue;
|
||||||
updatable.Update();
|
updatable.Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach (var element in _elements)
|
foreach (var element in _elements)
|
||||||
{
|
{
|
||||||
if (element is IRenderableElement renderable)
|
if (element is IRenderableElement renderable)
|
||||||
{
|
{
|
||||||
// TODO: normally you'd load a default style if the one supplied is empty,
|
// TODO: normally you'd load a default style if the one supplied is empty,
|
||||||
// but for now this will do.
|
// but for now this will do.
|
||||||
if (!_style.TryGetValue(out var value))
|
if (!_styleSheet.TryGet(element.StyleName, out var style))
|
||||||
{
|
{
|
||||||
value = new Style(string.Empty);
|
style = new Style(string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderable.Render(renderer, value);
|
renderable.Render(renderer, style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +142,7 @@ public class UISystem : IUpdatableSystem, IRenderableSystem
|
|||||||
{
|
{
|
||||||
MouseDown = _input.IsMouseButtonDown(MouseButton.Left),
|
MouseDown = _input.IsMouseButtonDown(MouseButton.Left),
|
||||||
MouseReleased = _input.IsMouseButtonReleased(MouseButton.Left),
|
MouseReleased = _input.IsMouseButtonReleased(MouseButton.Left),
|
||||||
MousePressed = _input.IsMouseButtonReleased(MouseButton.Left),
|
MousePressed = _input.IsMouseButtonPressed(MouseButton.Left),
|
||||||
};
|
};
|
||||||
PropagateInput(_elements, context);
|
PropagateInput(_elements, context);
|
||||||
}
|
}
|
||||||
@@ -169,7 +173,7 @@ public class UISystem : IUpdatableSystem, IRenderableSystem
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceRef<Style> _style;
|
private StyleSheet _styleSheet;
|
||||||
private List<UIElement> _elements = new();
|
private List<UIElement> _elements = new();
|
||||||
private InputSystem _input;
|
private InputSystem _input;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Voile.Input;
|
|
||||||
using Voile.Rendering;
|
using Voile.Rendering;
|
||||||
using Voile.Resources;
|
using Voile.Resources;
|
||||||
using Voile.UI.Containers;
|
using Voile.UI.Containers;
|
||||||
@@ -27,13 +26,28 @@ public class Button : Widget
|
|||||||
MarkDirty();
|
MarkDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ButtonState CurrentState { get; private set; } = ButtonState.Normal;
|
||||||
|
|
||||||
public override Rect MinimumSize => Padding + _textSize;
|
public override Rect MinimumSize => Padding + _textSize;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="FontSet"/> to use with this button.
|
/// <see cref="FontSet"/> to use with this button.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public FontSet FontSet { get; set; } = new();
|
public FontSet FontSet { get; set; } = new();
|
||||||
public Margin Padding { get; set; } = Margin.Zero;
|
public Margin 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)
|
public Button(string text, ResourceRef<Font> fontOverride, Action pressedAction)
|
||||||
{
|
{
|
||||||
@@ -60,19 +74,60 @@ public class Button : Widget
|
|||||||
public override void Render(RenderSystem renderer, Style style)
|
public override void Render(RenderSystem renderer, Style style)
|
||||||
{
|
{
|
||||||
// TODO: use a button color from style.
|
// TODO: use a button color from style.
|
||||||
renderer.SetTransform(GlobalPosition, Vector2.Zero);
|
|
||||||
renderer.DrawRectangle(new Vector2(MinimumSize.Width, MinimumSize.Height), new Color(0.25f, 0.25f, 0.25f));
|
var backgroundColor = style.BackgroundColor;
|
||||||
|
|
||||||
|
if (_padding != style.Padding)
|
||||||
|
{
|
||||||
|
MarkDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
_padding = style.Padding;
|
||||||
|
var textColor = style.TextColor;
|
||||||
|
|
||||||
|
// 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, Color.White);
|
renderer.DrawText(_suitableFont, _text, textColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnInput(UIInputContext action)
|
protected override void OnInput(UIInputContext action)
|
||||||
{
|
{
|
||||||
if (action.MouseReleased && ContainsPoint(action.MousePosition))
|
bool isHovering = ContainsPoint(action.MousePosition);
|
||||||
|
|
||||||
|
if (action.MousePressed && isHovering)
|
||||||
{
|
{
|
||||||
_pressedAction?.Invoke();
|
_isHeldDown = true;
|
||||||
|
CurrentState = ButtonState.Pressed;
|
||||||
|
}
|
||||||
|
else if (action.MouseReleased)
|
||||||
|
{
|
||||||
|
if (_isHeldDown && isHovering)
|
||||||
|
{
|
||||||
|
_pressedAction?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
_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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +150,7 @@ public class Button : Widget
|
|||||||
var font = _suitableFont.Value;
|
var font = _suitableFont.Value;
|
||||||
_textSize = font.Measure(_text);
|
_textSize = font.Measure(_text);
|
||||||
|
|
||||||
Size = Padding + _textSize;
|
Size = _padding + _textSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Action _pressedAction;
|
private Action _pressedAction;
|
||||||
@@ -104,4 +159,8 @@ public class Button : Widget
|
|||||||
|
|
||||||
private string _text = "Hello, World!";
|
private string _text = "Hello, World!";
|
||||||
private Rect _textSize = Rect.Zero;
|
private Rect _textSize = Rect.Zero;
|
||||||
|
|
||||||
|
private Margin _padding;
|
||||||
|
|
||||||
|
private bool _isHeldDown;
|
||||||
}
|
}
|
||||||
@@ -18,6 +18,8 @@ public class Label : Widget
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string? StyleElementName => nameof(Label);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="FontSet"/> to use with this label.
|
/// <see cref="FontSet"/> to use with this label.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -50,10 +52,10 @@ public class Label : Widget
|
|||||||
|
|
||||||
public override void Render(RenderSystem renderer, Style style)
|
public override void Render(RenderSystem renderer, Style style)
|
||||||
{
|
{
|
||||||
// TODO: use style here.
|
RenderStyleBox(renderer, style);
|
||||||
|
|
||||||
renderer.SetTransform(GlobalPosition, Vector2.Zero);
|
renderer.SetTransform(GlobalPosition, Vector2.Zero);
|
||||||
renderer.DrawText(_suitableFont, _text, Color.White);
|
renderer.DrawText(_suitableFont, _text, style.TextColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnUpdate()
|
protected override void OnUpdate()
|
||||||
|
|||||||
@@ -29,10 +29,7 @@ public abstract class Widget : UIElement, IInputElement
|
|||||||
public void Input(UIInputContext context)
|
public void Input(UIInputContext context)
|
||||||
{
|
{
|
||||||
if (context.Handled || IgnoreInput) return;
|
if (context.Handled || IgnoreInput) return;
|
||||||
if (ContainsPoint(context.MousePosition))
|
OnInput(context);
|
||||||
{
|
|
||||||
OnInput(context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user