ColorPickerTests.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. using UnitTests;
  2. namespace Terminal.Gui.ViewsTests;
  3. public class ColorPickerTests
  4. {
  5. [Fact]
  6. [SetupFakeDriver]
  7. public void ColorPicker_ChangeValueOnUI_UpdatesAllUIElements ()
  8. {
  9. ColorPicker cp = GetColorPicker (ColorModel.RGB, true);
  10. var otherView = new View { CanFocus = true };
  11. Application.Top?.Add (otherView); // thi sets focus to otherView
  12. Assert.True (otherView.HasFocus);
  13. cp.SetFocus ();
  14. Assert.False (otherView.HasFocus);
  15. cp.Draw ();
  16. ColorBar r = GetColorBar (cp, ColorPickerPart.Bar1);
  17. ColorBar g = GetColorBar (cp, ColorPickerPart.Bar2);
  18. ColorBar b = GetColorBar (cp, ColorPickerPart.Bar3);
  19. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  20. TextField rTextField = GetTextField (cp, ColorPickerPart.Bar1);
  21. TextField gTextField = GetTextField (cp, ColorPickerPart.Bar2);
  22. TextField bTextField = GetTextField (cp, ColorPickerPart.Bar3);
  23. Assert.Equal ("R:", r.Text);
  24. Assert.Equal (2, r.TrianglePosition);
  25. Assert.Equal ("0", rTextField.Text);
  26. Assert.Equal ("G:", g.Text);
  27. Assert.Equal (2, g.TrianglePosition);
  28. Assert.Equal ("0", gTextField.Text);
  29. Assert.Equal ("B:", b.Text);
  30. Assert.Equal (2, b.TrianglePosition);
  31. Assert.Equal ("0", bTextField.Text);
  32. Assert.Equal ("#000000", hex.Text);
  33. // Change value using text field
  34. TextField rBarTextField = cp.SubViews.OfType<TextField> ().First (tf => tf.Text == "0");
  35. rBarTextField.SetFocus ();
  36. rBarTextField.Text = "128";
  37. otherView.SetFocus ();
  38. Assert.True (otherView.HasFocus);
  39. cp.Draw ();
  40. Assert.Equal ("R:", r.Text);
  41. Assert.Equal (9, r.TrianglePosition);
  42. Assert.Equal ("128", rTextField.Text);
  43. Assert.Equal ("G:", g.Text);
  44. Assert.Equal (2, g.TrianglePosition);
  45. Assert.Equal ("0", gTextField.Text);
  46. Assert.Equal ("B:", b.Text);
  47. Assert.Equal (2, b.TrianglePosition);
  48. Assert.Equal ("0", bTextField.Text);
  49. Assert.Equal ("#800000", hex.Text);
  50. Application.Top?.Dispose ();
  51. Application.ResetState();
  52. }
  53. [Fact]
  54. [SetupFakeDriver]
  55. public void ColorPicker_ClickingAtEndOfBar_SetsMaxValue ()
  56. {
  57. ColorPicker cp = GetColorPicker (ColorModel.RGB, false);
  58. cp.Draw ();
  59. // Click at the end of the Red bar
  60. cp.Focused.RaiseMouseEvent (
  61. new ()
  62. {
  63. Flags = MouseFlags.Button1Pressed,
  64. Position = new (19, 0) // Assuming 0-based indexing
  65. });
  66. cp.Draw ();
  67. ColorBar r = GetColorBar (cp, ColorPickerPart.Bar1);
  68. ColorBar g = GetColorBar (cp, ColorPickerPart.Bar2);
  69. ColorBar b = GetColorBar (cp, ColorPickerPart.Bar3);
  70. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  71. Assert.Equal ("R:", r.Text);
  72. Assert.Equal (19, r.TrianglePosition);
  73. Assert.Equal ("G:", g.Text);
  74. Assert.Equal (2, g.TrianglePosition);
  75. Assert.Equal ("B:", b.Text);
  76. Assert.Equal (2, b.TrianglePosition);
  77. Assert.Equal ("#FF0000", hex.Text);
  78. Application.Top?.Dispose ();
  79. Application.ResetState ();
  80. }
  81. [Fact]
  82. [SetupFakeDriver]
  83. public void ColorPicker_ClickingBeyondBar_ChangesToMaxValue ()
  84. {
  85. ColorPicker cp = GetColorPicker (ColorModel.RGB, false);
  86. cp.Draw ();
  87. // Click beyond the bar
  88. cp.Focused.RaiseMouseEvent (
  89. new ()
  90. {
  91. Flags = MouseFlags.Button1Pressed,
  92. Position = new (21, 0) // Beyond the bar
  93. });
  94. cp.Draw ();
  95. ColorBar r = GetColorBar (cp, ColorPickerPart.Bar1);
  96. ColorBar g = GetColorBar (cp, ColorPickerPart.Bar2);
  97. ColorBar b = GetColorBar (cp, ColorPickerPart.Bar3);
  98. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  99. Assert.Equal ("R:", r.Text);
  100. Assert.Equal (19, r.TrianglePosition);
  101. Assert.Equal ("G:", g.Text);
  102. Assert.Equal (2, g.TrianglePosition);
  103. Assert.Equal ("B:", b.Text);
  104. Assert.Equal (2, b.TrianglePosition);
  105. Assert.Equal ("#FF0000", hex.Text);
  106. Application.Top?.Dispose ();
  107. Application.ResetState ();
  108. }
  109. [Fact]
  110. [SetupFakeDriver]
  111. public void ColorPicker_ClickingDifferentBars_ChangesFocus ()
  112. {
  113. ColorPicker cp = GetColorPicker (ColorModel.RGB, false);
  114. cp.Draw ();
  115. // Click on Green bar
  116. Application.RaiseMouseEvent (
  117. new ()
  118. {
  119. Flags = MouseFlags.Button1Pressed,
  120. ScreenPosition = new (0, 1)
  121. });
  122. //cp.SubViews.OfType<GBar> ()
  123. // .Single ()
  124. // .OnMouseEvent (
  125. // new ()
  126. // {
  127. // Flags = MouseFlags.Button1Pressed,
  128. // Position = new (0, 1)
  129. // });
  130. cp.Draw ();
  131. Assert.IsAssignableFrom<GBar> (cp.Focused);
  132. // Click on Blue bar
  133. Application.RaiseMouseEvent (
  134. new ()
  135. {
  136. Flags = MouseFlags.Button1Pressed,
  137. ScreenPosition = new (0, 2)
  138. });
  139. //cp.SubViews.OfType<BBar> ()
  140. // .Single ()
  141. // .OnMouseEvent (
  142. // new ()
  143. // {
  144. // Flags = MouseFlags.Button1Pressed,
  145. // Position = new (0, 2)
  146. // });
  147. cp.Draw ();
  148. Assert.IsAssignableFrom<BBar> (cp.Focused);
  149. Application.Top?.Dispose ();
  150. Application.ResetState ();
  151. }
  152. [Fact]
  153. [SetupFakeDriver]
  154. public void ColorPicker_Construct_DefaultValue ()
  155. {
  156. ColorPicker cp = GetColorPicker (ColorModel.HSV, false);
  157. // Should be only a single text field (Hex) because ShowTextFields is false
  158. Assert.Single (cp.SubViews.OfType<TextField> ());
  159. cp.Draw ();
  160. // All bars should be at 0 with the triangle at 0 (+2 because of "H:", "S:" etc)
  161. ColorBar h = GetColorBar (cp, ColorPickerPart.Bar1);
  162. Assert.Equal ("H:", h.Text);
  163. Assert.Equal (2, h.TrianglePosition);
  164. Assert.IsType<HueBar> (h);
  165. ColorBar s = GetColorBar (cp, ColorPickerPart.Bar2);
  166. Assert.Equal ("S:", s.Text);
  167. Assert.Equal (2, s.TrianglePosition);
  168. Assert.IsType<SaturationBar> (s);
  169. ColorBar v = GetColorBar (cp, ColorPickerPart.Bar3);
  170. Assert.Equal ("V:", v.Text);
  171. Assert.Equal (2, v.TrianglePosition);
  172. Assert.IsType<ValueBar> (v);
  173. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  174. Assert.Equal ("#000000", hex.Text);
  175. }
  176. [Fact]
  177. [SetupFakeDriver]
  178. public void ColorPicker_DisposesOldViews_OnModelChange ()
  179. {
  180. ColorPicker cp = GetColorPicker (ColorModel.HSL, true);
  181. ColorBar b1 = GetColorBar (cp, ColorPickerPart.Bar1);
  182. ColorBar b2 = GetColorBar (cp, ColorPickerPart.Bar2);
  183. ColorBar b3 = GetColorBar (cp, ColorPickerPart.Bar3);
  184. TextField tf1 = GetTextField (cp, ColorPickerPart.Bar1);
  185. TextField tf2 = GetTextField (cp, ColorPickerPart.Bar2);
  186. TextField tf3 = GetTextField (cp, ColorPickerPart.Bar3);
  187. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  188. #if DEBUG_IDISPOSABLE
  189. Assert.All (new View [] { b1, b2, b3, tf1, tf2, tf3, hex }, b => Assert.False (b.WasDisposed));
  190. #endif
  191. cp.Style.ColorModel = ColorModel.RGB;
  192. cp.ApplyStyleChanges ();
  193. ColorBar b1After = GetColorBar (cp, ColorPickerPart.Bar1);
  194. ColorBar b2After = GetColorBar (cp, ColorPickerPart.Bar2);
  195. ColorBar b3After = GetColorBar (cp, ColorPickerPart.Bar3);
  196. TextField tf1After = GetTextField (cp, ColorPickerPart.Bar1);
  197. TextField tf2After = GetTextField (cp, ColorPickerPart.Bar2);
  198. TextField tf3After = GetTextField (cp, ColorPickerPart.Bar3);
  199. TextField hexAfter = GetTextField (cp, ColorPickerPart.Hex);
  200. // Old bars should be disposed
  201. #if DEBUG_IDISPOSABLE
  202. Assert.All (new View [] { b1, b2, b3, tf1, tf2, tf3, hex }, b => Assert.True (b.WasDisposed));
  203. #endif
  204. Assert.NotSame (hex, hexAfter);
  205. Assert.NotSame (b1, b1After);
  206. Assert.NotSame (b2, b2After);
  207. Assert.NotSame (b3, b3After);
  208. Assert.NotSame (tf1, tf1After);
  209. Assert.NotSame (tf2, tf2After);
  210. Assert.NotSame (tf3, tf3After);
  211. }
  212. [Fact]
  213. [SetupFakeDriver]
  214. public void ColorPicker_EnterHexFor_ColorName ()
  215. {
  216. ColorPicker cp = GetColorPicker (ColorModel.RGB, true, true);
  217. cp.Draw ();
  218. TextField name = GetTextField (cp, ColorPickerPart.ColorName);
  219. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  220. hex.SetFocus ();
  221. Assert.True (hex.HasFocus);
  222. Assert.Same (hex, cp.Focused);
  223. hex.Text = "";
  224. name.Text = "";
  225. Assert.Empty (hex.Text);
  226. Assert.Empty (name.Text);
  227. Application.RaiseKeyDownEvent ('#');
  228. Assert.Empty (name.Text);
  229. //7FFFD4
  230. Assert.Equal ("#", hex.Text);
  231. Application.RaiseKeyDownEvent ('7');
  232. Application.RaiseKeyDownEvent ('F');
  233. Application.RaiseKeyDownEvent ('F');
  234. Application.RaiseKeyDownEvent ('F');
  235. Application.RaiseKeyDownEvent ('D');
  236. Assert.Empty (name.Text);
  237. Application.RaiseKeyDownEvent ('4');
  238. Assert.True (hex.HasFocus);
  239. // Tab out of the hex field - should wrap to first focusable subview
  240. Application.RaiseKeyDownEvent (Key.Tab);
  241. Assert.False (hex.HasFocus);
  242. Assert.NotSame (hex, cp.Focused);
  243. // Color name should be recognised as a known string and populated
  244. Assert.Equal ("#7FFFD4", hex.Text);
  245. Assert.Equal ("Aquamarine", name.Text);
  246. Application.Top?.Dispose ();
  247. Application.ResetState (true);
  248. }
  249. /// <summary>
  250. /// In this version we use the Enter button to accept the typed text instead
  251. /// of tabbing to the next view.
  252. /// </summary>
  253. [Fact]
  254. [SetupFakeDriver]
  255. public void ColorPicker_EnterHexFor_ColorName_AcceptVariation ()
  256. {
  257. ColorPicker cp = GetColorPicker (ColorModel.RGB, true, true);
  258. cp.Draw ();
  259. TextField name = GetTextField (cp, ColorPickerPart.ColorName);
  260. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  261. hex.SetFocus ();
  262. Assert.True (hex.HasFocus);
  263. Assert.Same (hex, cp.Focused);
  264. hex.Text = "";
  265. name.Text = "";
  266. Assert.Empty (hex.Text);
  267. Assert.Empty (name.Text);
  268. Application.RaiseKeyDownEvent ('#');
  269. Assert.Empty (name.Text);
  270. //7FFFD4
  271. Assert.Equal ("#", hex.Text);
  272. Application.RaiseKeyDownEvent ('7');
  273. Application.RaiseKeyDownEvent ('F');
  274. Application.RaiseKeyDownEvent ('F');
  275. Application.RaiseKeyDownEvent ('F');
  276. Application.RaiseKeyDownEvent ('D');
  277. Assert.Empty (name.Text);
  278. Application.RaiseKeyDownEvent ('4');
  279. Assert.True (hex.HasFocus);
  280. // Should stay in the hex field (because accept not tab)
  281. Application.RaiseKeyDownEvent (Key.Enter);
  282. Assert.True (hex.HasFocus);
  283. Assert.Same (hex, cp.Focused);
  284. // But still, Color name should be recognised as a known string and populated
  285. Assert.Equal ("#7FFFD4", hex.Text);
  286. Assert.Equal ("Aquamarine", name.Text);
  287. Application.Top?.Dispose ();
  288. Application.ResetState (true);
  289. }
  290. [Fact]
  291. [SetupFakeDriver]
  292. public void ColorPicker_InvalidHexInput_DoesNotChangeColor ()
  293. {
  294. ColorPicker cp = GetColorPicker (ColorModel.RGB, true);
  295. cp.Draw ();
  296. // Enter invalid hex value
  297. TextField hexField = cp.SubViews.OfType<TextField> ().First (tf => tf.Text == "#000000");
  298. hexField.SetFocus ();
  299. hexField.Text = "#ZZZZZZ";
  300. Assert.True (hexField.HasFocus);
  301. Assert.Equal ("#ZZZZZZ", hexField.Text);
  302. ColorBar r = GetColorBar (cp, ColorPickerPart.Bar1);
  303. ColorBar g = GetColorBar (cp, ColorPickerPart.Bar2);
  304. ColorBar b = GetColorBar (cp, ColorPickerPart.Bar3);
  305. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  306. Assert.Equal ("#ZZZZZZ", hex.Text);
  307. // Advance away from hexField to cause validation
  308. cp.AdvanceFocus (NavigationDirection.Forward, null);
  309. cp.Draw ();
  310. Assert.Equal ("R:", r.Text);
  311. Assert.Equal (2, r.TrianglePosition);
  312. Assert.Equal ("G:", g.Text);
  313. Assert.Equal (2, g.TrianglePosition);
  314. Assert.Equal ("B:", b.Text);
  315. Assert.Equal (2, b.TrianglePosition);
  316. Assert.Equal ("#000000", hex.Text);
  317. Application.Top?.Dispose ();
  318. Application.ResetState (true);
  319. }
  320. [Fact]
  321. [SetupFakeDriver]
  322. public void ColorPicker_RGB_KeyboardNavigation ()
  323. {
  324. ColorPicker cp = GetColorPicker (ColorModel.RGB, false);
  325. cp.Draw ();
  326. ColorBar r = GetColorBar (cp, ColorPickerPart.Bar1);
  327. ColorBar g = GetColorBar (cp, ColorPickerPart.Bar2);
  328. ColorBar b = GetColorBar (cp, ColorPickerPart.Bar3);
  329. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  330. Assert.Equal ("R:", r.Text);
  331. Assert.Equal (2, r.TrianglePosition);
  332. Assert.IsType<RBar> (r);
  333. Assert.Equal ("G:", g.Text);
  334. Assert.Equal (2, g.TrianglePosition);
  335. Assert.IsType<GBar> (g);
  336. Assert.Equal ("B:", b.Text);
  337. Assert.Equal (2, b.TrianglePosition);
  338. Assert.IsType<BBar> (b);
  339. Assert.Equal ("#000000", hex.Text);
  340. Assert.IsAssignableFrom<IColorBar> (cp.Focused);
  341. cp.Draw ();
  342. Application.RaiseKeyDownEvent (Key.CursorRight);
  343. cp.Draw ();
  344. Assert.Equal (3, r.TrianglePosition);
  345. Assert.Equal ("#0F0000", hex.Text);
  346. Application.RaiseKeyDownEvent (Key.CursorRight);
  347. cp.Draw ();
  348. Assert.Equal (4, r.TrianglePosition);
  349. Assert.Equal ("#1E0000", hex.Text);
  350. // Use cursor to move the triangle all the way to the right
  351. for (var i = 0; i < 1000; i++)
  352. {
  353. Application.RaiseKeyDownEvent (Key.CursorRight);
  354. }
  355. cp.Draw ();
  356. // 20 width and TrianglePosition is 0 indexed
  357. // Meaning we are asserting that triangle is at end
  358. Assert.Equal (19, r.TrianglePosition);
  359. Assert.Equal ("#FF0000", hex.Text);
  360. Application.Top.Dispose ();
  361. Application.ResetState (true);
  362. }
  363. [Fact]
  364. [SetupFakeDriver]
  365. public void ColorPicker_RGB_MouseNavigation ()
  366. {
  367. ColorPicker cp = GetColorPicker (ColorModel.RGB, false);
  368. cp.Draw ();
  369. ColorBar r = GetColorBar (cp, ColorPickerPart.Bar1);
  370. ColorBar g = GetColorBar (cp, ColorPickerPart.Bar2);
  371. ColorBar b = GetColorBar (cp, ColorPickerPart.Bar3);
  372. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  373. Assert.Equal ("R:", r.Text);
  374. Assert.Equal (2, r.TrianglePosition);
  375. Assert.IsType<RBar> (r);
  376. Assert.Equal ("G:", g.Text);
  377. Assert.Equal (2, g.TrianglePosition);
  378. Assert.IsType<GBar> (g);
  379. Assert.Equal ("B:", b.Text);
  380. Assert.Equal (2, b.TrianglePosition);
  381. Assert.IsType<BBar> (b);
  382. Assert.Equal ("#000000", hex.Text);
  383. Assert.IsAssignableFrom<IColorBar> (cp.Focused);
  384. cp.Focused.RaiseMouseEvent (
  385. new ()
  386. {
  387. Flags = MouseFlags.Button1Pressed,
  388. Position = new (3, 0)
  389. });
  390. cp.Draw ();
  391. Assert.Equal (3, r.TrianglePosition);
  392. Assert.Equal ("#0F0000", hex.Text);
  393. cp.Focused.RaiseMouseEvent (
  394. new ()
  395. {
  396. Flags = MouseFlags.Button1Pressed,
  397. Position = new (4, 0)
  398. });
  399. cp.Draw ();
  400. Assert.Equal (4, r.TrianglePosition);
  401. Assert.Equal ("#1E0000", hex.Text);
  402. Application.Top?.Dispose ();
  403. Application.ResetState (true);
  404. }
  405. [Theory]
  406. [SetupFakeDriver]
  407. [MemberData (nameof (ColorPickerTestData))]
  408. public void ColorPicker_RGB_NoText (
  409. Color c,
  410. string expectedR,
  411. int expectedRTriangle,
  412. string expectedG,
  413. int expectedGTriangle,
  414. string expectedB,
  415. int expectedBTriangle,
  416. string expectedHex
  417. )
  418. {
  419. ColorPicker cp = GetColorPicker (ColorModel.RGB, false);
  420. cp.SelectedColor = c;
  421. cp.Draw ();
  422. ColorBar r = GetColorBar (cp, ColorPickerPart.Bar1);
  423. ColorBar g = GetColorBar (cp, ColorPickerPart.Bar2);
  424. ColorBar b = GetColorBar (cp, ColorPickerPart.Bar3);
  425. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  426. Assert.Equal (expectedR, r.Text);
  427. Assert.Equal (expectedRTriangle, r.TrianglePosition);
  428. Assert.Equal (expectedG, g.Text);
  429. Assert.Equal (expectedGTriangle, g.TrianglePosition);
  430. Assert.Equal (expectedB, b.Text);
  431. Assert.Equal (expectedBTriangle, b.TrianglePosition);
  432. Assert.Equal (expectedHex, hex.Text);
  433. Application.Top.Dispose ();
  434. Application.ResetState (true);
  435. }
  436. [Theory]
  437. [SetupFakeDriver]
  438. [MemberData (nameof (ColorPickerTestData_WithTextFields))]
  439. public void ColorPicker_RGB_NoText_WithTextFields (
  440. Color c,
  441. string expectedR,
  442. int expectedRTriangle,
  443. int expectedRValue,
  444. string expectedG,
  445. int expectedGTriangle,
  446. int expectedGValue,
  447. string expectedB,
  448. int expectedBTriangle,
  449. int expectedBValue,
  450. string expectedHex
  451. )
  452. {
  453. ColorPicker cp = GetColorPicker (ColorModel.RGB, true);
  454. cp.SelectedColor = c;
  455. cp.Draw ();
  456. ColorBar r = GetColorBar (cp, ColorPickerPart.Bar1);
  457. ColorBar g = GetColorBar (cp, ColorPickerPart.Bar2);
  458. ColorBar b = GetColorBar (cp, ColorPickerPart.Bar3);
  459. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  460. TextField rTextField = GetTextField (cp, ColorPickerPart.Bar1);
  461. TextField gTextField = GetTextField (cp, ColorPickerPart.Bar2);
  462. TextField bTextField = GetTextField (cp, ColorPickerPart.Bar3);
  463. Assert.Equal (expectedR, r.Text);
  464. Assert.Equal (expectedRTriangle, r.TrianglePosition);
  465. Assert.Equal (expectedRValue.ToString (), rTextField.Text);
  466. Assert.Equal (expectedG, g.Text);
  467. Assert.Equal (expectedGTriangle, g.TrianglePosition);
  468. Assert.Equal (expectedGValue.ToString (), gTextField.Text);
  469. Assert.Equal (expectedB, b.Text);
  470. Assert.Equal (expectedBTriangle, b.TrianglePosition);
  471. Assert.Equal (expectedBValue.ToString (), bTextField.Text);
  472. Assert.Equal (expectedHex, hex.Text);
  473. Application.Top?.Dispose ();
  474. Application.ResetState (true);
  475. }
  476. [Fact]
  477. [SetupFakeDriver]
  478. public void ColorPicker_SwitchingColorModels_ResetsBars ()
  479. {
  480. ColorPicker cp = GetColorPicker (ColorModel.RGB, false);
  481. cp.BeginInit ();
  482. cp.EndInit ();
  483. cp.SelectedColor = new (255, 0);
  484. cp.Draw ();
  485. ColorBar r = GetColorBar (cp, ColorPickerPart.Bar1);
  486. ColorBar g = GetColorBar (cp, ColorPickerPart.Bar2);
  487. ColorBar b = GetColorBar (cp, ColorPickerPart.Bar3);
  488. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  489. Assert.Equal ("R:", r.Text);
  490. Assert.Equal (19, r.TrianglePosition);
  491. Assert.Equal ("G:", g.Text);
  492. Assert.Equal (2, g.TrianglePosition);
  493. Assert.Equal ("B:", b.Text);
  494. Assert.Equal (2, b.TrianglePosition);
  495. Assert.Equal ("#FF0000", hex.Text);
  496. // Switch to HSV
  497. cp.Style.ColorModel = ColorModel.HSV;
  498. cp.ApplyStyleChanges ();
  499. cp.Draw ();
  500. ColorBar h = GetColorBar (cp, ColorPickerPart.Bar1);
  501. ColorBar s = GetColorBar (cp, ColorPickerPart.Bar2);
  502. ColorBar v = GetColorBar (cp, ColorPickerPart.Bar3);
  503. Assert.Equal ("H:", h.Text);
  504. Assert.Equal (2, h.TrianglePosition);
  505. Assert.Equal ("S:", s.Text);
  506. Assert.Equal (19, s.TrianglePosition);
  507. Assert.Equal ("V:", v.Text);
  508. Assert.Equal (19, v.TrianglePosition);
  509. Assert.Equal ("#FF0000", hex.Text);
  510. Application.Top!.Dispose ();
  511. Application.ResetState (true);
  512. }
  513. [Fact]
  514. [SetupFakeDriver]
  515. public void ColorPicker_SyncBetweenTextFieldAndBars ()
  516. {
  517. ColorPicker cp = GetColorPicker (ColorModel.RGB, true);
  518. cp.Draw ();
  519. // Change value using the bar
  520. RBar rBar = cp.SubViews.OfType<RBar> ().First ();
  521. rBar.Value = 128;
  522. cp.Draw ();
  523. ColorBar r = GetColorBar (cp, ColorPickerPart.Bar1);
  524. ColorBar g = GetColorBar (cp, ColorPickerPart.Bar2);
  525. ColorBar b = GetColorBar (cp, ColorPickerPart.Bar3);
  526. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  527. TextField rTextField = GetTextField (cp, ColorPickerPart.Bar1);
  528. TextField gTextField = GetTextField (cp, ColorPickerPart.Bar2);
  529. TextField bTextField = GetTextField (cp, ColorPickerPart.Bar3);
  530. Assert.Equal ("R:", r.Text);
  531. Assert.Equal (9, r.TrianglePosition);
  532. Assert.Equal ("128", rTextField.Text);
  533. Assert.Equal ("G:", g.Text);
  534. Assert.Equal (2, g.TrianglePosition);
  535. Assert.Equal ("0", gTextField.Text);
  536. Assert.Equal ("B:", b.Text);
  537. Assert.Equal (2, b.TrianglePosition);
  538. Assert.Equal ("0", bTextField.Text);
  539. Assert.Equal ("#800000", hex.Text);
  540. Application.Top?.Dispose ();
  541. Application.ResetState (true);
  542. }
  543. [Fact]
  544. [SetupFakeDriver]
  545. public void ColorPicker_TabCompleteColorName ()
  546. {
  547. ColorPicker cp = GetColorPicker (ColorModel.RGB, true, true);
  548. cp.Draw ();
  549. ColorBar r = GetColorBar (cp, ColorPickerPart.Bar1);
  550. ColorBar g = GetColorBar (cp, ColorPickerPart.Bar2);
  551. ColorBar b = GetColorBar (cp, ColorPickerPart.Bar3);
  552. TextField name = GetTextField (cp, ColorPickerPart.ColorName);
  553. TextField hex = GetTextField (cp, ColorPickerPart.Hex);
  554. name.SetFocus ();
  555. Assert.True (name.HasFocus);
  556. Assert.Same (name, cp.Focused);
  557. name.Text = "";
  558. Assert.Empty (name.Text);
  559. Application.RaiseKeyDownEvent (Key.A);
  560. Application.RaiseKeyDownEvent (Key.Q);
  561. Assert.Equal ("aq", name.Text);
  562. // Auto complete the color name
  563. Application.RaiseKeyDownEvent (Key.Tab);
  564. // Match cyan alternative name
  565. Assert.Equal ("Aqua", name.Text);
  566. Assert.True (name.HasFocus);
  567. Application.RaiseKeyDownEvent (Key.Tab);
  568. // Resolves to cyan color
  569. Assert.Equal ("Aqua", name.Text);
  570. // Tab out of the text field
  571. Application.RaiseKeyDownEvent (Key.Tab);
  572. Assert.False (name.HasFocus);
  573. Assert.NotSame (name, cp.Focused);
  574. Assert.Equal ("#00FFFF", hex.Text);
  575. Application.Top?.Dispose ();
  576. Application.ResetState (true);
  577. }
  578. public static IEnumerable<object []> ColorPickerTestData ()
  579. {
  580. yield return new object []
  581. {
  582. new Color (255, 0),
  583. "R:", 19, "G:", 2, "B:", 2, "#FF0000"
  584. };
  585. yield return new object []
  586. {
  587. new Color (0, 255),
  588. "R:", 2, "G:", 19, "B:", 2, "#00FF00"
  589. };
  590. yield return new object []
  591. {
  592. new Color (0, 0, 255),
  593. "R:", 2, "G:", 2, "B:", 19, "#0000FF"
  594. };
  595. yield return new object []
  596. {
  597. new Color (125, 125, 125),
  598. "R:", 11, "G:", 11, "B:", 11, "#7D7D7D"
  599. };
  600. }
  601. public static IEnumerable<object []> ColorPickerTestData_WithTextFields ()
  602. {
  603. yield return new object []
  604. {
  605. new Color (255, 0),
  606. "R:", 15, 255, "G:", 2, 0, "B:", 2, 0, "#FF0000"
  607. };
  608. yield return new object []
  609. {
  610. new Color (0, 255),
  611. "R:", 2, 0, "G:", 15, 255, "B:", 2, 0, "#00FF00"
  612. };
  613. yield return new object []
  614. {
  615. new Color (0, 0, 255),
  616. "R:", 2, 0, "G:", 2, 0, "B:", 15, 255, "#0000FF"
  617. };
  618. yield return new object []
  619. {
  620. new Color (125, 125, 125),
  621. "R:", 9, 125, "G:", 9, 125, "B:", 9, 125, "#7D7D7D"
  622. };
  623. }
  624. private ColorBar GetColorBar (ColorPicker cp, ColorPickerPart toGet)
  625. {
  626. if (toGet <= ColorPickerPart.Bar3)
  627. {
  628. return cp.SubViews.OfType<ColorBar> ().ElementAt ((int)toGet);
  629. }
  630. throw new NotSupportedException ("ColorPickerPart must be a bar");
  631. }
  632. private ColorPicker GetColorPicker (ColorModel colorModel, bool showTextFields, bool showName = false)
  633. {
  634. var cp = new ColorPicker { Width = 20, SelectedColor = new (0, 0) };
  635. cp.Style.ColorModel = colorModel;
  636. cp.Style.ShowTextFields = showTextFields;
  637. cp.Style.ShowColorName = showName;
  638. cp.ApplyStyleChanges ();
  639. Application.Navigation = new ();
  640. Application.Top = new () { Width = 20, Height = 5 };
  641. Application.Top.Add (cp);
  642. Application.Top.LayoutSubViews ();
  643. Application.Top.SetFocus ();
  644. return cp;
  645. }
  646. private TextField GetTextField (ColorPicker cp, ColorPickerPart toGet)
  647. {
  648. bool hasBarValueTextFields = cp.Style.ShowTextFields;
  649. bool hasColorNameTextField = cp.Style.ShowColorName;
  650. switch (toGet)
  651. {
  652. case ColorPickerPart.Bar1:
  653. case ColorPickerPart.Bar2:
  654. case ColorPickerPart.Bar3:
  655. if (!hasBarValueTextFields)
  656. {
  657. throw new NotSupportedException ("Corresponding Style option is not enabled");
  658. }
  659. return cp.SubViews.OfType<TextField> ().ElementAt ((int)toGet);
  660. case ColorPickerPart.ColorName:
  661. if (!hasColorNameTextField)
  662. {
  663. throw new NotSupportedException ("Corresponding Style option is not enabled");
  664. }
  665. return cp.SubViews.OfType<TextField> ().ElementAt (hasBarValueTextFields ? (int)toGet : (int)toGet - 3);
  666. case ColorPickerPart.Hex:
  667. int offset = hasBarValueTextFields ? 0 : 3;
  668. offset += hasColorNameTextField ? 0 : 1;
  669. return cp.SubViews.OfType<TextField> ().ElementAt ((int)toGet - offset);
  670. default:
  671. throw new ArgumentOutOfRangeException (nameof (toGet), toGet, null);
  672. }
  673. }
  674. private enum ColorPickerPart
  675. {
  676. Bar1 = 0,
  677. Bar2 = 1,
  678. Bar3 = 2,
  679. ColorName = 3,
  680. Hex = 4
  681. }
  682. }