Browse Source

Merge branch 'v2_tabview-fix' of github.com:BDisp/Terminal.Gui into BDisp-v2_tabview-fix

Tig 8 months ago
parent
commit
9fcdc0a0a6

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

@@ -22,7 +22,7 @@ public class Tab : View
         set
         set
         {
         {
             _displayText = value;
             _displayText = value;
-            SetNeedsDraw ();
+            SetNeedsLayout ();
         }
         }
     }
     }
 
 

+ 114 - 137
Terminal.Gui/Views/TabView.cs

@@ -11,7 +11,7 @@ public class TabView : View
     ///     This sub view is the main client area of the current tab.  It hosts the <see cref="Tab.View"/> of the tab, the
     ///     This sub view is the main client area of the current tab.  It hosts the <see cref="Tab.View"/> of the tab, the
     ///     <see cref="SelectedTab"/>.
     ///     <see cref="SelectedTab"/>.
     /// </summary>
     /// </summary>
-    private readonly View _contentView;
+    private readonly View _containerView;
 
 
     private readonly List<Tab> _tabs = new ();
     private readonly List<Tab> _tabs = new ();
 
 
@@ -28,14 +28,11 @@ public class TabView : View
         CanFocus = true;
         CanFocus = true;
         TabStop = TabBehavior.TabStop; // Because TabView has focusable subviews, it must be a TabGroup
         TabStop = TabBehavior.TabStop; // Because TabView has focusable subviews, it must be a TabGroup
         _tabsBar = new TabRowView (this);
         _tabsBar = new TabRowView (this);
-        _contentView = new View ()
-        {
-            //Id = "TabView._contentView",
-        };
+        _containerView = new ();
         ApplyStyleChanges ();
         ApplyStyleChanges ();
 
 
         base.Add (_tabsBar);
         base.Add (_tabsBar);
-        base.Add (_contentView);
+        base.Add (_containerView);
 
 
         // Things this view knows how to do
         // Things this view knows how to do
         AddCommand (Command.Left, () => SwitchTabBy (-1));
         AddCommand (Command.Left, () => SwitchTabBy (-1));
@@ -101,6 +98,9 @@ public class TabView : View
     /// </summary>
     /// </summary>
     public uint MaxTabTextWidth { get; set; } = DefaultMaxTabTextWidth;
     public uint MaxTabTextWidth { get; set; } = DefaultMaxTabTextWidth;
 
 
+    // This is needed to hold initial value because it may change during the setter process
+    private bool _selectedTabHasFocus;
+
     /// <summary>The currently selected member of <see cref="Tabs"/> chosen by the user.</summary>
     /// <summary>The currently selected member of <see cref="Tabs"/> chosen by the user.</summary>
     /// <value></value>
     /// <value></value>
     public Tab? SelectedTab
     public Tab? SelectedTab
@@ -108,17 +108,16 @@ public class TabView : View
         get => _selectedTab;
         get => _selectedTab;
         set
         set
         {
         {
-            UnSetCurrentTabs ();
-
             Tab? old = _selectedTab;
             Tab? old = _selectedTab;
+            _selectedTabHasFocus = old is { } && (old.HasFocus || !_containerView.CanFocus);
 
 
             if (_selectedTab is { })
             if (_selectedTab is { })
             {
             {
                 if (_selectedTab.View is { })
                 if (_selectedTab.View is { })
                 {
                 {
-                    _selectedTab.View.CanFocusChanged -= ContentViewCanFocus!;
+                    _selectedTab.View.CanFocusChanged -= ContainerViewCanFocus!;
                     // remove old content
                     // remove old content
-                    _contentView.Remove (_selectedTab.View);
+                    _containerView.Remove (_selectedTab.View);
                 }
                 }
             }
             }
 
 
@@ -127,18 +126,17 @@ public class TabView : View
             // add new content
             // add new content
             if (_selectedTab?.View != null)
             if (_selectedTab?.View != null)
             {
             {
-                _selectedTab.View.CanFocusChanged += ContentViewCanFocus!;
-                _contentView.Add (_selectedTab.View);
-                // _contentView.Id = $"_contentView for {_selectedTab.DisplayText}";
+                _selectedTab.View.CanFocusChanged += ContainerViewCanFocus!;
+                _containerView.Add (_selectedTab.View);
             }
             }
 
 
-            ContentViewCanFocus (null!, null!);
+            ContainerViewCanFocus (null!, null!);
 
 
             EnsureSelectedTabIsVisible ();
             EnsureSelectedTabIsVisible ();
 
 
             if (old != _selectedTab)
             if (old != _selectedTab)
             {
             {
-                if (old?.HasFocus == true)
+                if (_selectedTabHasFocus || !_containerView.CanFocus)
                 {
                 {
                     SelectedTab?.SetFocus ();
                     SelectedTab?.SetFocus ();
                 }
                 }
@@ -149,9 +147,9 @@ public class TabView : View
         }
         }
     }
     }
 
 
-    private void ContentViewCanFocus (object sender, EventArgs eventArgs)
+    private void ContainerViewCanFocus (object sender, EventArgs eventArgs)
     {
     {
-        _contentView.CanFocus = _contentView.Subviews.Count (v => v.CanFocus) > 0;
+        _containerView.CanFocus = _containerView.Subviews.Count (v => v.CanFocus) > 0;
     }
     }
 
 
     private TabStyle _style = new ();
     private TabStyle _style = new ();
