ToplevelTests.cs 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207
  1. using Xunit.Abstractions;
  2. namespace Terminal.Gui.ViewsTests;
  3. public partial class ToplevelTests (ITestOutputHelper output)
  4. {
  5. [Fact]
  6. public void Constructor_Default ()
  7. {
  8. var top = new Toplevel ();
  9. Assert.Equal (Colors.ColorSchemes ["TopLevel"], top.ColorScheme);
  10. Assert.Equal ("Fill(Absolute(0))", top.Width.ToString ());
  11. Assert.Equal ("Fill(Absolute(0))", top.Height.ToString ());
  12. Assert.False (top.Running);
  13. Assert.False (top.Modal);
  14. Assert.Null (top.MenuBar);
  15. //Assert.Null (top.StatusBar);
  16. }
  17. [Fact]
  18. public void Arrangement_Default_Is_Overlapped ()
  19. {
  20. var top = new Toplevel ();
  21. Assert.Equal (ViewArrangement.Overlapped, top.Arrangement);
  22. }
  23. [Fact]
  24. [AutoInitShutdown]
  25. public void Internal_Tests ()
  26. {
  27. var top = new Toplevel ();
  28. var eventInvoked = "";
  29. top.Loaded += (s, e) => eventInvoked = "Loaded";
  30. top.OnLoaded ();
  31. Assert.Equal ("Loaded", eventInvoked);
  32. top.Ready += (s, e) => eventInvoked = "Ready";
  33. top.OnReady ();
  34. Assert.Equal ("Ready", eventInvoked);
  35. top.Unloaded += (s, e) => eventInvoked = "Unloaded";
  36. top.OnUnloaded ();
  37. Assert.Equal ("Unloaded", eventInvoked);
  38. top.Add (new MenuBar ());
  39. Assert.NotNull (top.MenuBar);
  40. //top.Add (new StatusBar ());
  41. //Assert.NotNull (top.StatusBar);
  42. var menuBar = top.MenuBar;
  43. top.Remove (top.MenuBar);
  44. Assert.Null (top.MenuBar);
  45. Assert.NotNull (menuBar);
  46. //var statusBar = top.StatusBar;
  47. //top.Remove (top.StatusBar);
  48. //Assert.Null (top.StatusBar);
  49. //Assert.NotNull (statusBar);
  50. #if DEBUG_IDISPOSABLE
  51. Assert.False (menuBar.WasDisposed);
  52. //Assert.False (statusBar.WasDisposed);
  53. menuBar.Dispose ();
  54. //statusBar.Dispose ();
  55. Assert.True (menuBar.WasDisposed);
  56. //Assert.True (statusBar.WasDisposed);
  57. #endif
  58. Application.Begin (top);
  59. Assert.Equal (top, Application.Top);
  60. // Application.Top without menu and status bar.
  61. View supView = View.GetLocationEnsuringFullVisibility (top, 2, 2, out int nx, out int ny/*, out StatusBar sb*/);
  62. Assert.Equal (Application.Top, supView);
  63. Assert.Equal (0, nx);
  64. Assert.Equal (0, ny);
  65. //Assert.Null (sb);
  66. top.Add (new MenuBar ());
  67. Assert.NotNull (top.MenuBar);
  68. // Application.Top with a menu and without status bar.
  69. View.GetLocationEnsuringFullVisibility (top, 2, 2, out nx, out ny/*, out sb*/);
  70. Assert.Equal (0, nx);
  71. Assert.Equal (1, ny);
  72. //Assert.Null (sb);
  73. //top.Add (new StatusBar ());
  74. //Assert.NotNull (top.StatusBar);
  75. // Application.Top with a menu and status bar.
  76. View.GetLocationEnsuringFullVisibility (top, 2, 2, out nx, out ny/*, out sb*/);
  77. Assert.Equal (0, nx);
  78. // The available height is lower than the Application.Top height minus
  79. // the menu bar and status bar, then the top can go beyond the bottom
  80. // Assert.Equal (2, ny);
  81. //Assert.NotNull (sb);
  82. menuBar = top.MenuBar;
  83. top.Remove (top.MenuBar);
  84. Assert.Null (top.MenuBar);
  85. Assert.NotNull (menuBar);
  86. // Application.Top without a menu and with a status bar.
  87. View.GetLocationEnsuringFullVisibility (top, 2, 2, out nx, out ny/*, out sb*/);
  88. Assert.Equal (0, nx);
  89. // The available height is lower than the Application.Top height minus
  90. // the status bar, then the top can go beyond the bottom
  91. // Assert.Equal (2, ny);
  92. //Assert.NotNull (sb);
  93. //statusBar = top.StatusBar;
  94. //top.Remove (top.StatusBar);
  95. //Assert.Null (top.StatusBar);
  96. //Assert.NotNull (statusBar);
  97. Assert.Null (top.MenuBar);
  98. var win = new Window { Width = Dim.Fill (), Height = Dim.Fill () };
  99. top.Add (win);
  100. top.LayoutSubviews ();
  101. // The SuperView is always the same regardless of the caller.
  102. supView = View.GetLocationEnsuringFullVisibility (win, 0, 0, out nx, out ny/*, out sb*/);
  103. Assert.Equal (Application.Top, supView);
  104. supView = View.GetLocationEnsuringFullVisibility (win, 0, 0, out nx, out ny/*, out sb*/);
  105. Assert.Equal (Application.Top, supView);
  106. // Application.Top without menu and status bar.
  107. View.GetLocationEnsuringFullVisibility (win, 0, 0, out nx, out ny/*, out sb*/);
  108. Assert.Equal (0, nx);
  109. Assert.Equal (0, ny);
  110. //Assert.Null (sb);
  111. top.Add (new MenuBar ());
  112. Assert.NotNull (top.MenuBar);
  113. // Application.Top with a menu and without status bar.
  114. View.GetLocationEnsuringFullVisibility (win, 2, 2, out nx, out ny/*, out sb*/);
  115. Assert.Equal (0, nx);
  116. Assert.Equal (1, ny);
  117. //Assert.Null (sb);
  118. top.Add (new StatusBar ());
  119. //Assert.NotNull (top.StatusBar);
  120. // Application.Top with a menu and status bar.
  121. View.GetLocationEnsuringFullVisibility (win, 30, 20, out nx, out ny/*, out sb*/);
  122. Assert.Equal (0, nx);
  123. // The available height is lower than the Application.Top height minus
  124. // the menu bar and status bar, then the top can go beyond the bottom
  125. //Assert.Equal (20, ny);
  126. //Assert.NotNull (sb);
  127. menuBar = top.MenuBar;
  128. //statusBar = top.StatusBar;
  129. top.Remove (top.MenuBar);
  130. Assert.Null (top.MenuBar);
  131. Assert.NotNull (menuBar);
  132. //top.Remove (top.StatusBar);
  133. //Assert.Null (top.StatusBar);
  134. //Assert.NotNull (statusBar);
  135. top.Remove (win);
  136. win = new () { Width = 60, Height = 15 };
  137. top.Add (win);
  138. // Application.Top without menu and status bar.
  139. View.GetLocationEnsuringFullVisibility (win, 0, 0, out nx, out ny/*, out sb*/);
  140. Assert.Equal (0, nx);
  141. Assert.Equal (0, ny);
  142. //Assert.Null (sb);
  143. top.Add (new MenuBar ());
  144. Assert.NotNull (top.MenuBar);
  145. // Application.Top with a menu and without status bar.
  146. View.GetLocationEnsuringFullVisibility (win, 2, 2, out nx, out ny/*, out sb*/);
  147. Assert.Equal (2, nx);
  148. Assert.Equal (2, ny);
  149. //Assert.Null (sb);
  150. top.Add (new StatusBar ());
  151. //Assert.NotNull (top.StatusBar);
  152. // Application.Top with a menu and status bar.
  153. View.GetLocationEnsuringFullVisibility (win, 30, 20, out nx, out ny/*, out sb*/);
  154. Assert.Equal (20, nx); // 20+60=80
  155. //Assert.Equal (9, ny); // 9+15+1(mb)=25
  156. //Assert.NotNull (sb);
  157. //Assert.Null (Toplevel._dragPosition);
  158. win.NewMouseEvent (new () { Position = new (6, 0), Flags = MouseFlags.Button1Pressed });
  159. // Assert.Equal (new Point (6, 0), Toplevel._dragPosition);
  160. win.NewMouseEvent (new () { Position = new (6, 0), Flags = MouseFlags.Button1Released });
  161. //Assert.Null (Toplevel._dragPosition);
  162. win.CanFocus = false;
  163. win.NewMouseEvent (new () { Position = new (6, 0), Flags = MouseFlags.Button1Pressed });
  164. //Assert.Null (Toplevel._dragPosition);
  165. #if DEBUG_IDISPOSABLE
  166. Assert.False (top.MenuBar.WasDisposed);
  167. //Assert.False (top.StatusBar.WasDisposed);
  168. #endif
  169. menuBar = top.MenuBar;
  170. //statusBar = top.StatusBar;
  171. top.Dispose ();
  172. Assert.Null (top.MenuBar);
  173. //Assert.Null (top.StatusBar);
  174. Assert.NotNull (menuBar);
  175. //Assert.NotNull (statusBar);
  176. #if DEBUG_IDISPOSABLE
  177. Assert.True (menuBar.WasDisposed);
  178. //Assert.True (statusBar.WasDisposed);
  179. #endif
  180. }
  181. [Fact (Skip = "#2491 - Test is broken until #2491 is more mature.")]
  182. [AutoInitShutdown]
  183. public void KeyBindings_Command ()
  184. {
  185. var isRunning = false;
  186. var win1 = new Window { Id = "win1", Width = Dim.Percent (50), Height = Dim.Fill () };
  187. var lblTf1W1 = new Label { Id = "lblTf1W1", Text = "Enter text in TextField on Win1:" };
  188. var tf1W1 = new TextField
  189. {
  190. Id = "tf1W1", X = Pos.Right (lblTf1W1) + 1, Width = Dim.Fill (), Text = "Text1 on Win1"
  191. };
  192. var lblTvW1 = new Label
  193. {
  194. Id = "lblTvW1", Y = Pos.Bottom (lblTf1W1) + 1, Text = "Enter text in TextView on Win1:"
  195. };
  196. var tvW1 = new TextView
  197. {
  198. Id = "tvW1",
  199. X = Pos.Left (tf1W1),
  200. Width = Dim.Fill (),
  201. Height = 2,
  202. Text = "First line Win1\nSecond line Win1"
  203. };
  204. var lblTf2W1 = new Label
  205. {
  206. Id = "lblTf2W1", Y = Pos.Bottom (lblTvW1) + 1, Text = "Enter text in TextField on Win1:"
  207. };
  208. var tf2W1 = new TextField { Id = "tf2W1", X = Pos.Left (tf1W1), Width = Dim.Fill (), Text = "Text2 on Win1" };
  209. win1.Add (lblTf1W1, tf1W1, lblTvW1, tvW1, lblTf2W1, tf2W1);
  210. var win2 = new Window
  211. {
  212. Id = "win2", X = Pos.Right (win1) + 1, Width = Dim.Percent (50), Height = Dim.Fill ()
  213. };
  214. var lblTf1W2 = new Label { Id = "lblTf1W2", Text = "Enter text in TextField on Win2:" };
  215. var tf1W2 = new TextField
  216. {
  217. Id = "tf1W2", X = Pos.Right (lblTf1W2) + 1, Width = Dim.Fill (), Text = "Text1 on Win2"
  218. };
  219. var lblTvW2 = new Label
  220. {
  221. Id = "lblTvW2", Y = Pos.Bottom (lblTf1W2) + 1, Text = "Enter text in TextView on Win2:"
  222. };
  223. var tvW2 = new TextView
  224. {
  225. Id = "tvW2",
  226. X = Pos.Left (tf1W2),
  227. Width = Dim.Fill (),
  228. Height = 2,
  229. Text = "First line Win1\nSecond line Win2"
  230. };
  231. var lblTf2W2 = new Label
  232. {
  233. Id = "lblTf2W2", Y = Pos.Bottom (lblTvW2) + 1, Text = "Enter text in TextField on Win2:"
  234. };
  235. var tf2W2 = new TextField { Id = "tf2W2", X = Pos.Left (tf1W2), Width = Dim.Fill (), Text = "Text2 on Win2" };
  236. win2.Add (lblTf1W2, tf1W2, lblTvW2, tvW2, lblTf2W2, tf2W2);
  237. Toplevel top = new ();
  238. top.Add (win1, win2);
  239. top.Loaded += (s, e) => isRunning = true;
  240. top.Closing += (s, e) => isRunning = false;
  241. Application.Begin (top);
  242. top.Running = true;
  243. Assert.Equal (new (0, 0, 40, 25), win1.Frame);
  244. Assert.Equal (new (41, 0, 40, 25), win2.Frame);
  245. Assert.Equal (win1, top.Focused);
  246. Assert.Equal (tf1W1, top.MostFocused);
  247. Assert.True (isRunning);
  248. Assert.True (Application.RaiseKeyDownEvent (Application.QuitKey));
  249. Assert.False (isRunning);
  250. Assert.True (Application.RaiseKeyDownEvent (Key.Z.WithCtrl));
  251. Assert.True (Application.RaiseKeyDownEvent (Key.F5)); // refresh
  252. Assert.True (Application.RaiseKeyDownEvent (Key.Tab));
  253. Assert.Equal (win1, top.Focused);
  254. Assert.Equal (tvW1, top.MostFocused);
  255. Assert.True (Application.RaiseKeyDownEvent (Key.Tab));
  256. Assert.Equal ($"\tFirst line Win1{Environment.NewLine}Second line Win1", tvW1.Text);
  257. Assert.True (Application.RaiseKeyDownEvent (Key.Tab.WithShift));
  258. Assert.Equal ($"First line Win1{Environment.NewLine}Second line Win1", tvW1.Text);
  259. var prevMostFocusedSubview = top.MostFocused;
  260. Assert.True (Application.RaiseKeyDownEvent (Key.F6)); // move to next TabGroup (win2)
  261. Assert.Equal (win2, top.Focused);
  262. Assert.True (Application.RaiseKeyDownEvent (Key.F6.WithShift)); // move to prev TabGroup (win1)
  263. Assert.Equal (win1, top.Focused);
  264. Assert.Equal (tf2W1, top.MostFocused); // BUGBUG: Should be prevMostFocusedSubview - We need to cache the last focused view in the TabGroup somehow
  265. prevMostFocusedSubview.SetFocus ();
  266. Assert.Equal (tvW1, top.MostFocused);
  267. tf2W1.SetFocus ();
  268. Assert.True (Application.RaiseKeyDownEvent (Key.Tab)); // tf2W1 is last subview in win1 - tabbing should take us to first subview of win1
  269. Assert.Equal (win1, top.Focused);
  270. Assert.Equal (tf1W1, top.MostFocused);
  271. Assert.True (Application.RaiseKeyDownEvent (Key.CursorRight)); // move char to right in tf1W1. We're at last char so nav to next view
  272. Assert.Equal (win1, top.Focused);
  273. Assert.Equal (tvW1, top.MostFocused);
  274. Assert.True (Application.RaiseKeyDownEvent (Key.CursorDown)); // move down to next view (tvW1)
  275. Assert.Equal (win1, top.Focused);
  276. Assert.Equal (tvW1, top.MostFocused);
  277. #if UNIX_KEY_BINDINGS
  278. Assert.True (Application.OnKeyDown (new (Key.I.WithCtrl)));
  279. Assert.Equal (win1, top.GetFocused ());
  280. Assert.Equal (tf2W1, top.MostFocused);
  281. #endif
  282. Assert.True (Application.RaiseKeyDownEvent (Key.Tab.WithShift)); // Ignored. TextView eats shift-tab by default
  283. Assert.Equal (win1, top.Focused);
  284. Assert.Equal (tvW1, top.MostFocused);
  285. tvW1.AllowsTab = false;
  286. Assert.True (Application.RaiseKeyDownEvent (Key.Tab.WithShift));
  287. Assert.Equal (win1, top.Focused);
  288. Assert.Equal (tf1W1, top.MostFocused);
  289. Assert.True (Application.RaiseKeyDownEvent (Key.CursorLeft));
  290. Assert.Equal (win1, top.Focused);
  291. Assert.Equal (tf2W1, top.MostFocused);
  292. Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
  293. Assert.Equal (win1, top.Focused);
  294. Assert.Equal (tvW1, top.MostFocused);
  295. // nav to win2
  296. Assert.True (Application.RaiseKeyDownEvent (Key.F6));
  297. Assert.Equal (win2, top.Focused);
  298. Assert.Equal (tf1W2, top.MostFocused);
  299. Assert.True (Application.RaiseKeyDownEvent (Key.F6.WithShift));
  300. Assert.Equal (win1, top.Focused);
  301. Assert.Equal (tf2W1, top.MostFocused);
  302. Assert.True (Application.RaiseKeyDownEvent (Application.NextTabGroupKey));
  303. Assert.Equal (win2, top.Focused);
  304. Assert.Equal (tf1W2, top.MostFocused);
  305. Assert.True (Application.RaiseKeyDownEvent (Application.PrevTabGroupKey));
  306. Assert.Equal (win1, top.Focused);
  307. Assert.Equal (tf2W1, top.MostFocused);
  308. Assert.True (Application.RaiseKeyDownEvent (Key.CursorUp));
  309. Assert.Equal (win1, top.Focused);
  310. Assert.Equal (tvW1, top.MostFocused);
  311. top.Dispose ();
  312. }
  313. [Fact]
  314. public void Added_Event_Should_Not_Be_Used_To_Initialize_Toplevel_Events ()
  315. {
  316. var wasAdded = false;
  317. var view = new View ();
  318. view.Added += View_Added;
  319. void View_Added (object sender, SuperViewChangedEventArgs e)
  320. {
  321. Assert.False (wasAdded);
  322. wasAdded = true;
  323. view.Added -= View_Added;
  324. }
  325. var win = new Window ();
  326. win.Add (view);
  327. Application.Init (new FakeDriver ());
  328. Toplevel top = new ();
  329. top.Add (win);
  330. Assert.True (wasAdded);
  331. Application.Shutdown ();
  332. }
  333. [Fact]
  334. [AutoInitShutdown]
  335. public void Mouse_Drag_On_Top_With_Superview_Null ()
  336. {
  337. var win = new Window ();
  338. Toplevel top = new ();
  339. top.Add (win);
  340. int iterations = -1;
  341. Window testWindow;
  342. Application.Iteration += (s, a) =>
  343. {
  344. iterations++;
  345. if (iterations == 0)
  346. {
  347. ((FakeDriver)Application.Driver!).SetBufferSize (15, 7);
  348. // Don't use MessageBox here; it's too complicated for this unit test; just use Window
  349. testWindow = new ()
  350. {
  351. Text = "Hello",
  352. X = 2,
  353. Y = 2,
  354. Width = 10,
  355. Height = 3,
  356. Arrangement = ViewArrangement.Movable
  357. };
  358. Application.Run (testWindow);
  359. }
  360. else if (iterations == 1)
  361. {
  362. Assert.Equal (new (2, 2), Application.Top!.Frame.Location);
  363. }
  364. else if (iterations == 2)
  365. {
  366. Assert.Null (Application.MouseGrabView);
  367. // Grab the mouse
  368. Application.RaiseMouseEvent (new () { ScreenPosition = new (3, 2), Flags = MouseFlags.Button1Pressed });
  369. Assert.Equal (Application.Top!.Border, Application.MouseGrabView);
  370. Assert.Equal (new (2, 2, 10, 3), Application.Top.Frame);
  371. }
  372. else if (iterations == 3)
  373. {
  374. Assert.Equal (Application.Top!.Border, Application.MouseGrabView);
  375. // Drag to left
  376. Application.RaiseMouseEvent (
  377. new ()
  378. {
  379. ScreenPosition = new (2, 2), Flags = MouseFlags.Button1Pressed
  380. | MouseFlags.ReportMousePosition
  381. });
  382. Application.Refresh ();
  383. Assert.Equal (Application.Top.Border, Application.MouseGrabView);
  384. Assert.Equal (new (1, 2, 10, 3), Application.Top.Frame);
  385. }
  386. else if (iterations == 4)
  387. {
  388. Assert.Equal (Application.Top!.Border, Application.MouseGrabView);
  389. Assert.Equal (new (1, 2), Application.Top.Frame.Location);
  390. Assert.Equal (Application.Top.Border, Application.MouseGrabView);
  391. }
  392. else if (iterations == 5)
  393. {
  394. Assert.Equal (Application.Top!.Border, Application.MouseGrabView);
  395. // Drag up
  396. Application.RaiseMouseEvent (
  397. new ()
  398. {
  399. ScreenPosition = new (2, 1), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  400. });
  401. Application.Refresh ();
  402. Assert.Equal (Application.Top!.Border, Application.MouseGrabView);
  403. Assert.Equal (new (1, 1, 10, 3), Application.Top.Frame);
  404. }
  405. else if (iterations == 6)
  406. {
  407. Assert.Equal (Application.Top!.Border, Application.MouseGrabView);
  408. Assert.Equal (new (1, 1), Application.Top.Frame.Location);
  409. Assert.Equal (Application.Top.Border, Application.MouseGrabView);
  410. Assert.Equal (new (1, 1, 10, 3), Application.Top.Frame);
  411. }
  412. else if (iterations == 7)
  413. {
  414. Assert.Equal (Application.Top!.Border, Application.MouseGrabView);
  415. // Ungrab the mouse
  416. Application.RaiseMouseEvent (new () { ScreenPosition = new (2, 1), Flags = MouseFlags.Button1Released });
  417. Application.Refresh ();
  418. Assert.Null (Application.MouseGrabView);
  419. }
  420. else if (iterations == 8)
  421. {
  422. Application.RequestStop ();
  423. }
  424. else if (iterations == 9)
  425. {
  426. Application.RequestStop ();
  427. }
  428. };
  429. Application.Run (top);
  430. top.Dispose ();
  431. }
  432. [Fact]
  433. [AutoInitShutdown]
  434. public void Mouse_Drag_On_Top_With_Superview_Not_Null ()
  435. {
  436. var win = new Window { X = 3, Y = 2, Width = 10, Height = 5, Arrangement = ViewArrangement.Movable };
  437. Toplevel top = new ();
  438. top.Add (win);
  439. int iterations = -1;
  440. var movex = 0;
  441. var movey = 0;
  442. var location = new Rectangle (win.Frame.X, win.Frame.Y, 7, 3);
  443. Application.Iteration += (s, a) =>
  444. {
  445. iterations++;
  446. if (iterations == 0)
  447. {
  448. ((FakeDriver)Application.Driver!).SetBufferSize (30, 10);
  449. }
  450. else if (iterations == 1)
  451. {
  452. location = win.Frame;
  453. Assert.Null (Application.MouseGrabView);
  454. // Grab the mouse
  455. Application.RaiseMouseEvent (
  456. new ()
  457. {
  458. ScreenPosition = new (win.Frame.X, win.Frame.Y), Flags = MouseFlags.Button1Pressed
  459. });
  460. Assert.Equal (win.Border, Application.MouseGrabView);
  461. }
  462. else if (iterations == 2)
  463. {
  464. Assert.Equal (win.Border, Application.MouseGrabView);
  465. // Drag to left
  466. movex = 1;
  467. movey = 0;
  468. Application.RaiseMouseEvent (
  469. new ()
  470. {
  471. ScreenPosition = new (win.Frame.X + movex, win.Frame.Y + movey), Flags =
  472. MouseFlags.Button1Pressed
  473. | MouseFlags.ReportMousePosition
  474. });
  475. Assert.Equal (win.Border, Application.MouseGrabView);
  476. }
  477. else if (iterations == 3)
  478. {
  479. // we should have moved +1, +0
  480. Assert.Equal (win.Border, Application.MouseGrabView);
  481. Assert.Equal (win.Border, Application.MouseGrabView);
  482. location.Offset (movex, movey);
  483. }
  484. else if (iterations == 4)
  485. {
  486. Assert.Equal (win.Border, Application.MouseGrabView);
  487. // Drag up
  488. movex = 0;
  489. movey = -1;
  490. Application.RaiseMouseEvent (
  491. new ()
  492. {
  493. ScreenPosition = new (win.Frame.X + movex, win.Frame.Y + movey), Flags =
  494. MouseFlags.Button1Pressed
  495. | MouseFlags.ReportMousePosition
  496. });
  497. Assert.Equal (win.Border, Application.MouseGrabView);
  498. }
  499. else if (iterations == 5)
  500. {
  501. // we should have moved +0, -1
  502. Assert.Equal (win.Border, Application.MouseGrabView);
  503. location.Offset (movex, movey);
  504. Assert.Equal (location, win.Frame);
  505. }
  506. else if (iterations == 6)
  507. {
  508. Assert.Equal (win.Border, Application.MouseGrabView);
  509. // Ungrab the mouse
  510. movex = 0;
  511. movey = 0;
  512. Application.RaiseMouseEvent (
  513. new ()
  514. {
  515. ScreenPosition = new (win.Frame.X + movex, win.Frame.Y + movey),
  516. Flags = MouseFlags.Button1Released
  517. });
  518. Assert.Null (Application.MouseGrabView);
  519. }
  520. else if (iterations == 7)
  521. {
  522. Application.RequestStop ();
  523. }
  524. };
  525. Application.Run (top);
  526. top.Dispose ();
  527. }
  528. [Fact]
  529. [SetupFakeDriver]
  530. public void GetLocationThatFits_With_Border_Null_Not_Throws ()
  531. {
  532. var top = new Toplevel ();
  533. top.BeginInit ();
  534. top.EndInit ();
  535. Exception exception = Record.Exception (() => ((FakeDriver)Application.Driver!).SetBufferSize (0, 10));
  536. Assert.Null (exception);
  537. exception = Record.Exception (() => ((FakeDriver)Application.Driver!).SetBufferSize (10, 0));
  538. Assert.Null (exception);
  539. }
  540. [Fact]
  541. [AutoInitShutdown]
  542. public void PositionCursor_SetCursorVisibility_To_Invisible_If_Focused_Is_Null ()
  543. {
  544. var tf = new TextField { Width = 5, Text = "test" };
  545. var view = new View { Width = 10, Height = 10, CanFocus = true };
  546. view.Add (tf);
  547. var top = new Toplevel ();
  548. top.Add (view);
  549. Application.Begin (top);
  550. Assert.True (tf.HasFocus);
  551. Application.PositionCursor ();
  552. Application.Driver!.GetCursorVisibility (out CursorVisibility cursor);
  553. Assert.Equal (CursorVisibility.Default, cursor);
  554. view.Enabled = false;
  555. Assert.False (tf.HasFocus);
  556. Application.PositionCursor ();
  557. Application.Driver!.GetCursorVisibility (out cursor);
  558. Assert.Equal (CursorVisibility.Invisible, cursor);
  559. top.Dispose ();
  560. }
  561. [Fact]
  562. [AutoInitShutdown]
  563. public void IsLoaded_Application_Begin ()
  564. {
  565. Toplevel top = new ();
  566. Assert.False (top.IsLoaded);
  567. Application.Begin (top);
  568. Assert.True (top.IsLoaded);
  569. top.Dispose ();
  570. }
  571. [Fact]
  572. [AutoInitShutdown]
  573. public void IsLoaded_With_Sub_Toplevel_Application_Begin_NeedDisplay ()
  574. {
  575. Toplevel top = new ();
  576. var subTop = new Toplevel ();
  577. var view = new View { Frame = new (0, 0, 20, 10) };
  578. subTop.Add (view);
  579. top.Add (subTop);
  580. Assert.False (top.IsLoaded);
  581. Assert.False (subTop.IsLoaded);
  582. Assert.Equal (new (0, 0, 20, 10), view.Frame);
  583. view.SubviewLayout += ViewLayoutStarted;
  584. void ViewLayoutStarted (object sender, LayoutEventArgs e)
  585. {
  586. Assert.Equal (new (0, 0, 20, 10), view._needsDisplayRect);
  587. view.SubviewLayout -= ViewLayoutStarted;
  588. }
  589. Application.Begin (top);
  590. Assert.True (top.IsLoaded);
  591. Assert.True (subTop.IsLoaded);
  592. Assert.Equal (new (0, 0, 20, 10), view.Frame);
  593. view.Frame = new (1, 3, 10, 5);
  594. Assert.Equal (new (1, 3, 10, 5), view.Frame);
  595. Assert.Equal (new (0, 0, 10, 5), view._needsDisplayRect);
  596. view.Frame = new (1, 3, 10, 5);
  597. top.Layout ();
  598. Assert.Equal (new (1, 3, 10, 5), view.Frame);
  599. Assert.Equal (new (0, 0, 10, 5), view._needsDisplayRect);
  600. top.Dispose ();
  601. }
  602. [Fact]
  603. [AutoInitShutdown]
  604. public void Toplevel_Inside_ScrollView_MouseGrabView ()
  605. {
  606. var scrollView = new ScrollView
  607. {
  608. X = 3,
  609. Y = 3,
  610. Width = 40,
  611. Height = 16
  612. };
  613. scrollView.SetContentSize (new (200, 100));
  614. var win = new Window { X = 3, Y = 3, Width = Dim.Fill (3), Height = Dim.Fill (3), Arrangement = ViewArrangement.Movable };
  615. scrollView.Add (win);
  616. Toplevel top = new ();
  617. top.Add (scrollView);
  618. Application.Begin (top);
  619. Assert.Equal (new (0, 0, 80, 25), top.Frame);
  620. Assert.Equal (new (3, 3, 40, 16), scrollView.Frame);
  621. Assert.Equal (new (0, 0, 200, 100), scrollView.Subviews [0].Frame);
  622. Assert.Equal (new (3, 3, 194, 94), win.Frame);
  623. Application.RaiseMouseEvent (new () { ScreenPosition = new (6, 6), Flags = MouseFlags.Button1Pressed });
  624. Assert.Equal (win.Border, Application.MouseGrabView);
  625. Assert.Equal (new (3, 3, 194, 94), win.Frame);
  626. Application.RaiseMouseEvent (new () { ScreenPosition = new (9, 9), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition });
  627. Assert.Equal (win.Border, Application.MouseGrabView);
  628. top.SetNeedsLayout ();
  629. top.LayoutSubviews ();
  630. Assert.Equal (new (6, 6, 191, 91), win.Frame);
  631. Application.Refresh ();
  632. Application.RaiseMouseEvent (
  633. new ()
  634. {
  635. ScreenPosition = new (5, 5), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  636. });
  637. Assert.Equal (win.Border, Application.MouseGrabView);
  638. top.SetNeedsLayout ();
  639. top.LayoutSubviews ();
  640. Assert.Equal (new (2, 2, 195, 95), win.Frame);
  641. Application.Refresh ();
  642. Application.RaiseMouseEvent (new () { ScreenPosition = new (5, 5), Flags = MouseFlags.Button1Released });
  643. // ScrollView always grab the mouse when the container's subview OnMouseEnter don't want grab the mouse
  644. Assert.Equal (scrollView, Application.MouseGrabView);
  645. Application.RaiseMouseEvent (new () { ScreenPosition = new (4, 4), Flags = MouseFlags.ReportMousePosition });
  646. Assert.Equal (scrollView, Application.MouseGrabView);
  647. top.Dispose ();
  648. }
  649. [Fact]
  650. [AutoInitShutdown]
  651. public void Window_Viewport_Bigger_Than_Driver_Cols_And_Rows_Allow_Drag_Beyond_Left_Right_And_Bottom ()
  652. {
  653. Toplevel top = new ();
  654. var window = new Window { Width = 20, Height = 3, Arrangement = ViewArrangement.Movable };
  655. RunState rsTop = Application.Begin (top);
  656. ((FakeDriver)Application.Driver!).SetBufferSize (40, 10);
  657. RunState rsWindow = Application.Begin (window);
  658. Application.Refresh ();
  659. Assert.Equal (new (0, 0, 40, 10), top.Frame);
  660. Assert.Equal (new (0, 0, 20, 3), window.Frame);
  661. Assert.Null (Application.MouseGrabView);
  662. Application.RaiseMouseEvent (new () { ScreenPosition = new (0, 0), Flags = MouseFlags.Button1Pressed });
  663. Assert.Equal (window.Border, Application.MouseGrabView);
  664. Application.RaiseMouseEvent (
  665. new ()
  666. {
  667. ScreenPosition = new (-11, -4), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  668. });
  669. Application.Refresh ();
  670. Assert.Equal (new (0, 0, 40, 10), top.Frame);
  671. Assert.Equal (new (-11, -4, 20, 3), window.Frame);
  672. // Changes Top size to same size as Dialog more menu and scroll bar
  673. ((FakeDriver)Application.Driver!).SetBufferSize (20, 3);
  674. Application.RaiseMouseEvent (
  675. new ()
  676. {
  677. ScreenPosition = new (-1, -1), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  678. });
  679. Application.Refresh ();
  680. Assert.Equal (new (0, 0, 20, 3), top.Frame);
  681. Assert.Equal (new (-1, -1, 20, 3), window.Frame);
  682. // Changes Top size smaller than Dialog size
  683. ((FakeDriver)Application.Driver!).SetBufferSize (19, 2);
  684. Application.RaiseMouseEvent (
  685. new ()
  686. {
  687. ScreenPosition = new (-1, -1), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  688. });
  689. Application.Refresh ();
  690. Assert.Equal (new (0, 0, 19, 2), top.Frame);
  691. Assert.Equal (new (-1, -1, 20, 3), window.Frame);
  692. Application.RaiseMouseEvent (
  693. new ()
  694. {
  695. ScreenPosition = new (18, 1), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  696. });
  697. Application.Refresh ();
  698. Assert.Equal (new (0, 0, 19, 2), top.Frame);
  699. Assert.Equal (new (18, 1, 20, 3), window.Frame);
  700. // On a real app we can't go beyond the SuperView bounds
  701. Application.RaiseMouseEvent (
  702. new ()
  703. {
  704. ScreenPosition = new (19, 2), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  705. });
  706. Application.Refresh ();
  707. Assert.Equal (new (0, 0, 19, 2), top.Frame);
  708. Assert.Equal (new (19, 2, 20, 3), window.Frame);
  709. //TestHelpers.AssertDriverContentsWithFrameAre (@"", output);
  710. Application.End (rsWindow);
  711. Application.End (rsTop);
  712. top.Dispose ();
  713. }
  714. [Fact]
  715. [AutoInitShutdown]
  716. public void Modal_As_Top_Will_Drag_Cleanly ()
  717. {
  718. // Don't use Dialog as a Top, use a Window instead - dialog has complex layout behavior that is not needed here.
  719. var window = new Window { Width = 10, Height = 3, Arrangement = ViewArrangement.Movable };
  720. window.Add (
  721. new Label
  722. {
  723. X = Pos.Center (),
  724. Y = Pos.Center (),
  725. Width = Dim.Fill (),
  726. Height = Dim.Fill (),
  727. TextAlignment = Alignment.Center,
  728. VerticalTextAlignment = Alignment.Center,
  729. Text = "Test"
  730. }
  731. );
  732. RunState rs = Application.Begin (window);
  733. Assert.Null (Application.MouseGrabView);
  734. Assert.Equal (new (0, 0, 10, 3), window.Frame);
  735. Application.RaiseMouseEvent (new () { ScreenPosition = new (0, 0), Flags = MouseFlags.Button1Pressed });
  736. var firstIteration = false;
  737. Application.RunIteration (ref rs, firstIteration);
  738. Assert.Equal (window.Border, Application.MouseGrabView);
  739. Assert.Equal (new (0, 0, 10, 3), window.Frame);
  740. Application.RaiseMouseEvent (
  741. new ()
  742. {
  743. ScreenPosition = new (1, 1), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  744. });
  745. firstIteration = false;
  746. Application.RunIteration (ref rs, firstIteration);
  747. Assert.Equal (window.Border, Application.MouseGrabView);
  748. Assert.Equal (new (1, 1, 10, 3), window.Frame);
  749. Application.End (rs);
  750. window.Dispose ();
  751. }
  752. [Fact]
  753. [AutoInitShutdown]
  754. public void Begin_With_Window_Sets_Size_Correctly ()
  755. {
  756. Toplevel top = new ();
  757. RunState rsTop = Application.Begin (top);
  758. ((FakeDriver)Application.Driver!).SetBufferSize (20, 20);
  759. var testWindow = new Window { X = 2, Y = 1, Width = 15, Height = 10 };
  760. Assert.Equal (new (2, 1, 15, 10), testWindow.Frame);
  761. RunState rsTestWindow = Application.Begin (testWindow);
  762. Assert.Equal (new (2, 1, 15, 10), testWindow.Frame);
  763. Application.End (rsTestWindow);
  764. Application.End (rsTop);
  765. top.Dispose ();
  766. }
  767. // Don't use Dialog as a Top, use a Window instead - dialog has complex layout behavior that is not needed here.
  768. [Fact]
  769. [AutoInitShutdown]
  770. public void Draw_A_Top_Subview_On_A_Window ()
  771. {
  772. // Override CM
  773. Dialog.DefaultButtonAlignment = Alignment.Center;
  774. Dialog.DefaultBorderStyle = LineStyle.Single;
  775. Dialog.DefaultShadow = ShadowStyle.None;
  776. Button.DefaultShadow = ShadowStyle.None;
  777. Toplevel top = new ();
  778. var win = new Window ();
  779. top.Add (win);
  780. RunState rsTop = Application.Begin (top);
  781. ((FakeDriver)Application.Driver!).SetBufferSize (20, 20);
  782. Assert.Equal (new (0, 0, 20, 20), win.Frame);
  783. var btnPopup = new Button { Text = "Popup" };
  784. var testWindow = new Window { X = 2, Y = 1, Width = 15, Height = 10 };
  785. testWindow.Add (btnPopup);
  786. btnPopup.Accepting += (s, e) =>
  787. {
  788. Rectangle viewToScreen = btnPopup.ViewportToScreen (top.Frame);
  789. var viewAddedToTop = new View
  790. {
  791. Text = "viewAddedToTop",
  792. X = 1,
  793. Y = viewToScreen.Y + 1,
  794. Width = 18,
  795. Height = 16,
  796. BorderStyle = LineStyle.Single
  797. };
  798. Assert.Equal (testWindow, Application.Top);
  799. Application.Top!.DrawComplete += OnDrawContentComplete;
  800. top.Add (viewAddedToTop);
  801. void OnDrawContentComplete (object sender, EventArgs _)
  802. {
  803. Assert.Equal (new (1, 3, 18, 16), viewAddedToTop.Frame);
  804. viewAddedToTop.SetNeedsDisplay ();
  805. viewAddedToTop.Draw ();
  806. top.Move (2, 15);
  807. View.Driver.AddStr ("One");
  808. top.Move (2, 16);
  809. View.Driver.AddStr ("Two");
  810. top.Move (2, 17);
  811. View.Driver.AddStr ("Three");
  812. Application.Top!.DrawComplete -= OnDrawContentComplete;
  813. }
  814. };
  815. RunState rsTestWindow = Application.Begin (testWindow);
  816. Assert.Equal (new (2, 1, 15, 10), testWindow.Frame);
  817. Application.RaiseMouseEvent (new () { ScreenPosition = new (5, 2), Flags = MouseFlags.Button1Clicked });
  818. Application.Refresh ();
  819. TestHelpers.AssertDriverContentsWithFrameAre (
  820. @$"
  821. ┌──────────────────┐
  822. │ ┌─────────────┐ │
  823. │ │{CM.Glyphs.LeftBracket} Popup {CM.Glyphs.RightBracket} │ │
  824. │┌────────────────┐│
  825. ││viewAddedToTop ││
  826. ││ ││
  827. ││ ││
  828. ││ ││
  829. ││ ││
  830. ││ ││
  831. ││ ││
  832. ││ ││
  833. ││ ││
  834. ││ ││
  835. ││ ││
  836. ││One ││
  837. ││Two ││
  838. ││Three ││
  839. │└────────────────┘│
  840. └──────────────────┘",
  841. output
  842. );
  843. Application.End (rsTestWindow);
  844. Application.End (rsTop);
  845. top.Dispose ();
  846. }
  847. private void OnDrawContentComplete (object sender, DrawEventArgs e) { throw new NotImplementedException (); }
  848. [Fact]
  849. [AutoInitShutdown]
  850. public void Activating_MenuBar_By_Alt_Key_Does_Not_Throw ()
  851. {
  852. var menu = new MenuBar
  853. {
  854. Menus =
  855. [
  856. new ("Child", new MenuItem [] { new ("_Create Child", "", null) })
  857. ]
  858. };
  859. var topChild = new Toplevel ();
  860. topChild.Add (menu);
  861. var top = new Toplevel ();
  862. top.Add (topChild);
  863. Application.Begin (top);
  864. Exception exception = Record.Exception (() => topChild.NewKeyDownEvent (KeyCode.AltMask));
  865. Assert.Null (exception);
  866. top.Dispose ();
  867. }
  868. [Fact]
  869. [TestRespondersDisposed]
  870. public void Multi_Thread_Toplevels ()
  871. {
  872. Application.Init (new FakeDriver ());
  873. Toplevel t = new ();
  874. var w = new Window ();
  875. t.Add (w);
  876. int count = 0, count1 = 0, count2 = 0;
  877. bool log = false, log1 = false, log2 = false;
  878. var fromTopStillKnowFirstIsRunning = false;
  879. var fromTopStillKnowSecondIsRunning = false;
  880. var fromFirstStillKnowSecondIsRunning = false;
  881. Application.AddTimeout (
  882. TimeSpan.FromMilliseconds (100),
  883. () =>
  884. {
  885. count++;
  886. if (count1 == 5)
  887. {
  888. log1 = true;
  889. }
  890. if (count1 == 14 && count2 == 10 && count == 15)
  891. {
  892. // count2 is already stopped
  893. fromTopStillKnowFirstIsRunning = true;
  894. }
  895. if (count1 == 7 && count2 == 7 && count == 8)
  896. {
  897. fromTopStillKnowSecondIsRunning = true;
  898. }
  899. if (count == 30)
  900. {
  901. Assert.Equal (30, count);
  902. Assert.Equal (20, count1);
  903. Assert.Equal (10, count2);
  904. Assert.True (log);
  905. Assert.True (log1);
  906. Assert.True (log2);
  907. Assert.True (fromTopStillKnowFirstIsRunning);
  908. Assert.True (fromTopStillKnowSecondIsRunning);
  909. Assert.True (fromFirstStillKnowSecondIsRunning);
  910. Application.RequestStop ();
  911. return false;
  912. }
  913. return true;
  914. }
  915. );
  916. t.Ready += FirstWindow;
  917. void FirstWindow (object sender, EventArgs args)
  918. {
  919. var firstWindow = new Window ();
  920. firstWindow.Ready += SecondWindow;
  921. Application.AddTimeout (
  922. TimeSpan.FromMilliseconds (100),
  923. () =>
  924. {
  925. count1++;
  926. if (count2 == 5)
  927. {
  928. log2 = true;
  929. }
  930. if (count2 == 4 && count1 == 5 && count == 5)
  931. {
  932. fromFirstStillKnowSecondIsRunning = true;
  933. }
  934. if (count1 == 20)
  935. {
  936. Assert.Equal (20, count1);
  937. Application.RequestStop ();
  938. return false;
  939. }
  940. return true;
  941. }
  942. );
  943. Application.Run (firstWindow);
  944. firstWindow.Dispose ();
  945. }
  946. void SecondWindow (object sender, EventArgs args)
  947. {
  948. var testWindow = new Window ();
  949. Application.AddTimeout (
  950. TimeSpan.FromMilliseconds (100),
  951. () =>
  952. {
  953. count2++;
  954. if (count < 30)
  955. {
  956. log = true;
  957. }
  958. if (count2 == 10)
  959. {
  960. Assert.Equal (10, count2);
  961. Application.RequestStop ();
  962. return false;
  963. }
  964. return true;
  965. }
  966. );
  967. Application.Run (testWindow);
  968. testWindow.Dispose ();
  969. }
  970. Application.Run (t);
  971. t.Dispose ();
  972. Application.Shutdown ();
  973. }
  974. [Fact]
  975. public void Remove_Do_Not_Dispose_MenuBar_Or_StatusBar ()
  976. {
  977. var mb = new MenuBar ();
  978. var sb = new StatusBar ();
  979. var tl = new Toplevel ();
  980. #if DEBUG
  981. Assert.False (mb.WasDisposed);
  982. Assert.False (sb.WasDisposed);
  983. #endif
  984. tl.Add (mb, sb);
  985. Assert.NotNull (tl.MenuBar);
  986. //Assert.NotNull (tl.StatusBar);
  987. #if DEBUG
  988. Assert.False (mb.WasDisposed);
  989. Assert.False (sb.WasDisposed);
  990. #endif
  991. tl.RemoveAll ();
  992. Assert.Null (tl.MenuBar);
  993. //Assert.Null (tl.StatusBar);
  994. #if DEBUG
  995. Assert.False (mb.WasDisposed);
  996. Assert.False (sb.WasDisposed);
  997. #endif
  998. }
  999. }