Browse Source

Enabled Adornment Focus

Tig 10 months ago
parent
commit
a94b085e0b

+ 21 - 0
Terminal.Gui/Drawing/Glyphs.cs

@@ -106,6 +106,27 @@ public class GlyphDefinitions
     /// <summary>Identical To (U+226)</summary>
     public Rune IdenticalTo { get; set; } = (Rune)'≡';
 
+    /// <summary>Move indicator. Default is Lozenge (U+25CA) - ◊.</summary>
+    public Rune Move { get; set; } = (Rune)'◊';
+
+    /// <summary>Size Horizontally indicator. Default is ┥Left Right Arrow - ↔ U+02194</summary>
+    public Rune SizeHorizontal { get; set; } = (Rune)'↔';
+    
+    /// <summary>Size Vertical indicator. Default Up Down Arrow - ↕ U+02195</summary>
+    public Rune SizeVertical { get; set; } = (Rune)'↕';
+
+    /// <summary>Size Top Left indicator. North West Arrow - ↖ U+02196</summary>
+    public Rune SizeTopLeft { get; set; } = (Rune)'↖';
+
+    /// <summary>Size Top Right indicator. North East Arrow - ↗ U+02197</summary>
+    public Rune SizeTopRight { get; set; } = (Rune)'↗';
+
+    /// <summary>Size Bottom Right indicator. South East Arrow - ↘ U+02198</summary>
+    public Rune SizeBottomRight { get; set; } = (Rune)'↘';
+
+    /// <summary>Size Bottom Left indicator. South West Arrow - ↙ U+02199</summary>
+    public Rune SizeBottomLLeft { get; set; } = (Rune)'↙';
+    
     /// <summary>Apple (non-BMP). Because snek. And because it's an example of a non-BMP surrogate pair. See Issue #2610.</summary>
     public Rune Apple { get; set; } = "🍎".ToRunes () [0]; // nonBMP
 

+ 2 - 1
Terminal.Gui/View/Adornment/Adornment.cs

@@ -26,7 +26,8 @@ public class Adornment : View
     /// <param name="parent"></param>
     public Adornment (View parent)
     {
-        CanFocus = true;
+        // By default Adornments can't get focus; has to be enabled specifically.
+        CanFocus = false;
         Parent = parent;
     }
 

+ 216 - 154
Terminal.Gui/View/Adornment/Border.cs

@@ -1,7 +1,5 @@
 #nullable enable
 using System.Diagnostics;
-using Microsoft.CodeAnalysis;
-using static Terminal.Gui.SpinnerStyle;
 
 namespace Terminal.Gui;
 
@@ -68,7 +66,6 @@ public class Border : Adornment
         Highlight += Border_Highlight;
     }
 
-
 #if SUBVIEW_BASED_BORDER
     private Line _left;
 
@@ -78,7 +75,6 @@ public class Border : Adornment
     public Button CloseButton { get; internal set; }
 #endif
 
-
     /// <inheritdoc/>
     public override void BeginInit ()
     {
@@ -117,11 +113,8 @@ public class Border : Adornment
             LayoutStarted += OnLayoutStarted;
     }
 #endif
-
     }
 
