Browse Source

WIP: Working through adornment focus stuff.

Tig 10 months ago
parent
commit
0a6a41d570

+ 5 - 0
Terminal.Gui/Application/ApplicationNavigation.cs

@@ -62,6 +62,11 @@ public class ApplicationNavigation
             }
         }
 
+        //if (start.Border is { })
+        //{
+        //    return IsInHierarchy (start.Border, view);
+        //}
+
         return false;
     }
 

+ 296 - 139
Terminal.Gui/View/Adornment/Border.cs

@@ -59,6 +59,7 @@ public class Border : Adornment
     {
         Parent = parent;
         CanFocus = false;
+        TabStop = TabBehavior.TabGroup;
 
         Application.GrabbingMouse += Application_GrabbingMouse;
         Application.UnGrabbingMouse += Application_UnGrabbingMouse;
@@ -291,22 +292,22 @@ public class Border : Adornment
             return true;
         }
 
-        if (!Parent!.Arrangement.HasFlag (ViewArrangement.Movable)
-            && !Parent!.Arrangement.HasFlag (ViewArrangement.BottomResizable)
-            && !Parent!.Arrangement.HasFlag (ViewArrangement.TopResizable)
-            && !Parent!.Arrangement.HasFlag (ViewArrangement.LeftResizable)
-            && !Parent!.Arrangement.HasFlag (ViewArrangement.RightResizable)
-           )
-        {
-            return false;
-        }
-
         // BUGBUG: See https://github.com/gui-cs/Terminal.Gui/issues/3312
         if (!_dragPosition.HasValue && mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed))
         {
             Parent.SetFocus ();
             ApplicationOverlapped.BringOverlappedTopToFront ();
 
+            if (!Parent!.Arrangement.HasFlag (ViewArrangement.Movable)
+                && !Parent!.Arrangement.HasFlag (ViewArrangement.BottomResizable)
+                && !Parent!.Arrangement.HasFlag (ViewArrangement.TopResizable)
+                && !Parent!.Arrangement.HasFlag (ViewArrangement.LeftResizable)
+                && !Parent!.Arrangement.HasFlag (ViewArrangement.RightResizable)
+               )
+            {
+                return false;
+            }
+
             // Only start grabbing if the user clicks in the Thickness area
             // 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)))
@@ -930,11 +931,16 @@ public class Border : Adornment
 
     private ViewArrangement _arranging;
 
-    private Button? _arrangeButton;
+    private Button? _moveButton; // always top-left
+    private Button? _allSizeButton;
+    private Button? _leftSizeButton;
+    private Button? _rightSizeButton;
+    private Button? _topSizeButton;
+    private Button? _bottomSizeButton;
 
     /// <summary>
     ///     Starts "Arrange Mode" where <see cref="Adornment.Parent"/> can be moved and/or resized using the mouse
-    ///     or keyboard.
+    ///     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
@@ -955,21 +961,231 @@ public class Border : Adornment
             return false;
         }
 
