From d0d17606d1ef53d2d576bb087f7dd8f8dd07048b Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 28 Jan 2023 11:13:51 +0000 Subject: [PATCH] Render Titles for Tiles properly --- Terminal.Gui/Views/TileView.cs | 103 +++++++++++++++++++++++---------- UnitTests/TileViewTests.cs | 29 +++++++++- 2 files changed, 101 insertions(+), 31 deletions(-) diff --git a/Terminal.Gui/Views/TileView.cs b/Terminal.Gui/Views/TileView.cs index 67ee2f704..bd6c27a44 100644 --- a/Terminal.Gui/Views/TileView.cs +++ b/Terminal.Gui/Views/TileView.cs @@ -253,13 +253,6 @@ namespace Terminal.Gui { contentArea.Y + 1, Math.Max (0, contentArea.Width - 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); @@ -297,15 +290,14 @@ namespace Terminal.Gui { /// public override void Redraw (Rect bounds) { - var childTitles = new List (); - Driver.SetAttribute (ColorScheme.Normal); Clear (); base.Redraw (bounds); var lc = new LineCanvas (); - var allLines = GetAllChildTileViewLineViewRecursively (this); + var allLines = GetAllLineViewsRecursively (this); + var allTitlesToRender = GetAllTitlesToRenderRecursively(this); if (IsRootTileView ()) { if (HasBorder ()) { @@ -333,10 +325,6 @@ namespace Terminal.Gui { origin.Y -= 1; } length += 2; - - childTitles.Add ( - new ChildSplitterLine (line)); - } lc.AddLine (origin, length, line.Orientation, IntegratedBorder); @@ -351,26 +339,26 @@ namespace Terminal.Gui { line.DrawSplitterSymbol (); } - foreach (var child in childTitles) { - child.DrawTitles (); - } - // Draw Titles over Border + foreach(var titleToRender in allTitlesToRender) + { + var renderAt = titleToRender.GetLocalCoordinateForTitle(this); - for (int i = 0; i < tiles.Count; i++) { + if(renderAt.Y < 0) + { + // If we have no border then root level tiles + // have nowhere to render their titles. + continue; + } - var tile = tiles [i]; + // TODO: Render with focus color if focused - if (tile.View.Visible && tile.Title.Length > 0) { + var title = titleToRender.Tile.Title; - var screen = i == 0 ? - ViewToScreen (new Rect (0, 0, bounds.Width, 1)) : - ViewToScreen (splitterLines [i - 1].Frame); - - - 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 GetAllChildTileViewLineViewRecursively (View v) + private List GetAllLineViewsRecursively (View v) { var lines = new List (); @@ -440,13 +428,44 @@ namespace Terminal.Gui { lines.Add (s); } } else { - lines.AddRange (GetAllChildTileViewLineViewRecursively (sub)); + lines.AddRange (GetAllLineViewsRecursively (sub)); } } return lines; } + private List GetAllTitlesToRenderRecursively (TileView v, int depth = 0) + { + var titles = new List (); + + 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; + } + /// /// /// if is nested within a parent @@ -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; + } + + /// + /// Translates the title location from its local + /// coordinate space . + /// + 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 { public TileView Parent { get; private set; } public int Idx { get; } diff --git a/UnitTests/TileViewTests.cs b/UnitTests/TileViewTests.cs index 4d2e1908c..092f97231 100644 --- a/UnitTests/TileViewTests.cs +++ b/UnitTests/TileViewTests.cs @@ -713,6 +713,28 @@ namespace UnitTests { Assert.Equal(3,subSplit.Tiles.ElementAt(1).View.Frame.Height); Assert.IsType(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] public void TestNestedContainer3RightAnd1Down_WithBorder_RemovingTiles () @@ -827,7 +849,7 @@ namespace UnitTests { /// /// /// - private TileView GetNestedContainer3Right1Down(bool withBorder) + private TileView GetNestedContainer3Right1Down(bool withBorder, bool withTitles = false) { var container = new TileView (3) @@ -846,6 +868,11 @@ namespace UnitTests { { i++; + if(withTitles) + { + tile.Title = "T"+i; + } + tile.View.Add(new TextView{ Width = Dim.Fill(), Height = Dim.Fill(),