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.

408 lines
14 KiB

  1. using UnityEngine.Experimental.UIElements;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using UnityEngine;
  6. namespace UnityEditor.PackageManager.UI
  7. {
  8. #if !UNITY_2018_3_OR_NEWER
  9. internal class PackageListFactory : UxmlFactory<PackageList>
  10. {
  11. protected override PackageList DoCreate(IUxmlAttributes bag, CreationContext cc)
  12. {
  13. return new PackageList();
  14. }
  15. }
  16. #endif
  17. internal class PackageList : VisualElement
  18. {
  19. #if UNITY_2018_3_OR_NEWER
  20. internal new class UxmlFactory : UxmlFactory<PackageList> { }
  21. #endif
  22. public event Action<Package> OnSelected = delegate { };
  23. public event Action OnLoaded = delegate { };
  24. public event Action OnFocusChange = delegate { };
  25. private readonly VisualElement root;
  26. internal PackageItem selectedItem;
  27. private List<PackageGroup> Groups;
  28. public PackageList()
  29. {
  30. Groups = new List<PackageGroup>();
  31. root = Resources.GetTemplate("PackageList.uxml");
  32. Add(root);
  33. root.StretchToParentSize();
  34. UIUtils.SetElementDisplay(Empty, false);
  35. UIUtils.SetElementDisplay(NoResult, false);
  36. PackageCollection.Instance.OnPackagesChanged += SetPackages;
  37. RegisterCallback<AttachToPanelEvent>(OnEnterPanel);
  38. RegisterCallback<DetachFromPanelEvent>(OnLeavePanel);
  39. Reload();
  40. }
  41. public void GrabFocus()
  42. {
  43. if (selectedItem == null)
  44. return;
  45. selectedItem.Focus();
  46. }
  47. public void ShowResults(PackageItem item)
  48. {
  49. NoResultText.text = string.Empty;
  50. UIUtils.SetElementDisplay(NoResult, false);
  51. Select(item);
  52. EditorApplication.delayCall += ScrollIfNeeded;
  53. UpdateGroups();
  54. }
  55. public void ShowNoResults()
  56. {
  57. NoResultText.text = string.Format("No results for \"{0}\"", PackageSearchFilter.Instance.SearchText);
  58. UIUtils.SetElementDisplay(NoResult, true);
  59. foreach (var group in Groups)
  60. {
  61. UIUtils.SetElementDisplay(group, false);
  62. }
  63. Select(null);
  64. OnSelected(null);
  65. }
  66. private void UpdateGroups()
  67. {
  68. foreach (var group in Groups)
  69. {
  70. PackageItem firstPackage = null;
  71. PackageItem lastPackage = null;
  72. var listGroup = group.Query<PackageItem>().ToList();
  73. foreach (var item in listGroup)
  74. {
  75. if (!item.visible)
  76. continue;
  77. if (firstPackage == null) firstPackage = item;
  78. lastPackage = item;
  79. }
  80. if (firstPackage == null && lastPackage == null)
  81. {
  82. UIUtils.SetElementDisplay(group, false);
  83. }
  84. else
  85. {
  86. UIUtils.SetElementDisplay(group, true);
  87. group.firstPackage = firstPackage;
  88. group.lastPackage = lastPackage;
  89. }
  90. }
  91. }
  92. private void OnEnterPanel(AttachToPanelEvent e)
  93. {
  94. panel.visualTree.RegisterCallback<KeyDownEvent>(OnKeyDownShortcut);
  95. }
  96. private void OnLeavePanel(DetachFromPanelEvent e)
  97. {
  98. panel.visualTree.UnregisterCallback<KeyDownEvent>(OnKeyDownShortcut);
  99. }
  100. private void ScrollIfNeeded()
  101. {
  102. EditorApplication.delayCall -= ScrollIfNeeded;
  103. if (selectedItem == null)
  104. return;
  105. var minY = List.worldBound.yMin;
  106. var maxY = List.worldBound.yMax;
  107. var itemMinY = selectedItem.worldBound.yMin;
  108. var itemMaxY = selectedItem.worldBound.yMax;
  109. var scroll = List.scrollOffset;
  110. if (itemMinY < minY)
  111. {
  112. scroll.y -= minY - itemMinY;
  113. if (scroll.y <= minY)
  114. scroll.y = 0;
  115. List.scrollOffset = scroll;
  116. }
  117. else if (itemMaxY > maxY)
  118. {
  119. scroll.y += itemMaxY - maxY;
  120. List.scrollOffset = scroll;
  121. }
  122. }
  123. private void OnKeyDownShortcut(KeyDownEvent evt)
  124. {
  125. if (selectedItem == null)
  126. return;
  127. if (evt.keyCode == KeyCode.Tab)
  128. {
  129. OnFocusChange();
  130. evt.StopPropagation();
  131. return;
  132. }
  133. if (evt.keyCode == KeyCode.UpArrow)
  134. {
  135. if (selectedItem.previousItem != null)
  136. {
  137. Select(selectedItem.previousItem);
  138. ScrollIfNeeded();
  139. }
  140. else if (selectedItem.packageGroup.previousGroup != null && selectedItem.packageGroup.previousGroup.visible)
  141. {
  142. Select(selectedItem.packageGroup.previousGroup.lastPackage);
  143. ScrollIfNeeded();
  144. }
  145. evt.StopPropagation();
  146. return;
  147. }
  148. if (evt.keyCode == KeyCode.DownArrow)
  149. {
  150. if (selectedItem.nextItem != null)
  151. {
  152. Select(selectedItem.nextItem);
  153. ScrollIfNeeded();
  154. }
  155. else if (selectedItem.packageGroup.nextGroup != null && selectedItem.packageGroup.nextGroup.visible)
  156. {
  157. Select(selectedItem.packageGroup.nextGroup.firstPackage);
  158. ScrollIfNeeded();
  159. }
  160. evt.StopPropagation();
  161. return;
  162. }
  163. if (evt.keyCode == KeyCode.PageUp)
  164. {
  165. if (selectedItem.packageGroup != null)
  166. {
  167. if (selectedItem == selectedItem.packageGroup.lastPackage && selectedItem != selectedItem.packageGroup.firstPackage)
  168. {
  169. Select(selectedItem.packageGroup.firstPackage);
  170. ScrollIfNeeded();
  171. }
  172. else if (selectedItem == selectedItem.packageGroup.firstPackage && selectedItem.packageGroup.previousGroup != null && selectedItem.packageGroup.previousGroup.visible)
  173. {
  174. Select(selectedItem.packageGroup.previousGroup.lastPackage);
  175. ScrollIfNeeded();
  176. }
  177. else if (selectedItem != selectedItem.packageGroup.lastPackage && selectedItem != selectedItem.packageGroup.firstPackage)
  178. {
  179. Select(selectedItem.packageGroup.firstPackage);
  180. ScrollIfNeeded();
  181. }
  182. }
  183. evt.StopPropagation();
  184. return;
  185. }
  186. if (evt.keyCode == KeyCode.PageDown)
  187. {
  188. if (selectedItem.packageGroup != null)
  189. {
  190. if (selectedItem == selectedItem.packageGroup.firstPackage && selectedItem != selectedItem.packageGroup.lastPackage)
  191. {
  192. Select(selectedItem.packageGroup.lastPackage);
  193. ScrollIfNeeded();
  194. }
  195. else if (selectedItem == selectedItem.packageGroup.lastPackage && selectedItem.packageGroup.nextGroup != null && selectedItem.packageGroup.nextGroup.visible)
  196. {
  197. Select(selectedItem.packageGroup.nextGroup.firstPackage);
  198. ScrollIfNeeded();
  199. }
  200. else if (selectedItem != selectedItem.packageGroup.firstPackage && selectedItem != selectedItem.packageGroup.lastPackage)
  201. {
  202. Select(selectedItem.packageGroup.lastPackage);
  203. ScrollIfNeeded();
  204. }
  205. }
  206. evt.StopPropagation();
  207. }
  208. }
  209. private void Reload()
  210. {
  211. // Force a re-init to initial condition
  212. PackageCollection.Instance.UpdatePackageCollection();
  213. SelectLastSelection();
  214. }
  215. private void ClearAll()
  216. {
  217. List.Clear();
  218. Groups.Clear();
  219. UIUtils.SetElementDisplay(Empty, false);
  220. UIUtils.SetElementDisplay(NoResult, false);
  221. }
  222. private void SetPackages(IEnumerable<Package> packages)
  223. {
  224. if (PackageCollection.Instance.Filter == PackageFilter.Modules)
  225. {
  226. packages = packages.Where(pkg => pkg.IsBuiltIn);
  227. }
  228. else if (PackageCollection.Instance.Filter== PackageFilter.All)
  229. {
  230. packages = packages.Where(pkg => !pkg.IsBuiltIn);
  231. }
  232. else
  233. {
  234. packages = packages.Where(pkg => !pkg.IsBuiltIn);
  235. packages = packages.Where(pkg => pkg.Current != null);
  236. }
  237. OnLoaded();
  238. ClearAll();
  239. var packagesGroup = new PackageGroup(PackageGroupOrigins.Packages.ToString());
  240. Groups.Add(packagesGroup);
  241. List.Add(packagesGroup);
  242. packagesGroup.previousGroup = null;
  243. var builtInGroup = new PackageGroup(PackageGroupOrigins.BuiltInPackages.ToString());
  244. Groups.Add(builtInGroup);
  245. List.Add(builtInGroup);
  246. if ((PackageCollection.Instance.Filter & PackageFilter.Modules) == PackageFilter.Modules)
  247. {
  248. packagesGroup.nextGroup = builtInGroup;
  249. builtInGroup.previousGroup = packagesGroup;
  250. builtInGroup.nextGroup = null;
  251. }
  252. else
  253. {
  254. packagesGroup.nextGroup = null;
  255. UIUtils.SetElementDisplay(builtInGroup, false);
  256. }
  257. var lastSelection = PackageCollection.Instance.SelectedPackage;
  258. Select(null);
  259. PackageItem defaultSelection = null;
  260. foreach (var package in packages.OrderBy(pkg => pkg.Versions.FirstOrDefault() == null ? pkg.Name : pkg.Versions.FirstOrDefault().DisplayName))
  261. {
  262. var item = AddPackage(package);
  263. if (null == selectedItem && defaultSelection == null)
  264. defaultSelection = item;
  265. if (null == selectedItem && !string.IsNullOrEmpty(lastSelection) && package.Name.Equals(lastSelection))
  266. Select(item);
  267. }
  268. if (selectedItem == null)
  269. Select(defaultSelection);
  270. PackageFiltering.FilterPackageList(this);
  271. }
  272. public void SelectLastSelection()
  273. {
  274. var lastSelection = PackageCollection.Instance.SelectedPackage;
  275. if (lastSelection == null)
  276. return;
  277. var list = List.Query<PackageItem>().ToList();
  278. PackageItem defaultSelection = null;
  279. foreach (var item in list)
  280. {
  281. if (defaultSelection == null)
  282. defaultSelection = item;
  283. if (!string.IsNullOrEmpty(lastSelection) && item.package.Name.Equals(lastSelection))
  284. {
  285. defaultSelection = item;
  286. break;
  287. }
  288. }
  289. selectedItem = null;
  290. Select(defaultSelection);
  291. }
  292. private PackageItem AddPackage(Package package)
  293. {
  294. var groupName = package.Latest != null ? package.Latest.Group : package.Current.Group;
  295. var group = GetOrCreateGroup(groupName);
  296. var packageItem = group.AddPackage(package);
  297. packageItem.OnSelected += Select;
  298. return packageItem;
  299. }
  300. private PackageGroup GetOrCreateGroup(string groupName)
  301. {
  302. foreach (var g in Groups)
  303. {
  304. if (g.name == groupName)
  305. return g;
  306. }
  307. var group = new PackageGroup(groupName);
  308. var latestGroup = Groups.LastOrDefault();
  309. Groups.Add(group);
  310. List.Add(group);
  311. group.previousGroup = null;
  312. if (latestGroup != null)
  313. {
  314. latestGroup.nextGroup = group;
  315. group.previousGroup = latestGroup;
  316. group.nextGroup = null;
  317. }
  318. return group;
  319. }
  320. private void Select(PackageItem packageItem)
  321. {
  322. if (packageItem == selectedItem)
  323. return;
  324. var selectedPackageName = packageItem != null ? packageItem.package.Name : null;
  325. PackageCollection.Instance.SelectedPackage = selectedPackageName;
  326. if (selectedItem != null)
  327. selectedItem.SetSelected(false); // Clear Previous selection
  328. selectedItem = packageItem;
  329. if (selectedItem == null)
  330. {
  331. OnSelected(null);
  332. return;
  333. }
  334. selectedItem.SetSelected(true);
  335. ScrollIfNeeded();
  336. OnSelected(selectedItem.package);
  337. }
  338. private ScrollView List { get { return root.Q<ScrollView>("scrollView"); } }
  339. private VisualElement Empty { get { return root.Q<VisualElement>("emptyArea"); } }
  340. private VisualElement NoResult { get { return root.Q<VisualElement>("noResult"); } }
  341. private Label NoResultText { get { return root.Q<Label>("noResultText"); } }
  342. }
  343. }