-        Debug.Assert (_arrangeButton is null);
-        _arrangeButton = new Button
+        // Add Commands and Keybindigs - Note it's ok these get added each time. KeyBindings are cleared in EndArrange()
+        AddArrangeModeKeyBindings ();
+
+        Application.MouseEvent += ApplicationOnMouseEvent;
+
+        // Create buttons for resizing and moving
+        if (Parent!.Arrangement.HasFlag (ViewArrangement.Movable))
         {
-            CanFocus = true,
-            Width = 1,
-            Height = 1,
-            NoDecorations = true,
-            NoPadding = true,
-            ShadowStyle = ShadowStyle.None,
-            Text = $"{Glyphs.Diamond}",
-        };
-        Add (_arrangeButton);
-
-        CanFocus = true;
+            Debug.Assert (_moveButton is null);
+
+            _moveButton = new Button
+            {
+                Id = "moveButton",
+                CanFocus = true,
+                Width = 1,
+                Height = 1,
+                NoDecorations = true,
+                NoPadding = true,
+                ShadowStyle = ShadowStyle.None,
+                Text = $"{Glyphs.Diamond}",
+                Visible = false,
+            };
+            Add (_moveButton);
+        }
+
+        if (Parent!.Arrangement.HasFlag (ViewArrangement.Resizable))
+        {
+            Debug.Assert (_allSizeButton is null);
+
+            _allSizeButton = new Button
+            {
+                Id = "allSizeButton",
+                CanFocus = true,
+                Width = 1,
+                Height = 1,
+                NoDecorations = true,
+                NoPadding = true,
+                ShadowStyle = ShadowStyle.None,
+                Text = $"{Glyphs.Diamond}",
+                X = Pos.AnchorEnd (),
+                Y = Pos.AnchorEnd (),
+                Visible = false,
+            };
+            Add (_allSizeButton);
+        }
+
+        if (Parent!.Arrangement.HasFlag (ViewArrangement.TopResizable))
+        {
+            Debug.Assert (_topSizeButton is null);
+
+            _topSizeButton = new Button
+            {
+                Id = "topSizeButton",
+                CanFocus = true,
+                Width = 1,
+                Height = 1,
+                NoDecorations = true,
+                NoPadding = true,
+                ShadowStyle = ShadowStyle.None,
+                Text = $"{Glyphs.Diamond}",
+                X = Pos.Center () + Parent!.Margin.Thickness.Horizontal,
+                Y = 0,
+                Visible = false,
+            };
+            Add (_topSizeButton);
+        }
+
+        if (Parent!.Arrangement.HasFlag (ViewArrangement.RightResizable))
+        {
+            Debug.Assert (_rightSizeButton is null);
+
+            _rightSizeButton = new Button
+            {
+                Id = "rightSizeButton",
+                CanFocus = true,
+                Width = 1,
+                Height = 1,
+                NoDecorations = true,
+                NoPadding = true,
+                ShadowStyle = ShadowStyle.None,
+                Text = $"{Glyphs.Diamond}",
+                X = Pos.AnchorEnd (),
+                Y = Pos.Center () + Parent!.Margin.Thickness.Vertical,
+                Visible = false,
+            };
+            Add (_rightSizeButton);
+        }
+
+        if (Parent!.Arrangement.HasFlag (ViewArrangement.LeftResizable))
+        {
+            Debug.Assert (_leftSizeButton is null);
+
+            _leftSizeButton = new Button
+            {
+                Id = "leftSizeButton",
+                CanFocus = true,
+                Width = 1,
+                Height = 1,
+                NoDecorations = true,
+                NoPadding = true,
+                ShadowStyle = ShadowStyle.None,
+                Text = $"{Glyphs.Diamond}",
+                X = 0,
+                Y = Pos.Center () + Parent!.Margin.Thickness.Vertical,
+                Visible = false,
+            };
+            Add (_leftSizeButton);
+        }
 
