Shortcuts.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. #nullable enable
  2. using System.Collections.ObjectModel;
  3. using Timer = System.Timers.Timer;
  4. namespace UICatalog.Scenarios;
  5. [ScenarioMetadata ("Shortcuts", "Illustrates Shortcut class.")]
  6. [ScenarioCategory ("Controls")]
  7. public class Shortcuts : Scenario
  8. {
  9. public override void Main ()
  10. {
  11. Application.Init ();
  12. var quitKey = Application.QuitKey;
  13. Window app = new ();
  14. app.IsModalChanged += App_Loaded;
  15. Application.Run (app);
  16. app.Dispose ();
  17. Application.Shutdown ();
  18. Application.QuitKey = quitKey;
  19. }
  20. // Setting everything up in Loaded handler because we change the
  21. // QuitKey and it only sticks if changed after init
  22. private void App_Loaded (object? sender, EventArgs e)
  23. {
  24. Application.QuitKey = Key.F4.WithCtrl;
  25. Application.TopRunnableView!.Title = GetQuitKeyAndName ();
  26. ObservableCollection<string> eventSource = new ();
  27. var eventLog = new ListView
  28. {
  29. Id = "eventLog",
  30. X = Pos.AnchorEnd (),
  31. Y = 0,
  32. Height = Dim.Fill (4),
  33. SchemeName = "Runnable",
  34. Source = new ListWrapper<string> (eventSource),
  35. BorderStyle = LineStyle.Double,
  36. Title = "E_vents"
  37. };
  38. eventLog.Width = Dim.Func (
  39. _ => Math.Min (
  40. Application.TopRunnableView.Viewport.Width / 2,
  41. eventLog?.MaxLength + eventLog!.GetAdornmentsThickness ().Horizontal ?? 0));
  42. eventLog.Width = Dim.Func (
  43. _ => Math.Min (
  44. eventLog.SuperView!.Viewport.Width / 2,
  45. eventLog?.MaxLength + eventLog!.GetAdornmentsThickness ().Horizontal ?? 0));
  46. Application.TopRunnableView.Add (eventLog);
  47. var alignKeysShortcut = new Shortcut
  48. {
  49. Id = "alignKeysShortcut",
  50. X = 0,
  51. Y = 0,
  52. Width = Dim.Fill ()! - Dim.Width (eventLog),
  53. HelpText = "Fill to log",
  54. CommandView = new CheckBox
  55. {
  56. Text = "_Align Keys",
  57. CanFocus = false,
  58. HighlightStates = MouseState.None,
  59. CheckedState = CheckState.Checked
  60. },
  61. Key = Key.F5.WithCtrl.WithAlt.WithShift
  62. };
  63. ((CheckBox)alignKeysShortcut.CommandView).CheckedStateChanging += (s, e) =>
  64. {
  65. if (alignKeysShortcut.CommandView is CheckBox cb)
  66. {
  67. bool align = e.Result == CheckState.Checked;
  68. eventSource.Add (
  69. $"{alignKeysShortcut.Id}.CommandView.CheckedStateChanging: {cb.Text}");
  70. eventLog.MoveDown ();
  71. AlignKeys (align);
  72. }
  73. };
  74. Application.TopRunnableView.Add (alignKeysShortcut);
  75. var commandFirstShortcut = new Shortcut
  76. {
  77. Id = "commandFirstShortcut",
  78. X = 0,
  79. Y = Pos.Bottom (alignKeysShortcut),
  80. Width = Dim.Fill ()! - Dim.Width (eventLog),
  81. HelpText = "Show _Command first",
  82. CommandView = new CheckBox
  83. {
  84. Text = "Command _First",
  85. CanFocus = false,
  86. HighlightStates = MouseState.None
  87. },
  88. Key = Key.F.WithCtrl
  89. };
  90. ((CheckBox)commandFirstShortcut.CommandView).CheckedState =
  91. commandFirstShortcut.AlignmentModes.HasFlag (AlignmentModes.EndToStart) ? CheckState.UnChecked : CheckState.Checked;
  92. ((CheckBox)commandFirstShortcut.CommandView).CheckedStateChanging += (s, e) =>
  93. {
  94. if (commandFirstShortcut.CommandView is CheckBox cb)
  95. {
  96. eventSource.Add (
  97. $"{commandFirstShortcut.Id}.CommandView.CheckedStateChanging: {cb.Text}");
  98. eventLog.MoveDown ();
  99. IEnumerable<View> toAlign = Application.TopRunnableView.SubViews.OfType<Shortcut> ();
  100. IEnumerable<View> enumerable = toAlign as View [] ?? toAlign.ToArray ();
  101. foreach (View view in enumerable)
  102. {
  103. var peer = (Shortcut)view;
  104. if (e.Result == CheckState.Checked)
  105. {
  106. peer.AlignmentModes &= ~AlignmentModes.EndToStart;
  107. }
  108. else
  109. {
  110. peer.AlignmentModes |= AlignmentModes.EndToStart;
  111. }
  112. }
  113. }
  114. };
  115. Application.TopRunnableView.Add (commandFirstShortcut);
  116. var canFocusShortcut = new Shortcut
  117. {
  118. Id = "canFocusShortcut",
  119. X = 0,
  120. Y = Pos.Bottom (commandFirstShortcut),
  121. Width = Dim.Fill ()! - Dim.Width (eventLog),
  122. Key = Key.F4,
  123. HelpText = "Changes all CommandView.CanFocus",
  124. CommandView = new CheckBox { Text = "_CommandView.CanFocus" },
  125. };
  126. ((CheckBox)canFocusShortcut.CommandView).CheckedStateChanging += (s, e) =>
  127. {
  128. if (canFocusShortcut.CommandView is CheckBox cb)
  129. {
  130. eventSource.Add ($"Toggle: {cb.Text}");
  131. eventLog.MoveDown ();
  132. //cb.CanFocus = e.NewValue == CheckState.Checked;
  133. SetCanFocus (e.Result == CheckState.Checked);
  134. }
  135. };
  136. Application.TopRunnableView.Add (canFocusShortcut);
  137. var appShortcut = new Shortcut
  138. {
  139. Id = "appShortcut",
  140. X = 0,
  141. Y = Pos.Bottom (canFocusShortcut),
  142. Width = Dim.Fill (Dim.Func (_ => eventLog.Frame.Width)),
  143. Title = "A_pp Shortcut",
  144. Key = Key.F1,
  145. Text = "Width is DimFill",
  146. BindKeyToApplication = true
  147. };
  148. Application.TopRunnableView.Add (appShortcut);
  149. var buttonShortcut = new Shortcut
  150. {
  151. Id = "buttonShortcut",
  152. X = 0,
  153. Y = Pos.Bottom (appShortcut),
  154. Width = Dim.Fill ()! - Dim.Width (eventLog),
  155. HelpText = "Accepting pops MB",
  156. CommandView = new Button
  157. {
  158. Title = "_Button",
  159. ShadowStyle = ShadowStyle.None,
  160. HighlightStates = MouseState.None
  161. },
  162. Key = Key.K
  163. };
  164. var button = (Button)buttonShortcut.CommandView;
  165. buttonShortcut.Accepting += Button_Clicked;
  166. Application.TopRunnableView.Add (buttonShortcut);
  167. var optionSelectorShortcut = new Shortcut
  168. {
  169. Id = "optionSelectorShortcut",
  170. HelpText = "Option Selector",
  171. X = 0,
  172. Y = Pos.Bottom (buttonShortcut),
  173. Key = Key.F2,
  174. Width = Dim.Fill ()! - Dim.Width (eventLog),
  175. CommandView = new OptionSelector ()
  176. {
  177. Orientation = Orientation.Vertical,
  178. Labels = ["O_ne", "T_wo", "Th_ree", "Fo_ur"],
  179. HighlightStates = MouseState.None,
  180. },
  181. };
  182. ((OptionSelector)optionSelectorShortcut.CommandView).ValueChanged += (o, args) =>
  183. {
  184. if (o is { })
  185. {
  186. eventSource.Add (
  187. $"ValueChanged: {o.GetType ().Name} - {args.Value}");
  188. eventLog.MoveDown ();
  189. }
  190. };
  191. Application.TopRunnableView.Add (optionSelectorShortcut);
  192. var sliderShortcut = new Shortcut
  193. {
  194. Id = "sliderShortcut",
  195. X = 0,
  196. Y = Pos.Bottom (optionSelectorShortcut),
  197. Width = Dim.Fill ()! - Dim.Width (eventLog),
  198. HelpText = "Sliders work!",
  199. CommandView = new Slider<string>
  200. {
  201. Orientation = Orientation.Horizontal,
  202. AllowEmpty = true
  203. },
  204. Key = Key.F5
  205. };
  206. ((Slider<string>)sliderShortcut.CommandView).Options = [new () { Legend = "A" }, new () { Legend = "B" }, new () { Legend = "C" }];
  207. ((Slider<string>)sliderShortcut.CommandView).SetOption (0);
  208. ((Slider<string>)sliderShortcut.CommandView).OptionsChanged += (o, args) =>
  209. {
  210. eventSource.Add (
  211. $"OptionsChanged: {o?.GetType ().Name} - {string.Join (",", ((Slider<string>)o!)!.GetSetOptions ())}");
  212. eventLog.MoveDown ();
  213. };
  214. Application.TopRunnableView.Add (sliderShortcut);
  215. ListView listView = new ListView ()
  216. {
  217. Height = Dim.Auto (),
  218. Width = Dim.Auto (),
  219. Title = "ListView",
  220. BorderStyle = LineStyle.Single
  221. };
  222. listView.EnableForDesign ();
  223. var listViewShortcut = new Shortcut ()
  224. {
  225. Id = "listViewShortcut",
  226. X = 0,
  227. Y = Pos.Bottom (sliderShortcut),
  228. Width = Dim.Fill ()! - Dim.Width (eventLog),
  229. HelpText = "A ListView with Border",
  230. CommandView = listView,
  231. Key = Key.F5.WithCtrl,
  232. };
  233. Application.TopRunnableView.Add (listViewShortcut);
  234. var noCommandShortcut = new Shortcut
  235. {
  236. Id = "noCommandShortcut",
  237. X = 0,
  238. Y = Pos.Bottom (listViewShortcut),
  239. Width = Dim.Width (listViewShortcut),
  240. HelpText = "No Command",
  241. Key = Key.D0
  242. };
  243. Application.TopRunnableView.Add (noCommandShortcut);
  244. var noKeyShortcut = new Shortcut
  245. {
  246. Id = "noKeyShortcut",
  247. X = 0,
  248. Y = Pos.Bottom (noCommandShortcut),
  249. Width = Dim.Width (noCommandShortcut),
  250. Title = "No Ke_y",
  251. HelpText = "Keyless"
  252. };
  253. Application.TopRunnableView.Add (noKeyShortcut);
  254. var noHelpShortcut = new Shortcut
  255. {
  256. Id = "noHelpShortcut",
  257. X = 0,
  258. Y = Pos.Bottom (noKeyShortcut),
  259. Width = Dim.Width (noKeyShortcut),
  260. Key = Key.F6,
  261. Title = "Not _very much help",
  262. HelpText = ""
  263. };
  264. Application.TopRunnableView.Add (noHelpShortcut);
  265. noHelpShortcut.SetFocus ();
  266. var framedShortcut = new Shortcut
  267. {
  268. Id = "framedShortcut",
  269. X = 0,
  270. Y = Pos.Bottom (noHelpShortcut) + 1,
  271. Width = Dim.Width (noHelpShortcut),
  272. Title = "Framed Shortcut",
  273. Key = Key.K.WithCtrl,
  274. Text = "Help: You can resize this",
  275. BorderStyle = LineStyle.Dotted,
  276. Arrangement = ViewArrangement.RightResizable | ViewArrangement.BottomResizable
  277. };
  278. framedShortcut.Border!.Settings = BorderSettings.Title;
  279. //framedShortcut.Orientation = Orientation.Horizontal;
  280. if (framedShortcut.Padding is { })
  281. {
  282. framedShortcut.Padding.Thickness = new (0, 1, 0, 0);
  283. framedShortcut.Padding.Diagnostics = ViewDiagnosticFlags.Ruler;
  284. }
  285. if (framedShortcut.CommandView.Margin is { })
  286. {
  287. framedShortcut.CommandView.SchemeName = framedShortcut.CommandView.SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Dialog);
  288. framedShortcut.HelpView.SchemeName = framedShortcut.HelpView.SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Error);
  289. framedShortcut.KeyView.SchemeName = framedShortcut.KeyView.SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Base);
  290. }
  291. framedShortcut.SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Runnable);
  292. Application.TopRunnableView.Add (framedShortcut);
  293. // Horizontal
  294. var progressShortcut = new Shortcut
  295. {
  296. Id = "progressShortcut",
  297. X = Pos.Align (Alignment.Start, AlignmentModes.IgnoreFirstOrLast, 1),
  298. Y = Pos.AnchorEnd () - 1,
  299. Key = Key.F7,
  300. HelpText = "Horizontal"
  301. };
  302. progressShortcut.CommandView = new ProgressBar
  303. {
  304. Text = "Progress",
  305. Title = "P",
  306. Fraction = 0.5f,
  307. Width = 10,
  308. Height = 1,
  309. ProgressBarStyle = ProgressBarStyle.Continuous
  310. };
  311. progressShortcut.CommandView.Width = 10;
  312. progressShortcut.CommandView.Height = 1;
  313. progressShortcut.CommandView.CanFocus = false;
  314. Timer timer = new (10)
  315. {
  316. AutoReset = true
  317. };
  318. timer.Elapsed += (o, args) =>
  319. {
  320. if (progressShortcut.CommandView is ProgressBar pb)
  321. {
  322. if (pb.Fraction == 1.0)
  323. {
  324. pb.Fraction = 0;
  325. }
  326. pb.Fraction += 0.01f;
  327. pb.SetNeedsDraw ();
  328. }
  329. };
  330. timer.Start ();
  331. Application.TopRunnableView.Add (progressShortcut);
  332. var textField = new TextField
  333. {
  334. Text = "Edit me",
  335. Width = 10,
  336. Height = 1
  337. };
  338. var textFieldShortcut = new Shortcut
  339. {
  340. Id = "textFieldShortcut",
  341. X = Pos.Align (Alignment.Start, AlignmentModes.IgnoreFirstOrLast, 1),
  342. Y = Pos.AnchorEnd () - 1,
  343. Key = Key.F8,
  344. HelpText = "TextField",
  345. CanFocus = true,
  346. CommandView = textField
  347. };
  348. textField.CanFocus = true;
  349. Application.TopRunnableView.Add (textFieldShortcut);
  350. var bgColorShortcut = new Shortcut
  351. {
  352. Id = "bgColorShortcut",
  353. X = Pos.Align (Alignment.Start, AlignmentModes.IgnoreFirstOrLast, 1),
  354. Y = Pos.AnchorEnd (),
  355. Key = Key.F9,
  356. HelpText = "Cycles BG Color"
  357. };
  358. var bgColor = new ColorPicker16
  359. {
  360. BoxHeight = 1,
  361. BoxWidth = 1
  362. };
  363. bgColorShortcut.Activating += (o, args) =>
  364. {
  365. //args.Cancel = true;
  366. };
  367. bgColorShortcut.Accepting += (o, args) =>
  368. {
  369. if (bgColor.SelectedColor == ColorName16.White)
  370. {
  371. bgColor.SelectedColor = ColorName16.Black;
  372. return;
  373. }
  374. bgColor.SelectedColor++;
  375. args.Handled = true;
  376. };
  377. bgColor.ColorChanged += (o, args) =>
  378. {
  379. if (o is { })
  380. {
  381. eventSource.Add ($"ColorChanged: {o.GetType ().Name} - {args.Result}");
  382. eventLog.MoveDown ();
  383. Application.TopRunnableView.SetScheme (
  384. new (Application.TopRunnableView.GetScheme ())
  385. {
  386. Normal = new (
  387. Application.TopRunnableView!.GetAttributeForRole (VisualRole.Normal).Foreground,
  388. args.Result,
  389. Application.TopRunnableView!.GetAttributeForRole (VisualRole.Normal).Style)
  390. });
  391. }
  392. };
  393. bgColorShortcut.CommandView = bgColor;
  394. Application.TopRunnableView.Add (bgColorShortcut);
  395. var appQuitShortcut = new Shortcut
  396. {
  397. Id = "appQuitShortcut",
  398. X = Pos.Align (Alignment.Start, AlignmentModes.IgnoreFirstOrLast, 1),
  399. Y = Pos.AnchorEnd () - 1,
  400. Key = Key.Esc,
  401. BindKeyToApplication = true,
  402. Title = "Quit",
  403. HelpText = "App Scope"
  404. };
  405. appQuitShortcut.Accepting += (o, args) => { Application.RequestStop (); };
  406. Application.TopRunnableView.Add (appQuitShortcut);
  407. foreach (Shortcut shortcut in Application.TopRunnableView.SubViews.OfType<Shortcut> ())
  408. {
  409. shortcut.Activating += (o, args) =>
  410. {
  411. if (args.Handled)
  412. {
  413. return;
  414. }
  415. eventSource.Add ($"{shortcut!.Id}.Activating: {shortcut!.CommandView.Text} {shortcut!.CommandView.GetType ().Name}");
  416. eventLog.MoveDown ();
  417. };
  418. shortcut.CommandView.Activating += (o, args) =>
  419. {
  420. if (args.Handled)
  421. {
  422. return;
  423. }
  424. eventSource.Add (
  425. $"{shortcut!.Id}.CommandView.Activating: {shortcut!.CommandView.Text} {shortcut!.CommandView.GetType ().Name}");
  426. eventLog.MoveDown ();
  427. //args.Handled = true;
  428. };
  429. shortcut.Accepting += (o, args) =>
  430. {
  431. eventSource.Add ($"{shortcut!.Id}.Accepting: {shortcut!.CommandView.Text} {shortcut!.CommandView.GetType ().Name}");
  432. eventLog.MoveDown ();
  433. // We don't want this to exit the Scenario
  434. //args.Handled = true;
  435. };
  436. shortcut.CommandView.Accepting += (o, args) =>
  437. {
  438. eventSource.Add (
  439. $"{shortcut!.Id}.CommandView.Accepting: {shortcut!.CommandView.Text} {shortcut!.CommandView.GetType ().Name}");
  440. eventLog.MoveDown ();
  441. };
  442. }
  443. SetCanFocus (false);
  444. AlignKeys (true);
  445. return;
  446. void SetCanFocus (bool canFocus)
  447. {
  448. foreach (Shortcut peer in Application.TopRunnableView!.SubViews.OfType<Shortcut> ())
  449. {
  450. if (peer.CanFocus)
  451. {
  452. peer.CommandView.CanFocus = canFocus;
  453. }
  454. }
  455. }
  456. void AlignKeys (bool align)
  457. {
  458. var max = 0;
  459. IEnumerable<Shortcut> toAlign = Application.TopRunnableView!.SubViews.OfType<Shortcut> ().Where(s => !s.Y.Has<PosAnchorEnd>(out _)).Cast<Shortcut>();
  460. IEnumerable<Shortcut> enumerable = toAlign as Shortcut [] ?? toAlign.ToArray ();
  461. if (align)
  462. {
  463. max = (from Shortcut? peer in enumerable
  464. select peer!.Key.ToString ().GetColumns ()).Prepend (max)
  465. .Max ();
  466. max = enumerable.Select (peer => peer.KeyView.Text.GetColumns ()).Prepend (max).Max ();
  467. }
  468. foreach (Shortcut shortcut in enumerable)
  469. {
  470. Shortcut peer = shortcut;
  471. peer.MinimumKeyTextSize = max;
  472. }
  473. }
  474. }
  475. private void Button_Clicked (object? sender, CommandEventArgs e)
  476. {
  477. e.Handled = true;
  478. var view = sender as View;
  479. MessageBox.Query ((sender as View)?.App, "Hi", $"You clicked {view?.Text}", "_Ok");
  480. }
  481. }