/NesMenuCollection.cs

https://github.com/ClusterM/hakchi2 · C# · 271 lines · 257 code · 12 blank · 2 comment · 79 complexity · 2f2c05c26a97b7b9779855a296ad7fa4 MD5 · raw file

  1. using com.clusterrr.hakchi_gui.Properties;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text.RegularExpressions;
  6. namespace com.clusterrr.hakchi_gui
  7. {
  8. public class NesMenuCollection : List<INesMenuElement>
  9. {
  10. const int FoldersEqualLetters = 3;
  11. const int PagesEqualLetters = 3;
  12. public enum SplitStyle
  13. {
  14. NoSplit = 0,
  15. Original_NoSplit = 1,
  16. Auto = 2,
  17. Original_Auto = 3,
  18. PagesEqual = 4,
  19. Original_PagesEqual = 5,
  20. FoldersEqual = 6,
  21. Original_FoldersEqual = 7,
  22. FoldersAlphabetic_FoldersEqual = 8,
  23. Original_FoldersAlphabetic_FoldersEqual = 9,
  24. FoldersAlphabetic_PagesEqual = 10,
  25. Original_FoldersAlphabetic_PagesEqual = 11,
  26. Custom = 99
  27. }
  28. public void Split(SplitStyle style, int maxElements = 35)
  29. {
  30. bool originalToRoot = false;
  31. int originalCount = 0;
  32. switch (style)
  33. {
  34. case SplitStyle.Original_NoSplit:
  35. case SplitStyle.Original_Auto:
  36. case SplitStyle.Original_FoldersAlphabetic_FoldersEqual:
  37. case SplitStyle.Original_FoldersAlphabetic_PagesEqual:
  38. case SplitStyle.Original_FoldersEqual:
  39. case SplitStyle.Original_PagesEqual:
  40. style--;
  41. originalCount = this.Where(o => o is NesDefaultGame).Count();
  42. if (originalCount > 0)
  43. originalToRoot = true;
  44. break;
  45. }
  46. if (style == SplitStyle.NoSplit && !originalToRoot) return;
  47. if (((style == SplitStyle.Auto && !originalToRoot) ||
  48. (style == SplitStyle.FoldersEqual && !originalToRoot) ||
  49. (style == SplitStyle.PagesEqual) && !originalToRoot) &&
  50. (Count <= maxElements)) return;
  51. var total = Count - originalCount;
  52. var partsCount = (int)Math.Ceiling((float)total / (float)maxElements);
  53. var perPart = (int)Math.Ceiling((float)total / (float)partsCount);
  54. var alphaNum = new Regex("[^a-zA-Z0-9]");
  55. NesMenuCollection root;
  56. if (!originalToRoot)
  57. root = this;
  58. else
  59. {
  60. root = new NesMenuCollection();
  61. root.AddRange(this.Where(o => !(o is NesDefaultGame || o.GetType() == typeof(NesMiniApplication))));
  62. if (root.Count == 0)
  63. return;
  64. this.RemoveAll(o => root.Contains(o));
  65. this.Add(new NesMenuFolder()
  66. {
  67. Name = Resources.FolderNameMoreGames,
  68. Position = NesMenuFolder.Priority.Rightmost,
  69. ChildMenuCollection = root
  70. });
  71. }
  72. var sorted = root.OrderBy(o => o.Name);
  73. var collections = new List<NesMenuCollection>();
  74. int i = 0;
  75. if (style == SplitStyle.Auto || style == SplitStyle.FoldersEqual || style == SplitStyle.PagesEqual)
  76. {
  77. var collection = new NesMenuCollection();
  78. foreach (var game in sorted)
  79. {
  80. collection.Add(game);
  81. i++;
  82. if (((i % perPart) == 0) || (i == sorted.Count()))
  83. {
  84. collections.Add(collection);
  85. collection = new NesMenuCollection();
  86. }
  87. }
  88. }
  89. if (style == SplitStyle.Auto)
  90. {
  91. if (collections.Count >= 12)
  92. style = SplitStyle.FoldersEqual;
  93. else
  94. style = SplitStyle.PagesEqual;
  95. }
  96. // Folders, equal
  97. if (style == SplitStyle.FoldersEqual) // minimum amount of games/folders on screen without glitches
  98. {
  99. root.Clear();
  100. foreach (var coll in collections)
  101. {
  102. var fname = alphaNum.Replace(coll.Where(o => (o is NesMiniApplication) || (o is NesDefaultGame)).First().Name.ToUpper(), "");
  103. var lname = alphaNum.Replace(coll.Where(o => (o is NesMiniApplication) || (o is NesDefaultGame)).Last().Name.ToUpper(), "");
  104. var folder = new NesMenuFolder() { ChildMenuCollection = coll, NameParts = new string[] { fname, lname }, Position = NesMenuFolder.Priority.Right };
  105. coll.Add(new NesMenuFolder() { Name = Resources.FolderNameBack, ImageId = "folder_back", Position = NesMenuFolder.Priority.Back, ChildMenuCollection = root });
  106. root.Add(folder);
  107. }
  108. TrimFolderNames(root);
  109. }
  110. else if (style == SplitStyle.PagesEqual)
  111. // Pages, equal
  112. {
  113. root.Clear();
  114. root.AddRange(collections[0]);
  115. collections[0] = root;
  116. for (i = 0; i < collections.Count; i++)
  117. {
  118. for (int j = i - 1; j >= 0; j--)
  119. {
  120. var fname = alphaNum.Replace(collections[j].Where(o => (o is NesMiniApplication) || (o is NesDefaultGame)).First().Name.ToUpper(), "");
  121. var lname = alphaNum.Replace(collections[j].Where(o => (o is NesMiniApplication) || (o is NesDefaultGame)).Last().Name.ToUpper(), "");
  122. var folder = new NesMenuFolder()
  123. {
  124. ChildMenuCollection = collections[j],
  125. NameParts = new string[] { fname, lname },
  126. Position = NesMenuFolder.Priority.Left
  127. };
  128. collections[i].Insert(0, folder);
  129. }
  130. for (int j = i + 1; j < collections.Count; j++)
  131. {
  132. var fname = alphaNum.Replace(collections[j].Where(o => (o is NesMiniApplication) || (o is NesDefaultGame)).First().Name.ToUpper(), "");
  133. var lname = alphaNum.Replace(collections[j].Where(o => (o is NesMiniApplication) || (o is NesDefaultGame)).Last().Name.ToUpper(), "");
  134. var folder = new NesMenuFolder()
  135. {
  136. ChildMenuCollection = collections[j],
  137. NameParts = new string[] { fname, lname },
  138. Position = NesMenuFolder.Priority.Right
  139. };
  140. collections[i].Insert(collections[i].Count, folder);
  141. }
  142. TrimFolderNames(collections[i]);
  143. }
  144. }
  145. else if (style == SplitStyle.FoldersAlphabetic_PagesEqual || style == SplitStyle.FoldersAlphabetic_FoldersEqual)
  146. {
  147. var letters = new Dictionary<char, NesMenuCollection>();
  148. for (char ch = 'A'; ch <= 'Z'; ch++)
  149. letters[ch] = new NesMenuCollection();
  150. letters['#'] = new NesMenuCollection();
  151. foreach (var game in root)
  152. {
  153. if (!(game is NesMiniApplication || game is NesDefaultGame)) continue;
  154. var letter = game.Name.Substring(0, 1).ToUpper()[0];
  155. if (letter < 'A' || letter > 'Z')
  156. letter = '#';
  157. letters[letter].Add(game);
  158. }
  159. root.Clear();
  160. foreach (var letter in letters.Keys)
  161. if (letters[letter].Count > 0)
  162. {
  163. string folderImageId = "folder_" + letter.ToString().ToLower();
  164. if (letter < 'A' || letter > 'Z') folderImageId = "folder_number";
  165. var folder = new NesMenuFolder() { ChildMenuCollection = letters[letter], Name = letter.ToString(), Position = NesMenuFolder.Priority.Right, ImageId = folderImageId };
  166. if (style == SplitStyle.FoldersAlphabetic_PagesEqual)
  167. {
  168. folder.ChildMenuCollection.Split(SplitStyle.PagesEqual, maxElements);
  169. folder.ChildMenuCollection.Add(new NesMenuFolder() { Name = Resources.FolderNameBack, ImageId = "folder_back", Position = NesMenuFolder.Priority.Back, ChildMenuCollection = root });
  170. foreach (NesMenuFolder f in folder.ChildMenuCollection.Where(o => o is NesMenuFolder))
  171. if (f.ChildMenuCollection != root)
  172. f.ChildMenuCollection.Add(new NesMenuFolder() { Name = Resources.FolderNameBack, ImageId = "folder_back", Position = NesMenuFolder.Priority.Back, ChildMenuCollection = root });
  173. }
  174. else if (style == SplitStyle.FoldersAlphabetic_FoldersEqual)
  175. {
  176. folder.ChildMenuCollection.Split(SplitStyle.FoldersEqual, maxElements);
  177. folder.ChildMenuCollection.Add(new NesMenuFolder() { Name = Resources.FolderNameBack, ImageId = "folder_back", Position = NesMenuFolder.Priority.Back, ChildMenuCollection = root });
  178. }
  179. root.Add(folder);
  180. }
  181. }
  182. if (originalToRoot)
  183. {
  184. if (style != SplitStyle.PagesEqual)
  185. root.Add(new NesMenuFolder() { Name = Resources.FolderNameOriginalGames, ImageId = "folder_back", Position = NesMenuFolder.Priority.Back, ChildMenuCollection = this });
  186. else
  187. {
  188. foreach (var collection in collections)
  189. collection.Add(new NesMenuFolder() { Name = Resources.FolderNameOriginalGames, ImageId = "folder_back", Position = NesMenuFolder.Priority.Back, ChildMenuCollection = this });
  190. }
  191. }
  192. }
  193. public void Unsplit(List<NesMenuCollection> ignore = null)
  194. {
  195. if (ignore == null)
  196. ignore = new List<NesMenuCollection>();
  197. ignore.Add(this);
  198. var newElements = new List<INesMenuElement>();
  199. var oldElements = new List<INesMenuElement>();
  200. foreach (NesMenuFolder item in from i in this where i is NesMenuFolder select i)
  201. {
  202. if (ignore.Contains(item.ChildMenuCollection))
  203. continue;
  204. item.ChildMenuCollection.Unsplit(ignore);
  205. newElements.AddRange(item.ChildMenuCollection);
  206. item.ChildMenuCollection.Clear();
  207. oldElements.Add(item);
  208. }
  209. this.AddRange(newElements);
  210. this.RemoveAll(o => oldElements.Contains(o));
  211. }
  212. public void AddBack(List<NesMenuCollection> ignore = null)
  213. {
  214. if (ignore == null)
  215. ignore = new List<NesMenuCollection>();
  216. ignore.Add(this);
  217. foreach (NesMenuFolder item in from i in this where i is NesMenuFolder select i)
  218. {
  219. if (ignore.Contains(item.ChildMenuCollection))
  220. continue;
  221. var back = new NesMenuFolder(Resources.FolderNameBack, "folder_back");
  222. back.Position = NesMenuFolder.Priority.Back;
  223. back.ChildMenuCollection = this;
  224. item.ChildMenuCollection.AddBack(ignore);
  225. item.ChildMenuCollection.Add(back);
  226. }
  227. }
  228. void TrimFolderNames(NesMenuCollection nesMenuCollection)
  229. {
  230. const int minChars = 3;
  231. const int maxChars = 8;
  232. var folders = nesMenuCollection.Where(o => o is NesMenuFolder).OrderBy(o => o.Name).ToArray();
  233. for (int i = 1; i < folders.Length; i++)
  234. {
  235. var prevFolder = i > 0 ? (folders[i - 1] as NesMenuFolder) : null;
  236. var currentFolder = folders[i] as NesMenuFolder;
  237. var nameA = prevFolder.NameParts[1];
  238. var nameB = currentFolder.NameParts[0];
  239. int l = Math.Min(maxChars - 1, Math.Max(nameA.Length, nameB.Length));
  240. while ((nameA.Substring(0, Math.Min(l, nameA.Length)) !=
  241. nameB.Substring(0, Math.Min(l, nameB.Length))) && l >= minChars)
  242. l--;
  243. nameA = nameA.Substring(0, Math.Min(l + 1, nameA.Length));
  244. nameB = nameB.Substring(0, Math.Min(l + 1, nameB.Length));
  245. if (nameA == nameB) // There is no point to make long name
  246. nameA = nameB = nameA.Substring(0, Math.Min(minChars, nameA.Length));
  247. prevFolder.NameParts = new string[] { prevFolder.NameParts[0], nameA };
  248. currentFolder.NameParts = new string[] { nameB, currentFolder.NameParts[1] };
  249. }
  250. if (folders.Length > 0)
  251. {
  252. var firstFolder = folders[0] as NesMenuFolder;
  253. firstFolder.NameParts = new string[] { firstFolder.NameParts[0].Substring(0, Math.Min(firstFolder.NameParts[0].Length, minChars)), firstFolder.NameParts[1] };
  254. var lastFolder = folders[folders.Length - 1] as NesMenuFolder;
  255. lastFolder.NameParts = new string[] { lastFolder.NameParts[0], lastFolder.NameParts[1].Substring(0, Math.Min(lastFolder.NameParts[1].Length, minChars)), };
  256. }
  257. }
  258. }
  259. }