From 7a15f7b39b80a92c65cb75ac8bfced4e26ee7106 Mon Sep 17 00:00:00 2001 From: Tig Date: Mon, 25 Nov 2024 10:12:01 -0700 Subject: [PATCH] Backported a bunch of fixes from #3691 --- .../Application/Application.Driver.cs | 2 + .../Application/Application.Keyboard.cs | 5 + Terminal.Gui/Drawing/Glyphs.cs | 5 + Terminal.Gui/Input/KeyBindings.cs | 54 +- Terminal.Gui/Resources/config.json | 171 +++++- Terminal.Gui/View/Layout/DimAuto.cs | 2 +- Terminal.Gui/View/View.Drawing.cs | 10 +- Terminal.Gui/View/View.Hierarchy.cs | 61 ++ Terminal.Gui/View/View.Keyboard.cs | 2 +- Terminal.Gui/View/View.Navigation.cs | 3 +- Terminal.Gui/Views/Bar.cs | 28 +- Terminal.Gui/Views/Line.cs | 51 +- Terminal.Gui/Views/Shortcut.cs | 29 +- UICatalog/Scenarios/KeyBindings.cs | 6 +- UICatalog/Scenarios/Shortcuts.cs | 82 +-- UnitTests/Application/KeyboardTests.cs | 9 +- .../Application/SynchronizatonContextTests.cs | 4 +- UnitTests/Dialogs/DialogTests.cs | 547 ++++++++---------- UnitTests/Input/KeyBindingTests.cs | 58 +- UnitTests/View/Draw/AllViewsDrawTests.cs | 13 +- UnitTests/View/SubviewTests.cs | 108 ++++ UnitTests/Views/DateFieldTests.cs | 2 +- UnitTests/Views/ToplevelTests.cs | 6 +- UnitTests/Views/ViewDisposalTest.cs | 5 +- 24 files changed, 795 insertions(+), 468 deletions(-) diff --git a/Terminal.Gui/Application/Application.Driver.cs b/Terminal.Gui/Application/Application.Driver.cs index c2f6431db..cdfd51ec5 100644 --- a/Terminal.Gui/Application/Application.Driver.cs +++ b/Terminal.Gui/Application/Application.Driver.cs @@ -8,6 +8,7 @@ public static partial class Application // Driver abstractions /// Gets the that has been selected. See also . public static ConsoleDriver? Driver { get; internal set; } + // BUGBUG: Force16Colors should be nullable. /// /// Gets or sets whether will be forced to output only the 16 colors defined in /// . The default is , meaning 24-bit (TrueColor) colors will be output @@ -16,6 +17,7 @@ public static partial class Application // Driver abstractions [SerializableConfigurationProperty (Scope = typeof (SettingsScope))] public static bool Force16Colors { get; set; } + // BUGBUG: ForceDriver should be nullable. /// /// Forces the use of the specified driver (one of "fake", "ansi", "curses", "net", or "windows"). If not /// specified, the driver is selected based on the platform. diff --git a/Terminal.Gui/Application/Application.Keyboard.cs b/Terminal.Gui/Application/Application.Keyboard.cs index 18881d6c5..97b566166 100644 --- a/Terminal.Gui/Application/Application.Keyboard.cs +++ b/Terminal.Gui/Application/Application.Keyboard.cs @@ -49,6 +49,11 @@ public static partial class Application // Keyboard handling { if (binding.Value.BoundView is { }) { + if (!binding.Value.BoundView.Enabled) + { + return false; + } + bool? handled = binding.Value.BoundView?.InvokeCommands (binding.Value.Commands, binding.Key, binding.Value); if (handled != null && (bool)handled) diff --git a/Terminal.Gui/Drawing/Glyphs.cs b/Terminal.Gui/Drawing/Glyphs.cs index c3b72711f..f3a0334bf 100644 --- a/Terminal.Gui/Drawing/Glyphs.cs +++ b/Terminal.Gui/Drawing/Glyphs.cs @@ -20,6 +20,11 @@ /// public class GlyphDefinitions { + // IMPORTANT: If you change these, make sure to update the ./Resources/config.json file as + // IMPORTANT: it is the source of truth for the default glyphs at runtime. + // IMPORTANT: Configuration Manager test SaveDefaults uses this class to generate the default config file + // IMPORTANT: in ./UnitTests/bin/Debug/netX.0/config.json + /// File icon. Defaults to ☰ (Trigram For Heaven) public Rune File { get; set; } = (Rune)'☰'; diff --git a/Terminal.Gui/Input/KeyBindings.cs b/Terminal.Gui/Input/KeyBindings.cs index 59a97bfd6..71777d804 100644 --- a/Terminal.Gui/Input/KeyBindings.cs +++ b/Terminal.Gui/Input/KeyBindings.cs @@ -1,5 +1,7 @@ #nullable enable +using static System.Formats.Asn1.AsnWriter; + namespace Terminal.Gui; /// @@ -17,7 +19,7 @@ public class KeyBindings public KeyBindings () { } /// Initializes a new instance bound to . - public KeyBindings (View boundView) { BoundView = boundView; } + public KeyBindings (View? boundView) { BoundView = boundView; } /// Adds a to the collection. /// @@ -27,7 +29,12 @@ public class KeyBindings { if (BoundView is { } && binding.Scope.FastHasFlags (KeyBindingScope.Application)) { - throw new ArgumentException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add"); + throw new InvalidOperationException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add"); + } + + if (BoundView is { } && boundViewForAppScope is null) + { + boundViewForAppScope = BoundView; } if (TryGet (key, out KeyBinding _)) @@ -78,6 +85,10 @@ public class KeyBindings { throw new ArgumentException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add"); } + else + { + // boundViewForAppScope = BoundView; + } if (key is null || !key.IsValid) { @@ -93,11 +104,9 @@ public class KeyBindings if (TryGet (key, out KeyBinding binding)) { throw new InvalidOperationException (@$"A key binding for {key} exists ({binding})."); - - //Bindings [key] = new (commands, scope, BoundView); } - Add (key, new KeyBinding (commands, scope, BoundView), boundViewForAppScope); + Add (key, new KeyBinding (commands, scope, boundViewForAppScope), boundViewForAppScope); } /// @@ -120,9 +129,14 @@ public class KeyBindings /// public void Add (Key key, KeyBindingScope scope, params Command [] commands) { + if (BoundView is null && !scope.FastHasFlags (KeyBindingScope.Application)) + { + throw new InvalidOperationException ("BoundView cannot be null."); + } + if (BoundView is { } && scope.FastHasFlags (KeyBindingScope.Application)) { - throw new ArgumentException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add"); + throw new InvalidOperationException ("Application scoped KeyBindings must be added via Application.KeyBindings.Add"); } if (key == Key.Empty || !key.IsValid) @@ -140,7 +154,7 @@ public class KeyBindings throw new InvalidOperationException (@$"A key binding for {key} exists ({binding})."); } - Add (key, new KeyBinding (commands, scope, BoundView)); + Add (key, new KeyBinding (commands, scope, BoundView), BoundView); } /// @@ -219,14 +233,22 @@ public class KeyBindings /// The collection of objects. public Dictionary Bindings { get; } = new (new KeyEqualityComparer ()); + /// + /// Gets the keys that are bound. + /// + /// + public IEnumerable GetBoundKeys () + { + return Bindings.Keys; + } + /// /// The view that the are bound to. /// /// - /// If , the are not bound to a . This is used for - /// Application.KeyBindings. + /// If the KeyBindings object is being used for Application.KeyBindings. /// - public View? BoundView { get; } + internal View? BoundView { get; } /// Removes all objects from the collection. public void Clear () { Bindings.Clear (); } @@ -312,7 +334,7 @@ public class KeyBindings /// Optional View for bindings. public void Remove (Key key, View? boundViewForAppScope = null) { - if (!TryGet (key, out KeyBinding binding)) + if (!TryGet (key, out KeyBinding _)) { return; } @@ -371,6 +393,11 @@ public class KeyBindings /// if the Key is bound; otherwise . public bool TryGet (Key key, out KeyBinding binding) { + //if (BoundView is null) + //{ + // throw new InvalidOperationException ("KeyBindings must be bound to a View to use this method."); + //} + binding = new (Array.Empty (), KeyBindingScope.Disabled, null); if (key.IsValid) @@ -394,6 +421,11 @@ public class KeyBindings { if (!key.IsValid) { + //if (BoundView is null) + //{ + // throw new InvalidOperationException ("KeyBindings must be bound to a View to use this method."); + //} + binding = new (Array.Empty (), KeyBindingScope.Disabled, null); return false; } diff --git a/Terminal.Gui/Resources/config.json b/Terminal.Gui/Resources/config.json index 07ba33650..ca6ab6a84 100644 --- a/Terminal.Gui/Resources/config.json +++ b/Terminal.Gui/Resources/config.json @@ -16,14 +16,173 @@ // to throw exceptions. "ConfigurationManager.ThrowOnJsonErrors": false, - "Application.NextTabKey": "Tab", - "Application.PrevTabKey": "Shift+Tab", - "Application.NextTabGroupKey": "F6", - "Application.PrevTabGroupKey": "Shift+F6", - "Application.QuitKey": "Esc", - "Application.ArrangeKey": "Ctrl+F5", + // --------------- Application Settings --------------- "Key.Separator": "+", + "Application.ArrangeKey": "Ctrl+F5", + "Application.Force16Colors": false, + //"Application.ForceDriver": "", // TODO: ForceDriver should be nullable + "Application.IsMouseDisabled": false, + "Application.NextTabGroupKey": "F6", + "Application.NextTabKey": "Tab", + "Application.PrevTabGroupKey": "Shift+F6", + "Application.PrevTabKey": "Shift+Tab", + "Application.QuitKey": "Esc", + + // --------------- Colors --------------- + + + // --------------- View Specific Settings --------------- + "ContextMenu.DefaultKey": "Shift+F10", + "FileDialog.MaxSearchResults": 10000, + "FileDialogStyle.DefaultUseColors": false, + "FileDialogStyle.DefaultUseUnicodeCharacters": false, + + // --------------- Glyphs --------------- + "Glyphs": { + "File": "☰", + "Folder": "꤉", + "HorizontalEllipsis": "…", + "VerticalFourDots": "⁞", + "CheckStateChecked": "☑", + "CheckStateUnChecked": "☐", + "CheckStateNone": "☒", + "Selected": "◉", + "UnSelected": "○", + "RightArrow": "►", + "LeftArrow": "◄", + "DownArrow": "▼", + "UpArrow": "▲", + "LeftDefaultIndicator": "►", + "RightDefaultIndicator": "◄", + "LeftBracket": "⟦", + "RightBracket": "⟧", + "BlocksMeterSegment": "▌", + "ContinuousMeterSegment": "█", + "Stipple": "░", + "Diamond": "◊", + "Close": "✘", + "Minimize": "❏", + "Maximize": "✽", + "Dot": "∙", + "BlackCircle": "●", + "Expand": "+", + "Collapse": "-", + "IdenticalTo": "≡", + "Move": "◊", + "SizeHorizontal": "↔", + "SizeVertical": "↕", + "SizeTopLeft": "↖", + "SizeTopRight": "↗", + "SizeBottomRight": "↘", + "SizeBottomLeft": "↙", + "Apple": "\uD83C\uDF4E", + "AppleBMP": "❦", + "HLine": "─", + "VLine": "│", + "HLineDbl": "═", + "VLineDbl": "║", + "HLineHvDa2": "╍", + "VLineHvDa3": "┇", + "HLineHvDa3": "┅", + "HLineHvDa4": "┉", + "VLineHvDa2": "╏", + "VLineHvDa4": "┋", + "HLineDa2": "╌", + "VLineDa3": "┆", + "HLineDa3": "┄", + "HLineDa4": "┈", + "VLineDa2": "╎", + "VLineDa4": "┊", + "HLineHv": "━", + "VLineHv": "┃", + "HalfLeftLine": "╴", + "HalfTopLine": "╵", + "HalfRightLine": "╶", + "HalfBottomLine": "╷", + "HalfLeftLineHv": "╸", + "HalfTopLineHv": "╹", + "HalfRightLineHv": "╺", + "HalfBottomLineLt": "╻", + "RightSideLineLtHv": "╼", + "BottomSideLineLtHv": "╽", + "LeftSideLineHvLt": "╾", + "TopSideLineHvLt": "╿", + "ULCorner": "┌", + "ULCornerDbl": "╔", + "ULCornerR": "╭", + "ULCornerHv": "┏", + "ULCornerHvLt": "┎", + "ULCornerLtHv": "┍", + "ULCornerDblSingle": "╓", + "ULCornerSingleDbl": "╒", + "LLCorner": "└", + "LLCornerHv": "┗", + "LLCornerHvLt": "┖", + "LLCornerLtHv": "┕", + "LLCornerDbl": "╚", + "LLCornerSingleDbl": "╘", + "LLCornerDblSingle": "╙", + "LLCornerR": "╰", + "URCorner": "┐", + "URCornerDbl": "╗", + "URCornerR": "╮", + "URCornerHv": "┓", + "URCornerHvLt": "┑", + "URCornerLtHv": "┒", + "URCornerDblSingle": "╖", + "URCornerSingleDbl": "╕", + "LRCorner": "┘", + "LRCornerDbl": "╝", + "LRCornerR": "╯", + "LRCornerHv": "┛", + "LRCornerDblSingle": "╜", + "LRCornerSingleDbl": "╛", + "LRCornerLtHv": "┙", + "LRCornerHvLt": "┚", + "LeftTee": "├", + "LeftTeeDblH": "╞", + "LeftTeeDblV": "╟", + "LeftTeeDbl": "╠", + "LeftTeeHvH": "┝", + "LeftTeeHvV": "┠", + "LeftTeeHvDblH": "┣", + "RightTee": "┤", + "RightTeeDblH": "╡", + "RightTeeDblV": "╢", + "RightTeeDbl": "╣", + "RightTeeHvH": "┥", + "RightTeeHvV": "┨", + "RightTeeHvDblH": "┫", + "TopTee": "┬", + "TopTeeDblH": "╤", + "TopTeeDblV": "╥", + "TopTeeDbl": "╦", + "TopTeeHvH": "┯", + "TopTeeHvV": "┰", + "TopTeeHvDblH": "┳", + "BottomTee": "┴", + "BottomTeeDblH": "╧", + "BottomTeeDblV": "╨", + "BottomTeeDbl": "╩", + "BottomTeeHvH": "┷", + "BottomTeeHvV": "┸", + "BottomTeeHvDblH": "┻", + "Cross": "┼", + "CrossDblH": "╪", + "CrossDblV": "╫", + "CrossDbl": "╬", + "CrossHvH": "┿", + "CrossHvV": "╂", + "CrossHv": "╋", + "ShadowVerticalStart": "▖", + "ShadowVertical": "▌", + "ShadowHorizontalStart": "▝", + "ShadowHorizontal": "▀", + "ShadowHorizontalEnd": "▘" + }, + + // --------------- Themes ----------------- "Theme": "Default", "Themes": [ { diff --git a/Terminal.Gui/View/Layout/DimAuto.cs b/Terminal.Gui/View/Layout/DimAuto.cs index 2d7f04479..8f5716b1e 100644 --- a/Terminal.Gui/View/Layout/DimAuto.cs +++ b/Terminal.Gui/View/Layout/DimAuto.cs @@ -35,7 +35,7 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt int screenX4 = dimension == Dimension.Width ? Application.Screen.Width * 4 : Application.Screen.Height * 4; int autoMax = MaximumContentDim?.GetAnchor (superviewContentSize) ?? screenX4; - Debug.Assert (autoMin <= autoMax, "MinimumContentDim must be less than or equal to MaximumContentDim."); + Debug.WriteLineIf (autoMin > autoMax, "MinimumContentDim must be less than or equal to MaximumContentDim."); if (Style.FastHasFlags (DimAutoStyle.Text)) { diff --git a/Terminal.Gui/View/View.Drawing.cs b/Terminal.Gui/View/View.Drawing.cs index 79ab737f7..f571893a2 100644 --- a/Terminal.Gui/View/View.Drawing.cs +++ b/Terminal.Gui/View/View.Drawing.cs @@ -55,6 +55,7 @@ public partial class View // Drawing APIs // Draw the Border and Padding. // We clip to the frame to prevent drawing outside the frame. saved = ClipFrame (); + DoDrawBorderAndPadding (); SetClip (saved); @@ -71,7 +72,7 @@ public partial class View // Drawing APIs DoSetAttribute (); DoClearViewport (); - // Draw the subviews + // Draw the subviews only if needed if (SubViewNeedsDraw) { DoSetAttribute (); @@ -166,6 +167,13 @@ public partial class View // Drawing APIs private void DoDrawBorderAndPadding () { + if (SubViewNeedsDraw) + { + // A Subview may add to the LineCanvas. This ensures any Adornment LineCanvas updates happen. + Border?.SetNeedsDraw (); + Padding?.SetNeedsDraw (); + } + if (OnDrawingBorderAndPadding ()) { return; diff --git a/Terminal.Gui/View/View.Hierarchy.cs b/Terminal.Gui/View/View.Hierarchy.cs index 4f9b089a1..5a0705ada 100644 --- a/Terminal.Gui/View/View.Hierarchy.cs +++ b/Terminal.Gui/View/View.Hierarchy.cs @@ -256,6 +256,67 @@ public partial class View // SuperView/SubView hierarchy management (SuperView, return top; } + /// + /// Gets whether is in the Subview hierarchy of . + /// + /// The View at the start of the hierarchy. + /// The View to test. + /// Will search the subview hierarchy of the adornments if true. + /// + public static bool IsInHierarchy (View? start, View? view, bool includeAdornments = false) + { + if (view is null || start is null) + { + return false; + } + + if (view == start) + { + return true; + } + + foreach (View subView in start.Subviews) + { + if (view == subView) + { + return true; + } + + bool found = IsInHierarchy (subView, view, includeAdornments); + + if (found) + { + return found; + } + } + + if (includeAdornments) + { + bool found = IsInHierarchy (start.Padding, view, includeAdornments); + + if (found) + { + return found; + } + + found = IsInHierarchy (start.Border, view, includeAdornments); + + if (found) + { + return found; + } + + found = IsInHierarchy (start.Margin, view, includeAdornments); + + if (found) + { + return found; + } + } + + return false; + } + #region SubViewOrdering /// diff --git a/Terminal.Gui/View/View.Keyboard.cs b/Terminal.Gui/View/View.Keyboard.cs index 87c5a1ce6..642c34635 100644 --- a/Terminal.Gui/View/View.Keyboard.cs +++ b/Terminal.Gui/View/View.Keyboard.cs @@ -690,7 +690,7 @@ public partial class View // Keyboard APIs #if DEBUG - if (Application.KeyBindings.TryGet (key, KeyBindingScope.Focused | KeyBindingScope.HotKey, out KeyBinding b)) + if (Application.KeyBindings.TryGet (key, out KeyBinding b)) { Debug.WriteLine ( $"WARNING: InvokeKeyBindings ({key}) - An Application scope binding exists for this key. The registered view will not invoke Command."); diff --git a/Terminal.Gui/View/View.Navigation.cs b/Terminal.Gui/View/View.Navigation.cs index cbd2963c4..6799edb9d 100644 --- a/Terminal.Gui/View/View.Navigation.cs +++ b/Terminal.Gui/View/View.Navigation.cs @@ -357,6 +357,7 @@ public partial class View // Focus and cross-view navigation management (TabStop /// internal bool RestoreFocus () { + // Ignore TabStop View [] indicies = GetFocusChain (NavigationDirection.Forward, null); if (Focused is null && _previouslyFocused is { } && indicies.Contains (_previouslyFocused)) @@ -495,7 +496,7 @@ public partial class View // Focus and cross-view navigation management (TabStop /// private (bool focusSet, bool cancelled) SetHasFocusTrue (View? currentFocusedView, bool traversingUp = false) { - Debug.Assert (SuperView is null || ApplicationNavigation.IsInHierarchy (SuperView, this)); + Debug.Assert (SuperView is null || View.IsInHierarchy (SuperView, this)); // Pre-conditions if (_hasFocus) diff --git a/Terminal.Gui/Views/Bar.cs b/Terminal.Gui/Views/Bar.cs index bece84078..05bcc1101 100644 --- a/Terminal.Gui/Views/Bar.cs +++ b/Terminal.Gui/Views/Bar.cs @@ -20,7 +20,7 @@ public class Bar : View, IOrientation, IDesignable public Bar () : this ([]) { } /// - public Bar (IEnumerable shortcuts) + public Bar (IEnumerable? shortcuts) { CanFocus = true; @@ -28,20 +28,16 @@ public class Bar : View, IOrientation, IDesignable Height = Dim.Auto (); _orientationHelper = new (this); - _orientationHelper.OrientationChanging += (sender, e) => OrientationChanging?.Invoke (this, e); - _orientationHelper.OrientationChanged += (sender, e) => OrientationChanged?.Invoke (this, e); // Initialized += Bar_Initialized; MouseEvent += OnMouseEvent; - if (shortcuts is null) + if (shortcuts is { }) { - return; - } - - foreach (Shortcut shortcut in shortcuts) - { - Add (shortcut); + foreach (Shortcut shortcut in shortcuts) + { + Add (shortcut); + } } } @@ -243,7 +239,6 @@ public class Bar : View, IOrientation, IDesignable { View barItem = Subviews [index]; - barItem.X = 0; barItem.ColorScheme = ColorScheme; @@ -254,6 +249,7 @@ public class Bar : View, IOrientation, IDesignable if (barItem is Shortcut scBarItem) { + barItem.X = 0; scBarItem.MinimumKeyTextSize = minKeyWidth; scBarItem.Width = scBarItem.GetWidthDimAuto (); barItem.Layout (Application.Screen.Size); @@ -278,14 +274,20 @@ public class Bar : View, IOrientation, IDesignable foreach (var subView in Subviews) { - subView.Width = Dim.Auto (DimAutoStyle.Auto, minimumContentDim: _maxBarItemWidth); + if (subView is not Line) + { + subView.Width = Dim.Auto (DimAutoStyle.Auto, minimumContentDim: _maxBarItemWidth); + } } } else { foreach (var subView in Subviews) { - subView.Width = Dim.Fill(); + if (subView is not Line) + { + subView.Width = Dim.Fill (); + } } } diff --git a/Terminal.Gui/Views/Line.cs b/Terminal.Gui/Views/Line.cs index 82b7499e1..9d2889373 100644 --- a/Terminal.Gui/Views/Line.cs +++ b/Terminal.Gui/Views/Line.cs @@ -1,6 +1,10 @@ namespace Terminal.Gui; -/// Draws a single line using the specified by . +/// +/// Draws a single line using the specified by . +/// +/// +/// public class Line : View, IOrientation { private readonly OrientationHelper _orientationHelper; @@ -8,14 +12,13 @@ public class Line : View, IOrientation /// Constructs a Line object. public Line () { - BorderStyle = LineStyle.Single; - Border.Thickness = new Thickness (0); - SuperViewRendersLineCanvas = true; + CanFocus = false; + + base.SuperViewRendersLineCanvas = true; _orientationHelper = new (this); _orientationHelper.Orientation = Orientation.Horizontal; - _orientationHelper.OrientationChanging += (sender, e) => OrientationChanging?.Invoke (this, e); - _orientationHelper.OrientationChanged += (sender, e) => OrientationChanged?.Invoke (this, e); + OnOrientationChanged(Orientation); } @@ -45,10 +48,12 @@ public class Line : View, IOrientation { case Orientation.Horizontal: Height = 1; + Width = Dim.Fill (); break; case Orientation.Vertical: Width = 1; + Height = Dim.Fill (); break; @@ -56,48 +61,20 @@ public class Line : View, IOrientation } #endregion - /// - public override void SetBorderStyle (LineStyle value) - { - // The default changes the thickness. We don't want that. We just set the style. - Border.LineStyle = value; - } - /// protected override bool OnDrawingContent () { - LineCanvas lc = LineCanvas; - - if (SuperViewRendersLineCanvas) - { - lc = SuperView?.LineCanvas; - } - - if (SuperView is Adornment adornment) - { - lc = adornment.Parent?.LineCanvas; - } - Point pos = ViewportToScreen (Viewport).Location; int length = Orientation == Orientation.Horizontal ? Frame.Width : Frame.Height; - if (SuperView is {} && SuperViewRendersLineCanvas && Orientation == Orientation.Horizontal) - { - pos.Offset (-SuperView.Border.Thickness.Left, 0); - length += SuperView.Border.Thickness.Horizontal; - } - - if (SuperView is { } && SuperViewRendersLineCanvas && Orientation == Orientation.Vertical) - { - pos.Offset (0, -SuperView.Border.Thickness.Top); - length += SuperView.Border.Thickness.Vertical; - } - lc?.AddLine ( + LineCanvas?.AddLine ( pos, length, Orientation, BorderStyle ); + + //SuperView?.SetNeedsDraw (); return true; } } diff --git a/Terminal.Gui/Views/Shortcut.cs b/Terminal.Gui/Views/Shortcut.cs index 175f8f569..f10bb423b 100644 --- a/Terminal.Gui/Views/Shortcut.cs +++ b/Terminal.Gui/Views/Shortcut.cs @@ -67,7 +67,7 @@ public class Shortcut : View, IOrientation, IDesignable /// /// The text to display for the command. /// The help text to display. - public Shortcut (View targetView, Command command, string commandText, string helpText) + public Shortcut (View targetView, Command command, string commandText, string? helpText = null) : this ( targetView?.KeyBindings.GetKeyFromCommands (command)!, commandText, @@ -75,7 +75,7 @@ public class Shortcut : View, IOrientation, IDesignable helpText) { _targetView = targetView; - _command = command; + Command = command; } /// @@ -92,7 +92,7 @@ public class Shortcut : View, IOrientation, IDesignable /// The help text to display. public Shortcut (Key key, string? commandText, Action? action, string? helpText = null) { - Id = "_shortcut"; + Id = $"shortcut:{commandText}"; HighlightStyle = HighlightStyle.None; CanFocus = true; @@ -280,7 +280,15 @@ public class Shortcut : View, IOrientation, IDesignable private readonly View? _targetView; // If set, _command will be invoked - private readonly Command _command; // Used when _targetView is set + /// + /// Gets the target that the will be invoked on. + /// + public View? TargetView => _targetView; + + /// + /// Gets the that will be invoked on when the Shortcut is activated. + /// + public Command Command { get; } private void AddCommands () { @@ -319,6 +327,11 @@ public class Shortcut : View, IOrientation, IDesignable return true; } + if (ctx.Command != Command.Accept) + { + // return false; + } + if (Action is { }) { Action.Invoke (); @@ -329,7 +342,7 @@ public class Shortcut : View, IOrientation, IDesignable if (_targetView is { }) { - _targetView.InvokeCommand (_command); + _targetView.InvokeCommand (Command); } return cancel; @@ -616,7 +629,7 @@ public class Shortcut : View, IOrientation, IDesignable if (_keyBindingScope == KeyBindingScope.Application) { - Application.KeyBindings.Remove (Key); + Application.KeyBindings.Remove (Key, this); } if (_keyBindingScope is KeyBindingScope.HotKey or KeyBindingScope.Focused) @@ -691,10 +704,10 @@ public class Shortcut : View, IOrientation, IDesignable { if (oldKey != Key.Empty) { - Application.KeyBindings.Remove (oldKey); + Application.KeyBindings.Remove (oldKey, this); } - Application.KeyBindings.Remove (Key); + Application.KeyBindings.Remove (Key, this); Application.KeyBindings.Add (Key, this, Command.HotKey); } else diff --git a/UICatalog/Scenarios/KeyBindings.cs b/UICatalog/Scenarios/KeyBindings.cs index afb69ec4e..2b5de89ac 100644 --- a/UICatalog/Scenarios/KeyBindings.cs +++ b/UICatalog/Scenarios/KeyBindings.cs @@ -80,10 +80,10 @@ public sealed class KeyBindings : Scenario }; appWindow.Add (appBindingsListView); - foreach (var appBinding in Application.KeyBindings.Bindings) + foreach (var key in Application.KeyBindings.GetBoundKeys()) { - var commands = Application.KeyBindings.GetCommands (appBinding.Key); - appBindings.Add ($"{appBinding.Key} -> {appBinding.Value.BoundView?.GetType ().Name} - {commands [0]}"); + var binding = Application.KeyBindings.Get (key); + appBindings.Add ($"{key} -> {binding.BoundView?.GetType ().Name} - {binding.Commands [0]}"); } ObservableCollection hotkeyBindings = new (); diff --git a/UICatalog/Scenarios/Shortcuts.cs b/UICatalog/Scenarios/Shortcuts.cs index e1d1f171b..5390e015d 100644 --- a/UICatalog/Scenarios/Shortcuts.cs +++ b/UICatalog/Scenarios/Shortcuts.cs @@ -1,11 +1,9 @@ +#nullable enable + using System; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Diagnostics; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Timers; using Terminal.Gui; @@ -29,10 +27,10 @@ public class Shortcuts : Scenario // Setting everything up in Loaded handler because we change the // QuitKey and it only sticks if changed after init - private void App_Loaded (object sender, EventArgs e) + private void App_Loaded (object? sender, EventArgs e) { Application.QuitKey = Key.F4.WithCtrl; - Application.Top.Title = GetQuitKeyAndName (); + Application.Top!.Title = GetQuitKeyAndName (); ObservableCollection eventSource = new (); @@ -47,7 +45,8 @@ public class Shortcuts : Scenario BorderStyle = LineStyle.Double, Title = "E_vents" }; - eventLog.Width = Dim.Func (() => Math.Min (eventLog.SuperView!.Viewport.Width / 2, eventLog?.MaxLength + eventLog.GetAdornmentsThickness ().Horizontal ?? 0)); + eventLog.Width = Dim.Func (() => Math.Min (Application.Top.Viewport.Width / 2, eventLog?.MaxLength + eventLog!.GetAdornmentsThickness ().Horizontal ?? 0)); + eventLog.Width = Dim.Func (() => Math.Min (eventLog.SuperView!.Viewport.Width / 2, eventLog?.MaxLength + eventLog!.GetAdornmentsThickness ().Horizontal ?? 0)); Application.Top.Add (eventLog); var alignKeysShortcut = new Shortcut @@ -55,7 +54,7 @@ public class Shortcuts : Scenario Id = "alignKeysShortcut", X = 0, Y = 0, - Width = Dim.Fill () - Dim.Width (eventLog), + Width = Dim.Fill ()! - Dim.Width (eventLog), HelpText = "Fill to log", CommandView = new CheckBox { @@ -67,6 +66,7 @@ public class Shortcuts : Scenario KeyBindingScope = KeyBindingScope.HotKey, }; + // ((CheckBox)vShortcut3.CommandView).CheckedStateChanging += (_, args) => ((CheckBox)alignKeysShortcut.CommandView).CheckedStateChanging += (s, e) => { if (alignKeysShortcut.CommandView is CheckBox cb) @@ -80,6 +80,7 @@ public class Shortcuts : Scenario if (e.NewValue == CheckState.Checked) { + max = (from Shortcut? peer in enumerable select peer.Key.ToString ().GetColumns ()).Prepend (max).Max (); foreach (var view in enumerable) { var peer = (Shortcut)view; @@ -87,7 +88,7 @@ public class Shortcuts : Scenario } } - foreach (var view in enumerable) + foreach (View view in enumerable) { var peer = (Shortcut)view; peer.MinimumKeyTextSize = max; @@ -101,7 +102,7 @@ public class Shortcuts : Scenario Id = "commandFirstShortcut", X = 0, Y = Pos.Bottom (alignKeysShortcut), - Width = Dim.Fill () - Dim.Width (eventLog), + Width = Dim.Fill ()! - Dim.Width (eventLog), HelpText = "Show Command first", CommandView = new CheckBox { @@ -122,7 +123,6 @@ public class Shortcuts : Scenario eventSource.Add ($"{commandFirstShortcut.Id}.CommandView.CheckedStateChanging: {cb.Text}"); eventLog.MoveDown (); - var max = 0; IEnumerable toAlign = Application.Top.Subviews.Where (v => v is Shortcut { Width: not DimAbsolute }); IEnumerable enumerable = toAlign as View [] ?? toAlign.ToArray (); @@ -148,7 +148,7 @@ public class Shortcuts : Scenario Id = "canFocusShortcut", X = 0, Y = Pos.Bottom (commandFirstShortcut), - Width = Dim.Fill () - Dim.Width (eventLog), + Width = Dim.Fill ()! - Dim.Width (eventLog), Key = Key.F4, HelpText = "Changes all Command.CanFocus", KeyBindingScope = KeyBindingScope.HotKey, @@ -194,7 +194,7 @@ public class Shortcuts : Scenario Id = "buttonShortcut", X = 0, Y = Pos.Bottom (appShortcut), - Width = Dim.Fill () - Dim.Width (eventLog), + Width = Dim.Fill ()! - Dim.Width (eventLog), HelpText = "Accepting pops MB", CommandView = new Button { @@ -217,7 +217,7 @@ public class Shortcuts : Scenario X = 0, Y = Pos.Bottom (buttonShortcut), Key = Key.F2, - Width = Dim.Fill () - Dim.Width (eventLog), + Width = Dim.Fill ()! - Dim.Width (eventLog), KeyBindingScope = KeyBindingScope.HotKey, CommandView = new RadioGroup { @@ -228,8 +228,12 @@ public class Shortcuts : Scenario ((RadioGroup)radioGroupShortcut.CommandView).SelectedItemChanged += (o, args) => { - eventSource.Add ($"SelectedItemChanged: {o.GetType ().Name} - {args.SelectedItem}"); - eventLog.MoveDown (); + if (o is { }) + { + eventSource.Add ( + $"SelectedItemChanged: {o.GetType ().Name} - {args.SelectedItem}"); + eventLog.MoveDown (); + } }; Application.Top.Add (radioGroupShortcut); @@ -239,7 +243,7 @@ public class Shortcuts : Scenario Id = "sliderShortcut", X = 0, Y = Pos.Bottom (radioGroupShortcut), - Width = Dim.Fill () - Dim.Width (eventLog), + Width = Dim.Fill ()! - Dim.Width (eventLog), KeyBindingScope = KeyBindingScope.HotKey, HelpText = "Sliders work!", CommandView = new Slider @@ -250,12 +254,12 @@ public class Shortcuts : Scenario Key = Key.F5, }; - ((Slider)sliderShortcut.CommandView).Options = new () { new () { Legend = "A" }, new () { Legend = "B" }, new () { Legend = "C" } }; + ((Slider)sliderShortcut.CommandView).Options = [new () { Legend = "A" }, new () { Legend = "B" }, new () { Legend = "C" }]; ((Slider)sliderShortcut.CommandView).SetOption (0); ((Slider)sliderShortcut.CommandView).OptionsChanged += (o, args) => { - eventSource.Add ($"OptionsChanged: {o.GetType ().Name} - {string.Join (",", ((Slider)o).GetSetOptions ())}"); + eventSource.Add ($"OptionsChanged: {o?.GetType ().Name} - {string.Join (",", ((Slider)o!)!.GetSetOptions ())}"); eventLog.MoveDown (); }; @@ -314,11 +318,20 @@ public class Shortcuts : Scenario Arrangement = ViewArrangement.RightResizable | ViewArrangement.BottomResizable, }; framedShortcut.Orientation = Orientation.Horizontal; - framedShortcut.Padding.Thickness = new (0, 1, 0, 0); - framedShortcut.Padding.Diagnostics = ViewDiagnosticFlags.Ruler; - framedShortcut.CommandView.Margin.ColorScheme = framedShortcut.CommandView.ColorScheme = Colors.ColorSchemes ["Error"]; - framedShortcut.HelpView.Margin.ColorScheme = framedShortcut.HelpView.ColorScheme = Colors.ColorSchemes ["Dialog"]; - framedShortcut.KeyView.Margin.ColorScheme = framedShortcut.KeyView.ColorScheme = Colors.ColorSchemes ["Menu"]; + + if (framedShortcut.Padding is { }) + { + framedShortcut.Padding.Thickness = new (0, 1, 0, 0); + framedShortcut.Padding.Diagnostics = ViewDiagnosticFlags.Ruler; + } + + if (framedShortcut.CommandView.Margin is { }) + { + framedShortcut.CommandView.Margin.ColorScheme = framedShortcut.CommandView.ColorScheme = Colors.ColorSchemes ["Error"]; + framedShortcut.HelpView.Margin!.ColorScheme = framedShortcut.HelpView.ColorScheme = Colors.ColorSchemes ["Dialog"]; + framedShortcut.KeyView.Margin!.ColorScheme = framedShortcut.KeyView.ColorScheme = Colors.ColorSchemes ["Menu"]; + } + framedShortcut.ColorScheme = Colors.ColorSchemes ["Toplevel"]; Application.Top.Add (framedShortcut); @@ -423,13 +436,16 @@ public class Shortcuts : Scenario bgColor.ColorChanged += (o, args) => { - eventSource.Add ($"ColorChanged: {o.GetType ().Name} - {args.CurrentValue}"); - eventLog.MoveDown (); - - Application.Top.ColorScheme = new ColorScheme (Application.Top.ColorScheme) + if (o is { }) { - Normal = new Attribute (Application.Top.ColorScheme.Normal.Foreground, args.CurrentValue), - }; + eventSource.Add ($"ColorChanged: {o.GetType ().Name} - {args.CurrentValue}"); + eventLog.MoveDown (); + + Application.Top.ColorScheme = new ColorScheme (Application.Top.ColorScheme) + { + Normal = new (Application.Top!.GetNormalColor ().Foreground, args.CurrentValue), + }; + } }; bgColorShortcut.CommandView = bgColor; @@ -494,10 +510,10 @@ public class Shortcuts : Scenario } } - private void Button_Clicked (object sender, CommandEventArgs e) + private void Button_Clicked (object? sender, CommandEventArgs e) { e.Cancel = true; - View view = sender as View; - MessageBox.Query ("Hi", $"You clicked {view!.Text}", "_Ok"); + View? view = sender as View; + MessageBox.Query ("Hi", $"You clicked {view?.Text}", "_Ok"); } } diff --git a/UnitTests/Application/KeyboardTests.cs b/UnitTests/Application/KeyboardTests.cs index 4c33361e6..99ea9df29 100644 --- a/UnitTests/Application/KeyboardTests.cs +++ b/UnitTests/Application/KeyboardTests.cs @@ -159,16 +159,14 @@ public class KeyboardTests } [Fact] - [AutoInitShutdown] public void KeyBinding_OnKeyDown () { + Application.Top = new Toplevel (); var view = new ScopedKeyBindingView (); var keyWasHandled = false; view.KeyDownNotHandled += (s, e) => keyWasHandled = true; - var top = new Toplevel (); - top.Add (view); - Application.Begin (top); + Application.Top.Add (view); Application.RaiseKeyDownEvent (Key.A); Assert.False (keyWasHandled); @@ -200,7 +198,8 @@ public class KeyboardTests Assert.True (view.ApplicationCommand); Assert.True (view.HotKeyCommand); Assert.False (view.FocusedCommand); - top.Dispose (); + Application.Top.Dispose (); + Application.ResetState (true); } [Fact] diff --git a/UnitTests/Application/SynchronizatonContextTests.cs b/UnitTests/Application/SynchronizatonContextTests.cs index fce4a3250..ce099fd10 100644 --- a/UnitTests/Application/SynchronizatonContextTests.cs +++ b/UnitTests/Application/SynchronizatonContextTests.cs @@ -33,7 +33,7 @@ public class SyncrhonizationContextTests Task.Run ( () => { - Thread.Sleep (1_000); + Thread.Sleep (500); // non blocking context.Post ( @@ -68,7 +68,7 @@ public class SyncrhonizationContextTests Task.Run ( () => { - Thread.Sleep (1_000); + Thread.Sleep (500); // blocking context.Send ( diff --git a/UnitTests/Dialogs/DialogTests.cs b/UnitTests/Dialogs/DialogTests.cs index b76498620..9320b8403 100644 --- a/UnitTests/Dialogs/DialogTests.cs +++ b/UnitTests/Dialogs/DialogTests.cs @@ -39,7 +39,7 @@ public class DialogTests Width = width, Height = 1, ButtonAlignment = Alignment.Center, - Buttons = [new Button { Text = btn1Text }] + Buttons = [new() { Text = btn1Text }] }; // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..) @@ -67,7 +67,7 @@ public class DialogTests Width = width, Height = 1, ButtonAlignment = Alignment.Fill, - Buttons = [new Button { Text = btn1Text }] + Buttons = [new() { Text = btn1Text }] }; // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..) @@ -94,7 +94,7 @@ public class DialogTests Width = width, Height = 1, ButtonAlignment = Alignment.End, - Buttons = [new Button { Text = btn1Text }] + Buttons = [new() { Text = btn1Text }] }; // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..) @@ -122,7 +122,7 @@ public class DialogTests Width = width, Height = 1, ButtonAlignment = Alignment.Start, - Buttons = [new Button { Text = btn1Text }] + Buttons = [new() { Text = btn1Text }] }; // Create with no top or bottom border to simplify testing button layout (no need to account for title etc..) @@ -169,17 +169,16 @@ public class DialogTests int width = buttonRow.Length; d.SetBufferSize (buttonRow.Length, 3); - // Default - Center (runstate, Dialog dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Center, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.Center, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -189,14 +188,14 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Fill, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.Fill, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -206,14 +205,14 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.End, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.End, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -223,14 +222,14 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Start, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.Start, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -285,14 +284,14 @@ public class DialogTests $"{CM.Glyphs.VLine}{CM.Glyphs.LeftBracket} yes {CM.Glyphs.LeftBracket} no {CM.Glyphs.LeftBracket} maybe {CM.Glyphs.LeftBracket} never {CM.Glyphs.RightBracket}{CM.Glyphs.VLine}"; (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Fill, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.Fill, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -302,14 +301,14 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.End, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.End, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -318,14 +317,14 @@ public class DialogTests buttonRow = $"{CM.Glyphs.VLine}{btn1}{btn2}{btn3}{CM.Glyphs.LeftBracket} neve{CM.Glyphs.VLine}"; (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Start, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.Start, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -361,14 +360,14 @@ public class DialogTests // Default - Center (runstate, Dialog dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Center, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.Center, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -378,14 +377,14 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Fill, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.Fill, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -395,14 +394,14 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.End, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.End, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -412,14 +411,14 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Start, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.Start, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -457,14 +456,14 @@ public class DialogTests // Default - Center (runstate, Dialog dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Center, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.Center, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -474,14 +473,14 @@ public class DialogTests Assert.Equal (width, buttonRow.GetColumns ()); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Fill, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.Fill, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -491,14 +490,14 @@ public class DialogTests Assert.Equal (width, buttonRow.GetColumns ()); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.End, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.End, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -508,14 +507,14 @@ public class DialogTests Assert.Equal (width, buttonRow.GetColumns ()); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Start, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text }, - new Button { Text = btn4Text } - ); + title, + width, + Alignment.Start, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text }, + new Button { Text = btn4Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -542,11 +541,11 @@ public class DialogTests d.SetBufferSize (width, 1); (runstate, Dialog dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Center, - new Button { Text = btnText } - ); + title, + width, + Alignment.Center, + new Button { Text = btnText } + ); // Center TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); @@ -559,11 +558,11 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Fill, - new Button { Text = btnText } - ); + title, + width, + Alignment.Fill, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -574,11 +573,11 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.End, - new Button { Text = btnText } - ); + title, + width, + Alignment.End, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -589,11 +588,11 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Start, - new Button { Text = btnText } - ); + title, + width, + Alignment.Start, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -606,11 +605,11 @@ public class DialogTests d.SetBufferSize (width, 1); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Center, - new Button { Text = btnText } - ); + title, + width, + Alignment.Center, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -621,11 +620,11 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Fill, - new Button { Text = btnText } - ); + title, + width, + Alignment.Fill, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -636,11 +635,11 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.End, - new Button { Text = btnText } - ); + title, + width, + Alignment.End, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -651,11 +650,11 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Start, - new Button { Text = btnText } - ); + title, + width, + Alignment.Start, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -687,13 +686,13 @@ public class DialogTests d.SetBufferSize (buttonRow.Length, 3); (runstate, Dialog dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Center, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text } - ); + title, + width, + Alignment.Center, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -703,13 +702,13 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Fill, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text } - ); + title, + width, + Alignment.Fill, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -719,13 +718,13 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.End, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text } - ); + title, + width, + Alignment.End, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -735,13 +734,13 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Start, - new Button { Text = btn1Text }, - new Button { Text = btn2Text }, - new Button { Text = btn3Text } - ); + title, + width, + Alignment.Start, + new Button { Text = btn1Text }, + new Button { Text = btn2Text }, + new Button { Text = btn3Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -771,12 +770,12 @@ public class DialogTests d.SetBufferSize (buttonRow.Length, 3); (runstate, Dialog dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Center, - new Button { Text = btn1Text }, - new Button { Text = btn2Text } - ); + title, + width, + Alignment.Center, + new Button { Text = btn1Text }, + new Button { Text = btn2Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -786,12 +785,12 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Fill, - new Button { Text = btn1Text }, - new Button { Text = btn2Text } - ); + title, + width, + Alignment.Fill, + new Button { Text = btn1Text }, + new Button { Text = btn2Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -801,12 +800,12 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.End, - new Button { Text = btn1Text }, - new Button { Text = btn2Text } - ); + title, + width, + Alignment.End, + new Button { Text = btn1Text }, + new Button { Text = btn2Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -816,12 +815,12 @@ public class DialogTests Assert.Equal (width, buttonRow.Length); (runstate, dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Start, - new Button { Text = btn1Text }, - new Button { Text = btn2Text } - ); + title, + width, + Alignment.Start, + new Button { Text = btn1Text }, + new Button { Text = btn2Text } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -855,8 +854,8 @@ public class DialogTests Button button1, button2; // Default (Center) - button1 = new Button { Text = btn1Text }; - button2 = new Button { Text = btn2Text }; + button1 = new() { Text = btn1Text }; + button2 = new() { Text = btn2Text }; (runstate, dlg) = BeginButtonTestDialog (title, width, Alignment.Center, button1, button2); button1.Visible = false; RunIteration (ref runstate, firstIteration); @@ -867,8 +866,8 @@ public class DialogTests // Justify Assert.Equal (width, buttonRow.Length); - button1 = new Button { Text = btn1Text }; - button2 = new Button { Text = btn2Text }; + button1 = new() { Text = btn1Text }; + button2 = new() { Text = btn2Text }; (runstate, dlg) = BeginButtonTestDialog (title, width, Alignment.Fill, button1, button2); button1.Visible = false; RunIteration (ref runstate, firstIteration); @@ -879,8 +878,8 @@ public class DialogTests // Right Assert.Equal (width, buttonRow.Length); - button1 = new Button { Text = btn1Text }; - button2 = new Button { Text = btn2Text }; + button1 = new() { Text = btn1Text }; + button2 = new() { Text = btn2Text }; (runstate, dlg) = BeginButtonTestDialog (title, width, Alignment.End, button1, button2); button1.Visible = false; RunIteration (ref runstate, firstIteration); @@ -890,8 +889,8 @@ public class DialogTests // Left Assert.Equal (width, buttonRow.Length); - button1 = new Button { Text = btn1Text }; - button2 = new Button { Text = btn2Text }; + button1 = new() { Text = btn1Text }; + button2 = new() { Text = btn2Text }; (runstate, dlg) = BeginButtonTestDialog (title, width, Alignment.Start, button1, button2); button1.Visible = false; RunIteration (ref runstate, firstIteration); @@ -1020,7 +1019,7 @@ public class DialogTests Dialog.DefaultBorderStyle = LineStyle.Single; Dialog.DefaultShadow = ShadowStyle.None; Button.DefaultShadow = ShadowStyle.None; - + Iteration += (s, a) => { iterations++; @@ -1151,7 +1150,7 @@ public class DialogTests _output ); - Assert.False (Top!.NewKeyDownEvent (Key.Enter)); + Assert.False (Top.NewKeyDownEvent (Key.Enter)); break; case 4: @@ -1194,7 +1193,7 @@ public class DialogTests [AutoInitShutdown] public void Location_Default () { - var d = new Dialog () + var d = new Dialog { Width = Dim.Percent (85), Height = Dim.Percent (85) @@ -1253,86 +1252,6 @@ public class DialogTests d.Dispose (); } -// [Fact] -// [AutoInitShutdown] -// public void Location_When_Not_Application_Top_Not_Default () -// { -// var top = new Toplevel (); -// top.BorderStyle = LineStyle.Double; - -// int iterations = -1; - -// // Override CM -// Window.DefaultBorderStyle = LineStyle.Single; -// Dialog.DefaultButtonAlignment = Alignment.Center; -// Dialog.DefaultBorderStyle = LineStyle.Single; -// Dialog.DefaultShadow = ShadowStyle.None; - -// Iteration += (s, a) => -// { -// iterations++; - -// if (iterations == 0) -// { -// var d = new Dialog { X = 5, Y = 5, Height = 3, Width = 5 }; -// RunState rs = Begin (d); - -// Assert.Equal (new (5, 5), d.Frame.Location); - -// TestHelpers.AssertDriverContentsWithFrameAre ( -// @" -//╔══════════════════╗ -//║ ║ -//║ ║ -//║ ║ -//║ ║ -//║ ┌───┐ ║ -//║ │ │ ║ -//║ └───┘ ║ -//║ ║ -//╚══════════════════╝", -// _output -// ); -// End (rs); -// d.Dispose (); - -// d = new () -// { -// X = 5, Y = 5, -// Width = Dim.Percent (85), -// Height = Dim.Percent (85) - -// }; -// rs = Begin (d); - -// TestHelpers.AssertDriverContentsWithFrameAre ( -// @" -//╔══════════════════╗ -//║ ║ -//║ ║ -//║ ║ -//║ ║ -//║ ┌────────────── -//║ │ -//║ │ -//║ │ -//╚════│ ", -// _output -// ); -// End (rs); -// d.Dispose (); -// } -// else if (iterations > 0) -// { -// RequestStop (); -// } -// }; - -// ((FakeDriver)Driver).SetBufferSize (20, 10); -// Run (top); -// top.Dispose (); -// } - [Fact] [AutoInitShutdown] public void One_Button_Works () @@ -1353,11 +1272,11 @@ public class DialogTests d.SetBufferSize (buttonRow.Length, 10); (runstate, Dialog dlg) = BeginButtonTestDialog ( - title, - width, - Alignment.Center, - new Button { Text = btnText } - ); + title, + width, + Alignment.Center, + new Button { Text = btnText } + ); TestHelpers.AssertDriverContentsWithFrameAre ($"{buttonRow}", _output); End (runstate); dlg.Dispose (); @@ -1367,7 +1286,7 @@ public class DialogTests [AutoInitShutdown] public void Size_Default () { - var d = new Dialog () + var d = new Dialog { Width = Dim.Percent (85), Height = Dim.Percent (85) diff --git a/UnitTests/Input/KeyBindingTests.cs b/UnitTests/Input/KeyBindingTests.cs index af95eff47..edade4239 100644 --- a/UnitTests/Input/KeyBindingTests.cs +++ b/UnitTests/Input/KeyBindingTests.cs @@ -1,4 +1,5 @@ -using Xunit.Abstractions; +using Terminal.Gui.EnumExtensions; +using Xunit.Abstractions; namespace Terminal.Gui.InputTests; @@ -10,11 +11,19 @@ public class KeyBindingTests [Fact] public void Add_Invalid_Key_Throws () { - var keyBindings = new KeyBindings (); + var keyBindings = new KeyBindings (new View ()); List commands = new (); Assert.Throws (() => keyBindings.Add (Key.Empty, KeyBindingScope.HotKey, Command.Accept)); } + [Fact] + public void Add_BoundView_Null_Non_AppScope_Throws () + { + var keyBindings = new KeyBindings (); + List commands = new (); + Assert.Throws (() => keyBindings.Add (Key.Empty, KeyBindingScope.HotKey, Command.Accept)); + } + [Fact] public void Add_Multiple_Adds () { @@ -53,32 +62,41 @@ public class KeyBindingTests Assert.Contains (Command.HotKey, resultCommands); } + // Add should not allow duplicates [Fact] - public void Add_Throws_If_Exists () + public void Add_With_Bound_View_Throws_If_App_Scope () { - var keyBindings = new KeyBindings (); - keyBindings.Add (Key.A, KeyBindingScope.Application, Command.HotKey); + var keyBindings = new KeyBindings (new View ()); Assert.Throws (() => keyBindings.Add (Key.A, KeyBindingScope.Application, Command.Accept)); + } + + // Add should not allow duplicates + [Fact] + public void Add_With_Throws_If_Exists () + { + var keyBindings = new KeyBindings (new View ()); + keyBindings.Add (Key.A, KeyBindingScope.HotKey, Command.HotKey); + Assert.Throws (() => keyBindings.Add (Key.A, KeyBindingScope.HotKey, Command.Accept)); Command [] resultCommands = keyBindings.GetCommands (Key.A); Assert.Contains (Command.HotKey, resultCommands); - keyBindings = new (); + keyBindings = new (new View ()); keyBindings.Add (Key.A, KeyBindingScope.Focused, Command.HotKey); Assert.Throws (() => keyBindings.Add (Key.A, KeyBindingScope.Focused, Command.Accept)); resultCommands = keyBindings.GetCommands (Key.A); Assert.Contains (Command.HotKey, resultCommands); - keyBindings = new (); + keyBindings = new (new View ()); keyBindings.Add (Key.A, KeyBindingScope.HotKey, Command.HotKey); - Assert.Throws (() => keyBindings.Add (Key.A, KeyBindingScope.Focused, Command.Accept)); + Assert.Throws (() => keyBindings.Add (Key.A, KeyBindingScope.HotKey, Command.Accept)); resultCommands = keyBindings.GetCommands (Key.A); Assert.Contains (Command.HotKey, resultCommands); - keyBindings = new (); + keyBindings = new (new View ()); keyBindings.Add (Key.A, new KeyBinding (new [] { Command.HotKey }, KeyBindingScope.HotKey)); Assert.Throws (() => keyBindings.Add (Key.A, new KeyBinding (new [] { Command.Accept }, KeyBindingScope.HotKey))); @@ -207,11 +225,11 @@ public class KeyBindingTests [Fact] public void ReplaceKey_Replaces () { - var keyBindings = new KeyBindings (); - keyBindings.Add (Key.A, KeyBindingScope.Application, Command.HotKey); - keyBindings.Add (Key.B, KeyBindingScope.Application, Command.HotKey); - keyBindings.Add (Key.C, KeyBindingScope.Application, Command.HotKey); - keyBindings.Add (Key.D, KeyBindingScope.Application, Command.HotKey); + var keyBindings = new KeyBindings (new ()); + keyBindings.Add (Key.A, KeyBindingScope.Focused, Command.HotKey); + keyBindings.Add (Key.B, KeyBindingScope.Focused, Command.HotKey); + keyBindings.Add (Key.C, KeyBindingScope.Focused, Command.HotKey); + keyBindings.Add (Key.D, KeyBindingScope.Focused, Command.HotKey); keyBindings.ReplaceKey (Key.A, Key.E); Assert.Empty (keyBindings.GetCommands (Key.A)); @@ -233,9 +251,9 @@ public class KeyBindingTests [Fact] public void ReplaceKey_Replaces_Leaves_Old_Binding () { - var keyBindings = new KeyBindings (); - keyBindings.Add (Key.A, KeyBindingScope.Application, Command.Accept); - keyBindings.Add (Key.B, KeyBindingScope.Application, Command.HotKey); + var keyBindings = new KeyBindings (new ()); + keyBindings.Add (Key.A, KeyBindingScope.Focused, Command.Accept); + keyBindings.Add (Key.B, KeyBindingScope.Focused, Command.HotKey); keyBindings.ReplaceKey (keyBindings.GetKeyFromCommands (Command.Accept), Key.C); Assert.Empty (keyBindings.GetCommands (Key.A)); @@ -264,7 +282,7 @@ public class KeyBindingTests [InlineData (KeyBindingScope.Application)] public void Scope_Add_Adds (KeyBindingScope scope) { - var keyBindings = new KeyBindings (); + var keyBindings = new KeyBindings (scope.FastHasFlags(KeyBindingScope.Application) ? null : new ()); Command [] commands = { Command.Right, Command.Left }; var key = new Key (Key.A); @@ -288,7 +306,7 @@ public class KeyBindingTests [InlineData (KeyBindingScope.Application)] public void Scope_Get_Filters (KeyBindingScope scope) { - var keyBindings = new KeyBindings (); + var keyBindings = new KeyBindings (scope.FastHasFlags (KeyBindingScope.Application) ? null : new ()); Command [] commands = { Command.Right, Command.Left }; var key = new Key (Key.A); @@ -308,7 +326,7 @@ public class KeyBindingTests [InlineData (KeyBindingScope.Application)] public void Scope_TryGet_Filters (KeyBindingScope scope) { - var keyBindings = new KeyBindings (); + var keyBindings = new KeyBindings (scope.FastHasFlags (KeyBindingScope.Application) ? null : new ()); Command [] commands = { Command.Right, Command.Left }; var key = new Key (Key.A); diff --git a/UnitTests/View/Draw/AllViewsDrawTests.cs b/UnitTests/View/Draw/AllViewsDrawTests.cs index 376f53d82..fa865068b 100644 --- a/UnitTests/View/Draw/AllViewsDrawTests.cs +++ b/UnitTests/View/Draw/AllViewsDrawTests.cs @@ -42,11 +42,14 @@ public class AllViewsDrawTests (ITestOutputHelper _output) : TestsAllViews Assert.Equal (1, layoutStartedCount); Assert.Equal (1, layoutCompleteCount); - view.SetNeedsDraw (); - view.Draw (); + if (view.Visible) + { + view.SetNeedsDraw (); + view.Draw (); - Assert.Equal (1, drawCompleteCount); - Assert.Equal (1, layoutStartedCount); - Assert.Equal (1, layoutCompleteCount); + Assert.Equal (1, drawCompleteCount); + Assert.Equal (1, layoutStartedCount); + Assert.Equal (1, layoutCompleteCount); + } } } diff --git a/UnitTests/View/SubviewTests.cs b/UnitTests/View/SubviewTests.cs index 34826427d..8dc057457 100644 --- a/UnitTests/View/SubviewTests.cs +++ b/UnitTests/View/SubviewTests.cs @@ -499,4 +499,112 @@ public class SubviewTests superView.MoveSubviewTowardsEnd (subview2); Assert.Equal (subview2, superView.Subviews [^1]); } + + [Fact] + public void IsInHierarchy_ViewIsNull_ReturnsFalse () + { + // Arrange + var start = new View (); + + // Act + var result = View.IsInHierarchy (start, null); + + // Assert + Assert.False (result); + } + + [Fact] + public void IsInHierarchy_StartIsNull_ReturnsFalse () + { + // Arrange + var view = new View (); + + // Act + var result = View.IsInHierarchy (null, view); + + // Assert + Assert.False (result); + } + + [Fact] + public void IsInHierarchy_ViewIsStart_ReturnsTrue () + { + // Arrange + var start = new View (); + + // Act + var result = View.IsInHierarchy (start, start); + + // Assert + Assert.True (result); + } + + [Fact] + public void IsInHierarchy_ViewIsDirectSubview_ReturnsTrue () + { + // Arrange + var start = new View (); + var subview = new View (); + start.Add (subview); + + // Act + var result = View.IsInHierarchy (start, subview); + + // Assert + Assert.True (result); + } + + [Fact] + public void IsInHierarchy_ViewIsNestedSubview_ReturnsTrue () + { + // Arrange + var start = new View (); + var subview = new View (); + var nestedSubview = new View (); + start.Add (subview); + subview.Add (nestedSubview); + + // Act + var result = View.IsInHierarchy (start, nestedSubview); + + // Assert + Assert.True (result); + } + + [Fact] + public void IsInHierarchy_ViewIsNotInHierarchy_ReturnsFalse () + { + // Arrange + var start = new View (); + var subview = new View (); + + // Act + var result = View.IsInHierarchy (start, subview); + + // Assert + Assert.False (result); + } + + [Theory] + [CombinatorialData] + public void IsInHierarchy_ViewIsInAdornments_ReturnsTrue (bool includeAdornments) + { + // Arrange + var start = new View () + { + Id = "start" + }; + var inPadding = new View () + { + Id = "inPadding" + }; + + start.Padding.Add (inPadding); + + // Act + var result = View.IsInHierarchy (start, inPadding, includeAdornments: includeAdornments); + + // Assert + Assert.Equal(includeAdornments, result); + } } diff --git a/UnitTests/Views/DateFieldTests.cs b/UnitTests/Views/DateFieldTests.cs index f02fcf5df..b0adc8707 100644 --- a/UnitTests/Views/DateFieldTests.cs +++ b/UnitTests/Views/DateFieldTests.cs @@ -188,7 +188,7 @@ public class DateFieldTests DateTime date = DateTime.Parse ("1/1/1971"); - foreach (CultureInfo culture in CultureInfo.GetCultures (CultureTypes.AllCultures)) + foreach (CultureInfo culture in CultureInfo.GetCultures (CultureTypes.NeutralCultures)) { CultureInfo.CurrentCulture = culture; string separator = culture.DateTimeFormat.DateSeparator.Trim (); diff --git a/UnitTests/Views/ToplevelTests.cs b/UnitTests/Views/ToplevelTests.cs index e39cd739a..8c45ad6f0 100644 --- a/UnitTests/Views/ToplevelTests.cs +++ b/UnitTests/Views/ToplevelTests.cs @@ -1,8 +1,6 @@ -using Xunit.Abstractions; +namespace Terminal.Gui.ViewsTests; -namespace Terminal.Gui.ViewsTests; - -public partial class ToplevelTests (ITestOutputHelper output) +public partial class ToplevelTests () { [Fact] public void Constructor_Default () diff --git a/UnitTests/Views/ViewDisposalTest.cs b/UnitTests/Views/ViewDisposalTest.cs index 1c70f5335..f171ff708 100644 --- a/UnitTests/Views/ViewDisposalTest.cs +++ b/UnitTests/Views/ViewDisposalTest.cs @@ -32,8 +32,8 @@ public class ViewDisposalTest (ITestOutputHelper output) private WeakReference DoTest () { GetSpecialParams (); - var container = new View (); - Toplevel top = new (); + var container = new View () { Id = "container" }; + Toplevel top = new () { Id = "top" }; List views = GetViews (); foreach (Type view in views) @@ -51,6 +51,7 @@ public class ViewDisposalTest (ITestOutputHelper output) } Assert.NotNull (instance); + instance.Id = $"{view.Name}"; container.Add (instance); output.WriteLine ($"Added instance of {view}!"); }