UnityExplorer/src/ObjectExplorer/ObjectSearch.cs

271 lines
12 KiB
C#
Raw Normal View History

2021-04-23 21:50:58 +10:00
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.Panels;
2021-04-23 21:50:58 +10:00
using UnityExplorer.UI.Widgets.AutoComplete;
2021-12-02 18:35:46 +11:00
using UniverseLib;
using UniverseLib.UI;
using UniverseLib.UI.Models;
2022-01-31 21:24:01 +11:00
using UniverseLib.UI.Widgets.ButtonList;
using UniverseLib.UI.Widgets.ScrollView;
using UniverseLib.Utility;
2021-04-23 21:50:58 +10:00
namespace UnityExplorer.ObjectExplorer
2021-04-23 21:50:58 +10:00
{
public class ObjectSearch : UIModel
{
public ObjectExplorerPanel Parent { get; }
2021-04-23 21:50:58 +10:00
public ObjectSearch(ObjectExplorerPanel parent)
2021-04-23 21:50:58 +10:00
{
Parent = parent;
}
2022-01-24 17:49:22 +11:00
private SearchContext context = SearchContext.UnityObject;
private SceneFilter sceneFilter = SceneFilter.Any;
private ChildFilter childFilter = ChildFilter.Any;
2021-05-05 21:27:09 +10:00
private string desiredTypeInput;
private string lastCheckedTypeInput;
2022-01-31 21:24:01 +11:00
private bool lastTypeCanHaveGameObject;
2021-04-23 21:50:58 +10:00
2021-05-16 21:46:38 +10:00
public ButtonListHandler<object, ButtonCell> dataHandler;
private ScrollPool<ButtonCell> resultsScrollPool;
2022-01-24 17:49:22 +11:00
private List<object> currentResults = new();
2021-04-23 21:50:58 +10:00
//public TypeCompleter typeAutocompleter;
public TypeCompleter unityObjectTypeCompleter;
public TypeCompleter allTypesCompleter;
2021-04-23 21:50:58 +10:00
public override GameObject UIRoot => uiRoot;
private GameObject uiRoot;
private GameObject sceneFilterRow;
private GameObject childFilterRow;
2022-01-31 21:24:01 +11:00
private GameObject classInputRow;
private GameObject nameInputRow;
private InputFieldRef nameInputField;
2021-04-23 21:50:58 +10:00
private Text resultsLabel;
public List<object> GetEntries() => currentResults;
public void DoSearch()
{
cachedCellTexts.Clear();
2022-01-24 17:49:22 +11:00
if (context == SearchContext.Singleton)
2022-01-31 21:24:01 +11:00
currentResults = SearchProvider.InstanceSearch(desiredTypeInput).ToList();
2022-01-24 17:49:22 +11:00
else if (context == SearchContext.Class)
2022-01-31 21:24:01 +11:00
currentResults = SearchProvider.ClassSearch(desiredTypeInput);
2021-04-23 21:50:58 +10:00
else
2022-01-24 17:49:22 +11:00
currentResults = SearchProvider.UnityObjectSearch(nameInputField.Text, desiredTypeInput, childFilter, sceneFilter);
2021-04-23 21:50:58 +10:00
dataHandler.RefreshData();
2021-04-30 23:12:18 +10:00
resultsScrollPool.Refresh(true);
2021-04-23 21:50:58 +10:00
resultsLabel.text = $"{currentResults.Count} results";
}
2021-05-05 21:27:09 +10:00
public void Update()
{
2022-01-24 17:49:22 +11:00
if (context == SearchContext.UnityObject && lastCheckedTypeInput != desiredTypeInput)
2021-05-05 21:27:09 +10:00
{
lastCheckedTypeInput = desiredTypeInput;
//var type = ReflectionUtility.GetTypeByName(desiredTypeInput);
if (ReflectionUtility.GetTypeByName(desiredTypeInput) is Type cachedType)
2021-05-05 21:27:09 +10:00
{
Type type = cachedType;
2022-01-31 21:24:01 +11:00
lastTypeCanHaveGameObject = typeof(Component).IsAssignableFrom(type) || type == typeof(GameObject);
sceneFilterRow.SetActive(lastTypeCanHaveGameObject);
childFilterRow.SetActive(lastTypeCanHaveGameObject);
2021-05-05 21:27:09 +10:00
}
else
{
sceneFilterRow.SetActive(false);
childFilterRow.SetActive(false);
2022-01-31 21:24:01 +11:00
lastTypeCanHaveGameObject = false;
2021-05-05 21:27:09 +10:00
}
}
}
// UI Callbacks
private void OnContextDropdownChanged(int value)
{
2022-01-24 17:49:22 +11:00
context = (SearchContext)value;
2021-05-05 21:27:09 +10:00
2021-05-16 21:46:38 +10:00
lastCheckedTypeInput = null;
sceneFilterRow.SetActive(false);
childFilterRow.SetActive(false);
2021-05-05 21:27:09 +10:00
2022-01-31 21:24:01 +11:00
nameInputRow.SetActive(context == SearchContext.UnityObject);
switch (context)
{
case SearchContext.UnityObject:
unityObjectTypeCompleter.Enabled = true;
allTypesCompleter.Enabled = false;
break;
case SearchContext.Singleton:
case SearchContext.Class:
allTypesCompleter.Enabled = true;
unityObjectTypeCompleter.Enabled = false;
break;
}
2021-05-05 21:27:09 +10:00
}
2022-01-24 17:49:22 +11:00
private void OnSceneFilterDropChanged(int value) => sceneFilter = (SceneFilter)value;
2021-05-05 21:27:09 +10:00
2022-01-24 17:49:22 +11:00
private void OnChildFilterDropChanged(int value) => childFilter = (ChildFilter)value;
2021-05-05 21:27:09 +10:00
private void OnTypeInputChanged(string val)
{
desiredTypeInput = val;
if (string.IsNullOrEmpty(val))
{
sceneFilterRow.SetActive(false);
childFilterRow.SetActive(false);
lastCheckedTypeInput = val;
}
}
// Cache the syntax-highlighted text for each search result to reduce allocs.
2022-01-31 21:24:01 +11:00
private static readonly Dictionary<int, string> cachedCellTexts = new();
public void SetCell(ButtonCell cell, int index)
2021-04-23 21:50:58 +10:00
{
if (!cachedCellTexts.ContainsKey(index))
{
string text;
2022-01-24 17:49:22 +11:00
if (context == SearchContext.Class)
{
Type type = currentResults[index] as Type;
text = $"{SignatureHighlighter.Parse(type, true)} <color=grey><i>({type.Assembly.GetName().Name})</i></color>";
}
else
text = ToStringUtility.ToStringWithType(currentResults[index], currentResults[index]?.GetActualType());
cachedCellTexts.Add(index, text);
}
cell.Button.ButtonText.text = cachedCellTexts[index];
2021-04-23 21:50:58 +10:00
}
private void OnCellClicked(int dataIndex)
{
2022-01-24 17:49:22 +11:00
if (context == SearchContext.Class)
InspectorManager.Inspect(currentResults[dataIndex] as Type);
else
InspectorManager.Inspect(currentResults[dataIndex]);
2021-04-23 21:50:58 +10:00
}
private bool ShouldDisplayCell(object arg1, string arg2) => true;
public override void ConstructUI(GameObject parent)
{
uiRoot = UIFactory.CreateVerticalGroup(parent, "ObjectSearch", true, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(uiRoot, flexibleHeight: 9999);
// Search context row
GameObject contextGroup = UIFactory.CreateHorizontalGroup(uiRoot, "SearchContextRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2));
2021-04-23 21:50:58 +10:00
UIFactory.SetLayoutElement(contextGroup, minHeight: 25, flexibleHeight: 0);
Text contextLbl = UIFactory.CreateLabel(contextGroup, "SearchContextLabel", "Searching for:", TextAnchor.MiddleLeft);
2021-04-23 21:50:58 +10:00
UIFactory.SetLayoutElement(contextLbl.gameObject, minWidth: 110, flexibleWidth: 0);
GameObject contextDropObj = UIFactory.CreateDropdown(contextGroup, "ContextDropdown", out Dropdown contextDrop, null, 14, OnContextDropdownChanged);
foreach (string name in Enum.GetNames(typeof(SearchContext)))
2021-04-23 21:50:58 +10:00
contextDrop.options.Add(new Dropdown.OptionData(name));
UIFactory.SetLayoutElement(contextDropObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
2022-01-31 21:24:01 +11:00
// Class input
2021-04-23 21:50:58 +10:00
2022-01-31 21:24:01 +11:00
classInputRow = UIFactory.CreateHorizontalGroup(uiRoot, "ClassRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(classInputRow, minHeight: 25, flexibleHeight: 0);
2021-04-23 21:50:58 +10:00
Text unityClassLbl = UIFactory.CreateLabel(classInputRow, "ClassLabel", "Class filter:", TextAnchor.MiddleLeft);
2021-04-23 21:50:58 +10:00
UIFactory.SetLayoutElement(unityClassLbl.gameObject, minWidth: 110, flexibleWidth: 0);
InputFieldRef classInputField = UIFactory.CreateInputField(classInputRow, "ClassInput", "...");
UIFactory.SetLayoutElement(classInputField.UIRoot, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
2021-04-23 21:50:58 +10:00
unityObjectTypeCompleter = new(typeof(UnityEngine.Object), classInputField, true, false, true);
allTypesCompleter = new(null, classInputField, true, false, true);
allTypesCompleter.Enabled = false;
classInputField.OnValueChanged += OnTypeInputChanged;
2021-04-23 21:50:58 +10:00
2021-05-05 21:27:09 +10:00
//unityObjectClassRow.SetActive(false);
2021-04-23 21:50:58 +10:00
// Child filter row
childFilterRow = UIFactory.CreateHorizontalGroup(uiRoot, "ChildFilterRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(childFilterRow, minHeight: 25, flexibleHeight: 0);
Text childLbl = UIFactory.CreateLabel(childFilterRow, "ChildLabel", "Child filter:", TextAnchor.MiddleLeft);
2021-04-23 21:50:58 +10:00
UIFactory.SetLayoutElement(childLbl.gameObject, minWidth: 110, flexibleWidth: 0);
GameObject childDropObj = UIFactory.CreateDropdown(childFilterRow, "ChildFilterDropdown", out Dropdown childDrop, null, 14, OnChildFilterDropChanged);
foreach (string name in Enum.GetNames(typeof(ChildFilter)))
2021-04-23 21:50:58 +10:00
childDrop.options.Add(new Dropdown.OptionData(name));
UIFactory.SetLayoutElement(childDropObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
childFilterRow.SetActive(false);
// Scene filter row
sceneFilterRow = UIFactory.CreateHorizontalGroup(uiRoot, "SceneFilterRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(sceneFilterRow, minHeight: 25, flexibleHeight: 0);
Text sceneLbl = UIFactory.CreateLabel(sceneFilterRow, "SceneLabel", "Scene filter:", TextAnchor.MiddleLeft);
2021-04-23 21:50:58 +10:00
UIFactory.SetLayoutElement(sceneLbl.gameObject, minWidth: 110, flexibleWidth: 0);
GameObject sceneDropObj = UIFactory.CreateDropdown(sceneFilterRow, "SceneFilterDropdown", out Dropdown sceneDrop, null, 14, OnSceneFilterDropChanged);
foreach (string name in Enum.GetNames(typeof(SceneFilter)))
2022-01-24 17:49:22 +11:00
{
if (!SceneHandler.DontDestroyExists && name == "DontDestroyOnLoad")
continue;
2021-04-23 21:50:58 +10:00
sceneDrop.options.Add(new Dropdown.OptionData(name));
2022-01-24 17:49:22 +11:00
}
2021-04-23 21:50:58 +10:00
UIFactory.SetLayoutElement(sceneDropObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
sceneFilterRow.SetActive(false);
// Name filter input
2022-01-31 21:24:01 +11:00
nameInputRow = UIFactory.CreateHorizontalGroup(uiRoot, "NameRow", true, true, true, true, 2, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(nameInputRow, minHeight: 25, flexibleHeight: 0);
2021-04-23 21:50:58 +10:00
Text nameLbl = UIFactory.CreateLabel(nameInputRow, "NameFilterLabel", "Name contains:", TextAnchor.MiddleLeft);
2021-04-23 21:50:58 +10:00
UIFactory.SetLayoutElement(nameLbl.gameObject, minWidth: 110, flexibleWidth: 0);
2022-01-31 21:24:01 +11:00
nameInputField = UIFactory.CreateInputField(nameInputRow, "NameFilterInput", "...");
UIFactory.SetLayoutElement(nameInputField.UIRoot, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
2021-04-23 21:50:58 +10:00
// Search button
ButtonRef searchButton = UIFactory.CreateButton(uiRoot, "SearchButton", "Search");
2021-05-11 19:18:27 +10:00
UIFactory.SetLayoutElement(searchButton.Component.gameObject, minHeight: 25, flexibleHeight: 0);
searchButton.OnClick += DoSearch;
2021-04-23 21:50:58 +10:00
// Results count label
GameObject resultsCountRow = UIFactory.CreateHorizontalGroup(uiRoot, "ResultsCountRow", true, true, true, true);
2021-04-23 21:50:58 +10:00
UIFactory.SetLayoutElement(resultsCountRow, minHeight: 25, flexibleHeight: 0);
resultsLabel = UIFactory.CreateLabel(resultsCountRow, "ResultsLabel", "0 results", TextAnchor.MiddleCenter);
// RESULTS SCROLL POOL
2021-05-16 21:46:38 +10:00
dataHandler = new ButtonListHandler<object, ButtonCell>(resultsScrollPool, GetEntries, SetCell, ShouldDisplayCell, OnCellClicked);
2021-06-05 19:36:09 +10:00
resultsScrollPool = UIFactory.CreateScrollPool<ButtonCell>(uiRoot, "ResultsList", out GameObject scrollObj,
2021-05-16 21:46:38 +10:00
out GameObject scrollContent);
2021-04-30 23:12:18 +10:00
resultsScrollPool.Initialize(dataHandler);
2021-04-23 21:50:58 +10:00
UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999);
}
}
}