+        if (Parent!.Arrangement.HasFlag (ViewArrangement.BottomResizable))
+        {
+            Debug.Assert (_bottomSizeButton is null);
+
+            _bottomSizeButton = new Button
+            {
+                Id = "bottomSizeButton",
+                CanFocus = true,
+                Width = 1,
+                Height = 1,
+                NoDecorations = true,
+                NoPadding = true,
+                ShadowStyle = ShadowStyle.None,
+                Text = $"{Glyphs.Diamond}",
+                X = Pos.Center () + Parent!.Margin.Thickness.Horizontal,
+                Y = Pos.AnchorEnd (),
+                Visible = false,
+            };
+            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;
+            }
+        }
+        else
+        {
+            // Mouse mode
+            _arranging = arrangement;
+
+            switch (_arranging)
+            {
+                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;
+                    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;
+                    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 (_arranging != ViewArrangement.Fixed)
+        {
+            if (arrangement == ViewArrangement.Fixed)
+            {
+                // Keyboard mode - enable nav
+                CanFocus = true;
+                SetFocus ();
+            }
+            return true;
+        }
+
+        // Hack for now
+        EndArrange ();
+        return false;
+    }
+
+    private void AddArrangeModeKeyBindings ()
+    {
         AddCommand (Command.Quit, EndArrange);
 
         AddCommand (Command.Up,
@@ -1060,8 +1276,18 @@ public class Border : Adornment
                         return true;
                     });
 
-        AddCommand (Command.Tab, Navigate);
-        AddCommand (Command.BackTab, Navigate);
+        AddCommand (Command.Tab, () =>
+                                 {
+                                     AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+
+                                     return true; // Always eat
+                                 });
+        AddCommand (Command.BackTab, () =>
+                                     {
+                                         AdvanceFocus (NavigationDirection.Backward, TabBehavior.TabStop);
+
+                                         return true;  // Always eat
+                                     });
 
         KeyBindings.Add (Key.Esc, KeyBindingScope.HotKey, Command.Quit);
         KeyBindings.Add (Application.ArrangeKey, KeyBindingScope.HotKey, Command.Quit);
@@ -1072,113 +1298,6 @@ public class Border : Adornment
 
         KeyBindings.Add (Key.Tab, KeyBindingScope.HotKey, Command.Tab);
         KeyBindings.Add (Key.Tab.WithShift, KeyBindingScope.HotKey, Command.BackTab);
-
-        Application.MouseEvent += ApplicationOnMouseEvent;
-
-        if (arrangement == ViewArrangement.Fixed)
-        {
-            if (Parent!.Arrangement.HasFlag (ViewArrangement.Movable))
-            {
-                _arranging = ViewArrangement.Movable;
-                _arrangeButton.X = 0;
-                _arrangeButton.Y = 0;
-                return true;
-            }
-
-            if (Parent!.Arrangement.HasFlag (ViewArrangement.Resizable))
-            {
-                _arranging = ViewArrangement.Resizable;
-                _arrangeButton.X = Pos.AnchorEnd ();
-                _arrangeButton.Y = Pos.AnchorEnd ();
-
-                return true;
-            }
-        }
-        else
-        {
-            _arranging = arrangement;
-
-            switch (_arranging)
-            {
-                case ViewArrangement.Movable:
-                    _arrangeButton.X = 0;
-                    _arrangeButton.Y = 0;
-                    return true;
-
-                case ViewArrangement.RightResizable | ViewArrangement.BottomResizable:
-                case ViewArrangement.Resizable:
-                    _arrangeButton.X = Pos.AnchorEnd ();
-                    _arrangeButton.Y = Pos.AnchorEnd ();
-                    return true;
-
-                case ViewArrangement.LeftResizable:
-                    _arrangeButton.X = 0;
-                    _arrangeButton.Y = Pos.Center () + Parent!.Margin.Thickness.Vertical;
-                    return true;
-
-                case ViewArrangement.RightResizable:
-                    _arrangeButton.X = Pos.AnchorEnd ();
-                    _arrangeButton.Y = Pos.Center ();
-                    return true;
-
-                case ViewArrangement.TopResizable:
-                    _arrangeButton.X = Pos.Center ();
-                    _arrangeButton.Y = 0;
-                    return true;
-
-                case ViewArrangement.BottomResizable:
-                    _arrangeButton.X = Pos.Center ();
-                    _arrangeButton.Y = Pos.AnchorEnd ();
-                    return true;
-
-                case ViewArrangement.LeftResizable | ViewArrangement.BottomResizable:
-                    _arrangeButton.X = 0;
-                    _arrangeButton.Y = Pos.AnchorEnd ();
-
-                    return true;
-
-                case ViewArrangement.LeftResizable | ViewArrangement.TopResizable:
-                    _arrangeButton.X = 0;
-                    _arrangeButton.Y = 0;
-
-                    return true;
-
-                case ViewArrangement.RightResizable | ViewArrangement.TopResizable:
-                    _arrangeButton.X = Pos.AnchorEnd (); ;
-                    _arrangeButton.Y = 0;
-
-                    return true;
-
-            }
-        }
-
-        // Hack for now
-        EndArrange ();
-        return false;
-
-        bool? Navigate ()
-        {
-            if (_arranging == ViewArrangement.Movable)
-            {
-                if (Parent!.Arrangement.HasFlag (ViewArrangement.Resizable))
-                {
-                    _arranging = ViewArrangement.Resizable;
-                    _arrangeButton.X = Pos.AnchorEnd ();
-                    _arrangeButton.Y = Pos.AnchorEnd ();
-                }
-            }
-            else if (_arranging == ViewArrangement.Resizable)
-            {
-                if (Parent!.Arrangement.HasFlag (ViewArrangement.Movable))
-                {
-                    _arranging = ViewArrangement.Movable;
-                    _arrangeButton.X = 0;
-                    _arrangeButton.Y = 0;
-                }
-            }
-
-            return true;
-        }
     }
 
     private void ApplicationOnMouseEvent (object? sender, MouseEvent e)
