147 lines
4.4 KiB
C#
147 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();
|
|
}
|
|
|
|
public void Render(RenderSystem renderer)
|
|
{
|
|
// Update elements each time UI system is rendered.
|
|
foreach (var element in _elements)
|
|
{
|
|
if (element is not IUpdatableElement updatable) continue;
|
|
updatable.Update();
|
|
}
|
|
|
|
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;
|
|
} |