mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 07:47:54 +01:00
Remove TileView; use View.Arrangement instead (#4271)
* Initial plan * Remove TileView and refactor to use View.Arrangement Co-authored-by: tig <585482+tig@users.noreply.github.com> * Fix FileDialog container focus behavior - all tests passing Co-authored-by: tig <585482+tig@users.noreply.github.com> * Remove obsolete TileView comment from View.Hierarchy.cs Co-authored-by: tig <585482+tig@users.noreply.github.com> * Add resizable splitter example to View.Arrangement docs Co-authored-by: tig <585482+tig@users.noreply.github.com> * 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 <585482+tig@users.noreply.github.com> * 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] <198982749+Copilot@users.noreply.github.com> Co-authored-by: tig <585482+tig@users.noreply.github.com> Co-authored-by: Tig <tig@users.noreply.github.com>
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user