Răsfoiți Sursa

Merge branch 'gui-cs:v2_develop' into v2_2491-Overlapped

Tig 10 luni în urmă
părinte
comite
6008949ec5
45 a modificat fișierele cu 1905 adăugiri și 1002 ștergeri
  1. 1 0
      Terminal.Gui/Configuration/ConfigurationManager.cs
  2. 6 6
      Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
  3. 1 1
      Terminal.Gui/Terminal.Gui.csproj
  4. 8 2
      Terminal.Gui/View/Layout/Dim.cs
  5. 14 14
      Terminal.Gui/View/Layout/DimAuto.cs
  6. 2 2
      Terminal.Gui/View/Layout/DimFill.cs
  7. 9 16
      Terminal.Gui/View/Layout/Pos.cs
  8. 7 7
      Terminal.Gui/View/Layout/PosAlign.cs
  9. 2 0
      Terminal.Gui/View/View.Hierarchy.cs
  10. 2 2
      Terminal.Gui/View/View.Layout.cs
  11. 3 3
      Terminal.Gui/Views/ColorPicker.cs
  12. 49 127
      Terminal.Gui/Views/FileDialog.cs
  13. 57 25
      Terminal.Gui/Views/Menu/ContextMenu.cs
  14. 114 87
      Terminal.Gui/Views/Menu/Menu.cs
  15. 138 128
      Terminal.Gui/Views/Menu/MenuBar.cs
  16. 39 23
      Terminal.Gui/Views/Menu/MenuBarItem.cs
  17. 58 41
      Terminal.Gui/Views/Menu/MenuItem.cs
  18. 39 32
      Terminal.Gui/Views/TableView/TableView.cs
  19. 3 5
      Terminal.Gui/Views/TextField.cs
  20. 5 7
      Terminal.Gui/Views/TextView.cs
  21. 1 1
      Terminal.Gui/Views/Toplevel.cs
  22. 11 9
      Terminal.Gui/Views/Wizard/Wizard.cs
  23. 2 1
      Terminal.Gui/Views/Wizard/WizardStep.cs
  24. 1 0
      Terminal.sln.DotSettings
  25. 3 3
      UICatalog/KeyBindingsDialog.cs
  26. 25 24
      UICatalog/Scenarios/CharacterMap.cs
  27. 120 120
      UICatalog/Scenarios/ContextMenus.cs
  28. 27 17
      UICatalog/Scenarios/DynamicMenuBar.cs
  29. 2 2
      UICatalog/Scenarios/Notepad.cs
  30. 20 20
      UICatalog/Scenarios/TableEditor.cs
  31. 6 7
      UICatalog/Scenarios/TreeViewFileSystem.cs
  32. 8 1
      UICatalog/Scenarios/WizardAsView.cs
  33. 12 2
      UICatalog/Scenarios/Wizards.cs
  34. 9 5
      UICatalog/UICatalog.cs
  35. 160 91
      UnitTests/FileServices/FileDialogTests.cs
  36. 1 1
      UnitTests/UnitTests.csproj
  37. 16 3
      UnitTests/View/Layout/Dim.FillTests.cs
  38. 7 7
      UnitTests/View/Layout/Dim.Tests.cs
  39. 6 6
      UnitTests/View/Layout/SetRelativeLayoutTests.cs
  40. 663 146
      UnitTests/Views/ContextMenuTests.cs
  41. 7 0
      UnitTests/Views/DateFieldTests.cs
  42. 3 3
      UnitTests/Views/MenuBarTests.cs
  43. 64 0
      UnitTests/Views/MenuTests.cs
  44. 172 3
      UnitTests/Views/TableViewTests.cs
  45. 2 2
      UnitTests/Views/ToplevelTests.cs

+ 1 - 0
Terminal.Gui/Configuration/ConfigurationManager.cs

@@ -110,6 +110,7 @@ public static class ConfigurationManager
         TypeInfoResolver = SourceGenerationContext.Default
     };
 
+    [SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
     internal static readonly SourceGenerationContext _serializerContext = new (_serializerOptions);
 
     [SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]

+ 6 - 6
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -1811,12 +1811,6 @@ internal class WindowsDriver : ConsoleDriver
         int delay = startDelay;
         while (_isButtonPressed)
         {
-            var me = new MouseEvent
-            {
-                Position = _pointMove,
-                Flags = mouseFlag
-            };
-
             // TODO: This makes ConsoleDriver dependent on Application, which is not ideal. This should be moved to Application.
             View view = Application.WantContinuousButtonPressedView;
 
@@ -1831,6 +1825,12 @@ internal class WindowsDriver : ConsoleDriver
             }
             await Task.Delay (delay);
 
+            var me = new MouseEvent
+            {
+                Position = _pointMove,
+                Flags = mouseFlag
+            };
+
             //Debug.WriteLine($"ProcessContinuousButtonPressedAsync: {view}");
             if (_isButtonPressed && (mouseFlag & MouseFlags.ReportMousePosition) == 0)
             {

+ 1 - 1
Terminal.Gui/Terminal.Gui.csproj

@@ -141,4 +141,4 @@
     <EnableSourceLink>true</EnableSourceLink>
     <Authors>Miguel de Icaza, Tig Kindel (@tig), @BDisp</Authors>
   </PropertyGroup>
-</Project>
+</Project>

+ 8 - 2
Terminal.Gui/View/Layout/Dim.cs

@@ -49,7 +49,7 @@ using System.Numerics;
 ///             </item>
 ///             <item>
 ///                 <term>
-///                     <see cref="Dim.Fill(int)"/>
+///                     <see cref="Dim.Fill(Dim)"/>
 ///                 </term>
 ///                 <description>
 ///                     Creates a <see cref="Dim"/> object that fills the dimension from the View's X position
@@ -119,12 +119,18 @@ public abstract record Dim : IEqualityOperators<Dim, Dim, bool>
                             Style: style);
     }
 
+    /// <summary>
+    ///     Creates a <see cref="Dim"/> object that fills the dimension, leaving no margin.
+    /// </summary>
+    /// <returns>The Fill dimension.</returns>
+    public static Dim? Fill () { return new DimFill (0); }
+
     /// <summary>
     ///     Creates a <see cref="Dim"/> object that fills the dimension, leaving the specified margin.
     /// </summary>
     /// <returns>The Fill dimension.</returns>
     /// <param name="margin">Margin to use.</param>
-    public static Dim? Fill (int margin = 0) { return new DimFill (margin); }
+    public static Dim? Fill (Dim margin) { return new DimFill (margin); }
 
     /// <summary>
     ///     Creates a function <see cref="Dim"/> object that computes the dimension by executing the provided function.

+ 14 - 14
Terminal.Gui/View/Layout/DimAuto.cs

@@ -131,9 +131,9 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
                     notDependentSubViews = includedSubviews.Where (
                                                                    v => v.Width is { }
                                                                         && (v.X is PosAbsolute or PosFunc || v.Width is DimAuto or DimAbsolute or DimFunc) // BUGBUG: We should use v.X.Has and v.Width.Has?
-                                                                        && !v.X.Has (typeof (PosAnchorEnd), out _)
-                                                                        && !v.X.Has (typeof (PosAlign), out _)
-                                                                        && !v.X.Has (typeof (PosCenter), out _)
+                                                                        && !v.X.Has<PosAnchorEnd> (out _)
+                                                                        && !v.X.Has<PosAlign> (out _)
+                                                                        && !v.X.Has<PosCenter> (out _)
                                                                         && !v.Width.Has<DimFill> (out _)
                                                                         && !v.Width.Has<DimPercent> (out _)
                                                                   )
@@ -144,9 +144,9 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
                     notDependentSubViews = includedSubviews.Where (
                                                                    v => v.Height is { }
                                                                         && (v.Y is PosAbsolute or PosFunc || v.Height is DimAuto or DimAbsolute or DimFunc) // BUGBUG: We should use v.Y.Has and v.Height.Has?
-                                                                        && !v.Y.Has (typeof (PosAnchorEnd), out _)
-                                                                        && !v.Y.Has (typeof (PosAlign), out _)
-                                                                        && !v.Y.Has (typeof (PosCenter), out _)
+                                                                        && !v.Y.Has<PosAnchorEnd> (out _)
+                                                                        && !v.Y.Has<PosAlign> (out _)
+                                                                        && !v.Y.Has<PosCenter> (out _)
                                                                         && !v.Height.Has<DimFill> (out _)
                                                                         && !v.Height.Has<DimPercent> (out _)
                                                                   )
@@ -190,11 +190,11 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
 
                 if (dimension == Dimension.Width)
                 {
-                    centeredSubViews = us.Subviews.Where (v => v.X.Has (typeof (PosCenter), out _)).ToList ();
+                    centeredSubViews = us.Subviews.Where (v => v.X.Has<PosCenter> (out _)).ToList ();
                 }
                 else
                 {
-                    centeredSubViews = us.Subviews.Where (v => v.Y.Has (typeof (PosCenter), out _)).ToList ();
+                    centeredSubViews = us.Subviews.Where (v => v.Y.Has<PosCenter> (out _)).ToList ();
                 }
 
                 viewsNeedingLayout.AddRange (centeredSubViews);
@@ -239,14 +239,14 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
                                                               {
                                                                   if (dimension == Dimension.Width)
                                                                   {
-                                                                      if (v.X.Has (typeof (PosAlign), out Pos posAlign))
+                                                                      if (v.X.Has<PosAlign> (out Pos posAlign))
                                                                       {
                                                                           return ((PosAlign)posAlign).GroupId;
                                                                       }
                                                                   }
                                                                   else
                                                                   {
-                                                                      if (v.Y.Has (typeof (PosAlign), out Pos posAlign))
+                                                                      if (v.Y.Has<PosAlign> (out Pos posAlign))
                                                                       {
                                                                           return ((PosAlign)posAlign).GroupId;
                                                                       }
@@ -294,11 +294,11 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
 
                 if (dimension == Dimension.Width)
                 {
-                    anchoredSubViews = includedSubviews.Where (v => v.X.Has (typeof (PosAnchorEnd), out _)).ToList ();
+                    anchoredSubViews = includedSubviews.Where (v => v.X.Has<PosAnchorEnd> (out _)).ToList ();
                 }
                 else
                 {
-                    anchoredSubViews = includedSubviews.Where (v => v.Y.Has (typeof (PosAnchorEnd), out _)).ToList ();
+                    anchoredSubViews = includedSubviews.Where (v => v.Y.Has<PosAnchorEnd> (out _)).ToList ();
                 }
 
                 viewsNeedingLayout.AddRange (anchoredSubViews);
@@ -336,11 +336,11 @@ public record DimAuto (Dim? MaximumContentDim, Dim? MinimumContentDim, DimAutoSt
 
                 if (dimension == Dimension.Width)
                 {
-                    posViewSubViews = includedSubviews.Where (v => v.X.Has (typeof (PosView), out _)).ToList ();
+                    posViewSubViews = includedSubviews.Where (v => v.X.Has<PosView> (out _)).ToList ();
                 }
                 else
                 {
-                    posViewSubViews = includedSubviews.Where (v => v.Y.Has (typeof (PosView), out _)).ToList ();
+                    posViewSubViews = includedSubviews.Where (v => v.Y.Has<PosView> (out _)).ToList ();
                 }
 
                 for (var i = 0; i < posViewSubViews.Count; i++)

+ 2 - 2
Terminal.Gui/View/Layout/DimFill.cs

@@ -9,10 +9,10 @@ namespace Terminal.Gui;
 ///     methods on the <see cref="Dim"/> class to create <see cref="Dim"/> objects instead.
 /// </remarks>
 /// <param name="Margin">The margin to not fill.</param>
-public record DimFill (int Margin) : Dim
+public record DimFill (Dim Margin) : Dim
 {
     /// <inheritdoc/>
     public override string ToString () { return $"Fill({Margin})"; }
 
-    internal override int GetAnchor (int size) { return size - Margin; }
+    internal override int GetAnchor (int size) { return size - Margin.GetAnchor(0); }
 }

+ 9 - 16
Terminal.Gui/View/Layout/Pos.cs

@@ -331,27 +331,20 @@ public abstract record Pos
     internal virtual bool ReferencesOtherViews () { return false; }
 
     /// <summary>
-    ///     Indicates whether the specified type is in the hierarchy of this Pos object.
+    ///     Indicates whether the specified type <typeparamref name="T"/> is in the hierarchy of this Pos object.
     /// </summary>
-    /// <param name="type"></param>
-    /// <param name="pos"></param>
+    /// <param name="pos">A reference to this <see cref="Pos"/> instance.</param>
     /// <returns></returns>
-    public bool Has (Type type, out Pos pos)
+    public bool Has<T> (out Pos pos) where T : Pos
     {
         pos = this;
-        if (type == GetType ())
-        {
-            return true;
-        }
-
-        // If we are a PosCombine, we have to check the left and right
-        // to see if they are of the type we are looking for.
-        if (this is PosCombine { } combine && (combine.Left.Has (type, out pos) || combine.Right.Has (type, out pos)))
-        {
-            return true;
-        }
 
-        return false;
+        return this switch
+               {
+                   PosCombine combine => combine.Left.Has<T> (out pos) || combine.Right.Has<T> (out pos),
+                   T => true,
+                   _ => false
+               };
     }
 
     #endregion virtual methods

+ 7 - 7
Terminal.Gui/View/Layout/PosAlign.cs

@@ -67,11 +67,11 @@ public record PosAlign : Pos
                                                v =>
                                                {
                                                    return dimension switch
-                                                          {
-                                                              Dimension.Width when v.X is PosAlign alignX => alignX.GroupId == groupId,
-                                                              Dimension.Height when v.Y is PosAlign alignY => alignY.GroupId == groupId,
-                                                              _ => false
-                                                          };
+                                                   {
+                                                       Dimension.Width when v.X is PosAlign alignX => alignX.GroupId == groupId,
+                                                       Dimension.Height when v.Y is PosAlign alignY => alignY.GroupId == groupId,
+                                                       _ => false
+                                                   };
                                                })
                                        .ToList ();
 
@@ -150,7 +150,7 @@ public record PosAlign : Pos
                                                   {
                                                       switch (dimension)
                                                       {
-                                                          case Dimension.Width when v.X.Has (typeof (PosAlign), out Pos pos):
+                                                          case Dimension.Width when v.X.Has<PosAlign> (out Pos pos):
 
                                                               if (pos is PosAlign posAlignX && posAlignX.GroupId == groupId)
                                                               {
@@ -158,7 +158,7 @@ public record PosAlign : Pos
                                                               }
 
                                                               break;
-                                                          case Dimension.Height when v.Y.Has (typeof (PosAlign), out Pos pos):
+                                                          case Dimension.Height when v.Y.Has<PosAlign> (out Pos pos):
                                                               if (pos is PosAlign posAlignY && posAlignY.GroupId == groupId)
                                                               {
                                                                   return posAlignY;

+ 2 - 0
Terminal.Gui/View/View.Hierarchy.cs

@@ -1,10 +1,12 @@
 #nullable enable
 using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 
 namespace Terminal.Gui;
 
 public partial class View // SuperView/SubView hierarchy management (SuperView, SubViews, Add, Remove, etc.)
 {
+    [SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
     private static readonly IList<View> _empty = new List<View> (0).AsReadOnly ();
 
     private List<View>? _subviews; // This is null, and allocated on demand.

+ 2 - 2
Terminal.Gui/View/View.Layout.cs

@@ -451,7 +451,7 @@ public partial class View // Layout APIs
     ///         .
     ///     </para>
     ///     <para>
-    ///         If set to a relative value (e.g. <see cref="Dim.Fill(int)"/>) the value is indeterminate until the view has
+    ///         If set to a relative value (e.g. <see cref="Dim.Fill(Dim)"/>) the value is indeterminate until the view has
     ///         been initialized ( <see cref="IsInitialized"/> is true) and <see cref="SetRelativeLayout"/> has been
     ///         called.
     ///     </para>
@@ -500,7 +500,7 @@ public partial class View // Layout APIs
     ///         .
     ///     </para>
     ///     <para>
-    ///         If set to a relative value (e.g. <see cref="Dim.Fill(int)"/>) the value is indeterminate until the view has
+    ///         If set to a relative value (e.g. <see cref="Dim.Fill(Dim)"/>) the value is indeterminate until the view has
     ///         been initialized ( <see cref="IsInitialized"/> is true) and <see cref="SetRelativeLayout"/> has been
     ///         called.
     ///     </para>

+ 3 - 3
Terminal.Gui/Views/ColorPicker.cs

@@ -154,7 +154,7 @@ public class ColorPicker : View
         _tfName.Autocomplete = auto;
 
         _tfName.HasFocusChanged += UpdateValueFromName;
-        _tfName.Accept += (_s, _) => UpdateValueFromName ();
+        _tfName.Accept += (s, _) => UpdateValueFromName ();
     }
 
     private void CreateTextField ()
@@ -303,7 +303,7 @@ public class ColorPicker : View
         }
     }
 
-    private void UpdateValueFromName (object sender, HasFocusEventArgs e)
+    private void UpdateValueFromName (object? sender, HasFocusEventArgs e)
     {
         // if the new value of Focused is true then it is an enter event so ignore
         if (e.NewValue)
@@ -361,7 +361,7 @@ public class ColorPicker : View
         }
     }
 
-
+    /// <inheritdoc />
     protected override void Dispose (bool disposing)
     {
         DisposeOldViews ();

+ 49 - 127
Terminal.Gui/Views/FileDialog.cs

@@ -10,6 +10,9 @@ namespace Terminal.Gui;
 /// </summary>
 public class FileDialog : Dialog
 {
+    private const int alignmentGroupInput = 32;
+    private const int alignmentGroupComplete = 55;
+
     /// <summary>Gets the Path separators for the operating system</summary>
     internal static char [] Separators =
     [
@@ -71,24 +74,20 @@ public class FileDialog : Dialog
 
         _btnOk = new Button
         {
-            Y = Pos.AnchorEnd (1), X = Pos.Func (CalculateOkButtonPosX), IsDefault = true, Text = Style.OkButtonText
+            X = Pos.Align (Alignment.End, AlignmentModes.AddSpaceBetweenItems, alignmentGroupComplete),
+            Y = Pos.AnchorEnd (),
+            IsDefault = true, Text = Style.OkButtonText
         };
         _btnOk.Accept += (s, e) => Accept (true);
 
-        _btnOk.KeyDown += (s, k) =>
-                          {
-                              NavigateIf (k, KeyCode.CursorLeft, _btnCancel);
-                              NavigateIf (k, KeyCode.CursorUp, _tableView);
-                          };
 
-        _btnCancel = new Button { Y = Pos.AnchorEnd (1), X = Pos.Right (_btnOk) + 1, Text = Strings.btnCancel };
+        _btnCancel = new Button
+        {
+            X = Pos.Align (Alignment.End, AlignmentModes.AddSpaceBetweenItems, alignmentGroupComplete),
+            Y = Pos.AnchorEnd(),
+            Text = Strings.btnCancel
+        };
 
-        _btnCancel.KeyDown += (s, k) =>
-                              {
-                                  NavigateIf (k, KeyCode.CursorLeft, _btnToggleSplitterCollapse);
-                                  NavigateIf (k, KeyCode.CursorUp, _tableView);
-                                  NavigateIf (k, KeyCode.CursorRight, _btnOk);
-                              };
         _btnCancel.Accept += (s, e) =>
         {
             Canceled = true;
@@ -121,7 +120,13 @@ public class FileDialog : Dialog
         _tbPath.Autocomplete = new AppendAutocomplete (_tbPath);
         _tbPath.Autocomplete.SuggestionGenerator = new FilepathSuggestionGenerator ();
 
-        _splitContainer = new TileView { X = 0, Y = 2, Width = Dim.Fill (), Height = Dim.Fill (1) };
+        _splitContainer = new TileView
+        {
+            X = 0,
+            Y = Pos.Bottom (_btnBack),
+            Width = Dim.Fill (),
+            Height = Dim.Fill (Dim.Func (() => IsInitialized ? _btnOk.Frame.Height : 1)),
+        };
 
         Initialized += (s, e) =>
                        {
@@ -129,7 +134,7 @@ public class FileDialog : Dialog
                            _splitContainer.Tiles.ElementAt (0).ContentView.Visible = false;
                        };
 
-        //			this.splitContainer.Border.BorderStyle = BorderStyle.None;
+        // this.splitContainer.Border.BorderStyle = BorderStyle.None;
 
         _tableView = new TableView
         {
@@ -158,28 +163,7 @@ public class FileDialog : Dialog
         ColumnStyle typeStyle = Style.TableStyle.GetOrCreateColumnStyle (3);
         typeStyle.MinWidth = 6;
         typeStyle.ColorGetter = ColorGetter;
-
-        _tableView.KeyDown += (s, k) =>
-                              {
-                                  if (_tableView.SelectedRow <= 0)
-                                  {
-                                      NavigateIf (k, KeyCode.CursorUp, _tbPath);
-                                  }
-
-                                  if (_tableView.SelectedRow == _tableView.Table.Rows - 1)
-                                  {
-                                      NavigateIf (k, KeyCode.CursorDown, _btnToggleSplitterCollapse);
-                                  }
-
-                                  if (_splitContainer.Tiles.First ().ContentView.Visible && _tableView.SelectedColumn == 0)
-                                  {
-                                      NavigateIf (k, KeyCode.CursorLeft, _treeView);
-                                  }
-
-                                  if (k.Handled)
-                                  { }
-                              };
-
+        
         _treeView = new TreeView<IFileSystemInfo> { Width = Dim.Fill (), Height = Dim.Fill () };
 
         var fileDialogTreeBuilder = new FileSystemTreeBuilder ();
@@ -192,7 +176,11 @@ public class FileDialog : Dialog
         _splitContainer.Tiles.ElementAt (0).ContentView.Add (_treeView);
         _splitContainer.Tiles.ElementAt (1).ContentView.Add (_tableView);
 
-        _btnToggleSplitterCollapse = new Button { Y = Pos.AnchorEnd (1), Text = GetToggleSplitterText (false) };
+        _btnToggleSplitterCollapse = new Button
+        {
+            X = Pos.Align (Alignment.Start, AlignmentModes.AddSpaceBetweenItems, alignmentGroupInput),
+            Y = Pos.AnchorEnd (), Text = GetToggleSplitterText (false)
+        };
 
         _btnToggleSplitterCollapse.Accept += (s, e) =>
                                               {
@@ -206,13 +194,13 @@ public class FileDialog : Dialog
 
         _tbFind = new TextField
         {
-            X = Pos.Right (_btnToggleSplitterCollapse) + 1,
+            X = Pos.Align (Alignment.Start,AlignmentModes.AddSpaceBetweenItems, alignmentGroupInput),
             CaptionColor = new Color (Color.Black),
             Width = 30,
-            Y = Pos.AnchorEnd (1),
+            Y = Pos.Top (_btnToggleSplitterCollapse),
             HotKey = Key.F.WithAlt
         };
-        _spinnerView = new SpinnerView { X = Pos.Right (_tbFind) + 1, Y = Pos.AnchorEnd (1), Visible = false };
+        _spinnerView = new SpinnerView { X = Pos.Align (Alignment.Start, AlignmentModes.AddSpaceBetweenItems, alignmentGroupInput), Y = Pos.AnchorEnd (1), Visible = false };
 
         _tbFind.TextChanged += (s, o) => RestartSearch ();
 
@@ -231,16 +219,6 @@ public class FileDialog : Dialog
                                        o.Handled = true;
                                    }
                                }
-
-                               if (_tbFind.CursorIsAtEnd ())
-                               {
-                                   NavigateIf (o, KeyCode.CursorRight, _btnCancel);
-                               }
-
-                               if (_tbFind.CursorIsAtStart ())
-                               {
-                                   NavigateIf (o, KeyCode.CursorLeft, _btnToggleSplitterCollapse);
-                               }
                            };
 
         _tableView.Style.ShowHorizontalHeaderOverline = true;
@@ -262,48 +240,22 @@ public class FileDialog : Dialog
         _tableView.KeyBindings.ReplaceCommands (Key.End, Command.BottomEnd);
         _tableView.KeyBindings.ReplaceCommands (Key.Home.WithShift, Command.TopHomeExtend);
         _tableView.KeyBindings.ReplaceCommands (Key.End.WithShift, Command.BottomEndExtend);
-
-        _treeView.KeyDown += (s, k) =>
-                             {
-                                 IFileSystemInfo selected = _treeView.SelectedObject;
-
-                                 if (selected is { })
-                                 {
-                                     if (!_treeView.CanExpand (selected) || _treeView.IsExpanded (selected))
-                                     {
-                                         NavigateIf (k, KeyCode.CursorRight, _tableView);
-                                     }
-                                     else if (_treeView.GetObjectRow (selected) == 0)
-                                     {
-                                         NavigateIf (k, KeyCode.CursorUp, _tbPath);
-                                     }
-                                 }
-
-                                 if (k.Handled)
-                                 {
-                                     return;
-                                 }
-
-                                 k.Handled = TreeView_KeyDown (k);
-                             };
-
+        
         AllowsMultipleSelection = false;
 
         UpdateNavigationVisibility ();
 
-        // BUGBUG: This TabOrder is counter-intuitive. The tab order for a dialog should match the
-        // order the Views' are presented, left to right, top to bottom.
-        // Determines tab order
-        Add (_btnToggleSplitterCollapse);
-        Add (_tbFind);
-        Add (_spinnerView);
-        Add (_btnOk);
-        Add (_btnCancel);
+        Add (_tbPath);
         Add (_btnUp);
         Add (_btnBack);
         Add (_btnForward);
-        Add (_tbPath);
         Add (_splitContainer);
+        Add (_btnToggleSplitterCollapse);
+        Add (_tbFind);
+        Add (_spinnerView);
+
+        Add(_btnOk);
+        Add(_btnCancel);
     }
 
     /// <summary>
@@ -1041,23 +993,6 @@ public class FileDialog : Dialog
         return toReturn;
     }
 
-    private bool NavigateIf (Key keyEvent, KeyCode isKey, View to)
-    {
-        if (keyEvent.KeyCode == isKey)
-        {
-            to.FocusDeepest (NavigationDirection.Forward, null);
-
-            if (to == _tbPath)
-            {
-                _tbPath.MoveEnd ();
-            }
-
-            return true;
-        }
-
-        return false;
-    }
-
     private void New ()
     {
         if (State is { })
@@ -1272,19 +1207,19 @@ public class FileDialog : Dialog
 
         var contextMenu = new ContextMenu
         {
-            Position = new Point (e.MouseEvent.Position.X + 1, e.MouseEvent.Position.Y + 1),
-            MenuItems = new MenuBarItem (
+            Position = new Point (e.MouseEvent.Position.X + 1, e.MouseEvent.Position.Y + 1)
+        };
+
+        var menuItems = new MenuBarItem (
                                          [
                                              new MenuItem (Strings.fdCtxNew, string.Empty, New),
                                              new MenuItem (Strings.fdCtxRename, string.Empty, Rename),
                                              new MenuItem (Strings.fdCtxDelete, string.Empty, Delete)
                                          ]
-                                        )
-        };
-
+                                        );
         _tableView.SetSelection (clickedCell.Value.X, clickedCell.Value.Y, false);
 
-        contextMenu.Show ();
+        contextMenu.Show (menuItems);
     }
 
     private void ShowHeaderContextMenu (int clickedCol, MouseEventEventArgs e)
@@ -1293,8 +1228,10 @@ public class FileDialog : Dialog
 
         var contextMenu = new ContextMenu
         {
-            Position = new Point (e.MouseEvent.Position.X + 1, e.MouseEvent.Position.Y + 1),
-            MenuItems = new MenuBarItem (
+            Position = new Point (e.MouseEvent.Position.X + 1, e.MouseEvent.Position.Y + 1)
+        };
+
+        var menuItems = new MenuBarItem (
                                          [
                                              new MenuItem (
                                                            string.Format (
@@ -1309,10 +1246,8 @@ public class FileDialog : Dialog
                                                            string.Empty,
                                                            () => SortColumn (clickedCol, isAsc))
                                          ]
-                                        )
-        };
-
-        contextMenu.Show ();
+                                        );
+        contextMenu.Show (menuItems);
     }
 
     private void SortColumn (int clickedCol)
@@ -1430,19 +1365,6 @@ public class FileDialog : Dialog
         }
     }
 