-
-
 #if SUBVIEW_BASED_BORDER
     private void OnLayoutStarted (object sender, LayoutEventArgs e)
     {
@@ -164,6 +157,7 @@ public class Border : Adornment
     internal Rectangle GetBorderRectangle ()
     {
         Rectangle screenRect = ViewportToScreen (Viewport);
+
         return new (
                     screenRect.X + Math.Max (0, Thickness.Left - 1),
                     screenRect.Y + Math.Max (0, Thickness.Top - 1),
@@ -312,6 +306,11 @@ public class Border : Adornment
             // Adornment.Contains takes Parent SuperView=relative coords.
             if (Contains (new (mouseEvent.Position.X + Parent.Frame.X + Frame.X, mouseEvent.Position.Y + Parent.Frame.Y + Frame.Y)))
             {
+                if (_arranging != ViewArrangement.Fixed)
+                {
+                    EndArrangeMode ();
+                }
+
                 // Set the start grab point to the Frame coords
                 _startGrabPoint = new (mouseEvent.Position.X + Frame.X, mouseEvent.Position.Y + Frame.Y);
                 _dragPosition = mouseEvent.Position;
@@ -319,23 +318,19 @@ public class Border : Adornment
 
                 SetHighlight (HighlightStyle);
 
+                // If not resizable, but movable: Drag anywhere is move
                 // If resizable and movable: Drag on top is move, other 3 sides are size
                 // If not movable, but resizable: Drag on any side sizes.
 
                 // Get rectangle representing Thickness.Top
                 // If mouse is in that rectangle, set _arranging to ViewArrangement.Movable
-                Rectangle sideRect = new (Frame.X + Thickness.Left, Frame.Y, Frame.Width - Thickness.Left - Thickness.Right, Thickness.Top);
-                if (Parent!.Arrangement.HasFlag (ViewArrangement.Movable) && sideRect.Contains (_startGrabPoint))
-                {
-                    EnterArrangeMode (ViewArrangement.Movable);
-
-                    return true;
-                }
+                Rectangle sideRect;
 
                 // If mouse is in any other rectangle, set _arranging to ViewArrangement.<side>
                 if (Parent!.Arrangement.HasFlag (ViewArrangement.LeftResizable))
                 {
                     sideRect = new (Frame.X, Frame.Y + Thickness.Top, Thickness.Left, Frame.Height - Thickness.Top - Thickness.Bottom);
+
                     if (sideRect.Contains (_startGrabPoint))
                     {
                         EnterArrangeMode (ViewArrangement.LeftResizable);
@@ -346,7 +341,12 @@ public class Border : Adornment
 
                 if (Parent!.Arrangement.HasFlag (ViewArrangement.RightResizable))
                 {
-                    sideRect = new (Frame.X + Frame.Width - Thickness.Right, Frame.Y + Thickness.Top, Thickness.Right, Frame.Height - Thickness.Top - Thickness.Bottom);
+                    sideRect = new (
+                                    Frame.X + Frame.Width - Thickness.Right,
+                                    Frame.Y + Thickness.Top,
+                                    Thickness.Right,
+                                    Frame.Height - Thickness.Top - Thickness.Bottom);
+
                     if (sideRect.Contains (_startGrabPoint))
                     {
                         EnterArrangeMode (ViewArrangement.RightResizable);
@@ -355,9 +355,10 @@ public class Border : Adornment
                     }
                 }
 
-                if (Parent!.Arrangement.HasFlag (ViewArrangement.TopResizable))
+                if (Parent!.Arrangement.HasFlag (ViewArrangement.TopResizable) && !Parent!.Arrangement.HasFlag (ViewArrangement.Movable))
                 {
                     sideRect = new (Frame.X + Thickness.Left, Frame.Y, Frame.Width - Thickness.Left - Thickness.Right, Thickness.Top);
+
                     if (sideRect.Contains (_startGrabPoint))
                     {
                         EnterArrangeMode (ViewArrangement.TopResizable);
@@ -368,7 +369,12 @@ public class Border : Adornment
 
                 if (Parent!.Arrangement.HasFlag (ViewArrangement.BottomResizable))
                 {
-                    sideRect = new (Frame.X + Thickness.Left, Frame.Y + Frame.Height - Thickness.Bottom, Frame.Width - Thickness.Left - Thickness.Right, Thickness.Bottom);
+                    sideRect = new (
+                                    Frame.X + Thickness.Left,
+                                    Frame.Y + Frame.Height - Thickness.Bottom,
+                                    Frame.Width - Thickness.Left - Thickness.Right,
+                                    Thickness.Bottom);
+
                     if (sideRect.Contains (_startGrabPoint))
                     {
                         EnterArrangeMode (ViewArrangement.BottomResizable);
@@ -377,10 +383,10 @@ public class Border : Adornment
                     }
                 }
 
-
                 if (Parent!.Arrangement.HasFlag (ViewArrangement.BottomResizable) && Parent!.Arrangement.HasFlag (ViewArrangement.LeftResizable))
                 {
                     sideRect = new (Frame.X, Frame.Height - Thickness.Top, Thickness.Left, Thickness.Bottom);
+
                     if (sideRect.Contains (_startGrabPoint))
                     {
                         EnterArrangeMode (ViewArrangement.BottomResizable | ViewArrangement.LeftResizable);
@@ -392,6 +398,7 @@ public class Border : Adornment
                 if (Parent!.Arrangement.HasFlag (ViewArrangement.BottomResizable) && Parent!.Arrangement.HasFlag (ViewArrangement.RightResizable))
                 {
                     sideRect = new (Frame.X + Frame.Width - Thickness.Right, Frame.Height - Thickness.Top, Thickness.Right, Thickness.Bottom);
+
                     if (sideRect.Contains (_startGrabPoint))
                     {
                         EnterArrangeMode (ViewArrangement.BottomResizable | ViewArrangement.RightResizable);
@@ -403,6 +410,7 @@ public class Border : Adornment
                 if (Parent!.Arrangement.HasFlag (ViewArrangement.TopResizable) && Parent!.Arrangement.HasFlag (ViewArrangement.RightResizable))
                 {
                     sideRect = new (Frame.X + Frame.Width - Thickness.Right, Frame.Y, Thickness.Right, Thickness.Top);
+
                     if (sideRect.Contains (_startGrabPoint))
                     {
                         EnterArrangeMode (ViewArrangement.TopResizable | ViewArrangement.RightResizable);
@@ -414,6 +422,7 @@ public class Border : Adornment
                 if (Parent!.Arrangement.HasFlag (ViewArrangement.TopResizable) && Parent!.Arrangement.HasFlag (ViewArrangement.LeftResizable))
                 {
                     sideRect = new (Frame.X, Frame.Y, Thickness.Left, Thickness.Top);
+
                     if (sideRect.Contains (_startGrabPoint))
                     {
                         EnterArrangeMode (ViewArrangement.TopResizable | ViewArrangement.LeftResizable);
@@ -422,7 +431,17 @@ public class Border : Adornment
                     }
                 }
 
+                if (Parent!.Arrangement.HasFlag (ViewArrangement.Movable))
+                {
+                    //sideRect = new (Frame.X + Thickness.Left, Frame.Y, Frame.Width - Thickness.Left - Thickness.Right, Thickness.Top);
 
+                    //if (sideRect.Contains (_startGrabPoint))
+                    {
+                        EnterArrangeMode (ViewArrangement.Movable);
+
+                        return true;
+                    }
+                }
             }
 
             return true;
@@ -449,11 +468,11 @@ public class Border : Adornment
 
                 int minHeight = Thickness.Vertical + Parent!.Margin.Thickness.Bottom;
                 int minWidth = Thickness.Horizontal + Parent!.Margin.Thickness.Right;
+
                 switch (_arranging)
                 {
                     case ViewArrangement.Movable:
 
-
                         GetLocationEnsuringFullVisibility (
                                                            Parent,
                                                            parentLoc.X - _startGrabPoint.X,
@@ -484,6 +503,7 @@ public class Border : Adornment
 
                     case ViewArrangement.BottomResizable:
                         Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin.Thickness.Bottom + 1);
+
                         break;
 
                     case ViewArrangement.LeftResizable:
@@ -497,6 +517,7 @@ public class Border : Adornment
                             Parent.Width = newWidth;
                             Parent.X = parentLoc.X - _startGrabPoint.X;
                         }
+
                         break;
 
                     case ViewArrangement.RightResizable:
@@ -521,6 +542,7 @@ public class Border : Adornment
                         }
 
                         Parent.Height = Math.Max (minHeight, parentLoc.Y - Parent.Frame.Y + Parent!.Margin.Thickness.Bottom + 1);
+
                         break;
 
                     case ViewArrangement.TopResizable | ViewArrangement.RightResizable:
@@ -534,6 +556,7 @@ public class Border : Adornment
                         }
 
                         Parent.Width = Math.Max (minWidth, parentLoc.X - Parent.Frame.X + Parent!.Margin.Thickness.Right + 1);
+
                         break;
 
                     case ViewArrangement.TopResizable | ViewArrangement.LeftResizable:
@@ -554,11 +577,10 @@ public class Border : Adornment
                             Parent.Width = newW2;
                             Parent.X = parentLoc.X - _startGrabPoint.X;
                         }
-                        break;
 
+                        break;
                 }
 
-
                 return true;
             }
         }
@@ -569,7 +591,7 @@ public class Border : Adornment
             Application.UngrabMouse ();
             SetHighlight (HighlightStyle.None);
 
-            EndArrange ();
+            EndArrangeMode ();
 
             return true;
         }
@@ -713,12 +735,12 @@ public class Border : Adornment
                 {
                     // ╔╡╞╗ should be ╔══╗
                     lc?.AddLine (
-                                new (borderBounds.Location.X, titleY),
-                                borderBounds.Width,
-                                Orientation.Horizontal,
-                                lineStyle,
-                                Driver.GetAttribute ()
-                               );
+                                 new (borderBounds.Location.X, titleY),
+                                 borderBounds.Width,
+                                 Orientation.Horizontal,
+                                 lineStyle,
+                                 Driver.GetAttribute ()
+                                );
                 }
                 else
                 {
@@ -728,12 +750,12 @@ public class Border : Adornment
                     if (Thickness.Top == 2)
                     {
                         lc?.AddLine (
-                                    new (borderBounds.X + 1, topTitleLineY),
-                                    Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
-                                    Orientation.Horizontal,
-                                    lineStyle,
-                                    Driver.GetAttribute ()
-                                   );
+                                     new (borderBounds.X + 1, topTitleLineY),
+                                     Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
+                                     Orientation.Horizontal,
+                                     lineStyle,
+                                     Driver.GetAttribute ()
+                                    );
                     }
 
                     // ┌────┐
@@ -742,70 +764,70 @@ public class Border : Adornment
                     if (borderBounds.Width >= 4 && Thickness.Top > 2)
                     {
                         lc?.AddLine (
-                                    new (borderBounds.X + 1, topTitleLineY),
-                                    Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
-                                    Orientation.Horizontal,
-                                    lineStyle,
-                                    Driver.GetAttribute ()
-                                   );
+                                     new (borderBounds.X + 1, topTitleLineY),
+                                     Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
+                                     Orientation.Horizontal,
+                                     lineStyle,
+                                     Driver.GetAttribute ()
+                                    );
 
                         lc?.AddLine (
-                                    new (borderBounds.X + 1, topTitleLineY + 2),
-                                    Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
-                                    Orientation.Horizontal,
-                                    lineStyle,
-                                    Driver.GetAttribute ()
-                                   );
+                                     new (borderBounds.X + 1, topTitleLineY + 2),
+                                     Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
+                                     Orientation.Horizontal,
+                                     lineStyle,
+                                     Driver.GetAttribute ()
+                                    );
                     }
 
                     // ╔╡Title╞═════╗
                     // Add a short horiz line for ╔╡
                     lc?.AddLine (
-                                new (borderBounds.Location.X, titleY),
-                                2,
-                                Orientation.Horizontal,
-                                lineStyle,
-                                Driver.GetAttribute ()
-                               );
+                                 new (borderBounds.Location.X, titleY),
+                                 2,
+                                 Orientation.Horizontal,
+                                 lineStyle,
+                                 Driver.GetAttribute ()
+                                );
 
                     // Add a vert line for ╔╡
                     lc?.AddLine (
-                                new (borderBounds.X + 1, topTitleLineY),
-                                titleBarsLength,
-                                Orientation.Vertical,
-                                LineStyle.Single,
-                                Driver.GetAttribute ()
-                               );
+                                 new (borderBounds.X + 1, topTitleLineY),
+                                 titleBarsLength,
+                                 Orientation.Vertical,
+                                 LineStyle.Single,
+                                 Driver.GetAttribute ()
+                                );
 
                     // Add a vert line for ╞
                     lc?.AddLine (
-                                new (
-                                     borderBounds.X
-                                     + 1
-                                     + Math.Min (borderBounds.Width - 2, maxTitleWidth + 2)
-                                     - 1,
-                                     topTitleLineY
-                                    ),
-                                titleBarsLength,
-                                Orientation.Vertical,
-                                LineStyle.Single,
-                                Driver.GetAttribute ()
-                               );
+                                 new (
+                                      borderBounds.X
+                                      + 1
+                                      + Math.Min (borderBounds.Width - 2, maxTitleWidth + 2)
+                                      - 1,
+                                      topTitleLineY
+                                     ),
+                                 titleBarsLength,
+                                 Orientation.Vertical,
+                                 LineStyle.Single,
+                                 Driver.GetAttribute ()
+                                );
 
                     // Add the right hand line for ╞═════╗
                     lc?.AddLine (
-                                new (
-                                     borderBounds.X
-                                     + 1
-                                     + Math.Min (borderBounds.Width - 2, maxTitleWidth + 2)
-                                     - 1,
-                                     titleY
-                                    ),
-                                borderBounds.Width - Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
-                                Orientation.Horizontal,
-                                lineStyle,
-                                Driver.GetAttribute ()
-                               );
+                                 new (
+                                      borderBounds.X
+                                      + 1
+                                      + Math.Min (borderBounds.Width - 2, maxTitleWidth + 2)
+                                      - 1,
+                                      titleY
+                                     ),
+                                 borderBounds.Width - Math.Min (borderBounds.Width - 2, maxTitleWidth + 2),
+                                 Orientation.Horizontal,
+                                 lineStyle,
+                                 Driver.GetAttribute ()
+                                );
                 }
             }
 
