ColorPickerTests.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  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.BeginInit ();
  383. cp.EndInit ();
  384. cp.SelectedColor = new (255, 0);
  385. cp.Draw ();
  386. var r = GetColorBar (cp, ColorPickerPart.Bar1);
  387. var g = GetColorBar (cp, ColorPickerPart.Bar2);
  388. var b = GetColorBar (cp, ColorPickerPart.Bar3);
  389. var hex = GetTextField (cp, ColorPickerPart.Hex);
  390. Assert.Equal ("R:", r.Text);
  391. Assert.Equal (19, r.TrianglePosition);
  392. Assert.Equal ("G:", g.Text);
  393. Assert.Equal (2, g.TrianglePosition);
  394. Assert.Equal ("B:", b.Text);
  395. Assert.Equal (2, b.TrianglePosition);
  396. Assert.Equal ("#FF0000", hex.Text);
  397. // Switch to HSV
  398. cp.Style.ColorModel = ColorModel.HSV;
  399. cp.ApplyStyleChanges ();
  400. cp.Draw ();
  401. var h = GetColorBar (cp, ColorPickerPart.Bar1);
  402. var s = GetColorBar (cp, ColorPickerPart.Bar2);
  403. var v = GetColorBar (cp, ColorPickerPart.Bar3);
  404. Assert.Equal ("H:", h.Text);
  405. Assert.Equal (2, h.TrianglePosition);
  406. Assert.Equal ("S:", s.Text);
  407. Assert.Equal (19, s.TrianglePosition);
  408. Assert.Equal ("V:", v.Text);
  409. Assert.Equal (19, v.TrianglePosition);
  410. Assert.Equal ("#FF0000", hex.Text);
  411. Application.Current?.Dispose ();
  412. }
  413. [Fact]
  414. [SetupFakeDriver]
  415. public void ColorPicker_SyncBetweenTextFieldAndBars ()
  416. {
  417. var cp = GetColorPicker (ColorModel.RGB, true);
  418. cp.Draw ();
  419. // Change value using the bar
  420. RBar rBar = cp.Subviews.OfType<RBar> ().First ();
  421. rBar.Value = 128;
  422. cp.Draw ();
  423. var r = GetColorBar (cp, ColorPickerPart.Bar1);
  424. var g = GetColorBar (cp, ColorPickerPart.Bar2);
  425. var b = GetColorBar (cp, ColorPickerPart.Bar3);
  426. var hex = GetTextField (cp, ColorPickerPart.Hex);
  427. var rTextField = GetTextField (cp, ColorPickerPart.Bar1);
  428. var gTextField = GetTextField (cp, ColorPickerPart.Bar2);
  429. var bTextField = GetTextField (cp, ColorPickerPart.Bar3);
  430. Assert.Equal ("R:", r.Text);
  431. Assert.Equal (9, r.TrianglePosition);
  432. Assert.Equal ("128", rTextField.Text);
  433. Assert.Equal ("G:", g.Text);
  434. Assert.Equal (2, g.TrianglePosition);
  435. Assert.Equal ("0", gTextField.Text);
  436. Assert.Equal ("B:", b.Text);
  437. Assert.Equal (2, b.TrianglePosition);
  438. Assert.Equal ("0", bTextField.Text);
  439. Assert.Equal ("#800000", hex.Text);
  440. Application.Current?.Dispose ();
  441. }
  442. enum ColorPickerPart
  443. {
  444. Bar1 = 0,
  445. Bar2 = 1,
  446. Bar3 = 2,
  447. ColorName = 3,
  448. Hex = 4,
  449. }
  450. private TextField GetTextField (ColorPicker cp, ColorPickerPart toGet)
  451. {
  452. var hasBarValueTextFields = cp.Style.ShowTextFields;
  453. var hasColorNameTextField = cp.Style.ShowColorName;
  454. switch (toGet)
  455. {
  456. case ColorPickerPart.Bar1:
  457. case ColorPickerPart.Bar2:
  458. case ColorPickerPart.Bar3:
  459. if (!hasBarValueTextFields)
  460. {
  461. throw new NotSupportedException ("Corresponding Style option is not enabled");
  462. }
  463. return cp.Subviews.OfType<TextField> ().ElementAt ((int)toGet);
  464. case ColorPickerPart.ColorName:
  465. if (!hasColorNameTextField)
  466. {
  467. throw new NotSupportedException ("Corresponding Style option is not enabled");
  468. }
  469. return cp.Subviews.OfType<TextField> ().ElementAt (hasBarValueTextFields ? (int)toGet : (int)toGet - 3);
  470. case ColorPickerPart.Hex:
  471. int offset = hasBarValueTextFields ? 0 : 3;
  472. offset += hasColorNameTextField ? 0 : 1;
  473. return cp.Subviews.OfType<TextField> ().ElementAt ((int)toGet - offset);
  474. default:
  475. throw new ArgumentOutOfRangeException (nameof (toGet), toGet, null);
  476. }
  477. }
  478. private ColorBar GetColorBar (ColorPicker cp, ColorPickerPart toGet)
  479. {
  480. if (toGet <= ColorPickerPart.Bar3)
  481. {
  482. return cp.Subviews.OfType<ColorBar> ().ElementAt ((int)toGet);
  483. }
  484. throw new NotSupportedException ("ColorPickerPart must be a bar");
  485. }
  486. [Fact]
  487. [SetupFakeDriver]
  488. public void ColorPicker_ChangedEvent_Fires ()
  489. {
  490. Color newColor = default;
  491. var count = 0;
  492. var cp = new ColorPicker ();
  493. cp.ColorChanged += (s, e) =>
  494. {
  495. count++;
  496. newColor = e.CurrentValue;
  497. Assert.Equal (cp.SelectedColor, e.CurrentValue);
  498. };
  499. cp.SelectedColor = new (1, 2, 3);
  500. Assert.Equal (1, count);
  501. Assert.Equal (new (1, 2, 3), newColor);
  502. cp.SelectedColor = new (2, 3, 4);
  503. Assert.Equal (2, count);
  504. Assert.Equal (new (2, 3, 4), newColor);
  505. // Set to same value
  506. cp.SelectedColor = new (2, 3, 4);
  507. // Should have no effect
  508. Assert.Equal (2, count);
  509. }
  510. [Fact]
  511. [SetupFakeDriver]
  512. public void ColorPicker_DisposesOldViews_OnModelChange ()
  513. {
  514. var cp = GetColorPicker (ColorModel.HSL, true);
  515. var b1 = GetColorBar (cp, ColorPickerPart.Bar1);
  516. var b2 = GetColorBar (cp, ColorPickerPart.Bar2);
  517. var b3 = GetColorBar (cp, ColorPickerPart.Bar3);
  518. var tf1 = GetTextField (cp, ColorPickerPart.Bar1);
  519. var tf2 = GetTextField (cp, ColorPickerPart.Bar2);
  520. var tf3 = GetTextField (cp, ColorPickerPart.Bar3);
  521. var hex = GetTextField (cp, ColorPickerPart.Hex);
  522. #if DEBUG_IDISPOSABLE
  523. Assert.All (new View [] { b1, b2, b3, tf1, tf2, tf3, hex }, b => Assert.False (b.WasDisposed));
  524. #endif
  525. cp.Style.ColorModel = ColorModel.RGB;
  526. cp.ApplyStyleChanges ();
  527. var b1After = GetColorBar (cp, ColorPickerPart.Bar1);
  528. var b2After = GetColorBar (cp, ColorPickerPart.Bar2);
  529. var b3After = GetColorBar (cp, ColorPickerPart.Bar3);
  530. var tf1After = GetTextField (cp, ColorPickerPart.Bar1);
  531. var tf2After = GetTextField (cp, ColorPickerPart.Bar2);
  532. var tf3After = GetTextField (cp, ColorPickerPart.Bar3);
  533. var hexAfter = GetTextField (cp, ColorPickerPart.Hex);
  534. // Old bars should be disposed
  535. #if DEBUG_IDISPOSABLE
  536. Assert.All (new View [] { b1, b2, b3, tf1, tf2, tf3, hex }, b => Assert.True (b.WasDisposed));
  537. #endif
  538. Assert.NotSame (hex, hexAfter);
  539. Assert.NotSame (b1, b1After);
  540. Assert.NotSame (b2, b2After);
  541. Assert.NotSame (b3, b3After);
  542. Assert.NotSame (tf1, tf1After);
  543. Assert.NotSame (tf2, tf2After);
  544. Assert.NotSame (tf3, tf3After);
  545. }
  546. [Fact]
  547. [SetupFakeDriver]
  548. public void ColorPicker_TabCompleteColorName ()
  549. {
  550. var cp = GetColorPicker (ColorModel.RGB, true, true);
  551. cp.Draw ();
  552. var r = GetColorBar (cp, ColorPickerPart.Bar1);
  553. var g = GetColorBar (cp, ColorPickerPart.Bar2);
  554. var b = GetColorBar (cp, ColorPickerPart.Bar3);
  555. var name = GetTextField (cp, ColorPickerPart.ColorName);
  556. var hex = GetTextField (cp, ColorPickerPart.Hex);
  557. name.SetFocus ();
  558. Assert.True (name.HasFocus);
  559. Assert.Same (name, cp.Focused);
  560. name.Text = "";
  561. Assert.Empty (name.Text);
  562. Application.OnKeyDown (Key.A);
  563. Application.OnKeyDown (Key.Q);
  564. Assert.Equal ("aq", name.Text);
  565. // Auto complete the color name
  566. Application.OnKeyDown (Key.Tab);
  567. Assert.Equal ("Aquamarine", name.Text);
  568. // Tab out of the text field
  569. Application.OnKeyDown (Key.Tab);
  570. Assert.False (name.HasFocus);
  571. Assert.NotSame (name, cp.Focused);
  572. Assert.Equal ("#7FFFD4", hex.Text);
  573. Application.Current?.Dispose ();
  574. }
  575. [Fact]
  576. [SetupFakeDriver]
  577. public void ColorPicker_EnterHexFor_ColorName ()
  578. {
  579. var cp = GetColorPicker (ColorModel.RGB, true, true);
  580. cp.Draw ();
  581. var name = GetTextField (cp, ColorPickerPart.ColorName);
  582. var hex = GetTextField (cp, ColorPickerPart.Hex);
  583. hex.SetFocus ();
  584. Assert.True (hex.HasFocus);
  585. Assert.Same (hex, cp.Focused);
  586. hex.Text = "";
  587. name.Text = "";
  588. Assert.Empty (hex.Text);
  589. Assert.Empty (name.Text);
  590. Application.OnKeyDown ('#');
  591. Assert.Empty (name.Text);
  592. //7FFFD4
  593. Assert.Equal ("#", hex.Text);
  594. Application.OnKeyDown ('7');
  595. Application.OnKeyDown ('F');
  596. Application.OnKeyDown ('F');
  597. Application.OnKeyDown ('F');
  598. Application.OnKeyDown ('D');
  599. Assert.Empty (name.Text);
  600. Application.OnKeyDown ('4');
  601. Assert.True (hex.HasFocus);
  602. // Tab out of the hex field - should wrap to first focusable subview
  603. Application.OnKeyDown (Key.Tab);
  604. Assert.False (hex.HasFocus);
  605. Assert.NotSame (hex, cp.Focused);
  606. // Color name should be recognised as a known string and populated
  607. Assert.Equal ("#7FFFD4", hex.Text);
  608. Assert.Equal ("Aquamarine", name.Text);
  609. Application.Current?.Dispose ();
  610. }
  611. [Fact]
  612. public void TestColorNames ()
  613. {
  614. var colors = new W3CColors ();
  615. Assert.Contains ("Aquamarine", colors.GetColorNames ());
  616. Assert.DoesNotContain ("Save as", colors.GetColorNames ());
  617. }
  618. private ColorPicker GetColorPicker (ColorModel colorModel, bool showTextFields, bool showName = false)
  619. {
  620. var cp = new ColorPicker { Width = 20, SelectedColor = new (0, 0) };
  621. cp.Style.ColorModel = colorModel;
  622. cp.Style.ShowTextFields = showTextFields;
  623. cp.Style.ShowColorName = showName;
  624. cp.ApplyStyleChanges ();
  625. Application.Current = new Toplevel () { Width = 20, Height = 5 };
  626. Application.Current.Add (cp);
  627. Application.Current.LayoutSubviews ();
  628. Application.Current.SetFocus ();
  629. return cp;
  630. }
  631. }