-    private bool TreeView_KeyDown (Key keyEvent)
-    {
-        if (_treeView.HasFocus && Separators.Contains ((char)keyEvent))
-        {
-            _tbPath.FocusDeepest (NavigationDirection.Forward, null);
-
-            // let that keystroke go through on the tbPath instead
-            return true;
-        }
-
-        return false;
-    }
-
     private void TreeView_SelectionChanged (object sender, SelectionChangedEventArgs<IFileSystemInfo> e)
     {
         if (e.NewValue is null)

+ 57 - 25
Terminal.Gui/Views/Menu/ContextMenu.cs

@@ -1,4 +1,6 @@
-namespace Terminal.Gui;
+#nullable enable
+
+namespace Terminal.Gui;
 
 /// <summary>
 ///     ContextMenu provides a pop-up menu that can be positioned anywhere within a <see cref="View"/>. ContextMenu is
@@ -16,15 +18,15 @@
 ///     </para>
 ///     <para>
 ///         Callers can cause the ContextMenu to be activated on a right-mouse click (or other interaction) by calling
-///         <see cref="Show()"/>.
+///         <see cref="Show"/>.
 ///     </para>
 ///     <para>ContextMenus are located using screen coordinates and appear above all other Views.</para>
 /// </summary>
 public sealed class ContextMenu : IDisposable
 {
-    private static MenuBar _menuBar;
+    private static MenuBar? _menuBar;
 
-    private Toplevel _container;
+    private Toplevel? _container;
     private Key _key = DefaultKey;
     private MouseFlags _mouseFlags = MouseFlags.Button3Clicked;
 
@@ -33,15 +35,9 @@ public sealed class ContextMenu : IDisposable
     {
         if (IsShow)
         {
-            if (_menuBar.SuperView is { })
-            {
-                Hide ();
-            }
-
+            Hide ();
             IsShow = false;
         }
-
-        MenuItems = new MenuBarItem ();
     }
 
     /// <summary>The default shortcut key for activating the context menu.</summary>
@@ -56,7 +52,7 @@ public sealed class ContextMenu : IDisposable
     public bool ForceMinimumPosToZero { get; set; } = true;
 
     /// <summary>The host <see cref="View "/> which position will be used, otherwise if it's null the container will be used.</summary>
-    public View Host { get; set; }
+    public View? Host { get; set; }
 
     /// <summary>Gets whether the ContextMenu is showing or not.</summary>
     public static bool IsShow { get; private set; }
@@ -74,10 +70,10 @@ public sealed class ContextMenu : IDisposable
     }
 
     /// <summary>Gets the <see cref="MenuBar"/> that is hosting this context menu.</summary>
-    public MenuBar MenuBar => _menuBar;
+    public MenuBar? MenuBar => _menuBar;
 
     /// <summary>Gets or sets the menu items for this context menu.</summary>
-    public MenuBarItem MenuItems { get; set; }
+    public MenuBarItem? MenuItems { get; private set; }
 
     /// <summary><see cref="Gui.MouseFlags"/> specifies the mouse action used to activate the context menu by mouse.</summary>
     public MouseFlags MouseFlags
@@ -105,11 +101,10 @@ public sealed class ContextMenu : IDisposable
     /// <summary>Disposes the context menu object.</summary>
     public void Dispose ()
     {
-        if (_menuBar is null)
+        if (_menuBar is { })
         {
-            return;
+            _menuBar.MenuAllClosed -= MenuBar_MenuAllClosed;
         }
-        _menuBar.MenuAllClosed -= MenuBar_MenuAllClosed;
         Application.UngrabMouse ();
         _menuBar?.Dispose ();
         _menuBar = null;
@@ -126,18 +121,49 @@ public sealed class ContextMenu : IDisposable
     /// <summary>Hides (closes) the ContextMenu.</summary>
     public void Hide ()
     {
+        RemoveKeyBindings (MenuItems);
         _menuBar?.CleanUp ();
         IsShow = false;
     }
 
+    private void RemoveKeyBindings (MenuBarItem? menuBarItem)
+    {
+        if (menuBarItem is null)
+        {
+            return;
+        }
+
+        foreach (MenuItem? menuItem in menuBarItem.Children!)
+        {
+            // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
+            if (menuItem is null)
+            {
+                continue;
+            }
+
+            if (menuItem is MenuBarItem barItem)
+            {
+                RemoveKeyBindings (barItem);
+            }
+            else
+            {
+                if (menuItem.ShortcutKey != Key.Empty)
+                {
+                    // Remove an existent ShortcutKey
+                    _menuBar?.KeyBindings.Remove (menuItem.ShortcutKey!);
+                }
+            }
+        }
+    }
+
     /// <summary>Event invoked when the <see cref="ContextMenu.Key"/> is changed.</summary>
-    public event EventHandler<KeyChangedEventArgs> KeyChanged;
+    public event EventHandler<KeyChangedEventArgs>? KeyChanged;
 
     /// <summary>Event invoked when the <see cref="ContextMenu.MouseFlags"/> is changed.</summary>
-    public event EventHandler<MouseFlagsChangedEventArgs> MouseFlagsChanged;
+    public event EventHandler<MouseFlagsChangedEventArgs>? MouseFlagsChanged;
 
     /// <summary>Shows (opens) the ContextMenu, displaying the <see cref="MenuItem"/>s it contains.</summary>
-    public void Show ()
+    public void Show (MenuBarItem? menuItems)
     {
         if (_menuBar is { })
         {
@@ -145,6 +171,12 @@ public sealed class ContextMenu : IDisposable
             Dispose ();
         }
 
+        if (menuItems is null || menuItems.Children!.Length == 0)
+        {
+            return;
+        }
+
+        MenuItems = menuItems;
         _container = Application.Current;
         _container!.Closing += Container_Closing;
         _container.Deactivate += Container_Deactivate;
@@ -155,7 +187,7 @@ public sealed class ContextMenu : IDisposable
         if (Host is { })
         {
             Point pos = Host.ViewportToScreen (frame).Location;
-            pos.Y += Host.Frame.Height - 1;
+            pos.Y += Host.Frame.Height > 0 ? Host.Frame.Height - 1 : 0;
 
             if (position != pos)
             {
@@ -224,9 +256,9 @@ public sealed class ContextMenu : IDisposable
         _menuBar.OpenMenu ();
     }
 
-    private void Container_Closing (object sender, ToplevelClosingEventArgs obj) { Hide (); }
-    private void Container_Deactivate (object sender, ToplevelEventArgs e) { Hide (); }
-    private void Container_Disposing (object sender, EventArgs e) { Dispose (); }
+    private void Container_Closing (object? sender, ToplevelClosingEventArgs obj) { Hide (); }
+    private void Container_Deactivate (object? sender, ToplevelEventArgs e) { Hide (); }
+    private void Container_Disposing (object? sender, EventArgs e) { Dispose (); }
 
-    private void MenuBar_MenuAllClosed (object sender, EventArgs e) { Hide (); }
+    private void MenuBar_MenuAllClosed (object? sender, EventArgs e) { Hide (); }
 }

+ 114 - 87
Terminal.Gui/Views/Menu/Menu.cs

@@ -1,3 +1,5 @@
+#nullable enable
+
 namespace Terminal.Gui;
 
 /// <summary>
@@ -6,12 +8,12 @@ namespace Terminal.Gui;
 /// </summary>
 internal sealed class Menu : View
 {
-    private readonly MenuBarItem _barItems;
+    private readonly MenuBarItem? _barItems;
     private readonly MenuBar _host;
     internal int _currentChild;
-    internal View _previousSubFocused;
+    internal View? _previousSubFocused;
 
-    internal static Rectangle MakeFrame (int x, int y, MenuItem [] items, Menu parent = null)
+    internal static Rectangle MakeFrame (int x, int y, MenuItem? []? items, Menu? parent = null)
     {
         if (items is null || items.Length == 0)
         {
@@ -47,9 +49,9 @@ internal sealed class Menu : View
         }
     }
 
-    internal required MenuBarItem BarItems
+    internal required MenuBarItem? BarItems
     {
-        get => _barItems;
+        get => _barItems!;
         init
         {
             ArgumentNullException.ThrowIfNull (value);
@@ -60,13 +62,32 @@ internal sealed class Menu : View
         }
     }
 
-    internal Menu Parent { get; init; }
+    internal Menu? Parent { get; init; }
 
     public override void BeginInit ()
     {
         base.BeginInit ();
 
-        Frame = MakeFrame (Frame.X, Frame.Y, _barItems?.Children, Parent);
+        Frame = MakeFrame (Frame.X, Frame.Y, _barItems!.Children!, Parent);
+
+        if (_barItems.Children is { })
+        {
+            foreach (MenuItem? menuItem in _barItems.Children)
+            {
+                if (menuItem is { })
+                {
+                    menuItem._menuBar = Host;
+
+                    if (menuItem.ShortcutKey != Key.Empty)
+                    {
+                        KeyBinding keyBinding = new ([Command.Select], KeyBindingScope.HotKey, menuItem);
+                        // Remove an existent ShortcutKey
+                        menuItem._menuBar.KeyBindings.Remove (menuItem.ShortcutKey!);
+                        menuItem._menuBar.KeyBindings.Add (menuItem.ShortcutKey!, keyBinding);
+                    }
+                }
+            }
+        }
 
         if (_barItems is { IsTopLevel: true })
         {
@@ -78,9 +99,9 @@ internal sealed class Menu : View
         {
             _currentChild = -1;
 
-            for (var i = 0; i < _barItems!.Children?.Length; i++)
+            for (var i = 0; i < _barItems.Children?.Length; i++)
             {
-                if (_barItems.Children [i]?.IsEnabled () == true)
+                if (_barItems.Children [i]!.IsEnabled ())
                 {
                     _currentChild = i;
 
@@ -101,19 +122,17 @@ internal sealed class Menu : View
                     {
                         _host.NextMenu (
                                         !_barItems.IsTopLevel
-                                        || (_barItems.Children != null
-                                            && _barItems!.Children.Length > 0
+                                        || (_barItems.Children is { Length: > 0 }
                                             && _currentChild > -1
                                             && _currentChild < _barItems.Children.Length
-                                            && _barItems.Children [_currentChild].IsFromSubMenu),
-                                        _barItems!.Children != null
-                                        && _barItems.Children.Length > 0
+                                            && _barItems.Children [_currentChild]!.IsFromSubMenu),
+                                        _barItems.Children is { Length: > 0 }
                                         && _currentChild > -1
                                         && _host.UseSubMenusSingleFrame
                                         && _barItems.SubMenu (
-                                                              _barItems.Children [_currentChild]
+                                                              _barItems.Children [_currentChild]!
                                                              )
-                                        != null
+                                        != null!
                                        );
 
                         return true;
@@ -141,7 +160,7 @@ internal sealed class Menu : View
                     Command.Left,
                     () =>
                     {
-                        _host.PreviousMenu (true);
+                        _host!.PreviousMenu (true);
 
                         return true;
                     }
@@ -166,9 +185,9 @@ internal sealed class Menu : View
                         return true;
                     }
                    );
-        AddCommand (Command.Select, ctx => _host?.SelectItem (ctx.KeyBinding?.Context as MenuItem));
-        AddCommand (Command.ToggleExpandCollapse, ctx => ExpandCollapse (ctx.KeyBinding?.Context as MenuItem));
-        AddCommand (Command.HotKey, ctx => _host?.SelectItem (ctx.KeyBinding?.Context as MenuItem));
+        AddCommand (Command.Select, ctx => _host?.SelectItem ((ctx.KeyBinding?.Context as MenuItem)!));
+        AddCommand (Command.ToggleExpandCollapse, ctx => ExpandCollapse ((ctx.KeyBinding?.Context as MenuItem)!));
+        AddCommand (Command.HotKey, ctx => _host?.SelectItem ((ctx.KeyBinding?.Context as MenuItem)!));
 
         // Default key bindings for this view
         KeyBindings.Add (Key.CursorUp, Command.LineUp);
@@ -179,47 +198,51 @@ internal sealed class Menu : View
         KeyBindings.Add (Key.Enter, Command.Accept);
     }
 
-    private void AddKeyBindingsHotKey (MenuBarItem menuBarItem)
+    private void AddKeyBindingsHotKey (MenuBarItem? menuBarItem)
     {
         if (menuBarItem is null || menuBarItem.Children is null)
         {
             return;
         }
 
-        foreach (MenuItem menuItem in menuBarItem.Children.Where (m => m is { }))
+        IEnumerable<MenuItem> menuItems = menuBarItem.Children.Where (m => m is { })!;
+
+        foreach (MenuItem menuItem in menuItems)
         {
             KeyBinding keyBinding = new ([Command.ToggleExpandCollapse], KeyBindingScope.HotKey, menuItem);
 
             if (menuItem.HotKey != Key.Empty)
             {
-                KeyBindings.Remove (menuItem.HotKey);
-                KeyBindings.Add (menuItem.HotKey, keyBinding);
-                KeyBindings.Remove (menuItem.HotKey.WithAlt);
+                KeyBindings.Remove (menuItem.HotKey!);
+                KeyBindings.Add (menuItem.HotKey!, keyBinding);
+                KeyBindings.Remove (menuItem.HotKey!.WithAlt);
                 KeyBindings.Add (menuItem.HotKey.WithAlt, keyBinding);
             }
         }
     }
 
-    private void RemoveKeyBindingsHotKey (MenuBarItem menuBarItem)
+    private void RemoveKeyBindingsHotKey (MenuBarItem? menuBarItem)
     {
         if (menuBarItem is null || menuBarItem.Children is null)
         {
             return;
         }
 
-        foreach (MenuItem menuItem in menuBarItem.Children.Where (m => m is { }))
+        IEnumerable<MenuItem> menuItems = menuBarItem.Children.Where (m => m is { })!;
+
+        foreach (MenuItem menuItem in menuItems)
         {
             if (menuItem.HotKey != Key.Empty)
             {
-                KeyBindings.Remove (menuItem.HotKey);
-                KeyBindings.Remove (menuItem.HotKey.WithAlt);
+                KeyBindings.Remove (menuItem.HotKey!);
+                KeyBindings.Remove (menuItem.HotKey!.WithAlt);
             }
         }
     }
 
     /// <summary>Called when a key bound to Command.ToggleExpandCollapse is pressed. This means a hot key was pressed.</summary>
     /// <returns></returns>
-    private bool ExpandCollapse (MenuItem menuItem)
+    private bool ExpandCollapse (MenuItem? menuItem)
     {
         if (!IsInitialized || !Visible)
         {
@@ -227,7 +250,7 @@ internal sealed class Menu : View
         }
 
 
-        for (var c = 0; c < _barItems.Children.Length; c++)
+        for (var c = 0; c < _barItems!.Children!.Length; c++)
         {
             if (_barItems.Children [c] == menuItem)
             {
@@ -243,13 +266,14 @@ internal sealed class Menu : View
 
             if (m?.Children?.Length > 0)
             {
-                MenuItem item = _barItems.Children [_currentChild];
+                MenuItem? item = _barItems.Children [_currentChild];
 
                 if (item is null)
                 {
                     return true;
                 }
 
+                // ReSharper disable once ConditionIsAlwaysTrueOrFalse
                 bool disabled = item is null || !item.IsEnabled ();
 
                 if (!disabled && (_host.UseSubMenusSingleFrame || !CheckSubMenu ()))
@@ -297,7 +321,7 @@ internal sealed class Menu : View
         return _host.OnInvokingKeyBindings (keyEvent, scope);
     }
 
-    private void Current_TerminalResized (object sender, SizeChangedEventArgs e)
+    private void Current_TerminalResized (object? sender, SizeChangedEventArgs e)
     {
         if (_host.IsMenuOpen)
         {
@@ -320,7 +344,7 @@ internal sealed class Menu : View
         }
     }
 
-    private void Application_RootMouseEvent (object sender, MouseEvent a)
+    private void Application_RootMouseEvent (object? sender, MouseEvent a)
     {
         if (a.View is { } and (MenuBar or not Menu))
         {
@@ -350,7 +374,7 @@ internal sealed class Menu : View
         }
     }
 
-    internal Attribute DetermineColorSchemeFor (MenuItem item, int index)
+    internal Attribute DetermineColorSchemeFor (MenuItem? item, int index)
     {
         if (item is null)
         {
@@ -367,7 +391,7 @@ internal sealed class Menu : View
 
     public override void OnDrawContent (Rectangle viewport)
     {
-        if (_barItems.Children is null)
+        if (_barItems!.Children is null)
         {
             return;
         }
@@ -379,7 +403,7 @@ internal sealed class Menu : View
         OnDrawAdornments ();
         OnRenderLineCanvas ();
 
-        for (int i = Viewport.Y; i < _barItems.Children.Length; i++)
+        for (int i = Viewport.Y; i < _barItems!.Children.Length; i++)
         {
             if (i < 0)
             {
@@ -391,9 +415,10 @@ internal sealed class Menu : View
                 break;
             }
 
-            MenuItem item = _barItems.Children [i];
+            MenuItem? item = _barItems.Children [i];
 
             Driver.SetAttribute (
+                                 // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
                                  item is null ? GetNormalColor () :
                                  i == _currentChild ? GetFocusColor () : GetNormalColor ()
                                 );
@@ -428,13 +453,13 @@ internal sealed class Menu : View
                 {
                     Driver.AddRune (Glyphs.HLine);
                 }
-                else if (i == 0 && p == 0 && _host.UseSubMenusSingleFrame && item.Parent.Parent is { })
+                else if (i == 0 && p == 0 && _host.UseSubMenusSingleFrame && item.Parent!.Parent is { })
                 {
                     Driver.AddRune (Glyphs.LeftArrow);
                 }
 
                 // This `- 3` is left border + right border + one row in from right
-                else if (p == Frame.Width - 3 && _barItems.SubMenu (_barItems.Children [i]) is { })
+                else if (p == Frame.Width - 3 && _barItems?.SubMenu (_barItems.Children [i]!) is { })
                 {
                     Driver.AddRune (Glyphs.RightArrow);
                 }
@@ -456,7 +481,7 @@ internal sealed class Menu : View
                 continue;
             }
 
-            string textToDraw = null;
+            string? textToDraw;
             Rune nullCheckedChar = Glyphs.CheckStateNone;
             Rune checkChar = Glyphs.Selected;
             Rune uncheckedChar = Glyphs.UnSelected;
@@ -468,7 +493,7 @@ internal sealed class Menu : View
             }
 
             // Support Checked even though CheckType wasn't set
-            if (item.CheckType == MenuItemCheckStyle.Checked && item.Checked is null)
+            if (item is { CheckType: MenuItemCheckStyle.Checked, Checked: null })
             {
                 textToDraw = $"{nullCheckedChar} {item.Title}";
             }
@@ -495,7 +520,7 @@ internal sealed class Menu : View
                 {
                     DrawHotString (textToDraw, ColorScheme.Disabled, ColorScheme.Disabled);
                 }
-                else if (i == 0 && _host.UseSubMenusSingleFrame && item.Parent.Parent is { })
+                else if (i == 0 && _host.UseSubMenusSingleFrame && item.Parent!.Parent is { })
                 {
                     var tf = new TextFormatter
                     {
@@ -548,7 +573,7 @@ internal sealed class Menu : View
         // PositionCursor ();
     }
 
-    private void Current_DrawContentComplete (object sender, DrawEventArgs e)
+    private void Current_DrawContentComplete (object? sender, DrawEventArgs e)
     {
         if (Visible)
         {
@@ -558,11 +583,11 @@ internal sealed class Menu : View
 
     public override Point? PositionCursor ()
     {
-        if (_host?.IsMenuOpen != false)
+        if (_host.IsMenuOpen)
         {
-            if (_barItems.IsTopLevel)
+            if (_barItems!.IsTopLevel)
             {
-                return _host?.PositionCursor ();
+                return _host.PositionCursor ();
             }
 
             Move (2, 1 + _currentChild);
@@ -570,12 +595,12 @@ internal sealed class Menu : View
             return null; // Don't show the cursor
         }
 
-        return _host?.PositionCursor ();
+        return _host.PositionCursor ();
     }
 
-    public void Run (Action action)
+    public void Run (Action? action)
     {
-        if (action is null || _host is null)
+        if (action is null)
         {
             return;
         }
@@ -587,17 +612,17 @@ internal sealed class Menu : View
         _host.Run (action);
     }
 
-    protected override void OnHasFocusChanged (bool newHasFocus, View previousFocusedView, View view)
+    protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocusedView, View? view)
     {
         if (!newHasFocus)
         {
-            _host.LostFocus (previousFocusedView);
+            _host.LostFocus (previousFocusedView!);
         }
     }
 
     private void RunSelected ()
     {
-        if (_barItems.IsTopLevel)
+        if (_barItems!.IsTopLevel)
         {
             Run (_barItems.Action);
         }
@@ -605,15 +630,15 @@ internal sealed class Menu : View
         {
             switch (_currentChild)
             {
-                case > -1 when _barItems.Children [_currentChild].Action != null:
-                    Run (_barItems.Children [_currentChild].Action);
+                case > -1 when _barItems.Children! [_currentChild]!.Action != null!:
+                    Run (_barItems.Children [_currentChild]?.Action);
 
                     break;
-                case 0 when _host.UseSubMenusSingleFrame && _barItems.Children [_currentChild].Parent.Parent != null:
-                    _host.PreviousMenu (_barItems.Children [_currentChild].Parent.IsFromSubMenu, true);
+                case 0 when _host.UseSubMenusSingleFrame && _barItems.Children [_currentChild]?.Parent!.Parent != null:
+                    _host.PreviousMenu (_barItems.Children [_currentChild]!.Parent!.IsFromSubMenu, true);
 
                     break;
-                case > -1 when _barItems.SubMenu (_barItems.Children [_currentChild]) != null:
+                case > -1 when _barItems.SubMenu (_barItems.Children [_currentChild]) != null!:
                     CheckSubMenu ();
 
                     break;
@@ -629,7 +654,7 @@ internal sealed class Menu : View
 
     private bool MoveDown ()
     {
-        if (_barItems.IsTopLevel)
+        if (_barItems!.IsTopLevel)
         {
             return true;
         }
@@ -640,19 +665,19 @@ internal sealed class Menu : View
         {
             _currentChild++;
 
-            if (_currentChild >= _barItems.Children.Length)
+            if (_currentChild >= _barItems?.Children?.Length)
             {
                 _currentChild = 0;
             }
 
-            if (this != _host.OpenCurrentMenu && _barItems.Children [_currentChild]?.IsFromSubMenu == true && _host._selectedSub > -1)
+            if (this != _host.OpenCurrentMenu && _barItems?.Children? [_currentChild]?.IsFromSubMenu == true && _host._selectedSub > -1)
             {
                 _host.PreviousMenu (true);
-                _host.SelectEnabledItem (_barItems.Children, _currentChild, out _currentChild);
+                _host.SelectEnabledItem (_barItems.Children!, _currentChild, out _currentChild);
                 _host.OpenCurrentMenu = this;
             }
 
-            MenuItem item = _barItems.Children [_currentChild];
+            MenuItem? item = _barItems?.Children? [_currentChild];
 
             if (item?.IsEnabled () != true)
             {
@@ -663,9 +688,8 @@ internal sealed class Menu : View
                 disabled = false;
             }
 
-            if (!_host.UseSubMenusSingleFrame
-                && _host.UseKeysUpDownAsKeysLeftRight
-                && _barItems.SubMenu (_barItems.Children [_currentChild]) != null
+            if (_host is { UseSubMenusSingleFrame: false, UseKeysUpDownAsKeysLeftRight: true }
+                && _barItems?.SubMenu (_barItems?.Children? [_currentChild]!) != null
                 && !disabled
                 && _host.IsMenuOpen)
             {
@@ -682,7 +706,7 @@ internal sealed class Menu : View
                 _host.OpenMenu (_host._selected);
             }
         }
-        while (_barItems.Children [_currentChild] is null || disabled);
+        while (_barItems?.Children? [_currentChild] is null || disabled);
 
         SetNeedsDisplay ();
         SetParentSetNeedsDisplay ();
@@ -697,7 +721,7 @@ internal sealed class Menu : View
 
     private bool MoveUp ()
     {
-        if (_barItems.IsTopLevel || _currentChild == -1)
+        if (_barItems!.IsTopLevel || _currentChild == -1)
         {
             return true;
         }
@@ -711,7 +735,7 @@ internal sealed class Menu : View
             if (_host.UseKeysUpDownAsKeysLeftRight && !_host.UseSubMenusSingleFrame)
             {
                 if ((_currentChild == -1 || this != _host.OpenCurrentMenu)
-                    && _barItems.Children [_currentChild + 1].IsFromSubMenu
+                    && _barItems.Children! [_currentChild + 1]!.IsFromSubMenu
                     && _host._selectedSub > -1)
                 {
                     _currentChild++;
@@ -729,14 +753,14 @@ internal sealed class Menu : View
 
             if (_currentChild < 0)
             {
-                _currentChild = _barItems.Children.Length - 1;
+                _currentChild = _barItems.Children!.Length - 1;
             }
 
-            if (!_host.SelectEnabledItem (_barItems.Children, _currentChild, out _currentChild, false))
+            if (!_host.SelectEnabledItem (_barItems.Children!, _currentChild, out _currentChild, false))
             {
                 _currentChild = 0;
 
-                if (!_host.SelectEnabledItem (_barItems.Children, _currentChild, out _currentChild) && !_host.CloseMenu (false))
+                if (!_host.SelectEnabledItem (_barItems.Children!, _currentChild, out _currentChild) && !_host.CloseMenu ())
                 {
                     return false;
                 }
@@ -744,12 +768,12 @@ internal sealed class Menu : View
                 break;
             }
 
-            MenuItem item = _barItems.Children [_currentChild];
-            disabled = item?.IsEnabled () != true;
+            MenuItem item = _barItems.Children! [_currentChild]!;
+            disabled = item.IsEnabled () != true;
 
             if (_host.UseSubMenusSingleFrame
                 || !_host.UseKeysUpDownAsKeysLeftRight
-                || _barItems.SubMenu (_barItems.Children [_currentChild]) == null
+                || _barItems.SubMenu (_barItems.Children [_currentChild]!) == null!
                 || disabled
                 || !_host.IsMenuOpen)
             {
@@ -786,8 +810,8 @@ internal sealed class Menu : View
             }
         }
 
-        _host?._openMenu?.SetNeedsDisplay ();
-        _host?.SetNeedsDisplay ();
+        _host._openMenu?.SetNeedsDisplay ();
+        _host.SetNeedsDisplay ();
     }
 
     protected internal override bool OnMouseEvent (MouseEvent me)
@@ -809,13 +833,14 @@ internal sealed class Menu : View
                 return me.Handled = true;
             }
 
-            if (me.Position.Y >= _barItems.Children.Length)
+            if (me.Position.Y >= _barItems!.Children!.Length)
             {
                 return me.Handled = true;
             }
 
-            MenuItem item = _barItems.Children [me.Position.Y];
+            MenuItem item = _barItems.Children [me.Position.Y]!;
 
+            // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
             if (item is null || !item.IsEnabled ())
             {
                 disabled = true;
@@ -844,19 +869,20 @@ internal sealed class Menu : View
         {
             disabled = false;
 
-            if (me.Position.Y < 0 || me.Position.Y >= _barItems.Children.Length)
+            if (me.Position.Y < 0 || me.Position.Y >= _barItems!.Children!.Length)
             {
                 return me.Handled = true;
             }
 
-            MenuItem item = _barItems.Children [me.Position.Y];
+            MenuItem item = _barItems.Children [me.Position.Y]!;
 
+            // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
             if (item is null)
             {
                 return me.Handled = true;
             }
 
-            if (item?.IsEnabled () != true)
+            if (item.IsEnabled () != true)
             {
                 disabled = true;
             }
@@ -882,25 +908,26 @@ internal sealed class Menu : View
 
     internal bool CheckSubMenu ()
     {
-        if (_currentChild == -1 || _barItems.Children [_currentChild] is null)
+        if (_currentChild == -1 || _barItems?.Children? [_currentChild] is null)
         {
             return true;
         }
 
-        MenuBarItem subMenu = _barItems.SubMenu (_barItems.Children [_currentChild]);
+        MenuBarItem? subMenu = _barItems.SubMenu (_barItems.Children [_currentChild]!);
 
+        // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
         if (subMenu is { })
         {
             int pos = -1;
 
             if (_host._openSubMenu is { })
             {
-                pos = _host._openSubMenu.FindIndex (o => o?._barItems == subMenu);
+                pos = _host._openSubMenu.FindIndex (o => o._barItems == subMenu);
             }
 
             if (pos == -1
                 && this != _host.OpenCurrentMenu
-                && subMenu.Children != _host.OpenCurrentMenu._barItems.Children
+                && subMenu.Children != _host.OpenCurrentMenu!._barItems!.Children
                 && !_host.CloseMenu (false, true))
             {
                 return false;
@@ -908,7 +935,7 @@ internal sealed class Menu : View
 
             _host.Activate (_host._selected, pos, subMenu);
         }
-        else if (_host._openSubMenu?.Count == 0 || _host._openSubMenu?.Last ()._barItems.IsSubMenuOf (_barItems.Children [_currentChild]) == false)
+        else if (_host._openSubMenu?.Count == 0 || _host._openSubMenu?.Last ()._barItems!.IsSubMenuOf (_barItems.Children [_currentChild]!) == false)
         {
             return _host.CloseMenu (false, true);
         }

+ 138 - 128
Terminal.Gui/Views/Menu/MenuBar.cs

@@ -1,3 +1,5 @@
+#nullable enable
+
 namespace Terminal.Gui;
 
 /// <summary>
@@ -50,24 +52,22 @@ public class MenuBar : View, IDesignable
     internal bool _isMenuClosing;
     internal bool _isMenuOpening;
 
-    internal Menu _openMenu;
-    internal List<Menu> _openSubMenu;
+    internal Menu? _openMenu;
+    internal List<Menu>? _openSubMenu;
     internal int _selected;
     internal int _selectedSub;
 
     private bool _initialCanFocus;
     private bool _isCleaning;
-    private View _lastFocused;
-    private Menu _ocm;
-    private View _previousFocused;
+    private View? _lastFocused;
+    private Menu? _ocm;
+    private View? _previousFocused;
     private bool _reopen;
     private bool _useSubMenusSingleFrame;
 
     /// <summary>Initializes a new instance of the <see cref="MenuBar"/>.</summary>
     public MenuBar ()
     {
-        MenuItem._menuBar = this;
-
         TabStop = TabBehavior.NoStop;
         X = 0;
         Y = 0;
@@ -78,7 +78,9 @@ public class MenuBar : View, IDesignable
         //CanFocus = true;
         _selected = -1;
         _selectedSub = -1;
+        // ReSharper disable once VirtualMemberCallInConstructor
         ColorScheme = Colors.ColorSchemes ["Menu"];
+        // ReSharper disable once VirtualMemberCallInConstructor
         WantMousePositionReports = true;
         IsMenuOpen = false;
 
@@ -124,8 +126,19 @@ public class MenuBar : View, IDesignable
                         return true;
                     }
                    );
-        AddCommand (Command.ToggleExpandCollapse, ctx => Select (Menus.IndexOf (ctx.KeyBinding?.Context)));
-        AddCommand (Command.Select, ctx => Run ((ctx.KeyBinding?.Context as MenuItem)?.Action));
+        AddCommand (Command.ToggleExpandCollapse, ctx =>
+                                                  {
+                                                      CloseOtherOpenedMenuBar ();
+
+                                                      return Select (Menus.IndexOf (ctx.KeyBinding?.Context));
+                                                  });
+        AddCommand (Command.Select, ctx =>
+                                    {
+                                        var res =  Run ((ctx.KeyBinding?.Context as MenuItem)?.Action!);
+                                        CloseAllMenus ();
+
+                                        return res;
+                                    });
 
         // Default key bindings for this view
         KeyBindings.Add (Key.CursorLeft, Command.Left);
@@ -150,7 +163,7 @@ public class MenuBar : View, IDesignable
     public bool IsMenuOpen { get; protected set; }
 
     /// <summary>Gets the view that was last focused before opening the menu.</summary>
-    public View LastFocused { get; private set; }
+    public View? LastFocused { get; private set; }
 
     /// <summary>
     ///     Gets or sets the array of <see cref="MenuBarItem"/>s for the menu. Only set this after the
@@ -164,7 +177,7 @@ public class MenuBar : View, IDesignable
         {
             _menus = value;
 
-            if (Menus is null)
+            if (Menus is [])
             {
                 return;
             }
@@ -174,26 +187,26 @@ public class MenuBar : View, IDesignable
             {
                 MenuBarItem menuBarItem = Menus [i];
 
-                if (menuBarItem?.HotKey != Key.Empty)
+                if (menuBarItem.HotKey != Key.Empty)
                 {
-                    KeyBindings.Remove (menuBarItem!.HotKey);
+                    KeyBindings.Remove (menuBarItem.HotKey!);
                     KeyBinding keyBinding = new ([Command.ToggleExpandCollapse], KeyBindingScope.Focused, menuBarItem);
-                    KeyBindings.Add (menuBarItem!.HotKey, keyBinding);
-                    KeyBindings.Remove (menuBarItem.HotKey.WithAlt);
+                    KeyBindings.Add (menuBarItem.HotKey!, keyBinding);
+                    KeyBindings.Remove (menuBarItem.HotKey!.WithAlt);
                     keyBinding = new ([Command.ToggleExpandCollapse], KeyBindingScope.HotKey, menuBarItem);
                     KeyBindings.Add (menuBarItem.HotKey.WithAlt, keyBinding);
                 }
 
-                if (menuBarItem?.ShortcutKey != Key.Empty)
+                if (menuBarItem.ShortcutKey != Key.Empty)
                 {
                     // Technically this will never run because MenuBarItems don't have shortcuts
                     // unless the IsTopLevel is true
-                    KeyBindings.Remove (menuBarItem.ShortcutKey);
+                    KeyBindings.Remove (menuBarItem.ShortcutKey!);
                     KeyBinding keyBinding = new ([Command.Select], KeyBindingScope.HotKey, menuBarItem);
-                    KeyBindings.Add (menuBarItem.ShortcutKey, keyBinding);
+                    KeyBindings.Add (menuBarItem.ShortcutKey!, keyBinding);
                 }
 
-                menuBarItem?.AddShortcutKeyBindings (this);
+                menuBarItem.AddShortcutKeyBindings (this);
             }
         }
     }
@@ -244,16 +257,16 @@ public class MenuBar : View, IDesignable
         }
     }
 
-    internal Menu OpenCurrentMenu
+    internal Menu? OpenCurrentMenu
     {
         get => _ocm;
         set
         {
             if (_ocm != value)
             {
-                _ocm = value;
+                _ocm = value!;
 
-                if (_ocm is { } && _ocm._currentChild > -1)
+                if (_ocm is { _currentChild: > -1 })
                 {
                     OnMenuOpened ();
                 }
@@ -265,16 +278,16 @@ public class MenuBar : View, IDesignable
     public bool CloseMenu (bool ignoreUseSubMenusSingleFrame = false) { return CloseMenu (false, false, ignoreUseSubMenusSingleFrame); }
 
     /// <summary>Raised when all the menu is closed.</summary>
-    public event EventHandler MenuAllClosed;
+    public event EventHandler? MenuAllClosed;
 
     /// <summary>Raised when a menu is closing passing <see cref="MenuClosingEventArgs"/>.</summary>
-    public event EventHandler<MenuClosingEventArgs> MenuClosing;
+    public event EventHandler<MenuClosingEventArgs>? MenuClosing;
 
     /// <summary>Raised when a menu is opened.</summary>
-    public event EventHandler<MenuOpenedEventArgs> MenuOpened;
+    public event EventHandler<MenuOpenedEventArgs>? MenuOpened;
 
     /// <summary>Raised as a menu is opening.</summary>
-    public event EventHandler<MenuOpeningEventArgs> MenuOpening;
+    public event EventHandler<MenuOpeningEventArgs>? MenuOpening;
 
     /// <inheritdoc/>
     public override void OnDrawContent (Rectangle viewport)
@@ -338,25 +351,24 @@ public class MenuBar : View, IDesignable
     /// <summary>Virtual method that will invoke the <see cref="MenuOpened"/> event if it's defined.</summary>
     public virtual void OnMenuOpened ()
     {
-        MenuItem mi = null;
-        MenuBarItem parent;
+        MenuItem? mi;
+        MenuBarItem? parent;
 
-        if (OpenCurrentMenu.BarItems.Children != null
-            && OpenCurrentMenu.BarItems!.Children.Length > 0
+        if (OpenCurrentMenu?.BarItems?.Children is { Length: > 0 }
             && OpenCurrentMenu?._currentChild > -1)
         {
             parent = OpenCurrentMenu.BarItems;
             mi = parent.Children [OpenCurrentMenu._currentChild];
         }
-        else if (OpenCurrentMenu!.BarItems.IsTopLevel)
+        else if (OpenCurrentMenu!.BarItems!.IsTopLevel)
         {
             parent = null;
             mi = OpenCurrentMenu.BarItems;
         }
         else
         {
-            parent = _openMenu.BarItems;
-            mi = parent.Children?.Length > 0 ? parent.Children [_openMenu._currentChild] : null;
+            parent = _openMenu?.BarItems;
+            mi = parent?.Children?.Length > 0 ? parent.Children [_openMenu!._currentChild] : null;
         }
 
         MenuOpened?.Invoke (this, new (parent, mi));
@@ -376,12 +388,11 @@ public class MenuBar : View, IDesignable
     /// <summary>Opens the Menu programatically, as though the F9 key were pressed.</summary>
     public void OpenMenu ()
     {
-        MenuBar mbar = GetMouseGrabViewInstance (this);
+        MenuBar? mbar = GetMouseGrabViewInstance (this);
 
-        if (mbar is { })
-        {
-            mbar.CleanUp ();
-        }
+        mbar?.CleanUp ();
+
+        CloseOtherOpenedMenuBar ();
 
         if (!Enabled || _openMenu is { })
         {
@@ -391,15 +402,15 @@ public class MenuBar : View, IDesignable
         _selected = 0;
         SetNeedsDisplay ();
 
-        _previousFocused = SuperView is null ? Application.Current?.Focused : SuperView.Focused;
+        _previousFocused = (SuperView is null ? Application.Current?.Focused : SuperView.Focused)!;
         OpenMenu (_selected);
 
         if (!SelectEnabledItem (
-                                OpenCurrentMenu.BarItems.Children,
-                                OpenCurrentMenu._currentChild,
+                                OpenCurrentMenu?.BarItems?.Children,
+                                OpenCurrentMenu!._currentChild,
                                 out OpenCurrentMenu._currentChild
                                )
-            && !CloseMenu (false))
+            && !CloseMenu ())
         {
             return;
         }
@@ -445,14 +456,14 @@ public class MenuBar : View, IDesignable
 
     // Activates the menu, handles either first focus, or activating an entry when it was already active
     // For mouse events.
-    internal void Activate (int idx, int sIdx = -1, MenuBarItem subMenu = null)
+    internal void Activate (int idx, int sIdx = -1, MenuBarItem? subMenu = null!)
     {
         _selected = idx;
         _selectedSub = sIdx;
 
         if (_openMenu is null)
         {
-            _previousFocused = SuperView is null ? Application.Current?.Focused ?? null : SuperView.Focused;
+            _previousFocused = (SuperView is null ? Application.Current?.Focused ?? null : SuperView.Focused)!;
         }
 
         OpenMenu (idx, sIdx, subMenu);
@@ -502,7 +513,7 @@ public class MenuBar : View, IDesignable
                 return;
             }
 
-            if (!CloseMenu (false))
+            if (!CloseMenu ())
             {
                 return;
             }
@@ -523,11 +534,23 @@ public class MenuBar : View, IDesignable
         IsMenuOpen = false;
         _openedByAltKey = false;
         OnMenuAllClosed ();
+
+        CloseOtherOpenedMenuBar ();
     }
 
-    internal bool CloseMenu (bool reopen = false, bool isSubMenu = false, bool ignoreUseSubMenusSingleFrame = false)
+    private void CloseOtherOpenedMenuBar ()
     {
-        MenuBarItem mbi = isSubMenu ? OpenCurrentMenu.BarItems : _openMenu?.BarItems;
+        if (Application.Current is { })
+        {
+            // Close others menu bar opened
+            Menu? menu = Application.Current.Subviews.FirstOrDefault (v => v is Menu m && m.Host != this && m.Host.IsMenuOpen) as Menu;
+            menu?.Host.CleanUp ();
+        }
+    }
+
+    internal bool CloseMenu (bool reopen, bool isSubMenu, bool ignoreUseSubMenusSingleFrame = false)
+    {
+        MenuBarItem? mbi = isSubMenu ? OpenCurrentMenu!.BarItems : _openMenu?.BarItems;
 
         if (UseSubMenusSingleFrame && mbi is { } && !ignoreUseSubMenusSingleFrame && mbi.Parent is { })
         {
@@ -536,7 +559,7 @@ public class MenuBar : View, IDesignable
 
         _isMenuClosing = true;
         _reopen = reopen;
-        MenuClosingEventArgs args = OnMenuClosing (mbi, reopen, isSubMenu);
+        MenuClosingEventArgs args = OnMenuClosing (mbi!, reopen, isSubMenu);
 
         if (args.Cancel)
         {
@@ -561,7 +584,7 @@ public class MenuBar : View, IDesignable
 
                 SetNeedsDisplay ();
 
-                if (_previousFocused is Menu && _openMenu is { } && _previousFocused.ToString () != OpenCurrentMenu.ToString ())
+                if (_previousFocused is Menu && _openMenu is { } && _previousFocused.ToString () != OpenCurrentMenu!.ToString ())
                 {
                     _previousFocused.SetFocus ();
                 }
@@ -615,7 +638,7 @@ public class MenuBar : View, IDesignable
                 _selectedSub = -1;
                 SetNeedsDisplay ();
                 RemoveAllOpensSubMenus ();
-                OpenCurrentMenu._previousSubFocused.SetFocus ();
+                OpenCurrentMenu!._previousSubFocused!.SetFocus ();
                 _openSubMenu = null;
                 IsMenuOpen = true;
 
@@ -632,13 +655,14 @@ public class MenuBar : View, IDesignable
     /// <returns>The location offset.</returns>
     internal Point GetScreenOffset ()
     {
+        // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
         if (Driver is null)
         {
             return Point.Empty;
         }
 
-        Rectangle superViewFrame = SuperView is null ? Application.Screen : SuperView.Frame;
-        View sv = SuperView is null ? Application.Current : SuperView;
+        Rectangle superViewFrame = SuperView?.Frame ?? Application.Screen;
+        View? sv = SuperView ?? Application.Current;
 
         if (sv is null)
         {
@@ -646,7 +670,7 @@ public class MenuBar : View, IDesignable
             return Point.Empty;
         }
 
-        Point viewportOffset = sv?.GetViewportOffsetFromFrame () ?? Point.Empty;
+        Point viewportOffset = sv.GetViewportOffsetFromFrame ();
 
         return new (
                     superViewFrame.X - sv.Frame.X - viewportOffset.X,
@@ -680,8 +704,8 @@ public class MenuBar : View, IDesignable
                 OpenMenu (_selected);
 
                 SelectEnabledItem (
-                                   OpenCurrentMenu.BarItems.Children,
-                                   OpenCurrentMenu._currentChild,
+                                   OpenCurrentMenu?.BarItems?.Children,
+                                   OpenCurrentMenu!._currentChild,
                                    out OpenCurrentMenu._currentChild
                                   );
 
@@ -696,9 +720,9 @@ public class MenuBar : View, IDesignable
                 }
                 else
                 {
-                    MenuBarItem subMenu = OpenCurrentMenu._currentChild > -1 && OpenCurrentMenu.BarItems.Children.Length > 0
+                    MenuBarItem? subMenu = OpenCurrentMenu!._currentChild > -1 && OpenCurrentMenu.BarItems?.Children!.Length > 0
                                               ? OpenCurrentMenu.BarItems.SubMenu (
-                                                                                  OpenCurrentMenu.BarItems.Children [OpenCurrentMenu._currentChild]
+                                                                                  OpenCurrentMenu.BarItems.Children? [OpenCurrentMenu._currentChild]!
                                                                                  )
                                               : null;
 
@@ -713,8 +737,8 @@ public class MenuBar : View, IDesignable
                     }
                     else if (subMenu != null
                              || (OpenCurrentMenu._currentChild > -1
-                                 && !OpenCurrentMenu.BarItems
-                                                    .Children [OpenCurrentMenu._currentChild]
+                                 && !OpenCurrentMenu.BarItems!
+                                                    .Children! [OpenCurrentMenu._currentChild]!
                                                     .IsFromSubMenu))
                     {
                         _selectedSub++;
@@ -742,7 +766,7 @@ public class MenuBar : View, IDesignable
         }
     }
 
-    internal void OpenMenu (int index, int sIndex = -1, MenuBarItem subMenu = null)
+    internal void OpenMenu (int index, int sIndex = -1, MenuBarItem? subMenu = null!)
     {
         _isMenuOpening = true;
         MenuOpeningEventArgs newMenu = OnMenuOpening (Menus [index]);
@@ -780,7 +804,7 @@ public class MenuBar : View, IDesignable
                 }
 
                 // This positions the submenu horizontally aligned with the first character of the
-                // text belonging to the menu 
+                // text belonging to the menu
                 for (var i = 0; i < index; i++)
                 {
                     pos += Menus [i].TitleLength + (Menus [i].Help.GetColumns () > 0 ? Menus [i].Help.GetColumns () + 2 : 0) + _leftPadding + _rightPadding;
@@ -837,7 +861,7 @@ public class MenuBar : View, IDesignable
                 }
                 else
                 {
-                    Menu last = _openSubMenu.Count > 0 ? _openSubMenu.Last () : _openMenu;
+                    Menu? last = _openSubMenu.Count > 0 ? _openSubMenu.Last () : _openMenu;
 
                     if (!UseSubMenusSingleFrame)
                     {
@@ -846,7 +870,7 @@ public class MenuBar : View, IDesignable
                         OpenCurrentMenu = new ()
                         {
                             Host = this,
-                            X = last.Frame.Left + last.Frame.Width + locationOffset.X,
+                            X = last!.Frame.Left + last.Frame.Width + locationOffset.X,
                             Y = last.Frame.Top + locationOffset.Y + last._currentChild,
                             BarItems = subMenu,
                             Parent = last
@@ -854,10 +878,10 @@ public class MenuBar : View, IDesignable
                     }
                     else
                     {
-                        Menu first = _openSubMenu.Count > 0 ? _openSubMenu.First () : _openMenu;
+                        Menu? first = _openSubMenu.Count > 0 ? _openSubMenu.First () : _openMenu;
 
                         // 2 is for the parent and the separator
-                        MenuItem [] mbi = new MenuItem [2 + subMenu.Children.Length];
+                        MenuItem? [] mbi = new MenuItem [2 + subMenu.Children!.Length];
                         mbi [0] = new () { Title = subMenu.Title, Parent = subMenu };
                         mbi [1] = null;
 
@@ -866,13 +890,13 @@ public class MenuBar : View, IDesignable
                             mbi [j + 2] = subMenu.Children [j];
                         }
 
-                        var newSubMenu = new MenuBarItem (mbi) { Parent = subMenu };
+                        var newSubMenu = new MenuBarItem (mbi!) { Parent = subMenu };
 
                         OpenCurrentMenu = new ()
                         {
-                            Host = this, X = first.Frame.Left, Y = first.Frame.Top, BarItems = newSubMenu
+                            Host = this, X = first!.Frame.Left, Y = first.Frame.Top, BarItems = newSubMenu
                         };
-                        last.Visible = false;
+                        last!.Visible = false;
                         Application.GrabMouse (OpenCurrentMenu);
                     }
 
@@ -892,7 +916,7 @@ public class MenuBar : View, IDesignable
 
                 if (_selectedSub > -1
                     && SelectEnabledItem (
-                                          OpenCurrentMenu.BarItems.Children,
+                                          OpenCurrentMenu!.BarItems!.Children,
                                           OpenCurrentMenu._currentChild,
                                           out OpenCurrentMenu._currentChild
                                          ))
@@ -929,8 +953,8 @@ public class MenuBar : View, IDesignable
                 OpenMenu (_selected);
 
                 if (!SelectEnabledItem (
-                                        OpenCurrentMenu.BarItems.Children,
-                                        OpenCurrentMenu._currentChild,
+                                        OpenCurrentMenu?.BarItems?.Children,
+                                        OpenCurrentMenu!._currentChild,
                                         out OpenCurrentMenu._currentChild,
                                         false
                                        ))
@@ -961,33 +985,33 @@ public class MenuBar : View, IDesignable
         {
             foreach (Menu item in _openSubMenu)
             {
-                Application.Current.Remove (item);
+                Application.Current!.Remove (item);
                 item.Dispose ();
             }
         }
     }
 
-    internal bool Run (Action action)
+    internal bool Run (Action? action)
     {
         if (action is null)
         {
             return false;
         }
 
-        Application.MainLoop.AddIdle (
-                                      () =>
-                                      {
-                                          action ();
+        Application.MainLoop!.AddIdle (
+                                       () =>
+                                       {
+                                           action ();
 
-                                          return false;
-                                      }
-                                     );
+                                           return false;
+                                       }
+                                      );
 
         return true;
     }
 
     internal bool SelectEnabledItem (
-        IEnumerable<MenuItem> children,
+        MenuItem? []? children,
         int current,
         out int newCurrent,
         bool forward = true
@@ -1000,11 +1024,11 @@ public class MenuBar : View, IDesignable
             return true;
         }
 
-        IEnumerable<MenuItem> childMenuItems = forward ? children : children.Reverse ();
+        IEnumerable<MenuItem?> childMenuItems = forward ? children : children.Reverse ();
 
         int count;
 
-        IEnumerable<MenuItem> menuItems = childMenuItems as MenuItem [] ?? childMenuItems.ToArray ();
+        IEnumerable<MenuItem?> menuItems = childMenuItems as MenuItem [] ?? childMenuItems.ToArray ();
 
         if (forward)
         {
@@ -1015,7 +1039,7 @@ public class MenuBar : View, IDesignable
             count = menuItems.Count ();
         }
 
-        foreach (MenuItem child in menuItems)
+        foreach (MenuItem? child in menuItems)
         {
             if (forward)
             {
@@ -1032,6 +1056,7 @@ public class MenuBar : View, IDesignable
                 }
             }
 
+            // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
             if (child is null || !child.IsEnabled ())
             {
                 if (forward)
@@ -1058,7 +1083,7 @@ public class MenuBar : View, IDesignable
 
     /// <summary>Called when an item is selected; Runs the action.</summary>
     /// <param name="item"></param>
-    internal bool SelectItem (MenuItem item)
+    internal bool SelectItem (MenuItem? item)
     {
         if (item?.Action is null)
         {
@@ -1070,12 +1095,12 @@ public class MenuBar : View, IDesignable
         Application.Refresh ();
         _openedByAltKey = true;
 
-        return Run (item?.Action);
+        return Run (item.Action);
     }
 
     private void CloseMenuBar ()
     {
-        if (!CloseMenu (false))
+        if (!CloseMenu ())
         {
             return;
         }
@@ -1099,7 +1124,7 @@ public class MenuBar : View, IDesignable
         return new (-2, 0);
     }
 
-    private void MenuBar_Added (object sender, SuperViewChangedEventArgs e)
+    private void MenuBar_Added (object? sender, SuperViewChangedEventArgs e)
     {
         _initialCanFocus = CanFocus;
         Added -= MenuBar_Added;
@@ -1146,11 +1171,11 @@ public class MenuBar : View, IDesignable
             OpenMenu (i);
 
             if (!SelectEnabledItem (
-                                    OpenCurrentMenu.BarItems.Children,
-                                    OpenCurrentMenu._currentChild,
+                                    OpenCurrentMenu?.BarItems?.Children,
+                                    OpenCurrentMenu!._currentChild,
                                     out OpenCurrentMenu._currentChild
                                    )
-                && !CloseMenu (false))
+                && !CloseMenu ())
             {
                 return;
             }
@@ -1177,9 +1202,9 @@ public class MenuBar : View, IDesignable
         for (int i = _openSubMenu.Count - 1; i > index; i--)
         {
             _isMenuClosing = true;
-            Menu menu;
+            Menu? menu;
 
-            if (_openSubMenu.Count - 1 > 0)
+            if (_openSubMenu!.Count - 1 > 0)
             {
                 menu = _openSubMenu [i - 1];
             }
@@ -1188,7 +1213,7 @@ public class MenuBar : View, IDesignable
                 menu = _openMenu;
             }
 
-            if (!menu.Visible)
+            if (!menu!.Visible)
             {
                 menu.Visible = true;
             }
@@ -1199,7 +1224,7 @@ public class MenuBar : View, IDesignable
             if (_openSubMenu is { })
             {
                 menu = _openSubMenu [i];
-                Application.Current.Remove (menu);
+                Application.Current!.Remove (menu);
                 _openSubMenu.Remove (menu);
 
                 if (Application.MouseGrabView == menu)
@@ -1213,7 +1238,7 @@ public class MenuBar : View, IDesignable
             RemoveSubMenu (i, ignoreUseSubMenusSingleFrame);
         }
 
-        if (_openSubMenu.Count > 0)
+        if (_openSubMenu!.Count > 0)
         {
             OpenCurrentMenu = _openSubMenu.Last ();
         }
@@ -1305,12 +1330,7 @@ public class MenuBar : View, IDesignable
             {
                 MenuBarItem open = Menus [i];
 
-                if (open is null)
-                {
-                    continue;
-                }
-
-                if (open == OpenCurrentMenu.BarItems && i == index)
+                if (open == OpenCurrentMenu!.BarItems && i == index)
                 {
                     CloseAllMenus ();
                     return true;
@@ -1338,15 +1358,12 @@ public class MenuBar : View, IDesignable
 
     #region Mouse Handling
 
-    /// <inheritdoc/>
     internal void LostFocus (View view)
     {
-        if (((!(view is MenuBar) && !(view is Menu))) && !_isCleaning && !_reopen)
+        if (view is not MenuBar && view is not Menu && !_isCleaning && !_reopen)
         {
             CleanUp ();
         }
-
-        return;
     }
 
     /// <inheritdoc/>
@@ -1411,7 +1428,7 @@ public class MenuBar : View, IDesignable
                     else if (_selected != i
                              && _selected > -1
                              && (me.Flags == MouseFlags.ReportMousePosition
-                                 || (me.Flags == MouseFlags.Button1Pressed && me.Flags == MouseFlags.ReportMousePosition)))
+                                 || (me.Flags is MouseFlags.Button1Pressed && me.Flags == MouseFlags.ReportMousePosition)))
                     {
                         if (IsMenuOpen)
                         {
@@ -1427,8 +1444,7 @@ public class MenuBar : View, IDesignable
                     {
                         if (!UseSubMenusSingleFrame
                             || (UseSubMenusSingleFrame
-                                && OpenCurrentMenu != null
-                                && OpenCurrentMenu.BarItems.Parent != null
+                                && OpenCurrentMenu is { BarItems.Parent: { } }
                                 && OpenCurrentMenu.BarItems.Parent.Parent != Menus [i]))
                         {
                             Activate (i);
@@ -1457,15 +1473,15 @@ public class MenuBar : View, IDesignable
 
     internal bool _handled;
     internal bool _isContextMenuLoading;
-    private MenuBarItem [] _menus;
+    private MenuBarItem [] _menus = [];
 
     internal bool HandleGrabView (MouseEvent me, View current)
     {
         if (Application.MouseGrabView is { })
         {
-            if (me.View is MenuBar || me.View is Menu)
+            if (me.View is MenuBar or Menu)
             {
-                MenuBar mbar = GetMouseGrabViewInstance (me.View);
+                MenuBar? mbar = GetMouseGrabViewInstance (me.View);
 
                 if (mbar is { })
                 {
@@ -1563,14 +1579,14 @@ public class MenuBar : View, IDesignable
         return true;
     }
 
-    private MenuBar GetMouseGrabViewInstance (View view)
+    private MenuBar? GetMouseGrabViewInstance (View? view)
     {
         if (view is null || Application.MouseGrabView is null)
         {
             return null;
         }
 
-        MenuBar hostView = null;
+        MenuBar? hostView = null;
 
         if (view is MenuBar)
         {
@@ -1582,15 +1598,15 @@ public class MenuBar : View, IDesignable
         }
 
         View grabView = Application.MouseGrabView;
-        MenuBar hostGrabView = null;
+        MenuBar? hostGrabView = null;
 
-        if (grabView is MenuBar)
+        if (grabView is MenuBar bar)
         {
-            hostGrabView = (MenuBar)grabView;
+            hostGrabView = bar;
         }
-        else if (grabView is Menu)
+        else if (grabView is Menu menu)
         {
-            hostGrabView = ((Menu)grabView).Host;
+            hostGrabView = menu.Host;
         }
 
         return hostView != hostGrabView ? hostGrabView : null;
@@ -1604,7 +1620,7 @@ public class MenuBar : View, IDesignable
     {
         if (context is not Func<string, bool> actionFn)
         {
-            actionFn = (s) => true;
+            actionFn = (_) => true;
         }
 
         Menus =
@@ -1637,7 +1653,9 @@ public class MenuBar : View, IDesignable
                                       null,
                                       KeyCode.CtrlMask | KeyCode.S
                                      ),
+#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
                                  null,
+#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type.
 
                                  // Don't use Application.Quit so we can disambiguate between quitting and closing the toplevel
                                  new (
@@ -1770,12 +1788,4 @@ public class MenuBar : View, IDesignable
         ];
         return true;
     }
-
-    /// <inheritdoc />
-    protected override void Dispose (bool disposing)
-    {
-        MenuItem._menuBar = null;
-
-        base.Dispose (disposing);
-    }
 }

+ 39 - 23
Terminal.Gui/Views/Menu/MenuBarItem.cs

@@ -1,3 +1,5 @@
+#nullable enable
+
 namespace Terminal.Gui;
 
 /// <summary>
@@ -16,8 +18,8 @@ public class MenuBarItem : MenuItem
         string title,
         string help,
         Action action,
-        Func<bool> canExecute = null,
-        MenuItem parent = null
+        Func<bool>? canExecute = null,
+        MenuItem? parent = null
     ) : base (title, help, action, canExecute, parent)
     {
         SetInitialProperties (title, null, null, true);
@@ -27,13 +29,13 @@ public class MenuBarItem : MenuItem
     /// <param name="title">Title for the menu item.</param>
     /// <param name="children">The items in the current menu.</param>
     /// <param name="parent">The parent <see cref="MenuItem"/> of this if any.</param>
-    public MenuBarItem (string title, MenuItem [] children, MenuItem parent = null) { SetInitialProperties (title, children, parent); }
+    public MenuBarItem (string title, MenuItem [] children, MenuItem? parent = null) { SetInitialProperties (title, children, parent); }
 
     /// <summary>Initializes a new <see cref="MenuBarItem"/> with separate list of items.</summary>
     /// <param name="title">Title for the menu item.</param>
     /// <param name="children">The list of items in the current menu.</param>
     /// <param name="parent">The parent <see cref="MenuItem"/> of this if any.</param>
-    public MenuBarItem (string title, List<MenuItem []> children, MenuItem parent = null) { SetInitialProperties (title, children, parent); }
+    public MenuBarItem (string title, List<MenuItem []> children, MenuItem? parent = null) { SetInitialProperties (title, children, parent); }
 
     /// <summary>Initializes a new <see cref="MenuBarItem"/>.</summary>
     /// <param name="children">The items in the current menu.</param>
@@ -47,7 +49,7 @@ public class MenuBarItem : MenuItem
     ///     <see cref="MenuBarItem"/>
     /// </summary>
     /// <value>The children.</value>
-    public MenuItem [] Children { get; set; }
+    public MenuItem? []? Children { get; set; }
 
     internal bool IsTopLevel => Parent is null && (Children is null || Children.Length == 0) && Action != null;
 
@@ -63,7 +65,7 @@ public class MenuBarItem : MenuItem
             return -1;
         }
 
-        foreach (MenuItem child in Children)
+        foreach (MenuItem? child in Children)
         {
             if (child == children)
             {
@@ -81,13 +83,13 @@ public class MenuBarItem : MenuItem
     /// <returns>Returns <c>true</c> if it is a submenu. <c>false</c> otherwise.</returns>
     public bool IsSubMenuOf (MenuItem menuItem)
     {
-        return Children.Any (child => child == menuItem && child.Parent == menuItem.Parent);
+        return Children!.Any (child => child == menuItem && child.Parent == menuItem.Parent);
     }
 
     /// <summary>Check if a <see cref="MenuItem"/> is a <see cref="MenuBarItem"/>.</summary>
     /// <param name="menuItem"></param>
     /// <returns>Returns a <see cref="MenuBarItem"/> or null otherwise.</returns>
-    public MenuBarItem SubMenu (MenuItem menuItem) { return menuItem as MenuBarItem; }
+    public MenuBarItem? SubMenu (MenuItem? menuItem) { return menuItem as MenuBarItem; }
 
     internal void AddShortcutKeyBindings (MenuBar menuBar)
     {
@@ -96,20 +98,27 @@ public class MenuBarItem : MenuItem
             return;
         }
 
-        foreach (MenuItem menuItem in Children.Where (m => m is { }))
+        _menuBar = menuBar;
+
+        IEnumerable<MenuItem> menuItems = Children.Where (m => m is { })!;
+
+        foreach (MenuItem menuItem in menuItems)
         {
-            // For MenuBar only add shortcuts for submenus
+            // Initialize MenuItem _menuBar
+            menuItem._menuBar = menuBar;
 
+            // For MenuBar only add shortcuts for submenus
             if (menuItem.ShortcutKey != Key.Empty)
             {
-                menuItem.UpdateShortcutKeyBinding (Key.Empty);
+                menuItem.AddShortcutKeyBinding (menuBar, Key.Empty);
             }
 
             SubMenu (menuItem)?.AddShortcutKeyBindings (menuBar);
         }
     }
 
-    private void SetInitialProperties (string title, object children, MenuItem parent = null, bool isTopLevel = false)
+    // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local
+    private void SetInitialProperties (string title, object? children, MenuItem? parent = null, bool isTopLevel = false)
     {
         if (!isTopLevel && children is null)
         {
@@ -119,7 +128,7 @@ public class MenuBarItem : MenuItem
                                             );
         }
 
-        SetTitle (title ?? "");
+        SetTitle (title);
 
         if (parent is { })
         {
@@ -169,7 +178,7 @@ public class MenuBarItem : MenuItem
         }
     }
 
-    private void SetTitle (string title)
+    private void SetTitle (string? title)
     {
         title ??= string.Empty;
         Title = title;
@@ -178,9 +187,14 @@ public class MenuBarItem : MenuItem
     /// <summary>
     /// Add a <see cref="MenuBarItem"/> dynamically into the <see cref="MenuBar"/><c>.Menus</c>.
     /// </summary>
+    /// <param name="menuBar"></param>
     /// <param name="menuItem"></param>
-    public void AddMenuBarItem (MenuItem menuItem = null)
+    public void AddMenuBarItem (MenuBar menuBar, MenuItem? menuItem = null)
     {
+        ArgumentNullException.ThrowIfNull (menuBar);
+
+        _menuBar = menuBar;
+
         if (menuItem is null)
         {
             MenuBarItem [] menus = _menuBar.Menus;
@@ -190,8 +204,9 @@ public class MenuBarItem : MenuItem
         }
         else
         {
-            MenuItem [] childrens = Children ?? [];
+            MenuItem [] childrens = (Children ?? [])!;
             Array.Resize (ref childrens, childrens.Length + 1);
+            menuItem._menuBar = menuBar;
             childrens [^1] = menuItem;
             Children = childrens;
         }
@@ -202,12 +217,12 @@ public class MenuBarItem : MenuItem
     {
         if (Children is { })
         {
-            foreach (MenuItem menuItem in Children)
+            foreach (MenuItem? menuItem in Children)
             {
-                if (menuItem.ShortcutKey != Key.Empty)
+                if (menuItem?.ShortcutKey != Key.Empty)
                 {
                     // Remove an existent ShortcutKey
-                    _menuBar?.KeyBindings.Remove (menuItem.ShortcutKey);
+                    _menuBar?.KeyBindings.Remove (menuItem?.ShortcutKey!);
                 }
             }
         }
@@ -215,25 +230,26 @@ public class MenuBarItem : MenuItem
         if (ShortcutKey != Key.Empty)
         {
             // Remove an existent ShortcutKey
-            _menuBar?.KeyBindings.Remove (ShortcutKey);
+            _menuBar?.KeyBindings.Remove (ShortcutKey!);
         }
 
         var index = _menuBar!.Menus.IndexOf (this);
         if (index > -1)
         {
-            if (_menuBar!.Menus [index].HotKey != Key.Empty)
+            if (_menuBar.Menus [index].HotKey != Key.Empty)
             {
                 // Remove an existent HotKey
-                _menuBar?.KeyBindings.Remove (HotKey.WithAlt);
+                _menuBar.KeyBindings.Remove (HotKey!.WithAlt);
             }
 
-            _menuBar!.Menus [index] = null;
+            _menuBar.Menus [index] = null!;
         }
 
         var i = 0;
 
         foreach (MenuBarItem m in _menuBar.Menus)
         {
+            // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
             if (m != null)
             {
                 _menuBar.Menus [i] = m;

+ 58 - 41
Terminal.Gui/Views/Menu/MenuItem.cs

@@ -1,3 +1,5 @@
+#nullable enable
+
 namespace Terminal.Gui;
 
 /// <summary>
@@ -6,10 +8,10 @@ namespace Terminal.Gui;
 /// </summary>
 public class MenuItem
 {
-    internal static MenuBar _menuBar;
+    internal MenuBar _menuBar;
 
     /// <summary>Initializes a new instance of <see cref="MenuItem"/></summary>
-    public MenuItem (Key shortcutKey = null) : this ("", "", null, null, null, shortcutKey) { }
+    public MenuItem (Key? shortcutKey = null) : this ("", "", null, null, null, shortcutKey) { }
 
     /// <summary>Initializes a new instance of <see cref="MenuItem"/>.</summary>
     /// <param name="title">Title for the menu item.</param>
@@ -19,26 +21,26 @@ public class MenuItem
     /// <param name="parent">The <see cref="Parent"/> of this menu item.</param>
     /// <param name="shortcutKey">The <see cref="ShortcutKey"/> keystroke combination.</param>
     public MenuItem (
-        string title,
-        string help,
-        Action action,
-        Func<bool> canExecute = null,
-        MenuItem parent = null,
-        Key shortcutKey = null
+        string? title,
+        string? help,
+        Action? action,
+        Func<bool>? canExecute = null,
+        MenuItem? parent = null,
+        Key? shortcutKey = null
     )
     {
         Title = title ?? "";
         Help = help ?? "";
-        Action = action;
-        CanExecute = canExecute;
-        Parent = parent;
+        Action = action!;
+        CanExecute = canExecute!;
+        Parent = parent!;
 
         if (Parent is { } && Parent.ShortcutKey != Key.Empty)
         {
             Parent.ShortcutKey = Key.Empty;
         }
         // Setter will ensure Key.Empty if it's null
-        ShortcutKey = shortcutKey;
+        ShortcutKey = shortcutKey!;
     }
 
     private bool _allowNullChecked;
@@ -48,7 +50,7 @@ public class MenuItem
 
     /// <summary>Gets or sets the action to be invoked when the menu item is triggered.</summary>
     /// <value>Method to invoke.</value>
-    public Action Action { get; set; }
+    public Action? Action { get; set; }
 
     /// <summary>
     ///     Used only if <see cref="CheckType"/> is of <see cref="MenuItemCheckStyle.Checked"/> type. If
@@ -70,7 +72,7 @@ public class MenuItem
     ///     returns <see langword="true"/> the menu item will be enabled. Otherwise, it will be disabled.
     /// </summary>
     /// <value>Function to determine if the action is can be executed or not.</value>
-    public Func<bool> CanExecute { get; set; }
+    public Func<bool>? CanExecute { get; set; }
 
     /// <summary>
     ///     Sets or gets whether the <see cref="MenuItem"/> shows a check indicator or not. See
@@ -112,7 +114,7 @@ public class MenuItem
 
     /// <summary>Gets the parent for this <see cref="MenuItem"/>.</summary>
     /// <value>The parent.</value>
-    public MenuItem Parent { get; set; }
+    public MenuItem? Parent { get; set; }
 
     /// <summary>Gets or sets the title of the menu item .</summary>
     /// <value>The title.</value>
@@ -186,7 +188,7 @@ public class MenuItem
                           (Checked == true || CheckType.HasFlag (MenuItemCheckStyle.Checked) || CheckType.HasFlag (MenuItemCheckStyle.Radio)
                                ? 2
                                : 0)
-                          + // check glyph + space 
+                          + // check glyph + space
                           (Help.GetColumns () > 0 ? 2 + Help.GetColumns () : 0)
                           + // Two spaces before Help
                           (ShortcutTag.GetColumns () > 0
@@ -217,12 +219,12 @@ public class MenuItem
     ///     </para>
     ///     <para>See also <see cref="ShortcutKey"/> which enable global key-bindings to menu items.</para>
     /// </summary>
-    public Key HotKey
+    public Key? HotKey
     {
         get => _hotKey;
         private set
         {
-            var oldKey = _hotKey ?? Key.Empty;
+            var oldKey = _hotKey;
             _hotKey = value ?? Key.Empty;
             UpdateHotKeyBinding (oldKey);
         }
@@ -260,30 +262,55 @@ public class MenuItem
     ///         <see cref="Help"/> text. See <see cref="ShortcutTag"/>.
     ///     </para>
     /// </summary>
-    public Key ShortcutKey
+    public Key? ShortcutKey
     {
         get => _shortcutKey;
         set
         {
-            var oldKey = _shortcutKey ?? Key.Empty;
+            var oldKey = _shortcutKey;
             _shortcutKey = value ?? Key.Empty;
             UpdateShortcutKeyBinding (oldKey);
         }
     }
 
     /// <summary>Gets the text describing the keystroke combination defined by <see cref="ShortcutKey"/>.</summary>
-    public string ShortcutTag => ShortcutKey != Key.Empty ? ShortcutKey.ToString () : string.Empty;
+    public string ShortcutTag => ShortcutKey != Key.Empty ? ShortcutKey!.ToString () : string.Empty;
+
+    internal void AddShortcutKeyBinding (MenuBar menuBar, Key key)
+    {
+        ArgumentNullException.ThrowIfNull (menuBar);
+
+        _menuBar = menuBar;
+
+        AddOrUpdateShortcutKeyBinding (key);
+    }
+
+    private void AddOrUpdateShortcutKeyBinding (Key key)
+    {
+        if (key != Key.Empty)
+        {
+            _menuBar.KeyBindings.Remove (key);
+        }
+
+        if (ShortcutKey != Key.Empty)
+        {
+            KeyBinding keyBinding = new ([Command.Select], KeyBindingScope.HotKey, this);
+            // Remove an existent ShortcutKey
+            _menuBar.KeyBindings.Remove (ShortcutKey!);
+            _menuBar.KeyBindings.Add (ShortcutKey!, keyBinding);
+        }
+    }
 
     private void UpdateHotKeyBinding (Key oldKey)
     {
-        if (_menuBar is null || _menuBar?.IsInitialized == false)
+        if (_menuBar is null or { IsInitialized: false })
         {
             return;
         }
 
         if (oldKey != Key.Empty)
         {
-            var index = _menuBar.Menus?.IndexOf (this);
+            var index = _menuBar.Menus.IndexOf (this);
 
             if (index > -1)
             {
@@ -293,36 +320,26 @@ public class MenuItem
 
         if (HotKey != Key.Empty)
         {
-            var index = _menuBar.Menus?.IndexOf (this);
+            var index = _menuBar.Menus.IndexOf (this);
 
             if (index > -1)
             {
-                _menuBar.KeyBindings.Remove (HotKey.WithAlt);
+                _menuBar.KeyBindings.Remove (HotKey!.WithAlt);
                 KeyBinding keyBinding = new ([Command.ToggleExpandCollapse], KeyBindingScope.HotKey, this);
                 _menuBar.KeyBindings.Add (HotKey.WithAlt, keyBinding);
             }
         }
     }
 
-    internal void UpdateShortcutKeyBinding (Key oldKey)
+    private void UpdateShortcutKeyBinding (Key oldKey)
     {
+        // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
         if (_menuBar is null)
         {
             return;
         }
 
-        if (oldKey != Key.Empty)
-        {
-            _menuBar.KeyBindings.Remove (oldKey);
-        }
-
-        if (ShortcutKey != Key.Empty)
-        {
-            KeyBinding keyBinding = new ([Command.Select], KeyBindingScope.HotKey, this);
-            // Remove an existent ShortcutKey
-            _menuBar?.KeyBindings.Remove (ShortcutKey);
-            _menuBar?.KeyBindings.Add (ShortcutKey, keyBinding);
-        }
+        AddOrUpdateShortcutKeyBinding (oldKey);
     }
 
     #endregion Keyboard Handling
@@ -334,10 +351,10 @@ public class MenuItem
     {
         if (Parent is { })
         {
-            MenuItem [] childrens = ((MenuBarItem)Parent).Children;
+            MenuItem? []? childrens = ((MenuBarItem)Parent).Children;
             var i = 0;
 
-            foreach (MenuItem c in childrens)
+            foreach (MenuItem? c in childrens!)
             {
                 if (c != this)
                 {
@@ -361,7 +378,7 @@ public class MenuItem
         if (ShortcutKey != Key.Empty)
         {
             // Remove an existent ShortcutKey
-            _menuBar?.KeyBindings.Remove (ShortcutKey);
+            _menuBar.KeyBindings.Remove (ShortcutKey!);
         }
     }
 }

+ 39 - 32
Terminal.Gui/Views/TableView/TableView.cs

@@ -54,47 +54,19 @@ public class TableView : View
         // Things this view knows how to do
         AddCommand (
                     Command.Right,
-                    () =>
-                    {
-                        // BUGBUG: SHould return false if selectokn doesn't change (to support nav to next view)
-                        ChangeSelectionByOffset (1, 0, false);
-
-                        return true;
-                    }
-                   );
+                    () => ChangeSelectionByOffsetWithReturn (1, 0));
 
         AddCommand (
                     Command.Left,
-                    () =>
-                    {
-                        // BUGBUG: SHould return false if selectokn doesn't change (to support nav to next view)
-                        ChangeSelectionByOffset (-1, 0, false);
-
-                        return true;
-                    }
-                   );
+                    () => ChangeSelectionByOffsetWithReturn (-1, 0));
 
         AddCommand (
                     Command.LineUp,
-                    () =>
-                    {
-                        // BUGBUG: SHould return false if selectokn doesn't change (to support nav to next view)
-                        ChangeSelectionByOffset (0, -1, false);
-
-                        return true;
-                    }
-                   );
+                    () => ChangeSelectionByOffsetWithReturn (0, -1));
 
         AddCommand (
                     Command.LineDown,
-                    () =>
-                    {
-                        // BUGBUG: SHould return false if selectokn doesn't change (to support nav to next view)
-                        ChangeSelectionByOffset (0, 1, false);
-
-                        return true;
-                    }
-                   );
+                    () => ChangeSelectionByOffsetWithReturn (0, 1));
 
         AddCommand (
                     Command.PageUp,
@@ -519,6 +491,41 @@ public class TableView : View
         return new Point (colHit.X, tableRow + headerHeight - RowOffset);
     }
 
+    /// <summary>
+    /// Private override of <see cref="ChangeSelectionByOffset"/> that returns true if the selection has
+    /// changed as a result of moving the selection. Used by key handling logic to determine whether e.g.
+    /// the cursor right resulted in a change or should be forwarded on to toggle logic handling.
+    /// </summary>
+    /// <param name="offsetX"></param>
+    /// <param name="offsetY"></param>
+    /// <returns></returns>
+    private bool ChangeSelectionByOffsetWithReturn (int offsetX, int offsetY)
+    {
+        var oldSelection = GetSelectionSnapshot ();
+        SetSelection (SelectedColumn + offsetX, SelectedRow + offsetY, false);
+        Update ();
+
+        return !SelectionIsSame (oldSelection);
+    }
+
+    private TableViewSelectionSnapshot GetSelectionSnapshot ()
+    {
+        return new (
+                    SelectedColumn,
+                    SelectedRow,
+                    MultiSelectedRegions.Select (s => s.Rectangle).ToArray ());
+    }
+
+    private bool SelectionIsSame (TableViewSelectionSnapshot oldSelection)
+    {
+        var newSelection = GetSelectionSnapshot ();
+
+        return oldSelection.SelectedColumn == newSelection.SelectedColumn
+               && oldSelection.SelectedRow == newSelection.SelectedRow
+               && oldSelection.multiSelection.SequenceEqual (newSelection.multiSelection);
+    }
+    private record TableViewSelectionSnapshot (int SelectedColumn, int SelectedRow, Rectangle [] multiSelection);
+
     /// <summary>
     ///     Moves the <see cref="SelectedRow"/> and <see cref="SelectedColumn"/> by the provided offsets. Optionally
     ///     starting a box selection (see <see cref="MultiSelect"/>)

+ 3 - 5
Terminal.Gui/Views/TextField.cs

@@ -405,7 +405,7 @@ public class TextField : View
 
         _currentCulture = Thread.CurrentThread.CurrentUICulture;
 
-        ContextMenu = new ContextMenu { Host = this, MenuItems = BuildContextMenuBarItem () };
+        ContextMenu = new ContextMenu { Host = this };
         ContextMenu.KeyChanged += ContextMenu_KeyChanged;
 
         KeyBindings.Add (ContextMenu.Key, KeyBindingScope.HotKey, Command.ShowContextMenu);
@@ -1853,14 +1853,12 @@ public class TextField : View
 
     private void ShowContextMenu ()
     {
-        if (_currentCulture != Thread.CurrentThread.CurrentUICulture)
+        if (!Equals (_currentCulture, Thread.CurrentThread.CurrentUICulture))
         {
             _currentCulture = Thread.CurrentThread.CurrentUICulture;
-
-            ContextMenu.MenuItems = BuildContextMenuBarItem ();
         }
 
-        ContextMenu.Show ();
+        ContextMenu.Show (BuildContextMenuBarItem ());
     }
 
     private void TextField_Added (object sender, SuperViewChangedEventArgs e)

+ 5 - 7
Terminal.Gui/Views/TextView.cs

@@ -2498,7 +2498,7 @@ public class TextView : View
 
         _currentCulture = Thread.CurrentThread.CurrentUICulture;
 
-        ContextMenu = new () { MenuItems = BuildContextMenuBarItem () };
+        ContextMenu = new ();
         ContextMenu.KeyChanged += ContextMenu_KeyChanged!;
 
         KeyBindings.Add ((KeyCode)ContextMenu.Key, KeyBindingScope.HotKey, Command.ShowContextMenu);
@@ -3494,7 +3494,7 @@ public class TextView : View
         }
         else if (ev.Flags == ContextMenu!.MouseFlags)
         {
-            ContextMenu.Position = new (ev.Position.X + 2, ev.Position.Y + 2);
+            ContextMenu.Position = ViewportToScreen ((Viewport with { X = ev.Position.X, Y = ev.Position.Y }).Location);
             ShowContextMenu ();
         }
 
@@ -4131,7 +4131,7 @@ public class TextView : View
 
     private void AppendClipboard (string text) { Clipboard.Contents += text; }
 
-    private MenuBarItem BuildContextMenuBarItem ()
+    private MenuBarItem? BuildContextMenuBarItem ()
     {
         return new (
                     new MenuItem []
@@ -6289,14 +6289,12 @@ public class TextView : View
 
     private void ShowContextMenu ()
     {
-        if (_currentCulture != Thread.CurrentThread.CurrentUICulture)
+        if (!Equals (_currentCulture, Thread.CurrentThread.CurrentUICulture))
         {
             _currentCulture = Thread.CurrentThread.CurrentUICulture;
-
-            ContextMenu!.MenuItems = BuildContextMenuBarItem ();
         }
 
-        ContextMenu!.Show ();
+        ContextMenu!.Show (BuildContextMenuBarItem ());
     }
 
     private void StartSelecting ()

+ 1 - 1
Terminal.Gui/Views/Toplevel.cs

@@ -24,7 +24,7 @@ public partial class Toplevel : View
     /// <summary>
     ///     Initializes a new instance of the <see cref="Toplevel"/> class,
     ///     defaulting to full screen. The <see cref="View.Width"/> and <see cref="View.Height"/> properties will be set to the
-    ///     dimensions of the terminal using <see cref="Dim.Fill"/>.
+    ///     dimensions of the terminal using <see cref="Dim.Fill(Dim)"/>.
     /// </summary>
     public Toplevel ()
     {

+ 11 - 9
Terminal.Gui/Views/Wizard/Wizard.cs

@@ -70,16 +70,18 @@ public class Wizard : Dialog
         ButtonAlignmentModes |= AlignmentModes.IgnoreFirstOrLast;
         BorderStyle = LineStyle.Double;
 
+        BackButton = new () { Text = Strings.wzBack };
+        NextFinishButton = new ()
+        {
+            Text = Strings.wzFinish,
+            IsDefault = true
+        };
+
         //// Add a horiz separator
-        var separator = new LineView (Orientation.Horizontal) { Y = Pos.AnchorEnd (2) };
-        Add (separator);
+        var separator = new LineView (Orientation.Horizontal) { Y = Pos.Top (BackButton) - 1 };
 
-        // BUGBUG: Space is to work around https://github.com/gui-cs/Terminal.Gui/issues/1812
-        BackButton = new () { Text = Strings.wzBack };
+        Add (separator);
         AddButton (BackButton);
-
-        NextFinishButton = new () { Text = Strings.wzFinish };
-        NextFinishButton.IsDefault = true;
         AddButton (NextFinishButton);
 
         BackButton.Accept += BackBtn_Clicked;
@@ -495,14 +497,14 @@ public class Wizard : Dialog
             // If we're modal, then we expand the WizardStep so that the top and side 
             // borders and not visible. The bottom border is the separator above the buttons.
             step.X = step.Y = 0;
-            step.Height = Dim.Fill (2); // for button frame
+            step.Height = Dim.Fill (Dim.Func (() => IsInitialized ? Subviews.First (view => view.Y.Has<PosAnchorEnd> (out _)).Frame.Height + 1 : 1)); // for button frame (+1 for lineView)
             step.Width = Dim.Fill ();
         }
         else
         {
             // If we're not a modal, then we show the border around the WizardStep
             step.X = step.Y = 0;
-            step.Height = Dim.Fill (1); // for button frame
+            step.Height = Dim.Fill (Dim.Func (() => IsInitialized ? Subviews.First (view => view.Y.Has<PosAnchorEnd> (out _)).Frame.Height + 1 : 2)); // for button frame (+1 for lineView)
             step.Width = Dim.Fill ();
         }
     }

+ 2 - 1
Terminal.Gui/Views/Wizard/WizardStep.cs

@@ -60,6 +60,7 @@ public class WizardStep : View
         TabStop = TabBehavior.TabStop;
         CanFocus = true;
         BorderStyle = LineStyle.None;
+
         base.Add (_contentView);
 
         base.Add (_helpTextView);
@@ -191,7 +192,7 @@ public class WizardStep : View
     internal void ShowHide ()
     {
         _contentView.Height = Dim.Fill ();
-        _helpTextView.Height = Dim.Fill ();
+        _helpTextView.Height = Dim.Height(_contentView);
         _helpTextView.Width = Dim.Fill ();
 
         if (_contentView.InternalSubviews?.Count > 0)

+ 1 - 0
Terminal.sln.DotSettings

@@ -400,6 +400,7 @@
 	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002EMemberReordering_002EMigrations_002ECSharpFileLayoutPatternRemoveIsAttributeUpgrade/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=Justifier/@EntryIndexedValue">True</s:Boolean>

+ 3 - 3
UICatalog/KeyBindingsDialog.cs

@@ -19,8 +19,8 @@ internal class KeyBindingsDialog : Dialog
     {
         Title = "Keybindings";
 
-        Height = Dim.Percent(80);
-        Width = Dim.Percent(80);
+        Height = Dim.Percent (80);
+        Width = Dim.Percent (80);
         if (ViewTracker.Instance == null)
         {
             ViewTracker.Initialize ();
@@ -32,7 +32,7 @@ internal class KeyBindingsDialog : Dialog
         _commandsListView = new ListView
         {
             Width = Dim.Percent (50),
-            Height = Dim.Fill () - 1,
+            Height = Dim.Fill (Dim.Func (() => IsInitialized ? Subviews.First (view => view.Y.Has<PosAnchorEnd> (out _)).Frame.Height : 1)),
             Source = new ListWrapper<Command> (_commands),
             SelectedItem = 0
         };

+ 25 - 24
UICatalog/Scenarios/CharacterMap.cs

@@ -902,31 +902,32 @@ internal class CharMap : View
 
             _contextMenu = new ()
             {
-                Position = new (me.Position.X + 1, me.Position.Y + 1),
-                MenuItems = new (
-                                 new MenuItem []
-                                 {
-                                     new (
-                                          "_Copy Glyph",
-                                          "",
-                                          CopyGlyph,
-                                          null,
-                                          null,
-                                          (KeyCode)Key.C.WithCtrl
-                                         ),
-                                     new (
-                                          "Copy Code _Point",
-                                          "",
-                                          CopyCodePoint,
-                                          null,
-                                          null,
-                                          (KeyCode)Key.C.WithCtrl
-                                                      .WithShift
-                                         )
-                                 }
-                                )
+                Position = new (me.Position.X + 1, me.Position.Y + 1)
             };
-            _contextMenu.Show ();
+
+            MenuBarItem menuItems = new (
+                                         new MenuItem []
+                                         {
+                                             new (
+                                                  "_Copy Glyph",
+                                                  "",
+                                                  CopyGlyph,
+                                                  null,
+                                                  null,
+                                                  (KeyCode)Key.C.WithCtrl
+                                                 ),
+                                             new (
+                                                  "Copy Code _Point",
+                                                  "",
+                                                  CopyCodePoint,
+                                                  null,
+                                                  null,
+                                                  (KeyCode)Key.C.WithCtrl
+                                                              .WithShift
+                                                 )
+                                         }
+                                        );
+            _contextMenu.Show (menuItems);
         }
     }
 

+ 120 - 120
UICatalog/Scenarios/ContextMenus.cs

@@ -98,8 +98,8 @@ public class ContextMenus : Scenario
             Menus =
             [
                 new (
-                     "File",
-                     new MenuItem [] { new ("Quit", "", () => Application.RequestStop (), null, null, Application.QuitKey) })
+                     "_File",
+                     new MenuItem [] { new ("_Quit", "", () => Application.RequestStop (), null, null, Application.QuitKey) })
             ]
         };
 
@@ -163,133 +163,133 @@ public class ContextMenus : Scenario
         _contextMenu = new()
         {
             Position = new (x, y),
-            MenuItems = new (
-                             new []
-                             {
-                                 new (
-                                      "_Configuration",
-                                      "Show configuration",
-                                      () => MessageBox.Query (
-                                                              50,
-                                                              5,
-                                                              "Info",
-                                                              "This would open settings dialog",
-                                                              "Ok"
-                                                             )
-                                     ),
-                                 new MenuBarItem (
-                                                  "More options",
-                                                  new MenuItem []
-                                                  {
-                                                      new (
-                                                           "_Setup",
-                                                           "Change settings",
-                                                           () => MessageBox
-                                                               .Query (
-                                                                       50,
-                                                                       5,
-                                                                       "Info",
-                                                                       "This would open setup dialog",
-                                                                       "Ok"
-                                                                      ),
-                                                           shortcutKey: KeyCode.T
-                                                                     | KeyCode
-                                                                         .CtrlMask
-                                                          ),
-                                                      new (
-                                                           "_Maintenance",
-                                                           "Maintenance mode",
-                                                           () => MessageBox
-                                                               .Query (
-                                                                       50,
-                                                                       5,
-                                                                       "Info",
-                                                                       "This would open maintenance dialog",
-                                                                       "Ok"
-                                                                      )
-                                                          )
-                                                  }
-                                                 ),
-                                 new MenuBarItem (
-                                                  "_Languages",
-                                                  GetSupportedCultures ()
-                                                 ),
-                                 _miForceMinimumPosToZero =
-                                     new (
-                                          "ForceMinimumPosToZero",
-                                          "",
-                                          () =>
-                                          {
-                                              _miForceMinimumPosToZero
-                                                      .Checked =
-                                                  _forceMinimumPosToZero =
-                                                      !_forceMinimumPosToZero;
-
-                                              _tfTopLeft.ContextMenu
-                                                        .ForceMinimumPosToZero =
-                                                  _forceMinimumPosToZero;
-
-                                              _tfTopRight.ContextMenu
-                                                         .ForceMinimumPosToZero =
-                                                  _forceMinimumPosToZero;
-
-                                              _tfMiddle.ContextMenu
-                                                       .ForceMinimumPosToZero =
-                                                  _forceMinimumPosToZero;
-
-                                              _tfBottomLeft.ContextMenu
-                                                           .ForceMinimumPosToZero =
-                                                  _forceMinimumPosToZero;
-
-                                              _tfBottomRight
-                                                      .ContextMenu
-                                                      .ForceMinimumPosToZero =
-                                                  _forceMinimumPosToZero;
-                                          }
-                                         )
-                                     {
-                                         CheckType =
-                                             MenuItemCheckStyle
-                                                 .Checked,
-                                         Checked =
-                                             _forceMinimumPosToZero
-                                     },
-                                 _miUseSubMenusSingleFrame =
-                                     new (
-                                          "Use_SubMenusSingleFrame",
-                                          "",
-                                          () => _contextMenu
-                                                        .UseSubMenusSingleFrame =
-                                                    (bool)
-                                                    (_miUseSubMenusSingleFrame
-                                                             .Checked =
-                                                         _useSubMenusSingleFrame =
-                                                             !_useSubMenusSingleFrame)
-                                         )
-                                     {
-                                         CheckType = MenuItemCheckStyle
-                                             .Checked,
-                                         Checked =
-                                             _useSubMenusSingleFrame
-                                     },
-                                 null,
-                                 new (
-                                      "_Quit",
-                                      "",
-                                      () => Application.RequestStop ()
-                                     )
-                             }
-                            ),
             ForceMinimumPosToZero = _forceMinimumPosToZero,
             UseSubMenusSingleFrame = _useSubMenusSingleFrame
         };
 
+        MenuBarItem menuItems = new (
+                                     new []
+                                     {
+                                         new MenuBarItem (
+                                                          "_Languages",
+                                                          GetSupportedCultures ()
+                                                         ),
+                                         new (
+                                              "_Configuration",
+                                              "Show configuration",
+                                              () => MessageBox.Query (
+                                                                      50,
+                                                                      5,
+                                                                      "Info",
+                                                                      "This would open settings dialog",
+                                                                      "Ok"
+                                                                     )
+                                             ),
+                                         new MenuBarItem (
+                                                          "M_ore options",
+                                                          new MenuItem []
+                                                          {
+                                                              new (
+                                                                   "_Setup",
+                                                                   "Change settings",
+                                                                   () => MessageBox
+                                                                       .Query (
+                                                                               50,
+                                                                               5,
+                                                                               "Info",
+                                                                               "This would open setup dialog",
+                                                                               "Ok"
+                                                                              ),
+                                                                   shortcutKey: KeyCode.T
+                                                                                | KeyCode
+                                                                                    .CtrlMask
+                                                                  ),
+                                                              new (
+                                                                   "_Maintenance",
+                                                                   "Maintenance mode",
+                                                                   () => MessageBox
+                                                                       .Query (
+                                                                               50,
+                                                                               5,
+                                                                               "Info",
+                                                                               "This would open maintenance dialog",
+                                                                               "Ok"
+                                                                              )
+                                                                  )
+                                                          }
+                                                         ),
+                                         _miForceMinimumPosToZero =
+                                             new (
+                                                  "Fo_rceMinimumPosToZero",
+                                                  "",
+                                                  () =>
+                                                  {
+                                                      _miForceMinimumPosToZero
+                                                              .Checked =
+                                                          _forceMinimumPosToZero =
+                                                              !_forceMinimumPosToZero;
+
+                                                      _tfTopLeft.ContextMenu
+                                                                .ForceMinimumPosToZero =
+                                                          _forceMinimumPosToZero;
+
+                                                      _tfTopRight.ContextMenu
+                                                                 .ForceMinimumPosToZero =
+                                                          _forceMinimumPosToZero;
+
+                                                      _tfMiddle.ContextMenu
+                                                               .ForceMinimumPosToZero =
+                                                          _forceMinimumPosToZero;
+
+                                                      _tfBottomLeft.ContextMenu
+                                                                   .ForceMinimumPosToZero =
+                                                          _forceMinimumPosToZero;
+
+                                                      _tfBottomRight
+                                                              .ContextMenu
+                                                              .ForceMinimumPosToZero =
+                                                          _forceMinimumPosToZero;
+                                                  }
+                                                 )
+                                             {
+                                                 CheckType =
+                                                     MenuItemCheckStyle
+                                                         .Checked,
+                                                 Checked =
+                                                     _forceMinimumPosToZero
+                                             },
+                                         _miUseSubMenusSingleFrame =
+                                             new (
+                                                  "Use_SubMenusSingleFrame",
+                                                  "",
+                                                  () => _contextMenu
+                                                                .UseSubMenusSingleFrame =
+                                                            (bool)
+                                                            (_miUseSubMenusSingleFrame
+                                                                     .Checked =
+                                                                 _useSubMenusSingleFrame =
+                                                                     !_useSubMenusSingleFrame)
+                                                 )
+                                             {
+                                                 CheckType = MenuItemCheckStyle
+                                                     .Checked,
+                                                 Checked =
+                                                     _useSubMenusSingleFrame
+                                             },
+                                         null,
+                                         new (
+                                              "_Quit",
+                                              "",
+                                              () => Application.RequestStop ()
+                                             )
+                                     }
+                                    );
         _tfTopLeft.ContextMenu.ForceMinimumPosToZero = _forceMinimumPosToZero;
         _tfTopRight.ContextMenu.ForceMinimumPosToZero = _forceMinimumPosToZero;
         _tfMiddle.ContextMenu.ForceMinimumPosToZero = _forceMinimumPosToZero;
         _tfBottomLeft.ContextMenu.ForceMinimumPosToZero = _forceMinimumPosToZero;
         _tfBottomRight.ContextMenu.ForceMinimumPosToZero = _forceMinimumPosToZero;
 
-        _contextMenu.Show ();
+        _contextMenu.Show (menuItems);
     }
 }

+ 27 - 17
UICatalog/Scenarios/DynamicMenuBar.cs

@@ -875,7 +875,7 @@ public class DynamicMenuBar : Scenario
                                   {
                                       MenuItem newMenu = CreateNewMenu (item, _currentMenuBarItem);
                                       var menuBarItem = _currentMenuBarItem as MenuBarItem;
-                                      menuBarItem.AddMenuBarItem (newMenu);
+                                      menuBarItem.AddMenuBarItem (MenuBar, newMenu);
 
 
                                       DataContext.Menus.Add (new () { Title = newMenu.Title, MenuItem = newMenu });
@@ -915,6 +915,11 @@ public class DynamicMenuBar : Scenario
                                             _lstMenus.SelectedItem = _lstMenus.Source.Count - 1;
                                         }
 
+                                        if (_menuBar.Menus.Length == 0)
+                                        {
+                                            RemoveMenuBar ();
+                                        }
+
                                         _lstMenus.SetNeedsDisplay ();
                                         SetFrameDetails ();
                                     }
@@ -992,7 +997,7 @@ public class DynamicMenuBar : Scenario
                                          }
 
                                          var newMenu = CreateNewMenu (item) as MenuBarItem;
-                                         newMenu.AddMenuBarItem ();
+                                         newMenu.AddMenuBarItem (MenuBar);
 
                                          _currentMenuBarItem = newMenu;
                                          _currentMenuBarItem.CheckType = item.CheckStyle;
@@ -1012,7 +1017,7 @@ public class DynamicMenuBar : Scenario
 
             btnRemoveMenuBar.Accept += (s, e) =>
                                         {
-                                            if (_menuBar == null || _menuBar.Menus.Length == 0)
+                                            if (_menuBar == null)
                                             {
                                                 return;
                                             }
@@ -1033,25 +1038,30 @@ public class DynamicMenuBar : Scenario
                                                                           : null;
                                             }
 
-                                            if (MenuBar != null && _currentMenuBarItem == null && _menuBar.Menus.Length == 0)
-                                            {
-                                                Remove (_menuBar);
-                                                _menuBar.Dispose ();
-                                                _menuBar = null;
-                                                DataContext.Menus = new ();
-                                                _currentMenuBarItem = null;
-                                                _currentSelectedMenuBar = -1;
-                                                lblMenuBar.Text = string.Empty;
-                                            }
-                                            else
-                                            {
-                                                lblMenuBar.Text = _menuBar.Menus [_currentSelectedMenuBar].Title;
-                                            }
+                                            RemoveMenuBar ();
 
                                             SetListViewSource (_currentMenuBarItem, true);
                                             SetFrameDetails ();
                                         };
 
+            void RemoveMenuBar ()
+            {
+                if (MenuBar != null && _currentMenuBarItem == null && _menuBar.Menus.Length == 0)
+                {
+                    Remove (_menuBar);
+                    _menuBar.Dispose ();
+                    _menuBar = null;
+                    DataContext.Menus = new ();
+                    _currentMenuBarItem = null;
+                    _currentSelectedMenuBar = -1;
+                    lblMenuBar.Text = string.Empty;
+                }
+                else
+                {
+                    lblMenuBar.Text = _menuBar.Menus [_currentSelectedMenuBar].Title;
+                }
+            }
+
             SetFrameDetails ();
 
             var ustringConverter = new UStringValueConverter ();

+ 2 - 2
UICatalog/Scenarios/Notepad.cs

@@ -362,9 +362,9 @@ public class Notepad : Scenario
 
         var screen = ((View)sender).ViewportToScreen (e.MouseEvent.Position);
 
-        var contextMenu = new ContextMenu { Position = screen, MenuItems = items };
+        var contextMenu = new ContextMenu { Position = screen };
 
-        contextMenu.Show ();
+        contextMenu.Show (items);
         e.MouseEvent.Handled = true;
     }
 

+ 20 - 20
UICatalog/Scenarios/TableEditor.cs

@@ -1266,28 +1266,28 @@ public class TableEditor : Scenario
 
         var contextMenu = new ContextMenu
         {
-            Position = new (e.MouseEvent.Position.X + 1, e.MouseEvent.Position.Y + 1),
-            MenuItems = new (
-                             [
-                                 new (
-                                      $"Hide {TrimArrows (colName)}",
-                                      "",
-                                      () => HideColumn (clickedCol)
-                                     ),
-                                 new (
-                                      $"Sort {StripArrows (sort)}",
-                                      "",
-                                      () => SortColumn (
-                                                        clickedCol,
-                                                        sort,
-                                                        isAsc
-                                                       )
-                                     )
-                             ]
-                            )
+            Position = new (e.MouseEvent.Position.X + 1, e.MouseEvent.Position.Y + 1)
         };
 
-        contextMenu.Show ();
+        MenuBarItem menuItems = new (
+                                     [
+                                         new (
+                                              $"Hide {TrimArrows (colName)}",
+                                              "",
+                                              () => HideColumn (clickedCol)
+                                             ),
+                                         new (
+                                              $"Sort {StripArrows (sort)}",
+                                              "",
+                                              () => SortColumn (
+                                                                clickedCol,
+                                                                sort,
+                                                                isAsc
+                                                               )
+                                             )
+                                     ]
+                                    );
+        contextMenu.Show (menuItems);
     }
 
     private void SortColumn (int clickedCol)

+ 6 - 7
UICatalog/Scenarios/TreeViewFileSystem.cs

@@ -415,21 +415,20 @@ public class TreeViewFileSystem : Scenario
 
     private void ShowContextMenu (Point screenPoint, IFileSystemInfo forObject)
     {
-        var menu = new ContextMenu ();
-        menu.Position = screenPoint;
+        var menu = new ContextMenu { Position = screenPoint };
 
-        menu.MenuItems = new MenuBarItem (
-                                          new [] { new MenuItem ("Properties", null, () => ShowPropertiesOf (forObject)) }
-                                         );
+        var menuItems = new MenuBarItem (
+                                         new [] { new MenuItem ("Properties", null, () => ShowPropertiesOf (forObject)) }
+                                        );
 
-        Application.Invoke (menu.Show);
+        Application.Invoke (() => menu.Show (menuItems));
     }
 
     private void ShowLines ()
     {
         _miShowLines.Checked = !_miShowLines.Checked;
 
-        _treeViewFiles.Style.ShowBranchLines = (bool)_miShowLines.Checked;
+        _treeViewFiles.Style.ShowBranchLines = (bool)_miShowLines.Checked!;
         _treeViewFiles.SetNeedsDisplay ();
     }
 

+ 8 - 1
UICatalog/Scenarios/WizardAsView.cs

@@ -57,7 +57,14 @@ public class WizardAsView : Scenario
         topLevel.Add (menu);
 
         // No need for a Title because the border is disabled
-        var wizard = new Wizard { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
+        var wizard = new Wizard
+        {
+            X = 0,
+            Y = 0,
+            Width = Dim.Fill (),
+            Height = Dim.Fill (),
+            ShadowStyle = ShadowStyle.None
+        };
 
         // Set Mdoal to false to cause the Wizard class to render without a frame and
         // behave like an non-modal View (vs. a modal/pop-up Window).

+ 12 - 2
UICatalog/Scenarios/Wizards.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Linq;
 using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
@@ -276,17 +277,26 @@ public class Wizards : Scenario
                                                X = 0,
                                                Y = 0,
                                                Width = Dim.Fill (),
-                                               Height = Dim.Fill (1),
                                                WordWrap = true,
                                                AllowsTab = false,
                                                ColorScheme = Colors.ColorSchemes ["Base"]
                                            };
+
+                                           someText.Height = Dim.Fill (
+                                                                       Dim.Func (
+                                                                                 () => someText.SuperView is { IsInitialized: true }
+                                                                                           ? someText.SuperView.Subviews
+                                                                                                     .First (view => view.Y.Has<PosAnchorEnd> (out _))
+                                                                                                     .Frame.Height
+                                                                                           : 1));
                                            var help = "This is helpful.";
                                            fourthStep.Add (someText);
 
                                            var hideHelpBtn = new Button
                                            {
-                                               Text = "Press me to show/hide help", X = Pos.Center (), Y = Pos.AnchorEnd (1)
+                                               Text = "Press me to show/hide help",
+                                               X = Pos.Center (),
+                                               Y = Pos.AnchorEnd ()
                                            };
 
                                            hideHelpBtn.Accept += (s, e) =>

+ 9 - 5
UICatalog/UICatalog.cs

@@ -5,6 +5,7 @@ using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.CommandLine;
 using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
 using System.IO;
 using System.Linq;
@@ -56,9 +57,11 @@ public class UICatalogApp
     private static int _cachedScenarioIndex;
     private static string? _cachedTheme = string.Empty;
     private static ObservableCollection<string>? _categories;
+    [SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
     private static readonly FileSystemWatcher _currentDirWatcher = new ();
     private static ViewDiagnosticFlags _diagnosticFlags;
     private static string _forceDriver = string.Empty;
+    [SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
     private static readonly FileSystemWatcher _homeDirWatcher = new ();
     private static bool _isFirstRunning = true;
     private static Options _options;
@@ -436,7 +439,7 @@ public class UICatalogApp
             _diagnosticFlags = Diagnostics;
 
             _themeMenuItems = CreateThemeMenuItems ();
-            _themeMenuBarItem = new ("_Themes", _themeMenuItems);
+            _themeMenuBarItem = new ("_Themes", _themeMenuItems!);
 
             MenuBar menuBar = new ()
             {
@@ -507,7 +510,7 @@ public class UICatalogApp
                 ShVersion = new ()
                 {
                     Title = "Version Info",
-                    CanFocus = false
+                    CanFocus = false,
                 };
 
                 var statusBarShortcut = new Shortcut
@@ -576,7 +579,7 @@ public class UICatalogApp
                 X = 0,
                 Y = 1,
                 Width = Dim.Auto (),
-                Height = Dim.Fill (1),
+                Height = Dim.Fill (Dim.Func (() => IsInitialized ? Subviews.First (view => view.Y.Has<PosAnchorEnd> (out _)).Frame.Height : 1)),
                 AllowsMarking = false,
                 CanFocus = true,
                 Title = "_Categories",
@@ -706,7 +709,7 @@ public class UICatalogApp
 
             ColorScheme = Colors.ColorSchemes [_topLevelColorScheme];
 
-            MenuBar!.Menus [0].Children [0].ShortcutKey = Application.QuitKey;
+            MenuBar!.Menus [0].Children! [0]!.ShortcutKey = Application.QuitKey;
 
             if (StatusBar is { })
             {
@@ -813,6 +816,7 @@ public class UICatalogApp
 
         private void ConfigAppliedHandler (object? sender, ConfigurationManagerEventArgs? a) { ConfigChanged (); }
 
+        [SuppressMessage ("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
         private MenuItem [] CreateDiagnosticFlagsMenuItems ()
         {
             const string OFF = "View Diagnostics: _Off";
@@ -905,7 +909,7 @@ public class UICatalogApp
                 };
             }
 
-            Enum GetDiagnosticsEnumValue (string title)
+            Enum GetDiagnosticsEnumValue (string? title)
             {
                 return title switch
                 {

+ 160 - 91
UnitTests/FileServices/FileDialogTests.cs

@@ -4,7 +4,7 @@ using Xunit.Abstractions;
 
 namespace Terminal.Gui.FileServicesTests;
 
-public class FileDialogTests (ITestOutputHelper output)
+public class FileDialogTests ()
 {
     [Theory]
     [InlineData (true)]
@@ -99,12 +99,13 @@ public class FileDialogTests (ITestOutputHelper output)
         string openIn = Path.Combine (Environment.CurrentDirectory, "zz");
         Directory.CreateDirectory (openIn);
         dlg.Path = openIn + Path.DirectorySeparatorChar;
-        Application.OnKeyDown (Key.Tab);
-        Application.OnKeyDown (Key.Tab);
-        Application.OnKeyDown (Key.Tab);
+
+        var tf = GetTextField (dlg, FileDialogPart.SearchField);
+        tf.SetFocus ();
 
         Assert.IsType<TextField> (dlg.MostFocused);
-        var tf = (TextField)dlg.MostFocused;
+        Assert.Same (tf, dlg.MostFocused);
+
         Assert.Equal ("Enter Search", tf.Caption);
 
         // Dialog has not yet been confirmed with a choice
@@ -140,6 +141,10 @@ public class FileDialogTests (ITestOutputHelper output)
 
         Assert.IsType<TextField> (dlg.MostFocused);
         Send ('v', ConsoleKey.DownArrow);
+
+        var tv = GetTableView(dlg);
+        tv.SetFocus ();
+
         Assert.IsType<TableView> (dlg.MostFocused);
 
         // ".." should be the first thing selected
@@ -177,8 +182,10 @@ public class FileDialogTests (ITestOutputHelper output)
         IReadOnlyCollection<string> eventMultiSelected = null;
         dlg.FilesSelected += (s, e) => { eventMultiSelected = e.Dialog.MultiSelected; };
 
-        Assert.IsType<TextField> (dlg.MostFocused);
-        Send ('v', ConsoleKey.DownArrow);
+
+        var tv = GetTableView (dlg);
+        tv.SetFocus ();
+
         Assert.IsType<TableView> (dlg.MostFocused);
 
         // Try to toggle '..'
@@ -232,8 +239,9 @@ public class FileDialogTests (ITestOutputHelper output)
         IReadOnlyCollection<string> eventMultiSelected = null;
         dlg.FilesSelected += (s, e) => { eventMultiSelected = e.Dialog.MultiSelected; };
 
-        Assert.IsType<TextField> (dlg.MostFocused);
-        Send ('v', ConsoleKey.DownArrow);
+        var tv = GetTableView (dlg);
+        tv.SetFocus ();
+
         Assert.IsType<TableView> (dlg.MostFocused);
 
         // Move selection to subfolder
@@ -284,8 +292,9 @@ public class FileDialogTests (ITestOutputHelper output)
         IReadOnlyCollection<string> eventMultiSelected = null;
         dlg.FilesSelected += (s, e) => { eventMultiSelected = e.Dialog.MultiSelected; };
 
-        Assert.IsType<TextField> (dlg.MostFocused);
-        Send ('v', ConsoleKey.DownArrow);
+        var tv = GetTableView (dlg);
+        tv.SetFocus ();
+
         Assert.IsType<TableView> (dlg.MostFocused);
 
         // Move selection to subfolder
@@ -327,8 +336,9 @@ public class FileDialogTests (ITestOutputHelper output)
         dlg.OpenMode = openModeMixed ? OpenMode.Mixed : OpenMode.Directory;
         dlg.AllowsMultipleSelection = multiple;
 
-        Assert.IsType<TextField> (dlg.MostFocused);
-        Send ('v', ConsoleKey.DownArrow);
+        var tv = GetTableView (dlg);
+        tv.SetFocus ();
+
         Assert.IsType<TableView> (dlg.MostFocused);
 
         // Should be selecting ..
@@ -421,45 +431,60 @@ public class FileDialogTests (ITestOutputHelper output)
 
         fd.Draw ();
 
-        var expected =
-            @$"
-┌─────────────────────────────────────────────────────────────────────────┐
-│/demo/                                                                   │
-│{
-    CM.Glyphs.LeftBracket
-}▲{
-    CM.Glyphs.RightBracket
-}                                                                      │
-│┌────────────┬──────────┬──────────────────────────────┬────────────────┐│
-││Filename (▲)│Size      │Modified                      │Type            ││
-│├────────────┼──────────┼──────────────────────────────┼────────────────┤│
-││..          │          │                              │<Directory>     ││
-││/subfolder  │          │2002-01-01T22:42:10           │<Directory>     ││
-││image.gif   │4.00 B    │2002-01-01T22:42:10           │.gif            ││
-││jQuery.js   │7.00 B    │2001-01-01T11:44:42           │.js             ││
-│                                                                         │
-│                                                                         │
-│                                                                         │
-│{
-    CM.Glyphs.LeftBracket
-} ►► {
-    CM.Glyphs.RightBracket
-} Enter Search                                 {
-    CM.Glyphs.LeftBracket
-}{
-    CM.Glyphs.LeftDefaultIndicator
-} OK {
-    CM.Glyphs.RightDefaultIndicator
-}{
-    CM.Glyphs.RightBracket
-} {
-    CM.Glyphs.LeftBracket
-} Cancel {
-    CM.Glyphs.RightBracket
-}  │
-└─────────────────────────────────────────────────────────────────────────┘
-";
-        TestHelpers.AssertDriverContentsAre (expected, output, ignoreLeadingWhitespace: true);
+        /*
+         *
+         *
+           ┌─────────────────────────────────────────────────────────────────────────┐
+           │/demo/                                                                   │
+           │⟦▲⟧                                                                      │
+           │┌────────────┬──────────┬──────────────────────────────┬────────────────┐│
+           ││Filename (▲)│Size      │Modified                      │Type            ││
+           │├────────────┼──────────┼──────────────────────────────┼────────────────┤│
+           ││..          │          │                              │<Directory>     ││
+           ││/subfolder  │          │2002-01-01T22:42:10           │<Directory>     ││
+           ││image.gif   │4.00 B    │2002-01-01T22:42:10           │.gif            ││
+           ││jQuery.js   │7.00 B    │2001-01-01T11:44:42           │.js             ││
+           │                                                                         │
+           │                                                                         │
+           │                                                                         │
+           │⟦ ►► ⟧ Enter Search                                 ⟦► OK ◄⟧ ⟦ Cancel ⟧  │
+           └─────────────────────────────────────────────────────────────────────────┘
+
+         *
+         */
+
+        var path = GetTextField (fd, FileDialogPart.Path);
+        Assert.Equal ("/demo/", path.Text);
+
+        var tv = GetTableView (fd);
+
+        // Asserting the headers
+        Assert.Equal ("Filename (▲)", tv.Table.ColumnNames.ElementAt (0));
+        Assert.Equal ("Size", tv.Table.ColumnNames.ElementAt (1));
+        Assert.Equal ("Modified", tv.Table.ColumnNames.ElementAt (2));
+        Assert.Equal ("Type", tv.Table.ColumnNames.ElementAt (3));
+
+        // Asserting the table contents
+        Assert.Equal ("..", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [0, 0]));
+        Assert.Equal ("/subfolder", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [1, 0]));
+        Assert.Equal ("image.gif", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [2, 0]));
+        Assert.Equal ("jQuery.js", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [3, 0]));
+
+        Assert.Equal ("", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [0, 1]));
+        Assert.Equal ("", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [1, 1]));
+        Assert.Equal ("4.00 B", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [2, 1]));
+        Assert.Equal ("7.00 B", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [3, 1]));
+
+        Assert.Equal ("", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [0, 2]));
+        Assert.Equal ("2002-01-01T22:42:10", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [1, 2]));
+        Assert.Equal ("2002-01-01T22:42:10", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [2, 2]));
+        Assert.Equal ("2001-01-01T11:44:42", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [3, 2]));
+
+        Assert.Equal ("<Directory>", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [0, 3]));
+        Assert.Equal ("<Directory>", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [1, 3]));
+        Assert.Equal (".gif", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [2, 3]));
+        Assert.Equal (".js", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [3, 3]));
+
         fd.Dispose ();
     }
 
@@ -479,45 +504,64 @@ public class FileDialogTests (ITestOutputHelper output)
 
         fd.Draw ();
 
-        var expected =
-            @$"
-┌─────────────────────────────────────────────────────────────────────────┐
-│c:\demo\                                                                 │
-│{
-    CM.Glyphs.LeftBracket
-}▲{
-    CM.Glyphs.RightBracket
-}                                                                      │
-│┌────────────┬──────────┬──────────────────────────────┬────────────────┐│
-││Filename (▲)│Size      │Modified                      │Type            ││
-│├────────────┼──────────┼──────────────────────────────┼────────────────┤│
-││..          │          │                              │<Directory>     ││
-││\subfolder  │          │2002-01-01T22:42:10           │<Directory>     ││
-││image.gif   │4.00 B    │2002-01-01T22:42:10           │.gif            ││
-││jQuery.js   │7.00 B    │2001-01-01T11:44:42           │.js             ││
-││mybinary.exe│7.00 B    │2001-01-01T11:44:42           │.exe            ││
-│                                                                         │
-│                                                                         │
-│{
-    CM.Glyphs.LeftBracket
-} ►► {
-    CM.Glyphs.RightBracket
-} Enter Search                                 {
-    CM.Glyphs.LeftBracket
-}{
-    CM.Glyphs.LeftDefaultIndicator
-} OK {
-    CM.Glyphs.RightDefaultIndicator
-}{
-    CM.Glyphs.RightBracket
-} {
-    CM.Glyphs.LeftBracket
-} Cancel {
-    CM.Glyphs.RightBracket
-}  │
-└─────────────────────────────────────────────────────────────────────────┘
-";
-        TestHelpers.AssertDriverContentsAre (expected, output, ignoreLeadingWhitespace: true);
+        /*
+         *
+         *
+           ┌─────────────────────────────────────────────────────────────────────────┐
+           │c:\demo\                                                                 │
+           │⟦▲⟧                                                                      │
+           │┌────────────┬──────────┬──────────────────────────────┬────────────────┐│
+           ││Filename (▲)│Size      │Modified                      │Type            ││
+           │├────────────┼──────────┼──────────────────────────────┼────────────────┤│
+           ││..          │          │                              │<Directory>     ││
+           ││\subfolder  │          │2002-01-01T22:42:10           │<Directory>     ││
+           ││image.gif   │4.00 B    │2002-01-01T22:42:10           │.gif            ││
+           ││jQuery.js   │7.00 B    │2001-01-01T11:44:42           │.js             ││
+           ││mybinary.exe│7.00 B    │2001-01-01T11:44:42           │.exe            ││
+           │                                                                         │
+           │                                                                         │
+           │⟦ ►► ⟧ Enter Search                                 ⟦► OK ◄⟧ ⟦ Cancel ⟧  │
+           └─────────────────────────────────────────────────────────────────────────┘
+           
+         *
+         */
+
+        var path = GetTextField (fd, FileDialogPart.Path);
+        Assert.Equal ("c:\\demo\\",path.Text);
+
+        var tv = GetTableView (fd);
+
+        // Asserting the headers
+        Assert.Equal ("Filename (▲)", tv.Table.ColumnNames.ElementAt (0));
+        Assert.Equal ("Size", tv.Table.ColumnNames.ElementAt (1));
+        Assert.Equal ("Modified", tv.Table.ColumnNames.ElementAt (2));
+        Assert.Equal ("Type", tv.Table.ColumnNames.ElementAt (3));
+
+        // Asserting the table contents
+        Assert.Equal ("..", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [0, 0]));
+        Assert.Equal (@"\subfolder", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [1, 0]));
+        Assert.Equal ("image.gif", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [2, 0]));
+        Assert.Equal ("jQuery.js", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [3, 0]));
+        Assert.Equal ("mybinary.exe", tv.Style.GetOrCreateColumnStyle (0).GetRepresentation (tv.Table [4, 0]));
+
+        Assert.Equal ("", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [0, 1]));
+        Assert.Equal ("", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [1, 1]));
+        Assert.Equal ("4.00 B", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [2, 1]));
+        Assert.Equal ("7.00 B", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [3, 1]));
+        Assert.Equal ("7.00 B", tv.Style.GetOrCreateColumnStyle (1).GetRepresentation (tv.Table [4, 1]));
+
+        Assert.Equal ("", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [0, 2]));
+        Assert.Equal ("2002-01-01T22:42:10", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [1, 2]));
+        Assert.Equal ("2002-01-01T22:42:10", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [2, 2]));
+        Assert.Equal ("2001-01-01T11:44:42", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [3, 2]));
+        Assert.Equal ("2001-01-01T11:44:42", tv.Style.GetOrCreateColumnStyle (2).GetRepresentation (tv.Table [4, 2]));
+
+        Assert.Equal ("<Directory>", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [0, 3]));
+        Assert.Equal ("<Directory>", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [1, 3]));
+        Assert.Equal (".gif", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [2, 3]));
+        Assert.Equal (".js", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [3, 3]));
+        Assert.Equal (".exe", tv.Style.GetOrCreateColumnStyle (3).GetRepresentation (tv.Table [4, 3]));
+
         fd.Dispose ();
     }
 
@@ -734,4 +778,29 @@ public class FileDialogTests (ITestOutputHelper output)
             Send ('\\', ConsoleKey.Separator);
         }
     }
+
+    private TextField GetTextField (FileDialog dlg, FileDialogPart part)
+    {
+        switch (part)
+        {
+            case FileDialogPart.Path:
+                return dlg.Subviews.OfType<TextField> ().ElementAt (0);
+            case FileDialogPart.SearchField:
+                return dlg.Subviews.OfType<TextField> ().ElementAt (1);
+            default:
+                throw new ArgumentOutOfRangeException (nameof (part), part, null);
+        }
+    }
+
+    private TableView GetTableView (FileDialog dlg)
+    {
+        var tile = dlg.Subviews.OfType<TileView> ().Single ();
+        return (TableView)tile.Tiles.ElementAt (1).ContentView.Subviews.ElementAt(0);
+    }
+
+    private enum FileDialogPart
+    {
+        Path,
+        SearchField,
+    }
 }

+ 1 - 1
UnitTests/UnitTests.csproj

@@ -81,4 +81,4 @@
       False
     </IncludeTestAssembly>
   </PropertyGroup>
-</Project>
+</Project>

+ 16 - 3
UnitTests/View/Layout/Dim.FillTests.cs

@@ -127,15 +127,28 @@ public class DimFillTests (ITestOutputHelper output)
     {
         var testMargin = 0;
         Dim dim = Dim.Fill ();
-        Assert.Equal ($"Fill({testMargin})", dim.ToString ());
+        Assert.Equal (testMargin, dim!.GetAnchor(0));
 
         testMargin = 0;
         dim = Dim.Fill (testMargin);
-        Assert.Equal ($"Fill({testMargin})", dim.ToString ());
+        Assert.Equal (testMargin, dim!.GetAnchor (0));
 
         testMargin = 5;
         dim = Dim.Fill (testMargin);
-        Assert.Equal ($"Fill({testMargin})", dim.ToString ());
+        Assert.Equal (-testMargin, dim!.GetAnchor (0));
+    }
+
+    [Fact]
+    public void DimFill_Margin_Is_Dim_SetsValue ()
+    {
+        Dim testMargin = Dim.Func (() => 0);
+        Dim dim = Dim.Fill (testMargin);
+        Assert.Equal (0, dim!.GetAnchor (0));
+
+
+        testMargin = Dim.Func (() => 5);
+        dim = Dim.Fill (testMargin);
+        Assert.Equal (-5, dim!.GetAnchor (0));
     }
 
     [Fact]

+ 7 - 7
UnitTests/View/Layout/Dim.Tests.cs

@@ -315,7 +315,7 @@ public class DimTests
                        Assert.Equal (49, f1.Frame.Width); // 50-1=49
                        Assert.Equal (5, f1.Frame.Height);
 
-                       Assert.Equal ("Fill(0)", f2.Width.ToString ());
+                       Assert.Equal ("Fill(Absolute(0))", f2.Width.ToString ());
                        Assert.Equal ("Absolute(5)", f2.Height.ToString ());
                        Assert.Equal (49, f2.Frame.Width); // 50-1=49
                        Assert.Equal (5, f2.Frame.Height);
@@ -325,7 +325,7 @@ public class DimTests
 #else
                        Assert.Equal ($"Combine(View(Width,FrameView(){f1.Border.Frame})-Absolute(2))", v1.Width.ToString ());
 #endif
-                       Assert.Equal ("Combine(Fill(0)-Absolute(2))", v1.Height.ToString ());
+                       Assert.Equal ("Combine(Fill(Absolute(0))-Absolute(2))", v1.Height.ToString ());
                        Assert.Equal (47, v1.Frame.Width); // 49-2=47
                        Assert.Equal (89, v1.Frame.Height); // 98-5-2-2=89
 
@@ -340,9 +340,9 @@ public class DimTests
 #endif
                                     );
 #if DEBUG
-                       Assert.Equal ("Combine(Fill(0)-Absolute(2))", v2.Height.ToString ());
+                       Assert.Equal ("Combine(Fill(Absolute(0))-Absolute(2))", v2.Height.ToString ());
 #else
-                       Assert.Equal ("Combine(Fill(0)-Absolute(2))", v2.Height.ToString ());
+                       Assert.Equal ("Combine(Fill(Absolute(0))-Absolute(2))", v2.Height.ToString ());
 #endif
                        Assert.Equal (47, v2.Frame.Width); // 49-2=47
                        Assert.Equal (89, v2.Frame.Height); // 98-5-2-2=89
@@ -380,7 +380,7 @@ public class DimTests
                        Assert.Equal (5, f1.Frame.Height);
 
                        f2.Text = "Frame2";
-                       Assert.Equal ("Fill(0)", f2.Width.ToString ());
+                       Assert.Equal ("Fill(Absolute(0))", f2.Width.ToString ());
                        Assert.Equal ("Absolute(5)", f2.Height.ToString ());
                        Assert.Equal (99, f2.Frame.Width); // 100-1=99
                        Assert.Equal (5, f2.Frame.Height);
@@ -391,7 +391,7 @@ public class DimTests
 #else
                        Assert.Equal ($"Combine(View(Width,FrameView(){f1.Frame})-Absolute(2))", v1.Width.ToString ());
 #endif
-                       Assert.Equal ("Combine(Fill(0)-Absolute(2))", v1.Height.ToString ());
+                       Assert.Equal ("Combine(Fill(Absolute(0))-Absolute(2))", v1.Height.ToString ());
                        Assert.Equal (97, v1.Frame.Width); // 99-2=97
                        Assert.Equal (189, v1.Frame.Height); // 198-2-7=189
 
@@ -402,7 +402,7 @@ public class DimTests
 #else
                        Assert.Equal ($"Combine(View(Width,FrameView(){f2.Frame})-Absolute(2))", v2.Width.ToString ());
 #endif
-                       Assert.Equal ("Combine(Fill(0)-Absolute(2))", v2.Height.ToString ());
+                       Assert.Equal ("Combine(Fill(Absolute(0))-Absolute(2))", v2.Height.ToString ());
                        Assert.Equal (97, v2.Frame.Width); // 99-2=97
                        Assert.Equal (189, v2.Frame.Height); // 198-2-7=189
 

+ 6 - 6
UnitTests/View/Layout/SetRelativeLayoutTests.cs

@@ -37,11 +37,11 @@ public class SetRelativeLayoutTests
 
         Assert.Equal ("Absolute(1)", view.X.ToString ());
         Assert.Equal ("Absolute(2)", view.Y.ToString ());
-        Assert.Equal ("Fill(0)", view.Width.ToString ());
-        Assert.Equal ("Fill(0)", view.Height.ToString ());
+        Assert.Equal ("Fill(Absolute(0))", view.Width.ToString ());
+        Assert.Equal ("Fill(Absolute(0))", view.Height.ToString ());
         view.SetRelativeLayout (screen);
-        Assert.Equal ("Fill(0)", view.Width.ToString ());
-        Assert.Equal ("Fill(0)", view.Height.ToString ());
+        Assert.Equal ("Fill(Absolute(0))", view.Width.ToString ());
+        Assert.Equal ("Fill(Absolute(0))", view.Height.ToString ());
     }
 
     [Fact]
@@ -50,7 +50,7 @@ public class SetRelativeLayoutTests
         var view = new View { X = 1, Y = 1, Width = Dim.Fill (), Height = Dim.Fill () };
 
         view.SetRelativeLayout (new Size (80, 25));
-        Assert.Equal ("Fill(0)", view.Width.ToString ());
+        Assert.Equal ("Fill(Absolute(0))", view.Width.ToString ());
         Assert.Equal (1, view.Frame.X);
         Assert.Equal (1, view.Frame.Y);
         Assert.Equal (79, view.Frame.Width);
@@ -63,7 +63,7 @@ public class SetRelativeLayoutTests
         view.X = 0;
         view.Y = 0;
         Assert.Equal ("Absolute(0)", view.X.ToString ());
-        Assert.Equal ("Fill(0)", view.Width.ToString ());
+        Assert.Equal ("Fill(Absolute(0))", view.Width.ToString ());
         view.SetRelativeLayout (new Size (80, 25));
         Assert.Equal (0, view.Frame.X);
         Assert.Equal (0, view.Frame.Y);

+ 663 - 146
UnitTests/Views/ContextMenuTests.cs

@@ -10,42 +10,54 @@ public class ContextMenuTests (ITestOutputHelper output)
     public void ContextMenu_Constructors ()
     {
         var cm = new ContextMenu ();
+        var top = new Toplevel ();
+        Application.Begin (top);
+
         Assert.Equal (Point.Empty, cm.Position);
-        Assert.Empty (cm.MenuItems.Children);
+        Assert.Null (cm.MenuItems);
         Assert.Null (cm.Host);
         cm.Position = new Point (20, 10);
 
-        cm.MenuItems = new MenuBarItem (
-                                        [
-                                            new MenuItem ("First", "", null)
-                                        ]
-                                       );
+        var menuItems = new MenuBarItem (
+                                         [
+                                             new MenuItem ("First", "", null)
+                                         ]
+                                        );
+        cm.Show (menuItems);
         Assert.Equal (new Point (20, 10), cm.Position);
-        Assert.Single (cm.MenuItems.Children);
+        Assert.Single (cm.MenuItems!.Children);
 
         cm = new ContextMenu
         {
-            Position = new Point (5, 10),
-            MenuItems = new MenuBarItem (
-                                         new [] { new MenuItem ("One", "", null), new MenuItem ("Two", "", null) }
-                                        )
+            Position = new Point (5, 10)
         };
+
+        menuItems = new MenuBarItem (
+                                     new [] { new MenuItem ("One", "", null), new MenuItem ("Two", "", null) }
+                                    );
+        cm.Show (menuItems);
         Assert.Equal (new Point (5, 10), cm.Position);
-        Assert.Equal (2, cm.MenuItems.Children.Length);
+        Assert.Equal (2, cm.MenuItems!.Children.Length);
         Assert.Null (cm.Host);
 
+        var view = new View { X = 5, Y = 10 };
+        top.Add (view);
+
         cm = new ContextMenu
         {
-            Host = new View { X = 5, Y = 10 },
-            Position = new Point (5, 10),
-            MenuItems = new MenuBarItem (
-                                         new [] { new MenuItem ("One", "", null), new MenuItem ("Two", "", null) }
-                                        )
+            Host = view,
+            Position = new Point (5, 10)
         };
 
+        menuItems = new MenuBarItem (
+                                     new [] { new MenuItem ("One", "", null), new MenuItem ("Two", "", null) }
+                                    );
+        cm.Show (menuItems);
         Assert.Equal (new Point (5, 10), cm.Position);
         Assert.Equal (2, cm.MenuItems.Children.Length);
         Assert.NotNull (cm.Host);
+
+        top.Dispose ();
     }
 
     [Fact]
@@ -54,14 +66,15 @@ public class ContextMenuTests (ITestOutputHelper output)
     {
         var cm = new ContextMenu
         {
-            Position = new Point (10, 5),
-            MenuItems = new MenuBarItem (
+            Position = new Point (10, 5)
+        };
+
+        var menuItems = new MenuBarItem (
                                          [
                                              new MenuItem ("One", "", null),
                                              new MenuItem ("Two", "", null)
                                          ]
-                                        )
-        };
+                                        );
 
         var menu = new MenuBar
         {
@@ -78,7 +91,7 @@ public class ContextMenuTests (ITestOutputHelper output)
 
         Assert.Null (Application.MouseGrabView);
 
-        cm.Show ();
+        cm.Show (menuItems);
         Assert.True (ContextMenu.IsShow);
         Assert.Equal (cm.MenuBar, Application.MouseGrabView);
         Assert.False (menu.IsMenuOpen);
@@ -87,7 +100,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.Equal (menu, Application.MouseGrabView);
         Assert.True (menu.IsMenuOpen);
 
-        cm.Show ();
+        cm.Show (menuItems);
         Assert.True (ContextMenu.IsShow);
         Assert.Equal (cm.MenuBar, Application.MouseGrabView);
         Assert.False (menu.IsMenuOpen);
@@ -98,7 +111,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (menu.IsMenuOpen);
 #endif
 
-        cm.Show ();
+        cm.Show (menuItems);
         Assert.True (ContextMenu.IsShow);
         Assert.Equal (cm.MenuBar, Application.MouseGrabView);
         Assert.False (menu.IsMenuOpen);
@@ -305,21 +318,21 @@ public class ContextMenuTests (ITestOutputHelper output)
     {
         var cm = new ContextMenu
         {
-            Position = new Point (-1, -2),
-            MenuItems = new MenuBarItem (
+            Position = new Point (-1, -2)
+        };
+
+        var menuItems = new MenuBarItem (
                                          [
                                              new MenuItem ("One", "", null),
                                              new MenuItem ("Two", "", null)
                                          ]
-                                        )
-        };
-
+                                        );
         Assert.Equal (new Point (-1, -2), cm.Position);
-        
+
         Toplevel top = new ();
         Application.Begin (top);
 
-        cm.Show ();
+        cm.Show (menuItems);
         Assert.Equal (new Point (-1, -2), cm.Position);
         Application.Refresh ();
 
@@ -334,7 +347,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.Equal (new Rectangle (0, 1, 8, 4), pos);
 
         cm.ForceMinimumPosToZero = false;
-        cm.Show ();
+        cm.Show (menuItems);
         Assert.Equal (new Point (-1, -2), cm.Position);
         Application.Refresh ();
 
@@ -355,22 +368,22 @@ public class ContextMenuTests (ITestOutputHelper output)
     {
         var cm = new ContextMenu
         {
-            Position = new Point (80, 25),
-            MenuItems = new MenuBarItem (
+            Position = new Point (80, 25)
+        };
+
+        var menuItems = new MenuBarItem (
                                          [
                                              new MenuItem ("One", "", null),
                                              new MenuItem ("Two", "", null)
                                          ]
-                                        )
-        };
-
+                                        );
         Toplevel top = new ();
         Application.Begin (top);
         top.Running = true;
 
         Assert.False (ContextMenu.IsShow);
 
-        cm.Show ();
+        cm.Show (menuItems);
         Assert.True (ContextMenu.IsShow);
 
         top.RequestStop ();
@@ -388,8 +401,9 @@ public class ContextMenuTests (ITestOutputHelper output)
         Application.Begin (top);
 
         Assert.True (Application.OnKeyDown (ContextMenu.DefaultKey));
-        Assert.True (tf.ContextMenu.MenuBar.IsMenuOpen);
+        Assert.True (tf.ContextMenu.MenuBar!.IsMenuOpen);
         Assert.True (Application.OnKeyDown (ContextMenu.DefaultKey));
+
         // The last context menu bar opened is always preserved
         Assert.NotNull (tf.ContextMenu.MenuBar);
         top.Dispose ();
@@ -415,18 +429,18 @@ public class ContextMenuTests (ITestOutputHelper output)
     {
         var cm = new ContextMenu
         {
-            Position = new Point (10, 5),
-            MenuItems = new MenuBarItem (
+            Position = new Point (10, 5)
+        };
+
+        var menuItems = new MenuBarItem (
                                          [
                                              new MenuItem ("One", "", null),
                                              new MenuItem ("Two", "", null)
                                          ]
-                                        )
-        };
-
+                                        );
         Toplevel top = new ();
         Application.Begin (top);
-        cm.Show ();
+        cm.Show (menuItems);
         Application.Refresh ();
 
         var expected = @"
@@ -438,15 +452,15 @@ public class ContextMenuTests (ITestOutputHelper output)
 
         TestHelpers.AssertDriverContentsAre (expected, output);
 
-        cm.MenuItems = new MenuBarItem (
-                                        [
-                                            new MenuItem ("First", "", null),
-                                            new MenuItem ("Second", "", null),
-                                            new MenuItem ("Third", "", null)
-                                        ]
-                                       );
+        menuItems = new MenuBarItem (
+                                     [
+                                         new MenuItem ("First", "", null),
+                                         new MenuItem ("Second", "", null),
+                                         new MenuItem ("Third", "", null)
+                                     ]
+                                    );
 
-        cm.Show ();
+        cm.Show (menuItems);
         Application.Refresh ();
 
         expected = @"
@@ -467,8 +481,10 @@ public class ContextMenuTests (ITestOutputHelper output)
     {
         var cm = new ContextMenu
         {
-            Position = new Point (-1, -2),
-            MenuItems = new MenuBarItem (
+            Position = new Point (-1, -2)
+        };
+
+        var menuItems = new MenuBarItem (
                                          [
                                              new MenuItem ("One", "", null),
                                              new MenuItem ("Two", "", null),
@@ -488,15 +504,13 @@ public class ContextMenuTests (ITestOutputHelper output)
                                              new MenuItem ("Five", "", null),
                                              new MenuItem ("Six", "", null)
                                          ]
-                                        )
-        };
-
+                                        );
         Assert.Equal (new Point (-1, -2), cm.Position);
 
         Toplevel top = new ();
         Application.Begin (top);
 
-        cm.Show ();
+        cm.Show (menuItems);
         Application.Refresh ();
 
         Assert.Equal (new Point (-1, -2), cm.Position);
@@ -518,8 +532,8 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (
                      top.Subviews [0]
                         .NewMouseEvent (
-                                     new MouseEvent { Position = new (0, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] }
-                                    )
+                                        new MouseEvent { Position = new (0, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] }
+                                       )
                     );
         Application.Refresh ();
         Assert.Equal (new Point (-1, -2), cm.Position);
@@ -545,7 +559,7 @@ public class ContextMenuTests (ITestOutputHelper output)
 
         ((FakeDriver)Application.Driver!).SetBufferSize (40, 20);
         cm.Position = new Point (41, -2);
-        cm.Show ();
+        cm.Show (menuItems);
         Application.Refresh ();
         Assert.Equal (new Point (41, -2), cm.Position);
 
@@ -566,8 +580,8 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (
                      top.Subviews [0]
                         .NewMouseEvent (
-                                     new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] }
-                                    )
+                                        new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] }
+                                       )
                     );
         Application.Refresh ();
         Assert.Equal (new Point (41, -2), cm.Position);
