mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-27 08:17:53 +01:00
* Fixes #2482. Refactor Redraw - Non-virtual with the right set of virtual OnXXX methods. * Change documentation comments. * Fixes #2575 - TableView to use interface instead of System.Data.DataTable (#2576) * WIP: Add ITableDataSource * WIP: Refactor TableView * WIP: Port CSVEditor * WIP: Port TableEditor * WIP: Port MultiColouredTable scenario * Fix bug of adding duplicate column styles * Update tests to use DataTableSource * Tidy up * Add EnumerableTableDataSource<T> * Add test for EnumerableTableDataSource * Add test for EnumerableTableDataSource * Add code example to xmldoc * Add ProcessTable scenario * Rename ITableDataSource to ITableSource and update docs * Rename EnumerableTableDataSource to EnumerableTableSource * Fixed Frame != Bounds; changed UICat Scenarios list to use tableview! * Fix scroll resetting in ProcessTable scenario * Fix unit tests by setting Frame to same as Bounds * Document why we have to measure our data for use with TableView --------- Co-authored-by: Tig Kindel <tig@users.noreply.github.com> * Fixes #2582 - Refactors FileDialog for cleaner data model (#2583) * WIP: Add ITableDataSource * WIP: Refactor TableView * WIP: Port CSVEditor * WIP: Port TableEditor * WIP: Port MultiColouredTable scenario * Fix bug of adding duplicate column styles * Update tests to use DataTableSource * Tidy up * Add EnumerableTableDataSource<T> * Add test for EnumerableTableDataSource * Add test for EnumerableTableDataSource * Add code example to xmldoc * Add ProcessTable scenario * Rename ITableDataSource to ITableSource and update docs * Rename EnumerableTableDataSource to EnumerableTableSource * Fixed Frame != Bounds; changed UICat Scenarios list to use tableview! * Fix scroll resetting in ProcessTable scenario * Fix unit tests by setting Frame to same as Bounds * Document why we have to measure our data for use with TableView * WIP: Simplify FileDialogs use of TableView * WIP start migrating sorter * WIP new filedialog table source mostly working * WIP remove sorter class * Refactor GetOrderByValue to be adjacent to GetColumnValue * Fix collection navigator back so it ignores icon * Fix unit tests * Tidy up * Fix UseColors * Add test for UseColors --------- Co-authored-by: Tig Kindel <tig@users.noreply.github.com> * Fixes #2196. TextView: Setting Text places cursor at beginning, unlike TextField (#2572) * Fixes #2196. TextView: Setting Text places cursor at beginning, unlike TextField * Change all private members to have the _prefix. * Renamed local member to prevLayoutStyle. * Helper function for SetNeedsDisplay. * Fixes #2569. Borders scenarios needed to be refactored. (#2570) * Fixes #2569. Borders scenarios needed to be refactored. * Fix border title with width equal to 4 and thickness top grater than 1. * Improves border manipulation on borders scenarios. * Prevents null value on the margin, border and padding thickness on the border scenarios. * Remove NStack using dependence and fix prior commit. * Refactoring the Frames scenario. * Deleted borders scenarios. * I did not realize that it was changed to SetSubViewNeedsDisplay. * Re-layout; fixed colorpicker; fixed radio group * Remove Thickness.IsEmpty as requested. * Change the Frames scenario as requested. --------- Co-authored-by: Tig Kindel <tig@users.noreply.github.com> * Builds CollectionNavigator support into UI Catalog for TableView (#2584) * Builds collectionnav support into UI cat for TableView * Fixes keyboard mapping * MultiSelect = false for TableView * MultiSelect = false doesn't unbind ctrl-a * Fixes #2581 Refactor CollectionNavigator so it supports TableView (#2586) * Refactor CollectionNavigator to a base and a collection implementation * Refactor CollectionNavigatorBase to look for first match smartly * Add TableCollectionNavigator * Make TableCollectionNavigator a core part of TableView * Fix bad merge * Added tests for tableview collection navigator * Add FileDialogCollectionNavigator which ignores . and directory separator prefixes on file names * whitespace fixes --------- Co-authored-by: Tig <tig@users.noreply.github.com> * Resolving merge conflicts. * Fix merge errors. * Fix merge errors. * Add Command.Accept and snap to the selected glyph when ShowHorizontalScrollIndicator change to true. * Reformat. * Reformat again. --------- Co-authored-by: Thomas Nind <31306100+tznind@users.noreply.github.com> Co-authored-by: Tig Kindel <tig@users.noreply.github.com>
853 lines
19 KiB
C#
853 lines
19 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Terminal.Gui;
|
|
using Xunit;
|
|
using System.Globalization;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace Terminal.Gui.ViewsTests {
|
|
|
|
public class TabViewTests {
|
|
readonly ITestOutputHelper output;
|
|
|
|
public TabViewTests (ITestOutputHelper output)
|
|
{
|
|
this.output = output;
|
|
}
|
|
|
|
private TabView GetTabView ()
|
|
{
|
|
return GetTabView (out _, out _);
|
|
}
|
|
|
|
private TabView GetTabView (out TabView.Tab tab1, out TabView.Tab tab2, bool initFakeDriver = true)
|
|
{
|
|
if (initFakeDriver)
|
|
InitFakeDriver ();
|
|
|
|
var tv = new TabView ();
|
|
tv.ColorScheme = new ColorScheme ();
|
|
tv.AddTab (tab1 = new TabView.Tab ("Tab1", new TextField ("hi")), false);
|
|
tv.AddTab (tab2 = new TabView.Tab ("Tab2", new Label ("hi2")), false);
|
|
return tv;
|
|
}
|
|
|
|
[Fact]
|
|
public void AddTwoTabs_SecondIsSelected ()
|
|
{
|
|
InitFakeDriver ();
|
|
|
|
var tv = new TabView ();
|
|
TabView.Tab tab1;
|
|
TabView.Tab tab2;
|
|
tv.AddTab (tab1 = new TabView.Tab ("Tab1", new TextField ("hi")), false);
|
|
tv.AddTab (tab2 = new TabView.Tab ("Tab1", new Label ("hi2")), true);
|
|
|
|
Assert.Equal (2, tv.Tabs.Count);
|
|
Assert.Equal (tab2, tv.SelectedTab);
|
|
|
|
Application.Shutdown ();
|
|
}
|
|
|
|
[Fact]
|
|
public void EnsureSelectedTabVisible_NullSelect ()
|
|
{
|
|
var tv = GetTabView ();
|
|
|
|
tv.SelectedTab = null;
|
|
|
|
Assert.Null (tv.SelectedTab);
|
|
Assert.Equal (0, tv.TabScrollOffset);
|
|
|
|
tv.EnsureSelectedTabIsVisible ();
|
|
|
|
Assert.Null (tv.SelectedTab);
|
|
Assert.Equal (0, tv.TabScrollOffset);
|
|
|
|
Application.Shutdown ();
|
|
}
|
|
|
|
[Fact]
|
|
public void EnsureSelectedTabVisible_MustScroll ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2);
|
|
|
|
// Make tab width small to force only one tab visible at once
|
|
tv.Width = 4;
|
|
|
|
tv.SelectedTab = tab1;
|
|
Assert.Equal (0, tv.TabScrollOffset);
|
|
tv.EnsureSelectedTabIsVisible ();
|
|
Assert.Equal (0, tv.TabScrollOffset);
|
|
|
|
// Asking to show tab2 should automatically move scroll offset accordingly
|
|
tv.SelectedTab = tab2;
|
|
Assert.Equal (1, tv.TabScrollOffset);
|
|
|
|
// Shutdown must be called to safely clean up Application if Init has been called
|
|
Application.Shutdown ();
|
|
}
|
|
|
|
[Fact]
|
|
public void SelectedTabChanged_Called ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2);
|
|
|
|
tv.SelectedTab = tab1;
|
|
|
|
TabView.Tab oldTab = null;
|
|
TabView.Tab newTab = null;
|
|
int called = 0;
|
|
|
|
tv.SelectedTabChanged += (s, e) => {
|
|
oldTab = e.OldTab;
|
|
newTab = e.NewTab;
|
|
called++;
|
|
};
|
|
|
|
tv.SelectedTab = tab2;
|
|
|
|
Assert.Equal (1, called);
|
|
Assert.Equal (tab1, oldTab);
|
|
Assert.Equal (tab2, newTab);
|
|
|
|
// Shutdown must be called to safely clean up Application if Init has been called
|
|
Application.Shutdown ();
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveTab_ChangesSelection ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2);
|
|
|
|
tv.SelectedTab = tab1;
|
|
tv.RemoveTab (tab1);
|
|
|
|
Assert.Equal (tab2, tv.SelectedTab);
|
|
|
|
// Shutdown must be called to safely clean up Application if Init has been called
|
|
Application.Shutdown ();
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveTab_MultipleCalls_NotAnError ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2);
|
|
|
|
tv.SelectedTab = tab1;
|
|
|
|
// Repeated calls to remove a tab that is not part of
|
|
// the collection should be ignored
|
|
tv.RemoveTab (tab1);
|
|
tv.RemoveTab (tab1);
|
|
tv.RemoveTab (tab1);
|
|
tv.RemoveTab (tab1);
|
|
|
|
Assert.Equal (tab2, tv.SelectedTab);
|
|
|
|
// Shutdown must be called to safely clean up Application if Init has been called
|
|
Application.Shutdown ();
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveAllTabs_ClearsSelection ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2);
|
|
|
|
tv.SelectedTab = tab1;
|
|
tv.RemoveTab (tab1);
|
|
tv.RemoveTab (tab2);
|
|
|
|
Assert.Null (tv.SelectedTab);
|
|
|
|
// Shutdown must be called to safely clean up Application if Init has been called
|
|
Application.Shutdown ();
|
|
}
|
|
|
|
[Fact]
|
|
public void SwitchTabBy_NormalUsage ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2);
|
|
|
|
TabView.Tab tab3;
|
|
TabView.Tab tab4;
|
|
TabView.Tab tab5;
|
|
|
|
tv.AddTab (tab3 = new TabView.Tab (), false);
|
|
tv.AddTab (tab4 = new TabView.Tab (), false);
|
|
tv.AddTab (tab5 = new TabView.Tab (), false);
|
|
|
|
tv.SelectedTab = tab1;
|
|
|
|
int called = 0;
|
|
tv.SelectedTabChanged += (s, e) => { called++; };
|
|
|
|
tv.SwitchTabBy (1);
|
|
|
|
Assert.Equal (1, called);
|
|
Assert.Equal (tab2, tv.SelectedTab);
|
|
|
|
//reset called counter
|
|
called = 0;
|
|
|
|
// go right 2
|
|
tv.SwitchTabBy (2);
|
|
|
|
// even though we go right 2 indexes the event should only be called once
|
|
Assert.Equal (1, called);
|
|
Assert.Equal (tab4, tv.SelectedTab);
|
|
|
|
// Shutdown must be called to safely clean up Application if Init has been called
|
|
Application.Shutdown ();
|
|
}
|
|
|
|
[Fact]
|
|
public void AddTab_SameTabMoreThanOnce ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2);
|
|
|
|
Assert.Equal (2, tv.Tabs.Count);
|
|
|
|
// Tab is already part of the control so shouldn't result in duplication
|
|
tv.AddTab (tab1, false);
|
|
tv.AddTab (tab1, false);
|
|
tv.AddTab (tab1, false);
|
|
tv.AddTab (tab1, false);
|
|
|
|
Assert.Equal (2, tv.Tabs.Count);
|
|
|
|
// Shutdown must be called to safely clean up Application if Init has been called
|
|
Application.Shutdown ();
|
|
}
|
|
|
|
[Fact]
|
|
public void SwitchTabBy_OutOfTabsRange ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2);
|
|
|
|
tv.SelectedTab = tab1;
|
|
tv.SwitchTabBy (500);
|
|
|
|
Assert.Equal (tab2, tv.SelectedTab);
|
|
|
|
tv.SwitchTabBy (-500);
|
|
|
|
Assert.Equal (tab1, tv.SelectedTab);
|
|
|
|
// Shutdown must be called to safely clean up Application if Init has been called
|
|
Application.Shutdown ();
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_True_TabsOnBottom_False_TestThinTabView_WithLongNames ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2, false);
|
|
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
|
|
tab1.Text = "12";
|
|
tab2.Text = "13";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌──┐
|
|
│12│13
|
|
│ └─────┐
|
|
│hi │
|
|
└────────┘", output);
|
|
|
|
tv.SelectedTab = tab2;
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌──┐
|
|
12│13│
|
|
┌──┘ └──┐
|
|
│hi2 │
|
|
└────────┘", output);
|
|
|
|
tv.SelectedTab = tab1;
|
|
// Test first tab name too long
|
|
tab1.Text = "12345678910";
|
|
tab2.Text = "13";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌───────┐
|
|
│1234567│
|
|
│ └►
|
|
│hi │
|
|
└────────┘", output);
|
|
|
|
//switch to tab2
|
|
tv.SelectedTab = tab2;
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌──┐
|
|
│13│
|
|
◄ └─────┐
|
|
│hi2 │
|
|
└────────┘", output);
|
|
|
|
// now make both tabs too long
|
|
tab1.Text = "12345678910";
|
|
tab2.Text = "abcdefghijklmnopq";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌───────┐
|
|
│abcdefg│
|
|
◄ └┐
|
|
│hi2 │
|
|
└────────┘", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_False_TabsOnBottom_False_TestThinTabView_WithLongNames ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2, false);
|
|
tv.Width = 10;
|
|
tv.Height = 5;
|
|
tv.Style = new TabView.TabStyle { 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
|
|
tab1.Text = "12";
|
|
tab2.Text = "13";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
│12│13
|
|
│ └─────┐
|
|
│hi │
|
|
│ │
|
|
└────────┘", output);
|
|
|
|
tv.SelectedTab = tab2;
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
12│13│
|
|
┌──┘ └──┐
|
|
│hi2 │
|
|
│ │
|
|
└────────┘", output);
|
|
|
|
tv.SelectedTab = tab1;
|
|
|
|
// Test first tab name too long
|
|
tab1.Text = "12345678910";
|
|
tab2.Text = "13";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
│1234567│
|
|
│ └►
|
|
│hi │
|
|
│ │
|
|
└────────┘", output);
|
|
|
|
//switch to tab2
|
|
tv.SelectedTab = tab2;
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
│13│
|
|
◄ └─────┐
|
|
│hi2 │
|
|
│ │
|
|
└────────┘", output);
|
|
|
|
// now make both tabs too long
|
|
tab1.Text = "12345678910";
|
|
tab2.Text = "abcdefghijklmnopq";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
│abcdefg│
|
|
◄ └┐
|
|
│hi2 │
|
|
│ │
|
|
└────────┘", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_True_TabsOnBottom_False_TestTabView_Width4 ()
|
|
{
|
|
var tv = GetTabView (out _, out _, false);
|
|
tv.Width = 4;
|
|
tv.Height = 5;
|
|
tv.LayoutSubviews ();
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌─┐
|
|
│T│
|
|
│ └►
|
|
│hi│
|
|
└──┘", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width4 ()
|
|
{
|
|
var tv = GetTabView (out _, out _, false);
|
|
tv.Width = 4;
|
|
tv.Height = 5;
|
|
tv.Style = new TabView.TabStyle { ShowTopLine = false };
|
|
tv.ApplyStyleChanges ();
|
|
tv.LayoutSubviews ();
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
│T│
|
|
│ └►
|
|
│hi│
|
|
│ │
|
|
└──┘", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_True_TabsOnBottom_False_TestTabView_Width3 ()
|
|
{
|
|
var tv = GetTabView (out _, out _, false);
|
|
tv.Width = 3;
|
|
tv.Height = 5;
|
|
tv.LayoutSubviews ();
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌┐
|
|
││
|
|
│└►
|
|
│h│
|
|
└─┘", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width3 ()
|
|
{
|
|
var tv = GetTabView (out _, out _, false);
|
|
tv.Width = 3;
|
|
tv.Height = 5;
|
|
tv.Style = new TabView.TabStyle { ShowTopLine = false };
|
|
tv.ApplyStyleChanges ();
|
|
tv.LayoutSubviews ();
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
││
|
|
│└►
|
|
│h│
|
|
│ │
|
|
└─┘", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_True_TabsOnBottom_True_TestThinTabView_WithLongNames ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2, false);
|
|
tv.Width = 10;
|
|
tv.Height = 5;
|
|
tv.Style = new TabView.TabStyle { TabsOnBottom = true };
|
|
tv.ApplyStyleChanges ();
|
|
|
|
// Ensures that the tab bar subview gets the bounds of the parent TabView
|
|
tv.LayoutSubviews ();
|
|
|
|
// Test two tab names that fit
|
|
tab1.Text = "12";
|
|
tab2.Text = "13";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌────────┐
|
|
│hi │
|
|
│ ┌─────┘
|
|
│12│13
|
|
└──┘ ", output);
|
|
|
|
// Test first tab name too long
|
|
tab1.Text = "12345678910";
|
|
tab2.Text = "13";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌────────┐
|
|
│hi │
|
|
│ ┌►
|
|
│1234567│
|
|
└───────┘ ", output);
|
|
|
|
//switch to tab2
|
|
tv.SelectedTab = tab2;
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌────────┐
|
|
│hi2 │
|
|
◄ ┌─────┘
|
|
│13│
|
|
└──┘ ", output);
|
|
|
|
// now make both tabs too long
|
|
tab1.Text = "12345678910";
|
|
tab2.Text = "abcdefghijklmnopq";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌────────┐
|
|
│hi2 │
|
|
◄ ┌┘
|
|
│abcdefg│
|
|
└───────┘ ", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_False_TabsOnBottom_True_TestThinTabView_WithLongNames ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2, false);
|
|
tv.Width = 10;
|
|
tv.Height = 5;
|
|
tv.Style = new TabView.TabStyle { ShowTopLine = false, TabsOnBottom = true };
|
|
tv.ApplyStyleChanges ();
|
|
|
|
// Ensures that the tab bar subview gets the bounds of the parent TabView
|
|
tv.LayoutSubviews ();
|
|
|
|
// Test two tab names that fit
|
|
tab1.Text = "12";
|
|
tab2.Text = "13";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌────────┐
|
|
│hi │
|
|
│ │
|
|
│ ┌─────┘
|
|
│12│13 ", output);
|
|
|
|
tv.SelectedTab = tab2;
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌────────┐
|
|
│hi2 │
|
|
│ │
|
|
└──┐ ┌──┘
|
|
12│13│ ", output);
|
|
|
|
tv.SelectedTab = tab1;
|
|
|
|
// Test first tab name too long
|
|
tab1.Text = "12345678910";
|
|
tab2.Text = "13";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌────────┐
|
|
│hi │
|
|
│ │
|
|
│ ┌►
|
|
│1234567│ ", output);
|
|
|
|
//switch to tab2
|
|
tv.SelectedTab = tab2;
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌────────┐
|
|
│hi2 │
|
|
│ │
|
|
◄ ┌─────┘
|
|
│13│ ", output);
|
|
|
|
// now make both tabs too long
|
|
tab1.Text = "12345678910";
|
|
tab2.Text = "abcdefghijklmnopq";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌────────┐
|
|
│hi2 │
|
|
│ │
|
|
◄ ┌┘
|
|
│abcdefg│ ", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width4 ()
|
|
{
|
|
var tv = GetTabView (out _, out _, false);
|
|
tv.Width = 4;
|
|
tv.Height = 5;
|
|
tv.Style = new TabView.TabStyle { TabsOnBottom = true };
|
|
tv.ApplyStyleChanges ();
|
|
tv.LayoutSubviews ();
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌──┐
|
|
│hi│
|
|
│ ┌►
|
|
│T│
|
|
└─┘ ", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width4 ()
|
|
{
|
|
var tv = GetTabView (out _, out _, false);
|
|
tv.Width = 4;
|
|
tv.Height = 5;
|
|
tv.Style = new TabView.TabStyle { ShowTopLine = false, TabsOnBottom = true };
|
|
tv.ApplyStyleChanges ();
|
|
tv.LayoutSubviews ();
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌──┐
|
|
│hi│
|
|
│ │
|
|
│ ┌►
|
|
│T│ ", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width3 ()
|
|
{
|
|
var tv = GetTabView (out _, out _, false);
|
|
tv.Width = 3;
|
|
tv.Height = 5;
|
|
tv.Style = new TabView.TabStyle { TabsOnBottom = true };
|
|
tv.ApplyStyleChanges ();
|
|
tv.LayoutSubviews ();
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌─┐
|
|
│h│
|
|
│┌►
|
|
││
|
|
└┘ ", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width3 ()
|
|
{
|
|
var tv = GetTabView (out _, out _, false);
|
|
tv.Width = 3;
|
|
tv.Height = 5;
|
|
tv.Style = new TabView.TabStyle { ShowTopLine = false, TabsOnBottom = true };
|
|
tv.ApplyStyleChanges ();
|
|
tv.LayoutSubviews ();
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌─┐
|
|
│h│
|
|
│ │
|
|
│┌►
|
|
││ ", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_True_TabsOnBottom_False_With_Unicode ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2, false);
|
|
tv.Width = 20;
|
|
tv.Height = 5;
|
|
|
|
tv.LayoutSubviews ();
|
|
|
|
tab1.Text = "Tab0";
|
|
tab2.Text = "Les Mise" + Char.ConvertFromUtf32 (Int32.Parse ("0301", NumberStyles.HexNumber)) + "rables";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌────┐
|
|
│Tab0│
|
|
│ └─────────────►
|
|
│hi │
|
|
└──────────────────┘", output);
|
|
|
|
tv.SelectedTab = tab2;
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌──────────────┐
|
|
│Les Misérables│
|
|
◄ └───┐
|
|
│hi2 │
|
|
└──────────────────┘", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void ShowTopLine_True_TabsOnBottom_True_With_Unicode ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2, false);
|
|
tv.Width = 20;
|
|
tv.Height = 5;
|
|
tv.Style = new TabView.TabStyle { TabsOnBottom = true };
|
|
tv.ApplyStyleChanges ();
|
|
|
|
tv.LayoutSubviews ();
|
|
|
|
tab1.Text = "Tab0";
|
|
tab2.Text = "Les Mise" + Char.ConvertFromUtf32 (Int32.Parse ("0301", NumberStyles.HexNumber)) + "rables";
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌──────────────────┐
|
|
│hi │
|
|
│ ┌─────────────►
|
|
│Tab0│
|
|
└────┘ ", output);
|
|
|
|
tv.SelectedTab = tab2;
|
|
|
|
tv.Draw ();
|
|
|
|
TestHelpers.AssertDriverContentsWithFrameAre (@"
|
|
┌──────────────────┐
|
|
│hi2 │
|
|
◄ ┌───┘
|
|
│Les Misérables│
|
|
└──────────────┘ ", output);
|
|
}
|
|
|
|
[Fact, AutoInitShutdown]
|
|
public void MouseClick_ChangesTab ()
|
|
{
|
|
var tv = GetTabView (out var tab1, out var tab2, false);
|
|
|
|
tv.Width = 20;
|
|
tv.Height = 5;
|
|
|
|
tv.LayoutSubviews ();
|
|
|
|
tv.Draw ();
|
|
|
|
var tabRow = tv.Subviews[0];
|
|
Assert.Equal("TabRowView",tabRow.GetType().Name);
|
|
|
|
TestHelpers.AssertDriverContentsAre (@"
|
|
┌────┐
|
|
│Tab1│Tab2
|
|
│ └─────────────┐
|
|
│hi │
|
|
└──────────────────┘
|
|
", output);
|
|
|
|
TabView.Tab clicked = null;
|
|
|
|
|
|
tv.TabClicked += (s,e)=>{
|
|
clicked = e.Tab;
|
|
};
|
|
|
|
// Waving mouse around does not trigger click
|
|
for(int i=0;i<100;i++)
|
|
{
|
|
tabRow.MouseEvent(new MouseEvent{
|
|
X = i,
|
|
Y = 1,
|
|
Flags = MouseFlags.ReportMousePosition
|
|
});
|
|
|
|
Assert.Null(clicked);
|
|
Assert.Equal(tab1, tv.SelectedTab);
|
|
}
|
|
|
|
tabRow.MouseEvent(new MouseEvent{
|
|
X = 3,
|
|
Y = 1,
|
|
Flags = MouseFlags.Button1Clicked
|
|
});
|
|
|
|
Assert.Equal(tab1, clicked);
|
|
Assert.Equal(tab1, tv.SelectedTab);
|
|
|
|
// Click to tab2
|
|
tabRow.MouseEvent(new MouseEvent{
|
|
X = 7,
|
|
Y = 1,
|
|
Flags = MouseFlags.Button1Clicked
|
|
});
|
|
|
|
Assert.Equal(tab2, clicked);
|
|
Assert.Equal(tab2, tv.SelectedTab);
|
|
|
|
// cancel navigation
|
|
tv.TabClicked += (s,e)=>{
|
|
clicked = e.Tab;
|
|
e.MouseEvent.Handled = true;
|
|
};
|
|
|
|
tabRow.MouseEvent(new MouseEvent{
|
|
X = 3,
|
|
Y = 1,
|
|
Flags = MouseFlags.Button1Clicked
|
|
});
|
|
|
|
// Tab 1 was clicked but event handler blocked navigation
|
|
Assert.Equal(tab1, clicked);
|
|
Assert.Equal(tab2, tv.SelectedTab);
|
|
|
|
tabRow.MouseEvent (new MouseEvent {
|
|
X = 10,
|
|
Y = 1,
|
|
Flags = MouseFlags.Button1Clicked
|
|
});
|
|
|
|
// Clicking beyond last tab should raise event with null Tab
|
|
Assert.Null (clicked);
|
|
Assert.Equal (tab2, tv.SelectedTab);
|
|
|
|
}
|
|
|
|
private void InitFakeDriver ()
|
|
{
|
|
var driver = new FakeDriver ();
|
|
Application.Init (driver);
|
|
driver.Init (() => { });
|
|
}
|
|
}
|
|
} |