using UnityEngine.Experimental.UIElements; using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace UnityEditor.PackageManager.UI { #if !UNITY_2018_3_OR_NEWER internal class PackageListFactory : UxmlFactory { protected override PackageList DoCreate(IUxmlAttributes bag, CreationContext cc) { return new PackageList(); } } #endif internal class PackageList : VisualElement { #if UNITY_2018_3_OR_NEWER internal new class UxmlFactory : UxmlFactory { } #endif public event Action OnSelected = delegate { }; public event Action OnLoaded = delegate { }; public event Action OnFocusChange = delegate { }; private readonly VisualElement root; internal PackageItem selectedItem; private List Groups; public PackageList() { Groups = new List(); root = Resources.GetTemplate("PackageList.uxml"); Add(root); root.StretchToParentSize(); UIUtils.SetElementDisplay(Empty, false); UIUtils.SetElementDisplay(NoResult, false); PackageCollection.Instance.OnPackagesChanged += SetPackages; RegisterCallback(OnEnterPanel); RegisterCallback(OnLeavePanel); Reload(); } public void GrabFocus() { if (selectedItem == null) return; selectedItem.Focus(); } public void ShowResults(PackageItem item) { NoResultText.text = string.Empty; UIUtils.SetElementDisplay(NoResult, false); Select(item); EditorApplication.delayCall += ScrollIfNeeded; UpdateGroups(); } public void ShowNoResults() { NoResultText.text = string.Format("No results for \"{0}\"", PackageSearchFilter.Instance.SearchText); UIUtils.SetElementDisplay(NoResult, true); foreach (var group in Groups) { UIUtils.SetElementDisplay(group, false); } Select(null); OnSelected(null); } private void UpdateGroups() { foreach (var group in Groups) { PackageItem firstPackage = null; PackageItem lastPackage = null; var listGroup = group.Query().ToList(); foreach (var item in listGroup) { if (!item.visible) continue; if (firstPackage == null) firstPackage = item; lastPackage = item; } if (firstPackage == null && lastPackage == null) { UIUtils.SetElementDisplay(group, false); } else { UIUtils.SetElementDisplay(group, true); group.firstPackage = firstPackage; group.lastPackage = lastPackage; } } } private void OnEnterPanel(AttachToPanelEvent e) { panel.visualTree.RegisterCallback(OnKeyDownShortcut); } private void OnLeavePanel(DetachFromPanelEvent e) { panel.visualTree.UnregisterCallback(OnKeyDownShortcut); } private void ScrollIfNeeded() { EditorApplication.delayCall -= ScrollIfNeeded; if (selectedItem == null) return; var minY = List.worldBound.yMin; var maxY = List.worldBound.yMax; var itemMinY = selectedItem.worldBound.yMin; var itemMaxY = selectedItem.worldBound.yMax; var scroll = List.scrollOffset; if (itemMinY < minY) { scroll.y -= minY - itemMinY; if (scroll.y <= minY) scroll.y = 0; List.scrollOffset = scroll; } else if (itemMaxY > maxY) { scroll.y += itemMaxY - maxY; List.scrollOffset = scroll; } } private void OnKeyDownShortcut(KeyDownEvent evt) { if (selectedItem == null) return; if (evt.keyCode == KeyCode.Tab) { OnFocusChange(); evt.StopPropagation(); return; } if (evt.keyCode == KeyCode.UpArrow) { if (selectedItem.previousItem != null) { Select(selectedItem.previousItem); ScrollIfNeeded(); } else if (selectedItem.packageGroup.previousGroup != null && selectedItem.packageGroup.previousGroup.visible) { Select(selectedItem.packageGroup.previousGroup.lastPackage); ScrollIfNeeded(); } evt.StopPropagation(); return; } if (evt.keyCode == KeyCode.DownArrow) { if (selectedItem.nextItem != null) { Select(selectedItem.nextItem); ScrollIfNeeded(); } else if (selectedItem.packageGroup.nextGroup != null && selectedItem.packageGroup.nextGroup.visible) { Select(selectedItem.packageGroup.nextGroup.firstPackage); ScrollIfNeeded(); } evt.StopPropagation(); return; } if (evt.keyCode == KeyCode.PageUp) { if (selectedItem.packageGroup != null) { if (selectedItem == selectedItem.packageGroup.lastPackage && selectedItem != selectedItem.packageGroup.firstPackage) { Select(selectedItem.packageGroup.firstPackage); ScrollIfNeeded(); } else if (selectedItem == selectedItem.packageGroup.firstPackage && selectedItem.packageGroup.previousGroup != null && selectedItem.packageGroup.previousGroup.visible) { Select(selectedItem.packageGroup.previousGroup.lastPackage); ScrollIfNeeded(); } else if (selectedItem != selectedItem.packageGroup.lastPackage && selectedItem != selectedItem.packageGroup.firstPackage) { Select(selectedItem.packageGroup.firstPackage); ScrollIfNeeded(); } } evt.StopPropagation(); return; } if (evt.keyCode == KeyCode.PageDown) { if (selectedItem.packageGroup != null) { if (selectedItem == selectedItem.packageGroup.firstPackage && selectedItem != selectedItem.packageGroup.lastPackage) { Select(selectedItem.packageGroup.lastPackage); ScrollIfNeeded(); } else if (selectedItem == selectedItem.packageGroup.lastPackage && selectedItem.packageGroup.nextGroup != null && selectedItem.packageGroup.nextGroup.visible) { Select(selectedItem.packageGroup.nextGroup.firstPackage); ScrollIfNeeded(); } else if (selectedItem != selectedItem.packageGroup.firstPackage && selectedItem != selectedItem.packageGroup.lastPackage) { Select(selectedItem.packageGroup.lastPackage); ScrollIfNeeded(); } } evt.StopPropagation(); } } private void Reload() { // Force a re-init to initial condition PackageCollection.Instance.UpdatePackageCollection(); SelectLastSelection(); } private void ClearAll() { List.Clear(); Groups.Clear(); UIUtils.SetElementDisplay(Empty, false); UIUtils.SetElementDisplay(NoResult, false); } private void SetPackages(IEnumerable packages) { if (PackageCollection.Instance.Filter == PackageFilter.Modules) { packages = packages.Where(pkg => pkg.IsBuiltIn); } else if (PackageCollection.Instance.Filter== PackageFilter.All) { packages = packages.Where(pkg => !pkg.IsBuiltIn); } else { packages = packages.Where(pkg => !pkg.IsBuiltIn); packages = packages.Where(pkg => pkg.Current != null); } OnLoaded(); ClearAll(); var packagesGroup = new PackageGroup(PackageGroupOrigins.Packages.ToString()); Groups.Add(packagesGroup); List.Add(packagesGroup); packagesGroup.previousGroup = null; var builtInGroup = new PackageGroup(PackageGroupOrigins.BuiltInPackages.ToString()); Groups.Add(builtInGroup); List.Add(builtInGroup); if ((PackageCollection.Instance.Filter & PackageFilter.Modules) == PackageFilter.Modules) { packagesGroup.nextGroup = builtInGroup; builtInGroup.previousGroup = packagesGroup; builtInGroup.nextGroup = null; } else { packagesGroup.nextGroup = null; UIUtils.SetElementDisplay(builtInGroup, false); } var lastSelection = PackageCollection.Instance.SelectedPackage; Select(null); PackageItem defaultSelection = null; foreach (var package in packages.OrderBy(pkg => pkg.Versions.FirstOrDefault() == null ? pkg.Name : pkg.Versions.FirstOrDefault().DisplayName)) { var item = AddPackage(package); if (null == selectedItem && defaultSelection == null) defaultSelection = item; if (null == selectedItem && !string.IsNullOrEmpty(lastSelection) && package.Name.Equals(lastSelection)) Select(item); } if (selectedItem == null) Select(defaultSelection); PackageFiltering.FilterPackageList(this); } public void SelectLastSelection() { var lastSelection = PackageCollection.Instance.SelectedPackage; if (lastSelection == null) return; var list = List.Query().ToList(); PackageItem defaultSelection = null; foreach (var item in list) { if (defaultSelection == null) defaultSelection = item; if (!string.IsNullOrEmpty(lastSelection) && item.package.Name.Equals(lastSelection)) { defaultSelection = item; break; } } selectedItem = null; Select(defaultSelection); } private PackageItem AddPackage(Package package) { var groupName = package.Latest != null ? package.Latest.Group : package.Current.Group; var group = GetOrCreateGroup(groupName); var packageItem = group.AddPackage(package); packageItem.OnSelected += Select; return packageItem; } private PackageGroup GetOrCreateGroup(string groupName) { foreach (var g in Groups) { if (g.name == groupName) return g; } var group = new PackageGroup(groupName); var latestGroup = Groups.LastOrDefault(); Groups.Add(group); List.Add(group); group.previousGroup = null; if (latestGroup != null) { latestGroup.nextGroup = group; group.previousGroup = latestGroup; group.nextGroup = null; } return group; } private void Select(PackageItem packageItem) { if (packageItem == selectedItem) return; var selectedPackageName = packageItem != null ? packageItem.package.Name : null; PackageCollection.Instance.SelectedPackage = selectedPackageName; if (selectedItem != null) selectedItem.SetSelected(false); // Clear Previous selection selectedItem = packageItem; if (selectedItem == null) { OnSelected(null); return; } selectedItem.SetSelected(true); ScrollIfNeeded(); OnSelected(selectedItem.package); } private ScrollView List { get { return root.Q("scrollView"); } } private VisualElement Empty { get { return root.Q("emptyArea"); } } private VisualElement NoResult { get { return root.Q("noResult"); } } private Label NoResultText { get { return root.Q