@@ -814,35 +836,35 @@ public class Border : Adornment
             if (drawLeft)
             {
                 lc?.AddLine (
-                            new (borderBounds.Location.X, titleY),
-                            sideLineLength,
-                            Orientation.Vertical,
-                            lineStyle,
-                            Driver.GetAttribute ()
-                           );
+                             new (borderBounds.Location.X, titleY),
+                             sideLineLength,
+                             Orientation.Vertical,
+                             lineStyle,
+                             Driver.GetAttribute ()
+                            );
             }
 #endif
 
             if (drawBottom)
             {
                 lc?.AddLine (
-                            new (borderBounds.X, borderBounds.Y + borderBounds.Height - 1),
-                            borderBounds.Width,
-                            Orientation.Horizontal,
-                            lineStyle,
-                            Driver.GetAttribute ()
-                           );
+                             new (borderBounds.X, borderBounds.Y + borderBounds.Height - 1),
+                             borderBounds.Width,
+                             Orientation.Horizontal,
+                             lineStyle,
+                             Driver.GetAttribute ()
+                            );
             }
 
             if (drawRight)
             {
                 lc?.AddLine (
-                            new (borderBounds.X + borderBounds.Width - 1, titleY),
-                            sideLineLength,
-                            Orientation.Vertical,
-                            lineStyle,
-                            Driver.GetAttribute ()
-                           );
+                             new (borderBounds.X + borderBounds.Width - 1, titleY),
+                             sideLineLength,
+                             Orientation.Vertical,
+                             lineStyle,
+                             Driver.GetAttribute ()
+                            );
             }
 
             Driver.SetAttribute (prevAttr);
