using Annulus; using Azimuth; using Clave; using Glass.Editing; using System; namespace Glass.Testbed.TestCases.Text { /// /// TextBoxes over a spread of behaviors, typed into, selected with the mouse or keyboard, and scrolled. A readout /// reports every OnTextChanged and OnSubmit. /// public class TextBoxTestCase : TestCase { private const int BoxWidth = 260; // One instance for every box but the Readline one, the way an app shares one across its whole UI. private readonly TextBoxBehavior sharedBehavior = new TextBoxBehavior(); private Label readout; private TextBox BuildBox(string debugName, string text, TextBoxBehavior behavior, int maxLength = EditBuffer.NoLimit) { var box = new TextBox(behavior, maxLength) { DebugName = debugName, TextBoxMaterial = Widgets.TextBox }; box.TextCursor = CursorExtraMaterials.Text; box.Bounds = Rect.FromPositionAndSize(Vector.Zero, Widgets.TextBoxSizeFor(BoxWidth)); box.Text = text; box.Buffer.ClearHistory(); box.OnTextChanged += (changed, _) => readout.Text = $"OnTextChanged: {changed.DebugName} is \"{changed.Text}\""; box.OnSubmit += (TextBox submitted, in KeyboardSnapshot _, KeyboardManager __) => readout.Text = $"OnSubmit: {submitted.DebugName} had \"{submitted.Text}\""; return box; } /// /// A row of with beside it. /// private void AddRow(TextBox box, string description) { var caption = new Label(Widgets.SmallCaptionStyle, description, Constraints.Unbounded); Vector captionSize = caption.Bounds.Size; Rect row = ContentAggregator.NewRow(Math.Max(box.Bounds.Height, captionSize.Y)); Rect boxSlot = row.NewCol(box.Bounds.Width, margin: Gutter); box.Bounds = box.Bounds.WithPosition(boxSlot.TopLeft); Add(box); caption.Bounds = caption.Bounds.WithPosition(row.TopLeft + new Vector(0, (row.Height - captionSize.Y) / 2)); Add(caption); } protected override void Populate() { AddCaption("Click a box to type in it. Drag to select, double click for a word, triple click for all."); AddCaption("Arrows, Home, End and Ctrl+arrows move (Shift extends). Tab and Shift+Tab change box."); AddCaption("Ctrl+C, X and V, or Ctrl+Insert, Shift+Delete and Shift+Insert, copy, cut and paste."); AddCaption("Ctrl+Z undoes a word at a time, and Ctrl+Y or Ctrl+Shift+Z redoes."); AddCaption("A browser pastes through its own paste event, and may ask permission to copy."); readout = new Label(Widgets.CaptionStyle, "Nothing yet"); readout.Bounds = ContentAggregator.NewRow(readout.PreferredSize(Constraints.Unbounded).Y); Add(readout); AddRow(BuildBox("plain", "Hello, world", sharedBehavior), "Windows keys"); AddRow(BuildBox("long", "The quick brown fox jumps over the lazy dog, and then keeps running", sharedBehavior), "Text wider than the box scrolls to keep the caret in view"); AddRow(BuildBox("short", "12345", sharedBehavior, maxLength: 8), "At most eight chars"); var readline = new TextBoxBehavior { Bindings = EditBindings.Readline }; AddRow(BuildBox("readline", "Ctrl+A, E, B, F, K, U, W", readline), "Readline keys: Ctrl+A and Ctrl+E for line start and end, Ctrl+K and Ctrl+U to kill"); var steady = new TextBoxBehavior { BlinkInterval = Amphora.Duration.Zero }; AddRow(BuildBox("steady", "No blinking caret", steady), "A caret that never blinks"); TextBox disabled = BuildBox("disabled", "Can't be edited", sharedBehavior); disabled.Enabled = false; AddRow(disabled, "Disabled"); AddRow(BuildBox("empty", "", sharedBehavior), "Empty"); TextBox multiline = BuildBox("multiline", "Enter adds a line and Ctrl+Enter submits.\n\nLong lines wrap at the edge of the box, and the box " + "scrolls down by lines to keep the caret in view.\n\nPageUp and PageDown move a page. The wheel, " + "the bar and a drag past the top or bottom scroll without moving the caret.\n\nThe bar's room is " + "kept from the start, so the text never rewraps when the bar is needed.", new TextBoxBehavior { Multiline = true }); Scalar barWidth = Widgets.TextBox.ScrollBar.Value.PreferredThickness(Orientation.Vertical); Scalar fourLines = Widgets.FieldTextStyle.SingleLineHeight * 4; multiline.Bounds = Rect.FromPositionAndSize(Vector.Zero, Widgets.TextBox.Background.BoundsSizeFor(new Vector(BoxWidth + barWidth, fourLines))); AddRow(multiline, "Multiline, four lines tall, with a scroll bar"); TextBox noWrap = BuildBox("no wrap", "Lines end only where Enter ended them, and the box scrolls sideways instead.\n\nShift and the " + "wheel, the bottom bar and a drag past the left or right edge scroll without moving the caret.\n\n" + "Short.\n\nBoth bars keep their room from the start, so neither can make the other appear.", new TextBoxBehavior { Multiline = true, Wrap = false }); Scalar acrossWidth = Widgets.TextBox.HorizontalScrollBar.Value.PreferredThickness(Orientation.Horizontal); noWrap.Bounds = Rect.FromPositionAndSize(Vector.Zero, Widgets.TextBox.Background.BoundsSizeFor(new Vector(BoxWidth + barWidth, fourLines + acrossWidth))); AddRow(noWrap, "Multiline that doesn't wrap, with both scroll bars"); TextBox noWrapRight = BuildBox("no wrap, right aligned", "Right aligned text starts scrolled to its right end.\nA short line sits against the right edge.\n" + "Scroll left to see the starts of the longer lines of this text.", new TextBoxBehavior { Multiline = true, Wrap = false }); noWrapRight.TextBoxMaterial = Widgets.TextBox with { Text = Widgets.TextBox.Text with { HorizontalAlignment = Alignment.Horizontal.Right }, }; noWrapRight.Bounds = noWrap.Bounds; AddRow(noWrapRight, "The same, right aligned"); } } }