diff --git a/Terminal.Gui/Views/Tab.cs b/Terminal.Gui/Views/Tab.cs
index b683b04b6..52fb0bdf9 100644
--- a/Terminal.Gui/Views/Tab.cs
+++ b/Terminal.Gui/Views/Tab.cs
@@ -22,7 +22,7 @@ public class Tab : View
set
{
_displayText = value;
- SetNeedsDraw ();
+ SetNeedsLayout ();
}
}
diff --git a/Terminal.Gui/Views/TabView.cs b/Terminal.Gui/Views/TabView.cs
index 99d90bec2..1a4d7c6a5 100644
--- a/Terminal.Gui/Views/TabView.cs
+++ b/Terminal.Gui/Views/TabView.cs
@@ -11,7 +11,7 @@ public class TabView : View
/// This sub view is the main client area of the current tab. It hosts the of the tab, the
/// .
///
- private readonly View _contentView;
+ private readonly View _containerView;
private readonly List _tabs = new ();
@@ -28,14 +28,11 @@ public class TabView : View
CanFocus = true;
TabStop = TabBehavior.TabStop; // Because TabView has focusable subviews, it must be a TabGroup
_tabsBar = new TabRowView (this);
- _contentView = new View ()
- {
- //Id = "TabView._contentView",
- };
+ _containerView = new ();
ApplyStyleChanges ();
base.Add (_tabsBar);
- base.Add (_contentView);
+ base.Add (_containerView);
// Things this view knows how to do
AddCommand (Command.Left, () => SwitchTabBy (-1));
@@ -101,6 +98,9 @@ public class TabView : View
///
public uint MaxTabTextWidth { get; set; } = DefaultMaxTabTextWidth;
+ // This is needed to hold initial value because it may change during the setter process
+ private bool _selectedTabHasFocus;
+
/// The currently selected member of chosen by the user.
///
public Tab? SelectedTab
@@ -108,17 +108,16 @@ public class TabView : View
get => _selectedTab;
set
{
- UnSetCurrentTabs ();
-
Tab? old = _selectedTab;
+ _selectedTabHasFocus = old is { } && (old.HasFocus || !_containerView.CanFocus);
if (_selectedTab is { })
{
if (_selectedTab.View is { })
{
- _selectedTab.View.CanFocusChanged -= ContentViewCanFocus!;
+ _selectedTab.View.CanFocusChanged -= ContainerViewCanFocus!;
// remove old content
- _contentView.Remove (_selectedTab.View);
+ _containerView.Remove (_selectedTab.View);
}
}
@@ -127,18 +126,17 @@ public class TabView : View
// add new content
if (_selectedTab?.View != null)
{
- _selectedTab.View.CanFocusChanged += ContentViewCanFocus!;
- _contentView.Add (_selectedTab.View);
- // _contentView.Id = $"_contentView for {_selectedTab.DisplayText}";
+ _selectedTab.View.CanFocusChanged += ContainerViewCanFocus!;
+ _containerView.Add (_selectedTab.View);
}
- ContentViewCanFocus (null!, null!);
+ ContainerViewCanFocus (null!, null!);
EnsureSelectedTabIsVisible ();
if (old != _selectedTab)
{
- if (old?.HasFocus == true)
+ if (_selectedTabHasFocus || !_containerView.CanFocus)
{
SelectedTab?.SetFocus ();
}
@@ -149,9 +147,9 @@ public class TabView : View
}
}
- private void ContentViewCanFocus (object sender, EventArgs eventArgs)
+ private void ContainerViewCanFocus (object sender, EventArgs eventArgs)
{
- _contentView.CanFocus = _contentView.Subviews.Count (v => v.CanFocus) > 0;
+ _containerView.CanFocus = _containerView.Subviews.Count (v => v.CanFocus) > 0;
}
private TabStyle _style = new ();
@@ -220,34 +218,34 @@ public class TabView : View
///
public void ApplyStyleChanges ()
{
- _contentView.BorderStyle = Style.ShowBorder ? LineStyle.Single : LineStyle.None;
- _contentView.Width = Dim.Fill ();
+ _containerView.BorderStyle = Style.ShowBorder ? LineStyle.Single : LineStyle.None;
+ _containerView.Width = Dim.Fill ();
if (Style.TabsOnBottom)
{
// Tabs are along the bottom so just dodge the border
if (Style.ShowBorder)
{
- _contentView.Border.Thickness = new Thickness (1, 1, 1, 0);
+ _containerView.Border!.Thickness = new Thickness (1, 1, 1, 0);
}
- _contentView.Y = 0;
+ _containerView.Y = 0;
int tabHeight = GetTabHeight (false);
// Fill client area leaving space at bottom for tabs
- _contentView.Height = Dim.Fill (tabHeight);
+ _containerView.Height = Dim.Fill (tabHeight);
_tabsBar.Height = tabHeight;
- _tabsBar.Y = Pos.Bottom (_contentView);
+ _tabsBar.Y = Pos.Bottom (_containerView);
}
else
{
// Tabs are along the top
if (Style.ShowBorder)
{
- _contentView.Border.Thickness = new Thickness (1, 0, 1, 1);
+ _containerView.Border!.Thickness = new Thickness (1, 0, 1, 1);
}
_tabsBar.Y = 0;
@@ -255,10 +253,10 @@ public class TabView : View
int tabHeight = GetTabHeight (true);
//move content down to make space for tabs
- _contentView.Y = Pos.Bottom (_tabsBar);
+ _containerView.Y = Pos.Bottom (_tabsBar);
// Fill client area leaving space at bottom for border
- _contentView.Height = Dim.Fill ();
+ _containerView.Height = Dim.Fill ();
// The top tab should be 2 or 3 rows high and on the top
@@ -270,6 +268,14 @@ public class TabView : View
SetNeedsLayout ();
}
+ ///
+ protected override void OnViewportChanged (DrawEventArgs e)
+ {
+ _tabLocations = CalculateViewport (Viewport).ToArray ();
+
+ base.OnViewportChanged (e);
+ }
+
/// Updates to ensure that is visible.
public void EnsureSelectedTabIsVisible ()
{
@@ -295,7 +301,7 @@ public class TabView : View
///
protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocusedView, View? focusedView)
{
- if (SelectedTab is { } && !_contentView.CanFocus && focusedView == this)
+ if (SelectedTab is { HasFocus: false } && !_containerView.CanFocus && focusedView == this)
{
SelectedTab?.SetFocus ();
@@ -305,25 +311,6 @@ public class TabView : View
base.OnHasFocusChanged (newHasFocus, previousFocusedView, focusedView);
}
- ///
- protected override bool OnDrawingContent ()
- {
- if (Tabs.Any ())
- {
- // Region savedClip = SetClip ();
- _tabsBar.Draw ();
- _contentView.SetNeedsDraw ();
- _contentView.Draw ();
-
- //if (Driver is { })
- //{
- // Driver.Clip = savedClip;
- //}
- }
-
- return true;
- }
-
///
/// Removes the given from . Caller is responsible for disposing the
/// tab's hosted if appropriate.
@@ -451,7 +438,7 @@ public class TabView : View
{
if (prevTab is { })
{
- tab.X = Pos.Right (prevTab);
+ tab.X = Pos.Right (prevTab) - 1;
}
else
{
@@ -463,15 +450,11 @@ public class TabView : View
// while there is space for the tab
int tabTextWidth = tab.DisplayText.EnumerateRunes ().Sum (c => c.GetColumns ());
- string text = tab.DisplayText;
-
// The maximum number of characters to use for the tab name as specified
// by the user (MaxTabTextWidth). But not more than the width of the view
// or we won't even be able to render a single tab!
long maxWidth = Math.Max (0, Math.Min (bounds.Width - 3, MaxTabTextWidth));
- prevTab = tab;
-
tab.Width = 2;
tab.Height = Style.ShowTopLine ? 3 : 2;
@@ -480,17 +463,22 @@ public class TabView : View
{
tab.Visible = true;
tab.MouseClick += Tab_MouseClick!;
+ tab.Border!.MouseClick += Tab_MouseClick!;
- yield return new TabToRender (tab, string.Empty, Equals (SelectedTab, tab));
+ yield return new (tab, Equals (SelectedTab, tab));
break;
}
if (tabTextWidth > maxWidth)
{
- text = tab.DisplayText.Substring (0, (int)maxWidth);
+ tab.Text = tab.DisplayText.Substring (0, (int)maxWidth);
tabTextWidth = (int)maxWidth;
}
+ else
+ {
+ tab.Text = tab.DisplayText;
+ }
tab.Width = Math.Max (tabTextWidth + 2, 1);
tab.Height = Style.ShowTopLine ? 3 : 2;
@@ -506,11 +494,19 @@ public class TabView : View
// there is enough space!
tab.Visible = true;
tab.MouseClick += Tab_MouseClick!;
+ tab.Border!.MouseClick += Tab_MouseClick!;
- yield return new TabToRender (tab, text, Equals (SelectedTab, tab));
+ yield return new (tab, Equals (SelectedTab, tab));
+
+ prevTab = tab;
i += tabTextWidth + 1;
}
+
+ if (_selectedTabHasFocus)
+ {
+ SelectedTab?.SetFocus ();
+ }
}
///
@@ -542,11 +538,27 @@ public class TabView : View
private void UnSetCurrentTabs ()
{
- if (_tabLocations is { })
+ if (_tabLocations is null)
+ {
+ // Ensures unset any visible tab prior to TabScrollOffset
+ for (int i = 0; i < TabScrollOffset; i++)
+ {
+ Tab tab = Tabs.ElementAt (i);
+
+ if (tab.Visible)
+ {
+ tab.MouseClick -= Tab_MouseClick!;
+ tab.Border!.MouseClick -= Tab_MouseClick!;
+ tab.Visible = false;
+ }
+ }
+ }
+ else if (_tabLocations is { })
{
foreach (TabToRender tabToRender in _tabLocations)
{
tabToRender.Tab.MouseClick -= Tab_MouseClick!;
+ tabToRender.Tab.Border!.MouseClick -= Tab_MouseClick!;
tabToRender.Tab.Visible = false;
}
@@ -570,7 +582,6 @@ public class TabView : View
Id = "tabRowView";
CanFocus = true;
- Height = 1; // BUGBUG: Views should avoid setting Height as doing so implies Frame.Size == GetContentSize ().
Width = Dim.Fill ();
_rightScrollIndicator = new View
@@ -598,17 +609,23 @@ public class TabView : View
protected override bool OnMouseEvent (MouseEventArgs me)
{
- Tab? hit = me.View as Tab;
+ View? parent = me.View is Adornment adornment ? adornment.Parent : me.View;
+ Tab? hit = parent as Tab;
if (me.IsSingleClicked)
{
- _host.OnTabClicked (new TabMouseEventArgs (hit, me));
+ _host.OnTabClicked (new TabMouseEventArgs (hit!, me));
// user canceled click
if (me.Handled)
{
return true;
}
+
+ if (parent == _host.SelectedTab)
+ {
+ _host.SelectedTab?.SetFocus ();
+ }
}
if (!me.IsSingleDoubleOrTripleClicked)
@@ -625,11 +642,11 @@ public class TabView : View
{
var scrollIndicatorHit = 0;
- if (me.View is { } && me.View.Id == "rightScrollIndicator")
+ if (me.View is { Id: "rightScrollIndicator" })
{
scrollIndicatorHit = 1;
}
- else if (me.View is { } && me.View.Id == "leftScrollIndicator")
+ else if (me.View is { Id: "leftScrollIndicator" })
{
scrollIndicatorHit = -1;
}
@@ -656,15 +673,20 @@ public class TabView : View
}
///
- protected override bool OnClearingViewport ()
+ protected override void OnHasFocusChanged (bool newHasFocus, View? previousFocusedView, View? focusedView)
{
- // clear any old text
- ClearViewport ();
+ if (_host.SelectedTab is { HasFocus: false, CanFocus: true } && focusedView == this)
+ {
+ _host.SelectedTab?.SetFocus ();
- return true;
+ return;
+ }
+
+ base.OnHasFocusChanged (newHasFocus, previousFocusedView, focusedView);
}
- protected override bool OnDrawingContent ()
+ ///
+ protected override void OnSubviewLayout (LayoutEventArgs args)
{
_host._tabLocations = _host.CalculateViewport (Viewport).ToArray ();
@@ -672,20 +694,18 @@ public class TabView : View
RenderUnderline ();
- SetAttribute (HasFocus ? GetFocusColor () : GetNormalColor ());
-
- return true;
+ base.OnSubviewLayout (args);
}
///
- protected override bool OnDrawingSubviews ()
+ protected override bool OnRenderingLineCanvas ()
{
- // RenderTabLine ();
+ RenderTabLineCanvas ();
return false;
}
- protected override void OnDrawComplete ()
+ private void RenderTabLineCanvas ()
{
if (_host._tabLocations is null)
{
@@ -694,12 +714,12 @@ public class TabView : View
TabToRender [] tabLocations = _host._tabLocations;
int selectedTab = -1;
+ var lc = new LineCanvas ();
for (var i = 0; i < tabLocations.Length; i++)
{
View tab = tabLocations [i].Tab;
Rectangle vts = tab.ViewportToScreen (tab.Viewport);
- var lc = new LineCanvas ();
int selectedOffset = _host.Style.ShowTopLine && tabLocations [i].IsSelected ? 0 : 1;
if (tabLocations [i].IsSelected)
@@ -1048,7 +1068,7 @@ public class TabView : View
}
}
- if (i == 0 && i != selectedTab && _host.TabScrollOffset == 0 && _host.Style.ShowBorder)
+ if (i == 0 && i != selectedTab && _host is { TabScrollOffset: 0, Style.ShowBorder: true })
{
if (_host.Style.TabsOnBottom)
{
@@ -1163,6 +1183,7 @@ public class TabView : View
}
else
{
+ // Right corner
if (_host.Style.TabsOnBottom)
{
lc.AddLine (
@@ -1213,12 +1234,9 @@ public class TabView : View
}
}
}
-
- tab.LineCanvas.Merge (lc);
- tab.RenderLineCanvas ();
-
- // RenderUnderline ();
}
+
+ _host.LineCanvas.Merge (lc);
}
private int GetUnderlineYPosition ()
@@ -1234,9 +1252,7 @@ public class TabView : View
/// Renders the line with the tab names in it.
private void RenderTabLine ()
{
- TabToRender []? tabLocations = _host._tabLocations;
-
- if (tabLocations is null)
+ if (_host._tabLocations is null)
{
return;
}
@@ -1244,7 +1260,7 @@ public class TabView : View
View? selected = null;
int topLine = _host.Style.ShowTopLine ? 1 : 0;
- foreach (TabToRender toRender in tabLocations)
+ foreach (TabToRender toRender in _host._tabLocations)
{
Tab tab = toRender.Tab;
@@ -1254,80 +1270,45 @@ public class TabView : View
if (_host.Style.TabsOnBottom)
{
- tab.Border.Thickness = new Thickness (1, 0, 1, topLine);
- tab.Margin.Thickness = new Thickness (0, 1, 0, 0);
+ tab.Border!.Thickness = new (1, 0, 1, topLine);
+ tab.Margin!.Thickness = new (0, 1, 0, 0);
}
else
{
- tab.Border.Thickness = new Thickness (1, topLine, 1, 0);
- tab.Margin.Thickness = new Thickness (0, 0, 0, topLine);
+ tab.Border!.Thickness = new (1, topLine, 1, 0);
+ tab.Margin!.Thickness = new (0, 0, 0, topLine);
}
}
else if (selected is null)
{
if (_host.Style.TabsOnBottom)
{
- tab.Border.Thickness = new Thickness (1, 1, 0, topLine);
- tab.Margin.Thickness = new Thickness (0, 0, 0, 0);
+ tab.Border!.Thickness = new (1, 1, 1, topLine);
+ tab.Margin!.Thickness = new (0, 0, 0, 0);
}
else
{
- tab.Border.Thickness = new Thickness (1, topLine, 0, 1);
- tab.Margin.Thickness = new Thickness (0, 0, 0, 0);
+ tab.Border!.Thickness = new (1, topLine, 1, 1);
+ tab.Margin!.Thickness = new (0, 0, 0, 0);
}
-
- tab.Width = Math.Max (tab.Width!.GetAnchor (0) - 1, 1);
}
else
{
if (_host.Style.TabsOnBottom)
{
- tab.Border.Thickness = new Thickness (0, 1, 1, topLine);
- tab.Margin.Thickness = new Thickness (0, 0, 0, 0);
+ tab.Border!.Thickness = new (1, 1, 1, topLine);
+ tab.Margin!.Thickness = new (0, 0, 0, 0);
}
else
{
- tab.Border.Thickness = new Thickness (0, topLine, 1, 1);
- tab.Margin.Thickness = new Thickness (0, 0, 0, 0);
- }
-
- tab.Width = Math.Max (tab.Width!.GetAnchor (0) - 1, 1);
- }
-
- tab.Text = toRender.TextToRender;
-
- // BUGBUG: Layout should only be called from Mainloop iteration!
- Layout ();
-
- tab.DrawBorderAndPadding ();
-
- Attribute prevAttr = Driver?.GetAttribute () ?? Attribute.Default;
-
- // if tab is the selected one and focus is inside this control
- if (toRender.IsSelected && _host.HasFocus)
- {
- if (_host.Focused == this)
- {
- // if focus is the tab bar itself then show that they can switch tabs
- prevAttr = ColorScheme.HotFocus;
- }
- else
- {
- // Focus is inside the tab
- prevAttr = ColorScheme.HotNormal;
+ tab.Border!.Thickness = new (1, topLine, 1, 1);
+ tab.Margin!.Thickness = new (0, 0, 0, 0);
}
}
- tab.TextFormatter.Draw (
- tab.ViewportToScreen (tab.Viewport),
- prevAttr,
- ColorScheme.HotNormal
- );
-
- tab.DrawBorderAndPadding ();
-
-
- SetAttribute (GetNormalColor ());
+ // Ensures updating TextFormatter constrains
+ tab.TextFormatter.ConstrainToWidth = tab.GetContentSize ().Width;
+ tab.TextFormatter.ConstrainToHeight = tab.GetContentSize ().Height;
}
}
@@ -1356,7 +1337,6 @@ public class TabView : View
// Ensures this is clicked instead of the first tab
MoveSubviewToEnd (_leftScrollIndicator);
- _leftScrollIndicator.Draw ();
}
else
{
@@ -1374,7 +1354,6 @@ public class TabView : View
// Ensures this is clicked instead of the last tab if under this
MoveSubviewToStart (_rightScrollIndicator);
- _rightScrollIndicator.Draw ();
}
else
{
@@ -1387,11 +1366,10 @@ public class TabView : View
private class TabToRender
{
- public TabToRender (Tab tab, string textToRender, bool isSelected)
+ public TabToRender (Tab tab, bool isSelected)
{
Tab = tab;
IsSelected = isSelected;
- TextToRender = textToRender;
}
/// True if the tab that is being rendered is the selected one.
@@ -1399,6 +1377,5 @@ public class TabView : View
public bool IsSelected { get; }
public Tab Tab { get; }
- public string TextToRender { get; }
}
}
diff --git a/UnitTests/View/Adornment/PaddingTests.cs b/UnitTests/View/Adornment/PaddingTests.cs
index 0242bcc1d..a4defc997 100644
--- a/UnitTests/View/Adornment/PaddingTests.cs
+++ b/UnitTests/View/Adornment/PaddingTests.cs
@@ -33,5 +33,7 @@ PPP",
output
);
TestHelpers.AssertDriverAttributesAre ("0", output, null, view.GetNormalColor ());
+
+ ((FakeDriver)Application.Driver!).End ();
}
}
diff --git a/UnitTests/View/Layout/SetLayoutTests.cs b/UnitTests/View/Layout/SetLayoutTests.cs
index 4859957d6..ce0addd54 100644
--- a/UnitTests/View/Layout/SetLayoutTests.cs
+++ b/UnitTests/View/Layout/SetLayoutTests.cs
@@ -813,5 +813,105 @@ public class SetLayoutTests (ITestOutputHelper output)
t.Dispose ();
}
+ [Fact]
+ [SetupFakeDriver]
+ public void Pos_Right_With_Adornments ()
+ {
+ View view1 = new () { Text = "View1", Width = 7, Height = 3, BorderStyle = LineStyle.Rounded };
+ View view2 = new () { Text = "View2", X = Pos.Right (view1) - 1, Width = 7, Height = 3, BorderStyle = LineStyle.Rounded };
+ View view3 = new () { Text = "View3", X = Pos.Right (view2) - 1, Width = 7, Height = 3, BorderStyle = LineStyle.Rounded };
+ View container = new () { Width = Dim.Fill (), Height = 3 };
+ container.Add (view1, view2, view3);
+ View view4 = new () { Text = "View4", Y = Pos.Bottom (container), Width = 21, Height = 3, BorderStyle = LineStyle.Rounded };
+ View superView = new () { Width = Dim.Fill (), Height = Dim.Fill () };
+ superView.Add (container, view4);
+
+ superView.Layout ();
+ superView.Draw ();
+
+ TestHelpers.AssertDriverContentsAre (
+ @"
+╭─────╭─────╭─────╮
+│View1│View2│View3│
+╰─────╰─────╰─────╯
+╭───────────────────╮
+│View4 │
+╰───────────────────╯
+",
+ output
+ );
+
+ // Remove border bottom from the view1
+ view1.Border!.Thickness = new (1, 1, 1, 0);
+ // Insert margin bottom into the view1
+ view1.Margin!.Thickness = new (0, 0, 0, 1);
+
+ View.SetClipToScreen ();
+ superView.Draw ();
+
+ TestHelpers.AssertDriverContentsAre (
+ @"
+╭─────╭─────╭─────╮
+│View1│View2│View3│
+ ╰─────╰─────╯
+╭───────────────────╮
+│View4 │
+╰───────────────────╯
+",
+ output
+ );
+
+ // Restore view1 border
+ view1.Border.Thickness = new (1);
+ // Restore view1 margin
+ view1.Margin.Thickness = Thickness.Empty;
+
+ // Remove border bottom from the view2
+ view2.Border!.Thickness = new (1, 1, 1, 0);
+ // Insert margin bottom into the view2
+ view2.Margin!.Thickness = new (0, 0, 0, 1);
+
+ View.SetClipToScreen ();
+ superView.Draw ();
+
+ TestHelpers.AssertDriverContentsAre (
+ @"
+╭─────╭─────╭─────╮
+│View1│View2│View3│
+╰─────╯ ╰─────╯
+╭───────────────────╮
+│View4 │
+╰───────────────────╯
+",
+ output
+ );
+
+ // Restore view2 border
+ view2.Border.Thickness = new (1);
+ // Restore view2 margin
+ view2.Margin.Thickness = Thickness.Empty;
+
+ // Remove border bottom from the view3
+ view3.Border!.Thickness = new (1, 1, 1, 0);
+ // Insert margin bottom into the view3
+ view3.Margin!.Thickness = new (0, 0, 0, 1);
+
+ View.SetClipToScreen ();
+ superView.Draw ();
+
+ TestHelpers.AssertDriverContentsAre (
+ @"
+╭─────╭─────╭─────╮
+│View1│View2│View3│
+╰─────╰─────╯
+╭───────────────────╮
+│View4 │
+╰───────────────────╯
+",
+ output
+ );
+
+ superView.Dispose ();
+ }
}
diff --git a/UnitTests/Views/TabViewTests.cs b/UnitTests/Views/TabViewTests.cs
index 3999142fa..1ab880b7f 100644
--- a/UnitTests/Views/TabViewTests.cs
+++ b/UnitTests/Views/TabViewTests.cs
@@ -3,7 +3,6 @@ using Xunit.Abstractions;
namespace Terminal.Gui.ViewsTests;
-#if foo
public class TabViewTests (ITestOutputHelper output)
{
[Fact]
@@ -113,8 +112,6 @@ public class TabViewTests (ITestOutputHelper output)
tv.Width = 20;
tv.Height = 5;
- tv.Layout ();
-
tv.Draw ();
View tabRow = tv.Subviews [0];
@@ -146,21 +143,21 @@ public class TabViewTests (ITestOutputHelper output)
{
args = new () { ScreenPosition = new (i, 1), Flags = MouseFlags.ReportMousePosition };
Application.RaiseMouseEvent (args);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
Assert.Null (clicked);
Assert.Equal (tab1, tv.SelectedTab);
}
args = new () { ScreenPosition = new (3, 1), Flags = MouseFlags.Button1Clicked };
Application.RaiseMouseEvent (args);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
Assert.Equal (tab1, clicked);
Assert.Equal (tab1, tv.SelectedTab);
// Click to tab2
args = new () { ScreenPosition = new (6, 1), Flags = MouseFlags.Button1Clicked };
Application.RaiseMouseEvent (args);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
Assert.Equal (tab2, clicked);
Assert.Equal (tab2, tv.SelectedTab);
@@ -173,7 +170,7 @@ public class TabViewTests (ITestOutputHelper output)
args = new () { ScreenPosition = new (3, 1), Flags = MouseFlags.Button1Clicked };
Application.RaiseMouseEvent (args);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
// Tab 1 was clicked but event handler blocked navigation
Assert.Equal (tab1, clicked);
@@ -181,7 +178,7 @@ public class TabViewTests (ITestOutputHelper output)
args = new () { ScreenPosition = new (12, 1), Flags = MouseFlags.Button1Clicked };
Application.RaiseMouseEvent (args);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
// Clicking beyond last tab should raise event with null Tab
Assert.Null (clicked);
@@ -198,8 +195,6 @@ public class TabViewTests (ITestOutputHelper output)
tv.Width = 7;
tv.Height = 5;
- tv.LayoutSubviews ();
-
tv.Draw ();
View tabRow = tv.Subviews [0];
@@ -236,7 +231,7 @@ public class TabViewTests (ITestOutputHelper output)
// Click the right arrow
var args = new MouseEventArgs { ScreenPosition = new (6, 2), Flags = MouseFlags.Button1Clicked };
Application.RaiseMouseEvent (args);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
Assert.Null (clicked);
Assert.Equal (tab1, oldChanged);
Assert.Equal (tab2, newChanged);
@@ -256,7 +251,7 @@ public class TabViewTests (ITestOutputHelper output)
// Click the left arrow
args = new () { ScreenPosition = new (0, 2), Flags = MouseFlags.Button1Clicked };
Application.RaiseMouseEvent (args);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
Assert.Null (clicked);
Assert.Equal (tab2, oldChanged);
Assert.Equal (tab1, newChanged);
@@ -286,8 +281,7 @@ public class TabViewTests (ITestOutputHelper output)
Assert.Equal (LineStyle.None, tv.BorderStyle);
tv.BorderStyle = LineStyle.Single;
-
- tv.LayoutSubviews ();
+ tv.Layout ();
tv.Draw ();
@@ -327,7 +321,7 @@ public class TabViewTests (ITestOutputHelper output)
// Click the right arrow
var args = new MouseEventArgs { ScreenPosition = new (7, 3), Flags = MouseFlags.Button1Clicked };
Application.RaiseMouseEvent (args);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
Assert.Null (clicked);
Assert.Equal (tab1, oldChanged);
Assert.Equal (tab2, newChanged);
@@ -349,7 +343,7 @@ public class TabViewTests (ITestOutputHelper output)
// Click the left arrow
args = new () { ScreenPosition = new (1, 3), Flags = MouseFlags.Button1Clicked };
Application.RaiseMouseEvent (args);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
Assert.Null (clicked);
Assert.Equal (tab2, oldChanged);
Assert.Equal (tab1, newChanged);
@@ -400,7 +394,7 @@ public class TabViewTests (ITestOutputHelper output)
// Press the cursor up key to focus the selected tab
Application.RaiseKeyDownEvent (Key.CursorUp);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
// Is the selected tab focused
Assert.Equal (tab1, tv.SelectedTab);
@@ -418,7 +412,7 @@ public class TabViewTests (ITestOutputHelper output)
// Press the cursor right key to select the next tab
Application.RaiseKeyDownEvent (Key.CursorRight);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
Assert.Equal (tab1, oldChanged);
Assert.Equal (tab2, newChanged);
Assert.Equal (tab2, tv.SelectedTab);
@@ -476,7 +470,7 @@ public class TabViewTests (ITestOutputHelper output)
// Press the cursor left key to select the previous tab
Application.RaiseKeyDownEvent (Key.CursorLeft);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
Assert.Equal (tab2, oldChanged);
Assert.Equal (tab1, newChanged);
Assert.Equal (tab1, tv.SelectedTab);
@@ -486,7 +480,7 @@ public class TabViewTests (ITestOutputHelper output)
// Press the end key to select the last tab
Application.RaiseKeyDownEvent (Key.End);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
Assert.Equal (tab1, oldChanged);
Assert.Equal (tab2, newChanged);
Assert.Equal (tab2, tv.SelectedTab);
@@ -495,7 +489,7 @@ public class TabViewTests (ITestOutputHelper output)
// Press the home key to select the first tab
Application.RaiseKeyDownEvent (Key.Home);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
Assert.Equal (tab2, oldChanged);
Assert.Equal (tab1, newChanged);
Assert.Equal (tab1, tv.SelectedTab);
@@ -504,7 +498,7 @@ public class TabViewTests (ITestOutputHelper output)
// Press the page down key to select the next set of tabs
Application.RaiseKeyDownEvent (Key.PageDown);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
Assert.Equal (tab1, oldChanged);
Assert.Equal (tab2, newChanged);
Assert.Equal (tab2, tv.SelectedTab);
@@ -513,7 +507,7 @@ public class TabViewTests (ITestOutputHelper output)
// Press the page up key to select the previous set of tabs
Application.RaiseKeyDownEvent (Key.PageUp);
- Application.LayoutAndDrawToplevels ();
+ Application.LayoutAndDraw ();
Assert.Equal (tab2, oldChanged);
Assert.Equal (tab1, newChanged);
Assert.Equal (tab1, tv.SelectedTab);
@@ -610,7 +604,6 @@ public class TabViewTests (ITestOutputHelper output)
tv.ApplyStyleChanges ();
tv.Layout ();
- View.ClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -633,7 +626,7 @@ public class TabViewTests (ITestOutputHelper output)
tv.Height = 5;
tv.Style = new () { ShowTopLine = false };
tv.ApplyStyleChanges ();
- tv.LayoutSubviews ();
+ tv.Layout ();
tv.Draw ();
@@ -658,13 +651,13 @@ public class TabViewTests (ITestOutputHelper output)
tv.Style = new () { ShowTopLine = false };
tv.ApplyStyleChanges ();
- // Ensures that the tab bar subview gets the bounds of the parent TabView
- tv.LayoutSubviews ();
-
- // Test two tab names that fit
+ // Test two tab names that fit
tab1.DisplayText = "12";
tab2.DisplayText = "13";
+ // Ensures that the tab bar subview gets the bounds of the parent TabView
+ tv.Layout ();
+
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -678,8 +671,10 @@ public class TabViewTests (ITestOutputHelper output)
);
tv.SelectedTab = tab2;
+ Assert.Equal (tab2, tv.Subviews.First (v => v.Id.Contains ("tabRowView")).MostFocused);
- View.ClipToScreen ();
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -697,8 +692,8 @@ public class TabViewTests (ITestOutputHelper output)
// Test first tab name too long
tab1.DisplayText = "12345678910";
tab2.DisplayText = "13";
-
- View.ClipToScreen ();
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -713,9 +708,10 @@ public class TabViewTests (ITestOutputHelper output)
//switch to tab2
tv.SelectedTab = tab2;
- View.ClipToScreen ();
- tv.Draw ();
+ tv.Layout ();
+ View.SetClipToScreen ();
+ tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@"
│13│
@@ -730,9 +726,9 @@ public class TabViewTests (ITestOutputHelper output)
tab1.DisplayText = "12345678910";
tab2.DisplayText = "abcdefghijklmnopq";
- View.ClipToScreen ();
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
-
TestHelpers.AssertDriverContentsWithFrameAre (
@"
│abcdefg│
@@ -753,9 +749,8 @@ public class TabViewTests (ITestOutputHelper output)
tv.Height = 5;
tv.Style = new () { ShowTopLine = false, TabsOnBottom = true };
tv.ApplyStyleChanges ();
- tv.LayoutSubviews ();
+ tv.Layout ();
- View.ClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -778,7 +773,7 @@ public class TabViewTests (ITestOutputHelper output)
tv.Height = 5;
tv.Style = new () { ShowTopLine = false, TabsOnBottom = true };
tv.ApplyStyleChanges ();
- tv.LayoutSubviews ();
+ tv.Layout ();
tv.Draw ();
@@ -802,15 +797,13 @@ public class TabViewTests (ITestOutputHelper output)
tv.Height = 5;
tv.Style = new () { ShowTopLine = false, TabsOnBottom = true };
tv.ApplyStyleChanges ();
+ tv.Layout ();
- // Ensures that the tab bar subview gets the bounds of the parent TabView
- tv.LayoutSubviews ();
-
- // Test two tab names that fit
+ // Test two tab names that fit
tab1.DisplayText = "12";
tab2.DisplayText = "13";
- View.ClipToScreen ();
+ tv.Layout ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -824,8 +817,10 @@ public class TabViewTests (ITestOutputHelper output)
);
tv.SelectedTab = tab2;
+ Assert.Equal (tab2, tv.Subviews.First (v => v.Id.Contains ("tabRowView")).MostFocused);
- View.ClipToScreen ();
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -844,7 +839,8 @@ public class TabViewTests (ITestOutputHelper output)
tab1.DisplayText = "12345678910";
tab2.DisplayText = "13";
- View.ClipToScreen ();
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -859,7 +855,9 @@ public class TabViewTests (ITestOutputHelper output)
//switch to tab2
tv.SelectedTab = tab2;
- View.ClipToScreen ();
+
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -876,7 +874,8 @@ public class TabViewTests (ITestOutputHelper output)
tab1.DisplayText = "12345678910";
tab2.DisplayText = "abcdefghijklmnopq";
- View.ClipToScreen ();
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -899,7 +898,6 @@ public class TabViewTests (ITestOutputHelper output)
tv.Height = 5;
tv.Layout ();
- View.ClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -922,7 +920,7 @@ public class TabViewTests (ITestOutputHelper output)
tv.Height = 5;
tv.Layout ();
- View.ClipToScreen ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -944,14 +942,11 @@ public class TabViewTests (ITestOutputHelper output)
tv.Width = 10;
tv.Height = 5;
- // Ensures that the tab bar subview gets the bounds of the parent TabView
- tv.LayoutSubviews ();
-
- // Test two tab names that fit
+ // Test two tab names that fit
tab1.DisplayText = "12";
tab2.DisplayText = "13";
- View.ClipToScreen ();
+ tv.Layout ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -966,7 +961,8 @@ public class TabViewTests (ITestOutputHelper output)
tv.SelectedTab = tab2;
- View.ClipToScreen ();
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -985,7 +981,8 @@ public class TabViewTests (ITestOutputHelper output)
tab1.DisplayText = "12345678910";
tab2.DisplayText = "13";
- View.ClipToScreen ();
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1000,7 +997,9 @@ public class TabViewTests (ITestOutputHelper output)
//switch to tab2
tv.SelectedTab = tab2;
- View.ClipToScreen ();
+
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1017,7 +1016,8 @@ public class TabViewTests (ITestOutputHelper output)
tab1.DisplayText = "12345678910";
tab2.DisplayText = "abcdefghijklmnopq";
- View.ClipToScreen ();
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1039,13 +1039,11 @@ public class TabViewTests (ITestOutputHelper output)
tv.Width = 20;
tv.Height = 5;
- tv.LayoutSubviews ();
-
tab1.DisplayText = "Tab0";
tab2.DisplayText = "Les Mise" + char.ConvertFromUtf32 (int.Parse ("0301", NumberStyles.HexNumber)) + "rables";
- View.ClipToScreen ();
+ tv.Layout ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1060,7 +1058,8 @@ public class TabViewTests (ITestOutputHelper output)
tv.SelectedTab = tab2;
- View.ClipToScreen ();
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1083,7 +1082,7 @@ public class TabViewTests (ITestOutputHelper output)
tv.Height = 5;
tv.Style = new () { TabsOnBottom = true };
tv.ApplyStyleChanges ();
- tv.LayoutSubviews ();
+ tv.Layout ();
tv.Draw ();
@@ -1107,7 +1106,7 @@ public class TabViewTests (ITestOutputHelper output)
tv.Height = 5;
tv.Style = new () { TabsOnBottom = true };
tv.ApplyStyleChanges ();
- tv.LayoutSubviews ();
+ tv.Layout ();
tv.Draw ();
@@ -1131,15 +1130,13 @@ public class TabViewTests (ITestOutputHelper output)
tv.Height = 5;
tv.Style = new () { TabsOnBottom = true };
tv.ApplyStyleChanges ();
+ tv.Layout ();
- // Ensures that the tab bar subview gets the bounds of the parent TabView
- tv.LayoutSubviews ();
-
- // Test two tab names that fit
+ // Test two tab names that fit
tab1.DisplayText = "12";
tab2.DisplayText = "13";
- View.ClipToScreen ();
+ tv.Layout ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1156,7 +1153,8 @@ public class TabViewTests (ITestOutputHelper output)
tab1.DisplayText = "12345678910";
tab2.DisplayText = "13";
- View.ClipToScreen ();
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1171,7 +1169,9 @@ public class TabViewTests (ITestOutputHelper output)
//switch to tab2
tv.SelectedTab = tab2;
- View.ClipToScreen ();
+
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1188,7 +1188,8 @@ public class TabViewTests (ITestOutputHelper output)
tab1.DisplayText = "12345678910";
tab2.DisplayText = "abcdefghijklmnopq";
- View.ClipToScreen ();
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1212,12 +1213,11 @@ public class TabViewTests (ITestOutputHelper output)
tv.Style = new () { TabsOnBottom = true };
tv.ApplyStyleChanges ();
- tv.LayoutSubviews ();
-
tab1.DisplayText = "Tab0";
tab2.DisplayText = "Les Mise" + char.ConvertFromUtf32 (int.Parse ("0301", NumberStyles.HexNumber)) + "rables";
+ tv.Layout ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1232,7 +1232,8 @@ public class TabViewTests (ITestOutputHelper output)
tv.SelectedTab = tab2;
- View.ClipToScreen ();
+ tv.Layout ();
+ View.SetClipToScreen ();
tv.Draw ();
TestHelpers.AssertDriverContentsWithFrameAre (
@@ -1322,6 +1323,138 @@ public class TabViewTests (ITestOutputHelper output)
Application.Shutdown ();
}
+ [Fact]
+ [SetupFakeDriver]
+ public void Add_Three_TabsOnTop_ChangesTab ()
+ {
+ TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
+ Tab tab3;
+
+ tv.AddTab (
+ tab3 = new () { Id = "tab3", DisplayText = "Tab3", View = new TextView { Id = "tab3.TextView", Width = 3, Height = 1, Text = "hi3" } },
+ false);
+
+ tv.Width = 20;
+ tv.Height = 5;
+
+ tv.Layout ();
+ tv.Draw ();
+
+ Assert.Equal (tab1, tv.SelectedTab);
+
+ TestHelpers.AssertDriverContentsAre (
+ @"
+╭────┬────┬────╮
+│Tab1│Tab2│Tab3│
+│ ╰────┴────┴───╮
+│hi │
+└──────────────────┘
+",
+ output
+ );
+
+ tv.SelectedTab = tab2;
+
+ tv.Layout ();
+ View.SetClipToScreen ();
+ tv.Draw ();
+
+ TestHelpers.AssertDriverContentsWithFrameAre (
+ @"
+╭────┬────┬────╮
+│Tab1│Tab2│Tab3│
+├────╯ ╰────┴───╮
+│hi2 │
+└──────────────────┘
+",
+ output
+ );
+
+ tv.SelectedTab = tab3;
+
+ tv.Layout ();
+ View.SetClipToScreen ();
+ tv.Draw ();
+
+ TestHelpers.AssertDriverContentsWithFrameAre (
+ @"
+╭────┬────┬────╮
+│Tab1│Tab2│Tab3│
+├────┴────╯ ╰───╮
+│hi3 │
+└──────────────────┘
+",
+ output
+ );
+ }
+
+ [Fact]
+ [SetupFakeDriver]
+ public void Add_Three_TabsOnBottom_ChangesTab ()
+ {
+ TabView tv = GetTabView (out Tab tab1, out Tab tab2, false);
+ Tab tab3;
+
+ tv.AddTab (
+ tab3 = new () { Id = "tab3", DisplayText = "Tab3", View = new TextView { Id = "tab3.TextView", Width = 3, Height = 1, Text = "hi3" } },
+ false);
+
+ tv.Width = 20;
+ tv.Height = 5;
+ tv.Style = new () { TabsOnBottom = true };
+ tv.ApplyStyleChanges ();
+
+ tv.Layout ();
+ tv.Draw ();
+
+ Assert.Equal (tab1, tv.SelectedTab);
+
+ TestHelpers.AssertDriverContentsAre (
+ @"
+┌──────────────────┐
+│hi │
+│ ╭────┬────┬───╯
+│Tab1│Tab2│Tab3│
+╰────┴────┴────╯
+",
+ output
+ );
+
+ tv.SelectedTab = tab2;
+
+ tv.Layout ();
+ View.SetClipToScreen ();
+ tv.Draw ();
+
+ TestHelpers.AssertDriverContentsWithFrameAre (
+ @"
+┌──────────────────┐
+│hi2 │
+├────╮ ╭────┬───╯
+│Tab1│Tab2│Tab3│
+╰────┴────┴────╯
+",
+ output
+ );
+
+ tv.SelectedTab = tab3;
+
+ tv.Layout ();
+ View.SetClipToScreen ();
+ tv.Draw ();
+
+ TestHelpers.AssertDriverContentsWithFrameAre (
+ @"
+┌──────────────────┐
+│hi3 │
+├────┬────╮ ╭───╯
+│Tab1│Tab2│Tab3│
+╰────┴────┴────╯
+",
+ output
+ );
+ }
+
private TabView GetTabView () { return GetTabView (out _, out _); }
private TabView GetTabView (out Tab tab1, out Tab tab2, bool initFakeDriver = true)
@@ -1355,4 +1488,3 @@ public class TabViewTests (ITestOutputHelper output)
driver.Init ();
}
}
-#endif