@@ -220,34 +218,34 @@ public class TabView : View
     /// </summary>
     /// </summary>
     public void ApplyStyleChanges ()
     public void ApplyStyleChanges ()
     {
     {
-        _contentView.BorderStyle = Style.ShowBorder ? LineStyle.Single : LineStyle.None;
-        _contentView.Width = Dim.Fill ();
+        _containerView.BorderStyle = Style.ShowBorder ? LineStyle.Single : LineStyle.None;
+        _containerView.Width = Dim.Fill ();
 
 
         if (Style.TabsOnBottom)
         if (Style.TabsOnBottom)
         {
         {
             // Tabs are along the bottom so just dodge the border
             // Tabs are along the bottom so just dodge the border
             if (Style.ShowBorder)
             if (Style.ShowBorder)
             {
             {
-                _contentView.Border.Thickness = new Thickness (1, 1, 1, 0);
+                _containerView.Border!.Thickness = new Thickness (1, 1, 1, 0);
             }
             }
 
 
-            _contentView.Y = 0;
+            _containerView.Y = 0;
 
 
             int tabHeight = GetTabHeight (false);
             int tabHeight = GetTabHeight (false);
 
 
             // Fill client area leaving space at bottom for tabs
             // Fill client area leaving space at bottom for tabs
-            _contentView.Height = Dim.Fill (tabHeight);
+            _containerView.Height = Dim.Fill (tabHeight);
 
 
             _tabsBar.Height = tabHeight;
             _tabsBar.Height = tabHeight;
 
 
-            _tabsBar.Y = Pos.Bottom (_contentView);
+            _tabsBar.Y = Pos.Bottom (_containerView);
         }
         }
         else
         else
         {
         {
             // Tabs are along the top
             // Tabs are along the top
             if (Style.ShowBorder)
             if (Style.ShowBorder)
             {
             {
-                _contentView.Border.Thickness = new Thickness (1, 0, 1, 1);
+                _containerView.Border!.Thickness = new Thickness (1, 0, 1, 1);
             }
             }
 
 
             _tabsBar.Y = 0;
             _tabsBar.Y = 0;
@@ -255,10 +253,10 @@ public class TabView : View
             int tabHeight = GetTabHeight (true);
             int tabHeight = GetTabHeight (true);
 
 
             //move content down to make space for tabs
             //move content down to make space for tabs
-            _contentView.Y = Pos.Bottom (_tabsBar);
+            _containerView.Y = Pos.Bottom (_tabsBar);
 
 
             // Fill client area leaving space at bottom for border
             // Fill client area leaving space at bottom for border
-            _contentView.Height = Dim.Fill ();
+            _containerView.Height = Dim.Fill ();
 
 
             // The top tab should be 2 or 3 rows high and on the top
             // The top tab should be 2 or 3 rows high and on the top
 
 
@@ -270,6 +268,14 @@ public class TabView : View
         SetNeedsLayout ();
         SetNeedsLayout ();
     }
     }
 
 
+    /// <inheritdoc />
+    protected override void OnViewportChanged (DrawEventArgs e)
+    {
+        _tabLocations = CalculateViewport (Viewport).ToArray ();
+
+        base.OnViewportChanged (e);
+    }
+
     /// <summary>Updates <see cref="TabScrollOffset"/> to ensure that <see cref="SelectedTab"/> is visible.</summary>
     /// <summary>Updates <see cref="TabScrollOffset"/> to ensure that <see cref="SelectedTab"/> is visible.</summary>
     public void EnsureSelectedTabIsVisible ()
     public void EnsureSelectedTabIsVisible ()
     {
     {
@@ -295,7 +301,7 @@ public class TabView : View
     /// <inheritdoc />
     /// <inheritdoc />
     protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocusedView, View? focusedView)
     protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocusedView, View? focusedView)
     {
     {
-        if (SelectedTab is { } && !_contentView.CanFocus && focusedView == this)
+        if (SelectedTab is { HasFocus: false } && !_containerView.CanFocus && focusedView == this)
         {
         {
             SelectedTab?.SetFocus ();
             SelectedTab?.SetFocus ();
 
 
@@ -305,25 +311,6 @@ public class TabView : View
         base.OnHasFocusChanged (newHasFocus, previousFocusedView, focusedView);
         base.OnHasFocusChanged (newHasFocus, previousFocusedView, focusedView);
     }
     }
 
 
-    /// <inheritdoc/>
-    protected override bool OnDrawingContent ()
-    {
-        if (Tabs.Any ())
-        {
-            // Region savedClip = SetClip ();
-            _tabsBar.Draw ();
-            _contentView.SetNeedsDraw ();
-            _contentView.Draw ();
-
-            //if (Driver is { })
-            //{
-            //    Driver.Clip = savedClip;
-            //}
-        }
-
-        return true;
-    }
-
     /// <summary>
     /// <summary>
     ///     Removes the given <paramref name="tab"/> from <see cref="Tabs"/>. Caller is responsible for disposing the
     ///     Removes the given <paramref name="tab"/> from <see cref="Tabs"/>. Caller is responsible for disposing the
     ///     tab's hosted <see cref="Tab.View"/> if appropriate.
     ///     tab's hosted <see cref="Tab.View"/> if appropriate.
@@ -451,7 +438,7 @@ public class TabView : View
         {
         {
             if (prevTab is { })
             if (prevTab is { })
             {
             {
-                tab.X = Pos.Right (prevTab);
+                tab.X = Pos.Right (prevTab) - 1;
             }
             }
             else
             else
             {
             {
@@ -463,15 +450,11 @@ public class TabView : View
             // while there is space for the tab
             // while there is space for the tab
             int tabTextWidth = tab.DisplayText.EnumerateRunes ().Sum (c => c.GetColumns ());
             int tabTextWidth = tab.DisplayText.EnumerateRunes ().Sum (c => c.GetColumns ());
 
 
-            string text = tab.DisplayText;
-
             // The maximum number of characters to use for the tab name as specified
             // The maximum number of characters to use for the tab name as specified
             // by the user (MaxTabTextWidth).  But not more than the width of the view
             // by the user (MaxTabTextWidth).  But not more than the width of the view
             // or we won't even be able to render a single tab!
             // or we won't even be able to render a single tab!
             long maxWidth = Math.Max (0, Math.Min (bounds.Width - 3, MaxTabTextWidth));
             long maxWidth = Math.Max (0, Math.Min (bounds.Width - 3, MaxTabTextWidth));
 
 
-            prevTab = tab;
-
             tab.Width = 2;
             tab.Width = 2;
             tab.Height = Style.ShowTopLine ? 3 : 2;
             tab.Height = Style.ShowTopLine ? 3 : 2;
 
 
@@ -480,17 +463,22 @@ public class TabView : View
             {
             {
                 tab.Visible = true;
                 tab.Visible = true;
                 tab.MouseClick += Tab_MouseClick!;
                 tab.MouseClick += Tab_MouseClick!;
+                tab.Border!.MouseClick += Tab_MouseClick!;
 
 
-                yield return new TabToRender (tab, string.Empty, Equals (SelectedTab, tab));
+                yield return new (tab, Equals (SelectedTab, tab));
 
 
                 break;
                 break;
             }
             }
 
 
             if (tabTextWidth > maxWidth)
             if (tabTextWidth > maxWidth)
             {
             {
-                text = tab.DisplayText.Substring (0, (int)maxWidth);
+                tab.Text = tab.DisplayText.Substring (0, (int)maxWidth);
                 tabTextWidth = (int)maxWidth;
                 tabTextWidth = (int)maxWidth;
             }
             }
+            else
+            {
+                tab.Text = tab.DisplayText;
+            }
 
 
             tab.Width = Math.Max (tabTextWidth + 2, 1);
             tab.Width = Math.Max (tabTextWidth + 2, 1);
             tab.Height = Style.ShowTopLine ? 3 : 2;
             tab.Height = Style.ShowTopLine ? 3 : 2;
@@ -506,11 +494,19 @@ public class TabView : View
             // there is enough space!
             // there is enough space!
             tab.Visible = true;
             tab.Visible = true;
             tab.MouseClick += Tab_MouseClick!;
             tab.MouseClick += Tab_MouseClick!;
+            tab.Border!.MouseClick += Tab_MouseClick!;
 
 
-            yield return new TabToRender (tab, text, Equals (SelectedTab, tab));
+            yield return new (tab, Equals (SelectedTab, tab));
+
+            prevTab = tab;
 
 
             i += tabTextWidth + 1;
             i += tabTextWidth + 1;
         }
         }
+
+        if (_selectedTabHasFocus)
+        {
+            SelectedTab?.SetFocus ();
+        }
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -542,11 +538,27 @@ public class TabView : View
 
 
     private void UnSetCurrentTabs ()
     private void UnSetCurrentTabs ()
     {
     {
-        if (_tabLocations is { })
+        if (_tabLocations is null)
+        {
+            // Ensures unset any visible tab prior to TabScrollOffset
+            for (int i = 0; i < TabScrollOffset; i++)
+            {
+                Tab tab = Tabs.ElementAt (i);
+
+                if (tab.Visible)
+                {
+                    tab.MouseClick -= Tab_MouseClick!;
+                    tab.Border!.MouseClick -= Tab_MouseClick!;
+                    tab.Visible = false;
+                }
+            }
+        }
+        else if (_tabLocations is { })
         {
         {
             foreach (TabToRender tabToRender in _tabLocations)
             foreach (TabToRender tabToRender in _tabLocations)
             {
             {
                 tabToRender.Tab.MouseClick -= Tab_MouseClick!;
                 tabToRender.Tab.MouseClick -= Tab_MouseClick!;
+                tabToRender.Tab.Border!.MouseClick -= Tab_MouseClick!;
                 tabToRender.Tab.Visible = false;
                 tabToRender.Tab.Visible = false;
             }
             }
 
 
@@ -570,7 +582,6 @@ public class TabView : View
             Id = "tabRowView";
             Id = "tabRowView";
 
 
             CanFocus = true;
             CanFocus = true;
-            Height = 1; // BUGBUG: Views should avoid setting Height as doing so implies Frame.Size == GetContentSize ().
             Width = Dim.Fill ();
             Width = Dim.Fill ();
 
 
             _rightScrollIndicator = new View
             _rightScrollIndicator = new View
@@ -598,17 +609,23 @@ public class TabView : View
 
 
         protected override bool OnMouseEvent (MouseEventArgs me)
         protected override bool OnMouseEvent (MouseEventArgs me)
         {
         {
-            Tab? hit = me.View as Tab;
+            View? parent = me.View is Adornment adornment ? adornment.Parent : me.View;
+            Tab? hit = parent as Tab;
 
 
             if (me.IsSingleClicked)
             if (me.IsSingleClicked)
             {
             {
-                _host.OnTabClicked (new TabMouseEventArgs (hit, me));
+                _host.OnTabClicked (new TabMouseEventArgs (hit!, me));
 
 
                 // user canceled click
                 // user canceled click
                 if (me.Handled)
                 if (me.Handled)
                 {
                 {
                     return true;
                     return true;
                 }
                 }
+
+                if (parent == _host.SelectedTab)
+                {
+                    _host.SelectedTab?.SetFocus ();
+                }
             }
             }
 
 
             if (!me.IsSingleDoubleOrTripleClicked)
             if (!me.IsSingleDoubleOrTripleClicked)
@@ -625,11 +642,11 @@ public class TabView : View
             {
             {
                 var scrollIndicatorHit = 0;
                 var scrollIndicatorHit = 0;
 
 
-                if (me.View is { } && me.View.Id == "rightScrollIndicator")
+                if (me.View is { Id: "rightScrollIndicator" })
                 {
                 {
                     scrollIndicatorHit = 1;
                     scrollIndicatorHit = 1;
                 }
                 }
-                else if (me.View is { } && me.View.Id == "leftScrollIndicator")
+                else if (me.View is { Id: "leftScrollIndicator" })
                 {
                 {
                     scrollIndicatorHit = -1;
                     scrollIndicatorHit = -1;
                 }
                 }
@@ -656,15 +673,20 @@ public class TabView : View
         }
         }
 
 
         /// <inheritdoc />
         /// <inheritdoc />
-        protected override bool OnClearingViewport ()
+        protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocusedView, View? focusedView)
         {
         {
-            // clear any old text
-            ClearViewport ();
+            if (_host.SelectedTab is { HasFocus: false, CanFocus: true } && focusedView == this)
+            {
+                _host.SelectedTab?.SetFocus ();
 
 
-            return true;
+                return;
+            }
+
+            base.OnHasFocusChanged (newHasFocus, previousFocusedView, focusedView);
         }
         }
 
 
-        protected override bool OnDrawingContent ()
+        /// <inheritdoc />
+        protected override void OnSubviewLayout (LayoutEventArgs args)
         {
         {
             _host._tabLocations = _host.CalculateViewport (Viewport).ToArray ();
             _host._tabLocations = _host.CalculateViewport (Viewport).ToArray ();
 
 
@@ -672,20 +694,18 @@ public class TabView : View
 
 
             RenderUnderline ();
             RenderUnderline ();
 
 
-            SetAttribute (HasFocus ? GetFocusColor () : GetNormalColor ());
-
-            return true;
+            base.OnSubviewLayout (args);
         }
         }
 
 
         /// <inheritdoc />
         /// <inheritdoc />
-        protected override bool OnDrawingSubviews ()
+        protected override bool OnRenderingLineCanvas ()
         {
         {
-           // RenderTabLine ();
+            RenderTabLineCanvas ();
 
 
             return false;
             return false;
         }
         }
 
 
-        protected override void OnDrawComplete ()
+        private void RenderTabLineCanvas ()
         {
         {
             if (_host._tabLocations is null)
             if (_host._tabLocations is null)
             {
             {
@@ -694,12 +714,12 @@ public class TabView : View
 
 
             TabToRender [] tabLocations = _host._tabLocations;
             TabToRender [] tabLocations = _host._tabLocations;
             int selectedTab = -1;
             int selectedTab = -1;
+            var lc = new LineCanvas ();
 
 
             for (var i = 0; i < tabLocations.Length; i++)
             for (var i = 0; i < tabLocations.Length; i++)
             {
             {
                 View tab = tabLocations [i].Tab;
                 View tab = tabLocations [i].Tab;
                 Rectangle vts = tab.ViewportToScreen (tab.Viewport);
                 Rectangle vts = tab.ViewportToScreen (tab.Viewport);
-                var lc = new LineCanvas ();
                 int selectedOffset = _host.Style.ShowTopLine && tabLocations [i].IsSelected ? 0 : 1;
                 int selectedOffset = _host.Style.ShowTopLine && tabLocations [i].IsSelected ? 0 : 1;
 
 
                 if (tabLocations [i].IsSelected)
                 if (tabLocations [i].IsSelected)
@@ -1048,7 +1068,7 @@ public class TabView : View
                     }
                     }
                 }
                 }
 
 
-                if (i == 0 && i != selectedTab && _host.TabScrollOffset == 0 && _host.Style.ShowBorder)
+                if (i == 0 && i != selectedTab && _host is { TabScrollOffset: 0, Style.ShowBorder: true })
                 {
                 {
                     if (_host.Style.TabsOnBottom)
                     if (_host.Style.TabsOnBottom)
                     {
                     {
@@ -1163,6 +1183,7 @@ public class TabView : View
                     }
                     }
                     else
                     else
                     {
                     {
+                        // Right corner
                         if (_host.Style.TabsOnBottom)
                         if (_host.Style.TabsOnBottom)
                         {
                         {
                             lc.AddLine (
                             lc.AddLine (
@@ -1213,12 +1234,9 @@ public class TabView : View
                         }
                         }
                     }
                     }
                 }
                 }
-
-                tab.LineCanvas.Merge (lc);
-                tab.RenderLineCanvas ();
-
-               // RenderUnderline ();
             }
             }
+
+            _host.LineCanvas.Merge (lc);
         }
         }
 
 
         private int GetUnderlineYPosition ()
         private int GetUnderlineYPosition ()
@@ -1234,9 +1252,7 @@ public class TabView : View
         /// <summary>Renders the line with the tab names in it.</summary>
         /// <summary>Renders the line with the tab names in it.</summary>
         private void RenderTabLine ()
         private void RenderTabLine ()
         {
         {
-            TabToRender []? tabLocations = _host._tabLocations;
-
-            if (tabLocations is null)
+            if (_host._tabLocations is null)
             {
             {
                 return;
                 return;
             }
             }
@@ -1244,7 +1260,7 @@ public class TabView : View
             View? selected = null;
             View? selected = null;
             int topLine = _host.Style.ShowTopLine ? 1 : 0;
             int topLine = _host.Style.ShowTopLine ? 1 : 0;
 
 
-            foreach (TabToRender toRender in tabLocations)
+            foreach (TabToRender toRender in _host._tabLocations)
             {
             {
                 Tab tab = toRender.Tab;
                 Tab tab = toRender.Tab;
 
 
@@ -1254,80 +1270,45 @@ public class TabView : View
 
 
                     if (_host.Style.TabsOnBottom)
                     if (_host.Style.TabsOnBottom)
                     {
                     {
-                        tab.Border.Thickness = new Thickness (1, 0, 1, topLine);
-                        tab.Margin.Thickness = new Thickness (0, 1, 0, 0);
+                        tab.Border!.Thickness = new (1, 0, 1, topLine);
+                        tab.Margin!.Thickness = new (0, 1, 0, 0);
                     }
                     }
                     else
                     else
                     {
                     {
-                        tab.Border.Thickness = new Thickness (1, topLine, 1, 0);
-                        tab.Margin.Thickness = new Thickness (0, 0, 0, topLine);
+                        tab.Border!.Thickness = new (1, topLine, 1, 0);
+                        tab.Margin!.Thickness = new (0, 0, 0, topLine);
                     }
                     }
                 }
                 }
                 else if (selected is null)
                 else if (selected is null)
                 {
                 {
                     if (_host.Style.TabsOnBottom)
                     if (_host.Style.TabsOnBottom)
                     {
                     {
-                        tab.Border.Thickness = new Thickness (1, 1, 0, topLine);
-                        tab.Margin.Thickness = new Thickness (0, 0, 0, 0);
+                        tab.Border!.Thickness = new (1, 1, 1, topLine);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
                     }
                     }
                     else
                     else
                     {
                     {
-                        tab.Border.Thickness = new Thickness (1, topLine, 0, 1);
-                        tab.Margin.Thickness = new Thickness (0, 0, 0, 0);
+                        tab.Border!.Thickness = new (1, topLine, 1, 1);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
                     }
                     }
-
-                    tab.Width = Math.Max (tab.Width!.GetAnchor (0) - 1, 1);
                 }
                 }
                 else
                 else
                 {
                 {
                     if (_host.Style.TabsOnBottom)
                     if (_host.Style.TabsOnBottom)
                     {
                     {
-                        tab.Border.Thickness = new Thickness (0, 1, 1, topLine);
-                        tab.Margin.Thickness = new Thickness (0, 0, 0, 0);
+                        tab.Border!.Thickness = new (1, 1, 1, topLine);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
                     }
                     }
                     else
                     else
                     {
                     {
-                        tab.Border.Thickness = new Thickness (0, topLine, 1, 1);
-                        tab.Margin.Thickness = new Thickness (0, 0, 0, 0);
+                        tab.Border!.Thickness = new (1, topLine, 1, 1);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
                     }
                     }
-
-                    tab.Width = Math.Max (tab.Width!.GetAnchor (0) - 1, 1);
                 }
                 }
 
 
-                tab.Text = toRender.TextToRender;
-
-                // BUGBUG: Layout should only be called from Mainloop iteration!
-                Layout ();
-
-                tab.DrawBorderAndPadding ();
-
-                Attribute prevAttr = Driver?.GetAttribute () ?? Attribute.Default;
-
-                // if tab is the selected one and focus is inside this control
-                if (toRender.IsSelected && _host.HasFocus)
-                {
-                    if (_host.Focused == this)
-                    {
-                        // if focus is the tab bar itself then show that they can switch tabs
-                        prevAttr = ColorScheme.HotFocus;
-                    }
-                    else
-                    {
-                        // Focus is inside the tab
-                        prevAttr = ColorScheme.HotNormal;
-                    }
-                }
-
-                tab.TextFormatter.Draw (
-                                        tab.ViewportToScreen (tab.Viewport),
-                                        prevAttr,
-                                        ColorScheme.HotNormal
-                                       );
-
-                tab.DrawBorderAndPadding ();
-
-
-                SetAttribute (GetNormalColor ());
+                // Ensures updating TextFormatter constrains
+                tab.TextFormatter.ConstrainToWidth = tab.GetContentSize ().Width;
+                tab.TextFormatter.ConstrainToHeight = tab.GetContentSize ().Height;
             }
             }
         }
         }
 
 
@@ -1356,7 +1337,6 @@ public class TabView : View
 
 
                 // Ensures this is clicked instead of the first tab
                 // Ensures this is clicked instead of the first tab
                 MoveSubviewToEnd (_leftScrollIndicator);
                 MoveSubviewToEnd (_leftScrollIndicator);
-                _leftScrollIndicator.Draw ();
             }
             }
             else
             else
             {
             {
@@ -1374,7 +1354,6 @@ public class TabView : View
 
 
                 // Ensures this is clicked instead of the last tab if under this
                 // Ensures this is clicked instead of the last tab if under this
                 MoveSubviewToStart (_rightScrollIndicator);
                 MoveSubviewToStart (_rightScrollIndicator);
-                _rightScrollIndicator.Draw ();
             }
             }
             else
             else
             {
             {
@@ -1387,11 +1366,10 @@ public class TabView : View
 
 
     private class TabToRender
     private class TabToRender
     {
     {
-        public TabToRender (Tab tab, string textToRender, bool isSelected)
+        public TabToRender (Tab tab, bool isSelected)
         {
         {
             Tab = tab;
             Tab = tab;
             IsSelected = isSelected;
             IsSelected = isSelected;
-            TextToRender = textToRender;
         }
         }
 
 
         /// <summary>True if the tab that is being rendered is the selected one.</summary>
         /// <summary>True if the tab that is being rendered is the selected one.</summary>
@@ -1399,6 +1377,5 @@ public class TabView : View
         public bool IsSelected { get; }
         public bool IsSelected { get; }
 
 
         public Tab Tab { get; }
         public Tab Tab { get; }
-        public string TextToRender { get; }
     }
     }
 }
 }

+ 2 - 0
UnitTests/View/Adornment/PaddingTests.cs

@@ -33,5 +33,7 @@ PPP",
                                              output
                                              output
                                             );
                                             );
         TestHelpers.AssertDriverAttributesAre ("0", output, null, view.GetNormalColor ());
         TestHelpers.AssertDriverAttributesAre ("0", output, null, view.GetNormalColor ());
+
+        ((FakeDriver)Application.Driver!).End ();
     }
     }
 }
 }

+ 100 - 0
UnitTests/View/Layout/SetLayoutTests.cs

@@ -813,5 +813,105 @@ public class SetLayoutTests (ITestOutputHelper output)
         t.Dispose ();
         t.Dispose ();
     }
     }
 
 
