Implement jumping to index in TransformTree

This commit is contained in:
Sinai 2021-05-26 17:42:31 +10:00
parent 9e7bb1a625
commit 041f2938f7
4 changed files with 166 additions and 81 deletions

View File

@ -232,6 +232,15 @@ namespace UnityExplorer.UI.Inspectors
} }
} }
private void OnExploreButtonClicked()
{
var panel = UIManager.GetPanel<Panels.ObjectExplorerPanel>(UIManager.Panels.ObjectExplorer);
UIManager.SetPanelActive(panel, true);
panel.SetTab(0);
panel.SceneExplorer.JumpToTransform(this.Parent.GOTarget.transform);
}
private void OnLayerDropdownChanged(int value) private void OnLayerDropdownChanged(int value)
{ {
GOTarget.layer = value; GOTarget.layer = value;
@ -533,6 +542,12 @@ namespace UnityExplorer.UI.Inspectors
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(thirdrow, false, false, true, true, 5, 0, 0, 0, 0, default); UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(thirdrow, false, false, true, true, 5, 0, 0, 0, 0, default);
UIFactory.SetLayoutElement(thirdrow, minHeight: 25, flexibleWidth: 9999); 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 // Scene
var sceneLabel = UIFactory.CreateLabel(thirdrow, "SceneLabel", "Scene:", TextAnchor.MiddleLeft, Color.grey); var sceneLabel = UIFactory.CreateLabel(thirdrow, "SceneLabel", "Scene:", TextAnchor.MiddleLeft, Color.grey);
UIFactory.SetLayoutElement(sceneLabel.gameObject, minHeight: 25, minWidth: 50); UIFactory.SetLayoutElement(sceneLabel.gameObject, minHeight: 25, minWidth: 50);
@ -547,7 +562,7 @@ namespace UnityExplorer.UI.Inspectors
UIFactory.SetLayoutElement(layerLabel.gameObject, minHeight: 25, minWidth: 50); UIFactory.SetLayoutElement(layerLabel.gameObject, minHeight: 25, minWidth: 50);
var layerDrop = UIFactory.CreateDropdown(thirdrow, out LayerDropdown, "0", 14, OnLayerDropdownChanged); 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; LayerDropdown.captionText.color = SignatureHighlighter.EnumGreen;
if (layerToNames == null) if (layerToNames == null)
GetLayerNames(); GetLayerNames();

View File

@ -58,6 +58,23 @@ namespace UnityExplorer.UI.ObjectExplorer
Tree.RefreshData(true); 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) private void OnDropdownChanged(int value)
{ {
if (value < 0 || SceneHandler.LoadedScenes.Count <= 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)) if ((!string.IsNullOrEmpty(input) && !Tree.Filtering) || (string.IsNullOrEmpty(input) && Tree.Filtering))
{ {
Tree.displayedObjects.Clear(); Tree.cachedTransforms.Clear();
} }
Tree.CurrentFilter = input; Tree.CurrentFilter = input;

View File

@ -7,7 +7,6 @@ using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.Core.Input; using UnityExplorer.Core.Input;
using UnityExplorer.UI.Models; using UnityExplorer.UI.Models;
using UnityExplorer.UI.ObjectPool;
using UnityExplorer.UI.Panels; using UnityExplorer.UI.Panels;
namespace UnityExplorer.UI.Widgets namespace UnityExplorer.UI.Widgets
@ -20,7 +19,7 @@ namespace UnityExplorer.UI.Widgets
/// <summary> /// <summary>
/// An object-pooled ScrollRect, attempts to support content of any size and provide a scrollbar for it. /// An object-pooled ScrollRect, attempts to support content of any size and provide a scrollbar for it.
/// </summary> /// </summary>
public class ScrollPool<T> : UIBehaviourModel where T : ICell public class ScrollPool<T> : UIBehaviourModel, IEnumerable<CellInfo> where T : ICell
{ {
public ScrollPool(ScrollRect scrollRect) public ScrollPool(ScrollRect scrollRect)
{ {
@ -138,9 +137,23 @@ namespace UnityExplorer.UI.Widgets
RefreshCells(setCellData, true); 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<CellInfo> GetEnumerator() => EnumerateCellPool();
IEnumerator IEnumerable.GetEnumerator() => EnumerateCellPool();
// Initialize
/// <summary>Should be called only once, when the scroll pool is created.</summary> /// <summary>Should be called only once, when the scroll pool is created.</summary>
public void Initialize(ICellPoolDataSource<T> dataSource, Action onHeightChangedListener = null) public void Initialize(ICellPoolDataSource<T> dataSource, Action onHeightChangedListener = null)
@ -178,9 +191,8 @@ namespace UnityExplorer.UI.Widgets
// create initial cell pool and set cells // create initial cell pool and set cells
CreateCellPool(); CreateCellPool();
var enumerator = GetPoolEnumerator(); foreach (var cell in this)
while (enumerator.MoveNext()) SetCell(CellPool[cell.cellIndex], cell.dataIndex);
SetCell(CellPool[enumerator.Current.cellIndex], enumerator.Current.dataIndex);
LayoutRebuilder.ForceRebuildLayoutImmediate(Content); LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
prevContentHeight = Content.rect.height; prevContentHeight = Content.rect.height;
@ -217,18 +229,18 @@ namespace UnityExplorer.UI.Widgets
// Cell pool // Cell pool
private CellInfo _cellInfo = new CellInfo(); private CellInfo _current;
public IEnumerator<CellInfo> GetPoolEnumerator() private IEnumerator<CellInfo> EnumerateCellPool()
{ {
int cellIdx = topPoolIndex; int cellIdx = topPoolIndex;
int dataIndex = TopDataIndex; int dataIndex = TopDataIndex;
int iterated = 0; int iterated = 0;
while (iterated < CellPool.Count) while (iterated < CellPool.Count)
{ {
_cellInfo.cellIndex = cellIdx; _current.cellIndex = cellIdx;
_cellInfo.dataIndex = dataIndex; _current.dataIndex = dataIndex;
yield return _cellInfo; yield return _current;
cellIdx++; cellIdx++;
if (cellIdx >= CellPool.Count) if (cellIdx >= CellPool.Count)
@ -368,16 +380,13 @@ namespace UnityExplorer.UI.Widgets
CheckDataSourceCountChange(out bool jumpToBottom); CheckDataSourceCountChange(out bool jumpToBottom);
// update date height cache, and set cells if 'andReload' // update date height cache, and set cells if 'andReload'
var enumerator = GetPoolEnumerator(); foreach (var cellInfo in this)
while (enumerator.MoveNext())
{ {
var curr = enumerator.Current; var cell = CellPool[cellInfo.cellIndex];
var cell = CellPool[curr.cellIndex];
if (andReloadFromDataSource) if (andReloadFromDataSource)
SetCell(cell, curr.dataIndex); SetCell(cell, cellInfo.dataIndex);
else else
HeightCache.SetIndex(curr.dataIndex, cell.Rect.rect.height); HeightCache.SetIndex(cellInfo.dataIndex, cell.Rect.rect.height);
} }
// force check recycles // force check recycles
@ -405,12 +414,8 @@ namespace UnityExplorer.UI.Widgets
private void RefreshCellHeightsFast() private void RefreshCellHeightsFast()
{ {
var enumerator = GetPoolEnumerator(); foreach (var cellInfo in this)
while (enumerator.MoveNext()) HeightCache.SetIndex(cellInfo.dataIndex, CellPool[cellInfo.cellIndex].Rect.rect.height);
{
var curr = enumerator.Current;
HeightCache.SetIndex(curr.dataIndex, CellPool[curr.cellIndex].Rect.rect.height);
}
} }
private void SetCell(T cachedCell, int dataIndex) private void SetCell(T cachedCell, int dataIndex)
@ -619,12 +624,10 @@ namespace UnityExplorer.UI.Widgets
else else
{ {
bottomDataIndex = desiredBottomIndex; bottomDataIndex = desiredBottomIndex;
var enumerator = GetPoolEnumerator(); foreach (var info in this)
while (enumerator.MoveNext())
{ {
var curr = enumerator.Current; var cell = CellPool[info.cellIndex];
var cell = CellPool[curr.cellIndex]; SetCell(cell, info.dataIndex);
SetCell(cell, curr.dataIndex);
} }
} }

View File

@ -6,8 +6,6 @@ using System.Linq;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityExplorer.UI.ObjectPool;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Widgets namespace UnityExplorer.UI.Widgets
{ {
@ -22,13 +20,19 @@ namespace UnityExplorer.UI.Widgets
/// Key: UnityEngine.Transform instance ID<br/> /// Key: UnityEngine.Transform instance ID<br/>
/// Value: CachedTransform /// Value: CachedTransform
/// </summary> /// </summary>
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. // for keeping track of which actual transforms are expanded or not, outside of the cache data.
private readonly HashSet<int> expandedInstanceIDs = new HashSet<int>(); private readonly HashSet<int> expandedInstanceIDs = new HashSet<int>();
private readonly HashSet<int> autoExpandedIDs = new HashSet<int>(); private readonly HashSet<int> autoExpandedIDs = new HashSet<int>();
public int ItemCount => displayedObjects.Count; private readonly HashSet<int> visited = new HashSet<int>();
private bool needRefresh;
private int displayIndex;
public int ItemCount => cachedTransforms.Count;
private readonly HashSet<int> highlightedTransforms = new HashSet<int>();
public bool Filtering => !string.IsNullOrEmpty(currentFilter); public bool Filtering => !string.IsNullOrEmpty(currentFilter);
private bool wasFiltering; private bool wasFiltering;
@ -50,6 +54,25 @@ namespace UnityExplorer.UI.Widgets
} }
private string currentFilter; private string currentFilter;
public TransformTree(ScrollPool<TransformCell> scrollPool, Func<IEnumerable<GameObject>> 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() public void Init()
{ {
@ -58,37 +81,79 @@ namespace UnityExplorer.UI.Widgets
public void Clear() public void Clear()
{ {
this.displayedObjects.Clear(); this.cachedTransforms.Clear();
displayIndex = 0; displayIndex = 0;
autoExpandedIDs.Clear(); autoExpandedIDs.Clear();
expandedInstanceIDs.Clear(); expandedInstanceIDs.Clear();
} }
public void OnGameObjectClicked(GameObject obj)
{
if (OnClickOverrideHandler != null)
{
OnClickOverrideHandler.Invoke(obj);
}
else
{
InspectorManager.Inspect(obj);
}
}
public TransformTree(ScrollPool<TransformCell> scrollPool, Func<IEnumerable<GameObject>> getRootEntriesMethod)
{
ScrollPool = scrollPool;
GetRootEntriesMethod = getRootEntriesMethod;
}
public bool IsCellExpanded(int instanceID) public bool IsCellExpanded(int instanceID)
{ {
return Filtering ? autoExpandedIDs.Contains(instanceID) return Filtering ? autoExpandedIDs.Contains(instanceID)
: expandedInstanceIDs.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() public void Rebuild()
{ {
autoExpandedIDs.Clear(); autoExpandedIDs.Clear();
@ -97,10 +162,6 @@ namespace UnityExplorer.UI.Widgets
RefreshData(true, true); RefreshData(true, true);
} }
private readonly HashSet<int> visited = new HashSet<int>();
private bool needRefresh;
private int displayIndex;
public void RefreshData(bool andReload = false, bool jumpToTop = false) public void RefreshData(bool andReload = false, bool jumpToTop = false)
{ {
visited.Clear(); visited.Clear();
@ -114,12 +175,12 @@ namespace UnityExplorer.UI.Widgets
if (obj) Traverse(obj.transform); if (obj) Traverse(obj.transform);
// Prune displayed transforms that we didnt visit in that traverse // 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)) if (!visited.Contains(obj.InstanceID))
{ {
displayedObjects.Remove(obj.InstanceID); cachedTransforms.Remove(obj.InstanceID);
needRefresh = true; needRefresh = true;
} }
} }
@ -159,9 +220,9 @@ namespace UnityExplorer.UI.Widgets
visited.Add(instanceID); visited.Add(instanceID);
CachedTransform cached; 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)) if (cached.Update(transform, depth))
needRefresh = true; needRefresh = true;
} }
@ -169,10 +230,10 @@ namespace UnityExplorer.UI.Widgets
{ {
needRefresh = true; needRefresh = true;
cached = new CachedTransform(this, transform, depth, parent); cached = new CachedTransform(this, transform, depth, parent);
if (displayedObjects.Count <= displayIndex) if (cachedTransforms.Count <= displayIndex)
displayedObjects.Add(instanceID, cached); cachedTransforms.Add(instanceID, cached);
else else
displayedObjects.Insert(displayIndex, instanceID, cached); cachedTransforms.Insert(displayIndex, instanceID, cached);
} }
displayIndex++; displayIndex++;
@ -201,9 +262,9 @@ namespace UnityExplorer.UI.Widgets
public void SetCell(TransformCell cell, int index) 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 (Filtering)
{ {
if (cell.cachedTransform.Name.ContainsIgnoreCase(currentFilter)) if (cell.cachedTransform.Name.ContainsIgnoreCase(currentFilter))
@ -226,16 +287,5 @@ namespace UnityExplorer.UI.Widgets
RefreshData(true); RefreshData(true);
} }
public void OnCellBorrowed(TransformCell cell)
{
cell.OnExpandToggled += ToggleExpandCell;
cell.OnGameObjectClicked += OnGameObjectClicked;
}
//public void ReleaseCell(TransformCell cell)
//{
// cell.OnExpandToggled -= ToggleExpandCell;
//}
} }
} }