using Annulus;
using Azimuth;
namespace Glass.Testbed
{
///
/// A ScrollingPanel: children laid out in a content region taller than the panel, with the panel showing a
/// scrolled-and-clipped window onto it. The buttons drive it through ScrollBy, and the mouse wheel through its
/// StepAmount.
///
public class ScrollingPanelTestCase : TestCase
{
private static readonly Material[] RowPalette =
{
UiPacksheetMaterials.RedFlatPanel,
UiPacksheetMaterials.YellowFlatPanel,
UiPacksheetMaterials.BlueFlatPanel,
};
public ScrollingPanelTestCase(string name) : base(name) { }
///
/// The height that fits a row label inside every palette material, so the rows stay uniform whichever
/// material each one wears.
///
private static Scalar RowHeightFor(Scalar width)
{
TextMaterial label = Widgets.ButtonLabel("Row 0");
Constraints offer = Constraints.TightWidth(width, Scalar.PositiveInfinity);
Vector returnMe = Vector.Zero;
foreach (Material rowMaterial in RowPalette)
{
returnMe = Vector.Max(returnMe, Material.SolveBoundsFor(rowMaterial, label, offer));
}
return returnMe.Y;
}
private static Button BuildScrollButton(
StringView caption, Vector labelSize, ScrollingPanel scroller, Scalar deltaY)
{
Button button = Widgets.ButtonLabel(caption)
.BuildControl(Constraints.Tight(labelSize))
.WrapIn(UiPacksheetMaterials.YellowButton);
button.OnClick += delegate (in MouseState _, MouseButtonFlags __)
{
scroller.ScrollBy(new Vector(0, deltaY));
};
return button;
}
// The row is consumed a column at a time, so it has to be the caller's rect rather than a copy of it.
private void AddToRow(ref Rect row, Button button)
{
Rect slot = row.NewCol(button.Bounds.Width, margin: Margin);
button.Bounds = button.Bounds.WithPosition(slot.TopLeft);
Add(button);
}
protected override void Populate()
{
var viewportSize = new Vector(240, 190);
const int rowCount = 16;
AddCaption("A list too tall for its panel — the panel clips and scrolls a window onto it");
AddCaption("Scroll up / down shift the content; rows past the edge are clipped, not laid out short");
AddCaption("The mouse wheel scrolls the panel too, a quarter of its height per notch");
Rect stage = ContentAggregator.NewRow(viewportSize.Y);
var scroller = NewChild("scroller");
scroller.Material = UiPacksheetMaterials.GreenFlatPanel;
scroller.Bounds = stage.NewCol(viewportSize.X);
Scalar rowHeight = RowHeightFor(scroller.ViewportRect.Width);
var content = new RectAggregator(
Rect.FromPositionAndSize(Vector.Zero, new Vector(scroller.ViewportRect.Width, 0)),
new Vector(0, Margin));
for (int index = 0; index < rowCount; ++index)
{
Rect rowSlot = content.NewRow(rowHeight);
var row = scroller.CanvasChildren.NewChild($"row {index}");
row.Material = RowPalette[index % RowPalette.Length];
row.Bounds = rowSlot;
Panel label = Widgets.ButtonLabel($"Row {index}").BuildControl(Constraints.Unbounded);
label.Bounds = Rect.FromPositionAndSize(
Control.CenteredIn(row.CanvasRect.Size, label.Bounds.Size), label.Bounds.Size);
row.CanvasChildren.Add(label);
}
scroller.ContentSize = content.Rect.Size;
// Both buttons share the wider label's size, so the pair reads as a set.
Vector labelSize = Vector.Max(
Widgets.ButtonLabel("Scroll up").PreferredSize(Constraints.Unbounded),
Widgets.ButtonLabel("Scroll down").PreferredSize(Constraints.Unbounded));
Scalar step = (rowHeight + Margin) * 3;
Button scrollUp = BuildScrollButton("Scroll up", labelSize, scroller, -step);
Button scrollDown = BuildScrollButton("Scroll down", labelSize, scroller, step);
Rect buttonRow = ContentAggregator.NewRow(scrollUp.Bounds.Height);
AddToRow(ref buttonRow, scrollUp);
AddToRow(ref buttonRow, scrollDown);
}
}
}