@@ -1210,17 +1329,55 @@ public class Border : Adornment
             Application.UngrabMouse ();
         }
 
-        CanFocus = false;
+        if (_moveButton is { })
+        {
+            Remove (_moveButton);
+            _moveButton.Dispose ();
+            _moveButton = null;
+        }
+
+        if (_allSizeButton is { })
+        {
+            Remove (_allSizeButton);
+            _allSizeButton.Dispose ();
+            _allSizeButton = null;
+        }
+
+        if (_leftSizeButton is { })
+        {
+            Remove (_leftSizeButton);
+            _leftSizeButton.Dispose ();
+            _leftSizeButton = null;
+        }
+
+        if (_rightSizeButton is { })
+        {
+            Remove (_rightSizeButton);
+            _rightSizeButton.Dispose ();
+            _rightSizeButton = null;
+        }
 
-        if (_arrangeButton is { })
+        if (_topSizeButton is { })
         {
-            Remove (_arrangeButton);
-            _arrangeButton.Dispose ();
-            _arrangeButton = null;
+            Remove (_topSizeButton);
+            _topSizeButton.Dispose ();
+            _topSizeButton = null;
+        }
+
+        if (_bottomSizeButton is { })
+        {
+            Remove (_bottomSizeButton);
+            _bottomSizeButton.Dispose ();
+            _bottomSizeButton = null;
         }
 
         KeyBindings.Clear ();
 
+        if (CanFocus)
+        {
+            CanFocus = false;
+        }
+
         return true;
     }
 

+ 5 - 4
Terminal.Gui/View/View.Drawing.cs

