Script for automating a large assortment of AME related actions
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

432 lines
16 KiB

9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading;
  5. using System.Windows.Forms;
  6. using amecs;
  7. namespace Ameliorated.ConsoleUtils
  8. {
  9. public class Menu
  10. {
  11. public List<MenuItem> Choices { get; set; } = new List<MenuItem>();
  12. private int TotalOffset = 2;
  13. private int? _offset = null;
  14. public int Offset
  15. {
  16. get
  17. {
  18. if (_offset == null)
  19. _offset = BindToOpenFrame ? 5 : 2;
  20. return _offset.Value;
  21. }
  22. set { _offset = value; }
  23. }
  24. public ConsoleColor? SelectionForeground { get; set; } = ConsoleColor.Green;
  25. public ConsoleColor? SelectionBackgound { get; set; } = null;
  26. public bool CloseFrame { get; set; } = true;
  27. private bool _bindToOpenFrame;
  28. public bool BindToOpenFrame { get; set; } = true;
  29. private int menuStart;
  30. private int pages;
  31. private int choicesPerPage;
  32. public void Write()
  33. {
  34. if (Choices.Count < 1) throw new ArgumentException("Property Choices must have at least one choice.");
  35. _bindToOpenFrame = ConsoleTUI.OpenFrame != null && BindToOpenFrame;
  36. int totalStaticChoices = Choices.Count(x => x.IsStatic || x.IsNextButton || x.IsPreviousButton);
  37. if (_bindToOpenFrame)
  38. {
  39. pages = (int)Math.Ceiling(((double)Choices.Count - totalStaticChoices) / (double)(ConsoleTUI.OpenFrame.DisplayHeight - totalStaticChoices + 1));
  40. choicesPerPage = (ConsoleTUI.OpenFrame.DisplayHeight - totalStaticChoices + 1);
  41. }
  42. else
  43. {
  44. pages = (int)Math.Ceiling(((double)Choices.Count - totalStaticChoices) / (double)(((Console.WindowHeight - Console.CursorTop) - totalStaticChoices)));
  45. choicesPerPage = (Console.WindowHeight - Console.CursorTop) - totalStaticChoices;
  46. }
  47. if (_bindToOpenFrame)
  48. ConsoleTUI.OpenFrame.Clear();
  49. TotalOffset = _bindToOpenFrame ? ConsoleTUI.OpenFrame.DisplayOffset + Offset : Offset;
  50. menuStart = Console.CursorTop;
  51. if (_bindToOpenFrame)
  52. {
  53. Console.SetCursorPosition(TotalOffset, Console.CursorTop);
  54. }
  55. var fluidChoices = Choices.Where(x => !x.IsStatic && !x.IsNextButton && !x.IsPreviousButton).Take(choicesPerPage);
  56. var staticChoices = Choices.Where(x => x.IsStatic || (pages > 1 && x.IsNextButton));
  57. WriteChoiceList(fluidChoices.Concat(staticChoices));
  58. Frame = ConsoleTUI.OpenFrame;
  59. if (_bindToOpenFrame && CloseFrame)
  60. {
  61. try
  62. {
  63. var offset = ConsoleTUI.OpenFrame.DisplayOffset;
  64. if (pages == 1)
  65. ConsoleTUI.OpenFrame.Close();
  66. else
  67. ConsoleTUI.OpenFrame.Close($"Page 1/{pages}");
  68. Console.WriteLine(new string(' ', offset) + "Use the arrow keys to navigate");
  69. } catch (Exception e)
  70. {
  71. Console.WriteLine(e);
  72. Console.ReadLine();
  73. }
  74. }
  75. }
  76. private void WriteChoiceList(IEnumerable<MenuItem> list)
  77. {
  78. bool selectedWritten = false;
  79. Console.SetCursorPosition(0, Console.CursorTop);
  80. foreach (MenuItem choice in list)
  81. {
  82. if (_bindToOpenFrame)
  83. {
  84. Console.Write(
  85. new string(' ', TotalOffset));
  86. if (choice.IsEnabled && !selectedWritten)
  87. {
  88. choice.WriteSelected(SelectionForeground, SelectionBackgound);
  89. selectedWritten = true;
  90. Console.WriteLine();
  91. continue;
  92. }
  93. choice.Write();
  94. }
  95. else
  96. {
  97. Console.Write(
  98. new string(' ', TotalOffset));
  99. if (choice.IsEnabled && !selectedWritten)
  100. {
  101. choice.WriteSelected(SelectionForeground, SelectionBackgound);
  102. selectedWritten = true;
  103. Console.WriteLine();
  104. continue;
  105. }
  106. choice.Write();
  107. }
  108. Console.WriteLine();
  109. }
  110. Console.SetCursorPosition(Console.CursorLeft, Console.CursorTop - 1);
  111. }
  112. private List<MenuItem> ValidChoices = new List<MenuItem>();
  113. private ConsoleTUI.Frame Frame;
  114. public object Load()
  115. {
  116. var visCache = Console.CursorVisible;
  117. Console.CursorVisible = false;
  118. int index = Math.Max(Choices.FindIndex(x => x.IsEnabled), 0);
  119. int validIndex = 0;
  120. ConsoleKey keyPressed;
  121. Console.SetCursorPosition(Console.CursorLeft, menuStart + index);
  122. var allFluidChoices = Choices.Where(x => !x.IsStatic && !x.IsNextButton && !x.IsPreviousButton).ToList();
  123. var allStaticChoices = Choices.Where(x => x.IsStatic || x.IsNextButton || x.IsPreviousButton).ToList();
  124. int pageIndex = 1;
  125. ConsoleUtils.ClearInputBuffer();
  126. var currentChoices = allFluidChoices.Take(choicesPerPage).Concat(Choices.Where(x => x.IsStatic || (pages > 1 && x.IsNextButton))).ToList();
  127. var currentValidChoices = currentChoices.Where(x => x.IsEnabled).ToList();
  128. while (true)
  129. {
  130. keyPressed = Console.ReadKey(true).Key;
  131. if (keyPressed == ConsoleKey.DownArrow || keyPressed == ConsoleKey.S)
  132. {
  133. if (validIndex >= currentValidChoices.Count - 1) continue;
  134. Console.SetCursorPosition(Math.Max(TotalOffset - 2, 0), Console.CursorTop);
  135. Console.Write(" ");
  136. currentValidChoices[validIndex].Write();
  137. var fromTop = currentChoices.Skip(index + 1).TakeWhile(x => !x.IsEnabled).Count() + 1;
  138. var choice = currentChoices.Skip(index + 1).First(x => x.IsEnabled);
  139. Console.SetCursorPosition(TotalOffset, Console.CursorTop + fromTop);
  140. choice.WriteSelected(SelectionForeground, SelectionBackgound);
  141. index += fromTop;
  142. validIndex += 1;
  143. }
  144. if (keyPressed == ConsoleKey.UpArrow || keyPressed == ConsoleKey.W)
  145. {
  146. if (!(validIndex > 0)) continue;
  147. Console.SetCursorPosition(Math.Max(TotalOffset - 2, 0), Console.CursorTop);
  148. Console.Write(" ");
  149. currentValidChoices[validIndex].Write();
  150. var fromTop = -currentChoices.Take(index).Reverse().TakeWhile(x => !x.IsEnabled).Count() - 1;
  151. var choice = currentChoices.Take(index).Last(x => x.IsEnabled);
  152. Console.SetCursorPosition(TotalOffset, Console.CursorTop + fromTop);
  153. choice.WriteSelected(SelectionForeground, SelectionBackgound);
  154. index += fromTop;
  155. validIndex -= 1;
  156. }
  157. if (keyPressed == ConsoleKey.RightArrow || keyPressed == ConsoleKey.A || keyPressed == ConsoleKey.PageUp ||
  158. (keyPressed == ConsoleKey.Enter && currentValidChoices[validIndex].IsNextButton))
  159. {
  160. if (pageIndex == pages)
  161. continue;
  162. Frame.Clear();
  163. pageIndex++;
  164. var pIndex = pageIndex;
  165. var fluidChoices = allFluidChoices.Skip((pIndex - 1) * choicesPerPage).Take(choicesPerPage).ToList();
  166. var staticChoices = allStaticChoices.Where(x => !(pages <= pIndex && x.IsNextButton));
  167. Console.SetCursorPosition(Console.CursorLeft, menuStart);
  168. currentChoices = fluidChoices.Concat(staticChoices).ToList();
  169. WriteChoiceList(currentChoices);
  170. if (_bindToOpenFrame && CloseFrame)
  171. {
  172. try
  173. {
  174. var offset = ConsoleTUI.OpenFrame.DisplayOffset;
  175. if (pages == 1)
  176. ConsoleTUI.OpenFrame.Close();
  177. else
  178. ConsoleTUI.OpenFrame.Close($"Page {pIndex}/{pages}");
  179. Console.WriteLine(new string(' ', offset) + "Use the arrow keys to navigate");
  180. } catch (Exception e)
  181. {
  182. Console.WriteLine(e);
  183. Console.ReadLine();
  184. }
  185. }
  186. Console.SetCursorPosition(Console.CursorLeft, menuStart);
  187. currentValidChoices = currentChoices.Where(x => x.IsEnabled).ToList();
  188. index = 0;
  189. validIndex = 0;
  190. continue;
  191. }
  192. if (keyPressed == ConsoleKey.LeftArrow || keyPressed == ConsoleKey.D || keyPressed == ConsoleKey.PageDown ||
  193. (keyPressed == ConsoleKey.Enter && currentValidChoices[validIndex].IsPreviousButton))
  194. {
  195. if (pageIndex == 1)
  196. continue;
  197. Frame.Clear();
  198. pageIndex--;
  199. var pIndex = pageIndex;
  200. var fluidChoices = allFluidChoices.Skip((pIndex - 1) * choicesPerPage).Take(choicesPerPage).ToList();
  201. var staticChoices = allStaticChoices.Where(x => !(pIndex <= 1 && x.IsPreviousButton));
  202. Console.SetCursorPosition(Console.CursorLeft, menuStart);
  203. currentChoices = fluidChoices.Concat(staticChoices).ToList();
  204. WriteChoiceList(currentChoices);
  205. if (_bindToOpenFrame && CloseFrame)
  206. {
  207. try
  208. {
  209. var offset = ConsoleTUI.OpenFrame.DisplayOffset;
  210. if (pages == 1)
  211. ConsoleTUI.OpenFrame.Close();
  212. else
  213. ConsoleTUI.OpenFrame.Close($"Page {pIndex}/{pages}");
  214. Console.WriteLine(new string(' ', offset) + "Use the arrow keys to navigate");
  215. } catch (Exception e)
  216. {
  217. Console.WriteLine(e);
  218. Console.ReadLine();
  219. }
  220. }
  221. Console.SetCursorPosition(Console.CursorLeft, menuStart);
  222. currentValidChoices = currentChoices.Where(x => x.IsEnabled).ToList();
  223. index = 0;
  224. validIndex = 0;
  225. continue;
  226. }
  227. if (keyPressed == ConsoleKey.Enter)
  228. {
  229. break;
  230. }
  231. }
  232. if (CloseFrame)
  233. Frame.Clear();
  234. Console.CursorVisible = visCache;
  235. return currentValidChoices[validIndex].ReturnValue;
  236. }
  237. private bool NextButtonPresent()
  238. {
  239. return Choices.Any(x => x.IsNextButton);
  240. }
  241. private bool PreviousButtonPresent()
  242. {
  243. return Choices.Any(x => x.IsNextButton);
  244. }
  245. public class MenuItem
  246. {
  247. public object ReturnValue { get; set; }
  248. public static readonly MenuItem Blank = new MenuItem("", null);
  249. public static readonly MenuItem BlankStatic = new MenuItem("", null) { IsStatic = true };
  250. public bool IsNextButton { get; set; } = false;
  251. public bool IsPreviousButton { get; set; } = false;
  252. public bool IsStatic { get; set; } = false;
  253. public string PrimaryText { get; set; } = "";
  254. public string SecondaryText { get; set; } = "";
  255. public MenuItem(string primaryText, object returnValue)
  256. {
  257. PrimaryText = primaryText;
  258. ReturnValue = returnValue;
  259. }
  260. public bool AddBetweenSpace { get; set; } = true;
  261. private ConsoleColor? _primaryTextForeground = null;
  262. public ConsoleColor? PrimaryTextForeground
  263. {
  264. get
  265. {
  266. if (_primaryTextForeground.HasValue)
  267. return _primaryTextForeground;
  268. if (IsEnabled) return null;
  269. if (Console.ForegroundColor == ConsoleColor.White) return ConsoleColor.DarkGray;
  270. if (Console.ForegroundColor == ConsoleColor.White) return ConsoleColor.DarkGray;
  271. return null;
  272. }
  273. set { _primaryTextForeground = value; }
  274. }
  275. public ConsoleColor? PrimaryTextBackground { get; set; } = null;
  276. public ConsoleColor? SecondaryTextForeground { get; set; } = null;
  277. public ConsoleColor? SecondaryTextBackground { get; set; } = null;
  278. private bool? _isEnabled = null;
  279. public bool IsEnabled
  280. {
  281. get
  282. {
  283. if (_isEnabled.HasValue)
  284. return _isEnabled.Value;
  285. if (!String.IsNullOrEmpty(PrimaryText) || !String.IsNullOrEmpty(SecondaryText))
  286. {
  287. return true;
  288. }
  289. return false;
  290. }
  291. set { _isEnabled = value; }
  292. }
  293. public bool StretchSelection = false;
  294. public void Write()
  295. {
  296. if (!String.IsNullOrEmpty(PrimaryText))
  297. {
  298. ConsoleUtils.SetColor(PrimaryTextForeground, PrimaryTextBackground);
  299. Console.Write(PrimaryText);
  300. ConsoleUtils.ResetColor();
  301. if (AddBetweenSpace)
  302. Console.Write(' ');
  303. }
  304. if (String.IsNullOrEmpty(SecondaryText))
  305. return;
  306. ConsoleUtils.SetColor(SecondaryTextForeground, SecondaryTextBackground);
  307. Console.Write(SecondaryText);
  308. ConsoleUtils.ResetColor();
  309. }
  310. public void WriteSelected(ConsoleColor? foreground, ConsoleColor? background)
  311. {
  312. Console.SetCursorPosition(Console.CursorLeft - 2, Console.CursorTop);
  313. if (!String.IsNullOrEmpty(PrimaryText))
  314. {
  315. ConsoleUtils.SetColor(foreground, background);
  316. Console.Write("> " + PrimaryText);
  317. if (!StretchSelection)
  318. ConsoleUtils.ResetColor();
  319. if (AddBetweenSpace)
  320. Console.Write(' ');
  321. }
  322. if (String.IsNullOrEmpty(SecondaryText))
  323. {
  324. if (StretchSelection)
  325. ConsoleUtils.ResetColor();
  326. return;
  327. }
  328. if (!String.IsNullOrEmpty(PrimaryText) && !StretchSelection)
  329. ConsoleUtils.SetColor(SecondaryTextForeground, SecondaryTextBackground);
  330. Console.Write(SecondaryText);
  331. ConsoleUtils.ResetColor();
  332. }
  333. }
  334. }
  335. }