2
0

OverlappedTests.cs 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313
  1. #nullable enable
  2. using System.Threading;
  3. using Xunit.Abstractions;
  4. namespace Terminal.Gui.ViewsTests;
  5. public class OverlappedTests
  6. {
  7. private readonly ITestOutputHelper _output;
  8. public OverlappedTests (ITestOutputHelper output)
  9. {
  10. _output = output;
  11. #if DEBUG_IDISPOSABLE
  12. Responder.Instances.Clear ();
  13. RunState.Instances.Clear ();
  14. #endif
  15. }
  16. [Fact]
  17. [AutoInitShutdown]
  18. public void AllChildClosed_Event_Test ()
  19. {
  20. var overlapped = new Overlapped ();
  21. var c1 = new Toplevel ();
  22. var c2 = new Window ();
  23. var c3 = new Window ();
  24. // OverlappedChild = c1, c2, c3
  25. var iterations = 3;
  26. overlapped.Ready += (s, e) =>
  27. {
  28. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  29. Application.Run (c1);
  30. };
  31. c1.Ready += (s, e) =>
  32. {
  33. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  34. Application.Run (c2);
  35. };
  36. c2.Ready += (s, e) =>
  37. {
  38. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  39. Application.Run (c3);
  40. };
  41. c3.Ready += (s, e) =>
  42. {
  43. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  44. c3.RequestStop ();
  45. c2.RequestStop ();
  46. c1.RequestStop ();
  47. };
  48. // Now this will close the OverlappedContainer when all OverlappedChildren was closed
  49. overlapped.AllChildClosed += (s, e) => { overlapped.RequestStop (); };
  50. Application.Iteration += (s, a) =>
  51. {
  52. if (iterations == 3)
  53. {
  54. // The Current still is c3 because Current.Running is false.
  55. Assert.True (Application.Current == c3);
  56. Assert.False (Application.Current.Running);
  57. // But the Children order were reorder by Running = false
  58. Assert.True (ApplicationOverlapped.OverlappedChildren! [0] == c3);
  59. Assert.True (ApplicationOverlapped.OverlappedChildren [1] == c2);
  60. Assert.True (ApplicationOverlapped.OverlappedChildren [^1] == c1);
  61. }
  62. else if (iterations == 2)
  63. {
  64. // The Current is c2 and Current.Running is false.
  65. Assert.True (Application.Current == c2);
  66. Assert.False (Application.Current.Running);
  67. Assert.True (ApplicationOverlapped.OverlappedChildren ![0] == c2);
  68. Assert.True (ApplicationOverlapped.OverlappedChildren [^1] == c1);
  69. }
  70. else if (iterations == 1)
  71. {
  72. // The Current is c1 and Current.Running is false.
  73. Assert.True (Application.Current == c1);
  74. Assert.False (Application.Current.Running);
  75. Assert.True (ApplicationOverlapped.OverlappedChildren! [^1] == c1);
  76. }
  77. else
  78. {
  79. // The Current is overlapped.
  80. Assert.True (Application.Current == overlapped);
  81. Assert.False (Application.Current.Running);
  82. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  83. }
  84. iterations--;
  85. };
  86. Application.Run (overlapped);
  87. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  88. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  89. Assert.NotNull (Application.Top);
  90. overlapped.Dispose ();
  91. }
  92. [Fact]
  93. [AutoInitShutdown]
  94. public void Application_RequestStop_With_Params_On_A_Not_OverlappedContainer_Always_Use_Application_Current ()
  95. {
  96. var top1 = new Toplevel ();
  97. var top2 = new Toplevel ();
  98. var top3 = new Window ();
  99. var top4 = new Window ();
  100. var d = new Dialog ();
  101. // top1, top2, top3, d1 = 4
  102. var iterations = 4;
  103. top1.Ready += (s, e) =>
  104. {
  105. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  106. Application.Run (top2);
  107. };
  108. top2.Ready += (s, e) =>
  109. {
  110. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  111. Application.Run (top3);
  112. };
  113. top3.Ready += (s, e) =>
  114. {
  115. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  116. Application.Run (top4);
  117. };
  118. top4.Ready += (s, e) =>
  119. {
  120. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  121. Application.Run (d);
  122. };
  123. d.Ready += (s, e) =>
  124. {
  125. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  126. // This will close the d because on a not OverlappedContainer the Application.Current it always used.
  127. Application.RequestStop (top1);
  128. Assert.True (Application.Current == d);
  129. };
  130. d.Closed += (s, e) => Application.RequestStop (top1);
  131. Application.Iteration += (s, a) =>
  132. {
  133. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  134. if (iterations == 4)
  135. {
  136. Assert.True (Application.Current == d);
  137. }
  138. else if (iterations == 3)
  139. {
  140. Assert.True (Application.Current == top4);
  141. }
  142. else if (iterations == 2)
  143. {
  144. Assert.True (Application.Current == top3);
  145. }
  146. else if (iterations == 1)
  147. {
  148. Assert.True (Application.Current == top2);
  149. }
  150. else
  151. {
  152. Assert.True (Application.Current == top1);
  153. }
  154. Application.RequestStop (top1);
  155. iterations--;
  156. };
  157. Application.Run (top1);
  158. Assert.Null (ApplicationOverlapped.OverlappedChildren);
  159. top1.Dispose ();
  160. }
  161. [Fact]
  162. [TestRespondersDisposed]
  163. public void Dispose_Toplevel_IsOverlappedContainer_False_With_Begin_End ()
  164. {
  165. Application.Init (new FakeDriver ());
  166. var top = new Toplevel ();
  167. RunState rs = Application.Begin (top);
  168. Application.End (rs);
  169. top.Dispose ();
  170. Application.Shutdown ();
  171. #if DEBUG_IDISPOSABLE
  172. Assert.Empty (Responder.Instances);
  173. #endif
  174. }
  175. [Fact]
  176. [TestRespondersDisposed]
  177. public void Dispose_Toplevel_IsOverlappedContainer_True_With_Begin ()
  178. {
  179. Application.Init (new FakeDriver ());
  180. var overlapped = new Toplevel { IsOverlappedContainer = true };
  181. RunState rs = Application.Begin (overlapped);
  182. Application.End (rs);
  183. overlapped.Dispose ();
  184. Application.Shutdown ();
  185. }
  186. [Fact]
  187. [AutoInitShutdown]
  188. public void IsOverlappedChild_Testing ()
  189. {
  190. var overlapped = new Overlapped ();
  191. var c1 = new Toplevel ();
  192. var c2 = new Window ();
  193. var c3 = new Window ();
  194. var d = new Dialog ();
  195. Application.Iteration += (s, a) =>
  196. {
  197. Assert.False (ApplicationOverlapped.IsOverlapped(overlapped));
  198. Assert.True (ApplicationOverlapped.IsOverlapped(c1));
  199. Assert.True (ApplicationOverlapped.IsOverlapped(c2));
  200. Assert.True (ApplicationOverlapped.IsOverlapped(c3));
  201. Assert.False (ApplicationOverlapped.IsOverlapped(d));
  202. overlapped.RequestStop ();
  203. };
  204. Application.Run (overlapped);
  205. overlapped.Dispose ();
  206. }
  207. [Fact]
  208. [AutoInitShutdown]
  209. public void
  210. Modal_Toplevel_Can_Open_Another_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too ()
  211. {
  212. var overlapped = new Overlapped ();
  213. var c1 = new Toplevel ();
  214. var c2 = new Window ();
  215. var c3 = new Window ();
  216. var d1 = new Dialog ();
  217. var d2 = new Dialog ();
  218. // OverlappedChild = c1, c2, c3 = 3
  219. // d1, d2 = 2
  220. var iterations = 5;
  221. overlapped.Ready += (s, e) =>
  222. {
  223. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  224. Application.Run (c1);
  225. };
  226. c1.Ready += (s, e) =>
  227. {
  228. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  229. Application.Run (c2);
  230. };
  231. c2.Ready += (s, e) =>
  232. {
  233. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  234. Application.Run (c3);
  235. };
  236. c3.Ready += (s, e) =>
  237. {
  238. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  239. Application.Run (d1);
  240. };
  241. d1.Ready += (s, e) =>
  242. {
  243. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  244. Application.Run (d2);
  245. };
  246. d2.Ready += (s, e) =>
  247. {
  248. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  249. Assert.True (Application.Current == d2);
  250. Assert.True (Application.Current.Running);
  251. // Trying to close the Dialog1
  252. d1.RequestStop ();
  253. };
  254. // Now this will close the OverlappedContainer propagating through the OverlappedChildren.
  255. d1.Closed += (s, e) =>
  256. {
  257. Assert.True (Application.Current == d1);
  258. Assert.False (Application.Current.Running);
  259. overlapped.RequestStop ();
  260. };
  261. Application.Iteration += (s, a) =>
  262. {
  263. if (iterations == 5)
  264. {
  265. // The Dialog2 still is the current top and we can't request stop to OverlappedContainer
  266. // because Dialog2 and Dialog1 must be closed first.
  267. // Dialog2 will be closed in this iteration.
  268. Assert.True (Application.Current == d2);
  269. Assert.False (Application.Current.Running);
  270. Assert.False (d1.Running);
  271. }
  272. else if (iterations == 4)
  273. {
  274. // Dialog1 will be closed in this iteration.
  275. Assert.True (Application.Current == d1);
  276. Assert.False (Application.Current.Running);
  277. }
  278. else
  279. {
  280. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  281. for (var i = 0; i < iterations; i++)
  282. {
  283. Assert.Equal ((iterations - i + 1).ToString (), ApplicationOverlapped.OverlappedChildren [i].Id);
  284. }
  285. }
  286. iterations--;
  287. };
  288. Application.Run (overlapped);
  289. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  290. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  291. Assert.NotNull (Application.Top);
  292. overlapped.Dispose ();
  293. }
  294. [Fact]
  295. [AutoInitShutdown]
  296. public void
  297. Modal_Toplevel_Can_Open_Another_Not_Modal_Toplevel_But_RequestStop_To_The_Caller_Also_Sets_Current_Running_To_False_Too ()
  298. {
  299. var overlapped = new Overlapped ();
  300. var c1 = new Toplevel ();
  301. var c2 = new Window ();
  302. var c3 = new Window ();
  303. var d1 = new Dialog ();
  304. var c4 = new Toplevel ();
  305. // OverlappedChild = c1, c2, c3, c4 = 4
  306. // d1 = 1
  307. var iterations = 5;
  308. overlapped.Ready += (s, e) =>
  309. {
  310. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  311. Application.Run (c1);
  312. };
  313. c1.Ready += (s, e) =>
  314. {
  315. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  316. Application.Run (c2);
  317. };
  318. c2.Ready += (s, e) =>
  319. {
  320. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  321. Application.Run (c3);
  322. };
  323. c3.Ready += (s, e) =>
  324. {
  325. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  326. Application.Run (d1);
  327. };
  328. d1.Ready += (s, e) =>
  329. {
  330. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  331. Application.Run (c4);
  332. };
  333. c4.Ready += (s, e) =>
  334. {
  335. Assert.Equal (4, ApplicationOverlapped.OverlappedChildren!.Count);
  336. // Trying to close the Dialog1
  337. d1.RequestStop ();
  338. };
  339. // Now this will close the OverlappedContainer propagating through the OverlappedChildren.
  340. d1.Closed += (s, e) => { overlapped.RequestStop (); };
  341. Application.Iteration += (s, a) =>
  342. {
  343. if (iterations == 5)
  344. {
  345. // The Dialog2 still is the current top and we can't request stop to OverlappedContainer
  346. // because Dialog2 and Dialog1 must be closed first.
  347. // Using request stop here will call the Dialog again without need
  348. Assert.True (Application.Current == d1);
  349. Assert.False (Application.Current.Running);
  350. Assert.True (c4.Running);
  351. }
  352. else
  353. {
  354. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  355. for (var i = 0; i < iterations; i++)
  356. {
  357. Assert.Equal (
  358. (iterations - i + (iterations == 4 && i == 0 ? 2 : 1)).ToString (),
  359. ApplicationOverlapped.OverlappedChildren [i].Id
  360. );
  361. }
  362. }
  363. iterations--;
  364. };
  365. Application.Run (overlapped);
  366. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  367. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  368. Assert.NotNull (Application.Top);
  369. overlapped.Dispose ();
  370. }
  371. [Fact]
  372. [AutoInitShutdown]
  373. public void MoveCurrent_Returns_False_If_The_Current_And_Top_Parameter_Are_Both_With_Running_Set_To_False ()
  374. {
  375. Overlapped? overlapped = new Overlapped ();
  376. var c1 = new Toplevel ();
  377. var c2 = new Window ();
  378. var c3 = new Window ();
  379. // OverlappedChild = c1, c2, c3
  380. var iterations = 3;
  381. overlapped.Ready += (s, e) =>
  382. {
  383. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  384. Application.Run (c1);
  385. };
  386. c1.Ready += (s, e) =>
  387. {
  388. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  389. Application.Run (c2);
  390. };
  391. c2.Ready += (s, e) =>
  392. {
  393. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  394. Application.Run (c3);
  395. };
  396. c3.Ready += (s, e) =>
  397. {
  398. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  399. c3.RequestStop ();
  400. c1.RequestStop ();
  401. };
  402. // Now this will close the OverlappedContainer propagating through the OverlappedChildren.
  403. c1.Closed += (s, e) => { overlapped.RequestStop (); };
  404. Application.Iteration += (s, a) =>
  405. {
  406. if (iterations == 3)
  407. {
  408. // The Current still is c3 because Current.Running is false.
  409. Assert.True (Application.Current == c3);
  410. Assert.False (Application.Current.Running);
  411. // But the Children order were reorder by Running = false
  412. Assert.True (ApplicationOverlapped.OverlappedChildren! [0] == c3);
  413. Assert.True (ApplicationOverlapped.OverlappedChildren [1] == c1);
  414. Assert.True (ApplicationOverlapped.OverlappedChildren [^1] == c2);
  415. }
  416. else if (iterations == 2)
  417. {
  418. // The Current is c1 and Current.Running is false.
  419. Assert.True (Application.Current == c1);
  420. Assert.False (Application.Current.Running);
  421. Assert.True (ApplicationOverlapped.OverlappedChildren! [0] == c1);
  422. Assert.True (ApplicationOverlapped.OverlappedChildren [^1] == c2);
  423. }
  424. else if (iterations == 1)
  425. {
  426. // The Current is c2 and Current.Running is false.
  427. Assert.True (Application.Current == c2);
  428. Assert.False (Application.Current.Running);
  429. Assert.True (ApplicationOverlapped.OverlappedChildren! [^1] == c2);
  430. }
  431. else
  432. {
  433. // The Current is overlapped.
  434. Assert.True (Application.Current == overlapped);
  435. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  436. }
  437. iterations--;
  438. };
  439. Application.Run (overlapped);
  440. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  441. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  442. Assert.NotNull (Application.Top);
  443. overlapped.Dispose ();
  444. }
  445. [Fact]
  446. public void MoveToOverlappedChild_Throw_NullReferenceException_Passing_Null_Parameter ()
  447. {
  448. Assert.Throws<ArgumentNullException> (delegate { ApplicationOverlapped.MoveToOverlappedChild (null); });
  449. }
  450. [Fact]
  451. [AutoInitShutdown]
  452. public void OverlappedContainer_Open_And_Close_Modal_And_Open_Not_Modal_Toplevels_Randomly ()
  453. {
  454. var overlapped = new Overlapped ();
  455. var logger = new Toplevel ();
  456. var iterations = 1; // The logger
  457. var running = true;
  458. var stageCompleted = true;
  459. var allStageClosed = false;
  460. var overlappedRequestStop = false;
  461. overlapped.Ready += (s, e) =>
  462. {
  463. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  464. Application.Run (logger);
  465. };
  466. logger.Ready += (s, e) => Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  467. Application.Iteration += (s, a) =>
  468. {
  469. if (stageCompleted && running)
  470. {
  471. stageCompleted = false;
  472. var stage = new Window { Modal = true };
  473. stage.Ready += (s, e) =>
  474. {
  475. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  476. stage.RequestStop ();
  477. };
  478. stage.Closed += (_, _) =>
  479. {
  480. if (iterations == 11)
  481. {
  482. allStageClosed = true;
  483. }
  484. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  485. if (running)
  486. {
  487. stageCompleted = true;
  488. var rpt = new Window ();
  489. rpt.Ready += (s, e) =>
  490. {
  491. iterations++;
  492. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren.Count);
  493. };
  494. Application.Run (rpt);
  495. }
  496. };
  497. Application.Run (stage);
  498. }
  499. else if (iterations == 11 && running)
  500. {
  501. running = false;
  502. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  503. }
  504. else if (!overlappedRequestStop && running && !allStageClosed)
  505. {
  506. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  507. }
  508. else if (!overlappedRequestStop && !running && allStageClosed)
  509. {
  510. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  511. overlappedRequestStop = true;
  512. overlapped?.RequestStop ();
  513. }
  514. else
  515. {
  516. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  517. }
  518. };
  519. Application.Run (overlapped);
  520. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  521. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  522. Assert.NotNull (Application.Top);
  523. overlapped.Dispose ();
  524. }
  525. [Fact]
  526. [AutoInitShutdown]
  527. public void OverlappedContainer_Throws_If_More_Than_One ()
  528. {
  529. var overlapped = new Overlapped ();
  530. var overlapped2 = new Overlapped ();
  531. overlapped.Ready += (s, e) =>
  532. {
  533. Assert.Throws<InvalidOperationException> (() => Application.Run (overlapped2));
  534. overlapped.RequestStop ();
  535. };
  536. Application.Run (overlapped);
  537. overlapped.Dispose ();
  538. }
  539. [Fact]
  540. [AutoInitShutdown]
  541. public void OverlappedContainer_With_Application_RequestStop_OverlappedTop_With_Params ()
  542. {
  543. var overlapped = new Overlapped ();
  544. var c1 = new Toplevel ();
  545. var c2 = new Window ();
  546. var c3 = new Window ();
  547. var d = new Dialog ();
  548. // OverlappedChild = c1, c2, c3
  549. // d1 = 1
  550. var iterations = 4;
  551. overlapped.Ready += (s, e) =>
  552. {
  553. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  554. Application.Run (c1);
  555. };
  556. c1.Ready += (s, e) =>
  557. {
  558. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  559. Application.Run (c2);
  560. };
  561. c2.Ready += (s, e) =>
  562. {
  563. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  564. Application.Run (c3);
  565. };
  566. c3.Ready += (s, e) =>
  567. {
  568. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  569. Application.Run (d);
  570. };
  571. // Also easy because the Overlapped Container handles all at once
  572. d.Ready += (s, e) =>
  573. {
  574. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  575. // This will not close the OverlappedContainer because d is a modal Toplevel
  576. Application.RequestStop (overlapped);
  577. };
  578. // Now this will close the OverlappedContainer propagating through the OverlappedChildren.
  579. d.Closed += (s, e) => Application.RequestStop (overlapped);
  580. Application.Iteration += (s, a) =>
  581. {
  582. if (iterations == 4)
  583. {
  584. // The Dialog was not closed before and will be closed now.
  585. Assert.True (Application.Current == d);
  586. Assert.False (d.Running);
  587. }
  588. else
  589. {
  590. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  591. for (var i = 0; i < iterations; i++)
  592. {
  593. Assert.Equal ((iterations - i + 1).ToString (), ApplicationOverlapped.OverlappedChildren [i].Id);
  594. }
  595. }
  596. iterations--;
  597. };
  598. Application.Run (overlapped);
  599. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  600. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  601. Assert.NotNull (Application.Top);
  602. overlapped.Dispose ();
  603. }
  604. [Fact]
  605. [AutoInitShutdown]
  606. public void OverlappedContainer_With_Application_RequestStop_OverlappedTop_Without_Params ()
  607. {
  608. var overlapped = new Overlapped ();
  609. var c1 = new Toplevel ();
  610. var c2 = new Window ();
  611. var c3 = new Window ();
  612. var d = new Dialog ();
  613. // OverlappedChild = c1, c2, c3 = 3
  614. // d1 = 1
  615. var iterations = 4;
  616. overlapped.Ready += (s, e) =>
  617. {
  618. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  619. Application.Run (c1);
  620. };
  621. c1.Ready += (s, e) =>
  622. {
  623. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  624. Application.Run (c2);
  625. };
  626. c2.Ready += (s, e) =>
  627. {
  628. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  629. Application.Run (c3);
  630. };
  631. c3.Ready += (s, e) =>
  632. {
  633. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  634. Application.Run (d);
  635. };
  636. //More harder because it's sequential.
  637. d.Ready += (s, e) =>
  638. {
  639. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  640. // Close the Dialog
  641. Application.RequestStop ();
  642. };
  643. // Now this will close the OverlappedContainer propagating through the OverlappedChildren.
  644. d.Closed += (s, e) => Application.RequestStop (overlapped);
  645. Application.Iteration += (s, a) =>
  646. {
  647. if (iterations == 4)
  648. {
  649. // The Dialog still is the current top and we can't request stop to OverlappedContainer
  650. // because we are not using parameter calls.
  651. Assert.True (Application.Current == d);
  652. Assert.False (d.Running);
  653. }
  654. else
  655. {
  656. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  657. for (var i = 0; i < iterations; i++)
  658. {
  659. Assert.Equal ((iterations - i + 1).ToString (), ApplicationOverlapped.OverlappedChildren [i].Id);
  660. }
  661. }
  662. iterations--;
  663. };
  664. Application.Run (overlapped);
  665. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  666. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  667. Assert.NotNull (Application.Top);
  668. overlapped.Dispose ();
  669. }
  670. [Fact]
  671. [AutoInitShutdown]
  672. public void OverlappedContainer_With_Toplevel_RequestStop_Balanced ()
  673. {
  674. var overlapped = new Overlapped ();
  675. var c1 = new Toplevel ();
  676. var c2 = new Window ();
  677. var c3 = new Window ();
  678. var d = new Dialog ();
  679. // OverlappedChild = c1, c2, c3
  680. // d1 = 1
  681. var iterations = 4;
  682. overlapped.Ready += (s, e) =>
  683. {
  684. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  685. Application.Run (c1);
  686. };
  687. c1.Ready += (s, e) =>
  688. {
  689. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  690. Application.Run (c2);
  691. };
  692. c2.Ready += (s, e) =>
  693. {
  694. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  695. Application.Run (c3);
  696. };
  697. c3.Ready += (s, e) =>
  698. {
  699. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  700. Application.Run (d);
  701. };
  702. // More easy because the Overlapped Container handles all at once
  703. d.Ready += (s, e) =>
  704. {
  705. Assert.Equal (3, ApplicationOverlapped.OverlappedChildren!.Count);
  706. // This will not close the OverlappedContainer because d is a modal Toplevel and will be closed.
  707. overlapped.RequestStop ();
  708. };
  709. // Now this will close the OverlappedContainer propagating through the OverlappedChildren.
  710. d.Closed += (s, e) => { overlapped.RequestStop (); };
  711. Application.Iteration += (s, a) =>
  712. {
  713. if (iterations == 4)
  714. {
  715. // The Dialog was not closed before and will be closed now.
  716. Assert.True (Application.Current == d);
  717. Assert.False (d.Running);
  718. }
  719. else
  720. {
  721. Assert.Equal (iterations, ApplicationOverlapped.OverlappedChildren!.Count);
  722. for (var i = 0; i < iterations; i++)
  723. {
  724. Assert.Equal ((iterations - i + 1).ToString (), ApplicationOverlapped.OverlappedChildren [i].Id);
  725. }
  726. }
  727. iterations--;
  728. };
  729. Application.Run (overlapped);
  730. Assert.Empty (ApplicationOverlapped.OverlappedChildren!);
  731. Assert.NotNull (ApplicationOverlapped.OverlappedTop);
  732. Assert.NotNull (Application.Top);
  733. overlapped.Dispose ();
  734. }
  735. [Fact]
  736. [AutoInitShutdown]
  737. public void Visible_False_Does_Not_Clear ()
  738. {
  739. var overlapped = new Overlapped ();
  740. var win1 = new Window { Width = 5, Height = 5, Visible = false };
  741. var win2 = new Window { X = 1, Y = 1, Width = 5, Height = 5 };
  742. ((FakeDriver)Application.Driver!).SetBufferSize (10, 10);
  743. RunState rsOverlapped = Application.Begin (overlapped);
  744. // Need to fool MainLoop into thinking it's running
  745. Application.MainLoop!.Running = true;
  746. // RunIteration must be call on each iteration because
  747. // it's using the Begin and not the Run method
  748. var firstIteration = false;
  749. Application.RunIteration (ref rsOverlapped, ref firstIteration);
  750. Assert.Equal (overlapped, rsOverlapped.Toplevel);
  751. Assert.Equal (Application.Top, rsOverlapped.Toplevel);
  752. Assert.Equal (ApplicationOverlapped.OverlappedTop, rsOverlapped.Toplevel);
  753. Assert.Equal (Application.Current, rsOverlapped.Toplevel);
  754. Assert.Equal (overlapped, Application.Current);
  755. RunState rsWin1 = Application.Begin (win1);
  756. Application.RunIteration (ref rsOverlapped, ref firstIteration);
  757. Assert.Equal (overlapped, rsOverlapped.Toplevel);
  758. Assert.Equal (Application.Top, rsOverlapped.Toplevel);
  759. Assert.Equal (ApplicationOverlapped.OverlappedTop, rsOverlapped.Toplevel);
  760. // The win1 Visible is false and cannot be set as the Current
  761. Assert.Equal (Application.Current, rsOverlapped.Toplevel);
  762. Assert.Equal (overlapped, Application.Current);
  763. Assert.Equal (win1, rsWin1.Toplevel);
  764. RunState rsWin2 = Application.Begin (win2);
  765. Application.RunIteration (ref rsOverlapped, ref firstIteration);
  766. // Here the Current and the rsOverlapped.Toplevel is now the win2
  767. // and not the original overlapped
  768. Assert.Equal (win2, rsOverlapped.Toplevel);
  769. Assert.Equal (Application.Top, overlapped);
  770. Assert.Equal (ApplicationOverlapped.OverlappedTop, overlapped);
  771. Assert.Equal (Application.Current, rsWin2.Toplevel);
  772. Assert.Equal (win2, Application.Current);
  773. Assert.Equal (win1, rsWin1.Toplevel);
  774. // Tests that rely on visuals are too fragile. If border style changes they break.
  775. // Instead we should just rely on the test above.
  776. Application.OnMouseEvent (new MouseEvent { Position = new (1, 1), Flags = MouseFlags.Button1Pressed });
  777. Assert.Equal (win2.Border, Application.MouseGrabView);
  778. Application.RunIteration (ref rsOverlapped, ref firstIteration);
  779. Assert.Equal (win2, rsOverlapped.Toplevel);
  780. Assert.Equal (Application.Top, overlapped);
  781. Assert.Equal (ApplicationOverlapped.OverlappedTop, overlapped);
  782. Assert.Equal (Application.Current, rsWin2.Toplevel);
  783. Assert.Equal (win2, Application.Current);
  784. Assert.Equal (win1, rsWin1.Toplevel);
  785. Application.OnMouseEvent (new MouseEvent
  786. {
  787. Position = new (2, 2), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  788. });
  789. Application.RunIteration (ref rsOverlapped, ref firstIteration);
  790. Assert.Equal (win2, rsOverlapped.Toplevel);
  791. Assert.Equal (Application.Top, overlapped);
  792. Assert.Equal (ApplicationOverlapped.OverlappedTop, overlapped);
  793. Assert.Equal (Application.Current, rsWin2.Toplevel);
  794. Assert.Equal (win2, Application.Current);
  795. Assert.Equal (win1, rsWin1.Toplevel);
  796. // Tests that rely on visuals are too fragile. If border style changes they break.
  797. // Instead we should just rely on the test above.
  798. // This will end the win2 and not the overlapped
  799. Application.End (rsOverlapped);
  800. // rsOverlapped has been disposed and Toplevel property is null
  801. // So we must use another valid RunState to iterate
  802. Application.RunIteration (ref rsWin1, ref firstIteration);
  803. #if DEBUG_IDISPOSABLE
  804. Assert.True (rsOverlapped.WasDisposed);
  805. #endif
  806. Assert.Null (rsOverlapped.Toplevel);
  807. Assert.Equal (Application.Top, overlapped);
  808. Assert.Equal (ApplicationOverlapped.OverlappedTop, overlapped);
  809. Assert.Equal (Application.Current, rsWin1.Toplevel);
  810. Assert.Equal (win1, Application.Current);
  811. Assert.Equal (win1, rsWin1.Toplevel);
  812. Application.End (rsWin1);
  813. // rsWin1 has been disposed and Toplevel property is null
  814. // So we must use another valid RunState to iterate
  815. Application.RunIteration (ref rsWin2, ref firstIteration);
  816. #if DEBUG_IDISPOSABLE
  817. Assert.True (rsOverlapped.WasDisposed);
  818. Assert.True (rsWin1.WasDisposed);
  819. #endif
  820. Assert.Null (rsOverlapped.Toplevel);
  821. Assert.Equal (Application.Top, overlapped);
  822. Assert.Equal (ApplicationOverlapped.OverlappedTop, overlapped);
  823. Assert.Equal (Application.Current, overlapped);
  824. Assert.Null (rsWin1.Toplevel);
  825. // See here that the only Toplevel that needs to End is the overlapped
  826. // which the rsWin2 now has the Toplevel set to the overlapped
  827. Assert.Equal (overlapped, rsWin2.Toplevel);
  828. Application.End (rsWin2);
  829. // There is no more RunState to iteration
  830. #if DEBUG_IDISPOSABLE
  831. Assert.True (rsOverlapped.WasDisposed);
  832. Assert.True (rsWin1.WasDisposed);
  833. Assert.True (rsWin2.WasDisposed);
  834. #endif
  835. Assert.Null (rsOverlapped.Toplevel);
  836. Assert.Equal (Application.Top, overlapped);
  837. Assert.Equal (ApplicationOverlapped.OverlappedTop, overlapped);
  838. Assert.Null (Application.Current);
  839. Assert.Null (rsWin1.Toplevel);
  840. Assert.Null (rsWin2.Toplevel);
  841. #if DEBUG_IDISPOSABLE
  842. Assert.False (win2.WasDisposed);
  843. Assert.False (win1.WasDisposed);
  844. Assert.False (overlapped.WasDisposed);
  845. #endif
  846. // Now dispose all them
  847. win2.Dispose ();
  848. win1.Dispose ();
  849. overlapped.Dispose ();
  850. Application.Shutdown ();
  851. }
  852. private class Overlapped : Toplevel
  853. {
  854. public Overlapped () { IsOverlappedContainer = true; }
  855. }
  856. [Fact (Skip = "#2491: This test is really bogus. It does things like Runnable = false and is overly convolulted. Replace.")]
  857. [AutoInitShutdown]
  858. public void KeyBindings_Command_With_OverlappedTop ()
  859. {
  860. Toplevel top = new ();
  861. Assert.Null (ApplicationOverlapped.OverlappedTop);
  862. top.IsOverlappedContainer = true;
  863. Application.Begin (top);
  864. Assert.Equal (Application.Top, ApplicationOverlapped.OverlappedTop);
  865. var isRunning = true;
  866. var win1 = new Window { Id = "win1", Width = Dim.Percent (50), Height = Dim.Fill () };
  867. var lblTf1W1 = new Label { Text = "Enter text in TextField on Win1:" };
  868. var tf1W1 = new TextField { Id="tf1W1", X = Pos.Right (lblTf1W1) + 1, Width = Dim.Fill (), Text = "Text1 on Win1" };
  869. var lblTvW1 = new Label { Y = Pos.Bottom (lblTf1W1) + 1, Text = "Enter text in TextView on Win1:" };
  870. var tvW1 = new TextView
  871. {
  872. Id = "tvW1",
  873. X = Pos.Left (tf1W1), Width = Dim.Fill (), Height = 2, Text = "First line Win1\nSecond line Win1"
  874. };
  875. var lblTf2W1 = new Label { Y = Pos.Bottom (lblTvW1) + 1, Text = "Enter text in TextField on Win1:" };
  876. var tf2W1 = new TextField { Id = "tf2W1", X = Pos.Left (tf1W1), Width = Dim.Fill (), Text = "Text2 on Win1" };
  877. win1.Add (lblTf1W1, tf1W1, lblTvW1, tvW1, lblTf2W1, tf2W1);
  878. var win2 = new Window { Id = "win2", Width = Dim.Percent (50), Height = Dim.Fill () };
  879. var lblTf1W2 = new Label { Text = "Enter text in TextField on Win2:" };
  880. var tf1W2 = new TextField { Id = "tf1W2", X = Pos.Right (lblTf1W2) + 1, Width = Dim.Fill (), Text = "Text1 on Win2" };
  881. var lblTvW2 = new Label { Y = Pos.Bottom (lblTf1W2) + 1, Text = "Enter text in TextView on Win2:" };
  882. var tvW2 = new TextView
  883. {
  884. Id = "tvW2",
  885. X = Pos.Left (tf1W2), Width = Dim.Fill (), Height = 2, Text = "First line Win1\nSecond line Win2"
  886. };
  887. var lblTf2W2 = new Label { Y = Pos.Bottom (lblTvW2) + 1, Text = "Enter text in TextField on Win2:" };
  888. var tf2W2 = new TextField { Id = "tf2W2", X = Pos.Left (tf1W2), Width = Dim.Fill (), Text = "Text2 on Win2" };
  889. win2.Add (lblTf1W2, tf1W2, lblTvW2, tvW2, lblTf2W2, tf2W2);
  890. win1.Closing += (s, e) => isRunning = false;
  891. Assert.Null (top.Focused);
  892. Assert.Equal (top, Application.Current);
  893. Assert.True (top.IsCurrentTop);
  894. Assert.Equal (top, ApplicationOverlapped.OverlappedTop);
  895. Application.Begin (win1);
  896. Assert.Equal (new (0, 0, 40, 25), win1.Frame);
  897. Assert.NotEqual (top, Application.Current);
  898. Assert.False (top.IsCurrentTop);
  899. Assert.Equal (win1, Application.Current);
  900. Assert.True (win1.IsCurrentTop);
  901. Assert.True (ApplicationOverlapped.IsOverlapped(win1));
  902. Assert.Null (top.Focused);
  903. Assert.Null (top.MostFocused);
  904. Assert.Equal (tf1W1, win1.MostFocused);
  905. Assert.True (ApplicationOverlapped.IsOverlapped(win1));
  906. Assert.Single (ApplicationOverlapped.OverlappedChildren!);
  907. Application.Begin (win2);
  908. Assert.Equal (new (0, 0, 40, 25), win2.Frame);
  909. Assert.NotEqual (top, Application.Current);
  910. Assert.False (top.IsCurrentTop);
  911. Assert.Equal (win2, Application.Current);
  912. Assert.True (win2.IsCurrentTop);
  913. Assert.True (ApplicationOverlapped.IsOverlapped(win2));
  914. Assert.Null (top.Focused);
  915. Assert.Null (top.MostFocused);
  916. Assert.Equal (tf1W2, win2.MostFocused);
  917. Assert.Equal (2, ApplicationOverlapped.OverlappedChildren!.Count);
  918. ApplicationOverlapped.MoveToOverlappedChild (win1);
  919. Assert.Equal (win1, Application.Current);
  920. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  921. win1.Running = true;
  922. Assert.True (Application.OnKeyDown (Application.QuitKey));
  923. Assert.False (isRunning);
  924. Assert.False (win1.Running);
  925. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  926. // win1 has been closed. It can no longer be focused or acted upon.
  927. // win2 should now have focus
  928. Assert.Equal (win2, Application.Current);
  929. Assert.True (win2.IsCurrentTop);
  930. Assert.Equal (Environment.OSVersion.Platform == PlatformID.Unix, Application.OnKeyDown (Key.Z.WithCtrl)); // suspend
  931. Assert.True (Application.OnKeyDown (Key.F5)); // refresh
  932. Assert.True (win1.IsCurrentTop);
  933. Assert.Equal (tvW1, win1.MostFocused);
  934. Assert.True (Application.OnKeyDown (Key.Tab));
  935. Assert.Equal ($"\tFirst line Win1{Environment.NewLine}Second line Win1", tvW1.Text);
  936. Assert.True (Application.OnKeyDown (Key.Tab.WithShift));
  937. Assert.Equal ($"First line Win1{Environment.NewLine}Second line Win1", tvW1.Text);
  938. Assert.True (Application.OnKeyDown (Key.Tab.WithCtrl)); // move to win2
  939. Assert.Equal (win2, ApplicationOverlapped.OverlappedChildren [0]);
  940. Assert.True (Application.OnKeyDown (Key.Tab.WithCtrl.WithShift)); // move back to win1
  941. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  942. Assert.Equal (tvW1, win1.MostFocused);
  943. Assert.True (Application.OnKeyDown (Key.Tab)); // text view eats tab
  944. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  945. Assert.Equal (tvW1, win1.MostFocused);
  946. tvW1.AllowsTab = false;
  947. Assert.True (Application.OnKeyDown (Key.Tab)); // text view eats tab
  948. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  949. Assert.Equal (tf2W1, win1.MostFocused);
  950. Assert.True (Application.OnKeyDown (Key.CursorRight));
  951. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  952. Assert.Equal (tf2W1, win1.MostFocused);
  953. Assert.True (Application.OnKeyDown (Key.CursorDown));
  954. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  955. Assert.Equal (tf1W1, win1.MostFocused);
  956. #if UNIX_KEY_BINDINGS
  957. Assert.True (ApplicationOverlapped.OverlappedChildren [0].ProcessKeyDown (new (Key.I.WithCtrl)));
  958. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  959. Assert.Equal (tf2W1, win1.MostFocused);
  960. #endif
  961. Assert.True (Application.OnKeyDown (Key.Tab));
  962. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  963. Assert.Equal (tvW1, win1.MostFocused);
  964. Assert.True (Application.OnKeyDown (Key.CursorLeft)); // The view to the left of tvW1 is tf2W1, but tvW1 is still focused and eats cursor keys
  965. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  966. Assert.Equal (tvW1, win1.MostFocused);
  967. Assert.True (Application.OnKeyDown (Key.CursorUp));
  968. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  969. Assert.Equal (tvW1, win1.MostFocused);
  970. Assert.True (Application.OnKeyDown (Key.Tab));
  971. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  972. Assert.Equal (tf2W1, win1.MostFocused);
  973. Assert.True (Application.OnKeyDown (Key.Tab.WithCtrl)); // Move to win2
  974. Assert.Equal (win2, ApplicationOverlapped.OverlappedChildren [0]);
  975. Assert.Equal (tf1W2, win2.MostFocused);
  976. tf2W2.SetFocus ();
  977. Assert.True (tf2W2.HasFocus);
  978. Assert.True (Application.OnKeyDown (Key.Tab.WithCtrl.WithShift));
  979. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  980. Assert.Equal (tf2W1, win1.MostFocused);
  981. Assert.True (Application.OnKeyDown (Application.AlternateForwardKey));
  982. Assert.Equal (win2, ApplicationOverlapped.OverlappedChildren [0]);
  983. Assert.Equal (tf2W2, win2.MostFocused);
  984. Assert.True (Application.OnKeyDown (Application.AlternateBackwardKey));
  985. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  986. Assert.Equal (tf2W1, win1.MostFocused);
  987. Assert.True (Application.OnKeyDown (Key.CursorDown));
  988. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  989. Assert.Equal (tf1W1, win1.MostFocused);
  990. #if UNIX_KEY_BINDINGS
  991. Assert.True (Application.OnKeyDown (new (Key.B.WithCtrl)));
  992. #else
  993. Assert.True (Application.OnKeyDown (Key.CursorLeft));
  994. #endif
  995. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  996. Assert.Equal (tf1W1, win1.MostFocused);
  997. Assert.True (Application.OnKeyDown (Key.CursorDown));
  998. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  999. Assert.Equal (tvW1, win1.MostFocused);
  1000. Assert.Equal (Point.Empty, tvW1.CursorPosition);
  1001. Assert.True (Application.OnKeyDown (Key.End.WithCtrl));
  1002. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  1003. Assert.Equal (tvW1, win1.MostFocused);
  1004. Assert.Equal (new (16, 1), tvW1.CursorPosition); // Last position of the text
  1005. #if UNIX_KEY_BINDINGS
  1006. Assert.True (Application.OnKeyDown (new (Key.F.WithCtrl)));
  1007. #else
  1008. Assert.True (Application.OnKeyDown (Key.CursorRight)); // should move to next view w/ in Group (tf2W1)
  1009. #endif
  1010. Assert.Equal (win1, ApplicationOverlapped.OverlappedChildren [0]);
  1011. Assert.Equal (tf2W1, win1.MostFocused);
  1012. #if UNIX_KEY_BINDINGS
  1013. Assert.True (ApplicationOverlapped.OverlappedChildren [0].ProcessKeyDown (new (Key.L.WithCtrl)));
  1014. #endif
  1015. win2.Dispose ();
  1016. win1.Dispose ();
  1017. top.Dispose ();
  1018. }
  1019. [Fact]
  1020. public void SetFocusToNextViewWithWrap_ShouldFocusNextView ()
  1021. {
  1022. // Arrange
  1023. var superView = new TestToplevel () { Id = "superView", IsOverlappedContainer = true };
  1024. var view1 = new TestView () { Id = "view1" };
  1025. var view2 = new TestView () { Id = "view2" };
  1026. var view3 = new TestView () { Id = "view3" }; ;
  1027. superView.Add (view1, view2, view3);
  1028. var current = new TestToplevel () { Id = "current", IsOverlappedContainer = true };
  1029. superView.Add (current);
  1030. superView.BeginInit ();
  1031. superView.EndInit ();
  1032. current.SetFocus ();
  1033. Application.Current = current;
  1034. Assert.True (current.HasFocus);
  1035. Assert.Equal (superView.Focused, current);
  1036. Assert.Equal (superView.MostFocused, current);
  1037. // Act
  1038. ApplicationOverlapped.SetFocusToNextViewWithWrap (Application.Current.SuperView.TabIndexes, NavigationDirection.Forward);
  1039. // Assert
  1040. Assert.True (view1.HasFocus);
  1041. }
  1042. [Fact]
  1043. public void SetFocusToNextViewWithWrap_ShouldNotChangeFocusIfViewsIsNull ()
  1044. {
  1045. // Arrange
  1046. var currentView = new TestToplevel ();
  1047. Application.Current = currentView;
  1048. // Act
  1049. ApplicationOverlapped.SetFocusToNextViewWithWrap (null, NavigationDirection.Forward);
  1050. // Assert
  1051. Assert.Equal (currentView, Application.Current);
  1052. }
  1053. [Fact]
  1054. public void SetFocusToNextViewWithWrap_ShouldNotChangeFocusIfCurrentViewNotFound ()
  1055. {
  1056. // Arrange
  1057. var view1 = new TestToplevel ();
  1058. var view2 = new TestToplevel ();
  1059. var view3 = new TestToplevel ();
  1060. var views = new List<View> { view1, view2, view3 };
  1061. var currentView = new TestToplevel () { IsOverlappedContainer = true }; // Current view is not in the list
  1062. Application.Current = currentView;
  1063. // Act
  1064. ApplicationOverlapped.SetFocusToNextViewWithWrap (views, NavigationDirection.Forward);
  1065. // Assert
  1066. Assert.False (view1.IsFocused);
  1067. Assert.False (view2.IsFocused);
  1068. Assert.False (view3.IsFocused);
  1069. }
  1070. private class TestToplevel : Toplevel
  1071. {
  1072. public bool IsFocused { get; private set; }
  1073. public override bool OnEnter (View view)
  1074. {
  1075. IsFocused = true;
  1076. return base.OnEnter (view);
  1077. }
  1078. public override bool OnLeave (View view)
  1079. {
  1080. IsFocused = false;
  1081. return base.OnLeave (view);
  1082. }
  1083. }
  1084. private class TestView : View
  1085. {
  1086. public TestView ()
  1087. {
  1088. CanFocus = true;
  1089. }
  1090. public bool IsFocused { get; private set; }
  1091. public override bool OnEnter (View view)
  1092. {
  1093. IsFocused = true;
  1094. return base.OnEnter (view);
  1095. }
  1096. public override bool OnLeave (View view)
  1097. {
  1098. IsFocused = false;
  1099. return base.OnLeave (view);
  1100. }
  1101. }
  1102. }