@@ -592,7 +606,7 @@ public class ContextMenuTests (ITestOutputHelper output)
                                                      );
 
         cm.Position = new Point (41, 9);
-        cm.Show ();
+        cm.Show (menuItems);
         Application.Refresh ();
         Assert.Equal (new Point (41, 9), cm.Position);
 
@@ -613,8 +627,8 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (
                      top.Subviews [0]
                         .NewMouseEvent (
-                                     new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] }
-                                    )
+                                        new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] }
+                                       )
                     );
         Application.Refresh ();
         Assert.Equal (new Point (41, 9), cm.Position);
@@ -636,7 +650,7 @@ public class ContextMenuTests (ITestOutputHelper output)
                                                      );
 
         cm.Position = new Point (41, 22);
-        cm.Show ();
+        cm.Show (menuItems);
         Application.Refresh ();
         Assert.Equal (new Point (41, 22), cm.Position);
 
@@ -657,8 +671,8 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (
                      top.Subviews [0]
                         .NewMouseEvent (
-                                     new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] }
-                                    )
+                                        new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] }
+                                       )
                     );
         Application.Refresh ();
         Assert.Equal (new Point (41, 22), cm.Position);
@@ -680,7 +694,7 @@ public class ContextMenuTests (ITestOutputHelper output)
 
         ((FakeDriver)Application.Driver!).SetBufferSize (18, 8);
         cm.Position = new Point (19, 10);
