Add debug rectangle size rendering, auto-resize containers to fit all children.
This commit is contained in:
@@ -187,6 +187,17 @@ namespace Voile.Rendering
|
||||
}, transformPivot, transformRotation, VoileColorToRaylibColor(color));
|
||||
}
|
||||
|
||||
public override void DrawRectangleOutline(Vector2 size, Color color, float outlineWidth = 1)
|
||||
{
|
||||
Raylib.DrawRectangleLinesEx(new Rectangle()
|
||||
{
|
||||
X = transformPosition.X,
|
||||
Y = transformPosition.Y,
|
||||
Width = size.X,
|
||||
Height = size.Y
|
||||
}, outlineWidth, VoileColorToRaylibColor(color));
|
||||
}
|
||||
|
||||
public override void DrawDebugText(string text, int fontSize, Color color)
|
||||
{
|
||||
Raylib.DrawText(text, (int)transformPosition.X, (int)transformPosition.Y, fontSize, VoileColorToRaylibColor(color));
|
||||
|
||||
@@ -180,6 +180,9 @@ namespace Voile.Rendering
|
||||
/// <param name="size">Rectangle size.</param>
|
||||
/// <param name="color">Fill color.</param>
|
||||
public abstract void DrawRectangle(Vector2 size, Color color);
|
||||
|
||||
public abstract void DrawRectangleOutline(Vector2 size, Color color, float outlineWidth = 1.0f);
|
||||
|
||||
/// <summary>
|
||||
/// Draws a debug text with a default font.
|
||||
/// </summary>
|
||||
|
||||
@@ -399,6 +399,11 @@ namespace Voile.Rendering
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void DrawRectangleOutline(Vector2 size, Color color, float outlineWidth = 1)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private Vector2 _windowSize = Vector2.Zero;
|
||||
private IWindow? _window;
|
||||
|
||||
|
||||
@@ -1,29 +1,40 @@
|
||||
using System.Numerics;
|
||||
using Voile.Rendering;
|
||||
|
||||
namespace Voile.UI.Containers;
|
||||
|
||||
/// <summary>
|
||||
/// A base class for all UI containers, used to position and rendering child <see cref="IElement">s.
|
||||
/// </summary>
|
||||
public abstract class Container : IElement, IParentableElement, IUpdatableElement
|
||||
public abstract class Container : IElement, IParentableElement, IUpdatableElement, IResizeableElement, IRenderableElement
|
||||
{
|
||||
public IReadOnlyList<IElement> 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 => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public Container()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Container(List<IElement> children)
|
||||
public Container(Rect minimumSize)
|
||||
{
|
||||
MinimumRect = minimumSize;
|
||||
}
|
||||
|
||||
public Container(Rect minimumSize, List<IElement> children)
|
||||
{
|
||||
MinimumRect = minimumSize;
|
||||
_children = children;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
Arrange();
|
||||
CalculateMinimumSize();
|
||||
|
||||
foreach (var child in _children)
|
||||
{
|
||||
if (child is not IUpdatableElement updatable) continue;
|
||||
@@ -32,11 +43,59 @@ public abstract class Container : IElement, IParentableElement, IUpdatableElemen
|
||||
}
|
||||
public abstract void Arrange();
|
||||
|
||||
public void CalculateMinimumSize()
|
||||
{
|
||||
if (Children.Count == 0)
|
||||
{
|
||||
Size = MinimumRect;
|
||||
return;
|
||||
}
|
||||
|
||||
float minX = float.MaxValue;
|
||||
float minY = float.MaxValue;
|
||||
float maxX = float.MinValue;
|
||||
float maxY = float.MinValue;
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
var pos = child.Position;
|
||||
var size = child.Size;
|
||||
|
||||
minX = MathF.Min(minX, pos.X);
|
||||
minY = MathF.Min(minY, pos.Y);
|
||||
maxX = MathF.Max(maxX, pos.X + size.Width);
|
||||
maxY = MathF.Max(maxY, pos.Y + size.Height);
|
||||
}
|
||||
|
||||
// Optionally apply padding
|
||||
float padding = 0f; // or make this configurable
|
||||
|
||||
Size = new Rect(
|
||||
maxX - minX + padding * 2,
|
||||
maxY - minY + padding * 2
|
||||
);
|
||||
}
|
||||
|
||||
public void AddChild(IElement child)
|
||||
{
|
||||
_children.Add(child);
|
||||
Update();
|
||||
}
|
||||
|
||||
public void Render(RenderSystem renderer, Style style)
|
||||
{
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (child is not IRenderableElement renderable) continue;
|
||||
renderable.Render(renderer, style);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawSize(RenderSystem renderer)
|
||||
{
|
||||
renderer.SetTransform(Position, Vector2.Zero);
|
||||
renderer.DrawRectangleOutline(new Vector2(Size.Width, Size.Height), Color.Red, 2.0f);
|
||||
}
|
||||
|
||||
private List<IElement> _children = new();
|
||||
}
|
||||
@@ -3,15 +3,14 @@ using Voile.Rendering;
|
||||
|
||||
namespace Voile.UI.Containers;
|
||||
|
||||
public class GridContainer : Container, IRenderableElement
|
||||
public class GridContainer : Container
|
||||
{
|
||||
public int Columns { get; set; } = 2;
|
||||
public float ColumnSpacing { get; set; } = 16.0f;
|
||||
public float RowSpacing { get; set; } = 16.0f;
|
||||
public bool Visible { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public GridContainer(List<IElement> children, int columns = 2, float colSpacing = 16.0f, float rowSpacing = 16.0f)
|
||||
: base(children)
|
||||
public GridContainer(Rect minimumSize, List<IElement> children, int columns = 2, float colSpacing = 16.0f, float rowSpacing = 16.0f)
|
||||
: base(minimumSize, children)
|
||||
{
|
||||
Columns = columns;
|
||||
ColumnSpacing = colSpacing;
|
||||
@@ -58,13 +57,4 @@ public class GridContainer : Container, IRenderableElement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Render(RenderSystem renderer, Style style)
|
||||
{
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (child is not IRenderableElement renderable) continue;
|
||||
renderable.Render(renderer, style);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,11 @@ using Voile.Rendering;
|
||||
|
||||
namespace Voile.UI.Containers;
|
||||
|
||||
public class HorizontalContainer : Container, IRenderableElement
|
||||
public class HorizontalContainer : Container
|
||||
{
|
||||
public float Spacing { get; set; } = 16.0f;
|
||||
public bool Visible { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public HorizontalContainer(List<IElement> children, float spacing = 16.0f) : base(children)
|
||||
public HorizontalContainer(Rect minimumSize, List<IElement> children, float spacing = 16.0f) : base(minimumSize, children)
|
||||
{
|
||||
Spacing = spacing;
|
||||
}
|
||||
@@ -36,13 +35,4 @@ public class HorizontalContainer : Container, IRenderableElement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Render(RenderSystem renderer, Style style)
|
||||
{
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (child is not IRenderableElement renderable) continue;
|
||||
renderable.Render(renderer, style);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,11 @@ using Voile.Rendering;
|
||||
|
||||
namespace Voile.UI.Containers;
|
||||
|
||||
public class VerticalContainer : Container, IRenderableElement
|
||||
public class VerticalContainer : Container
|
||||
{
|
||||
public float Spacing { get; set; } = 16.0f;
|
||||
public bool Visible { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public VerticalContainer(List<IElement> children, float spacing = 16.0f) : base(children)
|
||||
public VerticalContainer(Rect minimumSize, List<IElement> children, float spacing = 16.0f) : base(minimumSize, children)
|
||||
{
|
||||
Spacing = spacing;
|
||||
}
|
||||
@@ -36,13 +35,4 @@ public class VerticalContainer : Container, IRenderableElement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Render(RenderSystem renderer, Style style)
|
||||
{
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (child is not IRenderableElement renderable) continue;
|
||||
renderable.Render(renderer, style);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ public interface IRenderableElement
|
||||
{
|
||||
public bool Visible { get; set; }
|
||||
public void Render(RenderSystem renderer, Style style);
|
||||
public void DrawSize(RenderSystem renderer);
|
||||
}
|
||||
|
||||
public interface IInputElement
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Numerics;
|
||||
using Voile.Rendering;
|
||||
using Voile.UI.Containers;
|
||||
|
||||
@@ -7,6 +8,8 @@ public class UISystem : IUpdatableSystem, IRenderableSystem
|
||||
{
|
||||
public IReadOnlyList<IElement> Elements => _elements;
|
||||
|
||||
public bool RenderDebugRects { get; set; }
|
||||
|
||||
public UISystem(ResourceRef<Style> style)
|
||||
{
|
||||
_style = style;
|
||||
@@ -37,6 +40,20 @@ public class UISystem : IUpdatableSystem, IRenderableSystem
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ public abstract class Widget : IElement, IRenderableElement, IInputElement, IRes
|
||||
/// </summary>
|
||||
/// <param name="renderer"></param>
|
||||
public abstract void Render(RenderSystem renderer, Style style);
|
||||
|
||||
/// <summary>
|
||||
/// Called when this widget receives input.
|
||||
/// </summary>
|
||||
@@ -45,4 +46,10 @@ public abstract class Widget : IElement, IRenderableElement, IInputElement, IRes
|
||||
Size = MinimumRect;
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawSize(RenderSystem renderer)
|
||||
{
|
||||
renderer.SetTransform(Position, Vector2.Zero);
|
||||
renderer.DrawRectangleOutline(new Vector2(Size.Width, Size.Height), Color.Red, 2.0f);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user