using System; using System.Collections.Generic; using System.Linq; using System.Text; using UnityEngine; using UnityEngine.UI; using UnityExplorer.UI; using UnityExplorer.UI.Models; using UnityExplorer.UI.Panels; using UnityExplorer.UI.Widgets; using UnityExplorer.UI.Widgets.AutoComplete; namespace UnityExplorer.ObjectExplorer { public class ObjectSearch : UIModel { public ObjectExplorerPanel Parent { get; } public ObjectSearch(ObjectExplorerPanel parent) { Parent = parent; } private SearchContext m_context = SearchContext.UnityObject; private SceneFilter m_sceneFilter = SceneFilter.Any; private ChildFilter m_childFilter = ChildFilter.Any; private string desiredTypeInput; private string lastCheckedTypeInput; private bool lastTypeCanHaveGO; public ButtonListHandler dataHandler; private ScrollPool resultsScrollPool; private List currentResults = new List(); public TypeCompleter typeAutocompleter; public override GameObject UIRoot => uiRoot; private GameObject uiRoot; private GameObject sceneFilterRow; private GameObject childFilterRow; private GameObject unityObjectClassRow; private InputFieldRef nameInputField; private Text resultsLabel; public List GetEntries() => currentResults; public void DoSearch() { cachedCellTexts.Clear(); if (m_context == SearchContext.Singleton) currentResults = SearchProvider.SingletonSearch(nameInputField.Text); else if (m_context == SearchContext.Class) currentResults = SearchProvider.ClassSearch(nameInputField.Text); else { string compType = ""; if (m_context == SearchContext.UnityObject) compType = this.desiredTypeInput; currentResults = SearchProvider.UnityObjectSearch(nameInputField.Text, compType, m_context, m_childFilter, m_sceneFilter); } dataHandler.RefreshData(); resultsScrollPool.Refresh(true); resultsLabel.text = $"{currentResults.Count} results"; } public void Update() { if (m_context == SearchContext.UnityObject && lastCheckedTypeInput != desiredTypeInput) { lastCheckedTypeInput = desiredTypeInput; //var type = ReflectionUtility.GetTypeByName(desiredTypeInput); if (ReflectionUtility.GetTypeByName(desiredTypeInput) is Type cachedType) { var type = cachedType; lastTypeCanHaveGO = typeof(Component).IsAssignableFrom(type) || type == typeof(GameObject); sceneFilterRow.SetActive(lastTypeCanHaveGO); childFilterRow.SetActive(lastTypeCanHaveGO); } else { sceneFilterRow.SetActive(false); childFilterRow.SetActive(false); lastTypeCanHaveGO = false; } } } // UI Callbacks private void OnContextDropdownChanged(int value) { m_context = (SearchContext)value; lastCheckedTypeInput = null; sceneFilterRow.SetActive(false); childFilterRow.SetActive(false); unityObjectClassRow.SetActive(m_context == SearchContext.UnityObject); } private void OnSceneFilterDropChanged(int value) => m_sceneFilter = (SceneFilter)value; private void OnChildFilterDropChanged(int value) => m_childFilter = (ChildFilter)value; 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. private static readonly Dictionary cachedCellTexts = new Dictionary(); public void SetCell(ButtonCell cell, int index) { if (!cachedCellTexts.ContainsKey(index)) { string text; if (m_context == SearchContext.Class) text = SignatureHighlighter.Parse(currentResults[index] as Type, true); else text = ToStringUtility.ToStringWithType(currentResults[index], currentResults[index]?.GetActualType()); cachedCellTexts.Add(index, text); } cell.Button.ButtonText.text = cachedCellTexts[index]; } private void OnCellClicked(int dataIndex) { if (m_context == SearchContext.Class) InspectorManager.Inspect(currentResults[dataIndex] as Type); else InspectorManager.Inspect(currentResults[dataIndex]); } 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 var contextGroup = UIFactory.CreateHorizontalGroup(uiRoot, "SearchContextRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2)); UIFactory.SetLayoutElement(contextGroup, minHeight: 25, flexibleHeight: 0); var contextLbl = UIFactory.CreateLabel(contextGroup, "SearchContextLabel", "Searching for:", TextAnchor.MiddleLeft); UIFactory.SetLayoutElement(contextLbl.gameObject, minWidth: 110, flexibleWidth: 0); var contextDropObj = UIFactory.CreateDropdown(contextGroup, out Dropdown contextDrop, null, 14, OnContextDropdownChanged); foreach (var name in Enum.GetNames(typeof(SearchContext))) contextDrop.options.Add(new Dropdown.OptionData(name)); UIFactory.SetLayoutElement(contextDropObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999); // Unity class input unityObjectClassRow = UIFactory.CreateHorizontalGroup(uiRoot, "UnityClassRow", false, true, true, true, 2, new Vector4(2, 2, 2, 2)); UIFactory.SetLayoutElement(unityObjectClassRow, minHeight: 25, flexibleHeight: 0); var unityClassLbl = UIFactory.CreateLabel(unityObjectClassRow, "UnityClassLabel", "Class filter:", TextAnchor.MiddleLeft); UIFactory.SetLayoutElement(unityClassLbl.gameObject, minWidth: 110, flexibleWidth: 0); var classInputField = UIFactory.CreateInputField(unityObjectClassRow, "ClassInput", "..."); UIFactory.SetLayoutElement(classInputField.UIRoot, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999); typeAutocompleter = new TypeCompleter(typeof(UnityEngine.Object), classInputField); classInputField.OnValueChanged += OnTypeInputChanged; //unityObjectClassRow.SetActive(false); // 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); var childLbl = UIFactory.CreateLabel(childFilterRow, "ChildLabel", "Child filter:", TextAnchor.MiddleLeft); UIFactory.SetLayoutElement(childLbl.gameObject, minWidth: 110, flexibleWidth: 0); var childDropObj = UIFactory.CreateDropdown(childFilterRow, out Dropdown childDrop, null, 14, OnChildFilterDropChanged); foreach (var name in Enum.GetNames(typeof(ChildFilter))) 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); var sceneLbl = UIFactory.CreateLabel(sceneFilterRow, "SceneLabel", "Scene filter:", TextAnchor.MiddleLeft); UIFactory.SetLayoutElement(sceneLbl.gameObject, minWidth: 110, flexibleWidth: 0); var sceneDropObj = UIFactory.CreateDropdown(sceneFilterRow, out Dropdown sceneDrop, null, 14, OnSceneFilterDropChanged); foreach (var name in Enum.GetNames(typeof(SceneFilter))) sceneDrop.options.Add(new Dropdown.OptionData(name)); UIFactory.SetLayoutElement(sceneDropObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999); sceneFilterRow.SetActive(false); // Name filter input var nameRow = UIFactory.CreateHorizontalGroup(uiRoot, "NameRow", true, true, true, true, 2, new Vector4(2, 2, 2, 2)); UIFactory.SetLayoutElement(nameRow, minHeight: 25, flexibleHeight: 0); var nameLbl = UIFactory.CreateLabel(nameRow, "NameFilterLabel", "Name contains:", TextAnchor.MiddleLeft); UIFactory.SetLayoutElement(nameLbl.gameObject, minWidth: 110, flexibleWidth: 0); nameInputField = UIFactory.CreateInputField(nameRow, "NameFilterInput", "..."); UIFactory.SetLayoutElement(nameInputField.UIRoot, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999); // Search button var searchButton = UIFactory.CreateButton(uiRoot, "SearchButton", "Search"); UIFactory.SetLayoutElement(searchButton.Component.gameObject, minHeight: 25, flexibleHeight: 0); searchButton.OnClick += DoSearch; // Results count label var resultsCountRow = UIFactory.CreateHorizontalGroup(uiRoot, "ResultsCountRow", true, true, true, true); UIFactory.SetLayoutElement(resultsCountRow, minHeight: 25, flexibleHeight: 0); resultsLabel = UIFactory.CreateLabel(resultsCountRow, "ResultsLabel", "0 results", TextAnchor.MiddleCenter); // RESULTS SCROLL POOL dataHandler = new ButtonListHandler(resultsScrollPool, GetEntries, SetCell, ShouldDisplayCell, OnCellClicked); resultsScrollPool = UIFactory.CreateScrollPool(uiRoot, "ResultsList", out GameObject scrollObj, out GameObject scrollContent); resultsScrollPool.Initialize(dataHandler); UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999); } } }