ToplevelTests.cs 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  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.LayoutAndDraw ();
  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.LayoutAndDraw ();
  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.LayoutAndDraw ();
  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._needsDrawRect);
  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._needsDrawRect);
  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._needsDrawRect);
  600. top.Dispose ();
  601. }
  602. [Fact]
  603. [AutoInitShutdown]
  604. public void Window_Viewport_Bigger_Than_Driver_Cols_And_Rows_Allow_Drag_Beyond_Left_Right_And_Bottom ()
  605. {
  606. Toplevel top = new ();
  607. var window = new Window { Width = 20, Height = 3, Arrangement = ViewArrangement.Movable };
  608. RunState rsTop = Application.Begin (top);
  609. ((FakeDriver)Application.Driver!).SetBufferSize (40, 10);
  610. RunState rsWindow = Application.Begin (window);
  611. Application.LayoutAndDraw ();
  612. Assert.Equal (new (0, 0, 40, 10), top.Frame);
  613. Assert.Equal (new (0, 0, 20, 3), window.Frame);
  614. Assert.Null (Application.MouseGrabView);
  615. Application.RaiseMouseEvent (new () { ScreenPosition = new (0, 0), Flags = MouseFlags.Button1Pressed });
  616. Assert.Equal (window.Border, Application.MouseGrabView);
  617. Application.RaiseMouseEvent (
  618. new ()
  619. {
  620. ScreenPosition = new (-11, -4), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  621. });
  622. Application.LayoutAndDraw ();
  623. Assert.Equal (new (0, 0, 40, 10), top.Frame);
  624. Assert.Equal (new (-11, -4, 20, 3), window.Frame);
  625. // Changes Top size to same size as Dialog more menu and scroll bar
  626. ((FakeDriver)Application.Driver!).SetBufferSize (20, 3);
  627. Application.RaiseMouseEvent (
  628. new ()
  629. {
  630. ScreenPosition = new (-1, -1), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  631. });
  632. Application.LayoutAndDraw ();
  633. Assert.Equal (new (0, 0, 20, 3), top.Frame);
  634. Assert.Equal (new (-1, -1, 20, 3), window.Frame);
  635. // Changes Top size smaller than Dialog size
  636. ((FakeDriver)Application.Driver!).SetBufferSize (19, 2);
  637. Application.RaiseMouseEvent (
  638. new ()
  639. {
  640. ScreenPosition = new (-1, -1), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  641. });
  642. Application.LayoutAndDraw ();
  643. Assert.Equal (new (0, 0, 19, 2), top.Frame);
  644. Assert.Equal (new (-1, -1, 20, 3), window.Frame);
  645. Application.RaiseMouseEvent (
  646. new ()
  647. {
  648. ScreenPosition = new (18, 1), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  649. });
  650. Application.LayoutAndDraw ();
  651. Assert.Equal (new (0, 0, 19, 2), top.Frame);
  652. Assert.Equal (new (18, 1, 20, 3), window.Frame);
  653. // On a real app we can't go beyond the SuperView bounds
  654. Application.RaiseMouseEvent (
  655. new ()
  656. {
  657. ScreenPosition = new (19, 2), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  658. });
  659. Application.LayoutAndDraw ();
  660. Assert.Equal (new (0, 0, 19, 2), top.Frame);
  661. Assert.Equal (new (19, 2, 20, 3), window.Frame);
  662. //TestHelpers.AssertDriverContentsWithFrameAre (@"", output);
  663. Application.End (rsWindow);
  664. Application.End (rsTop);
  665. top.Dispose ();
  666. }
  667. [Fact]
  668. [AutoInitShutdown]
  669. public void Modal_As_Top_Will_Drag_Cleanly ()
  670. {
  671. // Don't use Dialog as a Top, use a Window instead - dialog has complex layout behavior that is not needed here.
  672. var window = new Window { Width = 10, Height = 3, Arrangement = ViewArrangement.Movable };
  673. window.Add (
  674. new Label
  675. {
  676. X = Pos.Center (),
  677. Y = Pos.Center (),
  678. Width = Dim.Fill (),
  679. Height = Dim.Fill (),
  680. TextAlignment = Alignment.Center,
  681. VerticalTextAlignment = Alignment.Center,
  682. Text = "Test"
  683. }
  684. );
  685. RunState rs = Application.Begin (window);
  686. Assert.Null (Application.MouseGrabView);
  687. Assert.Equal (new (0, 0, 10, 3), window.Frame);
  688. Application.RaiseMouseEvent (new () { ScreenPosition = new (0, 0), Flags = MouseFlags.Button1Pressed });
  689. var firstIteration = false;
  690. Application.RunIteration (ref rs, firstIteration);
  691. Assert.Equal (window.Border, Application.MouseGrabView);
  692. Assert.Equal (new (0, 0, 10, 3), window.Frame);
  693. Application.RaiseMouseEvent (
  694. new ()
  695. {
  696. ScreenPosition = new (1, 1), Flags = MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition
  697. });
  698. firstIteration = false;
  699. Application.RunIteration (ref rs, firstIteration);
  700. Assert.Equal (window.Border, Application.MouseGrabView);
  701. Assert.Equal (new (1, 1, 10, 3), window.Frame);
  702. Application.End (rs);
  703. window.Dispose ();
  704. }
  705. [Fact]
  706. [AutoInitShutdown]
  707. public void Begin_With_Window_Sets_Size_Correctly ()
  708. {
  709. Toplevel top = new ();
  710. RunState rsTop = Application.Begin (top);
  711. ((FakeDriver)Application.Driver!).SetBufferSize (20, 20);
  712. var testWindow = new Window { X = 2, Y = 1, Width = 15, Height = 10 };
  713. Assert.Equal (new (2, 1, 15, 10), testWindow.Frame);
  714. RunState rsTestWindow = Application.Begin (testWindow);
  715. Assert.Equal (new (2, 1, 15, 10), testWindow.Frame);
  716. Application.End (rsTestWindow);
  717. Application.End (rsTop);
  718. top.Dispose ();
  719. }
  720. [Fact]
  721. [AutoInitShutdown]
  722. public void Activating_MenuBar_By_Alt_Key_Does_Not_Throw ()
  723. {
  724. var menu = new MenuBar
  725. {
  726. Menus =
  727. [
  728. new ("Child", new MenuItem [] { new ("_Create Child", "", null) })
  729. ]
  730. };
  731. var topChild = new Toplevel ();
  732. topChild.Add (menu);
  733. var top = new Toplevel ();
  734. top.Add (topChild);
  735. Application.Begin (top);
  736. Exception exception = Record.Exception (() => topChild.NewKeyDownEvent (KeyCode.AltMask));
  737. Assert.Null (exception);
  738. top.Dispose ();
  739. }
  740. [Fact]
  741. [TestRespondersDisposed]
  742. public void Multi_Thread_Toplevels ()
  743. {
  744. Application.Init (new FakeDriver ());
  745. Toplevel t = new ();
  746. var w = new Window ();
  747. t.Add (w);
  748. int count = 0, count1 = 0, count2 = 0;
  749. bool log = false, log1 = false, log2 = false;
  750. var fromTopStillKnowFirstIsRunning = false;
  751. var fromTopStillKnowSecondIsRunning = false;
  752. var fromFirstStillKnowSecondIsRunning = false;
  753. Application.AddTimeout (
  754. TimeSpan.FromMilliseconds (100),
  755. () =>
  756. {
  757. count++;
  758. if (count1 == 5)
  759. {
  760. log1 = true;
  761. }
  762. if (count1 == 14 && count2 == 10 && count == 15)
  763. {
  764. // count2 is already stopped
  765. fromTopStillKnowFirstIsRunning = true;
  766. }
  767. if (count1 == 7 && count2 == 7 && count == 8)
  768. {
  769. fromTopStillKnowSecondIsRunning = true;
  770. }
  771. if (count == 30)
  772. {
  773. Assert.Equal (30, count);
  774. Assert.Equal (20, count1);
  775. Assert.Equal (10, count2);
  776. Assert.True (log);
  777. Assert.True (log1);
  778. Assert.True (log2);
  779. Assert.True (fromTopStillKnowFirstIsRunning);
  780. Assert.True (fromTopStillKnowSecondIsRunning);
  781. Assert.True (fromFirstStillKnowSecondIsRunning);
  782. Application.RequestStop ();
  783. return false;
  784. }
  785. return true;
  786. }
  787. );
  788. t.Ready += FirstWindow;
  789. void FirstWindow (object sender, EventArgs args)
  790. {
  791. var firstWindow = new Window ();
  792. firstWindow.Ready += SecondWindow;
  793. Application.AddTimeout (
  794. TimeSpan.FromMilliseconds (100),
  795. () =>
  796. {
  797. count1++;
  798. if (count2 == 5)
  799. {
  800. log2 = true;
  801. }
  802. if (count2 == 4 && count1 == 5 && count == 5)
  803. {
  804. fromFirstStillKnowSecondIsRunning = true;
  805. }
  806. if (count1 == 20)
  807. {
  808. Assert.Equal (20, count1);
  809. Application.RequestStop ();
  810. return false;
  811. }
  812. return true;
  813. }
  814. );
  815. Application.Run (firstWindow);
  816. firstWindow.Dispose ();
  817. }
  818. void SecondWindow (object sender, EventArgs args)
  819. {
  820. var testWindow = new Window ();
  821. Application.AddTimeout (
  822. TimeSpan.FromMilliseconds (100),
  823. () =>
  824. {
  825. count2++;
  826. if (count < 30)
  827. {
  828. log = true;
  829. }
  830. if (count2 == 10)
  831. {
  832. Assert.Equal (10, count2);
  833. Application.RequestStop ();
  834. return false;
  835. }
  836. return true;
  837. }
  838. );
  839. Application.Run (testWindow);
  840. testWindow.Dispose ();
  841. }
  842. Application.Run (t);
  843. t.Dispose ();
  844. Application.Shutdown ();
  845. }
  846. [Fact]
  847. public void Remove_Do_Not_Dispose_MenuBar_Or_StatusBar ()
  848. {
  849. var mb = new MenuBar ();
  850. var sb = new StatusBar ();
  851. var tl = new Toplevel ();
  852. #if DEBUG
  853. Assert.False (mb.WasDisposed);
  854. Assert.False (sb.WasDisposed);
  855. #endif
  856. tl.Add (mb, sb);
  857. Assert.NotNull (tl.MenuBar);
  858. //Assert.NotNull (tl.StatusBar);
  859. #if DEBUG
  860. Assert.False (mb.WasDisposed);
  861. Assert.False (sb.WasDisposed);
  862. #endif
  863. tl.RemoveAll ();
  864. Assert.Null (tl.MenuBar);
  865. //Assert.Null (tl.StatusBar);
  866. #if DEBUG
  867. Assert.False (mb.WasDisposed);
  868. Assert.False (sb.WasDisposed);
  869. #endif
  870. }
  871. }