@@ -862,9 +884,9 @@ public class Border : Adornment
                 if (drawTop && maxTitleWidth > 0 && Settings.FastHasFlags (BorderSettings.Title))
                 {
                     Parent!.TitleTextFormatter.Draw (
-                                                    new (borderBounds.X + 2, titleY, maxTitleWidth, 1),
-                                                    Parent.HasFocus ? Parent.GetFocusColor () : Parent.GetNormalColor (),
-                                                    Parent.HasFocus ? Parent.GetFocusColor () : Parent.GetNormalColor ());
+                                                     new (borderBounds.X + 2, titleY, maxTitleWidth, 1),
+                                                     Parent.HasFocus ? Parent.GetFocusColor () : Parent.GetNormalColor (),
+                                                     Parent.HasFocus ? Parent.GetFocusColor () : Parent.GetNormalColor ());
                 }
 
                 //Left
@@ -943,7 +965,8 @@ public class Border : Adornment
     ///     or keyboard. If <paramref name="arrangement"/> is <see cref="ViewArrangement.Fixed"/> keyboard mode is enabled.
     /// </summary>
     /// <remarks>
-    ///     Arrange Mode is exited by the user pressing <see cref="Application.ArrangeKey"/>, <see cref="Key.Esc"/>, or by clicking
+    ///     Arrange Mode is exited by the user pressing <see cref="Application.ArrangeKey"/>, <see cref="Key.Esc"/>, or by
+    ///     clicking
     ///     the mouse out of the <see cref="Adornment.Parent"/>'s Frame.
     /// </remarks>
     /// <returns></returns>
@@ -956,7 +979,7 @@ public class Border : Adornment
             && !Parent!.Arrangement.HasFlag (ViewArrangement.TopResizable)
             && !Parent!.Arrangement.HasFlag (ViewArrangement.LeftResizable)
             && !Parent!.Arrangement.HasFlag (ViewArrangement.RightResizable)
-            )
+           )
         {
             return false;
         }
@@ -971,7 +994,7 @@ public class Border : Adornment
         {
             Debug.Assert (_moveButton is null);
 
-            _moveButton = new Button
+            _moveButton = new ()
             {
                 Id = "moveButton",
                 CanFocus = true,
@@ -980,8 +1003,9 @@ public class Border : Adornment
                 NoDecorations = true,
                 NoPadding = true,
                 ShadowStyle = ShadowStyle.None,
-                Text = $"{Glyphs.Diamond}",
+                Text = $"{Glyphs.Move}",
                 Visible = false,
+                Data = ViewArrangement.Movable
             };
             Add (_moveButton);
         }
@@ -990,7 +1014,7 @@ public class Border : Adornment
         {
             Debug.Assert (_allSizeButton is null);
 
-            _allSizeButton = new Button
+            _allSizeButton = new ()
             {
                 Id = "allSizeButton",
                 CanFocus = true,
@@ -999,10 +1023,11 @@ public class Border : Adornment
                 NoDecorations = true,
                 NoPadding = true,
                 ShadowStyle = ShadowStyle.None,
-                Text = $"{Glyphs.Diamond}",
+                Text = $"{Glyphs.SizeBottomRight}",
                 X = Pos.AnchorEnd (),
                 Y = Pos.AnchorEnd (),
                 Visible = false,
+                Data = ViewArrangement.Resizable
             };
             Add (_allSizeButton);
         }
