UICatalogTop.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. using System.Collections.ObjectModel;
  2. using System.Diagnostics;
  3. using System.Runtime.InteropServices;
  4. using System.Text;
  5. using System.Text.Json.Serialization;
  6. using Microsoft.Extensions.Logging;
  7. using RuntimeEnvironment = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment;
  8. #nullable enable
  9. namespace UICatalog;
  10. /// <summary>
  11. /// This is the main UI Catalog app view. It is run fresh when the app loads (if a Scenario has not been passed on
  12. /// the command line) and each time a Scenario ends.
  13. /// </summary>
  14. public class UICatalogTop : Toplevel
  15. {
  16. // When a scenario is run, the main app is killed. The static
  17. // members are cached so that when the scenario exits the
  18. // main app UI can be restored to previous state
  19. // Note, we used to pass this to scenarios that run, but it just added complexity
  20. // So that was removed. But we still have this here to demonstrate how changing
  21. // the scheme works.
  22. public static string? CachedTopLevelScheme { get; set; }
  23. // Diagnostics
  24. private static ViewDiagnosticFlags _diagnosticFlags;
  25. public UICatalogTop ()
  26. {
  27. _diagnosticFlags = Diagnostics;
  28. _menuBar = CreateMenuBar ();
  29. _statusBar = CreateStatusBar ();
  30. _categoryList = CreateCategoryList ();
  31. _scenarioList = CreateScenarioList ();
  32. Add (_menuBar, _categoryList, _scenarioList, _statusBar);
  33. Loaded += LoadedHandler;
  34. Unloaded += UnloadedHandler;
  35. // Restore previous selections
  36. _categoryList.SelectedItem = _cachedCategoryIndex;
  37. _scenarioList.SelectedRow = _cachedScenarioIndex;
  38. SchemeName = CachedTopLevelScheme = SchemeManager.SchemesToSchemeName (Schemes.Base);
  39. ConfigurationManager.Applied += ConfigAppliedHandler;
  40. }
  41. private static bool _isFirstRunning = true;
  42. private void LoadedHandler (object? sender, EventArgs? args)
  43. {
  44. if (_disableMouseCb is { })
  45. {
  46. _disableMouseCb.CheckedState = Application.IsMouseDisabled ? CheckState.Checked : CheckState.UnChecked;
  47. }
  48. if (_shVersion is { })
  49. {
  50. _shVersion.Title = $"{RuntimeEnvironment.OperatingSystem} {RuntimeEnvironment.OperatingSystemVersion}, {Application.Driver!.GetVersionInfo ()}";
  51. }
  52. if (CachedSelectedScenario != null)
  53. {
  54. CachedSelectedScenario = null;
  55. _isFirstRunning = false;
  56. }
  57. if (!_isFirstRunning)
  58. {
  59. _scenarioList.SetFocus ();
  60. }
  61. if (_statusBar is { })
  62. {
  63. _statusBar.VisibleChanged += (s, e) => { ShowStatusBar = _statusBar.Visible; };
  64. }
  65. Loaded -= LoadedHandler;
  66. _categoryList!.EnsureSelectedItemVisible ();
  67. _scenarioList.EnsureSelectedCellIsVisible ();
  68. }
  69. private void UnloadedHandler (object? sender, EventArgs? args)
  70. {
  71. ConfigurationManager.Applied -= ConfigAppliedHandler;
  72. Unloaded -= UnloadedHandler;
  73. }
  74. #region MenuBar
  75. private readonly MenuBarv2? _menuBar;
  76. private CheckBox? _force16ColorsMenuItemCb;
  77. private OptionSelector? _themesRg;
  78. private OptionSelector? _topSchemeRg;
  79. private OptionSelector? _logLevelRg;
  80. private FlagSelector<ViewDiagnosticFlags>? _diagnosticFlagsSelector;
  81. private CheckBox? _disableMouseCb;
  82. private MenuBarv2 CreateMenuBar ()
  83. {
  84. MenuBarv2 menuBar = new (
  85. [
  86. new (
  87. "_File",
  88. [
  89. new MenuItemv2 ()
  90. {
  91. Title ="_Quit",
  92. HelpText = "Quit UI Catalog",
  93. Key = Application.QuitKey,
  94. // By not specifying TargetView the Key Binding will be Application-level
  95. Command = Command.Quit
  96. }
  97. ]),
  98. new ("_Themes", CreateThemeMenuItems ()),
  99. new ("Diag_nostics", CreateDiagnosticMenuItems ()),
  100. new ("_Logging", CreateLoggingMenuItems ()),
  101. new (
  102. "_Help",
  103. [
  104. new MenuItemv2 (
  105. "_Documentation",
  106. "",
  107. () => OpenUrl ("https://gui-cs.github.io/Terminal.Gui"),
  108. Key.F1
  109. ),
  110. new MenuItemv2 (
  111. "_README",
  112. "",
  113. () => OpenUrl ("https://github.com/gui-cs/Terminal.Gui"),
  114. Key.F2
  115. ),
  116. new MenuItemv2 (
  117. "_About...",
  118. "About UI Catalog",
  119. () => MessageBox.Query (
  120. "",
  121. GetAboutBoxMessage (),
  122. wrapMessage: false,
  123. buttons: "_Ok"
  124. ),
  125. Key.A.WithCtrl
  126. )
  127. ])
  128. ])
  129. {
  130. Title = "menuBar",
  131. Id = "menuBar"
  132. };
  133. return menuBar;
  134. View [] CreateThemeMenuItems ()
  135. {
  136. List<View> menuItems = [];
  137. _force16ColorsMenuItemCb = new ()
  138. {
  139. Title = "Force _16 Colors",
  140. CheckedState = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked
  141. };
  142. _force16ColorsMenuItemCb.CheckedStateChanging += (sender, args) =>
  143. {
  144. if (Application.Force16Colors
  145. && args.Result == CheckState.UnChecked
  146. && !Application.Driver!.SupportsTrueColor)
  147. {
  148. args.Handled = true;
  149. }
  150. };
  151. _force16ColorsMenuItemCb.CheckedStateChanged += (sender, args) =>
  152. {
  153. Application.Force16Colors = args.Value == CheckState.Checked;
  154. _force16ColorsShortcutCb!.CheckedState = args.Value;
  155. Application.LayoutAndDraw ();
  156. };
  157. menuItems.Add (
  158. new MenuItemv2
  159. {
  160. CommandView = _force16ColorsMenuItemCb
  161. });
  162. menuItems.Add (new Line ());
  163. if (ConfigurationManager.IsEnabled)
  164. {
  165. _themesRg = new ()
  166. {
  167. HighlightStates = Terminal.Gui.ViewBase.MouseState.None,
  168. };
  169. _themesRg.SelectedItemChanged += (_, args) =>
  170. {
  171. if (args.SelectedItem is null)
  172. {
  173. return;
  174. }
  175. ThemeManager.Theme = ThemeManager.GetThemeNames () [args.SelectedItem!.Value];
  176. };
  177. var menuItem = new MenuItemv2
  178. {
  179. CommandView = _themesRg,
  180. HelpText = "Cycle Through Themes",
  181. Key = Key.T.WithCtrl
  182. };
  183. menuItems.Add (menuItem);
  184. menuItems.Add (new Line ());
  185. _topSchemeRg = new ()
  186. {
  187. HighlightStates = Terminal.Gui.ViewBase.MouseState.None,
  188. };
  189. _topSchemeRg.SelectedItemChanged += (_, args) =>
  190. {
  191. if (args.SelectedItem is null)
  192. {
  193. return;
  194. }
  195. CachedTopLevelScheme = SchemeManager.GetSchemesForCurrentTheme ()!.Keys.ToArray () [args.SelectedItem!.Value];
  196. SchemeName = CachedTopLevelScheme;
  197. SetNeedsDraw ();
  198. };
  199. menuItem = new ()
  200. {
  201. Title = "Scheme for Toplevel",
  202. SubMenu = new (
  203. [
  204. new ()
  205. {
  206. CommandView = _topSchemeRg,
  207. HelpText = "Cycle Through schemes",
  208. Key = Key.S.WithCtrl
  209. }
  210. ])
  211. };
  212. menuItems.Add (menuItem);
  213. UpdateThemesMenu ();
  214. }
  215. else
  216. {
  217. menuItems.Add (new MenuItemv2 ()
  218. {
  219. Title = "Configuration Manager is not Enabled",
  220. Enabled = false
  221. });
  222. }
  223. return menuItems.ToArray ();
  224. }
  225. View [] CreateDiagnosticMenuItems ()
  226. {
  227. List<View> menuItems = [];
  228. _diagnosticFlagsSelector = new ()
  229. {
  230. CanFocus = true,
  231. Styles = FlagSelectorStyles.ShowNone,
  232. HighlightStates = Terminal.Gui.ViewBase.MouseState.None,
  233. };
  234. _diagnosticFlagsSelector.UsedHotKeys.Add (Key.D);
  235. _diagnosticFlagsSelector.AssignHotKeysToCheckBoxes = true;
  236. _diagnosticFlagsSelector.Value = Diagnostics;
  237. _diagnosticFlagsSelector.ValueChanged += (sender, args) =>
  238. {
  239. _diagnosticFlags = (ViewDiagnosticFlags)_diagnosticFlagsSelector.Value;
  240. Diagnostics = _diagnosticFlags;
  241. };
  242. menuItems.Add (
  243. new MenuItemv2
  244. {
  245. CommandView = _diagnosticFlagsSelector,
  246. HelpText = "View Diagnostics"
  247. });
  248. menuItems.Add (new Line ());
  249. _disableMouseCb = new ()
  250. {
  251. Title = "_Disable Mouse",
  252. CheckedState = Application.IsMouseDisabled ? CheckState.Checked : CheckState.UnChecked
  253. };
  254. _disableMouseCb.CheckedStateChanged += (_, args) => { Application.IsMouseDisabled = args.Value == CheckState.Checked; };
  255. menuItems.Add (
  256. new MenuItemv2
  257. {
  258. CommandView = _disableMouseCb,
  259. HelpText = "Disable Mouse"
  260. });
  261. return menuItems.ToArray ();
  262. }
  263. View [] CreateLoggingMenuItems ()
  264. {
  265. List<View?> menuItems = [];
  266. LogLevel [] logLevels = Enum.GetValues<LogLevel> ();
  267. _logLevelRg = new ()
  268. {
  269. AssignHotKeysToCheckBoxes = true,
  270. Options = Enum.GetNames<LogLevel> (),
  271. SelectedItem = logLevels.ToList ().IndexOf (Enum.Parse<LogLevel> (UICatalog.Options.DebugLogLevel)),
  272. HighlightStates = Terminal.Gui.ViewBase.MouseState.In
  273. };
  274. _logLevelRg.SelectedItemChanged += (_, args) =>
  275. {
  276. UICatalog.Options = UICatalog.Options with { DebugLogLevel = Enum.GetName (logLevels [args.SelectedItem!.Value])! };
  277. UICatalog.LogLevelSwitch.MinimumLevel =
  278. UICatalog.LogLevelToLogEventLevel (Enum.Parse<LogLevel> (UICatalog.Options.DebugLogLevel));
  279. };
  280. menuItems.Add (
  281. new MenuItemv2
  282. {
  283. CommandView = _logLevelRg,
  284. HelpText = "Cycle Through Log Levels",
  285. Key = Key.L.WithCtrl
  286. });
  287. // add a separator
  288. menuItems.Add (new Line ());
  289. menuItems.Add (
  290. new MenuItemv2 (
  291. "_Open Log Folder",
  292. string.Empty,
  293. () => OpenUrl (UICatalog.LOGFILE_LOCATION)
  294. ));
  295. return menuItems.ToArray ()!;
  296. }
  297. }
  298. private void UpdateThemesMenu ()
  299. {
  300. if (_themesRg is null)
  301. {
  302. return;
  303. }
  304. _themesRg.SelectedItem = null;
  305. _themesRg.AssignHotKeysToCheckBoxes = true;
  306. _themesRg.UsedHotKeys.Clear ();
  307. _themesRg.Options = ThemeManager.GetThemeNames ();
  308. _themesRg.SelectedItem =ThemeManager.GetThemeNames ().IndexOf (ThemeManager.GetCurrentThemeName ());
  309. if (_topSchemeRg is null)
  310. {
  311. return;
  312. }
  313. _topSchemeRg.AssignHotKeysToCheckBoxes = true;
  314. _topSchemeRg.UsedHotKeys.Clear ();
  315. int? selectedScheme = _topSchemeRg.SelectedItem;
  316. _topSchemeRg.Options = SchemeManager.GetSchemeNames ();
  317. _topSchemeRg.SelectedItem = selectedScheme;
  318. if (CachedTopLevelScheme is null || !SchemeManager.GetSchemeNames ().Contains (CachedTopLevelScheme))
  319. {
  320. CachedTopLevelScheme = SchemeManager.SchemesToSchemeName (Schemes.Base);
  321. }
  322. int newSelectedItem = SchemeManager.GetSchemeNames ().IndexOf (CachedTopLevelScheme!);
  323. // if the item is in bounds then select it
  324. if (newSelectedItem >= 0 && newSelectedItem < SchemeManager.GetSchemeNames ().Count)
  325. {
  326. _topSchemeRg.SelectedItem = newSelectedItem;
  327. }
  328. }
  329. #endregion MenuBar
  330. #region Scenario List
  331. private readonly TableView _scenarioList;
  332. private static int _cachedScenarioIndex;
  333. public static ObservableCollection<Scenario>? CachedScenarios { get; set; }
  334. // If set, holds the scenario the user selected to run
  335. public static Scenario? CachedSelectedScenario { get; set; }
  336. private TableView CreateScenarioList ()
  337. {
  338. // Create the scenario list. The contents of the scenario list changes whenever the
  339. // Category list selection changes (to show just the scenarios that belong to the selected
  340. // category).
  341. TableView scenarioList = new ()
  342. {
  343. X = Pos.Right (_categoryList!) - 1,
  344. Y = Pos.Bottom (_menuBar!),
  345. Width = Dim.Fill (),
  346. Height = Dim.Fill (Dim.Func (v => v!.Frame.Height, _statusBar)),
  347. //AllowsMarking = false,
  348. CanFocus = true,
  349. Title = "_Scenarios",
  350. BorderStyle = _categoryList!.BorderStyle,
  351. SuperViewRendersLineCanvas = true
  352. };
  353. // TableView provides many options for table headers. For simplicity, we turn all
  354. // of these off. By enabling FullRowSelect and turning off headers, TableView looks just
  355. // like a ListView
  356. scenarioList.FullRowSelect = true;
  357. scenarioList.Style.ShowHeaders = false;
  358. scenarioList.Style.ShowHorizontalHeaderOverline = false;
  359. scenarioList.Style.ShowHorizontalHeaderUnderline = false;
  360. scenarioList.Style.ShowHorizontalBottomline = false;
  361. scenarioList.Style.ShowVerticalCellLines = false;
  362. scenarioList.Style.ShowVerticalHeaderLines = false;
  363. /* By default, TableView lays out columns at render time and only
  364. * measures y rows of data at a time. Where y is the height of the
  365. * console. This is for the following reasons:
  366. *
  367. * - Performance, when tables have a large amount of data
  368. * - Defensive, prevents a single wide cell value pushing other
  369. * columns off-screen (requiring horizontal scrolling
  370. *
  371. * In the case of UICatalog here, such an approach is overkill so
  372. * we just measure all the data ourselves and set the appropriate
  373. * max widths as ColumnStyles
  374. */
  375. int longestName = CachedScenarios!.Max (s => s.GetName ().Length);
  376. scenarioList.Style.ColumnStyles.Add (
  377. 0,
  378. new () { MaxWidth = longestName, MinWidth = longestName, MinAcceptableWidth = longestName }
  379. );
  380. scenarioList.Style.ColumnStyles.Add (1, new () { MaxWidth = 1 });
  381. scenarioList.CellActivated += ScenarioView_OpenSelectedItem;
  382. // TableView typically is a grid where nav keys are biased for moving left/right.
  383. scenarioList.KeyBindings.Remove (Key.Home);
  384. scenarioList.KeyBindings.Add (Key.Home, Command.Start);
  385. scenarioList.KeyBindings.Remove (Key.End);
  386. scenarioList.KeyBindings.Add (Key.End, Command.End);
  387. // Ideally, TableView.MultiSelect = false would turn off any keybindings for
  388. // multi-select options. But it currently does not. UI Catalog uses Ctrl-A for
  389. // a shortcut to About.
  390. scenarioList.MultiSelect = false;
  391. scenarioList.KeyBindings.Remove (Key.A.WithCtrl);
  392. return scenarioList;
  393. }
  394. /// <summary>Launches the selected scenario, setting the global _selectedScenario</summary>
  395. /// <param name="e"></param>
  396. private void ScenarioView_OpenSelectedItem (object? sender, EventArgs? e)
  397. {
  398. if (CachedSelectedScenario is null)
  399. {
  400. // Save selected item state
  401. _cachedCategoryIndex = _categoryList!.SelectedItem;
  402. _cachedScenarioIndex = _scenarioList.SelectedRow;
  403. // Create new instance of scenario (even though Scenarios contains instances)
  404. var selectedScenarioName = (string)_scenarioList.Table [_scenarioList.SelectedRow, 0];
  405. CachedSelectedScenario = (Scenario)Activator.CreateInstance (
  406. CachedScenarios!.FirstOrDefault (
  407. s => s.GetName ()
  408. == selectedScenarioName
  409. )!
  410. .GetType ()
  411. )!;
  412. // Tell the main app to stop
  413. Application.RequestStop ();
  414. }
  415. }
  416. #endregion Scenario List
  417. #region Category List
  418. private readonly ListView? _categoryList;
  419. private static int _cachedCategoryIndex;
  420. public static ObservableCollection<string>? CachedCategories { get; set; }
  421. private ListView CreateCategoryList ()
  422. {
  423. // Create the Category list view. This list never changes.
  424. ListView categoryList = new ()
  425. {
  426. X = 0,
  427. Y = Pos.Bottom (_menuBar!),
  428. Width = Dim.Auto (),
  429. Height = Dim.Fill (Dim.Func (v => v!.Frame.Height, _statusBar)),
  430. AllowsMarking = false,
  431. CanFocus = true,
  432. Title = "_Categories",
  433. BorderStyle = LineStyle.Rounded,
  434. SuperViewRendersLineCanvas = true,
  435. Source = new ListWrapper<string> (CachedCategories)
  436. };
  437. categoryList.OpenSelectedItem += (s, a) => { _scenarioList!.SetFocus (); };
  438. categoryList.SelectedItemChanged += CategoryView_SelectedChanged;
  439. // This enables the scrollbar by causing lazy instantiation to happen
  440. categoryList.VerticalScrollBar.AutoShow = true;
  441. return categoryList;
  442. }
  443. private void CategoryView_SelectedChanged (object? sender, ListViewItemEventArgs? e)
  444. {
  445. string item = CachedCategories! [e!.Item];
  446. ObservableCollection<Scenario> newScenarioList;
  447. if (e.Item == 0)
  448. {
  449. // First category is "All"
  450. newScenarioList = CachedScenarios!;
  451. }
  452. else
  453. {
  454. newScenarioList = new (CachedScenarios!.Where (s => s.GetCategories ().Contains (item)).ToList ());
  455. }
  456. _scenarioList.Table = new EnumerableTableSource<Scenario> (
  457. newScenarioList,
  458. new ()
  459. {
  460. { "Name", s => s.GetName () }, { "Description", s => s.GetDescription () }
  461. }
  462. );
  463. }
  464. #endregion Category List
  465. #region StatusBar
  466. private readonly StatusBar? _statusBar;
  467. [ConfigurationProperty (Scope = typeof (AppSettingsScope), OmitClassName = true)]
  468. [JsonPropertyName ("UICatalog.StatusBar")]
  469. public static bool ShowStatusBar { get; set; } = true;
  470. private Shortcut? _shQuit;
  471. private Shortcut? _shVersion;
  472. private CheckBox? _force16ColorsShortcutCb;
  473. private StatusBar CreateStatusBar ()
  474. {
  475. StatusBar statusBar = new ()
  476. {
  477. Visible = ShowStatusBar,
  478. AlignmentModes = AlignmentModes.IgnoreFirstOrLast,
  479. CanFocus = false
  480. };
  481. // ReSharper disable All
  482. statusBar.Height = Dim.Auto (
  483. DimAutoStyle.Auto,
  484. minimumContentDim: Dim.Func (_ => statusBar.Visible ? 1 : 0),
  485. maximumContentDim: Dim.Func (_ => statusBar.Visible ? 1 : 0));
  486. // ReSharper restore All
  487. _shQuit = new ()
  488. {
  489. CanFocus = false,
  490. Title = "Quit",
  491. Key = Application.QuitKey
  492. };
  493. _shVersion = new ()
  494. {
  495. Title = "Version Info",
  496. CanFocus = false
  497. };
  498. var statusBarShortcut = new Shortcut
  499. {
  500. Key = Key.F10,
  501. Title = "Show/Hide Status Bar",
  502. CanFocus = false
  503. };
  504. statusBarShortcut.Accepting += (sender, args) =>
  505. {
  506. statusBar.Visible = !_statusBar!.Visible;
  507. args.Handled = true;
  508. };
  509. _force16ColorsShortcutCb = new ()
  510. {
  511. Title = "16 color mode",
  512. CheckedState = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
  513. CanFocus = false
  514. };
  515. _force16ColorsShortcutCb.CheckedStateChanging += (sender, args) =>
  516. {
  517. if (Application.Force16Colors
  518. && args.Result == CheckState.UnChecked
  519. && !Application.Driver!.SupportsTrueColor)
  520. {
  521. // If the driver does not support TrueColor, we cannot disable 16 colors
  522. args.Handled = true;
  523. }
  524. };
  525. _force16ColorsShortcutCb.CheckedStateChanged += (sender, args) =>
  526. {
  527. Application.Force16Colors = args.Value == CheckState.Checked;
  528. _force16ColorsMenuItemCb!.CheckedState = args.Value;
  529. Application.LayoutAndDraw ();
  530. };
  531. statusBar.Add (
  532. _shQuit,
  533. statusBarShortcut,
  534. new Shortcut
  535. {
  536. CanFocus = false,
  537. CommandView = _force16ColorsShortcutCb,
  538. HelpText = "",
  539. BindKeyToApplication = true,
  540. Key = Key.F7
  541. },
  542. _shVersion
  543. );
  544. if (UICatalog.Options.DontEnableConfigurationManagement)
  545. {
  546. statusBar.AddShortcutAt (statusBar.SubViews.ToList ().IndexOf (_shVersion), new Shortcut () { Title = "CM is Disabled" });
  547. }
  548. return statusBar;
  549. }
  550. #endregion StatusBar
  551. #region Configuration Manager
  552. /// <summary>
  553. /// Called when CM has applied changes.
  554. /// </summary>
  555. private void ConfigApplied ()
  556. {
  557. UpdateThemesMenu ();
  558. SchemeName = CachedTopLevelScheme;
  559. if (_shQuit is { })
  560. {
  561. _shQuit.Key = Application.QuitKey;
  562. }
  563. if (_statusBar is { })
  564. {
  565. _statusBar.Visible = ShowStatusBar;
  566. }
  567. _disableMouseCb!.CheckedState = Application.IsMouseDisabled ? CheckState.Checked : CheckState.UnChecked;
  568. _force16ColorsShortcutCb!.CheckedState = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked;
  569. Application.Top?.SetNeedsDraw ();
  570. }
  571. private void ConfigAppliedHandler (object? sender, ConfigurationManagerEventArgs? a) { ConfigApplied (); }
  572. #endregion Configuration Manager
  573. /// <summary>
  574. /// Gets the message displayed in the About Box. `public` so it can be used from Unit tests.
  575. /// </summary>
  576. /// <returns></returns>
  577. public static string GetAboutBoxMessage ()
  578. {
  579. // NOTE: Do not use multiline verbatim strings here.
  580. // WSL gets all confused.
  581. StringBuilder msg = new ();
  582. msg.AppendLine ("UI Catalog: A comprehensive sample library and test app for");
  583. msg.AppendLine ();
  584. msg.AppendLine (
  585. """
  586. _______ _ _ _____ _
  587. |__ __| (_) | | / ____| (_)
  588. | | ___ _ __ _ __ ___ _ _ __ __ _| || | __ _ _ _
  589. | |/ _ \ '__| '_ ` _ \| | '_ \ / _` | || | |_ | | | | |
  590. | | __/ | | | | | | | | | | | (_| | || |__| | |_| | |
  591. |_|\___|_| |_| |_| |_|_|_| |_|\__,_|_(_)_____|\__,_|_|
  592. """);
  593. msg.AppendLine ();
  594. msg.AppendLine ("v2 - Pre-Alpha");
  595. msg.AppendLine ();
  596. msg.AppendLine ("https://github.com/gui-cs/Terminal.Gui");
  597. return msg.ToString ();
  598. }
  599. public static void OpenUrl (string url)
  600. {
  601. if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows))
  602. {
  603. url = url.Replace ("&", "^&");
  604. Process.Start (new ProcessStartInfo ("cmd", $"/c start {url}") { CreateNoWindow = true });
  605. }
  606. else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux))
  607. {
  608. using var process = new Process
  609. {
  610. StartInfo = new ()
  611. {
  612. FileName = "xdg-open",
  613. Arguments = url,
  614. RedirectStandardError = true,
  615. RedirectStandardOutput = true,
  616. CreateNoWindow = true,
  617. UseShellExecute = false
  618. }
  619. };
  620. process.Start ();
  621. }
  622. else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX))
  623. {
  624. Process.Start ("open", url);
  625. }
  626. }
  627. }