소스 검색

Remove TileView; use View.Arrangement instead (#4271)

* Initial plan

* Remove TileView and refactor to use View.Arrangement

Co-authored-by: tig <[email protected]>

* Fix FileDialog container focus behavior - all tests passing

Co-authored-by: tig <[email protected]>

* Remove obsolete TileView comment from View.Hierarchy.cs

Co-authored-by: tig <[email protected]>

* Add resizable splitter example to View.Arrangement docs

Co-authored-by: tig <[email protected]>

* Refactored `TreeView` and `TableView` containersto use View.Arrangment.

Removed unused `_btnToggleSplitterCollapse` and related logic due to the new splitter design.

Simplified collection initialization and feedback/state handling. Improved code readability by replacing magic strings and redundant null checks.

Refactor FileDialog for null safety and UI improvements

Enabled nullable reference types to improve null safety across the codebase. Refactored constants to follow uppercase naming conventions. Introduced nullable annotations for fields and method parameters.

Updated test cases to reflect the removal of deprecated features. Skipped tests related to the removed splitter button. Made miscellaneous improvements, including adding comments and suppressing warnings.

* Add "_Find:" label to FileDialog search field

Co-authored-by: tig <[email protected]>

* Fixes Parallel unit test intermittent failure case.

Removed the initialization of the `Navigation` object in the `ResetState` method of the `Application` class, indicating a potential shift in its lifecycle management. Enhanced comments to clarify the role of `Shutdown` as a counterpart to `Init`, emphasizing resource cleanup and defensive coding for multithreaded scenarios. Referenced Issue #537 for additional context.

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: tig <[email protected]>
Co-authored-by: Tig <[email protected]>
Copilot 1 개월 전
부모
커밋
7a810b0b87

+ 8 - 72
Examples/UICatalog/Scenarios/Notepad.cs

@@ -59,12 +59,12 @@ public class Notepad : Scenario
         _tabView.Style.ShowBorder = true;
         _tabView.ApplyStyleChanges ();
 
-        // Start with only a single view but support splitting to show side by side
-        var split = new TileView (1) { X = 0, Y = 1, Width = Dim.Fill (), Height = Dim.Fill (1) };
-        split.Tiles.ElementAt (0).ContentView.Add (_tabView);
-        split.LineStyle = LineStyle.None;
+        _tabView.X = 0;
+        _tabView.Y = 1;
+        _tabView.Width = Dim.Fill ();
+        _tabView.Height = Dim.Fill (1);
 
-        top.Add (split);
+        top.Add (_tabView);
         LenShortcut = new (Key.Empty, "Len: ", null);
 
         var statusBar = new StatusBar (new [] {
@@ -199,38 +199,10 @@ public class Notepad : Scenario
         tab.View.Dispose ();
         _focusedTabView = tv;
 
+        // If last tab is closed, open a new one
         if (tv.Tabs.Count == 0)
         {
-            var split = (TileView)tv.SuperView.SuperView;
-
-            // if it is the last TabView on screen don't drop it or we will
-            // be unable to open new docs!
-            if (split.IsRootTileView () && split.Tiles.Count == 1)
-            {
-                return;
-            }
-
-            int tileIndex = split.IndexOf (tv);
-            split.RemoveTile (tileIndex);
-
-            if (split.Tiles.Count == 0)
-            {
-                TileView parent = split.GetParentTileView ();
-
-                if (parent == null)
-                {
-                    return;
-                }
-
-                int idx = parent.IndexOf (split);
-
-                if (idx == -1)
-                {
-                    return;
-                }
-
-                parent.RemoveTile (idx);
-            }
+            New ();
         }
     }
 
@@ -286,37 +258,6 @@ public class Notepad : Scenario
 
     private void Quit () { Application.RequestStop (); }
 
-    private void Split (int offset, Orientation orientation, TabView sender, OpenedFile tab)
-    {
-        var split = (TileView)sender.SuperView.SuperView;
-        int tileIndex = split.IndexOf (sender);
-
-        if (tileIndex == -1)
-        {
-            return;
-        }
-
-        if (orientation != split.Orientation)
-        {
-            split.TrySplitTile (tileIndex, 1, out split);
-            split.Orientation = orientation;
-            tileIndex = 0;
-        }
-
-        Tile newTile = split.InsertTile (tileIndex + offset);
-        TabView newTabView = CreateNewTabView ();
-        tab.CloneTo (newTabView);
-        newTile.ContentView.Add (newTabView);
-
-        newTabView.FocusDeepest (NavigationDirection.Forward, null);
-        newTabView.AdvanceFocus (NavigationDirection.Forward, null);
-    }
-
-    private void SplitDown (TabView sender, OpenedFile tab) { Split (1, Orientation.Horizontal, sender, tab); }
-    private void SplitLeft (TabView sender, OpenedFile tab) { Split (0, Orientation.Vertical, sender, tab); }
-    private void SplitRight (TabView sender, OpenedFile tab) { Split (1, Orientation.Vertical, sender, tab); }
-    private void SplitUp (TabView sender, OpenedFile tab) { Split (0, Orientation.Horizontal, sender, tab); }
-
     private void TabView_SelectedTabChanged (object sender, TabChangedEventArgs e)
     {
         LenShortcut.Title = $"Len:{e.NewTab?.View?.Text?.Length ?? 0}";
@@ -346,12 +287,7 @@ public class Notepad : Scenario
             items =
             [
                 new MenuItemv2 ("Save", "", () => Save (_focusedTabView, e.Tab)),
-                new MenuItemv2 ("Close", "", () => Close (tv, e.Tab)),
-                new Line (),
-                new MenuItemv2 ("Split Up", "", () => SplitUp (tv, t)),
-                new MenuItemv2 ("Split Down", "", () => SplitDown (tv, t)),
-                new MenuItemv2 ("Split Right", "", () => SplitRight (tv, t)),
-                new MenuItemv2 ("Split Left", "", () => SplitLeft (tv, t))
+                new MenuItemv2 ("Close", "", () => Close (tv, e.Tab))
             ];
 
             PopoverMenu? contextMenu = new (items);

+ 0 - 227
Examples/UICatalog/Scenarios/TileViewNesting.cs

@@ -1,227 +0,0 @@
-using System.Linq;
-
-namespace UICatalog.Scenarios;
-
-[ScenarioMetadata ("Tile View Nesting", "Demonstrates recursive nesting of TileViews")]
-[ScenarioCategory ("Controls")]
-public class TileViewNesting : Scenario
-{
-    private CheckBox _cbBorder;
-    private CheckBox _cbHorizontal;
-    private CheckBox _cbTitles;
-    private CheckBox _cbUseLabels;
-    private TextField _textField;
-    private int _viewsCreated;
-    private int _viewsToCreate;
-    private View _workArea;
-
-    /// <summary>Setup the scenario.</summary>
-    public override void Main ()
-    {
-        Application.Init ();
-        // Scenario Windows.
-        var win = new Window
-        {
-            Title = GetName (),
-            Y = 1
-        };
-
-        var lblViews = new Label { Text = "Number Of Views:" };
-        _textField = new() { X = Pos.Right (lblViews), Width = 10, Text = "2" };
-
-        _textField.TextChanged += (s, e) => SetupTileView ();
-
-        _cbHorizontal = new() { X = Pos.Right (_textField) + 1, Text = "Horizontal" };
-        _cbHorizontal.CheckedStateChanged += (s, e) => SetupTileView ();
-
-        _cbBorder = new() { X = Pos.Right (_cbHorizontal) + 1, Text = "Border" };
-        _cbBorder.CheckedStateChanged += (s, e) => SetupTileView ();
-
-        _cbTitles = new() { X = Pos.Right (_cbBorder) + 1, Text = "Titles" };
-        _cbTitles.CheckedStateChanged += (s, e) => SetupTileView ();
-
-        _cbUseLabels = new() { X = Pos.Right (_cbTitles) + 1, Text = "Use Labels" };
-        _cbUseLabels.CheckedStateChanged += (s, e) => SetupTileView ();
-
-        _workArea = new() { X = 0, Y = 1, Width = Dim.Fill (), Height = Dim.Fill () };
-
-        var menu = new MenuBar
-        {
-            Menus =
-            [
-                new ("_File", new MenuItem [] { new ("_Quit", "", () => Quit ()) })
-            ]
-        };
-
-        win.Add (lblViews);
-        win.Add (_textField);
-        win.Add (_cbHorizontal);
-        win.Add (_cbBorder);
-        win.Add (_cbTitles);
-        win.Add (_cbUseLabels);
-        win.Add (_workArea);
-
-        SetupTileView ();
-
-        var top = new Toplevel ();
-        top.Add (menu);
-        top.Add (win);
-
-        Application.Run (top);
-        top.Dispose ();
-        Application.Shutdown ();
-    }
-
-    private void AddMoreViews (TileView to)
-    {
-        if (_viewsCreated == _viewsToCreate)
-        {
-            return;
-        }
-
-        if (!(to.Tiles.ElementAt (0).ContentView is TileView))
-        {
-            Split (to, true);
-        }
-
-        if (!(to.Tiles.ElementAt (1).ContentView is TileView))
-        {
-            Split (to, false);
-        }
-
-        if (to.Tiles.ElementAt (0).ContentView is TileView && to.Tiles.ElementAt (1).ContentView is TileView)
-        {
-            AddMoreViews ((TileView)to.Tiles.ElementAt (0).ContentView);
-            AddMoreViews ((TileView)to.Tiles.ElementAt (1).ContentView);
-        }
-    }
-
-    private View CreateContentControl (int number) { return _cbUseLabels.CheckedState == CheckState.Checked ? CreateLabelView (number) : CreateTextView (number); }
-
-    private View CreateLabelView (int number)
-    {
-        return new Label
-        {
-            Width = Dim.Fill (),
-            Height = 1,
-
-            Text = number.ToString ().Repeat (1000),
-            CanFocus = true
-        };
-    }
-
-    private View CreateTextView (int number)
-    {
-        return new TextView
-        {
-            Width = Dim.Fill (), Height = Dim.Fill (), Text = number.ToString ().Repeat (1000), AllowsTab = false
-
-            //WordWrap = true,  // TODO: This is very slow (like 10s to render with 45 views)
-        };
-    }
-
-    private TileView CreateTileView (int titleNumber, Orientation orientation)
-    {
-        var toReturn = new TileView
-        {
-            Width = Dim.Fill (),
-            Height = Dim.Fill (),
-
-            // flip the orientation
-            Orientation = orientation
-        };
-
-        toReturn.Tiles.ElementAt (0).Title = _cbTitles.CheckedState == CheckState.Checked ? $"View {titleNumber}" : string.Empty;
-        toReturn.Tiles.ElementAt (1).Title = _cbTitles.CheckedState == CheckState.Checked ? $"View {titleNumber + 1}" : string.Empty;
-
-        return toReturn;
-    }
-
-    private int GetNumberOfViews ()
-    {
-        if (int.TryParse (_textField.Text, out int views) && views >= 0)
-        {
-            return views;
-        }
-
-        return 0;
-    }
-
-    private void Quit () { Application.RequestStop (); }
-
-    private void SetupTileView ()
-    {
-        int numberOfViews = GetNumberOfViews ();
-
-        CheckState titles = _cbTitles.CheckedState;
-        CheckState border = _cbBorder.CheckedState;
-        CheckState startHorizontal = _cbHorizontal.CheckedState;
-
-        foreach (View sub in _workArea.SubViews)
-        {
-            sub.Dispose ();
-        }
-
-        _workArea.RemoveAll ();
-
-        if (numberOfViews <= 0)
-        {
-            return;
-        }
-
-        TileView root = CreateTileView (1, startHorizontal == CheckState.Checked ? Orientation.Horizontal : Orientation.Vertical);
-
-        root.Tiles.ElementAt (0).ContentView.Add (CreateContentControl (1));
-        root.Tiles.ElementAt (0).Title = _cbTitles.CheckedState == CheckState.Checked ? "View 1" : string.Empty;
-        root.Tiles.ElementAt (1).ContentView.Add (CreateContentControl (2));
-        root.Tiles.ElementAt (1).Title = _cbTitles.CheckedState == CheckState.Checked ? "View 2" : string.Empty;
-
-        root.LineStyle = border  == CheckState.Checked? LineStyle.Rounded : LineStyle.None;
-
-        _workArea.Add (root);
-
-        if (numberOfViews == 1)
-        {
-            root.Tiles.ElementAt (1).ContentView.Visible = false;
-        }
-
-        if (numberOfViews > 2)
-        {
-            _viewsCreated = 2;
-            _viewsToCreate = numberOfViews;
-            AddMoreViews (root);
-        }
-    }
-
-    private void Split (TileView to, bool left)
-    {
-        if (_viewsCreated == _viewsToCreate)
-        {
-            return;
-        }
-
-        TileView newView;
-
-        if (left)
-        {
-            to.TrySplitTile (0, 2, out newView);
-        }
-        else
-        {
-            to.TrySplitTile (1, 2, out newView);
-        }
-
-        _viewsCreated++;
-
-        // During splitting the old Title will have been migrated to View1 so we only need
-        // to set the Title on View2 (the one that gets our new TextView)
-        newView.Tiles.ElementAt (1).Title = _cbTitles.CheckedState == CheckState.Checked ? $"View {_viewsCreated}" : string.Empty;
-
-        // Flip orientation
-        newView.Orientation = to.Orientation == Orientation.Vertical
-                                  ? Orientation.Horizontal
-                                  : Orientation.Vertical;
-
-        newView.Tiles.ElementAt (1).ContentView.Add (CreateContentControl (_viewsCreated));
-    }
-}

+ 0 - 2
Terminal.Gui/App/Application.cs

@@ -179,8 +179,6 @@ public static partial class Application
     // starts running and after Shutdown returns.
     internal static void ResetState (bool ignoreDisposed = false)
     {
-        Navigation = new ();
-
         // Shutdown is the bookend for Init. As such it needs to clean up all resources
         // Init created. Apps that do any threading will need to code defensively for this.
         // e.g. see Issue #537

+ 1 - 1
Terminal.Gui/Resources/Strings.resx

@@ -195,7 +195,7 @@
     <value>Enter Path</value>
   </data>
   <data name="fdSearchCaption" xml:space="preserve">
-    <value>Enter Search</value>
+    <value>_Find:</value>
   </data>
   <data name="fdSize" xml:space="preserve">
     <value>Size</value>

+ 36 - 0
Terminal.Gui/ViewBase/View.Arrangement.cs

@@ -11,5 +11,41 @@ public partial class View
     ///     See the View Arrangement Deep Dive for more information: <see href="https://gui-cs.github.io/Terminal.Gui/docs/arrangement.html"/>
     /// </para>
     /// </remarks>
+    /// <example>
+    /// <para>
+    ///     This example demonstrates how to create a resizable splitter between two views using <see cref="ViewArrangement.LeftResizable"/>:
+    /// </para>
+    /// <code>
+    /// // Create left pane that fills remaining space
+    /// View leftPane = new ()
+    /// {
+    ///     X = 0,
+    ///     Y = 0,
+    ///     Width = Dim.Fill (Dim.Func (_ => rightPane.Frame.Width)),
+    ///     Height = Dim.Fill (),
+    ///     CanFocus = true
+    /// };
+    /// 
+    /// // Create right pane with resizable left border (acts as splitter)
+    /// View rightPane = new ()
+    /// {
+    ///     X = Pos.Right (leftPane) - 1,
+    ///     Y = 0,
+    ///     Width = Dim.Fill (),
+    ///     Height = Dim.Fill (),
+    ///     Arrangement = ViewArrangement.LeftResizable,
+    ///     BorderStyle = LineStyle.Single,
+    ///     SuperViewRendersLineCanvas = true,
+    ///     CanFocus = true
+    /// };
+    /// rightPane.Border!.Thickness = new (1, 0, 0, 0); // Only left border
+    /// 
+    /// container.Add (leftPane, rightPane);
+    /// </code>
+    /// <para>
+    ///     The right pane's left border acts as a draggable splitter. The left pane's width automatically adjusts
+    ///     to fill the remaining space using <c>Dim.Fill</c> with a function that subtracts the right pane's width.
+    /// </para>
+    /// </example>
     public ViewArrangement Arrangement { get; set; }
 }

+ 1 - 1
Terminal.Gui/ViewBase/View.Hierarchy.cs

@@ -111,7 +111,7 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
             Logging.Warning ($"{view} has already been Added to {this}.");
         }
 
-        // TileView likes to add views that were previously added and have HasFocus = true. No bueno.
+        // Ensure views don't have focus when being added
         view.HasFocus = false;
 
         // TODO: Make this thread safe

+ 65 - 124
Terminal.Gui/Views/FileDialogs/FileDialog.cs

@@ -1,8 +1,7 @@
+#nullable enable
 using System.IO.Abstractions;
 using System.Text.RegularExpressions;
 
-#nullable enable
-
 namespace Terminal.Gui.Views;
 
 /// <summary>
@@ -10,10 +9,11 @@ namespace Terminal.Gui.Views;
 /// </summary>
 public class FileDialog : Dialog, IDesignable
 {
-    private const int alignmentGroupInput = 32;
-    private const int alignmentGroupComplete = 55;
+    private const int ALIGNMENT_GROUP_INPUT = 32;
+    private const int ALIGNMENT_GROUP_COMPLETE = 55;
 
     /// <summary>Gets the Path separators for the operating system</summary>
+    // ReSharper disable once InconsistentNaming
     internal static char [] Separators =
     [
         System.IO.Path.AltDirectorySeparatorChar,
@@ -34,12 +34,11 @@ public class FileDialog : Dialog, IDesignable
     private readonly Button _btnCancel;
     private readonly Button _btnForward;
     private readonly Button _btnOk;
-    private readonly Button _btnToggleSplitterCollapse;
     private readonly Button _btnUp;
-    private readonly IFileSystem _fileSystem;
+    private readonly IFileSystem? _fileSystem;
     private readonly FileDialogHistory _history;
     private readonly SpinnerView _spinnerView;
-    private readonly TileView _splitContainer;
+    private readonly View _tableViewContainer;
     private readonly TableView _tableView;
     private readonly TextField _tbFind;
     private readonly TextField _tbPath;
@@ -61,7 +60,7 @@ public class FileDialog : Dialog, IDesignable
 
     /// <summary>Initializes a new instance of the <see cref="FileDialog"/> class with a custom <see cref="IFileSystem"/>.</summary>
     /// <remarks>This overload is mainly useful for testing.</remarks>
-    internal FileDialog (IFileSystem fileSystem)
+    internal FileDialog (IFileSystem? fileSystem)
     {
         Height = Dim.Percent (80);
         Width = Dim.Percent (80);
@@ -74,7 +73,7 @@ public class FileDialog : Dialog, IDesignable
 
         _btnOk = new ()
         {
-            X = Pos.Align (Alignment.End, AlignmentModes.AddSpaceBetweenItems, alignmentGroupComplete),
+            X = Pos.Align (Alignment.End, AlignmentModes.AddSpaceBetweenItems, ALIGNMENT_GROUP_COMPLETE),
             Y = Pos.AnchorEnd (),
             IsDefault = true, Text = Style.OkButtonText
         };
@@ -91,7 +90,7 @@ public class FileDialog : Dialog, IDesignable
 
         _btnCancel = new ()
         {
-            X = Pos.Align (Alignment.End, AlignmentModes.AddSpaceBetweenItems, alignmentGroupComplete),
+            X = Pos.Align (Alignment.End, AlignmentModes.AddSpaceBetweenItems, ALIGNMENT_GROUP_COMPLETE),
             Y = Pos.AnchorEnd (),
             Text = Strings.btnCancel
         };
@@ -149,21 +148,29 @@ public class FileDialog : Dialog, IDesignable
         _tbPath.Autocomplete = new AppendAutocomplete (_tbPath);
         _tbPath.Autocomplete.SuggestionGenerator = new FilepathSuggestionGenerator ();
 
-        _splitContainer = new ()
+        // Create tree view container (left pane)
+        View treeViewContainer = new ()
+        {
+            X = -1,
+            Y = Pos.Bottom (_btnBack),
+            Width = Dim.Fill (Dim.Func (_ => IsInitialized ? _tableViewContainer!.Frame.Width - 1 : 1)),
+            Height = Dim.Fill (Dim.Func (_ => IsInitialized ? _btnOk.Frame.Height : 1)),
+            CanFocus = true,
+        };
+
+        // Create table view container (right pane)
+        _tableViewContainer = new ()
         {
             X = 0,
             Y = Pos.Bottom (_btnBack),
             Width = Dim.Fill (),
-            Height = Dim.Fill (Dim.Func (_ => IsInitialized ? _btnOk.Frame.Height : 1))
+            Height = Dim.Fill (Dim.Func (_ => IsInitialized ? _btnOk.Frame.Height : 1)),
+            Arrangement = ViewArrangement.LeftResizable,
+            BorderStyle = LineStyle.Dashed,
+            SuperViewRendersLineCanvas = true,
+            CanFocus = true
         };
-
-        Initialized += (s, e) =>
-                       {
-                           _splitContainer.SetSplitterPos (0, 30);
-                           _splitContainer.Tiles.ElementAt (0).ContentView.Visible = false;
-                       };
-
-        // this.splitContainer.Border.BorderStyle = BorderStyle.None;
+        _tableViewContainer.Border!.Thickness = new (1, 0, 0, 0);
 
         _tableView = new ()
         {
@@ -202,38 +209,20 @@ public class FileDialog : Dialog, IDesignable
 
         _treeView.SelectionChanged += TreeView_SelectionChanged;
 
-        _splitContainer.Tiles.ElementAt (0).ContentView.Add (_treeView);
-        _splitContainer.Tiles.ElementAt (1).ContentView.Add (_tableView);
-
-        _btnToggleSplitterCollapse = new ()
-        {
-            X = Pos.Align (Alignment.Start, AlignmentModes.AddSpaceBetweenItems, alignmentGroupInput),
-            Y = Pos.AnchorEnd (), Text = GetToggleSplitterText (false)
-        };
-
-        _btnToggleSplitterCollapse.Accepting += (s, e) =>
-                                                {
-                                                    // Required otherwise the Save button clicks itself
-                                                    e.Handled = true;
-                                                    Tile tile = _splitContainer.Tiles.ElementAt (0);
-
-                                                    bool newState = !tile.ContentView.Visible;
-                                                    tile.ContentView.Visible = newState;
-                                                    _btnToggleSplitterCollapse.Text = GetToggleSplitterText (newState);
-                                                    SetNeedsLayout ();
-                                                };
+        treeViewContainer.Add (_treeView);
+        _tableViewContainer.Add (_tableView);
 
         _tbFind = new ()
         {
-            X = Pos.Align (Alignment.Start, AlignmentModes.AddSpaceBetweenItems, alignmentGroupInput),
+            X = Pos.Align (Alignment.Start, AlignmentModes.AddSpaceBetweenItems, ALIGNMENT_GROUP_INPUT),
             CaptionColor = new (Color.Black),
             Width = 30,
-            Y = Pos.Top (_btnToggleSplitterCollapse),
+            Y = Pos.Top (_btnOk),
             HotKey = Key.F.WithAlt
         };
 
         _spinnerView = new ()
-        { X = Pos.Align (Alignment.Start, AlignmentModes.AddSpaceBetweenItems, alignmentGroupInput), Y = Pos.AnchorEnd (1), Visible = false };
+        { X = Pos.Align (Alignment.Start, AlignmentModes.AddSpaceBetweenItems, ALIGNMENT_GROUP_INPUT), Y = Pos.AnchorEnd (1), Visible = false };
 
         _tbFind.TextChanged += (s, o) => RestartSearch ();
 
@@ -278,17 +267,17 @@ public class FileDialog : Dialog, IDesignable
 
         UpdateNavigationVisibility ();
 
-        Add (_tbPath);
-        Add (_btnUp);
-        Add (_btnBack);
-        Add (_btnForward);
-        Add (_splitContainer);
-        Add (_btnToggleSplitterCollapse);
-        Add (_tbFind);
-        Add (_spinnerView);
-
-        Add (_btnOk);
-        Add (_btnCancel);
+        base.Add (_tbPath);
+        base.Add (_btnUp);
+        base.Add (_btnBack);
+        base.Add (_btnForward);
+        base.Add (treeViewContainer);
+        base.Add (_tableViewContainer);
+        base.Add (_tbFind);
+        base.Add (_spinnerView);
+
+        base.Add (_btnOk);
+        base.Add (_btnCancel);
     }
 
     /// <summary>
@@ -418,7 +407,7 @@ public class FileDialog : Dialog, IDesignable
             Move (0, Viewport.Height / 2);
 
             SetAttribute (new (Color.Red, GetAttributeForRole (VisualRole.Normal).Background));
-            Driver.AddStr (new (' ', feedbackPadLeft));
+            Driver!.AddStr (new (' ', feedbackPadLeft));
             Driver.AddStr (_feedback);
             Driver.AddStr (new (' ', feedbackPadRight));
         }
@@ -444,7 +433,6 @@ public class FileDialog : Dialog, IDesignable
         _btnUp.Text = GetUpButtonText ();
         _btnBack.Text = GetBackButtonText ();
         _btnForward.Text = GetForwardButtonText ();
-        _btnToggleSplitterCollapse.Text = GetToggleSplitterText (false);
 
         _tbPath.Caption = Style.PathCaption;
         _tbFind.Caption = Style.SearchCaption;
@@ -466,7 +454,7 @@ public class FileDialog : Dialog, IDesignable
             CurrentFilter = AllowedTypes [0];
 
             // Fiddle factor
-            int width = AllowedTypes.Max (a => a.ToString ().Length) + 6;
+            int width = AllowedTypes.Max (a => a.ToString ()!.Length) + 6;
 
             _allowedTypeMenu = new (
                                     "<placeholder>",
@@ -497,7 +485,7 @@ public class FileDialog : Dialog, IDesignable
             _allowedTypeMenuBar.DrawingContent += (s, e) =>
                                                   {
                                                       _allowedTypeMenuBar.Move (e.NewViewport.Width - 1, 0);
-                                                      Driver.AddRune (Glyphs.DownArrow);
+                                                      Driver!.AddRune (Glyphs.DownArrow);
                                                   };
 
             Add (_allowedTypeMenuBar);
@@ -506,7 +494,7 @@ public class FileDialog : Dialog, IDesignable
         // if no path has been provided
         if (_tbPath.Text.Length <= 0)
         {
-            Path = _fileSystem.Directory.GetCurrentDirectory ();
+            Path = _fileSystem!.Directory.GetCurrentDirectory ();
         }
 
         // to streamline user experience and allow direct typing of paths
@@ -693,11 +681,8 @@ public class FileDialog : Dialog, IDesignable
 
         if (!IsCompatibleWithOpenMode (_tbPath.Text, out string reason))
         {
-            if (reason is { })
-            {
-                _feedback = reason;
-                SetNeedsDraw ();
-            }
+            _feedback = reason;
+            SetNeedsDraw ();
 
             return;
         }
@@ -727,18 +712,15 @@ public class FileDialog : Dialog, IDesignable
             _allowedTypeMenuItems [i].Checked = i == idx;
         }
 
-        _allowedTypeMenu.Title = allow.ToString ();
+        _allowedTypeMenu.Title = allow.ToString ()!;
 
         CurrentFilter = allow;
 
         _tbPath.ClearAllSelection ();
         _tbPath.Autocomplete.ClearSuggestions ();
 
-        if (State is { })
-        {
-            State.RefreshChildren ();
-            WriteStateToTableView ();
-        }
+        State.RefreshChildren ();
+        WriteStateToTableView ();
     }
 
     private string AspectGetter (object o)
@@ -780,7 +762,7 @@ public class FileDialog : Dialog, IDesignable
         return false;
     }
 
-    private void CellActivate (object sender, CellActivatedEventArgs obj)
+    private void CellActivate (object? sender, CellActivatedEventArgs obj)
     {
         if (TryAcceptMulti ())
         {
@@ -835,7 +817,7 @@ public class FileDialog : Dialog, IDesignable
     {
         IFileSystemInfo [] toDelete = GetFocusedFiles ();
 
-        if (toDelete is { } && FileOperationsHandler.Delete (toDelete))
+        if (FileOperationsHandler.Delete (toDelete))
         {
             RefreshState ();
         }
@@ -911,13 +893,6 @@ public class FileDialog : Dialog, IDesignable
         return string.Format (Strings.fdCtxSortAsc, _tableView.Table.ColumnNames [clickedCol]);
     }
 
-    private string GetToggleSplitterText (bool isExpanded)
-    {
-        return isExpanded
-                   ? new ((char)Glyphs.LeftArrow.Value, 2)
-                   : new string ((char)Glyphs.RightArrow.Value, 2);
-    }
-
     private string GetUpButtonText () { return Style.UseUnicodeCharacters ? "◭" : "▲"; }
 
     private void HideColumn (int clickedCol)
@@ -1020,12 +995,9 @@ public class FileDialog : Dialog, IDesignable
         {
             foreach (Point p in _tableView.GetAllSelectedCells ())
             {
-                FileSystemInfoStats add = State?.Children [p.Y];
+                FileSystemInfoStats add = State?.Children [p.Y]!;
 
-                if (add is { })
-                {
-                    toReturn.Add (add);
-                }
+                toReturn.Add (add);
             }
         }
 
@@ -1034,7 +1006,6 @@ public class FileDialog : Dialog, IDesignable
 
     private void New ()
     {
-        if (State is { })
         {
             IFileSystemInfo created = FileOperationsHandler.New (_fileSystem, State.Directory);
 
@@ -1046,7 +1017,7 @@ public class FileDialog : Dialog, IDesignable
         }
     }
 
-    private void OnTableViewMouseClick (object sender, MouseEventArgs e)
+    private void OnTableViewMouseClick (object? sender, MouseEventArgs e)
     {
         Point? clickedCell = _tableView.ScreenToCell (e.Position.X, e.Position.Y, out int? clickedCol);
 
@@ -1187,26 +1158,6 @@ public class FileDialog : Dialog, IDesignable
         }
     }
 
-    //		/// <inheritdoc/>
-    //		public override bool OnHotKey (KeyEventArgs keyEvent)
-    //		{
-    //#if BROKE_IN_2927
-    //			// BUGBUG: Ctrl-F is forward in a TextField. 
-    //			if (this.NavigateIf (keyEvent, Key.Alt | Key.F, this.tbFind)) {
-    //				return true;
-    //			}
-    //#endif
-
-    //			ClearFeedback ();
-
-    //			if (allowedTypeMenuBar is { } &&
-    //				keyEvent.ConsoleDriverKey == Key.Tab &&
-    //				allowedTypeMenuBar.IsMenuOpen) {
-    //				allowedTypeMenuBar.CloseMenu (false, false, false);
-    //			}
-
-    //			return base.OnHotKey (keyEvent);
-    //		}
     private void RestartSearch ()
     {
         if (_disposed || State?.Directory is null)
@@ -1232,10 +1183,10 @@ public class FileDialog : Dialog, IDesignable
             return;
         }
 
-        PushState (new SearchState (State?.Directory, this, _tbFind.Text), true);
+        PushState (new SearchState (State?.Directory!, this, _tbFind.Text), true);
     }
 
-    private FileSystemInfoStats RowToStats (int rowIndex) { return State?.Children [rowIndex]; }
+    private FileSystemInfoStats RowToStats (int rowIndex) { return State?.Children [rowIndex]!; }
 
     private void ShowCellContextMenu (Point? clickedCell, MouseEventArgs e)
     {
@@ -1304,10 +1255,10 @@ public class FileDialog : Dialog, IDesignable
         // really not what most users would expect
         if (Regex.IsMatch (path, "^\\w:$"))
         {
-            return _fileSystem.DirectoryInfo.New (path + _fileSystem.Path.DirectorySeparatorChar);
+            return _fileSystem!.DirectoryInfo.New (path + _fileSystem.Path.DirectorySeparatorChar);
         }
 
-        return _fileSystem.DirectoryInfo.New (path);
+        return _fileSystem!.DirectoryInfo.New (path);
     }
 
     private static string StripArrows (string columnName) { return columnName.Replace (" (▼)", string.Empty).Replace (" (▲)", string.Empty); }
@@ -1359,7 +1310,7 @@ public class FileDialog : Dialog, IDesignable
         return false;
     }
 
-    private void TableView_SelectedCellChanged (object sender, SelectedCellChangedEventArgs obj)
+    private void TableView_SelectedCellChanged (object? sender, SelectedCellChangedEventArgs obj)
     {
         if (!_tableView.HasFocus || obj.NewRow == -1 || obj.Table.Rows == 0)
         {
@@ -1373,11 +1324,6 @@ public class FileDialog : Dialog, IDesignable
 
         FileSystemInfoStats stats = RowToStats (obj.NewRow);
 
-        if (stats is null)
-        {
-            return;
-        }
-
         IFileSystemInfo dest;
 
         if (stats.IsParent)
@@ -1403,7 +1349,7 @@ public class FileDialog : Dialog, IDesignable
         }
     }
 
-    private void TreeView_SelectionChanged (object sender, SelectionChangedEventArgs<IFileSystemInfo> e)
+    private void TreeView_SelectionChanged (object? sender, SelectionChangedEventArgs<IFileSystemInfo> e)
     {
         SetPathToSelectedObject (e.NewValue);
     }
@@ -1436,7 +1382,7 @@ public class FileDialog : Dialog, IDesignable
     private bool TryAcceptMulti ()
     {
         IEnumerable<FileSystemInfoStats> multi = MultiRowToStats ();
-        string reason = null;
+        string? reason = null;
 
         if (!multi.Any ())
         {
@@ -1473,11 +1419,6 @@ public class FileDialog : Dialog, IDesignable
 
     private void WriteStateToTableView ()
     {
-        if (State is null)
-        {
-            return;
-        }
-
         _tableView.Table =
             new FileDialogTableSource (this, State, Style, _currentSortColumn, _currentSortIsAsc);
 
@@ -1498,7 +1439,7 @@ public class FileDialog : Dialog, IDesignable
         public SearchState (IDirectoryInfo dir, FileDialog parent, string searchTerms) : base (dir, parent)
         {
             parent.SearchMatcher.Initialize (searchTerms);
-            Children = new FileSystemInfoStats [0];
+            Children = [];
             BeginSearch ();
         }
 

+ 0 - 29
Terminal.Gui/Views/SplitterEventArgs.cs

@@ -1,29 +0,0 @@
-
-namespace Terminal.Gui.Views;
-
-/// <summary>Provides data for <see cref="TileView"/> events.</summary>
-public class SplitterEventArgs : EventArgs
-{
-    /// <summary>Creates a new instance of the <see cref="SplitterEventArgs"/> class.</summary>
-    /// <param name="tileView"><see cref="TileView"/> in which splitter is being moved.</param>
-    /// <param name="idx">Index of the splitter being moved in <see cref="TileView.SplitterDistances"/>.</param>
-    /// <param name="splitterDistance">The new <see cref="Pos"/> of the splitter line.</param>
-    public SplitterEventArgs (TileView tileView, int idx, Pos splitterDistance)
-    {
-        SplitterDistance = splitterDistance;
-        TileView = tileView;
-        Idx = idx;
-    }
-
-    /// <summary>
-    ///     Gets the index of the splitter that is being moved. This can be used to index
-    ///     <see cref="TileView.SplitterDistances"/>
-    /// </summary>
-    public int Idx { get; }
-
-    /// <summary>New position of the splitter line (see <see cref="TileView.SplitterDistances"/>).</summary>
-    public Pos SplitterDistance { get; }
-
-    /// <summary>Container (sender) of the event.</summary>
-    public TileView TileView { get; }
-}

+ 0 - 97
Terminal.Gui/Views/Tile.cs

@@ -1,97 +0,0 @@
-#nullable enable
-using System.ComponentModel;
-
-namespace Terminal.Gui.Views;
-
-/// <summary>
-///     A single <see cref="ContentView"/> presented in a <see cref="TileView"/>. To create new instances use
-///     <see cref="TileView.RebuildForTileCount(int)"/> or <see cref="TileView.InsertTile(int)"/>.
-/// </summary>
-public class Tile
-{
-    private string _title = string.Empty;
-
-    /// <summary>Creates a new instance of the <see cref="Tile"/> class.</summary>
-    public Tile ()
-    {
-        ContentView = new View
-        {
-            Width = Dim.Fill (),
-            Height = Dim.Fill (),
-            CanFocus = true
-        };
-#if DEBUG_IDISPOSABLE
-        ContentView.Data = "Tile.ContentView";
-#endif
-        Title = string.Empty;
-        MinSize = 0;
-    }
-
-    /// <summary>
-    ///     The <see cref="ContentView"/> that is contained in this <see cref="TileView"/>. Add new child views to this
-    ///     member for multiple <see cref="ContentView"/>s within the <see cref="Tile"/>.
-    /// </summary>
-    public View? ContentView { get; internal set; }
-
-    /// <summary>
-    ///     Gets or Sets the minimum size you to allow when splitter resizing along parent
-    ///     <see cref="TileView.Orientation"/> direction.
-    /// </summary>
-    public int MinSize { get; set; }
-
-    /// <summary>
-    ///     The text that should be displayed above the <see cref="ContentView"/>. This will appear over the splitter line
-    ///     or border (above the view client area).
-    /// </summary>
-    /// <remarks>Title are not rendered for root level tiles <see cref="LineStyle"/> is <see cref="LineStyle.None"/>.</remarks>
-    public string Title
-    {
-        get => _title;
-        set
-        {
-            if (!OnTitleChanging (_title, value))
-            {
-                string old = _title;
-                _title = value;
-                OnTitleChanged (old, _title);
-
-                return;
-            }
-
-            _title = value;
-        }
-    }
-
-    /// <summary>Called when the <see cref="Title"/> has been changed. Invokes the <see cref="TitleChanged"/> event.</summary>
-    /// <param name="oldTitle">The <see cref="Title"/> that is/has been replaced.</param>
-    /// <param name="newTitle">The new <see cref="Title"/> to be replaced.</param>
-    public virtual void OnTitleChanged (string oldTitle, string newTitle)
-    {
-        var args = new EventArgs<string> (in newTitle);
-        TitleChanged?.Invoke (this, args);
-    }
-
-    /// <summary>
-    ///     Called before the <see cref="Title"/> changes. Invokes the <see cref="TitleChanging"/> event, which can be
-    ///     cancelled.
-    /// </summary>
-    /// <param name="oldTitle">The <see cref="Title"/> that is/has been replaced.</param>
-    /// <param name="newTitle">The new <see cref="Title"/> to be replaced.</param>
-    /// <returns><c>true</c> if an event handler cancelled the Title change.</returns>
-    public virtual bool OnTitleChanging (string oldTitle, string newTitle)
-    {
-        var args = new CancelEventArgs<string> (ref oldTitle, ref newTitle);
-        TitleChanging?.Invoke (this, args);
-
-        return args.Cancel;
-    }
-
-    /// <summary>Event fired after the <see cref="Title"/> has been changed.</summary>
-    public event EventHandler? TitleChanged;
-
-    /// <summary>
-    ///     Event fired when the <see cref="Title"/> is changing.
-    ///     <see cref="CancelEventArgs.Cancel"/> can be set to <c>true</c> to cancel the change.
-    /// </summary>
-    public event EventHandler<CancelEventArgs<string>>? TitleChanging;
-}

+ 0 - 1093
Terminal.Gui/Views/TileView.cs

@@ -1,1093 +0,0 @@
-#nullable enable
-
-namespace Terminal.Gui.Views;
-
-/// <summary>
-///     A <see cref="View"/> consisting of a moveable bar that divides the display area into resizeable
-///     <see cref="Tiles"/>.
-/// </summary>
-public class TileView : View
-{
-    private Orientation _orientation = Orientation.Vertical;
-    private List<Pos>? _splitterDistances;
-    private List<TileViewLineView>? _splitterLines;
-    private List<Tile>? _tiles;
-    private TileView? _parentTileView;
-
-    /// <summary>Creates a new instance of the <see cref="TileView"/> class with 2 tiles (i.e. left and right).</summary>
-    public TileView () : this (2) { }
-
-    /// <summary>Creates a new instance of the <see cref="TileView"/> class with <paramref name="tiles"/> number of tiles.</summary>
-    /// <param name="tiles"></param>
-    public TileView (int tiles)
-    {
-        CanFocus = true;
-        RebuildForTileCount (tiles);
-
-        SubViewLayout += (_, _) =>
-                         {
-                             Rectangle viewport = Viewport;
-
-                             if (HasBorder ())
-                             {
-                                 viewport = new (
-                                                 viewport.X + 1,
-                                                 viewport.Y + 1,
-                                                 Math.Max (0, viewport.Width - 2),
-                                                 Math.Max (0, viewport.Height - 2)
-                                                );
-                             }
-
-                             Setup (viewport);
-                         };
-    }
-
-    /// <summary>The line style to use when drawing the splitter lines.</summary>
-    public LineStyle LineStyle { get; set; } = LineStyle.None;
-
-    /// <summary>Orientation of the dividing line (Horizontal or Vertical).</summary>
-    public Orientation Orientation
-    {
-        get => _orientation;
-        set
-        {
-            if (_orientation == value)
-            {
-                return;
-            }
-
-            _orientation = value;
-
-            SetNeedsDraw ();
-            SetNeedsLayout ();
-
-        }
-    }
-
-    /// <summary>The splitter locations. Note that there will be N-1 splitters where N is the number of <see cref="Tiles"/>.</summary>
-    public IReadOnlyCollection<Pos> SplitterDistances => _splitterDistances!.AsReadOnly ();
-
-    /// <summary>The sub sections hosted by the view</summary>
-    public IReadOnlyCollection<Tile> Tiles => _tiles!.AsReadOnly ();
-
-    // TODO: Update to use Key instead of KeyCode
-    /// <summary>
-    ///     The keyboard key that the user can press to toggle resizing of splitter lines.  Mouse drag splitting is always
-    ///     enabled.
-    /// </summary>
-    public KeyCode ToggleResizable { get; set; } = KeyCode.CtrlMask | KeyCode.F10;
-
-    /// <summary>
-    ///     Returns the immediate parent <see cref="TileView"/> of this. Note that in case of deep nesting this might not
-    ///     be the root <see cref="TileView"/>. Returns null if this instance is not a nested child (created with
-    ///     <see cref="TrySplitTile(int, int, out TileView)"/>)
-    /// </summary>
-    /// <remarks>Use <see cref="IsRootTileView"/> to determine if the returned value is the root.</remarks>
-    /// <returns></returns>
-    public TileView? GetParentTileView () { return _parentTileView; }
-
-    /// <summary>
-    ///     Returns the index of the first <see cref="Tile"/> in <see cref="Tiles"/> which contains
-    ///     <paramref name="toFind"/>.
-    /// </summary>
-    public int IndexOf (View toFind, bool recursive = false)
-    {
-        for (var i = 0; i < _tiles!.Count; i++)
-        {
-            View v = _tiles [i].ContentView!;
-
-            if (v == toFind)
-            {
-                return i;
-            }
-
-            if (v.SubViews.Contains (toFind))
-            {
-                return i;
-            }
-
-            if (recursive)
-            {
-                if (RecursiveContains (v.SubViews, toFind))
-                {
-                    return i;
-                }
-            }
-        }
-
-        return -1;
-    }
-
-    /// <summary>
-    ///     Adds a new <see cref="Tile"/> to the collection at <paramref name="idx"/>. This will also add another splitter
-    ///     line
-    /// </summary>
-    /// <param name="idx"></param>
-    public Tile? InsertTile (int idx)
-    {
-        Tile [] oldTiles = Tiles.ToArray ();
-        RebuildForTileCount (oldTiles.Length + 1);
-
-        Tile? toReturn = null;
-
-        for (var i = 0; i < _tiles?.Count; i++)
-        {
-            if (i != idx)
-            {
-                Tile oldTile = oldTiles [i > idx ? i - 1 : i];
-
-                // remove the new empty View
-                Remove (_tiles [i].ContentView);
-                _tiles [i].ContentView?.Dispose ();
-                _tiles [i].ContentView = null;
-
-                // restore old Tile and View
-                _tiles [i] = oldTile;
-                _tiles [i].ContentView!.TabStop = TabStop;
-                Add (_tiles [i].ContentView);
-            }
-            else
-            {
-                toReturn = _tiles [i];
-            }
-        }
-
-        SetNeedsDraw ();
-        SetNeedsLayout ();
-
-        return toReturn;
-    }
-
-    /// <summary>
-    ///     <para>
-    ///         <see langword="true"/> if <see cref="TileView"/> is nested within a parent <see cref="TileView"/> e.g. via
-    ///         the <see cref="TrySplitTile"/>. <see langword="false"/> if it is a root level <see cref="TileView"/>.
-    ///     </para>
-    /// </summary>
-    /// <remarks>
-    ///     Note that manually adding one <see cref="TileView"/> to another will not result in a parent/child relationship
-    ///     and both will still be considered 'root' containers. Always use <see cref="TrySplitTile(int, int, out TileView)"/>
-    ///     if you want to subdivide a <see cref="TileView"/>.
-    /// </remarks>
-    /// <returns></returns>
-    public bool IsRootTileView () { return _parentTileView == null; }
-
-    /// <summary>Overridden so no Frames get drawn</summary>
-    /// <returns></returns>
-    protected override bool OnDrawingAdornments () { return true; }
-
-    /// <inheritdoc/>
-    protected override bool OnRenderingLineCanvas () { return false; }
-
-    /// <inheritdoc/>
-    protected override void OnDrawComplete (DrawContext? context)
-    {
-        SetAttributeForRole (Enabled ? VisualRole.Normal : VisualRole.Disabled);
-
-        var lc = new LineCanvas ();
-
-        List<TileViewLineView> allLines = GetAllLineViewsRecursively (this);
-        List<TileTitleToRender> allTitlesToRender = GetAllTitlesToRenderRecursively (this);
-
-        if (IsRootTileView ())
-        {
-            if (HasBorder ())
-            {
-                lc.AddLine (Point.Empty, Viewport.Width, Orientation.Horizontal, LineStyle);
-                lc.AddLine (Point.Empty, Viewport.Height, Orientation.Vertical, LineStyle);
-
-                lc.AddLine (
-                            new (Viewport.Width - 1, Viewport.Height - 1),
-                            -Viewport.Width,
-                            Orientation.Horizontal,
-                            LineStyle
-                           );
-
-                lc.AddLine (
-                            new (Viewport.Width - 1, Viewport.Height - 1),
-                            -Viewport.Height,
-                            Orientation.Vertical,
-                            LineStyle
-                           );
-            }
-
-            foreach (TileViewLineView line in allLines)
-            {
-                bool isRoot = _splitterLines!.Contains (line);
-
-                Rectangle screen = line.ViewportToScreen (Rectangle.Empty);
-                Point origin = ScreenToFrame (screen.Location);
-                int length = line.Orientation == Orientation.Horizontal ? line.Frame.Width : line.Frame.Height;
-
-                if (!isRoot)
-                {
-                    if (line.Orientation == Orientation.Horizontal)
-                    {
-                        origin.X -= 1;
-                    }
-                    else
-                    {
-                        origin.Y -= 1;
-                    }
-
-                    length += 2;
-                }
-
-                lc.AddLine (origin, length, line.Orientation, LineStyle);
-            }
-        }
-
-        SetAttributeForRole (Enabled ? VisualRole.Normal : VisualRole.Disabled);
-
-        foreach (KeyValuePair<Point, Rune> p in lc.GetMap (Viewport))
-        {
-            AddRune (p.Key.X, p.Key.Y, p.Value);
-        }
-
-        // Redraw the lines so that focus/drag symbol renders
-        foreach (TileViewLineView line in allLines)
-        {
-            line.DrawSplitterSymbol ();
-        }
-
-        // Draw Titles over Border
-
-        foreach (TileTitleToRender titleToRender in allTitlesToRender)
-        {
-            Point renderAt = titleToRender.GetLocalCoordinateForTitle (this);
-
-            if (renderAt.Y < 0)
-            {
-                // If we have no border then root level tiles
-                // have nowhere to render their titles.
-                continue;
-            }
-
-            // TODO: Render with focus color if focused
-
-            string title = titleToRender.GetTrimmedTitle ();
-
-            for (var i = 0; i < title.Length; i++)
-            {
-                AddRune (renderAt.X + i, renderAt.Y, (Rune)title [i]);
-            }
-        }
-
-        return;
-    }
-
-    //// BUGBUG: Why is this not handled by a key binding???
-    /// <inheritdoc/>
-    protected override bool OnKeyDownNotHandled (Key key)
-    {
-        var focusMoved = false;
-
-        if (key.KeyCode == ToggleResizable)
-        {
-            foreach (TileViewLineView l in _splitterLines!)
-            {
-                bool iniBefore = l.IsInitialized;
-                l.IsInitialized = false;
-                l.CanFocus = !l.CanFocus;
-                l.IsInitialized = iniBefore;
-
-                if (l.CanFocus && !focusMoved)
-                {
-                    l.SetFocus ();
-                    focusMoved = true;
-                }
-            }
-
-            return true;
-        }
-
-        return false;
-    }
-
-    /// <summary>
-    ///     Scraps all <see cref="Tiles"/> and creates <paramref name="count"/> new tiles in orientation
-    ///     <see cref="Orientation"/>
-    /// </summary>
-    /// <param name="count"></param>
-    public void RebuildForTileCount (int count)
-    {
-        _tiles = new ();
-        _splitterDistances = new ();
-
-        if (_splitterLines is { })
-        {
-            foreach (TileViewLineView sl in _splitterLines)
-            {
-                sl.Dispose ();
-            }
-        }
-
-        _splitterLines = new ();
-
-        RemoveAll ();
-
-        foreach (Tile tile in _tiles)
-        {
-            tile.ContentView?.Dispose ();
-            tile.ContentView = null;
-        }
-
-        _tiles.Clear ();
-        _splitterDistances.Clear ();
-
-        if (count == 0)
-        {
-            return;
-        }
-
-        for (var i = 0; i < count; i++)
-        {
-            if (i > 0)
-            {
-                Pos currentPos = Pos.Percent (100 / count * i);
-                _splitterDistances.Add (currentPos);
-                var line = new TileViewLineView (this, i - 1);
-                Add (line);
-                _splitterLines.Add (line);
-            }
-
-            var tile = new Tile ();
-            _tiles.Add (tile);
-            tile.ContentView!.Id = $"Tile.ContentView {i}";
-            Add (tile.ContentView);
-
-            // BUGBUG: This should not be needed:
-            tile.TitleChanged += (s, e) => SetNeedsLayout ();
-        }
-
-        SetNeedsLayout ();
-    }
-
-    /// <summary>
-    ///     Removes a <see cref="Tiles"/> at the provided <paramref name="idx"/> from the view. Returns the removed tile
-    ///     or null if already empty.
-    /// </summary>
-    /// <param name="idx"></param>
-    /// <returns></returns>
-    public Tile? RemoveTile (int idx)
-    {
-        Tile [] oldTiles = Tiles.ToArray ();
-
-        if (idx < 0 || idx >= oldTiles.Length)
-        {
-            return null;
-        }
-
-        Tile removed = Tiles.ElementAt (idx);
-
-        RebuildForTileCount (oldTiles.Length - 1);
-
-        for (var i = 0; i < _tiles?.Count; i++)
-        {
-            int oldIdx = i >= idx ? i + 1 : i;
-            Tile oldTile = oldTiles [oldIdx];
-
-            // remove the new empty View
-            Remove (_tiles [i].ContentView);
-            _tiles [i].ContentView?.Dispose ();
-            _tiles [i].ContentView = null;
-
-            // restore old Tile and View
-            _tiles [i] = oldTile;
-            Add (_tiles [i].ContentView);
-        }
-
-        return removed;
-    }
-
-    /// <summary>
-    ///     <para>
-    ///         Attempts to update the <see cref="SplitterDistances"/> of line at <paramref name="idx"/> to the new
-    ///         <paramref name="value"/>. Returns false if the new position is not allowed because of
-    ///         <see cref="Tile.MinSize"/>, location of other splitters etc.
-    ///     </para>
-    ///     <para>
-    ///         Only absolute values (e.g. 10) and percent values (i.e. <see cref="Pos.Percent(int)"/>) are supported for
-    ///         this property.
-    ///     </para>
-    /// </summary>
-    public bool SetSplitterPos (int idx, Pos value)
-    {
-        if (!(value is PosAbsolute) && !(value is PosPercent))
-        {
-            throw new ArgumentException (
-                                         $"Only Percent and Absolute values are supported. Passed value was {value.GetType ().Name}"
-                                        );
-        }
-
-        int fullSpace = _orientation == Orientation.Vertical ? Viewport.Width : Viewport.Height;
-
-        if (fullSpace != 0 && !IsValidNewSplitterPos (idx, value, fullSpace))
-        {
-            return false;
-        }
-
-        if (_splitterDistances is { })
-        {
-            _splitterDistances [idx] = value;
-        }
-
-        OnSplitterMoved (idx);
-        SetNeedsDraw ();
-        SetNeedsLayout ();
-
-        return true;
-    }
-
-    /// <summary>Invoked when any of the <see cref="SplitterDistances"/> is changed.</summary>
-    public event SplitterEventHandler? SplitterMoved;
-
-    /// <summary>
-    ///     Converts of <see cref="Tiles"/> element <paramref name="idx"/> from a regular <see cref="View"/> to a new
-    ///     nested <see cref="TileView"/> the specified <paramref name="numberOfPanels"/>. Returns false if the element already
-    ///     contains a nested view.
-    /// </summary>
-    /// <remarks>
-    ///     After successful splitting, the old contents will be moved to the <paramref name="result"/>
-    ///     <see cref="TileView"/> 's first tile.
-    /// </remarks>
-    /// <param name="idx">The element of <see cref="Tiles"/> that is to be subdivided.</param>
-    /// <param name="numberOfPanels">The number of panels that the <see cref="Tile"/> should be split into</param>
-    /// <param name="result">The new nested <see cref="TileView"/>.</param>
-    /// <returns>
-    ///     <see langword="true"/> if a <see cref="View"/> was converted to a new nested <see cref="TileView"/>.
-    ///     <see langword="false"/> if it was already a nested <see cref="TileView"/>
-    /// </returns>
-    public bool TrySplitTile (int idx, int numberOfPanels, out TileView result)
-    {
-        // when splitting a view into 2 sub views we will need to migrate
-        // the title too
-        Tile tile = _tiles! [idx];
-
-        string title = tile.Title;
-        View? toMove = tile.ContentView;
-
-        if (toMove is TileView existing)
-        {
-            result = existing;
-
-            return false;
-        }
-
-        var newContainer = new TileView (numberOfPanels)
-        {
-            Width = Dim.Fill (), Height = Dim.Fill (), _parentTileView = this
-        };
-
-        // Take everything out of the View we are moving
-        View [] childViews = toMove!.SubViews.ToArray ();
-        toMove.RemoveAll ();
-
-        // Remove the view itself and replace it with the new TileView
-        Remove (toMove);
-        toMove.Dispose ();
-        toMove = null;
-
-        Add (newContainer);
-
-        tile.ContentView = newContainer;
-
-        View newTileView1 = newContainer!._tiles? [0].ContentView!;
-
-        // Add the original content into the first view of the new container
-        foreach (View childView in childViews)
-        {
-            newTileView1!.Add (childView);
-        }
-
-        // Move the title across too
-        newContainer._tiles! [0].Title = title;
-        tile.Title = string.Empty;
-
-        result = newContainer;
-
-        return true;
-    }
-
-    /// <inheritdoc/>
-    protected override void Dispose (bool disposing)
-    {
-        foreach (Tile tile in Tiles)
-        {
-            Remove (tile.ContentView);
-            tile.ContentView?.Dispose ();
-        }
-
-        base.Dispose (disposing);
-    }
-
-    /// <summary>Raises the <see cref="SplitterMoved"/> event</summary>
-    protected virtual void OnSplitterMoved (int idx) { SplitterMoved?.Invoke (this, new (this, idx, _splitterDistances! [idx])); }
-
-    private List<TileViewLineView> GetAllLineViewsRecursively (View v)
-    {
-        List<TileViewLineView> lines = new ();
-
-        foreach (View sub in v.SubViews)
-        {
-            if (sub is TileViewLineView s)
-            {
-                if (s.Visible && s.Parent.GetRootTileView () == this)
-                {
-                    lines.Add (s);
-                }
-            }
-            else
-            {
-                if (sub.Visible)
-                {
-                    lines.AddRange (GetAllLineViewsRecursively (sub));
-                }
-            }
-        }
-
-        return lines;
-    }
-
-    private List<TileTitleToRender> GetAllTitlesToRenderRecursively (TileView? v, int depth = 0)
-    {
-        List<TileTitleToRender> titles = new ();
-
-        foreach (Tile sub in v!.Tiles)
-        {
-            // Don't render titles for invisible stuff!
-            if (!sub.ContentView!.Visible)
-            {
-                continue;
-            }
-
-            if (sub.ContentView is TileView subTileView)
-            {
-                // Panels with sub split tiles in them can never
-                // have their Titles rendered. Instead we dive in
-                // and pull up their children as titles
-                titles.AddRange (GetAllTitlesToRenderRecursively (subTileView, depth + 1));
-            }
-            else
-            {
-                if (sub.Title.Length > 0)
-                {
-                    titles.Add (new (v, sub, depth));
-                }
-            }
-        }
-
-        return titles;
-    }
-
-    private TileView GetRootTileView ()
-    {
-        TileView root = this;
-
-        while (root._parentTileView is { })
-        {
-            root = root._parentTileView;
-        }
-
-        return root;
-    }
-
-    private Dim GetTileWidthOrHeight (int i, int space, Tile? [] visibleTiles, TileViewLineView? [] visibleSplitterLines)
-    {
-        // last tile
-        if (i + 1 >= visibleTiles.Length)
-        {
-            return Dim.Fill (HasBorder () ? 1 : 0)!;
-        }
-
-        TileViewLineView? nextSplitter = visibleSplitterLines [i];
-        Pos? nextSplitterPos = Orientation == Orientation.Vertical ? nextSplitter!.X : nextSplitter!.Y;
-        int nextSplitterDistance = nextSplitterPos.GetAnchor (space);
-
-        TileViewLineView? lastSplitter = i >= 1 ? visibleSplitterLines [i - 1] : null;
-        Pos? lastSplitterPos = Orientation == Orientation.Vertical ? lastSplitter?.X : lastSplitter?.Y;
-        int lastSplitterDistance = lastSplitterPos?.GetAnchor (space) ?? 0;
-
-        int distance = nextSplitterDistance - lastSplitterDistance;
-
-        if (i > 0)
-        {
-            return distance - 1;
-        }
-
-        return distance - (HasBorder () ? 1 : 0);
-    }
-
-    private bool HasBorder () { return LineStyle != LineStyle.None; }
-
-    private void HideSplittersBasedOnTileVisibility ()
-    {
-        if (_splitterLines is { Count: 0 })
-        {
-            return;
-        }
-
-        foreach (TileViewLineView line in _splitterLines!)
-        {
-            line.Visible = true;
-        }
-
-        for (var i = 0; i < _tiles!.Count; i++)
-        {
-            if (!_tiles [i].ContentView!.Visible)
-            {
-                // when a tile is not visible, prefer hiding
-                // the splitter on it's left
-                TileViewLineView candidate = _splitterLines [Math.Max (0, i - 1)];
-
-                // unless that splitter is already hidden
-                // e.g. when hiding panels 0 and 1 of a 3 panel 
-                // container
-                if (candidate.Visible)
-                {
-                    candidate.Visible = false;
-                }
-                else
-                {
-                    _splitterLines [Math.Min (i, _splitterLines.Count - 1)].Visible = false;
-                }
-            }
-        }
-    }
-
-    private bool IsValidNewSplitterPos (int idx, Pos value, int fullSpace)
-    {
-        int newSize = value.GetAnchor (fullSpace);
-        bool isGettingBigger = newSize > _splitterDistances! [idx].GetAnchor (fullSpace);
-        int lastSplitterOrBorder = HasBorder () ? 1 : 0;
-        int nextSplitterOrBorder = HasBorder () ? fullSpace - 1 : fullSpace;
-
-        // Cannot move off screen right
-        if (newSize >= fullSpace - (HasBorder () ? 1 : 0))
-        {
-            if (isGettingBigger)
-            {
-                return false;
-            }
-        }
-
-        // Cannot move off screen left
-        if (newSize < (HasBorder () ? 1 : 0))
-        {
-            if (!isGettingBigger)
-            {
-                return false;
-            }
-        }
-
-        // Do not allow splitter to move left of the one before
-        if (idx > 0)
-        {
-            int posLeft = _splitterDistances [idx - 1].GetAnchor (fullSpace);
-
-            if (newSize <= posLeft)
-            {
-                return false;
-            }
-
-            lastSplitterOrBorder = posLeft;
-        }
-
-        // Do not allow splitter to move right of the one after
-        if (idx + 1 < _splitterDistances.Count)
-        {
-            int posRight = _splitterDistances [idx + 1].GetAnchor (fullSpace);
-
-            if (newSize >= posRight)
-            {
-                return false;
-            }
-
-            nextSplitterOrBorder = posRight;
-        }
-
-        if (isGettingBigger)
-        {
-            int spaceForNext = nextSplitterOrBorder - newSize;
-
-            // space required for the last line itself
-            if (idx > 0)
-            {
-                spaceForNext--;
-            }
-
-            // don't grow if it would take us below min size of right panel
-            if (spaceForNext < _tiles! [idx + 1].MinSize)
-            {
-                return false;
-            }
-        }
-        else
-        {
-            int spaceForLast = newSize - lastSplitterOrBorder;
-
-            // space required for the line itself
-            if (idx > 0)
-            {
-                spaceForLast--;
-            }
-
-            // don't shrink if it would take us below min size of left panel
-            if (spaceForLast < _tiles! [idx].MinSize)
-            {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    private bool RecursiveContains (IEnumerable<View> haystack, View needle)
-    {
-        foreach (View v in haystack)
-        {
-            if (v == needle)
-            {
-                return true;
-            }
-
-            if (RecursiveContains (v.SubViews, needle))
-            {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    private void Setup (Rectangle viewport)
-    {
-        if (viewport.IsEmpty || viewport.Height <= 0 || viewport.Width <= 0)
-        {
-            return;
-        }
-
-        for (var i = 0; i < _splitterLines!.Count; i++)
-        {
-            TileViewLineView line = _splitterLines [i];
-
-            line.Orientation = Orientation;
-
-            line.Width = _orientation == Orientation.Vertical
-                             ? 1
-                             : Dim.Fill ();
-
-            line.Height = _orientation == Orientation.Vertical
-                              ? Dim.Fill ()
-                              : 1;
-
-            if (_orientation == Orientation.Vertical)
-            {
-                line.X = _splitterDistances! [i];
-                line.Y = 0;
-            }
-            else
-            {
-                line.Y = _splitterDistances! [i];
-                line.X = 0;
-            }
-        }
-
-        HideSplittersBasedOnTileVisibility ();
-
-        Tile [] visibleTiles = _tiles!.Where (t => t.ContentView!.Visible).ToArray ();
-        TileViewLineView [] visibleSplitterLines = _splitterLines.Where (l => l.Visible).ToArray ();
-
-        for (var i = 0; i < visibleTiles.Length; i++)
-        {
-            Tile tile = visibleTiles [i];
-
-            if (Orientation == Orientation.Vertical)
-            {
-                tile.ContentView!.X = i == 0 ? viewport.X : Pos.Right (visibleSplitterLines [i - 1]);
-                tile.ContentView.Y = viewport.Y;
-                tile.ContentView.Height = viewport.Height;
-                tile.ContentView.Width = GetTileWidthOrHeight (i, Viewport.Width, visibleTiles, visibleSplitterLines);
-            }
-            else
-            {
-                tile.ContentView!.X = viewport.X;
-                tile.ContentView.Y = i == 0 ? viewport.Y : Pos.Bottom (visibleSplitterLines [i - 1]);
-                tile.ContentView.Width = viewport.Width;
-                tile.ContentView.Height = GetTileWidthOrHeight (i, Viewport.Height, visibleTiles, visibleSplitterLines);
-            }
-
-            //  BUGBUG: This should not be needed. If any of the pos/dim setters above actually changed values, NeedsDisplay should have already been set. 
-            tile.ContentView.SetNeedsDraw ();
-        }
-    }
-
-    private class TileTitleToRender
-    {
-        public TileTitleToRender (TileView? parent, Tile tile, int depth)
-        {
-            Parent = parent;
-            Tile = tile;
-            Depth = depth;
-        }
-
-        public int Depth { get; }
-        public TileView? Parent { get; }
-        public Tile? Tile { get; }
-
-        /// <summary>
-        ///     Translates the <see cref="Tile"/> title location from its local coordinate space
-        ///     <paramref name="intoCoordinateSpace"/>.
-        /// </summary>
-        public Point GetLocalCoordinateForTitle (TileView intoCoordinateSpace)
-        {
-            Rectangle screen = Tile!.ContentView!.ViewportToScreen (Rectangle.Empty);
-
-            return intoCoordinateSpace.ScreenToFrame (new (screen.X, screen.Y - 1));
-        }
-
-        internal string GetTrimmedTitle ()
-        {
-            Dim? spaceDim = Tile?.ContentView?.Width;
-
-            int spaceAbs = spaceDim!.GetAnchor (Parent!.Viewport.Width);
-
-            var title = $" {Tile!.Title} ";
-
-            if (title.Length > spaceAbs)
-            {
-                return title!.Substring (0, spaceAbs);
-            }
-
-            return title;
-        }
-    }
-
-    private class TileViewLineView : Line
-    {
-        public Point? moveRuneRenderLocation;
-
-        private Pos? dragOrignalPos;
-        private Point? dragPosition;
-
-        public TileViewLineView (TileView parent, int idx)
-        {
-            CanFocus = false;
-            TabStop = TabBehavior.TabStop;
-
-            Parent = parent;
-            Idx = idx;
-            AddCommand (Command.Right, () => MoveSplitter (1, 0));
-
-            AddCommand (Command.Left, () => MoveSplitter (-1, 0));
-
-            AddCommand (Command.Up, () => MoveSplitter (0, -1));
-
-            AddCommand (Command.Down, () => MoveSplitter (0, 1));
-
-            KeyBindings.Add (Key.CursorRight, Command.Right);
-            KeyBindings.Add (Key.CursorLeft, Command.Left);
-            KeyBindings.Add (Key.CursorUp, Command.Up);
-            KeyBindings.Add (Key.CursorDown, Command.Down);
-        }
-
-        public int Idx { get; }
-        public TileView Parent { get; }
-
-        public void DrawSplitterSymbol ()
-        {
-            if (dragPosition is { } || CanFocus)
-            {
-                Point location = moveRuneRenderLocation ?? new Point (Viewport.Width / 2, Viewport.Height / 2);
-
-                AddRune (location.X, location.Y, Glyphs.Diamond);
-            }
-        }
-
-        protected override bool OnMouseEvent (MouseEventArgs mouseEvent)
-        {
-            if (!dragPosition.HasValue && mouseEvent.Flags == MouseFlags.Button1Pressed)
-            {
-                // Start a Drag
-                SetFocus ();
-
-                if (mouseEvent.Flags == MouseFlags.Button1Pressed)
-                {
-                    dragPosition = mouseEvent.Position;
-                    dragOrignalPos = Orientation == Orientation.Horizontal ? Y : X;
-                    Application.MouseGrabHandler.GrabMouse (this);
-
-                    if (Orientation == Orientation.Horizontal)
-                    { }
-                    else
-                    {
-                        moveRuneRenderLocation = new Point (
-                                                            0,
-                                                            Math.Max (1, Math.Min (Viewport.Height - 2, mouseEvent.Position.Y))
-                                                           );
-                    }
-                }
-
-                return true;
-            }
-
-            if (
-                dragPosition.HasValue && mouseEvent.Flags == (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition))
-            {
-                // Continue Drag
-
-                // how far has user dragged from original location?
-                if (Orientation == Orientation.Horizontal)
-                {
-                    int dy = mouseEvent.Position.Y - dragPosition.Value.Y;
-                    Parent.SetSplitterPos (Idx, Offset (Y, dy));
-                    moveRuneRenderLocation = new Point (mouseEvent.Position.X, 0);
-                }
-                else
-                {
-                    int dx = mouseEvent.Position.X - dragPosition.Value.X;
-                    Parent.SetSplitterPos (Idx, Offset (X, dx));
-                    moveRuneRenderLocation = new Point (0, Math.Max (1, Math.Min (Viewport.Height - 2, mouseEvent.Position.Y)));
-                }
-
-                Parent.SetNeedsLayout ();
-
-                return true;
-            }
-
-            if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Released) && dragPosition.HasValue)
-            {
-                // End Drag
-
-                Application.MouseGrabHandler.UngrabMouse ();
-
-                //Driver.UncookMouse ();
-                FinalisePosition (
-                                  dragOrignalPos!,
-                                  Orientation == Orientation.Horizontal ? Y : X
-                                 );
-                dragPosition = null;
-                moveRuneRenderLocation = null;
-            }
-
-            return false;
-        }
-
-        /// <inheritdoc/>
-        protected override bool OnClearingViewport () { return true; }
-
-        protected override bool OnDrawingContent ()
-        {
-            DrawSplitterSymbol ();
-
-            return true;
-        }
-
-        public override Point? PositionCursor ()
-        {
-            base.PositionCursor ();
-
-            Point location = moveRuneRenderLocation ?? new Point (Viewport.Width / 2, Viewport.Height / 2);
-            Move (location.X, location.Y);
-
-            return null; // Hide cursor
-        }
-
-        /// <summary>
-        ///     <para>
-        ///         Determines the absolute position of <paramref name="p"/> and returns a <see cref="PosPercent"/> that
-        ///         describes the percentage of that.
-        ///     </para>
-        ///     <para>
-        ///         Effectively turning any <see cref="Pos"/> into a <see cref="PosPercent"/> (as if created with
-        ///         <see cref="Pos.Percent(int)"/>)
-        ///     </para>
-        /// </summary>
-        /// <param name="p">The <see cref="Pos"/> to convert to <see cref="Pos.Percent(int)"/></param>
-        /// <param name="parentLength">The Height/Width that <paramref name="p"/> lies within</param>
-        /// <returns></returns>
-        private Pos ConvertToPosPercent (Pos p, int parentLength)
-        {
-            // Calculate position in the 'middle' of the cell at p distance along parentLength
-            float position = p.GetAnchor (parentLength) + 0.5f;
-
-            // Calculate the percentage
-            var percent = (int)Math.Round (position / parentLength * 100);
-
-            // Return a new PosPercent object
-            return Pos.Percent (percent);
-        }
-
-        /// <summary>
-        ///     <para>
-        ///         Moves <see cref="Parent"/> <see cref="TileView.SplitterDistances"/> to <see cref="Pos"/>
-        ///         <paramref name="newValue"/> preserving <see cref="Pos"/> format (absolute / relative) that
-        ///         <paramref name="oldValue"/> had.
-        ///     </para>
-        ///     <remarks>
-        ///         This ensures that if splitter location was e.g. 50% before and you move it to absolute 5 then you end up
-        ///         with 10% (assuming a parent had 50 width).
-        ///     </remarks>
-        /// </summary>
-        /// <param name="oldValue"></param>
-        /// <param name="newValue"></param>
-        private bool FinalisePosition (Pos oldValue, Pos newValue)
-        {
-            SetNeedsDraw ();
-
-            SetNeedsLayout ();
-
-            if (oldValue is PosPercent)
-            {
-                if (Orientation == Orientation.Horizontal)
-                {
-                    return Parent.SetSplitterPos (Idx, ConvertToPosPercent (newValue, Parent.Viewport.Height));
-                }
-
-                return Parent.SetSplitterPos (Idx, ConvertToPosPercent (newValue, Parent.Viewport.Width));
-            }
-
-            return Parent.SetSplitterPos (Idx, newValue);
-        }
-
-        private bool MoveSplitter (int distanceX, int distanceY)
-        {
-            if (Orientation == Orientation.Vertical)
-            {
-                // Cannot move in this direction
-                if (distanceX == 0)
-                {
-                    return false;
-                }
-
-                Pos oldX = X;
-
-                return FinalisePosition (oldX, Offset (X, distanceX));
-            }
-
-            // Cannot move in this direction
-            if (distanceY == 0)
-            {
-                return false;
-            }
-
-            Pos oldY = Y;
-
-            return FinalisePosition (oldY, Offset (Y, distanceY));
-        }
-
-        private Pos Offset (Pos pos, int delta)
-        {
-            int posAbsolute = pos.GetAnchor (
-                                             Orientation == Orientation.Horizontal
-                                                 ? Parent.Viewport.Height
-                                                 : Parent.Viewport.Width
-                                            );
-
-            return posAbsolute + delta;
-        }
-    }
-}
-
-/// <summary>Represents a method that will handle splitter events.</summary>
-public delegate void SplitterEventHandler (object? sender, SplitterEventArgs e);

+ 6 - 6
Tests/IntegrationTests/FluentTests/FileDialogFluentTests.cs

@@ -159,7 +159,7 @@ public class FileDialogFluentTests
                 "/";
     }
 
-    [Theory]
+    [Theory (Skip = "New splitter design removes expand button.")]
     [ClassData (typeof (TestDrivers))]
     public void SaveFileDialog_PressingPopTree_ShouldNotChangeCancel (TestDriver d)
     {
@@ -177,7 +177,7 @@ public class FileDialogFluentTests
 
     }
 
-    [Theory]
+    [Theory (Skip = "New splitter design removes expand button.")]
     [ClassData (typeof (TestDrivers))]
     public void SaveFileDialog_PopTree_AndNavigate (TestDriver d)
     {
@@ -224,8 +224,8 @@ public class FileDialogFluentTests
                           .WaitIteration ()
                           .ScreenShot ("After typing filename 'hello'", _out)
                           .AssertEndsWith ("hello", sd.Path)
-                          .LeftClick<Button> (b => b.Text == "►►")
-                          .ScreenShot ("After pop tree", _out)
+                          //.LeftClick<Button> (b => b.Text == "►►")
+                          //.ScreenShot ("After pop tree", _out)
                           .Focus<TreeView<IFileSystemInfo>> (_ => true)
                           .Right ()
                           .ScreenShot ("After expand tree", _out)
@@ -267,8 +267,8 @@ public class FileDialogFluentTests
                           .WaitIteration ()
                           .ScreenShot ("After typing filename 'hello'", _out)
                           .AssertEndsWith ("hello", sd.Path)
-                          .LeftClick<Button> (b => b.Text == "►►")
-                          .ScreenShot ("After pop tree", _out)
+                          //.LeftClick<Button> (b => b.Text == "►►")
+                          //.ScreenShot ("After pop tree", _out)
                           .Focus<TreeView<IFileSystemInfo>> (_ => true)
                           .Right ()
                           .ScreenShot ("After expand tree", _out)

+ 23 - 3
Tests/UnitTests/FileServices/FileDialogTests.cs

@@ -107,7 +107,7 @@ public class FileDialogTests ()
         Assert.IsType<TextField> (dlg.MostFocused);
         Assert.Same (tf, dlg.MostFocused);
 
-        Assert.Equal ("Enter Search", tf.Caption);
+        Assert.Equal ("_Find:", tf.Caption);
 
         // Dialog has not yet been confirmed with a choice
         Assert.True (dlg.Canceled);
@@ -798,8 +798,28 @@ public class FileDialogTests ()
 
     private TableView GetTableView (FileDialog dlg)
     {
-        var tile = dlg.SubViews.OfType<TileView> ().Single ();
-        return (TableView)tile.Tiles.ElementAt (1).ContentView.SubViews.ElementAt(0);
+        // The table view is in the _tableViewContainer which is a direct subview of the dialog
+        // We need to search through all subviews recursively
+        TableView FindTableView (View view)
+        {
+            if (view is TableView tv)
+            {
+                return tv;
+            }
+
+            foreach (View subview in view.SubViews)
+            {
+                TableView result = FindTableView (subview);
+                if (result != null)
+                {
+                    return result;
+                }
+            }
+
+            return null;
+        }
+
+        return FindTableView (dlg);
     }
 
     private enum FileDialogPart

+ 0 - 2406
Tests/UnitTests/Views/TileViewTests.cs

@@ -1,2406 +0,0 @@
-using UnitTests;
-using Xunit.Abstractions;
-
-namespace UnitTests.ViewsTests;
-
-public class TileViewTests (ITestOutputHelper output)
-{
-    [Fact]
-    [AutoInitShutdown]
-    public void Test_SplitTop_WholeBottom ()
-    {
-        var tileView = new TileView (2)
-        {
-            Width = 20, Height = 10, Orientation = Orientation.Horizontal, LineStyle = LineStyle.Single
-        };
-
-        Assert.True (tileView.TrySplitTile (0, 2, out TileView top));
-
-        top.Tiles.ElementAt (0).ContentView!.Add (new Label { Text = "bleh" });
-        top.Tiles.ElementAt (1).ContentView!.Add (new Label { Text = "blah" });
-        top.Layout ();
-
-        tileView.Tiles.ElementAt (1).ContentView!.Add (new Label { Text = "Hello" });
-        tileView.SetScheme (new ());
-        top.SetScheme (new ());
-
-        top.Layout ();
-        tileView.Layout ();
-        tileView.Draw ();
-
-        var looksLike =
-            @"
-┌─────────┬────────┐
-│bleh     │blah    │
-│         │        │
-│         │        │
-│         │        │
-├─────────┴────────┤
-│Hello             │
-│                  │
-│                  │
-└──────────────────┘";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void Test5Panel_MinSizes_VerticalSplitters_ResizeSplitter1 ()
-    {
-        TileView tv = Get5x1TilesView ();
-
-        tv.Tiles.ElementAt (0).MinSize = int.MaxValue;
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-┌────┬────┬────┬────┬───┐
-│1111│2222│3333│4444│555│
-│    │    │    │    │   │
-└────┴────┴────┴────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 0; x <= 5; x++)
-        {
-            // All these values would result in tile 0 getting smaller
-            // so are not allowed (tile[0] has a min size of Int.Max)
-            Assert.False (tv.SetSplitterPos (0, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 6; x < 10; x++)
-        {
-            // All these values would result in tile 0 getting bigger
-            // so are allowed
-            Assert.True (tv.SetSplitterPos (0, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 10; x < 100; x++)
-        {
-            // These values would result in the first splitter moving past
-            // the second splitter so are not allowed
-            Assert.False (tv.SetSplitterPos (0, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌────────┬┬────┬────┬───┐
-│11111111││3333│4444│555│
-│        ││    │    │   │
-└────────┴┴────┴────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void Test5Panel_MinSizes_VerticalSplitters_ResizeSplitter1_NoBorder ()
-    {
-        TileView tv = Get5x1TilesView (false);
-
-        tv.Tiles.ElementAt (0).MinSize = int.MaxValue;
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-11111│2222│3333│4444│5555
-     │    │    │    │
-     │    │    │    │
-     │    │    │    │
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 0; x <= 5; x++)
-        {
-            // All these values would result in tile 0 getting smaller
-            // so are not allowed (tile[0] has a min size of Int.Max)
-            Assert.False (tv.SetSplitterPos (0, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 6; x < 10; x++)
-        {
-            // All these values would result in tile 0 getting bigger
-            // so are allowed
-            Assert.True (tv.SetSplitterPos (0, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 10; x < 100; x++)
-        {
-            // These values would result in the first splitter moving past
-            // the second splitter so are not allowed
-            Assert.False (tv.SetSplitterPos (0, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-111111111││3333│4444│5555
-         ││    │    │
-         ││    │    │
-         ││    │    │
-
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void Test5Panel_MinSizes_VerticalSplitters_ResizeSplitter2 ()
-    {
-        TileView tv = Get5x1TilesView ();
-
-        tv.Tiles.ElementAt (1).MinSize = 2;
-        tv.Tiles.ElementAt (2).MinSize = 3;
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-┌────┬────┬────┬────┬───┐
-│1111│2222│3333│4444│555│
-│    │    │    │    │   │
-└────┴────┴────┴────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 10; x > 7; x--)
-        {
-            Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 7; x > 0; x--)
-        {
-            Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌────┬──┬──────┬────┬───┐
-│1111│22│333333│4444│555│
-│    │  │      │    │   │
-└────┴──┴──────┴────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 10; x < 12; x++)
-        {
-            Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 12; x < 25; x++)
-        {
-            Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        Application.Top!.Layout ();
-        tv.Draw ();
-
-        looksLike =
-            @"
-┌────┬─────┬───┬────┬───┐
-│1111│22222│333│4444│555│
-│    │     │   │    │   │
-└────┴─────┴───┴────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void Test5Panel_MinSizes_VerticalSplitters_ResizeSplitter2_NoBorder ()
-    {
-        TileView tv = Get5x1TilesView (false);
-
-        tv.Tiles.ElementAt (1).MinSize = 2;
-        tv.Tiles.ElementAt (2).MinSize = 3;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-11111│2222│3333│4444│5555
-     │    │    │    │
-     │    │    │    │
-     │    │    │    │
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 10; x > 7; x--)
-        {
-            Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 7; x > 0; x--)
-        {
-            Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-
-11111│22│333333│4444│5555
-     │  │      │    │
-     │  │      │    │
-     │  │      │    │
-
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 10; x < 12; x++)
-        {
-            Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 12; x < 25; x++)
-        {
-            Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"  
-11111│22222│333│4444│5555
-     │     │   │    │
-     │     │   │    │
-     │     │   │    │
-
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void Test5Panel_MinSizes_VerticalSplitters_ResizeSplitter4 ()
-    {
-        TileView tv = Get5x1TilesView ();
-
-        tv.Tiles.ElementAt (3).MinSize = 2;
-        tv.Tiles.ElementAt (4).MinSize = 1;
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-┌────┬────┬────┬────┬───┐
-│1111│2222│3333│4444│555│
-│    │    │    │    │   │
-└────┴────┴────┴────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 20; x > 17; x--)
-        {
-            Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 17; x > 0; x--)
-        {
-            Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌────┬────┬────┬──┬─────┐
-│1111│2222│3333│44│55555│
-│    │    │    │  │     │
-└────┴────┴────┴──┴─────┘
-
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 20; x < 23; x++)
-        {
-            Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 23; x < 100; x++)
-        {
-            Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌────┬────┬────┬──────┬─┐
-│1111│2222│3333│444444│5│
-│    │    │    │      │ │
-└────┴────┴────┴──────┴─┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void Test5Panel_MinSizes_VerticalSplitters_ResizeSplitter4_NoBorder ()
-    {
-        TileView tv = Get5x1TilesView (false);
-
-        tv.Tiles.ElementAt (3).MinSize = 2;
-        tv.Tiles.ElementAt (4).MinSize = 1;
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-11111│2222│3333│4444│5555
-     │    │    │    │
-     │    │    │    │
-     │    │    │    │
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 20; x > 17; x--)
-        {
-            Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 17; x > 0; x--)
-        {
-            Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"   
-11111│2222│3333│44│555555
-     │    │    │  │
-     │    │    │  │
-     │    │    │  │
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 20; x < 24; x++)
-        {
-            Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 24; x < 100; x++)
-        {
-            Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-11111│2222│3333│4444444│5
-     │    │    │       │
-     │    │    │       │
-     │    │    │       │
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void Test5Panel_NoMinSizes_VerticalSplitters_ResizeSplitter1_CannotCrossBorder ()
-    {
-        TileView tv = Get5x1TilesView ();
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-┌────┬────┬────┬────┬───┐
-│1111│2222│3333│4444│555│
-│    │    │    │    │   │
-└────┴────┴────┴────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 5; x > 0; x--)
-        {
-            Assert.True (tv.SetSplitterPos (0, x), $"Assert failed for x={x}");
-        }
-
-        Assert.False (tv.SetSplitterPos (0, 0));
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌┬────────┬────┬────┬───┐
-││22222222│3333│4444│555│
-││        │    │    │   │
-└┴────────┴────┴────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 6; x < 10; x++)
-        {
-            Assert.True (tv.SetSplitterPos (0, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 10; x < 100; x++)
-        {
-            // These values would result in the first splitter moving past
-            // the second splitter so are not allowed
-            Assert.False (tv.SetSplitterPos (0, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌────────┬┬────┬────┬───┐
-│11111111││3333│4444│555│
-│        ││    │    │   │
-└────────┴┴────┴────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void Test5Panel_NoMinSizes_VerticalSplitters_ResizeSplitter1_CannotCrossBorder_NoBorder ()
-    {
-        TileView tv = Get5x1TilesView (false);
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-11111│2222│3333│4444│5555
-     │    │    │    │
-     │    │    │    │
-     │    │    │    │
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 5; x >= 0; x--)
-        {
-            Assert.True (tv.SetSplitterPos (0, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-│222222222│3333│4444│5555
-│         │    │    │
-│         │    │    │
-│         │    │    │
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 6; x < 10; x++)
-        {
-            Assert.True (tv.SetSplitterPos (0, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 10; x < 100; x++)
-        {
-            // These values would result in the first splitter moving past
-            // the second splitter so are not allowed
-            Assert.False (tv.SetSplitterPos (0, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-111111111││3333│4444│5555
-         ││    │    │
-         ││    │    │
-         ││    │    │
-
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void Test5Panel_NoMinSizes_VerticalSplitters_ResizeSplitter2_CannotMoveOverNeighbours ()
-    {
-        TileView tv = Get5x1TilesView ();
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-┌────┬────┬────┬────┬───┐
-│1111│2222│3333│4444│555│
-│    │    │    │    │   │
-└────┴────┴────┴────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 10; x > 5; x--)
-        {
-            Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 5; x > 0; x--)
-        {
-            Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌────┬┬────────┬────┬───┐
-│1111││33333333│4444│555│
-│    ││        │    │   │
-└────┴┴────────┴────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 10; x < 15; x++)
-        {
-            Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 15; x < 25; x++)
-        {
-            Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌────┬────────┬┬────┬───┐
-│1111│22222222││4444│555│
-│    │        ││    │   │
-└────┴────────┴┴────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void Test5Panel_NoMinSizes_VerticalSplitters_ResizeSplitter2_CannotMoveOverNeighbours_NoBorder ()
-    {
-        TileView tv = Get5x1TilesView (false);
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-11111│2222│3333│4444│5555
-     │    │    │    │
-     │    │    │    │
-     │    │    │    │
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 10; x > 5; x--)
-        {
-            Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 5; x > 0; x--)
-        {
-            Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-11111││33333333│4444│5555
-     ││        │    │
-     ││        │    │
-     ││        │    │
-
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 10; x < 15; x++)
-        {
-            Assert.True (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 15; x < 25; x++)
-        {
-            Assert.False (tv.SetSplitterPos (1, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-11111│22222222││4444│5555
-     │        ││    │
-     │        ││    │
-     │        ││    │
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void Test5Panel_NoMinSizes_VerticalSplitters_ResizeSplitter4_CannotMoveOverNeighbours ()
-    {
-        TileView tv = Get5x1TilesView ();
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-┌────┬────┬────┬────┬───┐
-│1111│2222│3333│4444│555│
-│    │    │    │    │   │
-└────┴────┴────┴────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 20; x > 15; x--)
-        {
-            Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 15; x > 0; x--)
-        {
-            Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌────┬────┬────┬┬───────┐
-│1111│2222│3333││5555555│
-│    │    │    ││       │
-└────┴────┴────┴┴───────┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 20; x < 24; x++)
-        {
-            Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 24; x < 100; x++)
-        {
-            Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌────┬────┬────┬───────┬┐
-│1111│2222│3333│4444444││
-│    │    │    │       ││
-└────┴────┴────┴───────┴┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void Test5Panel_NoMinSizes_VerticalSplitters_ResizeSplitter4_CannotMoveOverNeighbours_NoBorder ()
-    {
-        TileView tv = Get5x1TilesView (false);
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"   
-11111│2222│3333│4444│5555
-     │    │    │    │
-     │    │    │    │
-     │    │    │    │
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 20; x > 15; x--)
-        {
-            Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 15; x > 0; x--)
-        {
-            Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"  
-11111│2222│3333││55555555
-     │    │    ││
-     │    │    ││
-     │    │    ││
-
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        for (var x = 20; x < 25; x++)
-        {
-            Assert.True (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        for (var x = 25; x < 100; x++)
-        {
-            Assert.False (tv.SetSplitterPos (3, x), $"Assert failed for x={x}");
-        }
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-11111│2222│3333│44444444│
-     │    │    │        │
-     │    │    │        │
-     │    │    │        │
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringInsertTile ()
-    {
-        TileView tv = GetTileView (20, 10);
-
-        var myReusableView = new DisposeCounter ();
-
-        // I want my view in the first tile
-        tv.Tiles.ElementAt (0).ContentView.Add (myReusableView);
-        Assert.Equal (0, myReusableView.DisposalCount);
-
-        // I've changed my mind, I want 3 tiles now
-        tv.InsertTile (0);
-        tv.InsertTile (2);
-
-        // but I still want my view in the first tile
-        // BUGBUG: Adding a view twice is not legit
-        tv.Tiles.ElementAt (0).ContentView.Add (myReusableView);
-
-        Assert.Multiple (
-                         () => Assert.Equal (0, myReusableView.DisposalCount),
-                         () =>
-                         {
-                             tv.Dispose ();
-                             Assert.True (myReusableView.DisposalCount >= 1);
-                         }
-                        );
-    }
-
-    [Fact]
-    public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRebuildForTileCount ()
-    {
-        TileView tv = GetTileView (20, 10);
-
-        var myReusableView = new DisposeCounter ();
-
-        // I want my view in the first tile
-        tv.Tiles.ElementAt (0).ContentView.Add (myReusableView);
-        Assert.Equal (0, myReusableView.DisposalCount);
-
-        // I've changed my mind, I want 3 tiles now
-        tv.RebuildForTileCount (3);
-
-        // but I still want my view in the first tile
-        // BUGBUG: Adding a view twice is not legit
-        tv.Tiles.ElementAt (0).ContentView.Add (myReusableView);
-
-        Assert.Multiple (
-                         () => Assert.Equal (0, myReusableView.DisposalCount),
-                         () =>
-                         {
-                             tv.Dispose ();
-                             Assert.Equal (1, myReusableView.DisposalCount);
-                         }
-                        );
-
-        Assert.NotNull (Application.Top);
-        Application.Top.Dispose ();
-        Application.Shutdown ();
-    }
-
-    [Theory]
-    [InlineData (0)]
-    [InlineData (1)]
-    public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRemoveTile (int idx)
-    {
-        TileView tv = GetTileView (20, 10);
-
-        var myReusableView = new DisposeCounter ();
-
-        // I want my view in the first tile
-        tv.Tiles.ElementAt (0).ContentView.Add (myReusableView);
-        Assert.Equal (0, myReusableView.DisposalCount);
-
-        tv.RemoveTile (idx);
-
-        // but I still want my view in the first tile
-        // BUGBUG: Adding a view twice is not legit
-        tv.Tiles.ElementAt (0).ContentView.Add (myReusableView);
-
-        Assert.Multiple (
-                         () => Assert.Equal (0, myReusableView.DisposalCount),
-                         () =>
-                         {
-                             tv.Dispose ();
-                             Assert.True (myReusableView.DisposalCount >= 1);
-                         }
-                        );
-
-        Assert.NotNull (Application.Top);
-        Application.Top.Dispose ();
-        Application.Shutdown ();
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestNestedContainer2LeftAnd1Right_RendersNicely ()
-    {
-        TileView tileView = GetNestedContainer2Left1Right (false);
-
-        Assert.Equal (20, tileView.Frame.Width);
-        Assert.Equal (10, tileView.Tiles.ElementAt (0).ContentView.Frame.Width);
-        Assert.Equal (9, tileView.Tiles.ElementAt (1).ContentView.Frame.Width);
-
-        Assert.IsType<TileView> (tileView.Tiles.ElementAt (0).ContentView);
-        var left = (TileView)tileView.Tiles.ElementAt (0).ContentView;
-        Assert.Same (left.SuperView, tileView);
-
-        Assert.Equal (2, left.Tiles.ElementAt (0).ContentView.SubViews.Count);
-        Assert.IsType<Label> (left.Tiles.ElementAt (0).ContentView.SubViews.ElementAt (0));
-        Assert.IsType<Label> (left.Tiles.ElementAt (0).ContentView.SubViews.ElementAt (1));
-        var onesTop = (Label)left.Tiles.ElementAt (0).ContentView.SubViews.ElementAt (0);
-        var onesBottom = (Label)left.Tiles.ElementAt (0).ContentView.SubViews.ElementAt (1);
-
-        Assert.Same (left.Tiles.ElementAt (0).ContentView, onesTop.SuperView);
-        Assert.Same (left.Tiles.ElementAt (0).ContentView, onesBottom.SuperView);
-
-        Assert.Equal (10, onesTop.Frame.Width);
-        Assert.Equal (10, onesBottom.Frame.Width);
-
-        tileView.Draw ();
-
-        var looksLike =
-            @"    
-1111111111│222222222
-1111111111│222222222
-          │
-          │
-          │
-──────────┤
-          │
-          │
-          │
-          │";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestNestedContainer3RightAnd1Down_RendersNicely ()
-    {
-        TileView tileView = GetNestedContainer3Right1Down (false);
-
-        tileView.Draw ();
-
-        var looksLike =
-            @"
-111111│222222│333333
-111111│222222│333333
-111111│222222│333333
-111111│222222│333333
-111111│222222│333333
-111111│222222├──────
-111111│222222│444444
-111111│222222│444444
-111111│222222│444444
-111111│222222│444444
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // It looks good but lets double check the measurements incase
-        // anything is sticking out but drawn over
-
-        // 3 panels + 2 splitters
-        Assert.Equal (5, tileView.SubViews.Count);
-
-        // Check X and Widths of Tiles
-        Assert.Equal (0, tileView.Tiles.ElementAt (0).ContentView.Frame.X);
-        Assert.Equal (6, tileView.Tiles.ElementAt (0).ContentView.Frame.Width);
-
-        Assert.Equal (7, tileView.Tiles.ElementAt (1).ContentView.Frame.X);
-        Assert.Equal (6, tileView.Tiles.ElementAt (1).ContentView.Frame.Width);
-
-        Assert.Equal (14, tileView.Tiles.ElementAt (2).ContentView.Frame.X);
-        Assert.Equal (6, tileView.Tiles.ElementAt (2).ContentView.Frame.Width);
-
-        // Check Y and Heights of Tiles
-        Assert.Equal (0, tileView.Tiles.ElementAt (0).ContentView.Frame.Y);
-        Assert.Equal (10, tileView.Tiles.ElementAt (0).ContentView.Frame.Height);
-
-        Assert.Equal (0, tileView.Tiles.ElementAt (1).ContentView.Frame.Y);
-        Assert.Equal (10, tileView.Tiles.ElementAt (1).ContentView.Frame.Height);
-
-        Assert.Equal (0, tileView.Tiles.ElementAt (2).ContentView.Frame.Y);
-        Assert.Equal (10, tileView.Tiles.ElementAt (2).ContentView.Frame.Height);
-
-        // Check Sub containers in last panel
-        var subSplit = (TileView)tileView.Tiles.ElementAt (2).ContentView;
-        Assert.Equal (0, subSplit.Tiles.ElementAt (0).ContentView.Frame.X);
-        Assert.Equal (6, subSplit.Tiles.ElementAt (0).ContentView.Frame.Width);
-        Assert.Equal (0, subSplit.Tiles.ElementAt (0).ContentView.Frame.Y);
-        Assert.Equal (5, subSplit.Tiles.ElementAt (0).ContentView.Frame.Height);
-
-        //Assert.IsType<TextView> (subSplit.Tiles.ElementAt (0).ContentView.SubViews.Single ());
-
-        Assert.Equal (0, subSplit.Tiles.ElementAt (1).ContentView.Frame.X);
-        Assert.Equal (6, subSplit.Tiles.ElementAt (1).ContentView.Frame.Width);
-        Assert.Equal (6, subSplit.Tiles.ElementAt (1).ContentView.Frame.Y);
-        Assert.Equal (4, subSplit.Tiles.ElementAt (1).ContentView.Frame.Height);
-
-        //Assert.IsType<TextView> (subSplit.Tiles.ElementAt (1).ContentView.SubViews.Single ());
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestNestedContainer3RightAnd1Down_TileVisibility_WithBorder ()
-    {
-        TileView tileView = GetNestedContainer3Right1Down (true);
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-┌─────┬──────┬─────┐
-│11111│222222│33333│
-│11111│222222│33333│
-│11111│222222│33333│
-│11111│222222│33333│
-│11111│222222├─────┤
-│11111│222222│44444│
-│11111│222222│44444│
-│11111│222222│44444│
-└─────┴──────┴─────┘";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = true;
-        tileView.Tiles.ElementAt (2).ContentView.Visible = true;
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌────────────┬─────┐
-│222222222222│33333│
-│222222222222│33333│
-│222222222222│33333│
-│222222222222│33333│
-│222222222222├─────┤
-│222222222222│44444│
-│222222222222│44444│
-│222222222222│44444│
-└────────────┴─────┘";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = true;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = false;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌────────────┬─────┐
-│111111111111│33333│
-│111111111111│33333│
-│111111111111│33333│
-│111111111111│33333│
-│111111111111├─────┤
-│111111111111│44444│
-│111111111111│44444│
-│111111111111│44444│
-└────────────┴─────┘";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = true;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = true;
-        tileView.Tiles.ElementAt (2).ContentView.Visible = false;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌─────┬────────────┐
-│11111│222222222222│
-│11111│222222222222│
-│11111│222222222222│
-│11111│222222222222│
-│11111│222222222222│
-│11111│222222222222│
-│11111│222222222222│
-│11111│222222222222│
-└─────┴────────────┘";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = true;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (2).ContentView.Visible = false;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌──────────────────┐
-│111111111111111111│
-│111111111111111111│
-│111111111111111111│
-│111111111111111111│
-│111111111111111111│
-│111111111111111111│
-│111111111111111111│
-│111111111111111111│
-└──────────────────┘";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = true;
-        tileView.Tiles.ElementAt (2).ContentView.Visible = false;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌──────────────────┐
-│222222222222222222│
-│222222222222222222│
-│222222222222222222│
-│222222222222222222│
-│222222222222222222│
-│222222222222222222│
-│222222222222222222│
-│222222222222222222│
-└──────────────────┘";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (2).ContentView.Visible = true;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌──────────────────┐
-│333333333333333333│
-│333333333333333333│
-│333333333333333333│
-│333333333333333333│
-├──────────────────┤
-│444444444444444444│
-│444444444444444444│
-│444444444444444444│
-└──────────────────┘";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (2).ContentView.Visible = false;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌──────────────────┐
-│                  │
-│                  │
-│                  │
-│                  │
-│                  │
-│                  │
-│                  │
-│                  │
-└──────────────────┘";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestNestedContainer3RightAnd1Down_TileVisibility_WithoutBorder ()
-    {
-        TileView tileView = GetNestedContainer3Right1Down (false);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-111111│222222│333333
-111111│222222│333333
-111111│222222│333333
-111111│222222│333333
-111111│222222│333333
-111111│222222├──────
-111111│222222│444444
-111111│222222│444444
-111111│222222│444444
-111111│222222│444444";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = true;
-        tileView.Tiles.ElementAt (2).ContentView.Visible = true;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-2222222222222│333333
-2222222222222│333333
-2222222222222│333333
-2222222222222│333333
-2222222222222│333333
-2222222222222├──────
-2222222222222│444444
-2222222222222│444444
-2222222222222│444444
-2222222222222│444444";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = true;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (2).ContentView.Visible = true;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-1111111111111│333333
-1111111111111│333333
-1111111111111│333333
-1111111111111│333333
-1111111111111│333333
-1111111111111├──────
-1111111111111│444444
-1111111111111│444444
-1111111111111│444444
-1111111111111│444444";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = true;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = true;
-        tileView.Tiles.ElementAt (2).ContentView.Visible = false;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-111111│2222222222222
-111111│2222222222222
-111111│2222222222222
-111111│2222222222222
-111111│2222222222222
-111111│2222222222222
-111111│2222222222222
-111111│2222222222222
-111111│2222222222222
-111111│2222222222222";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = true;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (2).ContentView.Visible = false;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-11111111111111111111
-11111111111111111111
-11111111111111111111
-11111111111111111111
-11111111111111111111
-11111111111111111111
-11111111111111111111
-11111111111111111111
-11111111111111111111
-11111111111111111111";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = true;
-        tileView.Tiles.ElementAt (2).ContentView.Visible = false;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-22222222222222222222
-22222222222222222222
-22222222222222222222
-22222222222222222222
-22222222222222222222
-22222222222222222222
-22222222222222222222
-22222222222222222222
-22222222222222222222
-22222222222222222222";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (2).ContentView.Visible = true;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-33333333333333333333
-33333333333333333333
-33333333333333333333
-33333333333333333333
-33333333333333333333
-────────────────────
-44444444444444444444
-44444444444444444444
-44444444444444444444
-44444444444444444444";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        tileView.Tiles.ElementAt (0).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (1).ContentView.Visible = false;
-        tileView.Tiles.ElementAt (2).ContentView.Visible = false;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-			 ";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestNestedContainer3RightAnd1Down_TitleDoesNotOverspill ()
-    {
-        TileView tileView = GetNestedContainer3Right1Down (true, true, 1);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-┌ T1 ─┬ T3 ──┬ T2 ─┐
-│11111│333333│22222│
-│11111│333333│22222│
-│11111│333333│22222│
-│11111│333333│22222│
-│11111├ T4 ──┤22222│
-│11111│444444│22222│
-│11111│444444│22222│
-│11111│444444│22222│
-└─────┴──────┴─────┘";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestNestedContainer3RightAnd1Down_TitleTriesToOverspill ()
-    {
-        TileView tileView = GetNestedContainer3Right1Down (true, true, 1);
-
-        tileView.Tiles.ElementAt (0).Title = new ('x', 100);
-
-        ((TileView)tileView.Tiles.ElementAt (1).ContentView)
-            .Tiles.ElementAt (1)
-            .Title = new ('y', 100);
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-┌ xxxx┬ T3 ──┬ T2 ─┐
-│11111│333333│22222│
-│11111│333333│22222│
-│11111│333333│22222│
-│11111│333333│22222│
-│11111├ yyyyy┤22222│
-│11111│444444│22222│
-│11111│444444│22222│
-│11111│444444│22222│
-└─────┴──────┴─────┘";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestNestedContainer3RightAnd1Down_WithBorder_RemovingTiles ()
-    {
-        TileView tileView = GetNestedContainer3Right1Down (true);
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-┌─────┬──────┬─────┐
-│11111│222222│33333│
-│11111│222222│33333│
-│11111│222222│33333│
-│11111│222222│33333│
-│11111│222222├─────┤
-│11111│222222│44444│
-│11111│222222│44444│
-│11111│222222│44444│
-└─────┴──────┴─────┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        Tile toRemove = tileView.Tiles.ElementAt (1);
-        Tile removed = tileView.RemoveTile (1);
-        Assert.Same (toRemove, removed);
-        Assert.DoesNotContain (removed, tileView.Tiles);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌─────────┬────────┐
-│111111111│33333333│
-│111111111│33333333│
-│111111111│33333333│
-│111111111│33333333│
-│111111111├────────┤
-│111111111│44444444│
-│111111111│44444444│
-│111111111│44444444│
-└─────────┴────────┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // cannot remove at this index because there is only one horizontal tile left
-        Assert.Null (tileView.RemoveTile (2));
-        tileView.RemoveTile (0);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌──────────────────┐
-│333333333333333333│
-│333333333333333333│
-│333333333333333333│
-│333333333333333333│
-├──────────────────┤
-│444444444444444444│
-│444444444444444444│
-│444444444444444444│
-└──────────────────┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        Assert.NotNull (tileView.RemoveTile (0));
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌──────────────────┐
-│                  │
-│                  │
-│                  │
-│                  │
-│                  │
-│                  │
-│                  │
-│                  │
-└──────────────────┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // cannot remove
-        Assert.Null (tileView.RemoveTile (0));
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestNestedContainer3RightAnd1Down_WithBorder_RendersNicely ()
-    {
-        TileView tileView = GetNestedContainer3Right1Down (true);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-┌─────┬──────┬─────┐
-│11111│222222│33333│
-│11111│222222│33333│
-│11111│222222│33333│
-│11111│222222│33333│
-│11111│222222├─────┤
-│11111│222222│44444│
-│11111│222222│44444│
-│11111│222222│44444│
-└─────┴──────┴─────┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // It looks good but lets double check the measurements incase
-        // anything is sticking out but drawn over
-
-        // 3 panels + 2 splitters
-        Assert.Equal (5, tileView.SubViews.Count);
-
-        // Check X and Widths of Tiles
-        Assert.Equal (1, tileView.Tiles.ElementAt (0).ContentView.Frame.X);
-        Assert.Equal (5, tileView.Tiles.ElementAt (0).ContentView.Frame.Width);
-
-        Assert.Equal (7, tileView.Tiles.ElementAt (1).ContentView.Frame.X);
-        Assert.Equal (6, tileView.Tiles.ElementAt (1).ContentView.Frame.Width);
-
-        Assert.Equal (14, tileView.Tiles.ElementAt (2).ContentView.Frame.X);
-        Assert.Equal (5, tileView.Tiles.ElementAt (2).ContentView.Frame.Width);
-
-        // Check Y and Heights of Tiles
-        Assert.Equal (1, tileView.Tiles.ElementAt (0).ContentView.Frame.Y);
-        Assert.Equal (8, tileView.Tiles.ElementAt (0).ContentView.Frame.Height);
-
-        Assert.Equal (1, tileView.Tiles.ElementAt (1).ContentView.Frame.Y);
-        Assert.Equal (8, tileView.Tiles.ElementAt (1).ContentView.Frame.Height);
-
-        Assert.Equal (1, tileView.Tiles.ElementAt (2).ContentView.Frame.Y);
-        Assert.Equal (8, tileView.Tiles.ElementAt (2).ContentView.Frame.Height);
-
-        // Check Sub containers in last panel
-        var subSplit = (TileView)tileView.Tiles.ElementAt (2).ContentView;
-        Assert.Equal (0, subSplit.Tiles.ElementAt (0).ContentView.Frame.X);
-        Assert.Equal (5, subSplit.Tiles.ElementAt (0).ContentView.Frame.Width);
-        Assert.Equal (0, subSplit.Tiles.ElementAt (0).ContentView.Frame.Y);
-        Assert.Equal (4, subSplit.Tiles.ElementAt (0).ContentView.Frame.Height);
-
-        //Assert.IsType<TextView> (subSplit.Tiles.ElementAt (0).ContentView.SubViews.Single ());
-
-        Assert.Equal (0, subSplit.Tiles.ElementAt (1).ContentView.Frame.X);
-        Assert.Equal (5, subSplit.Tiles.ElementAt (1).ContentView.Frame.Width);
-        Assert.Equal (5, subSplit.Tiles.ElementAt (1).ContentView.Frame.Y);
-        Assert.Equal (3, subSplit.Tiles.ElementAt (1).ContentView.Frame.Height);
-
-        //Assert.IsType<TextView> (subSplit.Tiles.ElementAt (1).ContentView.SubViews.Single ());
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestNestedContainer3RightAnd1Down_WithTitledBorder_RendersNicely ()
-    {
-        TileView tileView = GetNestedContainer3Right1Down (true, true);
-
-        tileView.Draw ();
-
-        var looksLike =
-            @"
-┌ T1 ─┬ T2 ──┬ T3 ─┐
-│11111│222222│33333│
-│11111│222222│33333│
-│11111│222222│33333│
-│11111│222222│33333│
-│11111│222222├ T4 ─┤
-│11111│222222│44444│
-│11111│222222│44444│
-│11111│222222│44444│
-└─────┴──────┴─────┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestNestedNonRoots_OnlyOneRoot_OnlyRootCanHaveBorders ()
-    {
-        var tv = new TileView
-        {
-            Width = 10, Height = 5, LineStyle = LineStyle.Single
-        };
-
-        tv.TrySplitTile (1, 2, out TileView tv2);
-       // tv2.Scheme = new ();
-        tv2.LineStyle = LineStyle.Single;
-        tv2.Orientation = Orientation.Horizontal;
-
-        Assert.True (tv.IsRootTileView ());
-
-        var top = new Toplevel ();
-        top.Add (tv);
-        tv.BeginInit ();
-        tv.EndInit ();
-        tv.LayoutSubViews ();
-
-        tv.LayoutSubViews ();
-        tv.Tiles.ElementAt (1).ContentView.LayoutSubViews ();
-        tv2.LayoutSubViews ();
-
-        // tv2 is not considered a root because 
-        // it was created via TrySplitTile so it
-        // will have its lines joined to
-        // parent and cannot have its own border
-        Assert.False (tv2.IsRootTileView ());
-
-        tv.Draw ();
-
-        var looksLike =
-            @"
-┌────┬───┐
-│    │   │
-│    ├───┤
-│    │   │
-└────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestNestedRoots_BothRoots_BothCanHaveBorders ()
-    {
-        var tv = new TileView
-        {
-            Width = 10, Height = 5, LineStyle = LineStyle.Single
-        };
-
-        var tv2 = new TileView
-        {
-            Width = Dim.Fill (),
-            Height = Dim.Fill (),
-            LineStyle = LineStyle.Single,
-            Orientation = Orientation.Horizontal
-        };
-
-        Assert.True (tv.IsRootTileView ());
-        tv.Tiles.ElementAt (1).ContentView.Add (tv2);
-
-        var top = new Toplevel ();
-        top.Add (tv);
-        tv.BeginInit ();
-        tv.EndInit ();
-        tv.LayoutSubViews ();
-
-        tv.LayoutSubViews ();
-        tv.Tiles.ElementAt (1).ContentView.LayoutSubViews ();
-        tv2.LayoutSubViews ();
-
-        // tv2 is still considered a root because 
-        // it was manually created by API user. That
-        // means it will not have its lines joined to
-        // parents and it is permitted to have a border
-        Assert.True (tv2.IsRootTileView ());
-
-        tv.Draw ();
-
-        var looksLike =
-            @"
-┌────┬───┐
-│    │┌─┐│
-│    │├─┤│
-│    │└─┘│
-└────┴───┘
-";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_CannotSetSplitterPosToFuncEtc ()
-    {
-        TileView tileView = Get11By3TileView ();
-
-        var ex = Assert.Throws<ArgumentException> (() => tileView.SetSplitterPos (0, Pos.Right (tileView)));
-        Assert.Equal ("Only Percent and Absolute values are supported. Passed value was PosView", ex.Message);
-
-        ex = Assert.Throws<ArgumentException> (() => tileView.SetSplitterPos (0, Pos.Func (_ => 1)));
-        Assert.Equal ("Only Percent and Absolute values are supported. Passed value was PosFunc", ex.Message);
-
-        // Also not allowed because this results in a PosCombine
-        ex = Assert.Throws<ArgumentException> (() => tileView.SetSplitterPos (0, Pos.Percent (50) - 1));
-
-        Assert.Equal (
-                      "Only Percent and Absolute values are supported. Passed value was PosCombine",
-                      ex.Message
-                     );
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_Horizontal ()
-    {
-        TileView tileView = Get11By3TileView (out Line line);
-        tileView.Orientation = Orientation.Horizontal;
-        tileView.Layout ();
-        tileView.Draw ();
-
-        var looksLike =
-            @"    
-11111111111
-───────────
-22222222222";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Keyboard movement on splitter should have no effect if it is not focused
-        bool handled = tileView.NewKeyDownEvent (Key.CursorDown);
-        Assert.False (handled);
-        tileView.SetNeedsDraw ();
-        tileView.Draw ();
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_Horizontal_Focused ()
-    {
-        TileView tileView = Get11By3TileView (out Line line);
-
-        tileView.Orientation = Orientation.Horizontal;
-        tileView.NewKeyDownEvent (new (tileView.ToggleResizable));
-
-        Assert.True (line.HasFocus);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"    
-11111111111
-─────◊─────
-22222222222";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Now move splitter line down
-        tileView.NewKeyDownEvent (Key.CursorDown);
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"    
-11111111111
-11111111111
-─────◊─────";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // And 2 up
-        line.NewKeyDownEvent (Key.CursorUp);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        line.NewKeyDownEvent (Key.CursorUp);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"    
-─────◊─────
-22222222222
-22222222222";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_Horizontal_View1MinSize_Absolute ()
-    {
-        TileView tileView = Get11By3TileView (out Line line);
-        tileView.NewKeyDownEvent (new (tileView.ToggleResizable));
-
-        tileView.Orientation = Orientation.Horizontal;
-        tileView.Tiles.ElementAt (0).MinSize = 1;
-
-        // 0 should not be allowed because it brings us below minimum size of View1
-        Assert.False (tileView.SetSplitterPos (0, 0));
-
-        // position should remain where it was, at 50%
-        Assert.Equal (Pos.Percent (50), tileView.SplitterDistances.ElementAt (0));
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"    
-11111111111
-─────◊─────
-22222222222";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Now move splitter line down (allowed
-        line.NewKeyDownEvent (Key.CursorDown);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"    
-11111111111
-11111111111
-─────◊─────";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // And up 2 (only 1 is allowed because of minimum size of 1 on view1)
-        line.NewKeyDownEvent (Key.CursorUp);
-        line.NewKeyDownEvent (Key.CursorUp);
-
-        tileView.SetNeedsDraw ();
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"    
-11111111111
-─────◊─────
-22222222222";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Theory]
-    [AutoInitShutdown]
-    [InlineData (true)]
-    [InlineData (false)]
-    public void TestTileView_IndexOf (bool recursive)
-    {
-        var tv = new TileView ();
-        var lbl1 = new Label ();
-        var lbl2 = new Label ();
-        var frame = new FrameView ();
-        var sub = new Label ();
-        frame.Add (sub);
-
-        // IndexOf returns -1 when view not found
-        Assert.Equal (-1, tv.IndexOf (lbl1, recursive));
-        Assert.Equal (-1, tv.IndexOf (lbl2, recursive));
-
-        // IndexOf supports looking for Tile.View
-        Assert.Equal (0, tv.IndexOf (tv.Tiles.ElementAt (0).ContentView, recursive));
-        Assert.Equal (1, tv.IndexOf (tv.Tiles.ElementAt (1).ContentView, recursive));
-
-        // IndexOf supports looking for Tile.View.SubViews
-        tv.Tiles.ElementAt (0).ContentView.Add (lbl1);
-        Assert.Equal (0, tv.IndexOf (lbl1, recursive));
-
-        tv.Tiles.ElementAt (1).ContentView.Add (lbl2);
-        Assert.Equal (1, tv.IndexOf (lbl2, recursive));
-
-        // IndexOf supports looking deep into subviews only when
-        // the recursive true value is passed
-        tv.Tiles.ElementAt (1).ContentView.Add (frame);
-
-        if (recursive)
-        {
-            Assert.Equal (1, tv.IndexOf (sub, recursive));
-        }
-        else
-        {
-            Assert.Equal (-1, tv.IndexOf (sub, recursive));
-        }
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_InsertPanelAtEnd ()
-    {
-        TileView tileView = Get11By3TileView (out Line line, true);
-        tileView.InsertTile (2);
-
-        tileView.Layout ();
-        tileView.Draw ();
-
-        // so should ignore the 2 distance and stick to 6
-        var looksLike =
-            @"
-┌──┬───┬──┐
-│11│222│  │
-└──┴───┴──┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_InsertPanelAtStart ()
-    {
-        TileView tileView = Get11By3TileView (out Line line, true);
-        tileView.InsertTile (0);
-
-        tileView.Layout ();
-        tileView.Draw ();
-
-        // so should ignore the 2 distance and stick to 6
-        var looksLike =
-            @"
-┌──┬───┬──┐
-│  │111│22│
-└──┴───┴──┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_InsertPanelMiddle ()
-    {
-        TileView tileView = Get11By3TileView (out Line line, true);
-        tileView.InsertTile (1);
-
-        tileView.Layout ();
-        tileView.Draw ();
-
-        // so should ignore the 2 distance and stick to 6
-        var looksLike =
-            @"
-┌──┬───┬──┐
-│11│   │22│
-└──┴───┴──┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_Vertical ()
-    {
-        TileView tileView = Get11By3TileView (out Line line);
-
-        tileView.Layout ();
-        tileView.Draw ();
-
-        var looksLike =
-            @"
-11111│22222
-11111│22222
-     │     ";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Keyboard movement on splitter should have no effect if it is not focused
-        tileView.NewKeyDownEvent (Key.CursorRight);
-        tileView.SetNeedsDraw ();
-        tileView.Draw ();
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_Vertical_Focused ()
-    {
-        TileView tileView = Get11By3TileView (out Line line);
-        tileView.NewKeyDownEvent (new (tileView.ToggleResizable));
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-11111│22222
-11111◊22222
-     │     ";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Now while focused move the splitter 1 unit right
-        line.NewKeyDownEvent (Key.CursorRight);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-111111│2222
-111111◊2222
-      │     ";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // and 2 to the left
-        line.NewKeyDownEvent (Key.CursorLeft);
-        tileView.Layout ();
-        line.NewKeyDownEvent (Key.CursorLeft);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-1111│222222
-1111◊222222
-    │     ";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_Vertical_Focused_50PercentSplit ()
-    {
-        TileView tileView = Get11By3TileView (out Line line);
-        tileView.SetSplitterPos (0, Pos.Percent (50));
-        Assert.IsType<PosPercent> (tileView.SplitterDistances.ElementAt (0));
-        tileView.NewKeyDownEvent (new (tileView.ToggleResizable));
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-11111│22222
-11111◊22222
-     │     ";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Now while focused move the splitter 1 unit right
-        line.NewKeyDownEvent (Key.CursorRight);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-111111│2222
-111111◊2222
-      │     ";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Even when moving the splitter location it should stay a Percentage based one
-        Assert.IsType<PosPercent> (tileView.SplitterDistances.ElementAt (0));
-
-        // and 2 to the left
-        line.NewKeyDownEvent (Key.CursorLeft);
-        tileView.Layout ();
-        line.NewKeyDownEvent (Key.CursorLeft);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-1111│222222
-1111◊222222
-    │     ";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Even when moving the splitter location it should stay a Percentage based one
-        Assert.IsType<PosPercent> (tileView.SplitterDistances.ElementAt (0));
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_Vertical_Focused_WithBorder ()
-    {
-        TileView tileView = Get11By3TileView (out Line line, true);
-        tileView.NewKeyDownEvent (new (tileView.ToggleResizable));
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-┌────┬────┐
-│1111◊2222│
-└────┴────┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Now while focused move the splitter 1 unit right
-        line.NewKeyDownEvent (Key.CursorRight);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌─────┬───┐
-│11111◊222│
-└─────┴───┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // and 2 to the left
-        line.NewKeyDownEvent (Key.CursorLeft);
-        tileView.Layout ();
-        line.NewKeyDownEvent (Key.CursorLeft);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌───┬─────┐
-│111◊22222│
-└───┴─────┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_Vertical_View1MinSize_Absolute ()
-    {
-        TileView tileView = Get11By3TileView (out Line line);
-        tileView.NewKeyDownEvent (new (tileView.ToggleResizable));
-        tileView.Tiles.ElementAt (0).MinSize = 6;
-
-        // distance is too small (below 6)
-        Assert.False (tileView.SetSplitterPos (0, 2));
-
-        // Should stay where it was originally at (50%)
-        Assert.Equal (Pos.Percent (50), tileView.SplitterDistances.ElementAt (0));
-        AutoInitShutdownAttribute.RunIteration ();
-
-        // so should ignore the 2 distance and stick to 6
-        var looksLike =
-            @"
-11111│22222
-11111◊22222
-     │     ";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Keyboard movement on splitter should have no effect because it
-        // would take us below the minimum splitter size
-        line.NewKeyDownEvent (Key.CursorLeft);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // but we can continue to move the splitter right if we want
-        line.NewKeyDownEvent (Key.CursorRight);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-111111│2222
-111111◊2222
-      │     ";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_Vertical_View1MinSize_Absolute_WithBorder ()
-    {
-        TileView tileView = Get11By3TileView (out Line line, true);
-        tileView.NewKeyDownEvent (new (tileView.ToggleResizable));
-        tileView.Tiles.ElementAt (0).MinSize = 5;
-
-        // distance is too small (below 5)
-        Assert.False (tileView.SetSplitterPos (0, 2));
-
-        // Should stay where it was originally at (50%)
-        Assert.Equal (Pos.Percent (50), tileView.SplitterDistances.ElementAt (0));
-        AutoInitShutdownAttribute.RunIteration ();
-
-        // so should ignore the 2 distance and stick to 5
-        var looksLike =
-            @"
-┌────┬────┐
-│1111◊2222│
-└────┴────┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Keyboard movement on splitter should have no effect because it
-        // would take us below the minimum splitter size
-        line.NewKeyDownEvent (Key.CursorLeft);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // but we can continue to move the splitter right if we want
-        line.NewKeyDownEvent (Key.CursorRight);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌─────┬───┐
-│11111◊222│
-└─────┴───┘";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_Vertical_View2MinSize_Absolute ()
-    {
-        TileView tileView = Get11By3TileView (out Line line);
-        tileView.NewKeyDownEvent (new (tileView.ToggleResizable));
-        tileView.Tiles.ElementAt (1).MinSize = 6;
-        AutoInitShutdownAttribute.RunIteration ();
-
-        // distance leaves too little space for view2 (less than 6 would remain)
-        Assert.False (tileView.SetSplitterPos (0, 8));
-
-        //  Should stay where it was originally at (50%)
-        Assert.Equal (Pos.Percent (50), tileView.SplitterDistances.ElementAt (0));
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        // so should ignore the 2 distance and stick to 6
-        var looksLike =
-            @"
-11111│22222
-11111◊22222
-     │     ";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Keyboard movement on splitter should have no effect because it
-        // would take us below the minimum splitter size
-        line.NewKeyDownEvent (Key.CursorRight);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // but we can continue to move the splitter left if we want
-        line.NewKeyDownEvent (Key.CursorLeft);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-1111│222222
-1111◊222222
-    │    ";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_Vertical_View2MinSize_Absolute_WithBorder ()
-    {
-        TileView tileView = Get11By3TileView (out Line line, true);
-        tileView.NewKeyDownEvent (new (tileView.ToggleResizable));
-        tileView.Tiles.ElementAt (1).MinSize = 5;
-
-        // distance leaves too little space for view2 (less than 5 would remain)
-        Assert.False (tileView.SetSplitterPos (0, 8));
-        AutoInitShutdownAttribute.RunIteration ();
-
-        //  Should stay where it was originally at (50%)
-        Assert.Equal (Pos.Percent (50), tileView.SplitterDistances.ElementAt (0));
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        // so should ignore the 2 distance and stick to 6
-        var looksLike =
-            @"
-┌────┬────┐
-│1111◊2222│
-└────┴────┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Keyboard movement on splitter should have no effect because it
-        // would take us below the minimum splitter size
-        line.NewKeyDownEvent (Key.CursorRight);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // but we can continue to move the splitter left if we want
-        line.NewKeyDownEvent (Key.CursorLeft);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        looksLike =
-            @"
-┌───┬─────┐
-│111◊22222│
-└───┴─────┘";
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTileView_Vertical_WithBorder ()
-    {
-        TileView tileView = Get11By3TileView (out Line line, true);
-
-        AutoInitShutdownAttribute.RunIteration ();
-
-        var looksLike =
-            @"
-┌────┬────┐
-│1111│2222│
-└────┴────┘";
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-
-        // Keyboard movement on splitter should have no effect if it is not focused
-        tileView.NewKeyDownEvent (Key.CursorRight);
-        AutoInitShutdownAttribute.RunIteration ();
-
-        DriverAssert.AssertDriverContentsAre (looksLike, output);
-    }
-
-    [Fact]
-    [AutoInitShutdown]
-    public void TestTrySplit_ShouldRetainTitle ()
-    {
-        var tv = new TileView ();
-        tv.Tiles.ElementAt (0).Title = "flibble";
-        tv.TrySplitTile (0, 2, out TileView subTileView);
-
-        // We moved the content so the title should also have been moved
-        Assert.Equal ("flibble", subTileView.Tiles.ElementAt (0).Title);
-
-        // Secondly we should have cleared the old title (it should have been moved not copied)
-        Assert.Empty (tv.Tiles.ElementAt (0).Title);
-    }
-
-    private TileView Get11By3TileView (out Line line, bool withBorder = false)
-    {
-        TileView split = Get11By3TileView (withBorder);
-        line = GetLine (split);
-
-        return split;
-    }
-
-    private TileView Get11By3TileView (bool withBorder = false) { return GetTileView (11, 3, withBorder); }
-
-    private TileView Get5x1TilesView (bool border = true)
-    {
-        var tv = new TileView (5)
-        {
-            Width = 25, Height = 4, LineStyle = LineStyle.Single
-        };
-
-        if (!border)
-        {
-            tv.LineStyle = LineStyle.None;
-        }
-
-        tv.Tiles.ElementAt (0)
-          .ContentView.Add (
-                            new Label { Width = Dim.Fill (), Height = 1, Text = new ('1', 100) }
-                           );
-
-        tv.Tiles.ElementAt (1)
-          .ContentView.Add (
-                            new Label { Width = Dim.Fill (), Height = 1, Text = new ('2', 100) }
-                           );
-
-        tv.Tiles.ElementAt (2)
-          .ContentView.Add (
-                            new Label { Width = Dim.Fill (), Height = 1, Text = new ('3', 100) }
-                           );
-
-        tv.Tiles.ElementAt (3)
-          .ContentView.Add (
-                            new Label { Width = Dim.Fill (), Height = 1, Text = new ('4', 100) }
-                           );
-
-        tv.Tiles.ElementAt (4)
-          .ContentView.Add (
-                            new Label { Width = Dim.Fill (), Height = 1, Text = new ('5', 100) }
-                           );
-
-        Application.Top = new ();
-        Application.Top.Add (tv);
-
-        Application.Begin (Application.Top);
-
-        Application.Top.SetNeedsDraw();
-
-        return tv;
-    }
-
-    private Line GetLine (TileView tileView) { return tileView.SubViews.OfType<Line> ().Single (); }
-
-    /// <summary>Creates a vertical orientation root container with left pane split into two (with horizontal splitter line).</summary>
-    /// <param name="withBorder"></param>
-    /// <returns></returns>
-    private TileView GetNestedContainer2Left1Right (bool withBorder)
-    {
-        TileView container = GetTileView (20, 10, withBorder);
-        Assert.True (container.TrySplitTile (0, 2, out TileView newContainer));
-
-        newContainer.Orientation = Orientation.Horizontal;
-
-        container.LayoutSubViews ();
-
-        return container;
-    }
-
-    /// <summary>Creates a vertical orientation root container with 3 tiles. The rightmost is split horizontally</summary>
-    /// <param name="withBorder"></param>
-    /// <returns></returns>
-    private TileView GetNestedContainer3Right1Down (bool withBorder, bool withTitles = false, int split = 2)
-    {
-        Application.Top = new ();
-        var container = new TileView (3) { Width = 20, Height = 10 };
-        container.LineStyle = withBorder ? LineStyle.Single : LineStyle.None;
-
-        Assert.True (container.TrySplitTile (split, 2, out TileView newContainer));
-
-        newContainer.Orientation = Orientation.Horizontal;
-
-        var i = 0;
-
-        foreach (Tile tile in container.Tiles.Union (newContainer.Tiles))
-        {
-            if (tile.ContentView is TileView)
-            {
-                continue;
-            }
-
-            i++;
-
-            if (withTitles)
-            {
-                tile.Title = "T" + i;
-            }
-
-            tile.ContentView.Add (
-                                  new TextView
-                                  {
-                                      Width = Dim.Fill (),
-                                      Height = Dim.Fill (),
-                                      Text =
-                                          string.Join (
-                                                       '\n',
-                                                       Enumerable.Repeat (
-                                                                          new string (i.ToString () [0], 100),
-                                                                          10
-                                                                         )
-                                                                 .ToArray ()
-                                                      ),
-                                      WordWrap = false
-                                  }
-                                 );
-        }
-
-        Application.Top.Add (container);
-        Application.Begin (Application.Top);
-
-        return container;
-    }
-
-    private TileView GetTileView (int width, int height, bool withBorder = false)
-    {
-        var container = new TileView
-        {
-            Id = "container",
-            Width = width, Height = height
-        };
-
-        container.LineStyle = withBorder ? LineStyle.Single : LineStyle.None;
-
-        container.Tiles.ElementAt (0)
-                 .ContentView.Add (
-                                   new Label { Id = "label1", Width = Dim.Fill (), Height = 1, Text = new ('1', 100) }
-                                  );
-
-        container.Tiles.ElementAt (0)
-                 .ContentView.Add (
-                                   new Label
-                                   {
-                                       Id = "label2",
-                                       Width = Dim.Fill (),
-                                       Height = 1,
-                                       Y = 1,
-                                       Text = new ('1', 100)
-                                   }
-                                  );
-
-        container.Tiles.ElementAt (1)
-                 .ContentView.Add (
-                                   new Label { Id = "label3", Width = Dim.Fill (), Height = 1, Text = new ('2', 100) }
-                                  );
-
-        container.Tiles.ElementAt (1)
-                 .ContentView.Add (
-                                   new Label
-                                   {
-                                       Id = "label4",
-                                       Width = Dim.Fill (),
-                                       Height = 1,
-                                       Y = 1,
-                                       Text = new ('2', 100)
-                                   }
-                                  );
-
-        container.Tiles.ElementAt (0).MinSize = 0;
-        container.Tiles.ElementAt (1).MinSize = 0;
-
-        Application.Top = new ();
-        Application.Top.Add (container);
-
-        Application.Begin (Application.Top);
-
-        return container;
-    }
-
-    private class DisposeCounter : View
-    {
-        public int DisposalCount;
-
-        protected override void Dispose (bool disposing)
-        {
-            DisposalCount++;
-            base.Dispose (disposing);
-        }
-    }
-}

+ 43 - 0
docfx/docs/arrangement.md

@@ -50,6 +50,49 @@ A form of layout where SubViews of a View are visually arranged such that their
 
 In most use-cases, subviews do not overlap with each other (the exception being when it's done intentionally to create some visual effect). As a result, the default layout for most TUI apps is "tiled", and by default @Terminal.Gui.ViewBase.View.Arrangement is set to @Terminal.Gui.ViewBase.ViewArrangement.Fixed.
 
+### Creating a Resizable Splitter
+
+A common pattern in tiled layouts is to create a resizable splitter between two views. This can be achieved using the @Terminal.Gui.ViewBase.ViewArrangement.LeftResizable, @Terminal.Gui.ViewBase.ViewArrangement.RightResizable, @Terminal.Gui.ViewBase.ViewArrangement.TopResizable, or @Terminal.Gui.ViewBase.ViewArrangement.BottomResizable flags.
+
+Here's an example of creating a horizontal resizable splitter between two views:
+
+```csharp
+// Create left pane that fills remaining space
+View leftPane = new ()
+{
+    X = 0,
+    Y = 0,
+    Width = Dim.Fill (Dim.Func (_ => rightPane.Frame.Width)),
+    Height = Dim.Fill (),
+    CanFocus = true
+};
+
+// Create right pane with resizable left border (acts as splitter)
+View rightPane = new ()
+{
+    X = Pos.Right (leftPane) - 1,
+    Y = 0,
+    Width = Dim.Fill (),
+    Height = Dim.Fill (),
+    Arrangement = ViewArrangement.LeftResizable,
+    BorderStyle = LineStyle.Single,
+    SuperViewRendersLineCanvas = true,
+    CanFocus = true
+};
+rightPane.Border!.Thickness = new (1, 0, 0, 0); // Only left border
+
+container.Add (leftPane, rightPane);
+```
+
+In this example:
+- The `rightPane` has `ViewArrangement.LeftResizable` which makes its left border draggable
+- The left border acts as a splitter that users can drag to resize both panes
+- The `leftPane` uses `Dim.Fill` with a function that subtracts the `rightPane`'s width to automatically fill the remaining space
+- The `rightPane` has `SuperViewRendersLineCanvas = true` to ensure the border is rendered properly
+- Only the left border is shown by setting `Border.Thickness` to `(1, 0, 0, 0)`
+
+For a vertical splitter (top and bottom panes), use `ViewArrangement.TopResizable` or `ViewArrangement.BottomResizable` instead.
+
 ## Runnable
 
 Today, Overlapped and Runnable are intrinsically linked. A runnable view is one where `Application.Run(Toplevel)` is called. Each *Runnable* view where (`Modal == false`) has it's own `RunState` and is, effectively, a self-contained "application". 

+ 0 - 27
docfx/docs/views.md

@@ -628,33 +628,6 @@ TextView provides a fully featured multi-line text
 It supports word wrap and history for undo.
 ```
 
-## [TileView](~/api/Terminal.Gui.Views.TileView.yml)
-
-A [View](~/api/Terminal.Gui.ViewBase.View.yml) consisting of a moveable bar that divides the display area into resizeable [TileView.Tiles](~/api/Terminal.Gui.Views.TileView.Tiles.yml).
-
-```text
-│
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-                         │
-```
-
 ## [TimeField](~/api/Terminal.Gui.Views.TimeField.yml)
 
 Provides time editing functionality with mouse support