From 041f2938f7677eca8886e9587c9e5454112f2a92 Mon Sep 17 00:00:00 2001 From: Sinai Date: Wed, 26 May 2021 17:42:31 +1000 Subject: [PATCH] Implement jumping to index in TransformTree --- .../GameObjectWidgets/GameObjectControls.cs | 17 +- src/UI/ObjectExplorer/SceneExplorer.cs | 19 ++- src/UI/Widgets/ScrollPool/ScrollPool.cs | 63 ++++---- src/UI/Widgets/TransformTree/TransformTree.cs | 148 ++++++++++++------ 4 files changed, 166 insertions(+), 81 deletions(-) diff --git a/src/UI/Inspectors/GameObjectWidgets/GameObjectControls.cs b/src/UI/Inspectors/GameObjectWidgets/GameObjectControls.cs index f4cb64c..dc15039 100644 --- a/src/UI/Inspectors/GameObjectWidgets/GameObjectControls.cs +++ b/src/UI/Inspectors/GameObjectWidgets/GameObjectControls.cs @@ -232,6 +232,15 @@ namespace UnityExplorer.UI.Inspectors } } + private void OnExploreButtonClicked() + { + var panel = UIManager.GetPanel(UIManager.Panels.ObjectExplorer); + UIManager.SetPanelActive(panel, true); + panel.SetTab(0); + + panel.SceneExplorer.JumpToTransform(this.Parent.GOTarget.transform); + } + private void OnLayerDropdownChanged(int value) { GOTarget.layer = value; @@ -533,6 +542,12 @@ namespace UnityExplorer.UI.Inspectors UIFactory.SetLayoutGroup(thirdrow, false, false, true, true, 5, 0, 0, 0, 0, default); UIFactory.SetLayoutElement(thirdrow, minHeight: 25, flexibleWidth: 9999); + // Inspect in Explorer button + var explorerBtn = UIFactory.CreateButton(thirdrow, "ExploreBtn", "Show in Explorer", new Color(0.15f, 0.15f, 0.15f)); + UIFactory.SetLayoutElement(explorerBtn.Component.gameObject, minHeight: 25, minWidth: 100); + explorerBtn.ButtonText.fontSize = 12; + explorerBtn.OnClick += OnExploreButtonClicked; + // Scene var sceneLabel = UIFactory.CreateLabel(thirdrow, "SceneLabel", "Scene:", TextAnchor.MiddleLeft, Color.grey); UIFactory.SetLayoutElement(sceneLabel.gameObject, minHeight: 25, minWidth: 50); @@ -547,7 +562,7 @@ namespace UnityExplorer.UI.Inspectors UIFactory.SetLayoutElement(layerLabel.gameObject, minHeight: 25, minWidth: 50); var layerDrop = UIFactory.CreateDropdown(thirdrow, out LayerDropdown, "0", 14, OnLayerDropdownChanged); - UIFactory.SetLayoutElement(layerDrop, minHeight: 25, minWidth: 120, flexibleWidth: 999); + UIFactory.SetLayoutElement(layerDrop, minHeight: 25, minWidth: 110, flexibleWidth: 999); LayerDropdown.captionText.color = SignatureHighlighter.EnumGreen; if (layerToNames == null) GetLayerNames(); diff --git a/src/UI/ObjectExplorer/SceneExplorer.cs b/src/UI/ObjectExplorer/SceneExplorer.cs index ea94762..1d02af1 100644 --- a/src/UI/ObjectExplorer/SceneExplorer.cs +++ b/src/UI/ObjectExplorer/SceneExplorer.cs @@ -58,6 +58,23 @@ namespace UnityExplorer.UI.ObjectExplorer Tree.RefreshData(true); } + public void JumpToTransform(Transform transform) + { + if (!transform) + return; + + // select the transform's scene + var go = transform.gameObject; + if (SceneHandler.SelectedScene != go.scene) + { + int idx = sceneDropdown.options.IndexOf(sceneToDropdownOption[go.scene.handle]); + sceneDropdown.value = idx; + } + + // Let the TransformTree handle the rest + Tree.JumpAndExpandToTransform(transform); + } + private void OnDropdownChanged(int value) { if (value < 0 || SceneHandler.LoadedScenes.Count <= value) @@ -122,7 +139,7 @@ namespace UnityExplorer.UI.ObjectExplorer { if ((!string.IsNullOrEmpty(input) && !Tree.Filtering) || (string.IsNullOrEmpty(input) && Tree.Filtering)) { - Tree.displayedObjects.Clear(); + Tree.cachedTransforms.Clear(); } Tree.CurrentFilter = input; diff --git a/src/UI/Widgets/ScrollPool/ScrollPool.cs b/src/UI/Widgets/ScrollPool/ScrollPool.cs index 7d79f47..b3f073c 100644 --- a/src/UI/Widgets/ScrollPool/ScrollPool.cs +++ b/src/UI/Widgets/ScrollPool/ScrollPool.cs @@ -7,7 +7,6 @@ using UnityEngine; using UnityEngine.UI; using UnityExplorer.Core.Input; using UnityExplorer.UI.Models; -using UnityExplorer.UI.ObjectPool; using UnityExplorer.UI.Panels; namespace UnityExplorer.UI.Widgets @@ -20,7 +19,7 @@ namespace UnityExplorer.UI.Widgets /// /// An object-pooled ScrollRect, attempts to support content of any size and provide a scrollbar for it. /// - public class ScrollPool : UIBehaviourModel where T : ICell + public class ScrollPool : UIBehaviourModel, IEnumerable where T : ICell { public ScrollPool(ScrollRect scrollRect) { @@ -138,9 +137,23 @@ namespace UnityExplorer.UI.Widgets RefreshCells(setCellData, true); } - // Initialize + public void JumpToIndex(int index) + { + RefreshCells(true, true); - //private bool Initialized; + float normalized = HeightCache[index].startPosition / HeightCache.TotalHeight; + + // Slide to the normalized position + OnSliderValueChanged(normalized); + } + + // IEnumerable + + public IEnumerator GetEnumerator() => EnumerateCellPool(); + + IEnumerator IEnumerable.GetEnumerator() => EnumerateCellPool(); + + // Initialize /// Should be called only once, when the scroll pool is created. public void Initialize(ICellPoolDataSource dataSource, Action onHeightChangedListener = null) @@ -178,9 +191,8 @@ namespace UnityExplorer.UI.Widgets // create initial cell pool and set cells CreateCellPool(); - var enumerator = GetPoolEnumerator(); - while (enumerator.MoveNext()) - SetCell(CellPool[enumerator.Current.cellIndex], enumerator.Current.dataIndex); + foreach (var cell in this) + SetCell(CellPool[cell.cellIndex], cell.dataIndex); LayoutRebuilder.ForceRebuildLayoutImmediate(Content); prevContentHeight = Content.rect.height; @@ -217,18 +229,18 @@ namespace UnityExplorer.UI.Widgets // Cell pool - private CellInfo _cellInfo = new CellInfo(); + private CellInfo _current; - public IEnumerator GetPoolEnumerator() + private IEnumerator EnumerateCellPool() { int cellIdx = topPoolIndex; int dataIndex = TopDataIndex; int iterated = 0; while (iterated < CellPool.Count) { - _cellInfo.cellIndex = cellIdx; - _cellInfo.dataIndex = dataIndex; - yield return _cellInfo; + _current.cellIndex = cellIdx; + _current.dataIndex = dataIndex; + yield return _current; cellIdx++; if (cellIdx >= CellPool.Count) @@ -368,16 +380,13 @@ namespace UnityExplorer.UI.Widgets CheckDataSourceCountChange(out bool jumpToBottom); // update date height cache, and set cells if 'andReload' - var enumerator = GetPoolEnumerator(); - while (enumerator.MoveNext()) + foreach (var cellInfo in this) { - var curr = enumerator.Current; - var cell = CellPool[curr.cellIndex]; - + var cell = CellPool[cellInfo.cellIndex]; if (andReloadFromDataSource) - SetCell(cell, curr.dataIndex); + SetCell(cell, cellInfo.dataIndex); else - HeightCache.SetIndex(curr.dataIndex, cell.Rect.rect.height); + HeightCache.SetIndex(cellInfo.dataIndex, cell.Rect.rect.height); } // force check recycles @@ -405,12 +414,8 @@ namespace UnityExplorer.UI.Widgets private void RefreshCellHeightsFast() { - var enumerator = GetPoolEnumerator(); - while (enumerator.MoveNext()) - { - var curr = enumerator.Current; - HeightCache.SetIndex(curr.dataIndex, CellPool[curr.cellIndex].Rect.rect.height); - } + foreach (var cellInfo in this) + HeightCache.SetIndex(cellInfo.dataIndex, CellPool[cellInfo.cellIndex].Rect.rect.height); } private void SetCell(T cachedCell, int dataIndex) @@ -619,12 +624,10 @@ namespace UnityExplorer.UI.Widgets else { bottomDataIndex = desiredBottomIndex; - var enumerator = GetPoolEnumerator(); - while (enumerator.MoveNext()) + foreach (var info in this) { - var curr = enumerator.Current; - var cell = CellPool[curr.cellIndex]; - SetCell(cell, curr.dataIndex); + var cell = CellPool[info.cellIndex]; + SetCell(cell, info.dataIndex); } } diff --git a/src/UI/Widgets/TransformTree/TransformTree.cs b/src/UI/Widgets/TransformTree/TransformTree.cs index e4f0ddd..7e0c16e 100644 --- a/src/UI/Widgets/TransformTree/TransformTree.cs +++ b/src/UI/Widgets/TransformTree/TransformTree.cs @@ -6,8 +6,6 @@ using System.Linq; using System.Text; using UnityEngine; using UnityEngine.UI; -using UnityExplorer.UI.ObjectPool; -using UnityExplorer.UI.Widgets; namespace UnityExplorer.UI.Widgets { @@ -22,13 +20,19 @@ namespace UnityExplorer.UI.Widgets /// Key: UnityEngine.Transform instance ID
/// Value: CachedTransform /// - internal readonly OrderedDictionary displayedObjects = new OrderedDictionary(); + internal readonly OrderedDictionary cachedTransforms = new OrderedDictionary(); // for keeping track of which actual transforms are expanded or not, outside of the cache data. private readonly HashSet expandedInstanceIDs = new HashSet(); private readonly HashSet autoExpandedIDs = new HashSet(); - public int ItemCount => displayedObjects.Count; + private readonly HashSet visited = new HashSet(); + private bool needRefresh; + private int displayIndex; + + public int ItemCount => cachedTransforms.Count; + + private readonly HashSet highlightedTransforms = new HashSet(); public bool Filtering => !string.IsNullOrEmpty(currentFilter); private bool wasFiltering; @@ -50,6 +54,25 @@ namespace UnityExplorer.UI.Widgets } private string currentFilter; + public TransformTree(ScrollPool scrollPool, Func> getRootEntriesMethod) + { + ScrollPool = scrollPool; + GetRootEntriesMethod = getRootEntriesMethod; + } + + public void OnCellBorrowed(TransformCell cell) + { + cell.OnExpandToggled += ToggleExpandCell; + cell.OnGameObjectClicked += OnGameObjectClicked; + } + + private void OnGameObjectClicked(GameObject obj) + { + if (OnClickOverrideHandler != null) + OnClickOverrideHandler.Invoke(obj); + else + InspectorManager.Inspect(obj); + } public void Init() { @@ -58,37 +81,79 @@ namespace UnityExplorer.UI.Widgets public void Clear() { - this.displayedObjects.Clear(); + this.cachedTransforms.Clear(); displayIndex = 0; autoExpandedIDs.Clear(); expandedInstanceIDs.Clear(); } - - public void OnGameObjectClicked(GameObject obj) - { - if (OnClickOverrideHandler != null) - { - OnClickOverrideHandler.Invoke(obj); - } - else - { - InspectorManager.Inspect(obj); - } - } - - public TransformTree(ScrollPool scrollPool, Func> getRootEntriesMethod) - { - ScrollPool = scrollPool; - GetRootEntriesMethod = getRootEntriesMethod; - } - public bool IsCellExpanded(int instanceID) { return Filtering ? autoExpandedIDs.Contains(instanceID) : expandedInstanceIDs.Contains(instanceID); } + public void JumpAndExpandToTransform(Transform transform) + { + // make sure all parents of the object are expanded + var parent = transform.parent; + while (parent) + { + int pid = parent.GetInstanceID(); + if (!expandedInstanceIDs.Contains(pid)) + expandedInstanceIDs.Add(pid); + + parent = parent.parent; + } + + // Refresh cached transforms (no UI rebuild yet) + RefreshData(false); + + int transformID = transform.GetInstanceID(); + + // find the index of our transform in the list and jump to it + int idx; + for (idx = 0; idx < cachedTransforms.Count; idx++) + { + var cache = (CachedTransform)cachedTransforms[idx]; + if (cache.InstanceID == transformID) + break; + } + ScrollPool.JumpToIndex(idx); + + // 'select' (highlight) the cell containing our transform + foreach (var cellInfo in ScrollPool) + { + var cell = ScrollPool.CellPool[cellInfo.cellIndex]; + + if (!cell.Enabled) + continue; + + if (cell.cachedTransform.InstanceID == transformID) + { + RuntimeProvider.Instance.StartCoroutine(HighlightCellCoroutine(cell, transformID)); + break; + } + } + } + + private IEnumerator HighlightCellCoroutine(TransformCell cell, int transformID) + { + if (highlightedTransforms.Contains(transformID)) + yield break; + highlightedTransforms.Add(transformID); + + var button = cell.NameButton.Component; + button.StartColorTween(new Color(0.2f, 0.3f, 0.2f), false); + + float start = Time.realtimeSinceStartup; + while (Time.realtimeSinceStartup - start < 1.5f) + yield return null; + + button.OnDeselect(null); + highlightedTransforms.Remove(transformID); + } + public void Rebuild() { autoExpandedIDs.Clear(); @@ -97,10 +162,6 @@ namespace UnityExplorer.UI.Widgets RefreshData(true, true); } - private readonly HashSet visited = new HashSet(); - private bool needRefresh; - private int displayIndex; - public void RefreshData(bool andReload = false, bool jumpToTop = false) { visited.Clear(); @@ -114,12 +175,12 @@ namespace UnityExplorer.UI.Widgets if (obj) Traverse(obj.transform); // Prune displayed transforms that we didnt visit in that traverse - for (int i = displayedObjects.Count - 1; i >= 0; i--) + for (int i = cachedTransforms.Count - 1; i >= 0; i--) { - var obj = (CachedTransform)displayedObjects[i]; + var obj = (CachedTransform)cachedTransforms[i]; if (!visited.Contains(obj.InstanceID)) { - displayedObjects.Remove(obj.InstanceID); + cachedTransforms.Remove(obj.InstanceID); needRefresh = true; } } @@ -159,9 +220,9 @@ namespace UnityExplorer.UI.Widgets visited.Add(instanceID); CachedTransform cached; - if (displayedObjects.Contains(instanceID)) + if (cachedTransforms.Contains(instanceID)) { - cached = (CachedTransform)displayedObjects[(object)instanceID]; + cached = (CachedTransform)cachedTransforms[(object)instanceID]; if (cached.Update(transform, depth)) needRefresh = true; } @@ -169,10 +230,10 @@ namespace UnityExplorer.UI.Widgets { needRefresh = true; cached = new CachedTransform(this, transform, depth, parent); - if (displayedObjects.Count <= displayIndex) - displayedObjects.Add(instanceID, cached); + if (cachedTransforms.Count <= displayIndex) + cachedTransforms.Add(instanceID, cached); else - displayedObjects.Insert(displayIndex, instanceID, cached); + cachedTransforms.Insert(displayIndex, instanceID, cached); } displayIndex++; @@ -201,9 +262,9 @@ namespace UnityExplorer.UI.Widgets public void SetCell(TransformCell cell, int index) { - if (index < displayedObjects.Count) + if (index < cachedTransforms.Count) { - cell.ConfigureCell((CachedTransform)displayedObjects[index], index); + cell.ConfigureCell((CachedTransform)cachedTransforms[index], index); if (Filtering) { if (cell.cachedTransform.Name.ContainsIgnoreCase(currentFilter)) @@ -226,16 +287,5 @@ namespace UnityExplorer.UI.Widgets RefreshData(true); } - - public void OnCellBorrowed(TransformCell cell) - { - cell.OnExpandToggled += ToggleExpandCell; - cell.OnGameObjectClicked += OnGameObjectClicked; - } - - //public void ReleaseCell(TransformCell cell) - //{ - // cell.OnExpandToggled -= ToggleExpandCell; - //} } }