StatusBar.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. namespace Terminal.Gui.Views;
  2. /// <summary>
  3. /// A status bar is a <see cref="View"/> that snaps to the bottom of a <see cref="Toplevel"/> displaying set of
  4. /// <see cref="Shortcut"/>s. The <see cref="StatusBar"/> should be context sensitive. This means, if the main menu
  5. /// and an open text editor are visible, the items probably shown will be ~F1~ Help ~F2~ Save ~F3~ Load. While a dialog
  6. /// to ask a file to load is executed, the remaining commands will probably be ~F1~ Help. So for each context must be a
  7. /// new instance of a status bar.
  8. /// </summary>
  9. public class StatusBar : Bar, IDesignable
  10. {
  11. /// <inheritdoc/>
  12. public StatusBar () : this ([]) { }
  13. /// <inheritdoc/>
  14. public StatusBar (IEnumerable<Shortcut> shortcuts) : base (shortcuts)
  15. {
  16. TabStop = TabBehavior.NoStop;
  17. Orientation = Orientation.Horizontal;
  18. Y = Pos.AnchorEnd ();
  19. Width = Dim.Fill ();
  20. Height = Dim.Auto (DimAutoStyle.Content, 1);
  21. if (Border is { })
  22. {
  23. Border.LineStyle = DefaultSeparatorLineStyle;
  24. }
  25. SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Menu);
  26. ConfigurationManager.Applied += OnConfigurationManagerApplied;
  27. SuperViewChanged += OnSuperViewChanged;
  28. }
  29. private void OnSuperViewChanged (object? sender, SuperViewChangedEventArgs e)
  30. {
  31. if (SuperView is null)
  32. {
  33. // BUGBUG: This is a hack for avoiding a race condition in ConfigurationManager.Apply
  34. // BUGBUG: For some reason in some unit tests, when Top is disposed, MenuBar.Dispose does not get called.
  35. // BUGBUG: Yet, the MenuBar does get Removed from Top (and it's SuperView set to null).
  36. // BUGBUG: Related: https://github.com/gui-cs/Terminal.Gui/issues/4021
  37. ConfigurationManager.Applied -= OnConfigurationManagerApplied;
  38. }
  39. }
  40. private void OnConfigurationManagerApplied (object? sender, ConfigurationManagerEventArgs e)
  41. {
  42. if (Border is { })
  43. {
  44. Border.LineStyle = DefaultSeparatorLineStyle;
  45. }
  46. }
  47. /// <summary>
  48. /// Gets or sets the default Line Style for the separators between the shortcuts of the StatusBar.
  49. /// </summary>
  50. [ConfigurationProperty (Scope = typeof (ThemeScope))]
  51. public static LineStyle DefaultSeparatorLineStyle { get; set; } = LineStyle.Single;
  52. /// <inheritdoc />
  53. protected override void OnSubViewLayout (LayoutEventArgs args)
  54. {
  55. for (int index = 0; index < SubViews.Count; index++)
  56. {
  57. View barItem = SubViews.ElementAt (index);
  58. barItem.BorderStyle = BorderStyle;
  59. if (barItem.Border is { })
  60. {
  61. barItem.Border!.Thickness = index == SubViews.Count - 1 ? new Thickness (0, 0, 0, 0) : new Thickness (0, 0, 1, 0);
  62. }
  63. if (barItem is Shortcut shortcut)
  64. {
  65. shortcut.Orientation = Orientation.Horizontal;
  66. }
  67. }
  68. base.OnSubViewLayout (args);
  69. }
  70. /// <inheritdoc/>
  71. protected override void OnSubViewAdded (View subView)
  72. {
  73. subView.CanFocus = false;
  74. if (subView is Shortcut shortcut)
  75. {
  76. // TODO: not happy about using AlignmentModes for this. Too implied.
  77. // TODO: instead, add a property (a style enum?) to Shortcut to control this
  78. shortcut.AlignmentModes = AlignmentModes.EndToStart;
  79. }
  80. }
  81. /// <inheritdoc />
  82. bool IDesignable.EnableForDesign ()
  83. {
  84. var shortcut = new Shortcut
  85. {
  86. Text = "Quit",
  87. Title = "Q_uit",
  88. Key = Key.Z.WithCtrl,
  89. };
  90. Add (shortcut);
  91. shortcut = new Shortcut
  92. {
  93. Text = "Help Text",
  94. Title = "Help",
  95. Key = Key.F1,
  96. };
  97. Add (shortcut);
  98. shortcut = new Shortcut
  99. {
  100. Title = "_Show/Hide",
  101. Key = Key.F10,
  102. CommandView = new CheckBox
  103. {
  104. CanFocus = false,
  105. Text = "_Show/Hide"
  106. },
  107. };
  108. Add (shortcut);
  109. var button1 = new Button
  110. {
  111. Text = "I'll Hide",
  112. // Visible = false
  113. };
  114. button1.Accepting += OnButtonClicked;
  115. Add (button1);
  116. #pragma warning disable TGUI001
  117. shortcut.Accepting += (_, e) =>
  118. {
  119. button1.Visible = !button1.Visible;
  120. button1.Enabled = button1.Visible;
  121. e.Handled = false;
  122. };
  123. #pragma warning restore TGUI001
  124. Add (new Label
  125. {
  126. HotKeySpecifier = new Rune ('_'),
  127. Text = "Fo_cusLabel",
  128. CanFocus = true
  129. });
  130. var button2 = new Button
  131. {
  132. Text = "Or me!",
  133. };
  134. button2.Accepting += (s, e) => App?.RequestStop ();
  135. Add (button2);
  136. return true;
  137. void OnButtonClicked (object? sender, EventArgs? e) { MessageBox.Query ("Hi", $"You clicked {sender}"); }
  138. }
  139. /// <inheritdoc />
  140. protected override void Dispose (bool disposing)
  141. {
  142. base.Dispose (disposing);
  143. SuperViewChanged -= OnSuperViewChanged;
  144. ConfigurationManager.Applied -= OnConfigurationManagerApplied;
  145. }
  146. }