@@ -1011,7 +1036,7 @@ public class Border : Adornment
         {
             Debug.Assert (_topSizeButton is null);
 
-            _topSizeButton = new Button
+            _topSizeButton = new ()
             {
                 Id = "topSizeButton",
                 CanFocus = true,
@@ -1020,10 +1045,11 @@ public class Border : Adornment
                 NoDecorations = true,
                 NoPadding = true,
                 ShadowStyle = ShadowStyle.None,
-                Text = $"{Glyphs.Diamond}",
+                Text = $"{Glyphs.SizeVertical}",
                 X = Pos.Center () + Parent!.Margin.Thickness.Horizontal,
                 Y = 0,
                 Visible = false,
+                Data = ViewArrangement.TopResizable
             };
             Add (_topSizeButton);
         }
@@ -1032,7 +1058,7 @@ public class Border : Adornment
         {
             Debug.Assert (_rightSizeButton is null);
 
-            _rightSizeButton = new Button
+            _rightSizeButton = new ()
             {
                 Id = "rightSizeButton",
                 CanFocus = true,
@@ -1041,10 +1067,11 @@ public class Border : Adornment
                 NoDecorations = true,
                 NoPadding = true,
                 ShadowStyle = ShadowStyle.None,
-                Text = $"{Glyphs.Diamond}",
+                Text = $"{Glyphs.SizeHorizontal}",
                 X = Pos.AnchorEnd (),
-                Y = Pos.Center () + Parent!.Margin.Thickness.Vertical,
+                Y = Pos.Center () + Parent!.Margin.Thickness.Vertical / 2,
                 Visible = false,
+                Data = ViewArrangement.RightResizable
             };
             Add (_rightSizeButton);
         }
@@ -1053,7 +1080,7 @@ public class Border : Adornment
         {
             Debug.Assert (_leftSizeButton is null);
 
-            _leftSizeButton = new Button
+            _leftSizeButton = new ()
             {
                 Id = "leftSizeButton",
                 CanFocus = true,
@@ -1062,10 +1089,11 @@ public class Border : Adornment
                 NoDecorations = true,
                 NoPadding = true,
                 ShadowStyle = ShadowStyle.None,
-                Text = $"{Glyphs.Diamond}",
+                Text = $"{Glyphs.SizeHorizontal}",
                 X = 0,
-                Y = Pos.Center () + Parent!.Margin.Thickness.Vertical,
+                Y = Pos.Center () + Parent!.Margin.Thickness.Vertical / 2,
                 Visible = false,
+                Data = ViewArrangement.LeftResizable
             };
             Add (_leftSizeButton);
         }
@@ -1074,7 +1102,7 @@ public class Border : Adornment
         {
             Debug.Assert (_bottomSizeButton is null);
 
-            _bottomSizeButton = new Button
+            _bottomSizeButton = new ()
             {
                 Id = "bottomSizeButton",
                 CanFocus = true,
@@ -1083,29 +1111,31 @@ public class Border : Adornment
                 NoDecorations = true,
                 NoPadding = true,
                 ShadowStyle = ShadowStyle.None,
-                Text = $"{Glyphs.Diamond}",
-                X = Pos.Center () + Parent!.Margin.Thickness.Horizontal,
+                Text = $"{Glyphs.SizeVertical}",
+                X = Pos.Center () + Parent!.Margin.Thickness.Horizontal / 2,
                 Y = Pos.AnchorEnd (),
                 Visible = false,
+                Data = ViewArrangement.BottomResizable
             };
             Add (_bottomSizeButton);
         }
 
-
         if (arrangement == ViewArrangement.Fixed)
         {
             // Keyboard mode
             if (Parent!.Arrangement.HasFlag (ViewArrangement.Movable))
             {
-                _arranging = ViewArrangement.Movable;
                 _moveButton!.Visible = true;
             }
 
             if (Parent!.Arrangement.HasFlag (ViewArrangement.Resizable))
             {
-                _arranging = ViewArrangement.Resizable;
                 _allSizeButton!.Visible = true;
             }
+
+            _arranging = ViewArrangement.Movable;
+            CanFocus = true;
+            SetFocus ();
         }
         else
         {
@@ -1116,55 +1146,74 @@ public class Border : Adornment
             {
                 case ViewArrangement.Movable:
                     _moveButton!.Visible = true;
+
                     break;
 
                 case ViewArrangement.RightResizable | ViewArrangement.BottomResizable:
                 case ViewArrangement.Resizable:
                     _rightSizeButton!.Visible = true;
                     _bottomSizeButton!.Visible = true;
-                    _allSizeButton!.X = Pos.AnchorEnd ();
-                    _allSizeButton!.Y = Pos.AnchorEnd ();
-                    _allSizeButton!.Visible = true;
+
+                    if (_allSizeButton is { })
+                    {
+                        _allSizeButton!.X = Pos.AnchorEnd ();
+                        _allSizeButton!.Y = Pos.AnchorEnd ();
+                        _allSizeButton!.Visible = true;
+                    }
+
                     break;
 
                 case ViewArrangement.LeftResizable:
                     _leftSizeButton!.Visible = true;
+
                     break;
 
                 case ViewArrangement.RightResizable:
                     _rightSizeButton!.Visible = true;
+
                     break;
 
                 case ViewArrangement.TopResizable:
                     _topSizeButton!.Visible = true;
+
                     break;
 
                 case ViewArrangement.BottomResizable:
                     _bottomSizeButton!.Visible = true;
+
                     break;
 
                 case ViewArrangement.LeftResizable | ViewArrangement.BottomResizable:
                     _rightSizeButton!.Visible = true;
                     _bottomSizeButton!.Visible = true;
-                    _allSizeButton!.X = 0;
-                    _allSizeButton!.Y = Pos.AnchorEnd ();
-                    _allSizeButton!.Visible = true;
+
+                    if (_allSizeButton is { })
+                    {
+                        _allSizeButton.X = 0;
+                        _allSizeButton.Y = Pos.AnchorEnd ();
+                        _allSizeButton.Visible = true;
+                    }
+
                     break;
 
                 case ViewArrangement.LeftResizable | ViewArrangement.TopResizable:
                     _leftSizeButton!.Visible = true;
                     _topSizeButton!.Visible = true;
+
                     break;
 
                 case ViewArrangement.RightResizable | ViewArrangement.TopResizable:
                     _rightSizeButton!.Visible = true;
                     _topSizeButton!.Visible = true;
-                    _allSizeButton!.X = Pos.AnchorEnd ();
-                    _allSizeButton!.Y = 0;
-                    _allSizeButton!.Visible = true;
 
-                    break;
+                    if (_allSizeButton is { })
+                    {
+                        _allSizeButton.X = Pos.AnchorEnd ();
+                        _allSizeButton.Y = 0;
+                        _allSizeButton.Visible = true;
+                    }
 
+                    break;
             }
         }
 