+    [Fact]
+    [SetupFakeDriver]
+    public void Pos_Right_With_Adornments ()
+    {
+        View view1 = new () { Text = "View1", Width = 7, Height = 3, BorderStyle = LineStyle.Rounded };
+        View view2 = new () { Text = "View2", X = Pos.Right (view1) - 1, Width = 7, Height = 3, BorderStyle = LineStyle.Rounded };
+        View view3 = new () { Text = "View3", X = Pos.Right (view2) - 1, Width = 7, Height = 3, BorderStyle = LineStyle.Rounded };
+        View container = new () { Width = Dim.Fill (), Height = 3 };
+        container.Add (view1, view2, view3);
 
 
+        View view4 = new () { Text = "View4", Y = Pos.Bottom (container), Width = 21, Height = 3, BorderStyle = LineStyle.Rounded };
+        View superView = new () { Width = Dim.Fill (), Height = Dim.Fill () };
+        superView.Add (container, view4);
+
+        superView.Layout ();
+        superView.Draw ();
+
+        TestHelpers.AssertDriverContentsAre (
+                                             @"
+╭─────╭─────╭─────╮
+│View1│View2│View3│
+╰─────╰─────╰─────╯
+╭───────────────────╮
+│View4              │
+╰───────────────────╯
+",
+                                             output
+                                            );
+
+        // Remove border bottom from the view1
+        view1.Border!.Thickness = new (1, 1, 1, 0);
+        // Insert margin bottom into the view1
+        view1.Margin!.Thickness = new (0, 0, 0, 1);
+
+        View.SetClipToScreen ();
+        superView.Draw ();
+
+        TestHelpers.AssertDriverContentsAre (
+                                             @"
+╭─────╭─────╭─────╮
+│View1│View2│View3│
+      ╰─────╰─────╯
+╭───────────────────╮
+│View4              │
+╰───────────────────╯
+",
+                                             output
+                                            );
+
+        // Restore view1 border
+        view1.Border.Thickness = new (1);
+        // Restore view1 margin
+        view1.Margin.Thickness = Thickness.Empty;
+
+        // Remove border bottom from the view2
+        view2.Border!.Thickness = new (1, 1, 1, 0);
+        // Insert margin bottom into the view2
+        view2.Margin!.Thickness = new (0, 0, 0, 1);
+
+        View.SetClipToScreen ();
+        superView.Draw ();
+
+        TestHelpers.AssertDriverContentsAre (
+                                             @"
+╭─────╭─────╭─────╮
+│View1│View2│View3│
+╰─────╯     ╰─────╯
+╭───────────────────╮
+│View4              │
+╰───────────────────╯
+",
+                                             output
+                                            );
+
+        // Restore view2 border
+        view2.Border.Thickness = new (1);
+        // Restore view2 margin
+        view2.Margin.Thickness = Thickness.Empty;
+
+        // Remove border bottom from the view3
+        view3.Border!.Thickness = new (1, 1, 1, 0);
+        // Insert margin bottom into the view3
+        view3.Margin!.Thickness = new (0, 0, 0, 1);
+
+        View.SetClipToScreen ();
+        superView.Draw ();
+
+        TestHelpers.AssertDriverContentsAre (
+                                             @"
+╭─────╭─────╭─────╮
+│View1│View2│View3│
+╰─────╰─────╯
+╭───────────────────╮
+│View4              │
+╰───────────────────╯
+",
+                                             output
+                                            );
+
+        superView.Dispose ();
+    }
 }
 }