-        cm.Show ();
+        cm.Show (menuItems);
         Application.Refresh ();
         Assert.Equal (new Point (19, 10), cm.Position);
 
@@ -701,8 +715,8 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (
                      top.Subviews [0]
                         .NewMouseEvent (
-                                     new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] }
-                                    )
+                                        new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] }
+                                       )
                     );
         Application.Refresh ();
         Assert.Equal (new Point (19, 10), cm.Position);
@@ -773,18 +787,18 @@ public class ContextMenuTests (ITestOutputHelper output)
     {
         var cm = new ContextMenu
         {
-            Position = new Point (10, 5),
-            MenuItems = new MenuBarItem (
+            Position = new Point (10, 5)
+        };
+
+        var menuItems = new MenuBarItem (
                                          [
                                              new MenuItem ("One", "", null),
                                              new MenuItem ("Two", "", null)
                                          ]
-                                        )
-        };
-
+                                        );
         Toplevel top = new ();
         Application.Begin (top);
-        cm.Show ();
+        cm.Show (menuItems);
         Application.Refresh ();
 
         var expected = @"
@@ -798,7 +812,7 @@ public class ContextMenuTests (ITestOutputHelper output)
 
         cm.Position = new Point (5, 10);
 
-        cm.Show ();
+        cm.Show (menuItems);
         Application.Refresh ();
 
         expected = @"
