using Annulus; using Azimuth; using System; using System.Globalization; namespace Glass.Testbed { /// /// NumberFields over a spread of grids, each stepped by its arrows or the wheel, or scrubbed by dragging its number /// sideways. A readout reports every OnValueChanged. /// public class NumberFieldTestCase : TestCase { private static readonly NumberFieldMaterial FieldMaterial = new NumberFieldMaterial { Background = UiPacksheetMaterials.TextField, Label = Widgets.FieldText("") with { VerticalAlignment = Alignment.Vertical.Center }, IncrementButton = UiPacksheetMaterials.ScrollBarUpArrow, DecrementButton = UiPacksheetMaterials.ScrollBarDownArrow, }; private static readonly Cursor ScrubCursor = new SpriteCursor(ResizeCursorMaterials.DiagonalNeSw, new Point(8, 8)); // One instance for every field but the French one, the way an app shares one across its whole UI. private readonly NumberFieldBehavior sharedBehavior = new NumberFieldBehavior(); private TextMaterial readout; public NumberFieldTestCase(string name) : base(name) { } private NumberField BuildField(string debugName, NumberField.Data data, NumberFieldBehavior behavior) { var field = new NumberField(behavior, data) { DebugName = debugName, NumberFieldMaterial = FieldMaterial, ScrubCursor = ScrubCursor, }; field.Bounds = Rect.FromPositionAndSize(Vector.Zero, field.PreferredBoundsSize); field.OnValueChanged += (numberField, valueBefore, valueNow) => readout.Text = $"OnValueChanged: {numberField.DebugName} went from {valueBefore} to {valueNow}"; return field; } /// /// The shape a game's widget factory takes: it supplies the shared behavior and the look, and the call site's /// data passes straight through. /// private NumberField BuildField(string debugName, NumberField.Data data) { return BuildField(debugName, data, sharedBehavior); } /// /// A row of with beside it. /// private void AddRow(NumberField field, string description) { TextMaterial caption = Widgets.SmallCaption(description); Vector captionSize = caption.PreferredSize(Constraints.Unbounded); Rect row = ContentAggregator.NewRow(Math.Max(field.Bounds.Height, captionSize.Y)); Rect fieldSlot = row.NewCol(field.Bounds.Width, margin: Gutter); field.Bounds = field.Bounds.WithPosition(fieldSlot.TopLeft); Add(field); Panel captionPanel = caption.BuildControl(Constraints.Unbounded); captionPanel.Bounds = captionPanel.Bounds.WithPosition( row.TopLeft + new Vector(0, (row.Height - captionSize.Y) / 2)); Add(captionPanel); } protected override void Populate() { AddCaption("Click an arrow, spin the wheel over a field, or drag its number to scrub it: right or up to"); AddCaption("increase, left or down to decrease."); AddCaption("An arrow greys out at its end of the range."); readout = Widgets.Caption("OnValueChanged: nothing yet"); Panel readoutPanel = readout.BuildControl(Constraints.Unbounded); readoutPanel.Bounds = ContentAggregator.NewRow(readoutPanel.Bounds.Height); Add(readoutPanel); AddRow(BuildField("whole numbers", new() { Grid = new NumberGrid { Max = 100 } }), "0 to 100 in ones"); AddRow(BuildField("per unit voltage", new() { Grid = new NumberGrid { Min = 0.9m, Max = 1.1m, Resolution = 0.001m, Step = 0.01m }, Value = 1, }), "0.9 to 1.1: a 0.001 grid, stepping by 0.01"); AddRow(BuildField("off the lattice", new() { Grid = new NumberGrid { Max = 1, Resolution = 0.05m, Step = 0.3m }, Value = 0.45m, }), "0 to 1 stepping by 0.3, starting between steps at 0.45; the top step clamps to 1"); AddRow(BuildField("megawatts", new() { Grid = new NumberGrid { Max = 500, Step = 10 }, Format = (value, culture) => value.ToString("N0", culture) + " MW", }), "A custom format with units, stepping by 10"); var frenchBehavior = new NumberFieldBehavior { Culture = CultureInfo.GetCultureInfo("fr-FR"), ScrubDistancePerStep = 16, }; AddRow(BuildField("french", new() { Grid = new NumberGrid { Max = 10, Resolution = 0.5m } }, frenchBehavior), "French culture, and twice the drag per step"); NumberField disabled = BuildField("disabled", new() { Grid = new NumberGrid { Max = 100 }, Value = 50 }); disabled.Enabled = false; AddRow(disabled, "Disabled"); } } }