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");
}
}
}