Menu.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. using System;
  2. namespace Terminal {
  3. /// <summary>
  4. /// A menu item has a title, an associated help text, and an action to execute on activation.
  5. /// </summary>
  6. public class MenuItem {
  7. public MenuItem (string title, string help, Action action)
  8. {
  9. Title = title ?? "";
  10. Help = help ?? "";
  11. Action = action;
  12. Width = Title.Length + Help.Length + 1;
  13. }
  14. public string Title { get; set; }
  15. public string Help { get; set; }
  16. public Action Action { get; set; }
  17. public int Width { get; set; }
  18. }
  19. /// <summary>
  20. /// A menu bar item contains other menu items.
  21. /// </summary>
  22. public class MenuBarItem {
  23. public MenuBarItem (string title, MenuItem [] children)
  24. {
  25. Title = title ?? "";
  26. Children = children;
  27. }
  28. public string Title { get; set; }
  29. public MenuItem [] Children { get; set; }
  30. public int Current { get; set; }
  31. }
  32. /// <summary>
  33. /// A menu bar for your application.
  34. /// </summary>
  35. public class MenuBar : View {
  36. public MenuBarItem [] Menus { get; set; }
  37. int selected;
  38. Action action;
  39. public MenuBar (MenuBarItem [] menus) : base (new Rect (0, 0, Application.Driver.Cols, 1))
  40. {
  41. Menus = menus;
  42. CanFocus = false;
  43. selected = -1;
  44. }
  45. /// <summary>
  46. /// Activates the menubar
  47. /// </summary>
  48. public void Activate (int idx)
  49. {
  50. if (idx < 0 || idx > Menus.Length)
  51. throw new ArgumentException ("idx");
  52. action = null;
  53. selected = idx;
  54. foreach (var m in Menus)
  55. m.Current = 0;
  56. // TODO: Application.Run (this);
  57. selected = -1;
  58. SuperView.SetNeedsDisplay ();
  59. if (action != null)
  60. action ();
  61. }
  62. void DrawMenu (int idx, int col, int line)
  63. {
  64. int max = 0;
  65. var menu = Menus [idx];
  66. if (menu.Children == null)
  67. return;
  68. foreach (var m in menu.Children) {
  69. if (m == null)
  70. continue;
  71. if (m.Width > max)
  72. max = m.Width;
  73. }
  74. max += 4;
  75. DrawFrame (new Rect (col, line, max, menu.Children.Length + 2), true);
  76. for (int i = 0; i < menu.Children.Length; i++) {
  77. var item = menu.Children [i];
  78. Move (line + 1 + i, col + 1);
  79. Driver.SetAttribute (item == null ? Colors.Base.Focus : i == menu.Current ? Colors.Menu.MarkedSelected : Colors.Menu.Marked);
  80. for (int p = 0; p < max - 2; p++)
  81. if (item == null)
  82. Driver.AddSpecial (SpecialChar.HLine);
  83. else
  84. Driver.AddCh (' ');
  85. if (item == null)
  86. continue;
  87. Move (line + 1 + i, col + 2);
  88. DrawHotString (item.Title,
  89. i == menu.Current ? Colors.Menu.HotFocus: Colors.Menu.HotNormal,
  90. i == menu.Current ? Colors.Menu.MarkedSelected : Colors.Menu.Marked);
  91. // The help string
  92. var l = item.Help.Length;
  93. Move (col + max - l - 2, line + 1 + i);
  94. Driver.AddStr (item.Help);
  95. }
  96. }
  97. public override void Redraw (Rect region)
  98. {
  99. Move (0, 0);
  100. Driver.SetAttribute (Colors.Base.Focus);
  101. for (int i = 0; i < Frame.Width; i++)
  102. Driver.AddCh (' ');
  103. Move (1, 0);
  104. int pos = 0;
  105. for (int i = 0; i < Menus.Length; i++) {
  106. var menu = Menus [i];
  107. if (i == selected) {
  108. DrawMenu (i, pos, 1);
  109. Driver.SetAttribute (Colors.Menu.MarkedSelected);
  110. } else
  111. Driver.SetAttribute (Colors.Menu.Focus);
  112. Move (pos, 0);
  113. Driver.AddCh (' ');
  114. Driver.AddStr(menu.Title);
  115. Driver.AddCh (' ');
  116. if (HasFocus && i == selected)
  117. Driver.SetAttribute (Colors.Menu.MarkedSelected);
  118. else
  119. Driver.SetAttribute (Colors.Menu.Marked);
  120. Driver.AddStr (" ");
  121. pos += menu.Title.Length + 4;
  122. }
  123. PositionCursor ();
  124. }
  125. public override void PositionCursor ()
  126. {
  127. int pos = 0;
  128. for (int i = 0; i < Menus.Length; i++) {
  129. if (i == selected) {
  130. pos++;
  131. Move (pos, 0);
  132. return;
  133. } else {
  134. pos += Menus [i].Title.Length + 4;
  135. }
  136. }
  137. Move (0, 0);
  138. }
  139. void Selected (MenuItem item)
  140. {
  141. // TODO: Running = false;
  142. action = item.Action;
  143. }
  144. public override bool ProcessKey (KeyEvent kb)
  145. {
  146. switch (kb.Key) {
  147. case Key.CursorUp:
  148. if (Menus [selected].Children == null)
  149. return false;
  150. int current = Menus [selected].Current;
  151. do {
  152. current--;
  153. if (current < 0)
  154. current = Menus [selected].Children.Length - 1;
  155. } while (Menus [selected].Children [current] == null);
  156. Menus [selected].Current = current;
  157. SetNeedsDisplay ();
  158. return true;
  159. case Key.CursorDown:
  160. if (Menus [selected].Children == null)
  161. return false;
  162. do {
  163. Menus [selected].Current = (Menus [selected].Current + 1) % Menus [selected].Children.Length;
  164. } while (Menus [selected].Children [Menus [selected].Current] == null);
  165. SetNeedsDisplay ();
  166. break;
  167. case Key.CursorLeft:
  168. selected--;
  169. if (selected < 0)
  170. selected = Menus.Length - 1;
  171. break;
  172. case Key.CursorRight:
  173. selected = (selected + 1) % Menus.Length;
  174. break;
  175. case Key.Enter:
  176. if (Menus [selected].Children == null)
  177. return false;
  178. Selected (Menus [selected].Children [Menus [selected].Current]);
  179. break;
  180. case Key.Esc:
  181. case Key.ControlC:
  182. //TODO: Running = false;
  183. break;
  184. default:
  185. var key = kb.KeyValue;
  186. if ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z') || (key >= '0' && key <= '9')) {
  187. char c = Char.ToUpper ((char)key);
  188. if (Menus [selected].Children == null)
  189. return false;
  190. foreach (var mi in Menus [selected].Children) {
  191. int p = mi.Title.IndexOf ('_');
  192. if (p != -1 && p + 1 < mi.Title.Length) {
  193. if (mi.Title [p + 1] == c) {
  194. Selected (mi);
  195. return true;
  196. }
  197. }
  198. }
  199. }
  200. return false;
  201. }
  202. SetNeedsDisplay ();
  203. return true;
  204. }
  205. }
  206. }