@@ -816,7 +830,14 @@ public class ContextMenuTests (ITestOutputHelper output)
     [AutoInitShutdown]
     public void RequestStop_While_ContextMenu_Is_Open_Does_Not_Throws ()
     {
-        ContextMenu cm = Create_ContextMenu_With_Two_MenuItem (10, 5);
+        ContextMenu cm = new ContextMenu
+        {
+            Position = new Point (10, 5)
+        };
+
+        var menuItems = new MenuBarItem (
+                                         new MenuItem [] { new ("One", "", null), new ("Two", "", null) }
+                                        );
         Toplevel top = new ();
         var isMenuAllClosed = false;
         MenuBarItem mi = null;
@@ -828,7 +849,7 @@ public class ContextMenuTests (ITestOutputHelper output)
 
                                      if (iterations == 0)
                                      {
-                                         cm.Show ();
+                                         cm.Show (menuItems);
                                          Assert.True (ContextMenu.IsShow);
                                          mi = cm.MenuBar.Menus [0];
 
@@ -853,7 +874,7 @@ public class ContextMenuTests (ITestOutputHelper output)
                                      else if (iterations == 3)
                                      {
                                          isMenuAllClosed = false;
-                                         cm.Show ();
+                                         cm.Show (menuItems);
                                          Assert.True (ContextMenu.IsShow);
                                          cm.MenuBar.MenuAllClosed += (_, _) => isMenuAllClosed = true;
                                      }
@@ -896,20 +917,20 @@ public class ContextMenuTests (ITestOutputHelper output)
 
         var cm = new ContextMenu
         {
-            Position = Point.Empty,
-            MenuItems = new MenuBarItem (
+            Position = Point.Empty
+        };
+
+        var menuItems = new MenuBarItem (
                                          [
                                              new MenuItem ("One", "", null),
                                              new MenuItem ("Two", "", null)
                                          ]
-                                        )
-        };
-
+                                        );
         Assert.Equal (Point.Empty, cm.Position);
 
         Toplevel top = new ();
         Application.Begin (top);
-        cm.Show ();
+        cm.Show (menuItems);
         Assert.Equal (Point.Empty, cm.Position);
         Application.Refresh ();
 
@@ -934,20 +955,20 @@ public class ContextMenuTests (ITestOutputHelper output)
 
         var cm = new ContextMenu
         {
-            Position = Point.Empty,
-            MenuItems = new MenuBarItem (
+            Position = Point.Empty
+        };
+
+        var menuItems = new MenuBarItem (
                                          [
                                              new MenuItem ("One", "", null),
                                              new MenuItem ("Two", "", null)
                                          ]
-                                        )
-        };
-
+                                        );
         Assert.Equal (Point.Empty, cm.Position);
 
         Toplevel top = new ();
         Application.Begin (top);
