TabViewTests.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Linq;
  5. using System.Threading.Tasks;
  6. using Terminal.Gui;
  7. using Xunit;
  8. using System.Globalization;
  9. using Xunit.Abstractions;
  10. namespace Terminal.Gui.ViewsTests {
  11. public class TabViewTests {
  12. readonly ITestOutputHelper output;
  13. public TabViewTests (ITestOutputHelper output)
  14. {
  15. this.output = output;
  16. }
  17. private TabView GetTabView ()
  18. {
  19. return GetTabView (out _, out _);
  20. }
  21. private TabView GetTabView (out Tab tab1, out Tab tab2, bool initFakeDriver = true)
  22. {
  23. if (initFakeDriver) {
  24. InitFakeDriver ();
  25. }
  26. var tv = new TabView ();
  27. tv.BeginInit ();
  28. tv.EndInit ();
  29. tv.ColorScheme = new ColorScheme ();
  30. tv.AddTab (tab1 = new Tab ("Tab1", new TextField ("hi")), false);
  31. tv.AddTab (tab2 = new Tab ("Tab2", new Label ("hi2")), false);
  32. return tv;
  33. }
  34. [Fact]
  35. public void AddTwoTabs_SecondIsSelected ()
  36. {
  37. InitFakeDriver ();
  38. var tv = new TabView ();
  39. Tab tab1;
  40. Tab tab2;
  41. tv.AddTab (tab1 = new Tab ("Tab1", new TextField ("hi")), false);
  42. tv.AddTab (tab2 = new Tab ("Tab1", new Label ("hi2")), true);
  43. Assert.Equal (2, tv.Tabs.Count);
  44. Assert.Equal (tab2, tv.SelectedTab);
  45. Application.Shutdown ();
  46. }
  47. [Fact]
  48. public void EnsureSelectedTabVisible_NullSelect ()
  49. {
  50. var tv = GetTabView ();
  51. tv.SelectedTab = null;
  52. Assert.Null (tv.SelectedTab);
  53. Assert.Equal (0, tv.TabScrollOffset);
  54. tv.EnsureSelectedTabIsVisible ();
  55. Assert.Null (tv.SelectedTab);
  56. Assert.Equal (0, tv.TabScrollOffset);
  57. Application.Shutdown ();
  58. }
  59. [Fact]
  60. public void EnsureSelectedTabVisible_MustScroll ()
  61. {
  62. var tv = GetTabView (out var tab1, out var tab2);
  63. // Make tab width small to force only one tab visible at once
  64. tv.Width = 4;
  65. tv.SelectedTab = tab1;
  66. Assert.Equal (0, tv.TabScrollOffset);
  67. tv.EnsureSelectedTabIsVisible ();
  68. Assert.Equal (0, tv.TabScrollOffset);
  69. // Asking to show tab2 should automatically move scroll offset accordingly
  70. tv.SelectedTab = tab2;
  71. Assert.Equal (1, tv.TabScrollOffset);
  72. // Shutdown must be called to safely clean up Application if Init has been called
  73. Application.Shutdown ();
  74. }
  75. [Fact]
  76. public void SelectedTabChanged_Called ()
  77. {
  78. var tv = GetTabView (out var tab1, out var tab2);
  79. tv.SelectedTab = tab1;
  80. Tab oldTab = null;
  81. Tab newTab = null;
  82. int called = 0;
  83. tv.SelectedTabChanged += (s, e) => {
  84. oldTab = e.OldTab;
  85. newTab = e.NewTab;
  86. called++;
  87. };
  88. tv.SelectedTab = tab2;
  89. Assert.Equal (1, called);
  90. Assert.Equal (tab1, oldTab);
  91. Assert.Equal (tab2, newTab);
  92. // Shutdown must be called to safely clean up Application if Init has been called
  93. Application.Shutdown ();
  94. }
  95. [Fact]
  96. public void RemoveTab_ChangesSelection ()
  97. {
  98. var tv = GetTabView (out var tab1, out var tab2);
  99. tv.SelectedTab = tab1;
  100. tv.RemoveTab (tab1);
  101. Assert.Equal (tab2, tv.SelectedTab);
  102. // Shutdown must be called to safely clean up Application if Init has been called
  103. Application.Shutdown ();
  104. }
  105. [Fact]
  106. public void RemoveTab_MultipleCalls_NotAnError ()
  107. {
  108. var tv = GetTabView (out var tab1, out var tab2);
  109. tv.SelectedTab = tab1;
  110. // Repeated calls to remove a tab that is not part of
  111. // the collection should be ignored
  112. tv.RemoveTab (tab1);
  113. tv.RemoveTab (tab1);
  114. tv.RemoveTab (tab1);
  115. tv.RemoveTab (tab1);
  116. Assert.Equal (tab2, tv.SelectedTab);
  117. // Shutdown must be called to safely clean up Application if Init has been called
  118. Application.Shutdown ();
  119. }
  120. [Fact]
  121. public void RemoveAllTabs_ClearsSelection ()
  122. {
  123. var tv = GetTabView (out var tab1, out var tab2);
  124. tv.SelectedTab = tab1;
  125. tv.RemoveTab (tab1);
  126. tv.RemoveTab (tab2);
  127. Assert.Null (tv.SelectedTab);
  128. // Shutdown must be called to safely clean up Application if Init has been called
  129. Application.Shutdown ();
  130. }
  131. [Fact]
  132. public void SwitchTabBy_NormalUsage ()
  133. {
  134. var tv = GetTabView (out var tab1, out var tab2);
  135. Tab tab3;
  136. Tab tab4;
  137. Tab tab5;
  138. tv.AddTab (tab3 = new Tab (), false);
  139. tv.AddTab (tab4 = new Tab (), false);
  140. tv.AddTab (tab5 = new Tab (), false);
  141. tv.SelectedTab = tab1;
  142. int called = 0;
  143. tv.SelectedTabChanged += (s, e) => { called++; };
  144. tv.SwitchTabBy (1);
  145. Assert.Equal (1, called);
  146. Assert.Equal (tab2, tv.SelectedTab);
  147. //reset called counter
  148. called = 0;
  149. // go right 2
  150. tv.SwitchTabBy (2);
  151. // even though we go right 2 indexes the event should only be called once
  152. Assert.Equal (1, called);
  153. Assert.Equal (tab4, tv.SelectedTab);
  154. // Shutdown must be called to safely clean up Application if Init has been called
  155. Application.Shutdown ();
  156. }
  157. [Fact]
  158. public void AddTab_SameTabMoreThanOnce ()
  159. {
  160. var tv = GetTabView (out var tab1, out var tab2);
  161. Assert.Equal (2, tv.Tabs.Count);
  162. // Tab is already part of the control so shouldn't result in duplication
  163. tv.AddTab (tab1, false);
  164. tv.AddTab (tab1, false);
  165. tv.AddTab (tab1, false);
  166. tv.AddTab (tab1, false);
  167. Assert.Equal (2, tv.Tabs.Count);
  168. // Shutdown must be called to safely clean up Application if Init has been called
  169. Application.Shutdown ();
  170. }
  171. [Fact]
  172. public void SwitchTabBy_OutOfTabsRange ()
  173. {
  174. var tv = GetTabView (out var tab1, out var tab2);
  175. tv.SelectedTab = tab1;
  176. tv.SwitchTabBy (500);
  177. Assert.Equal (tab2, tv.SelectedTab);
  178. tv.SwitchTabBy (-500);
  179. Assert.Equal (tab1, tv.SelectedTab);
  180. // Shutdown must be called to safely clean up Application if Init has been called
  181. Application.Shutdown ();
  182. }
  183. [Fact, AutoInitShutdown]
  184. public void ShowTopLine_True_TabsOnBottom_False_TestThinTabView_WithLongNames ()
  185. {
  186. var tv = GetTabView (out var tab1, out var tab2, false);
  187. tv.Width = 10;
  188. tv.Height = 5;
  189. // Ensures that the tab bar subview gets the bounds of the parent TabView
  190. tv.LayoutSubviews ();
  191. // Test two tab names that fit
  192. tab1.Text = "12";
  193. tab2.Text = "13";
  194. tv.Draw ();
  195. TestHelpers.AssertDriverContentsWithFrameAre (@"
  196. ┌──┐
  197. │12│13
  198. │ └─────┐
  199. │hi │
  200. └────────┘", output);
  201. tv.SelectedTab = tab2;
  202. tv.Draw ();
  203. TestHelpers.AssertDriverContentsWithFrameAre (@"
  204. ┌──┐
  205. 12│13│
  206. ┌──┘ └──┐
  207. │hi2 │
  208. └────────┘", output);
  209. tv.SelectedTab = tab1;
  210. // Test first tab name too long
  211. tab1.Text = "12345678910";
  212. tab2.Text = "13";
  213. tv.Draw ();
  214. TestHelpers.AssertDriverContentsWithFrameAre (@"
  215. ┌───────┐
  216. │1234567│
  217. │ └►
  218. │hi │
  219. └────────┘", output);
  220. //switch to tab2
  221. tv.SelectedTab = tab2;
  222. tv.Draw ();
  223. TestHelpers.AssertDriverContentsWithFrameAre (@"
  224. ┌──┐
  225. │13│
  226. ◄ └─────┐
  227. │hi2 │
  228. └────────┘", output);
  229. // now make both tabs too long
  230. tab1.Text = "12345678910";
  231. tab2.Text = "abcdefghijklmnopq";
  232. tv.Draw ();
  233. TestHelpers.AssertDriverContentsWithFrameAre (@"
  234. ┌───────┐
  235. │abcdefg│
  236. ◄ └┐
  237. │hi2 │
  238. └────────┘", output);
  239. }
  240. [Fact, AutoInitShutdown]
  241. public void ShowTopLine_False_TabsOnBottom_False_TestThinTabView_WithLongNames ()
  242. {
  243. var tv = GetTabView (out var tab1, out var tab2, false);
  244. tv.Width = 10;
  245. tv.Height = 5;
  246. tv.Style = new TabStyle { ShowTopLine = false };
  247. tv.ApplyStyleChanges ();
  248. // Ensures that the tab bar subview gets the bounds of the parent TabView
  249. tv.LayoutSubviews ();
  250. // Test two tab names that fit
  251. tab1.Text = "12";
  252. tab2.Text = "13";
  253. tv.Draw ();
  254. TestHelpers.AssertDriverContentsWithFrameAre (@"
  255. │12│13
  256. │ └─────┐
  257. │hi │
  258. │ │
  259. └────────┘", output);
  260. tv.SelectedTab = tab2;
  261. tv.Draw ();
  262. TestHelpers.AssertDriverContentsWithFrameAre (@"
  263. 12│13│
  264. ┌──┘ └──┐
  265. │hi2 │
  266. │ │
  267. └────────┘", output);
  268. tv.SelectedTab = tab1;
  269. // Test first tab name too long
  270. tab1.Text = "12345678910";
  271. tab2.Text = "13";
  272. tv.Draw ();
  273. TestHelpers.AssertDriverContentsWithFrameAre (@"
  274. │1234567│
  275. │ └►
  276. │hi │
  277. │ │
  278. └────────┘", output);
  279. //switch to tab2
  280. tv.SelectedTab = tab2;
  281. tv.Draw ();
  282. TestHelpers.AssertDriverContentsWithFrameAre (@"
  283. │13│
  284. ◄ └─────┐
  285. │hi2 │
  286. │ │
  287. └────────┘", output);
  288. // now make both tabs too long
  289. tab1.Text = "12345678910";
  290. tab2.Text = "abcdefghijklmnopq";
  291. tv.Draw ();
  292. TestHelpers.AssertDriverContentsWithFrameAre (@"
  293. │abcdefg│
  294. ◄ └┐
  295. │hi2 │
  296. │ │
  297. └────────┘", output);
  298. }
  299. [Fact, AutoInitShutdown]
  300. public void ShowTopLine_True_TabsOnBottom_False_TestTabView_Width4 ()
  301. {
  302. var tv = GetTabView (out _, out _, false);
  303. tv.Width = 4;
  304. tv.Height = 5;
  305. tv.LayoutSubviews ();
  306. tv.Draw ();
  307. TestHelpers.AssertDriverContentsWithFrameAre (@"
  308. ┌─┐
  309. │T│
  310. │ └►
  311. │hi│
  312. └──┘", output);
  313. }
  314. [Fact, AutoInitShutdown]
  315. public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width4 ()
  316. {
  317. var tv = GetTabView (out _, out _, false);
  318. tv.Width = 4;
  319. tv.Height = 5;
  320. tv.Style = new TabStyle { ShowTopLine = false };
  321. tv.ApplyStyleChanges ();
  322. tv.LayoutSubviews ();
  323. tv.Draw ();
  324. TestHelpers.AssertDriverContentsWithFrameAre (@"
  325. │T│
  326. │ └►
  327. │hi│
  328. │ │
  329. └──┘", output);
  330. }
  331. [Fact, AutoInitShutdown]
  332. public void ShowTopLine_True_TabsOnBottom_False_TestTabView_Width3 ()
  333. {
  334. var tv = GetTabView (out _, out _, false);
  335. tv.Width = 3;
  336. tv.Height = 5;
  337. tv.LayoutSubviews ();
  338. tv.Draw ();
  339. TestHelpers.AssertDriverContentsWithFrameAre (@"
  340. ┌┐
  341. ││
  342. │└►
  343. │h│
  344. └─┘", output);
  345. }
  346. [Fact, AutoInitShutdown]
  347. public void ShowTopLine_False_TabsOnBottom_False_TestTabView_Width3 ()
  348. {
  349. var tv = GetTabView (out _, out _, false);
  350. tv.Width = 3;
  351. tv.Height = 5;
  352. tv.Style = new TabStyle { ShowTopLine = false };
  353. tv.ApplyStyleChanges ();
  354. tv.LayoutSubviews ();
  355. tv.Draw ();
  356. TestHelpers.AssertDriverContentsWithFrameAre (@"
  357. ││
  358. │└►
  359. │h│
  360. │ │
  361. └─┘", output);
  362. }
  363. [Fact, AutoInitShutdown]
  364. public void ShowTopLine_True_TabsOnBottom_True_TestThinTabView_WithLongNames ()
  365. {
  366. var tv = GetTabView (out var tab1, out var tab2, false);
  367. tv.Width = 10;
  368. tv.Height = 5;
  369. tv.Style = new TabStyle { TabsOnBottom = true };
  370. tv.ApplyStyleChanges ();
  371. // Ensures that the tab bar subview gets the bounds of the parent TabView
  372. tv.LayoutSubviews ();
  373. // Test two tab names that fit
  374. tab1.Text = "12";
  375. tab2.Text = "13";
  376. tv.Draw ();
  377. TestHelpers.AssertDriverContentsWithFrameAre (@"
  378. ┌────────┐
  379. │hi │
  380. │ ┌─────┘
  381. │12│13
  382. └──┘ ", output);
  383. // Test first tab name too long
  384. tab1.Text = "12345678910";
  385. tab2.Text = "13";
  386. tv.Draw ();
  387. TestHelpers.AssertDriverContentsWithFrameAre (@"
  388. ┌────────┐
  389. │hi │
  390. │ ┌►
  391. │1234567│
  392. └───────┘ ", output);
  393. //switch to tab2
  394. tv.SelectedTab = tab2;
  395. tv.Draw ();
  396. TestHelpers.AssertDriverContentsWithFrameAre (@"
  397. ┌────────┐
  398. │hi2 │
  399. ◄ ┌─────┘
  400. │13│
  401. └──┘ ", output);
  402. // now make both tabs too long
  403. tab1.Text = "12345678910";
  404. tab2.Text = "abcdefghijklmnopq";
  405. tv.Draw ();
  406. TestHelpers.AssertDriverContentsWithFrameAre (@"
  407. ┌────────┐
  408. │hi2 │
  409. ◄ ┌┘
  410. │abcdefg│
  411. └───────┘ ", output);
  412. }
  413. [Fact, AutoInitShutdown]
  414. public void ShowTopLine_False_TabsOnBottom_True_TestThinTabView_WithLongNames ()
  415. {
  416. var tv = GetTabView (out var tab1, out var tab2, false);
  417. tv.Width = 10;
  418. tv.Height = 5;
  419. tv.Style = new TabStyle { ShowTopLine = false, TabsOnBottom = true };
  420. tv.ApplyStyleChanges ();
  421. // Ensures that the tab bar subview gets the bounds of the parent TabView
  422. tv.LayoutSubviews ();
  423. // Test two tab names that fit
  424. tab1.Text = "12";
  425. tab2.Text = "13";
  426. tv.Draw ();
  427. TestHelpers.AssertDriverContentsWithFrameAre (@"
  428. ┌────────┐
  429. │hi │
  430. │ │
  431. │ ┌─────┘
  432. │12│13 ", output);
  433. tv.SelectedTab = tab2;
  434. tv.Draw ();
  435. TestHelpers.AssertDriverContentsWithFrameAre (@"
  436. ┌────────┐
  437. │hi2 │
  438. │ │
  439. └──┐ ┌──┘
  440. 12│13│ ", output);
  441. tv.SelectedTab = tab1;
  442. // Test first tab name too long
  443. tab1.Text = "12345678910";
  444. tab2.Text = "13";
  445. tv.Draw ();
  446. TestHelpers.AssertDriverContentsWithFrameAre (@"
  447. ┌────────┐
  448. │hi │
  449. │ │
  450. │ ┌►
  451. │1234567│ ", output);
  452. //switch to tab2
  453. tv.SelectedTab = tab2;
  454. tv.Draw ();
  455. TestHelpers.AssertDriverContentsWithFrameAre (@"
  456. ┌────────┐
  457. │hi2 │
  458. │ │
  459. ◄ ┌─────┘
  460. │13│ ", output);
  461. // now make both tabs too long
  462. tab1.Text = "12345678910";
  463. tab2.Text = "abcdefghijklmnopq";
  464. tv.Draw ();
  465. TestHelpers.AssertDriverContentsWithFrameAre (@"
  466. ┌────────┐
  467. │hi2 │
  468. │ │
  469. ◄ ┌┘
  470. │abcdefg│ ", output);
  471. }
  472. [Fact, AutoInitShutdown]
  473. public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width4 ()
  474. {
  475. var tv = GetTabView (out _, out _, false);
  476. tv.Width = 4;
  477. tv.Height = 5;
  478. tv.Style = new TabStyle { TabsOnBottom = true };
  479. tv.ApplyStyleChanges ();
  480. tv.LayoutSubviews ();
  481. tv.Draw ();
  482. TestHelpers.AssertDriverContentsWithFrameAre (@"
  483. ┌──┐
  484. │hi│
  485. │ ┌►
  486. │T│
  487. └─┘ ", output);
  488. }
  489. [Fact, AutoInitShutdown]
  490. public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width4 ()
  491. {
  492. var tv = GetTabView (out _, out _, false);
  493. tv.Width = 4;
  494. tv.Height = 5;
  495. tv.Style = new TabStyle { ShowTopLine = false, TabsOnBottom = true };
  496. tv.ApplyStyleChanges ();
  497. tv.LayoutSubviews ();
  498. tv.Draw ();
  499. TestHelpers.AssertDriverContentsWithFrameAre (@"
  500. ┌──┐
  501. │hi│
  502. │ │
  503. │ ┌►
  504. │T│ ", output);
  505. }
  506. [Fact, AutoInitShutdown]
  507. public void ShowTopLine_True_TabsOnBottom_True_TestTabView_Width3 ()
  508. {
  509. var tv = GetTabView (out _, out _, false);
  510. tv.Width = 3;
  511. tv.Height = 5;
  512. tv.Style = new TabStyle { TabsOnBottom = true };
  513. tv.ApplyStyleChanges ();
  514. tv.LayoutSubviews ();
  515. tv.Draw ();
  516. TestHelpers.AssertDriverContentsWithFrameAre (@"
  517. ┌─┐
  518. │h│
  519. │┌►
  520. ││
  521. └┘ ", output);
  522. }
  523. [Fact, AutoInitShutdown]
  524. public void ShowTopLine_False_TabsOnBottom_True_TestTabView_Width3 ()
  525. {
  526. var tv = GetTabView (out _, out _, false);
  527. tv.Width = 3;
  528. tv.Height = 5;
  529. tv.Style = new TabStyle { ShowTopLine = false, TabsOnBottom = true };
  530. tv.ApplyStyleChanges ();
  531. tv.LayoutSubviews ();
  532. tv.Draw ();
  533. TestHelpers.AssertDriverContentsWithFrameAre (@"
  534. ┌─┐
  535. │h│
  536. │ │
  537. │┌►
  538. ││ ", output);
  539. }
  540. [Fact, AutoInitShutdown]
  541. public void ShowTopLine_True_TabsOnBottom_False_With_Unicode ()
  542. {
  543. var tv = GetTabView (out var tab1, out var tab2, false);
  544. tv.Width = 20;
  545. tv.Height = 5;
  546. tv.LayoutSubviews ();
  547. tab1.Text = "Tab0";
  548. tab2.Text = "Les Mise" + Char.ConvertFromUtf32 (Int32.Parse ("0301", NumberStyles.HexNumber)) + "rables";
  549. tv.Draw ();
  550. TestHelpers.AssertDriverContentsWithFrameAre (@"
  551. ┌────┐
  552. │Tab0│
  553. │ └─────────────►
  554. │hi │
  555. └──────────────────┘", output);
  556. tv.SelectedTab = tab2;
  557. tv.Draw ();
  558. TestHelpers.AssertDriverContentsWithFrameAre (@"
  559. ┌──────────────┐
  560. │Les Misérables│
  561. ◄ └───┐
  562. │hi2 │
  563. └──────────────────┘", output);
  564. }
  565. [Fact, AutoInitShutdown]
  566. public void ShowTopLine_True_TabsOnBottom_True_With_Unicode ()
  567. {
  568. var tv = GetTabView (out var tab1, out var tab2, false);
  569. tv.Width = 20;
  570. tv.Height = 5;
  571. tv.Style = new TabStyle { TabsOnBottom = true };
  572. tv.ApplyStyleChanges ();
  573. tv.LayoutSubviews ();
  574. tab1.Text = "Tab0";
  575. tab2.Text = "Les Mise" + Char.ConvertFromUtf32 (Int32.Parse ("0301", NumberStyles.HexNumber)) + "rables";
  576. tv.Draw ();
  577. TestHelpers.AssertDriverContentsWithFrameAre (@"
  578. ┌──────────────────┐
  579. │hi │
  580. │ ┌─────────────►
  581. │Tab0│
  582. └────┘ ", output);
  583. tv.SelectedTab = tab2;
  584. tv.Draw ();
  585. TestHelpers.AssertDriverContentsWithFrameAre (@"
  586. ┌──────────────────┐
  587. │hi2 │
  588. ◄ ┌───┘
  589. │Les Misérables│
  590. └──────────────┘ ", output);
  591. }
  592. [Fact, AutoInitShutdown]
  593. public void MouseClick_ChangesTab ()
  594. {
  595. var tv = GetTabView (out var tab1, out var tab2, false);
  596. tv.Width = 20;
  597. tv.Height = 5;
  598. tv.LayoutSubviews ();
  599. tv.Draw ();
  600. var tabRow = tv.Subviews[0];
  601. Assert.Equal("TabRowView",tabRow.GetType().Name);
  602. TestHelpers.AssertDriverContentsAre (@"
  603. ┌────┐
  604. │Tab1│Tab2
  605. │ └─────────────┐
  606. │hi │
  607. └──────────────────┘
  608. ", output);
  609. Tab clicked = null;
  610. tv.TabClicked += (s,e)=>{
  611. clicked = e.Tab;
  612. };
  613. // Waving mouse around does not trigger click
  614. for(int i=0;i<100;i++)
  615. {
  616. tabRow.MouseEvent(new MouseEvent{
  617. X = i,
  618. Y = 1,
  619. Flags = MouseFlags.ReportMousePosition
  620. });
  621. Assert.Null(clicked);
  622. Assert.Equal(tab1, tv.SelectedTab);
  623. }
  624. tabRow.MouseEvent(new MouseEvent{
  625. X = 3,
  626. Y = 1,
  627. Flags = MouseFlags.Button1Clicked
  628. });
  629. Assert.Equal(tab1, clicked);
  630. Assert.Equal(tab1, tv.SelectedTab);
  631. // Click to tab2
  632. tabRow.MouseEvent(new MouseEvent{
  633. X = 7,
  634. Y = 1,
  635. Flags = MouseFlags.Button1Clicked
  636. });
  637. Assert.Equal(tab2, clicked);
  638. Assert.Equal(tab2, tv.SelectedTab);
  639. // cancel navigation
  640. tv.TabClicked += (s,e)=>{
  641. clicked = e.Tab;
  642. e.MouseEvent.Handled = true;
  643. };
  644. tabRow.MouseEvent(new MouseEvent{
  645. X = 3,
  646. Y = 1,
  647. Flags = MouseFlags.Button1Clicked
  648. });
  649. // Tab 1 was clicked but event handler blocked navigation
  650. Assert.Equal(tab1, clicked);
  651. Assert.Equal(tab2, tv.SelectedTab);
  652. tabRow.MouseEvent (new MouseEvent {
  653. X = 10,
  654. Y = 1,
  655. Flags = MouseFlags.Button1Clicked
  656. });
  657. // Clicking beyond last tab should raise event with null Tab
  658. Assert.Null (clicked);
  659. Assert.Equal (tab2, tv.SelectedTab);
  660. }
  661. private void InitFakeDriver ()
  662. {
  663. var driver = new FakeDriver ();
  664. Application.Init (driver);
  665. driver.Init (() => { });
  666. }
  667. }
  668. }