mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-01-06 01:23:31 +08:00
Added Search page and AutoCompleter
This commit is contained in:
parent
eb58ab5327
commit
f509a985e7
@ -1,69 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.Core;
|
||||
|
||||
namespace UnityExplorer.Core.CSharp
|
||||
{
|
||||
public struct Suggestion
|
||||
{
|
||||
public enum Contexts
|
||||
{
|
||||
Namespace,
|
||||
Keyword,
|
||||
Other
|
||||
}
|
||||
|
||||
// ~~~~ Instance ~~~~
|
||||
|
||||
public readonly string Prefix;
|
||||
public readonly string Addition;
|
||||
public readonly Contexts Context;
|
||||
|
||||
public string Full => Prefix + Addition;
|
||||
|
||||
public Color TextColor => GetTextColor();
|
||||
|
||||
public Suggestion(string addition, string prefix, Contexts type)
|
||||
{
|
||||
Addition = addition;
|
||||
Prefix = prefix;
|
||||
Context = type;
|
||||
}
|
||||
|
||||
private Color GetTextColor()
|
||||
{
|
||||
switch (Context)
|
||||
{
|
||||
case Contexts.Namespace: return Color.grey;
|
||||
case Contexts.Keyword: return keywordColor;
|
||||
default: return Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
// ~~~~ Static ~~~~
|
||||
|
||||
public static HashSet<string> Namespaces => m_namespaces ?? GetNamespaces();
|
||||
private static HashSet<string> m_namespaces;
|
||||
|
||||
public static HashSet<string> Keywords => throw new NotImplementedException("TODO!"); // m_keywords ?? (m_keywords = new HashSet<string>(CSLexerHighlighter.validKeywordMatcher.Keywords));
|
||||
//private static HashSet<string> m_keywords;
|
||||
|
||||
private static readonly Color keywordColor = new Color(80f / 255f, 150f / 255f, 215f / 255f);
|
||||
|
||||
private static HashSet<string> GetNamespaces()
|
||||
{
|
||||
HashSet<string> set = new HashSet<string>(
|
||||
AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(GetTypes)
|
||||
.Where(x => x.IsPublic && !string.IsNullOrEmpty(x.Namespace))
|
||||
.Select(x => x.Namespace));
|
||||
|
||||
return m_namespaces = set;
|
||||
|
||||
IEnumerable<Type> GetTypes(Assembly asm) => asm.TryGetTypes();
|
||||
}
|
||||
}
|
||||
}
|
@ -120,7 +120,7 @@ namespace UnityExplorer
|
||||
}
|
||||
|
||||
// cache for GetBaseTypes
|
||||
internal static readonly Dictionary<string, Type[]> s_cachedTypeInheritance = new Dictionary<string, Type[]>();
|
||||
internal static readonly Dictionary<string, Type[]> s_cachedBaseTypes = new Dictionary<string, Type[]>();
|
||||
|
||||
/// <summary>
|
||||
/// Get all base types of the provided Type, including itself.
|
||||
@ -137,7 +137,7 @@ namespace UnityExplorer
|
||||
|
||||
var name = type.AssemblyQualifiedName;
|
||||
|
||||
if (s_cachedTypeInheritance.TryGetValue(name, out Type[] ret))
|
||||
if (s_cachedBaseTypes.TryGetValue(name, out Type[] ret))
|
||||
return ret;
|
||||
|
||||
List<Type> list = new List<Type>();
|
||||
@ -150,11 +150,52 @@ namespace UnityExplorer
|
||||
|
||||
ret = list.ToArray();
|
||||
|
||||
s_cachedTypeInheritance.Add(name, ret);
|
||||
s_cachedBaseTypes.Add(name, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// cache for GetImplementationsOf
|
||||
internal static readonly Dictionary<Type, HashSet<Type>> s_cachedTypeInheritance = new Dictionary<Type, HashSet<Type>>();
|
||||
internal static int s_lastAssemblyCount;
|
||||
|
||||
/// <summary>
|
||||
/// Get all non-abstract implementations of the provided type (include itself, if not abstract) in the current AppDomain.
|
||||
/// </summary>
|
||||
/// <param name="baseType">The base type, which can optionally be abstract / interface.</param>
|
||||
/// <returns>All implementations of the type in the current AppDomain.</returns>
|
||||
public static HashSet<Type> GetImplementationsOf(this Type baseType, bool allowAbstract)
|
||||
{
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
if (!s_cachedTypeInheritance.ContainsKey(baseType) || assemblies.Length != s_lastAssemblyCount)
|
||||
{
|
||||
if (assemblies.Length != s_lastAssemblyCount)
|
||||
{
|
||||
s_cachedTypeInheritance.Clear();
|
||||
s_lastAssemblyCount = assemblies.Length;
|
||||
}
|
||||
|
||||
var set = new HashSet<Type>();
|
||||
|
||||
if (!baseType.IsAbstract && !baseType.IsInterface)
|
||||
set.Add(baseType);
|
||||
|
||||
foreach (var asm in assemblies)
|
||||
{
|
||||
foreach (var t in asm.TryGetTypes().Where(t => allowAbstract || (!t.IsAbstract && !t.IsInterface)))
|
||||
{
|
||||
if (baseType.IsAssignableFrom(t) && !set.Contains(t))
|
||||
set.Add(t);
|
||||
}
|
||||
}
|
||||
|
||||
s_cachedTypeInheritance.Add(baseType, set);
|
||||
}
|
||||
|
||||
return s_cachedTypeInheritance[baseType];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Safely get all valid Types inside an Assembly.
|
||||
/// </summary>
|
||||
|
@ -5,7 +5,7 @@ using System.Text;
|
||||
|
||||
namespace UnityExplorer.Core.Search
|
||||
{
|
||||
internal enum ChildFilter
|
||||
public enum ChildFilter
|
||||
{
|
||||
Any,
|
||||
RootObject,
|
||||
|
@ -5,11 +5,11 @@ using System.Text;
|
||||
|
||||
namespace UnityExplorer.Core.Search
|
||||
{
|
||||
internal enum SceneFilter
|
||||
public enum SceneFilter
|
||||
{
|
||||
Any,
|
||||
Asset,
|
||||
ActivelyLoaded,
|
||||
DontDestroyOnLoad,
|
||||
Explicit,
|
||||
HideAndDontSave,
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ using System.Text;
|
||||
|
||||
namespace UnityExplorer.Core.Search
|
||||
{
|
||||
internal enum SearchContext
|
||||
public enum SearchContext
|
||||
{
|
||||
UnityObject,
|
||||
GameObject,
|
||||
|
@ -4,15 +4,16 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
|
||||
namespace UnityExplorer.Core.Search
|
||||
{
|
||||
public static class SearchProvider
|
||||
{
|
||||
internal static object[] StaticClassSearch(string input)
|
||||
internal static List<object> StaticClassSearch(string input)
|
||||
{
|
||||
var list = new List<Type>();
|
||||
var list = new List<object>();
|
||||
|
||||
var nameFilter = "";
|
||||
if (!string.IsNullOrEmpty(input))
|
||||
@ -29,7 +30,7 @@ namespace UnityExplorer.Core.Search
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
return list;
|
||||
}
|
||||
|
||||
internal static string[] s_instanceNames = new string[]
|
||||
@ -46,7 +47,7 @@ namespace UnityExplorer.Core.Search
|
||||
"<instance>k__BackingField",
|
||||
};
|
||||
|
||||
internal static object[] SingletonSearch(string input)
|
||||
internal static List<object> SingletonSearch(string input)
|
||||
{
|
||||
var instances = new List<object>();
|
||||
|
||||
@ -72,12 +73,31 @@ namespace UnityExplorer.Core.Search
|
||||
}
|
||||
}
|
||||
|
||||
return instances.ToArray();
|
||||
return instances;
|
||||
}
|
||||
|
||||
internal static object[] UnityObjectSearch(string input, string customTypeInput, SearchContext context,
|
||||
ChildFilter childFilter, SceneFilter sceneFilter, string sceneName = null)
|
||||
private static bool Filter(Scene scene, SceneFilter filter)
|
||||
{
|
||||
switch (filter)
|
||||
{
|
||||
case SceneFilter.Any:
|
||||
return true;
|
||||
case SceneFilter.DontDestroyOnLoad:
|
||||
return scene == SceneHandler.DontDestroyScene;
|
||||
case SceneFilter.HideAndDontSave:
|
||||
return scene == SceneHandler.AssetScene;
|
||||
case SceneFilter.ActivelyLoaded:
|
||||
return scene != SceneHandler.DontDestroyScene && scene != SceneHandler.AssetScene;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<object> UnityObjectSearch(string input, string customTypeInput, SearchContext context,
|
||||
ChildFilter childFilter, SceneFilter sceneFilter)
|
||||
{
|
||||
var results = new List<object>();
|
||||
|
||||
Type searchType = null;
|
||||
switch (context)
|
||||
{
|
||||
@ -91,13 +111,15 @@ namespace UnityExplorer.Core.Search
|
||||
if (string.IsNullOrEmpty(customTypeInput))
|
||||
{
|
||||
ExplorerCore.LogWarning("Custom Type input must not be empty!");
|
||||
return null;
|
||||
return results;
|
||||
}
|
||||
if (ReflectionUtility.GetTypeByName(customTypeInput) is Type customType)
|
||||
{
|
||||
if (typeof(UnityEngine.Object).IsAssignableFrom(customType))
|
||||
searchType = customType;
|
||||
else
|
||||
ExplorerCore.LogWarning($"Custom type '{customType.FullName}' is not assignable from UnityEngine.Object!");
|
||||
}
|
||||
else
|
||||
ExplorerCore.LogWarning($"Could not find a type by the name '{customTypeInput}'!");
|
||||
break;
|
||||
@ -106,11 +128,11 @@ namespace UnityExplorer.Core.Search
|
||||
searchType = typeof(UnityEngine.Object); break;
|
||||
}
|
||||
|
||||
|
||||
if (searchType == null)
|
||||
return null;
|
||||
return results;
|
||||
|
||||
var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(searchType);
|
||||
var results = new List<object>();
|
||||
|
||||
// perform filter comparers
|
||||
|
||||
@ -121,20 +143,11 @@ namespace UnityExplorer.Core.Search
|
||||
bool canGetGameObject = (sceneFilter != SceneFilter.Any || childFilter != ChildFilter.Any)
|
||||
&& (context == SearchContext.GameObject || typeof(Component).IsAssignableFrom(searchType));
|
||||
|
||||
string sceneFilterString = null;
|
||||
if (!canGetGameObject)
|
||||
{
|
||||
if (context != SearchContext.UnityObject && (sceneFilter != SceneFilter.Any || childFilter != ChildFilter.Any))
|
||||
ExplorerCore.LogWarning($"Type '{searchType}' cannot have Scene or Child filters applied to it");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sceneFilter == SceneFilter.DontDestroyOnLoad)
|
||||
sceneFilterString = "DontDestroyOnLoad";
|
||||
else if (sceneFilter == SceneFilter.Explicit)
|
||||
//sceneFilterString = SearchPage.Instance.m_sceneDropdown.options[SearchPage.Instance.m_sceneDropdown.value].text;
|
||||
sceneFilterString = sceneName;
|
||||
}
|
||||
|
||||
foreach (var obj in allObjects)
|
||||
{
|
||||
@ -157,12 +170,9 @@ namespace UnityExplorer.Core.Search
|
||||
switch (context)
|
||||
{
|
||||
case SearchContext.GameObject:
|
||||
if (go.scene.name != sceneFilterString)
|
||||
continue;
|
||||
break;
|
||||
case SearchContext.Custom:
|
||||
case SearchContext.Component:
|
||||
if (go.scene.name != sceneFilterString)
|
||||
if (!Filter(go.scene, sceneFilter))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
@ -184,7 +194,7 @@ namespace UnityExplorer.Core.Search
|
||||
results.Add(obj);
|
||||
}
|
||||
|
||||
return results.ToArray();
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,13 @@ namespace UnityExplorer.UI.Models
|
||||
|
||||
public abstract void ConstructUI(GameObject parent);
|
||||
|
||||
public virtual void Toggle() => SetActive(!Enabled);
|
||||
|
||||
public virtual void SetActive(bool active)
|
||||
{
|
||||
UIRoot?.SetActive(active);
|
||||
}
|
||||
|
||||
public virtual void Destroy()
|
||||
{
|
||||
if (UIRoot)
|
||||
|
@ -13,17 +13,19 @@ namespace UnityExplorer.UI.Models
|
||||
{
|
||||
public abstract class UIPanel : UIBehaviourModel
|
||||
{
|
||||
// STATIC
|
||||
|
||||
public static event Action OnPanelsReordered;
|
||||
|
||||
public static void UpdateFocus()
|
||||
{
|
||||
if (InputManager.GetMouseButtonDown(0) || InputManager.GetMouseButtonDown(1))
|
||||
{
|
||||
int count = UIManager.CanvasRoot.transform.childCount;
|
||||
int count = UIManager.PanelHolder.transform.childCount;
|
||||
var mousePos = InputManager.MousePosition;
|
||||
for (int i = count - 1; i >= 0; i--)
|
||||
{
|
||||
var transform = UIManager.CanvasRoot.transform.GetChild(i);
|
||||
var transform = UIManager.PanelHolder.transform.GetChild(i);
|
||||
if (transformToPanelDict.TryGetValue(transform.GetInstanceID(), out UIPanel panel))
|
||||
{
|
||||
var pos = panel.mainPanelRect.InverseTransformPoint(mousePos);
|
||||
@ -44,16 +46,18 @@ namespace UnityExplorer.UI.Models
|
||||
private static readonly List<UIPanel> instances = new List<UIPanel>();
|
||||
private static readonly Dictionary<int, UIPanel> transformToPanelDict = new Dictionary<int, UIPanel>();
|
||||
|
||||
// INSTANCE
|
||||
|
||||
public UIPanel()
|
||||
{
|
||||
instances.Add(this);
|
||||
}
|
||||
|
||||
public override void Destroy()
|
||||
{
|
||||
instances.Remove(this);
|
||||
base.Destroy();
|
||||
}
|
||||
public abstract UIManager.Panels PanelType { get; }
|
||||
|
||||
public abstract string Name { get; }
|
||||
|
||||
public virtual bool ShouldSaveActiveState => true;
|
||||
|
||||
public override GameObject UIRoot => uiRoot;
|
||||
protected GameObject uiRoot;
|
||||
@ -61,7 +65,23 @@ namespace UnityExplorer.UI.Models
|
||||
public GameObject content;
|
||||
public PanelDragger dragger;
|
||||
|
||||
public abstract string Name { get; }
|
||||
public abstract void ConstructPanelContent();
|
||||
|
||||
public virtual void OnFinishResize(RectTransform panel)
|
||||
{
|
||||
SaveToConfigManager();
|
||||
}
|
||||
|
||||
public virtual void OnFinishDrag(RectTransform panel)
|
||||
{
|
||||
SaveToConfigManager();
|
||||
}
|
||||
|
||||
public override void Destroy()
|
||||
{
|
||||
instances.Remove(this);
|
||||
base.Destroy();
|
||||
}
|
||||
|
||||
public override void ConstructUI(GameObject parent)
|
||||
{
|
||||
@ -79,11 +99,28 @@ namespace UnityExplorer.UI.Models
|
||||
SetDefaultPosAndAnchors();
|
||||
|
||||
// Title bar
|
||||
var titleGroup = UIFactory.CreateHorizontalGroup(content, "TitleBar", false, true, true, true, 2,
|
||||
new Vector4(2, 2, 2, 2), new Color(0.09f, 0.09f, 0.09f));
|
||||
UIFactory.SetLayoutElement(titleGroup, minHeight: 25, flexibleHeight: 0);
|
||||
|
||||
var titleBar = UIFactory.CreateLabel(content, "TitleBar", Name, TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(titleBar.gameObject, minHeight: 25, flexibleHeight: 0);
|
||||
// Title text
|
||||
|
||||
dragger = new PanelDragger(titleBar.GetComponent<RectTransform>(), mainPanelRect);
|
||||
var titleTxt = UIFactory.CreateLabel(titleGroup, "TitleBar", Name, TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(titleTxt.gameObject, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
|
||||
|
||||
// close button
|
||||
|
||||
var closeBtn = UIFactory.CreateButton(titleGroup, "CloseButton", "X", () =>
|
||||
{
|
||||
UIManager.SetPanelActive(this.PanelType, false);
|
||||
});
|
||||
UIFactory.SetLayoutElement(closeBtn.gameObject, minHeight: 25, minWidth: 25, flexibleWidth: 0);
|
||||
RuntimeProvider.Instance.SetColorBlock(closeBtn, new Color(0.63f, 0.32f, 0.31f),
|
||||
new Color(0.81f, 0.25f, 0.2f), new Color(0.6f, 0.18f, 0.16f));
|
||||
|
||||
// Panel dragger
|
||||
|
||||
dragger = new PanelDragger(titleTxt.GetComponent<RectTransform>(), mainPanelRect);
|
||||
dragger.OnFinishResize += OnFinishResize;
|
||||
dragger.OnFinishDrag += OnFinishDrag;
|
||||
|
||||
@ -97,8 +134,9 @@ namespace UnityExplorer.UI.Models
|
||||
LoadSaveData();
|
||||
dragger.OnEndResize();
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.Log($"Exception loading panel save data: {ex}");
|
||||
SetDefaultPosAndAnchors();
|
||||
}
|
||||
|
||||
@ -108,18 +146,8 @@ namespace UnityExplorer.UI.Models
|
||||
SaveToConfigManager();
|
||||
};
|
||||
}
|
||||
|
||||
public abstract void ConstructPanelContent();
|
||||
|
||||
public virtual void OnFinishResize(RectTransform panel)
|
||||
{
|
||||
SaveToConfigManager();
|
||||
}
|
||||
|
||||
public virtual void OnFinishDrag(RectTransform panel)
|
||||
{
|
||||
SaveToConfigManager();
|
||||
}
|
||||
|
||||
// SAVE DATA
|
||||
|
||||
public abstract void SaveToConfigManager();
|
||||
|
||||
@ -127,11 +155,11 @@ namespace UnityExplorer.UI.Models
|
||||
|
||||
public abstract void LoadSaveData();
|
||||
|
||||
public string ToSaveData()
|
||||
public virtual string ToSaveData()
|
||||
{
|
||||
try
|
||||
{
|
||||
return $"{Enabled}" +
|
||||
return $"{(ShouldSaveActiveState ? Enabled : false)}" +
|
||||
$"|{mainPanelRect.RectAnchorsToString()}" +
|
||||
$"|{mainPanelRect.RectPositionToString()}";
|
||||
}
|
||||
@ -141,7 +169,7 @@ namespace UnityExplorer.UI.Models
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplySaveData(string data)
|
||||
public virtual void ApplySaveData(string data)
|
||||
{
|
||||
if (string.IsNullOrEmpty(data))
|
||||
return;
|
||||
@ -150,11 +178,15 @@ namespace UnityExplorer.UI.Models
|
||||
|
||||
try
|
||||
{
|
||||
uiRoot.SetActive(bool.Parse(split[0]));
|
||||
mainPanelRect.SetAnchorsFromString(split[1]);
|
||||
mainPanelRect.SetPositionFromString(split[2]);
|
||||
UIManager.SetPanelActive(this.PanelType, bool.Parse(split[0]));
|
||||
}
|
||||
catch
|
||||
{
|
||||
ExplorerCore.LogWarning("Invalid or corrupt panel save data! Restoring to default.");
|
||||
SetDefaultPosAndAnchors();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,9 +196,6 @@ namespace UnityExplorer.UI.Models
|
||||
|
||||
// Window Anchors helpers
|
||||
|
||||
//private const string DEFAULT_WINDOW_ANCHORS = "0.25,0.10,0.78,0.95";
|
||||
//private const string DEFAULT_WINDOW_POSITION = "0,0";
|
||||
|
||||
internal static CultureInfo _enCulture = new CultureInfo("en-US");
|
||||
|
||||
internal static string RectAnchorsToString(this RectTransform rect)
|
||||
|
@ -16,6 +16,8 @@ namespace UnityExplorer.UI.Panels
|
||||
public class InspectorTest : UIPanel
|
||||
{
|
||||
public override string Name => "Inspector";
|
||||
public override UIManager.Panels PanelType => UIManager.Panels.Inspector;
|
||||
public override bool ShouldSaveActiveState => false;
|
||||
|
||||
//public SimpleListSource<Component> ComponentList;
|
||||
|
||||
@ -81,6 +83,8 @@ namespace UnityExplorer.UI.Panels
|
||||
ExplorerCore.Log("Done");
|
||||
|
||||
//previousRectHeight = mainPanelRect.rect.height;
|
||||
|
||||
UIManager.SetPanelActive(PanelType, false);
|
||||
}
|
||||
|
||||
internal GameObject contentHolder;
|
||||
|
139
src/UI/Panels/ObjectExplorer.cs
Normal file
139
src/UI/Panels/ObjectExplorer.cs
Normal file
@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
public class ObjectExplorer : UIPanel
|
||||
{
|
||||
public override string Name => "Object Explorer";
|
||||
public override UIManager.Panels PanelType => UIManager.Panels.ObjectExplorer;
|
||||
|
||||
public SceneExplorer SceneExplorer;
|
||||
public ObjectSearch ObjectSearch;
|
||||
|
||||
public int SelectedTab = -1;
|
||||
private readonly List<UIModel> tabPages = new List<UIModel>();
|
||||
private readonly List<Button> tabButtons = new List<Button>();
|
||||
|
||||
public void SetTab(int tabIndex)
|
||||
{
|
||||
if (SelectedTab != -1)
|
||||
DisableTab(SelectedTab);
|
||||
|
||||
var content = tabPages[tabIndex];
|
||||
content.SetActive(true);
|
||||
|
||||
var button = tabButtons[tabIndex];
|
||||
RuntimeProvider.Instance.SetColorBlock(button, UIManager.navButtonEnabledColor, UIManager.navButtonEnabledColor * 1.2f);
|
||||
|
||||
SelectedTab = tabIndex;
|
||||
SaveToConfigManager();
|
||||
}
|
||||
|
||||
private void DisableTab(int tabIndex)
|
||||
{
|
||||
tabPages[tabIndex].SetActive(false);
|
||||
RuntimeProvider.Instance.SetColorBlock(tabButtons[tabIndex], UIManager.navButtonDisabledColor, UIManager.navButtonDisabledColor * 1.2f);
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
SceneExplorer.Update();
|
||||
}
|
||||
|
||||
public override void SaveToConfigManager()
|
||||
{
|
||||
ConfigManager.SceneExplorerData.Value = this.ToSaveData();
|
||||
}
|
||||
|
||||
public override void LoadSaveData()
|
||||
{
|
||||
ApplySaveData(ConfigManager.SceneExplorerData.Value);
|
||||
}
|
||||
|
||||
public override string ToSaveData()
|
||||
{
|
||||
string ret = base.ToSaveData();
|
||||
ret += "|" + SelectedTab;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override void ApplySaveData(string data)
|
||||
{
|
||||
base.ApplySaveData(data);
|
||||
|
||||
try
|
||||
{
|
||||
int tab = int.Parse(data.Split('|').Last());
|
||||
SelectedTab = tab;
|
||||
}
|
||||
catch
|
||||
{
|
||||
SelectedTab = 0;
|
||||
}
|
||||
|
||||
SetTab(SelectedTab);
|
||||
}
|
||||
|
||||
public override void SetDefaultPosAndAnchors()
|
||||
{
|
||||
mainPanelRect.localPosition = Vector2.zero;
|
||||
mainPanelRect.anchorMin = Vector3.zero;
|
||||
mainPanelRect.anchorMax = new Vector2(0, 1);
|
||||
mainPanelRect.sizeDelta = new Vector2(320f, mainPanelRect.sizeDelta.y);
|
||||
mainPanelRect.anchoredPosition = new Vector2(200, 0);
|
||||
mainPanelRect.offsetMin = new Vector2(mainPanelRect.offsetMin.x, 100); // bottom
|
||||
mainPanelRect.offsetMax = new Vector2(mainPanelRect.offsetMax.x, -50); // top
|
||||
mainPanelRect.pivot = new Vector2(0.5f, 0.5f);
|
||||
}
|
||||
|
||||
public override void ConstructPanelContent()
|
||||
{
|
||||
// Tab bar
|
||||
var tabGroup = UIFactory.CreateHorizontalGroup(content, "TabBar", true, true, true, true, 2, new Vector4(2, 2, 2, 2));
|
||||
UIFactory.SetLayoutElement(tabGroup, minHeight: 25, flexibleHeight: 0);
|
||||
|
||||
// Scene Explorer
|
||||
SceneExplorer = new SceneExplorer(this);
|
||||
SceneExplorer.ConstructUI(content);
|
||||
tabPages.Add(SceneExplorer);
|
||||
|
||||
// Object search
|
||||
ObjectSearch = new ObjectSearch(this);
|
||||
ObjectSearch.ConstructUI(content);
|
||||
tabPages.Add(ObjectSearch);
|
||||
|
||||
// set up tabs
|
||||
AddTabButton(tabGroup, "Scene Explorer");
|
||||
AddTabButton(tabGroup, "Object Search");
|
||||
|
||||
// default active state: Active
|
||||
UIManager.SetPanelActive(PanelType, true);
|
||||
}
|
||||
|
||||
private void AddTabButton(GameObject tabGroup, string label)
|
||||
{
|
||||
var button = UIFactory.CreateButton(tabGroup, $"Button_{label}", label);
|
||||
|
||||
int idx = tabButtons.Count;
|
||||
button.onClick.AddListener(() => { SetTab(idx); });
|
||||
|
||||
tabButtons.Add(button);
|
||||
|
||||
DisableTab(tabButtons.Count - 1);
|
||||
}
|
||||
}
|
||||
}
|
@ -150,7 +150,7 @@ namespace UnityExplorer.UI
|
||||
/// </summary>
|
||||
public static GameObject CreatePanel(string name, out GameObject contentHolder, Color? bgColor = null)
|
||||
{
|
||||
var panelObj = CreateUIObject(name, UIManager.CanvasRoot);
|
||||
var panelObj = CreateUIObject(name, UIManager.PanelHolder);
|
||||
var rect = panelObj.GetComponent<RectTransform>();
|
||||
rect.anchorMin = Vector2.zero;
|
||||
rect.anchorMax = Vector2.one;
|
||||
@ -506,7 +506,7 @@ namespace UnityExplorer.UI
|
||||
|
||||
Image mainImage = mainObj.AddComponent<Image>();
|
||||
mainImage.type = Image.Type.Sliced;
|
||||
mainImage.color = new Color(0.15f, 0.15f, 0.15f);
|
||||
mainImage.color = new Color(0.12f, 0.12f, 0.12f);
|
||||
|
||||
inputField = mainObj.AddComponent<InputField>();
|
||||
Navigation nav = inputField.navigation;
|
||||
@ -721,7 +721,7 @@ namespace UnityExplorer.UI
|
||||
}
|
||||
|
||||
public static ScrollPool CreateScrollPool(GameObject parent, string name, out GameObject uiRoot,
|
||||
out GameObject content, Color? bgColor = null, bool autoResizeSliderHandle = true)
|
||||
out GameObject content, Color? bgColor = null)
|
||||
{
|
||||
var mainObj = CreateUIObject(name, parent, new Vector2(1, 1));
|
||||
mainObj.AddComponent<Image>().color = bgColor ?? new Color(0.12f, 0.12f, 0.12f);
|
||||
@ -774,17 +774,14 @@ namespace UnityExplorer.UI
|
||||
|
||||
RuntimeProvider.Instance.SetColorBlock(slider, disabled: new Color(0.1f, 0.1f, 0.1f));
|
||||
|
||||
if (autoResizeSliderHandle)
|
||||
{
|
||||
slider.handleRect.offsetMin = new Vector2(slider.handleRect.offsetMin.x, 0);
|
||||
slider.handleRect.offsetMax = new Vector2(slider.handleRect.offsetMax.x, 0);
|
||||
slider.handleRect.pivot = new Vector2(0.5f, 0.5f);
|
||||
slider.handleRect.offsetMin = new Vector2(slider.handleRect.offsetMin.x, 0);
|
||||
slider.handleRect.offsetMax = new Vector2(slider.handleRect.offsetMax.x, 0);
|
||||
slider.handleRect.pivot = new Vector2(0.5f, 0.5f);
|
||||
|
||||
var container = slider.m_HandleContainerRect;
|
||||
container.anchorMin = Vector3.zero;
|
||||
container.anchorMax = Vector3.one;
|
||||
container.pivot = new Vector3(0.5f, 0.5f);
|
||||
}
|
||||
var container = slider.m_HandleContainerRect;
|
||||
container.anchorMin = Vector3.zero;
|
||||
container.anchorMax = Vector3.one;
|
||||
container.pivot = new Vector3(0.5f, 0.5f);
|
||||
|
||||
// finalize and create ScrollPool
|
||||
|
||||
|
@ -12,22 +12,37 @@ using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
|
||||
namespace UnityExplorer.UI
|
||||
{
|
||||
public static class UIManager
|
||||
{
|
||||
public enum Panels
|
||||
{
|
||||
ObjectExplorer,
|
||||
Inspector,
|
||||
CSConsole,
|
||||
Options,
|
||||
ConsoleLog,
|
||||
}
|
||||
|
||||
public static GameObject CanvasRoot { get; private set; }
|
||||
public static Canvas Canvas { get; private set; }
|
||||
public static EventSystem EventSys { get; private set; }
|
||||
|
||||
// panels
|
||||
public static SceneExplorer SceneExplorer { get; private set; }
|
||||
internal static GameObject PanelHolder { get; private set; }
|
||||
public static ObjectExplorer Explorer { get; private set; }
|
||||
public static InspectorTest Inspector { get; private set; }
|
||||
|
||||
// bundle assets
|
||||
internal static Font ConsoleFont { get; private set; }
|
||||
internal static Shader BackupShader { get; private set; }
|
||||
|
||||
internal static readonly Color navButtonEnabledColor = new Color(0.2f, 0.4f, 0.28f);
|
||||
internal static readonly Color navButtonDisabledColor = new Color(0.25f, 0.25f, 0.25f);
|
||||
|
||||
public static bool ShowMenu
|
||||
{
|
||||
get => s_showMenu;
|
||||
@ -50,20 +65,17 @@ namespace UnityExplorer.UI
|
||||
UIFactory.Init();
|
||||
|
||||
CreateRootCanvas();
|
||||
CreateTopNavBar();
|
||||
|
||||
SceneExplorer = new SceneExplorer();
|
||||
SceneExplorer.ConstructUI(CanvasRoot);
|
||||
AutoCompleter.ConstructUI();
|
||||
//InspectUnderMouse.ConstructUI();
|
||||
|
||||
Explorer = new ObjectExplorer();
|
||||
Explorer.ConstructUI(CanvasRoot);
|
||||
|
||||
Inspector = new InspectorTest();
|
||||
Inspector.ConstructUI(CanvasRoot);
|
||||
|
||||
//MainMenu.Create();
|
||||
//InspectUnderMouse.ConstructUI();
|
||||
//PanelDragger.CreateCursorUI();
|
||||
|
||||
// Force refresh of anchors etc
|
||||
Canvas.ForceUpdateCanvases();
|
||||
|
||||
ShowMenu = !ConfigManager.Hide_On_Startup.Value;
|
||||
|
||||
ExplorerCore.Log("UI initialized.");
|
||||
@ -89,17 +101,14 @@ namespace UnityExplorer.UI
|
||||
if (InputManager.GetKeyDown(ConfigManager.Force_Unlock_Keybind.Value))
|
||||
CursorUnlocker.Unlock = !CursorUnlocker.Unlock;
|
||||
|
||||
UIPanel.UpdateFocus();
|
||||
|
||||
UIBehaviourModel.UpdateInstances();
|
||||
|
||||
if (EventSystem.current != EventSys)
|
||||
CursorUnlocker.SetEventSystem();
|
||||
|
||||
// TODO could make these UIBehaviourModels
|
||||
UIPanel.UpdateFocus();
|
||||
PanelDragger.UpdateInstances();
|
||||
SliderScrollbar.UpdateInstances();
|
||||
InputFieldScroller.UpdateInstances();
|
||||
|
||||
UIBehaviourModel.UpdateInstances();
|
||||
AutoCompleter.Update();
|
||||
}
|
||||
|
||||
private static void CreateRootCanvas()
|
||||
@ -113,18 +122,114 @@ namespace UnityExplorer.UI
|
||||
EventSys = CanvasRoot.AddComponent<EventSystem>();
|
||||
InputManager.AddUIModule();
|
||||
|
||||
Canvas canvas = CanvasRoot.AddComponent<Canvas>();
|
||||
canvas.renderMode = RenderMode.ScreenSpaceCamera;
|
||||
canvas.referencePixelsPerUnit = 100;
|
||||
canvas.sortingOrder = 999;
|
||||
Canvas = CanvasRoot.AddComponent<Canvas>();
|
||||
Canvas.renderMode = RenderMode.ScreenSpaceCamera;
|
||||
Canvas.referencePixelsPerUnit = 100;
|
||||
Canvas.sortingOrder = 999;
|
||||
|
||||
CanvasScaler scaler = CanvasRoot.AddComponent<CanvasScaler>();
|
||||
scaler.referenceResolution = new Vector2(1920, 1080);
|
||||
scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.Expand;
|
||||
|
||||
CanvasRoot.AddComponent<GraphicRaycaster>();
|
||||
|
||||
PanelHolder = new GameObject("PanelHolder");
|
||||
PanelHolder.transform.SetParent(CanvasRoot.transform, false);
|
||||
PanelHolder.layer = 5;
|
||||
var rect = PanelHolder.AddComponent<RectTransform>();
|
||||
rect.sizeDelta = Vector2.zero;
|
||||
rect.anchoredPosition = Vector2.zero;
|
||||
rect.pivot = new Vector2(0.5f, 0.5f);
|
||||
rect.anchorMin = Vector2.zero;
|
||||
rect.anchorMax = Vector2.one;
|
||||
PanelHolder.transform.SetAsFirstSibling();
|
||||
}
|
||||
|
||||
public static UIPanel GetPanel(Panels panel)
|
||||
{
|
||||
switch (panel)
|
||||
{
|
||||
case Panels.ObjectExplorer:
|
||||
return Explorer;
|
||||
case Panels.Inspector:
|
||||
return Inspector;
|
||||
default:
|
||||
throw new NotImplementedException($"TODO GetPanel: {panel}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void TogglePanel(Panels panel)
|
||||
{
|
||||
var uiPanel = GetPanel(panel);
|
||||
SetPanelActive(panel, !uiPanel.Enabled);
|
||||
}
|
||||
|
||||
public static void SetPanelActive(Panels panel, bool active)
|
||||
{
|
||||
GetPanel(panel).SetActive(active);
|
||||
var color = active ? navButtonEnabledColor : navButtonDisabledColor;
|
||||
RuntimeProvider.Instance.SetColorBlock(navButtonDict[panel], color, color * 1.2f);
|
||||
}
|
||||
|
||||
public static void CreateTopNavBar()
|
||||
{
|
||||
var panel = UIFactory.CreateUIObject("MainNavbar", CanvasRoot);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(panel, false, true, true, true, 5, 3, 3, 10, 10, TextAnchor.MiddleCenter);
|
||||
panel.AddComponent<Image>().color = new Color(0.1f, 0.1f, 0.1f);
|
||||
var panelRect = panel.GetComponent<RectTransform>();
|
||||
panelRect.pivot = new Vector2(0.5f, 1f);
|
||||
panelRect.anchorMin = new Vector2(0.5f, 1f);
|
||||
panelRect.anchorMax = new Vector2(0.5f, 1f);
|
||||
panelRect.sizeDelta = new Vector2(900f, 35f);
|
||||
|
||||
string titleTxt = $"{ExplorerCore.NAME} <i><color=grey>{ExplorerCore.VERSION}</color></i>";
|
||||
var title = UIFactory.CreateLabel(panel, "Title", titleTxt, TextAnchor.MiddleLeft, default, true, 18);
|
||||
UIFactory.SetLayoutElement(title.gameObject, minWidth: 240, flexibleWidth: 0);
|
||||
|
||||
CreateNavButton(panel, Panels.ObjectExplorer, "Object Explorer");
|
||||
CreateNavButton(panel, Panels.Inspector, "Inspector");
|
||||
CreateNavButton(panel, Panels.CSConsole, "C# Console");
|
||||
CreateNavButton(panel, Panels.Options, "Options");
|
||||
CreateNavButton(panel, Panels.ConsoleLog, "Console Log");
|
||||
|
||||
// close button
|
||||
|
||||
var closeBtn = UIFactory.CreateButton(panel, "CloseButton", "X", () => { ShowMenu = false; });
|
||||
UIFactory.SetLayoutElement(closeBtn.gameObject, minHeight: 25, minWidth: 25, flexibleWidth: 0);
|
||||
RuntimeProvider.Instance.SetColorBlock(closeBtn, new Color(0.63f, 0.32f, 0.31f),
|
||||
new Color(0.81f, 0.25f, 0.2f), new Color(0.6f, 0.18f, 0.16f));
|
||||
}
|
||||
|
||||
private static readonly Dictionary<Panels, Button> navButtonDict = new Dictionary<Panels, Button>();
|
||||
|
||||
private static void CreateNavButton(GameObject navbar, Panels panel, string label)
|
||||
{
|
||||
var button = UIFactory.CreateButton(navbar, $"Button_{panel}", label);
|
||||
UIFactory.SetLayoutElement(button.gameObject, minWidth: 118, flexibleWidth: 0);
|
||||
RuntimeProvider.Instance.SetColorBlock(button, navButtonDisabledColor, navButtonDisabledColor * 1.2f);
|
||||
button.onClick.AddListener(() =>
|
||||
{
|
||||
TogglePanel(panel);
|
||||
});
|
||||
navButtonDict.Add(panel, button);
|
||||
}
|
||||
|
||||
// Could be cool, need to investigate properly.
|
||||
// It works but the input/eventsystem doesnt respond properly or at all.
|
||||
//public static void TrySetTargetDisplay(int displayIndex)
|
||||
//{
|
||||
// ExplorerCore.Log("displays connected: " + Display.displays.Length);
|
||||
// // Display.displays[0] is the primary, default display and is always ON, so start at index 1.
|
||||
|
||||
// if (Display.displays.Length > displayIndex)
|
||||
// {
|
||||
// Display.displays[displayIndex].Activate();
|
||||
// Canvas.targetDisplay = displayIndex;
|
||||
// }
|
||||
//}
|
||||
|
||||
#region UI AssetBundle
|
||||
|
||||
private static void LoadBundle()
|
||||
{
|
||||
AssetBundle bundle = null;
|
||||
@ -178,5 +283,7 @@ namespace UnityExplorer.UI
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ using System.Linq;
|
||||
|
||||
namespace UnityExplorer.UI.Utility
|
||||
{
|
||||
public class PanelDragger
|
||||
public class PanelDragger
|
||||
{
|
||||
static PanelDragger()
|
||||
{
|
||||
@ -51,6 +51,9 @@ namespace UnityExplorer.UI.Utility
|
||||
handledInstanceThisFrame = false;
|
||||
foreach (var instance in Instances)
|
||||
{
|
||||
if (!instance.Panel.gameObject.activeSelf)
|
||||
continue;
|
||||
|
||||
instance.Update(state, mousePos);
|
||||
if (handledInstanceThisFrame)
|
||||
break;
|
||||
|
@ -14,15 +14,23 @@ namespace UnityExplorer.UI.Utility
|
||||
internal static Dictionary<Type, MethodInfo> toStringMethods = new Dictionary<Type, MethodInfo>();
|
||||
internal static Dictionary<Type, MethodInfo> toStringFormattedMethods = new Dictionary<Type, MethodInfo>();
|
||||
|
||||
public static string GetDefaultLabel(object value, Type fallbackType, bool includeNamespace = true, bool includeName = true)
|
||||
public static string ToString(object value, Type fallbackType, bool includeNamespace = true, bool includeName = true, bool objectAsType = false)
|
||||
{
|
||||
if (value == null && fallbackType == null)
|
||||
return "<null>";
|
||||
|
||||
var type = value?.GetActualType() ?? fallbackType;
|
||||
Type type;
|
||||
if (objectAsType)
|
||||
type = value.TryCast<Type>();
|
||||
else
|
||||
type = value?.GetActualType() ?? fallbackType;
|
||||
|
||||
|
||||
var richType = SignatureHighlighter.ParseFullSyntax(type, includeNamespace);
|
||||
|
||||
if (objectAsType)
|
||||
return richType;
|
||||
|
||||
if (!includeName)
|
||||
return richType;
|
||||
|
||||
|
140
src/UI/Widgets/AutoComplete/AutoCompleter.cs
Normal file
140
src/UI/Widgets/AutoComplete/AutoCompleter.cs
Normal file
@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
{
|
||||
// todo add a 'close' button if the user wants to manually hide the suggestions box
|
||||
|
||||
public static class AutoCompleter
|
||||
{
|
||||
public static ISuggestionProvider CurrentHandler;
|
||||
|
||||
public static GameObject UIRoot => uiRoot;
|
||||
public static GameObject uiRoot;
|
||||
|
||||
public static ButtonListSource<Suggestion> dataHandler;
|
||||
public static ScrollPool scrollPool;
|
||||
|
||||
private static List<Suggestion> suggestions = new List<Suggestion>();
|
||||
|
||||
private static int lastCaretPos;
|
||||
|
||||
public static void Update()
|
||||
{
|
||||
if (!UIRoot || !UIRoot.activeSelf)
|
||||
return;
|
||||
|
||||
if (suggestions.Any() && CurrentHandler != null)
|
||||
{
|
||||
if (!CurrentHandler.InputField.gameObject.activeInHierarchy)
|
||||
ReleaseOwnership(CurrentHandler);
|
||||
else
|
||||
{
|
||||
lastCaretPos = CurrentHandler.InputField.caretPosition;
|
||||
UpdatePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void TakeOwnership(ISuggestionProvider provider)
|
||||
{
|
||||
CurrentHandler = provider;
|
||||
}
|
||||
|
||||
public static void ReleaseOwnership(ISuggestionProvider provider)
|
||||
{
|
||||
if (CurrentHandler == null)
|
||||
return;
|
||||
|
||||
if (CurrentHandler == provider)
|
||||
{
|
||||
CurrentHandler = null;
|
||||
UIRoot.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Suggestion> GetEntries() => suggestions;
|
||||
|
||||
private static bool ShouldDisplay(Suggestion data, string filter) => true;
|
||||
|
||||
public static void SetSuggestions(List<Suggestion> collection)
|
||||
{
|
||||
suggestions = collection;
|
||||
|
||||
if (!suggestions.Any())
|
||||
UIRoot.SetActive(false);
|
||||
else
|
||||
{
|
||||
UIRoot.SetActive(true);
|
||||
dataHandler.RefreshData();
|
||||
scrollPool.Rebuild();
|
||||
//scrollPool.RefreshCells(true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnCellClicked(int dataIndex)
|
||||
{
|
||||
var suggestion = suggestions[dataIndex];
|
||||
CurrentHandler.OnSuggestionClicked(suggestion);
|
||||
}
|
||||
|
||||
private static void SetCell(ButtonCell<Suggestion> cell, int index)
|
||||
{
|
||||
if (index < 0 || index >= suggestions.Count)
|
||||
{
|
||||
cell.Disable();
|
||||
return;
|
||||
}
|
||||
|
||||
var suggestion = suggestions[index];
|
||||
cell.buttonText.text = suggestion.DisplayText;
|
||||
}
|
||||
|
||||
private static void UpdatePosition()
|
||||
{
|
||||
if (CurrentHandler == null || !CurrentHandler.InputField.isFocused)
|
||||
return;
|
||||
|
||||
var input = CurrentHandler.InputField;
|
||||
var textGen = input.textComponent.cachedTextGenerator;
|
||||
int caretPos = lastCaretPos;
|
||||
caretPos--;
|
||||
|
||||
caretPos = Math.Max(0, caretPos);
|
||||
caretPos = Math.Min(textGen.characters.Count - 1, caretPos);
|
||||
|
||||
var pos = textGen.characters[caretPos].cursorPos;
|
||||
pos = input.transform.TransformPoint(pos);
|
||||
|
||||
uiRoot.transform.position = new Vector3(pos.x + 10, pos.y - 20, 0);
|
||||
}
|
||||
|
||||
public static void ConstructUI()
|
||||
{
|
||||
var parent = UIManager.CanvasRoot;
|
||||
|
||||
dataHandler = new ButtonListSource<Suggestion>(scrollPool, GetEntries, SetCell, ShouldDisplay, OnCellClicked);
|
||||
|
||||
scrollPool = UIFactory.CreateScrollPool(parent, "AutoCompleter", out uiRoot, out GameObject scrollContent);
|
||||
var mainRect = uiRoot.GetComponent<RectTransform>();
|
||||
mainRect.pivot = new Vector2(0f, 1f);
|
||||
mainRect.anchorMin = new Vector2(0.45f, 0.45f);
|
||||
mainRect.anchorMax = new Vector2(0.65f, 0.6f);
|
||||
mainRect.offsetMin = Vector2.zero;
|
||||
mainRect.offsetMax = Vector2.zero;
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(scrollContent, true, false, true, false);
|
||||
|
||||
scrollPool.Initialize(dataHandler, ButtonCell<Suggestion>.CreatePrototypeCell(parent));
|
||||
|
||||
UIRoot.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
16
src/UI/Widgets/AutoComplete/ISuggestionProvider.cs
Normal file
16
src/UI/Widgets/AutoComplete/ISuggestionProvider.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
{
|
||||
public interface ISuggestionProvider
|
||||
{
|
||||
InputField InputField { get; }
|
||||
|
||||
void OnSuggestionClicked(Suggestion suggestion);
|
||||
}
|
||||
}
|
27
src/UI/Widgets/AutoComplete/Suggestion.cs
Normal file
27
src/UI/Widgets/AutoComplete/Suggestion.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.Core;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
{
|
||||
public struct Suggestion
|
||||
{
|
||||
public readonly string DisplayText;
|
||||
public readonly string Prefix;
|
||||
public readonly string Addition;
|
||||
public readonly Color TextColor;
|
||||
|
||||
public string Full => Prefix + Addition;
|
||||
|
||||
public Suggestion(string displayText, string prefix, string addition, Color color)
|
||||
{
|
||||
DisplayText = displayText;
|
||||
Addition = addition;
|
||||
Prefix = prefix;
|
||||
TextColor = color;
|
||||
}
|
||||
}
|
||||
}
|
119
src/UI/Widgets/AutoComplete/TypeCompleter.cs
Normal file
119
src/UI/Widgets/AutoComplete/TypeCompleter.cs
Normal file
@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
{
|
||||
public class TypeCompleter : ISuggestionProvider
|
||||
{
|
||||
private struct CachedType
|
||||
{
|
||||
public string FilteredName;
|
||||
public string DisplayName;
|
||||
}
|
||||
|
||||
public Type BaseType { get; }
|
||||
public InputField InputField { get; }
|
||||
|
||||
public event Action<Suggestion> SuggestionClicked;
|
||||
public void OnSuggestionClicked(Suggestion suggestion)
|
||||
{
|
||||
SuggestionClicked?.Invoke(suggestion);
|
||||
suggestions.Clear();
|
||||
AutoCompleter.SetSuggestions(suggestions);
|
||||
|
||||
timeOfLastCheck = Time.time;
|
||||
InputField.text = suggestion.DisplayText;
|
||||
}
|
||||
|
||||
private readonly List<Suggestion> suggestions = new List<Suggestion>();
|
||||
|
||||
private readonly Dictionary<string, CachedType> typeCache = new Dictionary<string, CachedType>();
|
||||
|
||||
//// cached list of names for displaying (with proper case)
|
||||
//private readonly List<string> cachedTypesNames = new List<string>();
|
||||
//// cached list of lookup by index (lowercase)
|
||||
//private readonly List<string> cachedTypesFilter = new List<string>();
|
||||
//// cached hashset of names (lower case)
|
||||
//private readonly HashSet<string> cachedTypesSet = new HashSet<string>();
|
||||
|
||||
public TypeCompleter(Type baseType, InputField inputField)
|
||||
{
|
||||
BaseType = baseType;
|
||||
InputField = inputField;
|
||||
|
||||
inputField.onValueChanged.AddListener(OnInputFieldChanged);
|
||||
|
||||
var types = ReflectionUtility.GetImplementationsOf(typeof(UnityEngine.Object), true);
|
||||
foreach (var type in types.OrderBy(it => it.FullName))
|
||||
{
|
||||
var name = type.FullName;
|
||||
typeCache.Add(name.ToLower(), new CachedType
|
||||
{
|
||||
DisplayName = name,
|
||||
FilteredName = name.ToLower()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private float timeOfLastCheck;
|
||||
|
||||
private void OnInputFieldChanged(string value)
|
||||
{
|
||||
if (timeOfLastCheck == Time.time)
|
||||
return;
|
||||
|
||||
timeOfLastCheck = Time.time;
|
||||
|
||||
value = value?.ToLower() ?? "";
|
||||
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
AutoCompleter.ReleaseOwnership(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetSuggestions(value);
|
||||
|
||||
AutoCompleter.TakeOwnership(this);
|
||||
AutoCompleter.SetSuggestions(suggestions);
|
||||
}
|
||||
}
|
||||
|
||||
private void GetSuggestions(string value)
|
||||
{
|
||||
suggestions.Clear();
|
||||
|
||||
var added = new HashSet<string>();
|
||||
|
||||
if (typeCache.TryGetValue(value, out CachedType cache))
|
||||
{
|
||||
added.Add(value);
|
||||
suggestions.Add(new Suggestion(cache.DisplayName,
|
||||
value,
|
||||
cache.FilteredName.Substring(value.Length, cache.FilteredName.Length - value.Length),
|
||||
Color.white));
|
||||
}
|
||||
|
||||
foreach (var entry in typeCache.Values)
|
||||
{
|
||||
if (added.Contains(entry.FilteredName))
|
||||
continue;
|
||||
|
||||
if (entry.FilteredName.Contains(value))
|
||||
{
|
||||
suggestions.Add(new Suggestion(entry.DisplayName,
|
||||
value,
|
||||
entry.FilteredName.Substring(value.Length, entry.FilteredName.Length - value.Length),
|
||||
Color.white));
|
||||
}
|
||||
|
||||
added.Add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,8 @@ namespace UnityExplorer.UI.Widgets
|
||||
public bool Enabled => m_enabled;
|
||||
private bool m_enabled;
|
||||
|
||||
public Action<ButtonCell<T>> OnClick;
|
||||
public Action<int> OnClick;
|
||||
public int CurrentDataIndex;
|
||||
|
||||
public ButtonListSource<T> list;
|
||||
|
||||
@ -30,7 +31,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
this.buttonText = text;
|
||||
this.button = button;
|
||||
|
||||
button.onClick.AddListener(() => { OnClick?.Invoke(this); });
|
||||
button.onClick.AddListener(() => { OnClick?.Invoke(CurrentDataIndex); });
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
|
@ -21,7 +21,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
public Func<List<T>> GetEntries;
|
||||
public Action<ButtonCell<T>, int> SetICell;
|
||||
public Func<T, string, bool> ShouldDisplay;
|
||||
public Action<ButtonCell<T>> OnCellClicked;
|
||||
public Action<int> OnCellClicked;
|
||||
|
||||
public string CurrentFilter
|
||||
{
|
||||
@ -30,11 +30,11 @@ namespace UnityExplorer.UI.Widgets
|
||||
}
|
||||
private string currentFilter;
|
||||
|
||||
public ButtonListSource(ScrollPool infiniteScroller, Func<List<T>> getEntriesMethod,
|
||||
public ButtonListSource(ScrollPool scrollPool, Func<List<T>> getEntriesMethod,
|
||||
Action<ButtonCell<T>, int> setICellMethod, Func<T, string, bool> shouldDisplayMethod,
|
||||
Action<ButtonCell<T>> onCellClickedMethod)
|
||||
Action<int> onCellClickedMethod)
|
||||
{
|
||||
Scroller = infiniteScroller;
|
||||
Scroller = scrollPool;
|
||||
|
||||
GetEntries = getEntriesMethod;
|
||||
SetICell = setICellMethod;
|
||||
@ -44,13 +44,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
public void Init()
|
||||
{
|
||||
RuntimeProvider.Instance.StartCoroutine(InitCoroutine());
|
||||
}
|
||||
|
||||
private IEnumerator InitCoroutine()
|
||||
{
|
||||
yield return null;
|
||||
|
||||
var proto = ButtonCell<T>.CreatePrototypeCell(Scroller.UIRoot);
|
||||
|
||||
RefreshData();
|
||||
@ -90,11 +83,15 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
public void SetCell(ICell cell, int index)
|
||||
{
|
||||
if (currentEntries == null)
|
||||
RefreshData();
|
||||
|
||||
if (index < 0 || index >= currentEntries.Count)
|
||||
cell.Disable();
|
||||
else
|
||||
{
|
||||
cell.Enable();
|
||||
(cell as ButtonCell<T>).CurrentDataIndex = index;
|
||||
SetICell.Invoke((ButtonCell<T>)cell, index);
|
||||
}
|
||||
}
|
||||
|
@ -7,30 +7,33 @@ using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Events;
|
||||
using UnityExplorer.UI.Models;
|
||||
|
||||
namespace UnityExplorer.UI.Utility
|
||||
{
|
||||
// To fix an issue with Input Fields and allow them to go inside a ScrollRect nicely.
|
||||
|
||||
public class InputFieldScroller
|
||||
public class InputFieldScroller : UIBehaviourModel
|
||||
{
|
||||
public static readonly List<InputFieldScroller> Instances = new List<InputFieldScroller>();
|
||||
//public static readonly List<InputFieldScroller> Instances = new List<InputFieldScroller>();
|
||||
|
||||
public static void UpdateInstances()
|
||||
{
|
||||
if (!Instances.Any())
|
||||
return;
|
||||
//public static void UpdateInstances()
|
||||
//{
|
||||
// if (!Instances.Any())
|
||||
// return;
|
||||
|
||||
for (int i = 0; i < Instances.Count; i++)
|
||||
{
|
||||
var input = Instances[i];
|
||||
// for (int i = 0; i < Instances.Count; i++)
|
||||
// {
|
||||
// var input = Instances[i];
|
||||
|
||||
if (input.CheckDestroyed())
|
||||
i--;
|
||||
else
|
||||
input.Update();
|
||||
}
|
||||
}
|
||||
// if (input.CheckDestroyed())
|
||||
// i--;
|
||||
// else
|
||||
// input.Update();
|
||||
// }
|
||||
//}
|
||||
|
||||
public override GameObject UIRoot => inputField.gameObject;
|
||||
|
||||
internal SliderScrollbar sliderScroller;
|
||||
internal InputField inputField;
|
||||
@ -43,7 +46,7 @@ namespace UnityExplorer.UI.Utility
|
||||
|
||||
public InputFieldScroller(SliderScrollbar sliderScroller, InputField inputField)
|
||||
{
|
||||
Instances.Add(this);
|
||||
//Instances.Add(this);
|
||||
|
||||
this.sliderScroller = sliderScroller;
|
||||
this.inputField = inputField;
|
||||
@ -69,7 +72,7 @@ namespace UnityExplorer.UI.Utility
|
||||
// only done once, to fix height on creation.
|
||||
internal bool heightInitAfterLayout;
|
||||
|
||||
public void Update()
|
||||
public override void Update()
|
||||
{
|
||||
if (!heightInitAfterLayout)
|
||||
{
|
||||
@ -85,16 +88,16 @@ namespace UnityExplorer.UI.Utility
|
||||
}
|
||||
}
|
||||
|
||||
internal bool CheckDestroyed()
|
||||
{
|
||||
if (sliderScroller == null || sliderScroller.CheckDestroyed())
|
||||
{
|
||||
Instances.Remove(this);
|
||||
return true;
|
||||
}
|
||||
//internal bool CheckDestroyed()
|
||||
//{
|
||||
// if (sliderScroller == null || sliderScroller.CheckDestroyed())
|
||||
// {
|
||||
// Instances.Remove(this);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
// return false;
|
||||
//}
|
||||
|
||||
internal void OnTextChanged(string text)
|
||||
{
|
||||
@ -128,5 +131,10 @@ namespace UnityExplorer.UI.Utility
|
||||
sliderScroller.m_slider.value = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ConstructUI(GameObject parent)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
194
src/UI/Widgets/ObjectExplorer/ObjectSearch.cs
Normal file
194
src/UI/Widgets/ObjectExplorer/ObjectSearch.cs
Normal file
@ -0,0 +1,194 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core.Search;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
public class ObjectSearch : UIModel
|
||||
{
|
||||
public ObjectExplorer Parent { get; }
|
||||
|
||||
public ObjectSearch(ObjectExplorer parent)
|
||||
{
|
||||
Parent = parent;
|
||||
}
|
||||
|
||||
private SearchContext m_context = SearchContext.UnityObject;
|
||||
private SceneFilter m_sceneFilter = SceneFilter.Any;
|
||||
private ChildFilter m_childFilter = ChildFilter.Any;
|
||||
|
||||
public ButtonListSource<object> dataHandler;
|
||||
|
||||
private ScrollPool resultsScrollPool;
|
||||
private List<object> currentResults = new List<object>();
|
||||
|
||||
public override GameObject UIRoot => uiRoot;
|
||||
private GameObject uiRoot;
|
||||
|
||||
private GameObject sceneFilterRow;
|
||||
private GameObject childFilterRow;
|
||||
private GameObject unityObjectClassRow;
|
||||
|
||||
private InputField nameInputField;
|
||||
private InputField classInputField;
|
||||
|
||||
private Text resultsLabel;
|
||||
|
||||
public List<object> GetEntries() => currentResults;
|
||||
|
||||
private void OnContextDropdownChanged(int value)
|
||||
{
|
||||
m_context = (SearchContext)value;
|
||||
|
||||
// show/hide other filters depending on what we just selected.
|
||||
bool shouldShowGoFilters = m_context == SearchContext.GameObject
|
||||
|| m_context == SearchContext.Component
|
||||
|| m_context == SearchContext.Custom;
|
||||
|
||||
sceneFilterRow.SetActive(shouldShowGoFilters);
|
||||
childFilterRow.SetActive(shouldShowGoFilters);
|
||||
|
||||
unityObjectClassRow.SetActive(m_context == SearchContext.Custom);
|
||||
}
|
||||
|
||||
private void OnSceneFilterDropChanged(int value) => m_sceneFilter = (SceneFilter)value;
|
||||
|
||||
private void OnChildFilterDropChanged(int value) => m_childFilter = (ChildFilter)value;
|
||||
|
||||
public void DoSearch()
|
||||
{
|
||||
if (m_context == SearchContext.Singleton)
|
||||
currentResults = SearchProvider.SingletonSearch(nameInputField.text);
|
||||
else if (m_context == SearchContext.StaticClass)
|
||||
currentResults = SearchProvider.StaticClassSearch(nameInputField.text);
|
||||
else
|
||||
{
|
||||
string compType = "";
|
||||
if (m_context == SearchContext.Custom)
|
||||
compType = classInputField.text;
|
||||
|
||||
currentResults = SearchProvider.UnityObjectSearch(nameInputField.text, compType, m_context, m_childFilter, m_sceneFilter);
|
||||
}
|
||||
|
||||
dataHandler.RefreshData();
|
||||
resultsScrollPool.RefreshCells(true);
|
||||
|
||||
resultsLabel.text = $"{currentResults.Count} results";
|
||||
}
|
||||
|
||||
public void SetCell(ButtonCell<object> cell, int index)
|
||||
{
|
||||
bool objectAsType = m_context == SearchContext.StaticClass;
|
||||
cell.buttonText.text = ToStringUtility.ToString(currentResults[index], currentResults[index].GetActualType(), objectAsType: objectAsType);
|
||||
}
|
||||
|
||||
private void OnCellClicked(int dataIndex)
|
||||
{
|
||||
ExplorerCore.Log("TODO");
|
||||
}
|
||||
|
||||
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", "Custom Type:", TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(unityClassLbl.gameObject, minWidth: 110, flexibleWidth: 0);
|
||||
|
||||
var classInputObj = UIFactory.CreateInputField(unityObjectClassRow, "ClassInput", "...", out this.classInputField);
|
||||
UIFactory.SetLayoutElement(classInputObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
|
||||
|
||||
new TypeCompleter(typeof(UnityEngine.Object), classInputField);
|
||||
|
||||
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);
|
||||
|
||||
var nameInputObj = UIFactory.CreateInputField(nameRow, "NameFilterInput", "...", out this.nameInputField);
|
||||
UIFactory.SetLayoutElement(nameInputObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 9999);
|
||||
|
||||
// Search button
|
||||
|
||||
var searchButton = UIFactory.CreateButton(uiRoot, "SearchButton", "Search", DoSearch);
|
||||
UIFactory.SetLayoutElement(searchButton.gameObject, minHeight: 25, flexibleHeight: 0);
|
||||
|
||||
// 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 ButtonListSource<object>(resultsScrollPool, GetEntries, SetCell, ShouldDisplayCell, OnCellClicked);
|
||||
resultsScrollPool = UIFactory.CreateScrollPool(uiRoot, "ResultsList", out GameObject scrollObj, out GameObject scrollContent);
|
||||
resultsScrollPool.Initialize(dataHandler, ButtonCell<object>.CreatePrototypeCell(uiRoot));
|
||||
UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
@ -9,16 +8,25 @@ using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
using UnityExplorer.UI.Panels;
|
||||
|
||||
namespace UnityExplorer.UI.Panels
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
public class SceneExplorer : UIPanel
|
||||
public class SceneExplorer : UIModel
|
||||
{
|
||||
public override string Name => "Scene Explorer";
|
||||
public ObjectExplorer Parent { get; }
|
||||
|
||||
public SceneExplorer(ObjectExplorer parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
SceneHandler.OnInspectedSceneChanged += SceneHandler_OnInspectedSceneChanged;
|
||||
SceneHandler.OnLoadedScenesChanged += SceneHandler_OnLoadedScenesChanged;
|
||||
}
|
||||
|
||||
public override GameObject UIRoot => m_uiRoot;
|
||||
private GameObject m_uiRoot;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to automatically update per auto-update interval or not.
|
||||
@ -32,12 +40,6 @@ namespace UnityExplorer.UI.Panels
|
||||
private Dropdown sceneDropdown;
|
||||
private readonly Dictionary<int, Dropdown.OptionData> sceneToDropdownOption = new Dictionary<int, Dropdown.OptionData>();
|
||||
|
||||
public SceneExplorer()
|
||||
{
|
||||
SceneHandler.OnInspectedSceneChanged += SceneHandler_OnInspectedSceneChanged;
|
||||
SceneHandler.OnLoadedScenesChanged += SceneHandler_OnLoadedScenesChanged;
|
||||
}
|
||||
|
||||
private IEnumerable<GameObject> GetRootEntries() => SceneHandler.CurrentRootObjects;
|
||||
|
||||
public void ForceUpdate()
|
||||
@ -45,7 +47,7 @@ namespace UnityExplorer.UI.Panels
|
||||
ExpensiveUpdate();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
public void Update()
|
||||
{
|
||||
if ((AutoUpdate || !SceneHandler.InspectingAssetScene) && Time.realtimeSinceStartup - timeOfLastUpdate >= 1f)
|
||||
{
|
||||
@ -56,10 +58,8 @@ namespace UnityExplorer.UI.Panels
|
||||
|
||||
public void ExpensiveUpdate()
|
||||
{
|
||||
//Tree.Scroller.WritingLocked = true;
|
||||
SceneHandler.Update();
|
||||
Tree.RefreshData(true);
|
||||
////Tree.Scroller.WritingLocked = false;
|
||||
}
|
||||
|
||||
private void OnDropdownChanged(int value)
|
||||
@ -128,54 +128,33 @@ namespace UnityExplorer.UI.Panels
|
||||
Tree.RefreshData(true, true);
|
||||
}
|
||||
|
||||
//private float highestRectHeight;
|
||||
|
||||
//public override void OnFinishResize(RectTransform panel)
|
||||
//{
|
||||
// base.OnFinishResize(panel);
|
||||
// RuntimeProvider.Instance.StartCoroutine(DelayedRefresh(panel));
|
||||
//}
|
||||
|
||||
//private IEnumerator DelayedRefresh(RectTransform obj)
|
||||
//{
|
||||
// yield return null;
|
||||
|
||||
// if (obj.rect.height > highestRectHeight)
|
||||
// {
|
||||
// // height increased, hard refresh required.
|
||||
// highestRectHeight = obj.rect.height;
|
||||
// //Tree.Scroller.ReloadData();
|
||||
// }
|
||||
// Tree.Scroller.RefreshCells(true);
|
||||
//}
|
||||
|
||||
public override void SaveToConfigManager()
|
||||
private void TryLoadScene(LoadSceneMode mode, Dropdown allSceneDrop)
|
||||
{
|
||||
ConfigManager.SceneExplorerData.Value = this.ToSaveData();
|
||||
var text = allSceneDrop.options[allSceneDrop.value].text;
|
||||
|
||||
if (text == DEFAULT_LOAD_TEXT)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
SceneManager.LoadScene(text, mode);
|
||||
allSceneDrop.value = 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Unable to load the Scene! {ex.ReflectionExToString()}");
|
||||
}
|
||||
}
|
||||
|
||||
public override void LoadSaveData()
|
||||
public override void ConstructUI(GameObject content)
|
||||
{
|
||||
ApplySaveData(ConfigManager.SceneExplorerData.Value);
|
||||
}
|
||||
m_uiRoot = UIFactory.CreateUIObject("SceneExplorer", content);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(m_uiRoot, true, true, true, true, 0, 2, 2, 2, 2);
|
||||
UIFactory.SetLayoutElement(m_uiRoot, flexibleHeight: 9999);
|
||||
|
||||
public override void SetDefaultPosAndAnchors()
|
||||
{
|
||||
mainPanelRect.localPosition = Vector2.zero;
|
||||
mainPanelRect.anchorMin = Vector3.zero;
|
||||
mainPanelRect.anchorMax = new Vector2(0, 1);
|
||||
mainPanelRect.sizeDelta = new Vector2(300f, mainPanelRect.sizeDelta.y);
|
||||
mainPanelRect.anchoredPosition = new Vector2(200, 0);
|
||||
mainPanelRect.offsetMin = new Vector2(mainPanelRect.offsetMin.x, 100); // bottom
|
||||
mainPanelRect.offsetMax = new Vector2(mainPanelRect.offsetMax.x, -50); // top
|
||||
mainPanelRect.pivot = new Vector2(0.5f, 0.5f);
|
||||
}
|
||||
|
||||
public override void ConstructPanelContent()
|
||||
{
|
||||
// Tool bar (top area)
|
||||
|
||||
var toolbar = UIFactory.CreateVerticalGroup(content, "Toolbar", true, true, true, true, 2, new Vector4(2, 2, 2, 2),
|
||||
var toolbar = UIFactory.CreateVerticalGroup(m_uiRoot, "Toolbar", true, true, true, true, 2, new Vector4(2, 2, 2, 2),
|
||||
new Color(0.15f, 0.15f, 0.15f));
|
||||
|
||||
// Scene selector dropdown
|
||||
@ -219,8 +198,8 @@ namespace UnityExplorer.UI.Panels
|
||||
refreshRow.SetActive(false);
|
||||
|
||||
// Transform Tree
|
||||
|
||||
var scrollPool = UIFactory.CreateScrollPool(content, "TransformTree", out GameObject scrollObj,
|
||||
|
||||
var scrollPool = UIFactory.CreateScrollPool(m_uiRoot, "TransformTree", out GameObject scrollObj,
|
||||
out GameObject scrollContent, new Color(0.15f, 0.15f, 0.15f));
|
||||
UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999);
|
||||
UIFactory.SetLayoutElement(scrollContent, flexibleHeight: 9999);
|
||||
@ -245,7 +224,7 @@ namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
if (SceneHandler.WasAbleToGetScenesInBuild)
|
||||
{
|
||||
var sceneLoaderObj = UIFactory.CreateVerticalGroup(content, "SceneLoader", true, true, true, true);
|
||||
var sceneLoaderObj = UIFactory.CreateVerticalGroup(m_uiRoot, "SceneLoader", true, true, true, true);
|
||||
UIFactory.SetLayoutElement(sceneLoaderObj, minHeight: 25);
|
||||
//sceneLoaderObj.SetActive(false);
|
||||
|
||||
@ -284,7 +263,7 @@ namespace UnityExplorer.UI.Panels
|
||||
loadButton.interactable = false;
|
||||
loadAdditiveButton.interactable = false;
|
||||
|
||||
allSceneDrop.onValueChanged.AddListener((int val) =>
|
||||
allSceneDrop.onValueChanged.AddListener((int val) =>
|
||||
{
|
||||
var text = allSceneDrop.options[val].text;
|
||||
if (text == DEFAULT_LOAD_TEXT)
|
||||
@ -305,23 +284,5 @@ namespace UnityExplorer.UI.Panels
|
||||
ExplorerCore.LogWarning($"Could not create the Scene Loader helper! {ex.ReflectionExToString()}");
|
||||
}
|
||||
}
|
||||
|
||||
private void TryLoadScene(LoadSceneMode mode, Dropdown allSceneDrop)
|
||||
{
|
||||
var text = allSceneDrop.options[allSceneDrop.value].text;
|
||||
|
||||
if (text == DEFAULT_LOAD_TEXT)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
SceneManager.LoadScene(text, mode);
|
||||
allSceneDrop.value = 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Unable to load the Scene! {ex.ReflectionExToString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -223,7 +223,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
cache = null;
|
||||
int rangeIndex = GetNormalizedHeight(desiredHeight);
|
||||
|
||||
if (rangeToDataIndexCache.Count <= rangeIndex)
|
||||
if (rangeToDataIndexCache.Count <= rangeIndex || rangeIndex < 0)
|
||||
return -1;
|
||||
|
||||
int dataIndex = rangeToDataIndexCache[rangeIndex];
|
||||
|
@ -106,7 +106,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
public void Rebuild()
|
||||
{
|
||||
RecreateCellPool(true, true, null);
|
||||
RecreateCellPool(true, true, null);
|
||||
}
|
||||
|
||||
public void EnableTempCache()
|
||||
|
@ -8,32 +8,35 @@ using UnityEngine.UI;
|
||||
using UnityExplorer;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Models;
|
||||
|
||||
namespace UnityExplorer.UI.Utility
|
||||
{
|
||||
// Basically just to fix an issue with Scrollbars, instead we use a Slider as the scrollbar.
|
||||
public class SliderScrollbar
|
||||
public class SliderScrollbar : UIBehaviourModel
|
||||
{
|
||||
internal static readonly List<SliderScrollbar> Instances = new List<SliderScrollbar>();
|
||||
//internal static readonly List<SliderScrollbar> Instances = new List<SliderScrollbar>();
|
||||
|
||||
public static void UpdateInstances()
|
||||
{
|
||||
if (!Instances.Any())
|
||||
return;
|
||||
//public static void UpdateInstances()
|
||||
//{
|
||||
// if (!Instances.Any())
|
||||
// return;
|
||||
|
||||
for (int i = 0; i < Instances.Count; i++)
|
||||
{
|
||||
var slider = Instances[i];
|
||||
// for (int i = 0; i < Instances.Count; i++)
|
||||
// {
|
||||
// var slider = Instances[i];
|
||||
|
||||
if (slider.CheckDestroyed())
|
||||
i--;
|
||||
else
|
||||
slider.Update();
|
||||
}
|
||||
}
|
||||
// if (slider.CheckDestroyed())
|
||||
// i--;
|
||||
// else
|
||||
// slider.Update();
|
||||
// }
|
||||
//}
|
||||
|
||||
public bool IsActive { get; private set; }
|
||||
|
||||
public override GameObject UIRoot => m_slider.gameObject;
|
||||
|
||||
public event Action<float> OnValueChanged;
|
||||
|
||||
internal readonly Scrollbar m_scrollbar;
|
||||
@ -44,7 +47,7 @@ namespace UnityExplorer.UI.Utility
|
||||
|
||||
public SliderScrollbar(Scrollbar scrollbar, Slider slider)
|
||||
{
|
||||
Instances.Add(this);
|
||||
//Instances.Add(this);
|
||||
|
||||
this.m_scrollbar = scrollbar;
|
||||
this.m_slider = slider;
|
||||
@ -57,18 +60,18 @@ namespace UnityExplorer.UI.Utility
|
||||
this.m_slider.Set(1f, false);
|
||||
}
|
||||
|
||||
internal bool CheckDestroyed()
|
||||
{
|
||||
if (!m_slider || !m_scrollbar)
|
||||
{
|
||||
Instances.Remove(this);
|
||||
return true;
|
||||
}
|
||||
//internal bool CheckDestroyed()
|
||||
//{
|
||||
// if (!m_slider || !m_scrollbar)
|
||||
// {
|
||||
// Instances.Remove(this);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
// return false;
|
||||
//}
|
||||
|
||||
internal void Update()
|
||||
public override void Update()
|
||||
{
|
||||
this.RefreshVisibility();
|
||||
}
|
||||
@ -167,6 +170,11 @@ namespace UnityExplorer.UI.Utility
|
||||
return sliderObj;
|
||||
}
|
||||
|
||||
public override void ConstructUI(GameObject parent)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -219,7 +219,8 @@
|
||||
<Compile Include="Core\Config\InternalConfigHandler.cs" />
|
||||
<Compile Include="Core\CSharp\ScriptEvaluator.cs" />
|
||||
<Compile Include="Core\CSharp\ScriptInteraction.cs" />
|
||||
<Compile Include="Core\CSharp\Suggestion.cs" />
|
||||
<Compile Include="UI\Widgets\AutoComplete\ISuggestionProvider.cs" />
|
||||
<Compile Include="UI\Widgets\AutoComplete\Suggestion.cs" />
|
||||
<Compile Include="Core\Config\ConfigElement.cs" />
|
||||
<Compile Include="Core\Config\ConfigHandler.cs" />
|
||||
<Compile Include="Core\Config\ConfigManager.cs" />
|
||||
@ -266,12 +267,16 @@
|
||||
<Compile Include="UI\Models\UIModel.cs" />
|
||||
<Compile Include="UI\Models\UIPanel.cs" />
|
||||
<Compile Include="UI\Panels\InspectorTest.cs" />
|
||||
<Compile Include="UI\Panels\SceneExplorer.cs" />
|
||||
<Compile Include="UI\Panels\ObjectExplorer.cs" />
|
||||
<Compile Include="UI\UIFactory.cs" />
|
||||
<Compile Include="UI\UIManager.cs" />
|
||||
<Compile Include="UI\Utility\PanelDragger.cs" />
|
||||
<Compile Include="UI\Utility\SignatureHighlighter.cs" />
|
||||
<Compile Include="UI\Utility\ToStringUtility.cs" />
|
||||
<Compile Include="UI\Widgets\AutoComplete\AutoCompleter.cs" />
|
||||
<Compile Include="UI\Widgets\AutoComplete\TypeCompleter.cs" />
|
||||
<Compile Include="UI\Widgets\ObjectExplorer\ObjectSearch.cs" />
|
||||
<Compile Include="UI\Widgets\ObjectExplorer\SceneExplorer.cs" />
|
||||
<Compile Include="UI\Widgets\ScrollPool\DataHeightCache.cs" />
|
||||
<Compile Include="UI\Widgets\ScrollPool\CellViewHolder.cs" />
|
||||
<Compile Include="UI\Widgets\ScrollPool\ICell.cs" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user