@@ -1173,22 +1222,24 @@ public class Border : Adornment
             if (arrangement == ViewArrangement.Fixed)
             {
                 // Keyboard mode - enable nav
-                CanFocus = true;
-                SetFocus ();
+
             }
+
             return true;
         }
 
         // Hack for now
-        EndArrange ();
+        EndArrangeMode ();
+
         return false;
     }
 
     private void AddArrangeModeKeyBindings ()
     {
-        AddCommand (Command.Quit, EndArrange);
+        AddCommand (Command.Quit, EndArrangeMode);
 
-        AddCommand (Command.Up,
+        AddCommand (
+                    Command.Up,
                     () =>
                     {
                         if (Parent is null)
@@ -1212,7 +1263,8 @@ public class Border : Adornment
                         return true;
                     });
 
-        AddCommand (Command.Down,
+        AddCommand (
+                    Command.Down,
                     () =>
                     {
                         if (Parent is null)
@@ -1232,7 +1284,9 @@ public class Border : Adornment
 
                         return true;
                     });
-        AddCommand (Command.Left,
+
+        AddCommand (
+                    Command.Left,
                     () =>
                     {
                         if (Parent is null)
@@ -1252,10 +1306,12 @@ public class Border : Adornment
                                 Parent!.Width = Parent.Width! - 1;
                             }
                         }
+
                         return true;
                     });
 
-        AddCommand (Command.Right,
+        AddCommand (
+                    Command.Right,
                     () =>
                     {
                         if (Parent is null)
@@ -1276,18 +1332,25 @@ public class Border : Adornment
                         return true;
                     });
 
-        AddCommand (Command.Tab, () =>
-                                 {
-                                     AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        AddCommand (
+                    Command.Tab,
+                    () =>
+                    {
+                        AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+                        _arranging = (ViewArrangement)(Focused?.Data ?? ViewArrangement.Fixed);
+
+                        return true; // Always eat
+                    });
 
-                                     return true; // Always eat
-                                 });
-        AddCommand (Command.BackTab, () =>
-                                     {
-                                         AdvanceFocus (NavigationDirection.Backward, TabBehavior.TabStop);
+        AddCommand (
+                    Command.BackTab,
+                    () =>
+                    {
+                        AdvanceFocus (NavigationDirection.Backward, TabBehavior.TabStop);
+                        _arranging = (ViewArrangement)(Focused?.Data ?? ViewArrangement.Fixed);
 
-                                         return true;  // Always eat
-                                     });
+                        return true; // Always eat
+                    });
 
         KeyBindings.Add (Key.Esc, KeyBindingScope.HotKey, Command.Quit);
         KeyBindings.Add (Application.ArrangeKey, KeyBindingScope.HotKey, Command.Quit);
@@ -1313,11 +1376,11 @@ public class Border : Adornment
 
         if (!Thickness.Contains (Frame, framePos))
         {
-            EndArrange ();
+            EndArrangeMode ();
         }
     }
 
-    private bool? EndArrange ()
+    private bool? EndArrangeMode ()
     {
         // Debug.Assert (_arranging != ViewArrangement.Fixed);
         _arranging = ViewArrangement.Fixed;
@@ -1390,5 +1453,4 @@ public class Border : Adornment
         _dragPosition = null;
         base.Dispose (disposing);
     }
-
 }

+ 13 - 8
Terminal.Gui/View/View.Hierarchy.cs

@@ -159,14 +159,10 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
 
         Rectangle touched = view.Frame;
 
-        // If a view being removed is focused, it should lose focus.
-        if (view.HasFocus)
-        {
-            view.HasFocus = false;
-        }
+        bool hadFocus = view.HasFocus;
 
         _subviews.Remove (view);
-        view._superView = null; // Null this AFTER removing focus
+        view._superView = null;
 
         SetNeedsLayout ();
         SetNeedsDisplay ();
@@ -179,11 +175,20 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
             }
         }
 
-        if (HasFocus)
+        if (_previouslyFocused == view)
+        {
+            _previouslyFocused = null;
+        }
+
+        if (hadFocus)
         {
-            FocusDeepest (NavigationDirection.Forward, TabStop);
+            // Access _hasFocus directly; don't use HasFocus because it will try to find the focused view
+            view._hasFocus = false;
+            AdvanceFocus (NavigationDirection.Forward, null);
         }
 
+        Debug.Assert (!view.HasFocus);
+
         OnRemoved (new (this, view));
 
         return view;

+ 55 - 40
Terminal.Gui/View/View.Navigation.cs

@@ -1,5 +1,6 @@
 #nullable enable
 using System.Diagnostics;
+using System.Reflection.PortableExecutable;
 
 namespace Terminal.Gui;
 