+ 209 - 77
UnitTests/Views/TabViewTests.cs

@@ -3,7 +3,6 @@ using Xunit.Abstractions;
 
 
 namespace Terminal.Gui.ViewsTests;
 namespace Terminal.Gui.ViewsTests;
 
 
-#if foo
 public class TabViewTests (ITestOutputHelper output)
 public class TabViewTests (ITestOutputHelper output)
 {
 {
     [Fact]
     [Fact]
@@ -113,8 +112,6 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Width = 20;
         tv.Width = 20;
         tv.Height = 5;
         tv.Height = 5;
 
 
-        tv.Layout ();
-
         tv.Draw ();
         tv.Draw ();
 
 
         View tabRow = tv.Subviews [0];
         View tabRow = tv.Subviews [0];
@@ -146,21 +143,21 @@ public class TabViewTests (ITestOutputHelper output)
         {
         {
             args = new () { ScreenPosition = new (i, 1), Flags = MouseFlags.ReportMousePosition };
             args = new () { ScreenPosition = new (i, 1), Flags = MouseFlags.ReportMousePosition };
             Application.RaiseMouseEvent (args);
             Application.RaiseMouseEvent (args);
-            Application.LayoutAndDrawToplevels ();
+            Application.LayoutAndDraw ();
             Assert.Null (clicked);
             Assert.Null (clicked);
             Assert.Equal (tab1, tv.SelectedTab);
             Assert.Equal (tab1, tv.SelectedTab);
         }
         }
 
 
         args = new () { ScreenPosition = new (3, 1), Flags = MouseFlags.Button1Clicked };
         args = new () { ScreenPosition = new (3, 1), Flags = MouseFlags.Button1Clicked };
         Application.RaiseMouseEvent (args);
         Application.RaiseMouseEvent (args);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
         Assert.Equal (tab1, clicked);
         Assert.Equal (tab1, clicked);
         Assert.Equal (tab1, tv.SelectedTab);
         Assert.Equal (tab1, tv.SelectedTab);
 
 
         // Click to tab2
         // Click to tab2
         args = new () { ScreenPosition = new (6, 1), Flags = MouseFlags.Button1Clicked };
         args = new () { ScreenPosition = new (6, 1), Flags = MouseFlags.Button1Clicked };
         Application.RaiseMouseEvent (args);
         Application.RaiseMouseEvent (args);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
         Assert.Equal (tab2, clicked);
         Assert.Equal (tab2, clicked);
         Assert.Equal (tab2, tv.SelectedTab);
         Assert.Equal (tab2, tv.SelectedTab);
 
 
@@ -173,7 +170,7 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         args = new () { ScreenPosition = new (3, 1), Flags = MouseFlags.Button1Clicked };
         args = new () { ScreenPosition = new (3, 1), Flags = MouseFlags.Button1Clicked };
         Application.RaiseMouseEvent (args);
         Application.RaiseMouseEvent (args);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
 
 
         // Tab 1 was clicked but event handler blocked navigation
         // Tab 1 was clicked but event handler blocked navigation
         Assert.Equal (tab1, clicked);
         Assert.Equal (tab1, clicked);
@@ -181,7 +178,7 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         args = new () { ScreenPosition = new (12, 1), Flags = MouseFlags.Button1Clicked };
         args = new () { ScreenPosition = new (12, 1), Flags = MouseFlags.Button1Clicked };
         Application.RaiseMouseEvent (args);
         Application.RaiseMouseEvent (args);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
 
 
         // Clicking beyond last tab should raise event with null Tab
         // Clicking beyond last tab should raise event with null Tab
         Assert.Null (clicked);
         Assert.Null (clicked);
@@ -198,8 +195,6 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Width = 7;
         tv.Width = 7;
         tv.Height = 5;
         tv.Height = 5;
 
 
-        tv.LayoutSubviews ();
-
         tv.Draw ();
         tv.Draw ();
 
 
         View tabRow = tv.Subviews [0];
         View tabRow = tv.Subviews [0];
@@ -236,7 +231,7 @@ public class TabViewTests (ITestOutputHelper output)
         // Click the right arrow
         // Click the right arrow
         var args = new MouseEventArgs { ScreenPosition = new (6, 2), Flags = MouseFlags.Button1Clicked };
         var args = new MouseEventArgs { ScreenPosition = new (6, 2), Flags = MouseFlags.Button1Clicked };
         Application.RaiseMouseEvent (args);
         Application.RaiseMouseEvent (args);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
         Assert.Null (clicked);
         Assert.Null (clicked);
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab2, newChanged);
         Assert.Equal (tab2, newChanged);
@@ -256,7 +251,7 @@ public class TabViewTests (ITestOutputHelper output)
         // Click the left arrow
         // Click the left arrow
         args = new () { ScreenPosition = new (0, 2), Flags = MouseFlags.Button1Clicked };
         args = new () { ScreenPosition = new (0, 2), Flags = MouseFlags.Button1Clicked };
         Application.RaiseMouseEvent (args);
         Application.RaiseMouseEvent (args);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
         Assert.Null (clicked);
         Assert.Null (clicked);
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab1, newChanged);
         Assert.Equal (tab1, newChanged);
