소스 검색

Render Titles for Tiles properly

Thomas 2 년 전
부모
커밋
d0d17606d1
2개의 변경된 파일101개의 추가작업 그리고 31개의 파일을 삭제
  1. 73 30
      Terminal.Gui/Views/TileView.cs
  2. 28 1
      UnitTests/TileViewTests.cs

+ 73 - 30
Terminal.Gui/Views/TileView.cs

@@ -253,13 +253,6 @@ namespace Terminal.Gui {
 					contentArea.Y + 1,
 					contentArea.Y + 1,
 					Math.Max (0, contentArea.Width - 2),
 					Math.Max (0, contentArea.Width - 2),
 					Math.Max (0, contentArea.Height - 2));
 					Math.Max (0, contentArea.Height - 2));
-			} else if (HasAnyTitles () && IsRootTileView ()) {
-				// TODO: Bound with Max/Min
-				contentArea = new Rect (
-					contentArea.X,
-					contentArea.Y + 1,
-					contentArea.Width,
-					Math.Max (0, contentArea.Height - 1));
 			}
 			}
 
 
 			Setup (contentArea);
 			Setup (contentArea);
@@ -297,15 +290,14 @@ namespace Terminal.Gui {
 		/// <inheritdoc/>
 		/// <inheritdoc/>
 		public override void Redraw (Rect bounds)
 		public override void Redraw (Rect bounds)
 		{
 		{
-			var childTitles = new List<ChildSplitterLine> ();
-
 			Driver.SetAttribute (ColorScheme.Normal);
 			Driver.SetAttribute (ColorScheme.Normal);
 			Clear ();
 			Clear ();
 			base.Redraw (bounds);
 			base.Redraw (bounds);
 
 
 			var lc = new LineCanvas ();
 			var lc = new LineCanvas ();
 
 
-			var allLines = GetAllChildTileViewLineViewRecursively (this);
+			var allLines = GetAllLineViewsRecursively (this);
+			var allTitlesToRender = GetAllTitlesToRenderRecursively(this);
 
 
 			if (IsRootTileView ()) {
 			if (IsRootTileView ()) {
 				if (HasBorder ()) {
 				if (HasBorder ()) {
@@ -333,10 +325,6 @@ namespace Terminal.Gui {
 							origin.Y -= 1;
 							origin.Y -= 1;
 						}
 						}
 						length += 2;
 						length += 2;
-
-						childTitles.Add (
-							new ChildSplitterLine (line));
-
 					}
 					}
 
 
 					lc.AddLine (origin, length, line.Orientation, IntegratedBorder);
 					lc.AddLine (origin, length, line.Orientation, IntegratedBorder);
@@ -351,26 +339,26 @@ namespace Terminal.Gui {
 				line.DrawSplitterSymbol ();
 				line.DrawSplitterSymbol ();
 			}
 			}
 
 
-			foreach (var child in childTitles) {
-				child.DrawTitles ();
-			}
-
 			// Draw Titles over Border
 			// Draw Titles over Border
 
 
+			foreach(var titleToRender in allTitlesToRender)
+			{
+				var renderAt = titleToRender.GetLocalCoordinateForTitle(this);
 
 
-			for (int i = 0; i < tiles.Count; i++) {
-
-				var tile = tiles [i];
-
-				if (tile.View.Visible && tile.Title.Length > 0) {
+				if(renderAt.Y < 0)
+				{
+					// If we have no border then root level tiles
+					// have nowhere to render their titles.
+					continue;
+				}
 
 
-					var screen = i == 0 ?
-						ViewToScreen (new Rect (0, 0, bounds.Width, 1)) :
-						ViewToScreen (splitterLines [i - 1].Frame);
+				// TODO: Render with focus color if focused
 
 
+				var title = titleToRender.Tile.Title;
 
 
-					Driver.SetAttribute (tile.View.HasFocus ? ColorScheme.HotNormal : ColorScheme.Normal);
-					Driver.DrawWindowTitle (new Rect (screen.X, screen.Y, tile.View.Frame.Width, 0), tile.Title, 0, 0, 0, 0);
+				for(int i=0;i<title.Length;i++)
+				{
+					AddRune(renderAt.X+i,renderAt.Y,title[i]);
 				}
 				}
 			}
 			}
 		}
 		}
@@ -430,7 +418,7 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 
 
-		private List<TileViewLineView> GetAllChildTileViewLineViewRecursively (View v)
+		private List<TileViewLineView> GetAllLineViewsRecursively (View v)
 		{
 		{
 			var lines = new List<TileViewLineView> ();
 			var lines = new List<TileViewLineView> ();
 
 
@@ -440,13 +428,44 @@ namespace Terminal.Gui {
 						lines.Add (s);
 						lines.Add (s);
 					}
 					}
 				} else {
 				} else {
-					lines.AddRange (GetAllChildTileViewLineViewRecursively (sub));
+					lines.AddRange (GetAllLineViewsRecursively (sub));
 				}
 				}
 			}
 			}
 
 
 			return lines;
 			return lines;
 		}
 		}
 
 
