2
0
Эх сурвалжийг харах

Fixes #505. Finishes merge of TileView (previously SplitContainer) (#2258)

* Add tests for proper disposing

* Make Ctrl+F10 toggle split line focusability

* Fix layout bug in first tile when orientation is horizontal

* Switch to GenerateImage

* Fix not calling base constructor

* Revert "Merges latest LineCanvas into TileView"

* Fix keyboard tab navigation problems

* Workaround for changing CanFocus throwing Exceptions sometimes

* Fix bad merges

* Fix bad merging

* Fix disposing in TileViewNesting scenario

---------

Co-authored-by: Tig <[email protected]>
Thomas Nind 2 жил өмнө
parent
commit
0bd32c282e

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

@@ -310,7 +310,7 @@ namespace Terminal.Gui {
 				foreach (var p in lc.GenerateImage (bounds)) {
 				foreach (var p in lc.GenerateImage (bounds)) {
 					this.AddRune (p.Key.X, p.Key.Y, p.Value);
 					this.AddRune (p.Key.X, p.Key.Y, p.Value);
 				}
 				}
-				
+
 				// Redraw the lines so that focus/drag symbol renders
 				// Redraw the lines so that focus/drag symbol renders
 				foreach (var subview in contentView.Subviews) {
 				foreach (var subview in contentView.Subviews) {
 					//	line.DrawSplitterSymbol ();
 					//	line.DrawSplitterSymbol ();

+ 33 - 17
Terminal.Gui/Views/TileView.cs

@@ -13,6 +13,12 @@ namespace Terminal.Gui {
 	public class TileView : View {
 	public class TileView : View {
 		TileView parentTileView;
 		TileView parentTileView;
 
 
+		/// <summary>
+		/// The keyboard key that the user can press to toggle resizing
+		/// of splitter lines.  Mouse drag splitting is always enabled.
+		/// </summary>
+		public Key ToggleResizable { get; set; } = Key.CtrlMask | Key.F10;
+
 		/// <summary>
 		/// <summary>
 		/// A single <see cref="ContentView"/> presented in a <see cref="TileView"/>. To create
 		/// A single <see cref="ContentView"/> presented in a <see cref="TileView"/>. To create
 		/// new instances use <see cref="TileView.RebuildForTileCount(int)"/> 
 		/// new instances use <see cref="TileView.RebuildForTileCount(int)"/> 
@@ -167,7 +173,6 @@ namespace Terminal.Gui {
 		/// <param name="tiles"></param>
 		/// <param name="tiles"></param>
 		public TileView (int tiles)
 		public TileView (int tiles)
 		{
 		{
-			CanFocus = true;
 			RebuildForTileCount (tiles);
 			RebuildForTileCount (tiles);
 			IgnoreBorderPropertyOnRedraw = true;
 			IgnoreBorderPropertyOnRedraw = true;
 			Border = new Border () {
 			Border = new Border () {
@@ -403,15 +408,6 @@ namespace Terminal.Gui {
 			return true;
 			return true;
 		}
 		}
 
 
-		/// <inheritdoc/>
-		public override bool OnEnter (View view)
-		{
-			Driver.SetCursorVisibility (CursorVisibility.Invisible);
-			if (!Tiles.Where (t => t.ContentView.HasFocus).Any ()) {
-				Tiles.FirstOrDefault ()?.ContentView.SetFocus ();
-			}
-			return base.OnEnter (view);
-		}
 
 
 		/// <inheritdoc/>
 		/// <inheritdoc/>
 		public override void Redraw (Rect bounds)
 		public override void Redraw (Rect bounds)
@@ -550,6 +546,30 @@ namespace Terminal.Gui {
 			return true;
 			return true;
 		}
 		}
 
 
+		/// <inheritdoc/>
+		public override bool ProcessHotKey (KeyEvent keyEvent)
+		{
+			bool focusMoved = false;
+
+			if(keyEvent.Key == ToggleResizable) {
+				foreach(var l in splitterLines) {
+
+					var iniBefore = l.IsInitialized;
+					l.IsInitialized = false;
+					l.CanFocus = !l.CanFocus;
+					l.IsInitialized = iniBefore;
+
+					if (l.CanFocus && !focusMoved) {
+						l.SetFocus ();
+						focusMoved = true;
+					}
+				}
+				return true;
+			}
+
+			return base.ProcessHotKey (keyEvent);
+		}
+
 		private bool IsValidNewSplitterPos (int idx, Pos value, int fullSpace)
 		private bool IsValidNewSplitterPos (int idx, Pos value, int fullSpace)
 		{
 		{
 			int newSize = value.Anchor (fullSpace);
 			int newSize = value.Anchor (fullSpace);
@@ -750,7 +770,7 @@ namespace Terminal.Gui {
 					tile.ContentView.Width = GetTileWidthOrHeight (i, Bounds.Width, visibleTiles, visibleSplitterLines);
 					tile.ContentView.Width = GetTileWidthOrHeight (i, Bounds.Width, visibleTiles, visibleSplitterLines);
 				} else {
 				} else {
 					tile.ContentView.X = bounds.X;
 					tile.ContentView.X = bounds.X;
-					tile.ContentView.Y = i == 0 ? 0 : Pos.Bottom (visibleSplitterLines [i - 1]);
+					tile.ContentView.Y = i == 0 ? bounds.Y : Pos.Bottom (visibleSplitterLines [i - 1]);
 					tile.ContentView.Width = bounds.Width;
 					tile.ContentView.Width = bounds.Width;
 					tile.ContentView.Height = GetTileWidthOrHeight (i, Bounds.Height, visibleTiles, visibleSplitterLines);
 					tile.ContentView.Height = GetTileWidthOrHeight (i, Bounds.Height, visibleTiles, visibleSplitterLines);
 				}
 				}
@@ -864,7 +884,7 @@ namespace Terminal.Gui {
 
 
 			public TileViewLineView (TileView parent, int idx)
 			public TileViewLineView (TileView parent, int idx)
 			{
 			{
-				CanFocus = true;
+				CanFocus = false;
 				TabStop = true;
 				TabStop = true;
 
 
 				this.Parent = parent;
 				this.Parent = parent;
@@ -929,7 +949,7 @@ namespace Terminal.Gui {
 
 
 			public void DrawSplitterSymbol ()
 			public void DrawSplitterSymbol ()
 			{
 			{
-				if (CanFocus && HasFocus) {
+				if (dragPosition != null || CanFocus) {
 					var location = moveRuneRenderLocation ??
 					var location = moveRuneRenderLocation ??
 						new Point (Bounds.Width / 2, Bounds.Height / 2);
 						new Point (Bounds.Width / 2, Bounds.Height / 2);
 
 
@@ -939,10 +959,6 @@ namespace Terminal.Gui {
 
 
 			public override bool MouseEvent (MouseEvent mouseEvent)
 			public override bool MouseEvent (MouseEvent mouseEvent)
 			{
 			{
-				if (!CanFocus) {
-					return true;
-				}
-
 				if (!dragPosition.HasValue && (mouseEvent.Flags == MouseFlags.Button1Pressed)) {
 				if (!dragPosition.HasValue && (mouseEvent.Flags == MouseFlags.Button1Pressed)) {
 
 
 					// Start a Drag
 					// Start a Drag

+ 4 - 4
UICatalog/Scenarios/TileViewExperiment.cs

@@ -32,7 +32,7 @@ namespace UICatalog.Scenarios {
 				Y = 1,
 				Y = 1,
 				Width = 15, //Dim.Fill (),
 				Width = 15, //Dim.Fill (),
 				Height = 15, //Dim.Fill (),
 				Height = 15, //Dim.Fill (),
-				//IgnoreBorderPropertyOnRedraw = true
+					     //IgnoreBorderPropertyOnRedraw = true
 
 
 			};
 			};
 			frame1.Border.BorderStyle = BorderStyle.Double;
 			frame1.Border.BorderStyle = BorderStyle.Double;
@@ -60,11 +60,11 @@ namespace UICatalog.Scenarios {
 				Width = 14, //Dim.Percent (30) - 5,
 				Width = 14, //Dim.Percent (30) - 5,
 				Height = 14, //Dim.Percent (50) - 5,
 				Height = 14, //Dim.Percent (50) - 5,
 				ColorScheme = Colors.ColorSchemes ["Dialog"],
 				ColorScheme = Colors.ColorSchemes ["Dialog"],
-				Border = new Border () { 
-					BorderStyle = BorderStyle.Single, 
+				Border = new Border () {
+					BorderStyle = BorderStyle.Single,
 					//BorderThickness = new Thickness (1), 
 					//BorderThickness = new Thickness (1), 
 					DrawMarginFrame = true,
 					DrawMarginFrame = true,
-					Padding = new Thickness(1),
+					Padding = new Thickness (1),
 					BorderBrush = Color.BrightMagenta,
 					BorderBrush = Color.BrightMagenta,
 					Title = "Border Title"
 					Title = "Border Title"
 				}
 				}

+ 3 - 0
UICatalog/Scenarios/TileViewNesting.cs

@@ -94,6 +94,9 @@ namespace UICatalog.Scenarios {
 			bool? border = cbBorder.Checked;
 			bool? border = cbBorder.Checked;
 			bool? startHorizontal = cbHorizontal.Checked;
 			bool? startHorizontal = cbHorizontal.Checked;
 
 
+			foreach(var sub in workArea.Subviews) {
+				sub.Dispose ();
+			}
 			workArea.RemoveAll ();
 			workArea.RemoveAll ();
 
 
 			if (numberOfViews <= 0) {
 			if (numberOfViews <= 0) {

+ 61 - 40
UnitTests/Views/TileViewTests.cs

@@ -1,6 +1,6 @@
 using System;
 using System;
+using System.ComponentModel;
 using System.Linq;
 using System.Linq;
-using Terminal.Gui;
 using Terminal.Gui.Graphs;
 using Terminal.Gui.Graphs;
 using Xunit;
 using Xunit;
 using Xunit.Abstractions;
 using Xunit.Abstractions;
@@ -60,7 +60,7 @@ namespace Terminal.Gui.ViewTests {
 		public void TestTileView_Vertical_Focused ()
 		public void TestTileView_Vertical_Focused ()
 		{
 		{
 			var tileView = Get11By3TileView (out var line);
 			var tileView = Get11By3TileView (out var line);
-			SetInputFocusLine (tileView);
+			tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ()));
 
 
 			tileView.Redraw (tileView.Bounds);
 			tileView.Redraw (tileView.Bounds);
 
 
@@ -100,7 +100,7 @@ namespace Terminal.Gui.ViewTests {
 		public void TestTileView_Vertical_Focused_WithBorder ()
 		public void TestTileView_Vertical_Focused_WithBorder ()
 		{
 		{
 			var tileView = Get11By3TileView (out var line, true);
 			var tileView = Get11By3TileView (out var line, true);
-			SetInputFocusLine (tileView);
+			tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ()));
 
 
 			tileView.Redraw (tileView.Bounds);
 			tileView.Redraw (tileView.Bounds);
 
 
@@ -141,9 +141,10 @@ namespace Terminal.Gui.ViewTests {
 		public void TestTileView_Vertical_Focused_50PercentSplit ()
 		public void TestTileView_Vertical_Focused_50PercentSplit ()
 		{
 		{
 			var tileView = Get11By3TileView (out var line);
 			var tileView = Get11By3TileView (out var line);
-			SetInputFocusLine (tileView);
 			tileView.SetSplitterPos (0, Pos.Percent (50));
 			tileView.SetSplitterPos (0, Pos.Percent (50));
 			Assert.IsType<Pos.PosFactor> (tileView.SplitterDistances.ElementAt (0));
 			Assert.IsType<Pos.PosFactor> (tileView.SplitterDistances.ElementAt (0));
+			tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ()));
+
 			tileView.Redraw (tileView.Bounds);
 			tileView.Redraw (tileView.Bounds);
 
 
 			string looksLike =
 			string looksLike =
@@ -209,7 +210,7 @@ namespace Terminal.Gui.ViewTests {
 		public void TestTileView_Vertical_View1MinSize_Absolute ()
 		public void TestTileView_Vertical_View1MinSize_Absolute ()
 		{
 		{
 			var tileView = Get11By3TileView (out var line);
 			var tileView = Get11By3TileView (out var line);
-			SetInputFocusLine (tileView);
+			tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ()));
 			tileView.Tiles.ElementAt (0).MinSize = 6;
 			tileView.Tiles.ElementAt (0).MinSize = 6;
 
 
 			// distance is too small (below 6)
 			// distance is too small (below 6)
@@ -254,7 +255,7 @@ namespace Terminal.Gui.ViewTests {
 		public void TestTileView_Vertical_View1MinSize_Absolute_WithBorder ()
 		public void TestTileView_Vertical_View1MinSize_Absolute_WithBorder ()
 		{
 		{
 			var tileView = Get11By3TileView (out var line, true);
 			var tileView = Get11By3TileView (out var line, true);
-			SetInputFocusLine (tileView);
+			tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ()));
 			tileView.Tiles.ElementAt (0).MinSize = 5;
 			tileView.Tiles.ElementAt (0).MinSize = 5;
 
 
 			// distance is too small (below 5)
 			// distance is too small (below 5)
@@ -298,7 +299,7 @@ namespace Terminal.Gui.ViewTests {
 		public void TestTileView_Vertical_View2MinSize_Absolute ()
 		public void TestTileView_Vertical_View2MinSize_Absolute ()
 		{
 		{
 			var tileView = Get11By3TileView (out var line);
 			var tileView = Get11By3TileView (out var line);
-			SetInputFocusLine (tileView);
+			tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ()));
 			tileView.Tiles.ElementAt (1).MinSize = 6;
 			tileView.Tiles.ElementAt (1).MinSize = 6;
 
 
 			// distance leaves too little space for view2 (less than 6 would remain)
 			// distance leaves too little space for view2 (less than 6 would remain)
@@ -342,7 +343,7 @@ namespace Terminal.Gui.ViewTests {
 		public void TestTileView_Vertical_View2MinSize_Absolute_WithBorder ()
 		public void TestTileView_Vertical_View2MinSize_Absolute_WithBorder ()
 		{
 		{
 			var tileView = Get11By3TileView (out var line, true);
 			var tileView = Get11By3TileView (out var line, true);
-			SetInputFocusLine (tileView);
+			tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ()));
 			tileView.Tiles.ElementAt (1).MinSize = 5;
 			tileView.Tiles.ElementAt (1).MinSize = 5;
 
 
 			// distance leaves too little space for view2 (less than 5 would remain)
 			// distance leaves too little space for view2 (less than 5 would remain)
@@ -386,8 +387,6 @@ namespace Terminal.Gui.ViewTests {
 		public void TestTileView_InsertPanelAtStart ()
 		public void TestTileView_InsertPanelAtStart ()
 		{
 		{
 			var tileView = Get11By3TileView (out var line, true);
 			var tileView = Get11By3TileView (out var line, true);
-			SetInputFocusLine (tileView);
-
 			tileView.InsertTile (0);
 			tileView.InsertTile (0);
 
 
 			tileView.Redraw (tileView.Bounds);
 			tileView.Redraw (tileView.Bounds);
@@ -405,8 +404,6 @@ namespace Terminal.Gui.ViewTests {
 		public void TestTileView_InsertPanelMiddle ()
 		public void TestTileView_InsertPanelMiddle ()
 		{
 		{
 			var tileView = Get11By3TileView (out var line, true);
 			var tileView = Get11By3TileView (out var line, true);
-			SetInputFocusLine (tileView);
-
 			tileView.InsertTile (1);
 			tileView.InsertTile (1);
 
 
 			tileView.Redraw (tileView.Bounds);
 			tileView.Redraw (tileView.Bounds);
@@ -424,8 +421,6 @@ namespace Terminal.Gui.ViewTests {
 		public void TestTileView_InsertPanelAtEnd ()
 		public void TestTileView_InsertPanelAtEnd ()
 		{
 		{
 			var tileView = Get11By3TileView (out var line, true);
 			var tileView = Get11By3TileView (out var line, true);
-			SetInputFocusLine (tileView);
-
 			tileView.InsertTile (2);
 			tileView.InsertTile (2);
 
 
 			tileView.Redraw (tileView.Bounds);
 			tileView.Redraw (tileView.Bounds);
@@ -445,7 +440,9 @@ namespace Terminal.Gui.ViewTests {
 			var tileView = Get11By3TileView (out var line);
 			var tileView = Get11By3TileView (out var line);
 
 
 			tileView.Orientation = Terminal.Gui.Graphs.Orientation.Horizontal;
 			tileView.Orientation = Terminal.Gui.Graphs.Orientation.Horizontal;
-			SetInputFocusLine (tileView);
+			tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ()));
+
+			Assert.True (line.HasFocus);
 
 
 			tileView.Redraw (tileView.Bounds);
 			tileView.Redraw (tileView.Bounds);
 
 
@@ -485,9 +482,9 @@ namespace Terminal.Gui.ViewTests {
 		public void TestTileView_Horizontal_View1MinSize_Absolute ()
 		public void TestTileView_Horizontal_View1MinSize_Absolute ()
 		{
 		{
 			var tileView = Get11By3TileView (out var line);
 			var tileView = Get11By3TileView (out var line);
+			tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ()));
 
 
 			tileView.Orientation = Terminal.Gui.Graphs.Orientation.Horizontal;
 			tileView.Orientation = Terminal.Gui.Graphs.Orientation.Horizontal;
-			SetInputFocusLine (tileView);
 			tileView.Tiles.ElementAt (0).MinSize = 1;
 			tileView.Tiles.ElementAt (0).MinSize = 1;
 
 
 			// 0 should not be allowed because it brings us below minimum size of View1
 			// 0 should not be allowed because it brings us below minimum size of View1
@@ -2045,6 +2042,45 @@ namespace Terminal.Gui.ViewTests {
 
 
 		}
 		}
 
 
+		[Fact, AutoInitShutdown]
+		public void Test_SplitTop_WholeBottom()
+		{
+			var tileView = new TileView (2) {
+				Width = 20,
+				Height = 10,
+				Orientation = Orientation.Horizontal,
+			};
+			tileView.Border.BorderStyle = BorderStyle.Single;
+
+			Assert.True (tileView.TrySplitTile (0,2,out TileView top));
+
+			top.Tiles.ElementAt (0).ContentView.Add (new Label ("bleh"));
+			top.Tiles.ElementAt (1).ContentView.Add (new Label ("blah"));
+
+			tileView.Tiles.ElementAt (1).ContentView.Add (new Label ("Hello"));
+			tileView.ColorScheme = new ColorScheme ();
+			top.ColorScheme = new ColorScheme ();
+			tileView.LayoutSubviews ();
+
+			tileView.Redraw (tileView.Bounds);
+
+			string looksLike =
+@"
+┌─────────┬────────┐
+│bleh     │blah    │
+│         │        │
+│         │        │
+│         │        │
+├─────────┴────────┤
+│Hello             │
+│                  │
+│                  │
+└──────────────────┘";
+
+			TestHelpers.AssertDriverContentsAre (looksLike, output);
+
+		}
+
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
 		public void TestNestedContainer3RightAnd1Down_TitleDoesNotOverspill()
 		public void TestNestedContainer3RightAnd1Down_TitleDoesNotOverspill()
 		{
 		{
@@ -2094,12 +2130,10 @@ namespace Terminal.Gui.ViewTests {
 
 
 			TestHelpers.AssertDriverContentsAre (looksLike, output);
 			TestHelpers.AssertDriverContentsAre (looksLike, output);
 		}
 		}
-
-
-		[Fact,AutoInitShutdown]
+		[Fact, AutoInitShutdown]
 		public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRebuildForTileCount ()
 		public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRebuildForTileCount ()
 		{
 		{
-			var tv = GetTileView (20,10);
+			var tv = GetTileView (20, 10);
 
 
 			var myReusableView = new DisposeCounter ();
 			var myReusableView = new DisposeCounter ();
 
 
@@ -2113,10 +2147,10 @@ namespace Terminal.Gui.ViewTests {
 			// but I still want my view in the first tile
 			// but I still want my view in the first tile
 			tv.Tiles.ElementAt (0).ContentView.Add (myReusableView);
 			tv.Tiles.ElementAt (0).ContentView.Add (myReusableView);
 			Assert.Multiple (
 			Assert.Multiple (
-				()=>Assert.Equal (0, myReusableView.DisposalCount)
-				,()=> {
+				() => Assert.Equal (0, myReusableView.DisposalCount)
+				, () => {
 					tv.Dispose ();
 					tv.Dispose ();
-					Assert.Equal (1, myReusableView.DisposalCount); 
+					Assert.Equal (1, myReusableView.DisposalCount);
 				});
 				});
 		}
 		}
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
@@ -2140,15 +2174,13 @@ namespace Terminal.Gui.ViewTests {
 				() => Assert.Equal (0, myReusableView.DisposalCount)
 				() => Assert.Equal (0, myReusableView.DisposalCount)
 				, () => {
 				, () => {
 					tv.Dispose ();
 					tv.Dispose ();
-
-					// TODO seems to be double disposed ?!
-					Assert.True (myReusableView.DisposalCount >= 1);
+					Assert.True (myReusableView.DisposalCount>=1);
 				});
 				});
 		}
 		}
 		[Theory, AutoInitShutdown]
 		[Theory, AutoInitShutdown]
-		[InlineData(0)]
+		[InlineData (0)]
 		[InlineData (1)]
 		[InlineData (1)]
-		public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRemoveTile(int idx)
+		public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRemoveTile (int idx)
 		{
 		{
 			var tv = GetTileView (20, 10);
 			var tv = GetTileView (20, 10);
 
 
@@ -2166,14 +2198,10 @@ namespace Terminal.Gui.ViewTests {
 				() => Assert.Equal (0, myReusableView.DisposalCount)
 				() => Assert.Equal (0, myReusableView.DisposalCount)
 				, () => {
 				, () => {
 					tv.Dispose ();
 					tv.Dispose ();
-
-					// TODO seems to be double disposed ?!
 					Assert.True (myReusableView.DisposalCount >= 1);
 					Assert.True (myReusableView.DisposalCount >= 1);
 				});
 				});
 		}
 		}
-
-		private class DisposeCounter : View
-		{
+		private class DisposeCounter : View {
 			public int DisposalCount;
 			public int DisposalCount;
 			protected override void Dispose (bool disposing)
 			protected override void Dispose (bool disposing)
 			{
 			{
@@ -2255,13 +2283,6 @@ namespace Terminal.Gui.ViewTests {
 			return tileView.Subviews.OfType<LineView> ().Single ();
 			return tileView.Subviews.OfType<LineView> ().Single ();
 		}
 		}
 
 
-		private void SetInputFocusLine (TileView tileView)
-		{
-			var line = GetLine (tileView);
-			line.SetFocus ();
-			Assert.True (line.HasFocus);
-		}
-
 
 
 		private TileView Get5x1TilesView (bool border = true)
 		private TileView Get5x1TilesView (bool border = true)
 		{
 		{