@@ -473,16 +473,17 @@ public partial class View // Drawing APIs
     {
         if (NeedsDisplay)
         {
-            if (SuperView is { })
+            if (!CanBeVisible (this))
             {
-                Clear ();
+                return;
             }
 
-            if (!CanBeVisible (this))
+            if (SuperView is { })
             {
-                return;
+                Clear ();
             }
 
+
             if (!string.IsNullOrEmpty (TextFormatter.Text))
             {
                 if (TextFormatter is { })

+ 64 - 51
Terminal.Gui/View/View.Navigation.cs

@@ -214,7 +214,33 @@ public partial class View // Focus and cross-view navigation management (TabStop
     /// <summary>Gets the currently focused Subview of this view, or <see langword="null"/> if nothing is focused.</summary>
     public View? Focused
     {
-        get { return Subviews.FirstOrDefault (v => v.HasFocus); }
+        get
+        {
+            View? focused = Subviews.FirstOrDefault (v => v.HasFocus);
+
+            if (focused is { })
+            {
+                return focused;
+            }
+
+            // How about in Adornments?
+            if (Margin is { HasFocus:true })
+            {
+                return Margin;
+            }
+
+            if (Border is { HasFocus: true })
+            {
+                return Border;
+            }
+
+            if (Padding is { HasFocus: true })
+            {
+                return Padding;
+            }
+
+            return null;
+        }
     }
 
     /// <summary>Returns a value indicating if this View is currently on Top (Active)</summary>
@@ -384,7 +410,10 @@ public partial class View // Focus and cross-view navigation management (TabStop
             return (false, false);
         }
 
-        if (CanFocus && SuperView is { CanFocus: false })
+        var thisAsAdornment = this as Adornment;
+        View? superViewOrParent = thisAsAdornment?.Parent ?? SuperView;
+
+        if (CanFocus && superViewOrParent is { CanFocus: false })
         {
             Debug.WriteLine ($@"WARNING: Attempt to FocusChanging where SuperView.CanFocus == false. {this}");
 
@@ -412,7 +441,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
 
         // Make sure superviews up the superview hierarchy have focus.
         // Any of them may cancel gaining focus. In which case we need to back out.
-        if (SuperView is { HasFocus: false } sv)
+        if (superViewOrParent is { HasFocus: false } sv)
         {
             (bool focusSet, bool svCancelled) = sv.SetHasFocusTrue (previousFocusedView, true);
 
@@ -422,20 +451,6 @@ public partial class View // Focus and cross-view navigation management (TabStop
             }
         }
 
-        // Are we an Adornment? 
-        if (this is Adornment adornment)
-        {
-            if (adornment.Parent is { HasFocus: false } parent)
-            {
-                (bool focusSet, bool parentCancelled) = parent.SetHasFocusTrue (previousFocusedView, true);
-
-                if (!focusSet)
-                {
-                    return (false, parentCancelled);
-                }
-            }
-        }
-
         if (_hasFocus)
         {
             // Something else beat us to the change (likely a FocusChanged handler).
@@ -445,16 +460,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
         // By setting _hasFocus to true we definitively change HasFocus for this view.
 
         // Get whatever peer has focus, if any
-        View? focusedPeer = SuperView?.Focused;
-
-        if (focusedPeer is null)
-        {
-            // Are we an Adornment? 
-            if (this is Adornment ad)
-            {
-                focusedPeer = ad.Parent?.Focused;
-            }
-        }
+        View? focusedPeer = superViewOrParent?.Focused;
 
         _hasFocus = true;
 
@@ -481,6 +487,14 @@ public partial class View // Focus and cross-view navigation management (TabStop
             previousFocusedView.SetHasFocusFalse (this);
         }
 
+        if (previousFocusedView is { HasFocus: true })
+        {
+            if (previousFocusedView.SuperView is Adornment a)
+            {
+                previousFocusedView.SetHasFocusFalse (this);
+            }
+        }
+
         if (Arrangement.HasFlag (ViewArrangement.Overlapped))
         {
             SuperView?.MoveSubviewToEnd (this);
@@ -570,43 +584,34 @@ public partial class View // Focus and cross-view navigation management (TabStop
             throw new InvalidOperationException ("SetHasFocusFalse should not be called if the view does not have focus.");
         }
 
+        var thisAsAdornment = this as Adornment;
+        View? superViewOrParent = thisAsAdornment?.Parent ?? SuperView;
+
         // If newFocusedVew is null, we need to find the view that should get focus, and SetFocus on it.
         if (!traversingDown && newFocusedView is null)
         {
-            if (SuperView?._previouslyMostFocused is { })
+            if (superViewOrParent?._previouslyMostFocused is { })
             {
-                if (SuperView?._previouslyMostFocused != this)
+                if (superViewOrParent?._previouslyMostFocused != this)
                 {
-                    SuperView?._previouslyMostFocused?.SetFocus ();
+                    superViewOrParent?._previouslyMostFocused?.SetFocus ();
 
                     // The above will cause SetHasFocusFalse, so we can return
                     return;
                 }
-                newFocusedView = SuperView?._previouslyMostFocused;
+
+                newFocusedView = superViewOrParent?._previouslyMostFocused;
             }
 
-            if (SuperView is { })
+            if (superViewOrParent is { })
             {
-                if (SuperView.AdvanceFocus (NavigationDirection.Forward, TabStop))
+                if (superViewOrParent.AdvanceFocus (NavigationDirection.Forward, TabStop))
                 {
                     // The above will cause SetHasFocusFalse, so we can return
                     return;
                 }
-                newFocusedView = SuperView;
-            }
 
-            // Are we an Adornment? 
-            if (this is Adornment ad)
-            {
-                if (ad.Parent is {})
-                {
-                    if (ad.Parent.RestoreFocus ())
-                    {
-                        // The above will cause SetHasFocusFalse, so we can return
-                        return;
-                    }
-                    newFocusedView = ad.Parent;
-                }
+                newFocusedView = superViewOrParent;
             }
 
             if (Application.Navigation is { } && Application.Current is { })
@@ -645,6 +650,13 @@ public partial class View // Focus and cross-view navigation management (TabStop
                 bottom = bottom.SuperView;
             }
 
+            if (bottom == this && bottom.SuperView is Adornment a)
+            {
+                a.SetHasFocusFalse (newFocusedView, true);
+            }
+
+            Debug.Assert (!mostFocused.WasDisposed);
+
             _previouslyMostFocused = mostFocused;
         }
 
@@ -654,7 +666,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
         NotifyFocusChanging (HasFocus, !HasFocus, newFocusedView, this);
 
         // Get whatever peer has focus, if any
-        View? focusedPeer = SuperView?.Focused;
+        View? focusedPeer = superViewOrParent?.Focused;
         _hasFocus = false;
 
         if (Application.Navigation is { })
@@ -663,7 +675,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
 
             if (appFocused is { } || appFocused == this)
             {
-                Application.Navigation.SetFocused (newFocusedView ?? SuperView);
+                Application.Navigation.SetFocused (newFocusedView ?? superViewOrParent);
             }
         }
 
