2
0

TextAlignmentAndDirection.cs 21 KB

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