@@ -286,8 +281,7 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         Assert.Equal (LineStyle.None, tv.BorderStyle);
         Assert.Equal (LineStyle.None, tv.BorderStyle);
         tv.BorderStyle = LineStyle.Single;
         tv.BorderStyle = LineStyle.Single;
-
-        tv.LayoutSubviews ();
+        tv.Layout ();
 
 
         tv.Draw ();
         tv.Draw ();
 
 
@@ -327,7 +321,7 @@ public class TabViewTests (ITestOutputHelper output)
         // Click the right arrow
         // Click the right arrow
         var args = new MouseEventArgs { ScreenPosition = new (7, 3), Flags = MouseFlags.Button1Clicked };
         var args = new MouseEventArgs { ScreenPosition = new (7, 3), Flags = MouseFlags.Button1Clicked };
         Application.RaiseMouseEvent (args);
         Application.RaiseMouseEvent (args);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
         Assert.Null (clicked);
         Assert.Null (clicked);
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab2, newChanged);
         Assert.Equal (tab2, newChanged);
@@ -349,7 +343,7 @@ public class TabViewTests (ITestOutputHelper output)
         // Click the left arrow
         // Click the left arrow
         args = new () { ScreenPosition = new (1, 3), Flags = MouseFlags.Button1Clicked };
         args = new () { ScreenPosition = new (1, 3), Flags = MouseFlags.Button1Clicked };
         Application.RaiseMouseEvent (args);
         Application.RaiseMouseEvent (args);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
         Assert.Null (clicked);
         Assert.Null (clicked);
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab1, newChanged);
         Assert.Equal (tab1, newChanged);