-        cm.Show ();
+        cm.Show (menuItems);
         Assert.Equal (Point.Empty, cm.Position);
         Application.Refresh ();
 
@@ -981,22 +1002,22 @@ public class ContextMenuTests (ITestOutputHelper output)
         var cm = new ContextMenu
         {
             Host = view,
-            Position = new Point (10, 5),
-            MenuItems = new MenuBarItem (
+            Position = new Point (10, 5)
+        };
+
+        var menuItems = new MenuBarItem (
                                          [
                                              new MenuItem ("One", "", null),
                                              new MenuItem ("Two", "", null)
                                          ]
-                                        )
-        };
-
+                                        );
         var top = new Toplevel ();
         top.Add (view);
         Application.Begin (top);
 
         Assert.Equal (new Point (10, 5), cm.Position);
 
-        cm.Show ();
+        cm.Show (menuItems);
         top.Draw ();
         Assert.Equal (new Point (10, 5), cm.Position);
 
@@ -1017,7 +1038,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         cm.Host.Y = 10;
         cm.Host.Height = 3;
 
-        cm.Show ();
+        cm.Show (menuItems);
         Application.Top.Draw ();
         Assert.Equal (new Point (5, 12), cm.Position);
 
@@ -1045,20 +1066,20 @@ public class ContextMenuTests (ITestOutputHelper output)
     {
         var cm = new ContextMenu
         {
-            Position = new Point (80, 25),
-            MenuItems = new MenuBarItem (
+            Position = new Point (80, 25)
+        };
+
+        var menuItems = new MenuBarItem (
                                          [
                                              new MenuItem ("One", "", null),
                                              new MenuItem ("Two", "", null)
                                          ]
-                                        )
-        };
-
+                                        );
         Assert.Equal (new Point (80, 25), cm.Position);
 
         Toplevel top = new ();
         Application.Begin (top);
