using Annulus;
using Azimuth;
using System;
namespace Glass.Testbed
{
///
/// One named UI experiment.
///
public abstract class TestCase
{
// Margin separates a thing from its neighbour; Gutter separates one band of the layout from the next.
public const int Margin = 8;
public const int Gutter = 12;
public string Name { get; }
public Panel Root { get; }
protected TestCase(string name)
{
Name = name;
// Invisible rather than null: a null material reaches NullRenderer, which BlacklightRenderer throws on.
Root = new Panel { Material = Material.Invisible, DebugName = name };
}
public Rect ClientRect => Rect.FromPositionAndSize(Vector.Zero, Root.ClientRect.Size);
protected RectAggregator ContentAggregator;
public Rect ContentBounds => ContentAggregator.Rect;
public void Add(Control control)
{
Root.ChildControls.Add(control);
}
public T NewChild(string debugName = null) where T : Control, new()
{
return Root.ChildControls.NewChild(debugName);
}
private void PlaceCaption(TextMaterial material, Rect row)
{
Panel caption = material.BuildControl(Constraints.Unbounded);
caption.Bounds = row;
Add(caption);
}
///
/// Adds a row to this case's content sized to the caption's own text, and puts the caption in it.
///
protected void AddCaption(StringView text)
{
TextMaterial material = Widgets.Caption(text);
PlaceCaption(material, ContentAggregator.NewRow(material, margin: 4));
}
///
/// Takes the row off instead, for a caption inside a rect the case has already
/// claimed rather than one at the end of its content.
///
protected void AddCaption(StringView text, ref Rect remaining)
{
TextMaterial material = Widgets.Caption(text);
PlaceCaption(material, remaining.NewRow(material, margin: 4));
}
///
/// Lays this case out within . Runs once.
///
///
/// Not the constructor, because the area isn't known until the tab strip has been built and measured,
/// and the tab strip is built from the cases.
///
public void Build(Rect area)
{
Root.Bounds = area;
// Seeded with the client width so a full-width row still spans the window, but with no height, so a case
// is free to grow past the bottom of it.
ContentAggregator = new RectAggregator(
Rect.FromPositionAndSize(Vector.Zero, new Vector(ClientRect.Width, 0)), new Vector(Gutter, Gutter));
Populate();
Root.Bounds = Rect.FromPositionAndSize(area.TopLeft, ContentBounds.Size);
}
///
/// Fills this case with whatever it is demonstrating.
///
protected abstract void Populate();
///
/// Runs each time this case is shown, so one a user can leave in some other state resets itself.
///
protected virtual void Setup()
{
}
///
/// Runs each tick this case is the shown one, for a case with something moving in it.
///
public virtual void Update(TimeSpan elapsed)
{
}
public void Show(ControlContainer host)
{
host.Add(Root);
Setup();
}
public void Hide(ControlContainer host)
{
host.Remove(Root);
}
}
}