From e02df8c0437265c509fd8cf59f3434a91de768be Mon Sep 17 00:00:00 2001 From: BDisp Date: Sat, 2 Jul 2022 00:44:39 +0100 Subject: [PATCH] Added some more features and bug fixes. --- Terminal.Gui/Core/Border.cs | 1 + Terminal.Gui/Core/TextFormatter.cs | 52 +- Terminal.Gui/Core/View.cs | 416 ++++++---- Terminal.Gui/Views/Button.cs | 79 +- Terminal.Gui/Views/Checkbox.cs | 87 +- Terminal.Gui/Views/ComboBox.cs | 2 +- Terminal.Gui/Views/Label.cs | 26 +- Terminal.Gui/Views/PanelView.cs | 8 +- Terminal.Gui/Views/RadioGroup.cs | 34 +- Terminal.Gui/Views/TextField.cs | 3 + .../Scenarios/AutoSizeAndDirectionText.cs | 14 + UICatalog/Scenarios/Dialogs.cs | 4 +- UICatalog/Scenarios/Editor.cs | 45 +- UICatalog/Scenarios/LabelsAsButtons.cs | 4 + UICatalog/Scenarios/Scrolling.cs | 6 +- UICatalog/Scenarios/TextAlignments.cs | 4 +- .../Scenarios/TextAlignmentsAndDirection.cs | 2 +- UICatalog/Scenarios/TextFormatterDemo.cs | 6 +- UICatalog/Scenarios/Wizards.cs | 20 +- UnitTests/ButtonTests.cs | 222 ++++- UnitTests/CheckboxTests.cs | 44 +- UnitTests/ComboBoxTests.cs | 52 +- UnitTests/DimTests.cs | 171 ++-- UnitTests/PanelViewTests.cs | 7 +- UnitTests/PosTests.cs | 192 ++++- UnitTests/RadioGroupTests.cs | 104 ++- UnitTests/ScrollViewTests.cs | 18 +- UnitTests/StatusBarTests.cs | 2 +- UnitTests/TextFieldTests.cs | 38 +- UnitTests/TextFormatterTests.cs | 592 +++++++++++--- UnitTests/ToplevelTests.cs | 1 + UnitTests/ViewTests.cs | 758 ++++++++++++++---- UnitTests/WindowTests.cs | 25 +- 33 files changed, 2265 insertions(+), 774 deletions(-) diff --git a/Terminal.Gui/Core/Border.cs b/Terminal.Gui/Core/Border.cs index 91979f994..a479d934f 100644 --- a/Terminal.Gui/Core/Border.cs +++ b/Terminal.Gui/Core/Border.cs @@ -165,6 +165,7 @@ namespace Terminal.Gui { { ColorScheme = Colors.TopLevel; Text = title ?? ""; + Frame = frame; if (border == null) { Border = new Border () { BorderStyle = BorderStyle.Single, diff --git a/Terminal.Gui/Core/TextFormatter.cs b/Terminal.Gui/Core/TextFormatter.cs index 4e7be576b..a417febb9 100644 --- a/Terminal.Gui/Core/TextFormatter.cs +++ b/Terminal.Gui/Core/TextFormatter.cs @@ -136,7 +136,7 @@ namespace Terminal.Gui { set { text = value; - if (text.RuneCount > 0 && (Size.Width == 0 || Size.Height == 0 || Size.Width != text.ConsoleWidth)) { + if (text != null && text.RuneCount > 0 && (Size.Width == 0 || Size.Height == 0 || Size.Width != text.ConsoleWidth)) { // Provide a default size (width = length of longest line, height = 1) // TODO: It might makes more sense for the default to be width = length of first line? Size = new Size (TextFormatter.MaxWidth (Text, int.MaxValue), 1); @@ -154,9 +154,15 @@ namespace Terminal.Gui { /// public bool AutoSize { get; set; } + /// + /// Get or sets a flag if the wrapped text will keep the trailing spaces or + /// the trailing spaces will be trimmed (default). + /// + public bool PreserveTrailingSpaces { get; set; } + // TODO: Add Vertical Text Alignment /// - /// Controls the horizontal text-alignment property. + /// Controls the horizontal text-alignment property. /// /// The text alignment. public TextAlignment Alignment { @@ -327,18 +333,16 @@ namespace Terminal.Gui { if (IsVerticalDirection (textDirection)) { var colsWidth = GetSumMaxCharWidth (shown_text, 0, 1); lines = Format (shown_text, Size.Height, textVerticalAlignment == VerticalTextAlignment.Justified, Size.Width > colsWidth, - false, 0, textDirection); + PreserveTrailingSpaces, 0, textDirection); if (!AutoSize) { colsWidth = GetMaxColsForWidth (lines, Size.Width); if (lines.Count > colsWidth) { - for (int i = colsWidth; i < lines.Count; i++) { - lines.Remove (lines [i]); - } + lines.RemoveRange (colsWidth, lines.Count - colsWidth); } } } else { lines = Format (shown_text, Size.Width, textAlignment == TextAlignment.Justified, Size.Height > 1, - false, 0, textDirection); + PreserveTrailingSpaces, 0, textDirection); if (!AutoSize && lines.Count > Size.Height) { lines.RemoveRange (Size.Height, lines.Count - Size.Height); } @@ -468,7 +472,7 @@ namespace Terminal.Gui { var runes = StripCRLF (text).ToRuneList (); if (!preserveTrailingSpaces) { if (IsHorizontalDirection (textDirection)) { - while ((end = start + GetMaxLengthForWidth (runes.GetRange (start, runes.Count - start), width)) < runes.Count) { + while ((end = start + Math.Max (GetMaxLengthForWidth (runes.GetRange (start, runes.Count - start), width), 1)) < runes.Count) { while (runes [end] != ' ' && end > start) end--; if (end == start) @@ -494,16 +498,25 @@ namespace Terminal.Gui { } } else { while ((end = start) < runes.Count) { - end = GetNextWhiteSpace (start, width); + end = GetNextWhiteSpace (start, width, out bool incomplete); + if (end == 0 && incomplete) { + start = text.RuneCount; + break; + } lines.Add (ustring.Make (runes.GetRange (start, end - start))); start = end; + if (incomplete) { + start = text.RuneCount; + break; + } } } - int GetNextWhiteSpace (int from, int cWidth, int cLength = 0) + int GetNextWhiteSpace (int from, int cWidth, out bool incomplete, int cLength = 0) { var to = from; var length = cLength; + incomplete = false; while (length < cWidth && to < runes.Count) { var rune = runes [to]; @@ -512,13 +525,19 @@ namespace Terminal.Gui { } else { length++; } + if (length > cWidth) { + if (to >= runes.Count || (length > 1 && cWidth <= 1)) { + incomplete = true; + } + return to; + } if (rune == ' ') { if (length == cWidth) { return to + 1; } else if (length > cWidth) { return to; } else { - return GetNextWhiteSpace (to + 1, cWidth, length); + return GetNextWhiteSpace (to + 1, cWidth, out incomplete, length); } } else if (rune == '\t') { length += tabWidth + 1; @@ -527,7 +546,7 @@ namespace Terminal.Gui { } else if (length > cWidth && tabWidth > cWidth) { return to; } else { - return GetNextWhiteSpace (to + 1, cWidth, length); + return GetNextWhiteSpace (to + 1, cWidth, out incomplete, length); } } to++; @@ -694,9 +713,6 @@ namespace Terminal.Gui { if (width < 0) { throw new ArgumentOutOfRangeException ("width cannot be negative"); } - if (preserveTrailingSpaces && !wordWrap) { - throw new ArgumentException ("if 'preserveTrailingSpaces' is true, then 'wordWrap' must be true either."); - } List lineResult = new List (); if (ustring.IsNullOrEmpty (text) || width == 0) { @@ -1093,10 +1109,10 @@ namespace Terminal.Gui { break; } - for (int line = 0; line < linesFormated.Count; line++) { - var isVertical = IsVerticalDirection (textDirection); + var isVertical = IsVerticalDirection (textDirection); - if ((isVertical && (line > bounds.Width)) || (!isVertical && (line > bounds.Height))) + for (int line = 0; line < linesFormated.Count; line++) { + if ((isVertical && line > bounds.Width) || (!isVertical && line > bounds.Height)) continue; var runes = lines [line].ToRunes (); diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index 1dfa23a06..3b4d87f93 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -181,15 +181,28 @@ namespace Terminal.Gui { /// public event Action HotKeyChanged; + Key hotKey = Key.Null; + /// /// Gets or sets the HotKey defined for this view. A user pressing HotKey on the keyboard while this view has focus will cause the Clicked event to fire. /// - public virtual Key HotKey { get => TextFormatter.HotKey; set => TextFormatter.HotKey = value; } + public virtual Key HotKey { + get => hotKey; + set { + hotKey = TextFormatter.HotKey = value; + } + } /// /// Gets or sets the specifier character for the hotkey (e.g. '_'). Set to '\xffff' to disable hotkey support for this View instance. The default is '\xffff'. /// - public virtual Rune HotKeySpecifier { get => TextFormatter.HotKeySpecifier; set => TextFormatter.HotKeySpecifier = value; } + public virtual Rune HotKeySpecifier { + get => TextFormatter.HotKeySpecifier; + set { + TextFormatter.HotKeySpecifier = value; + SetHotKey (); + } + } /// /// This is the global setting that can be used as a global shortcut to invoke an action if provided. @@ -445,8 +458,8 @@ namespace Terminal.Gui { SuperView.SetNeedsDisplay (frame); SuperView.SetNeedsDisplay (value); } - frame = value; - + frame = new Rect (value.X, value.Y, Math.Max (value.Width, 0), Math.Max (value.Height, 0)); + TextFormatter.Size = GetBoundsTextFormatterSize (); SetNeedsLayout (); SetNeedsDisplay (frame); } @@ -513,17 +526,13 @@ namespace Terminal.Gui { public Pos X { get => x; set { - if (!ValidatePosDim (x, value)) { + if (ForceValidatePosDim && !ValidatePosDim (x, value)) { throw new ArgumentException (); } x = value; - SetNeedsLayout (); - if (x is Pos.PosAbsolute) { - frame = new Rect (x.Anchor (0), frame.Y, frame.Width, frame.Height); - } - TextFormatter.Size = GetBoundsTextFormatterSize (); - SetNeedsDisplay (frame); + + ProcessResizeView (); } } @@ -537,20 +546,15 @@ namespace Terminal.Gui { public Pos Y { get => y; set { - if (!ValidatePosDim (y, value)) { + if (ForceValidatePosDim && !ValidatePosDim (y, value)) { throw new ArgumentException (); } y = value; - SetNeedsLayout (); - if (y is Pos.PosAbsolute) { - frame = new Rect (frame.X, y.Anchor (0), frame.Width, frame.Height); - } - TextFormatter.Size = GetBoundsTextFormatterSize (); - SetNeedsDisplay (frame); + + ProcessResizeView (); } } - Dim width, height; /// @@ -563,24 +567,20 @@ namespace Terminal.Gui { public Dim Width { get => width; set { - if (!ValidatePosDim (width, value)) { - throw new ArgumentException (); + if (ForceValidatePosDim && !ValidatePosDim (width, value)) { + throw new ArgumentException ("ForceValidatePosDim is enabled", nameof (Width)); } width = value; - var isValidNewAutSize = autoSize ? IsValidAutoSizeWidth (width) : false; + if (ForceValidatePosDim) { + var isValidNewAutSize = autoSize && IsValidAutoSizeWidth (width); - if (IsInitialized && autoSize && !isValidNewAutSize) { - throw new InvalidOperationException ("Must set AutoSize to false before set the Width."); + if (IsAdded && autoSize && !isValidNewAutSize) { + throw new InvalidOperationException ("Must set AutoSize to false before set the Width."); + } } - SetMinWidthHeight (); - SetNeedsLayout (); - if (width is Dim.DimAbsolute) { - frame = new Rect (frame.X, frame.Y, width.Anchor (0), frame.Height); - } - TextFormatter.Size = GetBoundsTextFormatterSize (); - SetNeedsDisplay (frame); + ProcessResizeView (); } } @@ -592,27 +592,29 @@ namespace Terminal.Gui { public Dim Height { get => height; set { - if (!ValidatePosDim (height, value)) { - throw new ArgumentException (); + if (ForceValidatePosDim && !ValidatePosDim (height, value)) { + throw new ArgumentException ("ForceValidatePosDim is enabled", nameof (Height)); } height = value; - var isValidNewAutSize = autoSize ? IsValidAutoSizeHeight (height) : false; + if (ForceValidatePosDim) { + var isValidNewAutSize = autoSize && IsValidAutoSizeHeight (height); - if (IsInitialized && autoSize && !isValidNewAutSize) { - throw new InvalidOperationException ("Must set AutoSize to false before set the Height."); + if (IsAdded && autoSize && !isValidNewAutSize) { + throw new InvalidOperationException ("Must set AutoSize to false before set the Height."); + } } - SetMinWidthHeight (); - SetNeedsLayout (); - if (height is Dim.DimAbsolute) { - frame = new Rect (frame.X, frame.Y, frame.Width, height.Anchor (0)); - } - TextFormatter.Size = GetBoundsTextFormatterSize (); - SetNeedsDisplay (frame); + ProcessResizeView (); } } + /// + /// Forces validation with layout + /// to avoid breaking the and settings. + /// + public bool ForceValidatePosDim { get; set; } + bool ValidatePosDim (object oldvalue, object newValue) { if (!IsInitialized || layoutStyle == LayoutStyle.Absolute || oldvalue == null || oldvalue.GetType () == newValue.GetType () || this is Toplevel) { @@ -626,27 +628,48 @@ namespace Terminal.Gui { return false; } - void SetMinWidthHeight () + /// + /// Verifies if the minimum width or height can be sets in the view. + /// + /// The size. + /// if the size can be set, otherwise. + public bool GetMinWidthHeight (out Size size) { + size = Size.Empty; + if (!AutoSize && !ustring.IsNullOrEmpty (TextFormatter.Text)) { switch (TextFormatter.IsVerticalDirection (TextDirection)) { case true: var colWidth = TextFormatter.GetSumMaxCharWidth (new List { TextFormatter.Text }, 0, 1); - if (Width == null || (Width is Dim.DimAbsolute && Width.Anchor (0) < colWidth)) { - width = colWidth; - Bounds = new Rect (Bounds.X, Bounds.Y, colWidth, Bounds.Height); - TextFormatter.Size = GetBoundsTextFormatterSize (); + if (frame.Width < colWidth && (Width == null || (Bounds.Width >= 0 && Width is Dim.DimAbsolute + && Width.Anchor (0) >= 0 && Width.Anchor (0) < colWidth))) { + size = new Size (colWidth, Bounds.Height); + return true; } break; default: - if (Height == null || (Height is Dim.DimAbsolute && Height.Anchor (0) == 0)) { - height = 1; - Bounds = new Rect (Bounds.X, Bounds.Y, Bounds.Width, 1); - TextFormatter.Size = GetBoundsTextFormatterSize (); + if (frame.Height < 1 && (Height == null || (Height is Dim.DimAbsolute && Height.Anchor (0) == 0))) { + size = new Size (Bounds.Width, 1); + return true; } break; } } + return false; + } + + /// + /// Sets the minimum width or height if the view can be resized. + /// + /// if the size can be set, otherwise. + public bool SetMinWidthHeight () + { + if (GetMinWidthHeight (out Size size)) { + Bounds = new Rect (Bounds.Location, size); + TextFormatter.Size = GetBoundsTextFormatterSize (); + return true; + } + return false; } /// @@ -755,7 +778,7 @@ namespace Terminal.Gui { } void Initialize (ustring text, Rect rect, LayoutStyle layoutStyle = LayoutStyle.Computed, - TextDirection direction = TextDirection.LeftRight_TopBottom, Border border = null) + TextDirection direction = TextDirection.LeftRight_TopBottom, Border border = null) { TextFormatter = new TextFormatter (); TextFormatter.HotKeyChanged += TextFormatter_HotKeyChanged; @@ -776,14 +799,45 @@ namespace Terminal.Gui { } else { r = rect; } - x = Pos.At (r.X); - y = Pos.At (r.Y); - Width = r.Width; - Height = r.Height; - Frame = r; Text = text; + UpdateTextFormatterText (); + ProcessResizeView (); + } + + /// + /// Can be overridden if the has + /// different format than the default. + /// + protected virtual void UpdateTextFormatterText () + { + TextFormatter.Text = text; + } + + /// + /// Can be overridden if the view resize behavior is + /// different than the default. + /// + protected virtual void ProcessResizeView () + { + var _x = x is Pos.PosAbsolute ? x.Anchor (0) : frame.X; + var _y = y is Pos.PosAbsolute ? y.Anchor (0) : frame.Y; + + if (AutoSize) { + var s = CalculateAutoSize (); + var w = width is Dim.DimAbsolute && width.Anchor (0) > s.Width ? width.Anchor (0) : s.Width; + var h = height is Dim.DimAbsolute && height.Anchor (0) > s.Height ? height.Anchor (0) : s.Height; + frame = new Rect (new Point (_x, _y), new Size (w, h)); + } else { + var w = width is Dim.DimAbsolute ? width.Anchor (0) : frame.Width; + var h = height is Dim.DimAbsolute ? height.Anchor (0) : frame.Height; + frame = new Rect (new Point (_x, _y), new Size (w, h)); + SetMinWidthHeight (); + } + TextFormatter.Size = GetBoundsTextFormatterSize (); + SetNeedsLayout (); + SetNeedsDisplay (); } private void TextFormatter_HotKeyChanged (Key obj) @@ -1310,6 +1364,12 @@ namespace Terminal.Gui { /// The subview being added. public virtual void OnAdded (View view) { + view.IsAdded = true; + view.x = view.x ?? view.frame.X; + view.y = view.y ?? view.frame.Y; + view.width = view.width ?? view.frame.Width; + view.height = view.height ?? view.frame.Height; + view.Added?.Invoke (this); } @@ -1319,6 +1379,7 @@ namespace Terminal.Gui { /// The subview being removed. public virtual void OnRemoved (View view) { + view.IsAdded = false; view.Removed?.Invoke (this); } @@ -1460,8 +1521,8 @@ namespace Terminal.Gui { containerBounds.Width = Math.Min (containerBounds.Width, Driver.Clip.Width); containerBounds.Height = Math.Min (containerBounds.Height, Driver.Clip.Height); TextFormatter?.Draw (ViewToScreen (Bounds), HasFocus ? ColorScheme.Focus : GetNormalColor (), - HasFocus ? ColorScheme.HotFocus : Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled, - containerBounds); + HasFocus ? ColorScheme.HotFocus : Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled, + containerBounds); } // Invoke DrawContentEvent @@ -2052,47 +2113,64 @@ namespace Terminal.Gui { internal void SetRelativeLayout (Rect hostFrame) { int w, h, _x, _y; + var s = Size.Empty; + + if (AutoSize) { + s = CalculateAutoSize (); + } if (x is Pos.PosCenter) { - if (width == null) - w = hostFrame.Width; - else + if (width == null) { + w = AutoSize ? s.Width : hostFrame.Width; + } else { w = width.Anchor (hostFrame.Width); + w = AutoSize && s.Width > w ? s.Width : w; + } _x = x.Anchor (hostFrame.Width - w); } else { if (x == null) _x = 0; else _x = x.Anchor (hostFrame.Width); - if (width == null) - w = hostFrame.Width; - else if (width is Dim.DimFactor && !((Dim.DimFactor)width).IsFromRemaining ()) + if (width == null) { + w = AutoSize ? s.Width : hostFrame.Width; + } else if (width is Dim.DimFactor && !((Dim.DimFactor)width).IsFromRemaining ()) { w = width.Anchor (hostFrame.Width); - else + w = AutoSize && s.Width > w ? s.Width : w; + } else { w = Math.Max (width.Anchor (hostFrame.Width - _x), 0); + w = AutoSize && s.Width > w ? s.Width : w; + } } if (y is Pos.PosCenter) { - if (height == null) - h = hostFrame.Height; - else + if (height == null) { + h = AutoSize ? s.Height : hostFrame.Height; + } else { h = height.Anchor (hostFrame.Height); + h = AutoSize && s.Height > h ? s.Height : h; + } _y = y.Anchor (hostFrame.Height - h); } else { if (y == null) _y = 0; else _y = y.Anchor (hostFrame.Height); - if (height == null) - h = hostFrame.Height; - else if (height is Dim.DimFactor && !((Dim.DimFactor)height).IsFromRemaining ()) + if (height == null) { + h = AutoSize ? s.Height : hostFrame.Height; + } else if (height is Dim.DimFactor && !((Dim.DimFactor)height).IsFromRemaining ()) { h = height.Anchor (hostFrame.Height); - else + h = AutoSize && s.Height > h ? s.Height : h; + } else { h = Math.Max (height.Anchor (hostFrame.Height - _y), 0); + h = AutoSize && s.Height > h ? s.Height : h; + } } var r = new Rect (_x, _y, w, h); if (Frame != r) { Frame = new Rect (_x, _y, w, h); + if (!SetMinWidthHeight ()) + TextFormatter.Size = GetBoundsTextFormatterSize (); } } @@ -2281,7 +2359,7 @@ namespace Terminal.Gui { } if (SuperView != null && SuperView == Application.Top && LayoutNeeded - && ordered.Count == 0 && LayoutStyle == LayoutStyle.Computed) { + && ordered.Count == 0 && LayoutStyle == LayoutStyle.Computed) { SetRelativeLayout (SuperView.Frame); } @@ -2290,6 +2368,8 @@ namespace Terminal.Gui { OnLayoutComplete (new LayoutEventArgs () { OldBounds = oldBounds }); } + ustring text; + /// /// The text displayed by the . /// @@ -2309,29 +2389,20 @@ namespace Terminal.Gui { /// /// public virtual ustring Text { - get => TextFormatter.Text; + get => text; set { - TextFormatter.Text = value; - var prevSize = frame.Size; - var canResize = ResizeView (autoSize); - var txtFmtSize = GetTextFormatterBoundsSize (); - if (canResize && txtFmtSize != Bounds.Size) { - Bounds = new Rect (new Point (Bounds.X, Bounds.Y), txtFmtSize); - } else if (!canResize && txtFmtSize != Bounds.Size) { - TextFormatter.Size = GetBoundsTextFormatterSize (); - } - SetMinWidthHeight (); - SetNeedsLayout (); - SetNeedsDisplay (new Rect (new Point (0, 0), - new Size (Math.Max (frame.Width, prevSize.Width), Math.Max (frame.Height, prevSize.Height)))); + text = value; + SetHotKey (); + UpdateTextFormatterText (); + ProcessResizeView (); } } /// /// Used by to resize the view's with the . /// Setting to true only work if the and are null or - /// values and doesn't work with layout, - /// to avoid breaking the and settings. + /// values and doesn't work with layout + /// and to avoid breaking the and settings. /// public virtual bool AutoSize { get => autoSize; @@ -2341,8 +2412,22 @@ namespace Terminal.Gui { if (autoSize != v) { autoSize = v; TextFormatter.NeedsFormat = true; - SetNeedsLayout (); - SetNeedsDisplay (); + UpdateTextFormatterText (); + ProcessResizeView (); + } + } + } + + /// + /// Get or sets a flag if the wrapped text will keep the trailing spaces or + /// the trailing spaces will be trimmed (default). + /// + public virtual bool PreserveTrailingSpaces { + get => TextFormatter.PreserveTrailingSpaces; + set { + if (TextFormatter.PreserveTrailingSpaces != value) { + TextFormatter.PreserveTrailingSpaces = value; + TextFormatter.NeedsFormat = true; } } } @@ -2355,7 +2440,8 @@ namespace Terminal.Gui { get => TextFormatter.Alignment; set { TextFormatter.Alignment = value; - SetNeedsDisplay (); + UpdateTextFormatterText (); + ProcessResizeView (); } } @@ -2379,42 +2465,38 @@ namespace Terminal.Gui { get => TextFormatter.Direction; set { if (TextFormatter.Direction != value) { - var isValidOldAutSize = autoSize ? IsValidAutoSize (out Size autSize) : false; + var isValidOldAutSize = autoSize && IsValidAutoSize (out Size autSize); var directionChanged = TextFormatter.IsHorizontalDirection (TextFormatter.Direction) - != TextFormatter.IsHorizontalDirection (value); + != TextFormatter.IsHorizontalDirection (value); TextFormatter.Direction = value; + UpdateTextFormatterText (); - if ((IsInitialized && AutoSize) || (directionChanged && AutoSize && isValidOldAutSize)) { - ResizeView (true); - } else if (IsInitialized) { - var b = new Rect (Bounds.X, Bounds.Y, Bounds.Height, Bounds.Width); - SetWidthHeight (b); + if ((!ForceValidatePosDim && directionChanged && AutoSize) + || (ForceValidatePosDim && directionChanged && AutoSize && isValidOldAutSize)) { + ProcessResizeView (); + } else if (directionChanged && IsAdded) { + SetWidthHeight (Bounds.Size); + SetMinWidthHeight (); + } else { + SetMinWidthHeight (); } - TextFormatter.Size = GetBoundsTextFormatterSize (); SetNeedsDisplay (); } } } - bool isInitialized; - /// /// Get or sets if the was already initialized. /// This derived from to allow notify all the views that are being initialized. /// - public virtual bool IsInitialized { - get => isInitialized; - private set { - isInitialized = value; - SetMinWidthHeight (); - if (autoSize && !IsValidAutoSize (out Size autSize)) { - TextFormatter.AutoSize = false; - autoSize = false; - } - } - } + public virtual bool IsInitialized { get; set; } + + /// + /// Gets information if the view was already added to the superview. + /// + public bool IsAdded { get; private set; } bool oldEnabled; @@ -2482,29 +2564,34 @@ namespace Terminal.Gui { return $"{GetType ().Name}({Id})({Frame})"; } + void SetHotKey () + { + TextFormatter.FindHotKey (text, HotKeySpecifier, true, out _, out Key hk); + if (hotKey != hk) { + HotKey = hk; + } + } + bool ResizeView (bool autoSize) { if (!autoSize) { return false; } - var aSize = autoSize; - Rect nBounds = TextFormatter.CalcRect (Bounds.X, Bounds.Y, Text, TextFormatter.Direction); - if (TextFormatter.Size != nBounds.Size) { - TextFormatter.Size = nBounds.Size; - } - var fmtSize = GetTextFormatterBoundsSize (); - if ((fmtSize != Bounds.Size || fmtSize != nBounds.Size) - && (((width == null || width is Dim.DimAbsolute) && (Bounds.Width == 0 - || autoSize && Bounds.Width != nBounds.Width)) - || ((height == null || height is Dim.DimAbsolute) && (Bounds.Height == 0 - || autoSize && Bounds.Height != nBounds.Height)))) { - aSize = SetWidthHeight (nBounds); + var aSize = true; + var nBoundsSize = CalculateAutoSize (); + if (nBoundsSize != Bounds.Size) { + if (ForceValidatePosDim) { + aSize = SetWidthHeight (nBoundsSize); + } else { + Bounds = new Rect (Bounds.X, Bounds.Y, nBoundsSize.Width, nBoundsSize.Height); + } } + TextFormatter.Size = GetBoundsTextFormatterSize (); return aSize; } - bool SetWidthHeight (Rect nBounds) + bool SetWidthHeight (Size nBounds) { bool aSize = false; var canSizeW = SetWidth (nBounds.Width - GetHotKeySpecifierLength (), out int rW); @@ -2525,30 +2612,59 @@ namespace Terminal.Gui { return aSize; } + /// + /// Calculates the size to fit all text if is true. + /// + /// The + public Size CalculateAutoSize () + { + var rect = TextFormatter.CalcRect (Bounds.X, Bounds.Y, TextFormatter.Text, TextFormatter.Direction); + return new Size (rect.Size.Width - GetHotKeySpecifierLength (), + rect.Size.Height - GetHotKeySpecifierLength (false)); + } + + /// + /// Calculates the width to fit the text if is true. + /// + /// The width length. + public int CalculateAutoSizeWidth () + { + return CalculateAutoSize ().Width; + } + + /// + /// Calculates the height to fit the text if is true. + /// + /// The height length. + public int CalculateAutoSizeHeight () + { + return CalculateAutoSize ().Height; + } + bool IsValidAutoSize (out Size autoSize) { var rect = TextFormatter.CalcRect (frame.X, frame.Y, TextFormatter.Text, TextDirection); autoSize = new Size (rect.Size.Width - GetHotKeySpecifierLength (), - rect.Size.Height - GetHotKeySpecifierLength (false)); - return !(!(Width is Dim.DimAbsolute) || !(Height is Dim.DimAbsolute) - || frame.Size.Width != rect.Size.Width - GetHotKeySpecifierLength () - || frame.Size.Height != rect.Size.Height - GetHotKeySpecifierLength (false)); + rect.Size.Height - GetHotKeySpecifierLength (false)); + return !(ForceValidatePosDim && (!(Width is Dim.DimAbsolute) || !(Height is Dim.DimAbsolute)) + || frame.Size.Width != rect.Size.Width - GetHotKeySpecifierLength () + || frame.Size.Height != rect.Size.Height - GetHotKeySpecifierLength (false)); } bool IsValidAutoSizeWidth (Dim width) { var rect = TextFormatter.CalcRect (frame.X, frame.Y, TextFormatter.Text, TextDirection); var dimValue = width.Anchor (0); - return !(!(width is Dim.DimAbsolute) || dimValue != rect.Size.Width - - GetHotKeySpecifierLength ()); + return !(ForceValidatePosDim && (!(width is Dim.DimAbsolute)) || dimValue != rect.Size.Width + - GetHotKeySpecifierLength ()); } bool IsValidAutoSizeHeight (Dim height) { var rect = TextFormatter.CalcRect (frame.X, frame.Y, TextFormatter.Text, TextDirection); var dimValue = height.Anchor (0); - return !(!(height is Dim.DimAbsolute) || dimValue != rect.Size.Height - - GetHotKeySpecifierLength (false)); + return !(ForceValidatePosDim && (!(height is Dim.DimAbsolute)) || dimValue != rect.Size.Height + - GetHotKeySpecifierLength (false)); } /// @@ -2560,12 +2676,12 @@ namespace Terminal.Gui { { if (isWidth) { return TextFormatter.IsHorizontalDirection (TextDirection) && - TextFormatter.Text?.Contains (HotKeySpecifier) == true - ? Math.Max (Rune.ColumnWidth (HotKeySpecifier), 0) : 0; + TextFormatter.Text?.Contains (HotKeySpecifier) == true + ? Math.Max (Rune.ColumnWidth (HotKeySpecifier), 0) : 0; } else { return TextFormatter.IsVerticalDirection (TextDirection) && - TextFormatter.Text?.Contains (HotKeySpecifier) == true - ? Math.Max (Rune.ColumnWidth (HotKeySpecifier), 0) : 0; + TextFormatter.Text?.Contains (HotKeySpecifier) == true + ? Math.Max (Rune.ColumnWidth (HotKeySpecifier), 0) : 0; } } @@ -2576,7 +2692,7 @@ namespace Terminal.Gui { public Size GetTextFormatterBoundsSize () { return new Size (TextFormatter.Size.Width - GetHotKeySpecifierLength (), - TextFormatter.Size.Height - GetHotKeySpecifierLength (false)); + TextFormatter.Size.Height - GetHotKeySpecifierLength (false)); } /// @@ -2589,7 +2705,7 @@ namespace Terminal.Gui { return Bounds.Size; return new Size (frame.Size.Width + GetHotKeySpecifierLength (), - frame.Size.Height + GetHotKeySpecifierLength (false)); + frame.Size.Height + GetHotKeySpecifierLength (false)); } /// @@ -2774,7 +2890,7 @@ namespace Terminal.Gui { if (Width is Dim.DimCombine || Width is Dim.DimView || Width is Dim.DimFill) { // It's a Dim.DimCombine and so can't be assigned. Let it have it's width anchored. w = Width.Anchor (w); - canSetWidth = false; + canSetWidth = !ForceValidatePosDim; } else if (Width is Dim.DimFactor factor) { // Tries to get the SuperView width otherwise the view width. var sw = SuperView != null ? SuperView.Frame.Width : w; @@ -2782,7 +2898,7 @@ namespace Terminal.Gui { sw -= Frame.X; } w = Width.Anchor (sw); - canSetWidth = false; + canSetWidth = !ForceValidatePosDim; } else { canSetWidth = true; } @@ -2798,7 +2914,7 @@ namespace Terminal.Gui { if (Height is Dim.DimCombine || Height is Dim.DimView || Height is Dim.DimFill) { // It's a Dim.DimCombine and so can't be assigned. Let it have it's height anchored. h = Height.Anchor (h); - canSetHeight = false; + canSetHeight = !ForceValidatePosDim; } else if (Height is Dim.DimFactor factor) { // Tries to get the SuperView height otherwise the view height. var sh = SuperView != null ? SuperView.Frame.Height : h; @@ -2806,7 +2922,7 @@ namespace Terminal.Gui { sh -= Frame.Y; } h = Height.Anchor (sh); - canSetHeight = false; + canSetHeight = !ForceValidatePosDim; } else { canSetHeight = true; } @@ -2844,8 +2960,8 @@ namespace Terminal.Gui { /// true if the width can be directly assigned, false otherwise. public bool GetCurrentWidth (out int currentWidth) { - SetRelativeLayout (SuperView == null ? Frame : SuperView.Frame); - currentWidth = Frame.Width; + SetRelativeLayout (SuperView == null ? frame : SuperView.frame); + currentWidth = frame.Width; return CanSetWidth (0, out _); } @@ -2857,8 +2973,8 @@ namespace Terminal.Gui { /// true if the height can be directly assigned, false otherwise. public bool GetCurrentHeight (out int currentHeight) { - SetRelativeLayout (SuperView == null ? Frame : SuperView.Frame); - currentHeight = Frame.Height; + SetRelativeLayout (SuperView == null ? frame : SuperView.frame); + currentHeight = frame.Height; return CanSetHeight (0, out _); } diff --git a/Terminal.Gui/Views/Button.cs b/Terminal.Gui/Views/Button.cs index ebe54e1b0..d33e34e8b 100644 --- a/Terminal.Gui/Views/Button.cs +++ b/Terminal.Gui/Views/Button.cs @@ -31,8 +31,13 @@ namespace Terminal.Gui { /// /// public class Button : View { - ustring text; bool is_default; + Rune _leftBracket; + Rune _rightBracket; + Rune _leftDefault; + Rune _rightDefault; + Key hotKey = Key.Null; + Rune hotKeySpecifier; /// /// Initializes a new instance of using layout. @@ -92,16 +97,10 @@ namespace Terminal.Gui { Initialize (text, is_default); } - Rune _leftBracket; - Rune _rightBracket; - Rune _leftDefault; - Rune _rightDefault; - private Key hotKey = Key.Null; - private Rune hotKeySpecifier; - void Initialize (ustring text, bool is_default) { TextAlignment = TextAlignment.Centered; + VerticalTextAlignment = VerticalTextAlignment.Middle; HotKeySpecifier = new Rune ('_'); @@ -113,8 +112,9 @@ namespace Terminal.Gui { CanFocus = true; AutoSize = true; this.is_default = is_default; - this.text = text ?? string.Empty; - Update (); + Text = text ?? string.Empty; + UpdateTextFormatterText (); + ProcessResizeView (); // Things this view knows how to do AddCommand (Command.Accept, () => AcceptKey ()); @@ -127,21 +127,6 @@ namespace Terminal.Gui { } } - /// > - public override ustring Text { - get { - return text; - } - set { - text = value; - TextFormatter.FindHotKey (text, HotKeySpecifier, true, out _, out Key hk); - if (hotKey != hk) { - HotKey = hk; - } - Update (); - } - } - /// /// Gets or sets whether the is the default action to activate in a dialog. /// @@ -150,7 +135,8 @@ namespace Terminal.Gui { get => is_default; set { is_default = value; - Update (); + UpdateTextFormatterText (); + ProcessResizeView (); } } @@ -183,43 +169,12 @@ namespace Terminal.Gui { } /// - public override bool AutoSize { - get => base.AutoSize; - set { - base.AutoSize = value; - Update (); - } - } - - internal void Update () + protected override void UpdateTextFormatterText () { if (IsDefault) - TextFormatter.Text = ustring.Make (_leftBracket) + ustring.Make (_leftDefault) + " " + text + " " + ustring.Make (_rightDefault) + ustring.Make (_rightBracket); + TextFormatter.Text = ustring.Make (_leftBracket) + ustring.Make (_leftDefault) + " " + Text + " " + ustring.Make (_rightDefault) + ustring.Make (_rightBracket); else - TextFormatter.Text = ustring.Make (_leftBracket) + " " + text + " " + ustring.Make (_rightBracket); - - int w = TextFormatter.Size.Width - GetHotKeySpecifierLength (); - GetCurrentWidth (out int cWidth); - var canSetWidth = SetWidth (w, out int rWidth); - if (canSetWidth && (cWidth < rWidth || AutoSize)) { - Width = rWidth; - w = rWidth; - } else if (!canSetWidth || !AutoSize) { - w = cWidth; - } - var layout = LayoutStyle; - bool layoutChanged = false; - if (!(Height is Dim.DimAbsolute)) { - // The height is always equal to 1 and must be Dim.DimAbsolute. - layoutChanged = true; - LayoutStyle = LayoutStyle.Absolute; - } - Height = 1; - if (layoutChanged) { - LayoutStyle = layout; - } - Frame = new Rect (Frame.Location, new Size (w, 1)); - SetNeedsDisplay (); + TextFormatter.Text = ustring.Make (_leftBracket) + " " + Text + " " + ustring.Make (_rightBracket); } /// @@ -322,9 +277,9 @@ namespace Terminal.Gui { /// public override void PositionCursor () { - if (HotKey == Key.Unknown && text != "") { + if (HotKey == Key.Unknown && Text != "") { for (int i = 0; i < TextFormatter.Text.RuneCount; i++) { - if (TextFormatter.Text [i] == text [0]) { + if (TextFormatter.Text [i] == Text [0]) { Move (i, 0); return; } diff --git a/Terminal.Gui/Views/Checkbox.cs b/Terminal.Gui/Views/Checkbox.cs index 9108283c1..79704061a 100644 --- a/Terminal.Gui/Views/Checkbox.cs +++ b/Terminal.Gui/Views/Checkbox.cs @@ -13,7 +13,6 @@ namespace Terminal.Gui { /// The shows an on/off toggle that the user can set /// public class CheckBox : View { - ustring text; Key hotKey = Key.Null; Rune hotKeySpecifier; Rune charChecked; @@ -71,7 +70,7 @@ namespace Terminal.Gui { /// The size of is computed based on the /// text length. /// - public CheckBox (int x, int y, ustring s, bool is_checked) : base (new Rect (x, y, s.Length + 4, 1)) + public CheckBox (int x, int y, ustring s, bool is_checked) : base (new Rect (x, y, s.Length, 1)) { Initialize (s, is_checked); } @@ -85,7 +84,8 @@ namespace Terminal.Gui { CanFocus = true; AutoSize = true; Text = s; - Update (); + UpdateTextFormatterText (); + ProcessResizeView (); // Things this view knows how to do AddCommand (Command.ToggleChecked, () => ToggleChecked ()); @@ -95,55 +95,27 @@ namespace Terminal.Gui { AddKeyBinding (Key.Space, Command.ToggleChecked); } - void Update () + /// + protected override void UpdateTextFormatterText () { switch (TextAlignment) { case TextAlignment.Left: case TextAlignment.Centered: case TextAlignment.Justified: - if (Checked) - TextFormatter.Text = ustring.Make (charChecked) + " " + GetFormatterText (); - else - TextFormatter.Text = ustring.Make (charUnChecked) + " " + GetFormatterText (); + TextFormatter.Text = ustring.Make (Checked ? charChecked : charUnChecked) + " " + GetFormatterText (); break; case TextAlignment.Right: - if (Checked) - TextFormatter.Text = GetFormatterText () + " " + ustring.Make (charChecked); - else - TextFormatter.Text = GetFormatterText () + " " + ustring.Make (charUnChecked); + TextFormatter.Text = GetFormatterText () + " " + ustring.Make (Checked ? charChecked : charUnChecked); break; } - - int w = TextFormatter.Size.Width - GetHotKeySpecifierLength (); - GetCurrentWidth (out int cWidth); - var canSetWidth = SetWidth (w, out int rWidth); - if (canSetWidth && (cWidth < rWidth || AutoSize)) { - Width = rWidth; - w = rWidth; - } else if (!canSetWidth || !AutoSize) { - w = cWidth; - } - var layout = LayoutStyle; - bool layoutChanged = false; - if (!(Height is Dim.DimAbsolute)) { - // The height is always equal to 1 and must be Dim.DimAbsolute. - layoutChanged = true; - LayoutStyle = LayoutStyle.Absolute; - } - Height = 1; - if (layoutChanged) { - LayoutStyle = layout; - } - Frame = new Rect (Frame.Location, new Size (w, 1)); - SetNeedsDisplay (); } ustring GetFormatterText () { - if (AutoSize || ustring.IsNullOrEmpty (text)) { - return text; + if (AutoSize || ustring.IsNullOrEmpty (Text) || Frame.Width <= 2) { + return Text; } - return text.RuneSubstring (0, Math.Min (Frame.Width - 2, text.RuneCount)); + return Text.RuneSubstring (0, Math.Min (Frame.Width - 2, Text.RuneCount)); } /// @@ -165,15 +137,6 @@ namespace Terminal.Gui { } } - /// - public override bool AutoSize { - get => base.AutoSize; - set { - base.AutoSize = value; - Update (); - } - } - /// /// The state of the /// @@ -181,34 +144,8 @@ namespace Terminal.Gui { get => @checked; set { @checked = value; - Update (); - } - } - - /// - /// The text displayed by this - /// - public new ustring Text { - get { - return text; - } - - set { - text = value; - TextFormatter.FindHotKey (text, HotKeySpecifier, true, out _, out Key hk); - if (hotKey != hk) { - HotKey = hk; - } - Update (); - } - } - - /// - public override TextAlignment TextAlignment { - get => base.TextAlignment; - set { - base.TextAlignment = value; - Update (); + UpdateTextFormatterText (); + ProcessResizeView (); } } diff --git a/Terminal.Gui/Views/ComboBox.cs b/Terminal.Gui/Views/ComboBox.cs index e92b4b2ed..f1b8c48b4 100644 --- a/Terminal.Gui/Views/ComboBox.cs +++ b/Terminal.Gui/Views/ComboBox.cs @@ -109,7 +109,7 @@ namespace Terminal.Gui { private void Initialize () { - if (Bounds.Height < minimumHeight && Height is Dim.DimAbsolute) { + if (Bounds.Height < minimumHeight && (Height == null || Height is Dim.DimAbsolute)) { Height = minimumHeight; } diff --git a/Terminal.Gui/Views/Label.cs b/Terminal.Gui/Views/Label.cs index 83931ab77..0a1d795b3 100644 --- a/Terminal.Gui/Views/Label.cs +++ b/Terminal.Gui/Views/Label.cs @@ -6,9 +6,6 @@ // using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; using NStack; namespace Terminal.Gui { @@ -110,7 +107,7 @@ namespace Terminal.Gui { SetNeedsDisplay (); } - Clicked?.Invoke (); + OnClicked (); return true; } return false; @@ -123,5 +120,26 @@ namespace Terminal.Gui { return base.OnEnter (view); } + + /// + public override bool ProcessHotKey (KeyEvent ke) + { + if (ke.Key == (Key.AltMask | HotKey)) { + if (!HasFocus) { + SetFocus (); + } + OnClicked (); + return true; + } + return base.ProcessHotKey (ke); + } + + /// + /// Virtual method to invoke the event. + /// + public virtual void OnClicked () + { + Clicked?.Invoke (); + } } } diff --git a/Terminal.Gui/Views/PanelView.cs b/Terminal.Gui/Views/PanelView.cs index 6f513119c..12fdbfcab 100644 --- a/Terminal.Gui/Views/PanelView.cs +++ b/Terminal.Gui/Views/PanelView.cs @@ -68,10 +68,10 @@ namespace Terminal.Gui { } child = value; savedChild = new SavedPosDim () { - X = child?.X, - Y = child?.Y, - Width = child?.Width, - Height = child?.Height + X = child?.X ?? child?.Frame.X, + Y = child?.Y ?? child?.Frame.Y, + Width = child?.Width ?? child?.Frame.Width, + Height = child?.Height ?? child?.Frame.Height }; if (child == null) { Visible = false; diff --git a/Terminal.Gui/Views/RadioGroup.cs b/Terminal.Gui/Views/RadioGroup.cs index e215af55b..fc558485e 100644 --- a/Terminal.Gui/Views/RadioGroup.cs +++ b/Terminal.Gui/Views/RadioGroup.cs @@ -26,7 +26,7 @@ namespace Terminal.Gui { /// The index of the item to be selected, the value is clamped to the number of items. public RadioGroup (ustring [] radioLabels, int selected = 0) : base () { - Initialize (radioLabels, selected); + Initialize (Rect.Empty, radioLabels, selected); } /// @@ -37,7 +37,7 @@ namespace Terminal.Gui { /// The index of item to be selected, the value is clamped to the number of items. public RadioGroup (Rect rect, ustring [] radioLabels, int selected = 0) : base (rect) { - Initialize (radioLabels, selected); + Initialize (rect, radioLabels, selected); } /// @@ -52,7 +52,7 @@ namespace Terminal.Gui { this (MakeRect (x, y, radioLabels != null ? radioLabels.ToList () : null), radioLabels, selected) { } - void Initialize (ustring [] radioLabels, int selected) + void Initialize (Rect rect, ustring [] radioLabels, int selected) { if (radioLabels == null) { this.radioLabels = new List (); @@ -61,7 +61,11 @@ namespace Terminal.Gui { } this.selected = selected; - SetWidthHeight (this.radioLabels); + if (rect == Rect.Empty) { + SetWidthHeight (this.radioLabels); + } else { + Frame = rect; + } CanFocus = true; // Things this view knows how to do @@ -102,6 +106,7 @@ namespace Terminal.Gui { if (horizontalSpace != value && displayMode == DisplayModeLayout.Horizontal) { horizontalSpace = value; SetWidthHeight (radioLabels); + UpdateTextFormatterText (); SetNeedsDisplay (); } } @@ -112,7 +117,7 @@ namespace Terminal.Gui { switch (displayMode) { case DisplayModeLayout.Vertical: var r = MakeRect (0, 0, radioLabels); - if (LayoutStyle == LayoutStyle.Computed) { + if (IsAdded && LayoutStyle == LayoutStyle.Computed) { Width = r.Width; Height = radioLabels.Count; } else { @@ -126,9 +131,11 @@ namespace Terminal.Gui { length += item.length; } var hr = new Rect (0, 0, length, 1); - if (LayoutStyle == LayoutStyle.Computed) { + if (IsAdded && LayoutStyle == LayoutStyle.Computed) { Width = hr.Width; Height = 1; + } else { + Frame = new Rect (Frame.Location, new Size (hr.Width, radioLabels.Count)); } break; } @@ -136,18 +143,17 @@ namespace Terminal.Gui { static Rect MakeRect (int x, int y, List radioLabels) { - int width = 0; - if (radioLabels == null) { - return new Rect (x, y, width, 0); + return new Rect (x, y, 0, 0); } + int width = 0; + foreach (var s in radioLabels) - width = Math.Max (s.RuneCount + 3, width); + width = Math.Max (s.ConsoleWidth + 3, width); return new Rect (x, y, width, radioLabels.Count); } - List radioLabels = new List (); /// @@ -176,7 +182,7 @@ namespace Terminal.Gui { int length = 0; for (int i = 0; i < radioLabels.Count; i++) { start += length; - length = radioLabels [i].RuneCount + horizontalSpace; + length = radioLabels [i].ConsoleWidth + 2 + (i < radioLabels.Count - 1 ? horizontalSpace : 0); horizontal.Add ((start, length)); } } @@ -188,7 +194,7 @@ namespace Terminal.Gui { // for (int i = 0; i < radioLabels.Count; i++) { // Move(0, i); // Driver.SetAttribute(ColorScheme.Normal); - // Driver.AddStr(ustring.Make(new string (' ', radioLabels[i].RuneCount + 4))); + // Driver.AddStr(ustring.Make(new string (' ', radioLabels[i].ConsoleWidth + 4))); // } // if (newRadioLabels.Count != radioLabels.Count) { // SetWidthHeight(newRadioLabels); @@ -210,7 +216,7 @@ namespace Terminal.Gui { break; } Driver.SetAttribute (GetNormalColor ()); - Driver.AddStr (ustring.Make (new Rune [] { (i == selected ? Driver.Selected : Driver.UnSelected), ' ' })); + Driver.AddStr (ustring.Make (new Rune [] { i == selected ? Driver.Selected : Driver.UnSelected, ' ' })); DrawHotString (radioLabels [i], HasFocus && i == cursor, ColorScheme); } } diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs index 3185bb3a3..ebd900da2 100644 --- a/Terminal.Gui/Views/TextField.cs +++ b/Terminal.Gui/Views/TextField.cs @@ -474,6 +474,9 @@ namespace Terminal.Gui { void Adjust () { + if (!IsAdded) + return; + int offB = OffSetBackground (); if (point < first) { first = point; diff --git a/UICatalog/Scenarios/AutoSizeAndDirectionText.cs b/UICatalog/Scenarios/AutoSizeAndDirectionText.cs index 048eca48d..1068f6796 100644 --- a/UICatalog/Scenarios/AutoSizeAndDirectionText.cs +++ b/UICatalog/Scenarios/AutoSizeAndDirectionText.cs @@ -7,11 +7,14 @@ namespace UICatalog.Scenarios { public override void Setup () { var text = "Hello World"; + //var text = "Hello World 你"; var color = Colors.Dialog; var labelH = new Label (text, TextDirection.LeftRight_TopBottom) { X = 1, Y = 1, + Width = 11, + Height = 1, ColorScheme = color }; Win.Add (labelH); @@ -19,6 +22,8 @@ namespace UICatalog.Scenarios { var labelV = new Label (text, TextDirection.TopBottom_LeftRight) { X = 70, Y = 1, + Width = 1, + Height = 11, ColorScheme = color }; Win.Add (labelV); @@ -59,6 +64,15 @@ namespace UICatalog.Scenarios { ckbAutoSize.Toggled += (_) => labelH.AutoSize = labelV.AutoSize = ckbAutoSize.Checked; Win.Add (ckbAutoSize); + var ckbPreserveTrailingSpaces = new CheckBox ("Preserve Trailing Spaces") { + X = Pos.Center (), + Y = Pos.Center () + 7, + Checked = labelH.PreserveTrailingSpaces = labelV.PreserveTrailingSpaces + }; + ckbPreserveTrailingSpaces.Toggled += (_) => + labelH.PreserveTrailingSpaces = labelV.PreserveTrailingSpaces = ckbPreserveTrailingSpaces.Checked; + Win.Add (ckbPreserveTrailingSpaces); + Win.KeyUp += (_) => labelH.Text = labelV.Text = text = editText.Text.ToString (); } diff --git a/UICatalog/Scenarios/Dialogs.cs b/UICatalog/Scenarios/Dialogs.cs index 766c1e719..696ff1933 100644 --- a/UICatalog/Scenarios/Dialogs.cs +++ b/UICatalog/Scenarios/Dialogs.cs @@ -103,8 +103,7 @@ namespace UICatalog.Scenarios { label = new Label ("Button Style:") { X = 0, Y = Pos.Bottom (glyphsNotWords), - AutoSize = true, - TextAlignment = Terminal.Gui.TextAlignment.Right, + TextAlignment = Terminal.Gui.TextAlignment.Right }; frame.Add (label); var styleRadioGroup = new RadioGroup (new ustring [] { "Center", "Justify", "Left", "Right" }) { @@ -133,7 +132,6 @@ namespace UICatalog.Scenarios { Y = Pos.Bottom (frame) + 5, Width = 25, Height = 1, - ColorScheme = Colors.Error, }; // glyphsNotWords diff --git a/UICatalog/Scenarios/Editor.cs b/UICatalog/Scenarios/Editor.cs index 259164aa5..bca03b41f 100644 --- a/UICatalog/Scenarios/Editor.cs +++ b/UICatalog/Scenarios/Editor.cs @@ -748,12 +748,7 @@ namespace UICatalog.Scenarios { private View FindTab () { - var d = new View () { - X = 0, - Y = 0, - Width = Dim.Fill (), - Height = Dim.Fill () - }; + var d = new View (); d.DrawContent += (e) => { foreach (var v in d.Subviews) { v.SetNeedsDisplay (); @@ -762,10 +757,11 @@ namespace UICatalog.Scenarios { var lblWidth = "Replace:".Length; - var label = new Label (0, 1, "Find:") { + var label = new Label ("Find:") { + Y = 1, Width = lblWidth, TextAlignment = TextAlignment.Right, - LayoutStyle = LayoutStyle.Computed + AutoSize = false }; d.Add (label); @@ -784,7 +780,8 @@ namespace UICatalog.Scenarios { Width = 20, Enabled = !txtToFind.Text.IsEmpty, TextAlignment = TextAlignment.Centered, - IsDefault = true + IsDefault = true, + AutoSize = false }; btnFindNext.Clicked += () => FindNext (); d.Add (btnFindNext); @@ -794,7 +791,8 @@ namespace UICatalog.Scenarios { Y = Pos.Top (btnFindNext) + 1, Width = 20, Enabled = !txtToFind.Text.IsEmpty, - TextAlignment = TextAlignment.Centered + TextAlignment = TextAlignment.Centered, + AutoSize = false }; btnFindPrevious.Clicked += () => FindPrevious (); d.Add (btnFindPrevious); @@ -810,7 +808,8 @@ namespace UICatalog.Scenarios { X = Pos.Right (txtToFind) + 1, Y = Pos.Top (btnFindPrevious) + 2, Width = 20, - TextAlignment = TextAlignment.Centered + TextAlignment = TextAlignment.Centered, + AutoSize = false }; btnCancel.Clicked += () => { DisposeWinDialog (); @@ -841,12 +840,7 @@ namespace UICatalog.Scenarios { private View ReplaceTab () { - var d = new View () { - X = 0, - Y = 0, - Width = Dim.Fill (), - Height = Dim.Fill () - }; + var d = new View (); d.DrawContent += (e) => { foreach (var v in d.Subviews) { v.SetNeedsDisplay (); @@ -855,10 +849,11 @@ namespace UICatalog.Scenarios { var lblWidth = "Replace:".Length; - var label = new Label (0, 1, "Find:") { + var label = new Label ("Find:") { + Y = 1, Width = lblWidth, TextAlignment = TextAlignment.Right, - LayoutStyle = LayoutStyle.Computed + AutoSize = false }; d.Add (label); @@ -877,7 +872,8 @@ namespace UICatalog.Scenarios { Width = 20, Enabled = !txtToFind.Text.IsEmpty, TextAlignment = TextAlignment.Centered, - IsDefault = true + IsDefault = true, + AutoSize = false }; btnFindNext.Clicked += () => ReplaceNext (); d.Add (btnFindNext); @@ -904,7 +900,8 @@ namespace UICatalog.Scenarios { Y = Pos.Top (btnFindNext) + 1, Width = 20, Enabled = !txtToFind.Text.IsEmpty, - TextAlignment = TextAlignment.Centered + TextAlignment = TextAlignment.Centered, + AutoSize = false }; btnFindPrevious.Clicked += () => ReplacePrevious (); d.Add (btnFindPrevious); @@ -914,7 +911,8 @@ namespace UICatalog.Scenarios { Y = Pos.Top (btnFindPrevious) + 1, Width = 20, Enabled = !txtToFind.Text.IsEmpty, - TextAlignment = TextAlignment.Centered + TextAlignment = TextAlignment.Centered, + AutoSize = false }; btnReplaceAll.Clicked += () => ReplaceAll (); d.Add (btnReplaceAll); @@ -931,7 +929,8 @@ namespace UICatalog.Scenarios { X = Pos.Right (txtToFind) + 1, Y = Pos.Top (btnReplaceAll) + 1, Width = 20, - TextAlignment = TextAlignment.Centered + TextAlignment = TextAlignment.Centered, + AutoSize = false }; btnCancel.Clicked += () => { DisposeWinDialog (); diff --git a/UICatalog/Scenarios/LabelsAsButtons.cs b/UICatalog/Scenarios/LabelsAsButtons.cs index 8fdf027cb..395a042ec 100644 --- a/UICatalog/Scenarios/LabelsAsButtons.cs +++ b/UICatalog/Scenarios/LabelsAsButtons.cs @@ -90,6 +90,8 @@ namespace UICatalog.Scenarios { Y = Pos.Bottom (Label) + 1, HotKeySpecifier = (System.Rune)'_', CanFocus = true, + TextAlignment = TextAlignment.Centered, + VerticalTextAlignment = VerticalTextAlignment.Middle }); Label.Clicked += () => MessageBox.Query ("Message", "Question?", "Yes", "No"); @@ -159,6 +161,7 @@ namespace UICatalog.Scenarios { ColorScheme = Colors.Error, HotKeySpecifier = (System.Rune)'_', CanFocus = true, + AutoSize = false }; sizeBtn.Clicked += () => { sizeBtn.Width = sizeBtn.Frame.Width + 5; @@ -190,6 +193,7 @@ namespace UICatalog.Scenarios { ColorScheme = Colors.Error, HotKeySpecifier = (System.Rune)'_', CanFocus = true, + AutoSize = false }; sizeBtnA.Clicked += () => { sizeBtnA.Frame = new Rect (sizeBtnA.Frame.X, sizeBtnA.Frame.Y, sizeBtnA.Frame.Width + 5, sizeBtnA.Frame.Height); diff --git a/UICatalog/Scenarios/Scrolling.cs b/UICatalog/Scenarios/Scrolling.cs index db460e4d4..aec97e7a7 100644 --- a/UICatalog/Scenarios/Scrolling.cs +++ b/UICatalog/Scenarios/Scrolling.cs @@ -129,7 +129,8 @@ namespace UICatalog.Scenarios { Y = 0, Width = Dim.Fill (), // FIXED: I don't think this should be needed; DimFill() should respect container's frame. X does. Height = 2, - ColorScheme = Colors.Error + ColorScheme = Colors.Error, + AutoSize = false }; scrollView.Add (horizontalRuler); const string vrule = "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n"; @@ -139,7 +140,8 @@ namespace UICatalog.Scenarios { Y = 0, Width = 1, Height = Dim.Fill (), - ColorScheme = Colors.Error + ColorScheme = Colors.Error, + AutoSize = false }; scrollView.Add (verticalRuler); diff --git a/UICatalog/Scenarios/TextAlignments.cs b/UICatalog/Scenarios/TextAlignments.cs index 91dcbb2cc..1b538f423 100644 --- a/UICatalog/Scenarios/TextAlignments.cs +++ b/UICatalog/Scenarios/TextAlignments.cs @@ -22,8 +22,8 @@ namespace UICatalog.Scenarios { var multiLineHeight = 5; foreach (var alignment in alignments) { - singleLines [(int)alignment] = new Label (txt) { TextAlignment = alignment, X = 1, Width = Dim.Fill (1), Height = 1, ColorScheme = Colors.Dialog }; - multipleLines [(int)alignment] = new Label (txt) { TextAlignment = alignment, X = 1, Width = Dim.Fill (1), Height = multiLineHeight, ColorScheme = Colors.Dialog }; + singleLines [(int)alignment] = new Label (txt) { TextAlignment = alignment, X = 1, Width = Dim.Fill (1), Height = 1, ColorScheme = Colors.Dialog, AutoSize = false }; + multipleLines [(int)alignment] = new Label (txt) { TextAlignment = alignment, X = 1, Width = Dim.Fill (1), Height = multiLineHeight, ColorScheme = Colors.Dialog, AutoSize = false }; } // Add a label & text field so we can demo IsDefault diff --git a/UICatalog/Scenarios/TextAlignmentsAndDirection.cs b/UICatalog/Scenarios/TextAlignmentsAndDirection.cs index 06d241a01..aa58bf2d0 100644 --- a/UICatalog/Scenarios/TextAlignmentsAndDirection.cs +++ b/UICatalog/Scenarios/TextAlignmentsAndDirection.cs @@ -60,7 +60,7 @@ namespace UICatalog.Scenarios { // Multi-Line - var container = new View () { X = 0, Y = Pos.Bottom (txtLabelHJ), Width = Dim.Fill (31), Height = Dim.Fill (7), ColorScheme = color2 }; + var container = new View () { X = 0, Y = Pos.Bottom (txtLabelHJ), Width = Dim.Fill (31), Height = Dim.Fill (6), ColorScheme = color2 }; var txtLabelTL = new Label (txt) { X = 1 /* */, Y = 1, Width = Dim.Percent (100f / 3f), Height = Dim.Percent (100f / 3f), TextAlignment = TextAlignment.Left, VerticalTextAlignment = VerticalTextAlignment.Top, ColorScheme = color1 }; var txtLabelTC = new Label (txt) { X = Pos.Right (txtLabelTL) + 2, Y = 1, Width = Dim.Percent (100f / 3f), Height = Dim.Percent (100f / 3f), TextAlignment = TextAlignment.Centered, VerticalTextAlignment = VerticalTextAlignment.Top, ColorScheme = color1 }; diff --git a/UICatalog/Scenarios/TextFormatterDemo.cs b/UICatalog/Scenarios/TextFormatterDemo.cs index 21f6eba36..fb5187673 100644 --- a/UICatalog/Scenarios/TextFormatterDemo.cs +++ b/UICatalog/Scenarios/TextFormatterDemo.cs @@ -26,7 +26,7 @@ namespace UICatalog.Scenarios { string text = "Hello world, how are you today? Pretty neat!\nSecond line\n\nFourth Line."; string unicode = "Τὴ γλῶσσα μοῦ ἔδωσαν ἑλληνικὴ\nτὸ σπίτι φτωχικὸ στὶς ἀμμουδιὲς τοῦ Ὁμήρου.\nΜονάχη ἔγνοια ἡ γλῶσσα μου στὶς ἀμμουδιὲς τοῦ Ὁμήρου."; - Label blockText = new Label () { ColorScheme = Colors.TopLevel, X = 0, Y = 0, Height = 10, Width = Dim.Fill (0) }; + Label blockText = new Label () { ColorScheme = Colors.TopLevel, X = 0, Y = 0, Height = 10, Width = Dim.Fill (0), AutoSize = false }; var block = new StringBuilder (); block.AppendLine (" ▄████ █ ██ ██▓ ▄████▄ ██████ "); @@ -56,8 +56,8 @@ namespace UICatalog.Scenarios { var multiLineHeight = 5; foreach (var alignment in alignments) { - singleLines [(int)alignment] = new Label (text) { TextAlignment = alignment, X = 0, Width = Dim.Fill (), Height = 1, ColorScheme = Colors.Dialog }; - multipleLines [(int)alignment] = new Label (text) { TextAlignment = alignment, X = 0, Width = Dim.Fill (), Height = multiLineHeight, ColorScheme = Colors.Dialog }; + singleLines [(int)alignment] = new Label (text) { TextAlignment = alignment, X = 0, Width = Dim.Fill (), Height = 1, ColorScheme = Colors.Dialog, AutoSize = false }; + multipleLines [(int)alignment] = new Label (text) { TextAlignment = alignment, X = 0, Width = Dim.Fill (), Height = multiLineHeight, ColorScheme = Colors.Dialog, AutoSize = false }; } var label = new Label ($"Demonstrating single-line (should clip):") { Y = Pos.Bottom (unicodeCheckBox) + 1 }; diff --git a/UICatalog/Scenarios/Wizards.cs b/UICatalog/Scenarios/Wizards.cs index 565382962..07ebc827e 100644 --- a/UICatalog/Scenarios/Wizards.cs +++ b/UICatalog/Scenarios/Wizards.cs @@ -26,6 +26,7 @@ namespace UICatalog.Scenarios { Width = 15, Height = 1, TextAlignment = Terminal.Gui.TextAlignment.Right, + AutoSize = false }; frame.Add (label); var widthEdit = new TextField ("80") { @@ -42,6 +43,7 @@ namespace UICatalog.Scenarios { Width = Dim.Width (label), Height = 1, TextAlignment = Terminal.Gui.TextAlignment.Right, + AutoSize = false }; frame.Add (label); var heightEdit = new TextField ("20") { @@ -58,6 +60,7 @@ namespace UICatalog.Scenarios { Width = Dim.Width (label), Height = 1, TextAlignment = Terminal.Gui.TextAlignment.Right, + AutoSize = false }; frame.Add (label); var titleEdit = new TextField ("Title") { @@ -87,14 +90,12 @@ namespace UICatalog.Scenarios { label = new Label ("Action:") { X = Pos.Center (), Y = Pos.AnchorEnd (1), - AutoSize = true, TextAlignment = Terminal.Gui.TextAlignment.Right, }; Win.Add (label); var actionLabel = new Label (" ") { X = Pos.Right (label), Y = Pos.AnchorEnd (1), - AutoSize = true, ColorScheme = Colors.Error, }; @@ -159,7 +160,7 @@ namespace UICatalog.Scenarios { frameMsg = "Added to WizardStep directly"; } - var buttonLbl = new Label () { Text = "Second Step Button: ", AutoSize = true, X = 1, Y = 1 }; + var buttonLbl = new Label () { Text = "Second Step Button: ", X = 1, Y = 1 }; var button = new Button () { Text = "Press Me to Rename Step", X = Pos.Right (buttonLbl), @@ -170,10 +171,10 @@ namespace UICatalog.Scenarios { MessageBox.Query ("Wizard Scenario", "This Wizard Step's title was changed to '2nd Step'"); }; viewForControls.Add (buttonLbl, button); - var lbl = new Label () { Text = "First Name: ", AutoSize = true, X = 1, Y = Pos.Bottom (buttonLbl) }; + var lbl = new Label () { Text = "First Name: ", X = 1, Y = Pos.Bottom (buttonLbl) }; var firstNameField = new TextField () { Text = "Number", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) }; viewForControls.Add (lbl, firstNameField); - lbl = new Label () { Text = "Last Name: ", AutoSize = true, X = 1, Y = Pos.Bottom (lbl) }; + lbl = new Label () { Text = "Last Name: ", X = 1, Y = Pos.Bottom (lbl) }; var lastNameField = new TextField () { Text = "Six", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) }; viewForControls.Add (lbl, lastNameField); var thirdStepEnabledCeckBox = new CheckBox () { Text = "Enable Step _3", Checked = false, X = Pos.Left (lastNameField), Y = Pos.Bottom (lastNameField) }; @@ -192,7 +193,7 @@ namespace UICatalog.Scenarios { frame.Add (new TextField ("This is a TextField inside of the frame.")); viewForControls.Add (frame); wizard.StepChanging += (args) => { - if (args.OldStep == secondStep && firstNameField.Text.IsEmpty ) { + if (args.OldStep == secondStep && firstNameField.Text.IsEmpty) { args.Cancel = true; var btn = MessageBox.ErrorQuery ("Second Step", "You must enter a First Name to continue", "Ok"); } @@ -205,11 +206,10 @@ namespace UICatalog.Scenarios { var step3Label = new Label () { Text = "This step is optional.", X = 0, - Y = 0, - AutoSize = true + Y = 0 }; thirdStep.Controls.Add (step3Label); - var progLbl = new Label () { Text = "Third Step ProgressBar: ", AutoSize = true, X = 1, Y = 10 }; + var progLbl = new Label () { Text = "Third Step ProgressBar: ", X = 1, Y = 10 }; var progressBar = new ProgressBar () { X = Pos.Right (progLbl), Y = Pos.Top (progLbl), @@ -221,7 +221,7 @@ namespace UICatalog.Scenarios { thirdStepEnabledCeckBox.Toggled += (args) => { thirdStep.Enabled = thirdStepEnabledCeckBox.Checked; }; - + // Add 4th step var fourthStep = new Wizard.WizardStep ("Step Four"); wizard.AddStep (fourthStep); diff --git a/UnitTests/ButtonTests.cs b/UnitTests/ButtonTests.cs index 6c42514d1..b7bc55685 100644 --- a/UnitTests/ButtonTests.cs +++ b/UnitTests/ButtonTests.cs @@ -17,47 +17,57 @@ namespace Terminal.Gui.Views { var btn = new Button (); Assert.Equal (string.Empty, btn.Text); Application.Top.Add (btn); - btn.Redraw (btn.Bounds); - Assert.Equal ("[ ]", GetContents (btn.Bounds.Width)); + var rs = Application.Begin (Application.Top); + + Assert.Equal ("[ ]", btn.TextFormatter.Text); Assert.False (btn.IsDefault); Assert.Equal (TextAlignment.Centered, btn.TextAlignment); Assert.Equal ('_', btn.HotKeySpecifier); Assert.True (btn.CanFocus); Assert.Equal (new Rect (0, 0, 4, 1), btn.Frame); Assert.Equal (Key.Null, btn.HotKey); + var expected = @" +[ ] +"; + GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Application.End (rs); btn = new Button ("ARGS", true) { Text = "Test" }; Assert.Equal ("Test", btn.Text); Application.Top.Add (btn); - btn.Redraw (btn.Bounds); - Assert.Equal ("[◦ Test ◦]", GetContents (btn.Bounds.Width)); + rs = Application.Begin (Application.Top); + + Assert.Equal ("[◦ Test ◦]", btn.TextFormatter.Text); Assert.True (btn.IsDefault); Assert.Equal (TextAlignment.Centered, btn.TextAlignment); Assert.Equal ('_', btn.HotKeySpecifier); Assert.True (btn.CanFocus); Assert.Equal (new Rect (0, 0, 10, 1), btn.Frame); Assert.Equal (Key.T, btn.HotKey); + expected = @" +[◦ Test ◦] +"; + GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Application.End (rs); btn = new Button (3, 4, "Test", true); Assert.Equal ("Test", btn.Text); Application.Top.Add (btn); - btn.Redraw (btn.Bounds); - Assert.Equal ("[◦ Test ◦]", GetContents (btn.Bounds.Width)); + rs = Application.Begin (Application.Top); + + Assert.Equal ("[◦ Test ◦]", btn.TextFormatter.Text); Assert.True (btn.IsDefault); Assert.Equal (TextAlignment.Centered, btn.TextAlignment); Assert.Equal ('_', btn.HotKeySpecifier); Assert.True (btn.CanFocus); Assert.Equal (new Rect (3, 4, 10, 1), btn.Frame); Assert.Equal (Key.T, btn.HotKey); - } + expected = @" + [◦ Test ◦] +"; + GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); - private string GetContents (int width) - { - string output = ""; - for (int i = 0; i < width; i++) { - output += (char)Application.Driver.Contents [0, i, 0]; - } - return output; + Application.End (rs); } [Fact] @@ -273,8 +283,7 @@ namespace Terminal.Gui.Views { var btn = new Button () { X = Pos.Center (), Y = Pos.Center (), - Text = "Say Hello 你", - AutoSize = true + Text = "Say Hello 你" }; var win = new Window () { @@ -322,7 +331,7 @@ namespace Terminal.Gui.Views { Text = "Say Hello 你", AutoSize = true }; - btn.X = Pos.AnchorEnd () - Pos.Function (() => TextFormatter.GetTextWidth (btn.TextFormatter.Text)); + btn.X = Pos.AnchorEnd () - Pos.Function (() => TextFormatter.GetTextWidth (btn.TextFormatter.Text)); var win = new Window () { Width = Dim.Fill (), @@ -356,6 +365,185 @@ namespace Terminal.Gui.Views { │ [ Say Hello 你 changed ]│ │ │ └────────────────────────────┘ +"; + + GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + } + + [Fact, AutoInitShutdown] + public void AutoSize_False_With_Fixed_Width () + { + var tab = new View (); + + var lblWidth = 8; + + var label = new Label ("Find:") { + Y = 1, + Width = lblWidth, + TextAlignment = TextAlignment.Right, + AutoSize = false + }; + tab.Add (label); + + var txtToFind = new TextField ("Testing buttons.") { + X = Pos.Right (label) + 1, + Y = Pos.Top (label), + Width = 20 + }; + tab.Add (txtToFind); + + var btnFindNext = new Button ("Find _Next") { + X = Pos.Right (txtToFind) + 1, + Y = Pos.Top (label), + Width = 20, + Enabled = !txtToFind.Text.IsEmpty, + TextAlignment = TextAlignment.Centered, + IsDefault = true, + AutoSize = false + }; + tab.Add (btnFindNext); + + var btnFindPrevious = new Button ("Find _Previous") { + X = Pos.Right (txtToFind) + 1, + Y = Pos.Top (btnFindNext) + 1, + Width = 20, + Enabled = !txtToFind.Text.IsEmpty, + TextAlignment = TextAlignment.Centered, + AutoSize = false + }; + tab.Add (btnFindPrevious); + + var btnCancel = new Button ("Cancel") { + X = Pos.Right (txtToFind) + 1, + Y = Pos.Top (btnFindPrevious) + 2, + Width = 20, + TextAlignment = TextAlignment.Centered, + AutoSize = false + }; + tab.Add (btnCancel); + + var ckbMatchCase = new CheckBox ("Match c_ase") { + X = 0, + Y = Pos.Top (txtToFind) + 2, + Checked = true + }; + tab.Add (ckbMatchCase); + + var ckbMatchWholeWord = new CheckBox ("Match _whole word") { + X = 0, + Y = Pos.Top (ckbMatchCase) + 1, + Checked = false + }; + tab.Add (ckbMatchWholeWord); + + var tabView = new TabView () { + Width = Dim.Fill (), + Height = Dim.Fill () + }; + tabView.AddTab (new TabView.Tab ("Find", tab), true); + + var win = new Window ("Find") { + Width = Dim.Fill (), + Height = Dim.Fill () + }; + + tab.Width = label.Width + txtToFind.Width + btnFindNext.Width + 2; + tab.Height = btnFindNext.Height + btnFindPrevious.Height + btnCancel.Height + 4; + + win.Add (tabView); + Application.Top.Add (win); + + Application.Begin (Application.Top); + ((FakeDriver)Application.Driver).SetBufferSize (54, 11); + + Assert.Equal (new Rect (0, 0, 54, 11), win.Frame); + Assert.Equal (new Rect (0, 0, 52, 9), tabView.Frame); + Assert.Equal (new Rect (0, 0, 50, 7), tab.Frame); + Assert.Equal (new Rect (0, 1, 8, 1), label.Frame); + Assert.Equal (new Rect (9, 1, 20, 1), txtToFind.Frame); + + Assert.Equal (0, txtToFind.ScrollOffset); + Assert.Equal (16, txtToFind.CursorPosition); + + Assert.Equal (new Rect (30, 1, 20, 1), btnFindNext.Frame); + Assert.Equal (new Rect (30, 2, 20, 1), btnFindPrevious.Frame); + Assert.Equal (new Rect (30, 4, 20, 1), btnCancel.Frame); + Assert.Equal (new Rect (0, 3, 12, 1), ckbMatchCase.Frame); + Assert.Equal (new Rect (0, 4, 18, 1), ckbMatchWholeWord.Frame); + var expected = @" +┌ Find ──────────────────────────────────────────────┐ +│┌────┐ │ +││Find│ │ +││ └─────────────────────────────────────────────┐│ +││ ││ +││ Find: Testing buttons. [◦ Find Next ◦] ││ +││ [ Find Previous ] ││ +││√ Match case ││ +││╴ Match whole word [ Cancel ] ││ +│└──────────────────────────────────────────────────┘│ +└────────────────────────────────────────────────────┘ +"; + + GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + } + + [Fact, AutoInitShutdown] + public void Pos_Center_Layout_AutoSize_True () + { + var button = new Button ("Process keys") { + X = Pos.Center (), + Y = Pos.Center (), + IsDefault = true + }; + var win = new Window () { + Width = Dim.Fill (), + Height = Dim.Fill () + }; + win.Add (button); + Application.Top.Add (win); + + Application.Begin (Application.Top); + ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + Assert.True (button.AutoSize); + Assert.Equal (new Rect (5, 1, 18, 1), button.Frame); + var expected = @" +┌────────────────────────────┐ +│ │ +│ [◦ Process keys ◦] │ +│ │ +└────────────────────────────┘ +"; + + GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + } + + [Fact, AutoInitShutdown] + public void Pos_Center_Layout_AutoSize_False () + { + var button = new Button ("Process keys") { + X = Pos.Center (), + Y = Pos.Center (), + Width = 20, + IsDefault = true, + AutoSize = false + }; + var win = new Window () { + Width = Dim.Fill (), + Height = Dim.Fill () + }; + win.Add (button); + Application.Top.Add (win); + + Application.Begin (Application.Top); + ((FakeDriver)Application.Driver).SetBufferSize (30, 5); + Assert.False (button.AutoSize); + Assert.Equal (new Rect (4, 1, 20, 1), button.Frame); + var expected = @" +┌────────────────────────────┐ +│ │ +│ [◦ Process keys ◦] │ +│ │ +└────────────────────────────┘ "; GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); diff --git a/UnitTests/CheckboxTests.cs b/UnitTests/CheckboxTests.cs index b25aecb94..6dac85088 100644 --- a/UnitTests/CheckboxTests.cs +++ b/UnitTests/CheckboxTests.cs @@ -19,26 +19,34 @@ namespace Terminal.Gui.Views { public void Constructors_Defaults () { var ckb = new CheckBox (); + Assert.True (ckb.AutoSize); Assert.False (ckb.Checked); Assert.Equal (string.Empty, ckb.Text); + Assert.Equal ("╴ ", ckb.TextFormatter.Text); Assert.True (ckb.CanFocus); Assert.Equal (new Rect (0, 0, 2, 1), ckb.Frame); ckb = new CheckBox ("Test", true); + Assert.True (ckb.AutoSize); Assert.True (ckb.Checked); Assert.Equal ("Test", ckb.Text); + Assert.Equal ("√ Test", ckb.TextFormatter.Text); Assert.True (ckb.CanFocus); Assert.Equal (new Rect (0, 0, 6, 1), ckb.Frame); ckb = new CheckBox (1, 2, "Test"); + Assert.True (ckb.AutoSize); Assert.False (ckb.Checked); Assert.Equal ("Test", ckb.Text); + Assert.Equal ("╴ Test", ckb.TextFormatter.Text); Assert.True (ckb.CanFocus); Assert.Equal (new Rect (1, 2, 6, 1), ckb.Frame); ckb = new CheckBox (3, 4, "Test", true); + Assert.True (ckb.AutoSize); Assert.True (ckb.Checked); Assert.Equal ("Test", ckb.Text); + Assert.Equal ("√ Test", ckb.TextFormatter.Text); Assert.True (ckb.CanFocus); Assert.Equal (new Rect (3, 4, 6, 1), ckb.Frame); } @@ -106,7 +114,6 @@ namespace Terminal.Gui.Views { Assert.Equal ("Check this out 你", checkBox.Text); Assert.Equal ("╴ Check this out 你", checkBox.TextFormatter.Text); Assert.True (checkBox.AutoSize); - var expected = @" ┌ Test Demo 你 ──────────────┐ │ │ @@ -123,12 +130,21 @@ namespace Terminal.Gui.Views { checkBox.AutoSize = true; bool first = false; Application.RunMainLoopIteration (ref runstate, true, ref first); + Assert.Equal (new Rect (1, 1, 19, 1), checkBox.Frame); + expected = @" +┌ Test Demo 你 ──────────────┐ +│ │ +│ ╴ Check this out 你 │ +│ │ +└────────────────────────────┘ +"; GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); Assert.Equal (new Rect (0, 0, 30, 5), pos); checkBox.Checked = true; Application.RunMainLoopIteration (ref runstate, true, ref first); + Assert.Equal (new Rect (1, 1, 19, 1), checkBox.Frame); expected = @" ┌ Test Demo 你 ──────────────┐ │ │ @@ -141,8 +157,27 @@ namespace Terminal.Gui.Views { Assert.Equal (new Rect (0, 0, 30, 5), pos); checkBox.AutoSize = false; + // It isn't auto-size so the height is guaranteed by the SetMinWidthHeight checkBox.Text = "Check this out 你 changed"; Application.RunMainLoopIteration (ref runstate, true, ref first); + Assert.Equal (new Rect (1, 1, 19, 1), checkBox.Frame); + expected = @" +┌ Test Demo 你 ──────────────┐ +│ │ +│ √ Check this out 你 │ +│ │ +└────────────────────────────┘ +"; + + pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (0, 0, 30, 5), pos); + + checkBox.Width = 19; + // It isn't auto-size so the height is guaranteed by the SetMinWidthHeight + checkBox.Text = "Check this out 你 changed"; + Application.RunMainLoopIteration (ref runstate, true, ref first); + Assert.False (checkBox.AutoSize); + Assert.Equal (new Rect (1, 1, 19, 1), checkBox.Frame); expected = @" ┌ Test Demo 你 ──────────────┐ │ │ @@ -156,6 +191,7 @@ namespace Terminal.Gui.Views { checkBox.AutoSize = true; Application.RunMainLoopIteration (ref runstate, true, ref first); + Assert.Equal (new Rect (1, 1, 27, 1), checkBox.Frame); expected = @" ┌ Test Demo 你 ──────────────┐ │ │ @@ -191,6 +227,7 @@ namespace Terminal.Gui.Views { Assert.Equal (TextAlignment.Left, checkBox.TextAlignment); Assert.Equal (new Rect (1, 1, 25, 1), checkBox.Frame); + Assert.Equal (new Size (25, 1), checkBox.TextFormatter.Size); Assert.Equal ("Check this out 你", checkBox.Text); Assert.Equal ("╴ Check this out 你", checkBox.TextFormatter.Text); Assert.False (checkBox.AutoSize); @@ -244,6 +281,7 @@ namespace Terminal.Gui.Views { Assert.Equal (TextAlignment.Centered, checkBox.TextAlignment); Assert.Equal (new Rect (1, 1, 25, 1), checkBox.Frame); + Assert.Equal (new Size (25, 1), checkBox.TextFormatter.Size); Assert.Equal ("Check this out 你", checkBox.Text); Assert.Equal ("╴ Check this out 你", checkBox.TextFormatter.Text); Assert.False (checkBox.AutoSize); @@ -297,6 +335,7 @@ namespace Terminal.Gui.Views { Assert.Equal (TextAlignment.Justified, checkBox.TextAlignment); Assert.Equal (new Rect (1, 1, 25, 1), checkBox.Frame); + Assert.Equal (new Size (25, 1), checkBox.TextFormatter.Size); Assert.Equal ("Check this out 你", checkBox.Text); Assert.Equal ("╴ Check this out 你", checkBox.TextFormatter.Text); Assert.False (checkBox.AutoSize); @@ -313,6 +352,8 @@ namespace Terminal.Gui.Views { Assert.Equal (new Rect (0, 0, 30, 5), pos); checkBox.Checked = true; + Assert.Equal (new Rect (1, 1, 25, 1), checkBox.Frame); + Assert.Equal (new Size (25, 1), checkBox.TextFormatter.Size); Application.Refresh (); expected = @" ┌ Test Demo 你 ──────────────┐ @@ -350,6 +391,7 @@ namespace Terminal.Gui.Views { Assert.Equal (TextAlignment.Right, checkBox.TextAlignment); Assert.Equal (new Rect (1, 1, 25, 1), checkBox.Frame); + Assert.Equal (new Size (25, 1), checkBox.TextFormatter.Size); Assert.Equal ("Check this out 你", checkBox.Text); Assert.Equal ("Check this out 你 ╴", checkBox.TextFormatter.Text); Assert.False (checkBox.AutoSize); diff --git a/UnitTests/ComboBoxTests.cs b/UnitTests/ComboBoxTests.cs index 8fefd4c60..8286e7cfb 100644 --- a/UnitTests/ComboBoxTests.cs +++ b/UnitTests/ComboBoxTests.cs @@ -1,25 +1,38 @@ using System; using System.Collections.Generic; using System.Linq; -using Terminal.Gui; using Xunit; +using Xunit.Abstractions; namespace Terminal.Gui.Views { public class ComboBoxTests { + ITestOutputHelper output; + + public ComboBoxTests (ITestOutputHelper output) + { + this.output = output; + } + [Fact] public void Constructors_Defaults () { var cb = new ComboBox (); Assert.Equal (string.Empty, cb.Text); Assert.Null (cb.Source); + Assert.False (cb.AutoSize); + Assert.Equal (new Rect (0, 0, 0, 2), cb.Frame); cb = new ComboBox ("Test"); Assert.Equal ("Test", cb.Text); Assert.Null (cb.Source); + Assert.False (cb.AutoSize); + Assert.Equal (new Rect (0, 0, 0, 2), cb.Frame); cb = new ComboBox (new Rect (1, 2, 10, 20), new List () { "One", "Two", "Three" }); Assert.Equal (string.Empty, cb.Text); Assert.NotNull (cb.Source); + Assert.False (cb.AutoSize); + Assert.Equal (new Rect (1, 2, 10, 20), cb.Frame); } [Fact] @@ -44,12 +57,12 @@ namespace Terminal.Gui.Views { public void KeyBindings_Command () { List source = new List () { "One", "Two", "Three" }; - ComboBox cb = new ComboBox (); + ComboBox cb = new ComboBox () { Width = 10 }; cb.SetSource (source); Application.Top.Add (cb); Application.Top.FocusFirst (); Assert.Equal (-1, cb.SelectedItem); - Assert.Equal(string.Empty,cb.Text); + Assert.Equal (string.Empty, cb.Text); var opened = false; cb.OpenSelectedItem += (_) => opened = true; Assert.True (cb.ProcessKey (new KeyEvent (Key.Enter, new KeyModifiers ()))); @@ -63,7 +76,7 @@ namespace Terminal.Gui.Views { Assert.True (cb.ProcessKey (new KeyEvent (Key.F4, new KeyModifiers ()))); // with no source also expand empty Assert.True (cb.IsShow); Assert.Equal (-1, cb.SelectedItem); - cb.SetSource(source); + cb.SetSource (source); cb.Text = ""; Assert.True (cb.ProcessKey (new KeyEvent (Key.F4, new KeyModifiers ()))); // collapse Assert.False (cb.IsShow); @@ -106,10 +119,35 @@ namespace Terminal.Gui.Views { Assert.True (cb.IsShow); Assert.Equal (0, cb.SelectedItem); Assert.Equal ("One", cb.Text); + Application.Begin (Application.Top); + GraphViewTests.AssertDriverContentsWithFrameAre (@" +One ▼ +One +", output); + Assert.True (cb.ProcessKey (new KeyEvent (Key.PageDown, new KeyModifiers ()))); Assert.True (cb.IsShow); Assert.Equal (1, cb.SelectedItem); Assert.Equal ("Two", cb.Text); + Application.Begin (Application.Top); + GraphViewTests.AssertDriverContentsWithFrameAre (@" +Two ▼ +Two +", output); + + Assert.True (cb.ProcessKey (new KeyEvent (Key.PageDown, new KeyModifiers ()))); + Assert.True (cb.IsShow); + Assert.Equal (2, cb.SelectedItem); + Assert.Equal ("Three", cb.Text); + Application.Begin (Application.Top); + GraphViewTests.AssertDriverContentsWithFrameAre (@" +Three ▼ +Three +", output); + Assert.True (cb.ProcessKey (new KeyEvent (Key.PageUp, new KeyModifiers ()))); + Assert.True (cb.IsShow); + Assert.Equal (1, cb.SelectedItem); + Assert.Equal ("Two", cb.Text); Assert.True (cb.ProcessKey (new KeyEvent (Key.PageUp, new KeyModifiers ()))); Assert.True (cb.IsShow); Assert.Equal (0, cb.SelectedItem); @@ -167,10 +205,10 @@ namespace Terminal.Gui.Views { var cb = new ComboBox (); Application.Top.Add (cb); Application.Top.FocusFirst (); - Assert.Null(cb.Source); + Assert.Null (cb.Source); Assert.Equal (-1, cb.SelectedItem); var source = new List (); - cb.SetSource(source); + cb.SetSource (source); Assert.NotNull (cb.Source); Assert.Equal (0, cb.Source.Count); Assert.Equal (-1, cb.SelectedItem); @@ -197,7 +235,7 @@ namespace Terminal.Gui.Views { Assert.False (cb.IsShow); Assert.Equal (1, cb.SelectedItem); // retains last accept selected item Assert.Equal ("", cb.Text); // clear text - cb.SetSource(new List ()); + cb.SetSource (new List ()); Assert.Equal (0, cb.Source.Count); Assert.Equal (-1, cb.SelectedItem); Assert.Equal ("", cb.Text); diff --git a/UnitTests/DimTests.cs b/UnitTests/DimTests.cs index 538c2d906..0d4dbeb9b 100644 --- a/UnitTests/DimTests.cs +++ b/UnitTests/DimTests.cs @@ -250,7 +250,7 @@ namespace Terminal.Gui.Core { } [Fact] - public void Dim_Validation_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type () + public void ForceValidatePosDim_True_Dim_Validation_Throws_If_NewValue_Is_DimAbsolute_And_OldValue_Is_Another_Type () { Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true))); @@ -262,7 +262,8 @@ namespace Terminal.Gui.Core { }; var v = new View ("v") { Width = Dim.Width (w) - 2, - Height = Dim.Percent (10) + Height = Dim.Percent (10), + ForceValidatePosDim = true }; w.Add (v); @@ -273,6 +274,13 @@ namespace Terminal.Gui.Core { Assert.Equal (2, w.Height = 2); Assert.Throws (() => v.Width = 2); Assert.Throws (() => v.Height = 2); + v.ForceValidatePosDim = false; + var exception = Record.Exception (() => v.Width = 2); + Assert.Null (exception); + Assert.Equal (2, v.Width); + exception = Record.Exception (() => v.Height = 2); + Assert.Null (exception); + Assert.Equal (2, v.Height); }; Application.Iteration += () => Application.RequestStop (); @@ -362,39 +370,51 @@ namespace Terminal.Gui.Core { }; var v1 = new Button ("v1") { + AutoSize = false, X = Pos.X (f1) + 2, Y = Pos.Bottom (f1) + 2, Width = Dim.Width (f1) - 2, - Height = Dim.Fill () - 2 + Height = Dim.Fill () - 2, + ForceValidatePosDim = true }; var v2 = new Button ("v2") { + AutoSize = false, X = Pos.X (f2) + 2, Y = Pos.Bottom (f2) + 2, Width = Dim.Width (f2) - 2, - Height = Dim.Fill () - 2 + Height = Dim.Fill () - 2, + ForceValidatePosDim = true }; var v3 = new Button ("v3") { + AutoSize = false, Width = Dim.Percent (10), - Height = Dim.Percent (10) + Height = Dim.Percent (10), + ForceValidatePosDim = true }; var v4 = new Button ("v4") { + AutoSize = false, Width = Dim.Sized (50), - Height = Dim.Sized (50) + Height = Dim.Sized (50), + ForceValidatePosDim = true }; var v5 = new Button ("v5") { + AutoSize = false, Width = Dim.Width (v1) - Dim.Width (v3), - Height = Dim.Height (v1) - Dim.Height (v3) + Height = Dim.Height (v1) - Dim.Height (v3), + ForceValidatePosDim = true }; var v6 = new Button ("v6") { + AutoSize = false, X = Pos.X (f2), Y = Pos.Bottom (f2) + 2, Width = Dim.Percent (20, true), - Height = Dim.Percent (20, true) + Height = Dim.Percent (20, true), + ForceValidatePosDim = true }; w.Add (f1, f2, v1, v2, v3, v4, v5, v6); @@ -421,7 +441,6 @@ namespace Terminal.Gui.Core { Assert.Equal (47, v1.Frame.Width); // 49-2=47 Assert.Equal (89, v1.Frame.Height); // 98-5-2-2=89 - Assert.Equal ("Dim.Combine(DimView(side=Width, target=FrameView()({X=49,Y=0,Width=49,Height=5}))-Dim.Absolute(2))", v2.Width.ToString ()); Assert.Equal ("Dim.Combine(Dim.Fill(margin=0)-Dim.Absolute(2))", v2.Height.ToString ()); Assert.Equal (47, v2.Frame.Width); // 49-2=47 @@ -471,26 +490,28 @@ namespace Terminal.Gui.Core { v1.Text = "Button1"; Assert.Equal ("Dim.Combine(DimView(side=Width, target=FrameView()({X=0,Y=0,Width=99,Height=5}))-Dim.Absolute(2))", v1.Width.ToString ()); - Assert.Equal ("Dim.Absolute(1)", v1.Height.ToString ()); + Assert.Equal ("Dim.Combine(Dim.Fill(margin=0)-Dim.Absolute(2))", v1.Height.ToString ()); Assert.Equal (97, v1.Frame.Width); // 99-2=97 - Assert.Equal (1, v1.Frame.Height); // 1 because is Dim.DimAbsolute + Assert.Equal (189, v1.Frame.Height); // 198-2-7=189 v2.Text = "Button2"; Assert.Equal ("Dim.Combine(DimView(side=Width, target=FrameView()({X=99,Y=0,Width=99,Height=5}))-Dim.Absolute(2))", v2.Width.ToString ()); - Assert.Equal ("Dim.Absolute(1)", v2.Height.ToString ()); + Assert.Equal ("Dim.Combine(Dim.Fill(margin=0)-Dim.Absolute(2))", v2.Height.ToString ()); Assert.Equal (97, v2.Frame.Width); // 99-2=97 - Assert.Equal (1, v2.Frame.Height); // 1 because is Dim.DimAbsolute + Assert.Equal (189, v2.Frame.Height); // 198-2-7=189 v3.Text = "Button3"; Assert.Equal ("Dim.Factor(factor=0.1, remaining=False)", v3.Width.ToString ()); - Assert.Equal ("Dim.Absolute(1)", v3.Height.ToString ()); + Assert.Equal ("Dim.Factor(factor=0.1, remaining=False)", v3.Height.ToString ()); Assert.Equal (19, v3.Frame.Width); // 198*10%=19 * Percent is related to the super-view if it isn't null otherwise the view width - Assert.Equal (1, v3.Frame.Height); // 1 because is Dim.DimAbsolute + Assert.Equal (19, v3.Frame.Height); // 199*10%=19 v4.Text = "Button4"; v4.AutoSize = false; Assert.Equal ("Dim.Absolute(50)", v4.Width.ToString ()); - Assert.Equal ("Dim.Absolute(1)", v4.Height.ToString ()); + Assert.Equal ("Dim.Absolute(50)", v4.Height.ToString ()); + Assert.Equal (50, v4.Frame.Width); + Assert.Equal (50, v4.Frame.Height); v4.AutoSize = true; Assert.Equal ("Dim.Absolute(11)", v4.Width.ToString ()); Assert.Equal ("Dim.Absolute(1)", v4.Height.ToString ()); @@ -498,16 +519,16 @@ namespace Terminal.Gui.Core { Assert.Equal (1, v4.Frame.Height); // 1 because is Dim.DimAbsolute v5.Text = "Button5"; - Assert.Equal ("Dim.Combine(DimView(side=Width, target=Button()({X=2,Y=7,Width=97,Height=1}))-DimView(side=Width, target=Button()({X=0,Y=0,Width=19,Height=1})))", v5.Width.ToString ()); - Assert.Equal ("Dim.Absolute(1)", v5.Height.ToString ()); + Assert.Equal ("Dim.Combine(DimView(side=Width, target=Button()({X=2,Y=7,Width=97,Height=189}))-DimView(side=Width, target=Button()({X=0,Y=0,Width=19,Height=19})))", v5.Width.ToString ()); + Assert.Equal ("Dim.Combine(DimView(side=Height, target=Button()({X=2,Y=7,Width=97,Height=189}))-DimView(side=Height, target=Button()({X=0,Y=0,Width=19,Height=19})))", v5.Height.ToString ()); Assert.Equal (78, v5.Frame.Width); // 97-19=78 - Assert.Equal (1, v5.Frame.Height); // 1 because is Dim.DimAbsolute + Assert.Equal (170, v5.Frame.Height); // 189-19=170 v6.Text = "Button6"; Assert.Equal ("Dim.Factor(factor=0.2, remaining=True)", v6.Width.ToString ()); - Assert.Equal ("Dim.Absolute(1)", v6.Height.ToString ()); + Assert.Equal ("Dim.Factor(factor=0.2, remaining=True)", v6.Height.ToString ()); Assert.Equal (19, v6.Frame.Width); // 99*20%=19 - Assert.Equal (1, v6.Frame.Height); // 1 because is Dim.DimAbsolute + Assert.Equal (38, v6.Frame.Height); // 198-7*20=38 }; Application.Iteration += () => Application.RequestStop (); @@ -649,56 +670,63 @@ namespace Terminal.Gui.Core { private string [] expecteds = new string [21] { @" ┌────────────────────┐ -│View │ +│View with long text │ +│ │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ +│Label 0 │ │Label 0 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ +│Label 1 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ +│Label 2 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ │Label 3 │ +│Label 3 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ │Label 3 │ │Label 4 │ +│Label 4 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ │Label 3 │ │Label 4 │ │Label 5 │ +│Label 5 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -706,10 +734,11 @@ namespace Terminal.Gui.Core { │Label 4 │ │Label 5 │ │Label 6 │ +│Label 6 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -718,10 +747,11 @@ namespace Terminal.Gui.Core { │Label 5 │ │Label 6 │ │Label 7 │ +│Label 7 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -731,10 +761,11 @@ namespace Terminal.Gui.Core { │Label 6 │ │Label 7 │ │Label 8 │ +│Label 8 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -745,10 +776,11 @@ namespace Terminal.Gui.Core { │Label 7 │ │Label 8 │ │Label 9 │ +│Label 9 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -760,10 +792,11 @@ namespace Terminal.Gui.Core { │Label 8 │ │Label 9 │ │Label 10 │ +│Label 10 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -776,10 +809,11 @@ namespace Terminal.Gui.Core { │Label 9 │ │Label 10 │ │Label 11 │ +│Label 11 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -793,10 +827,11 @@ namespace Terminal.Gui.Core { │Label 10 │ │Label 11 │ │Label 12 │ +│Label 12 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -811,10 +846,11 @@ namespace Terminal.Gui.Core { │Label 11 │ │Label 12 │ │Label 13 │ +│Label 13 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -830,10 +866,11 @@ namespace Terminal.Gui.Core { │Label 12 │ │Label 13 │ │Label 14 │ +│Label 14 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -850,10 +887,11 @@ namespace Terminal.Gui.Core { │Label 13 │ │Label 14 │ │Label 15 │ +│Label 15 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -871,10 +909,11 @@ namespace Terminal.Gui.Core { │Label 14 │ │Label 15 │ │Label 16 │ +│Label 16 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -893,10 +932,11 @@ namespace Terminal.Gui.Core { │Label 15 │ │Label 16 │ │Label 17 │ +│Label 17 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -916,10 +956,11 @@ namespace Terminal.Gui.Core { │Label 16 │ │Label 17 │ │Label 18 │ +│Label 18 │ └────────────────────┘", @" ┌────────────────────┐ -│View │ +│View with long text │ │Label 0 │ │Label 1 │ │Label 2 │ @@ -940,7 +981,8 @@ namespace Terminal.Gui.Core { │Label 17 │ │Label 18 │ │Label 19 │ -└────────────────────┘" +│Label 19 │ +└────────────────────┘", }; [Fact] @@ -951,26 +993,32 @@ namespace Terminal.Gui.Core { var top = Application.Top; - var view = new View ("View") { X = 0, Y = 0, Width = 20, Height = 0 }; + // Although view height is zero the text it's draw due the SetMinWidthHeight method + var view = new View ("View with long text") { X = 0, Y = 0, Width = 20, Height = 0 }; var field = new TextField () { X = 0, Y = Pos.Bottom (view), Width = 20 }; var count = 0; var listLabels = new List