-        cm.Show ();
+        cm.Show (menuItems);
         Assert.Equal (new Point (80, 25), cm.Position);
         Application.Refresh ();
 
@@ -1092,15 +1113,15 @@ public class ContextMenuTests (ITestOutputHelper output)
 
         var cm = new ContextMenu
         {
-            Host = view,
-            MenuItems = new MenuBarItem (
+            Host = view
+        };
+
+        var menuItems = new MenuBarItem (
                                          [
                                              new MenuItem ("One", "", null),
                                              new MenuItem ("Two", "", null)
                                          ]
-                                        )
-        };
-
+                                        );
         var top = new Toplevel ();
         top.Add (view);
         Application.Begin (top);
@@ -1108,7 +1129,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.Equal (new Rectangle (70, 24, 10, 1), view.Frame);
         Assert.Equal (Point.Empty, cm.Position);
 
-        cm.Show ();
+        cm.Show (menuItems);
         Assert.Equal (new Point (70, 24), cm.Position);
         top.Draw ();
 
@@ -1132,11 +1153,18 @@ public class ContextMenuTests (ITestOutputHelper output)
     [AutoInitShutdown]
     public void Show_Hide_IsShow ()
     {
-        ContextMenu cm = Create_ContextMenu_With_Two_MenuItem (10, 5);
+        ContextMenu cm = new ContextMenu
+        {
+            Position = new Point (10, 5)
+        };
+
+        var menuItems = new MenuBarItem (
+                                         new MenuItem [] { new ("One", "", null), new ("Two", "", null) }
+                                        );
 
         Toplevel top = new ();
         Application.Begin (top);
-        cm.Show ();
+        cm.Show (menuItems);
         Assert.True (ContextMenu.IsShow);
         Application.Refresh ();
 
@@ -1167,7 +1195,10 @@ public class ContextMenuTests (ITestOutputHelper output)
         var cm = new ContextMenu
         {
             Position = new Point (5, 10),
-            MenuItems = new MenuBarItem (
+            UseSubMenusSingleFrame = true
+        };
+
+        var menuItems = new MenuBarItem (
                                          "Numbers",
                                          [
                                              new MenuItem ("One", "", null),
@@ -1184,19 +1215,11 @@ public class ContextMenuTests (ITestOutputHelper output)
                                                              ),
                                              new MenuItem ("Three", "", null)
                                          ]
-                                        ),
-            UseSubMenusSingleFrame = true
-        };
+                                        );
         Toplevel top = new ();
         RunState rs = Application.Begin (top);
-        top.SetFocus ();
-        Assert.NotNull (Application.Current);
-
-        cm.Show ();
-        Assert.True(ContextMenu.IsShow);
-        Assert.True (Application.Top.Subviews [0].HasFocus);
-        Assert.Equal(Application.Top.Subviews [0], Application.Navigation.GetFocused());
-        Assert.Equal (new Rectangle (5, 11, 10, 5), Application.Top.Subviews [0].Frame);
+        cm.Show (menuItems);
+        Assert.Equal (new Rectangle (5, 11, 10, 5), Application.Top!.Subviews [0].Frame);
         Application.Refresh ();
 
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1254,8 +1277,10 @@ public class ContextMenuTests (ITestOutputHelper output)
     {
         var cm = new ContextMenu
         {
-            Position = new Point (5, 10),
-            MenuItems = new MenuBarItem (
+            Position = new Point (5, 10)
+        };
+
+        var menuItems = new MenuBarItem (
                                          "Numbers",
                                          [
                                              new MenuItem ("One", "", null),
@@ -1270,7 +1295,8 @@ public class ContextMenuTests (ITestOutputHelper output)
                                                                   new MenuItem ("Two-Menu 2", "", null)
                                                               ]
                                                              ),
-                                             new MenuBarItem ("Three",
+                                             new MenuBarItem (
+                                                              "Three",
                                                               [
                                                                   new MenuItem (
                                                                                 "Three-Menu 1",
@@ -1281,11 +1307,10 @@ public class ContextMenuTests (ITestOutputHelper output)
                                                               ]
                                                              )
                                          ]
-                                        )
-        };
+                                        );
         Toplevel top = new ();
         RunState rs = Application.Begin (top);
-        cm.Show ();
+        cm.Show (menuItems);
 
         Assert.Equal (new Rectangle (5, 11, 10, 5), Application.Top.Subviews [0].Frame);
         Application.Refresh ();
@@ -1356,17 +1381,6 @@ public class ContextMenuTests (ITestOutputHelper output)
         top.Dispose ();
     }
 
-    private ContextMenu Create_ContextMenu_With_Two_MenuItem (int x, int y)
-    {
-        return new ContextMenu
-        {
-            Position = new Point (x, y),
-            MenuItems = new MenuBarItem (
-                                         new MenuItem [] { new ("One", "", null), new ("Two", "", null) }
-                                        )
-        };
-    }
-
     [Fact]
     [AutoInitShutdown]
     public void Handling_TextField_With_Opened_ContextMenu_By_Mouse_HasFocus ()
@@ -1397,6 +1411,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (tf1.HasFocus);
         Assert.False (tf2.HasFocus);
         Assert.Equal (4, win.Subviews.Count);
+
         // The last context menu bar opened is always preserved
         Assert.NotNull (tf2.ContextMenu.MenuBar);
         Assert.Equal (win.Focused, tf1);
@@ -1408,6 +1423,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.False (tf1.HasFocus);
         Assert.True (tf2.HasFocus);
         Assert.Equal (4, win.Subviews.Count);
+
         // The last context menu bar opened is always preserved
         Assert.NotNull (tf2.ContextMenu.MenuBar);
         Assert.Equal (win.Focused, tf2);
@@ -1417,4 +1433,505 @@ public class ContextMenuTests (ITestOutputHelper output)
         Application.End (rs);
         win.Dispose ();
     }
