2021-04-15 20:18:03 +10:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
2021-05-05 21:27:09 +10:00
|
|
|
|
using System.Collections.Specialized;
|
2021-04-15 20:18:03 +10:00
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.UI;
|
2021-04-26 19:56:21 +10:00
|
|
|
|
using UnityExplorer.UI.ObjectPool;
|
2021-04-16 21:07:32 +10:00
|
|
|
|
using UnityExplorer.UI.Widgets;
|
2021-04-15 20:18:03 +10:00
|
|
|
|
|
|
|
|
|
namespace UnityExplorer.UI.Widgets
|
|
|
|
|
{
|
2021-05-13 23:03:30 +10:00
|
|
|
|
public class TransformTree : ICellPoolDataSource<TransformCell>
|
2021-04-15 20:18:03 +10:00
|
|
|
|
{
|
|
|
|
|
public Func<IEnumerable<GameObject>> GetRootEntriesMethod;
|
2021-05-16 21:46:19 +10:00
|
|
|
|
public Action<GameObject> OnClickOverrideHandler;
|
2021-04-15 20:18:03 +10:00
|
|
|
|
|
2021-05-16 21:46:19 +10:00
|
|
|
|
public ScrollPool<TransformCell> ScrollPool;
|
2021-05-05 21:27:09 +10:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Key: UnityEngine.Transform instance ID<br/>
|
|
|
|
|
/// Value: CachedTransform
|
|
|
|
|
/// </summary>
|
2021-05-16 21:46:19 +10:00
|
|
|
|
internal readonly OrderedDictionary displayedObjects = new OrderedDictionary();
|
2021-05-05 21:27:09 +10:00
|
|
|
|
|
|
|
|
|
// 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> autoExpandedIDs = new HashSet<int>();
|
|
|
|
|
|
|
|
|
|
public int ItemCount => displayedObjects.Count;
|
|
|
|
|
|
2021-04-16 02:52:54 +10:00
|
|
|
|
public bool Filtering => !string.IsNullOrEmpty(currentFilter);
|
|
|
|
|
private bool wasFiltering;
|
|
|
|
|
|
2021-04-15 20:18:03 +10:00
|
|
|
|
public string CurrentFilter
|
|
|
|
|
{
|
|
|
|
|
get => currentFilter;
|
2021-04-16 02:52:54 +10:00
|
|
|
|
set
|
|
|
|
|
{
|
2021-04-30 23:43:27 +10:00
|
|
|
|
currentFilter = value ?? "";
|
2021-04-16 02:52:54 +10:00
|
|
|
|
if (!wasFiltering && Filtering)
|
|
|
|
|
wasFiltering = true;
|
|
|
|
|
else if (wasFiltering && !Filtering)
|
|
|
|
|
{
|
|
|
|
|
wasFiltering = false;
|
|
|
|
|
autoExpandedIDs.Clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-15 20:18:03 +10:00
|
|
|
|
}
|
|
|
|
|
private string currentFilter;
|
|
|
|
|
|
2021-05-17 21:48:39 +10:00
|
|
|
|
|
|
|
|
|
public void Init()
|
|
|
|
|
{
|
|
|
|
|
ScrollPool.Initialize(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Clear()
|
|
|
|
|
{
|
|
|
|
|
this.displayedObjects.Clear();
|
|
|
|
|
displayIndex = 0;
|
|
|
|
|
autoExpandedIDs.Clear();
|
|
|
|
|
expandedInstanceIDs.Clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2021-05-16 21:46:19 +10:00
|
|
|
|
public void OnGameObjectClicked(GameObject obj)
|
|
|
|
|
{
|
|
|
|
|
if (OnClickOverrideHandler != null)
|
|
|
|
|
{
|
|
|
|
|
OnClickOverrideHandler.Invoke(obj);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
InspectorManager.Inspect(obj);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public TransformTree(ScrollPool<TransformCell> scrollPool, Func<IEnumerable<GameObject>> getRootEntriesMethod)
|
2021-04-16 02:52:54 +10:00
|
|
|
|
{
|
2021-04-26 19:56:21 +10:00
|
|
|
|
ScrollPool = scrollPool;
|
2021-05-16 21:46:19 +10:00
|
|
|
|
GetRootEntriesMethod = getRootEntriesMethod;
|
2021-04-16 02:52:54 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsCellExpanded(int instanceID)
|
|
|
|
|
{
|
|
|
|
|
return Filtering ? autoExpandedIDs.Contains(instanceID)
|
|
|
|
|
: expandedInstanceIDs.Contains(instanceID);
|
2021-04-15 20:18:03 +10:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-26 19:56:21 +10:00
|
|
|
|
public void Rebuild()
|
|
|
|
|
{
|
|
|
|
|
autoExpandedIDs.Clear();
|
|
|
|
|
expandedInstanceIDs.Clear();
|
|
|
|
|
|
|
|
|
|
RefreshData(true, true);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-05 21:27:09 +10:00
|
|
|
|
private readonly HashSet<int> visited = new HashSet<int>();
|
|
|
|
|
private bool needRefresh;
|
|
|
|
|
private int displayIndex;
|
|
|
|
|
|
2021-04-30 23:12:18 +10:00
|
|
|
|
public void RefreshData(bool andReload = false, bool jumpToTop = false)
|
2021-04-15 20:18:03 +10:00
|
|
|
|
{
|
2021-05-05 21:27:09 +10:00
|
|
|
|
visited.Clear();
|
|
|
|
|
displayIndex = 0;
|
|
|
|
|
needRefresh = false;
|
2021-04-15 20:18:03 +10:00
|
|
|
|
|
2021-04-16 02:52:54 +10:00
|
|
|
|
var rootObjects = GetRootEntriesMethod.Invoke();
|
2021-04-15 20:18:03 +10:00
|
|
|
|
|
2021-05-05 21:27:09 +10:00
|
|
|
|
//int displayIndex = 0;
|
2021-04-16 02:52:54 +10:00
|
|
|
|
foreach (var obj in rootObjects)
|
2021-05-05 21:27:09 +10:00
|
|
|
|
if (obj) Traverse(obj.transform);
|
|
|
|
|
|
|
|
|
|
// Prune displayed transforms that we didnt visit in that traverse
|
|
|
|
|
for (int i = displayedObjects.Count - 1; i >= 0; i--)
|
2021-04-16 17:49:05 +10:00
|
|
|
|
{
|
2021-05-05 21:27:09 +10:00
|
|
|
|
var obj = (CachedTransform)displayedObjects[i];
|
|
|
|
|
if (!visited.Contains(obj.InstanceID))
|
|
|
|
|
{
|
|
|
|
|
displayedObjects.Remove(obj.InstanceID);
|
|
|
|
|
needRefresh = true;
|
|
|
|
|
}
|
2021-04-16 17:49:05 +10:00
|
|
|
|
}
|
2021-04-15 20:18:03 +10:00
|
|
|
|
|
2021-05-05 21:27:09 +10:00
|
|
|
|
if (!needRefresh)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
//displayedObjects.Clear();
|
|
|
|
|
|
2021-04-15 20:18:03 +10:00
|
|
|
|
if (andReload)
|
2021-04-22 17:53:29 +10:00
|
|
|
|
{
|
2021-04-30 23:12:18 +10:00
|
|
|
|
if (!jumpToTop)
|
|
|
|
|
ScrollPool.Refresh(true);
|
2021-04-22 17:53:29 +10:00
|
|
|
|
else
|
2021-04-30 23:12:18 +10:00
|
|
|
|
ScrollPool.Refresh(true, true);
|
2021-04-22 17:53:29 +10:00
|
|
|
|
}
|
2021-04-15 20:18:03 +10:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-26 19:56:21 +10:00
|
|
|
|
private void Traverse(Transform transform, CachedTransform parent = null, int depth = 0)
|
2021-04-15 20:18:03 +10:00
|
|
|
|
{
|
2021-04-16 02:52:54 +10:00
|
|
|
|
int instanceID = transform.GetInstanceID();
|
|
|
|
|
|
2021-05-05 21:27:09 +10:00
|
|
|
|
if (visited.Contains(instanceID))
|
|
|
|
|
return;
|
|
|
|
|
|
2021-04-16 02:52:54 +10:00
|
|
|
|
if (Filtering)
|
|
|
|
|
{
|
2021-05-05 21:27:09 +10:00
|
|
|
|
if (!FilterHierarchy(transform))
|
2021-04-16 02:52:54 +10:00
|
|
|
|
return;
|
2021-05-05 21:27:09 +10:00
|
|
|
|
|
2021-05-16 21:46:19 +10:00
|
|
|
|
visited.Add(instanceID);
|
|
|
|
|
|
2021-05-05 21:27:09 +10:00
|
|
|
|
if (!autoExpandedIDs.Contains(instanceID))
|
|
|
|
|
autoExpandedIDs.Add(instanceID);
|
2021-04-16 02:52:54 +10:00
|
|
|
|
}
|
2021-05-16 21:46:19 +10:00
|
|
|
|
else
|
|
|
|
|
visited.Add(instanceID);
|
2021-04-16 02:52:54 +10:00
|
|
|
|
|
2021-04-15 20:18:03 +10:00
|
|
|
|
CachedTransform cached;
|
2021-05-05 21:27:09 +10:00
|
|
|
|
if (displayedObjects.Contains(instanceID))
|
2021-04-15 20:18:03 +10:00
|
|
|
|
{
|
2021-05-05 21:27:09 +10:00
|
|
|
|
cached = (CachedTransform)displayedObjects[(object)instanceID];
|
2021-05-08 06:18:28 +10:00
|
|
|
|
if (cached.Update(transform, depth))
|
|
|
|
|
needRefresh = true;
|
2021-04-15 20:18:03 +10:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-05-05 21:27:09 +10:00
|
|
|
|
needRefresh = true;
|
2021-04-26 19:56:21 +10:00
|
|
|
|
cached = new CachedTransform(this, transform, depth, parent);
|
2021-05-05 21:27:09 +10:00
|
|
|
|
if (displayedObjects.Count <= displayIndex)
|
|
|
|
|
displayedObjects.Add(instanceID, cached);
|
|
|
|
|
else
|
|
|
|
|
displayedObjects.Insert(displayIndex, instanceID, cached);
|
2021-04-15 20:18:03 +10:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-05 21:27:09 +10:00
|
|
|
|
displayIndex++;
|
2021-04-15 20:18:03 +10:00
|
|
|
|
|
2021-04-16 02:52:54 +10:00
|
|
|
|
if (IsCellExpanded(instanceID) && cached.Value.childCount > 0)
|
2021-04-15 20:18:03 +10:00
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < transform.childCount; i++)
|
2021-04-26 19:56:21 +10:00
|
|
|
|
Traverse(transform.GetChild(i), cached, depth + 1);
|
2021-04-15 20:18:03 +10:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool FilterHierarchy(Transform obj)
|
|
|
|
|
{
|
2021-04-30 23:43:27 +10:00
|
|
|
|
if (obj.name.ContainsIgnoreCase(currentFilter))
|
2021-04-15 20:18:03 +10:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (obj.childCount <= 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < obj.childCount; i++)
|
|
|
|
|
if (FilterHierarchy(obj.GetChild(i)))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-30 23:43:27 +10:00
|
|
|
|
public void SetCell(TransformCell cell, int index)
|
2021-04-15 20:18:03 +10:00
|
|
|
|
{
|
2021-04-16 02:52:54 +10:00
|
|
|
|
if (index < displayedObjects.Count)
|
2021-05-16 21:46:19 +10:00
|
|
|
|
{
|
2021-05-05 21:27:09 +10:00
|
|
|
|
cell.ConfigureCell((CachedTransform)displayedObjects[index], index);
|
2021-05-16 21:46:19 +10:00
|
|
|
|
if (Filtering)
|
|
|
|
|
{
|
|
|
|
|
if (cell.cachedTransform.Name.ContainsIgnoreCase(currentFilter))
|
|
|
|
|
{
|
|
|
|
|
cell.NameButton.ButtonText.color = Color.green;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-15 20:18:03 +10:00
|
|
|
|
else
|
|
|
|
|
cell.Disable();
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-26 19:56:21 +10:00
|
|
|
|
public void ToggleExpandCell(CachedTransform cache)
|
2021-04-15 20:18:03 +10:00
|
|
|
|
{
|
2021-04-26 19:56:21 +10:00
|
|
|
|
var instanceID = cache.InstanceID;
|
2021-04-16 02:52:54 +10:00
|
|
|
|
if (expandedInstanceIDs.Contains(instanceID))
|
|
|
|
|
expandedInstanceIDs.Remove(instanceID);
|
|
|
|
|
else
|
|
|
|
|
expandedInstanceIDs.Add(instanceID);
|
2021-04-15 20:18:03 +10:00
|
|
|
|
|
2021-04-16 02:52:54 +10:00
|
|
|
|
RefreshData(true);
|
2021-04-15 20:18:03 +10:00
|
|
|
|
}
|
2021-04-26 19:56:21 +10:00
|
|
|
|
|
|
|
|
|
public void OnCellBorrowed(TransformCell cell)
|
|
|
|
|
{
|
|
|
|
|
cell.OnExpandToggled += ToggleExpandCell;
|
2021-05-16 21:46:19 +10:00
|
|
|
|
cell.OnGameObjectClicked += OnGameObjectClicked;
|
2021-04-26 19:56:21 +10:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-16 21:46:19 +10:00
|
|
|
|
//public void ReleaseCell(TransformCell cell)
|
|
|
|
|
//{
|
|
|
|
|
// cell.OnExpandToggled -= ToggleExpandCell;
|
|
|
|
|
//}
|
2021-04-15 20:18:03 +10:00
|
|
|
|
}
|
|
|
|
|
}
|