ColorPickerTests.cs 25 KB

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