Theater-Gui/src/Controls/Container.bf

147 lines
No EOL
3.2 KiB
Beef

namespace TheaterGui.Controls;
using System;
using System.Collections;
class Container : GuiObject
{
private List<GuiObject> _LayoutData = new .() ~ delete _;
public List<GuiObject> Children = new .() ~ DeleteContainerAndItems!(_); //Entries => LayoutData without nulls
public this(StringView pName, StringView pComponentName = "Container") : base(pName, pComponentName)
{
}
///Reorder all entries
/// @params w The Maximum width that the container should take
public virtual void Reorder(int32 w)
{
/*
List<Entries> {Entry, Entry, Entry, RB, Entry, Entry, RB, Entry, RB}
null is a rowbreak while non null isnt a rowbreak
Algorithm
if the current entry is a rowbreak, reset the cursor to x = 0, y = y + height
try to fit the current entry after the cursor
if it fits add it,
if it doesnt fit break
*/
int32 maxWidth = 0; //The highest width line
int32 rowHeight = 0; //How high the current row is
int32 x = 0;
int32 y = 0;
for(var e in _LayoutData)
{
if(e == null)
{ //Manual row break
x = 0;
y = y + rowHeight;
rowHeight = 0;
continue;
}
if(e is Container)
{
((Container)e).Reorder(w);
for(var i in ((Container)e).Children)
{
i.X += x + Padding + e.Padding;
i.Y += y + Padding + e.Padding;
}
}
if(x+e.Width+e.Padding > w-Padding) //Change both instances of padding to 2*Padding to ensure proper padding on the leftmost side of the screen
{ //Automatic row break
x = 0;
y = y + rowHeight;
rowHeight = 0;
}
e.X = x + e.Padding;
x = x + e.Width + 2*e.Padding;
e.Y = y + e.Padding;
if(x > maxWidth)
maxWidth = x;
if(rowHeight < e.Height+2*e.Padding)
rowHeight = e.Height+2*e.Padding;
}
Width = maxWidth + 2*Padding;
Height = y + rowHeight + 2*Padding;
}
///Add a new item to the list of items
public void AddChild(GuiObject pToAdd)
{
_LayoutData.Add(pToAdd);
Children.Add(pToAdd);
pToAdd.Parent = this;
}
public virtual void InsertBefore(GuiObject pToAdd, GuiObject Position, bool pReorder = true)
{
var idx = _LayoutData.IndexOf(Position);
if(idx < 0)
{
delete pToAdd; //Avoid memory leaks
return;
}
_LayoutData.Insert(idx, pToAdd);
Children.Add(pToAdd);
pToAdd.Parent = this;
if(pReorder)
App.ForceReorder();
}
public virtual void InsertAfter(GuiObject pToAdd, GuiObject Position, bool pReorder = true)
{
var idx = _LayoutData.IndexOf(Position);
idx++;
if(idx < 0)
{
delete pToAdd; //Avoid memory leaks
return;
}
_LayoutData.Insert(idx, pToAdd);
Children.Add(pToAdd);
pToAdd.Parent = this;
if(pReorder)
App.ForceReorder();
}
///Forcefully terminates the current row
public void EndRow() => _LayoutData.Add(null);
public override void Render()
{
for(var i in Children)
i.Render();
}
public override bool OnClick(int32 x, int32 y)
{
for(var e in Children)
{
if(RaylibBeef.Rectangle(e.X, e.Y, e.Width, e.Height).Overlaps(x, y))
return e.OnClick(x, y);
}
return false;
}
public override GuiObject OnHover(int32 x, int32 y)
{
for(var e in Children)
{
if(RaylibBeef.Rectangle(e.X, e.Y, e.Width, e.Height).Overlaps(x, y))
return e.OnHover(x, y);
}
return null;
}
}