@@ -675,9 +687,10 @@ public partial class View // Focus and cross-view navigation management (TabStop
             return;
         }
 
-        if (SuperView is { })
+        if (superViewOrParent is { })
         {
-            SuperView._previouslyMostFocused = focusedPeer;
+            Debug.Assert(!focusedPeer.WasDisposed);
+            superViewOrParent._previouslyMostFocused = focusedPeer;
         }
 
         // Post-conditions - prove correctness

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

@@ -190,6 +190,115 @@ public class SetFocusTests () : TestsAllViews
         Assert.False (subViewSubView3.HasFocus);
     }
 
+
+    [Fact]
+    public void SetFocus_AdornmentSubView_SetFocus_Sets ()
+    {
+        var view = new View
+        {
+            Id = "view",
+            CanFocus = true
+        };
+
+        var subView = new View
+        {
+            Id = "subView",
+            CanFocus = true
+        };
+
+        view.Add (subView);
+
+        var borderSubView = new View
+        {
+            Id = "borderSubView",
+            CanFocus = true
+        };
+
+
+        var subViewSubView1 = new View
+        {
+            Id = "subViewSubView1",
+            CanFocus = true
+        };
+
+        var subViewSubView2 = new View
+        {
+            Id = "subViewSubView2",
+            CanFocus = true
+        };
+
+        var subViewSubView3 = new View
+        {
+            Id = "subViewSubView3",
+            CanFocus = true
+        };
+        borderSubView.Add (subViewSubView1, subViewSubView2, subViewSubView3);
+
+        view.Border.Add (borderSubView);
+
+        view.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.True (subView.HasFocus);
+        Assert.False (borderSubView.HasFocus);
+
+        view.Border.CanFocus = true;
+        subViewSubView1.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.False (subView.HasFocus);
+        Assert.True (borderSubView.HasFocus);
+        Assert.True (subViewSubView1.HasFocus);
+        Assert.False (subViewSubView2.HasFocus);
+        Assert.False (subViewSubView3.HasFocus);
+
+        view.Border.CanFocus = false;
+        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.CanFocus = true;
+        view.Border.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.True (view.Border.HasFocus);
+        Assert.False (subView.HasFocus);
+        Assert.True (borderSubView.HasFocus);
+        Assert.True (subViewSubView1.HasFocus);
+        Assert.False (subViewSubView2.HasFocus);
+        Assert.False (subViewSubView3.HasFocus);
+
+        view.Border.CanFocus = false;
+        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.CanFocus = true;
+        subViewSubView1.SetFocus ();
+        Assert.True (view.HasFocus);
+        Assert.False (subView.HasFocus);
+        Assert.True (view.Border.HasFocus);
+        Assert.True (borderSubView.HasFocus);
+        Assert.True (subViewSubView1.HasFocus);
+        Assert.False (subViewSubView2.HasFocus);
+        Assert.False (subViewSubView3.HasFocus);
+
+        subView.SetFocus ();
+        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);
+    }
+
+
     [Fact]
     public void SetFocus_Peer_LeavesOther ()
     {