Bar.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. namespace Terminal.Gui.Views;
  2. /// <summary>
  3. /// Provides a horizontally or vertically oriented container for <see cref="Shortcut"/>s to be used as a menu, toolbar, or status
  4. /// bar.
  5. /// </summary>
  6. /// <remarks>
  7. /// <para>
  8. /// Any <see cref="View"/> can be added to a <see cref="Bar"/>. However, the <see cref="Bar"/> is designed to work with
  9. /// <see cref="Shortcut"/> objects. The <see cref="Shortcut"/> class provides a way to display a command, help, and key and
  10. /// align them in a specific order.
  11. /// </para>
  12. /// </remarks>
  13. public class Bar : View, IOrientation, IDesignable
  14. {
  15. private readonly OrientationHelper _orientationHelper;
  16. /// <inheritdoc/>
  17. public Bar () : this ([]) { }
  18. /// <inheritdoc/>
  19. public Bar (IEnumerable<View>? shortcuts)
  20. {
  21. CanFocus = true;
  22. Width = Dim.Auto ();
  23. Height = Dim.Auto ();
  24. _orientationHelper = new (this);
  25. // Initialized += Bar_Initialized;
  26. MouseEvent += OnMouseEvent;
  27. if (shortcuts is null)
  28. {
  29. return;
  30. }
  31. foreach (View shortcut in shortcuts)
  32. {
  33. base.Add (shortcut);
  34. }
  35. }
  36. private void OnMouseEvent (object? sender, MouseEventArgs e)
  37. {
  38. NavigationDirection direction = NavigationDirection.Backward;
  39. if (e.Flags == MouseFlags.WheeledDown)
  40. {
  41. e.Handled = true;
  42. }
  43. if (e.Flags == MouseFlags.WheeledUp)
  44. {
  45. direction = NavigationDirection.Forward;
  46. e.Handled = true;
  47. }
  48. if (e.Flags == MouseFlags.WheeledRight)
  49. {
  50. e.Handled = true;
  51. }
  52. if (e.Flags == MouseFlags.WheeledLeft)
  53. {
  54. direction = NavigationDirection.Forward;
  55. e.Handled = true;
  56. }
  57. if (e.Handled)
  58. {
  59. e.Handled = AdvanceFocus (direction, TabBehavior.TabStop);
  60. }
  61. }
  62. #region IOrientation members
  63. /// <summary>
  64. /// Gets or sets the <see cref="Orientation"/> for this <see cref="Bar"/>. The default is
  65. /// <see cref="Orientation.Horizontal"/>.
  66. /// </summary>
  67. /// <remarks>
  68. /// <para>
  69. /// Horizontal orientation arranges the command, help, and key parts of each <see cref="Shortcut"/>s from right to left
  70. /// Vertical orientation arranges the command, help, and key parts of each <see cref="Shortcut"/>s from left to right.
  71. /// </para>
  72. /// </remarks>
  73. public Orientation Orientation
  74. {
  75. get => _orientationHelper.Orientation;
  76. set => _orientationHelper.Orientation = value;
  77. }
  78. #pragma warning disable CS0067 // The event is never used
  79. /// <inheritdoc/>
  80. public event EventHandler<CancelEventArgs<Orientation>>? OrientationChanging;
  81. /// <inheritdoc/>
  82. public event EventHandler<EventArgs<Orientation>>? OrientationChanged;
  83. #pragma warning restore CS0067 // The event is never used
  84. /// <summary>Called when <see cref="Orientation"/> has changed.</summary>
  85. /// <param name="newOrientation"></param>
  86. public void OnOrientationChanged (Orientation newOrientation)
  87. {
  88. // BUGBUG: this should not be SuperView.GetContentSize
  89. LayoutBarItems (SuperView?.GetContentSize () ?? App?.Screen.Size ?? Size.Empty);
  90. }
  91. #endregion
  92. private AlignmentModes _alignmentModes = AlignmentModes.StartToEnd;
  93. /// <summary>
  94. /// Gets or sets the <see cref="AlignmentModes"/> for this <see cref="Bar"/>. The default is
  95. /// <see cref="AlignmentModes.StartToEnd"/>.
  96. /// </summary>
  97. public AlignmentModes AlignmentModes
  98. {
  99. get => _alignmentModes;
  100. set
  101. {
  102. _alignmentModes = value;
  103. //SetNeedsDraw ();
  104. SetNeedsLayout ();
  105. }
  106. }
  107. // TODO: Move this to View
  108. /// <summary>Inserts a <see cref="Shortcut"/> in the specified index of <see cref="View.SubViews"/>.</summary>
  109. /// <param name="index">The zero-based index at which item should be inserted.</param>
  110. /// <param name="item">The item to insert.</param>
  111. public void AddShortcutAt (int index, Shortcut item)
  112. {
  113. List<View> savedSubViewList = SubViews.ToList ();
  114. int count = savedSubViewList.Count;
  115. RemoveAll ();
  116. for (var i = 0; i <= count; i++)
  117. {
  118. if (i == index)
  119. {
  120. Add (item);
  121. }
  122. if (i < count)
  123. {
  124. Add (savedSubViewList [i]);
  125. }
  126. }
  127. //SetNeedsDraw ();
  128. SetNeedsLayout ();
  129. }
  130. // TODO: Move this to View
  131. /// <summary>Removes a <see cref="Shortcut"/> at specified index of <see cref="View.SubViews"/>.</summary>
  132. /// <param name="index">The zero-based index of the item to remove.</param>
  133. /// <returns>The <see cref="Shortcut"/> removed.</returns>
  134. public Shortcut? RemoveShortcut (int index)
  135. {
  136. View? toRemove = null;
  137. for (var i = 0; i < SubViews.Count; i++)
  138. {
  139. if (i == index)
  140. {
  141. toRemove = SubViews.ElementAt (i);
  142. }
  143. }
  144. if (toRemove is { })
  145. {
  146. Remove (toRemove);
  147. //SetNeedsDraw ();
  148. SetNeedsLayout ();
  149. }
  150. return toRemove as Shortcut;
  151. }
  152. /// <inheritdoc />
  153. protected override void OnSubViewLayout (LayoutEventArgs args)
  154. {
  155. LayoutBarItems (args.OldContentSize);
  156. }
  157. private void LayoutBarItems (Size contentSize)
  158. {
  159. View? prevBarItem = null;
  160. switch (Orientation)
  161. {
  162. case Orientation.Horizontal:
  163. for (var index = 0; index < SubViews.Count; index++)
  164. {
  165. View barItem = SubViews.ElementAt (index);
  166. //barItem.Scheme = Scheme;
  167. barItem.X = Pos.Align (Alignment.Start, AlignmentModes);
  168. barItem.Y = 0; //Pos.Center ();
  169. if (barItem is Shortcut sc)
  170. {
  171. sc.Width = sc.GetWidthDimAuto ();
  172. }
  173. }
  174. break;
  175. case Orientation.Vertical:
  176. if (Width!.Has<DimAuto> (out _))
  177. {
  178. // Set the overall size of the Bar and arrange the views vertically
  179. var minKeyWidth = 0;
  180. List<Shortcut> shortcuts = SubViews.OfType<Shortcut> ().Where (s => s.Visible).ToList ();
  181. foreach (Shortcut shortcut in shortcuts)
  182. {
  183. // Get the largest width of all KeyView's
  184. minKeyWidth = int.Max (minKeyWidth, shortcut.KeyView.Text.GetColumns ());
  185. }
  186. var maxBarItemWidth = 0;
  187. for (var index = 0; index < SubViews.Count; index++)
  188. {
  189. View barItem = SubViews.ElementAt (index);
  190. // barItem.Scheme = Scheme;
  191. if (!barItem.Visible)
  192. {
  193. continue;
  194. }
  195. if (barItem is Shortcut scBarItem)
  196. {
  197. barItem.X = 0;
  198. scBarItem.MinimumKeyTextSize = minKeyWidth;
  199. scBarItem.Width = scBarItem.GetWidthDimAuto ();
  200. barItem.Layout (App?.Screen.Size ?? Size.Empty);
  201. maxBarItemWidth = Math.Max (maxBarItemWidth, barItem.Frame.Width);
  202. }
  203. if (prevBarItem == null)
  204. {
  205. // TODO: Just use Pos.Align!
  206. barItem.Y = 0;
  207. }
  208. else
  209. {
  210. // TODO: Just use Pos.Align!
  211. // Align the view to the bottom of the previous view
  212. barItem.Y = Pos.Bottom (prevBarItem);
  213. }
  214. prevBarItem = barItem;
  215. }
  216. foreach (var subView in SubViews)
  217. {
  218. if (subView is not Line)
  219. {
  220. subView.Width = Dim.Auto (DimAutoStyle.Auto, minimumContentDim: maxBarItemWidth, maximumContentDim: maxBarItemWidth);
  221. }
  222. }
  223. }
  224. else
  225. {
  226. foreach (var subView in SubViews)
  227. {
  228. if (subView is not Line)
  229. {
  230. subView.Width = Dim.Fill ();
  231. }
  232. }
  233. }
  234. break;
  235. }
  236. }
  237. /// <inheritdoc />
  238. public virtual bool EnableForDesign ()
  239. {
  240. var shortcut = new Shortcut
  241. {
  242. Text = "Quit",
  243. Title = "Q_uit",
  244. Key = Key.Z.WithCtrl,
  245. };
  246. Add (shortcut);
  247. shortcut = new Shortcut
  248. {
  249. Text = "Help Text",
  250. Title = "Help",
  251. Key = Key.F1,
  252. };
  253. Add (shortcut);
  254. shortcut = new Shortcut
  255. {
  256. Text = "Czech",
  257. CommandView = new CheckBox ()
  258. {
  259. Title = "_Check"
  260. },
  261. Key = Key.F9,
  262. CanFocus = false
  263. };
  264. Add (shortcut);
  265. return true;
  266. }
  267. }