From cb7682f9a61ff2828858effadf81baa4d4d9a8b7 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Mon, 25 Nov 2024 21:41:09 +0000
Subject: [PATCH 01/18] Add TabSide enum.

---
 Terminal.Gui/Views/TabView/TabRow.cs   | 744 +++++++++++++++----------
 Terminal.Gui/Views/TabView/TabSide.cs  |  27 +
 Terminal.Gui/Views/TabView/TabStyle.cs |   9 +-
 Terminal.Gui/Views/TabView/TabView.cs  |  75 +--
 UICatalog/Scenarios/TabViewExample.cs  |  57 +-
 UnitTests/Views/TabViewTests.cs        |  16 +-
 6 files changed, 564 insertions(+), 364 deletions(-)
 create mode 100644 Terminal.Gui/Views/TabView/TabSide.cs

diff --git a/Terminal.Gui/Views/TabView/TabRow.cs b/Terminal.Gui/Views/TabView/TabRow.cs
index 2ca80a69ae..ffff8ab4d8 100644
--- a/Terminal.Gui/Views/TabView/TabRow.cs
+++ b/Terminal.Gui/Views/TabView/TabRow.cs
@@ -157,187 +157,249 @@ private void RenderTabLineCanvas ()
 
                 if (i == 0 && _host.TabScrollOffset == 0)
                 {
-                    if (_host.Style.TabsOnBottom)
+                    switch (_host.Style.TabsSide)
                     {
-                        // Upper left vertical line
-                        lc.AddLine (
-                                    new Point (vts.X - 1, vts.Y - 1),
-                                    -1,
-                                    Orientation.Vertical,
-                                    tab.BorderStyle
-                                   );
-                    }
-                    else
-                    {
-                        // Lower left vertical line
-                        lc.AddLine (
-                                    new Point (vts.X - 1, vts.Bottom - selectedOffset),
-                                    -1,
-                                    Orientation.Vertical,
-                                    tab.BorderStyle
-                                   );
-                    }
-                }
-                else if (i > 0 && i <= tabLocations.Length - 1)
-                {
-                    if (_host.Style.TabsOnBottom)
-                    {
-                        // URCorner
-                        lc.AddLine (
-                                    new Point (vts.X - 1, vts.Y - 1),
-                                    1,
-                                    Orientation.Vertical,
-                                    tab.BorderStyle
-                                   );
-
-                        lc.AddLine (
-                                    new Point (vts.X - 1, vts.Y - 1),
-                                    -1,
-                                    Orientation.Horizontal,
-                                    tab.BorderStyle
-                                   );
-                    }
-                    else
-                    {
-                        // LRCorner
-                        lc.AddLine (
-                                    new Point (vts.X - 1, vts.Bottom - selectedOffset),
-                                    -1,
-                                    Orientation.Vertical,
-                                    tab.BorderStyle
-                                   );
-
-                        lc.AddLine (
-                                    new Point (vts.X - 1, vts.Bottom - selectedOffset),
-                                    -1,
-                                    Orientation.Horizontal,
-                                    tab.BorderStyle
-                                   );
-                    }
-
-                    if (_host.Style.ShowTopLine)
-                    {
-                        if (_host.Style.TabsOnBottom)
-                        {
-                            // Lower left tee
+                        case TabSide.Top:
+                            // Lower left vertical line
                             lc.AddLine (
-                                        new Point (vts.X - 1, vts.Bottom),
+                                        new Point (vts.X - 1, vts.Bottom - selectedOffset),
                                         -1,
                                         Orientation.Vertical,
                                         tab.BorderStyle
                                        );
 
-                            lc.AddLine (
-                                        new Point (vts.X - 1, vts.Bottom),
-                                        0,
-                                        Orientation.Horizontal,
-                                        tab.BorderStyle
-                                       );
-                        }
-                        else
-                        {
-                            // Upper left tee
+                            break;
+                        case TabSide.Bottom:
+                            // Upper left vertical line
                             lc.AddLine (
                                         new Point (vts.X - 1, vts.Y - 1),
-                                        1,
+                                        -1,
                                         Orientation.Vertical,
                                         tab.BorderStyle
                                        );
 
-                            lc.AddLine (
-                                        new Point (vts.X - 1, vts.Y - 1),
-                                        0,
-                                        Orientation.Horizontal,
-                                        tab.BorderStyle
-                                       );
-                        }
+                            break;
+                        case TabSide.Left:
+                            break;
+                        case TabSide.Right:
+                            break;
+                        default:
+                            throw new ArgumentOutOfRangeException ();
                     }
                 }
