mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
* Added ClipRegion; cleaned up driver code * clip region unit tests * api docs * Moved color stuff from ConsoleDriver to Color.cs * Removes unused ConsoleDriver APIs * Code cleanup and Removes unused ConsoleDriver APIs * Code cleanup and Removes unused ConsoleDriver APIs * Work around https://github.com/gui-cs/Terminal.Gui/issues/2610 * adjusted unit tests * initial commit * Made Rows, Cols, Top, Left virtual * Made Clipboard non-virtual * Made EnableConsoleScrolling non-virtual * Made Contents non-virtual * Pulled Row/Col up * Made MoveTo virtual; fixed stupid FakeDriver cursor issue * Made CurrentAttribute non-virtual * Made SetAttribute non-virtual * Moved clipboard code out * Code cleanup * Removes dependecy on NStack from ConsoleDrivers - WIP * Fixed unit tests * Fixed unit tests * Added list of unit tests needed * Did some perf testing; tweaked code and charmap to address * Brough in code from PR #2264 (but commented) * Tons of code cleanup * Fighting with ScrollView * Fixing bugs * Fixed TabView tests * Fixed View.Visible test that was not really working * Fixed unit tests * Cleaned up clipboard APIs in attempt to track down unit test failure * Add Cut_Preserves_Selection test * Removed invalid code * Removed invalid test code; unit tests now pass * EscSeq* - Adjusted naming, added more sequences, made code more consistent, simplified, etc... * Added CSI_SetGraphicsRendition * NetDriver code cleanup * code cleanup * Cleaned up color handling in NetDriver * refixed tabview unit test * WindowsDriver color code cleanup * WindowsDriver color code cleanup * CursesDriver color code cleanup * CursesDriver - Adding _BOLD has no effect. Further up the stack we cast the return of ColorToCursesColor from int to short and the _BOLD values don't fit in a short. * CursesDriver color code - make code more accurate * CursesDriver color code - make code more accurate * Simplified ConsoleDriver.GetColors API * Simplified ConsoleDriver.GetColors API further * Improved encapslation of Attribute; prep for TrueColor & other attributes like blink * Fixes #2249. CharacterMap isn't refreshing well non-BMP code points on scroll. * Use GetRange to take some of the runes before convert to string. * Attempting to fix unit tests not being cleaned up * Fixes #2658 - ConsoleDriver.IsRuneSupported * Fixes #2658 - ConsoleDriver.IsRuneSupported (for WindowsDriver) * Check all the range values and not only the max value. * Reducing code. * Fixes #2674 - Unit test process doesn't exit * Changed Cell to support IsDirty and list of Runes * add support for rendering TrueColor output on Windows merging veeman & tznind code * add colorconverter changes * fixed merged v2_develop * Fixing merge bugs * Fixed merge bugs * Fixed merge bugs - all unit tests pass * Debugging netdriver * More netdriver diag * API docs for escutils * Update unicode scenario to stress more stuff * Contents: Now a 2D array of Cells; WIP * AddRune and ClearContents no longer virtual/abstract * WindowsDriver renders correctly again * Progress on Curses * Progress on Curses * broke windowsdriver * Cleaned up FakeMainLoop * Cleaned up some build warnings * Removed _init from AutoInitShutdown as it's not needed anymore * Removed unused var * Removed unused var * Fixed nullabiltiy warning in LineCanvas * Fixed charmap crash * Fixes #2758 in v2 * Port testonfail fix to v2 * Remove EnableConsoleScrolling * Backport #2764 from develop (clear last line) * Remove uneeded usings * Progress on unicode * Merged in changes from PR #2786, Fixes #2784 * revamp charmap rendering * Charmap option to show glyph widths * Fixed issue with wide glpyhs being overwritten * Fixed charmap startcodepoint change issue * Added abiltiy to see ncurses verison/lib * Fought with CursesDriver; giving up for now. See notes. * Leverage Wcwidth nuget library instaed of our own tables * enhanced charmap Details dialog * Final attempt at fixing curses --------- Co-authored-by: BDisp <bd.bdisp@gmail.com> Co-authored-by: adstep <stephensonadamj@gmail.com>
856 lines
19 KiB
C#
856 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 Tab tab1, out Tab tab2, bool initFakeDriver = true)
|
|
{
|
|
if (initFakeDriver) {
|
|
InitFakeDriver ();
|
|
}
|
|
|
|
var tv = new TabView ();
|
|
tv.BeginInit ();
|
|
tv.EndInit ();
|
|
tv.ColorScheme = new ColorScheme ();
|
|
tv.AddTab (tab1 = new Tab ("Tab1", new TextField ("hi")), false);
|
|
tv.AddTab (tab2 = new Tab ("Tab2", new Label ("hi2")), false);
|
|
return tv;
|
|
}
|
|
|
|
[Fact]
|
|
public void AddTwoTabs_SecondIsSelected ()
|
|
{
|
|
InitFakeDriver ();
|
|
|
|
var tv = new TabView ();
|
|
Tab tab1;
|
|
Tab tab2;
|
|
tv.AddTab (tab1 = new Tab ("Tab1", new TextField ("hi")), false);
|
|
tv.AddTab (tab2 = new 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;
|
|
|
|
Tab oldTab = null;
|
|
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);
|
|
|
|
Tab tab3;
|
|
Tab tab4;
|
|
Tab tab5;
|
|
|
|
tv.AddTab (tab3 = new Tab (), false);
|
|
tv.AddTab (tab4 = new Tab (), false);
|
|
tv.AddTab (tab5 = new 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 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 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 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 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 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 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 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 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 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 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);
|
|
|
|
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 (() => { });
|
|
}
|
|
}
|
|
} |