TextAlignmentAndDirection.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Terminal.Gui;
  6. namespace UICatalog.Scenarios;
  7. [ScenarioMetadata ("Text Alignment and Direction", "Demos horizontal and vertical text alignment and direction.")]
  8. [ScenarioCategory ("Text and Formatting")]
  9. public class TextAlignmentAndDirection : Scenario
  10. {
  11. public override void Main ()
  12. {
  13. Application.Init ();
  14. Window app = new ()
  15. {
  16. Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}"
  17. };
  18. var txt = $"Hello World{Environment.NewLine}HELLO WORLD{Environment.NewLine}世界 您好";
  19. var color1 = new ColorScheme { Normal = new (Color.Black, Color.Gray) };
  20. var color2 = new ColorScheme { Normal = new (Color.Black, Color.DarkGray) };
  21. List<Label> singleLineLabels = new (); // single line
  22. List<Label> multiLineLabels = new (); // multi line
  23. // Horizontal Single-Line
  24. var labelHL = new Label
  25. {
  26. X = 0,
  27. Y = 0,
  28. Width = 6,
  29. Height = 1,
  30. TextAlignment = Alignment.End,
  31. ColorScheme = Colors.ColorSchemes ["Dialog"],
  32. Text = "Start"
  33. };
  34. var labelHC = new Label
  35. {
  36. X = 0,
  37. Y = 1,
  38. Width = 6,
  39. Height = 1,
  40. TextAlignment = Alignment.End,
  41. ColorScheme = Colors.ColorSchemes ["Dialog"],
  42. Text = "Center"
  43. };
  44. var labelHR = new Label
  45. {
  46. X = 0,
  47. Y = 2,
  48. Width = 6,
  49. Height = 1,
  50. TextAlignment = Alignment.End,
  51. ColorScheme = Colors.ColorSchemes ["Dialog"],
  52. Text = "End"
  53. };
  54. var labelHJ = new Label
  55. {
  56. X = 0,
  57. Y = 3,
  58. Width = 6,
  59. Height = 1,
  60. TextAlignment = Alignment.End,
  61. ColorScheme = Colors.ColorSchemes ["Dialog"],
  62. Text = "Fill"
  63. };
  64. var txtLabelHL = new Label
  65. {
  66. X = Pos.Right (labelHL) + 1,
  67. Y = Pos.Y (labelHL),
  68. Width = Dim.Fill (9),
  69. Height = 1,
  70. ColorScheme = color1,
  71. TextAlignment = Alignment.Start,
  72. Text = txt
  73. };
  74. var txtLabelHC = new Label
  75. {
  76. X = Pos.Right (labelHC) + 1,
  77. Y = Pos.Y (labelHC),
  78. Width = Dim.Fill (9),
  79. Height = 1,
  80. ColorScheme = color2,
  81. TextAlignment = Alignment.Center,
  82. Text = txt
  83. };
  84. var txtLabelHR = new Label
  85. {
  86. X = Pos.Right (labelHR) + 1,
  87. Y = Pos.Y (labelHR),
  88. Width = Dim.Fill (9),
  89. Height = 1,
  90. ColorScheme = color1,
  91. TextAlignment = Alignment.End,
  92. Text = txt
  93. };
  94. var txtLabelHJ = new Label
  95. {
  96. X = Pos.Right (labelHJ) + 1,
  97. Y = Pos.Y (labelHJ),
  98. Width = Dim.Fill (9),
  99. Height = 1,
  100. ColorScheme = color2,
  101. TextAlignment = Alignment.Fill,
  102. Text = txt
  103. };
  104. singleLineLabels.Add (txtLabelHL);
  105. singleLineLabels.Add (txtLabelHC);
  106. singleLineLabels.Add (txtLabelHR);
  107. singleLineLabels.Add (txtLabelHJ);
  108. app.Add (labelHL);
  109. app.Add (txtLabelHL);
  110. app.Add (labelHC);
  111. app.Add (txtLabelHC);
  112. app.Add (labelHR);
  113. app.Add (txtLabelHR);
  114. app.Add (labelHJ);
  115. app.Add (txtLabelHJ);
  116. // Vertical Single-Line
  117. var labelVT = new Label
  118. {
  119. X = Pos.AnchorEnd () - 6,
  120. Y = 0,
  121. Width = 2,
  122. Height = 6,
  123. ColorScheme = color1,
  124. TextDirection = TextDirection.TopBottom_LeftRight,
  125. VerticalTextAlignment = Alignment.End,
  126. Text = "Start"
  127. };
  128. labelVT.TextFormatter.WordWrap = false;
  129. var labelVM = new Label
  130. {
  131. X = Pos.AnchorEnd () - 4,
  132. Y = 0,
  133. Width = 2,
  134. Height = 6,
  135. ColorScheme = color1,
  136. TextDirection = TextDirection.TopBottom_LeftRight,
  137. VerticalTextAlignment = Alignment.End,
  138. Text = "Center"
  139. };
  140. labelVM.TextFormatter.WordWrap = false;
  141. var labelVB = new Label
  142. {
  143. X = Pos.AnchorEnd () - 2,
  144. Y = 0,
  145. Width = 2,
  146. Height = 6,
  147. ColorScheme = color1,
  148. TextDirection = TextDirection.TopBottom_LeftRight,
  149. VerticalTextAlignment = Alignment.End,
  150. Text = "End"
  151. };
  152. labelVB.TextFormatter.WordWrap = false;
  153. var labelVJ = new Label
  154. {
  155. X = Pos.AnchorEnd (),
  156. Y = 0,
  157. Width = 2,
  158. Height = 6,
  159. ColorScheme = color1,
  160. TextDirection = TextDirection.TopBottom_LeftRight,
  161. VerticalTextAlignment = Alignment.End,
  162. Text = "Fill"
  163. };
  164. labelVJ.TextFormatter.WordWrap = false;
  165. var txtLabelVT = new Label
  166. {
  167. X = Pos.X (labelVT),
  168. Y = Pos.Bottom (labelVT) + 1,
  169. Width = 2,
  170. Height = Dim.Fill (),
  171. ColorScheme = color1,
  172. TextDirection = TextDirection.TopBottom_LeftRight,
  173. VerticalTextAlignment = Alignment.Start,
  174. Text = txt
  175. };
  176. txtLabelVT.TextFormatter.WordWrap = false;
  177. var txtLabelVM = new Label
  178. {
  179. X = Pos.X (labelVM),
  180. Y = Pos.Bottom (labelVM) + 1,
  181. Width = 2,
  182. Height = Dim.Fill (),
  183. ColorScheme = color2,
  184. TextDirection = TextDirection.TopBottom_LeftRight,
  185. VerticalTextAlignment = Alignment.Center,
  186. Text = txt
  187. };
  188. txtLabelVM.TextFormatter.WordWrap = false;
  189. var txtLabelVB = new Label
  190. {
  191. X = Pos.X (labelVB),
  192. Y = Pos.Bottom (labelVB) + 1,
  193. Width = 2,
  194. Height = Dim.Fill (),
  195. ColorScheme = color1,
  196. TextDirection = TextDirection.TopBottom_LeftRight,
  197. VerticalTextAlignment = Alignment.End,
  198. Text = txt
  199. };
  200. txtLabelVB.TextFormatter.WordWrap = false;
  201. var txtLabelVJ = new Label
  202. {
  203. X = Pos.X (labelVJ),
  204. Y = Pos.Bottom (labelVJ) + 1,
  205. Width = 2,
  206. Height = Dim.Fill (),
  207. ColorScheme = color2,
  208. TextDirection = TextDirection.TopBottom_LeftRight,
  209. VerticalTextAlignment = Alignment.Fill,
  210. Text = txt
  211. };
  212. txtLabelVJ.TextFormatter.WordWrap = false;
  213. singleLineLabels.Add (txtLabelVT);
  214. singleLineLabels.Add (txtLabelVM);
  215. singleLineLabels.Add (txtLabelVB);
  216. singleLineLabels.Add (txtLabelVJ);
  217. app.Add (labelVT);
  218. app.Add (txtLabelVT);
  219. app.Add (labelVM);
  220. app.Add (txtLabelVM);
  221. app.Add (labelVB);
  222. app.Add (txtLabelVB);
  223. app.Add (labelVJ);
  224. app.Add (txtLabelVJ);
  225. // Multi-Line
  226. var container = new View
  227. {
  228. X = 0,
  229. Y = Pos.Bottom (txtLabelHJ),
  230. Width = Dim.Fill (31),
  231. Height = Dim.Fill (4)
  232. //ColorScheme = color2
  233. };
  234. var txtLabelTL = new Label
  235. {
  236. X = 0 /* */,
  237. Y = 1,
  238. Width = Dim.Percent (100 / 3),
  239. Height = Dim.Percent (100 / 3),
  240. TextAlignment = Alignment.Start,
  241. VerticalTextAlignment = Alignment.Start,
  242. ColorScheme = color1,
  243. Text = txt
  244. };
  245. txtLabelTL.TextFormatter.MultiLine = true;
  246. var txtLabelTC = new Label
  247. {
  248. X = Pos.Right (txtLabelTL) + 2,
  249. Y = 1,
  250. Width = Dim.Percent (33),
  251. Height = Dim.Percent (33),
  252. TextAlignment = Alignment.Center,
  253. VerticalTextAlignment = Alignment.Start,
  254. ColorScheme = color1,
  255. Text = txt
  256. };
  257. txtLabelTC.TextFormatter.MultiLine = true;
  258. var txtLabelTR = new Label
  259. {
  260. X = Pos.Right (txtLabelTC) + 2,
  261. Y = 1,
  262. Width = Dim.Percent (100, DimPercentMode.Position),
  263. Height = Dim.Percent (33),
  264. TextAlignment = Alignment.End,
  265. VerticalTextAlignment = Alignment.Start,
  266. ColorScheme = color1,
  267. Text = txt
  268. };
  269. txtLabelTR.TextFormatter.MultiLine = true;
  270. var txtLabelML = new Label
  271. {
  272. X = Pos.X (txtLabelTL),
  273. Y = Pos.Bottom (txtLabelTL) + 1,
  274. Width = Dim.Width (txtLabelTL),
  275. Height = Dim.Percent (33),
  276. TextAlignment = Alignment.Start,
  277. VerticalTextAlignment = Alignment.Center,
  278. ColorScheme = color1,
  279. Text = txt
  280. };
  281. txtLabelML.TextFormatter.MultiLine = true;
  282. var txtLabelMC = new Label
  283. {
  284. X = Pos.X (txtLabelTC),
  285. Y = Pos.Bottom (txtLabelTC) + 1,
  286. Width = Dim.Width (txtLabelTC),
  287. Height = Dim.Percent (33),
  288. TextAlignment = Alignment.Center,
  289. VerticalTextAlignment = Alignment.Center,
  290. ColorScheme = color1,
  291. Text = txt
  292. };
  293. txtLabelMC.TextFormatter.MultiLine = true;
  294. var txtLabelMR = new Label
  295. {
  296. X = Pos.X (txtLabelTR),
  297. Y = Pos.Bottom (txtLabelTR) + 1,
  298. Width = Dim.Percent (100, DimPercentMode.Position),
  299. Height = Dim.Percent (33),
  300. TextAlignment = Alignment.End,
  301. VerticalTextAlignment = Alignment.Center,
  302. ColorScheme = color1,
  303. Text = txt
  304. };
  305. txtLabelMR.TextFormatter.MultiLine = true;
  306. var txtLabelBL = new Label
  307. {
  308. X = Pos.X (txtLabelML),
  309. Y = Pos.Bottom (txtLabelML) + 1,
  310. Width = Dim.Width (txtLabelML),
  311. Height = Dim.Percent (100, DimPercentMode.Position),
  312. TextAlignment = Alignment.Start,
  313. VerticalTextAlignment = Alignment.End,
  314. ColorScheme = color1,
  315. Text = txt
  316. };
  317. txtLabelBL.TextFormatter.MultiLine = true;
  318. var txtLabelBC = new Label
  319. {
  320. X = Pos.X (txtLabelMC),
  321. Y = Pos.Bottom (txtLabelMC) + 1,
  322. Width = Dim.Width (txtLabelMC),
  323. Height = Dim.Percent (100, DimPercentMode.Position),
  324. TextAlignment = Alignment.Center,
  325. VerticalTextAlignment = Alignment.End,
  326. ColorScheme = color1,
  327. Text = txt
  328. };
  329. txtLabelBC.TextFormatter.MultiLine = true;
  330. var txtLabelBR = new Label
  331. {
  332. X = Pos.X (txtLabelMR),
  333. Y = Pos.Bottom (txtLabelMR) + 1,
  334. Width = Dim.Percent (100, DimPercentMode.Position),
  335. Height = Dim.Percent (100, DimPercentMode.Position),
  336. TextAlignment = Alignment.End,
  337. VerticalTextAlignment = Alignment.End,
  338. ColorScheme = color1,
  339. Text = txt
  340. };
  341. txtLabelBR.TextFormatter.MultiLine = true;
  342. multiLineLabels.Add (txtLabelTL);
  343. multiLineLabels.Add (txtLabelTC);
  344. multiLineLabels.Add (txtLabelTR);
  345. multiLineLabels.Add (txtLabelML);
  346. multiLineLabels.Add (txtLabelMC);
  347. multiLineLabels.Add (txtLabelMR);
  348. multiLineLabels.Add (txtLabelBL);
  349. multiLineLabels.Add (txtLabelBC);
  350. multiLineLabels.Add (txtLabelBR);
  351. // Save Alignment in Data
  352. foreach (Label t in multiLineLabels)
  353. {
  354. t.Data = new { h = t.TextAlignment, v = t.VerticalTextAlignment };
  355. }
  356. container.Add (txtLabelTL);
  357. container.Add (txtLabelTC);
  358. container.Add (txtLabelTR);
  359. container.Add (txtLabelML);
  360. container.Add (txtLabelMC);
  361. container.Add (txtLabelMR);
  362. container.Add (txtLabelBL);
  363. container.Add (txtLabelBC);
  364. container.Add (txtLabelBR);
  365. app.Add (container);
  366. // Edit Text
  367. var label = new Label
  368. {
  369. X = 1,
  370. Y = Pos.Bottom (container) + 1,
  371. Width = 10,
  372. Height = 1,
  373. Text = "Edit Text:"
  374. };
  375. var editText = new TextView
  376. {
  377. X = Pos.Right (label) + 1,
  378. Y = Pos.Top (label),
  379. Width = Dim.Fill (31),
  380. Height = 3,
  381. Text = txt
  382. };
  383. editText.MouseClick += (s, m) =>
  384. {
  385. foreach (Label v in singleLineLabels)
  386. {
  387. v.Text = editText.Text;
  388. }
  389. foreach (Label v in multiLineLabels)
  390. {
  391. v.Text = editText.Text;
  392. }
  393. };
  394. app.KeyUp += (s, m) =>
  395. {
  396. foreach (Label v in singleLineLabels)
  397. {
  398. v.Text = editText.Text;
  399. }
  400. foreach (Label v in multiLineLabels)
  401. {
  402. v.Text = editText.Text;
  403. }
  404. };
  405. editText.SetFocus ();
  406. app.Add (label, editText);
  407. // JUSTIFY CHECKBOX
  408. var justifyCheckbox = new CheckBox
  409. {
  410. X = Pos.Right (container) + 1,
  411. Y = Pos.Y (container) + 1,
  412. Width = Dim.Fill (10),
  413. Height = 1,
  414. Text = "Fill"
  415. };
  416. app.Add (justifyCheckbox);
  417. // JUSTIFY OPTIONS
  418. var justifyOptions = new RadioGroup
  419. {
  420. X = Pos.Left (justifyCheckbox) + 1,
  421. Y = Pos.Y (justifyCheckbox) + 1,
  422. Width = Dim.Fill (9),
  423. RadioLabels = ["Current direction", "Opposite direction", "FIll Both"],
  424. Enabled = false
  425. };
  426. justifyCheckbox.Toggled += (s, e) => ToggleJustify (e.OldValue is { } && (bool)e.OldValue);
  427. justifyOptions.SelectedItemChanged += (s, e) => { ToggleJustify (false, true); };
  428. app.Add (justifyOptions);
  429. // WRAP CHECKBOX
  430. var wrapCheckbox = new CheckBox
  431. {
  432. X = Pos.Right (container) + 1,
  433. Y = Pos.Bottom (justifyOptions),
  434. Width = Dim.Fill (10),
  435. Height = 1,
  436. Text = "Word Wrap"
  437. };
  438. wrapCheckbox.Checked = wrapCheckbox.TextFormatter.WordWrap;
  439. wrapCheckbox.Toggled += (s, e) =>
  440. {
  441. if (e.OldValue == true)
  442. {
  443. foreach (Label t in multiLineLabels)
  444. {
  445. t.TextFormatter.WordWrap = false;
  446. }
  447. }
  448. else
  449. {
  450. foreach (Label t in multiLineLabels)
  451. {
  452. t.TextFormatter.WordWrap = true;
  453. }
  454. }
  455. };
  456. app.Add (wrapCheckbox);
  457. // AUTOSIZE CHECKBOX
  458. var autoSizeCheckbox = new CheckBox
  459. {
  460. X = Pos.Right (container) + 1,
  461. Y = Pos.Y (wrapCheckbox) + 1,
  462. Width = Dim.Fill (10),
  463. Height = 1,
  464. Text = "AutoSize"
  465. };
  466. autoSizeCheckbox.Checked = autoSizeCheckbox.TextFormatter.AutoSize;
  467. autoSizeCheckbox.Toggled += (s, e) =>
  468. {
  469. if (e.OldValue == true)
  470. {
  471. foreach (Label t in multiLineLabels)
  472. {
  473. t.TextFormatter.AutoSize = false;
  474. }
  475. }
  476. else
  477. {
  478. foreach (Label t in multiLineLabels)
  479. {
  480. t.TextFormatter.AutoSize = true;
  481. }
  482. }
  483. };
  484. app.Add (autoSizeCheckbox);
  485. // Direction Options
  486. List<TextDirection> directionsEnum = Enum.GetValues (typeof (TextDirection)).Cast<TextDirection> ().ToList ();
  487. var directionOptions = new RadioGroup
  488. {
  489. X = Pos.Right (container) + 1,
  490. Y = Pos.Bottom (autoSizeCheckbox) + 1,
  491. Width = Dim.Fill (10),
  492. Height = Dim.Fill (1),
  493. HotKeySpecifier = (Rune)'\xffff',
  494. RadioLabels = directionsEnum.Select (e => e.ToString ()).ToArray ()
  495. };
  496. directionOptions.SelectedItemChanged += (s, ev) =>
  497. {
  498. bool justChecked = justifyCheckbox.Checked is { } && (bool)justifyCheckbox.Checked;
  499. if (justChecked)
  500. {
  501. ToggleJustify (true);
  502. }
  503. foreach (Label v in multiLineLabels)
  504. {
  505. v.TextDirection = (TextDirection)ev.SelectedItem;
  506. }
  507. if (justChecked)
  508. {
  509. ToggleJustify (false);
  510. }
  511. };
  512. app.Add (directionOptions);
  513. Application.Run (app);
  514. app.Dispose ();
  515. void ToggleJustify (bool oldValue, bool wasJustOptions = false)
  516. {
  517. if (oldValue)
  518. {
  519. if (!wasJustOptions)
  520. {
  521. justifyOptions.Enabled = false;
  522. }
  523. foreach (Label t in multiLineLabels)
  524. {
  525. t.TextAlignment = (Alignment)((dynamic)t.Data).h;
  526. t.VerticalTextAlignment = (Alignment)((dynamic)t.Data).v;
  527. }
  528. }
  529. else
  530. {
  531. foreach (Label t in multiLineLabels)
  532. {
  533. if (!wasJustOptions)
  534. {
  535. justifyOptions.Enabled = true;
  536. }
  537. if (TextFormatter.IsVerticalDirection (t.TextDirection))
  538. {
  539. switch (justifyOptions.SelectedItem)
  540. {
  541. case 0:
  542. t.VerticalTextAlignment = Alignment.Fill;
  543. t.TextAlignment = ((dynamic)t.Data).h;
  544. break;
  545. case 1:
  546. t.VerticalTextAlignment = (Alignment)((dynamic)t.Data).v;
  547. t.TextAlignment = Alignment.Fill;
  548. break;
  549. case 2:
  550. t.VerticalTextAlignment = Alignment.Fill;
  551. t.TextAlignment = Alignment.Fill;
  552. break;
  553. }
  554. }
  555. else
  556. {
  557. switch (justifyOptions.SelectedItem)
  558. {
  559. case 0:
  560. t.TextAlignment = Alignment.Fill;
  561. t.VerticalTextAlignment = ((dynamic)t.Data).v;
  562. break;
  563. case 1:
  564. t.TextAlignment = (Alignment)((dynamic)t.Data).h;
  565. t.VerticalTextAlignment = Alignment.Fill;
  566. break;
  567. case 2:
  568. t.TextAlignment = Alignment.Fill;
  569. t.VerticalTextAlignment = Alignment.Fill;
  570. break;
  571. }
  572. }
  573. }
  574. }
  575. }
  576. }
  577. }