Text.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. using System;
  2. using System.ComponentModel;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. using Terminal.Gui;
  8. using Terminal.Gui.TextValidateProviders;
  9. namespace UICatalog.Scenarios;
  10. [ScenarioMetadata ("Text Input Controls", "Tests all text input controls")]
  11. [ScenarioCategory ("Controls")]
  12. [ScenarioCategory ("Mouse and Keyboard")]
  13. [ScenarioCategory ("Text and Formatting")]
  14. public class Text : Scenario
  15. {
  16. private Label _labelMirroringTimeField;
  17. private TimeField _timeField;
  18. public override void Main ()
  19. {
  20. Application.Init ();
  21. var win = new Window { Title = GetQuitKeyAndName () };
  22. // TextField is a simple, single-line text input control
  23. var label = new Label { Text = "_TextField:" };
  24. win.Add (label);
  25. var textField = new TextField
  26. {
  27. X = Pos.Right (label) + 1,
  28. Y = 0,
  29. Width = Dim.Percent (50) - 1,
  30. Text = "TextField with test text. Unicode shouldn't 𝔹Aℝ𝔽!"
  31. };
  32. var singleWordGenerator = new SingleWordSuggestionGenerator ();
  33. textField.Autocomplete.SuggestionGenerator = singleWordGenerator;
  34. textField.TextChanging += TextField_TextChanging;
  35. void TextField_TextChanging (object sender, CancelEventArgs<string> e)
  36. {
  37. singleWordGenerator.AllSuggestions = Regex.Matches (e.NewValue, "\\w+")
  38. .Select (s => s.Value)
  39. .Distinct ()
  40. .ToList ();
  41. }
  42. win.Add (textField);
  43. var labelMirroringTextField = new Label
  44. {
  45. X = Pos.Right (textField) + 1,
  46. Y = Pos.Top (textField),
  47. Width = Dim.Fill (1) - 1,
  48. Height = 1,
  49. Text = textField.Text
  50. };
  51. win.Add (labelMirroringTextField);
  52. textField.TextChanged += (s, prev) => { labelMirroringTextField.Text = textField.Text; };
  53. // TextView is a rich (as in functionality, not formatting) text editing control
  54. label = new() { Text = "T_extView:", Y = Pos.Bottom (label) + 1 };
  55. win.Add (label);
  56. var textView = new TextView
  57. {
  58. X = Pos.Right (label) + 1,
  59. Y = Pos.Top (label),
  60. Width = Dim.Percent (50) - 1,
  61. Height = Dim.Percent (20)
  62. };
  63. textView.Text = "TextView with some more test text. Unicode shouldn't 𝔹Aℝ𝔽!";
  64. textView.DrawContent += TextView_DrawContent;
  65. // This shows how to enable autocomplete in TextView.
  66. void TextView_DrawContent (object sender, DrawEventArgs e)
  67. {
  68. singleWordGenerator.AllSuggestions = Regex.Matches (textView.Text, "\\w+")
  69. .Select (s => s.Value)
  70. .Distinct ()
  71. .ToList ();
  72. }
  73. win.Add (textView);
  74. var labelMirroringTextView = new Label
  75. {
  76. X = Pos.Right (textView) + 1,
  77. Y = Pos.Top (textView),
  78. Width = Dim.Fill (1) - 1,
  79. Height = Dim.Height (textView) - 1
  80. };
  81. win.Add (labelMirroringTextView);
  82. // Use ContentChanged to detect if the user has typed something in a TextView.
  83. // The TextChanged property is only fired if the TextView.Text property is
  84. // explicitly set
  85. textView.ContentsChanged += (s, a) =>
  86. {
  87. labelMirroringTextView.Enabled = !labelMirroringTextView.Enabled;
  88. labelMirroringTextView.Text = textView.Text;
  89. };
  90. // By default TextView is a multi-line control. It can be forced to
  91. // single-line mode.
  92. var chxMultiline = new CheckBox
  93. {
  94. X = Pos.Left (textView), Y = Pos.Bottom (textView), CheckedState = textView.Multiline ? CheckState.Checked : CheckState.UnChecked, Text = "_Multiline"
  95. };
  96. win.Add (chxMultiline);
  97. var chxWordWrap = new CheckBox
  98. {
  99. X = Pos.Right (chxMultiline) + 2,
  100. Y = Pos.Top (chxMultiline),
  101. CheckedState = textView.WordWrap ? CheckState.Checked : CheckState.UnChecked,
  102. Text = "_Word Wrap"
  103. };
  104. chxWordWrap.CheckedStateChanging += (s, e) => textView.WordWrap = e.NewValue == CheckState.Checked;
  105. win.Add (chxWordWrap);
  106. // TextView captures Tabs (so users can enter /t into text) by default;
  107. // This means using Tab to navigate doesn't work by default. This shows
  108. // how to turn tab capture off.
  109. var chxCaptureTabs = new CheckBox
  110. {
  111. X = Pos.Right (chxWordWrap) + 2,
  112. Y = Pos.Top (chxWordWrap),
  113. CheckedState = textView.AllowsTab ? CheckState.Checked : CheckState.UnChecked,
  114. Text = "_Capture Tabs"
  115. };
  116. chxMultiline.CheckedStateChanging += (s, e) =>
  117. {
  118. textView.Multiline = e.NewValue == CheckState.Checked;
  119. if (!textView.Multiline && chxWordWrap.CheckedState == CheckState.Checked)
  120. {
  121. chxWordWrap.CheckedState = CheckState.UnChecked;
  122. }
  123. if (!textView.Multiline && chxCaptureTabs.CheckedState == CheckState.Checked)
  124. {
  125. chxCaptureTabs.CheckedState = CheckState.UnChecked;
  126. }
  127. };
  128. Key keyTab = textView.KeyBindings.GetKeyFromCommands (Command.Tab);
  129. Key keyBackTab = textView.KeyBindings.GetKeyFromCommands (Command.BackTab);
  130. chxCaptureTabs.CheckedStateChanging += (s, e) =>
  131. {
  132. if (e.NewValue == CheckState.Checked)
  133. {
  134. textView.KeyBindings.Add (keyTab, Command.Tab);
  135. textView.KeyBindings.Add (keyBackTab, Command.BackTab);
  136. }
  137. else
  138. {
  139. textView.KeyBindings.Remove (keyTab);
  140. textView.KeyBindings.Remove (keyBackTab);
  141. }
  142. textView.AllowsTab = e.NewValue == CheckState.Checked;
  143. };
  144. win.Add (chxCaptureTabs);
  145. // Hex editor
  146. label = new() { Text = "_HexView:", Y = Pos.Bottom (chxMultiline) + 1 };
  147. win.Add (label);
  148. var hexEditor =
  149. new HexView (
  150. new MemoryStream (Encoding.UTF8.GetBytes ("HexEditor Unicode that shouldn't 𝔹Aℝ𝔽!"))
  151. )
  152. {
  153. X = Pos.Right (label) + 1, Y = Pos.Bottom (chxMultiline) + 1, Width = Dim.Percent (50) - 1, Height = Dim.Percent (30)
  154. };
  155. win.Add (hexEditor);
  156. var labelMirroringHexEditor = new Label
  157. {
  158. X = Pos.Right (hexEditor) + 1,
  159. Y = Pos.Top (hexEditor),
  160. Width = Dim.Fill (1) - 1,
  161. Height = Dim.Height (hexEditor) - 1
  162. };
  163. byte [] array = ((MemoryStream)hexEditor.Source).ToArray ();
  164. labelMirroringHexEditor.Text = Encoding.UTF8.GetString (array, 0, array.Length);
  165. hexEditor.Edited += (s, kv) =>
  166. {
  167. hexEditor.ApplyEdits ();
  168. byte [] array = ((MemoryStream)hexEditor.Source).ToArray ();
  169. labelMirroringHexEditor.Text = Encoding.UTF8.GetString (array, 0, array.Length);
  170. };
  171. win.Add (labelMirroringHexEditor);
  172. // DateField
  173. label = new() { Text = "_DateField:", Y = Pos.Bottom (hexEditor) + 1 };
  174. win.Add (label);
  175. var dateField = new DateField (DateTime.Now) { X = Pos.Right (label) + 1, Y = Pos.Bottom (hexEditor) + 1, Width = 20 };
  176. win.Add (dateField);
  177. var labelMirroringDateField = new Label
  178. {
  179. X = Pos.Right (dateField) + 1,
  180. Y = Pos.Top (dateField),
  181. Width = Dim.Width (dateField),
  182. Height = Dim.Height (dateField),
  183. Text = dateField.Text
  184. };
  185. win.Add (labelMirroringDateField);
  186. dateField.TextChanged += (s, prev) => { labelMirroringDateField.Text = dateField.Text; };
  187. // TimeField
  188. label = new() { Text = "T_imeField:", Y = Pos.Top (dateField), X = Pos.Right (labelMirroringDateField) + 5 };
  189. win.Add (label);
  190. _timeField = new()
  191. {
  192. X = Pos.Right (label) + 1,
  193. Y = Pos.Top (dateField),
  194. Width = 20,
  195. IsShortFormat = false,
  196. Time = DateTime.Now.TimeOfDay
  197. };
  198. win.Add (_timeField);
  199. _labelMirroringTimeField = new()
  200. {
  201. X = Pos.Right (_timeField) + 1,
  202. Y = Pos.Top (_timeField),
  203. Width = Dim.Width (_timeField),
  204. Height = Dim.Height (_timeField),
  205. Text = _timeField.Text
  206. };
  207. win.Add (_labelMirroringTimeField);
  208. _timeField.TimeChanged += TimeChanged;
  209. // MaskedTextProvider - uses .NET MaskedTextProvider
  210. var netProviderLabel = new Label
  211. {
  212. X = Pos.Left (dateField),
  213. Y = Pos.Bottom (dateField) + 1,
  214. Text = "_NetMaskedTextProvider [ 999 000 LLL >LLL |AAA aaa ]:"
  215. };
  216. win.Add (netProviderLabel);
  217. var netProvider = new NetMaskedTextProvider ("999 000 LLL >LLL |AAA aaa");
  218. var netProviderField = new TextValidateField
  219. {
  220. X = Pos.Right (netProviderLabel) + 1, Y = Pos.Y (netProviderLabel), Provider = netProvider
  221. };
  222. win.Add (netProviderField);
  223. var labelMirroringNetProviderField = new Label
  224. {
  225. X = Pos.Right (netProviderField) + 1,
  226. Y = Pos.Top (netProviderField),
  227. Width = Dim.Width (netProviderField),
  228. Height = Dim.Height (netProviderField),
  229. Text = netProviderField.Text
  230. };
  231. win.Add (labelMirroringNetProviderField);
  232. netProviderField.Provider.TextChanged += (s, prev) => { labelMirroringNetProviderField.Text = netProviderField.Text; };
  233. // TextRegexProvider - Regex provider implemented by Terminal.Gui
  234. var regexProvider = new Label
  235. {
  236. X = Pos.Left (netProviderLabel),
  237. Y = Pos.Bottom (netProviderLabel) + 1,
  238. Text = "Text_RegexProvider [ ^([0-9]?[0-9]?[0-9]|1000)$ ]:"
  239. };
  240. win.Add (regexProvider);
  241. var provider2 = new TextRegexProvider ("^([0-9]?[0-9]?[0-9]|1000)$") { ValidateOnInput = false };
  242. var regexProviderField = new TextValidateField
  243. {
  244. X = Pos.Right (regexProvider) + 1,
  245. Y = Pos.Y (regexProvider),
  246. Width = 30,
  247. TextAlignment = Alignment.Center,
  248. Provider = provider2
  249. };
  250. win.Add (regexProviderField);
  251. var labelMirroringRegexProviderField = new Label
  252. {
  253. X = Pos.Right (regexProviderField) + 1,
  254. Y = Pos.Top (regexProviderField),
  255. Width = Dim.Width (regexProviderField),
  256. Height = Dim.Height (regexProviderField),
  257. Text = regexProviderField.Text
  258. };
  259. win.Add (labelMirroringRegexProviderField);
  260. regexProviderField.Provider.TextChanged += (s, prev) => { labelMirroringRegexProviderField.Text = regexProviderField.Text; };
  261. var labelAppendAutocomplete = new Label
  262. {
  263. Y = Pos.Y (regexProviderField) + 2, X = 1, Text = "_Append Autocomplete:"
  264. };
  265. var appendAutocompleteTextField = new TextField
  266. {
  267. X = Pos.Right (labelAppendAutocomplete) + 1, Y = Pos.Top (labelAppendAutocomplete), Width = Dim.Fill ()
  268. };
  269. appendAutocompleteTextField.Autocomplete = new AppendAutocomplete (appendAutocompleteTextField);
  270. appendAutocompleteTextField.Autocomplete.SuggestionGenerator = new SingleWordSuggestionGenerator
  271. {
  272. AllSuggestions = new()
  273. {
  274. "fish",
  275. "flipper",
  276. "fin",
  277. "fun",
  278. "the",
  279. "at",
  280. "there",
  281. "some",
  282. "my",
  283. "of",
  284. "be",
  285. "use",
  286. "her",
  287. "than",
  288. "and",
  289. "this",
  290. "an",
  291. "would",
  292. "first",
  293. "have",
  294. "each",
  295. "make",
  296. "water",
  297. "to",
  298. "from",
  299. "which",
  300. "like",
  301. "been",
  302. "in",
  303. "or",
  304. "she",
  305. "him",
  306. "call",
  307. "is",
  308. "one",
  309. "do",
  310. "into",
  311. "who",
  312. "you",
  313. "had",
  314. "how",
  315. "time",
  316. "oil",
  317. "that",
  318. "by",
  319. "their",
  320. "has",
  321. "its",
  322. "it",
  323. "word",
  324. "if",
  325. "look",
  326. "now",
  327. "he",
  328. "but",
  329. "will",
  330. "two",
  331. "find",
  332. "was",
  333. "not",
  334. "up",
  335. "more",
  336. "long",
  337. "for",
  338. "what",
  339. "other",
  340. "write",
  341. "down",
  342. "on",
  343. "all",
  344. "about",
  345. "go",
  346. "day",
  347. "are",
  348. "were",
  349. "out",
  350. "see",
  351. "did",
  352. "as",
  353. "we",
  354. "many",
  355. "number",
  356. "get",
  357. "with",
  358. "when",
  359. "then",
  360. "no",
  361. "come",
  362. "his",
  363. "your",
  364. "them",
  365. "way",
  366. "made",
  367. "they",
  368. "can",
  369. "these",
  370. "could",
  371. "may",
  372. "said",
  373. "so",
  374. "people",
  375. "part"
  376. }
  377. };
  378. win.Add (labelAppendAutocomplete);
  379. win.Add (appendAutocompleteTextField);
  380. Label acceptView = new ()
  381. {
  382. X = Pos.Center (),
  383. Y = Pos.AnchorEnd (),
  384. };
  385. win.Add (acceptView);
  386. win.Accepting += WinOnAccept;
  387. Application.Run (win);
  388. win.Dispose ();
  389. Application.Shutdown ();
  390. return;
  391. void WinOnAccept (object sender, CommandEventArgs e)
  392. {
  393. e.Cancel = true; // Don't let it close
  394. acceptView.Text = $"Accept was Invoked via {win.Focused.GetType().Name}";
  395. // Start a task that will set acceptView.Text to an empty string after 1 second
  396. System.Threading.Tasks.Task.Run (async () =>
  397. {
  398. await System.Threading.Tasks.Task.Delay (1000);
  399. Application.Invoke (() => acceptView.Text = "");
  400. });
  401. }
  402. }
  403. private void TimeChanged (object sender, DateTimeEventArgs<TimeSpan> e) { _labelMirroringTimeField.Text = _timeField.Text; }
  404. }