diff --git a/Terminal.Gui/Views/FrameView.cs b/Terminal.Gui/Views/FrameView.cs index eb63f2f26a..f6809d109e 100644 --- a/Terminal.Gui/Views/FrameView.cs +++ b/Terminal.Gui/Views/FrameView.cs @@ -310,7 +310,7 @@ public override void Redraw (Rect bounds) foreach (var p in lc.GenerateImage (bounds)) { this.AddRune (p.Key.X, p.Key.Y, p.Value); } - + // Redraw the lines so that focus/drag symbol renders foreach (var subview in contentView.Subviews) { // line.DrawSplitterSymbol (); diff --git a/Terminal.Gui/Views/TileView.cs b/Terminal.Gui/Views/TileView.cs index c45401abe3..d5a431721f 100644 --- a/Terminal.Gui/Views/TileView.cs +++ b/Terminal.Gui/Views/TileView.cs @@ -13,6 +13,12 @@ namespace Terminal.Gui { public class TileView : View { TileView parentTileView; + /// + /// The keyboard key that the user can press to toggle resizing + /// of splitter lines. Mouse drag splitting is always enabled. + /// + public Key ToggleResizable { get; set; } = Key.CtrlMask | Key.F10; + /// /// A single presented in a . To create /// new instances use @@ -167,7 +173,6 @@ public TileView () : this (2) /// public TileView (int tiles) { - CanFocus = true; RebuildForTileCount (tiles); IgnoreBorderPropertyOnRedraw = true; Border = new Border () { @@ -403,15 +408,6 @@ public bool SetSplitterPos (int idx, Pos value) return true; } - /// - 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); - } /// public override void Redraw (Rect bounds) @@ -550,6 +546,30 @@ public bool TrySplitTile (int idx, int numberOfPanels, out TileView result) return true; } + /// + 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) { int newSize = value.Anchor (fullSpace); @@ -750,7 +770,7 @@ private void Setup (Rect bounds) tile.ContentView.Width = GetTileWidthOrHeight (i, Bounds.Width, visibleTiles, visibleSplitterLines); } else { 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.Height = GetTileWidthOrHeight (i, Bounds.Height, visibleTiles, visibleSplitterLines); } @@ -864,7 +884,7 @@ private class TileViewLineView : LineView { public TileViewLineView (TileView parent, int idx) { - CanFocus = true; + CanFocus = false; TabStop = true; this.Parent = parent; @@ -929,7 +949,7 @@ public override void Redraw (Rect bounds) public void DrawSplitterSymbol () { - if (CanFocus && HasFocus) { + if (dragPosition != null || CanFocus) { var location = moveRuneRenderLocation ?? new Point (Bounds.Width / 2, Bounds.Height / 2); @@ -939,10 +959,6 @@ public void DrawSplitterSymbol () public override bool MouseEvent (MouseEvent mouseEvent) { - if (!CanFocus) { - return true; - } - if (!dragPosition.HasValue && (mouseEvent.Flags == MouseFlags.Button1Pressed)) { // Start a Drag diff --git a/UICatalog/Scenarios/TileViewExperiment.cs b/UICatalog/Scenarios/TileViewExperiment.cs index 5053920e18..6430ce9a66 100644 --- a/UICatalog/Scenarios/TileViewExperiment.cs +++ b/UICatalog/Scenarios/TileViewExperiment.cs @@ -32,7 +32,7 @@ public override void Setup () Y = 1, Width = 15, //Dim.Fill (), Height = 15, //Dim.Fill (), - //IgnoreBorderPropertyOnRedraw = true + //IgnoreBorderPropertyOnRedraw = true }; frame1.Border.BorderStyle = BorderStyle.Double; @@ -60,11 +60,11 @@ public override void Setup () Width = 14, //Dim.Percent (30) - 5, Height = 14, //Dim.Percent (50) - 5, ColorScheme = Colors.ColorSchemes ["Dialog"], - Border = new Border () { - BorderStyle = BorderStyle.Single, + Border = new Border () { + BorderStyle = BorderStyle.Single, //BorderThickness = new Thickness (1), DrawMarginFrame = true, - Padding = new Thickness(1), + Padding = new Thickness (1), BorderBrush = Color.BrightMagenta, Title = "Border Title" } diff --git a/UICatalog/Scenarios/TileViewNesting.cs b/UICatalog/Scenarios/TileViewNesting.cs index 795de65e67..c14a69c5d8 100644 --- a/UICatalog/Scenarios/TileViewNesting.cs +++ b/UICatalog/Scenarios/TileViewNesting.cs @@ -94,6 +94,9 @@ private void SetupTileView () bool? border = cbBorder.Checked; bool? startHorizontal = cbHorizontal.Checked; + foreach(var sub in workArea.Subviews) { + sub.Dispose (); + } workArea.RemoveAll (); if (numberOfViews <= 0) { diff --git a/UnitTests/Views/TileViewTests.cs b/UnitTests/Views/TileViewTests.cs index 0155d3abae..d3e97acec9 100644 --- a/UnitTests/Views/TileViewTests.cs +++ b/UnitTests/Views/TileViewTests.cs @@ -1,6 +1,6 @@ using System; +using System.ComponentModel; using System.Linq; -using Terminal.Gui; using Terminal.Gui.Graphs; using Xunit; using Xunit.Abstractions; @@ -60,7 +60,7 @@ public void TestTileView_Vertical_WithBorder () public void TestTileView_Vertical_Focused () { var tileView = Get11By3TileView (out var line); - SetInputFocusLine (tileView); + tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ())); tileView.Redraw (tileView.Bounds); @@ -100,7 +100,7 @@ public void TestTileView_Vertical_Focused () public void TestTileView_Vertical_Focused_WithBorder () { var tileView = Get11By3TileView (out var line, true); - SetInputFocusLine (tileView); + tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ())); tileView.Redraw (tileView.Bounds); @@ -141,9 +141,10 @@ public void TestTileView_Vertical_Focused_WithBorder () public void TestTileView_Vertical_Focused_50PercentSplit () { var tileView = Get11By3TileView (out var line); - SetInputFocusLine (tileView); tileView.SetSplitterPos (0, Pos.Percent (50)); Assert.IsType (tileView.SplitterDistances.ElementAt (0)); + tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ())); + tileView.Redraw (tileView.Bounds); string looksLike = @@ -209,7 +210,7 @@ public void TestTileView_Horizontal () public void TestTileView_Vertical_View1MinSize_Absolute () { var tileView = Get11By3TileView (out var line); - SetInputFocusLine (tileView); + tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ())); tileView.Tiles.ElementAt (0).MinSize = 6; // distance is too small (below 6) @@ -254,7 +255,7 @@ public void TestTileView_Vertical_View1MinSize_Absolute () public void TestTileView_Vertical_View1MinSize_Absolute_WithBorder () { var tileView = Get11By3TileView (out var line, true); - SetInputFocusLine (tileView); + tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ())); tileView.Tiles.ElementAt (0).MinSize = 5; // distance is too small (below 5) @@ -298,7 +299,7 @@ public void TestTileView_Vertical_View1MinSize_Absolute_WithBorder () public void TestTileView_Vertical_View2MinSize_Absolute () { var tileView = Get11By3TileView (out var line); - SetInputFocusLine (tileView); + tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ())); tileView.Tiles.ElementAt (1).MinSize = 6; // distance leaves too little space for view2 (less than 6 would remain) @@ -342,7 +343,7 @@ public void TestTileView_Vertical_View2MinSize_Absolute () public void TestTileView_Vertical_View2MinSize_Absolute_WithBorder () { var tileView = Get11By3TileView (out var line, true); - SetInputFocusLine (tileView); + tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ())); tileView.Tiles.ElementAt (1).MinSize = 5; // distance leaves too little space for view2 (less than 5 would remain) @@ -386,8 +387,6 @@ public void TestTileView_Vertical_View2MinSize_Absolute_WithBorder () public void TestTileView_InsertPanelAtStart () { var tileView = Get11By3TileView (out var line, true); - SetInputFocusLine (tileView); - tileView.InsertTile (0); tileView.Redraw (tileView.Bounds); @@ -405,8 +404,6 @@ public void TestTileView_InsertPanelAtStart () public void TestTileView_InsertPanelMiddle () { var tileView = Get11By3TileView (out var line, true); - SetInputFocusLine (tileView); - tileView.InsertTile (1); tileView.Redraw (tileView.Bounds); @@ -424,8 +421,6 @@ public void TestTileView_InsertPanelMiddle () public void TestTileView_InsertPanelAtEnd () { var tileView = Get11By3TileView (out var line, true); - SetInputFocusLine (tileView); - tileView.InsertTile (2); tileView.Redraw (tileView.Bounds); @@ -445,7 +440,9 @@ public void TestTileView_Horizontal_Focused () var tileView = Get11By3TileView (out var line); 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); @@ -485,9 +482,9 @@ public void TestTileView_Horizontal_Focused () public void TestTileView_Horizontal_View1MinSize_Absolute () { var tileView = Get11By3TileView (out var line); + tileView.ProcessHotKey (new KeyEvent (tileView.ToggleResizable, new KeyModifiers ())); tileView.Orientation = Terminal.Gui.Graphs.Orientation.Horizontal; - SetInputFocusLine (tileView); tileView.Tiles.ElementAt (0).MinSize = 1; // 0 should not be allowed because it brings us below minimum size of View1 @@ -2045,6 +2042,45 @@ public void TestNestedContainer3RightAnd1Down_TileVisibility_WithoutBorder () } + [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] public void TestNestedContainer3RightAnd1Down_TitleDoesNotOverspill() { @@ -2094,12 +2130,10 @@ public void TestNestedContainer3RightAnd1Down_TitleTriesToOverspill () TestHelpers.AssertDriverContentsAre (looksLike, output); } - - - [Fact,AutoInitShutdown] + [Fact, AutoInitShutdown] public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRebuildForTileCount () { - var tv = GetTileView (20,10); + var tv = GetTileView (20, 10); var myReusableView = new DisposeCounter (); @@ -2113,10 +2147,10 @@ public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRebuildForTileCount // but I still want my view in the first tile tv.Tiles.ElementAt (0).ContentView.Add (myReusableView); Assert.Multiple ( - ()=>Assert.Equal (0, myReusableView.DisposalCount) - ,()=> { + () => Assert.Equal (0, myReusableView.DisposalCount) + , () => { tv.Dispose (); - Assert.Equal (1, myReusableView.DisposalCount); + Assert.Equal (1, myReusableView.DisposalCount); }); } [Fact, AutoInitShutdown] @@ -2140,15 +2174,13 @@ public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringInsertTile () () => Assert.Equal (0, myReusableView.DisposalCount) , () => { tv.Dispose (); - - // TODO seems to be double disposed ?! - Assert.True (myReusableView.DisposalCount >= 1); + Assert.True (myReusableView.DisposalCount>=1); }); } [Theory, AutoInitShutdown] - [InlineData(0)] + [InlineData (0)] [InlineData (1)] - public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRemoveTile(int idx) + public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRemoveTile (int idx) { var tv = GetTileView (20, 10); @@ -2166,14 +2198,10 @@ public void TestDisposal_NoEarlyDisposalsOfUsersViews_DuringRemoveTile(int idx) () => Assert.Equal (0, myReusableView.DisposalCount) , () => { tv.Dispose (); - - // TODO seems to be double disposed ?! Assert.True (myReusableView.DisposalCount >= 1); }); } - - private class DisposeCounter : View - { + private class DisposeCounter : View { public int DisposalCount; protected override void Dispose (bool disposing) { @@ -2255,13 +2283,6 @@ private LineView GetLine (TileView tileView) return tileView.Subviews.OfType ().Single (); } - private void SetInputFocusLine (TileView tileView) - { - var line = GetLine (tileView); - line.SetFocus (); - Assert.True (line.HasFocus); - } - private TileView Get5x1TilesView (bool border = true) {