-
-                if (i < tabLocations.Length - 1)
+                else if (i > 0 && i <= tabLocations.Length - 1)
                 {
-                    if (_host.Style.ShowTopLine)
+                    switch (_host.Style.TabsSide)
                     {
-                        if (_host.Style.TabsOnBottom)
-                        {
-                            // Lower right tee
+                        case TabSide.Top:
+                            // LRCorner
                             lc.AddLine (
-                                        new Point (vts.Right, vts.Bottom),
+                                        new Point (vts.X - 1, vts.Bottom - selectedOffset),
                                         -1,
                                         Orientation.Vertical,
                                         tab.BorderStyle
                                        );
 
                             lc.AddLine (
-                                        new Point (vts.Right, vts.Bottom),
-                                        0,
+                                        new Point (vts.X - 1, vts.Bottom - selectedOffset),
+                                        -1,
                                         Orientation.Horizontal,
                                         tab.BorderStyle
                                        );
-                        }
-                        else
-                        {
-                            // Upper right tee
+
+                            break;
+                        case TabSide.Bottom:
+                            // URCorner
                             lc.AddLine (
-                                        new Point (vts.Right, vts.Y - 1),
+                                        new Point (vts.X - 1, vts.Y - 1),
                                         1,
                                         Orientation.Vertical,
                                         tab.BorderStyle
                                        );
 
                             lc.AddLine (
-                                        new Point (vts.Right, vts.Y - 1),
-                                        0,
+                                        new Point (vts.X - 1, vts.Y - 1),
+                                        -1,
                                         Orientation.Horizontal,
                                         tab.BorderStyle
                                        );
+
+                            break;
+                        case TabSide.Left:
+                            break;
+                        case TabSide.Right:
+                            break;
+                        default:
+                            throw new ArgumentOutOfRangeException ();
+                    }
+
+                    if (_host.Style.ShowTopLine)
+                    {
+                        switch (_host.Style.TabsSide)
+                        {
+                            case TabSide.Top:
+                                // Upper left tee
+                                lc.AddLine (
+                                            new Point (vts.X - 1, vts.Y - 1),
+                                            1,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new Point (vts.X - 1, vts.Y - 1),
+                                            0,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+
+                                break;
+                            case TabSide.Bottom:
+                                // Lower left tee
+                                lc.AddLine (
+                                            new Point (vts.X - 1, vts.Bottom),
+                                            -1,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new Point (vts.X - 1, vts.Bottom),
+                                            0,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+
+                                break;
+                            case TabSide.Left:
+                                break;
+                            case TabSide.Right:
+                                break;
+                            default:
+                                throw new ArgumentOutOfRangeException ();
                         }
                     }
                 }
 
-                if (_host.Style.TabsOnBottom)
+                if (i < tabLocations.Length - 1)
                 {
-                    //URCorner
-                    lc.AddLine (
-                                new Point (vts.Right, vts.Y - 1),
-                                1,
-                                Orientation.Vertical,
-                                tab.BorderStyle
-                               );
-
-                    lc.AddLine (
-                                new Point (vts.Right, vts.Y - 1),
-                                1,
-                                Orientation.Horizontal,
-                                tab.BorderStyle
-                               );
+                    if (_host.Style.ShowTopLine)
+                    {
+                        switch (_host.Style.TabsSide)
+                        {
+                            case TabSide.Top:
+                                // Upper right tee
+                                lc.AddLine (
+                                            new Point (vts.Right, vts.Y - 1),
+                                            1,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new Point (vts.Right, vts.Y - 1),
+                                            0,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+
+                                break;
+                            case TabSide.Bottom:
+                                // Lower right tee
+                                lc.AddLine (
+                                            new Point (vts.Right, vts.Bottom),
+                                            -1,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new Point (vts.Right, vts.Bottom),
+                                            0,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+
+                                break;
+                            case TabSide.Left:
+                                break;
+                            case TabSide.Right:
+                                break;
+                            default:
+                                throw new ArgumentOutOfRangeException ();
+                        }
+                    }
                 }
-                else
+
+                switch (_host.Style.TabsSide)
                 {
-                    //LLCorner
-                    lc.AddLine (
-                                new Point (vts.Right, vts.Bottom - selectedOffset),
-                                -1,
-                                Orientation.Vertical,
-                                tab.BorderStyle
-                               );
+                    case TabSide.Top:
+                        //LLCorner
+                        lc.AddLine (
+                                    new Point (vts.Right, vts.Bottom - selectedOffset),
+                                    -1,
+                                    Orientation.Vertical,
+                                    tab.BorderStyle
+                                   );
 
-                    lc.AddLine (
-                                new Point (vts.Right, vts.Bottom - selectedOffset),
-                                1,
-                                Orientation.Horizontal,
-                                tab.BorderStyle
-                               );
+                        lc.AddLine (
+                                    new Point (vts.Right, vts.Bottom - selectedOffset),
+                                    1,
+                                    Orientation.Horizontal,
+                                    tab.BorderStyle
+                                   );
+
+                        break;
+                    case TabSide.Bottom:
+                        //URCorner
+                        lc.AddLine (
+                                    new Point (vts.Right, vts.Y - 1),
+                                    1,
+                                    Orientation.Vertical,
+                                    tab.BorderStyle
+                                   );
+
+                        lc.AddLine (
+                                    new Point (vts.Right, vts.Y - 1),
+                                    1,
+                                    Orientation.Horizontal,
+                                    tab.BorderStyle
+                                   );
+
+                        break;
+                    case TabSide.Left:
+                        break;
+                    case TabSide.Right:
+                        break;
+                    default:
+                        throw new ArgumentOutOfRangeException ();
                 }
             }
             else if (selectedTab == -1)
             {
                 if (i == 0 && string.IsNullOrEmpty (tab.Text))
                 {
-                    if (_host.Style.TabsOnBottom)
+                    switch (_host.Style.TabsSide)
                     {
-                        if (_host.Style.ShowTopLine)
-                        {
+                        case TabSide.Top:
+                            if (_host.Style.ShowTopLine)
+                            {
+                                // ULCorner
+                                lc.AddLine (
+                                            new Point (vts.X - 1, vts.Y - 1),
+                                            1,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new Point (vts.X - 1, vts.Y - 1),
+                                            1,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+                            }
+
                             // LLCorner
                             lc.AddLine (
                                         new Point (vts.X - 1, vts.Bottom),
@@ -352,27 +414,27 @@ private void RenderTabLineCanvas ()
                                         Orientation.Horizontal,
                                         tab.BorderStyle
                                        );
-                        }
 
-                        // ULCorner
-                        lc.AddLine (
-                                    new Point (vts.X - 1, vts.Y - 1),
-                                    1,
-                                    Orientation.Vertical,
-                                    tab.BorderStyle
-                                   );
+                            break;
+                        case TabSide.Bottom:
+                            if (_host.Style.ShowTopLine)
+                            {
+                                // LLCorner
+                                lc.AddLine (
+                                            new Point (vts.X - 1, vts.Bottom),
+                                            -1,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new Point (vts.X - 1, vts.Bottom),
+                                            1,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+                            }
 
-                        lc.AddLine (
-                                    new Point (vts.X - 1, vts.Y - 1),
-                                    1,
-                                    Orientation.Horizontal,
-                                    tab.BorderStyle
-                                   );
-                    }
-                    else
-                    {
-                        if (_host.Style.ShowTopLine)
-                        {
                             // ULCorner
                             lc.AddLine (
                                         new Point (vts.X - 1, vts.Y - 1),
@@ -387,27 +449,19 @@ private void RenderTabLineCanvas ()
                                         Orientation.Horizontal,
                                         tab.BorderStyle
                                        );
-                        }
-
-                        // LLCorner
-                        lc.AddLine (
-                                    new Point (vts.X - 1, vts.Bottom),
-                                    -1,
-                                    Orientation.Vertical,
-                                    tab.BorderStyle
-                                   );
 
-                        lc.AddLine (
-                                    new Point (vts.X - 1, vts.Bottom),
-                                    1,
-                                    Orientation.Horizontal,
-                                    tab.BorderStyle
-                                   );
+                            break;
+                        case TabSide.Left:
+                            break;
+                        case TabSide.Right:
+                            break;
+                        default:
+                            throw new ArgumentOutOfRangeException ();
                     }
                 }
                 else if (i > 0)
                 {
-                    if (_host.Style.ShowTopLine || _host.Style.TabsOnBottom)
+                    if (_host.Style.ShowTopLine || _host.Style.TabsSide == TabSide.Bottom)
                     {
                         // Upper left tee
                         lc.AddLine (
@@ -461,7 +515,7 @@ private void RenderTabLineCanvas ()
                                );
                 }
 
-                if (_host.Style.ShowTopLine || !_host.Style.TabsOnBottom)
+                if (_host.Style.ShowTopLine || _host.Style.TabsSide == TabSide.Top)
                 {
                     // Lower right tee
                     lc.AddLine (
@@ -499,77 +553,95 @@ private void RenderTabLineCanvas ()
 
             if (i == 0 && i != selectedTab && _host is { TabScrollOffset: 0, Style.ShowBorder: true })
             {
-                if (_host.Style.TabsOnBottom)
+                switch (_host.Style.TabsSide)
                 {
-                    // Upper left vertical line
-                    lc.AddLine (
-                                new Point (vts.X - 1, vts.Y - 1),
-                                0,
-                                Orientation.Vertical,
-                                tab.BorderStyle
-                               );
+                    case TabSide.Top:
+                        // Lower left vertical line
+                        lc.AddLine (
+                                    new Point (vts.X - 1, vts.Bottom),
+                                    0,
+                                    Orientation.Vertical,
+                                    tab.BorderStyle
+                                   );
 
-                    lc.AddLine (
-                                new Point (vts.X - 1, vts.Y - 1),
-                                1,
-                                Orientation.Horizontal,
-                                tab.BorderStyle
-                               );
-                }
-                else
-                {
-                    // Lower left vertical line
-                    lc.AddLine (
-                                new Point (vts.X - 1, vts.Bottom),
-                                0,
-                                Orientation.Vertical,
-                                tab.BorderStyle
-                               );
+                        lc.AddLine (
+                                    new Point (vts.X - 1, vts.Bottom),
+                                    1,
+                                    Orientation.Horizontal,
+                                    tab.BorderStyle
+                                   );
 
-                    lc.AddLine (
-                                new Point (vts.X - 1, vts.Bottom),
-                                1,
-                                Orientation.Horizontal,
-                                tab.BorderStyle
-                               );
+                        break;
+                    case TabSide.Bottom:
+                        // Upper left vertical line
+                        lc.AddLine (
+                                    new Point (vts.X - 1, vts.Y - 1),
+                                    0,
+                                    Orientation.Vertical,
+                                    tab.BorderStyle
+                                   );
+
+                        lc.AddLine (
+                                    new Point (vts.X - 1, vts.Y - 1),
+                                    1,
+                                    Orientation.Horizontal,
+                                    tab.BorderStyle
+                                   );
+
+                        break;
+                    case TabSide.Left:
+                        break;
+                    case TabSide.Right:
+                        break;
+                    default:
+                        throw new ArgumentOutOfRangeException ();
                 }
             }
 
             if (i == tabLocations.Length - 1 && i != selectedTab)
             {
-                if (_host.Style.TabsOnBottom)
+                switch (_host.Style.TabsSide)
                 {
-                    // Upper right tee
-                    lc.AddLine (
-                                new Point (vts.Right, vts.Y - 1),
-                                1,
-                                Orientation.Vertical,
-                                tab.BorderStyle
-                               );
+                    case TabSide.Top:
+                        // Lower right tee
+                        lc.AddLine (
+                                    new Point (vts.Right, vts.Bottom),
+                                    -1,
+                                    Orientation.Vertical,
+                                    tab.BorderStyle
+                                   );
 
-                    lc.AddLine (
-                                new Point (vts.Right, vts.Y - 1),
-                                0,
-                                Orientation.Horizontal,
-                                tab.BorderStyle
-                               );
-                }
-                else
-                {
-                    // Lower right tee
-                    lc.AddLine (
-                                new Point (vts.Right, vts.Bottom),
-                                -1,
-                                Orientation.Vertical,
-                                tab.BorderStyle
-                               );
+                        lc.AddLine (
+                                    new Point (vts.Right, vts.Bottom),
+                                    0,
+                                    Orientation.Horizontal,
+                                    tab.BorderStyle
+                                   );
 
-                    lc.AddLine (
-                                new Point (vts.Right, vts.Bottom),
-                                0,
-                                Orientation.Horizontal,
-                                tab.BorderStyle
-                               );
+                        break;
+                    case TabSide.Bottom:
+                        // Upper right tee
+                        lc.AddLine (
+                                    new Point (vts.Right, vts.Y - 1),
+                                    1,
+                                    Orientation.Vertical,
+                                    tab.BorderStyle
+                                   );
+
+                        lc.AddLine (
+                                    new Point (vts.Right, vts.Y - 1),
+                                    0,
+                                    Orientation.Horizontal,
+                                    tab.BorderStyle
+                                   );
+
+                        break;
+                    case TabSide.Left:
+                        break;
+                    case TabSide.Right:
+                        break;
+                    default:
+                        throw new ArgumentOutOfRangeException ();
                 }
             }
 
@@ -578,7 +650,7 @@ private void RenderTabLineCanvas ()
                 var arrowOffset = 1;
 
                 int lastSelectedTab = !_host.Style.ShowTopLine && i == selectedTab ? 1 :
-                                      _host.Style.TabsOnBottom ? 1 : 0;
+                                      _host.Style.TabsSide == TabSide.Bottom ? 1 : 0;
                 Rectangle tabsBarVts = ViewportToScreen (Viewport);
                 int lineLength = tabsBarVts.Right - vts.Right;
 
@@ -587,78 +659,105 @@ private void RenderTabLineCanvas ()
                 {
                     if (lineLength - arrowOffset > 0)
                     {
-                        if (_host.Style.TabsOnBottom)
-                        {
-                            lc.AddLine (
-                                        new Point (vts.Right, vts.Y - lastSelectedTab),
-                                        lineLength - arrowOffset,
-                                        Orientation.Horizontal,
-                                        tab.BorderStyle
-                                       );
-                        }
-                        else
+                        switch (_host.Style.TabsSide)
                         {
-                            lc.AddLine (
-                                        new Point (
-                                                   vts.Right,
-                                                   vts.Bottom - lastSelectedTab
-                                                  ),
-                                        lineLength - arrowOffset,
-                                        Orientation.Horizontal,
-                                        tab.BorderStyle
-                                       );
+                            case TabSide.Top:
+                                lc.AddLine (
+                                            new Point (
+                                                       vts.Right,
+                                                       vts.Bottom - lastSelectedTab
+                                                      ),
+                                            lineLength - arrowOffset,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+
+                                break;
+                            case TabSide.Bottom:
+                                lc.AddLine (
+                                            new Point (vts.Right, vts.Y - lastSelectedTab),
+                                            lineLength - arrowOffset,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+
+                                break;
+                            case TabSide.Left:
+                                break;
+                            case TabSide.Right:
+                                break;
+                            default:
+                                throw new ArgumentOutOfRangeException ();
                         }
                     }
                 }
                 else
                 {
                     // Right corner
-                    if (_host.Style.TabsOnBottom)
+                    switch (_host.Style.TabsSide)
                     {
-                        lc.AddLine (
-                                    new Point (vts.Right, vts.Y - lastSelectedTab),
-                                    lineLength,
-                                    Orientation.Horizontal,
-                                    tab.BorderStyle
-                                   );
-                    }
-                    else
-                    {
-                        lc.AddLine (
-                                    new Point (vts.Right, vts.Bottom - lastSelectedTab),
-                                    lineLength,
-                                    Orientation.Horizontal,
-                                    tab.BorderStyle
-                                   );
-                    }
-
-                    if (_host.Style.ShowBorder)
-                    {
-                        if (_host.Style.TabsOnBottom)
-                        {
-                            // More LRCorner
+                        case TabSide.Top:
                             lc.AddLine (
-                                        new Point (
-                                                   tabsBarVts.Right - 1,
-                                                   vts.Y - lastSelectedTab
-                                                  ),
-                                        -1,
-                                        Orientation.Vertical,
+                                        new Point (vts.Right, vts.Bottom - lastSelectedTab),
+                                        lineLength,
+                                        Orientation.Horizontal,
                                         tab.BorderStyle
                                        );
-                        }
-                        else
-                        {
-                            // More URCorner
+
+                            break;
+                        case TabSide.Bottom:
                             lc.AddLine (
-                                        new Point (
-                                                   tabsBarVts.Right - 1,
-                                                   vts.Bottom - lastSelectedTab
-                                                  ),
-                                        1,
-                                        Orientation.Vertical,
+                                        new Point (vts.Right, vts.Y - lastSelectedTab),
+                                        lineLength,
+                                        Orientation.Horizontal,
                                         tab.BorderStyle
                                        );
+
+                            break;
+                        case TabSide.Left:
+                            break;
+                        case TabSide.Right:
+                            break;
+                        default:
+                            throw new ArgumentOutOfRangeException ();
+                    }
+
+                    if (_host.Style.ShowBorder)
+                    {
+                        switch (_host.Style.TabsSide)
+                        {
+                            case TabSide.Top:
+                                // More URCorner
+                                lc.AddLine (
+                                            new Point (
+                                                       tabsBarVts.Right - 1,
+                                                       vts.Bottom - lastSelectedTab
+                                                      ),
+                                            1,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                break;
+                            case TabSide.Bottom:
+                                // More LRCorner
+                                lc.AddLine (
+                                            new Point (
+                                                       tabsBarVts.Right - 1,
+                                                       vts.Y - lastSelectedTab
+                                                      ),
+                                            -1,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                break;
+                            case TabSide.Left:
+                                break;
+                            case TabSide.Right:
+                                break;
+                            default:
+                                throw new ArgumentOutOfRangeException ();
                         }
                     }
                 }
@@ -670,7 +769,7 @@ private void RenderTabLineCanvas ()
 
     private int GetUnderlineYPosition ()
     {
-        if (_host.Style.TabsOnBottom)
+        if (_host.Style.TabsSide == TabSide.Bottom)
         {
             return 0;
         }
@@ -697,41 +796,68 @@ private void RenderTabLine ()
             {
                 selected = tab;
 
-                if (_host.Style.TabsOnBottom)
+                switch (_host.Style.TabsSide)
                 {
-                    tab.Border!.Thickness = new (1, 0, 1, topLine);
-                    tab.Margin!.Thickness = new (0, 1, 0, 0);
-                }
-                else
-                {
-                    tab.Border!.Thickness = new (1, topLine, 1, 0);
-                    tab.Margin!.Thickness = new (0, 0, 0, topLine);
+                    case TabSide.Top:
+                        tab.Border!.Thickness = new (1, topLine, 1, 0);
+                        tab.Margin!.Thickness = new (0, 0, 0, topLine);
+
+                        break;
+                    case TabSide.Bottom:
+                        tab.Border!.Thickness = new (1, 0, 1, topLine);
+                        tab.Margin!.Thickness = new (0, 1, 0, 0);
+
+                        break;
+                    case TabSide.Left:
+                        break;
+                    case TabSide.Right:
+                        break;
+                    default:
+                        throw new ArgumentOutOfRangeException ();
                 }
             }
             else if (selected is null)
             {
-                if (_host.Style.TabsOnBottom)
-                {
-                    tab.Border!.Thickness = new (1, 1, 1, topLine);
-                    tab.Margin!.Thickness = new (0, 0, 0, 0);
-                }
-                else
+                switch (_host.Style.TabsSide)
                 {
-                    tab.Border!.Thickness = new (1, topLine, 1, 1);
-                    tab.Margin!.Thickness = new (0, 0, 0, 0);
+                    case TabSide.Top:
+                        tab.Border!.Thickness = new (1, topLine, 1, 1);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
+
+                        break;
+                    case TabSide.Bottom:
+                        tab.Border!.Thickness = new (1, 1, 1, topLine);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
+
+                        break;
+                    case TabSide.Left:
+                        break;
+                    case TabSide.Right:
+                        break;
+                    default:
+                        throw new ArgumentOutOfRangeException ();
                 }
             }
             else
             {
-                if (_host.Style.TabsOnBottom)
-                {
-                    tab.Border!.Thickness = new (1, 1, 1, topLine);
-                    tab.Margin!.Thickness = new (0, 0, 0, 0);
-                }
-                else
+                switch (_host.Style.TabsSide)
                 {
-                    tab.Border!.Thickness = new (1, topLine, 1, 1);
-                    tab.Margin!.Thickness = new (0, 0, 0, 0);
+                    case TabSide.Top:
+                        tab.Border!.Thickness = new (1, topLine, 1, 1);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
+
+                        break;
+                    case TabSide.Bottom:
+                        tab.Border!.Thickness = new (1, 1, 1, topLine);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
+
+                        break;
+                    case TabSide.Left:
+                        break;
+                    case TabSide.Right:
+                        break;
+                    default:
+                        throw new ArgumentOutOfRangeException ();
                 }
             }
 
diff --git a/Terminal.Gui/Views/TabView/TabSide.cs b/Terminal.Gui/Views/TabView/TabSide.cs
new file mode 100644
index 0000000000..eef3a51c39
--- /dev/null
+++ b/Terminal.Gui/Views/TabView/TabSide.cs
@@ -0,0 +1,27 @@
+namespace Terminal.Gui;
+
+/// <summary>
+///     Defines tab side.
+/// </summary>
+public enum TabSide
+{
+    /// <summary>
+    ///     Top side.
+    /// </summary>
+    Top,
+
+    /// <summary>
+    ///     Bottom side.
+    /// </summary>
+    Bottom,
+
+    /// <summary>
+    ///     Left side.
+    /// </summary>
+    Left,
+
+    /// <summary>
+    ///     Right side.
+    /// </summary>
+    Right
+}
diff --git a/Terminal.Gui/Views/TabView/TabStyle.cs b/Terminal.Gui/Views/TabView/TabStyle.cs
index 85404d05d9..c6734260c9 100644
--- a/Terminal.Gui/Views/TabView/TabStyle.cs
+++ b/Terminal.Gui/Views/TabView/TabStyle.cs
@@ -1,4 +1,5 @@
-namespace Terminal.Gui;
+#nullable enable
+namespace Terminal.Gui;
 
 /// <summary>Describes render stylistic selections of a <see cref="TabView"/></summary>
 public class TabStyle
@@ -9,10 +10,10 @@ public class TabStyle
     /// <summary>
     ///     True to show the top lip of tabs.  False to directly begin with tab text during rendering.  When true header
     ///     line occupies 3 rows, when false only 2. Defaults to true.
-    ///     <para>When <see cref="TabsOnBottom"/> is enabled this instead applies to the bottommost line of the control</para>
+    ///     <para>When <see cref="TabsSide"/> is enabled this instead applies to the bottommost line of the control</para>
     /// </summary>
     public bool ShowTopLine { get; set; } = true;
 
-    /// <summary>True to render tabs at the bottom of the view instead of the top</summary>
-    public bool TabsOnBottom { get; set; } = false;
+    /// <summary>Gets or sets the tabs side to render.</summary>
+    public TabSide TabsSide { get; set; }
 }
diff --git a/Terminal.Gui/Views/TabView/TabView.cs b/Terminal.Gui/Views/TabView/TabView.cs
index 73f286b564..fe856451c4 100644
--- a/Terminal.Gui/Views/TabView/TabView.cs
+++ b/Terminal.Gui/Views/TabView/TabView.cs
@@ -232,48 +232,59 @@ public void ApplyStyleChanges ()
         _containerView.BorderStyle = Style.ShowBorder ? LineStyle.Single : LineStyle.None;
         _containerView.Width = Dim.Fill ();
 
-        if (Style.TabsOnBottom)
+        int tabHeight;
+
+        switch (Style.TabsSide)
         {
-            // Tabs are along the bottom so just dodge the border
-            if (Style.ShowBorder)
-            {
-                _containerView.Border!.Thickness = new Thickness (1, 1, 1, 0);
-            }
+            case TabSide.Top:
+                // Tabs are along the top
+                if (Style.ShowBorder)
+                {
+                    _containerView.Border!.Thickness = new Thickness (1, 0, 1, 1);
+                }
 
-            _containerView.Y = 0;
+                _tabsBar.Y = 0;
 
-            int tabHeight = GetTabHeight (false);
+                tabHeight = GetTabHeight (true);
 
-            // Fill client area leaving space at bottom for tabs
-            _containerView.Height = Dim.Fill (tabHeight);
+                //move content down to make space for tabs
+                _containerView.Y = Pos.Bottom (_tabsBar);
 
-            _tabsBar.Height = tabHeight;
+                // Fill client area leaving space at bottom for border
+                _containerView.Height = Dim.Fill ();
 
-            _tabsBar.Y = Pos.Bottom (_containerView);
-        }
-        else
-        {
-            // Tabs are along the top
-            if (Style.ShowBorder)
-            {
-                _containerView.Border!.Thickness = new Thickness (1, 0, 1, 1);
-            }
+                // The top tab should be 2 or 3 rows high and on the top
+
+                _tabsBar.Height = tabHeight;
 
-            _tabsBar.Y = 0;
+                // Should be able to just use 0 but switching between top/bottom tabs repeatedly breaks in ValidatePosDim if just using the absolute value 0
 
-            int tabHeight = GetTabHeight (true);
+                break;
+            case TabSide.Bottom:
+                // Tabs are along the bottom so just dodge the border
+                if (Style.ShowBorder)
+                {
+                    _containerView.Border!.Thickness = new Thickness (1, 1, 1, 0);
+                }
 
-            //move content down to make space for tabs
-            _containerView.Y = Pos.Bottom (_tabsBar);
+                _containerView.Y = 0;
 
-            // Fill client area leaving space at bottom for border
-            _containerView.Height = Dim.Fill ();
+                tabHeight = GetTabHeight (false);
 
-            // The top tab should be 2 or 3 rows high and on the top
+                // Fill client area leaving space at bottom for tabs
+                _containerView.Height = Dim.Fill (tabHeight);
 
-            _tabsBar.Height = tabHeight;
+                _tabsBar.Height = tabHeight;
 
-            // Should be able to just use 0 but switching between top/bottom tabs repeatedly breaks in ValidatePosDim if just using the absolute value 0
+                _tabsBar.Y = Pos.Bottom (_containerView);
+
+                break;
+            case TabSide.Left:
+                break;
+            case TabSide.Right:
+                break;
+            default:
+                throw new ArgumentOutOfRangeException ();
         }
 
         SetNeedsLayout ();
@@ -526,19 +537,19 @@ internal IEnumerable<Tab> CalculateViewport (Rectangle bounds)
 
     /// <summary>
     ///     Returns the number of rows occupied by rendering the tabs, this depends on <see cref="TabStyle.ShowTopLine"/>
-    ///     and can be 0 (e.g. if <see cref="TabStyle.TabsOnBottom"/> and you ask for <paramref name="top"/>).
+    ///     and can be 0 (e.g. if <see cref="TabStyle.TabsSide"/> and you ask for <paramref name="top"/>).
     /// </summary>
     /// <param name="top">True to measure the space required at the top of the control, false to measure space at the bottom.</param>
     /// .
     /// <returns></returns>
     private int GetTabHeight (bool top)
     {
-        if (top && Style.TabsOnBottom)
+        if (top && Style.TabsSide == TabSide.Bottom)
         {
             return 0;
         }
 
-        if (!top && !Style.TabsOnBottom)
+        if (!top && Style.TabsSide == TabSide.Top)
         {
             return 0;
         }
diff --git a/UICatalog/Scenarios/TabViewExample.cs b/UICatalog/Scenarios/TabViewExample.cs
index 9d48c05685..b3f896e2e6 100644
--- a/UICatalog/Scenarios/TabViewExample.cs
+++ b/UICatalog/Scenarios/TabViewExample.cs
@@ -1,4 +1,6 @@
-using System.Linq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
 using System.Text;
 using Terminal.Gui;
 
@@ -12,7 +14,8 @@ public class TabViewExample : Scenario
     private MenuItem _miShowBorder;
     private MenuItem _miShowTabViewBorder;
     private MenuItem _miShowTopLine;
-    private MenuItem _miTabsOnBottom;
+    private MenuItem [] _miTabsSide;
+    private MenuItem _cachedTabsSide;
     private TabView _tabView;
 
     public override void Main ()
@@ -23,6 +26,8 @@ public override void Main ()
         // Setup - Create a top-level application window and configure it.
         Toplevel appWindow = new ();
 
+        _miTabsSide = SetTabsSide ();
+
         var menu = new MenuBar
         {
             Menus =
@@ -54,11 +59,12 @@ public override void Main ()
                              {
                                  Checked = true, CheckType = MenuItemCheckStyle.Checked
                              },
-                         _miTabsOnBottom =
-                             new ("_Tabs On Bottom", "", SetTabsOnBottom)
-                             {
-                                 Checked = false, CheckType = MenuItemCheckStyle.Checked
-                             },
+                         null,
+                         _miTabsSide [0],
+                         _miTabsSide [1],
+                         _miTabsSide [2],
+                         _miTabsSide [3],
+                         null,
                          _miShowTabViewBorder =
                              new (
                                   "_Show TabView Border",
@@ -241,12 +247,41 @@ private View GetInteractiveTab ()
 
     private void Quit () { Application.RequestStop (); }
 
-    private void SetTabsOnBottom ()
+    private MenuItem [] SetTabsSide ()
     {
-        _miTabsOnBottom.Checked = !_miTabsOnBottom.Checked;
+        List<MenuItem> menuItems = [];
 
-        _tabView.Style.TabsOnBottom = (bool)_miTabsOnBottom.Checked;
-        _tabView.ApplyStyleChanges ();
+        foreach (TabSide side in Enum.GetValues (typeof (TabSide)))
+        {
+            string sideName = Enum.GetName (typeof (TabSide), side);
+            var item = new MenuItem { Title = $"_{sideName}", Data = side };
+            item.CheckType |= MenuItemCheckStyle.Radio;
+
+            item.Action += () =>
+                           {
+                               if (_cachedTabsSide == item)
+                               {
+                                   return;
+                               }
+
+                               _cachedTabsSide.Checked = false;
+                               item.Checked = true;
+                               _cachedTabsSide = item;
+                               _tabView.Style.TabsSide = (TabSide)item.Data;
+                               _tabView.ApplyStyleChanges ();
+                           };
+            item.ShortcutKey = ((Key)sideName! [0].ToString ().ToLower ()).WithCtrl;
+
+            if (sideName == "Top")
+            {
+                item.Checked = true;
+                _cachedTabsSide = item;
+            }
+
+            menuItems.Add (item);
+        }
+
+        return menuItems.ToArray ();
     }
 
     private void ShowBorder ()
diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs
index ac12a55564..8ffa49c2e8 100644
--- a/UnitTests/Views/TabViewTests.cs
+++ b/UnitTests/Views/TabViewTests.cs
@@ -736,7 +736,7 @@ public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width3 ()
         TabView tv = GetTabView (out _, out _);
         tv.Width = 3;
         tv.Height = 5;
-        tv.Style = new () { ShowTopLine = false, TabsOnBottom = true };
+        tv.Style = new () { ShowTopLine = false, TabsSide = TabSide.Bottom };
         tv.ApplyStyleChanges ();
         tv.Layout ();
 
@@ -760,7 +760,7 @@ public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width4 ()
         TabView tv = GetTabView (out _, out _);
         tv.Width = 4;
         tv.Height = 5;
-        tv.Style = new () { ShowTopLine = false, TabsOnBottom = true };
+        tv.Style = new () { ShowTopLine = false, TabsSide = TabSide.Bottom };
         tv.ApplyStyleChanges ();
         tv.Layout ();
 
@@ -784,7 +784,7 @@ public void ShowTopLine_False_TabsOnBottom_True_TestThinTabView_WithLongNames ()
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 10;
         tv.Height = 5;
-        tv.Style = new () { ShowTopLine = false, TabsOnBottom = true };
+        tv.Style = new () { ShowTopLine = false, TabsSide = TabSide.Bottom };
         tv.ApplyStyleChanges ();
         tv.Layout ();
 
@@ -1069,7 +1069,7 @@ public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width3 ()
         TabView tv = GetTabView (out _, out _);
         tv.Width = 3;
         tv.Height = 5;
-        tv.Style = new () { TabsOnBottom = true };
+        tv.Style = new () { TabsSide = TabSide.Bottom };
         tv.ApplyStyleChanges ();
         tv.Layout ();
 
@@ -1093,7 +1093,7 @@ public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width4 ()
         TabView tv = GetTabView (out _, out _);
         tv.Width = 4;
         tv.Height = 5;
-        tv.Style = new () { TabsOnBottom = true };
+        tv.Style = new () { TabsSide = TabSide.Bottom };
         tv.ApplyStyleChanges ();
         tv.Layout ();
 
@@ -1117,7 +1117,7 @@ public void ShowTopLine_True_TabsOnBottom_True_TestThinTabView_WithLongNames ()
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 10;
         tv.Height = 5;
-        tv.Style = new () { TabsOnBottom = true };
+        tv.Style = new () { TabsSide = TabSide.Bottom };
         tv.ApplyStyleChanges ();
         tv.Layout ();
 
@@ -1199,7 +1199,7 @@ public void ShowTopLine_True_TabsOnBottom_True_With_Unicode ()
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 20;
         tv.Height = 5;
-        tv.Style = new () { TabsOnBottom = true };
+        tv.Style = new () { TabsSide = TabSide.Bottom };
         tv.ApplyStyleChanges ();
 
         tab1.DisplayText = "Tab0";
@@ -1381,7 +1381,7 @@ public void Add_Three_TabsOnBottom_ChangesTab ()
 
         tv.Width = 20;
         tv.Height = 5;
-        tv.Style = new () { TabsOnBottom = true };
+        tv.Style = new () { TabsSide = TabSide.Bottom };
         tv.ApplyStyleChanges ();
 
         tv.Layout ();

From 6dd1016d4c548f6ca511d54bada17ece04656e11 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Mon, 25 Nov 2024 22:18:28 +0000
Subject: [PATCH 02/18] Rename to ShowInitialLine.

---
 Terminal.Gui/Views/TabView/TabRow.cs   | 22 +++++++++++-----------
 Terminal.Gui/Views/TabView/TabStyle.cs | 12 ++++++++----
 Terminal.Gui/Views/TabView/TabView.cs  |  8 ++++----
 UICatalog/Scenarios/TabViewExample.cs  |  2 +-
 UnitTests/Views/TabViewTests.cs        | 12 ++++++------
 5 files changed, 30 insertions(+), 26 deletions(-)

diff --git a/Terminal.Gui/Views/TabView/TabRow.cs b/Terminal.Gui/Views/TabView/TabRow.cs
index ffff8ab4d8..0ee4f2b805 100644
--- a/Terminal.Gui/Views/TabView/TabRow.cs
+++ b/Terminal.Gui/Views/TabView/TabRow.cs
@@ -149,7 +149,7 @@ private void RenderTabLineCanvas ()
         {
             View tab = tabLocations [i];
             Rectangle vts = tab.ViewportToScreen (tab.Viewport);
-            int selectedOffset = _host.Style.ShowTopLine && tabLocations [i] == _host.SelectedTab ? 0 : 1;
+            int selectedOffset = _host.Style.ShowInitialLine && tabLocations [i] == _host.SelectedTab ? 0 : 1;
 
             if (tabLocations [i] == _host.SelectedTab)
             {
@@ -233,7 +233,7 @@ private void RenderTabLineCanvas ()
                             throw new ArgumentOutOfRangeException ();
                     }
 
-                    if (_host.Style.ShowTopLine)
+                    if (_host.Style.ShowInitialLine)
                     {
                         switch (_host.Style.TabsSide)
                         {
@@ -283,7 +283,7 @@ private void RenderTabLineCanvas ()
 
                 if (i < tabLocations.Length - 1)
                 {
-                    if (_host.Style.ShowTopLine)
+                    if (_host.Style.ShowInitialLine)
                     {
                         switch (_host.Style.TabsSide)
                         {
@@ -382,7 +382,7 @@ private void RenderTabLineCanvas ()
                     switch (_host.Style.TabsSide)
                     {
                         case TabSide.Top:
-                            if (_host.Style.ShowTopLine)
+                            if (_host.Style.ShowInitialLine)
                             {
                                 // ULCorner
                                 lc.AddLine (
@@ -417,7 +417,7 @@ private void RenderTabLineCanvas ()
 
                             break;
                         case TabSide.Bottom:
-                            if (_host.Style.ShowTopLine)
+                            if (_host.Style.ShowInitialLine)
                             {
                                 // LLCorner
                                 lc.AddLine (
@@ -461,7 +461,7 @@ private void RenderTabLineCanvas ()
                 }
                 else if (i > 0)
                 {
-                    if (_host.Style.ShowTopLine || _host.Style.TabsSide == TabSide.Bottom)
+                    if (_host.Style.ShowInitialLine || _host.Style.TabsSide == TabSide.Bottom)
                     {
                         // Upper left tee
                         lc.AddLine (
@@ -497,7 +497,7 @@ private void RenderTabLineCanvas ()
             }
             else if (i < tabLocations.Length - 1)
             {
-                if (_host.Style.ShowTopLine)
+                if (_host.Style.ShowInitialLine)
                 {
                     // Upper right tee
                     lc.AddLine (
@@ -515,7 +515,7 @@ private void RenderTabLineCanvas ()
                                );
                 }
 
-                if (_host.Style.ShowTopLine || _host.Style.TabsSide == TabSide.Top)
+                if (_host.Style.ShowInitialLine || _host.Style.TabsSide == TabSide.Top)
                 {
                     // Lower right tee
                     lc.AddLine (
@@ -649,7 +649,7 @@ private void RenderTabLineCanvas ()
             {
                 var arrowOffset = 1;
 
-                int lastSelectedTab = !_host.Style.ShowTopLine && i == selectedTab ? 1 :
+                int lastSelectedTab = !_host.Style.ShowInitialLine && i == selectedTab ? 1 :
                                       _host.Style.TabsSide == TabSide.Bottom ? 1 : 0;
                 Rectangle tabsBarVts = ViewportToScreen (Viewport);
                 int lineLength = tabsBarVts.Right - vts.Right;
@@ -774,7 +774,7 @@ private int GetUnderlineYPosition ()
             return 0;
         }
 
-        return _host.Style.ShowTopLine ? 2 : 1;
+        return _host.Style.ShowInitialLine ? 2 : 1;
     }
 
     /// <summary>Renders the line with the tab names in it.</summary>
@@ -786,7 +786,7 @@ private void RenderTabLine ()
         }
 
         View? selected = null;
-        int topLine = _host.Style.ShowTopLine ? 1 : 0;
+        int topLine = _host.Style.ShowInitialLine ? 1 : 0;
 
         foreach (Tab toRender in _host._tabLocations)
         {
diff --git a/Terminal.Gui/Views/TabView/TabStyle.cs b/Terminal.Gui/Views/TabView/TabStyle.cs
index c6734260c9..900b882631 100644
--- a/Terminal.Gui/Views/TabView/TabStyle.cs
+++ b/Terminal.Gui/Views/TabView/TabStyle.cs
@@ -8,11 +8,15 @@ public class TabStyle
     public bool ShowBorder { get; set; } = true;
 
     /// <summary>
-    ///     True to show the top lip of tabs.  False to directly begin with tab text during rendering.  When true header
-    ///     line occupies 3 rows, when false only 2. Defaults to true.
-    ///     <para>When <see cref="TabsSide"/> is enabled this instead applies to the bottommost line of the control</para>
+    ///     True to show the top lip of tabs.  False to directly begin with tab text during rendering. Defaults to true.
+    ///     When true and <see cref="TabSide.Top"/> or <see cref="TabSide.Bottom"/>, header
+    ///     line occupies 3 rows, when false only 2.
+    ///     <para>When <see cref="TabSide.Bottom"/> is enabled this instead applies to the bottommost line of the control</para>
+    ///     When true and <see cref="TabSide.Left"/> or <see cref="TabSide.Right"/>, header
+    ///     line occupies 1 more column, when false 1 column less.
+    ///     <para>When <see cref="TabSide.Right"/> is enabled this instead applies to the rightmost column of the control</para>
     /// </summary>
-    public bool ShowTopLine { get; set; } = true;
+    public bool ShowInitialLine { get; set; } = true;
 
     /// <summary>Gets or sets the tabs side to render.</summary>
     public TabSide TabsSide { get; set; }
diff --git a/Terminal.Gui/Views/TabView/TabView.cs b/Terminal.Gui/Views/TabView/TabView.cs
index fe856451c4..fe67db4006 100644
--- a/Terminal.Gui/Views/TabView/TabView.cs
+++ b/Terminal.Gui/Views/TabView/TabView.cs
@@ -478,7 +478,7 @@ internal IEnumerable<Tab> CalculateViewport (Rectangle bounds)
             long maxWidth = Math.Max (0, Math.Min (bounds.Width - 3, MaxTabTextWidth));
 
             tab.Width = 2;
-            tab.Height = Style.ShowTopLine ? 3 : 2;
+            tab.Height = Style.ShowInitialLine ? 3 : 2;
 
             // if tab view is width <= 3 don't render any tabs
             if (maxWidth == 0)
@@ -503,7 +503,7 @@ internal IEnumerable<Tab> CalculateViewport (Rectangle bounds)
             }
 
             tab.Width = Math.Max (tabTextWidth + 2, 1);
-            tab.Height = Style.ShowTopLine ? 3 : 2;
+            tab.Height = Style.ShowInitialLine ? 3 : 2;
 
             // if there is not enough space for this tab
             if (i + tabTextWidth >= bounds.Width)
@@ -536,7 +536,7 @@ internal IEnumerable<Tab> CalculateViewport (Rectangle bounds)
     }
 
     /// <summary>
-    ///     Returns the number of rows occupied by rendering the tabs, this depends on <see cref="TabStyle.ShowTopLine"/>
+    ///     Returns the number of rows occupied by rendering the tabs, this depends on <see cref="TabStyle.ShowInitialLine"/>
     ///     and can be 0 (e.g. if <see cref="TabStyle.TabsSide"/> and you ask for <paramref name="top"/>).
     /// </summary>
     /// <param name="top">True to measure the space required at the top of the control, false to measure space at the bottom.</param>
@@ -554,7 +554,7 @@ private int GetTabHeight (bool top)
             return 0;
         }
 
-        return Style.ShowTopLine ? 3 : 2;
+        return Style.ShowInitialLine ? 3 : 2;
     }
 
     internal void Tab_MouseClick (object sender, MouseEventArgs e)
diff --git a/UICatalog/Scenarios/TabViewExample.cs b/UICatalog/Scenarios/TabViewExample.cs
index b3f896e2e6..1d107aee97 100644
--- a/UICatalog/Scenarios/TabViewExample.cs
+++ b/UICatalog/Scenarios/TabViewExample.cs
@@ -306,7 +306,7 @@ private void ShowTopLine ()
     {
         _miShowTopLine.Checked = !_miShowTopLine.Checked;
 
-        _tabView.Style.ShowTopLine = (bool)_miShowTopLine.Checked;
+        _tabView.Style.ShowInitialLine = (bool)_miShowTopLine.Checked;
         _tabView.ApplyStyleChanges ();
     }
 }
diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs
index 8ffa49c2e8..d97f8e73ab 100644
--- a/UnitTests/Views/TabViewTests.cs
+++ b/UnitTests/Views/TabViewTests.cs
@@ -589,7 +589,7 @@ public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width3 ()
         TabView tv = GetTabView (out _, out _);
         tv.Width = 3;
         tv.Height = 5;
-        tv.Style = new () { ShowTopLine = false };
+        tv.Style = new () { ShowInitialLine = false };
         tv.ApplyStyleChanges ();
         tv.Layout ();
 
@@ -613,7 +613,7 @@ public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width4 ()
         TabView tv = GetTabView (out _, out _);
         tv.Width = 4;
         tv.Height = 5;
-        tv.Style = new () { ShowTopLine = false };
+        tv.Style = new () { ShowInitialLine = false };
         tv.ApplyStyleChanges ();
         tv.Layout ();
 
@@ -637,7 +637,7 @@ public void ShowTopLine_False_TabsOnBottom_False_TestThinTabView_WithLongNames (
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 10;
         tv.Height = 5;
-        tv.Style = new () { ShowTopLine = false };
+        tv.Style = new () { ShowInitialLine = false };
         tv.ApplyStyleChanges ();
 
         // Test two tab names that fit
@@ -736,7 +736,7 @@ public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width3 ()
         TabView tv = GetTabView (out _, out _);
         tv.Width = 3;
         tv.Height = 5;
-        tv.Style = new () { ShowTopLine = false, TabsSide = TabSide.Bottom };
+        tv.Style = new () { ShowInitialLine = false, TabsSide = TabSide.Bottom };
         tv.ApplyStyleChanges ();
         tv.Layout ();
 
@@ -760,7 +760,7 @@ public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width4 ()
         TabView tv = GetTabView (out _, out _);
         tv.Width = 4;
         tv.Height = 5;
-        tv.Style = new () { ShowTopLine = false, TabsSide = TabSide.Bottom };
+        tv.Style = new () { ShowInitialLine = false, TabsSide = TabSide.Bottom };
         tv.ApplyStyleChanges ();
         tv.Layout ();
 
@@ -784,7 +784,7 @@ public void ShowTopLine_False_TabsOnBottom_True_TestThinTabView_WithLongNames ()
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 10;
         tv.Height = 5;
-        tv.Style = new () { ShowTopLine = false, TabsSide = TabSide.Bottom };
+        tv.Style = new () { ShowInitialLine = false, TabsSide = TabSide.Bottom };
         tv.ApplyStyleChanges ();
         tv.Layout ();
 

From 58e929df33da6a07e84633b43a00684b3047b80c Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Tue, 26 Nov 2024 13:35:33 +0000
Subject: [PATCH 03/18] Replace ShowTopLine with ShowInitialLine.

---
 UnitTests/Views/TabViewTests.cs | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs
index d97f8e73ab..f6bda567c4 100644
--- a/UnitTests/Views/TabViewTests.cs
+++ b/UnitTests/Views/TabViewTests.cs
@@ -584,7 +584,7 @@ public void SelectedTabChanged_Called ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width3 ()
+    public void ShowInitialLine_False_TabsOnBottom_False_TestTabView_Width3 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 3;
@@ -608,7 +608,7 @@ public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width3 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width4 ()
+    public void ShowInitialLine_False_TabsOnBottom_False_TestTabView_Width4 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 4;
@@ -632,7 +632,7 @@ public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width4 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_False_TabsOnBottom_False_TestThinTabView_WithLongNames ()
+    public void ShowInitialLine_False_TabsOnBottom_False_TestThinTabView_WithLongNames ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 10;
@@ -731,7 +731,7 @@ public void ShowTopLine_False_TabsOnBottom_False_TestThinTabView_WithLongNames (
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width3 ()
+    public void ShowInitialLine_False_TabsOnBottom_True_TestTabView_Width3 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 3;
@@ -755,7 +755,7 @@ public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width3 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width4 ()
+    public void ShowInitialLine_False_TabsOnBottom_True_TestTabView_Width4 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 4;
@@ -779,7 +779,7 @@ public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width4 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_False_TabsOnBottom_True_TestThinTabView_WithLongNames ()
+    public void ShowInitialLine_False_TabsOnBottom_True_TestThinTabView_WithLongNames ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 10;
@@ -880,7 +880,7 @@ public void ShowTopLine_False_TabsOnBottom_True_TestThinTabView_WithLongNames ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_True_TabsOnBottom_False_TestTabView_Width3 ()
+    public void ShowInitialLine_True_TabsOnBottom_False_TestTabView_Width3 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 3;
@@ -902,7 +902,7 @@ public void ShowTopLine_True_TabsOnBottom_False_TestTabView_Width3 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_True_TabsOnBottom_False_TestTabView_Width4 ()
+    public void ShowInitialLine_True_TabsOnBottom_False_TestTabView_Width4 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 4;
@@ -925,7 +925,7 @@ public void ShowTopLine_True_TabsOnBottom_False_TestTabView_Width4 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_True_TabsOnBottom_False_TestThinTabView_WithLongNames ()
+    public void ShowInitialLine_True_TabsOnBottom_False_TestThinTabView_WithLongNames ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 10;
@@ -1022,7 +1022,7 @@ public void ShowTopLine_True_TabsOnBottom_False_TestThinTabView_WithLongNames ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_True_TabsOnBottom_False_With_Unicode ()
+    public void ShowInitialLine_True_TabsOnBottom_False_With_Unicode ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 20;
@@ -1064,7 +1064,7 @@ public void ShowTopLine_True_TabsOnBottom_False_With_Unicode ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width3 ()
+    public void ShowInitialLine_True_TabsOnBottom_True_TestTabView_Width3 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 3;
@@ -1088,7 +1088,7 @@ public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width3 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width4 ()
+    public void ShowInitialLine_True_TabsOnBottom_True_TestTabView_Width4 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 4;
@@ -1112,7 +1112,7 @@ public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width4 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_True_TabsOnBottom_True_TestThinTabView_WithLongNames ()
+    public void ShowInitialLine_True_TabsOnBottom_True_TestThinTabView_WithLongNames ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 10;
@@ -1194,7 +1194,7 @@ public void ShowTopLine_True_TabsOnBottom_True_TestThinTabView_WithLongNames ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowTopLine_True_TabsOnBottom_True_With_Unicode ()
+    public void ShowInitialLine_True_TabsOnBottom_True_With_Unicode ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 20;

From a1d14136150e0e2ee63ae73854c216b72df02382 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Tue, 26 Nov 2024 13:48:47 +0000
Subject: [PATCH 04/18] Replace TabsOnBottom_False with TabsSide_Top.

---
 UnitTests/Views/TabViewTests.cs | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs
index f6bda567c4..5768ac832c 100644
--- a/UnitTests/Views/TabViewTests.cs
+++ b/UnitTests/Views/TabViewTests.cs
@@ -584,7 +584,7 @@ public void SelectedTabChanged_Called ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_False_TabsOnBottom_False_TestTabView_Width3 ()
+    public void ShowInitialLine_False_TabsSide_Top_TestTabView_Width3 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 3;
@@ -608,7 +608,7 @@ public void ShowInitialLine_False_TabsOnBottom_False_TestTabView_Width3 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_False_TabsOnBottom_False_TestTabView_Width4 ()
+    public void ShowInitialLine_False_TabsSide_Top_TestTabView_Width4 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 4;
@@ -632,7 +632,7 @@ public void ShowInitialLine_False_TabsOnBottom_False_TestTabView_Width4 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_False_TabsOnBottom_False_TestThinTabView_WithLongNames ()
+    public void ShowInitialLine_False_TabsSide_Top_TestThinTabView_WithLongNames ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 10;
@@ -880,7 +880,7 @@ public void ShowInitialLine_False_TabsOnBottom_True_TestThinTabView_WithLongName
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_True_TabsOnBottom_False_TestTabView_Width3 ()
+    public void ShowInitialLine_True_TabsSide_Top_TestTabView_Width3 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 3;
@@ -902,7 +902,7 @@ public void ShowInitialLine_True_TabsOnBottom_False_TestTabView_Width3 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_True_TabsOnBottom_False_TestTabView_Width4 ()
+    public void ShowInitialLine_True_TabsSide_Top_TestTabView_Width4 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 4;
@@ -925,7 +925,7 @@ public void ShowInitialLine_True_TabsOnBottom_False_TestTabView_Width4 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_True_TabsOnBottom_False_TestThinTabView_WithLongNames ()
+    public void ShowInitialLine_True_TabsSide_Top_TestThinTabView_WithLongNames ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 10;
@@ -1022,7 +1022,7 @@ public void ShowInitialLine_True_TabsOnBottom_False_TestThinTabView_WithLongName
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_True_TabsOnBottom_False_With_Unicode ()
+    public void ShowInitialLine_True_TabsSide_Top_With_Unicode ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 20;

From 76332b262d87867058b98773e0ad98f57d8c64a4 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Tue, 26 Nov 2024 13:50:52 +0000
Subject: [PATCH 05/18] Replace TabsOnBottom_True with TabsSide_Bottom.

---
 UnitTests/Views/TabViewTests.cs | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs
index 5768ac832c..457291b966 100644
--- a/UnitTests/Views/TabViewTests.cs
+++ b/UnitTests/Views/TabViewTests.cs
@@ -731,7 +731,7 @@ public void ShowInitialLine_False_TabsSide_Top_TestThinTabView_WithLongNames ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_False_TabsOnBottom_True_TestTabView_Width3 ()
+    public void ShowInitialLine_False_TabsSide_Bottom_TestTabView_Width3 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 3;
@@ -755,7 +755,7 @@ public void ShowInitialLine_False_TabsOnBottom_True_TestTabView_Width3 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_False_TabsOnBottom_True_TestTabView_Width4 ()
+    public void ShowInitialLine_False_TabsSide_Bottom_TestTabView_Width4 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 4;
@@ -779,7 +779,7 @@ public void ShowInitialLine_False_TabsOnBottom_True_TestTabView_Width4 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_False_TabsOnBottom_True_TestThinTabView_WithLongNames ()
+    public void ShowInitialLine_False_TabsSide_Bottom_TestThinTabView_WithLongNames ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 10;
@@ -1064,7 +1064,7 @@ public void ShowInitialLine_True_TabsSide_Top_With_Unicode ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_True_TabsOnBottom_True_TestTabView_Width3 ()
+    public void ShowInitialLine_True_TabsSide_Bottom_TestTabView_Width3 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 3;
@@ -1088,7 +1088,7 @@ public void ShowInitialLine_True_TabsOnBottom_True_TestTabView_Width3 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_True_TabsOnBottom_True_TestTabView_Width4 ()
+    public void ShowInitialLine_True_TabsSide_Bottom_TestTabView_Width4 ()
     {
         TabView tv = GetTabView (out _, out _);
         tv.Width = 4;
@@ -1112,7 +1112,7 @@ public void ShowInitialLine_True_TabsOnBottom_True_TestTabView_Width4 ()
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_True_TabsOnBottom_True_TestThinTabView_WithLongNames ()
+    public void ShowInitialLine_True_TabsSide_Bottom_TestThinTabView_WithLongNames ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 10;
@@ -1194,7 +1194,7 @@ public void ShowInitialLine_True_TabsOnBottom_True_TestThinTabView_WithLongNames
 
     [Fact]
     [SetupFakeDriver]
-    public void ShowInitialLine_True_TabsOnBottom_True_With_Unicode ()
+    public void ShowInitialLine_True_TabsSide_Bottom_With_Unicode ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         tv.Width = 20;

From b2b32889eed326ec63aae700d36d85c62dd7ae60 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Tue, 26 Nov 2024 17:37:25 +0000
Subject: [PATCH 06/18] Fix bug that was passing the TabRow.Viewport instead of
 the TabView.Viewport.

---
 Terminal.Gui/Views/TabView/TabRow.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Terminal.Gui/Views/TabView/TabRow.cs b/Terminal.Gui/Views/TabView/TabRow.cs
index 0ee4f2b805..f421e4c106 100644
--- a/Terminal.Gui/Views/TabView/TabRow.cs
+++ b/Terminal.Gui/Views/TabView/TabRow.cs
@@ -117,7 +117,7 @@ protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocus
     /// <inheritdoc/>
     protected override void OnSubviewLayout (LayoutEventArgs args)
     {
-        _host._tabLocations = _host.CalculateViewport (Viewport).ToArray ();
+        _host._tabLocations = _host.CalculateViewport (_host.Viewport).ToArray ();
 
         RenderTabLine ();
 

From 7d6bb3718dc466dbe13c18d381b73e5f4a8c0585 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Wed, 27 Nov 2024 21:35:34 +0000
Subject: [PATCH 07/18] Add DisplayTextChanged event.

---
 Terminal.Gui/Views/TabView/Tab.cs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Terminal.Gui/Views/TabView/Tab.cs b/Terminal.Gui/Views/TabView/Tab.cs
index 52fb0bdf9d..8451b74136 100644
--- a/Terminal.Gui/Views/TabView/Tab.cs
+++ b/Terminal.Gui/Views/TabView/Tab.cs
@@ -22,6 +22,7 @@ public string DisplayText
         set
         {
             _displayText = value;
+            DisplayTextChanged?.Invoke (this, EventArgs.Empty);
             SetNeedsLayout ();
         }
     }
@@ -29,4 +30,9 @@ public string DisplayText
     /// <summary>The control to display when the tab is selected.</summary>
     /// <value></value>
     public View? View { get; set; }
+
+    /// <summary>
+    /// Raised when <see cref="DisplayText"/> changed.
+    /// </summary>
+    public event EventHandler? DisplayTextChanged;
 }

From 97246256ed5cf46255a8c0e3bd8d04ae11bc1a17 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Wed, 27 Nov 2024 21:37:43 +0000
Subject: [PATCH 08/18] Fix unit test. Now F6 focus the select tab.

---
 UnitTests/Views/TabViewTests.cs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs
index 457291b966..4cced1ff5d 100644
--- a/UnitTests/Views/TabViewTests.cs
+++ b/UnitTests/Views/TabViewTests.cs
@@ -378,8 +378,8 @@ public void ProcessKey_Down_Up_Right_Left_Home_End_PageDown_PageUp_F6 ()
         Assert.Equal (tv.MostFocused, top.Focused.MostFocused);
         Assert.Equal (tv.SelectedTab.View, top.Focused.MostFocused);
 
-        // Press the cursor up key to focus the selected tab
-        Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
+        // Press F6 key to focus the selected tab
+        Assert.True (Application.RaiseKeyDownEvent (Key.F6));
         Application.LayoutAndDraw ();
 
         // Is the selected tab focused

From fa1bdae84d9faaf9a3a7e17f585509347fc91441 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Thu, 28 Nov 2024 00:06:11 +0000
Subject: [PATCH 09/18] Add Command.Up and Command.Down.

---
 Terminal.Gui/Views/TabView/TabRow.cs  |  1 +
 Terminal.Gui/Views/TabView/TabView.cs | 48 ++++++++++++++++++++++++---
 2 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/Terminal.Gui/Views/TabView/TabRow.cs b/Terminal.Gui/Views/TabView/TabRow.cs
index f421e4c106..e9aecf7727 100644
--- a/Terminal.Gui/Views/TabView/TabRow.cs
+++ b/Terminal.Gui/Views/TabView/TabRow.cs
@@ -13,6 +13,7 @@ public TabRow (TabView host)
         Id = "tabRow";
 
         CanFocus = true;
+        // Because TabRow has focusable subviews, it must be a TabGroup
         TabStop = TabBehavior.TabGroup;
         Width = Dim.Fill ();
 
diff --git a/Terminal.Gui/Views/TabView/TabView.cs b/Terminal.Gui/Views/TabView/TabView.cs
index fe67db4006..3da5baf232 100644
--- a/Terminal.Gui/Views/TabView/TabView.cs
+++ b/Terminal.Gui/Views/TabView/TabView.cs
@@ -27,8 +27,8 @@ public class TabView : View
     public TabView ()
     {
         CanFocus = true;
-        TabStop = TabBehavior.TabStop; // Because TabView has focusable subviews, it must be a TabGroup
-        _tabsBar = new TabRow (this);
+        TabStop = TabBehavior.TabStop;
+        _tabsBar = new (this);
         _containerView = new ();
         ApplyStyleChanges ();
 
@@ -36,9 +36,45 @@ public TabView ()
         base.Add (_containerView);
 
         // Things this view knows how to do
-        AddCommand (Command.Left, () => SwitchTabBy (-1));
-
-        AddCommand (Command.Right, () => SwitchTabBy (1));
+        AddCommand (Command.Left, () =>
+                                  {
+                                      if (Style.TabsSide is TabSide.Top or TabSide.Bottom)
+                                      {
+                                          return SwitchTabBy (-1);
+                                      }
+
+                                      return false;
+                                  });
+
+        AddCommand (Command.Right, () =>
+                                   {
+                                       if (Style.TabsSide is TabSide.Top or TabSide.Bottom)
+                                       {
+                                           return SwitchTabBy (1);
+                                       }
+
+                                       return false;
+                                   });
+
+        AddCommand (Command.Up, () =>
+                                  {
+                                      if (Style.TabsSide is TabSide.Left or TabSide.Right)
+                                      {
+                                          return SwitchTabBy (-1);
+                                      }
+
+                                      return false;
+                                  });
+
+        AddCommand (Command.Down, () =>
+                                   {
+                                       if (Style.TabsSide is TabSide.Left or TabSide.Right)
+                                       {
+                                           return SwitchTabBy (1);
+                                       }
+
+                                       return false;
+                                   });
 
         AddCommand (
                     Command.LeftStart,
@@ -87,6 +123,8 @@ public TabView ()
         // Default keybindings for this view
         KeyBindings.Add (Key.CursorLeft, Command.Left);
         KeyBindings.Add (Key.CursorRight, Command.Right);
+        KeyBindings.Add (Key.CursorUp, Command.Up);
+        KeyBindings.Add (Key.CursorDown, Command.Down);
         KeyBindings.Add (Key.Home, Command.LeftStart);
         KeyBindings.Add (Key.End, Command.RightEnd);
         KeyBindings.Add (Key.PageDown, Command.PageDown);

From 427d1183d56456bec20942a8a546e5df7a520c8f Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Thu, 28 Nov 2024 00:19:40 +0000
Subject: [PATCH 10/18] Starting TabSide.Left feature.

---
 Terminal.Gui/Views/TabView/TabRow.cs  | 111 ++------
 Terminal.Gui/Views/TabView/TabView.cs | 376 +++++++++++++++++++++-----
 2 files changed, 321 insertions(+), 166 deletions(-)

diff --git a/Terminal.Gui/Views/TabView/TabRow.cs b/Terminal.Gui/Views/TabView/TabRow.cs
index e9aecf7727..26ef662ae8 100644
--- a/Terminal.Gui/Views/TabView/TabRow.cs
+++ b/Terminal.Gui/Views/TabView/TabRow.cs
@@ -40,6 +40,14 @@ public TabRow (TabView host)
         Add (_rightScrollIndicator, _leftScrollIndicator);
     }
 
+    /// <inheritdoc />
+    public override void EndInit ()
+    {
+        _host._tabLocations = _host.CalculateViewport (Viewport);
+
+        base.EndInit ();
+    }
+
     protected override bool OnMouseEvent (MouseEventArgs me)
     {
         View? parent = me.View is Adornment adornment ? adornment.Parent : me.View;
@@ -118,9 +126,16 @@ protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocus
     /// <inheritdoc/>
     protected override void OnSubviewLayout (LayoutEventArgs args)
     {
-        _host._tabLocations = _host.CalculateViewport (_host.Viewport).ToArray ();
+        if (_host._tabLocations is null)
+        {
+            return;
+        }
 
-        RenderTabLine ();
+        if (_host is { SelectedTab: { }, _tabLocations: { } } && !_host._tabLocations!.Contains (_host.SelectedTab))
+        {
+            _host.SelectedTab = _host._tabLocations [0];
+            Application.Invoke (() => _host.SetNeedsLayout ());
+        }
 
         RenderUnderline ();
 
@@ -765,7 +780,7 @@ private void RenderTabLineCanvas ()
             }
         }
 
-        _host.LineCanvas.Merge (lc);
+        LineCanvas.Merge (lc);
     }
 
     private int GetUnderlineYPosition ()
@@ -778,96 +793,6 @@ private int GetUnderlineYPosition ()
         return _host.Style.ShowInitialLine ? 2 : 1;
     }
 
-    /// <summary>Renders the line with the tab names in it.</summary>
-    private void RenderTabLine ()
-    {
-        if (_host._tabLocations is null)
-        {
-            return;
-        }
-
-        View? selected = null;
-        int topLine = _host.Style.ShowInitialLine ? 1 : 0;
-
-        foreach (Tab toRender in _host._tabLocations)
-        {
-            Tab tab = toRender;
-
-            if (toRender == _host.SelectedTab)
-            {
-                selected = tab;
-
-                switch (_host.Style.TabsSide)
-                {
-                    case TabSide.Top:
-                        tab.Border!.Thickness = new (1, topLine, 1, 0);
-                        tab.Margin!.Thickness = new (0, 0, 0, topLine);
-
-                        break;
-                    case TabSide.Bottom:
-                        tab.Border!.Thickness = new (1, 0, 1, topLine);
-                        tab.Margin!.Thickness = new (0, 1, 0, 0);
-
-                        break;
-                    case TabSide.Left:
-                        break;
-                    case TabSide.Right:
-                        break;
-                    default:
-                        throw new ArgumentOutOfRangeException ();
-                }
-            }
-            else if (selected is null)
-            {
-                switch (_host.Style.TabsSide)
-                {
-                    case TabSide.Top:
-                        tab.Border!.Thickness = new (1, topLine, 1, 1);
-                        tab.Margin!.Thickness = new (0, 0, 0, 0);
-
-                        break;
-                    case TabSide.Bottom:
-                        tab.Border!.Thickness = new (1, 1, 1, topLine);
-                        tab.Margin!.Thickness = new (0, 0, 0, 0);
-
-                        break;
-                    case TabSide.Left:
-                        break;
-                    case TabSide.Right:
-                        break;
-                    default:
-                        throw new ArgumentOutOfRangeException ();
-                }
-            }
-            else
-            {
-                switch (_host.Style.TabsSide)
-                {
-                    case TabSide.Top:
-                        tab.Border!.Thickness = new (1, topLine, 1, 1);
-                        tab.Margin!.Thickness = new (0, 0, 0, 0);
-
-                        break;
-                    case TabSide.Bottom:
-                        tab.Border!.Thickness = new (1, 1, 1, topLine);
-                        tab.Margin!.Thickness = new (0, 0, 0, 0);
-
-                        break;
-                    case TabSide.Left:
-                        break;
-                    case TabSide.Right:
-                        break;
-                    default:
-                        throw new ArgumentOutOfRangeException ();
-                }
-            }
-
-            // Ensures updating TextFormatter constrains
-            tab.TextFormatter.ConstrainToWidth = tab.GetContentSize ().Width;
-            tab.TextFormatter.ConstrainToHeight = tab.GetContentSize ().Height;
-        }
-    }
-
     /// <summary>Renders the line of the tab that adjoins the content of the tab.</summary>
     private void RenderUnderline ()
     {
diff --git a/Terminal.Gui/Views/TabView/TabView.cs b/Terminal.Gui/Views/TabView/TabView.cs
index 3da5baf232..a136a199c1 100644
--- a/Terminal.Gui/Views/TabView/TabView.cs
+++ b/Terminal.Gui/Views/TabView/TabView.cs
@@ -267,57 +267,71 @@ public void AddTab (Tab tab, bool andSelect)
     /// </summary>
     public void ApplyStyleChanges ()
     {
+        _tabLocations = CalculateViewport (Viewport);
+
         _containerView.BorderStyle = Style.ShowBorder ? LineStyle.Single : LineStyle.None;
         _containerView.Width = Dim.Fill ();
 
-        int tabHeight;
-
         switch (Style.TabsSide)
         {
             case TabSide.Top:
                 // Tabs are along the top
                 if (Style.ShowBorder)
                 {
-                    _containerView.Border!.Thickness = new Thickness (1, 0, 1, 1);
+                    _containerView.Border!.Thickness = new (1, 0, 1, 1);
                 }
 
+                _tabsBar.X = 0;
                 _tabsBar.Y = 0;
+                _tabsBar.Width = Dim.Fill ();
+                _tabsBar.Height = GetTabHeight (true);
 
-                tabHeight = GetTabHeight (true);
-
+                _containerView.X = 0;
                 //move content down to make space for tabs
                 _containerView.Y = Pos.Bottom (_tabsBar);
-
-                // Fill client area leaving space at bottom for border
+                _containerView.Width = Dim.Fill ();
                 _containerView.Height = Dim.Fill ();
 
-                // The top tab should be 2 or 3 rows high and on the top
-
-                _tabsBar.Height = tabHeight;
-
-                // Should be able to just use 0 but switching between top/bottom tabs repeatedly breaks in ValidatePosDim if just using the absolute value 0
-
                 break;
             case TabSide.Bottom:
                 // Tabs are along the bottom so just dodge the border
                 if (Style.ShowBorder)
                 {
-                    _containerView.Border!.Thickness = new Thickness (1, 1, 1, 0);
+                    _containerView.Border!.Thickness = new (1, 1, 1, 0);
                 }
 
-                _containerView.Y = 0;
-
-                tabHeight = GetTabHeight (false);
+                _tabsBar.X = 0;
+                _tabsBar.Width = Dim.Fill ();
+                int tabHeight = GetTabHeight (false);
+                _tabsBar.Height = tabHeight;
 
+                _containerView.X = 0;
+                _containerView.Y = 0;
+                _containerView.Width = Dim.Fill ();
                 // Fill client area leaving space at bottom for tabs
                 _containerView.Height = Dim.Fill (tabHeight);
 
-                _tabsBar.Height = tabHeight;
-
                 _tabsBar.Y = Pos.Bottom (_containerView);
 
                 break;
             case TabSide.Left:
+                // Tabs are along the left
+                if (Style.ShowBorder)
+                {
+                    _containerView.Border!.Thickness = new (0, 1, 1, 1);
+                }
+
+                _tabsBar.X = 0;
+                _tabsBar.Y = 0;
+                _tabsBar.Height = Dim.Fill ();
+
+                //move content right to make space for tabs
+                _containerView.X = Pos.Right (_tabsBar);
+                _containerView.Y = 0;
+                // Fill client area leaving space at left for tabs
+                _containerView.Width = Dim.Fill ();
+                _containerView.Height = Dim.Fill ();
+
                 break;
             case TabSide.Right:
                 break;
@@ -331,7 +345,7 @@ public void ApplyStyleChanges ()
     /// <inheritdoc />
     protected override void OnViewportChanged (DrawEventArgs e)
     {
-        _tabLocations = CalculateViewport (Viewport).ToArray ();
+        _tabLocations = CalculateViewport (Viewport);
 
         base.OnViewportChanged (e);
     }
@@ -345,10 +359,15 @@ public void EnsureSelectedTabIsVisible ()
         }
 
         // if current viewport does not include the selected tab
-        if (!CalculateViewport (Viewport).Any (t => Equals (SelectedTab, t)))
+        if (_tabLocations is null || (_tabLocations is { } && !_tabLocations.Any (t => Equals (SelectedTab, t))))
         {
             // Set scroll offset so the first tab rendered is the
             TabScrollOffset = Math.Max (0, Tabs.IndexOf (SelectedTab));
+            _tabLocations = CalculateViewport (Viewport);
+        }
+        else
+        {
+            RenderTabLine (_tabLocations);
         }
     }
 
@@ -486,81 +505,180 @@ protected virtual void OnSelectedTabChanged (Tab oldTab, Tab newTab)
 
     /// <summary>Returns which tabs to render at each x location.</summary>
     /// <returns></returns>
-    internal IEnumerable<Tab> CalculateViewport (Rectangle bounds)
+    internal Tab []? CalculateViewport (Rectangle bounds)
     {
         UnSetCurrentTabs ();
 
+        List<Tab> tabs = [];
         var i = 1;
         View? prevTab = null;
 
-        // Starting at the first or scrolled to tab
-        foreach (Tab tab in Tabs.Skip (TabScrollOffset))
+        switch (Style.TabsSide)
         {
-            if (prevTab is { })
-            {
-                tab.X = Pos.Right (prevTab) - 1;
-            }
-            else
-            {
-                tab.X = 0;
-            }
+            case TabSide.Top:
+            case TabSide.Bottom:
+                // Starting at the first or scrolled to tab
+                foreach (Tab tab in Tabs.Skip (TabScrollOffset))
+                {
+                    if (prevTab is { })
+                    {
+                        tab.X = Pos.Right (prevTab) - 1;
+                    }
+                    else
+                    {
+                        tab.X = 0;
+                    }
 
-            tab.Y = 0;
+                    tab.Y = 0;
 
-            // while there is space for the tab
-            int tabTextWidth = tab.DisplayText.EnumerateRunes ().Sum (c => c.GetColumns ());
+                    // while there is space for the tab
+                    int tabTextWidth = tab.DisplayText.EnumerateRunes ().Sum (c => c.GetColumns ());
 
-            // 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
-            // or we won't even be able to render a single tab!
-            long maxWidth = Math.Max (0, Math.Min (bounds.Width - 3, MaxTabTextWidth));
+                    // 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
+                    // or we won't even be able to render a single tab!
+                    long maxWidth = Math.Max (0, Math.Min (bounds.Width - 3, MaxTabTextWidth));
 
-            tab.Width = 2;
-            tab.Height = Style.ShowInitialLine ? 3 : 2;
+                    tab.Width = 2;
+                    tab.Height = Style.ShowInitialLine ? 3 : 2;
 
-            // if tab view is width <= 3 don't render any tabs
-            if (maxWidth == 0)
-            {
-                tab.Visible = true;
-                tab.MouseClick += Tab_MouseClick!;
-                tab.Border!.MouseClick += Tab_MouseClick!;
+                    // if tab view is width <= 3 don't render any tabs
+                    if (maxWidth == 0)
+                    {
+                        tab.Visible = true;
+                        tab.MouseClick += Tab_MouseClick!;
+                        tab.Border!.MouseClick += Tab_MouseClick!;
+                        tab.DisplayTextChanged += Tab_DisplayTextChanged;
 
-                yield return tab;
+                        tabs.Add (tab);
 
-                break;
-            }
+                        break;
+                    }
 
-            if (tabTextWidth > maxWidth)
-            {
-                tab.Text = tab.DisplayText.Substring (0, (int)maxWidth);
-                tabTextWidth = (int)maxWidth;
-            }
-            else
-            {
-                tab.Text = tab.DisplayText;
-            }
+                    if (tabTextWidth > maxWidth)
+                    {
+                        tab.Text = tab.DisplayText.Substring (0, (int)maxWidth);
+                        tabTextWidth = (int)maxWidth;
+                    }
+                    else
+                    {
+                        tab.Text = tab.DisplayText;
+                    }
 
-            tab.Width = Math.Max (tabTextWidth + 2, 1);
-            tab.Height = Style.ShowInitialLine ? 3 : 2;
+                    tab.Width = tabTextWidth + 2;
+                    tab.Height = Style.ShowInitialLine ? 3 : 2;
 
-            // if there is not enough space for this tab
-            if (i + tabTextWidth >= bounds.Width)
-            {
-                tab.Visible = false;
+                    // if there is not enough space for this tab
+                    if (i + tabTextWidth >= bounds.Width)
+                    {
+                        tab.Visible = false;
+
+                        break;
+                    }
+
+                    // there is enough space!
+                    tab.Visible = true;
+                    tab.MouseClick += Tab_MouseClick!;
+                    tab.Border!.MouseClick += Tab_MouseClick!;
+                    tab.DisplayTextChanged += Tab_DisplayTextChanged;
+
+                    tabs.Add (tab);
+
+                    prevTab = tab;
+
+                    i += tabTextWidth + 1;
+                }
 
                 break;
-            }
+            case TabSide.Left:
+            case TabSide.Right:
+                int maxColWidth = 0;
+
+                // Starting at the first or scrolled to tab
+                foreach (Tab tab in Tabs.Skip (TabScrollOffset))
+                {
+                    tab.X = 0;
 
-            // there is enough space!
-            tab.Visible = true;
-            tab.MouseClick += Tab_MouseClick!;
-            tab.Border!.MouseClick += Tab_MouseClick!;
+                    if (prevTab is { })
+                    {
+                        tab.Y = Pos.Bottom (prevTab) - 1;
+                    }
+                    else
+                    {
+                        tab.Y = 0;
+                    }
 
-            yield return tab;
+                    // while there is space for the tab
+                    int tabTextWidth = tab.DisplayText.EnumerateRunes ().Sum (c => c.GetColumns ());
 
-            prevTab = tab;
+                    // 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
+                    // or we won't even be able to render a single tab!
+                    long maxWidth = Math.Max (0, Math.Min (bounds.Width - (Style.ShowInitialLine ? 2 : 1), MaxTabTextWidth));
+
+                    // The maximum height to use for the tab. But not more than the height of the view
+                    // or we won't even be able to render a single tab!
+                    int maxHeight = Math.Max (0, Math.Min (bounds.Height - 3, 3));
+
+                    tab.Height = 2;
+
+                    // if tab view is height <= 3 don't render any tabs
+                    if (maxHeight == 0)
+                    {
+                        tab.Width = maxColWidth = Math.Max (Style.ShowInitialLine ? 3 : 2, maxColWidth);
+                        tab.Visible = true;
+                        tab.MouseClick += Tab_MouseClick!;
+                        tab.Border!.MouseClick += Tab_MouseClick!;
+                        tab.DisplayTextChanged += Tab_DisplayTextChanged;
+
+                        tabs.Add (tab);
+
+                        break;
+                    }
+
+                    if (tabTextWidth > maxWidth)
+                    {
+                        tab.Text = tab.DisplayText.Substring (0, (int)maxWidth);
+                        tabTextWidth = (int)maxWidth;
+                    }
+                    else
+                    {
+                        tab.Text = tab.DisplayText;
+                    }
 
-            i += tabTextWidth + 1;
+                    maxColWidth = Math.Max (tabTextWidth + 2, maxColWidth);
+                    tab.Height = 3;
+
+                    // if there is not enough space for this tab
+                    if (i + 1 >= bounds.Height)
+                    {
+                        tab.Visible = false;
+
+                        break;
+                    }
+
+                    // there is enough space!
+                    tab.Visible = true;
+                    tab.MouseClick += Tab_MouseClick!;
+                    tab.Border!.MouseClick += Tab_MouseClick!;
+                    tab.DisplayTextChanged += Tab_DisplayTextChanged;
+
+                    tabs.Add (tab);
+
+                    prevTab = tab;
+
+                    i += 2;
+                }
+
+                foreach (Tab t in tabs)
+                {
+                    t.Width = maxColWidth;
+                }
+                _tabsBar.Width = maxColWidth;
+
+                break;
+            default:
+                throw new ArgumentOutOfRangeException ();
         }
 
         if (TabCanSetFocus ())
@@ -571,6 +689,116 @@ internal IEnumerable<Tab> CalculateViewport (Rectangle bounds)
         {
             SelectedTab?.View?.SetFocus ();
         }
+
+        RenderTabLine (tabs.Count == 0 ? null : tabs.ToArray ());
+
+        SetNeedsLayout ();
+
+        return tabs.Count == 0 ? null : tabs.ToArray ();
+    }
+
+    private void Tab_DisplayTextChanged (object? sender, EventArgs e)
+    {
+        _tabLocations = CalculateViewport (Viewport);
+    }
+
+    /// <summary>Renders the line with the tab names in it.</summary>
+    private void RenderTabLine (Tab []? tabLocations)
+    {
+        if (tabLocations is null)
+        {
+            return;
+        }
+
+        View? selected = null;
+        int topLine = Style.ShowInitialLine ? 1 : 0;
+
+        foreach (Tab toRender in tabLocations)
+        {
+            Tab tab = toRender;
+
+            if (toRender == SelectedTab)
+            {
+                selected = tab;
+
+                switch (Style.TabsSide)
+                {
+                    case TabSide.Top:
+                        tab.Border!.Thickness = new (1, topLine, 1, 0);
+                        tab.Margin!.Thickness = new (0, 0, 0, topLine);
+
+                        break;
+                    case TabSide.Bottom:
+                        tab.Border!.Thickness = new (1, 0, 1, topLine);
+                        tab.Margin!.Thickness = new (0, 1, 0, 0);
+
+                        break;
+                    case TabSide.Left:
+                        tab.Border!.Thickness = new (topLine, 1, 0, 1);
+                        tab.Margin!.Thickness = new (0, 0, topLine, 0);
+
+                        break;
+                    case TabSide.Right:
+                        break;
+                    default:
+                        throw new ArgumentOutOfRangeException ();
+                }
+            }
+            else if (selected is null)
+            {
+                switch (Style.TabsSide)
+                {
+                    case TabSide.Top:
+                        tab.Border!.Thickness = new (1, topLine, 1, 1);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
+
+                        break;
+                    case TabSide.Bottom:
+                        tab.Border!.Thickness = new (1, 1, 1, topLine);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
+
+                        break;
+                    case TabSide.Left:
+                        tab.Border!.Thickness = new (topLine, 1, 1, 1);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
+
+                        break;
+                    case TabSide.Right:
+                        break;
+                    default:
+                        throw new ArgumentOutOfRangeException ();
+                }
+            }
+            else
+            {
+                switch (Style.TabsSide)
+                {
+                    case TabSide.Top:
+                        tab.Border!.Thickness = new (1, topLine, 1, 1);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
+
+                        break;
+                    case TabSide.Bottom:
+                        tab.Border!.Thickness = new (1, 1, 1, topLine);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
+
+                        break;
+                    case TabSide.Left:
+                        tab.Border!.Thickness = new (topLine, 1, 1, 1);
+                        tab.Margin!.Thickness = new (0, 0, 0, 0);
+
+                        break;
+                    case TabSide.Right:
+                        break;
+                    default:
+                        throw new ArgumentOutOfRangeException ();
+                }
+            }
+
+            // Ensures updating TextFormatter constrains
+            tab.TextFormatter.ConstrainToWidth = tab.GetContentSize ().Width;
+            tab.TextFormatter.ConstrainToHeight = tab.GetContentSize ().Height;
+        }
     }
 
     /// <summary>
@@ -613,6 +841,7 @@ private void UnSetCurrentTabs ()
                 {
                     tab.MouseClick -= Tab_MouseClick!;
                     tab.Border!.MouseClick -= Tab_MouseClick!;
+                    tab.DisplayTextChanged -= Tab_DisplayTextChanged;
                     tab.Visible = false;
                 }
             }
@@ -623,6 +852,7 @@ private void UnSetCurrentTabs ()
             {
                 tabToRender.MouseClick -= Tab_MouseClick!;
                 tabToRender.Border!.MouseClick -= Tab_MouseClick!;
+                tabToRender.DisplayTextChanged -= Tab_DisplayTextChanged;
                 tabToRender.Visible = false;
             }
 

From bb0491ed260543332a5e525f823c8dd7f9772574 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Thu, 28 Nov 2024 16:43:48 +0000
Subject: [PATCH 11/18] Add up and down arrows feature.

---
 Terminal.Gui/Views/TabView/TabRow.cs | 127 +++++++++++++++++++--------
 1 file changed, 92 insertions(+), 35 deletions(-)

diff --git a/Terminal.Gui/Views/TabView/TabRow.cs b/Terminal.Gui/Views/TabView/TabRow.cs
index 26ef662ae8..31aa909e19 100644
--- a/Terminal.Gui/Views/TabView/TabRow.cs
+++ b/Terminal.Gui/Views/TabView/TabRow.cs
@@ -4,8 +4,8 @@ namespace Terminal.Gui;
 internal class TabRow : View
 {
     private readonly TabView _host;
-    private readonly View _leftScrollIndicator;
-    private readonly View _rightScrollIndicator;
+    private readonly View _leftUpScrollIndicator;
+    private readonly View _rightDownScrollIndicator;
 
     public TabRow (TabView host)
     {
@@ -17,27 +17,25 @@ public TabRow (TabView host)
         TabStop = TabBehavior.TabGroup;
         Width = Dim.Fill ();
 
-        _rightScrollIndicator = new View
+        _rightDownScrollIndicator = new View
         {
-            Id = "rightScrollIndicator",
+            Id = "rightDownScrollIndicator",
             Width = 1,
             Height = 1,
-            Visible = false,
-            Text = Glyphs.RightArrow.ToString ()
+            Visible = false
         };
-        _rightScrollIndicator.MouseClick += _host.Tab_MouseClick!;
+        _rightDownScrollIndicator.MouseClick += _host.Tab_MouseClick!;
 
-        _leftScrollIndicator = new View
+        _leftUpScrollIndicator = new View
         {
-            Id = "leftScrollIndicator",
+            Id = "leftUpScrollIndicator",
             Width = 1,
             Height = 1,
-            Visible = false,
-            Text = Glyphs.LeftArrow.ToString ()
+            Visible = false
         };
-        _leftScrollIndicator.MouseClick += _host.Tab_MouseClick!;
+        _leftUpScrollIndicator.MouseClick += _host.Tab_MouseClick!;
 
-        Add (_rightScrollIndicator, _leftScrollIndicator);
+        Add (_rightDownScrollIndicator, _leftUpScrollIndicator);
     }
 
     /// <inheritdoc />
@@ -83,11 +81,11 @@ protected override bool OnMouseEvent (MouseEventArgs me)
         {
             var scrollIndicatorHit = 0;
 
-            if (me.View is { Id: "rightScrollIndicator" } || me.Flags.HasFlag (MouseFlags.WheeledDown) || me.Flags.HasFlag (MouseFlags.WheeledRight))
+            if (me.View is { Id: "rightDownScrollIndicator" } || me.Flags.HasFlag (MouseFlags.WheeledDown) || me.Flags.HasFlag (MouseFlags.WheeledRight))
             {
                 scrollIndicatorHit = 1;
             }
-            else if (me.View is { Id: "leftScrollIndicator" } || me.Flags.HasFlag (MouseFlags.WheeledUp) || me.Flags.HasFlag (MouseFlags.WheeledLeft))
+            else if (me.View is { Id: "leftUpScrollIndicator" } || me.Flags.HasFlag (MouseFlags.WheeledUp) || me.Flags.HasFlag (MouseFlags.WheeledLeft))
             {
                 scrollIndicatorHit = -1;
             }
@@ -671,7 +669,7 @@ private void RenderTabLineCanvas ()
                 int lineLength = tabsBarVts.Right - vts.Right;
 
                 // Right horizontal line
-                if (ShouldDrawRightScrollIndicator ())
+                if (ShouldDrawRightDownScrollIndicator ())
                 {
                     if (lineLength - arrowOffset > 0)
                     {
@@ -783,20 +781,30 @@ private void RenderTabLineCanvas ()
         LineCanvas.Merge (lc);
     }
 
-    private int GetUnderlineYPosition ()
+    private int GetUnderlineXOrYPosition ()
     {
-        if (_host.Style.TabsSide == TabSide.Bottom)
+        switch (_host.Style.TabsSide)
         {
-            return 0;
-        }
+            case TabSide.Top:
+
+                return _host.Style.ShowInitialLine ? 2 : 1;
+            case TabSide.Bottom:
+
+                return 0;
+            case TabSide.Left:
 
-        return _host.Style.ShowInitialLine ? 2 : 1;
+                return _host.Style.ShowInitialLine ? Frame.Right - 1 : Frame.Right;
+            case TabSide.Right:
+                return 0;
+            default:
+                throw new ArgumentOutOfRangeException ();
+        }
     }
 
     /// <summary>Renders the line of the tab that adjoins the content of the tab.</summary>
     private void RenderUnderline ()
     {
-        int y = GetUnderlineYPosition ();
+        int xOrY = GetUnderlineXOrYPosition ();
 
         Tab? selected = _host._tabLocations?.FirstOrDefault (t => t == _host.SelectedTab);
 
@@ -805,42 +813,91 @@ private void RenderUnderline ()
             return;
         }
 
-        // draw scroll indicators
+        // Set the correct glyphs for scroll indicators
+        switch (_host.Style.TabsSide)
+        {
+            case TabSide.Top:
+            case TabSide.Bottom:
+                _rightDownScrollIndicator.Text = Glyphs.RightArrow.ToString ();
+                _leftUpScrollIndicator.Text = Glyphs.LeftArrow.ToString ();
+
+                break;
+            case TabSide.Left:
+            case TabSide.Right:
+                _rightDownScrollIndicator.Text = Glyphs.DownArrow.ToString ();
+                _leftUpScrollIndicator.Text = Glyphs.UpArrow.ToString ();
+
+                break;
+            default:
+                throw new ArgumentOutOfRangeException ();
+        }
+
+        // position scroll indicators
 
         // if there are more tabs to the left not visible
         if (_host.TabScrollOffset > 0)
         {
-            _leftScrollIndicator.X = 0;
-            _leftScrollIndicator.Y = y;
+            switch (_host.Style.TabsSide)
+            {
+                case TabSide.Top:
+                case TabSide.Bottom:
+                    _leftUpScrollIndicator.X = 0;
+                    _leftUpScrollIndicator.Y = xOrY;
+
+                    break;
+                case TabSide.Left:
+                case TabSide.Right:
+                    _leftUpScrollIndicator.X = xOrY;
+                    _leftUpScrollIndicator.Y = 0;
+
+                    break;
+                default:
+                    throw new ArgumentOutOfRangeException ();
+            }
 
             // indicate that
-            _leftScrollIndicator.Visible = true;
+            _leftUpScrollIndicator.Visible = true;
 
             // Ensures this is clicked instead of the first tab
-            MoveSubviewToEnd (_leftScrollIndicator);
+            MoveSubviewToEnd (_leftUpScrollIndicator);
         }
         else
         {
-            _leftScrollIndicator.Visible = false;
+            _leftUpScrollIndicator.Visible = false;
         }
 
         // if there are more tabs to the right not visible
-        if (ShouldDrawRightScrollIndicator ())
+        if (ShouldDrawRightDownScrollIndicator ())
         {
-            _rightScrollIndicator.X = Viewport.Width - 1;
-            _rightScrollIndicator.Y = y;
+            switch (_host.Style.TabsSide)
+            {
+                case TabSide.Top:
+                case TabSide.Bottom:
+                    _rightDownScrollIndicator.X = Viewport.Width - 1;
+                    _rightDownScrollIndicator.Y = xOrY;
+
+                    break;
+                case TabSide.Left:
+                case TabSide.Right:
+                    _rightDownScrollIndicator.X = xOrY;
+                    _rightDownScrollIndicator.Y = Viewport.Height - 1;
+
+                    break;
+                default:
+                    throw new ArgumentOutOfRangeException ();
+            }
 
             // indicate that
-            _rightScrollIndicator.Visible = true;
+            _rightDownScrollIndicator.Visible = true;
 
             // Ensures this is clicked instead of the last tab if under this
-            MoveSubviewToStart (_rightScrollIndicator);
+            MoveSubviewToStart (_rightDownScrollIndicator);
         }
         else
         {
-            _rightScrollIndicator.Visible = false;
+            _rightDownScrollIndicator.Visible = false;
         }
     }
 
-    private bool ShouldDrawRightScrollIndicator () { return _host._tabLocations!.LastOrDefault () != _host.Tabs.LastOrDefault (); }
+    private bool ShouldDrawRightDownScrollIndicator () { return _host._tabLocations!.LastOrDefault () != _host.Tabs.LastOrDefault (); }
 }

From 3c6e8a1b9a859bdd3d41d538e8e4edc5ec1ea448 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Thu, 28 Nov 2024 16:49:45 +0000
Subject: [PATCH 12/18] Cleanup Point.

---
 Terminal.Gui/Views/TabView/TabRow.cs | 100 +++++++++++++--------------
 1 file changed, 50 insertions(+), 50 deletions(-)

diff --git a/Terminal.Gui/Views/TabView/TabRow.cs b/Terminal.Gui/Views/TabView/TabRow.cs
index 31aa909e19..529cde99a4 100644
--- a/Terminal.Gui/Views/TabView/TabRow.cs
+++ b/Terminal.Gui/Views/TabView/TabRow.cs
@@ -176,7 +176,7 @@ private void RenderTabLineCanvas ()
                         case TabSide.Top:
                             // Lower left vertical line
                             lc.AddLine (
-                                        new Point (vts.X - 1, vts.Bottom - selectedOffset),
+                                        new (vts.X - 1, vts.Bottom - selectedOffset),
                                         -1,
                                         Orientation.Vertical,
                                         tab.BorderStyle
@@ -186,7 +186,7 @@ private void RenderTabLineCanvas ()
                         case TabSide.Bottom:
                             // Upper left vertical line
                             lc.AddLine (
-                                        new Point (vts.X - 1, vts.Y - 1),
+                                        new (vts.X - 1, vts.Y - 1),
                                         -1,
                                         Orientation.Vertical,
                                         tab.BorderStyle
@@ -208,14 +208,14 @@ private void RenderTabLineCanvas ()
                         case TabSide.Top:
                             // LRCorner
                             lc.AddLine (
-                                        new Point (vts.X - 1, vts.Bottom - selectedOffset),
+                                        new (vts.X - 1, vts.Bottom - selectedOffset),
                                         -1,
                                         Orientation.Vertical,
                                         tab.BorderStyle
                                        );
 
                             lc.AddLine (
-                                        new Point (vts.X - 1, vts.Bottom - selectedOffset),
+                                        new (vts.X - 1, vts.Bottom - selectedOffset),
                                         -1,
                                         Orientation.Horizontal,
                                         tab.BorderStyle
@@ -225,14 +225,14 @@ private void RenderTabLineCanvas ()
                         case TabSide.Bottom:
                             // URCorner
                             lc.AddLine (
-                                        new Point (vts.X - 1, vts.Y - 1),
+                                        new (vts.X - 1, vts.Y - 1),
                                         1,
                                         Orientation.Vertical,
                                         tab.BorderStyle
                                        );
 
                             lc.AddLine (
-                                        new Point (vts.X - 1, vts.Y - 1),
+                                        new (vts.X - 1, vts.Y - 1),
                                         -1,
                                         Orientation.Horizontal,
                                         tab.BorderStyle
@@ -254,14 +254,14 @@ private void RenderTabLineCanvas ()
                             case TabSide.Top:
                                 // Upper left tee
                                 lc.AddLine (
-                                            new Point (vts.X - 1, vts.Y - 1),
+                                            new (vts.X - 1, vts.Y - 1),
                                             1,
                                             Orientation.Vertical,
                                             tab.BorderStyle
                                            );
 
                                 lc.AddLine (
-                                            new Point (vts.X - 1, vts.Y - 1),
+                                            new (vts.X - 1, vts.Y - 1),
                                             0,
                                             Orientation.Horizontal,
                                             tab.BorderStyle
@@ -271,14 +271,14 @@ private void RenderTabLineCanvas ()
                             case TabSide.Bottom:
                                 // Lower left tee
                                 lc.AddLine (
-                                            new Point (vts.X - 1, vts.Bottom),
+                                            new (vts.X - 1, vts.Bottom),
                                             -1,
                                             Orientation.Vertical,
                                             tab.BorderStyle
                                            );
 
                                 lc.AddLine (
-                                            new Point (vts.X - 1, vts.Bottom),
+                                            new (vts.X - 1, vts.Bottom),
                                             0,
                                             Orientation.Horizontal,
                                             tab.BorderStyle
@@ -304,14 +304,14 @@ private void RenderTabLineCanvas ()
                             case TabSide.Top:
                                 // Upper right tee
                                 lc.AddLine (
-                                            new Point (vts.Right, vts.Y - 1),
+                                            new (vts.Right, vts.Y - 1),
                                             1,
                                             Orientation.Vertical,
                                             tab.BorderStyle
                                            );
 
                                 lc.AddLine (
-                                            new Point (vts.Right, vts.Y - 1),
+                                            new (vts.Right, vts.Y - 1),
                                             0,
                                             Orientation.Horizontal,
                                             tab.BorderStyle
@@ -321,14 +321,14 @@ private void RenderTabLineCanvas ()
                             case TabSide.Bottom:
                                 // Lower right tee
                                 lc.AddLine (
-                                            new Point (vts.Right, vts.Bottom),
+                                            new (vts.Right, vts.Bottom),
                                             -1,
                                             Orientation.Vertical,
                                             tab.BorderStyle
                                            );
 
                                 lc.AddLine (
-                                            new Point (vts.Right, vts.Bottom),
+                                            new (vts.Right, vts.Bottom),
                                             0,
                                             Orientation.Horizontal,
                                             tab.BorderStyle
@@ -350,14 +350,14 @@ private void RenderTabLineCanvas ()
                     case TabSide.Top:
                         //LLCorner
                         lc.AddLine (
-                                    new Point (vts.Right, vts.Bottom - selectedOffset),
+                                    new (vts.Right, vts.Bottom - selectedOffset),
                                     -1,
                                     Orientation.Vertical,
                                     tab.BorderStyle
                                    );
 
                         lc.AddLine (
-                                    new Point (vts.Right, vts.Bottom - selectedOffset),
+                                    new (vts.Right, vts.Bottom - selectedOffset),
                                     1,
                                     Orientation.Horizontal,
                                     tab.BorderStyle
@@ -367,14 +367,14 @@ private void RenderTabLineCanvas ()
                     case TabSide.Bottom:
                         //URCorner
                         lc.AddLine (
-                                    new Point (vts.Right, vts.Y - 1),
+                                    new (vts.Right, vts.Y - 1),
                                     1,
                                     Orientation.Vertical,
                                     tab.BorderStyle
                                    );
 
                         lc.AddLine (
-                                    new Point (vts.Right, vts.Y - 1),
+                                    new (vts.Right, vts.Y - 1),
                                     1,
                                     Orientation.Horizontal,
                                     tab.BorderStyle
@@ -400,14 +400,14 @@ private void RenderTabLineCanvas ()
                             {
                                 // ULCorner
                                 lc.AddLine (
-                                            new Point (vts.X - 1, vts.Y - 1),
+                                            new (vts.X - 1, vts.Y - 1),
                                             1,
                                             Orientation.Vertical,
                                             tab.BorderStyle
                                            );
 
                                 lc.AddLine (
-                                            new Point (vts.X - 1, vts.Y - 1),
+                                            new (vts.X - 1, vts.Y - 1),
                                             1,
                                             Orientation.Horizontal,
                                             tab.BorderStyle
@@ -416,14 +416,14 @@ private void RenderTabLineCanvas ()
 
                             // LLCorner
                             lc.AddLine (
-                                        new Point (vts.X - 1, vts.Bottom),
+                                        new (vts.X - 1, vts.Bottom),
                                         -1,
                                         Orientation.Vertical,
                                         tab.BorderStyle
                                        );
 
                             lc.AddLine (
-                                        new Point (vts.X - 1, vts.Bottom),
+                                        new (vts.X - 1, vts.Bottom),
                                         1,
                                         Orientation.Horizontal,
                                         tab.BorderStyle
@@ -435,14 +435,14 @@ private void RenderTabLineCanvas ()
                             {
                                 // LLCorner
                                 lc.AddLine (
-                                            new Point (vts.X - 1, vts.Bottom),
+                                            new (vts.X - 1, vts.Bottom),
                                             -1,
                                             Orientation.Vertical,
                                             tab.BorderStyle
                                            );
 
                                 lc.AddLine (
-                                            new Point (vts.X - 1, vts.Bottom),
+                                            new (vts.X - 1, vts.Bottom),
                                             1,
                                             Orientation.Horizontal,
                                             tab.BorderStyle
@@ -451,14 +451,14 @@ private void RenderTabLineCanvas ()
 
                             // ULCorner
                             lc.AddLine (
-                                        new Point (vts.X - 1, vts.Y - 1),
+                                        new (vts.X - 1, vts.Y - 1),
                                         1,
                                         Orientation.Vertical,
                                         tab.BorderStyle
                                        );
 
                             lc.AddLine (
-                                        new Point (vts.X - 1, vts.Y - 1),
+                                        new (vts.X - 1, vts.Y - 1),
                                         1,
                                         Orientation.Horizontal,
                                         tab.BorderStyle
@@ -479,14 +479,14 @@ private void RenderTabLineCanvas ()
                     {
                         // Upper left tee
                         lc.AddLine (
-                                    new Point (vts.X - 1, vts.Y - 1),
+                                    new (vts.X - 1, vts.Y - 1),
                                     1,
                                     Orientation.Vertical,
                                     tab.BorderStyle
                                    );
 
                         lc.AddLine (
-                                    new Point (vts.X - 1, vts.Y - 1),
+                                    new (vts.X - 1, vts.Y - 1),
                                     0,
                                     Orientation.Horizontal,
                                     tab.BorderStyle
@@ -495,14 +495,14 @@ private void RenderTabLineCanvas ()
 
                     // Lower left tee
                     lc.AddLine (
-                                new Point (vts.X - 1, vts.Bottom),
+                                new (vts.X - 1, vts.Bottom),
                                 -1,
                                 Orientation.Vertical,
                                 tab.BorderStyle
                                );
 
                     lc.AddLine (
-                                new Point (vts.X - 1, vts.Bottom),
+                                new (vts.X - 1, vts.Bottom),
                                 0,
                                 Orientation.Horizontal,
                                 tab.BorderStyle
@@ -515,14 +515,14 @@ private void RenderTabLineCanvas ()
                 {
                     // Upper right tee
                     lc.AddLine (
-                                new Point (vts.Right, vts.Y - 1),
+                                new (vts.Right, vts.Y - 1),
                                 1,
                                 Orientation.Vertical,
                                 tab.BorderStyle
                                );
 
                     lc.AddLine (
-                                new Point (vts.Right, vts.Y - 1),
+                                new (vts.Right, vts.Y - 1),
                                 0,
                                 Orientation.Horizontal,
                                 tab.BorderStyle
@@ -533,14 +533,14 @@ private void RenderTabLineCanvas ()
                 {
                     // Lower right tee
                     lc.AddLine (
-                                new Point (vts.Right, vts.Bottom),
+                                new (vts.Right, vts.Bottom),
                                 -1,
                                 Orientation.Vertical,
                                 tab.BorderStyle
                                );
 
                     lc.AddLine (
-                                new Point (vts.Right, vts.Bottom),
+                                new (vts.Right, vts.Bottom),
                                 0,
                                 Orientation.Horizontal,
                                 tab.BorderStyle
@@ -550,14 +550,14 @@ private void RenderTabLineCanvas ()
                 {
                     // Upper right tee
                     lc.AddLine (
-                                new Point (vts.Right, vts.Y - 1),
+                                new (vts.Right, vts.Y - 1),
                                 1,
                                 Orientation.Vertical,
                                 tab.BorderStyle
                                );
 
                     lc.AddLine (
-                                new Point (vts.Right, vts.Y - 1),
+                                new (vts.Right, vts.Y - 1),
                                 0,
                                 Orientation.Horizontal,
                                 tab.BorderStyle
@@ -572,14 +572,14 @@ private void RenderTabLineCanvas ()
                     case TabSide.Top:
                         // Lower left vertical line
                         lc.AddLine (
-                                    new Point (vts.X - 1, vts.Bottom),
+                                    new (vts.X - 1, vts.Bottom),
                                     0,
                                     Orientation.Vertical,
                                     tab.BorderStyle
                                    );
 
                         lc.AddLine (
-                                    new Point (vts.X - 1, vts.Bottom),
+                                    new (vts.X - 1, vts.Bottom),
                                     1,
                                     Orientation.Horizontal,
                                     tab.BorderStyle
@@ -589,14 +589,14 @@ private void RenderTabLineCanvas ()
                     case TabSide.Bottom:
                         // Upper left vertical line
                         lc.AddLine (
-                                    new Point (vts.X - 1, vts.Y - 1),
+                                    new (vts.X - 1, vts.Y - 1),
                                     0,
                                     Orientation.Vertical,
                                     tab.BorderStyle
                                    );
 
                         lc.AddLine (
-                                    new Point (vts.X - 1, vts.Y - 1),
+                                    new (vts.X - 1, vts.Y - 1),
                                     1,
                                     Orientation.Horizontal,
                                     tab.BorderStyle
@@ -619,14 +619,14 @@ private void RenderTabLineCanvas ()
                     case TabSide.Top:
                         // Lower right tee
                         lc.AddLine (
-                                    new Point (vts.Right, vts.Bottom),
+                                    new (vts.Right, vts.Bottom),
                                     -1,
                                     Orientation.Vertical,
                                     tab.BorderStyle
                                    );
 
                         lc.AddLine (
-                                    new Point (vts.Right, vts.Bottom),
+                                    new (vts.Right, vts.Bottom),
                                     0,
                                     Orientation.Horizontal,
                                     tab.BorderStyle
@@ -636,14 +636,14 @@ private void RenderTabLineCanvas ()
                     case TabSide.Bottom:
                         // Upper right tee
                         lc.AddLine (
-                                    new Point (vts.Right, vts.Y - 1),
+                                    new (vts.Right, vts.Y - 1),
                                     1,
                                     Orientation.Vertical,
                                     tab.BorderStyle
                                    );
 
                         lc.AddLine (
-                                    new Point (vts.Right, vts.Y - 1),
+                                    new (vts.Right, vts.Y - 1),
                                     0,
                                     Orientation.Horizontal,
                                     tab.BorderStyle
@@ -677,7 +677,7 @@ private void RenderTabLineCanvas ()
                         {
                             case TabSide.Top:
                                 lc.AddLine (
-                                            new Point (
+                                            new (
                                                        vts.Right,
                                                        vts.Bottom - lastSelectedTab
                                                       ),
@@ -689,7 +689,7 @@ private void RenderTabLineCanvas ()
                                 break;
                             case TabSide.Bottom:
                                 lc.AddLine (
-                                            new Point (vts.Right, vts.Y - lastSelectedTab),
+                                            new (vts.Right, vts.Y - lastSelectedTab),
                                             lineLength - arrowOffset,
                                             Orientation.Horizontal,
                                             tab.BorderStyle
@@ -712,7 +712,7 @@ private void RenderTabLineCanvas ()
                     {
                         case TabSide.Top:
                             lc.AddLine (
-                                        new Point (vts.Right, vts.Bottom - lastSelectedTab),
+                                        new (vts.Right, vts.Bottom - lastSelectedTab),
                                         lineLength,
                                         Orientation.Horizontal,
                                         tab.BorderStyle
@@ -721,7 +721,7 @@ private void RenderTabLineCanvas ()
                             break;
                         case TabSide.Bottom:
                             lc.AddLine (
-                                        new Point (vts.Right, vts.Y - lastSelectedTab),
+                                        new (vts.Right, vts.Y - lastSelectedTab),
                                         lineLength,
                                         Orientation.Horizontal,
                                         tab.BorderStyle
@@ -743,7 +743,7 @@ private void RenderTabLineCanvas ()
                             case TabSide.Top:
                                 // More URCorner
                                 lc.AddLine (
-                                            new Point (
+                                            new (
                                                        tabsBarVts.Right - 1,
                                                        vts.Bottom - lastSelectedTab
                                                       ),
@@ -756,7 +756,7 @@ private void RenderTabLineCanvas ()
                             case TabSide.Bottom:
                                 // More LRCorner
                                 lc.AddLine (
-                                            new Point (
+                                            new (
                                                        tabsBarVts.Right - 1,
                                                        vts.Y - lastSelectedTab
                                                       ),

From ee4923e0c5cf2cec9ebcbca5a52bc7ed3981a641 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Sat, 30 Nov 2024 19:26:50 +0000
Subject: [PATCH 13/18] Implemented almost left side feature.

---
 Terminal.Gui/Views/TabView/TabRow.cs  | 635 ++++++++++++++++++++------
 Terminal.Gui/Views/TabView/TabView.cs | 188 ++++----
 UnitTests/Views/TabViewTests.cs       | 543 +++++++++++++++++++++-
 3 files changed, 1129 insertions(+), 237 deletions(-)

diff --git a/Terminal.Gui/Views/TabView/TabRow.cs b/Terminal.Gui/Views/TabView/TabRow.cs
index 529cde99a4..175d500710 100644
--- a/Terminal.Gui/Views/TabView/TabRow.cs
+++ b/Terminal.Gui/Views/TabView/TabRow.cs
@@ -13,11 +13,12 @@ public TabRow (TabView host)
         Id = "tabRow";
 
         CanFocus = true;
+
         // Because TabRow has focusable subviews, it must be a TabGroup
         TabStop = TabBehavior.TabGroup;
         Width = Dim.Fill ();
 
-        _rightDownScrollIndicator = new View
+        _rightDownScrollIndicator = new ()
         {
             Id = "rightDownScrollIndicator",
             Width = 1,
@@ -26,7 +27,7 @@ public TabRow (TabView host)
         };
         _rightDownScrollIndicator.MouseClick += _host.Tab_MouseClick!;
 
-        _leftUpScrollIndicator = new View
+        _leftUpScrollIndicator = new ()
         {
             Id = "leftUpScrollIndicator",
             Width = 1,
@@ -38,7 +39,7 @@ public TabRow (TabView host)
         Add (_rightDownScrollIndicator, _leftUpScrollIndicator);
     }
 
-    /// <inheritdoc />
+    /// <inheritdoc/>
     public override void EndInit ()
     {
         _host._tabLocations = _host.CalculateViewport (Viewport);
@@ -49,11 +50,11 @@ public override void EndInit ()
     protected override bool OnMouseEvent (MouseEventArgs me)
     {
         View? parent = me.View is Adornment adornment ? adornment.Parent : me.View;
-        Tab? hit = parent as Tab;
+        var hit = parent as Tab;
 
         if (me.IsSingleClicked)
         {
-            _host.OnTabClicked (new TabMouseEventArgs (hit!, me));
+            _host.OnTabClicked (new (hit!, me));
 
             // user canceled click
             if (me.Handled)
@@ -108,7 +109,7 @@ protected override bool OnMouseEvent (MouseEventArgs me)
         return false;
     }
 
-    /// <inheritdoc />
+    /// <inheritdoc/>
     protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocusedView, View? focusedView)
     {
         if (_host.SelectedTab is { HasFocus: false, CanFocus: true } && focusedView == this)
@@ -140,7 +141,7 @@ protected override void OnSubviewLayout (LayoutEventArgs args)
         base.OnSubviewLayout (args);
     }
 
-    /// <inheritdoc />
+    /// <inheritdoc/>
     protected override bool OnRenderingLineCanvas ()
     {
         RenderTabLineCanvas ();
@@ -163,7 +164,6 @@ private void RenderTabLineCanvas ()
         {
             View tab = tabLocations [i];
             Rectangle vts = tab.ViewportToScreen (tab.Viewport);
-            int selectedOffset = _host.Style.ShowInitialLine && tabLocations [i] == _host.SelectedTab ? 0 : 1;
 
             if (tabLocations [i] == _host.SelectedTab)
             {
@@ -176,7 +176,7 @@ private void RenderTabLineCanvas ()
                         case TabSide.Top:
                             // Lower left vertical line
                             lc.AddLine (
-                                        new (vts.X - 1, vts.Bottom - selectedOffset),
+                                        new (vts.X - 1, vts.Bottom),
                                         -1,
                                         Orientation.Vertical,
                                         tab.BorderStyle
@@ -194,6 +194,14 @@ private void RenderTabLineCanvas ()
 
                             break;
                         case TabSide.Left:
+                            // Upper horizontal line
+                            lc.AddLine (
+                                        new (vts.Right, vts.Y - 1),
+                                        -1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
                             break;
                         case TabSide.Right:
                             break;
@@ -208,14 +216,14 @@ private void RenderTabLineCanvas ()
                         case TabSide.Top:
                             // LRCorner
                             lc.AddLine (
-                                        new (vts.X - 1, vts.Bottom - selectedOffset),
+                                        new (vts.X - 1, vts.Bottom),
                                         -1,
                                         Orientation.Vertical,
                                         tab.BorderStyle
                                        );
 
                             lc.AddLine (
-                                        new (vts.X - 1, vts.Bottom - selectedOffset),
+                                        new (vts.X - 1, vts.Bottom),
                                         -1,
                                         Orientation.Horizontal,
                                         tab.BorderStyle
@@ -240,6 +248,24 @@ private void RenderTabLineCanvas ()
 
                             break;
                         case TabSide.Left:
+                            if (Frame.Bottom > tab.Frame.Bottom)
+                            {
+                                // LRCorner
+                                lc.AddLine (
+                                            new (vts.Right, vts.Bottom),
+                                            1,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new (vts.Right, vts.Bottom),
+                                            -1,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+                            }
+
                             break;
                         case TabSide.Right:
                             break;
@@ -286,6 +312,21 @@ private void RenderTabLineCanvas ()
 
                                 break;
                             case TabSide.Left:
+                                // Upper left tee
+                                lc.AddLine (
+                                            new (vts.X - 1, vts.Y - 1),
+                                            0,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new (vts.X - 1, vts.Y - 1),
+                                            1,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+
                                 break;
                             case TabSide.Right:
                                 break;
@@ -336,6 +377,21 @@ private void RenderTabLineCanvas ()
 
                                 break;
                             case TabSide.Left:
+                                // Upper right tee
+                                lc.AddLine (
+                                            new (vts.X - 1, vts.Bottom),
+                                            0,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new (vts.X - 1, vts.Bottom),
+                                            1,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+
                                 break;
                             case TabSide.Right:
                                 break;
@@ -348,16 +404,16 @@ private void RenderTabLineCanvas ()
                 switch (_host.Style.TabsSide)
                 {
                     case TabSide.Top:
-                        //LLCorner
+                        //LRCorner
                         lc.AddLine (
-                                    new (vts.Right, vts.Bottom - selectedOffset),
+                                    new (vts.Right, vts.Bottom),
                                     -1,
                                     Orientation.Vertical,
                                     tab.BorderStyle
                                    );
 
                         lc.AddLine (
-                                    new (vts.Right, vts.Bottom - selectedOffset),
+                                    new (vts.Right, vts.Bottom),
                                     1,
                                     Orientation.Horizontal,
                                     tab.BorderStyle
@@ -382,6 +438,24 @@ private void RenderTabLineCanvas ()
 
                         break;
                     case TabSide.Left:
+                        if (Frame.Bottom > tab.Frame.Bottom)
+                        {
+                            //LRCorner
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        1,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        -1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+                        }
+
                         break;
                     case TabSide.Right:
                         break;
@@ -466,6 +540,39 @@ private void RenderTabLineCanvas ()
 
                             break;
                         case TabSide.Left:
+                            if (_host.Style.ShowInitialLine)
+                            {
+                                // ULCorner
+                                lc.AddLine (
+                                            new (vts.X - 1, vts.Y - 1),
+                                            1,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new (vts.X - 1, vts.Y - 1),
+                                            1,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+                            }
+
+                            // LLCorner
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        -1,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
                             break;
                         case TabSide.Right:
                             break;
@@ -475,93 +582,239 @@ private void RenderTabLineCanvas ()
                 }
                 else if (i > 0)
                 {
-                    if (_host.Style.ShowInitialLine || _host.Style.TabsSide == TabSide.Bottom)
+                    switch (_host.Style.TabsSide)
                     {
-                        // Upper left tee
-                        lc.AddLine (
-                                    new (vts.X - 1, vts.Y - 1),
-                                    1,
-                                    Orientation.Vertical,
-                                    tab.BorderStyle
-                                   );
+                        case TabSide.Top:
+                        case TabSide.Bottom:
+                            if (_host.Style.ShowInitialLine || _host.Style.TabsSide == TabSide.Bottom)
+                            {
+                                // Upper left tee
+                                lc.AddLine (
+                                            new (vts.X - 1, vts.Y - 1),
+                                            1,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
 
-                        lc.AddLine (
-                                    new (vts.X - 1, vts.Y - 1),
-                                    0,
-                                    Orientation.Horizontal,
-                                    tab.BorderStyle
-                                   );
-                    }
+                                lc.AddLine (
+                                            new (vts.X - 1, vts.Y - 1),
+                                            0,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+                            }
+
+                            // Lower left tee
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        -1,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
 
-                    // Lower left tee
-                    lc.AddLine (
-                                new (vts.X - 1, vts.Bottom),
-                                -1,
-                                Orientation.Vertical,
-                                tab.BorderStyle
-                               );
-
-                    lc.AddLine (
-                                new (vts.X - 1, vts.Bottom),
-                                0,
-                                Orientation.Horizontal,
-                                tab.BorderStyle
-                               );
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        0,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
+                            break;
+                        case TabSide.Left:
+                            if (_host.Style.ShowInitialLine || _host.Style.TabsSide == TabSide.Right)
+                            {
+                                // Upper left tee
+                                lc.AddLine (
+                                            new (vts.X - 1, vts.Y - 1),
+                                            0,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new (vts.X - 1, vts.Y - 1),
+                                            1,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+                            }
+
+                            // Lower left tee
+                            lc.AddLine (
+                                        new (vts.Right, vts.Y - 1),
+                                        0,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.Right, vts.Y - 1),
+                                        -1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
+                            break;
+                        case TabSide.Right:
+                            break;
+                        default:
+                            throw new ArgumentOutOfRangeException ();
+                    }
                 }
             }
             else if (i < tabLocations.Length - 1)
             {
                 if (_host.Style.ShowInitialLine)
                 {
-                    // Upper right tee
-                    lc.AddLine (
-                                new (vts.Right, vts.Y - 1),
-                                1,
-                                Orientation.Vertical,
-                                tab.BorderStyle
-                               );
-
-                    lc.AddLine (
-                                new (vts.Right, vts.Y - 1),
-                                0,
-                                Orientation.Horizontal,
-                                tab.BorderStyle
-                               );
+                    switch (_host.Style.TabsSide)
+                    {
+                        case TabSide.Top:
+                        case TabSide.Bottom:
+                            // Upper right tee
+                            lc.AddLine (
+                                        new (vts.Right, vts.Y - 1),
+                                        1,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.Right, vts.Y - 1),
+                                        0,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
+                            break;
+                        case TabSide.Left:
+                            // Upper right tee
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        0,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
+                            break;
+                        case TabSide.Right:
+                            break;
+                        default:
+                            throw new ArgumentOutOfRangeException ();
+                    }
                 }
 
-                if (_host.Style.ShowInitialLine || _host.Style.TabsSide == TabSide.Top)
+                if (_host.Style.ShowInitialLine)
                 {
-                    // Lower right tee
-                    lc.AddLine (
-                                new (vts.Right, vts.Bottom),
-                                -1,
-                                Orientation.Vertical,
-                                tab.BorderStyle
-                               );
-
-                    lc.AddLine (
-                                new (vts.Right, vts.Bottom),
-                                0,
-                                Orientation.Horizontal,
-                                tab.BorderStyle
-                               );
+                    switch (_host.Style.TabsSide)
+                    {
+                        case TabSide.Top:
+                        case TabSide.Bottom:
+                            // Lower right tee
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        -1,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        0,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
+                            break;
+                        case TabSide.Left:
+                            // Lower right tee
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        0,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        -1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
+                            break;
+                        case TabSide.Right:
+                            break;
+                        default:
+                            throw new ArgumentOutOfRangeException ();
+                    }
                 }
                 else
                 {
-                    // Upper right tee
-                    lc.AddLine (
-                                new (vts.Right, vts.Y - 1),
-                                1,
-                                Orientation.Vertical,
-                                tab.BorderStyle
-                               );
-
-                    lc.AddLine (
-                                new (vts.Right, vts.Y - 1),
-                                0,
-                                Orientation.Horizontal,
-                                tab.BorderStyle
-                               );
+                    switch (_host.Style.TabsSide)
+                    {
+                        case TabSide.Top:
+                            // Lower right tee
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        -1,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        0,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
+                            break;
+                        case TabSide.Bottom:
+                            // Upper right tee
+                            lc.AddLine (
+                                        new (vts.Right, vts.Y - 1),
+                                        1,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.Right, vts.Y - 1),
+                                        0,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
+                            break;
+                        case TabSide.Left:
+                            // Lower right tee
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        0,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        -1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
+                            break;
+                        case TabSide.Right:
+                            break;
+                        default:
+                            throw new ArgumentOutOfRangeException ();
+                    }
                 }
             }
 
@@ -604,6 +857,21 @@ private void RenderTabLineCanvas ()
 
                         break;
                     case TabSide.Left:
+                        // Upper horizontal line
+                        lc.AddLine (
+                                    new (vts.Right, vts.Y - 1),
+                                    1,
+                                    Orientation.Vertical,
+                                    tab.BorderStyle
+                                   );
+
+                        lc.AddLine (
+                                    new (vts.Right, vts.Y - 1),
+                                    0,
+                                    Orientation.Horizontal,
+                                    tab.BorderStyle
+                                   );
+
                         break;
                     case TabSide.Right:
                         break;
@@ -651,6 +919,24 @@ private void RenderTabLineCanvas ()
 
                         break;
                     case TabSide.Left:
+                        if (Frame.Bottom > tab.Frame.Bottom)
+                        {
+                            // Lower right tee
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        0,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        -1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+                        }
+
                         break;
                     case TabSide.Right:
                         break;
@@ -663,12 +949,26 @@ private void RenderTabLineCanvas ()
             {
                 var arrowOffset = 1;
 
-                int lastSelectedTab = !_host.Style.ShowInitialLine && i == selectedTab ? 1 :
-                                      _host.Style.TabsSide == TabSide.Bottom ? 1 : 0;
                 Rectangle tabsBarVts = ViewportToScreen (Viewport);
-                int lineLength = tabsBarVts.Right - vts.Right;
+                int lineLength;
+
+                switch (_host.Style.TabsSide)
+                {
+                    case TabSide.Top:
+                    case TabSide.Bottom:
+                        lineLength = tabsBarVts.Right - vts.Right;
+
+                        break;
+                    case TabSide.Left:
+                    case TabSide.Right:
+                        lineLength = tabsBarVts.Bottom - vts.Bottom;
 
-                // Right horizontal line
+                        break;
+                    default:
+                        throw new ArgumentOutOfRangeException ();
+                }
+
+                // Right horizontal/vertical line
                 if (ShouldDrawRightDownScrollIndicator ())
                 {
                     if (lineLength - arrowOffset > 0)
@@ -678,9 +978,9 @@ private void RenderTabLineCanvas ()
                             case TabSide.Top:
                                 lc.AddLine (
                                             new (
-                                                       vts.Right,
-                                                       vts.Bottom - lastSelectedTab
-                                                      ),
+                                                 vts.Right,
+                                                 vts.Bottom
+                                                ),
                                             lineLength - arrowOffset,
                                             Orientation.Horizontal,
                                             tab.BorderStyle
@@ -689,7 +989,8 @@ private void RenderTabLineCanvas ()
                                 break;
                             case TabSide.Bottom:
                                 lc.AddLine (
-                                            new (vts.Right, vts.Y - lastSelectedTab),
+
+                                            new (vts.Right, vts.Y - 1),
                                             lineLength - arrowOffset,
                                             Orientation.Horizontal,
                                             tab.BorderStyle
@@ -697,6 +998,16 @@ private void RenderTabLineCanvas ()
 
                                 break;
                             case TabSide.Left:
+                                lc.AddLine (
+                                            new (
+                                                 vts.Right,
+                                                 vts.Bottom
+                                                ),
+                                            lineLength - arrowOffset,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
                                 break;
                             case TabSide.Right:
                                 break;
@@ -712,7 +1023,7 @@ private void RenderTabLineCanvas ()
                     {
                         case TabSide.Top:
                             lc.AddLine (
-                                        new (vts.Right, vts.Bottom - lastSelectedTab),
+                                        new (vts.Right, vts.Bottom),
                                         lineLength,
                                         Orientation.Horizontal,
                                         tab.BorderStyle
@@ -721,7 +1032,8 @@ private void RenderTabLineCanvas ()
                             break;
                         case TabSide.Bottom:
                             lc.AddLine (
-                                        new (vts.Right, vts.Y - lastSelectedTab),
+
+                                        new (vts.Right, vts.Y - 1),
                                         lineLength,
                                         Orientation.Horizontal,
                                         tab.BorderStyle
@@ -729,6 +1041,65 @@ private void RenderTabLineCanvas ()
 
                             break;
                         case TabSide.Left:
+                            if (i == selectedTab)
+                            {
+                                if (Frame.Bottom == tab.Frame.Bottom)
+                                {
+                                    // Lower right horizontal line
+                                    lc.AddLine (
+                                                new (vts.Right, vts.Bottom),
+                                                0,
+                                                Orientation.Horizontal,
+                                                tab.BorderStyle
+                                               );
+                                }
+                                else
+                                {
+                                    lc.AddLine (
+                                                new (vts.Right, vts.Bottom),
+                                                lineLength,
+                                                Orientation.Vertical,
+                                                tab.BorderStyle
+                                               );
+                                }
+                            }
+                            else
+                            {
+                                if (Frame.Bottom == tab.Frame.Bottom)
+                                {
+                                    lc.AddLine (
+                                                new (vts.Right, vts.Bottom),
+                                                -1,
+                                                Orientation.Vertical,
+                                                tab.BorderStyle
+                                               );
+
+                                    lc.AddLine (
+                                                new (vts.Right, vts.Bottom),
+                                                0,
+                                                Orientation.Horizontal,
+                                                tab.BorderStyle
+                                               );
+
+                                }
+                                else
+                                {
+                                    lc.AddLine (
+                                                new (vts.Right, vts.Bottom),
+                                                lineLength,
+                                                Orientation.Vertical,
+                                                tab.BorderStyle
+                                               );
+
+                                    lc.AddLine (
+                                                new (vts.Right, tabsBarVts.Bottom),
+                                                1,
+                                                Orientation.Horizontal,
+                                                tab.BorderStyle
+                                               );
+                                }
+                            }
+
                             break;
                         case TabSide.Right:
                             break;
@@ -744,9 +1115,9 @@ private void RenderTabLineCanvas ()
                                 // More URCorner
                                 lc.AddLine (
                                             new (
-                                                       tabsBarVts.Right - 1,
-                                                       vts.Bottom - lastSelectedTab
-                                                      ),
+                                                 tabsBarVts.Right - 1,
+                                                 vts.Bottom
+                                                ),
                                             1,
                                             Orientation.Vertical,
                                             tab.BorderStyle
@@ -757,9 +1128,9 @@ private void RenderTabLineCanvas ()
                                 // More LRCorner
                                 lc.AddLine (
                                             new (
-                                                       tabsBarVts.Right - 1,
-                                                       vts.Y - lastSelectedTab
-                                                      ),
+                                                 tabsBarVts.Right - 1,
+                                                 vts.Y - 1
+                                                ),
                                             -1,
                                             Orientation.Vertical,
                                             tab.BorderStyle
@@ -767,6 +1138,20 @@ private void RenderTabLineCanvas ()
 
                                 break;
                             case TabSide.Left:
+                                if (Frame.Bottom > tab.Frame.Bottom)
+                                {
+                                    // More URCorner
+                                    lc.AddLine (
+                                                new (
+                                                     vts.Right,
+                                                     tabsBarVts.Bottom - 1
+                                                    ),
+                                                1,
+                                                Orientation.Horizontal,
+                                                tab.BorderStyle
+                                               );
+                                }
+
                                 break;
                             case TabSide.Right:
                                 break;
@@ -781,31 +1166,9 @@ private void RenderTabLineCanvas ()
         LineCanvas.Merge (lc);
     }
 
-    private int GetUnderlineXOrYPosition ()
-    {
-        switch (_host.Style.TabsSide)
-        {
-            case TabSide.Top:
-
-                return _host.Style.ShowInitialLine ? 2 : 1;
-            case TabSide.Bottom:
-
-                return 0;
-            case TabSide.Left:
-
-                return _host.Style.ShowInitialLine ? Frame.Right - 1 : Frame.Right;
-            case TabSide.Right:
-                return 0;
-            default:
-                throw new ArgumentOutOfRangeException ();
-        }
-    }
-
     /// <summary>Renders the line of the tab that adjoins the content of the tab.</summary>
     private void RenderUnderline ()
     {
-        int xOrY = GetUnderlineXOrYPosition ();
-
         Tab? selected = _host._tabLocations?.FirstOrDefault (t => t == _host.SelectedTab);
 
         if (selected is null)
@@ -840,16 +1203,21 @@ private void RenderUnderline ()
             switch (_host.Style.TabsSide)
             {
                 case TabSide.Top:
+                    _leftUpScrollIndicator.X = 0;
+                    _leftUpScrollIndicator.Y = Pos.AnchorEnd (1);
+
+                    break;
                 case TabSide.Bottom:
                     _leftUpScrollIndicator.X = 0;
-                    _leftUpScrollIndicator.Y = xOrY;
+                    _leftUpScrollIndicator.Y = 0;
 
                     break;
                 case TabSide.Left:
-                case TabSide.Right:
-                    _leftUpScrollIndicator.X = xOrY;
+                    _leftUpScrollIndicator.X = Pos.AnchorEnd (1);
                     _leftUpScrollIndicator.Y = 0;
 
+                    break;
+                case TabSide.Right:
                     break;
                 default:
                     throw new ArgumentOutOfRangeException ();
@@ -872,16 +1240,17 @@ private void RenderUnderline ()
             switch (_host.Style.TabsSide)
             {
                 case TabSide.Top:
+                case TabSide.Left:
+                    _rightDownScrollIndicator.X = Pos.AnchorEnd (1);
+                    _rightDownScrollIndicator.Y = Pos.AnchorEnd (1);
+
+                    break;
                 case TabSide.Bottom:
-                    _rightDownScrollIndicator.X = Viewport.Width - 1;
-                    _rightDownScrollIndicator.Y = xOrY;
+                    _rightDownScrollIndicator.X = Pos.AnchorEnd (1);
+                    _rightDownScrollIndicator.Y = 0;
 
                     break;
-                case TabSide.Left:
                 case TabSide.Right:
-                    _rightDownScrollIndicator.X = xOrY;
-                    _rightDownScrollIndicator.Y = Viewport.Height - 1;
-
                     break;
                 default:
                     throw new ArgumentOutOfRangeException ();
diff --git a/Terminal.Gui/Views/TabView/TabView.cs b/Terminal.Gui/Views/TabView/TabView.cs
index a136a199c1..c04229a679 100644
--- a/Terminal.Gui/Views/TabView/TabView.cs
+++ b/Terminal.Gui/Views/TabView/TabView.cs
@@ -36,45 +36,53 @@ public TabView ()
         base.Add (_containerView);
 
         // Things this view knows how to do
-        AddCommand (Command.Left, () =>
-                                  {
-                                      if (Style.TabsSide is TabSide.Top or TabSide.Bottom)
-                                      {
-                                          return SwitchTabBy (-1);
-                                      }
-
-                                      return false;
-                                  });
-
-        AddCommand (Command.Right, () =>
-                                   {
-                                       if (Style.TabsSide is TabSide.Top or TabSide.Bottom)
-                                       {
-                                           return SwitchTabBy (1);
-                                       }
-
-                                       return false;
-                                   });
-
-        AddCommand (Command.Up, () =>
-                                  {
-                                      if (Style.TabsSide is TabSide.Left or TabSide.Right)
-                                      {
-                                          return SwitchTabBy (-1);
-                                      }
-
-                                      return false;
-                                  });
-
-        AddCommand (Command.Down, () =>
-                                   {
-                                       if (Style.TabsSide is TabSide.Left or TabSide.Right)
-                                       {
-                                           return SwitchTabBy (1);
-                                       }
-
-                                       return false;
-                                   });
+        AddCommand (
+                    Command.Left,
+                    () =>
+                    {
+                        if (Style.TabsSide is TabSide.Top or TabSide.Bottom)
+                        {
+                            return SwitchTabBy (-1);
+                        }
+
+                        return false;
+                    });
+
+        AddCommand (
+                    Command.Right,
+                    () =>
+                    {
+                        if (Style.TabsSide is TabSide.Top or TabSide.Bottom)
+                        {
+                            return SwitchTabBy (1);
+                        }
+
+                        return false;
+                    });
+
+        AddCommand (
+                    Command.Up,
+                    () =>
+                    {
+                        if (Style.TabsSide is TabSide.Left or TabSide.Right)
+                        {
+                            return SwitchTabBy (-1);
+                        }
+
+                        return false;
+                    });
+
+        AddCommand (
+                    Command.Down,
+                    () =>
+                    {
+                        if (Style.TabsSide is TabSide.Left or TabSide.Right)
+                        {
+                            return SwitchTabBy (1);
+                        }
+
+                        return false;
+                    });
 
         AddCommand (
                     Command.LeftStart,
@@ -160,6 +168,7 @@ public Tab? SelectedTab
                 if (_selectedTab.View is { })
                 {
                     _selectedTab.View.CanFocusChanged -= ContainerViewCanFocus!;
+
                     // remove old content
                     _containerView.Remove (_selectedTab.View);
                 }
@@ -187,19 +196,14 @@ public Tab? SelectedTab
 
                 OnSelectedTabChanged (old!, _selectedTab!);
             }
+
             SetNeedsLayout ();
         }
     }
 
-    private bool TabCanSetFocus ()
-    {
-        return IsInitialized && SelectedTab is { } && (_selectedTabHasFocus || !_containerView.CanFocus);
-    }
+    private bool TabCanSetFocus () { return IsInitialized && SelectedTab is { } && (_selectedTabHasFocus || !_containerView.CanFocus); }
 
-    private void ContainerViewCanFocus (object sender, EventArgs eventArgs)
-    {
-        _containerView.CanFocus = _containerView.Subviews.Count (v => v.CanFocus) > 0;
-    }
+    private void ContainerViewCanFocus (object sender, EventArgs eventArgs) { _containerView.CanFocus = _containerView.Subviews.Count (v => v.CanFocus) > 0; }
 
     private TabStyle _style = new ();
 
@@ -214,6 +218,7 @@ public TabStyle Style
             {
                 return;
             }
+
             _style = value;
             SetNeedsLayout ();
         }
@@ -287,6 +292,7 @@ public void ApplyStyleChanges ()
                 _tabsBar.Height = GetTabHeight (true);
 
                 _containerView.X = 0;
+
                 //move content down to make space for tabs
                 _containerView.Y = Pos.Bottom (_tabsBar);
                 _containerView.Width = Dim.Fill ();
@@ -308,6 +314,7 @@ public void ApplyStyleChanges ()
                 _containerView.X = 0;
                 _containerView.Y = 0;
                 _containerView.Width = Dim.Fill ();
+
                 // Fill client area leaving space at bottom for tabs
                 _containerView.Height = Dim.Fill (tabHeight);
 
@@ -328,6 +335,7 @@ public void ApplyStyleChanges ()
                 //move content right to make space for tabs
                 _containerView.X = Pos.Right (_tabsBar);
                 _containerView.Y = 0;
+
                 // Fill client area leaving space at left for tabs
                 _containerView.Width = Dim.Fill ();
                 _containerView.Height = Dim.Fill ();
@@ -342,7 +350,7 @@ public void ApplyStyleChanges ()
         SetNeedsLayout ();
     }
 
-    /// <inheritdoc />
+    /// <inheritdoc/>
     protected override void OnViewportChanged (DrawEventArgs e)
     {
         _tabLocations = CalculateViewport (Viewport);
@@ -377,7 +385,7 @@ public void EnsureSelectedTabIsVisible ()
     /// <returns>The valid <see cref="TabScrollOffset"/> for the given value.</returns>
     public int EnsureValidScrollOffsets (int value) { return Math.Max (Math.Min (value, Tabs.Count - 1), 0); }
 
-    /// <inheritdoc />
+    /// <inheritdoc/>
     protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocusedView, View? focusedView)
     {
         if (SelectedTab is { HasFocus: false } && !_containerView.CanFocus && focusedView == this)
@@ -456,6 +464,7 @@ public bool SwitchTabBy (int amount)
         if (currentIdx == -1)
         {
             SelectedTab = Tabs.ElementAt (0);
+
             return true;
         }
 
@@ -498,10 +507,7 @@ protected override void Dispose (bool disposing)
     }
 
     /// <summary>Raises the <see cref="SelectedTabChanged"/> event.</summary>
-    protected virtual void OnSelectedTabChanged (Tab oldTab, Tab newTab)
-    {
-        SelectedTabChanged?.Invoke (this, new TabChangedEventArgs (oldTab, newTab));
-    }
+    protected virtual void OnSelectedTabChanged (Tab oldTab, Tab newTab) { SelectedTabChanged?.Invoke (this, new (oldTab, newTab)); }
 
     /// <summary>Returns which tabs to render at each x location.</summary>
     /// <returns></returns>
@@ -592,7 +598,7 @@ protected virtual void OnSelectedTabChanged (Tab oldTab, Tab newTab)
                 break;
             case TabSide.Left:
             case TabSide.Right:
-                int maxColWidth = 0;
+                var maxColWidth = 0;
 
                 // Starting at the first or scrolled to tab
                 foreach (Tab tab in Tabs.Skip (TabScrollOffset))
@@ -616,16 +622,18 @@ protected virtual void OnSelectedTabChanged (Tab oldTab, Tab newTab)
                     // or we won't even be able to render a single tab!
                     long maxWidth = Math.Max (0, Math.Min (bounds.Width - (Style.ShowInitialLine ? 2 : 1), MaxTabTextWidth));
 
+                    maxColWidth = GetMaxColWidth (Math.Min (tabTextWidth, (int)maxWidth));
+
                     // The maximum height to use for the tab. But not more than the height of the view
                     // or we won't even be able to render a single tab!
-                    int maxHeight = Math.Max (0, Math.Min (bounds.Height - 3, 3));
+                    int maxHeight = Math.Max (0, Math.Min (bounds.Height - 2, 2));
 
                     tab.Height = 2;
 
                     // if tab view is height <= 3 don't render any tabs
                     if (maxHeight == 0)
                     {
-                        tab.Width = maxColWidth = Math.Max (Style.ShowInitialLine ? 3 : 2, maxColWidth);
+                        tab.Width = maxColWidth;
                         tab.Visible = true;
                         tab.MouseClick += Tab_MouseClick!;
                         tab.Border!.MouseClick += Tab_MouseClick!;
@@ -646,7 +654,7 @@ protected virtual void OnSelectedTabChanged (Tab oldTab, Tab newTab)
                         tab.Text = tab.DisplayText;
                     }
 
-                    maxColWidth = Math.Max (tabTextWidth + 2, maxColWidth);
+                    maxColWidth = GetMaxColWidth (tabTextWidth);
                     tab.Height = 3;
 
                     // if there is not enough space for this tab
@@ -674,8 +682,21 @@ protected virtual void OnSelectedTabChanged (Tab oldTab, Tab newTab)
                 {
                     t.Width = maxColWidth;
                 }
+
                 _tabsBar.Width = maxColWidth;
 
+                int GetMaxColWidth (int textWidth)
+                {
+                    int maxViewportWidth = Math.Max (0, Viewport.Width - (Style.ShowBorder ? 2 : 0));
+
+                    if (Math.Max (textWidth + (Style.ShowInitialLine ? 2 : 1), maxColWidth) > maxViewportWidth)
+                    {
+                        return maxViewportWidth;
+                    }
+
+                    return Math.Max (textWidth + (Style.ShowInitialLine ? 2 : 1), maxColWidth);
+                }
+
                 break;
             default:
                 throw new ArgumentOutOfRangeException ();
@@ -697,10 +718,7 @@ protected virtual void OnSelectedTabChanged (Tab oldTab, Tab newTab)
         return tabs.Count == 0 ? null : tabs.ToArray ();
     }
 
-    private void Tab_DisplayTextChanged (object? sender, EventArgs e)
-    {
-        _tabLocations = CalculateViewport (Viewport);
-    }
+    private void Tab_DisplayTextChanged (object? sender, EventArgs e) { _tabLocations = CalculateViewport (Viewport); }
 
     /// <summary>Renders the line with the tab names in it.</summary>
     private void RenderTabLine (Tab []? tabLocations)
@@ -710,7 +728,6 @@ private void RenderTabLine (Tab []? tabLocations)
             return;
         }
 
-        View? selected = null;
         int topLine = Style.ShowInitialLine ? 1 : 0;
 
         foreach (Tab toRender in tabLocations)
@@ -719,13 +736,11 @@ private void RenderTabLine (Tab []? tabLocations)
 
             if (toRender == SelectedTab)
             {
-                selected = tab;
-
                 switch (Style.TabsSide)
                 {
                     case TabSide.Top:
                         tab.Border!.Thickness = new (1, topLine, 1, 0);
-                        tab.Margin!.Thickness = new (0, 0, 0, topLine);
+                        tab.Margin!.Thickness = new (0, 0, 0, 1);
 
                         break;
                     case TabSide.Bottom:
@@ -735,32 +750,7 @@ private void RenderTabLine (Tab []? tabLocations)
                         break;
                     case TabSide.Left:
                         tab.Border!.Thickness = new (topLine, 1, 0, 1);
-                        tab.Margin!.Thickness = new (0, 0, topLine, 0);
-
-                        break;
-                    case TabSide.Right:
-                        break;
-                    default:
-                        throw new ArgumentOutOfRangeException ();
-                }
-            }
-            else if (selected is null)
-            {
-                switch (Style.TabsSide)
-                {
-                    case TabSide.Top:
-                        tab.Border!.Thickness = new (1, topLine, 1, 1);
-                        tab.Margin!.Thickness = new (0, 0, 0, 0);
-
-                        break;
-                    case TabSide.Bottom:
-                        tab.Border!.Thickness = new (1, 1, 1, topLine);
-                        tab.Margin!.Thickness = new (0, 0, 0, 0);
-
-                        break;
-                    case TabSide.Left:
-                        tab.Border!.Thickness = new (topLine, 1, 1, 1);
-                        tab.Margin!.Thickness = new (0, 0, 0, 0);
+                        tab.Margin!.Thickness = new (0, 0, 1, 0);
 
                         break;
                     case TabSide.Right:
@@ -771,21 +761,20 @@ private void RenderTabLine (Tab []? tabLocations)
             }
             else
             {
+                tab.Margin!.Thickness = new (0, 0, 0, 0);
+
                 switch (Style.TabsSide)
                 {
                     case TabSide.Top:
                         tab.Border!.Thickness = new (1, topLine, 1, 1);
-                        tab.Margin!.Thickness = new (0, 0, 0, 0);
 
                         break;
                     case TabSide.Bottom:
                         tab.Border!.Thickness = new (1, 1, 1, topLine);
-                        tab.Margin!.Thickness = new (0, 0, 0, 0);
 
                         break;
                     case TabSide.Left:
                         tab.Border!.Thickness = new (topLine, 1, 1, 1);
-                        tab.Margin!.Thickness = new (0, 0, 0, 0);
 
                         break;
                     case TabSide.Right:
@@ -823,17 +812,14 @@ private int GetTabHeight (bool top)
         return Style.ShowInitialLine ? 3 : 2;
     }
 
-    internal void Tab_MouseClick (object sender, MouseEventArgs e)
-    {
-        e.Handled = _tabsBar.NewMouseEvent (e) == true;
-    }
+    internal void Tab_MouseClick (object sender, MouseEventArgs e) { e.Handled = _tabsBar.NewMouseEvent (e) == true; }
 
     private void UnSetCurrentTabs ()
     {
         if (_tabLocations is null)
         {
             // Ensures unset any visible tab prior to TabScrollOffset
-            for (int i = 0; i < TabScrollOffset; i++)
+            for (var i = 0; i < TabScrollOffset; i++)
             {
                 Tab tab = Tabs.ElementAt (i);
 
@@ -863,6 +849,4 @@ private void UnSetCurrentTabs ()
     /// <summary>Raises the <see cref="TabClicked"/> event.</summary>
     /// <param name="tabMouseEventArgs"></param>
     internal virtual void OnTabClicked (TabMouseEventArgs tabMouseEventArgs) { TabClicked?.Invoke (this, tabMouseEventArgs); }
-
-
-}
\ No newline at end of file
+}
diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs
index 4cced1ff5d..071a160423 100644
--- a/UnitTests/Views/TabViewTests.cs
+++ b/UnitTests/Views/TabViewTests.cs
@@ -1236,6 +1236,545 @@ public void ShowInitialLine_True_TabsSide_Bottom_With_Unicode ()
                                                      );
     }
 
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Left_TestTabView_Height3 ()
+    {
+        TabView tv = GetTabView (out _, out _);
+        tv.Width = 5;
+        tv.Height = 3;
+        tv.Style = new () { TabsSide = TabSide.Left };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭───┐
+│T h│
+╰─▼─┘",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Left_TestTabView_Height4 ()
+    {
+        TabView tv = GetTabView (out _, out _);
+        tv.Width = 5;
+        tv.Height = 4;
+        tv.Style = new () { TabsSide = TabSide.Left };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭───┐
+│T h│
+╰─╮ │
+  ▼─┘",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Left_TestTabView_Height5_One_Tab ()
+    {
+        TabView tv = GetTabView (out _, out Tab tab2);
+        tv.RemoveTab (tab2);
+        tv.Width = 5;
+        tv.Height = 5;
+        tv.Style = new () { TabsSide = TabSide.Left };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭───┐
+│T h│
+╰─╮ │
+  │ │
+  ╰─┘",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Left_TestTabView_Height6_Two_Tab ()
+    {
+        TabView tv = GetTabView (out _, out Tab tab2);
+        tv.Width = 5;
+        tv.Height = 6;
+        tv.Style = new () { TabsSide = TabSide.Left };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭───┐
+│T h│
+├─╮ │
+│T│ │
+╰─┤ │
+  ╰─┘",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭─┬─┐
+│T│h│
+├─╯ │
+│T  │
+╰─╮ │
+  ╰─┘",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Left_TestTabView_Height7_Two_Tab ()
+    {
+        TabView tv = GetTabView (out _, out Tab tab2);
+        tv.Width = 5;
+        tv.Height = 7;
+        tv.Style = new () { TabsSide = TabSide.Left };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭───┐
+│T h│
+├─╮ │
+│T│ │
+╰─┤ │
+  │ │
+  ╰─┘",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭─┬─┐
+│T│h│
+├─╯ │
+│T  │
+╰─╮ │
+  │ │
+  ╰─┘",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Left_TestThinTabView_WithLongNames ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        tv.Width = 10;
+        tv.Height = 5;
+        tv.Style = new () { TabsSide = TabSide.Left };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        // Test two tab names that fit
+        tab1.DisplayText = "12";
+        tab2.DisplayText = "13";
+
+        tv.Layout ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭────────┐
+│12 hi   │
+├──╮     │
+│13│     │
+╰──┴─────┘",
+                                                      output
+                                                     );
+
+        // Test first tab name too long
+        tab1.DisplayText = "12345678910";
+        tab2.DisplayText = "13";
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭────────┐
+│123456 h│
+├──────╮ │
+│13    │ │
+╰──────┴─┘",
+                                                      output
+                                                     );
+
+        //switch to tab2
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭──────┬─┐
+│123456│h│
+├──────╯ │
+│13      │
+╰────────┘",
+                                                      output
+                                                     );
+
+        // now make both tabs too long
+        tab1.DisplayText = "12345678910";
+        tab2.DisplayText = "abcdefghijklmnopq";
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭──────┬─┐
+│123456│h│
+├──────╯ │
+│abcdef  │
+╰────────┘",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Left_With_Unicode ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        tv.Width = 20;
+        tv.Height = 5;
+        tv.Style = new () { TabsSide = TabSide.Left };
+        tv.ApplyStyleChanges ();
+
+        tab1.DisplayText = "Tab0";
+
+        tab2.DisplayText = "Les Mise" + char.ConvertFromUtf32 (int.Parse ("0301", NumberStyles.HexNumber)) + "rables";
+
+        tv.Layout ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭──────────────────┐
+│Tab0           hi │
+├──────────────╮   │
+│Les Misérables│   │
+╰──────────────┴───┘",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭──────────────┬───┐
+│Tab0          │hi2│
+├──────────────╯   │
+│Les Misérables    │
+╰──────────────────┘",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_False_TabsSide_Left_TestTabView_Height3 ()
+    {
+        TabView tv = GetTabView (out _, out _);
+        tv.Width = 5;
+        tv.Height = 3;
+        tv.Style = new () { ShowInitialLine = false, TabsSide = TabSide.Left };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+────┐
+Ta h│
+──▼─┘",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_False_TabsSide_Left_TestTabView_Height4 ()
+    {
+        TabView tv = GetTabView (out _, out _);
+        tv.Width = 5;
+        tv.Height = 4;
+        tv.Style = new () { ShowInitialLine = false, TabsSide = TabSide.Left };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+────┐
+Ta h│
+──╮ │
+  ▼─┘",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_False_TabsSide_Left_TestTabView_Height5_One_Tab ()
+    {
+        TabView tv = GetTabView (out _, out Tab tab2);
+        tv.RemoveTab (tab2);
+        tv.Width = 5;
+        tv.Height = 5;
+        tv.Style = new () { TabsSide = TabSide.Left, ShowInitialLine = false };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+────┐
+Ta h│
+──╮ │
+  │ │
+  ╰─┘",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_False_TabsSide_Left_TestTabView_Height6_Two_Tab ()
+    {
+        TabView tv = GetTabView (out _, out Tab tab2);
+        tv.Width = 5;
+        tv.Height = 6;
+        tv.Style = new () { TabsSide = TabSide.Left, ShowInitialLine = false };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+────┐
+Ta h│
+──╮ │
+Ta│ │
+──┤ │
+  ╰─┘",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+──┬─┐
+Ta│h│
+──╯ │
+Ta  │
+──╮ │
+  ╰─┘",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_False_TabsSide_Left_TestTabView_Height7_Two_Tab ()
+    {
+        TabView tv = GetTabView (out _, out Tab tab2);
+        tv.Width = 5;
+        tv.Height = 7;
+        tv.Style = new () { TabsSide = TabSide.Left, ShowInitialLine = false };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+────┐
+Ta h│
+──╮ │
+Ta│ │
+──┤ │
+  │ │
+  ╰─┘",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+──┬─┐
+Ta│h│
+──╯ │
+Ta  │
+──╮ │
+  │ │
+  ╰─┘",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_False_TabsSide_Left_TestThinTabView_WithLongNames ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        tv.Width = 10;
+        tv.Height = 5;
+        tv.Style = new () { ShowInitialLine = false, TabsSide = TabSide.Left };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        // Test two tab names that fit
+        tab1.DisplayText = "12";
+        tab2.DisplayText = "13";
+
+        tv.Layout ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+─────────┐
+12 hi    │
+──╮      │
+13│      │
+──┴──────┘",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab2;
+        Assert.Equal (tab2, tv.Subviews.First (v => v.Id.Contains ("tabRow")).MostFocused);
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+──┬──────┐
+12│hi2   │
+──╯      │
+13       │
+─────────┘",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab1;
+
+        // Test first tab name too long
+        tab1.DisplayText = "12345678910";
+        tab2.DisplayText = "13";
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+─────────┐
+1234567 h│
+───────╮ │
+13     │ │
+───────┴─┘",
+                                                      output
+                                                     );
+
+        //switch to tab2
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+───────┬─┐
+1234567│h│
+───────╯ │
+13       │
+─────────┘",
+                                                      output
+                                                     );
+
+        // now make both tabs too long
+        tab1.DisplayText = "12345678910";
+        tab2.DisplayText = "abcdefghijklmnopq";
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+───────┬─┐
+1234567│h│
+───────╯ │
+abcdefg  │
+─────────┘",
+                                                      output
+                                                     );
+    }
+
     [Fact]
     public void SwitchTabBy_NormalUsage ()
     {
@@ -1305,7 +1844,7 @@ public void RemoveTab_ThatHasFocus ()
 
     [Fact]
     [SetupFakeDriver]
-    public void Add_Three_TabsOnTop_ChangesTab ()
+    public void Add_Three_TabsSide_Top_ChangesTab ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         Tab tab3;
@@ -1370,7 +1909,7 @@ public void Add_Three_TabsOnTop_ChangesTab ()
 
     [Fact]
     [SetupFakeDriver]
-    public void Add_Three_TabsOnBottom_ChangesTab ()
+    public void Add_Three_TabsSide_Bottom_ChangesTab ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         Tab tab3;

From bd666934985a677496312fbd3a099f2691cb4b5c Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Sun, 1 Dec 2024 12:16:43 +0000
Subject: [PATCH 14/18] Implemented right side feature.

---
 Terminal.Gui/Views/TabView/TabRow.cs  |  259 ++++-
 Terminal.Gui/Views/TabView/TabView.cs |   28 +-
 UnitTests/Views/TabViewTests.cs       | 1389 +++++++++++++++++++++++--
 3 files changed, 1606 insertions(+), 70 deletions(-)

diff --git a/Terminal.Gui/Views/TabView/TabRow.cs b/Terminal.Gui/Views/TabView/TabRow.cs
index 175d500710..7f6ec99bb9 100644
--- a/Terminal.Gui/Views/TabView/TabRow.cs
+++ b/Terminal.Gui/Views/TabView/TabRow.cs
@@ -204,6 +204,14 @@ private void RenderTabLineCanvas ()
 
                             break;
                         case TabSide.Right:
+                            // Upper horizontal line
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Y - 1),
+                                        -1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
                             break;
                         default:
                             throw new ArgumentOutOfRangeException ();
@@ -268,6 +276,24 @@ private void RenderTabLineCanvas ()
 
                             break;
                         case TabSide.Right:
+                            if (Frame.Bottom > tab.Frame.Bottom)
+                            {
+                                // LRCorner
+                                lc.AddLine (
+                                            new (vts.X - 1, vts.Bottom),
+                                            1,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new (vts.X - 1, vts.Bottom),
+                                            1,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+                            }
+
                             break;
                         default:
                             throw new ArgumentOutOfRangeException ();
@@ -329,6 +355,21 @@ private void RenderTabLineCanvas ()
 
                                 break;
                             case TabSide.Right:
+                                // Upper left tee
+                                lc.AddLine (
+                                            new (vts.Right, vts.Y - 1),
+                                            0,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new (vts.Right, vts.Y - 1),
+                                            -1,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+
                                 break;
                             default:
                                 throw new ArgumentOutOfRangeException ();
@@ -394,6 +435,21 @@ private void RenderTabLineCanvas ()
 
                                 break;
                             case TabSide.Right:
+                                // Upper right tee
+                                lc.AddLine (
+                                            new (vts.Right, vts.Bottom),
+                                            0,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new (vts.Right, vts.Bottom),
+                                            -1,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+
                                 break;
                             default:
                                 throw new ArgumentOutOfRangeException ();
@@ -458,6 +514,24 @@ private void RenderTabLineCanvas ()
 
                         break;
                     case TabSide.Right:
+                        if (Frame.Bottom > tab.Frame.Bottom)
+                        {
+                            //LRCorner
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        1,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+                        }
+
                         break;
                     default:
                         throw new ArgumentOutOfRangeException ();
@@ -656,6 +730,39 @@ private void RenderTabLineCanvas ()
 
                             break;
                         case TabSide.Right:
+                            if (_host.Style.ShowInitialLine || _host.Style.TabsSide == TabSide.Right)
+                            {
+                                // Upper left tee
+                                lc.AddLine (
+                                            new (vts.Right, vts.Y - 1),
+                                            0,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
+                                lc.AddLine (
+                                            new (vts.Right, vts.Y - 1),
+                                            -1,
+                                            Orientation.Horizontal,
+                                            tab.BorderStyle
+                                           );
+                            }
+
+                            // Lower left tee
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Y - 1),
+                                        0,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Y - 1),
+                                        1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
                             break;
                         default:
                             throw new ArgumentOutOfRangeException ();
@@ -704,6 +811,21 @@ private void RenderTabLineCanvas ()
 
                             break;
                         case TabSide.Right:
+                            // Upper right tee
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        0,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
                             break;
                         default:
                             throw new ArgumentOutOfRangeException ();
@@ -750,6 +872,21 @@ private void RenderTabLineCanvas ()
 
                             break;
                         case TabSide.Right:
+                            // Lower right tee
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        0,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.Right, vts.Bottom),
+                                        -1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
                             break;
                         default:
                             throw new ArgumentOutOfRangeException ();
@@ -874,6 +1011,21 @@ private void RenderTabLineCanvas ()
 
                         break;
                     case TabSide.Right:
+                        // Upper horizontal line
+                        lc.AddLine (
+                                    new (vts.X - 1, vts.Y - 1),
+                                    1,
+                                    Orientation.Vertical,
+                                    tab.BorderStyle
+                                   );
+
+                        lc.AddLine (
+                                    new (vts.X - 1, vts.Y - 1),
+                                    0,
+                                    Orientation.Horizontal,
+                                    tab.BorderStyle
+                                   );
+
                         break;
                     default:
                         throw new ArgumentOutOfRangeException ();
@@ -939,6 +1091,24 @@ private void RenderTabLineCanvas ()
 
                         break;
                     case TabSide.Right:
+                        if (Frame.Bottom > tab.Frame.Bottom)
+                        {
+                            // Lower right tee
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        0,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+                        }
+
                         break;
                     default:
                         throw new ArgumentOutOfRangeException ();
@@ -1010,6 +1180,16 @@ private void RenderTabLineCanvas ()
 
                                 break;
                             case TabSide.Right:
+                                lc.AddLine (
+                                            new (
+                                                 vts.X - 1,
+                                                 vts.Bottom
+                                                ),
+                                            lineLength - arrowOffset,
+                                            Orientation.Vertical,
+                                            tab.BorderStyle
+                                           );
+
                                 break;
                             default:
                                 throw new ArgumentOutOfRangeException ();
@@ -1102,6 +1282,65 @@ private void RenderTabLineCanvas ()
 
                             break;
                         case TabSide.Right:
+                            if (i == selectedTab)
+                            {
+                                if (Frame.Bottom == tab.Frame.Bottom)
+                                {
+                                    // Lower right horizontal line
+                                    lc.AddLine (
+                                                new (vts.X - 1, vts.Bottom),
+                                                0,
+                                                Orientation.Horizontal,
+                                                tab.BorderStyle
+                                               );
+                                }
+                                else
+                                {
+                                    lc.AddLine (
+                                                new (vts.X - 1, vts.Bottom),
+                                                lineLength,
+                                                Orientation.Vertical,
+                                                tab.BorderStyle
+                                               );
+                                }
+                            }
+                            else
+                            {
+                                if (Frame.Bottom == tab.Frame.Bottom)
+                                {
+                                    lc.AddLine (
+                                                new (vts.X - 1, vts.Bottom),
+                                                -1,
+                                                Orientation.Vertical,
+                                                tab.BorderStyle
+                                               );
+
+                                    lc.AddLine (
+                                                new (vts.X - 1, vts.Bottom),
+                                                0,
+                                                Orientation.Horizontal,
+                                                tab.BorderStyle
+                                               );
+
+                                }
+                                else
+                                {
+                                    lc.AddLine (
+                                                new (vts.X - 1, vts.Bottom),
+                                                lineLength,
+                                                Orientation.Vertical,
+                                                tab.BorderStyle
+                                               );
+
+                                    lc.AddLine (
+                                                new (vts.X - 1, tabsBarVts.Bottom),
+                                                1,
+                                                Orientation.Horizontal,
+                                                tab.BorderStyle
+                                               );
+                                }
+                            }
+
                             break;
                         default:
                             throw new ArgumentOutOfRangeException ();
@@ -1154,6 +1393,20 @@ private void RenderTabLineCanvas ()
 
                                 break;
                             case TabSide.Right:
+                                if (Frame.Bottom > tab.Frame.Bottom)
+                                {
+                                    // More URCorner
+                                    lc.AddLine (
+                                                new (
+                                                     vts.X - 1,
+                                                     tabsBarVts.Bottom - 1
+                                                    ),
+                                                -1,
+                                                Orientation.Horizontal,
+                                                tab.BorderStyle
+                                               );
+                                }
+
                                 break;
                             default:
                                 throw new ArgumentOutOfRangeException ();
@@ -1208,6 +1461,7 @@ private void RenderUnderline ()
 
                     break;
                 case TabSide.Bottom:
+                case TabSide.Right:
                     _leftUpScrollIndicator.X = 0;
                     _leftUpScrollIndicator.Y = 0;
 
@@ -1216,8 +1470,6 @@ private void RenderUnderline ()
                     _leftUpScrollIndicator.X = Pos.AnchorEnd (1);
                     _leftUpScrollIndicator.Y = 0;
 
-                    break;
-                case TabSide.Right:
                     break;
                 default:
                     throw new ArgumentOutOfRangeException ();
@@ -1251,6 +1503,9 @@ private void RenderUnderline ()
 
                     break;
                 case TabSide.Right:
+                    _rightDownScrollIndicator.X = 0;
+                    _rightDownScrollIndicator.Y = Pos.AnchorEnd (1);
+
                     break;
                 default:
                     throw new ArgumentOutOfRangeException ();
diff --git a/Terminal.Gui/Views/TabView/TabView.cs b/Terminal.Gui/Views/TabView/TabView.cs
index c04229a679..96c036e8af 100644
--- a/Terminal.Gui/Views/TabView/TabView.cs
+++ b/Terminal.Gui/Views/TabView/TabView.cs
@@ -275,7 +275,6 @@ public void ApplyStyleChanges ()
         _tabLocations = CalculateViewport (Viewport);
 
         _containerView.BorderStyle = Style.ShowBorder ? LineStyle.Single : LineStyle.None;
-        _containerView.Width = Dim.Fill ();
 
         switch (Style.TabsSide)
         {
@@ -342,6 +341,21 @@ public void ApplyStyleChanges ()
 
                 break;
             case TabSide.Right:
+                // Tabs are along the right
+                if (Style.ShowBorder)
+                {
+                    _containerView.Border!.Thickness = new (1, 1, 0, 1);
+                }
+
+                _tabsBar.Y = 0;
+                _tabsBar.Height = Dim.Fill ();
+
+                //move content left to make space for tabs
+                _containerView.X = 0;
+                _containerView.Y = 0;
+
+                _containerView.Height = Dim.Fill ();
+
                 break;
             default:
                 throw new ArgumentOutOfRangeException ();
@@ -685,6 +699,13 @@ protected override void Dispose (bool disposing)
 
                 _tabsBar.Width = maxColWidth;
 
+                if (Style.TabsSide == TabSide.Right)
+                {
+                    _tabsBar.X = Pos.AnchorEnd (maxColWidth);
+                    // Fill client area leaving space at right for tabs
+                    _containerView.Width = Dim.Fill (maxColWidth);
+                }
+
                 int GetMaxColWidth (int textWidth)
                 {
                     int maxViewportWidth = Math.Max (0, Viewport.Width - (Style.ShowBorder ? 2 : 0));
@@ -754,6 +775,9 @@ private void RenderTabLine (Tab []? tabLocations)
 
                         break;
                     case TabSide.Right:
+                        tab.Border!.Thickness = new (0, 1, topLine, 1);
+                        tab.Margin!.Thickness = new (1, 0, 0, 0);
+
                         break;
                     default:
                         throw new ArgumentOutOfRangeException ();
@@ -778,6 +802,8 @@ private void RenderTabLine (Tab []? tabLocations)
 
                         break;
                     case TabSide.Right:
+                        tab.Border!.Thickness = new (1, 1, topLine, 1);
+
                         break;
                     default:
                         throw new ArgumentOutOfRangeException ();
diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs
index 071a160423..1a0921df2c 100644
--- a/UnitTests/Views/TabViewTests.cs
+++ b/UnitTests/Views/TabViewTests.cs
@@ -1775,76 +1775,1238 @@ 1234567 h│
                                                      );
     }
 
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Right_TestTabView_Height3 ()
+    {
+        TabView tv = GetTabView (out _, out _);
+        tv.Width = 5;
+        tv.Height = 3;
+        tv.Style = new () { TabsSide = TabSide.Right };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌───╮
+│h T│
+└─▼─╯",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Right_TestTabView_Height4 ()
+    {
+        TabView tv = GetTabView (out _, out _);
+        tv.Width = 5;
+        tv.Height = 4;
+        tv.Style = new () { TabsSide = TabSide.Right };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌───╮
+│h T│
+│ ╭─╯
+└─▼  ",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Right_TestTabView_Height5_One_Tab ()
+    {
+        TabView tv = GetTabView (out _, out Tab tab2);
+        tv.RemoveTab (tab2);
+        tv.Width = 5;
+        tv.Height = 5;
+        tv.Style = new () { TabsSide = TabSide.Right };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌───╮
+│h T│
+│ ╭─╯
+│ │  
+└─╯  ",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Right_TestTabView_Height6_Two_Tab ()
+    {
+        TabView tv = GetTabView (out _, out Tab tab2);
+        tv.Width = 5;
+        tv.Height = 6;
+        tv.Style = new () { TabsSide = TabSide.Right };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌───╮
+│h T│
+│ ╭─┤
+│ │T│
+│ ├─╯
+└─╯  ",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌─┬─╮
+│h│T│
+│ ╰─┤
+│  T│
+│ ╭─╯
+└─╯  ",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Right_TestTabView_Height7_Two_Tab ()
+    {
+        TabView tv = GetTabView (out _, out Tab tab2);
+        tv.Width = 5;
+        tv.Height = 7;
+        tv.Style = new () { TabsSide = TabSide.Right };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌───╮
+│h T│
+│ ╭─┤
+│ │T│
+│ ├─╯
+│ │  
+└─╯  ",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌─┬─╮
+│h│T│
+│ ╰─┤
+│  T│
+│ ╭─╯
+│ │  
+└─╯  ",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Right_TestThinTabView_WithLongNames ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        tv.Width = 10;
+        tv.Height = 5;
+        tv.Style = new () { TabsSide = TabSide.Right };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        // Test two tab names that fit
+        tab1.DisplayText = "12";
+        tab2.DisplayText = "13";
+
+        tv.Layout ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌────────╮
+│hi    12│
+│     ╭──┤
+│     │13│
+└─────┴──╯",
+                                                      output
+                                                     );
+
+        // Test first tab name too long
+        tab1.DisplayText = "12345678910";
+        tab2.DisplayText = "13";
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌────────╮
+│h 123456│
+│ ╭──────┤
+│ │13    │
+└─┴──────╯",
+                                                      output
+                                                     );
+
+        //switch to tab2
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌─┬──────╮
+│h│123456│
+│ ╰──────┤
+│  13    │
+└────────╯",
+                                                      output
+                                                     );
+
+        // now make both tabs too long
+        tab1.DisplayText = "12345678910";
+        tab2.DisplayText = "abcdefghijklmnopq";
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌─┬──────╮
+│h│123456│
+│ ╰──────┤
+│  abcdef│
+└────────╯",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_True_TabsSide_Right_With_Unicode ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        tv.Width = 20;
+        tv.Height = 5;
+        tv.Style = new () { TabsSide = TabSide.Right };
+        tv.ApplyStyleChanges ();
+
+        tab1.DisplayText = "Tab0";
+
+        tab2.DisplayText = "Les Mise" + char.ConvertFromUtf32 (int.Parse ("0301", NumberStyles.HexNumber)) + "rables";
+
+        tv.Layout ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌──────────────────╮
+│hi  Tab0          │
+│   ╭──────────────┤
+│   │Les Misérables│
+└───┴──────────────╯",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌───┬──────────────╮
+│hi2│Tab0          │
+│   ╰──────────────┤
+│    Les Misérables│
+└──────────────────╯",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_False_TabsSide_Right_TestTabView_Height3 ()
+    {
+        TabView tv = GetTabView (out _, out _);
+        tv.Width = 5;
+        tv.Height = 3;
+        tv.Style = new () { ShowInitialLine = false, TabsSide = TabSide.Right };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌────
+│h Ta
+└─▼──",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_False_TabsSide_Right_TestTabView_Height4 ()
+    {
+        TabView tv = GetTabView (out _, out _);
+        tv.Width = 5;
+        tv.Height = 4;
+        tv.Style = new () { ShowInitialLine = false, TabsSide = TabSide.Right };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌────
+│h Ta
+│ ╭──
+└─▼  ",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_False_TabsSide_Right_TestTabView_Height5_One_Tab ()
+    {
+        TabView tv = GetTabView (out _, out Tab tab2);
+        tv.RemoveTab (tab2);
+        tv.Width = 5;
+        tv.Height = 5;
+        tv.Style = new () { TabsSide = TabSide.Right, ShowInitialLine = false };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌────
+│h Ta
+│ ╭──
+│ │  
+└─╯  ",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_False_TabsSide_Right_TestTabView_Height6_Two_Tab ()
+    {
+        TabView tv = GetTabView (out _, out Tab tab2);
+        tv.Width = 5;
+        tv.Height = 6;
+        tv.Style = new () { TabsSide = TabSide.Right, ShowInitialLine = false };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌────
+│h Ta
+│ ╭──
+│ │Ta
+│ ├──
+└─╯  ",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌─┬──
+│h│Ta
+│ ╰──
+│  Ta
+│ ╭──
+└─╯  ",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_False_TabsSide_Right_TestTabView_Height7_Two_Tab ()
+    {
+        TabView tv = GetTabView (out _, out Tab tab2);
+        tv.Width = 5;
+        tv.Height = 7;
+        tv.Style = new () { TabsSide = TabSide.Right, ShowInitialLine = false };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌────
+│h Ta
+│ ╭──
+│ │Ta
+│ ├──
+│ │  
+└─╯  ",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌─┬──
+│h│Ta
+│ ╰──
+│  Ta
+│ ╭──
+│ │  
+└─╯  ",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void ShowInitialLine_False_TabsSide_Right_TestThinTabView_WithLongNames ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        tv.Width = 10;
+        tv.Height = 5;
+        tv.Style = new () { ShowInitialLine = false, TabsSide = TabSide.Right };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+
+        // Test two tab names that fit
+        tab1.DisplayText = "12";
+        tab2.DisplayText = "13";
+
+        tv.Layout ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌─────────
+│hi     12
+│      ╭──
+│      │13
+└──────┴──",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab2;
+        Assert.Equal (tab2, tv.Subviews.First (v => v.Id.Contains ("tabRow")).MostFocused);
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌──────┬──
+│hi2   │12
+│      ╰──
+│       13
+└─────────",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab1;
+
+        // Test first tab name too long
+        tab1.DisplayText = "12345678910";
+        tab2.DisplayText = "13";
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌─────────
+│h 1234567
+│ ╭───────
+│ │13     
+└─┴───────",
+                                                      output
+                                                     );
+
+        //switch to tab2
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌─┬───────
+│h│1234567
+│ ╰───────
+│  13     
+└─────────",
+                                                      output
+                                                     );
+
+        // now make both tabs too long
+        tab1.DisplayText = "12345678910";
+        tab2.DisplayText = "abcdefghijklmnopq";
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌─┬───────
+│h│1234567
+│ ╰───────
+│  abcdefg
+└─────────",
+                                                      output
+                                                     );
+    }
+
     [Fact]
     public void SwitchTabBy_NormalUsage ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
-
+
+        Tab tab3;
+        Tab tab4;
+        Tab tab5;
+
+        tv.AddTab (tab3 = new (), false);
+        tv.AddTab (tab4 = new (), false);
+        tv.AddTab (tab5 = new (), false);
+
+        tv.SelectedTab = tab1;
+
+        var called = 0;
+        tv.SelectedTabChanged += (s, e) => { called++; };
+
+        tv.SwitchTabBy (1);
+
+        Assert.Equal (1, called);
+        Assert.Equal (tab2, tv.SelectedTab);
+
+        //reset called counter
+        called = 0;
+
+        // go right 2
+        tv.SwitchTabBy (2);
+
+        // even though we go right 2 indexes the event should only be called once
+        Assert.Equal (1, called);
+        Assert.Equal (tab4, tv.SelectedTab);
+    }
+
+    [Fact]
+    public void SwitchTabBy_OutOfTabsRange ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+
+        tv.SelectedTab = tab1;
+        tv.SwitchTabBy (500);
+
+        Assert.Equal (tab2, tv.SelectedTab);
+
+        tv.SwitchTabBy (-500);
+
+        Assert.Equal (tab1, tv.SelectedTab);
+    }
+
+    [Fact]
+    public void RemoveTab_ThatHasFocus ()
+    {
+        TabView tv = GetTabView (out Tab _, out Tab tab2);
+
+        tv.SelectedTab = tab2;
+        tab2.HasFocus = true;
+
+        Assert.Equal (2, tv.Tabs.Count);
+
+        foreach (Tab t in tv.Tabs.ToArray ())
+        {
+            tv.RemoveTab (t);
+        }
+
+        Assert.Empty (tv.Tabs);
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void Add_Three_TabsSide_Top_ShowInitialLine_True_ChangesTab ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        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_TabsSide_Top_ShowInitialLine_False_ChangesTab ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        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 () { ShowInitialLine = false };
+        tv.ApplyStyleChanges ();
+
+        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_TabsSide_Bottom_ShowInitialLine_True_ChangesTab ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        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 () { TabsSide = TabSide.Bottom };
+        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
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void Add_Three_TabsSide_Bottom_ShowInitialLine_False_ChangesTab ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        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 () { TabsSide = TabSide.Bottom, ShowInitialLine = false };
+        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
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void Add_Three_TabsSide_Left_ShowInitialLine_True_ChangesTab_Height5 ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        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 () { TabsSide = TabSide.Left };
+        tv.ApplyStyleChanges ();
+
+        tv.Layout ();
+        tv.Draw ();
+
+        Assert.Equal (tab1, tv.SelectedTab);
+
+        TestHelpers.AssertDriverContentsAre (
+                                             @"
+╭──────────────────┐
+│Tab1 hi           │
+├────╮             │
+│Tab2│             │
+╰────▼─────────────┘
+",
+                                             output
+                                            );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭────┬─────────────┐
+│Tab1│hi2          │
+├────╯             │
+│Tab2              │
+╰────▼─────────────┘
+",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab3;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭────▲─────────────┐
+│Tab3 hi3          │
+╰────╮             │
+     │             │
+     ╰─────────────┘
+",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void Add_Three_TabsSide_Left_ShowInitialLine_False_ChangesTab_Height5 ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        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 () { TabsSide = TabSide.Left, ShowInitialLine = false };
+        tv.ApplyStyleChanges ();
+
+        tv.Layout ();
+        tv.Draw ();
+
+        Assert.Equal (tab1, tv.SelectedTab);
+
+        TestHelpers.AssertDriverContentsAre (
+                                             @"
+───────────────────┐
+Tab1 hi            │
+────╮              │
+Tab2│              │
+────▼──────────────┘
+",
+                                             output
+                                            );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+────┬──────────────┐
+Tab1│hi2           │
+────╯              │
+Tab2               │
+────▼──────────────┘
+",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab3;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+────▲──────────────┐
+Tab3 hi3           │
+────╮              │
+    │              │
+    ╰──────────────┘
+",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void Add_Three_TabsSide_Left_ShowInitialLine_True_ChangesTab_Height9 ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         Tab tab3;
-        Tab tab4;
-        Tab tab5;
 
-        tv.AddTab (tab3 = new (), false);
-        tv.AddTab (tab4 = new (), false);
-        tv.AddTab (tab5 = new (), false);
+        tv.AddTab (
+                   tab3 = new () { Id = "tab3", DisplayText = "Tab3", View = new TextView { Id = "tab3.TextView", Width = 3, Height = 1, Text = "hi3" } },
+                   false);
 
-        tv.SelectedTab = tab1;
+        tv.Width = 20;
+        tv.Height = 9;
+        tv.Style = new () { TabsSide = TabSide.Left };
+        tv.ApplyStyleChanges ();
 
-        var called = 0;
-        tv.SelectedTabChanged += (s, e) => { called++; };
+        tv.Layout ();
+        tv.Draw ();
 
-        tv.SwitchTabBy (1);
+        Assert.Equal (tab1, tv.SelectedTab);
 
-        Assert.Equal (1, called);
-        Assert.Equal (tab2, tv.SelectedTab);
+        TestHelpers.AssertDriverContentsAre (
+                                             @"
+╭──────────────────┐
+│Tab1 hi           │
+├────╮             │
+│Tab2│             │
+├────┤             │
+│Tab3│             │
+╰────┤             │
+     │             │
+     ╰─────────────┘",
+                                             output
+                                            );
 
-        //reset called counter
-        called = 0;
+        tv.SelectedTab = tab2;
 
-        // go right 2
-        tv.SwitchTabBy (2);
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
 
-        // even though we go right 2 indexes the event should only be called once
-        Assert.Equal (1, called);
-        Assert.Equal (tab4, tv.SelectedTab);
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭────┬─────────────┐
+│Tab1│hi2          │
+├────╯             │
+│Tab2              │
+├────╮             │
+│Tab3│             │
+╰────┤             │
+     │             │
+     ╰─────────────┘
+",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab3;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭────┬─────────────┐
+│Tab1│hi3          │
+├────┤             │
+│Tab2│             │
+├────╯             │
+│Tab3              │
+╰────╮             │
+     │             │
+     ╰─────────────┘
+",
+                                                      output
+                                                     );
     }
 
     [Fact]
-    public void SwitchTabBy_OutOfTabsRange ()
+    [SetupFakeDriver]
+    public void Add_Three_TabsSide_Left_ShowInitialLine_False_ChangesTab_Height9 ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        Tab tab3;
 
-        tv.SelectedTab = tab1;
-        tv.SwitchTabBy (500);
+        tv.AddTab (
+                   tab3 = new () { Id = "tab3", DisplayText = "Tab3", View = new TextView { Id = "tab3.TextView", Width = 3, Height = 1, Text = "hi3" } },
+                   false);
 
-        Assert.Equal (tab2, tv.SelectedTab);
+        tv.Width = 20;
+        tv.Height = 9;
+        tv.Style = new () { TabsSide = TabSide.Left, ShowInitialLine = false };
+        tv.ApplyStyleChanges ();
 
-        tv.SwitchTabBy (-500);
+        tv.Layout ();
+        tv.Draw ();
 
         Assert.Equal (tab1, tv.SelectedTab);
+
+        TestHelpers.AssertDriverContentsAre (
+                                             @"
+───────────────────┐
+Tab1 hi            │
+────╮              │
+Tab2│              │
+────┤              │
+Tab3│              │
+────┤              │
+    │              │
+    ╰──────────────┘
+",
+                                             output
+                                            );
+
+        tv.SelectedTab = tab2;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+────┬──────────────┐
+Tab1│hi2           │
+────╯              │
+Tab2               │
+────╮              │
+Tab3│              │
+────┤              │
+    │              │
+    ╰──────────────┘
+",
+                                                      output
+                                                     );
+
+        tv.SelectedTab = tab3;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+────┬──────────────┐
+Tab1│hi3           │
+────┤              │
+Tab2│              │
+────╯              │
+Tab3               │
+────╮              │
+    │              │
+    ╰──────────────┘
+",
+                                                      output
+                                                     );
     }
 
     [Fact]
-    public void RemoveTab_ThatHasFocus ()
+    [SetupFakeDriver]
+    public void Add_Three_TabsSide_Right_ShowInitialLine_True_ChangesTab_Height5 ()
     {
-        TabView tv = GetTabView (out Tab _, out Tab tab2);
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        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 () { TabsSide = TabSide.Right };
+        tv.ApplyStyleChanges ();
+
+        tv.Layout ();
+        tv.Draw ();
+
+        Assert.Equal (tab1, tv.SelectedTab);
+
+        TestHelpers.AssertDriverContentsAre (
+                                             @"
+┌──────────────────╮
+│hi            Tab1│
+│             ╭────┤
+│             │Tab2│
+└─────────────▼────╯
+",
+                                             output
+                                            );
 
         tv.SelectedTab = tab2;
-        tab2.HasFocus = true;
 
-        Assert.Equal (2, tv.Tabs.Count);
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
 
-        foreach (Tab t in tv.Tabs.ToArray ())
-        {
-            tv.RemoveTab (t);
-        }
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌─────────────┬────╮
+│hi2          │Tab1│
+│             ╰────┤
+│              Tab2│
+└─────────────▼────╯
+",
+                                                      output
+                                                     );
 
-        Assert.Empty (tv.Tabs);
+        tv.SelectedTab = tab3;
+
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌─────────────▲────╮
+│hi3           Tab3│
+│             ╭────╯
+│             │     
+└─────────────╯     
+",
+                                                      output
+                                                     );
     }
 
     [Fact]
     [SetupFakeDriver]
-    public void Add_Three_TabsSide_Top_ChangesTab ()
+    public void Add_Three_TabsSide_Right_ShowInitialLine_False_ChangesTab_Height5 ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         Tab tab3;
@@ -1855,6 +3017,8 @@ public void Add_Three_TabsSide_Top_ChangesTab ()
 
         tv.Width = 20;
         tv.Height = 5;
+        tv.Style = new () { TabsSide = TabSide.Right, ShowInitialLine = false };
+        tv.ApplyStyleChanges ();
 
         tv.Layout ();
         tv.Draw ();
@@ -1863,11 +3027,11 @@ public void Add_Three_TabsSide_Top_ChangesTab ()
 
         TestHelpers.AssertDriverContentsAre (
                                              @"
-╭────┬────┬────╮
-│Tab1│Tab2│Tab3│
-│    ╰────┴────┴───╮
-│hi                │
-└──────────────────┘
+┌───────────────────
+│hi             Tab1
+│              ╭────
+│              │Tab2
+└──────────────▼────
 ",
                                              output
                                             );
@@ -1880,11 +3044,11 @@ public void Add_Three_TabsSide_Top_ChangesTab ()
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
-╭────┬────┬────╮    
-│Tab1│Tab2│Tab3│    
-├────╯    ╰────┴───╮
-│hi2               │
-└──────────────────┘
+┌──────────────┬────
+│hi2           │Tab1
+│              ╰────
+│               Tab2
+└──────────────▼────
 ",
                                                       output
                                                      );
@@ -1897,11 +3061,11 @@ public void Add_Three_TabsSide_Top_ChangesTab ()
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
-╭────┬────┬────╮    
-│Tab1│Tab2│Tab3│    
-├────┴────╯    ╰───╮
-│hi3               │
-└──────────────────┘
+┌──────────────▲────
+│hi3            Tab3
+│              ╭────
+│              │    
+└──────────────╯    
 ",
                                                       output
                                                      );
@@ -1909,7 +3073,7 @@ public void Add_Three_TabsSide_Top_ChangesTab ()
 
     [Fact]
     [SetupFakeDriver]
-    public void Add_Three_TabsSide_Bottom_ChangesTab ()
+    public void Add_Three_TabsSide_Right_ShowInitialLine_True_ChangesTab_Height9 ()
     {
         TabView tv = GetTabView (out Tab tab1, out Tab tab2);
         Tab tab3;
@@ -1919,8 +3083,8 @@ public void Add_Three_TabsSide_Bottom_ChangesTab ()
                    false);
 
         tv.Width = 20;
-        tv.Height = 5;
-        tv.Style = new () { TabsSide = TabSide.Bottom };
+        tv.Height = 9;
+        tv.Style = new () { TabsSide = TabSide.Right };
         tv.ApplyStyleChanges ();
 
         tv.Layout ();
@@ -1930,11 +3094,15 @@ public void Add_Three_TabsSide_Bottom_ChangesTab ()
 
         TestHelpers.AssertDriverContentsAre (
                                              @"
-┌──────────────────┐
-│hi                │
-│    ╭────┬────┬───╯
-│Tab1│Tab2│Tab3│
-╰────┴────┴────╯
+┌──────────────────╮
+│hi            Tab1│
+│             ╭────┤
+│             │Tab2│
+│             ├────┤
+│             │Tab3│
+│             ├────╯
+│             │
+└─────────────╯
 ",
                                              output
                                             );
@@ -1947,11 +3115,15 @@ public void Add_Three_TabsSide_Bottom_ChangesTab ()
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
-┌──────────────────┐
-│hi2               │
-├────╮    ╭────┬───╯
-│Tab1│Tab2│Tab3│    
-╰────┴────┴────╯    
+┌─────────────┬────╮
+│hi2          │Tab1│
+│             ╰────┤
+│              Tab2│
+│             ╭────┤
+│             │Tab3│
+│             ├────╯
+│             │     
+└─────────────╯     
 ",
                                                       output
                                                      );
@@ -1964,11 +3136,94 @@ public void Add_Three_TabsSide_Bottom_ChangesTab ()
 
         TestHelpers.AssertDriverContentsWithFrameAre (
                                                       @"
-┌──────────────────┐
-│hi3               │
-├────┬────╮    ╭───╯
-│Tab1│Tab2│Tab3│    
-╰────┴────┴────╯    
+┌─────────────┬────╮
+│hi3          │Tab1│
+│             ├────┤
+│             │Tab2│
+│             ╰────┤
+│              Tab3│
+│             ╭────╯
+│             │     
+└─────────────╯     
+",
+                                                      output
+                                                     );
+    }
+
+    [Fact]
+    [SetupFakeDriver]
+    public void Add_Three_TabsSide_Right_ShowInitialLine_False_ChangesTab_Height9 ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        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 = 9;
+        tv.Style = new () { TabsSide = TabSide.Right, ShowInitialLine = false };
+        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
                                                      );

From 43c83ee1cf28a3e857f91a499812e35cde3b35d3 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Mon, 2 Dec 2024 00:41:24 +0000
Subject: [PATCH 15/18] Fix ShowInitialLine right side bug.

---
 Terminal.Gui/Views/TabView/TabRow.cs | 15 +++++++++++++++
 UnitTests/Views/TabViewTests.cs      |  2 +-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/Terminal.Gui/Views/TabView/TabRow.cs b/Terminal.Gui/Views/TabView/TabRow.cs
index 7f6ec99bb9..925b019f38 100644
--- a/Terminal.Gui/Views/TabView/TabRow.cs
+++ b/Terminal.Gui/Views/TabView/TabRow.cs
@@ -948,6 +948,21 @@ private void RenderTabLineCanvas ()
 
                             break;
                         case TabSide.Right:
+                            // Lower right tee
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        0,
+                                        Orientation.Vertical,
+                                        tab.BorderStyle
+                                       );
+
+                            lc.AddLine (
+                                        new (vts.X - 1, vts.Bottom),
+                                        1,
+                                        Orientation.Horizontal,
+                                        tab.BorderStyle
+                                       );
+
                             break;
                         default:
                             throw new ArgumentOutOfRangeException ();
diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs
index 1a0921df2c..2315394777 100644
--- a/UnitTests/Views/TabViewTests.cs
+++ b/UnitTests/Views/TabViewTests.cs
@@ -3177,7 +3177,7 @@ public void Add_Three_TabsSide_Right_ShowInitialLine_False_ChangesTab_Height9 ()
 │hi             Tab1
 │              ╭────
 │              │Tab2
-│              ╭────
+│              ├────
 │              │Tab3
 │              ├────
 │              │

From 97c2d528002e15d9a0cebc654b8e8d71e731a304 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Mon, 2 Dec 2024 01:38:14 +0000
Subject: [PATCH 16/18] Add TabsTextAlignment feature.

---
 Terminal.Gui/Views/TabView/TabStyle.cs |   5 +
 Terminal.Gui/Views/TabView/TabView.cs  |   1 +
 UICatalog/Scenarios/TabViewExample.cs  |  47 ++-
 UnitTests/Views/TabViewTests.cs        | 445 +++++++++++++++++++++++++
 4 files changed, 497 insertions(+), 1 deletion(-)

diff --git a/Terminal.Gui/Views/TabView/TabStyle.cs b/Terminal.Gui/Views/TabView/TabStyle.cs
index 900b882631..74107d2c1e 100644
--- a/Terminal.Gui/Views/TabView/TabStyle.cs
+++ b/Terminal.Gui/Views/TabView/TabStyle.cs
@@ -20,4 +20,9 @@ public class TabStyle
 
     /// <summary>Gets or sets the tabs side to render.</summary>
     public TabSide TabsSide { get; set; }
+
+    /// <summary>
+    ///     Gets or sets the tabs text alignments.
+    /// </summary>
+    public Alignment TabsTextAlignment { get; set; }
 }
diff --git a/Terminal.Gui/Views/TabView/TabView.cs b/Terminal.Gui/Views/TabView/TabView.cs
index 96c036e8af..6a910a16f1 100644
--- a/Terminal.Gui/Views/TabView/TabView.cs
+++ b/Terminal.Gui/Views/TabView/TabView.cs
@@ -643,6 +643,7 @@ protected override void Dispose (bool disposing)
                     int maxHeight = Math.Max (0, Math.Min (bounds.Height - 2, 2));
 
                     tab.Height = 2;
+                    tab.TextAlignment = Style.TabsTextAlignment;
 
                     // if tab view is height <= 3 don't render any tabs
                     if (maxHeight == 0)
diff --git a/UICatalog/Scenarios/TabViewExample.cs b/UICatalog/Scenarios/TabViewExample.cs
index 1d107aee97..6a6f574d99 100644
--- a/UICatalog/Scenarios/TabViewExample.cs
+++ b/UICatalog/Scenarios/TabViewExample.cs
@@ -16,6 +16,8 @@ public class TabViewExample : Scenario
     private MenuItem _miShowTopLine;
     private MenuItem [] _miTabsSide;
     private MenuItem _cachedTabsSide;
+    private MenuItem [] _miTabsTextAlignment;
+    private MenuItem _cachedTabsTextAlignment;
     private TabView _tabView;
 
     public override void Main ()
@@ -27,6 +29,7 @@ public override void Main ()
         Toplevel appWindow = new ();
 
         _miTabsSide = SetTabsSide ();
+        _miTabsTextAlignment = SetTabsTextAlignment ();
 
         var menu = new MenuBar
         {
@@ -70,7 +73,12 @@ public override void Main ()
                                   "_Show TabView Border",
                                   "",
                                   ShowTabViewBorder
-                                 ) { Checked = true, CheckType = MenuItemCheckStyle.Checked }
+                                 ) { Checked = true, CheckType = MenuItemCheckStyle.Checked },
+                         null,
+                         _miTabsTextAlignment [0],
+                         _miTabsTextAlignment [1],
+                         _miTabsTextAlignment [2],
+                         _miTabsTextAlignment [3]
                      }
                     )
             ]
@@ -284,6 +292,43 @@ private MenuItem [] SetTabsSide ()
         return menuItems.ToArray ();
     }
 
+    private MenuItem [] SetTabsTextAlignment ()
+    {
+        List<MenuItem> menuItems = [];
+
+        foreach (TabSide align in Enum.GetValues (typeof (Alignment)))
+        {
+            string alignName = Enum.GetName (typeof (Alignment), align);
+            var item = new MenuItem { Title = $"_{alignName}", Data = align };
+            item.CheckType |= MenuItemCheckStyle.Radio;
+
+            item.Action += () =>
+                           {
+                               if (_cachedTabsTextAlignment == item)
+                               {
+                                   return;
+                               }
+
+                               _cachedTabsTextAlignment.Checked = false;
+                               item.Checked = true;
+                               _cachedTabsTextAlignment = item;
+                               _tabView.Style.TabsTextAlignment = (Alignment)item.Data;
+                               _tabView.ApplyStyleChanges ();
+                           };
+            item.ShortcutKey = ((Key)alignName! [0].ToString ().ToLower ()).WithCtrl;
+
+            if (alignName == "Start")
+            {
+                item.Checked = true;
+                _cachedTabsTextAlignment = item;
+            }
+
+            menuItems.Add (item);
+        }
+
+        return menuItems.ToArray ();
+    }
+
     private void ShowBorder ()
     {
         _miShowBorder.Checked = !_miShowBorder.Checked;
diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs
index 2315394777..ef39655b6b 100644
--- a/UnitTests/Views/TabViewTests.cs
+++ b/UnitTests/Views/TabViewTests.cs
@@ -3278,6 +3278,451 @@ public void Mouse_Wheel_Changes_Tab ()
         top.Dispose ();
     }
 
+    [Fact]
+    [SetupFakeDriver]
+    public void Tabs_Alignments ()
+    {
+        TabView tv = GetTabView (out Tab tab1, out Tab tab2);
+        tv.Width = 20;
+        tv.Height = 5;
+
+        tab1.DisplayText = "Tab 1";
+        tab2.DisplayText = "Long Text";
+
+        tv.Layout ();
+        tv.Draw ();
+
+        string top = @"
+╭─────┬─────────╮   
+│Tab 1│Long Text│   
+│     ╰─────────┴──╮
+│hi                │
+└──────────────────┘
+";
+
+        TestHelpers.AssertDriverContentsWithFrameAre (top, output);
+
+        tv.Style = new () { TabsSide = TabSide.Bottom };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        string bottom = @"
+┌──────────────────┐
+│hi                │
+│     ╭─────────┬──╯
+│Tab 1│Long Text│   
+╰─────┴─────────╯   
+";
+
+        TestHelpers.AssertDriverContentsWithFrameAre (bottom, output);
+
+        tv.Style = new () { TabsSide = TabSide.Left };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭──────────────────┐
+│Tab 1     hi      │
+├─────────╮        │
+│Long Text│        │
+╰─────────┴────────┘
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Right };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌──────────────────╮
+│hi       Tab 1    │
+│        ╭─────────┤
+│        │Long Text│
+└────────┴─────────╯
+",
+                                                      output
+                                                     );
+
+        Assert.Equal (Alignment.Start, tv.Style.TabsTextAlignment);
+
+        tv.Style = new () { TabsSide = TabSide.Top, TabsTextAlignment = Alignment.End };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (top, output);
+
+        tv.Style = new () { TabsSide = TabSide.Bottom, TabsTextAlignment = Alignment.End };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (bottom, output);
+
+        tv.Style = new () { TabsSide = TabSide.Left, TabsTextAlignment = Alignment.End };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭──────────────────┐
+│    Tab 1 hi      │
+├─────────╮        │
+│Long Text│        │
+╰─────────┴────────┘
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Right, TabsTextAlignment = Alignment.End };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌──────────────────╮
+│hi           Tab 1│
+│        ╭─────────┤
+│        │Long Text│
+└────────┴─────────╯
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Top, TabsTextAlignment = Alignment.Center };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (top, output);
+
+        tv.Style = new () { TabsSide = TabSide.Bottom, TabsTextAlignment = Alignment.Center };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (bottom, output);
+
+        tv.Style = new () { TabsSide = TabSide.Left, TabsTextAlignment = Alignment.Center };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭──────────────────┐
+│  Tab 1   hi      │
+├─────────╮        │
+│Long Text│        │
+╰─────────┴────────┘
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Right, TabsTextAlignment = Alignment.Center };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌──────────────────╮
+│hi         Tab 1  │
+│        ╭─────────┤
+│        │Long Text│
+└────────┴─────────╯
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Top, TabsTextAlignment = Alignment.Fill };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (top, output);
+
+        tv.Style = new () { TabsSide = TabSide.Bottom, TabsTextAlignment = Alignment.Fill };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (bottom, output);
+
+        tv.Style = new () { TabsSide = TabSide.Left, TabsTextAlignment = Alignment.Fill };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+╭──────────────────┐
+│Tab     1 hi      │
+├─────────╮        │
+│Long Text│        │
+╰─────────┴────────┘
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Right, TabsTextAlignment = Alignment.Fill };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌──────────────────╮
+│hi       Tab     1│
+│        ╭─────────┤
+│        │Long Text│
+└────────┴─────────╯
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Top, ShowInitialLine = false, TabsTextAlignment = Alignment.Start };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        top = @"
+│Tab 1│Long Text│   
+│     ╰─────────┴──╮
+│hi                │
+│                  │
+└──────────────────┘
+";
+
+        TestHelpers.AssertDriverContentsWithFrameAre (top, output);
+
+        // ShowInitialLine false
+
+        tv.Style = new () { TabsSide = TabSide.Bottom, ShowInitialLine = false, TabsTextAlignment = Alignment.Start };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        bottom = @"
+┌──────────────────┐
+│hi                │
+│                  │
+│     ╭─────────┬──╯
+│Tab 1│Long Text│   
+";
+
+        TestHelpers.AssertDriverContentsWithFrameAre (bottom, output);
+
+        tv.Style = new () { TabsSide = TabSide.Left, ShowInitialLine = false, TabsTextAlignment = Alignment.Start };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+───────────────────┐
+Tab 1     hi       │
+─────────╮         │
+Long Text│         │
+─────────┴─────────┘
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Right, ShowInitialLine = false, TabsTextAlignment = Alignment.Start };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌───────────────────
+│hi        Tab 1    
+│         ╭─────────
+│         │Long Text
+└─────────┴─────────
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Top, ShowInitialLine = false, TabsTextAlignment = Alignment.End };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (top, output);
+
+        tv.Style = new () { TabsSide = TabSide.Bottom, ShowInitialLine = false, TabsTextAlignment = Alignment.End };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (bottom, output);
+
+        tv.Style = new () { TabsSide = TabSide.Left, ShowInitialLine = false, TabsTextAlignment = Alignment.End };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+───────────────────┐
+    Tab 1 hi       │
+─────────╮         │
+Long Text│         │
+─────────┴─────────┘
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Right, ShowInitialLine = false, TabsTextAlignment = Alignment.End };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌───────────────────
+│hi            Tab 1
+│         ╭─────────
+│         │Long Text
+└─────────┴─────────
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Top, ShowInitialLine = false, TabsTextAlignment = Alignment.Center };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (top, output);
+
+        tv.Style = new () { TabsSide = TabSide.Bottom, ShowInitialLine = false, TabsTextAlignment = Alignment.Center };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (bottom, output);
+
+        tv.Style = new () { TabsSide = TabSide.Left, ShowInitialLine = false, TabsTextAlignment = Alignment.Center };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+───────────────────┐
+  Tab 1   hi       │
+─────────╮         │
+Long Text│         │
+─────────┴─────────┘
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Right, ShowInitialLine = false, TabsTextAlignment = Alignment.Center };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌───────────────────
+│hi          Tab 1  
+│         ╭─────────
+│         │Long Text
+└─────────┴─────────
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Top, ShowInitialLine = false, TabsTextAlignment = Alignment.Fill };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (top, output);
+
+        tv.Style = new () { TabsSide = TabSide.Bottom, ShowInitialLine = false, TabsTextAlignment = Alignment.Fill };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (bottom, output);
+
+        tv.Style = new () { TabsSide = TabSide.Left, ShowInitialLine = false, TabsTextAlignment = Alignment.Fill };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+───────────────────┐
+Tab     1 hi       │
+─────────╮         │
+Long Text│         │
+─────────┴─────────┘
+",
+                                                      output
+                                                     );
+
+        tv.Style = new () { TabsSide = TabSide.Right, ShowInitialLine = false, TabsTextAlignment = Alignment.Fill };
+        tv.ApplyStyleChanges ();
+        tv.Layout ();
+        View.SetClipToScreen ();
+        tv.Draw ();
+
+        TestHelpers.AssertDriverContentsWithFrameAre (
+                                                      @"
+┌───────────────────
+│hi        Tab     1
+│         ╭─────────
+│         │Long Text
+└─────────┴─────────
+",
+                                                      output
+                                                     );
+    }
+
     private TabView GetTabView () { return GetTabView (out _, out _); }
 
     private TabView GetTabView (out Tab tab1, out Tab tab2)

From 1c77b0748260043d367f66525184d3216846d5fc Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Mon, 2 Dec 2024 01:49:54 +0000
Subject: [PATCH 17/18] Fixes #3873. TextFormatter isn't properly handling
 combining marks on alignments.

---
 Terminal.Gui/Text/TextFormatter.cs   | 12 ++--
 UnitTests/Text/TextFormatterTests.cs | 84 ++++++++++++++++++++++++++++
 2 files changed, 90 insertions(+), 6 deletions(-)

diff --git a/Terminal.Gui/Text/TextFormatter.cs b/Terminal.Gui/Text/TextFormatter.cs
index 90152452fd..a4a8b7060a 100644
--- a/Terminal.Gui/Text/TextFormatter.cs
+++ b/Terminal.Gui/Text/TextFormatter.cs
@@ -1411,7 +1411,7 @@ public static string ClipAndJustify (
 
                 if (textFormatter is { Alignment: Alignment.Center })
                 {
-                    return GetRangeThatFits (runes, Math.Max ((runes.Count - width) / 2, 0), text, width, tabWidth, textDirection);
+                    return GetRangeThatFits (runes, Math.Max ((runes.Count - width - zeroLength) / 2, 0), text, width, tabWidth, textDirection);
                 }
 
                 return GetRangeThatFits (runes, 0, text, width, tabWidth, textDirection);
@@ -1426,7 +1426,7 @@ public static string ClipAndJustify (
 
                 if (textFormatter is { VerticalAlignment: Alignment.Center })
                 {
-                    return GetRangeThatFits (runes, Math.Max ((runes.Count - width) / 2, 0), text, width, tabWidth, textDirection);
+                    return GetRangeThatFits (runes, Math.Max ((runes.Count - width - zeroLength) / 2, 0), text, width, tabWidth, textDirection);
                 }
 
                 return GetRangeThatFits (runes, 0, text, width, tabWidth, textDirection);
@@ -1451,7 +1451,7 @@ public static string ClipAndJustify (
             }
             else if (textFormatter is { Alignment: Alignment.Center })
             {
-                return GetRangeThatFits (runes, Math.Max ((runes.Count - width) / 2, 0), text, width, tabWidth, textDirection);
+                return GetRangeThatFits (runes, Math.Max ((runes.Count - width - zeroLength) / 2, 0), text, width, tabWidth, textDirection);
             }
             else if (GetRuneWidth (text, tabWidth, textDirection) > width)
             {
@@ -1470,7 +1470,7 @@ public static string ClipAndJustify (
             }
             else if (textFormatter is { VerticalAlignment: Alignment.Center })
             {
-                return GetRangeThatFits (runes, Math.Max ((runes.Count - width) / 2, 0), text, width, tabWidth, textDirection);
+                return GetRangeThatFits (runes, Math.Max ((runes.Count - width - zeroLength) / 2, 0), text, width, tabWidth, textDirection);
             }
             else if (runes.Count - zeroLength > width)
             {
@@ -1526,7 +1526,7 @@ public static string Justify (
         }
         else
         {
-            textCount = words.Sum (arg => arg.GetRuneCount ());
+            textCount = words.Sum (arg => arg.GetRuneCount ()) - text.EnumerateRunes ().Sum (r => r.GetColumns () == 0 ? 1 : 0);
         }
 
         int spaces = words.Length > 1 ? (width - textCount) / (words.Length - 1) : 0;
@@ -1936,7 +1936,7 @@ private static int GetRuneWidth (List<Rune> runes, int tabWidth, TextDirection t
 
     private static int GetRuneWidth (Rune rune, int tabWidth, TextDirection textDirection = TextDirection.LeftRight_TopBottom)
     {
-        int runeWidth = IsHorizontalDirection (textDirection) ? rune.GetColumns () : 1;
+        int runeWidth = IsHorizontalDirection (textDirection) ? rune.GetColumns () : rune.GetColumns () == 0 ? 0 : 1;
 
         if (rune.Value == '\t')
         {
diff --git a/UnitTests/Text/TextFormatterTests.cs b/UnitTests/Text/TextFormatterTests.cs
index d83ab398f2..5435d02044 100644
--- a/UnitTests/Text/TextFormatterTests.cs
+++ b/UnitTests/Text/TextFormatterTests.cs
@@ -4629,6 +4629,90 @@ string expectedWrappedText
         Assert.Equal (expectedWrappedText, wrappedText);
     }
 
+    [Theory]
+    [InlineData (
+                    "Les Mise\u0301rables",
+                    14,
+                    -1,
+                    false,
+                    new [] { "Les Misérables" },
+                    "Les Misérables"
+                )]
+    [InlineData (
+                    "Les Mise\u0328\u0301rables",
+                    14,
+                    -2,
+                    false,
+                    new [] { "Les Misę́rables" },
+                    "Les Misę́rables"
+                )]
+    public void Format_Combining_Marks_Alignments (
+        string text,
+        int maxWidth,
+        int widthOffset,
+        bool wrap,
+        IEnumerable<string> resultLines,
+        string expectedText
+    )
+    {
+        Assert.Equal (maxWidth, text.GetRuneCount () + widthOffset);
+
+        // Horizontal text direction
+        foreach (Alignment alignment in Enum.GetValues (typeof (Alignment)))
+        {
+            TextFormatter tf = new () { Text = text, ConstrainToSize = new (maxWidth, 1), WordWrap = wrap, Alignment = alignment };
+
+            List<string> list = TextFormatter.Format (
+                                                      text,
+                                                      maxWidth,
+                                                      alignment,
+                                                      wrap,
+                                                      tf.PreserveTrailingSpaces,
+                                                      tf.TabWidth,
+                                                      tf.Direction,
+                                                      tf.MultiLine,
+                                                      tf);
+            Assert.Equal (list.Count, resultLines.Count ());
+            Assert.Equal (resultLines, list);
+            var formattedText = string.Empty;
+
+            foreach (string txt in list)
+            {
+                formattedText += txt;
+            }
+
+            Assert.Equal (expectedText, formattedText);
+        }
+
+        // Vertical text direction
+        foreach (Alignment alignment in Enum.GetValues (typeof (Alignment)))
+        {
+            TextFormatter tf = new ()
+                { Text = text, ConstrainToSize = new (1, maxWidth), WordWrap = wrap, VerticalAlignment = alignment, Direction = TextDirection.TopBottom_LeftRight };
+
+            List<string> list = TextFormatter.Format (
+                                                      text,
+                                                      maxWidth,
+                                                      alignment,
+                                                      wrap,
+                                                      tf.PreserveTrailingSpaces,
+                                                      tf.TabWidth,
+                                                      tf.Direction,
+                                                      tf.MultiLine,
+                                                      tf);
+            Assert.Equal (list.Count, resultLines.Count ());
+            Assert.Equal (resultLines, list);
+            var formattedText = string.Empty;
+
+            foreach (string txt in list)
+            {
+                formattedText += txt;
+            }
+
+            Assert.Equal (expectedText, formattedText);
+        }
+    }
+
     public static IEnumerable<object []> FormatEnvironmentNewLine =>
         new List<object []>
         {

From c93230689be4a4181e919b40f561a6e7f2d818f4 Mon Sep 17 00:00:00 2001
From: BDisp <bd.bdisp@gmail.com>
Date: Tue, 3 Dec 2024 22:30:08 +0000
Subject: [PATCH 18/18] Fix bug with the _rightDownScrollIndicator.

---
 Terminal.Gui/Views/TabView/TabRow.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Terminal.Gui/Views/TabView/TabRow.cs b/Terminal.Gui/Views/TabView/TabRow.cs
index 925b019f38..d1a72b4322 100644
--- a/Terminal.Gui/Views/TabView/TabRow.cs
+++ b/Terminal.Gui/Views/TabView/TabRow.cs
@@ -1530,7 +1530,7 @@ private void RenderUnderline ()
             _rightDownScrollIndicator.Visible = true;
 
             // Ensures this is clicked instead of the last tab if under this
-            MoveSubviewToStart (_rightDownScrollIndicator);
+            MoveSubviewToEnd (_rightDownScrollIndicator);
         }
         else
         {