+		private List<TileTitleToRender> GetAllTitlesToRenderRecursively (TileView v, int depth = 0)
+		{
+			var titles = new List<TileTitleToRender> ();
+
+			foreach (var sub in v.Tiles) {
+
+				// Don't render titles for invisible stuff!
+				if(!sub.View.Visible)
+				{
+					continue;
+				}
+
+				if(sub.View 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 TileTitleToRender(sub,depth));
+					}
+				}
+			}
+
+			return titles;
+		}
+
 		/// <summary>
 		/// <summary>
 		/// <para>
 		/// <para>
 		/// <see langword="true"/> if <see cref="TileView"/> is nested within a parent <see cref="TileView"/>
 		/// <see langword="true"/> if <see cref="TileView"/> is nested within a parent <see cref="TileView"/>
@@ -618,6 +637,30 @@ namespace Terminal.Gui {
 			}
 			}
 		}
 		}
 
 
+		private class TileTitleToRender
+		{
+			public Tile Tile {get;}
+
+			public int Depth {get;}
+
+			public TileTitleToRender(Tile tile, int depth)
+			{
+				Tile = tile;
+				Depth = depth;				
+			}
+			
+			/// <summary>
+			/// Translates the <see cref="Tile"/> title location from its local
+			/// coordinate space <paramref name="intoCoordinateSpace"/>.
+			/// </summary>
+			public Point GetLocalCoordinateForTitle(TileView intoCoordinateSpace)
+			{
+				Tile.View.ViewToScreen(0,0, out var screenCol, out var screenRow);
+				screenRow--;
+				return intoCoordinateSpace.ScreenToView(screenCol,screenRow);
+			}
+		}
+
 		private class TileViewLineView : LineView {
 		private class TileViewLineView : LineView {
 			public TileView Parent { get; private set; }
 			public TileView Parent { get; private set; }
 			public int Idx { get; }
 			public int Idx { get; }

+ 28 - 1
UnitTests/TileViewTests.cs

@@ -713,6 +713,28 @@ namespace UnitTests {
 			Assert.Equal(3,subSplit.Tiles.ElementAt(1).View.Frame.Height);
 			Assert.Equal(3,subSplit.Tiles.ElementAt(1).View.Frame.Height);
 			Assert.IsType<TextView>(subSplit.Tiles.ElementAt(1).View.Subviews.Single());
 			Assert.IsType<TextView>(subSplit.Tiles.ElementAt(1).View.Subviews.Single());
 		}
 		}
+		
+		[Fact,AutoInitShutdown]
+		public void TestNestedContainer3RightAnd1Down_WithTitledBorder_RendersNicely()
+		{
+			var tileView = GetNestedContainer3Right1Down (true,true);
+
+			tileView.Redraw (tileView.Bounds);
+
+			string 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│
+└─────┴──────┴─────┘";
+			TestHelpers.AssertDriverContentsAre (looksLike, output);
+		}
 
 
 		[Fact, AutoInitShutdown]
 		[Fact, AutoInitShutdown]
 		public void TestNestedContainer3RightAnd1Down_WithBorder_RemovingTiles ()
 		public void TestNestedContainer3RightAnd1Down_WithBorder_RemovingTiles ()
@@ -827,7 +849,7 @@ namespace UnitTests {
 		/// </summary>
 		/// </summary>
 		/// <param name="withBorder"></param>
 		/// <param name="withBorder"></param>
 		/// <returns></returns>
 		/// <returns></returns>
-		private TileView GetNestedContainer3Right1Down(bool withBorder)
+		private TileView GetNestedContainer3Right1Down(bool withBorder, bool withTitles = false)
 		{
 		{
 			var container = 
 			var container = 
 			new TileView (3)
 			new TileView (3)
@@ -846,6 +868,11 @@ namespace UnitTests {
 			{
 			{
 				i++;
 				i++;
 
 
+				if(withTitles)
+				{
+					tile.Title = "T"+i;
+				}
+
 				tile.View.Add(new TextView{
 				tile.View.Add(new TextView{
 					Width = Dim.Fill(),
 					Width = Dim.Fill(),
 					Height = Dim.Fill(),
 					Height = Dim.Fill(),