@@ -400,7 +394,7 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         // Press the cursor up key to focus the selected tab
         // Press the cursor up key to focus the selected tab
         Application.RaiseKeyDownEvent (Key.CursorUp);
         Application.RaiseKeyDownEvent (Key.CursorUp);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
 
 
         // Is the selected tab focused
         // Is the selected tab focused
         Assert.Equal (tab1, tv.SelectedTab);
         Assert.Equal (tab1, tv.SelectedTab);
@@ -418,7 +412,7 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         // Press the cursor right key to select the next tab
         // Press the cursor right key to select the next tab
         Application.RaiseKeyDownEvent (Key.CursorRight);
         Application.RaiseKeyDownEvent (Key.CursorRight);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab2, newChanged);
         Assert.Equal (tab2, newChanged);
         Assert.Equal (tab2, tv.SelectedTab);
         Assert.Equal (tab2, tv.SelectedTab);
@@ -476,7 +470,7 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         // Press the cursor left key to select the previous tab
         // Press the cursor left key to select the previous tab
         Application.RaiseKeyDownEvent (Key.CursorLeft);
         Application.RaiseKeyDownEvent (Key.CursorLeft);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab1, newChanged);
         Assert.Equal (tab1, newChanged);
         Assert.Equal (tab1, tv.SelectedTab);
         Assert.Equal (tab1, tv.SelectedTab);
@@ -486,7 +480,7 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         // Press the end key to select the last tab
         // Press the end key to select the last tab
         Application.RaiseKeyDownEvent (Key.End);
         Application.RaiseKeyDownEvent (Key.End);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab2, newChanged);
         Assert.Equal (tab2, newChanged);
         Assert.Equal (tab2, tv.SelectedTab);
         Assert.Equal (tab2, tv.SelectedTab);
@@ -495,7 +489,7 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         // Press the home key to select the first tab
         // Press the home key to select the first tab
         Application.RaiseKeyDownEvent (Key.Home);
         Application.RaiseKeyDownEvent (Key.Home);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab1, newChanged);
         Assert.Equal (tab1, newChanged);
         Assert.Equal (tab1, tv.SelectedTab);
         Assert.Equal (tab1, tv.SelectedTab);
@@ -504,7 +498,7 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         // Press the page down key to select the next set of tabs
         // Press the page down key to select the next set of tabs
         Application.RaiseKeyDownEvent (Key.PageDown);
         Application.RaiseKeyDownEvent (Key.PageDown);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab1, oldChanged);
         Assert.Equal (tab2, newChanged);
         Assert.Equal (tab2, newChanged);
         Assert.Equal (tab2, tv.SelectedTab);
         Assert.Equal (tab2, tv.SelectedTab);
@@ -513,7 +507,7 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         // Press the page up key to select the previous set of tabs
         // Press the page up key to select the previous set of tabs
         Application.RaiseKeyDownEvent (Key.PageUp);
         Application.RaiseKeyDownEvent (Key.PageUp);
-        Application.LayoutAndDrawToplevels ();
+        Application.LayoutAndDraw ();
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab2, oldChanged);
         Assert.Equal (tab1, newChanged);
         Assert.Equal (tab1, newChanged);
         Assert.Equal (tab1, tv.SelectedTab);
         Assert.Equal (tab1, tv.SelectedTab);
@@ -610,7 +604,6 @@ public class TabViewTests (ITestOutputHelper output)
         tv.ApplyStyleChanges ();
         tv.ApplyStyleChanges ();
         tv.Layout ();
         tv.Layout ();
 
 
