diff --git a/Voile/Source/UI/Containers/Container.cs b/Voile/Source/UI/Containers/Container.cs index 58ff889..1288d55 100644 --- a/Voile/Source/UI/Containers/Container.cs +++ b/Voile/Source/UI/Containers/Container.cs @@ -8,41 +8,65 @@ namespace Voile.UI.Containers; /// public abstract class Container : IElement, IParentableElement, IUpdatableElement, IResizeableElement, IRenderableElement { + /// public IReadOnlyList Children => _children; + /// public Vector2 Position { get; set; } + /// public Rect MinimumRect { get; set; } = Rect.Zero; + /// public Rect Size { get; set; } = Rect.Zero; + /// public bool Visible { get; set; } = true; + /// + public bool Dirty => _isDirty; public Container() { - + MarkDirty(); } public Container(Rect minimumSize) { MinimumRect = minimumSize; + + MarkDirty(); } public Container(Rect minimumSize, List children) { MinimumRect = minimumSize; _children = children; + + MarkDirty(); } public void Update() { - Arrange(); - CalculateMinimumSize(); + if (!_isDirty) return; + _isDirty = false; + foreach (var child in _children) { if (child is not IUpdatableElement updatable) continue; updatable.Update(); } + + Arrange(); + CalculateMinimumSize(); } + + public void MarkDirty() => _isDirty = true; + + /// + /// Called when this has to rearrange its children. + /// public abstract void Arrange(); + /// + /// Recalculates a minimum size for this . + /// public void CalculateMinimumSize() { if (Children.Count == 0) @@ -81,12 +105,16 @@ public abstract class Container : IElement, IParentableElement, IUpdatableElemen public void AddChild(IElement child) { _children.Add(child); + + MarkDirty(); Update(); } public void RemoveChild(IElement child) { _children.Remove(child); + + MarkDirty(); Update(); } @@ -106,4 +134,5 @@ public abstract class Container : IElement, IParentableElement, IUpdatableElemen } private List _children = new(); + private bool _isDirty; } \ No newline at end of file diff --git a/Voile/Source/UI/IElement.cs b/Voile/Source/UI/IElement.cs index 26af153..786ce90 100644 --- a/Voile/Source/UI/IElement.cs +++ b/Voile/Source/UI/IElement.cs @@ -6,14 +6,31 @@ namespace Voile.UI; public interface IElement { + /// + /// This element's position in pixels relative to the viewport top-left edge. + /// public Vector2 Position { get; set; } + /// + /// The size of this element. + /// public Rect Size { get; set; } } public interface IParentableElement { + /// + /// This parentable element's children. + /// public IReadOnlyList Children { get; } + /// + /// Add a child element to this element. + /// + /// Child . public void AddChild(IElement child); + /// + /// Remove a child element from this element. + /// + /// Child to remove. public void RemoveChild(IElement child); } @@ -27,18 +44,48 @@ public interface IResizeableElement public interface IUpdatableElement { + /// + /// Specifies if this element's properties have changed, making it necessary to update it. + /// + public bool Dirty { get; } + /// + /// Update this element. + /// void Update(); + /// + /// Marks this element as changed, requiring an update. + /// + void MarkDirty(); } public interface IRenderableElement { + /// + /// Specifies if this element should be drawn. + /// public bool Visible { get; set; } + /// + /// Render this element. + /// + /// Renderer to call draw operations on. + /// A style to use to draw this element. public void Render(RenderSystem renderer, Style style); + /// + /// Draws this element's size bounds. + /// + /// Renderer to use. public void DrawSize(RenderSystem renderer); } public interface IInputElement { + /// + /// Specifies if this element should ignore inputs. + /// public bool IgnoreInput { get; set; } + /// + /// Send an input action to this element. + /// + /// Input action to send. void Input(IInputAction action); } \ No newline at end of file diff --git a/Voile/Source/UI/Widgets/Widget.cs b/Voile/Source/UI/Widgets/Widget.cs index c7c235a..81bce9c 100644 --- a/Voile/Source/UI/Widgets/Widget.cs +++ b/Voile/Source/UI/Widgets/Widget.cs @@ -22,11 +22,14 @@ public abstract class Widget : IElement, IRenderableElement, IInputElement, IRes public Widget(Vector2 position) { Position = position; + Size = MinimumRect; } /// public abstract Rect MinimumRect { get; } + public bool Dirty => _isDirty; + /// /// Called when its time to draw this widget. /// @@ -41,15 +44,22 @@ public abstract class Widget : IElement, IRenderableElement, IInputElement, IRes public void Update() { + if (!_isDirty) return; + _isDirty = false; + if (Size == Rect.Zero) { Size = MinimumRect; } } + public void MarkDirty() => _isDirty = true; + public void DrawSize(RenderSystem renderer) { renderer.SetTransform(Position, Vector2.Zero); renderer.DrawRectangleOutline(new Vector2(Size.Width, Size.Height), Color.Red, 2.0f); } + + private bool _isDirty = true; } \ No newline at end of file