-}
+
+    [Fact]
+    [AutoInitShutdown]
+    public void Empty_Menus_Items_Children_Does_Not_Open_The_Menu ()
+    {
+        var cm = new ContextMenu ();
+        Assert.Null (cm.MenuItems);
+
+        var top = new Toplevel ();
+        Application.Begin (top);
+
+        cm.Show (cm.MenuItems);
+        Assert.Null (cm.MenuBar);
+
+        top.Dispose ();
+    }
+
+    [Fact]
+    [AutoInitShutdown]
+    public void KeyBindings_Removed_On_Close_ContextMenu ()
+    {
+        var newFile = false;
+        var renameFile = false;
+        var deleteFile = false;
+
+        var cm = new ContextMenu ();
+
+        var menuItems = new MenuBarItem (
+                                         [
+                                             new MenuItem ("New File", string.Empty, New, null, null, Key.N.WithCtrl),
+                                             new MenuItem ("Rename File", string.Empty, Rename, null, null, Key.R.WithCtrl),
+                                             new MenuItem ("Delete File", string.Empty, Delete, null, null, Key.D.WithCtrl)
+                                         ]
+                                        );
+        var top = new Toplevel ();
+        Application.Begin (top);
+
+        Assert.Null (cm.MenuBar);
+        Assert.False (Application.OnKeyDown (Key.N.WithCtrl));
+        Assert.False (Application.OnKeyDown (Key.R.WithCtrl));
+        Assert.False (Application.OnKeyDown (Key.D.WithCtrl));
+        Assert.False (newFile);
+        Assert.False (renameFile);
+        Assert.False (deleteFile);
+
+        cm.Show (menuItems);
+        Assert.True (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
+        Assert.True (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithCtrl));
+        Assert.True (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.D.WithCtrl));
+
+        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
+        Application.MainLoop!.RunIteration ();
+        Assert.True (newFile);
+        Assert.False (cm.MenuBar!.IsMenuOpen);
+        cm.Show (menuItems);
+        Assert.True (Application.OnKeyDown (Key.R.WithCtrl));
+        Application.MainLoop!.RunIteration ();
+        Assert.True (renameFile);
+        Assert.False (cm.MenuBar.IsMenuOpen);
+        cm.Show (menuItems);
+        Assert.True (Application.OnKeyDown (Key.D.WithCtrl));
+        Application.MainLoop!.RunIteration ();
+        Assert.True (deleteFile);
+        Assert.False (cm.MenuBar.IsMenuOpen);
+
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithCtrl));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.D.WithCtrl));
+
+        newFile = false;
+        renameFile = false;
+        deleteFile = false;
+        Assert.False (Application.OnKeyDown (Key.N.WithCtrl));
+        Assert.False (Application.OnKeyDown (Key.R.WithCtrl));
+        Assert.False (Application.OnKeyDown (Key.D.WithCtrl));
+        Assert.False (newFile);
+        Assert.False (renameFile);
+        Assert.False (deleteFile);
+
+        top.Dispose ();
+
+        void New () { newFile = true; }
+
+        void Rename () { renameFile = true; }
+
+        void Delete () { deleteFile = true; }
+    }
+
+    [Fact]
+    [AutoInitShutdown]
+    public void KeyBindings_With_ContextMenu_And_MenuBar ()
+    {
+        var newFile = false;
+        var renameFile = false;
+
+        var menuBar = new MenuBar
+        {
+            Menus =
+            [
+                new (
+                     "File",
+                     new MenuItem []
+                     {
+                         new ("New", string.Empty, New, null, null, Key.N.WithCtrl)
+                     })
+            ]
+        };
+        var cm = new ContextMenu ();
+
+        var menuItems = new MenuBarItem (
+                                         [
+                                             new ("Rename File", string.Empty, Rename, null, null, Key.R.WithCtrl),
+                                         ]
+                                        );
+        var top = new Toplevel ();
+        top.Add (menuBar);
+        Application.Begin (top);
+
+        Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
+        Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithCtrl));
+        Assert.Null (cm.MenuBar);
+
+        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
+        Assert.False (Application.OnKeyDown (Key.R.WithCtrl));
+        Application.MainLoop!.RunIteration ();
+        Assert.True (newFile);
+        Assert.False (renameFile);
+
+        newFile = false;
+
+        cm.Show (menuItems);
+        Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
+        Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithCtrl));
+        Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
+        Assert.True (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithCtrl));
+
+        Assert.True (cm.MenuBar.IsMenuOpen);
+        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
+        Application.MainLoop!.RunIteration ();
+        Assert.True (newFile);
+        Assert.False (cm.MenuBar!.IsMenuOpen);
+        cm.Show (menuItems);
+        Assert.True (Application.OnKeyDown (Key.R.WithCtrl));
+        Application.MainLoop!.RunIteration ();
+        Assert.True (renameFile);
+        Assert.False (cm.MenuBar.IsMenuOpen);
+
+        Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
+        Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithCtrl));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithCtrl));
+
+        newFile = false;
+        renameFile = false;
+        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
+        Assert.False (Application.OnKeyDown (Key.R.WithCtrl));
+        Application.MainLoop!.RunIteration ();
+        Assert.True (newFile);
+        Assert.False (renameFile);
+
+        top.Dispose ();
+
+        void New () { newFile = true; }
+
+        void Rename () { renameFile = true; }
+    }
+
+    [Fact]
+    [AutoInitShutdown]
+    public void KeyBindings_With_Same_Shortcut_ContextMenu_And_MenuBar ()
+    {
+        var newMenuBar = false;
+        var newContextMenu = false;
+
+        var menuBar = new MenuBar
+        {
+            Menus =
+            [
+                new (
+                     "File",
+                     new MenuItem []
+                     {
+                         new ("New", string.Empty, NewMenuBar, null, null, Key.N.WithCtrl)
+                     })
+            ]
+        };
+        var cm = new ContextMenu ();
+
+        var menuItems = new MenuBarItem (
+                                         [
+                                             new ("New File", string.Empty, NewContextMenu, null, null, Key.N.WithCtrl),
+                                         ]
+                                        );
+        var top = new Toplevel ();
+        top.Add (menuBar);
+        Application.Begin (top);
+
+        Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
+        Assert.Null (cm.MenuBar);
+
+        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
+        Application.MainLoop!.RunIteration ();
+        Assert.True (newMenuBar);
+        Assert.False (newContextMenu);
+
+        newMenuBar = false;
+
+        cm.Show (menuItems);
+        Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
+        Assert.True (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
+
+        Assert.True (cm.MenuBar.IsMenuOpen);
+        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
+        Application.MainLoop!.RunIteration ();
+        Assert.False (newMenuBar);
+
+        // The most focused shortcut is executed
+        Assert.True (newContextMenu);
+        Assert.False (cm.MenuBar!.IsMenuOpen);
+
+        Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithCtrl));
+
+        newMenuBar = false;
+        newContextMenu = false;
+        Assert.True (Application.OnKeyDown (Key.N.WithCtrl));
+        Application.MainLoop!.RunIteration ();
+        Assert.True (newMenuBar);
+        Assert.False (newContextMenu);
+
+        top.Dispose ();
+
+        void NewMenuBar () { newMenuBar = true; }
+
+        void NewContextMenu () { newContextMenu = true; }
+    }
+
+    [Fact]
+    [AutoInitShutdown]
+    public void HotKeys_Removed_On_Close_ContextMenu ()
+    {
+        var newFile = false;
+        var renameFile = false;
+        var deleteFile = false;
+
+        var cm = new ContextMenu ();
+
+        var menuItems = new MenuBarItem (
+                                         [
+                                             new ("_New File", string.Empty, New, null, null),
+                                             new ("_Rename File", string.Empty, Rename, null, null),
+                                             new ("_Delete File", string.Empty, Delete, null, null)
+                                         ]
+                                        );
+        var top = new Toplevel ();
+        Application.Begin (top);
+
+        Assert.Null (cm.MenuBar);
+        Assert.False (Application.OnKeyDown (Key.N.WithAlt));
+        Assert.False (Application.OnKeyDown (Key.R.WithAlt));
+        Assert.False (Application.OnKeyDown (Key.D.WithAlt));
+        Assert.False (newFile);
+        Assert.False (renameFile);
+        Assert.False (deleteFile);
+
+        cm.Show (menuItems);
+        Assert.True (cm.MenuBar!.IsMenuOpen);
+        Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.N.WithAlt));
+        Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.N.NoShift));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithAlt));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.NoShift));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.D.WithAlt));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.D.NoShift));
+        Assert.Single (Application.Current!.Subviews);
+        View [] menus = Application.Current!.Subviews.Where (v => v is Menu m && m.Host == cm.MenuBar).ToArray ();
+        Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.N.WithAlt));
+        Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.N.NoShift));
+        Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.R.WithAlt));
+        Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.R.NoShift));
+        Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.D.WithAlt));
+        Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.D.NoShift));
+
+        Assert.True (Application.OnKeyDown (Key.N.WithAlt));
+        Assert.False (cm.MenuBar!.IsMenuOpen);
+        Application.MainLoop!.RunIteration ();
+        Assert.True (newFile);
+        cm.Show (menuItems);
+        Assert.True (Application.OnKeyDown (Key.R.WithAlt));
+        Assert.False (cm.MenuBar.IsMenuOpen);
+        Application.MainLoop!.RunIteration ();
+        Assert.True (renameFile);
+        cm.Show (menuItems);
+        Assert.True (Application.OnKeyDown (Key.D.WithAlt));
+        Assert.False (cm.MenuBar.IsMenuOpen);
+        Application.MainLoop!.RunIteration ();
+        Assert.True (deleteFile);
+
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithAlt));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.N.NoShift));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithAlt));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.NoShift));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.D.WithAlt));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.D.NoShift));
+
+        newFile = false;
+        renameFile = false;
+        deleteFile = false;
+        Assert.False (Application.OnKeyDown (Key.N.WithAlt));
+        Assert.False (Application.OnKeyDown (Key.R.WithAlt));
+        Assert.False (Application.OnKeyDown (Key.D.WithAlt));
+        Assert.False (newFile);
+        Assert.False (renameFile);
+        Assert.False (deleteFile);
+
+        top.Dispose ();
+
+        void New () { newFile = true; }
+
+        void Rename () { renameFile = true; }
+
+        void Delete () { deleteFile = true; }
+    }
+
+    [Fact]
+    [AutoInitShutdown]
+    public void HotKeys_With_ContextMenu_And_MenuBar ()
+    {
+        var newFile = false;
+        var renameFile = false;
+
+        var menuBar = new MenuBar
+        {
+            Menus =
+            [
+                new (
+                     "_File",
+                     new MenuItem []
+                     {
+                         new ("_New", string.Empty, New)
+                     })
+            ]
+        };
+        var cm = new ContextMenu ();
+
+        var menuItems = new MenuBarItem (
+                                         [
+                                             new MenuBarItem (
+                                                              "_Edit",
+                                                              new MenuItem []
+                                                              {
+                                                                  new ("_Rename File", string.Empty, Rename)
+                                                              }
+                                                             )
+                                         ]
+                                        );
+        var top = new Toplevel ();
+        top.Add (menuBar);
+        Application.Begin (top);
+
+        Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.F.WithAlt));
+        Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithAlt));
+        Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithAlt));
+        View [] menus = Application.Current!.Subviews.Where (v => v is Menu m && m.Host == menuBar).ToArray ();
+        Assert.Empty (menus);
+        Assert.Null (cm.MenuBar);
+
+        Assert.True (Application.OnKeyDown (Key.F.WithAlt));
+        Assert.True (menuBar.IsMenuOpen);
+        Assert.Equal (2, Application.Current!.Subviews.Count);
+        menus = Application.Current!.Subviews.Where (v => v is Menu m && m.Host == menuBar).ToArray ();
+        Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.N.WithAlt));
+        Assert.True (Application.OnKeyDown (Key.N.WithAlt));
+        Assert.False (menuBar.IsMenuOpen);
+        Assert.False (Application.OnKeyDown (Key.R.WithAlt));
+        Application.MainLoop!.RunIteration ();
+        Assert.True (newFile);
+        Assert.False (renameFile);
+
+        newFile = false;
+
+        cm.Show (menuItems);
+        Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.F.WithAlt));
+        Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.F.NoShift));
+        Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithAlt));
+        Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.NoShift));
+        Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.E.WithAlt));
+        Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.E.NoShift));
+        Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithAlt));
+        Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.R.NoShift));
+        Assert.True (cm.MenuBar!.IsMenuOpen);
+        Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.F.WithAlt));
+        Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.F.NoShift));
+        Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.N.WithAlt));
+        Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.N.NoShift));
+        Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.E.WithAlt));
+        Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.E.NoShift));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithAlt));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.NoShift));
+        Assert.Equal (3, Application.Current!.Subviews.Count);
+        menus = Application.Current!.Subviews.Where (v => v is Menu m && m.Host == cm.MenuBar).ToArray ();
+        Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.E.WithAlt));
+        Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.E.NoShift));
+        Assert.True (menus [1].KeyBindings.Bindings.ContainsKey (Key.R.WithAlt));
+        Assert.True (menus [1].KeyBindings.Bindings.ContainsKey (Key.R.NoShift));
+        Assert.True (cm.MenuBar.IsMenuOpen);
+        Assert.True (Application.OnKeyDown (Key.F.WithAlt));
+        Assert.False (cm.MenuBar.IsMenuOpen);
+        Assert.True (Application.OnKeyDown (Key.N.WithAlt));
+        Application.MainLoop!.RunIteration ();
+        Assert.True (newFile);
+
+        cm.Show (menuItems);
+        Assert.True (cm.MenuBar.IsMenuOpen);
+        Assert.Equal (3, Application.Current!.Subviews.Count);
+        menus = Application.Current!.Subviews.Where (v => v is Menu m && m.Host == cm.MenuBar).ToArray ();
+        Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.E.WithAlt));
+        Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.E.NoShift));
+        Assert.False (menus [0].KeyBindings.Bindings.ContainsKey (Key.R.WithAlt));
+        Assert.False (menus [0].KeyBindings.Bindings.ContainsKey (Key.R.NoShift));
+        Assert.False (menus [1].KeyBindings.Bindings.ContainsKey (Key.E.WithAlt));
+        Assert.False (menus [1].KeyBindings.Bindings.ContainsKey (Key.E.NoShift));
+        Assert.True (menus [1].KeyBindings.Bindings.ContainsKey (Key.R.WithAlt));
+        Assert.True (menus [1].KeyBindings.Bindings.ContainsKey (Key.R.NoShift));
+        Assert.True (Application.OnKeyDown (Key.E.NoShift));
+        Assert.True (Application.OnKeyDown (Key.R.WithAlt));
+        Assert.False (cm.MenuBar.IsMenuOpen);
+        Application.MainLoop!.RunIteration ();
+        Assert.True (renameFile);
+
+        Assert.Single (Application.Current!.Subviews);
+        Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.F.WithAlt));
+        Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.F.NoShift));
+        Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithAlt));
+        Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.NoShift));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.E.WithAlt));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.E.NoShift));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithAlt));
+        Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.NoShift));
+
+        newFile = false;
+        renameFile = false;
+        Assert.True (Application.OnKeyDown (Key.F.WithAlt));
+        Assert.True (Application.OnKeyDown (Key.N.WithAlt));
+        Assert.False (Application.OnKeyDown (Key.R.WithAlt));
+        Application.MainLoop!.RunIteration ();
+        Assert.True (newFile);
+        Assert.False (renameFile);
+
+        top.Dispose ();
+
+        void New () { newFile = true; }
+
+        void Rename () { renameFile = true; }
+    }
+
+    [Fact]
+    [AutoInitShutdown]
+    public void Opened_MenuBar_Is_Closed_When_Another_MenuBar_Is_Opening_Also_By_HotKey ()
+    {
+        var menuBar = new MenuBar
+        {
+            Menus =
+            [
+                new (
+                     "_File",
+                     new MenuItem []
+                     {
+                         new ("_New", string.Empty, null)
+                     })
+            ]
+        };
+        var cm = new ContextMenu ();
+
+        var menuItems = new MenuBarItem (
+                                         [
+                                             new MenuBarItem (
+                                                              "_Edit",
+                                                              new MenuItem []
+                                                              {
+                                                                  new ("_Rename File", string.Empty, null)
+                                                              }
+                                                             )
+                                         ]
+                                        );
+        var top = new Toplevel ();
+        top.Add (menuBar);
+        Application.Begin (top);
+
+        Assert.True (Application.OnKeyDown (Key.F.WithAlt));
+        Assert.True (menuBar.IsMenuOpen);
+
+        cm.Show (menuItems);
+        Assert.False (menuBar.IsMenuOpen);
+        Assert.True (cm.MenuBar!.IsMenuOpen);
+
+        Assert.True (Application.OnKeyDown (Key.F.WithAlt));
+        Assert.True (menuBar.IsMenuOpen);
+        Assert.False (cm.MenuBar!.IsMenuOpen);
+
+        top.Dispose ();
+    }
+}

+ 7 - 0
UnitTests/Views/DateFieldTests.cs

@@ -175,6 +175,12 @@ public class DateFieldTests
     [Fact]
     public void Using_All_Culture_StandardizeDateFormat ()
     {
+        // BUGBUG: This is a workaround for the issue with the date separator in macOS. See https://github.com/gui-cs/Terminal.Gui/issues/3592
+        if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX))
+        {
+            return;
+        }
+
         CultureInfo cultureBackup = CultureInfo.CurrentCulture;
 
         DateTime date = DateTime.Parse ("1/1/1971");
@@ -193,6 +199,7 @@ public class DateFieldTests
                 separator = " ";
             }
 
+
             string format = culture.DateTimeFormat.ShortDatePattern;
             var df = new DateField (date);
 

+ 3 - 3
UnitTests/Views/MenuBarTests.cs

@@ -15,10 +15,10 @@ public class MenuBarTests (ITestOutputHelper output)
         Assert.Equal ("n", menuBarItem.HotKey);
         Assert.Equal ("i", menuItem.HotKey);
         Assert.Empty (menuBar.Menus);
-        menuBarItem.AddMenuBarItem (menuItem);
+        menuBarItem.AddMenuBarItem (menuBar, menuItem);
         menuBar.Menus = [menuBarItem];
         Assert.Single (menuBar.Menus);
-        Assert.Single (menuBar.Menus [0].Children);
+        Assert.Single (menuBar.Menus [0].Children!);
         Assert.Contains (Key.N.WithAlt, menuBar.KeyBindings.Bindings);
         Assert.DoesNotContain (Key.I, menuBar.KeyBindings.Bindings);
 
@@ -2938,7 +2938,7 @@ Edit
 
         Assert.Contains (Key.A.WithCtrl, menuBar.KeyBindings.Bindings);
 
-        menuBar.Menus [0].Children [0].ShortcutKey = Key.B.WithCtrl;
+        menuBar.Menus [0].Children! [0].ShortcutKey = Key.B.WithCtrl;
 
         Assert.DoesNotContain (Key.A.WithCtrl, menuBar.KeyBindings.Bindings);
         Assert.Contains (Key.B.WithCtrl, menuBar.KeyBindings.Bindings);

+ 64 - 0
UnitTests/Views/MenuTests.cs

@@ -43,4 +43,68 @@ public class MenuTests
 
         void Run () { }
     }
+
+    [Fact]
+    public void MenuBarItem_SubMenu_Can_Return_Null ()
+    {
+        var menuItem = new MenuItem ();
+        var menuBarItem = new MenuBarItem ();
+        Assert.Null (menuBarItem.SubMenu (menuItem));
+    }
+
+    [Fact]
+    public void MenuBarItem_Constructors_Defaults ()
+    {
+        var menuBarItem = new MenuBarItem ();
+        Assert.Equal ("", menuBarItem.Title);
+        Assert.Equal ("", menuBarItem.Help);
+        Assert.Null (menuBarItem.Action);
+        Assert.Null (menuBarItem.CanExecute);
+        Assert.Null (menuBarItem.Parent);
+        Assert.Equal (Key.Empty, menuBarItem.ShortcutKey);
+        Assert.Equal ([], menuBarItem.Children);
+        Assert.False (menuBarItem.IsTopLevel);
+
+        menuBarItem = new MenuBarItem (null!, null!, Run, () => true, new ());
+        Assert.Equal ("", menuBarItem.Title);
+        Assert.Equal ("", menuBarItem.Help);
+        Assert.Equal (Run, menuBarItem.Action);
+        Assert.NotNull (menuBarItem.CanExecute);
+        Assert.NotNull (menuBarItem.Parent);
+        Assert.Equal (Key.Empty, menuBarItem.ShortcutKey);
+        Assert.Null (menuBarItem.Children);
+        Assert.False (menuBarItem.IsTopLevel);
+
+        menuBarItem = new MenuBarItem (null!, Array.Empty<MenuItem> (), new ());
+        Assert.Equal ("", menuBarItem.Title);
+        Assert.Equal ("", menuBarItem.Help);
+        Assert.Null (menuBarItem.Action);
+        Assert.Null (menuBarItem.CanExecute);
+        Assert.NotNull (menuBarItem.Parent);
+        Assert.Equal (Key.Empty, menuBarItem.ShortcutKey);
+        Assert.Equal ([], menuBarItem.Children);
+        Assert.False (menuBarItem.IsTopLevel);
+
+        menuBarItem = new MenuBarItem (null!, new List<MenuItem []> (), new ());
+        Assert.Equal ("", menuBarItem.Title);
+        Assert.Equal ("", menuBarItem.Help);
+        Assert.Null (menuBarItem.Action);
+        Assert.Null (menuBarItem.CanExecute);
+        Assert.NotNull (menuBarItem.Parent);
+        Assert.Equal (Key.Empty, menuBarItem.ShortcutKey);
+        Assert.Equal ([], menuBarItem.Children);
+        Assert.False (menuBarItem.IsTopLevel);
+
+        menuBarItem = new MenuBarItem ([]);
+        Assert.Equal ("", menuBarItem.Title);
+        Assert.Equal ("", menuBarItem.Help);
+        Assert.Null (menuBarItem.Action);
+        Assert.Null (menuBarItem.CanExecute);
+        Assert.Null (menuBarItem.Parent);
+        Assert.Equal (Key.Empty, menuBarItem.ShortcutKey);
+        Assert.Equal ([], menuBarItem.Children);
+        Assert.False (menuBarItem.IsTopLevel);
+
+        void Run () { }
+    }
 }

+ 172 - 3
UnitTests/Views/TableViewTests.cs

@@ -1068,7 +1068,7 @@ public class TableViewTests (ITestOutputHelper output)
         Application.Begin (top);
 
         tv.HasFocus = focused;
-        Assert.Equal(focused, tv.HasFocus);
+        Assert.Equal (focused, tv.HasFocus);
 
         tv.Draw ();
 
@@ -1155,7 +1155,7 @@ public class TableViewTests (ITestOutputHelper output)
 
         // when B is 2 use the custom highlight color for the row
         tv.Style.RowColorGetter += e => Convert.ToInt32 (e.Table [e.RowIndex, 1]) == 2 ? rowHighlight : null;
-        
+
         var top = new Toplevel ();
         top.Add (tv);
         Application.Begin (top);
@@ -3169,7 +3169,7 @@ A B C
     }
 
     [Fact]
-    public void TestDataColumnCaption()
+    public void TestDataColumnCaption ()
     {
         var tableView = new TableView ();
 
@@ -3191,6 +3191,175 @@ A B C
         Assert.Equal ("Column Name 2", cn [1]);
     }
 
+
+    [Fact]
+    public void CanTabOutOfTableViewUsingCursor_Left ()
+    {
+        GetTableViewWithSiblings (out var tf1, out var tableView, out var tf2);
+
+        // Make the selected cell one in
+        tableView.SelectedColumn = 1;
+
+        // Pressing left should move us to the first column without changing focus
+        Application.OnKeyDown (Key.CursorLeft);
+        Assert.Same (tableView, Application.Current.MostFocused);
+        Assert.True (tableView.HasFocus);
+
+        // Because we are now on the leftmost cell a further left press should move focus
+        Application.OnKeyDown (Key.CursorLeft);
+
+        Assert.NotSame (tableView, Application.Current.MostFocused);
+        Assert.False (tableView.HasFocus);
+
+        Assert.Same (tf1, Application.Current.MostFocused);
+        Assert.True (tf1.HasFocus);
+
+        Application.Current.Dispose ();
+    }
+
+    [Fact]
+    public void CanTabOutOfTableViewUsingCursor_Up ()
+    {
+        GetTableViewWithSiblings (out var tf1, out var tableView, out var tf2);
+
+        // Make the selected cell one in
+        tableView.SelectedRow = 1;
+
+        // First press should move us up
+        Application.OnKeyDown (Key.CursorUp);
+        Assert.Same (tableView, Application.Current.MostFocused);
+        Assert.True (tableView.HasFocus);
+
+        // Because we are now on the top row a further press should move focus
+        Application.OnKeyDown (Key.CursorUp);
+
+        Assert.NotSame (tableView, Application.Current.MostFocused);
+        Assert.False (tableView.HasFocus);
+
+        Assert.Same (tf1, Application.Current.MostFocused);
+        Assert.True (tf1.HasFocus);
+
+        Application.Current.Dispose ();
+    }
+    [Fact]
+    public void CanTabOutOfTableViewUsingCursor_Right ()
+    {
+        GetTableViewWithSiblings (out var tf1, out var tableView, out var tf2);
+
+        // Make the selected cell one in from the rightmost column
+        tableView.SelectedColumn = tableView.Table.Columns - 2;
+
+        // First press should move us to the rightmost column without changing focus
+        Application.OnKeyDown (Key.CursorRight);
+        Assert.Same (tableView, Application.Current.MostFocused);
+        Assert.True (tableView.HasFocus);
+
+        // Because we are now on the rightmost cell, a further right press should move focus
+        Application.OnKeyDown (Key.CursorRight);
+
+        Assert.NotSame (tableView, Application.Current.MostFocused);
+        Assert.False (tableView.HasFocus);
+
+        Assert.Same (tf2, Application.Current.MostFocused);
+        Assert.True (tf2.HasFocus);
+
+        Application.Current.Dispose ();
+    }
+
+    [Fact]
+    public void CanTabOutOfTableViewUsingCursor_Down ()
+    {
+        GetTableViewWithSiblings (out var tf1, out var tableView, out var tf2);
+
+        // Make the selected cell one in from the bottommost row
+        tableView.SelectedRow = tableView.Table.Rows - 2;
+
+        // First press should move us to the bottommost row without changing focus
+        Application.OnKeyDown (Key.CursorDown);
+        Assert.Same (tableView, Application.Current.MostFocused);
+        Assert.True (tableView.HasFocus);
+
+        // Because we are now on the bottommost cell, a further down press should move focus
+        Application.OnKeyDown (Key.CursorDown);
+
+        Assert.NotSame (tableView, Application.Current.MostFocused);
+        Assert.False (tableView.HasFocus);
+
+        Assert.Same (tf2, Application.Current.MostFocused);
+        Assert.True (tf2.HasFocus);
+
+        Application.Current.Dispose ();
+    }
+
+
+    [Fact]
+    public void CanTabOutOfTableViewUsingCursor_Left_ClearsSelectionFirst ()
+    {
+        GetTableViewWithSiblings (out var tf1, out var tableView, out var tf2);
+
+        // Make the selected cell one in
+        tableView.SelectedColumn = 1;
+
+        // Pressing shift-left should give us a multi selection
+        Application.OnKeyDown (Key.CursorLeft.WithShift);
+        Assert.Same (tableView, Application.Current.MostFocused);
+        Assert.True (tableView.HasFocus);
+        Assert.Equal (2, tableView.GetAllSelectedCells ().Count ());
+
+        // Because we are now on the leftmost cell a further left press would normally move focus
+        // However there is an ongoing selection so instead the operation clears the selection and
+        // gets swallowed (not resulting in a focus change)
+        Application.OnKeyDown (Key.CursorLeft);
+
+        // Selection 'clears' just to the single cell and we remain focused
+        Assert.Single (tableView.GetAllSelectedCells ());
+        Assert.Same (tableView, Application.Current.MostFocused);
+        Assert.True (tableView.HasFocus);
+
+        // A further left will switch focus
+        Application.OnKeyDown (Key.CursorLeft);
+
+        Assert.NotSame (tableView, Application.Current.MostFocused);
+        Assert.False (tableView.HasFocus);
+
+        Assert.Same (tf1, Application.Current.MostFocused);
+        Assert.True (tf1.HasFocus);
+
+        Application.Current.Dispose ();
+    }
+
+    /// <summary>
+    /// Creates 3 views on <see cref="Application.Current"/> with the focus in the
+    /// <see cref="TableView"/>.  This is a helper method to setup tests that want to
+    /// explore moving input focus out of a tableview.
+    /// </summary>
+    /// <param name="tv"></param>
+    /// <param name="tf1"></param>
+    /// <param name="tf2"></param>
+    private void GetTableViewWithSiblings (out TextField tf1, out TableView tableView, out TextField tf2)
+    {
+        tableView = new TableView ();
+        tableView.BeginInit ();
+        tableView.EndInit ();
+
+        Application.Navigation = new ();
+        Application.Current = new ();
+        tf1 = new TextField ();
+        tf2 = new TextField ();
+        Application.Current.Add (tf1);
+        Application.Current.Add (tableView);
+        Application.Current.Add (tf2);
+
+        tableView.SetFocus ();
+
+        Assert.Same (tableView, Application.Current.MostFocused);
+        Assert.True (tableView.HasFocus);
+
+
+        // Set big table
+        tableView.Table = BuildTable (25, 50);
+    }
+
     private TableView GetABCDEFTableView (out DataTable dt)
     {
         var tableView = new TableView ();

+ 2 - 2
UnitTests/Views/ToplevelTests.cs

@@ -10,8 +10,8 @@ public partial class ToplevelTests (ITestOutputHelper output)
         var top = new Toplevel ();
 
         Assert.Equal (Colors.ColorSchemes ["TopLevel"], top.ColorScheme);
-        Assert.Equal ("Fill(0)", top.Width.ToString ());
-        Assert.Equal ("Fill(0)", top.Height.ToString ());
+        Assert.Equal ("Fill(Absolute(0))", top.Width.ToString ());
+        Assert.Equal ("Fill(Absolute(0))", top.Height.ToString ());
         Assert.False (top.Running);
         Assert.False (top.Modal);
         Assert.Null (top.MenuBar);