Files
Voile/Voile/Source/UI/UISystem.cs
2025-06-20 22:24:30 +02:00

146 lines
4.4 KiB
C#

using System.Numerics;
using Voile.Input;
using Voile.Rendering;
namespace Voile.UI;
public class UISystem : IUpdatableSystem, IRenderableSystem
{
public IReadOnlyList<IElement> Elements => _elements;
public bool RenderDebugRects { get; set; }
public UISystem(InputSystem inputSystem)
{
_style = ResourceRef<Style>.Empty();
_input = inputSystem;
}
public UISystem(InputSystem inputSystem, ResourceRef<Style> style)
{
_input = inputSystem;
_style = style;
}
public UISystem(InputSystem inputSystem, ResourceRef<Style> style, List<IElement> elements)
{
_input = inputSystem;
_style = style;
_elements = elements;
}
public void AddElement(IElement element) => _elements.Add(element);
public void RemoveElement(IElement element) => _elements.Remove(element);
public void Update(double deltaTime)
{
HandleInput();
foreach (var element in _elements)
{
if (element is not IUpdatableElement updatable) continue;
updatable.Update();
}
}
public void Render(RenderSystem renderer)
{
foreach (var element in _elements)
{
if (element is IRenderableElement renderable)
{
renderable.Render(renderer, _style.Value);
if (!RenderDebugRects) return;
renderable.DrawSize(renderer);
}
if (element is IParentableElement parentable)
{
foreach (var child in parentable.Children)
{
if (child is not IRenderableElement renderableChild) continue;
if (!RenderDebugRects) return;
renderableChild.DrawSize(renderer);
}
}
}
}
private void HandleInput()
{
int charPressed = _input.GetCharPressed();
Vector2 mousePos = _input.GetMousePosition();
Vector2 currentMousePosition = _input.GetMousePosition();
foreach (var (actionName, mappings) in InputSystem.InputMappings)
{
foreach (var action in mappings)
{
if (action.IsPressed(_input))
{
// TODO: specify which mouse button is used in the context.
var context = new UIInputContext(action, mousePos, actionName, charPressed)
{
MouseDown = _input.IsMouseButtonDown(MouseButton.Left),
MouseReleased = _input.IsMouseButtonReleased(MouseButton.Left),
MousePressed = _input.IsMouseButtonReleased(MouseButton.Left),
};
if (PropagateInput(_elements, context))
return;
}
}
}
if (charPressed != 0)
{
var context = new UIInputContext(new KeyInputAction(KeyboardKey.Null), mousePos, "", charPressed);
PropagateInput(_elements, context);
}
if (currentMousePosition != _lastMousePosition)
{
// TODO: specify which mouse button is used in the context.
var context = new UIInputContext(new MouseInputAction(MouseButton.Left), mousePos, "", charPressed)
{
MouseDown = _input.IsMouseButtonDown(MouseButton.Left),
MouseReleased = _input.IsMouseButtonReleased(MouseButton.Left),
MousePressed = _input.IsMouseButtonReleased(MouseButton.Left),
};
PropagateInput(_elements, context);
}
}
private bool PropagateInput(List<IElement> elements, UIInputContext context)
{
for (int i = elements.Count - 1; i >= 0; i--)
{
var element = elements[i];
if (element is IInputElement inputElement && !inputElement.IgnoreInput)
{
inputElement.Input(context);
_input.SetAsHandled();
// return true;
}
if (element is IParentableElement parent)
{
if (PropagateInput(parent.Children.ToList(), context))
return true;
}
}
return false;
}
private ResourceRef<Style> _style;
private List<IElement> _elements = new();
private InputSystem _input;
private Vector2 _lastMousePosition = Vector2.Zero;
}