Added Search page and AutoCompleter

This commit is contained in:
Sinai 2021-04-23 21:50:58 +10:00
parent eb58ab5327
commit f509a985e7
27 changed files with 1070 additions and 318 deletions

View File

@ -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();
}
}
}

View File

@ -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>

View File

@ -5,7 +5,7 @@ using System.Text;
namespace UnityExplorer.Core.Search
{
internal enum ChildFilter
public enum ChildFilter
{
Any,
RootObject,

View File

@ -5,11 +5,11 @@ using System.Text;
namespace UnityExplorer.Core.Search
{
internal enum SceneFilter
public enum SceneFilter
{
Any,
Asset,
ActivelyLoaded,
DontDestroyOnLoad,
Explicit,
HideAndDontSave,
}
}

View File

@ -5,7 +5,7 @@ using System.Text;
namespace UnityExplorer.Core.Search
{
internal enum SearchContext
public enum SearchContext
{
UnityObject,
GameObject,

View File

@ -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;
}
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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;

View 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);
}
}
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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;

View File

@ -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;

View 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);
}
}
}

View 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);
}
}

View 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;
}
}
}

View 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);
}
}
}
}

View File

@ -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()

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View 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);
}
}
}

View File

@ -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()}");
}
}
}
}

View File

@ -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];

View File

@ -106,7 +106,7 @@ namespace UnityExplorer.UI.Widgets
public void Rebuild()
{
RecreateCellPool(true, true, null);
RecreateCellPool(true, true, null);
}
public void EnableTempCache()

View File

@ -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
}
}

View File

@ -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" />