using Annulus; using Azimuth; using Glass.Blacklight; using System; using System.Globalization; namespace Glass.Testbed.TestCases.Controls { /// /// 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 { // 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 readonly NumberFieldBehavior typingBehavior = new NumberFieldBehavior { AllowsTyping = true }; private Label readout; private NumberField BuildField(string debugName, NumberField.Data data, NumberFieldBehavior behavior) { var field = new NumberField(behavior, data) { DebugName = debugName, NumberFieldMaterial = Widgets.NumberField, ScrubCursor = CursorExtraMaterials.Scrub, }; 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) { var caption = new Label(Widgets.SmallCaptionStyle, description, Constraints.Unbounded); Vector captionSize = caption.Bounds.Size; 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); caption.Bounds = caption.Bounds.WithPosition(row.TopLeft + new Vector(0, (row.Height - captionSize.Y) / 2)); Add(caption); } 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 = new Label(Widgets.CaptionStyle, "OnValueChanged: nothing yet"); readout.Bounds = ContentAggregator.NewRow(readout.PreferredSize(Constraints.Unbounded).Y); Add(readout); 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"); AddCaption("These fields can also be typed into: click the number without dragging, or Tab to one"); AddCaption("and press Enter or F2. Enter commits, Escape cancels, and clicking away commits."); AddCaption("Up and Down still step, Home and End move the caret, and Ctrl+Home and Ctrl+End"); AddCaption("jump the value to its ends."); AddRow(BuildField("typed whole numbers", new() { Grid = new NumberGrid { Max = 100 } }, typingBehavior), "0 to 100 in ones; text outside the range clamps"); AddRow(BuildField("typed per unit voltage", new() { Grid = new NumberGrid { Min = 0.9m, Max = 1.1m, Resolution = 0.001m, Step = 0.01m }, Value = 1, }, typingBehavior), "0.9 to 1.1: typed values snap to the 0.001 grid"); AddRow(BuildField("typed megawatts", new() { Grid = new NumberGrid { Max = 500, Step = 10 }, Format = (value, culture) => value.ToString("N0", culture) + " MW", }, typingBehavior), "A custom format: the units are in the label, and the typed text is plain digits"); var typedFrench = new NumberFieldBehavior { Culture = CultureInfo.GetCultureInfo("fr-FR"), AllowsTyping = true, }; AddRow(BuildField("typed french", new() { Grid = new NumberGrid { Max = 10, Resolution = 0.5m } }, typedFrench), "French culture: type 2,5 or 2.5"); } } }