ASCIICustomButton.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Text;
  5. using JetBrains.Annotations;
  6. using Terminal.Gui;
  7. namespace UICatalog.Scenarios;
  8. [ScenarioMetadata ("ASCIICustomButtonTest", "ASCIICustomButton sample")]
  9. [ScenarioCategory ("Controls")]
  10. public class ASCIICustomButtonTest : Scenario
  11. {
  12. private static bool _smallerWindow;
  13. private MenuItem _miSmallerWindow;
  14. private ScrollViewTestWindow _scrollViewTestWindow;
  15. public override void Main ()
  16. {
  17. _smallerWindow = false;
  18. Application.Init ();
  19. Toplevel top = new ();
  20. var menu = new MenuBar
  21. {
  22. Menus =
  23. [
  24. new MenuBarItem (
  25. "_Window Size",
  26. new []
  27. {
  28. _miSmallerWindow =
  29. new MenuItem (
  30. "Smaller Window",
  31. "",
  32. ChangeWindowSize
  33. )
  34. {
  35. CheckType = MenuItemCheckStyle
  36. .Checked
  37. },
  38. null,
  39. new MenuItem (
  40. "Quit",
  41. "",
  42. () => Application.RequestStop (),
  43. null,
  44. null,
  45. (KeyCode)Application.QuitKey
  46. )
  47. }
  48. )
  49. ]
  50. };
  51. _scrollViewTestWindow = new ScrollViewTestWindow { Y = Pos.Bottom (menu) };
  52. top.Add (menu, _scrollViewTestWindow);
  53. Application.Run (top);
  54. top.Dispose ();
  55. Application.Shutdown ();
  56. return;
  57. void ChangeWindowSize ()
  58. {
  59. _smallerWindow = (bool)(_miSmallerWindow.Checked = !_miSmallerWindow.Checked);
  60. top.Remove (_scrollViewTestWindow);
  61. _scrollViewTestWindow.Dispose ();
  62. _scrollViewTestWindow = new ScrollViewTestWindow ();
  63. top.Add (_scrollViewTestWindow);
  64. }
  65. }
  66. public class ASCIICustomButton : Button
  67. {
  68. private FrameView _border;
  69. private Label _fill;
  70. public string Description => $"Description of: {Id}";
  71. public void CustomInitialize ()
  72. {
  73. _border = new FrameView { Width = Width, Height = Height };
  74. var fillText = new StringBuilder ();
  75. for (var i = 0; i < Viewport.Height; i++)
  76. {
  77. if (i > 0)
  78. {
  79. fillText.AppendLine ("");
  80. }
  81. for (var j = 0; j < Viewport.Width; j++)
  82. {
  83. fillText.Append ("█");
  84. }
  85. }
  86. _fill = new Label { Visible = false, CanFocus = false, Text = fillText.ToString () };
  87. var title = new Label { X = Pos.Center (), Y = Pos.Center (), Text = Text };
  88. _border.MouseClick += This_MouseClick;
  89. _fill.MouseClick += This_MouseClick;
  90. title.MouseClick += This_MouseClick;
  91. Add (_border, _fill, title);
  92. }
  93. protected override void OnHasFocusChanged (bool newHasFocus, [CanBeNull] View previousFocusedView, [CanBeNull] View focusedVew)
  94. {
  95. if (newHasFocus)
  96. {
  97. _border.Visible = false;
  98. _fill.Visible = true;
  99. PointerEnter?.Invoke (this);
  100. }
  101. else
  102. {
  103. _border.Visible = true;
  104. _fill.Visible = false;
  105. }
  106. }
  107. public event Action<ASCIICustomButton> PointerEnter;
  108. private void This_MouseClick (object sender, MouseEventEventArgs obj) { NewMouseEvent (obj.MouseEvent); }
  109. }
  110. public class ScrollViewTestWindow : Window
  111. {
  112. private const int BUTTON_HEIGHT = 3;
  113. private const int BUTTON_WIDTH = 25;
  114. private const int BUTTONS_ON_PAGE = 7;
  115. private readonly List<Button> _buttons;
  116. private readonly ScrollView _scrollView;
  117. private ASCIICustomButton _selected;
  118. public ScrollViewTestWindow ()
  119. {
  120. Title = $"{Application.QuitKey} to Quit - Scenario: ScrollViewTestWindow";
  121. Label titleLabel = null;
  122. if (_smallerWindow)
  123. {
  124. Width = 80;
  125. Height = 25;
  126. _scrollView = new ScrollView
  127. {
  128. X = 3,
  129. Y = 1,
  130. Width = 24,
  131. Height = BUTTONS_ON_PAGE * BUTTON_HEIGHT,
  132. ShowVerticalScrollIndicator = true,
  133. ShowHorizontalScrollIndicator = false
  134. };
  135. }
  136. else
  137. {
  138. Width = Dim.Fill ();
  139. Height = Dim.Fill ();
  140. titleLabel = new Label { X = 0, Y = 0, Text = "DOCUMENTS" };
  141. _scrollView = new ScrollView
  142. {
  143. X = 0,
  144. Y = 1,
  145. Width = 27,
  146. Height = BUTTONS_ON_PAGE * BUTTON_HEIGHT,
  147. ShowVerticalScrollIndicator = true,
  148. ShowHorizontalScrollIndicator = false
  149. };
  150. }
  151. _scrollView.KeyBindings.Clear ();
  152. _buttons = new List<Button> ();
  153. Button prevButton = null;
  154. var count = 20;
  155. for (var j = 0; j < count; j++)
  156. {
  157. Pos yPos = prevButton == null ? 0 : Pos.Bottom (prevButton);
  158. var button = new ASCIICustomButton
  159. {
  160. Id = j.ToString (),
  161. Text = $"section {j}",
  162. Y = yPos,
  163. Width = BUTTON_WIDTH,
  164. Height = BUTTON_HEIGHT
  165. };
  166. button.Initialized += Button_Initialized;
  167. button.Accepting += Button_Clicked;
  168. button.PointerEnter += Button_PointerEnter;
  169. button.MouseClick += Button_MouseClick;
  170. button.KeyDown += Button_KeyPress;
  171. _scrollView.Add (button);
  172. _buttons.Add (button);
  173. prevButton = button;
  174. }
  175. var closeButton = new ASCIICustomButton
  176. {
  177. Id = "close",
  178. Text = "Close",
  179. Y = Pos.Bottom (prevButton),
  180. Width = BUTTON_WIDTH,
  181. Height = BUTTON_HEIGHT
  182. };
  183. closeButton.Initialized += Button_Initialized;
  184. closeButton.Accepting += Button_Clicked;
  185. closeButton.PointerEnter += Button_PointerEnter;
  186. closeButton.MouseClick += Button_MouseClick;
  187. closeButton.KeyDown += Button_KeyPress;
  188. _scrollView.Add (closeButton);
  189. _buttons.Add (closeButton);
  190. int pages = _buttons.Count / BUTTONS_ON_PAGE;
  191. if (_buttons.Count % BUTTONS_ON_PAGE > 0)
  192. {
  193. pages++;
  194. }
  195. // BUGBUG: set_ContentSize is supposed to be `protected`.
  196. _scrollView.SetContentSize (new (25, pages * BUTTONS_ON_PAGE * BUTTON_HEIGHT));
  197. if (_smallerWindow)
  198. {
  199. Add (_scrollView);
  200. }
  201. else
  202. {
  203. Add (titleLabel, _scrollView);
  204. }
  205. Y = 1;
  206. }
  207. private void Button_Initialized (object sender, EventArgs e)
  208. {
  209. var button = sender as ASCIICustomButton;
  210. button?.CustomInitialize ();
  211. }
  212. private void Button_Clicked (object sender, EventArgs e)
  213. {
  214. MessageBox.Query ("Button clicked.", $"'{_selected.Text}' clicked!", "Ok");
  215. if (_selected.Text == "Close")
  216. {
  217. Application.RequestStop ();
  218. }
  219. }
  220. private void Button_KeyPress (object sender, Key obj)
  221. {
  222. switch (obj.KeyCode)
  223. {
  224. case KeyCode.End:
  225. _scrollView.ContentOffset = new Point (
  226. _scrollView.ContentOffset.X,
  227. -(_scrollView.GetContentSize ().Height
  228. - _scrollView.Frame.Height
  229. + (_scrollView.ShowHorizontalScrollIndicator ? 1 : 0))
  230. );
  231. obj.Handled = true;
  232. return;
  233. case KeyCode.Home:
  234. _scrollView.ContentOffset = new Point (_scrollView.ContentOffset.X, 0);
  235. obj.Handled = true;
  236. return;
  237. case KeyCode.PageDown:
  238. _scrollView.ContentOffset = new Point (
  239. _scrollView.ContentOffset.X,
  240. Math.Max (
  241. _scrollView.ContentOffset.Y
  242. - _scrollView.Frame.Height,
  243. -(_scrollView.GetContentSize ().Height
  244. - _scrollView.Frame.Height
  245. + (_scrollView.ShowHorizontalScrollIndicator
  246. ? 1
  247. : 0))
  248. )
  249. );
  250. obj.Handled = true;
  251. return;
  252. case KeyCode.PageUp:
  253. _scrollView.ContentOffset = new Point (
  254. _scrollView.ContentOffset.X,
  255. Math.Min (
  256. _scrollView.ContentOffset.Y
  257. + _scrollView.Frame.Height,
  258. 0
  259. )
  260. );
  261. obj.Handled = true;
  262. return;
  263. }
  264. }
  265. private void Button_MouseClick (object sender, MouseEventEventArgs obj)
  266. {
  267. if (obj.MouseEvent.Flags == MouseFlags.WheeledDown)
  268. {
  269. _scrollView.ContentOffset = new Point (
  270. _scrollView.ContentOffset.X,
  271. _scrollView.ContentOffset.Y - BUTTON_HEIGHT
  272. );
  273. obj.Handled = true;
  274. }
  275. else if (obj.MouseEvent.Flags == MouseFlags.WheeledUp)
  276. {
  277. _scrollView.ContentOffset = new Point (
  278. _scrollView.ContentOffset.X,
  279. Math.Min (_scrollView.ContentOffset.Y + BUTTON_HEIGHT, 0)
  280. );
  281. obj.Handled = true;
  282. }
  283. }
  284. private void Button_PointerEnter (ASCIICustomButton obj)
  285. {
  286. bool? moveDown;
  287. if (obj.Frame.Y > _selected?.Frame.Y)
  288. {
  289. moveDown = true;
  290. }
  291. else if (obj.Frame.Y < _selected?.Frame.Y)
  292. {
  293. moveDown = false;
  294. }
  295. else
  296. {
  297. moveDown = null;
  298. }
  299. int offSet = _selected != null
  300. ? obj.Frame.Y - _selected.Frame.Y + -_scrollView.ContentOffset.Y % BUTTON_HEIGHT
  301. : 0;
  302. _selected = obj;
  303. if (moveDown == true && _selected.Frame.Y + _scrollView.ContentOffset.Y + BUTTON_HEIGHT >= _scrollView.Frame.Height && offSet != BUTTON_HEIGHT)
  304. {
  305. _scrollView.ContentOffset = new Point (
  306. _scrollView.ContentOffset.X,
  307. Math.Min (
  308. _scrollView.ContentOffset.Y - BUTTON_HEIGHT,
  309. -(_selected.Frame.Y
  310. - _scrollView.Frame.Height
  311. + BUTTON_HEIGHT)
  312. )
  313. );
  314. }
  315. else if (moveDown == true && _selected.Frame.Y + _scrollView.ContentOffset.Y >= _scrollView.Frame.Height)
  316. {
  317. _scrollView.ContentOffset = new Point (
  318. _scrollView.ContentOffset.X,
  319. _scrollView.ContentOffset.Y - BUTTON_HEIGHT
  320. );
  321. }
  322. else if (moveDown == true && _selected.Frame.Y + _scrollView.ContentOffset.Y < 0)
  323. {
  324. _scrollView.ContentOffset = new Point (
  325. _scrollView.ContentOffset.X,
  326. -_selected.Frame.Y
  327. );
  328. }
  329. else if (moveDown == false && _selected.Frame.Y < -_scrollView.ContentOffset.Y)
  330. {
  331. _scrollView.ContentOffset = new Point (
  332. _scrollView.ContentOffset.X,
  333. Math.Max (
  334. _scrollView.ContentOffset.Y + BUTTON_HEIGHT,
  335. _selected.Frame.Y
  336. )
  337. );
  338. }
  339. else if (moveDown == false && _selected.Frame.Y + _scrollView.ContentOffset.Y > _scrollView.Frame.Height)
  340. {
  341. _scrollView.ContentOffset = new Point (
  342. _scrollView.ContentOffset.X,
  343. -(_selected.Frame.Y - _scrollView.Frame.Height + BUTTON_HEIGHT)
  344. );
  345. }
  346. }
  347. }
  348. }