-        View.ClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -633,7 +626,7 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Height = 5;
         tv.Height = 5;
         tv.Style = new () { ShowTopLine = false };
         tv.Style = new () { ShowTopLine = false };
         tv.ApplyStyleChanges ();
         tv.ApplyStyleChanges ();
-        tv.LayoutSubviews ();
+        tv.Layout ();
 
 
         tv.Draw ();
         tv.Draw ();
 
 
@@ -658,13 +651,13 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Style = new () { ShowTopLine = false };
         tv.Style = new () { ShowTopLine = false };
         tv.ApplyStyleChanges ();
         tv.ApplyStyleChanges ();
 
 
-        // Ensures that the tab bar subview gets the bounds of the parent TabView
-        tv.LayoutSubviews ();
-
-        // Test two tab names that fit 
+        // Test two tab names that fit
         tab1.DisplayText = "12";
         tab1.DisplayText = "12";
         tab2.DisplayText = "13";
         tab2.DisplayText = "13";
 
 
+        // Ensures that the tab bar subview gets the bounds of the parent TabView
+        tv.Layout ();
+
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -678,8 +671,10 @@ public class TabViewTests (ITestOutputHelper output)
                                                      );
                                                      );
 
 
         tv.SelectedTab = tab2;
         tv.SelectedTab = tab2;
+        Assert.Equal (tab2, tv.Subviews.First (v => v.Id.Contains ("tabRowView")).MostFocused);
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -697,8 +692,8 @@ public class TabViewTests (ITestOutputHelper output)
         // Test first tab name too long
         // Test first tab name too long
         tab1.DisplayText = "12345678910";
         tab1.DisplayText = "12345678910";
         tab2.DisplayText = "13";
         tab2.DisplayText = "13";
-
-        View.ClipToScreen ();
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -713,9 +708,10 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         //switch to tab2
         //switch to tab2
         tv.SelectedTab = tab2;
         tv.SelectedTab = tab2;
-        View.ClipToScreen ();
-        tv.Draw ();
 
 
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
                                                       @"
 │13│      
 │13│      
@@ -730,9 +726,9 @@ public class TabViewTests (ITestOutputHelper output)
         tab1.DisplayText = "12345678910";
         tab1.DisplayText = "12345678910";
         tab2.DisplayText = "abcdefghijklmnopq";
         tab2.DisplayText = "abcdefghijklmnopq";
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
-
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
                                                       @"
 │abcdefg│ 
 │abcdefg│ 
@@ -753,9 +749,8 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Height = 5;
         tv.Height = 5;
         tv.Style = new () { ShowTopLine = false, TabsOnBottom = true };
         tv.Style = new () { ShowTopLine = false, TabsOnBottom = true };
         tv.ApplyStyleChanges ();
         tv.ApplyStyleChanges ();
-        tv.LayoutSubviews ();
+        tv.Layout ();
 
 
-        View.ClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -778,7 +773,7 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Height = 5;
         tv.Height = 5;
         tv.Style = new () { ShowTopLine = false, TabsOnBottom = true };
         tv.Style = new () { ShowTopLine = false, TabsOnBottom = true };
         tv.ApplyStyleChanges ();
         tv.ApplyStyleChanges ();
-        tv.LayoutSubviews ();
+        tv.Layout ();
 
 
         tv.Draw ();
         tv.Draw ();
 
 
@@ -802,15 +797,13 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Height = 5;
         tv.Height = 5;
         tv.Style = new () { ShowTopLine = false, TabsOnBottom = true };
         tv.Style = new () { ShowTopLine = false, TabsOnBottom = true };
         tv.ApplyStyleChanges ();
         tv.ApplyStyleChanges ();
+        tv.Layout ();
 
 
-        // Ensures that the tab bar subview gets the bounds of the parent TabView
-        tv.LayoutSubviews ();
-
-        // Test two tab names that fit 
+        // Test two tab names that fit
         tab1.DisplayText = "12";
         tab1.DisplayText = "12";
         tab2.DisplayText = "13";
         tab2.DisplayText = "13";
-        View.ClipToScreen ();
 
 
+        tv.Layout ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -824,8 +817,10 @@ public class TabViewTests (ITestOutputHelper output)
                                                      );
                                                      );
 
 
         tv.SelectedTab = tab2;
         tv.SelectedTab = tab2;
+        Assert.Equal (tab2, tv.Subviews.First (v => v.Id.Contains ("tabRowView")).MostFocused);
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -844,7 +839,8 @@ public class TabViewTests (ITestOutputHelper output)
         tab1.DisplayText = "12345678910";
         tab1.DisplayText = "12345678910";
         tab2.DisplayText = "13";
         tab2.DisplayText = "13";
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -859,7 +855,9 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         //switch to tab2
         //switch to tab2
         tv.SelectedTab = tab2;
         tv.SelectedTab = tab2;
-        View.ClipToScreen ();
+
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -876,7 +874,8 @@ public class TabViewTests (ITestOutputHelper output)
         tab1.DisplayText = "12345678910";
         tab1.DisplayText = "12345678910";
         tab2.DisplayText = "abcdefghijklmnopq";
         tab2.DisplayText = "abcdefghijklmnopq";
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -899,7 +898,6 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Height = 5;
         tv.Height = 5;
         tv.Layout ();
         tv.Layout ();
 
 
-        View.ClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -922,7 +920,7 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Height = 5;
         tv.Height = 5;
         tv.Layout ();
         tv.Layout ();
 
 
-        View.ClipToScreen ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -944,14 +942,11 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Width = 10;
         tv.Width = 10;
         tv.Height = 5;
         tv.Height = 5;
 
 
-        // Ensures that the tab bar subview gets the bounds of the parent TabView
-        tv.LayoutSubviews ();
-
-        // Test two tab names that fit 
+        // Test two tab names that fit
         tab1.DisplayText = "12";
         tab1.DisplayText = "12";
         tab2.DisplayText = "13";
         tab2.DisplayText = "13";
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -966,7 +961,8 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         tv.SelectedTab = tab2;
         tv.SelectedTab = tab2;
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -985,7 +981,8 @@ public class TabViewTests (ITestOutputHelper output)
         tab1.DisplayText = "12345678910";
         tab1.DisplayText = "12345678910";
         tab2.DisplayText = "13";
         tab2.DisplayText = "13";
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1000,7 +997,9 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         //switch to tab2
         //switch to tab2
         tv.SelectedTab = tab2;
         tv.SelectedTab = tab2;
-        View.ClipToScreen ();
+
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1017,7 +1016,8 @@ public class TabViewTests (ITestOutputHelper output)
         tab1.DisplayText = "12345678910";
         tab1.DisplayText = "12345678910";
         tab2.DisplayText = "abcdefghijklmnopq";
         tab2.DisplayText = "abcdefghijklmnopq";
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1039,13 +1039,11 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Width = 20;
         tv.Width = 20;
         tv.Height = 5;
         tv.Height = 5;
 
 
