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