Buttons.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. using System.Collections.Generic;
  2. using System.Text;
  3. using Terminal.Gui;
  4. namespace UICatalog.Scenarios;
  5. [ScenarioMetadata ("Buttons", "Demonstrates all sorts of Buttons.")]
  6. [ScenarioCategory ("Controls")]
  7. [ScenarioCategory ("Layout")]
  8. public class Buttons : Scenario
  9. {
  10. public override void Main ()
  11. {
  12. Window main = new ()
  13. {
  14. Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}",
  15. };
  16. // Add a label & text field so we can demo IsDefault
  17. var editLabel = new Label { X = 0, Y = 0, TabStop = true, Text = "TextField (to demo IsDefault):" };
  18. main.Add (editLabel);
  19. // Add a TextField using Absolute layout.
  20. var edit = new TextField { X = 31, Width = 15, HotKey = Key.Y.WithAlt };
  21. main.Add (edit);
  22. // This is the default button (IsDefault = true); if user presses ENTER in the TextField
  23. // the scenario will quit
  24. var defaultButton = new Button { X = Pos.Center (), Y = Pos.AnchorEnd (1), IsDefault = true, Text = "_Quit" };
  25. defaultButton.Accept += (s, e) => Application.RequestStop ();
  26. main.Add (defaultButton);
  27. var swapButton = new Button { X = 50, Text = "S_wap Default (Absolute Layout)" };
  28. swapButton.Accept += (s, e) =>
  29. {
  30. defaultButton.IsDefault = !defaultButton.IsDefault;
  31. swapButton.IsDefault = !swapButton.IsDefault;
  32. };
  33. main.Add (swapButton);
  34. static void DoMessage (Button button, string txt)
  35. {
  36. button.Accept += (s, e) =>
  37. {
  38. string btnText = button.Text;
  39. MessageBox.Query ("Message", $"Did you click {txt}?", "Yes", "No");
  40. };
  41. }
  42. var colorButtonsLabel = new Label { X = 0, Y = Pos.Bottom (editLabel) + 1, Text = "Color Buttons:" };
  43. main.Add (colorButtonsLabel);
  44. View prev = colorButtonsLabel;
  45. //With this method there is no need to call Application.TopReady += () => Application.TopRedraw (Top.Bounds);
  46. Pos x = Pos.Right (colorButtonsLabel) + 2;
  47. foreach (KeyValuePair<string, ColorScheme> colorScheme in Colors.ColorSchemes)
  48. {
  49. var colorButton = new Button
  50. {
  51. ColorScheme = colorScheme.Value,
  52. X = Pos.Right (prev) + 2,
  53. //X = x,
  54. Y = Pos.Y (colorButtonsLabel),
  55. Text = $"_{colorScheme.Key}"
  56. };
  57. DoMessage (colorButton, colorButton.Text);
  58. main.Add (colorButton);
  59. prev = colorButton;
  60. // BUGBUG: AutoSize is true and the X doesn't change
  61. //x += colorButton.Frame.Width + 2;
  62. }
  63. Button button;
  64. main.Add (
  65. button = new Button
  66. {
  67. X = 2,
  68. Y = Pos.Bottom (colorButtonsLabel) + 1,
  69. Text =
  70. "A super l_öng Button that will probably expose a bug in clipping or wrapping of text. Will it?"
  71. }
  72. );
  73. DoMessage (button, button.Text);
  74. // Note the 'N' in 'Newline' will be the hotkey
  75. main.Add (
  76. button = new Button { X = 2, Y = Pos.Bottom (button) + 1, Text = "a Newline\nin the button" }
  77. );
  78. button.Accept += (s, e) => MessageBox.Query ("Message", "Question?", "Yes", "No");
  79. var textChanger = new Button { X = 2, Y = Pos.Bottom (button) + 1, Text = "Te_xt Changer" };
  80. main.Add (textChanger);
  81. textChanger.Accept += (s, e) => textChanger.Text += "!";
  82. main.Add (
  83. button = new Button
  84. {
  85. X = Pos.Right (textChanger) + 2,
  86. Y = Pos.Y (textChanger),
  87. Text = "Lets see if this will move as \"Text Changer\" grows"
  88. }
  89. );
  90. var removeButton = new Button
  91. {
  92. X = 2, Y = Pos.Bottom (button) + 1, ColorScheme = Colors.ColorSchemes ["Error"], Text = "Remove this button"
  93. };
  94. main.Add (removeButton);
  95. // This in interesting test case because `moveBtn` and below are laid out relative to this one!
  96. removeButton.Accept += (s, e) =>
  97. {
  98. // Now this throw a InvalidOperationException on the TopologicalSort method as is expected.
  99. //main.Remove (removeButton);
  100. removeButton.Visible = false;
  101. };
  102. var computedFrame = new FrameView
  103. {
  104. X = 0,
  105. Y = Pos.Bottom (removeButton) + 1,
  106. Width = Dim.Percent (50),
  107. Height = 5,
  108. Title = "Computed Layout"
  109. };
  110. main.Add (computedFrame);
  111. // Demonstrates how changing the View.Frame property can move Views
  112. var moveBtn = new Button
  113. {
  114. X = 0,
  115. Y = Pos.Center () - 1,
  116. AutoSize = false,
  117. Width = 30,
  118. Height = 1,
  119. ColorScheme = Colors.ColorSchemes ["Error"],
  120. Text = "Move This \u263b Button v_ia Pos"
  121. };
  122. moveBtn.Accept += (s, e) =>
  123. {
  124. moveBtn.X = moveBtn.Frame.X + 5;
  125. // This is already fixed with the call to SetNeedDisplay() in the Pos Dim.
  126. //computedFrame.LayoutSubviews (); // BUGBUG: This call should not be needed. View.X is not causing relayout correctly
  127. };
  128. computedFrame.Add (moveBtn);
  129. // Demonstrates how changing the View.Frame property can SIZE Views (#583)
  130. var sizeBtn = new Button
  131. {
  132. X = 0,
  133. Y = Pos.Center () + 1,
  134. AutoSize = false,
  135. Width = 30,
  136. Height = 1,
  137. ColorScheme = Colors.ColorSchemes ["Error"],
  138. Text = "Size This \u263a Button _via Pos"
  139. };
  140. sizeBtn.Accept += (s, e) =>
  141. {
  142. sizeBtn.Width = sizeBtn.Frame.Width + 5;
  143. //computedFrame.LayoutSubviews (); // FIXED: This call should not be needed. View.X is not causing relayout correctly
  144. };
  145. computedFrame.Add (sizeBtn);
  146. var absoluteFrame = new FrameView
  147. {
  148. X = Pos.Right (computedFrame),
  149. Y = Pos.Bottom (removeButton) + 1,
  150. Width = Dim.Fill (),
  151. Height = 5,
  152. Title = "Absolute Layout"
  153. };
  154. main.Add (absoluteFrame);
  155. // Demonstrates how changing the View.Frame property can move Views
  156. var moveBtnA = new Button { ColorScheme = Colors.ColorSchemes ["Error"], Text = "Move This Button via Frame" };
  157. moveBtnA.Accept += (s, e) =>
  158. {
  159. moveBtnA.Frame = new Rectangle (
  160. moveBtnA.Frame.X + 5,
  161. moveBtnA.Frame.Y,
  162. moveBtnA.Frame.Width,
  163. moveBtnA.Frame.Height
  164. );
  165. };
  166. absoluteFrame.Add (moveBtnA);
  167. // Demonstrates how changing the View.Frame property can SIZE Views (#583)
  168. var sizeBtnA = new Button
  169. {
  170. Y = 2, ColorScheme = Colors.ColorSchemes ["Error"], Text = " ~  s  gui.cs   master ↑_10 = Сохранить"
  171. };
  172. sizeBtnA.Accept += (s, e) =>
  173. {
  174. sizeBtnA.Frame = new Rectangle (
  175. sizeBtnA.Frame.X,
  176. sizeBtnA.Frame.Y,
  177. sizeBtnA.Frame.Width + 5,
  178. sizeBtnA.Frame.Height
  179. );
  180. };
  181. absoluteFrame.Add (sizeBtnA);
  182. var label = new Label
  183. {
  184. X = 2, Y = Pos.Bottom (computedFrame) + 1, Text = "Text Alignment (changes the four buttons above): "
  185. };
  186. main.Add (label);
  187. var radioGroup = new RadioGroup
  188. {
  189. X = 4,
  190. Y = Pos.Bottom (label) + 1,
  191. SelectedItem = 2,
  192. RadioLabels = new [] { "Left", "Right", "Centered", "Justified" }
  193. };
  194. main.Add (radioGroup);
  195. // Demo changing hotkey
  196. string MoveHotkey (string txt)
  197. {
  198. // Remove the '_'
  199. List<Rune> runes = txt.ToRuneList ();
  200. int i = runes.IndexOf ((Rune)'_');
  201. var start = "";
  202. if (i > -1)
  203. {
  204. start = StringExtensions.ToString (runes.GetRange (0, i));
  205. }
  206. txt = start + StringExtensions.ToString (runes.GetRange (i + 1, runes.Count - (i + 1)));
  207. runes = txt.ToRuneList ();
  208. // Move over one or go to start
  209. i++;
  210. if (i >= runes.Count)
  211. {
  212. i = 0;
  213. }
  214. // Slip in the '_'
  215. start = StringExtensions.ToString (runes.GetRange (0, i));
  216. return start + '_' + StringExtensions.ToString (runes.GetRange (i, runes.Count - i));
  217. }
  218. var mhkb = "Click to Change th_is Button's Hotkey";
  219. var moveHotKeyBtn = new Button
  220. {
  221. X = 2,
  222. Y = Pos.Bottom (radioGroup) + 1,
  223. AutoSize = false,
  224. Height = 1,
  225. Width = Dim.Width (computedFrame) - 2,
  226. ColorScheme = Colors.ColorSchemes ["TopLevel"],
  227. Text = mhkb
  228. };
  229. moveHotKeyBtn.Accept += (s, e) => { moveHotKeyBtn.Text = MoveHotkey (moveHotKeyBtn.Text); };
  230. main.Add (moveHotKeyBtn);
  231. var muhkb = " ~  s  gui.cs   master ↑10 = Сохранить";
  232. var moveUnicodeHotKeyBtn = new Button
  233. {
  234. X = Pos.Left (absoluteFrame) + 1,
  235. Y = Pos.Bottom (radioGroup) + 1,
  236. AutoSize = false,
  237. Height = 1,
  238. Width = Dim.Width (absoluteFrame) - 2, // BUGBUG: Not always the width isn't calculated correctly.
  239. ColorScheme = Colors.ColorSchemes ["TopLevel"],
  240. Text = muhkb
  241. };
  242. moveUnicodeHotKeyBtn.Accept += (s, e) => { moveUnicodeHotKeyBtn.Text = MoveHotkey (moveUnicodeHotKeyBtn.Text); };
  243. main.Add (moveUnicodeHotKeyBtn);
  244. radioGroup.SelectedItemChanged += (s, args) =>
  245. {
  246. switch (args.SelectedItem)
  247. {
  248. case 0:
  249. moveBtn.TextAlignment = TextAlignment.Left;
  250. sizeBtn.TextAlignment = TextAlignment.Left;
  251. moveBtnA.TextAlignment = TextAlignment.Left;
  252. sizeBtnA.TextAlignment = TextAlignment.Left;
  253. moveHotKeyBtn.TextAlignment = TextAlignment.Left;
  254. moveUnicodeHotKeyBtn.TextAlignment = TextAlignment.Left;
  255. break;
  256. case 1:
  257. moveBtn.TextAlignment = TextAlignment.Right;
  258. sizeBtn.TextAlignment = TextAlignment.Right;
  259. moveBtnA.TextAlignment = TextAlignment.Right;
  260. sizeBtnA.TextAlignment = TextAlignment.Right;
  261. moveHotKeyBtn.TextAlignment = TextAlignment.Right;
  262. moveUnicodeHotKeyBtn.TextAlignment = TextAlignment.Right;
  263. break;
  264. case 2:
  265. moveBtn.TextAlignment = TextAlignment.Centered;
  266. sizeBtn.TextAlignment = TextAlignment.Centered;
  267. moveBtnA.TextAlignment = TextAlignment.Centered;
  268. sizeBtnA.TextAlignment = TextAlignment.Centered;
  269. moveHotKeyBtn.TextAlignment = TextAlignment.Centered;
  270. moveUnicodeHotKeyBtn.TextAlignment = TextAlignment.Centered;
  271. break;
  272. case 3:
  273. moveBtn.TextAlignment = TextAlignment.Justified;
  274. sizeBtn.TextAlignment = TextAlignment.Justified;
  275. moveBtnA.TextAlignment = TextAlignment.Justified;
  276. sizeBtnA.TextAlignment = TextAlignment.Justified;
  277. moveHotKeyBtn.TextAlignment = TextAlignment.Justified;
  278. moveUnicodeHotKeyBtn.TextAlignment = TextAlignment.Justified;
  279. break;
  280. }
  281. };
  282. label = new Label ()
  283. {
  284. X = 0,
  285. Y = Pos.Bottom (moveUnicodeHotKeyBtn) + 1,
  286. Title = "_Numeric Up/Down (press-and-hold):",
  287. };
  288. var downButton = new Button ()
  289. {
  290. CanFocus = false,
  291. AutoSize = false,
  292. X = Pos.Right(label)+1,
  293. Y = Pos.Top (label),
  294. Height = 1,
  295. Width = 1,
  296. NoPadding = true,
  297. NoDecorations = true,
  298. Title = $"{CM.Glyphs.DownArrow}",
  299. WantContinuousButtonPressed = true,
  300. };
  301. var numericEdit = new TextField ()
  302. {
  303. Text = "1966",
  304. X = Pos.Right (downButton),
  305. Y = Pos.Top (downButton),
  306. Width = 5,
  307. Height = 1,
  308. };
  309. var upButton = new Button ()
  310. {
  311. CanFocus = false,
  312. AutoSize = false,
  313. X = Pos.Right (numericEdit),
  314. Y = Pos.Top (numericEdit),
  315. Height = 1,
  316. Width = 1,
  317. NoPadding = true,
  318. NoDecorations = true,
  319. Title = $"{CM.Glyphs.UpArrow}",
  320. WantContinuousButtonPressed = true,
  321. };
  322. downButton.Accept += (s, e) =>
  323. {
  324. numericEdit.Text = $"{int.Parse(numericEdit.Text) - 1}";
  325. };
  326. upButton.Accept += (s, e) =>
  327. {
  328. numericEdit.Text = $"{int.Parse (numericEdit.Text) + 1}";
  329. };
  330. main.Add (label, downButton, numericEdit, upButton);
  331. label = new Label ()
  332. {
  333. X = 0,
  334. Y = Pos.Bottom (label) + 1,
  335. Title = "_No Repeat:",
  336. };
  337. int noRepeatAcceptCount = 0;
  338. var noRepeatButton = new Button ()
  339. {
  340. X = Pos.Right (label) + 1,
  341. Y = Pos.Top (label),
  342. Title = $"Accept Cou_nt: {noRepeatAcceptCount}",
  343. WantContinuousButtonPressed = false,
  344. };
  345. noRepeatButton.Accept += (s, e) =>
  346. {
  347. noRepeatButton.Title = $"Accept Cou_nt: {++noRepeatAcceptCount}";
  348. };
  349. main.Add(label, noRepeatButton);
  350. label = new Label ()
  351. {
  352. X = 0,
  353. Y = Pos.Bottom (label) + 1,
  354. Title = "_Repeat (press-and-hold):",
  355. };
  356. int acceptCount = 0;
  357. var repeatButton = new Button ()
  358. {
  359. X = Pos.Right (label) + 1,
  360. Y = Pos.Top (label),
  361. Title = $"Accept Co_unt: {acceptCount}",
  362. WantContinuousButtonPressed = true,
  363. };
  364. repeatButton.Accept += (s, e) =>
  365. {
  366. repeatButton.Title = $"Accept Co_unt: {++acceptCount}";
  367. };
  368. var enableCB = new CheckBox ()
  369. {
  370. X = Pos.Right (repeatButton) + 1,
  371. Y = Pos.Top (repeatButton),
  372. Title = "Enabled",
  373. Checked = true,
  374. };
  375. enableCB.Toggled += (s, e) =>
  376. {
  377. repeatButton.Enabled = !repeatButton.Enabled;
  378. };
  379. main.Add(label, repeatButton, enableCB);
  380. main.Ready += (s, e) => radioGroup.Refresh ();
  381. Application.Run (main);
  382. main.Dispose ();
  383. }
  384. }