@@ -39,7 +40,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
 
         // AdvanceFocus did not advance - do we wrap, or move up to the superview?
 
-        View [] focusChain = GetSubviewFocusChain (direction, behavior);
+        View [] focusChain = GetFocusChain (direction, behavior);
 
         if (focusChain.Length == 0)
         {
@@ -52,11 +53,11 @@ public partial class View // Focus and cross-view navigation management (TabStop
             if (direction == NavigationDirection.Forward && focused == focusChain [^1] && SuperView is null)
             {
                 // We're at the top of the focus chain. Go back down the focus chain and focus the first TabGroup
-                View [] views = GetSubviewFocusChain (NavigationDirection.Forward, TabBehavior.TabGroup);
+                View [] views = GetFocusChain (NavigationDirection.Forward, TabBehavior.TabGroup);
 
                 if (views.Length > 0)
                 {
-                    View [] subViews = views [0].GetSubviewFocusChain (NavigationDirection.Forward, TabBehavior.TabStop);
+                    View [] subViews = views [0].GetFocusChain (NavigationDirection.Forward, TabBehavior.TabStop);
 
                     if (subViews.Length > 0)
                     {
@@ -71,11 +72,11 @@ public partial class View // Focus and cross-view navigation management (TabStop
             if (direction == NavigationDirection.Backward && focused == focusChain [0])
             {
                 // We're at the bottom of the focus chain
-                View [] views = GetSubviewFocusChain (NavigationDirection.Forward, TabBehavior.TabGroup);
+                View [] views = GetFocusChain (NavigationDirection.Forward, TabBehavior.TabGroup);
 
                 if (views.Length > 0)
                 {
-                    View [] subViews = views [^1].GetSubviewFocusChain (NavigationDirection.Forward, TabBehavior.TabStop);
+                    View [] subViews = views [^1].GetFocusChain (NavigationDirection.Forward, TabBehavior.TabStop);
 
                     if (subViews.Length > 0)
                     {
@@ -102,7 +103,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
             if (SuperView is { })
             {
                 // If we are TabStop, and we have at least one other focusable peer, move to the SuperView's chain
-                if (TabStop == TabBehavior.TabStop && SuperView is { } && SuperView.GetSubviewFocusChain (direction, behavior).Length > 1)
+                if (TabStop == TabBehavior.TabStop && SuperView is { } && SuperView.GetFocusChain (direction, behavior).Length > 1)
                 {
                     return false;
                 }
@@ -110,7 +111,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
                 // TabGroup is special-cased. 
                 if (focused?.TabStop == TabBehavior.TabGroup)
                 {
-                    if (SuperView?.GetSubviewFocusChain (direction, TabBehavior.TabGroup)?.Length > 0)
+                    if (SuperView?.GetFocusChain (direction, TabBehavior.TabGroup)?.Length > 0)
                     {
                         // Our superview has a TabGroup subview; signal we couldn't move so we nav out to it
                         return false;
@@ -176,7 +177,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
                 HasFocus = false;
             }
 
-            if (_canFocus && !HasFocus && Visible && SuperView is { } && SuperView.Focused is null)
+            if (_canFocus && !HasFocus && Visible && SuperView is { Focused: null })
             {
                 // If CanFocus is set to true and this view does not have focus, make it enter focus
                 SetFocus ();
@@ -211,7 +212,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
         return SetFocus ();
     }
 
-    /// <summary>Gets the currently focused Subview of this view, or <see langword="null"/> if nothing is focused.</summary>
+    /// <summary>Gets the currently focused Subview or Adornment of this view, or <see langword="null"/> if nothing is focused.</summary>
     public View? Focused
     {
         get
@@ -224,7 +225,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
             }
 
             // How about in Adornments?
-            if (Margin is { HasFocus:true })
+            if (Margin is { HasFocus: true })
             {
                 return Margin;
             }
@@ -287,9 +288,9 @@ public partial class View // Focus and cross-view navigation management (TabStop
     {
         if (Focused is null && _subviews?.Count > 0)
         {
-            if (_previouslyMostFocused is { })
+            if (_previouslyFocused is { })
             {
-                return _previouslyMostFocused.SetFocus ();
+                return _previouslyFocused.SetFocus ();
             }
 
             return false;
@@ -300,7 +301,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
 
     private View? FindDeepestFocusableView (NavigationDirection direction, TabBehavior? behavior)
     {
-        View [] indicies = GetSubviewFocusChain (direction, behavior);
+        View [] indicies = GetFocusChain (direction, behavior);
 
         foreach (View v in indicies)
         {
@@ -384,9 +385,9 @@ public partial class View // Focus and cross-view navigation management (TabStop
     }
 
     /// <summary>
-    ///     Caches the most focused subview when this view is losing focus. This is used by <see cref="RestoreFocus"/>.
+    ///     A cache of the subview that was focused when this view last lost focus. This is used by <see cref="RestoreFocus"/>.
     /// </summary>
-    private View? _previouslyMostFocused;
+    private View? _previouslyFocused;
 
     /// <summary>
     ///     INTERNAL: Called when focus is going to change to this view. This method is called by <see cref="SetFocus"/> and
@@ -469,14 +470,15 @@ public partial class View // Focus and cross-view navigation management (TabStop
 
         if (!traversingUp)
         {
-            // Restore focus to the previously most focused subview in the subview-hierarchy
+            // Restore focus to the previously focused subview 
             if (!RestoreFocus ())
             {
                 // Couldn't restore focus, so use Advance to navigate to the next focusable subview
                 if (!AdvanceFocus (NavigationDirection.Forward, null))
                 {
                     // Couldn't advance, so we're the most focused view in the application
-                    _previouslyMostFocused = null;
+                    _previouslyFocused = null;
+
                     Application.Navigation?.SetFocused (this);
                 }
             }
@@ -590,17 +592,16 @@ public partial class View // Focus and cross-view navigation management (TabStop
         // If newFocusedVew is null, we need to find the view that should get focus, and SetFocus on it.
         if (!traversingDown && newFocusedView is null)
         {
-            if (superViewOrParent?._previouslyMostFocused is { })
+            if (superViewOrParent?._previouslyFocused is { })
             {
-                if (superViewOrParent?._previouslyMostFocused != this)
+                Debug.Assert (!superViewOrParent._previouslyFocused.WasDisposed);
+                if (superViewOrParent._previouslyFocused != this)
                 {
-                    superViewOrParent?._previouslyMostFocused?.SetFocus ();
+                    superViewOrParent?._previouslyFocused?.SetFocus ();
 
                     // The above will cause SetHasFocusFalse, so we can return
                     return;
                 }
-
-                newFocusedView = superViewOrParent?._previouslyMostFocused;
             }
 
             if (superViewOrParent is { })
@@ -655,9 +656,11 @@ public partial class View // Focus and cross-view navigation management (TabStop
                 a.SetHasFocusFalse (newFocusedView, true);
             }
 
-            Debug.Assert (!mostFocused.WasDisposed);
+        }
 
-            _previouslyMostFocused = mostFocused;
+        if (superViewOrParent is { })
+        {
+            superViewOrParent._previouslyFocused = this;
         }
 
         bool previousValue = HasFocus;
@@ -665,8 +668,10 @@ public partial class View // Focus and cross-view navigation management (TabStop
         // Note, can't be cancelled.
         NotifyFocusChanging (HasFocus, !HasFocus, newFocusedView, this);
 
-        // Get whatever peer has focus, if any
+        // Get whatever peer has focus, if any so we can update our superview's _previouslyMostFocused
         View? focusedPeer = superViewOrParent?.Focused;
+
+        // Set HasFocus false
         _hasFocus = false;
 
         if (Application.Navigation is { })
@@ -687,12 +692,6 @@ public partial class View // Focus and cross-view navigation management (TabStop
             return;
         }
 
-        if (superViewOrParent is { })
-        {
-            Debug.Assert(!focusedPeer.WasDisposed);
-            superViewOrParent._previouslyMostFocused = focusedPeer;
-        }
-
         // Post-conditions - prove correctness
         if (HasFocus == previousValue)
         {
@@ -739,32 +738,48 @@ public partial class View // Focus and cross-view navigation management (TabStop
     #region Tab/Focus Handling
 
     /// <summary>
-    ///     Gets TabIndexes that are scoped to the specified behavior and direction. If behavior is null, all TabIndexes are
-    ///     returned.
+    ///     Gets the subviews and Adornments of this view that are scoped to the specified behavior and direction. If behavior is null, all focusable subviews and
+    ///     Adornments are returned.
     /// </summary>
     /// <param name="direction"></param>
     /// <param name="behavior"></param>
     /// <returns></returns>
-    /// GetScopedTabIndexes
-    internal View [] GetSubviewFocusChain (NavigationDirection direction, TabBehavior? behavior)
+    internal View [] GetFocusChain (NavigationDirection direction, TabBehavior? behavior)
     {
-        IEnumerable<View>? fitleredSubviews;
+        IEnumerable<View>? filteredSubviews;
 
         if (behavior.HasValue)
         {
-            fitleredSubviews = _subviews?.Where (v => v.TabStop == behavior && v is { CanFocus: true, Visible: true, Enabled: true });
+            filteredSubviews = _subviews?.Where (v => v.TabStop == behavior && v is { CanFocus: true, Visible: true, Enabled: true });
         }
         else
         {
-            fitleredSubviews = _subviews?.Where (v => v is { CanFocus: true, Visible: true, Enabled: true });
+            filteredSubviews = _subviews?.Where (v => v is { CanFocus: true, Visible: true, Enabled: true });
+        }
+
+
+        // How about in Adornments? 
+        if (Padding is { CanFocus: true, Visible: true, Enabled: true } && Padding.TabStop == behavior)
+        {
+            filteredSubviews = filteredSubviews?.Append (Padding);
+        }
+
+        if (Border is { CanFocus: true, Visible: true, Enabled: true } && Border.TabStop == behavior)
+        {
+            filteredSubviews = filteredSubviews?.Append (Border);
+        }
+
+        if (Margin is { CanFocus: true, Visible: true, Enabled: true } && Margin.TabStop == behavior)
+        {
+            filteredSubviews = filteredSubviews?.Append (Margin);
         }
 
         if (direction == NavigationDirection.Backward)
         {
-            fitleredSubviews = fitleredSubviews?.Reverse ();
+            filteredSubviews = filteredSubviews?.Reverse ();
         }
 
-        return fitleredSubviews?.ToArray () ?? Array.Empty<View> ();
+        return filteredSubviews?.ToArray () ?? Array.Empty<View> ();
     }
 
     private TabBehavior? _tabStop;

+ 8 - 0
UnitTests/View/Navigation/SetFocusTests.cs

@@ -260,6 +260,14 @@ public class SetFocusTests () : TestsAllViews
         Assert.False (subViewSubView3.HasFocus);
 
         view.Border.CanFocus = true;
+        Assert.True (view.HasFocus);
+        Assert.True (subView.HasFocus);
+        Assert.False (view.Border.HasFocus);
+        Assert.False (borderSubView.HasFocus);
+        Assert.False (subViewSubView1.HasFocus);
+        Assert.False (subViewSubView2.HasFocus);
+        Assert.False (subViewSubView3.HasFocus);
+
         view.Border.SetFocus ();
         Assert.True (view.HasFocus);
         Assert.True (view.Border.HasFocus);