-        tv.LayoutSubviews ();
-
         tab1.DisplayText = "Tab0";
         tab1.DisplayText = "Tab0";
 
 
         tab2.DisplayText = "Les Mise" + char.ConvertFromUtf32 (int.Parse ("0301", NumberStyles.HexNumber)) + "rables";
         tab2.DisplayText = "Les Mise" + char.ConvertFromUtf32 (int.Parse ("0301", NumberStyles.HexNumber)) + "rables";
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1060,7 +1058,8 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         tv.SelectedTab = tab2;
         tv.SelectedTab = tab2;
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1083,7 +1082,7 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Height = 5;
         tv.Height = 5;
         tv.Style = new () { TabsOnBottom = true };
         tv.Style = new () { TabsOnBottom = true };
         tv.ApplyStyleChanges ();
         tv.ApplyStyleChanges ();
-        tv.LayoutSubviews ();
+        tv.Layout ();
 
 
         tv.Draw ();
         tv.Draw ();
 
 
@@ -1107,7 +1106,7 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Height = 5;
         tv.Height = 5;
         tv.Style = new () { TabsOnBottom = true };
         tv.Style = new () { TabsOnBottom = true };
         tv.ApplyStyleChanges ();
         tv.ApplyStyleChanges ();
-        tv.LayoutSubviews ();
+        tv.Layout ();
 
 
         tv.Draw ();
         tv.Draw ();
 
 
@@ -1131,15 +1130,13 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Height = 5;
         tv.Height = 5;
         tv.Style = new () { TabsOnBottom = true };
         tv.Style = new () { TabsOnBottom = true };
         tv.ApplyStyleChanges ();
         tv.ApplyStyleChanges ();
+        tv.Layout ();
 
 
-        // Ensures that the tab bar subview gets the bounds of the parent TabView
-        tv.LayoutSubviews ();
-
-        // Test two tab names that fit 
+        // Test two tab names that fit
         tab1.DisplayText = "12";
         tab1.DisplayText = "12";
         tab2.DisplayText = "13";
         tab2.DisplayText = "13";
-        View.ClipToScreen ();
 
 
+        tv.Layout ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1156,7 +1153,8 @@ public class TabViewTests (ITestOutputHelper output)
         tab1.DisplayText = "12345678910";
         tab1.DisplayText = "12345678910";
         tab2.DisplayText = "13";
         tab2.DisplayText = "13";
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1171,7 +1169,9 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         //switch to tab2
         //switch to tab2
         tv.SelectedTab = tab2;
         tv.SelectedTab = tab2;
-        View.ClipToScreen ();
+
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1188,7 +1188,8 @@ public class TabViewTests (ITestOutputHelper output)
         tab1.DisplayText = "12345678910";
         tab1.DisplayText = "12345678910";
         tab2.DisplayText = "abcdefghijklmnopq";
         tab2.DisplayText = "abcdefghijklmnopq";
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1212,12 +1213,11 @@ public class TabViewTests (ITestOutputHelper output)
         tv.Style = new () { TabsOnBottom = true };
         tv.Style = new () { TabsOnBottom = true };
         tv.ApplyStyleChanges ();
         tv.ApplyStyleChanges ();
 
 
-        tv.LayoutSubviews ();
-
         tab1.DisplayText = "Tab0";
         tab1.DisplayText = "Tab0";
 
 
         tab2.DisplayText = "Les Mise" + char.ConvertFromUtf32 (int.Parse ("0301", NumberStyles.HexNumber)) + "rables";
         tab2.DisplayText = "Les Mise" + char.ConvertFromUtf32 (int.Parse ("0301", NumberStyles.HexNumber)) + "rables";
 
 
+        tv.Layout ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1232,7 +1232,8 @@ public class TabViewTests (ITestOutputHelper output)
 
 
         tv.SelectedTab = tab2;
         tv.SelectedTab = tab2;
 
 
-        View.ClipToScreen ();
+        tv.Layout ();
+        View.SetClipToScreen ();
         tv.Draw ();
         tv.Draw ();
 
 
         TestHelpers.AssertDriverContentsWithFrameAre (
         TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1322,6 +1323,138 @@ public class TabViewTests (ITestOutputHelper output)
         Application.Shutdown ();
         Application.Shutdown ();
     }
     }
 
 
+    [Fact]
+    [SetupFakeDriver]
+    public void Add_Three_TabsOnTop_ChangesTab ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
+        Tab tab3;
+
+        tv.AddTab (
+                   tab3 = new () { Id = "tab3", DisplayText = "Tab3", View = new TextView { Id = "tab3.TextView", Width = 3, Height = 1, Text = "hi3" } },
+                   false);
+
+        tv.Width = 20;
+        tv.Height = 5;
+
+        tv.Layout ();
+        tv.Draw ();
+
+        Assert.Equal (tab1, tv.SelectedTab);
+
+        TestHelpers.AssertDriverContentsAre (
+                                             @"
+╭────┬────┬────╮
+│Tab1│Tab2│Tab3│
+│    ╰────┴────┴───╮
+│hi                │
+└──────────────────┘
+",
+                                             output
+                                            );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭────┬────┬────╮    
+│Tab1│Tab2│Tab3│    
+├────╯    ╰────┴───╮
+│hi2               │
+└──────────────────┘
+",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab3;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭────┬────┬────╮    
+│Tab1│Tab2│Tab3│    
+├────┴────╯    ╰───╮
+│hi3               │
+└──────────────────┘
+",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void Add_Three_TabsOnBottom_ChangesTab ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
+        Tab tab3;
+
+        tv.AddTab (
+                   tab3 = new () { Id = "tab3", DisplayText = "Tab3", View = new TextView { Id = "tab3.TextView", Width = 3, Height = 1, Text = "hi3" } },
+                   false);
+
+        tv.Width = 20;
+        tv.Height = 5;
+        tv.Style = new () { TabsOnBottom = true };
+        tv.ApplyStyleChanges ();
+
+        tv.Layout ();
+        tv.Draw ();
+
+        Assert.Equal (tab1, tv.SelectedTab);
+
+        TestHelpers.AssertDriverContentsAre (
+                                             @"
+┌──────────────────┐
+│hi                │
+│    ╭────┬────┬───╯
+│Tab1│Tab2│Tab3│
+╰────┴────┴────╯
+",
+                                             output
+                                            );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌──────────────────┐
+│hi2               │
+├────╮    ╭────┬───╯
+│Tab1│Tab2│Tab3│    
+╰────┴────┴────╯    
+",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab3;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌──────────────────┐
+│hi3               │
+├────┬────╮    ╭───╯
+│Tab1│Tab2│Tab3│    
+╰────┴────┴────╯    
+",
+                                                      output
+                                                     );
+    }
+
     private TabView GetTabView () { return GetTabView (out _, out _); }
     private TabView GetTabView () { return GetTabView (out _, out _); }
 
 
     private TabView GetTabView (out Tab tab1, out Tab tab2, bool initFakeDriver = true)
     private TabView GetTabView (out Tab tab1, out Tab tab2, bool initFakeDriver = true)
@@ -1355,4 +1488,3 @@ public class TabViewTests (ITestOutputHelper output)
         driver.Init ();
         driver.Init ();
     }
     }
 }
 }
-#endif