289 lines
8.8 KiB
C#
Raw Normal View History

using System;
using System.Collections;
using System.Collections.Generic;
2021-05-05 21:27:09 +10:00
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
2021-12-02 18:35:46 +11:00
using UniverseLib;
using UniverseLib.UI.Widgets;
2022-01-31 21:24:01 +11:00
using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility;
namespace UnityExplorer.UI.Widgets
{
2021-05-13 23:03:30 +10:00
public class TransformTree : ICellPoolDataSource<TransformCell>
{
public Func<IEnumerable<GameObject>> GetRootEntriesMethod;
public Action<GameObject> OnClickOverrideHandler;
public ScrollPool<TransformCell> ScrollPool;
2021-05-05 21:27:09 +10:00
/// <summary>
/// Key: UnityEngine.Transform instance ID<br/>
/// Value: CachedTransform
/// </summary>
internal readonly OrderedDictionary cachedTransforms = 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>();
private readonly HashSet<int> visited = new HashSet<int>();
private bool needRefresh;
private int displayIndex;
public int ItemCount => cachedTransforms.Count;
public bool Filtering => !string.IsNullOrEmpty(currentFilter);
private bool wasFiltering;
public string CurrentFilter
{
get => currentFilter;
set
{
currentFilter = value ?? "";
if (!wasFiltering && Filtering)
wasFiltering = true;
else if (wasFiltering && !Filtering)
{
wasFiltering = false;
autoExpandedIDs.Clear();
}
}
}
private string currentFilter;
public TransformTree(ScrollPool<TransformCell> scrollPool, Func<IEnumerable<GameObject>> getRootEntriesMethod)
{
ScrollPool = scrollPool;
GetRootEntriesMethod = getRootEntriesMethod;
}
public void OnCellBorrowed(TransformCell cell)
{
cell.OnExpandToggled += OnCellExpandToggled;
cell.OnGameObjectClicked += OnGameObjectClicked;
cell.OnEnableToggled += OnCellEnableToggled;
}
private void OnGameObjectClicked(GameObject obj)
{
if (OnClickOverrideHandler != null)
OnClickOverrideHandler.Invoke(obj);
else
InspectorManager.Inspect(obj);
}
2021-05-17 21:48:39 +10:00
public void OnCellExpandToggled(CachedTransform cache)
{
var instanceID = cache.InstanceID;
if (expandedInstanceIDs.Contains(instanceID))
expandedInstanceIDs.Remove(instanceID);
else
expandedInstanceIDs.Add(instanceID);
RefreshData(true);
}
public void OnCellEnableToggled(CachedTransform cache)
{
cache.Value.gameObject.SetActive(!cache.Value.gameObject.activeSelf);
RefreshData(true);
}
2021-05-17 21:48:39 +10:00
public void Init()
{
ScrollPool.Initialize(this);
}
public void Clear()
{
this.cachedTransforms.Clear();
2021-05-17 21:48:39 +10:00
displayIndex = 0;
autoExpandedIDs.Clear();
expandedInstanceIDs.Clear();
this.ScrollPool.Refresh(true, true);
2021-05-17 21:48:39 +10:00
}
public bool IsCellExpanded(int instanceID)
{
return Filtering ? autoExpandedIDs.Contains(instanceID)
: expandedInstanceIDs.Contains(instanceID);
}
2021-05-17 21:48:39 +10:00
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, OnCellJumpedTo);
}
private void OnCellJumpedTo(TransformCell cell)
{
2022-01-31 21:24:01 +11:00
RuntimeHelper.StartCoroutine(HighlightCellCoroutine(cell));
}
private IEnumerator HighlightCellCoroutine(TransformCell cell)
{
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);
}
public void Rebuild()
{
autoExpandedIDs.Clear();
expandedInstanceIDs.Clear();
RefreshData(true, true);
}
2021-04-30 23:12:18 +10:00
public void RefreshData(bool andReload = false, bool jumpToTop = false)
{
2021-05-05 21:27:09 +10:00
visited.Clear();
displayIndex = 0;
needRefresh = false;
var rootObjects = GetRootEntriesMethod.Invoke();
2021-05-05 21:27:09 +10:00
//int displayIndex = 0;
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 = cachedTransforms.Count - 1; i >= 0; i--)
{
var obj = (CachedTransform)cachedTransforms[i];
2021-05-05 21:27:09 +10:00
if (!visited.Contains(obj.InstanceID))
{
cachedTransforms.Remove(obj.InstanceID);
2021-05-05 21:27:09 +10:00
needRefresh = true;
}
}
2021-05-05 21:27:09 +10:00
if (!needRefresh)
return;
//displayedObjects.Clear();
if (andReload)
{
2021-04-30 23:12:18 +10:00
if (!jumpToTop)
ScrollPool.Refresh(true);
else
2021-04-30 23:12:18 +10:00
ScrollPool.Refresh(true, true);
}
}
private void Traverse(Transform transform, CachedTransform parent = null, int depth = 0)
{
int instanceID = transform.GetInstanceID();
2021-05-05 21:27:09 +10:00
if (visited.Contains(instanceID))
return;
if (Filtering)
{
2021-05-05 21:27:09 +10:00
if (!FilterHierarchy(transform))
return;
2021-05-05 21:27:09 +10:00
visited.Add(instanceID);
2021-05-05 21:27:09 +10:00
if (!autoExpandedIDs.Contains(instanceID))
autoExpandedIDs.Add(instanceID);
}
else
visited.Add(instanceID);
CachedTransform cached;
if (cachedTransforms.Contains(instanceID))
{
cached = (CachedTransform)cachedTransforms[(object)instanceID];
if (cached.Update(transform, depth))
needRefresh = true;
}
else
{
2021-05-05 21:27:09 +10:00
needRefresh = true;
cached = new CachedTransform(this, transform, depth, parent);
if (cachedTransforms.Count <= displayIndex)
cachedTransforms.Add(instanceID, cached);
2021-05-05 21:27:09 +10:00
else
cachedTransforms.Insert(displayIndex, instanceID, cached);
}
2021-05-05 21:27:09 +10:00
displayIndex++;
if (IsCellExpanded(instanceID) && cached.Value.childCount > 0)
{
for (int i = 0; i < transform.childCount; i++)
Traverse(transform.GetChild(i), cached, depth + 1);
}
}
private bool FilterHierarchy(Transform obj)
{
if (obj.name.ContainsIgnoreCase(currentFilter))
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;
}
public void SetCell(TransformCell cell, int index)
{
if (index < cachedTransforms.Count)
{
cell.ConfigureCell((CachedTransform)cachedTransforms[index], index);
if (Filtering)
{
if (cell.cachedTransform.Name.ContainsIgnoreCase(currentFilter))
{
cell.NameButton.ButtonText.color = Color.green;
}
}
}
else
cell.Disable();
}
}
}