diff --git a/lib/UnityEngine.UI.dll b/lib/UnityEngine.UI.dll index 74933d5..cf7c37e 100644 Binary files a/lib/UnityEngine.UI.dll and b/lib/UnityEngine.UI.dll differ diff --git a/lib/publicized_assemblies/UnityEngine.UI.dll b/lib/publicized_assemblies/UnityEngine.UI.dll new file mode 100644 index 0000000..838d63b Binary files /dev/null and b/lib/publicized_assemblies/UnityEngine.UI.dll differ diff --git a/lib/publicized_assemblies/UnityEngine.dll b/lib/publicized_assemblies/UnityEngine.dll new file mode 100644 index 0000000..606ce38 Binary files /dev/null and b/lib/publicized_assemblies/UnityEngine.dll differ diff --git a/src/Core/CSharp/ScriptInteraction.cs b/src/Core/CSharp/ScriptInteraction.cs index 0c71220..24804c8 100644 --- a/src/Core/CSharp/ScriptInteraction.cs +++ b/src/Core/CSharp/ScriptInteraction.cs @@ -5,9 +5,6 @@ using UnityEngine; using System.Collections.Generic; using System.Linq; using UnityExplorer.Core.Runtime; -using UnityExplorer.UI.Main.CSConsole; -using UnityExplorer.UI.Main.Home; -using UnityExplorer.UI.Inspectors; namespace UnityExplorer.Core.CSharp { @@ -23,45 +20,45 @@ namespace UnityExplorer.Core.CSharp RuntimeProvider.Instance.StartCoroutine(ienumerator); } - public static void AddUsing(string directive) - { - CSharpConsole.Instance.AddUsing(directive); - } + //public static void AddUsing(string directive) + //{ + // CSharpConsole.Instance.AddUsing(directive); + //} - public static void GetUsing() - { - ExplorerCore.Log(CSharpConsole.Instance.Evaluator.GetUsing()); - } + //public static void GetUsing() + //{ + // ExplorerCore.Log(CSharpConsole.Instance.Evaluator.GetUsing()); + //} - public static void Reset() - { - CSharpConsole.Instance.ResetConsole(); - } + //public static void Reset() + //{ + // CSharpConsole.Instance.ResetConsole(); + //} - public static object CurrentTarget() - { - return InspectorManager.Instance?.m_activeInspector?.Target; - } + //public static object CurrentTarget() + //{ + // return InspectorManager.Instance?.m_activeInspector?.Target; + //} - public static object[] AllTargets() - { - int count = InspectorManager.Instance?.m_currentInspectors.Count ?? 0; - object[] ret = new object[count]; - for (int i = 0; i < count; i++) - { - ret[i] = InspectorManager.Instance?.m_currentInspectors[i].Target; - } - return ret; - } + //public static object[] AllTargets() + //{ + // int count = InspectorManager.Instance?.m_currentInspectors.Count ?? 0; + // object[] ret = new object[count]; + // for (int i = 0; i < count; i++) + // { + // ret[i] = InspectorManager.Instance?.m_currentInspectors[i].Target; + // } + // return ret; + //} - public static void Inspect(object obj) - { - InspectorManager.Instance.Inspect(obj); - } + //public static void Inspect(object obj) + //{ + // InspectorManager.Instance.Inspect(obj); + //} - public static void Inspect(Type type) - { - InspectorManager.Instance.Inspect(type); - } + //public static void Inspect(Type type) + //{ + // InspectorManager.Instance.Inspect(type); + //} } } \ No newline at end of file diff --git a/src/Core/CSharp/Suggestion.cs b/src/Core/CSharp/Suggestion.cs index 2bdd0dc..e452ff8 100644 --- a/src/Core/CSharp/Suggestion.cs +++ b/src/Core/CSharp/Suggestion.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Reflection; using UnityEngine; using UnityExplorer.Core; -using UnityExplorer.UI.Main.CSConsole; namespace UnityExplorer.Core.CSharp { @@ -49,8 +48,8 @@ namespace UnityExplorer.Core.CSharp public static HashSet Namespaces => m_namespaces ?? GetNamespaces(); private static HashSet m_namespaces; - public static HashSet Keywords => m_keywords ?? (m_keywords = new HashSet(CSLexerHighlighter.validKeywordMatcher.Keywords)); - private static HashSet m_keywords; + public static HashSet Keywords => throw new NotImplementedException("TODO!"); // m_keywords ?? (m_keywords = new HashSet(CSLexerHighlighter.validKeywordMatcher.Keywords)); + //private static HashSet m_keywords; private static readonly Color keywordColor = new Color(80f / 255f, 150f / 255f, 215f / 255f); diff --git a/src/Core/Config/ConfigManager.cs b/src/Core/Config/ConfigManager.cs index 44d1ee0..c487c36 100644 --- a/src/Core/Config/ConfigManager.cs +++ b/src/Core/Config/ConfigManager.cs @@ -6,8 +6,6 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; using UnityEngine; -using UnityExplorer.UI.Main; -using UnityExplorer.UI.Main.Home; namespace UnityExplorer.Core.Config { @@ -19,7 +17,7 @@ namespace UnityExplorer.Core.Config public static ConfigElement Main_Menu_Toggle; public static ConfigElement Force_Unlock_Mouse; - public static ConfigElement Default_Tab; + //public static ConfigElement Default_Tab; public static ConfigElement Default_Page_Limit; public static ConfigElement Default_Output_Path; public static ConfigElement Log_Unity_Debug; @@ -42,10 +40,10 @@ namespace UnityExplorer.Core.Config Handler.LoadConfig(); - SceneExplorer.OnToggleShow += SceneExplorer_OnToggleShow; - PanelDragger.OnFinishResize += PanelDragger_OnFinishResize; - PanelDragger.OnFinishDrag += PanelDragger_OnFinishDrag; - DebugConsole.OnToggleShow += DebugConsole_OnToggleShow; + //SceneExplorer.OnToggleShow += SceneExplorer_OnToggleShow; + //PanelDragger.OnFinishResize += PanelDragger_OnFinishResize; + //PanelDragger.OnFinishDrag += PanelDragger_OnFinishDrag; + //DebugConsole.OnToggleShow += DebugConsole_OnToggleShow; InitConsoleCallback(); } @@ -66,9 +64,9 @@ namespace UnityExplorer.Core.Config "Should UnityExplorer be hidden on startup?", false); - Default_Tab = new ConfigElement("Default Tab", - "The default menu page when starting the game.", - MenuPages.Home); + //Default_Tab = new ConfigElement("Default Tab", + // "The default menu page when starting the game.", + // MenuPages.Home); Log_Unity_Debug = new ConfigElement("Log Unity Debug", "Should UnityEngine.Debug.Log messages be printed to UnityExplorer's log?", diff --git a/src/Core/Input/CursorUnlocker.cs b/src/Core/Input/CursorUnlocker.cs index ab5dc9a..6ef9bba 100644 --- a/src/Core/Input/CursorUnlocker.cs +++ b/src/Core/Input/CursorUnlocker.cs @@ -1,6 +1,5 @@ using System; using UnityEngine; -using UnityExplorer.Core.Unity; using UnityEngine.EventSystems; using UnityExplorer.Core.Input; using BF = System.Reflection.BindingFlags; diff --git a/src/Core/Input/InputSystem.cs b/src/Core/Input/InputSystem.cs index 5fcf2d5..3f6ac33 100644 --- a/src/Core/Input/InputSystem.cs +++ b/src/Core/Input/InputSystem.cs @@ -1,11 +1,9 @@ using System; using System.Reflection; -using UnityExplorer.Core.Unity; using UnityEngine; using UnityEngine.EventSystems; using UnityExplorer.UI; using System.Collections.Generic; -using UnityExplorer.UI.Inspectors; using System.Linq; namespace UnityExplorer.Core.Input @@ -164,13 +162,13 @@ namespace UnityExplorer.Core.Input var assetType = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.InputActionAsset"); m_newInputModule = RuntimeProvider.Instance.AddComponent(UIManager.CanvasRoot, TInputSystemUIInputModule); var asset = RuntimeProvider.Instance.CreateScriptable(assetType) - .Cast(assetType); + .TryCast(assetType); inputExtensions = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.InputActionSetupExtensions"); var addMap = inputExtensions.GetMethod("AddActionMap", new Type[] { assetType, typeof(string) }); var map = addMap.Invoke(null, new object[] { asset, "UI" }) - .Cast(ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.InputActionMap")); + .TryCast(ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.InputActionMap")); CreateAction(map, "point", new[] { "/position" }, "point"); CreateAction(map, "click", new[] { "/leftButton" }, "leftClick"); @@ -191,22 +189,22 @@ namespace UnityExplorer.Core.Input var inputActionType = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.InputAction"); var addAction = inputExtensions.GetMethod("AddAction"); var action = addAction.Invoke(null, new object[] { map, actionName, default, null, null, null, null, null }) - .Cast(inputActionType); + .TryCast(inputActionType); var addBinding = inputExtensions.GetMethod("AddBinding", new Type[] { inputActionType, typeof(string), typeof(string), typeof(string), typeof(string) }); foreach (string binding in bindings) - addBinding.Invoke(null, new object[] { action.Cast(inputActionType), binding, null, null, null }); + addBinding.Invoke(null, new object[] { action.TryCast(inputActionType), binding, null, null, null }); var refType = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.InputActionReference"); var inputRef = refType.GetMethod("Create") .Invoke(null, new object[] { action }) - .Cast(refType); + .TryCast(refType); TInputSystemUIInputModule .GetProperty(propertyName) - .SetValue(m_newInputModule.Cast(TInputSystemUIInputModule), inputRef, null); + .SetValue(m_newInputModule.TryCast(TInputSystemUIInputModule), inputRef, null); } public void ActivateModule() diff --git a/src/Core/Input/LegacyInput.cs b/src/Core/Input/LegacyInput.cs index 65d4ad1..8463cc4 100644 --- a/src/Core/Input/LegacyInput.cs +++ b/src/Core/Input/LegacyInput.cs @@ -1,6 +1,5 @@ using System; using System.Reflection; -using UnityExplorer.Core.Unity; using UnityEngine; using UnityEngine.EventSystems; using UnityExplorer.UI; diff --git a/src/Core/ReflectionUtility.cs b/src/Core/ReflectionUtility.cs index b7e8a8f..6e872b1 100644 --- a/src/Core/ReflectionUtility.cs +++ b/src/Core/ReflectionUtility.cs @@ -13,6 +13,36 @@ namespace UnityExplorer { public const BF AllFlags = BF.Public | BF.Instance | BF.NonPublic | BF.Static; + public static void Test() + { + AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(AssemblyResolver); + } + + private static Assembly AssemblyResolver(object sender, ResolveEventArgs args) + { + if (args.Name.StartsWith("UnityExplorer")) + return typeof(ExplorerCore).Assembly; + + return null; + } + + public static bool ValueEqual(this T objA, T objB) + { + return (objA == null && objB == null) || (objA != null && objA.Equals(objB)); + } + + public static bool ReferenceEqual(this object objA, object objB) + { + if (objA.TryCast() is UnityEngine.Object unityA) + { + var unityB = objB.TryCast(); + if (unityB && unityA.m_CachedPtr == unityB.m_CachedPtr) + return true; + } + + return object.ReferenceEquals(objA, objB); + } + /// /// Helper for IL2CPP to get the underlying true Type (Unhollowed) of the object. /// @@ -31,7 +61,7 @@ namespace UnityExplorer /// /// The object to cast /// The object, cast to the underlying Type if possible, otherwise the original object. - public static object Cast(this object obj) + public static object TryCast(this object obj) => ReflectionProvider.Instance.Cast(obj, GetActualType(obj)); /// @@ -40,7 +70,7 @@ namespace UnityExplorer /// The object to cast /// The Type to cast to /// The object, cast to the Type provided if possible, otherwise the original object. - public static object Cast(this object obj, Type castTo) + public static object TryCast(this object obj, Type castTo) => ReflectionProvider.Instance.Cast(obj, castTo); public static T TryCast(this object obj) diff --git a/src/Core/Runtime/Il2Cpp/Il2CppProvider.cs b/src/Core/Runtime/Il2Cpp/Il2CppProvider.cs index 76b1a3a..637bc71 100644 --- a/src/Core/Runtime/Il2Cpp/Il2CppProvider.cs +++ b/src/Core/Runtime/Il2Cpp/Il2CppProvider.cs @@ -21,6 +21,7 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp { public override void Initialize() { + ExplorerCore.Context = RuntimeContext.IL2CPP; Reflection = new Il2CppReflection(); TextureUtil = new Il2CppTextureUtil(); } @@ -80,18 +81,6 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp list.AddRange(il2cppList.ToArray()); } - public override bool IsReferenceEqual(object a, object b) - { - if (a.TryCast() is UnityEngine.Object ua) - { - var ub = b.TryCast(); - if (ub && ua.m_CachedPtr == ub.m_CachedPtr) - return true; - } - - return base.IsReferenceEqual(a, b); - } - // LayerMask.LayerToName internal delegate IntPtr d_LayerToName(int layer); @@ -117,9 +106,6 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp return new Il2CppReferenceArray(iCall.Invoke(Il2CppType.From(type).Pointer)); } - public override int GetSceneHandle(Scene scene) - => scene.handle; - // Scene.GetRootGameObjects(); internal delegate void d_GetRootGameObjects(int handle, IntPtr list); @@ -250,41 +236,31 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp ExplorerCore.Log(ex); } } - - public override void FindSingleton(string[] possibleNames, Type type, BF flags, List instances) - { - PropertyInfo pi; - foreach (var name in possibleNames) - { - pi = type.GetProperty(name, flags); - if (pi != null) - { - var instance = pi.GetValue(null, null); - if (instance != null) - { - instances.Add(instance); - return; - } - } - } - - base.FindSingleton(possibleNames, type, flags, instances); - } } } public static class Il2CppExtensions { - public static void AddListener(this UnityEvent action, Action listener) + public static void AddListenerEx(this UnityEvent action, Action listener) { action.AddListener(listener); } - public static void AddListener(this UnityEvent action, Action listener) + public static void AddListenerEx(this UnityEvent action, Action listener) { action.AddListener(listener); } + public static void RemoveListener(this UnityEvent action, Action listener) + { + action.RemoveListener(listener); + } + + public static void RemoveListener(this UnityEvent action, Action listener) + { + action.RemoveListener(listener); + } + public static void SetChildControlHeight(this HorizontalOrVerticalLayoutGroup group, bool value) => group.childControlHeight = value; public static void SetChildControlWidth(this HorizontalOrVerticalLayoutGroup group, bool value) => group.childControlWidth = value; } diff --git a/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs b/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs index 8d10743..a253b30 100644 --- a/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs +++ b/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs @@ -412,7 +412,7 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp var keyList = new List(); var valueList = new List(); - var hashtable = value.Cast(typeof(Il2CppSystem.Collections.Hashtable)) as Il2CppSystem.Collections.Hashtable; + var hashtable = value.TryCast(typeof(Il2CppSystem.Collections.Hashtable)) as Il2CppSystem.Collections.Hashtable; if (hashtable != null) { @@ -465,6 +465,26 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp } } + public override void FindSingleton(string[] possibleNames, Type type, BF flags, List instances) + { + PropertyInfo pi; + foreach (var name in possibleNames) + { + pi = type.GetProperty(name, flags); + if (pi != null) + { + var instance = pi.GetValue(null, null); + if (instance != null) + { + instances.Add(instance); + return; + } + } + } + + base.FindSingleton(possibleNames, type, flags, instances); + } + // ~~~~~~~~~~ not used ~~~~~~~~~~~~ // cached il2cpp unbox methods diff --git a/src/Core/Runtime/Mono/MonoProvider.cs b/src/Core/Runtime/Mono/MonoProvider.cs index 3501634..bf6a918 100644 --- a/src/Core/Runtime/Mono/MonoProvider.cs +++ b/src/Core/Runtime/Mono/MonoProvider.cs @@ -19,6 +19,7 @@ namespace UnityExplorer.Core.Runtime.Mono { public override void Initialize() { + ExplorerCore.Context = RuntimeContext.Mono; Reflection = new MonoReflection(); TextureUtil = new MonoTextureUtil(); @@ -66,12 +67,12 @@ namespace UnityExplorer.Core.Runtime.Mono public override UnityEngine.Object[] FindObjectsOfTypeAll(Type type) => Resources.FindObjectsOfTypeAll(type); - private static readonly FieldInfo fi_Scene_handle = typeof(Scene).GetField("m_Handle", ReflectionUtility.AllFlags); + //private static readonly FieldInfo fi_Scene_handle = typeof(Scene).GetField("m_Handle", ReflectionUtility.AllFlags); - public override int GetSceneHandle(Scene scene) - { - return (int)fi_Scene_handle.GetValue(scene); - } + //public override int GetSceneHandle(Scene scene) + //{ + // return (int)fi_Scene_handle.GetValue(scene); + //} public override GameObject[] GetRootGameObjects(Scene scene) { @@ -125,6 +126,16 @@ public static class MonoExtensions _event.AddListener(new UnityAction(listener)); } + public static void RemoveListener(this UnityEvent _event, Action listener) + { + _event.RemoveListener(new UnityAction(listener)); + } + + public static void RemoveListener(this UnityEvent _event, Action listener) + { + _event.RemoveListener(new UnityAction(listener)); + } + public static void Clear(this StringBuilder sb) { sb.Remove(0, sb.Length); diff --git a/src/Core/Runtime/ReflectionProvider.cs b/src/Core/Runtime/ReflectionProvider.cs index 6ddd10b..80c9b84 100644 --- a/src/Core/Runtime/ReflectionProvider.cs +++ b/src/Core/Runtime/ReflectionProvider.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Text; namespace UnityExplorer.Core.Runtime @@ -38,5 +39,24 @@ namespace UnityExplorer.Core.Runtime public virtual IEnumerable EnumerateEnumerable(object value) => null; + + public virtual void FindSingleton(string[] s_instanceNames, Type type, BindingFlags flags, List instances) + { + // Look for a typical Instance backing field. + FieldInfo fi; + foreach (var name in s_instanceNames) + { + fi = type.GetField(name, flags); + if (fi != null) + { + var instance = fi.GetValue(null); + if (instance != null) + { + instances.Add(instance); + return; + } + } + } + } } } diff --git a/src/Core/Runtime/RuntimeContext.cs b/src/Core/Runtime/RuntimeContext.cs new file mode 100644 index 0000000..1dbd7fe --- /dev/null +++ b/src/Core/Runtime/RuntimeContext.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UnityExplorer.Core.Runtime +{ + public enum RuntimeContext + { + Mono, + IL2CPP + } +} diff --git a/src/Core/Runtime/RuntimeProvider.cs b/src/Core/Runtime/RuntimeProvider.cs index 7715676..60cb6f9 100644 --- a/src/Core/Runtime/RuntimeProvider.cs +++ b/src/Core/Runtime/RuntimeProvider.cs @@ -2,7 +2,6 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using System.Reflection; using System.Text; using UnityEngine; using UnityEngine.EventSystems; @@ -42,7 +41,7 @@ namespace UnityExplorer public abstract void Update(); - public virtual bool IsReferenceEqual(object a, object b) => ReferenceEquals(a, b); + //public virtual bool IsReferenceEqual(object a, object b) => ReferenceEquals(a, b); // Unity API handlers @@ -56,7 +55,7 @@ namespace UnityExplorer public abstract void GraphicRaycast(GraphicRaycaster raycaster, PointerEventData data, List list); - public abstract int GetSceneHandle(Scene scene); + //public abstract int GetSceneHandle(Scene scene); public abstract GameObject[] GetRootGameObjects(Scene scene); @@ -66,24 +65,5 @@ namespace UnityExplorer public abstract void SetColorBlock(Selectable selectable, Color? normal = null, Color? highlighted = null, Color? pressed = null, Color? disabled = null); - - public virtual void FindSingleton(string[] s_instanceNames, Type type, BindingFlags flags, List instances) - { - // Look for a typical Instance backing field. - FieldInfo fi; - foreach (var name in s_instanceNames) - { - fi = type.GetField(name, flags); - if (fi != null) - { - var instance = fi.GetValue(null); - if (instance != null) - { - instances.Add(instance); - return; - } - } - } - } } } diff --git a/src/Core/SceneHandler.cs b/src/Core/SceneHandler.cs new file mode 100644 index 0000000..a10c08f --- /dev/null +++ b/src/Core/SceneHandler.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace UnityExplorer.Core +{ + public static class SceneHandler + { + /// + /// The currently inspected Scene. + /// + public static Scene? SelectedScene + { + get => m_selectedScene; + internal set + { + if (m_selectedScene != null && m_selectedScene?.handle == value?.handle) + return; + m_selectedScene = value; + OnInspectedSceneChanged?.Invoke((Scene)m_selectedScene); + } + } + private static Scene? m_selectedScene; + + /// + /// The GameObjects in the currently inspected scene. + /// + public static ReadOnlyCollection CurrentRootObjects => new ReadOnlyCollection(rootObjects); + private static GameObject[] rootObjects = new GameObject[0]; + + /// + /// All currently loaded Scenes. + /// + public static ReadOnlyCollection LoadedScenes => new ReadOnlyCollection(allLoadedScenes); + private static readonly List allLoadedScenes = new List(); + + /// + /// The names of all scenes in the build settings, if they could be retrieved. + /// + public static ReadOnlyCollection AllSceneNames => new ReadOnlyCollection(allScenesInBuild); + private static readonly List allScenesInBuild = new List(); + + /// + /// Whether or not we successfuly retrieved the names of the scenes in the build settings. + /// + public static bool WasAbleToGetScenesInBuild => gotAllScenesInBuild; + private static bool gotAllScenesInBuild = true; + + /// + /// Invoked when the currently inspected Scene changes. The argument is the new scene. + /// + public static event Action OnInspectedSceneChanged; + + /// + /// Invoked whenever the list of currently loaded Scenes changes. The argument contains all loaded scenes after the change. + /// + public static event Action> OnLoadedScenesChanged; + + /// + /// Equivalent to + 1, to include 'DontDestroyOnLoad'. + /// + public static int LoadedSceneCount => SceneManager.sceneCount + 1; + + // Cached on startup, will never change during runtime (and generally doesn't change between Unity versions either) + + internal static Scene DontDestroyScene => DontDestroyMe.scene; + internal static int DontDestroyHandle => DontDestroyScene.handle; + + internal static GameObject DontDestroyMe + { + get + { + if (!dontDestroyObject) + { + dontDestroyObject = new GameObject("DontDestroyMe"); + GameObject.DontDestroyOnLoad(dontDestroyObject); + } + return dontDestroyObject; + } + } + private static GameObject dontDestroyObject; + + internal static Scene AssetScene => AssetObject.scene; + internal static int AssetHandle => AssetScene.handle; + + internal static GameObject AssetObject + { + get + { + if (!assetObject) + { + assetObject = RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(GameObject)) + .First(it => !it.TryCast().scene.IsValid()) + .TryCast(); + } + return assetObject; + } + } + private static GameObject assetObject; + + internal static void Init() + { + // Try to get all scenes in the build settings. This may not work. + try + { + Type sceneUtil = ReflectionUtility.GetTypeByName("UnityEngine.SceneManagement.SceneUtility"); + if (sceneUtil == null) + throw new Exception("This version of Unity does not ship with the 'SceneUtility' class, or it was not unstripped."); + + var method = sceneUtil.GetMethod("GetScenePathByBuildIndex", ReflectionUtility.AllFlags); + int sceneCount = SceneManager.sceneCountInBuildSettings; + for (int i = 0; i < sceneCount; i++) + { + var scenePath = (string)method.Invoke(null, new object[] { i }); + allScenesInBuild.Add(scenePath); + } + } + catch (Exception ex) + { + gotAllScenesInBuild = false; + ExplorerCore.Log($"Unable to generate list of all Scenes in the build: {ex}"); + } + } + + internal static void Update() + { + int curHandle = SelectedScene?.handle ?? -1; + // DontDestroyOnLoad always exists, so default to true if our curHandle is that handle. + // otherwise we will check while iterating. + bool inspectedExists = curHandle == DontDestroyHandle || curHandle == AssetHandle; + + // Quick sanity check if the loaded scenes changed + bool anyChange = LoadedSceneCount != allLoadedScenes.Count; + // otherwise keep a lookup table of the previous handles to check if the list changed at all. + HashSet previousHandles = null; + if (!anyChange) + previousHandles = new HashSet(allLoadedScenes.Select(it => it.handle)); + + allLoadedScenes.Clear(); + + for (int i = 0; i < SceneManager.sceneCount; i++) + { + Scene scene = SceneManager.GetSceneAt(i); + if (scene == default || scene.handle == -1) + continue; + + // If no changes yet, ensure the previous list contained this handle. + if (!anyChange && !previousHandles.Contains(scene.handle)) + anyChange = true; + + // If we have not yet confirmed inspectedExists, check if this scene is our currently inspected one. + if (curHandle != -1 && !inspectedExists && scene.handle == curHandle) + inspectedExists = true; + + allLoadedScenes.Add(scene); + } + + // Always add the DontDestroyOnLoad scene and the "none" scene. + allLoadedScenes.Add(DontDestroyScene); + allLoadedScenes.Add(AssetScene); + + // Default to first scene if none selected or previous selection no longer exists. + if (!inspectedExists) + { + SelectedScene = allLoadedScenes.First(); + } + + // Notify on the list changing at all + if (anyChange) + { + OnLoadedScenesChanged?.Invoke(LoadedScenes); + } + + // Finally, update the root objects list. + if (SelectedScene != null && ((Scene)SelectedScene).IsValid()) + rootObjects = RuntimeProvider.Instance.GetRootGameObjects((Scene)SelectedScene); + else + { + var allObjects = RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(GameObject)); + var list = new List(); + foreach (var obj in allObjects) + { + if (obj.TryCast() is GameObject go && !go.scene.IsValid() && go.transform.parent == null) + list.Add(go); + } + rootObjects = list.ToArray(); + } + } + } +} diff --git a/src/Core/Search/SearchProvider.cs b/src/Core/Search/SearchProvider.cs index a21f20a..bd198f9 100644 --- a/src/Core/Search/SearchProvider.cs +++ b/src/Core/Search/SearchProvider.cs @@ -5,8 +5,6 @@ using System.Reflection; using System.Text; using UnityEngine; using UnityExplorer.Core.Runtime; -using UnityExplorer.UI.Main; -using UnityExplorer.UI.Main.Search; namespace UnityExplorer.Core.Search { @@ -68,7 +66,7 @@ namespace UnityExplorer.Core.Search if (!string.IsNullOrEmpty(nameFilter) && !type.FullName.ToLower().Contains(nameFilter)) continue; - RuntimeProvider.Instance.FindSingleton(s_instanceNames, type, flags, instances); + ReflectionProvider.Instance.FindSingleton(s_instanceNames, type, flags, instances); } catch { } } @@ -78,7 +76,7 @@ namespace UnityExplorer.Core.Search } internal static object[] UnityObjectSearch(string input, string customTypeInput, SearchContext context, - ChildFilter childFilter, SceneFilter sceneFilter) + ChildFilter childFilter, SceneFilter sceneFilter, string sceneName = null) { Type searchType = null; switch (context) @@ -134,7 +132,8 @@ namespace UnityExplorer.Core.Search if (sceneFilter == SceneFilter.DontDestroyOnLoad) sceneFilterString = "DontDestroyOnLoad"; else if (sceneFilter == SceneFilter.Explicit) - sceneFilterString = SearchPage.Instance.m_sceneDropdown.options[SearchPage.Instance.m_sceneDropdown.value].text; + //sceneFilterString = SearchPage.Instance.m_sceneDropdown.options[SearchPage.Instance.m_sceneDropdown.value].text; + sceneFilterString = sceneName; } foreach (var obj in allObjects) diff --git a/src/Core/TestClass.cs b/src/Core/Tests/TestClass.cs similarity index 89% rename from src/Core/TestClass.cs rename to src/Core/Tests/TestClass.cs index b9747c9..1923855 100644 --- a/src/Core/TestClass.cs +++ b/src/Core/Tests/TestClass.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace UnityExplorer +namespace UnityExplorer.Tests { public static class TestClass { - public static UI.Main.PanelDragger.ResizeTypes flags = UI.Main.PanelDragger.ResizeTypes.NONE; + //public static UI.Main.PanelDragger.ResizeTypes flags = UI.Main.PanelDragger.ResizeTypes.NONE; #if CPP public static string testStringOne = "Test"; diff --git a/src/Core/Unity/UnityHelpers.cs b/src/Core/Unity/UnityHelpers.cs index fc401c1..feabcea 100644 --- a/src/Core/Unity/UnityHelpers.cs +++ b/src/Core/Unity/UnityHelpers.cs @@ -4,9 +4,11 @@ using System.Globalization; using System.Linq; using System.Text; using UnityEngine; +using UnityEngine.Events; using Object = UnityEngine.Object; -namespace UnityExplorer.Core.Unity +// Project-wide namespace for accessibility +namespace UnityExplorer { public static class UnityHelpers { diff --git a/src/ExplorerCore.cs b/src/ExplorerCore.cs index 47b7cff..dd72b26 100644 --- a/src/ExplorerCore.cs +++ b/src/ExplorerCore.cs @@ -2,12 +2,11 @@ using System.Collections; using System.IO; using UnityEngine; +using UnityExplorer.Core; using UnityExplorer.Core.Config; using UnityExplorer.Core.Input; using UnityExplorer.Core.Runtime; using UnityExplorer.UI; -using UnityExplorer.UI.Inspectors; -using UnityExplorer.UI.Main; namespace UnityExplorer { @@ -21,10 +20,14 @@ namespace UnityExplorer public static ExplorerCore Instance { get; private set; } public static IExplorerLoader Loader { get; private set; } + public static RuntimeContext Context { get; internal set; } // Prevent using ctor, must use Init method. private ExplorerCore() { } + /// + /// Initialize UnityExplorer with the provided Loader implementation. + /// public static void Init(IExplorerLoader loader) { if (Instance != null) @@ -42,7 +45,7 @@ namespace UnityExplorer ConfigManager.Init(Loader.ConfigHandler); RuntimeProvider.Init(); - + SceneHandler.Init(); InputManager.Init(); Log($"{NAME} {VERSION} initialized."); @@ -61,11 +64,15 @@ namespace UnityExplorer yield return null; Log($"Creating UI, after delay of {delay} second(s)."); - UIManager.Init(); + + UIManager.InitUI(); //InspectorManager.Instance.Inspect(typeof(TestClass)); } + /// + /// Should be called once per frame. + /// public static void Update() { RuntimeProvider.Instance.Update(); @@ -73,6 +80,8 @@ namespace UnityExplorer UIManager.Update(); } + #region LOGGING + public static void Log(object message) => Log(message, LogType.Log, false); @@ -94,20 +103,22 @@ namespace UnityExplorer case LogType.Assert: case LogType.Log: Loader.OnLogMessage(log); - DebugConsole.Log(log, Color.white); + //DebugConsole.Log(log, Color.white); break; case LogType.Warning: Loader.OnLogWarning(log); - DebugConsole.Log(log, Color.yellow); + //DebugConsole.Log(log, Color.yellow); break; case LogType.Error: case LogType.Exception: Loader.OnLogError(log); - DebugConsole.Log(log, Color.red); + //DebugConsole.Log(log, Color.red); break; } } + + #endregion } } diff --git a/src/UI/CacheObject/CacheConfigEntry.cs b/src/UI/CacheObject/CacheConfigEntry.cs deleted file mode 100644 index ca27b2e..0000000 --- a/src/UI/CacheObject/CacheConfigEntry.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Config; -using UnityExplorer.UI.InteractiveValues; - -namespace UnityExplorer.UI.CacheObject -{ - public class CacheConfigEntry : CacheObjectBase - { - public IConfigElement RefConfig { get; } - - public override Type FallbackType => RefConfig.ElementType; - - public override bool HasEvaluated => true; - public override bool HasParameters => false; - public override bool IsMember => false; - public override bool CanWrite => true; - - public CacheConfigEntry(IConfigElement config, GameObject parent) - { - RefConfig = config; - - m_parentContent = parent; - - config.OnValueChangedNotify += () => { UpdateValue(); }; - - CreateIValue(config.BoxedValue, config.ElementType); - } - - public override void CreateIValue(object value, Type fallbackType) - { - IValue = InteractiveValue.Create(value, fallbackType); - IValue.Owner = this; - IValue.m_mainContentParent = m_mainGroup; - IValue.m_subContentParent = this.m_subContent; - } - - public override void UpdateValue() - { - IValue.Value = RefConfig.BoxedValue; - - base.UpdateValue(); - } - - public override void SetValue() - { - RefConfig.BoxedValue = IValue.Value; - } - - internal GameObject m_mainGroup; - - internal override void ConstructUI() - { - base.ConstructUI(); - - m_mainGroup = UIFactory.CreateVerticalGroup(m_mainContent, "ConfigHolder", true, false, true, true, 5, new Vector4(2, 2, 2, 2)); - - var horiGroup = UIFactory.CreateHorizontalGroup(m_mainGroup, "ConfigEntryHolder", false, false, true, true, childAlignment: TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(horiGroup, minHeight: 30, flexibleHeight: 0); - - // config entry label - - var configLabel = UIFactory.CreateLabel(horiGroup, "ConfigLabel", this.RefConfig.Name, TextAnchor.MiddleLeft); - var leftRect = configLabel.GetComponent(); - leftRect.anchorMin = Vector2.zero; - leftRect.anchorMax = Vector2.one; - leftRect.offsetMin = Vector2.zero; - leftRect.offsetMax = Vector2.zero; - leftRect.sizeDelta = Vector2.zero; - UIFactory.SetLayoutElement(configLabel.gameObject, minWidth: 250, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0); - - // Default button - - var defaultButton = UIFactory.CreateButton(horiGroup, - "RevertDefaultButton", - "Default", - () => { RefConfig.RevertToDefaultValue(); }, - new Color(0.3f, 0.3f, 0.3f)); - UIFactory.SetLayoutElement(defaultButton.gameObject, minWidth: 80, minHeight: 22, flexibleWidth: 0); - - // Description label - - var desc = UIFactory.CreateLabel(m_mainGroup, "Description", $"{RefConfig.Description}", TextAnchor.MiddleLeft, Color.grey); - UIFactory.SetLayoutElement(desc.gameObject, minWidth: 250, minHeight: 20, flexibleWidth: 9999, flexibleHeight: 0); - - // IValue - - if (IValue != null) - { - IValue.m_mainContentParent = m_mainGroup; - IValue.m_subContentParent = this.m_subContent; - } - - // makes the subcontent look nicer - m_subContent.transform.SetParent(m_mainGroup.transform, false); - } - } -} diff --git a/src/UI/CacheObject/CacheEnumerated.cs b/src/UI/CacheObject/CacheEnumerated.cs deleted file mode 100644 index 97fae07..0000000 --- a/src/UI/CacheObject/CacheEnumerated.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityExplorer.UI; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.UI.InteractiveValues; - -namespace UnityExplorer.UI.CacheObject -{ - public class CacheEnumerated : CacheObjectBase - { - public override Type FallbackType => ParentEnumeration.m_baseEntryType; - public override bool CanWrite => RefIList != null && ParentEnumeration.Owner.CanWrite; - - public int Index { get; set; } - public IList RefIList { get; set; } - public InteractiveEnumerable ParentEnumeration { get; set; } - - public CacheEnumerated(int index, InteractiveEnumerable parentEnumeration, IList refIList, GameObject parentContent) - { - this.ParentEnumeration = parentEnumeration; - this.Index = index; - this.RefIList = refIList; - this.m_parentContent = parentContent; - } - - public override void CreateIValue(object value, Type fallbackType) - { - IValue = InteractiveValue.Create(value, fallbackType); - IValue.Owner = this; - } - - public override void SetValue() - { - RefIList[Index] = IValue.Value; - ParentEnumeration.Value = RefIList; - - ParentEnumeration.Owner.SetValue(); - } - - internal override void ConstructUI() - { - base.ConstructUI(); - - var rowObj = UIFactory.CreateHorizontalGroup(m_mainContent, "CacheEnumeratedGroup", false, true, true, true, 0, new Vector4(0,0,5,2), - new Color(1, 1, 1, 0)); - - var indexLabel = UIFactory.CreateLabel(rowObj, "IndexLabel", $"{this.Index}:", TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(indexLabel.gameObject, minWidth: 20, flexibleWidth: 30, minHeight: 25); - - IValue.m_mainContentParent = rowObj; - } - } -} diff --git a/src/UI/CacheObject/CacheField.cs b/src/UI/CacheObject/CacheField.cs deleted file mode 100644 index d3f5160..0000000 --- a/src/UI/CacheObject/CacheField.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Reflection; -using UnityExplorer.UI; -using UnityEngine; - -namespace UnityExplorer.UI.CacheObject -{ - public class CacheField : CacheMember - { - public override bool IsStatic => (MemInfo as FieldInfo).IsStatic; - - public override Type FallbackType => (MemInfo as FieldInfo).FieldType; - - public CacheField(FieldInfo fieldInfo, object declaringInstance, GameObject parent) : base(fieldInfo, declaringInstance, parent) - { - CreateIValue(null, fieldInfo.FieldType); - } - - public override void UpdateReflection() - { - var fi = MemInfo as FieldInfo; - IValue.Value = fi.GetValue(fi.IsStatic ? null : DeclaringInstance); - - m_evaluated = true; - ReflectionException = null; - } - - public override void SetValue() - { - var fi = MemInfo as FieldInfo; - fi.SetValue(fi.IsStatic ? null : DeclaringInstance, IValue.Value); - - if (this.ParentInspector?.ParentMember != null) - this.ParentInspector.ParentMember.SetValue(); - } - } -} diff --git a/src/UI/CacheObject/CacheMember.cs b/src/UI/CacheObject/CacheMember.cs deleted file mode 100644 index df5cbe8..0000000 --- a/src/UI/CacheObject/CacheMember.cs +++ /dev/null @@ -1,383 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.UI; -using UnityExplorer.Core.Unity; -using UnityExplorer.Core.Runtime; -using UnityExplorer.Core; -using UnityExplorer.UI.Utility; -using UnityExplorer.UI.InteractiveValues; -using UnityExplorer.UI.Inspectors.Reflection; - -namespace UnityExplorer.UI.CacheObject -{ - public abstract class CacheMember : CacheObjectBase - { - public override bool IsMember => true; - - public override Type FallbackType { get; } - - public ReflectionInspector ParentInspector { get; set; } - public MemberInfo MemInfo { get; set; } - public Type DeclaringType { get; set; } - public object DeclaringInstance { get; set; } - public virtual bool IsStatic { get; private set; } - - public string ReflectionException { get; set; } - - public override bool CanWrite => m_canWrite ?? GetCanWrite(); - private bool? m_canWrite; - - public override bool HasParameters => ParamCount > 0; - public virtual int ParamCount => m_arguments.Length; - public override bool HasEvaluated => m_evaluated; - public bool m_evaluated = false; - public bool m_isEvaluating; - public ParameterInfo[] m_arguments = new ParameterInfo[0]; - public string[] m_argumentInput = new string[0]; - - public string NameForFiltering => m_nameForFilter ?? (m_nameForFilter = $"{MemInfo.DeclaringType.Name}.{MemInfo.Name}".ToLower()); - private string m_nameForFilter; - - public string RichTextName => m_richTextName ?? GetRichTextName(); - private string m_richTextName; - - public CacheMember(MemberInfo memberInfo, object declaringInstance, GameObject parentContent) - { - MemInfo = memberInfo; - DeclaringType = memberInfo.DeclaringType; - DeclaringInstance = declaringInstance; - this.m_parentContent = parentContent; - - DeclaringInstance = ReflectionProvider.Instance.Cast(declaringInstance, DeclaringType); - } - - public static bool CanProcessArgs(ParameterInfo[] parameters) - { - foreach (var param in parameters) - { - var pType = param.ParameterType; - - if (pType.IsByRef && pType.HasElementType) - pType = pType.GetElementType(); - - if (pType != null && (pType.IsPrimitive || pType == typeof(string))) - continue; - else - return false; - } - return true; - } - - public override void CreateIValue(object value, Type fallbackType) - { - IValue = InteractiveValue.Create(value, fallbackType); - IValue.Owner = this; - IValue.m_mainContentParent = this.m_rightGroup; - IValue.m_subContentParent = this.m_subContent; - } - - public override void UpdateValue() - { - if (!HasParameters || m_isEvaluating) - { - try - { - Type baseType = ReflectionUtility.GetActualType(IValue.Value) ?? FallbackType; - - if (!ReflectionProvider.Instance.IsReflectionSupported(baseType)) - throw new Exception("Type not supported with reflection"); - - UpdateReflection(); - - if (IValue.Value != null) - IValue.Value = IValue.Value.Cast(ReflectionUtility.GetActualType(IValue.Value)); - } - catch (Exception e) - { - ReflectionException = e.ReflectionExToString(true); - } - } - - base.UpdateValue(); - } - - public abstract void UpdateReflection(); - - public override void SetValue() - { - // no implementation for base class - } - - public object[] ParseArguments() - { - if (m_arguments.Length < 1) - return new object[0]; - - var parsedArgs = new List(); - for (int i = 0; i < m_arguments.Length; i++) - { - var input = m_argumentInput[i]; - var type = m_arguments[i].ParameterType; - - if (type.IsByRef) - type = type.GetElementType(); - - if (!string.IsNullOrEmpty(input)) - { - if (type == typeof(string)) - { - parsedArgs.Add(input); - continue; - } - else - { - try - { - var arg = type.GetMethod("Parse", new Type[] { typeof(string) }) - .Invoke(null, new object[] { input }); - - parsedArgs.Add(arg); - continue; - } - catch - { - ExplorerCore.Log($"Could not parse input '{input}' for argument #{i} '{m_arguments[i].Name}' ({type.FullName})"); - } - } - } - - // No input, see if there is a default value. - if (m_arguments[i].IsOptional) - { - parsedArgs.Add(m_arguments[i].DefaultValue); - continue; - } - - // Try add a null arg I guess - parsedArgs.Add(null); - } - - return parsedArgs.ToArray(); - } - - private bool GetCanWrite() - { - if (MemInfo is FieldInfo fi) - m_canWrite = !(fi.IsLiteral && !fi.IsInitOnly); - else if (MemInfo is PropertyInfo pi) - m_canWrite = pi.CanWrite; - else - m_canWrite = false; - - return (bool)m_canWrite; - } - - private string GetRichTextName() - { - return m_richTextName = SignatureHighlighter.ParseFullSyntax(MemInfo.DeclaringType, false, MemInfo); - } - - #region UI - - internal float GetMemberLabelWidth(RectTransform scrollRect) - { - var textGenSettings = m_memLabelText.GetGenerationSettings(m_topRowRect.rect.size); - textGenSettings.scaleFactor = InputFieldScroller.canvasScaler.scaleFactor; - - var textGen = m_memLabelText.cachedTextGeneratorForLayout; - float preferredWidth = textGen.GetPreferredWidth(RichTextName, textGenSettings); - - float max = scrollRect.rect.width * 0.4f; - - if (preferredWidth > max) preferredWidth = max; - - return preferredWidth < 125f ? 125f : preferredWidth; - } - - internal void SetWidths(float labelWidth, float valueWidth) - { - m_leftLayout.preferredWidth = labelWidth; - m_rightLayout.preferredWidth = valueWidth; - } - - internal RectTransform m_topRowRect; - internal Text m_memLabelText; - internal GameObject m_leftGroup; - internal LayoutElement m_leftLayout; - internal GameObject m_rightGroup; - internal LayoutElement m_rightLayout; - - internal override void ConstructUI() - { - base.ConstructUI(); - - var topGroupObj = UIFactory.CreateHorizontalGroup(m_mainContent, "CacheMemberGroup", false, false, true, true, 10, new Vector4(0, 0, 3, 3), - new Color(1, 1, 1, 0)); - - m_topRowRect = topGroupObj.GetComponent(); - - UIFactory.SetLayoutElement(topGroupObj, minHeight: 25, flexibleHeight: 0, minWidth: 300, flexibleWidth: 5000); - - // left group - - m_leftGroup = UIFactory.CreateHorizontalGroup(topGroupObj, "LeftGroup", false, true, true, true, 4, default, new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(m_leftGroup, minHeight: 25, flexibleHeight: 0, minWidth: 125, flexibleWidth: 200); - - // member label - - m_memLabelText = UIFactory.CreateLabel(m_leftGroup, "MemLabelText", RichTextName, TextAnchor.MiddleLeft); - m_memLabelText.horizontalOverflow = HorizontalWrapMode.Wrap; - var leftRect = m_memLabelText.GetComponent(); - leftRect.anchorMin = Vector2.zero; - leftRect.anchorMax = Vector2.one; - leftRect.offsetMin = Vector2.zero; - leftRect.offsetMax = Vector2.zero; - leftRect.sizeDelta = Vector2.zero; - m_leftLayout = m_memLabelText.gameObject.AddComponent(); - m_leftLayout.preferredWidth = 125; - m_leftLayout.minHeight = 25; - m_leftLayout.flexibleHeight = 100; - var labelFitter = m_memLabelText.gameObject.AddComponent(); - labelFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; - labelFitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize; - - // right group - - m_rightGroup = UIFactory.CreateVerticalGroup(topGroupObj, "RightGroup", false, true, true, true, 2, new Vector4(4,2,0,0), - new Color(1, 1, 1, 0)); - - m_rightLayout = m_rightGroup.AddComponent(); - m_rightLayout.minHeight = 25; - m_rightLayout.flexibleHeight = 480; - m_rightLayout.minWidth = 125; - m_rightLayout.flexibleWidth = 5000; - - ConstructArgInput(out GameObject argsHolder); - - ConstructEvaluateButtons(argsHolder); - - IValue.m_mainContentParent = m_rightGroup; - } - - internal void ConstructArgInput(out GameObject argsHolder) - { - argsHolder = null; - - if (HasParameters) - { - argsHolder = UIFactory.CreateVerticalGroup(m_rightGroup, "ArgsHolder", true, false, true, true, 4, new Color(1, 1, 1, 0)); - - if (this is CacheMethod cm && cm.GenericArgs.Length > 0) - cm.ConstructGenericArgInput(argsHolder); - - if (m_arguments.Length > 0) - { - UIFactory.CreateLabel(argsHolder, "ArgumentsLabel", "Arguments:", TextAnchor.MiddleLeft); - - for (int i = 0; i < m_arguments.Length; i++) - AddArgRow(i, argsHolder); - } - - argsHolder.SetActive(false); - } - } - - internal void AddArgRow(int i, GameObject parent) - { - var arg = m_arguments[i]; - - var rowObj = UIFactory.CreateHorizontalGroup(parent, "ArgRow", true, false, true, true, 4, default, new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleWidth: 5000); - - var argTypeTxt = SignatureHighlighter.ParseFullSyntax(arg.ParameterType, false); - var argLabel = UIFactory.CreateLabel(rowObj, "ArgLabel", $"{argTypeTxt} {arg.Name}", - TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(argLabel.gameObject, minHeight: 25); - - var argInputObj = UIFactory.CreateInputField(rowObj, "ArgInput", "...", 14, (int)TextAnchor.MiddleLeft, 1); - UIFactory.SetLayoutElement(argInputObj, flexibleWidth: 1200, preferredWidth: 150, minWidth: 20, minHeight: 25, flexibleHeight: 0); - - var argInput = argInputObj.GetComponent(); - argInput.onValueChanged.AddListener((string val) => { m_argumentInput[i] = val; }); - - if (arg.IsOptional) - { - var phInput = argInput.placeholder.GetComponent(); - phInput.text = " = " + arg.DefaultValue?.ToString() ?? "null"; - } - } - - internal void ConstructEvaluateButtons(GameObject argsHolder) - { - if (HasParameters) - { - var evalGroupObj = UIFactory.CreateHorizontalGroup(m_rightGroup, "EvalGroup", false, false, true, true, 5, - default, new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(evalGroupObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 5000); - - var evalButton = UIFactory.CreateButton(evalGroupObj, - "EvalButton", - $"Evaluate ({ParamCount})", - null); - - RuntimeProvider.Instance.SetColorBlock(evalButton, new Color(0.4f, 0.4f, 0.4f), - new Color(0.4f, 0.7f, 0.4f), new Color(0.3f, 0.3f, 0.3f)); - - UIFactory.SetLayoutElement(evalButton.gameObject, minWidth: 100, minHeight: 22, flexibleWidth: 0); - - var evalText = evalButton.GetComponentInChildren(); - - var cancelButton = UIFactory.CreateButton(evalGroupObj, "CancelButton", "Close", null, new Color(0.3f, 0.3f, 0.3f)); - UIFactory.SetLayoutElement(cancelButton.gameObject, minWidth: 100, minHeight: 22, flexibleWidth: 0); - - cancelButton.gameObject.SetActive(false); - - evalButton.onClick.AddListener(() => - { - if (!m_isEvaluating) - { - argsHolder.SetActive(true); - m_isEvaluating = true; - evalText.text = "Evaluate"; - RuntimeProvider.Instance.SetColorBlock(evalButton, new Color(0.3f, 0.6f, 0.3f)); - - cancelButton.gameObject.SetActive(true); - } - else - { - if (this is CacheMethod cm) - cm.Evaluate(); - else - UpdateValue(); - } - }); - - cancelButton.onClick.AddListener(() => - { - cancelButton.gameObject.SetActive(false); - argsHolder.SetActive(false); - m_isEvaluating = false; - - evalText.text = $"Evaluate ({ParamCount})"; - RuntimeProvider.Instance.SetColorBlock(evalButton, new Color(0.4f, 0.4f, 0.4f)); - }); - } - else if (this is CacheMethod) - { - // simple method evaluate button - - var evalButton = UIFactory.CreateButton(m_rightGroup, "EvalButton", "Evaluate", () => { (this as CacheMethod).Evaluate(); }); - RuntimeProvider.Instance.SetColorBlock(evalButton, new Color(0.4f, 0.4f, 0.4f), - new Color(0.4f, 0.7f, 0.4f), new Color(0.3f, 0.3f, 0.3f)); - - UIFactory.SetLayoutElement(evalButton.gameObject, minWidth: 100, minHeight: 22, flexibleWidth: 0); - } - } - - #endregion - } -} diff --git a/src/UI/CacheObject/CacheMethod.cs b/src/UI/CacheObject/CacheMethod.cs deleted file mode 100644 index e34d3f6..0000000 --- a/src/UI/CacheObject/CacheMethod.cs +++ /dev/null @@ -1,173 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.UI; -using UnityExplorer.Core.Unity; -using UnityExplorer.Core; -using UnityExplorer.UI.Utility; - -namespace UnityExplorer.UI.CacheObject -{ - public class CacheMethod : CacheMember - { - //private CacheObjectBase m_cachedReturnValue; - - public override Type FallbackType => (MemInfo as MethodInfo).ReturnType; - - public override bool HasParameters => base.HasParameters || GenericArgs.Length > 0; - - public override bool IsStatic => (MemInfo as MethodInfo).IsStatic; - - public override int ParamCount => base.ParamCount + m_genericArgInput.Length; - - public Type[] GenericArgs { get; private set; } - public Type[][] GenericConstraints { get; private set; } - - public string[] m_genericArgInput = new string[0]; - - public CacheMethod(MethodInfo methodInfo, object declaringInstance, GameObject parent) : base(methodInfo, declaringInstance, parent) - { - GenericArgs = methodInfo.GetGenericArguments(); - - GenericConstraints = GenericArgs.Select(x => x.GetGenericParameterConstraints()) - .Where(x => x != null) - .ToArray(); - - m_genericArgInput = new string[GenericArgs.Length]; - - m_arguments = methodInfo.GetParameters(); - m_argumentInput = new string[m_arguments.Length]; - - CreateIValue(null, methodInfo.ReturnType); - } - - public override void UpdateReflection() - { - // CacheMethod cannot UpdateValue directly. Need to Evaluate. - } - - public void Evaluate() - { - MethodInfo mi; - if (GenericArgs.Length > 0) - { - mi = MakeGenericMethodFromInput(); - if (mi == null) return; - } - else - { - mi = MemInfo as MethodInfo; - } - - object ret = null; - - try - { - ret = mi.Invoke(mi.IsStatic ? null : DeclaringInstance, ParseArguments()); - m_evaluated = true; - m_isEvaluating = false; - ReflectionException = null; - } - catch (Exception e) - { - while (e.InnerException != null) - e = e.InnerException; - - ExplorerCore.LogWarning($"Exception evaluating: {e.GetType()}, {e.Message}"); - ReflectionException = ReflectionUtility.ReflectionExToString(e); - } - - IValue.Value = ret; - UpdateValue(); - } - - private MethodInfo MakeGenericMethodFromInput() - { - var mi = MemInfo as MethodInfo; - - var list = new List(); - for (int i = 0; i < GenericArgs.Length; i++) - { - var input = m_genericArgInput[i]; - if (ReflectionUtility.GetTypeByName(input) is Type t) - { - if (GenericConstraints[i].Length == 0) - { - list.Add(t); - } - else - { - foreach (var constraint in GenericConstraints[i].Where(x => x != null)) - { - if (!constraint.IsAssignableFrom(t)) - { - ExplorerCore.LogWarning($"Generic argument #{i}, '{input}' is not assignable from the constraint '{constraint}'!"); - return null; - } - } - - list.Add(t); - } - } - else - { - ExplorerCore.LogWarning($"Generic argument #{i}, could not get any type by the name of '{input}'!" + - $" Make sure you use the full name including the namespace."); - return null; - } - } - - // make into a generic with type list - mi = mi.MakeGenericMethod(list.ToArray()); - - return mi; - } - - #region UI CONSTRUCTION - - internal void ConstructGenericArgInput(GameObject parent) - { - UIFactory.CreateLabel(parent, "GenericArgLabel", "Generic Arguments:", TextAnchor.MiddleLeft); - - for (int i = 0; i < GenericArgs.Length; i++) - AddGenericArgRow(i, parent); - } - - internal void AddGenericArgRow(int i, GameObject parent) - { - var arg = GenericArgs[i]; - - string constrainTxt = ""; - if (this.GenericConstraints[i].Length > 0) - { - foreach (var constraint in this.GenericConstraints[i]) - { - if (constrainTxt != "") - constrainTxt += ", "; - - constrainTxt += $"{SignatureHighlighter.ParseFullSyntax(constraint, false)}"; - } - } - else - constrainTxt = $"Any"; - - var rowObj = UIFactory.CreateHorizontalGroup(parent, "ArgRowObj", false, true, true, true, 4, default, new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleWidth: 5000); - - var argLabelObj = UIFactory.CreateLabel(rowObj, "ArgLabelObj", $"{constrainTxt} {arg.Name}", - TextAnchor.MiddleLeft); - - var argInputObj = UIFactory.CreateInputField(rowObj, "ArgInput", "...", 14, (int)TextAnchor.MiddleLeft, 1); - UIFactory.SetLayoutElement(argInputObj, flexibleWidth: 1200); - - var argInput = argInputObj.GetComponent(); - argInput.onValueChanged.AddListener((string val) => { m_genericArgInput[i] = val; }); - - } - - #endregion - } -} diff --git a/src/UI/CacheObject/CacheObjectBase.cs b/src/UI/CacheObject/CacheObjectBase.cs deleted file mode 100644 index b9516c7..0000000 --- a/src/UI/CacheObject/CacheObjectBase.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using UnityEngine; -using UnityExplorer.UI; -using UnityExplorer.Core.Unity; -using UnityEngine.UI; -using UnityExplorer.Core; -using UnityExplorer.UI.InteractiveValues; - -namespace UnityExplorer.UI.CacheObject -{ - public abstract class CacheObjectBase - { - public InteractiveValue IValue; - - public virtual bool CanWrite => false; - public virtual bool HasParameters => false; - public virtual bool IsMember => false; - public virtual bool HasEvaluated => true; - - public abstract Type FallbackType { get; } - - public abstract void CreateIValue(object value, Type fallbackType); - - public virtual void Enable() - { - if (!m_constructedUI) - { - ConstructUI(); - UpdateValue(); - } - - m_mainContent.SetActive(true); - m_mainContent.transform.SetAsLastSibling(); - } - - public virtual void Disable() - { - if (m_mainContent) - m_mainContent.SetActive(false); - } - - public void Destroy() - { - if (this.m_mainContent) - GameObject.Destroy(this.m_mainContent); - } - - public virtual void UpdateValue() - { - var value = IValue.Value; - - // if the type has changed fundamentally, make a new interactivevalue for it - var type = value == null - ? FallbackType - : ReflectionUtility.GetActualType(value); - - var ivalueType = InteractiveValue.GetIValueForType(type); - - if (ivalueType != IValue.GetType()) - { - IValue.OnDestroy(); - CreateIValue(value, FallbackType); - m_subContent.SetActive(false); - } - - IValue.OnValueUpdated(); - - IValue.RefreshElementsAfterUpdate(); - } - - public virtual void SetValue() => throw new NotImplementedException(); - - #region UI CONSTRUCTION - - internal bool m_constructedUI; - internal GameObject m_parentContent; - internal RectTransform m_mainRect; - internal GameObject m_mainContent; - internal GameObject m_subContent; - - // Make base UI holder for CacheObject, this doesnt actually display anything. - internal virtual void ConstructUI() - { - m_constructedUI = true; - - m_mainContent = UIFactory.CreateVerticalGroup(m_parentContent, "CacheObjectBase.MainContent", true, true, true, true, 0, default, - new Color(0.1f, 0.1f, 0.1f)); - m_mainRect = m_mainContent.GetComponent(); - m_mainRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 25); - - UIFactory.SetLayoutElement(m_mainContent, minHeight: 25, flexibleHeight: 9999, minWidth: 200, flexibleWidth: 5000); - - // subcontent - - m_subContent = UIFactory.CreateVerticalGroup(m_mainContent, "CacheObjectBase.SubContent", true, false, true, true, 0, default, - new Color(0.085f, 0.085f, 0.085f)); - UIFactory.SetLayoutElement(m_subContent, minHeight: 30, flexibleHeight: 9999, minWidth: 125, flexibleWidth: 9000); - - m_subContent.SetActive(false); - - IValue.m_subContentParent = m_subContent; - } - - #endregion - - } -} diff --git a/src/UI/CacheObject/CachePaired.cs b/src/UI/CacheObject/CachePaired.cs deleted file mode 100644 index ec508df..0000000 --- a/src/UI/CacheObject/CachePaired.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityExplorer.UI; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.UI.InteractiveValues; - -namespace UnityExplorer.UI.CacheObject -{ - public enum PairTypes - { - Key, - Value - } - - public class CachePaired : CacheObjectBase - { - public override Type FallbackType => PairType == PairTypes.Key - ? ParentDictionary.m_typeOfKeys - : ParentDictionary.m_typeofValues; - - public override bool CanWrite => false; // todo? - - public PairTypes PairType; - public int Index { get; private set; } - public InteractiveDictionary ParentDictionary { get; private set; } - internal IDictionary RefIDict; - - public CachePaired(int index, InteractiveDictionary parentDict, IDictionary refIDict, PairTypes pairType, GameObject parentContent) - { - Index = index; - ParentDictionary = parentDict; - RefIDict = refIDict; - this.PairType = pairType; - this.m_parentContent = parentContent; - } - - public override void CreateIValue(object value, Type fallbackType) - { - IValue = InteractiveValue.Create(value, fallbackType); - IValue.Owner = this; - } - - #region UI CONSTRUCTION - - internal override void ConstructUI() - { - base.ConstructUI(); - - Color bgColor = this.PairType == PairTypes.Key - ? new Color(0.07f, 0.07f, 0.07f) - : new Color(0.1f, 0.1f, 0.1f); - - var rowObj = UIFactory.CreateHorizontalGroup(m_mainContent, "PairedGroup", false, false, true, true, 0, new Vector4(0,0,5,2), - bgColor); - - string lbl = $"{this.PairType}"; - if (this.PairType == PairTypes.Key) - lbl = $"[{Index}] {lbl}"; - - var indexLabel = UIFactory.CreateLabel(rowObj, "IndexLabel", lbl, TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(indexLabel.gameObject, minWidth: 80, flexibleWidth: 30, minHeight: 25); - - IValue.m_mainContentParent = rowObj; - } - - #endregion - } -} diff --git a/src/UI/CacheObject/CacheProperty.cs b/src/UI/CacheObject/CacheProperty.cs deleted file mode 100644 index 5e3620b..0000000 --- a/src/UI/CacheObject/CacheProperty.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Reflection; -using UnityExplorer.UI; -using UnityExplorer.Core.Unity; -using UnityEngine; - -namespace UnityExplorer.UI.CacheObject -{ - public class CacheProperty : CacheMember - { - public override Type FallbackType => (MemInfo as PropertyInfo).PropertyType; - - public override bool IsStatic => (MemInfo as PropertyInfo).GetAccessors(true)[0].IsStatic; - - public CacheProperty(PropertyInfo propertyInfo, object declaringInstance, GameObject parent) : base(propertyInfo, declaringInstance, parent) - { - this.m_arguments = propertyInfo.GetIndexParameters(); - this.m_argumentInput = new string[m_arguments.Length]; - - CreateIValue(null, propertyInfo.PropertyType); - } - - public override void UpdateReflection() - { - if (HasParameters && !m_isEvaluating) - { - // Need to enter parameters first. - return; - } - - var pi = MemInfo as PropertyInfo; - - if (pi.CanRead) - { - var target = pi.GetAccessors(true)[0].IsStatic ? null : DeclaringInstance; - - IValue.Value = pi.GetValue(target, ParseArguments()); - - m_evaluated = true; - ReflectionException = null; - } - else - { - if (FallbackType == typeof(string)) - { - IValue.Value = ""; - } - else if (FallbackType.IsPrimitive) - { - IValue.Value = Activator.CreateInstance(FallbackType); - } - m_evaluated = true; - ReflectionException = null; - } - } - - public override void SetValue() - { - var pi = MemInfo as PropertyInfo; - var target = pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance; - - pi.SetValue(target, IValue.Value, ParseArguments()); - - if (this.ParentInspector?.ParentMember != null) - this.ParentInspector.ParentMember.SetValue(); - } - } -} diff --git a/src/UI/InspectorManager.cs b/src/UI/InspectorManager.cs new file mode 100644 index 0000000..9672332 --- /dev/null +++ b/src/UI/InspectorManager.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace UnityExplorer.UI +{ + public static class InspectorManager + { + // internal static readonly List InspectedObjects; + + public static void Inspect(this object obj) + => throw new NotImplementedException("TODO"); + + + } +} diff --git a/src/UI/Inspectors/GameObjects/ChildList.cs b/src/UI/Inspectors/GameObjects/ChildList.cs deleted file mode 100644 index 28b7276..0000000 --- a/src/UI/Inspectors/GameObjects/ChildList.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Runtime; -using UnityExplorer.UI.Utility; - -namespace UnityExplorer.UI.Inspectors.GameObjects -{ - public class ChildList - { - internal static ChildList Instance; - - public ChildList() - { - Instance = this; - } - - public static PageHandler s_childListPageHandler; - private static GameObject s_childListContent; - - private static GameObject[] s_allChildren = new GameObject[0]; - private static readonly List s_childrenShortlist = new List(); - private static int s_lastChildCount; - - private static readonly List s_childListTexts = new List(); - private static readonly List s_childListToggles = new List(); - - internal void RefreshChildObjectList() - { - var go = GameObjectInspector.ActiveInstance.TargetGO; - - s_allChildren = new GameObject[go.transform.childCount]; - for (int i = 0; i < go.transform.childCount; i++) - { - var child = go.transform.GetChild(i); - s_allChildren[i] = child.gameObject; - } - - var objects = s_allChildren; - s_childListPageHandler.ListCount = objects.Length; - - int newCount = 0; - - foreach (var itemIndex in s_childListPageHandler) - { - newCount++; - - // normalized index starting from 0 - var i = itemIndex - s_childListPageHandler.StartIndex; - - if (itemIndex >= objects.Length) - { - if (i > s_lastChildCount || i >= s_childListTexts.Count) - break; - - GameObject label = s_childListTexts[i].transform.parent.parent.gameObject; - if (label.activeSelf) - label.SetActive(false); - } - else - { - GameObject obj = objects[itemIndex]; - - if (!obj) - continue; - - if (i >= s_childrenShortlist.Count) - { - s_childrenShortlist.Add(obj); - AddChildListButton(); - } - else - { - s_childrenShortlist[i] = obj; - } - - var text = s_childListTexts[i]; - - var name = obj.name; - - if (obj.transform.childCount > 0) - name = $"[{obj.transform.childCount}] {name}"; - - text.text = name; - text.color = obj.activeSelf ? Color.green : Color.red; - - var tog = s_childListToggles[i]; - tog.isOn = obj.activeSelf; - - var label = text.transform.parent.parent.gameObject; - if (!label.activeSelf) - { - label.SetActive(true); - } - } - } - - s_lastChildCount = newCount; - } - - internal static void OnChildListObjectClicked(int index) - { - if (GameObjectInspector.ActiveInstance == null) - return; - - if (index >= s_childrenShortlist.Count || !s_childrenShortlist[index]) - return; - - GameObjectInspector.ActiveInstance.ChangeInspectorTarget(s_childrenShortlist[index]); - GameObjectInspector.ActiveInstance.Update(); - } - - internal static void OnChildListPageTurn() - { - if (Instance == null) - return; - - Instance.RefreshChildObjectList(); - } - - internal static void OnToggleClicked(int index, bool newVal) - { - if (GameObjectInspector.ActiveInstance == null) - return; - - if (index >= s_childrenShortlist.Count || !s_childrenShortlist[index]) - return; - - var obj = s_childrenShortlist[index]; - obj.SetActive(newVal); - } - - #region UI CONSTRUCTION - - internal void ConstructChildList(GameObject parent) - { - var vertGroupObj = UIFactory.CreateVerticalGroup(parent, "ChildListGroup", false, true, true, true, 5, default, new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(vertGroupObj, minWidth: 120, flexibleWidth: 25000, minHeight: 200, flexibleHeight: 5000); - - var childTitle = UIFactory.CreateLabel(vertGroupObj, "ChildListTitle", "Children:", TextAnchor.MiddleLeft, Color.grey, true, 14); - UIFactory.SetLayoutElement(childTitle.gameObject, minHeight: 30); - - var childrenScrollObj = UIFactory.CreateScrollView(vertGroupObj, "ChildListScrollView", out s_childListContent, - out SliderScrollbar scroller, new Color(0.07f, 0.07f, 0.07f)); - UIFactory.SetLayoutElement(childrenScrollObj, minHeight: 50); - - s_childListPageHandler = new PageHandler(scroller); - s_childListPageHandler.ConstructUI(vertGroupObj); - s_childListPageHandler.OnPageChanged += OnChildListPageTurn; - } - - internal void AddChildListButton() - { - int thisIndex = s_childListTexts.Count; - - var btnGroupObj = UIFactory.CreateHorizontalGroup(s_childListContent, "ChildButtonGroup", true, false, true, true, - 0, default, new Color(0.07f, 0.07f, 0.07f)); - UIFactory.SetLayoutElement(btnGroupObj, flexibleWidth: 320, minHeight: 25, flexibleHeight: 0); - btnGroupObj.AddComponent(); - - var toggleObj = UIFactory.CreateToggle(btnGroupObj, "Toggle", out Toggle toggle, out Text toggleText, new Color(0.3f, 0.3f, 0.3f)); - UIFactory.SetLayoutElement(toggleObj, minHeight: 25, minWidth: 25); - toggleText.text = ""; - toggle.isOn = false; - s_childListToggles.Add(toggle); - toggle.onValueChanged.AddListener((bool val) => { OnToggleClicked(thisIndex, val); }); - - var mainBtn = UIFactory.CreateButton(btnGroupObj, - "MainButton", - "", - () => { OnChildListObjectClicked(thisIndex); }); - - RuntimeProvider.Instance.SetColorBlock(mainBtn, new Color(0.07f, 0.07f, 0.07f), - new Color(0.2f, 0.2f, 0.2f, 1), new Color(0.05f, 0.05f, 0.05f)); - - UIFactory.SetLayoutElement(mainBtn.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 25, flexibleWidth: 9999); - - Text mainText = mainBtn.GetComponentInChildren(); - mainText.alignment = TextAnchor.MiddleLeft; - mainText.horizontalOverflow = HorizontalWrapMode.Overflow; - mainText.resizeTextForBestFit = true; - mainText.resizeTextMaxSize = 14; - mainText.resizeTextMinSize = 10; - - s_childListTexts.Add(mainText); - } - - #endregion - } -} diff --git a/src/UI/Inspectors/GameObjects/ComponentList.cs b/src/UI/Inspectors/GameObjects/ComponentList.cs deleted file mode 100644 index 869a66a..0000000 --- a/src/UI/Inspectors/GameObjects/ComponentList.cs +++ /dev/null @@ -1,192 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core; -using UnityExplorer.Core.Runtime; -using UnityExplorer.UI.Utility; - -namespace UnityExplorer.UI.Inspectors.GameObjects -{ - public class ComponentList - { - internal static ComponentList Instance; - - public ComponentList() - { - Instance = this; - } - - public static PageHandler s_compListPageHandler; - private static Component[] s_allComps = new Component[0]; - private static readonly List s_compShortlist = new List(); - private static GameObject s_compListContent; - private static readonly List s_compListTexts = new List(); - private static int s_lastCompCount; - public static readonly List s_compToggles = new List(); - - internal void RefreshComponentList() - { - var go = GameObjectInspector.ActiveInstance.TargetGO; - - s_allComps = go.GetComponents().ToArray(); - - var components = s_allComps; - s_compListPageHandler.ListCount = components.Length; - - //int startIndex = m_sceneListPageHandler.StartIndex; - - int newCount = 0; - - foreach (var itemIndex in s_compListPageHandler) - { - newCount++; - - // normalized index starting from 0 - var i = itemIndex - s_compListPageHandler.StartIndex; - - if (itemIndex >= components.Length) - { - if (i > s_lastCompCount || i >= s_compListTexts.Count) - break; - - GameObject label = s_compListTexts[i].transform.parent.parent.gameObject; - if (label.activeSelf) - label.SetActive(false); - } - else - { - Component comp = components[itemIndex]; - - if (!comp) - continue; - - if (i >= s_compShortlist.Count) - { - s_compShortlist.Add(comp); - AddCompListButton(); - } - else - { - s_compShortlist[i] = comp; - } - - var text = s_compListTexts[i]; - - text.text = SignatureHighlighter.ParseFullSyntax(ReflectionUtility.GetActualType(comp), true); - - var toggle = s_compToggles[i]; - if (comp.TryCast() is Behaviour behaviour) - { - if (!toggle.gameObject.activeSelf) - toggle.gameObject.SetActive(true); - - toggle.isOn = behaviour.enabled; - } - else - { - if (toggle.gameObject.activeSelf) - toggle.gameObject.SetActive(false); - } - - var label = text.transform.parent.parent.gameObject; - if (!label.activeSelf) - { - label.SetActive(true); - } - } - } - - s_lastCompCount = newCount; - } - - internal static void OnCompToggleClicked(int index, bool value) - { - var comp = s_compShortlist[index]; - comp.TryCast().enabled = value; - } - - internal static void OnCompListObjectClicked(int index) - { - if (index >= s_compShortlist.Count || !s_compShortlist[index]) - return; - - InspectorManager.Instance.Inspect(s_compShortlist[index]); - } - - internal static void OnCompListPageTurn() - { - if (Instance == null) - return; - - Instance.RefreshComponentList(); - } - - - #region UI CONSTRUCTION - - internal void ConstructCompList(GameObject parent) - { - var vertGroupObj = UIFactory.CreateVerticalGroup(parent, "ComponentList", false, true, true, true, 5, default, new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(vertGroupObj, minWidth: 120, flexibleWidth: 25000, minHeight: 200, flexibleHeight: 5000); - - var compTitle = UIFactory.CreateLabel(vertGroupObj, "ComponentsTitle", "Components:", TextAnchor.MiddleLeft, Color.grey); - UIFactory.SetLayoutElement(compTitle.gameObject, minHeight: 30); - - var compScrollObj = UIFactory.CreateScrollView(vertGroupObj, "ComponentListScrollView", out s_compListContent, - out SliderScrollbar scroller, new Color(0.07f, 0.07f, 0.07f)); - - UIFactory.SetLayoutElement(compScrollObj, minHeight: 50, flexibleHeight: 5000); - - s_compListPageHandler = new PageHandler(scroller); - s_compListPageHandler.ConstructUI(vertGroupObj); - s_compListPageHandler.OnPageChanged += OnCompListPageTurn; - } - - internal void AddCompListButton() - { - int thisIndex = s_compListTexts.Count; - - GameObject groupObj = UIFactory.CreateHorizontalGroup(s_compListContent, "CompListButton", true, false, true, true, 0, default, - new Color(0.07f, 0.07f, 0.07f), TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(groupObj, minWidth: 25, flexibleWidth: 999, minHeight: 25, flexibleHeight: 0); - groupObj.AddComponent(); - - // Behaviour enabled toggle - - var toggleObj = UIFactory.CreateToggle(groupObj, "EnabledToggle", out Toggle toggle, out Text toggleText, new Color(0.3f, 0.3f, 0.3f)); - UIFactory.SetLayoutElement(toggleObj, minWidth: 25, minHeight: 25); - toggleText.text = ""; - toggle.isOn = true; - s_compToggles.Add(toggle); - toggle.onValueChanged.AddListener((bool val) => { OnCompToggleClicked(thisIndex, val); }); - - // Main component button - - var mainBtn = UIFactory.CreateButton(groupObj, - "MainButton", - "", - () => { OnCompListObjectClicked(thisIndex); }); - - RuntimeProvider.Instance.SetColorBlock(mainBtn, new Color(0.07f, 0.07f, 0.07f), - new Color(0.2f, 0.2f, 0.2f, 1), new Color(0.05f, 0.05f, 0.05f)); - - UIFactory.SetLayoutElement(mainBtn.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 25, flexibleWidth: 999); - - // Component button text - - Text mainText = mainBtn.GetComponentInChildren(); - mainText.alignment = TextAnchor.MiddleLeft; - mainText.horizontalOverflow = HorizontalWrapMode.Overflow; - mainText.resizeTextForBestFit = true; - mainText.resizeTextMaxSize = 14; - mainText.resizeTextMinSize = 8; - - s_compListTexts.Add(mainText); - } - - #endregion - } -} diff --git a/src/UI/Inspectors/GameObjects/GameObjectControls.cs b/src/UI/Inspectors/GameObjects/GameObjectControls.cs deleted file mode 100644 index bd9bc66..0000000 --- a/src/UI/Inspectors/GameObjects/GameObjectControls.cs +++ /dev/null @@ -1,468 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Input; -using UnityExplorer.Core.Runtime; -using UnityExplorer.Core.Unity; - -namespace UnityExplorer.UI.Inspectors.GameObjects -{ - public class GameObjectControls - { - internal static GameObjectControls Instance; - - public GameObjectControls() - { - Instance = this; - } - - internal static bool Showing; - - internal static void ToggleVisibility() => SetVisibility(!Showing); - - internal static void SetVisibility(bool show) - { - if (show == Showing) - return; - - Showing = show; - - m_hideShowLabel.text = show ? "Hide" : "Show"; - m_contentObj.SetActive(show); - } - - internal static GameObject m_contentObj; - internal static Text m_hideShowLabel; - - private static InputField s_setParentInput; - - private static ControlEditor s_positionControl; - private static ControlEditor s_localPosControl; - private static ControlEditor s_rotationControl; - private static ControlEditor s_scaleControl; - - // Transform Vector editors - - internal struct ControlEditor - { - public InputField fullValue; - public Slider[] sliders; - public InputField[] inputs; - public Text[] values; - } - - internal static bool s_sliderChangedWanted; - private static Slider s_currentSlider; - private static ControlType s_currentSliderType; - private static VectorValue s_currentSliderValueType; - private static float s_currentSliderValue; - - internal enum ControlType - { - position, - localPosition, - eulerAngles, - localScale - } - - internal enum VectorValue - { - x, y, z - }; - - internal void RefreshControls() - { - var go = GameObjectInspector.ActiveInstance.TargetGO; - - s_positionControl.fullValue.text = go.transform.position.ToStringPretty(); - s_positionControl.values[0].text = go.transform.position.x.ToString("F3"); - s_positionControl.values[1].text = go.transform.position.y.ToString("F3"); - s_positionControl.values[2].text = go.transform.position.z.ToString("F3"); - - s_localPosControl.fullValue.text = go.transform.localPosition.ToStringPretty(); - s_localPosControl.values[0].text = go.transform.localPosition.x.ToString("F3"); - s_localPosControl.values[1].text = go.transform.localPosition.y.ToString("F3"); - s_localPosControl.values[2].text = go.transform.localPosition.z.ToString("F3"); - - s_rotationControl.fullValue.text = go.transform.eulerAngles.ToStringPretty(); - s_rotationControl.values[0].text = go.transform.eulerAngles.x.ToString("F3"); - s_rotationControl.values[1].text = go.transform.eulerAngles.y.ToString("F3"); - s_rotationControl.values[2].text = go.transform.eulerAngles.z.ToString("F3"); - - s_scaleControl.fullValue.text = go.transform.localScale.ToStringPretty(); - s_scaleControl.values[0].text = go.transform.localScale.x.ToString("F3"); - s_scaleControl.values[1].text = go.transform.localScale.y.ToString("F3"); - s_scaleControl.values[2].text = go.transform.localScale.z.ToString("F3"); - - } - - internal static void OnSetParentClicked() - { - var go = GameObjectInspector.ActiveInstance.TargetGO; - - if (!go) - return; - - var input = s_setParentInput.text; - - if (string.IsNullOrEmpty(input)) - { - go.transform.parent = null; - } - else - { - if (GameObject.Find(input) is GameObject newParent) - { - go.transform.parent = newParent.transform; - } - else - { - ExplorerCore.Log($"Could not find any GameObject from name or path '{input}'! Note: The target must be enabled."); - } - } - } - - internal static void OnSliderControlChanged(float value, Slider slider, ControlType controlType, VectorValue vectorValue) - { - if (value == 0) - s_sliderChangedWanted = false; - else - { - if (!s_sliderChangedWanted) - { - s_sliderChangedWanted = true; - s_currentSlider = slider; - s_currentSliderType = controlType; - s_currentSliderValueType = vectorValue; - } - - s_currentSliderValue = value; - } - } - - internal static void UpdateSliderControl() - { - if (!InputManager.GetMouseButton(0)) - { - s_sliderChangedWanted = false; - s_currentSlider.value = 0; - - return; - } - - if (GameObjectInspector.ActiveInstance == null) return; - - var transform = GameObjectInspector.ActiveInstance.TargetGO.transform; - - // get the current vector for the control type - Vector3 vector = Vector2.zero; - switch (s_currentSliderType) - { - case ControlType.position: - vector = transform.position; break; - case ControlType.localPosition: - vector = transform.localPosition; break; - case ControlType.eulerAngles: - vector = transform.eulerAngles; break; - case ControlType.localScale: - vector = transform.localScale; break; - } - - // apply vector value change - switch (s_currentSliderValueType) - { - case VectorValue.x: - vector.x += s_currentSliderValue; break; - case VectorValue.y: - vector.y += s_currentSliderValue; break; - case VectorValue.z: - vector.z += s_currentSliderValue; break; - } - - // set vector to transform member - switch (s_currentSliderType) - { - case ControlType.position: - transform.position = vector; break; - case ControlType.localPosition: - transform.localPosition = vector; break; - case ControlType.eulerAngles: - transform.eulerAngles = vector; break; - case ControlType.localScale: - transform.localScale = vector; break; - } - } - - internal static void OnVectorControlInputApplied(ControlType controlType, VectorValue vectorValue) - { - if (!(InspectorManager.Instance.m_activeInspector is GameObjectInspector instance)) return; - - // get relevant input for controltype + value - - InputField[] inputs = null; - switch (controlType) - { - case ControlType.position: - inputs = s_positionControl.inputs; break; - case ControlType.localPosition: - inputs = s_localPosControl.inputs; break; - case ControlType.eulerAngles: - inputs = s_rotationControl.inputs; break; - case ControlType.localScale: - inputs = s_scaleControl.inputs; break; - } - InputField input = inputs[(int)vectorValue]; - - float val = float.Parse(input.text); - - // apply transform value - - Vector3 vector = Vector3.zero; - var transform = instance.TargetGO.transform; - switch (controlType) - { - case ControlType.position: - vector = transform.position; break; - case ControlType.localPosition: - vector = transform.localPosition; break; - case ControlType.eulerAngles: - vector = transform.eulerAngles; break; - case ControlType.localScale: - vector = transform.localScale; break; - } - - switch (vectorValue) - { - case VectorValue.x: - vector.x = val; break; - case VectorValue.y: - vector.y = val; break; - case VectorValue.z: - vector.z = val; break; - } - - // set back to transform - switch (controlType) - { - case ControlType.position: - transform.position = vector; break; - case ControlType.localPosition: - transform.localPosition = vector; break; - case ControlType.eulerAngles: - transform.eulerAngles = vector; break; - case ControlType.localScale: - transform.localScale = vector; break; - } - } - - #region UI CONSTRUCTION - - internal void ConstructControls(GameObject parent) - { - var mainGroup = UIFactory.CreateVerticalGroup(parent, "ControlsGroup", false, false, true, true, 5, new Vector4(4,4,4,4), - new Color(0.07f, 0.07f, 0.07f)); - - // ~~~~~~ Top row ~~~~~~ - - var topRow = UIFactory.CreateHorizontalGroup(mainGroup, "TopRow", false, false, true, true, 5, default, new Color(1, 1, 1, 0)); - - var hideButton = UIFactory.CreateButton(topRow, "ToggleShowButton", "Show", ToggleVisibility, new Color(0.16f, 0.16f, 0.16f)); - UIFactory.SetLayoutElement(hideButton.gameObject, minWidth: 40, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0); - m_hideShowLabel = hideButton.GetComponentInChildren(); - - var topTitle = UIFactory.CreateLabel(topRow, "ControlsLabel", "Controls", TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(topTitle.gameObject, minWidth: 100, flexibleWidth: 9500, minHeight: 25); - - //// ~~~~~~~~ Content ~~~~~~~~ // - - m_contentObj = UIFactory.CreateVerticalGroup(mainGroup, "ContentGroup", true, false, true, true, 5, default, new Color(1, 1, 1, 0)); - - // transform controls - ConstructVector3Editor(m_contentObj, "Position", ControlType.position, out s_positionControl); - ConstructVector3Editor(m_contentObj, "Local Position", ControlType.localPosition, out s_localPosControl); - ConstructVector3Editor(m_contentObj, "Rotation", ControlType.eulerAngles, out s_rotationControl); - ConstructVector3Editor(m_contentObj, "Scale", ControlType.localScale, out s_scaleControl); - - // set parent - ConstructSetParent(m_contentObj); - - // bottom row buttons - ConstructBottomButtons(m_contentObj); - - // set controls content inactive now that content is made (otherwise TMP font size goes way too big?) - m_contentObj.SetActive(false); - } - - internal void ConstructSetParent(GameObject contentObj) - { - var setParentGroupObj = UIFactory.CreateHorizontalGroup(contentObj, "SetParentRow", false, false, true, true, 5, default, - new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(setParentGroupObj, minHeight: 25, flexibleHeight: 0); - - var title = UIFactory.CreateLabel(setParentGroupObj, "SetParentLabel", "Set Parent:", TextAnchor.MiddleLeft, Color.grey); - UIFactory.SetLayoutElement(title.gameObject, minWidth: 110, minHeight: 25, flexibleHeight: 0); - - var inputFieldObj = UIFactory.CreateInputField(setParentGroupObj, "SetParentInputField", "Enter a GameObject name or path..."); - s_setParentInput = inputFieldObj.GetComponent(); - UIFactory.SetLayoutElement(inputFieldObj, minHeight: 25, preferredWidth: 400, flexibleWidth: 9999); - - var applyButton = UIFactory.CreateButton(setParentGroupObj, "SetParentButton", "Apply", OnSetParentClicked); - UIFactory.SetLayoutElement(applyButton.gameObject, minWidth: 55, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0); - } - - internal void ConstructVector3Editor(GameObject parent, string titleText, ControlType type, out ControlEditor editor) - { - editor = new ControlEditor(); - - var topBarObj = UIFactory.CreateHorizontalGroup(parent, "Vector3Editor", false, false, true, true, 5, default, new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(topBarObj, minHeight: 25, flexibleHeight: 0); - - var title = UIFactory.CreateLabel(topBarObj, "Title", titleText, TextAnchor.MiddleLeft, Color.grey); - UIFactory.SetLayoutElement(title.gameObject, minWidth: 110, flexibleWidth: 0, minHeight: 25); - - // expand button - var expandButton = UIFactory.CreateButton(topBarObj, "ExpandArrow", "▼"); - var expandText = expandButton.GetComponentInChildren(); - expandText.fontSize = 12; - UIFactory.SetLayoutElement(expandButton.gameObject, minWidth: 35, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0); - - // readonly value input - - var valueInputObj = UIFactory.CreateInputField(topBarObj, "ValueInput", "..."); - var valueInput = valueInputObj.GetComponent(); - valueInput.readOnly = true; - UIFactory.SetLayoutElement(valueInputObj, minHeight: 25, flexibleHeight: 0, preferredWidth: 400, flexibleWidth: 9999); - - editor.fullValue = valueInput; - - editor.sliders = new Slider[3]; - editor.inputs = new InputField[3]; - editor.values = new Text[3]; - - var xRow = ConstructEditorRow(parent, editor, type, VectorValue.x); - xRow.SetActive(false); - var yRow = ConstructEditorRow(parent, editor, type, VectorValue.y); - yRow.SetActive(false); - var zRow = ConstructEditorRow(parent, editor, type, VectorValue.z); - zRow.SetActive(false); - - // add expand callback now that we have group reference - expandButton.onClick.AddListener(ToggleExpand); - void ToggleExpand() - { - if (xRow.activeSelf) - { - xRow.SetActive(false); - yRow.SetActive(false); - zRow.SetActive(false); - expandText.text = "▼"; - } - else - { - xRow.SetActive(true); - yRow.SetActive(true); - zRow.SetActive(true); - expandText.text = "▲"; - } - } - } - - internal GameObject ConstructEditorRow(GameObject parent, ControlEditor editor, ControlType type, VectorValue vectorValue) - { - var rowObject = UIFactory.CreateHorizontalGroup(parent, "EditorRow", false, false, true, true, 5, default, new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(rowObject, minHeight: 25, flexibleHeight: 0, minWidth: 100); - - // Value labels - - var valueTitle = UIFactory.CreateLabel(rowObject, "ValueTitle", $"{vectorValue.ToString().ToUpper()}:", TextAnchor.MiddleLeft, Color.cyan); - UIFactory.SetLayoutElement(valueTitle.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 25, flexibleWidth: 0); - - // actual value label - var valueLabel = UIFactory.CreateLabel(rowObject, "ValueLabel", "", TextAnchor.MiddleLeft); - editor.values[(int)vectorValue] = valueLabel; - UIFactory.SetLayoutElement(valueLabel.gameObject, minWidth: 85, flexibleWidth: 0, minHeight: 25); - - // input field - - var inputHolder = UIFactory.CreateVerticalGroup(rowObject, "InputFieldGroup", false, false, true, true, 0, default, new Color(1, 1, 1, 0)); - - var inputObj = UIFactory.CreateInputField(inputHolder, "InputField", "..."); - var input = inputObj.GetComponent(); - //input.characterValidation = InputField.CharacterValidation.Decimal; - - UIFactory.SetLayoutElement(inputObj, minHeight: 25, flexibleHeight: 0, minWidth: 90, flexibleWidth: 50); - - editor.inputs[(int)vectorValue] = input; - - // apply button - - var applyBtn = UIFactory.CreateButton(rowObject, "ApplyButton", "Apply", () => { OnVectorControlInputApplied(type, vectorValue); }); - UIFactory.SetLayoutElement(applyBtn.gameObject, minWidth: 60, minHeight: 25); - - - // Slider - - var sliderObj = UIFactory.CreateSlider(rowObject, "VectorSlider", out Slider slider); - UIFactory.SetLayoutElement(sliderObj, minHeight: 20, flexibleHeight: 0, minWidth: 200, flexibleWidth: 9000); - sliderObj.transform.Find("Fill Area").gameObject.SetActive(false); - RuntimeProvider.Instance.SetColorBlock(slider, new Color(0.65f, 0.65f, 0.65f)); - slider.minValue = -2; - slider.maxValue = 2; - slider.value = 0; - slider.onValueChanged.AddListener((float val) => { OnSliderControlChanged(val, slider, type, vectorValue); }); - editor.sliders[(int)vectorValue] = slider; - - return rowObject; - } - - internal void ConstructBottomButtons(GameObject contentObj) - { - var bottomRow = UIFactory.CreateHorizontalGroup(contentObj, "BottomButtons", true, true, false, false, 4, default, new Color(1, 1, 1, 0)); - - var instantiateBtn = UIFactory.CreateButton(bottomRow, "InstantiateBtn", "Instantiate", InstantiateBtn, new Color(0.2f, 0.2f, 0.2f)); - UIFactory.SetLayoutElement(instantiateBtn.gameObject, minWidth: 150); - - void InstantiateBtn() - { - var go = GameObjectInspector.ActiveInstance.TargetGO; - if (!go) - return; - - var clone = GameObject.Instantiate(go); - InspectorManager.Instance.Inspect(clone); - } - - var dontDestroyBtn = UIFactory.CreateButton(bottomRow, "DontDestroyButton", "Set DontDestroyOnLoad", DontDestroyOnLoadBtn, - new Color(0.2f, 0.2f, 0.2f)); - UIFactory.SetLayoutElement(dontDestroyBtn.gameObject, flexibleWidth: 5000); - - void DontDestroyOnLoadBtn() - { - var go = GameObjectInspector.ActiveInstance.TargetGO; - if (!go) - return; - - GameObject.DontDestroyOnLoad(go); - } - - var destroyBtn = UIFactory.CreateButton(bottomRow, "DestroyButton", "Destroy", DestroyBtn, new Color(0.2f, 0.2f, 0.2f)); - UIFactory.SetLayoutElement(destroyBtn.gameObject, minWidth: 150); - var destroyText = destroyBtn.GetComponentInChildren(); - destroyText.color = Color.red; - - void DestroyBtn() - { - var go = GameObjectInspector.ActiveInstance.TargetGO; - if (!go) - return; - - GameObject.Destroy(go); - } - } - - #endregion - } -} diff --git a/src/UI/Inspectors/GameObjects/GameObjectInspector.cs b/src/UI/Inspectors/GameObjects/GameObjectInspector.cs deleted file mode 100644 index df01178..0000000 --- a/src/UI/Inspectors/GameObjects/GameObjectInspector.cs +++ /dev/null @@ -1,350 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Runtime; -using UnityExplorer.Core.Unity; - -namespace UnityExplorer.UI.Inspectors.GameObjects -{ - public class GameObjectInspector : InspectorBase - { - public override string TabLabel => $" [G] {TargetGO?.name}"; - - public static GameObjectInspector ActiveInstance { get; private set; } - - public GameObject TargetGO; - - // sub modules - internal static ChildList s_childList; - internal static ComponentList s_compList; - internal static GameObjectControls s_controls; - - internal static bool m_UIConstructed; - - public GameObjectInspector(GameObject target) : base(target) - { - ActiveInstance = this; - - TargetGO = target; - - if (!TargetGO) - { - ExplorerCore.LogWarning("Target GameObject is null!"); - return; - } - - // one UI is used for all gameobject inspectors. no point recreating it. - if (!m_UIConstructed) - { - m_UIConstructed = true; - - s_childList = new ChildList(); - s_compList = new ComponentList(); - s_controls = new GameObjectControls(); - - ConstructUI(); - } - } - - public override void SetActive() - { - base.SetActive(); - ActiveInstance = this; - } - - public override void SetInactive() - { - base.SetInactive(); - ActiveInstance = null; - } - - internal void ChangeInspectorTarget(GameObject newTarget) - { - if (!newTarget) - return; - - this.Target = this.TargetGO = newTarget; - } - - // Update - - public override void Update() - { - base.Update(); - - if (m_pendingDestroy || !this.IsActive) - return; - - RefreshTopInfo(); - - s_childList.RefreshChildObjectList(); - - s_compList.RefreshComponentList(); - - s_controls.RefreshControls(); - - if (GameObjectControls.s_sliderChangedWanted) - GameObjectControls.UpdateSliderControl(); - } - - private static GameObject s_content; - public override GameObject Content - { - get => s_content; - set => s_content = value; - } - - private static string m_lastName; - public static InputField m_nameInput; - - private static string m_lastPath; - public static InputField m_pathInput; - private static RectTransform m_pathInputRect; - private static GameObject m_pathGroupObj; - private static Text m_hiddenPathText; - private static RectTransform m_hiddenPathRect; - - private static Toggle m_enabledToggle; - private static Text m_enabledText; - private static bool? m_lastEnabledState; - - private static Dropdown m_layerDropdown; - private static int m_lastLayer = -1; - - private static Text m_sceneText; - private static string m_lastScene; - - internal void RefreshTopInfo() - { - var target = TargetGO; - string name = target.name; - - if (m_lastName != name) - { - m_lastName = name; - m_nameInput.text = m_lastName; - } - - if (target.transform.parent) - { - if (!m_pathGroupObj.activeSelf) - m_pathGroupObj.SetActive(true); - - var path = target.transform.GetTransformPath(true); - if (m_lastPath != path) - { - m_lastPath = path; - - m_pathInput.text = path; - m_hiddenPathText.text = path; - - LayoutRebuilder.ForceRebuildLayoutImmediate(m_pathInputRect); - LayoutRebuilder.ForceRebuildLayoutImmediate(m_hiddenPathRect); - } - } - else if (m_pathGroupObj.activeSelf) - m_pathGroupObj.SetActive(false); - - if (m_lastEnabledState != target.activeSelf) - { - m_lastEnabledState = target.activeSelf; - - m_enabledToggle.isOn = target.activeSelf; - m_enabledText.text = target.activeSelf ? "Enabled" : "Disabled"; - m_enabledText.color = target.activeSelf ? Color.green : Color.red; - } - - if (m_lastLayer != target.layer) - { - m_lastLayer = target.layer; - m_layerDropdown.value = target.layer; - } - - if (string.IsNullOrEmpty(m_lastScene) || m_lastScene != target.scene.name) - { - m_lastScene = target.scene.name; - - if (!string.IsNullOrEmpty(target.scene.name)) - m_sceneText.text = m_lastScene; - else - m_sceneText.text = "None (Asset/Resource)"; - } - } - - // UI Callbacks - - private static void OnApplyNameClicked() - { - if (ActiveInstance == null) - return; - - ActiveInstance.TargetGO.name = m_nameInput.text; - } - - private static void OnEnableToggled(bool enabled) - { - if (ActiveInstance == null) - return; - - ActiveInstance.TargetGO.SetActive(enabled); - } - - private static void OnLayerSelected(int layer) - { - if (ActiveInstance == null) - return; - - ActiveInstance.TargetGO.layer = layer; - } - - internal static void OnBackButtonClicked() - { - if (ActiveInstance == null) - return; - - ActiveInstance.ChangeInspectorTarget(ActiveInstance.TargetGO.transform.parent.gameObject); - } - - #region UI CONSTRUCTION - - internal void ConstructUI() - { - var parent = InspectorManager.m_inspectorContent; - - s_content = UIFactory.CreateScrollView(parent, "GameObjectInspector_Content", out GameObject scrollContent, out _, - new Color(0.1f, 0.1f, 0.1f)); - - UIFactory.SetLayoutGroup(scrollContent.transform.parent.gameObject, true, true, true, true); - - UIFactory.SetLayoutGroup(scrollContent, true, true, true, true, 5); - var contentFitter = scrollContent.GetComponent(); - contentFitter.verticalFit = ContentSizeFitter.FitMode.Unconstrained; - - ConstructTopArea(scrollContent); - - s_controls.ConstructControls(scrollContent); - - var midGroupObj = ConstructMidGroup(scrollContent); - - s_childList.ConstructChildList(midGroupObj); - s_compList.ConstructCompList(midGroupObj); - - LayoutRebuilder.ForceRebuildLayoutImmediate(s_content.GetComponent()); - Canvas.ForceUpdateCanvases(); - } - - private void ConstructTopArea(GameObject scrollContent) - { - // path row - - m_pathGroupObj = UIFactory.CreateHorizontalGroup(scrollContent, "TopArea", false, false, true, true, 5, default, new Color(0.1f, 0.1f, 0.1f)); - - var pathRect = m_pathGroupObj.GetComponent(); - pathRect.sizeDelta = new Vector2(pathRect.sizeDelta.x, 20); - UIFactory.SetLayoutElement(m_pathGroupObj, minHeight: 20, flexibleHeight: 75); - - // Back button - - var backButton = UIFactory.CreateButton(m_pathGroupObj, "BackButton", "◄", OnBackButtonClicked, new Color(0.15f, 0.15f, 0.15f)); - UIFactory.SetLayoutElement(backButton.gameObject, minWidth: 55, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0); - - m_hiddenPathText = UIFactory.CreateLabel(m_pathGroupObj, "HiddenPathText", "", TextAnchor.MiddleLeft); - m_hiddenPathText.color = Color.clear; - m_hiddenPathText.fontSize = 14; - m_hiddenPathText.raycastTarget = false; - - var hiddenFitter = m_hiddenPathText.gameObject.AddComponent(); - hiddenFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; - - UIFactory.SetLayoutElement(m_hiddenPathText.gameObject, minHeight: 25, flexibleHeight: 125, minWidth: 250, flexibleWidth: 9000); - UIFactory.SetLayoutGroup(m_hiddenPathText.gameObject, true, true, true, true); - - // Path input - - var pathInputObj = UIFactory.CreateInputField(m_hiddenPathText.gameObject, "PathInputField", "..."); - UIFactory.SetLayoutElement(pathInputObj, minHeight: 25, flexibleHeight: 75, preferredWidth: 400, flexibleWidth: 9999); - var pathInputRect = pathInputObj.GetComponent(); - pathInputRect.sizeDelta = new Vector2(pathInputRect.sizeDelta.x, 25); - - m_pathInput = pathInputObj.GetComponent(); - m_pathInput.text = ActiveInstance.TargetGO.transform.GetTransformPath(); - m_pathInput.readOnly = true; - m_pathInput.lineType = InputField.LineType.MultiLineNewline; - m_pathInput.textComponent.color = new Color(0.75f, 0.75f, 0.75f); - - var textRect = m_pathInput.textComponent.GetComponent(); - textRect.offsetMin = new Vector2(3, 3); - textRect.offsetMax = new Vector2(3, 3); - - m_pathInputRect = m_pathInput.GetComponent(); - m_hiddenPathRect = m_hiddenPathText.GetComponent(); - - // name and enabled row - - var nameRowObj = UIFactory.CreateHorizontalGroup(scrollContent, "NameGroup", false, false, true, true, 5, default, new Color(0.1f, 0.1f, 0.1f)); - UIFactory.SetLayoutElement(nameRowObj, minHeight: 25, flexibleHeight: 0); - var nameRect = nameRowObj.GetComponent(); - nameRect.sizeDelta = new Vector2(nameRect.sizeDelta.x, 25); - - var nameLabel = UIFactory.CreateLabel(nameRowObj, "NameLabel", "Name:", TextAnchor.MiddleCenter, Color.grey, true, 14); - UIFactory.SetLayoutElement(nameLabel.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 55, flexibleWidth: 0); - - var nameInputObj = UIFactory.CreateInputField(nameRowObj, "NameInput", "..."); - var nameInputRect = nameInputObj.GetComponent(); - nameInputRect.sizeDelta = new Vector2(nameInputRect.sizeDelta.x, 25); - m_nameInput = nameInputObj.GetComponent(); - m_nameInput.text = ActiveInstance.TargetGO.name; - - var applyNameBtn = UIFactory.CreateButton(nameRowObj, "ApplyNameButton", "Apply", OnApplyNameClicked); - UIFactory.SetLayoutElement(applyNameBtn.gameObject, minWidth: 65, minHeight: 25, flexibleHeight: 0); - var applyNameRect = applyNameBtn.GetComponent(); - applyNameRect.sizeDelta = new Vector2(applyNameRect.sizeDelta.x, 25); - - var activeLabel = UIFactory.CreateLabel(nameRowObj, "ActiveLabel", "Active:", TextAnchor.MiddleCenter, Color.grey, true, 14); - UIFactory.SetLayoutElement(activeLabel.gameObject, minWidth: 55, minHeight: 25); - - var enabledToggleObj = UIFactory.CreateToggle(nameRowObj, "EnabledToggle", out m_enabledToggle, out m_enabledText); - UIFactory.SetLayoutElement(enabledToggleObj, minHeight: 25, minWidth: 100, flexibleWidth: 0); - m_enabledText.text = "Enabled"; - m_enabledText.color = Color.green; - m_enabledToggle.onValueChanged.AddListener(OnEnableToggled); - - // layer and scene row - - var sceneLayerRow = UIFactory.CreateHorizontalGroup(scrollContent, "SceneLayerRow", false, true, true, true, 5, default, new Color(0.1f, 0.1f, 0.1f)); - - // layer - - var layerLabel = UIFactory.CreateLabel(sceneLayerRow, "LayerLabel", "Layer:", TextAnchor.MiddleCenter, Color.grey, true, 14); - UIFactory.SetLayoutElement(layerLabel.gameObject, minWidth: 55, flexibleWidth: 0); - - var layerDropdownObj = UIFactory.CreateDropdown(sceneLayerRow, out m_layerDropdown, "", 14, OnLayerSelected); - m_layerDropdown.options.Clear(); - for (int i = 0; i < 32; i++) - { - var layer = RuntimeProvider.Instance.LayerToName(i); - m_layerDropdown.options.Add(new Dropdown.OptionData { text = $"{i}: {layer}" }); - } - UIFactory.SetLayoutElement(layerDropdownObj, minWidth: 120, flexibleWidth: 2000, minHeight: 25); - - // scene - - var sceneLabel = UIFactory.CreateLabel(sceneLayerRow, "SceneLabel", "Scene:", TextAnchor.MiddleCenter, Color.grey, true, 14); - UIFactory.SetLayoutElement(sceneLabel.gameObject, minWidth: 55, flexibleWidth: 0); - - m_sceneText = UIFactory.CreateLabel(sceneLayerRow, "SceneText", "", TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(m_sceneText.gameObject, minWidth: 120, flexibleWidth: 2000); - } - - private GameObject ConstructMidGroup(GameObject parent) - { - var midGroupObj = UIFactory.CreateHorizontalGroup(parent, "MidGroup", true, true, true, true, 5, default, new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(midGroupObj, minHeight: 300, flexibleHeight: 3000); - return midGroupObj; - } - #endregion - } -} diff --git a/src/UI/Inspectors/InspectUnderMouse.cs b/src/UI/Inspectors/InspectUnderMouse.cs deleted file mode 100644 index ae837c6..0000000 --- a/src/UI/Inspectors/InspectUnderMouse.cs +++ /dev/null @@ -1,328 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.EventSystems; -using UnityEngine.UI; -using UnityExplorer.Core; -using UnityExplorer.Core.Unity; -using UnityExplorer.Core.Input; -using UnityExplorer.Core.Runtime; -using UnityExplorer.UI; -using UnityExplorer.UI.Main; -using UnityExplorer.UI.Inspectors; - -namespace UnityExplorer.UI.Main.Home -{ - public class InspectUnderMouse - { - public enum MouseInspectMode - { - World, - UI - } - - public static bool Inspecting { get; set; } - - public static MouseInspectMode Mode { get; set; } - - private static GameObject s_lastHit; - private static Vector3 s_lastMousePos; - - private static readonly List _wasDisabledGraphics = new List(); - private static readonly List _wasDisabledCanvasGroups = new List(); - private static readonly List _objectsAddedCastersTo = new List(); - - internal static Camera MainCamera; - internal static GraphicRaycaster[] graphicRaycasters; - - public static void Init() - { - ConstructUI(); - } - - public static void StartInspect(MouseInspectMode mode) - { - MainCamera = Camera.main; - if (!MainCamera) - return; - - Mode = mode; - Inspecting = true; - MainMenu.Instance.MainPanel.SetActive(false); - - s_UIContent.SetActive(true); - - if (mode == MouseInspectMode.UI) - SetupUIRaycast(); - } - - internal static void ClearHitData() - { - s_lastHit = null; - s_objNameLabel.text = "No hits..."; - s_objPathLabel.text = ""; - } - - public static void StopInspect() - { - Inspecting = false; - MainMenu.Instance.MainPanel.SetActive(true); - s_UIContent.SetActive(false); - - if (Mode == MouseInspectMode.UI) - StopUIInspect(); - - ClearHitData(); - } - - public static void UpdateInspect() - { - if (InputManager.GetKeyDown(KeyCode.Escape)) - { - StopInspect(); - return; - } - - var mousePos = InputManager.MousePosition; - - if (mousePos != s_lastMousePos) - UpdatePosition(mousePos); - - // actual inspect raycast - - switch (Mode) - { - case MouseInspectMode.UI: - RaycastUI(mousePos); break; - case MouseInspectMode.World: - RaycastWorld(mousePos); break; - } - } - - internal static void UpdatePosition(Vector2 mousePos) - { - s_lastMousePos = mousePos; - - var inversePos = UIManager.CanvasRoot.transform.InverseTransformPoint(mousePos); - - s_mousePosLabel.text = $"Mouse Position: {mousePos.ToString()}"; - - float yFix = mousePos.y < 120 ? 80 : -80; - s_UIContent.transform.localPosition = new Vector3(inversePos.x, inversePos.y + yFix, 0); - } - - internal static void OnHitGameObject(GameObject obj) - { - if (obj != s_lastHit) - { - s_lastHit = obj; - s_objNameLabel.text = $"Click to Inspect: {obj.name}"; - s_objPathLabel.text = $"Path: {obj.transform.GetTransformPath(true)}"; - } - - if (InputManager.GetMouseButtonDown(0)) - { - StopInspect(); - InspectorManager.Instance.Inspect(obj); - } - } - - // Collider raycasting - - internal static void RaycastWorld(Vector2 mousePos) - { - var ray = MainCamera.ScreenPointToRay(mousePos); - Physics.Raycast(ray, out RaycastHit hit, 1000f); - - if (hit.transform) - { - var obj = hit.transform.gameObject; - OnHitGameObject(obj); - } - else - { - if (s_lastHit) - ClearHitData(); - } - } - - // UI Graphic raycasting - - private static void SetupUIRaycast() - { - foreach (var obj in RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(Canvas))) - { - var canvas = obj.Cast(typeof(Canvas)) as Canvas; - if (!canvas || !canvas.enabled || !canvas.gameObject.activeInHierarchy) - continue; - if (!canvas.GetComponent()) - { - canvas.gameObject.AddComponent(); - //ExplorerCore.Log("Added raycaster to " + canvas.name); - _objectsAddedCastersTo.Add(canvas.gameObject); - } - } - - // recache Graphic Raycasters each time we start - var casters = RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(GraphicRaycaster)); - graphicRaycasters = new GraphicRaycaster[casters.Length]; - for (int i = 0; i < casters.Length; i++) - { - graphicRaycasters[i] = casters[i].Cast(typeof(GraphicRaycaster)) as GraphicRaycaster; - } - - // enable raycastTarget on Graphics - foreach (var obj in RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(Graphic))) - { - var graphic = obj.Cast(typeof(Graphic)) as Graphic; - if (!graphic || !graphic.enabled || graphic.raycastTarget || !graphic.gameObject.activeInHierarchy) - continue; - graphic.raycastTarget = true; - //ExplorerCore.Log("Enabled raycastTarget on " + graphic.name); - _wasDisabledGraphics.Add(graphic); - } - - // enable blocksRaycasts on CanvasGroups - foreach (var obj in RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(CanvasGroup))) - { - var canvas = obj.Cast(typeof(CanvasGroup)) as CanvasGroup; - if (!canvas || !canvas.gameObject.activeInHierarchy || canvas.blocksRaycasts) - continue; - canvas.blocksRaycasts = true; - //ExplorerCore.Log("Enabled raycasts on " + canvas.name); - _wasDisabledCanvasGroups.Add(canvas); - } - } - - internal static void RaycastUI(Vector2 mousePos) - { - var ped = new PointerEventData(null) - { - position = mousePos - }; - - //ExplorerCore.Log("~~~~~~~~~ begin raycast ~~~~~~~~"); - GameObject hitObject = null; - int highestLayer = int.MinValue; - int highestOrder = int.MinValue; - int highestDepth = int.MinValue; - foreach (var gr in graphicRaycasters) - { - var list = new List(); - RuntimeProvider.Instance.GraphicRaycast(gr, ped, list); - - //gr.Raycast(ped, list); - - if (list.Count > 0) - { - foreach (var hit in list) - { - // Manual trying to determine which object is "on top". - // Not perfect, but not terrible. - - if (!hit.gameObject) - continue; - - if (hit.gameObject.GetComponent() is CanvasGroup group && group.alpha == 0) - continue; - - if (hit.gameObject.GetComponent() is Graphic graphic && graphic.color.a == 0f) - continue; - - if (hit.sortingLayer < highestLayer) - continue; - - if (hit.sortingLayer > highestLayer) - { - highestLayer = hit.sortingLayer; - highestDepth = int.MinValue; - } - - if (hit.depth < highestDepth) - continue; - - if (hit.depth > highestDepth) - { - highestDepth = hit.depth; - highestOrder = int.MinValue; - } - - if (hit.sortingOrder <= highestOrder) - continue; - - highestOrder = hit.sortingOrder; - hitObject = hit.gameObject; - } - } - else - { - if (s_lastHit) - ClearHitData(); - } - } - - if (hitObject) - OnHitGameObject(hitObject); - - //ExplorerCore.Log("~~~~~~~~~ end raycast ~~~~~~~~"); - } - - private static void StopUIInspect() - { - foreach (var obj in _objectsAddedCastersTo) - { - if (obj.GetComponent() is GraphicRaycaster raycaster) - GameObject.Destroy(raycaster); - } - - foreach (var graphic in _wasDisabledGraphics) - graphic.raycastTarget = false; - - foreach (var canvas in _wasDisabledCanvasGroups) - canvas.blocksRaycasts = false; - - _objectsAddedCastersTo.Clear(); - _wasDisabledCanvasGroups.Clear(); - _wasDisabledGraphics.Clear(); - } - - internal static Text s_objNameLabel; - internal static Text s_objPathLabel; - internal static Text s_mousePosLabel; - internal static GameObject s_UIContent; - - internal static void ConstructUI() - { - s_UIContent = UIFactory.CreatePanel("InspectUnderMouse_UI", out GameObject content); - - var baseRect = s_UIContent.GetComponent(); - var half = new Vector2(0.5f, 0.5f); - baseRect.anchorMin = half; - baseRect.anchorMax = half; - baseRect.pivot = half; - baseRect.sizeDelta = new Vector2(700, 150); - - var group = content.GetComponent(); - group.childForceExpandHeight = true; - - // Title text - - UIFactory.CreateLabel(content, "InspectLabel", "Mouse Inspector (press ESC to cancel)", TextAnchor.MiddleCenter); - - s_mousePosLabel = UIFactory.CreateLabel(content, "MousePosLabel", "Mouse Position:", TextAnchor.MiddleCenter); - - s_objNameLabel = UIFactory.CreateLabel(content, "HitLabelObj", "No hits...", TextAnchor.MiddleLeft); - s_objNameLabel.horizontalOverflow = HorizontalWrapMode.Overflow; - - s_objPathLabel = UIFactory.CreateLabel(content, "PathLabel", "", TextAnchor.MiddleLeft); - s_objPathLabel.fontStyle = FontStyle.Italic; - s_objPathLabel.horizontalOverflow = HorizontalWrapMode.Wrap; - - UIFactory.SetLayoutElement(s_objPathLabel.gameObject, minHeight: 75); - - s_UIContent.SetActive(false); - } - } -} diff --git a/src/UI/Inspectors/InspectorBase.cs b/src/UI/Inspectors/InspectorBase.cs deleted file mode 100644 index 2e167c0..0000000 --- a/src/UI/Inspectors/InspectorBase.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Unity; - -namespace UnityExplorer.UI.Inspectors -{ - public abstract class InspectorBase - { - public object Target; - public bool IsActive { get; private set; } - - public abstract string TabLabel { get; } - - internal bool m_pendingDestroy; - - public InspectorBase(object target) - { - Target = target; - - if (Target.IsNullOrDestroyed(false)) - { - Destroy(); - return; - } - - AddInspectorTab(this); - } - - public virtual void SetActive() - { - this.IsActive = true; - Content?.SetActive(true); - } - - public virtual void SetInactive() - { - this.IsActive = false; - Content?.SetActive(false); - } - - public virtual void Update() - { - if (Target.IsNullOrDestroyed(false)) - { - Destroy(); - return; - } - - m_tabText.text = TabLabel; - } - - public virtual void Destroy() - { - m_pendingDestroy = true; - - GameObject tabGroup = m_tabButton?.transform.parent.gameObject; - - if (tabGroup) - GameObject.Destroy(tabGroup); - - int thisIndex = -1; - if (InspectorManager.Instance.m_currentInspectors.Contains(this)) - { - thisIndex = InspectorManager.Instance.m_currentInspectors.IndexOf(this); - InspectorManager.Instance.m_currentInspectors.Remove(this); - } - - if (ReferenceEquals(InspectorManager.Instance.m_activeInspector, this)) - { - InspectorManager.Instance.UnsetInspectorTab(); - - if (InspectorManager.Instance.m_currentInspectors.Count > 0) - { - var prevTab = InspectorManager.Instance.m_currentInspectors[thisIndex > 0 ? thisIndex - 1 : 0]; - InspectorManager.Instance.SetInspectorTab(prevTab); - } - } - } - - #region UI - - public abstract GameObject Content { get; set; } - public Button m_tabButton; - public Text m_tabText; - - public void AddInspectorTab(InspectorBase parent) - { - var tabContent = InspectorManager.m_tabBarContent; - - var tabGroupObj = UIFactory.CreateHorizontalGroup(tabContent, "TabObject", true, true, true, true); - UIFactory.SetLayoutElement(tabGroupObj, minWidth: 185, flexibleWidth: 0); - tabGroupObj.AddComponent(); - - m_tabButton = UIFactory.CreateButton(tabGroupObj, - "TabButton", - "", - () => { InspectorManager.Instance.SetInspectorTab(parent); }); - - UIFactory.SetLayoutElement(m_tabButton.gameObject, minWidth: 165, flexibleWidth: 0); - - m_tabText = m_tabButton.GetComponentInChildren(); - m_tabText.horizontalOverflow = HorizontalWrapMode.Overflow; - m_tabText.alignment = TextAnchor.MiddleLeft; - - var closeBtn = UIFactory.CreateButton(tabGroupObj, - "CloseButton", - "X", - parent.Destroy, - new Color(0.2f, 0.2f, 0.2f, 1)); - - UIFactory.SetLayoutElement(closeBtn.gameObject, minWidth: 20, flexibleWidth: 0); - - var closeBtnText = closeBtn.GetComponentInChildren(); - closeBtnText.color = new Color(1, 0, 0, 1); - } - - #endregion - } -} diff --git a/src/UI/Inspectors/InspectorManager.cs b/src/UI/Inspectors/InspectorManager.cs deleted file mode 100644 index 739a193..0000000 --- a/src/UI/Inspectors/InspectorManager.cs +++ /dev/null @@ -1,204 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityExplorer.Core.Unity; -using UnityExplorer.UI; -using UnityExplorer.UI.Main; -using UnityEngine; -using UnityEngine.SceneManagement; -using UnityEngine.UI; -using UnityExplorer.Core.Runtime; -using UnityExplorer.UI.Main.Home; -using UnityExplorer.UI.CacheObject; -using UnityExplorer.UI.Inspectors.GameObjects; -using UnityExplorer.UI.Inspectors.Reflection; - -namespace UnityExplorer.UI.Inspectors -{ - public class InspectorManager - { - public static InspectorManager Instance { get; private set; } - - public InspectorManager() - { - Instance = this; - - ConstructInspectorPane(); - } - - public InspectorBase m_activeInspector; - public readonly List m_currentInspectors = new List(); - - public void Update() - { - for (int i = 0; i < m_currentInspectors.Count; i++) - { - if (i >= m_currentInspectors.Count) - break; - - m_currentInspectors[i].Update(); - } - } - - public void Inspect(object obj, CacheObjectBase parentMember = null) - { - obj = ReflectionProvider.Instance.Cast(obj, ReflectionProvider.Instance.GetActualType(obj)); - - UnityEngine.Object unityObj = obj as UnityEngine.Object; - - if (obj.IsNullOrDestroyed(false)) - { - return; - } - - // check if currently inspecting this object - foreach (InspectorBase tab in m_currentInspectors) - { - if (RuntimeProvider.Instance.IsReferenceEqual(obj, tab.Target)) - { - SetInspectorTab(tab); - return; - } - } - - InspectorBase inspector; - if (obj is GameObject go) - inspector = new GameObjectInspector(go); - else - inspector = new InstanceInspector(obj); - - if (inspector is ReflectionInspector ri) - ri.ParentMember = parentMember; - - m_currentInspectors.Add(inspector); - SetInspectorTab(inspector); - } - - public void Inspect(Type type) - { - if (type == null) - { - ExplorerCore.LogWarning("The provided type was null!"); - return; - } - - foreach (var tab in m_currentInspectors.Where(x => x is StaticInspector)) - { - if (ReferenceEquals(tab.Target as Type, type)) - { - SetInspectorTab(tab); - return; - } - } - - var inspector = new StaticInspector(type); - - m_currentInspectors.Add(inspector); - SetInspectorTab(inspector); - } - - public void SetInspectorTab(InspectorBase inspector) - { - MainMenu.Instance.SetPage(HomePage.Instance); - - if (m_activeInspector == inspector) - return; - - UnsetInspectorTab(); - - m_activeInspector = inspector; - inspector.SetActive(); - - OnSetInspectorTab(inspector); - } - - public void UnsetInspectorTab() - { - if (m_activeInspector == null) - return; - - m_activeInspector.SetInactive(); - - OnUnsetInspectorTab(); - - m_activeInspector = null; - } - - public static GameObject m_tabBarContent; - public static GameObject m_inspectorContent; - - public void OnSetInspectorTab(InspectorBase inspector) - { - Color activeColor = new Color(0, 0.25f, 0, 1); - RuntimeProvider.Instance.SetColorBlock(inspector.m_tabButton, activeColor, activeColor); - } - - public void OnUnsetInspectorTab() - { - RuntimeProvider.Instance.SetColorBlock(m_activeInspector.m_tabButton, - new Color(0.2f, 0.2f, 0.2f, 1), new Color(0.1f, 0.3f, 0.1f, 1)); - } - - public void ConstructInspectorPane() - { - var mainObj = UIFactory.CreateVerticalGroup(HomePage.Instance.Content, - "InspectorManager_Root", - true, true, true, true, - 4, - new Vector4(4,4,4,4)); - - UIFactory.SetLayoutElement(mainObj, preferredHeight: 400, flexibleHeight: 9000, preferredWidth: 620, flexibleWidth: 9000); - - var topRowObj = UIFactory.CreateHorizontalGroup(mainObj, "TopRow", false, true, true, true, 15); - - var inspectorTitle = UIFactory.CreateLabel(topRowObj, "Title", "Inspector", TextAnchor.MiddleLeft, default, true, 25); - - UIFactory.SetLayoutElement(inspectorTitle.gameObject, minHeight: 30, flexibleHeight: 0, minWidth: 90, flexibleWidth: 20000); - - ConstructToolbar(topRowObj); - - // inspector tab bar - - m_tabBarContent = UIFactory.CreateGridGroup(mainObj, "TabHolder", new Vector2(185, 20), new Vector2(5, 2), new Color(0.1f, 0.1f, 0.1f, 1)); - - var gridGroup = m_tabBarContent.GetComponent(); - gridGroup.padding.top = 3; - gridGroup.padding.left = 3; - gridGroup.padding.right = 3; - gridGroup.padding.bottom = 3; - - // inspector content area - - m_inspectorContent = UIFactory.CreateVerticalGroup(mainObj, "InspectorContent", - true, true, true, true, - 0, - new Vector4(2,2,2,2), - new Color(0.1f, 0.1f, 0.1f)); - - UIFactory.SetLayoutElement(m_inspectorContent, preferredHeight: 900, flexibleHeight: 10000, preferredWidth: 600, flexibleWidth: 10000); - } - - private static void ConstructToolbar(GameObject topRowObj) - { - // invisible group - UIFactory.CreateHorizontalGroup(topRowObj, "Toolbar", false, false, true, true, 10, new Vector4(2, 2, 2, 2), new Color(1,1,1,0)); - - // inspect under mouse button - AddMouseInspectButton(topRowObj, "UI", InspectUnderMouse.MouseInspectMode.UI); - AddMouseInspectButton(topRowObj, "3D", InspectUnderMouse.MouseInspectMode.World); - } - - private static void AddMouseInspectButton(GameObject topRowObj, string suffix, InspectUnderMouse.MouseInspectMode mode) - { - string lbl = $"Mouse Inspect ({suffix})"; - - var inspectObj = UIFactory.CreateButton(topRowObj, - lbl, - lbl, - () => { InspectUnderMouse.StartInspect(mode); }, - new Color(0.2f, 0.2f, 0.2f)); - - UIFactory.SetLayoutElement(inspectObj.gameObject, minWidth: 150, flexibleWidth: 0); - } - } -} diff --git a/src/UI/Inspectors/Reflection/InstanceInspector.cs b/src/UI/Inspectors/Reflection/InstanceInspector.cs deleted file mode 100644 index 8806b4a..0000000 --- a/src/UI/Inspectors/Reflection/InstanceInspector.cs +++ /dev/null @@ -1,253 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core; -using UnityExplorer.Core.Config; -using UnityExplorer.Core.Runtime; - -namespace UnityExplorer.UI.Inspectors.Reflection -{ - public enum MemberScopes - { - All, - Instance, - Static - } - - public class InstanceInspector : ReflectionInspector - { - public override string TabLabel => $" [R] {base.TabLabel}"; - - internal MemberScopes m_scopeFilter; - internal Button m_lastActiveScopeButton; - - public InstanceInspector(object target) : base(target) { } - - internal void OnScopeFilterClicked(MemberScopes type, Button button) - { - if (m_lastActiveScopeButton) - RuntimeProvider.Instance.SetColorBlock(m_lastActiveScopeButton, new Color(0.2f, 0.2f, 0.2f)); - - m_scopeFilter = type; - m_lastActiveScopeButton = button; - - RuntimeProvider.Instance.SetColorBlock(m_lastActiveScopeButton, new Color(0.2f, 0.6f, 0.2f)); - - FilterMembers(null, true); - m_sliderScroller.m_slider.value = 1f; - } - - public void ConstructUnityInstanceHelpers() - { - if (!typeof(UnityEngine.Object).IsAssignableFrom(m_targetType)) - return; - - var rowObj = UIFactory.CreateHorizontalGroup(Content, "InstanceHelperRow", true, true, true, true, 5, new Vector4(2,2,2,2), - new Color(0.1f, 0.1f, 0.1f)); - UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleWidth: 5000); - - if (typeof(Component).IsAssignableFrom(m_targetType)) - ConstructCompHelper(rowObj); - - ConstructUnityObjHelper(rowObj); - - if (m_targetType == typeof(Texture2D)) - ConstructTextureHelper(); - } - - internal void ConstructCompHelper(GameObject rowObj) - { - var gameObjectLabel = UIFactory.CreateLabel(rowObj, "GameObjectLabel", "GameObject:", TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(gameObjectLabel.gameObject, minWidth: 90, minHeight: 25, flexibleWidth: 0); - - var comp = Target.Cast(typeof(Component)) as Component; - - var btn = UIFactory.CreateButton(rowObj, - "GameObjectButton", - comp.name, - () => { InspectorManager.Instance.Inspect(comp.gameObject); }, - new Color(0.2f, 0.5f, 0.2f)); - UIFactory.SetLayoutElement(btn.gameObject, minHeight: 25, minWidth: 200, flexibleWidth: 0); - } - - internal void ConstructUnityObjHelper(GameObject rowObj) - { - var label = UIFactory.CreateLabel(rowObj, "NameLabel", "Name:", TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(label.gameObject, minWidth: 60, minHeight: 25, flexibleWidth: 0); - - var uObj = Target.Cast(typeof(UnityEngine.Object)) as UnityEngine.Object; - - var inputObj = UIFactory.CreateInputField(rowObj, "NameInput", "...", 14, 3, 1); - UIFactory.SetLayoutElement(inputObj, minHeight: 25, flexibleWidth: 2000); - var inputField = inputObj.GetComponent(); - inputField.readOnly = true; - inputField.text = uObj.name; - } - - internal bool showingTextureHelper; - internal bool constructedTextureViewer; - - internal GameObject m_textureViewerObj; - - internal void ConstructTextureHelper() - { - var rowObj = UIFactory.CreateHorizontalGroup(Content, "TextureHelper", true, false, true, true, 5, new Vector4(3,3,3,3), - new Color(0.1f, 0.1f, 0.1f)); - UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleHeight: 0); - - var showBtn = UIFactory.CreateButton(rowObj, "ShowButton", "Show", null, new Color(0.2f, 0.6f, 0.2f)); - UIFactory.SetLayoutElement(showBtn.gameObject, minWidth: 50, flexibleWidth: 0); - - UIFactory.CreateLabel(rowObj, "TextureViewerLabel", "Texture Viewer", TextAnchor.MiddleLeft); - - var textureViewerObj = UIFactory.CreateScrollView(Content, "TextureViewerContent", out GameObject scrollContent, out _, new Color(0.1f, 0.1f, 0.1f)); - UIFactory.SetLayoutGroup(textureViewerObj, false, false, true, true); - UIFactory.SetLayoutElement(textureViewerObj, minHeight: 100, flexibleHeight: 9999, flexibleWidth: 9999); - - textureViewerObj.SetActive(false); - - m_textureViewerObj = textureViewerObj; - - var showText = showBtn.GetComponentInChildren(); - showBtn.onClick.AddListener(() => - { - showingTextureHelper = !showingTextureHelper; - - if (showingTextureHelper) - { - if (!constructedTextureViewer) - ConstructTextureViewerArea(scrollContent); - - showText.text = "Hide"; - ToggleTextureViewer(true); - } - else - { - showText.text = "Show"; - ToggleTextureViewer(false); - } - }); - } - - internal void ConstructTextureViewerArea(GameObject parent) - { - constructedTextureViewer = true; - - var tex = Target.Cast(typeof(Texture2D)) as Texture2D; - - if (!tex) - { - ExplorerCore.LogWarning("Could not cast the target instance to Texture2D! Maybe its null or destroyed?"); - return; - } - - // Save helper - - var saveRowObj = UIFactory.CreateHorizontalGroup(parent, "SaveRow", true, true, true, true, 2, new Vector4(2,2,2,2), - new Color(0.1f, 0.1f, 0.1f)); - - var saveBtn = UIFactory.CreateButton(saveRowObj, "SaveButton", "Save .PNG", null, new Color(0.2f, 0.2f, 0.2f)); - UIFactory.SetLayoutElement(saveBtn.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 0); - - var inputObj = UIFactory.CreateInputField(saveRowObj, "SaveInput", "..."); - UIFactory.SetLayoutElement(inputObj, minHeight: 25, minWidth: 100, flexibleWidth: 9999); - var inputField = inputObj.GetComponent(); - - var name = tex.name; - if (string.IsNullOrEmpty(name)) - name = "untitled"; - - inputField.text = Path.Combine(ConfigManager.Default_Output_Path.Value, $"{name}.png"); - - saveBtn.onClick.AddListener(() => - { - if (tex && !string.IsNullOrEmpty(inputField.text)) - { - var path = inputField.text; - if (!path.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase)) - { - ExplorerCore.LogWarning("Desired save path must end with '.png'!"); - return; - } - - var dir = Path.GetDirectoryName(path); - if (!Directory.Exists(dir)) - Directory.CreateDirectory(dir); - - if (File.Exists(path)) - File.Delete(path); - - if (!TextureUtilProvider.IsReadable(tex)) - tex = TextureUtilProvider.ForceReadTexture(tex); - - byte[] data = TextureUtilProvider.Instance.EncodeToPNG(tex); - - File.WriteAllBytes(path, data); - } - }); - - // Actual texture viewer - - var imageObj = UIFactory.CreateUIObject("TextureViewerImage", parent); - var image = imageObj.AddComponent(); - var sprite = TextureUtilProvider.Instance.CreateSprite(tex); - image.sprite = sprite; - - var fitter = imageObj.AddComponent(); - fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; - - var imageLayout = imageObj.AddComponent(); - imageLayout.preferredHeight = sprite.rect.height; - imageLayout.preferredWidth = sprite.rect.width; - } - - internal void ToggleTextureViewer(bool enabled) - { - m_textureViewerObj.SetActive(enabled); - - m_filterAreaObj.SetActive(!enabled); - m_memberListObj.SetActive(!enabled); - m_updateRowObj.SetActive(!enabled); - } - - public void ConstructInstanceFilters(GameObject parent) - { - var memberFilterRowObj = UIFactory.CreateHorizontalGroup(parent, "InstanceFilterRow", false, false, true, true, 5, default, - new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(memberFilterRowObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 5000); - - var memLabel = UIFactory.CreateLabel(memberFilterRowObj, "MemberLabel", "Filter scope:", TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(memLabel.gameObject, minWidth: 100, minHeight: 25, flexibleWidth: 0); - - AddFilterButton(memberFilterRowObj, MemberScopes.All, true); - AddFilterButton(memberFilterRowObj, MemberScopes.Instance); - AddFilterButton(memberFilterRowObj, MemberScopes.Static); - } - - private void AddFilterButton(GameObject parent, MemberScopes type, bool setEnabled = false) - { - var btn = UIFactory.CreateButton(parent, - "ScopeFilterButton_" + type, - type.ToString(), - null, - new Color(0.2f, 0.2f, 0.2f)); - - UIFactory.SetLayoutElement(btn.gameObject, minHeight: 25, minWidth: 70); - - btn.onClick.AddListener(() => { OnScopeFilterClicked(type, btn); }); - - RuntimeProvider.Instance.SetColorBlock(btn, highlighted: new Color(0.3f, 0.7f, 0.3f)); - - if (setEnabled) - { - RuntimeProvider.Instance.SetColorBlock(btn, new Color(0.2f, 0.6f, 0.2f)); - m_scopeFilter = type; - m_lastActiveScopeButton = btn; - } - } - } -} diff --git a/src/UI/Inspectors/Reflection/ReflectionInspector.cs b/src/UI/Inspectors/Reflection/ReflectionInspector.cs deleted file mode 100644 index 0787477..0000000 --- a/src/UI/Inspectors/Reflection/ReflectionInspector.cs +++ /dev/null @@ -1,518 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core; -using UnityExplorer.Core.Config; -using UnityExplorer.Core.Runtime; -using UnityExplorer.UI.CacheObject; -using UnityExplorer.UI.Main; -using UnityExplorer.UI.Main.Home; -using UnityExplorer.UI.Utility; - -namespace UnityExplorer.UI.Inspectors.Reflection -{ - public class ReflectionInspector : InspectorBase - { - #region STATIC - - public static ReflectionInspector ActiveInstance { get; private set; } - - static ReflectionInspector() - { - PanelDragger.OnFinishResize += (RectTransform _) => OnContainerResized(); - SceneExplorer.OnToggleShow += OnContainerResized; - } - - private static void OnContainerResized(bool _ = false) - { - if (ActiveInstance == null) - return; - - ActiveInstance.m_widthUpdateWanted = true; - } - - // Blacklists - private static readonly HashSet bl_typeAndMember = new HashSet - { -#if CPP - // these cause a crash in IL2CPP - "Type.DeclaringMethod", - "Rigidbody2D.Cast", - "Collider2D.Cast", - "Collider2D.Raycast", - "Texture2D.SetPixelDataImpl", - "Camera.CalculateProjectionMatrixFromPhysicalProperties", -#endif - }; - private static readonly HashSet bl_memberNameStartsWith = new HashSet - { - // these are redundant - "get_", - "set_", - }; - - #endregion - - #region INSTANCE - - public override string TabLabel => m_targetTypeShortName; - - internal CacheObjectBase ParentMember { get; set; } - - internal readonly Type m_targetType; - internal readonly string m_targetTypeShortName; - - // all cached members of the target - internal CacheMember[] m_allMembers; - // filtered members based on current filters - internal readonly List m_membersFiltered = new List(); - // actual shortlist of displayed members - internal readonly CacheMember[] m_displayedMembers = new CacheMember[ConfigManager.Default_Page_Limit.Value]; - - internal bool m_autoUpdate; - - public ReflectionInspector(object target) : base(target) - { - if (this is StaticInspector) - m_targetType = target as Type; - else - m_targetType = ReflectionUtility.GetActualType(target); - - m_targetTypeShortName = SignatureHighlighter.ParseFullSyntax(m_targetType, false); - - ConstructUI(); - - CacheMembers(m_targetType); - - FilterMembers(); - } - - public override void SetActive() - { - base.SetActive(); - ActiveInstance = this; - } - - public override void SetInactive() - { - base.SetInactive(); - ActiveInstance = null; - } - - public override void Destroy() - { - base.Destroy(); - - if (this.Content) - GameObject.Destroy(this.Content); - } - - internal void OnPageTurned() - { - RefreshDisplay(); - } - - internal bool IsBlacklisted(string sig) => bl_typeAndMember.Any(it => sig.Contains(it)); - internal bool IsBlacklisted(MethodInfo method) => bl_memberNameStartsWith.Any(it => method.Name.StartsWith(it)); - - internal string GetSig(MemberInfo member) => $"{member.DeclaringType.Name}.{member.Name}"; - internal string AppendArgsToSig(ParameterInfo[] args) - { - string ret = " ("; - foreach (var param in args) - ret += $"{param.ParameterType.Name} {param.Name}, "; - ret += ")"; - return ret; - } - - public void CacheMembers(Type type) - { - var list = new List(); - var cachedSigs = new HashSet(); - - var types = ReflectionUtility.GetAllBaseTypes(type); - - var flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static; - if (this is InstanceInspector) - flags |= BindingFlags.Instance; - - foreach (var declaringType in types) - { - var target = Target; - target = target.Cast(declaringType); - - IEnumerable infos = declaringType.GetMethods(flags); - infos = infos.Concat(declaringType.GetProperties(flags)); - infos = infos.Concat(declaringType.GetFields(flags)); - - foreach (var member in infos) - { - try - { - var sig = GetSig(member); - - //ExplorerCore.Log($"Trying to cache member {sig}..."); - //ExplorerCore.Log(member.DeclaringType.FullName + "." + member.Name); - - var mi = member as MethodInfo; - var pi = member as PropertyInfo; - var fi = member as FieldInfo; - - if (IsBlacklisted(sig) || (mi != null && IsBlacklisted(mi))) - continue; - - var args = mi?.GetParameters() ?? pi?.GetIndexParameters(); - if (args != null) - { - if (!CacheMember.CanProcessArgs(args)) - continue; - - sig += AppendArgsToSig(args); - } - - if (cachedSigs.Contains(sig)) - continue; - - cachedSigs.Add(sig); - - if (mi != null) - list.Add(new CacheMethod(mi, target, m_scrollContent)); - else if (pi != null) - list.Add(new CacheProperty(pi, target, m_scrollContent)); - else - list.Add(new CacheField(fi, target, m_scrollContent)); - - list.Last().ParentInspector = this; - } - catch (Exception e) - { - ExplorerCore.LogWarning($"Exception caching member {member.DeclaringType.FullName}.{member.Name}!"); - ExplorerCore.Log(e.ToString()); - } - } - } - - var typeList = types.ToList(); - - var sorted = new List(); - sorted.AddRange(list.Where(it => it is CacheMethod) - .OrderBy(it => typeList.IndexOf(it.DeclaringType)) - .ThenBy(it => it.NameForFiltering)); - sorted.AddRange(list.Where(it => it is CacheProperty) - .OrderBy(it => typeList.IndexOf(it.DeclaringType)) - .ThenBy(it => it.NameForFiltering)); - sorted.AddRange(list.Where(it => it is CacheField) - .OrderBy(it => typeList.IndexOf(it.DeclaringType)) - .ThenBy(it => it.NameForFiltering)); - - m_allMembers = sorted.ToArray(); - } - - public override void Update() - { - base.Update(); - - if (m_autoUpdate) - { - foreach (var member in m_displayedMembers) - { - if (member == null) break; - member.UpdateValue(); - } - } - - if (m_widthUpdateWanted) - { - if (!m_widthUpdateWaiting) - m_widthUpdateWaiting = true; - else - { - UpdateWidths(); - m_widthUpdateWaiting = false; - m_widthUpdateWanted = false; - } - } - } - - internal void OnMemberFilterClicked(MemberTypes type, Button button) - { - if (m_lastActiveMemButton) - RuntimeProvider.Instance.SetColorBlock(m_lastActiveMemButton, new Color(0.2f, 0.2f, 0.2f)); - - m_memberFilter = type; - m_lastActiveMemButton = button; - - RuntimeProvider.Instance.SetColorBlock(m_lastActiveMemButton, new Color(0.2f, 0.6f, 0.2f)); - - FilterMembers(null, true); - m_sliderScroller.m_slider.value = 1f; - } - - public void FilterMembers(string nameFilter = null, bool force = false) - { - int lastCount = m_membersFiltered.Count; - m_membersFiltered.Clear(); - - nameFilter = nameFilter?.ToLower() ?? m_nameFilterText.text.ToLower(); - - foreach (var mem in m_allMembers) - { - // membertype filter - if (m_memberFilter != MemberTypes.All && mem.MemInfo.MemberType != m_memberFilter) - continue; - - if (this is InstanceInspector ii && ii.m_scopeFilter != MemberScopes.All) - { - if (mem.IsStatic && ii.m_scopeFilter != MemberScopes.Static) - continue; - else if (!mem.IsStatic && ii.m_scopeFilter != MemberScopes.Instance) - continue; - } - - // name filter - if (!string.IsNullOrEmpty(nameFilter) && !mem.NameForFiltering.Contains(nameFilter)) - continue; - - m_membersFiltered.Add(mem); - } - - if (force || lastCount != m_membersFiltered.Count) - RefreshDisplay(); - } - - public void RefreshDisplay() - { - var members = m_membersFiltered; - m_pageHandler.ListCount = members.Count; - - // disable current members - for (int i = 0; i < m_displayedMembers.Length; i++) - { - var mem = m_displayedMembers[i]; - if (mem != null) - mem.Disable(); - else - break; - } - - if (members.Count < 1) - return; - - foreach (var itemIndex in m_pageHandler) - { - if (itemIndex >= members.Count) - break; - - CacheMember member = members[itemIndex]; - m_displayedMembers[itemIndex - m_pageHandler.StartIndex] = member; - member.Enable(); - } - - m_widthUpdateWanted = true; - } - - internal void UpdateWidths() - { - float labelWidth = 125; - - foreach (var cache in m_displayedMembers) - { - if (cache == null) - break; - - var width = cache.GetMemberLabelWidth(m_scrollContentRect); - - if (width > labelWidth) - labelWidth = width; - } - - float valueWidth = m_scrollContentRect.rect.width - labelWidth - 20; - - foreach (var cache in m_displayedMembers) - { - if (cache == null) - break; - cache.SetWidths(labelWidth, valueWidth); - } - } - - - #endregion // end instance - - #region UI - - private GameObject m_content; - public override GameObject Content - { - get => m_content; - set => m_content = value; - } - - internal Text m_nameFilterText; - internal MemberTypes m_memberFilter; - internal Button m_lastActiveMemButton; - - internal PageHandler m_pageHandler; - internal SliderScrollbar m_sliderScroller; - internal GameObject m_scrollContent; - internal RectTransform m_scrollContentRect; - - internal bool m_widthUpdateWanted; - internal bool m_widthUpdateWaiting; - - internal GameObject m_filterAreaObj; - internal GameObject m_updateRowObj; - internal GameObject m_memberListObj; - - internal void ConstructUI() - { - var parent = InspectorManager.m_inspectorContent; - - this.Content = UIFactory.CreateVerticalGroup(parent, "ReflectionInspector", true, false, true, true, 5, new Vector4(4,4,4,4), - new Color(0.15f, 0.15f, 0.15f)); - - ConstructTopArea(); - - ConstructMemberList(); - } - - internal void ConstructTopArea() - { - var nameRowObj = UIFactory.CreateHorizontalGroup(Content, "NameRowObj", true, true, true, true, 2, default, new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(nameRowObj, minHeight: 25, flexibleHeight: 0, minWidth: 200, flexibleWidth: 5000); - - var typeLabelText = UIFactory.CreateLabel(nameRowObj, "TypeLabel", "Type:", TextAnchor.MiddleLeft); - typeLabelText.horizontalOverflow = HorizontalWrapMode.Overflow; - UIFactory.SetLayoutElement(typeLabelText.gameObject, minWidth: 40, flexibleWidth: 0, minHeight: 25); - - var typeDisplay = UIFactory.CreateLabel(nameRowObj, "TypeDisplayText", SignatureHighlighter.ParseFullSyntax(m_targetType, true), - TextAnchor.MiddleLeft); - - UIFactory.SetLayoutElement(typeDisplay.gameObject, minHeight: 25, flexibleWidth: 5000); - - // instance helper tools - - if (this is InstanceInspector instanceInspector) - { - instanceInspector.ConstructUnityInstanceHelpers(); - } - - ConstructFilterArea(); - - ConstructUpdateRow(); - } - - internal void ConstructFilterArea() - { - // Filters - - m_filterAreaObj = UIFactory.CreateVerticalGroup(Content, "FilterGroup", true, true, true, true, 4, new Vector4(4,4,4,4), - new Color(0.1f, 0.1f, 0.1f)); - UIFactory.SetLayoutElement(m_filterAreaObj, minHeight: 60); - - // name filter - - var nameFilterRowObj = UIFactory.CreateHorizontalGroup(m_filterAreaObj, "NameFilterRow", false, false, true, true, 5, default, - new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(nameFilterRowObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 5000); - - var nameLabel = UIFactory.CreateLabel(nameFilterRowObj, "NameLabel", "Filter names:", TextAnchor.MiddleLeft, Color.grey); - UIFactory.SetLayoutElement(nameLabel.gameObject, minWidth: 100, minHeight: 25, flexibleWidth: 0); - - var nameInputObj = UIFactory.CreateInputField(nameFilterRowObj, "NameInput", "...", 14, (int)TextAnchor.MiddleLeft, (int)HorizontalWrapMode.Overflow); - UIFactory.SetLayoutElement(nameInputObj, flexibleWidth: 5000, minWidth: 100, minHeight: 25); - var nameInput = nameInputObj.GetComponent(); - nameInput.onValueChanged.AddListener((string val) => { FilterMembers(val); }); - m_nameFilterText = nameInput.textComponent; - - // membertype filter - - var memberFilterRowObj = UIFactory.CreateHorizontalGroup(m_filterAreaObj, "MemberFilter", false, false, true, true, 5, default, - new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(memberFilterRowObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 5000); - - var memLabel = UIFactory.CreateLabel(memberFilterRowObj, "MemberFilterLabel", "Filter members:", TextAnchor.MiddleLeft, Color.grey); - UIFactory.SetLayoutElement(memLabel.gameObject, minWidth: 100, minHeight: 25, flexibleWidth: 0); - - AddFilterButton(memberFilterRowObj, MemberTypes.All); - AddFilterButton(memberFilterRowObj, MemberTypes.Method); - AddFilterButton(memberFilterRowObj, MemberTypes.Property, true); - AddFilterButton(memberFilterRowObj, MemberTypes.Field); - - // Instance filters - - if (this is InstanceInspector instanceInspector) - { - instanceInspector.ConstructInstanceFilters(m_filterAreaObj); - } - } - - private void AddFilterButton(GameObject parent, MemberTypes type, bool setEnabled = false) - { - var btn = UIFactory.CreateButton(parent, - "FilterButton_" + type, - type.ToString(), - null, - new Color(0.2f, 0.2f, 0.2f)); - UIFactory.SetLayoutElement(btn.gameObject, minHeight: 25, minWidth: 70); - btn.onClick.AddListener(() => { OnMemberFilterClicked(type, btn); }); - - RuntimeProvider.Instance.SetColorBlock(btn, highlighted: new Color(0.3f, 0.7f, 0.3f)); - - if (setEnabled) - { - RuntimeProvider.Instance.SetColorBlock(btn, new Color(0.2f, 0.6f, 0.2f)); - m_memberFilter = type; - m_lastActiveMemButton = btn; - } - } - - internal void ConstructUpdateRow() - { - m_updateRowObj = UIFactory.CreateHorizontalGroup(Content, "UpdateRow", false, true, true, true, 10, default, new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(m_updateRowObj, minHeight: 25); - - // update button - - var updateBtn = UIFactory.CreateButton(m_updateRowObj, "UpdateButton", "Update Values", null, new Color(0.2f, 0.2f, 0.2f)); - UIFactory.SetLayoutElement(updateBtn.gameObject, minWidth: 110, flexibleWidth: 0); - updateBtn.onClick.AddListener(() => - { - bool orig = m_autoUpdate; - m_autoUpdate = true; - Update(); - if (!orig) - m_autoUpdate = orig; - }); - - // auto update - - var autoUpdateObj = UIFactory.CreateToggle(m_updateRowObj, "UpdateToggle", out Toggle autoUpdateToggle, out Text autoUpdateText); - var autoUpdateLayout = autoUpdateObj.AddComponent(); - autoUpdateLayout.minWidth = 150; - autoUpdateLayout.minHeight = 25; - autoUpdateText.text = "Auto-update?"; - autoUpdateToggle.isOn = false; - autoUpdateToggle.onValueChanged.AddListener((bool val) => { m_autoUpdate = val; }); - } - - internal void ConstructMemberList() - { - m_memberListObj = UIFactory.CreateScrollView(Content, "MemberList", out m_scrollContent, out m_sliderScroller, new Color(0.05f, 0.05f, 0.05f)); - - m_scrollContentRect = m_scrollContent.GetComponent(); - - UIFactory.SetLayoutGroup(m_scrollContent, forceHeight: true, spacing: 3, padLeft: 0, padRight: 0); - - m_pageHandler = new PageHandler(m_sliderScroller); - m_pageHandler.ConstructUI(Content); - m_pageHandler.OnPageChanged += OnPageTurned; - } - } - - #endregion -} \ No newline at end of file diff --git a/src/UI/Inspectors/Reflection/StaticInspector.cs b/src/UI/Inspectors/Reflection/StaticInspector.cs deleted file mode 100644 index eeeb537..0000000 --- a/src/UI/Inspectors/Reflection/StaticInspector.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace UnityExplorer.UI.Inspectors.Reflection -{ - public class StaticInspector : ReflectionInspector - { - public override string TabLabel => $" [S] {base.TabLabel}"; - - public StaticInspector(Type type) : base(type) { } - } -} diff --git a/src/UI/InteractiveValues/InteractiveBool.cs b/src/UI/InteractiveValues/InteractiveBool.cs deleted file mode 100644 index 15970f5..0000000 --- a/src/UI/InteractiveValues/InteractiveBool.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Unity; -using UnityExplorer.UI; -using UnityExplorer.UI.CacheObject; - -namespace UnityExplorer.UI.InteractiveValues -{ - public class InteractiveBool : InteractiveValue - { - public InteractiveBool(object value, Type valueType) : base(value, valueType) { } - - public override bool HasSubContent => false; - public override bool SubContentWanted => false; - public override bool WantInspectBtn => false; - - internal Toggle m_toggle; - internal Button m_applyBtn; - - public override void OnValueUpdated() - { - base.OnValueUpdated(); - } - - public override void RefreshUIForValue() - { - GetDefaultLabel(); - - if (Owner.HasEvaluated) - { - var val = (bool)Value; - - if (Owner.CanWrite) - { - if (!m_toggle.gameObject.activeSelf) - m_toggle.gameObject.SetActive(true); - - if (!m_applyBtn.gameObject.activeSelf) - m_applyBtn.gameObject.SetActive(true); - - if (val != m_toggle.isOn) - m_toggle.isOn = val; - } - - var color = val - ? "6bc981" // on - : "c96b6b"; // off - - m_baseLabel.text = $"{val}"; - } - else - { - m_baseLabel.text = DefaultLabel; - } - } - - public override void OnException(CacheMember member) - { - base.OnException(member); - - if (Owner.CanWrite) - { - if (m_toggle.gameObject.activeSelf) - m_toggle.gameObject.SetActive(false); - - if (m_applyBtn.gameObject.activeSelf) - m_applyBtn.gameObject.SetActive(false); - } - } - - internal void OnToggleValueChanged(bool val) - { - Value = val; - RefreshUIForValue(); - } - - public override void ConstructUI(GameObject parent, GameObject subGroup) - { - base.ConstructUI(parent, subGroup); - - var baseLayout = m_baseLabel.gameObject.GetComponent(); - baseLayout.flexibleWidth = 0; - baseLayout.minWidth = 50; - - if (Owner.CanWrite) - { - var toggleObj = UIFactory.CreateToggle(m_mainContent, "InteractiveBoolToggle", out m_toggle, out _, new Color(0.1f, 0.1f, 0.1f)); - UIFactory.SetLayoutElement(toggleObj, minWidth: 24); - m_toggle.onValueChanged.AddListener(OnToggleValueChanged); - - m_baseLabel.transform.SetAsLastSibling(); - - m_applyBtn = UIFactory.CreateButton(m_mainContent, - "ApplyButton", - "Apply", - () => { Owner.SetValue(); }, - new Color(0.2f, 0.2f, 0.2f)); - - UIFactory.SetLayoutElement(m_applyBtn.gameObject, minWidth: 50, minHeight: 25, flexibleWidth: 0); - - toggleObj.SetActive(false); - m_applyBtn.gameObject.SetActive(false); - } - } - } -} diff --git a/src/UI/InteractiveValues/InteractiveColor.cs b/src/UI/InteractiveValues/InteractiveColor.cs deleted file mode 100644 index 501d129..0000000 --- a/src/UI/InteractiveValues/InteractiveColor.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.UI; - -namespace UnityExplorer.UI.InteractiveValues -{ - public class InteractiveColor : InteractiveValue - { - //~~~~~~~~~ Instance ~~~~~~~~~~ - - public InteractiveColor(object value, Type valueType) : base(value, valueType) { } - - public override bool HasSubContent => true; - public override bool SubContentWanted => true; - public override bool WantInspectBtn => true; - - public override void RefreshUIForValue() - { - base.RefreshUIForValue(); - - if (m_subContentConstructed) - RefreshUI(); - } - - private void RefreshUI() - { - var color = (Color)this.Value; - - m_inputs[0].text = color.r.ToString(); - m_inputs[1].text = color.g.ToString(); - m_inputs[2].text = color.b.ToString(); - m_inputs[3].text = color.a.ToString(); - - if (m_colorImage) - m_colorImage.color = color; - } - - internal override void OnToggleSubcontent(bool toggle) - { - base.OnToggleSubcontent(toggle); - - RefreshUI(); - } - - #region UI CONSTRUCTION - - private Image m_colorImage; - - private readonly InputField[] m_inputs = new InputField[4]; - private readonly Slider[] m_sliders = new Slider[4]; - - public override void ConstructUI(GameObject parent, GameObject subGroup) - { - base.ConstructUI(parent, subGroup); - - //// Limit the label width for colors, they're always about the same so make use of that space. - //UIFactory.SetLayoutElement(this.m_baseLabel.gameObject, flexibleWidth: 0, minWidth: 250); - } - - public override void ConstructSubcontent() - { - base.ConstructSubcontent(); - - var horiGroup = UIFactory.CreateHorizontalGroup(m_subContentParent, "ColorEditor", false, false, true, true, 5, - default, default, TextAnchor.MiddleLeft); - - var editorContainer = UIFactory.CreateVerticalGroup(horiGroup, "EditorContent", false, true, true, true, 2, new Vector4(4, 4, 4, 4), - new Color(0.08f, 0.08f, 0.08f)); - UIFactory.SetLayoutElement(editorContainer, minWidth: 300, flexibleWidth: 0); - - for (int i = 0; i < 4; i++) - AddEditorRow(i, editorContainer); - - if (Owner.CanWrite) - { - var applyBtn = UIFactory.CreateButton(editorContainer, "ApplyButton", "Apply", OnSetValue, new Color(0.2f, 0.2f, 0.2f)); - UIFactory.SetLayoutElement(applyBtn.gameObject, minWidth: 175, minHeight: 25, flexibleWidth: 0); - - void OnSetValue() - { - Owner.SetValue(); - RefreshUIForValue(); - } - } - - var imgHolder = UIFactory.CreateVerticalGroup(horiGroup, "ImgHolder", true, true, true, true, 0, new Vector4(1, 1, 1, 1), - new Color(0.08f, 0.08f, 0.08f)); - UIFactory.SetLayoutElement(imgHolder, minWidth: 128, minHeight: 128, flexibleWidth: 0, flexibleHeight: 0); - - var imgObj = UIFactory.CreateUIObject("ColorImageHelper", imgHolder, new Vector2(100, 25)); - m_colorImage = imgObj.AddComponent(); - m_colorImage.color = (Color)this.Value; - } - - private static readonly string[] s_fieldNames = new[] { "R", "G", "B", "A" }; - - internal void AddEditorRow(int index, GameObject groupObj) - { - var row = UIFactory.CreateHorizontalGroup(groupObj, "EditorRow_" + s_fieldNames[index], - false, true, true, true, 5, default, new Color(1, 1, 1, 0)); - - var label = UIFactory.CreateLabel(row, "RowLabel", $"{s_fieldNames[index]}:", TextAnchor.MiddleRight, Color.cyan); - UIFactory.SetLayoutElement(label.gameObject, minWidth: 50, flexibleWidth: 0, minHeight: 25); - - var inputFieldObj = UIFactory.CreateInputField(row, "InputField", "...", 14, 3, 1); - UIFactory.SetLayoutElement(inputFieldObj, minWidth: 120, minHeight: 25, flexibleWidth: 0); - - var inputField = inputFieldObj.GetComponent(); - m_inputs[index] = inputField; - inputField.characterValidation = InputField.CharacterValidation.Decimal; - - inputField.onValueChanged.AddListener((string value) => - { - float val = float.Parse(value); - SetValueToColor(val); - m_sliders[index].value = val; - }); - - var sliderObj = UIFactory.CreateSlider(row, "Slider", out Slider slider); - m_sliders[index] = slider; - UIFactory.SetLayoutElement(sliderObj, minWidth: 200, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0); - slider.minValue = 0; - slider.maxValue = 1; - slider.value = GetValueFromColor(); - - slider.onValueChanged.AddListener((float value) => - { - inputField.text = value.ToString(); - SetValueToColor(value); - m_inputs[index].text = value.ToString(); - }); - - // methods for writing to the color for this field - - void SetValueToColor(float floatValue) - { - Color _color = (Color)Value; - switch (index) - { - case 0: _color.r = floatValue; break; - case 1: _color.g = floatValue; break; - case 2: _color.b = floatValue; break; - case 3: _color.a = floatValue; break; - } - Value = _color; - m_colorImage.color = _color; - } - - float GetValueFromColor() - { - Color _color = (Color)Value; - switch (index) - { - case 0: return _color.r; - case 1: return _color.g; - case 2: return _color.b; - case 3: return _color.a; - default: throw new NotImplementedException(); - } - } - } - - #endregion - } -} diff --git a/src/UI/InteractiveValues/InteractiveDictionary.cs b/src/UI/InteractiveValues/InteractiveDictionary.cs deleted file mode 100644 index e2a182c..0000000 --- a/src/UI/InteractiveValues/InteractiveDictionary.cs +++ /dev/null @@ -1,247 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Config; -using UnityExplorer.Core.Unity; -using UnityExplorer.UI; -using System.Reflection; -using UnityExplorer.UI.CacheObject; -using UnityExplorer.Core; -using UnityExplorer.UI.Utility; -#if CPP -using AltIDictionary = Il2CppSystem.Collections.IDictionary; -#else -using AltIDictionary = System.Collections.IDictionary; -#endif - -namespace UnityExplorer.UI.InteractiveValues -{ - public class InteractiveDictionary : InteractiveValue - { - public InteractiveDictionary(object value, Type valueType) : base(value, valueType) - { - if (valueType.IsGenericType) - { - var gArgs = valueType.GetGenericArguments(); - m_typeOfKeys = gArgs[0]; - m_typeofValues = gArgs[1]; - } - else - { - m_typeOfKeys = typeof(object); - m_typeofValues = typeof(object); - } - } - - public override bool WantInspectBtn => false; - public override bool HasSubContent => true; - public override bool SubContentWanted - { - get - { - if (m_recacheWanted) - return true; - else return m_entries.Count > 0; - } - } - - internal IDictionary RefIDictionary; - internal AltIDictionary RefAltIDictionary; - internal Type m_typeOfKeys; - internal Type m_typeofValues; - - internal readonly List> m_entries - = new List>(); - - internal readonly KeyValuePair[] m_displayedEntries - = new KeyValuePair[ConfigManager.Default_Page_Limit.Value]; - - internal bool m_recacheWanted = true; - - public override void OnDestroy() - { - base.OnDestroy(); - } - - public override void OnValueUpdated() - { - RefIDictionary = Value as IDictionary; - - if (RefIDictionary == null) - { - try { RefAltIDictionary = Value.TryCast(); } - catch { } - } - - if (m_subContentParent.activeSelf) - { - GetCacheEntries(); - RefreshDisplay(); - } - else - m_recacheWanted = true; - - base.OnValueUpdated(); - } - - internal void OnPageTurned() - { - RefreshDisplay(); - } - - public override void RefreshUIForValue() - { - GetDefaultLabel(); - - if (Value != null) - { - string count = "?"; - if (m_recacheWanted && RefIDictionary != null) - count = RefIDictionary.Count.ToString(); - else if (!m_recacheWanted) - count = m_entries.Count.ToString(); - - m_baseLabel.text = $"[{count}] {m_richValueType}"; - } - else - { - m_baseLabel.text = DefaultLabel; - } - } - - public void GetCacheEntries() - { - if (m_entries.Any()) - { - // maybe improve this, probably could be more efficient i guess - - foreach (var pair in m_entries) - { - pair.Key.Destroy(); - pair.Value.Destroy(); - } - - m_entries.Clear(); - } - - if (RefIDictionary == null && Value != null) - RefIDictionary = RuntimeProvider.Instance.Reflection.EnumerateDictionary(Value, m_typeOfKeys, m_typeofValues); - - if (RefIDictionary != null) - { - int index = 0; - - foreach (var key in RefIDictionary.Keys) - { - var value = RefIDictionary[key]; - - var cacheKey = new CachePaired(index, this, this.RefIDictionary, PairTypes.Key, m_listContent); - cacheKey.CreateIValue(key, this.m_typeOfKeys); - cacheKey.Disable(); - - var cacheValue = new CachePaired(index, this, this.RefIDictionary, PairTypes.Value, m_listContent); - cacheValue.CreateIValue(value, this.m_typeofValues); - cacheValue.Disable(); - - //holder.SetActive(false); - - m_entries.Add(new KeyValuePair(cacheKey, cacheValue)); - - index++; - } - } - - RefreshDisplay(); - } - - public void RefreshDisplay() - { - var entries = m_entries; - m_pageHandler.ListCount = entries.Count; - - for (int i = 0; i < m_displayedEntries.Length; i++) - { - var entry = m_displayedEntries[i]; - if (entry.Key != null && entry.Value != null) - { - //m_rowHolders[i].SetActive(false); - entry.Key.Disable(); - entry.Value.Disable(); - } - else - break; - } - - if (entries.Count < 1) - return; - - foreach (var itemIndex in m_pageHandler) - { - if (itemIndex >= entries.Count) - break; - - var entry = entries[itemIndex]; - m_displayedEntries[itemIndex - m_pageHandler.StartIndex] = entry; - - //m_rowHolders[itemIndex].SetActive(true); - entry.Key.Enable(); - entry.Value.Enable(); - } - - //UpdateSubcontentHeight(); - } - - internal override void OnToggleSubcontent(bool active) - { - base.OnToggleSubcontent(active); - - if (active && m_recacheWanted) - { - m_recacheWanted = false; - GetCacheEntries(); - RefreshUIForValue(); - } - - RefreshDisplay(); - } - - internal GameObject m_listContent; - internal LayoutElement m_listLayout; - - internal PageHandler m_pageHandler; - - public override void ConstructUI(GameObject parent, GameObject subGroup) - { - base.ConstructUI(parent, subGroup); - } - - public override void ConstructSubcontent() - { - base.ConstructSubcontent(); - - m_pageHandler = new PageHandler(null); - m_pageHandler.ConstructUI(m_subContentParent); - m_pageHandler.OnPageChanged += OnPageTurned; - - m_listContent = UIFactory.CreateVerticalGroup(m_subContentParent, "DictionaryContent", true, true, true, true, 2, new Vector4(5,5,5,5), - new Color(0.08f, 0.08f, 0.08f)); - - var scrollRect = m_listContent.GetComponent(); - scrollRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 0); - - m_listLayout = Owner.m_mainContent.GetComponent(); - m_listLayout.minHeight = 25; - m_listLayout.flexibleHeight = 0; - - Owner.m_mainRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 25); - - var contentFitter = m_listContent.AddComponent(); - contentFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained; - contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; - } - } -} diff --git a/src/UI/InteractiveValues/InteractiveEnum.cs b/src/UI/InteractiveValues/InteractiveEnum.cs deleted file mode 100644 index 5384013..0000000 --- a/src/UI/InteractiveValues/InteractiveEnum.cs +++ /dev/null @@ -1,164 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Unity; -using UnityExplorer.UI; - -namespace UnityExplorer.UI.InteractiveValues -{ - public class InteractiveEnum : InteractiveValue - { - internal static Dictionary[]> s_enumNamesCache = new Dictionary[]>(); - - public InteractiveEnum(object value, Type valueType) : base(value, valueType) - { - GetNames(); - } - - public override bool HasSubContent => true; - public override bool SubContentWanted => Owner.CanWrite; - public override bool WantInspectBtn => false; - - internal KeyValuePair[] m_values = new KeyValuePair[0]; - - internal Type m_lastEnumType; - - internal void GetNames() - { - var type = Value?.GetType() ?? FallbackType; - - if (m_lastEnumType == type) - return; - - m_lastEnumType = type; - - if (m_subContentConstructed) - { - DestroySubContent(); - } - - if (!s_enumNamesCache.ContainsKey(type)) - { - // using GetValues not GetNames, to catch instances of weird enums (eg CameraClearFlags) - var values = Enum.GetValues(type); - - var list = new List>(); - var set = new HashSet(); - - foreach (var value in values) - { - var name = value.ToString(); - - if (set.Contains(name)) - continue; - - set.Add(name); - - var backingType = Enum.GetUnderlyingType(type); - int intValue; - try - { - // this approach is necessary, a simple '(int)value' is not sufficient. - - var unbox = Convert.ChangeType(value, backingType); - - intValue = (int)Convert.ChangeType(unbox, typeof(int)); - } - catch (Exception ex) - { - ExplorerCore.LogWarning("[InteractiveEnum] Could not Unbox underlying type " + backingType.Name + " from " + type.FullName); - ExplorerCore.Log(ex.ToString()); - continue; - } - - list.Add(new KeyValuePair(intValue, name)); - } - - s_enumNamesCache.Add(type, list.ToArray()); - } - - m_values = s_enumNamesCache[type]; - } - - public override void OnValueUpdated() - { - GetNames(); - - base.OnValueUpdated(); - } - - public override void RefreshUIForValue() - { - base.RefreshUIForValue(); - - if (m_subContentConstructed && !(this is InteractiveFlags)) - { - m_dropdownText.text = Value?.ToString() ?? ""; - } - } - - internal override void OnToggleSubcontent(bool toggle) - { - base.OnToggleSubcontent(toggle); - - RefreshUIForValue(); - } - - private void SetValueFromDropdown() - { - var type = Value?.GetType() ?? FallbackType; - var index = m_dropdown.value; - - var value = Enum.Parse(type, s_enumNamesCache[type][index].Value); - - if (value != null) - { - Value = value; - Owner.SetValue(); - RefreshUIForValue(); - } - } - - internal Dropdown m_dropdown; - internal Text m_dropdownText; - - public override void ConstructUI(GameObject parent, GameObject subGroup) - { - base.ConstructUI(parent, subGroup); - } - - public override void ConstructSubcontent() - { - base.ConstructSubcontent(); - - if (Owner.CanWrite) - { - var groupObj = UIFactory.CreateHorizontalGroup(m_subContentParent, "InteractiveEnumGroup", false, true, true, true, 5, - new Vector4(3,3,3,3),new Color(1, 1, 1, 0)); - - // apply button - - var apply = UIFactory.CreateButton(groupObj, "ApplyButton", "Apply", SetValueFromDropdown, new Color(0.3f, 0.3f, 0.3f)); - UIFactory.SetLayoutElement(apply.gameObject, minHeight: 25, minWidth: 50); - - // dropdown - - var dropdownObj = UIFactory.CreateDropdown(groupObj, out m_dropdown, "", 14, null); - UIFactory.SetLayoutElement(dropdownObj, minWidth: 150, minHeight: 25, flexibleWidth: 120); - - foreach (var kvp in m_values) - { - m_dropdown.options.Add(new Dropdown.OptionData - { - text = $"{kvp.Key}: {kvp.Value}" - }); - } - - m_dropdownText = m_dropdown.transform.Find("Label").GetComponent(); - } - } - } -} diff --git a/src/UI/InteractiveValues/InteractiveEnumerable.cs b/src/UI/InteractiveValues/InteractiveEnumerable.cs deleted file mode 100644 index 65731db..0000000 --- a/src/UI/InteractiveValues/InteractiveEnumerable.cs +++ /dev/null @@ -1,207 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core; -using UnityExplorer.Core.Config; -using UnityExplorer.Core.Unity; -using UnityExplorer.UI; -using UnityExplorer.UI.CacheObject; -using UnityExplorer.UI.Utility; - -namespace UnityExplorer.UI.InteractiveValues -{ - public class InteractiveEnumerable : InteractiveValue - { - public InteractiveEnumerable(object value, Type valueType) : base(value, valueType) - { - if (valueType.IsGenericType) - m_baseEntryType = valueType.GetGenericArguments()[0]; - else - m_baseEntryType = typeof(object); - } - - public override bool WantInspectBtn => false; - public override bool HasSubContent => true; - public override bool SubContentWanted - { - get - { - if (m_recacheWanted) - return true; - else return m_entries.Count > 0; - } - } - - internal IEnumerable RefIEnumerable; - internal IList RefIList; - - internal readonly Type m_baseEntryType; - - internal readonly List m_entries = new List(); - internal readonly CacheEnumerated[] m_displayedEntries = new CacheEnumerated[ConfigManager.Default_Page_Limit.Value]; - internal bool m_recacheWanted = true; - - public override void OnValueUpdated() - { - RefIEnumerable = Value as IEnumerable; - RefIList = Value as IList; - - if (m_subContentParent.activeSelf) - { - GetCacheEntries(); - RefreshDisplay(); - } - else - m_recacheWanted = true; - - base.OnValueUpdated(); - } - - public override void OnException(CacheMember member) - { - base.OnException(member); - } - - private void OnPageTurned() - { - RefreshDisplay(); - } - - public override void RefreshUIForValue() - { - GetDefaultLabel(); - - if (Value != null) - { - string count = "?"; - if (m_recacheWanted && RefIList != null) - count = RefIList.Count.ToString(); - else if (!m_recacheWanted) - count = m_entries.Count.ToString(); - - m_baseLabel.text = $"[{count}] {m_richValueType}"; - } - else - { - m_baseLabel.text = DefaultLabel; - } - } - - public void GetCacheEntries() - { - if (m_entries.Any()) - { - // maybe improve this, probably could be more efficient i guess - - foreach (var entry in m_entries) - entry.Destroy(); - - m_entries.Clear(); - } - - if (RefIEnumerable == null && Value != null) - RefIEnumerable = RuntimeProvider.Instance.Reflection.EnumerateEnumerable(Value); - - if (RefIEnumerable != null) - { - int index = 0; - foreach (var entry in RefIEnumerable) - { - var cache = new CacheEnumerated(index, this, RefIList, this.m_listContent); - cache.CreateIValue(entry, m_baseEntryType); - m_entries.Add(cache); - - cache.Disable(); - - index++; - } - } - - RefreshDisplay(); - } - - public void RefreshDisplay() - { - var entries = m_entries; - m_pageHandler.ListCount = entries.Count; - - for (int i = 0; i < m_displayedEntries.Length; i++) - { - var entry = m_displayedEntries[i]; - if (entry != null) - entry.Disable(); - else - break; - } - - if (entries.Count < 1) - return; - - foreach (var itemIndex in m_pageHandler) - { - if (itemIndex >= entries.Count) - break; - - CacheEnumerated entry = entries[itemIndex]; - m_displayedEntries[itemIndex - m_pageHandler.StartIndex] = entry; - entry.Enable(); - } - - //UpdateSubcontentHeight(); - } - - internal override void OnToggleSubcontent(bool active) - { - base.OnToggleSubcontent(active); - - if (active && m_recacheWanted) - { - m_recacheWanted = false; - GetCacheEntries(); - RefreshUIForValue(); - } - - RefreshDisplay(); - } - - - internal GameObject m_listContent; - internal LayoutElement m_listLayout; - - internal PageHandler m_pageHandler; - - public override void ConstructUI(GameObject parent, GameObject subGroup) - { - base.ConstructUI(parent, subGroup); - } - - public override void ConstructSubcontent() - { - base.ConstructSubcontent(); - - m_pageHandler = new PageHandler(null); - m_pageHandler.ConstructUI(m_subContentParent); - m_pageHandler.OnPageChanged += OnPageTurned; - - m_listContent = UIFactory.CreateVerticalGroup(this.m_subContentParent, "EnumerableContent", true, true, true, true, 2, new Vector4(5,5,5,5), - new Color(0.08f, 0.08f, 0.08f)); - - var scrollRect = m_listContent.GetComponent(); - scrollRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 0); - - m_listLayout = Owner.m_mainContent.GetComponent(); - m_listLayout.minHeight = 25; - m_listLayout.flexibleHeight = 0; - Owner.m_mainRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 25); - - var contentFitter = m_listContent.AddComponent(); - contentFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained; - contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; - } - } -} diff --git a/src/UI/InteractiveValues/InteractiveFlags.cs b/src/UI/InteractiveValues/InteractiveFlags.cs deleted file mode 100644 index 48b94dc..0000000 --- a/src/UI/InteractiveValues/InteractiveFlags.cs +++ /dev/null @@ -1,126 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Unity; -using UnityExplorer.UI; - -namespace UnityExplorer.UI.InteractiveValues -{ - public class InteractiveFlags : InteractiveEnum - { - public InteractiveFlags(object value, Type valueType) : base(value, valueType) - { - m_toggles = new Toggle[m_values.Length]; - m_enabledFlags = new bool[m_values.Length]; - } - - public override bool HasSubContent => true; - public override bool SubContentWanted => Owner.CanWrite; - public override bool WantInspectBtn => false; - - internal bool[] m_enabledFlags; - internal Toggle[] m_toggles; - - public override void OnValueUpdated() - { - if (Owner.CanWrite) - { - var enabledNames = new List(); - - var enabled = Value?.ToString().Split(',').Select(it => it.Trim()); - if (enabled != null) - enabledNames.AddRange(enabled); - - for (int i = 0; i < m_values.Length; i++) - m_enabledFlags[i] = enabledNames.Contains(m_values[i].Value); - } - - base.OnValueUpdated(); - } - - public override void RefreshUIForValue() - { - GetDefaultLabel(); - m_baseLabel.text = DefaultLabel; - - base.RefreshUIForValue(); - - if (m_subContentConstructed) - { - for (int i = 0; i < m_values.Length; i++) - { - var toggle = m_toggles[i]; - if (toggle.isOn != m_enabledFlags[i]) - toggle.isOn = m_enabledFlags[i]; - } - } - } - - private void SetValueFromToggles() - { - string val = ""; - for (int i = 0; i < m_values.Length; i++) - { - if (m_enabledFlags[i]) - { - if (val != "") val += ", "; - val += m_values[i].Value; - } - } - var type = Value?.GetType() ?? FallbackType; - Value = Enum.Parse(type, val); - RefreshUIForValue(); - Owner.SetValue(); - } - - internal override void OnToggleSubcontent(bool toggle) - { - base.OnToggleSubcontent(toggle); - - RefreshUIForValue(); - } - - public override void ConstructUI(GameObject parent, GameObject subGroup) - { - base.ConstructUI(parent, subGroup); - } - - public override void ConstructSubcontent() - { - m_subContentConstructed = true; - - if (Owner.CanWrite) - { - var groupObj = UIFactory.CreateVerticalGroup(m_subContentParent, "InteractiveFlagsContent", false, true, true, true, 5, - new Vector4(3,3,3,3), new Color(1, 1, 1, 0)); - - // apply button - - var apply = UIFactory.CreateButton(groupObj, "ApplyButton", "Apply", SetValueFromToggles, new Color(0.3f, 0.3f, 0.3f)); - UIFactory.SetLayoutElement(apply.gameObject, minWidth: 50, minHeight: 25); - - // toggles - - for (int i = 0; i < m_values.Length; i++) - AddToggle(i, groupObj); - } - } - - internal void AddToggle(int index, GameObject groupObj) - { - var value = m_values[index]; - - var toggleObj = UIFactory.CreateToggle(groupObj, "FlagToggle", out Toggle toggle, out Text text, new Color(0.1f, 0.1f, 0.1f)); - UIFactory.SetLayoutElement(toggleObj, minWidth: 100, flexibleWidth: 2000, minHeight: 25); - - m_toggles[index] = toggle; - - toggle.onValueChanged.AddListener((bool val) => { m_enabledFlags[index] = val; }); - - text.text = $"{value.Key}: {value.Value}"; - } - } -} diff --git a/src/UI/InteractiveValues/InteractiveFloatStruct.cs b/src/UI/InteractiveValues/InteractiveFloatStruct.cs deleted file mode 100644 index 81a1bef..0000000 --- a/src/UI/InteractiveValues/InteractiveFloatStruct.cs +++ /dev/null @@ -1,201 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.UI; -using System.Reflection; - -namespace UnityExplorer.UI.InteractiveValues -{ - // Class for supporting any "float struct" (ie Vector, Rect, etc). - // Supports any struct where all the public instance fields are floats (or types assignable to float) - - public class StructInfo - { - public string[] FieldNames { get; } - private readonly FieldInfo[] m_fields; - - public StructInfo(Type type) - { - m_fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public) - .Where(it => !it.IsLiteral) - .ToArray(); - - FieldNames = m_fields.Select(it => it.Name) - .ToArray(); - } - - public object SetValue(ref object instance, int fieldIndex, float val) - { - m_fields[fieldIndex].SetValue(instance, val); - return instance; - } - - public float GetValue(object instance, int fieldIndex) - => (float)m_fields[fieldIndex].GetValue(instance); - - public void RefreshUI(InputField[] inputs, object instance) - { - try - { - for (int i = 0; i < m_fields.Length; i++) - { - var field = m_fields[i]; - float val = (float)field.GetValue(instance); - inputs[i].text = val.ToString(); - } - } - catch (Exception ex) - { - ExplorerCore.Log(ex); - } - } - } - - public class InteractiveFloatStruct : InteractiveValue - { - private static readonly Dictionary _typeSupportCache = new Dictionary(); - public static bool IsTypeSupported(Type type) - { - if (!type.IsValueType) - return false; - - if (string.IsNullOrEmpty(type.AssemblyQualifiedName)) - return false; - - if (_typeSupportCache.TryGetValue(type.AssemblyQualifiedName, out bool ret)) - return ret; - - ret = true; - var fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); - foreach (var field in fields) - { - if (field.IsLiteral) - continue; - - if (!typeof(float).IsAssignableFrom(field.FieldType)) - { - ret = false; - break; - } - } - _typeSupportCache.Add(type.AssemblyQualifiedName, ret); - return ret; - } - - //~~~~~~~~~ Instance ~~~~~~~~~~ - - public InteractiveFloatStruct(object value, Type valueType) : base(value, valueType) { } - - public override bool HasSubContent => true; - public override bool SubContentWanted => true; - - public StructInfo StructInfo; - - public override void RefreshUIForValue() - { - InitializeStructInfo(); - - base.RefreshUIForValue(); - - if (m_subContentConstructed) - StructInfo.RefreshUI(m_inputs, this.Value); - } - - internal override void OnToggleSubcontent(bool toggle) - { - InitializeStructInfo(); - - base.OnToggleSubcontent(toggle); - - StructInfo.RefreshUI(m_inputs, this.Value); - } - - internal Type m_lastStructType; - - internal void InitializeStructInfo() - { - var type = Value?.GetType() ?? FallbackType; - - if (StructInfo != null && type == m_lastStructType) - return; - - if (StructInfo != null && m_subContentConstructed) - DestroySubContent(); - - m_lastStructType = type; - - StructInfo = new StructInfo(type); - - if (m_subContentParent.activeSelf) - ConstructSubcontent(); - } - - #region UI CONSTRUCTION - - internal InputField[] m_inputs; - - public override void ConstructUI(GameObject parent, GameObject subGroup) - { - base.ConstructUI(parent, subGroup); - } - - public override void ConstructSubcontent() - { - base.ConstructSubcontent(); - - if (StructInfo == null) - { - ExplorerCore.LogWarning("Setting up subcontent but structinfo is null"); - return; - } - - var editorContainer = UIFactory.CreateVerticalGroup(m_subContentParent, "EditorContent", false, true, true, true, 2, new Vector4(4, 4, 4, 4), - new Color(0.08f, 0.08f, 0.08f)); - - m_inputs = new InputField[StructInfo.FieldNames.Length]; - - for (int i = 0; i < StructInfo.FieldNames.Length; i++) - AddEditorRow(i, editorContainer); - - RefreshUIForValue(); - } - - internal void AddEditorRow(int index, GameObject groupObj) - { - try - { - var row = UIFactory.CreateHorizontalGroup(groupObj, "EditorRow", false, true, true, true, 5, default, new Color(1, 1, 1, 0)); - - string name = StructInfo.FieldNames[index]; - - var label = UIFactory.CreateLabel(row, "RowLabel", $"{name}:", TextAnchor.MiddleRight, Color.cyan); - UIFactory.SetLayoutElement(label.gameObject, minWidth: 30, flexibleWidth: 0, minHeight: 25); - - var inputFieldObj = UIFactory.CreateInputField(row, "InputField", "...", 14, 3, 1); - UIFactory.SetLayoutElement(inputFieldObj, minWidth: 120, minHeight: 25, flexibleWidth: 0); - - var inputField = inputFieldObj.GetComponent(); - m_inputs[index] = inputField; - - inputField.onValueChanged.AddListener((string val) => - { - try - { - float f = float.Parse(val); - Value = StructInfo.SetValue(ref this.Value, index, f); - Owner.SetValue(); - } - catch { } - }); - } - catch (Exception ex) - { - ExplorerCore.Log(ex); - } - } - - #endregion - } -} diff --git a/src/UI/InteractiveValues/InteractiveNumber.cs b/src/UI/InteractiveValues/InteractiveNumber.cs deleted file mode 100644 index 32b3d3e..0000000 --- a/src/UI/InteractiveValues/InteractiveNumber.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Reflection; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Unity; -using UnityExplorer.UI; -using UnityExplorer.Core; -using UnityExplorer.UI.Utility; -using UnityExplorer.UI.CacheObject; - -namespace UnityExplorer.UI.InteractiveValues -{ - public class InteractiveNumber : InteractiveValue - { - public InteractiveNumber(object value, Type valueType) : base(value, valueType) { } - - public override bool HasSubContent => false; - public override bool SubContentWanted => false; - public override bool WantInspectBtn => false; - - public override void OnValueUpdated() - { - base.OnValueUpdated(); - } - - public override void OnException(CacheMember member) - { - base.OnException(member); - - if (m_valueInput.gameObject.activeSelf) - m_valueInput.gameObject.SetActive(false); - - if (Owner.CanWrite) - { - if (m_applyBtn.gameObject.activeSelf) - m_applyBtn.gameObject.SetActive(false); - } - } - - public override void RefreshUIForValue() - { - if (!Owner.HasEvaluated) - { - GetDefaultLabel(); - m_baseLabel.text = DefaultLabel; - return; - } - - m_baseLabel.text = SignatureHighlighter.ParseFullSyntax(FallbackType, false); - m_valueInput.text = Value.ToString(); - - var type = Value.GetType(); - if (type == typeof(float) - || type == typeof(double) - || type == typeof(decimal)) - { - m_valueInput.characterValidation = InputField.CharacterValidation.Decimal; - } - else - { - m_valueInput.characterValidation = InputField.CharacterValidation.Integer; - } - - if (Owner.CanWrite) - { - if (!m_applyBtn.gameObject.activeSelf) - m_applyBtn.gameObject.SetActive(true); - } - - if (!m_valueInput.gameObject.activeSelf) - m_valueInput.gameObject.SetActive(true); - } - - public MethodInfo ParseMethod => m_parseMethod ?? (m_parseMethod = Value.GetType().GetMethod("Parse", new Type[] { typeof(string) })); - private MethodInfo m_parseMethod; - - internal void OnApplyClicked() - { - try - { - Value = ParseMethod.Invoke(null, new object[] { m_valueInput.text }); - Owner.SetValue(); - RefreshUIForValue(); - } - catch (Exception e) - { - ExplorerCore.LogWarning("Could not parse input! " + ReflectionUtility.ReflectionExToString(e, true)); - } - } - - internal InputField m_valueInput; - internal Button m_applyBtn; - - public override void ConstructUI(GameObject parent, GameObject subGroup) - { - base.ConstructUI(parent, subGroup); - - var labelLayout = m_baseLabel.gameObject.GetComponent(); - labelLayout.minWidth = 50; - labelLayout.flexibleWidth = 0; - - var inputObj = UIFactory.CreateInputField(m_mainContent, "InteractiveNumberInput", "..."); - UIFactory.SetLayoutElement(inputObj, minWidth: 120, minHeight: 25, flexibleWidth: 0); - - m_valueInput = inputObj.GetComponent(); - m_valueInput.gameObject.SetActive(false); - - if (Owner.CanWrite) - { - m_applyBtn = UIFactory.CreateButton(m_mainContent, "ApplyButton", "Apply", OnApplyClicked, new Color(0.2f, 0.2f, 0.2f)); - UIFactory.SetLayoutElement(m_applyBtn.gameObject, minWidth: 50, minHeight: 25, flexibleWidth: 0); - } - } - } -} diff --git a/src/UI/InteractiveValues/InteractiveString.cs b/src/UI/InteractiveValues/InteractiveString.cs deleted file mode 100644 index c14d758..0000000 --- a/src/UI/InteractiveValues/InteractiveString.cs +++ /dev/null @@ -1,188 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Reflection; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Unity; -using UnityExplorer.UI; -using UnityExplorer.UI.Utility; -using UnityExplorer.UI.CacheObject; -using UnityExplorer.Core.Runtime; - -namespace UnityExplorer.UI.InteractiveValues -{ - public class InteractiveString : InteractiveValue - { - public InteractiveString(object value, Type valueType) : base(value, valueType) { } - - public override bool HasSubContent => true; - public override bool SubContentWanted => true; - - public override bool WantInspectBtn => false; - - public override void OnValueUpdated() - { - if (!(Value is string) && Value != null) - Value = RuntimeProvider.Instance.Reflection.UnboxString(Value); - - base.OnValueUpdated(); - } - - public override void OnException(CacheMember member) - { - base.OnException(member); - - if (m_subContentConstructed && m_hiddenObj.gameObject.activeSelf) - m_hiddenObj.gameObject.SetActive(false); - - m_labelLayout.minWidth = 200; - m_labelLayout.flexibleWidth = 5000; - } - - public override void RefreshUIForValue() - { - GetDefaultLabel(false); - - if (!Owner.HasEvaluated) - { - m_baseLabel.text = DefaultLabel; - return; - } - - m_baseLabel.text = m_richValueType; - - if (m_subContentConstructed) - { - if (!m_hiddenObj.gameObject.activeSelf) - m_hiddenObj.gameObject.SetActive(true); - } - - if (!string.IsNullOrEmpty((string)Value)) - { - var toString = (string)Value; - if (toString.Length > 15000) - toString = toString.Substring(0, 15000); - - m_readonlyInput.text = toString; - - if (m_subContentConstructed) - { - m_valueInput.text = toString; - m_placeholderText.text = toString; - } - } - else - { - string s = Value == null - ? "null" - : "empty"; - - m_readonlyInput.text = $"{s}"; - - if (m_subContentConstructed) - { - m_valueInput.text = ""; - m_placeholderText.text = s; - } - } - - m_labelLayout.minWidth = 50; - m_labelLayout.flexibleWidth = 0; - } - - internal void SetValueFromInput() - { - Value = m_valueInput.text; - - if (!typeof(string).IsAssignableFrom(Owner.FallbackType)) - ReflectionProvider.Instance.BoxStringToType(ref Value, Owner.FallbackType); - - Owner.SetValue(); - - // revert back to string now - OnValueUpdated(); - - RefreshUIForValue(); - } - - // for the default label - internal LayoutElement m_labelLayout; - - //internal InputField m_readonlyInput; - internal Text m_readonlyInput; - - // for input - internal InputField m_valueInput; - internal GameObject m_hiddenObj; - internal Text m_placeholderText; - - public override void ConstructUI(GameObject parent, GameObject subGroup) - { - base.ConstructUI(parent, subGroup); - - GetDefaultLabel(false); - m_richValueType = SignatureHighlighter.ParseFullSyntax(FallbackType, false); - - m_labelLayout = m_baseLabel.gameObject.GetComponent(); - - m_readonlyInput = UIFactory.CreateLabel(m_mainContent, "ReadonlyLabel", "", TextAnchor.MiddleLeft); - m_readonlyInput.horizontalOverflow = HorizontalWrapMode.Overflow; - - var testFitter = m_readonlyInput.gameObject.AddComponent(); - testFitter.verticalFit = ContentSizeFitter.FitMode.MinSize; - - UIFactory.SetLayoutElement(m_readonlyInput.gameObject, minHeight: 25, preferredHeight: 25, flexibleHeight: 0); - } - - public override void ConstructSubcontent() - { - base.ConstructSubcontent(); - - var groupObj = UIFactory.CreateVerticalGroup(m_subContentParent, "SubContent", false, false, true, true, 4, new Vector4(3,3,3,3), - new Color(1, 1, 1, 0)); - - m_hiddenObj = UIFactory.CreateLabel(groupObj, "HiddenLabel", "", TextAnchor.MiddleLeft).gameObject; - m_hiddenObj.SetActive(false); - var hiddenText = m_hiddenObj.GetComponent(); - hiddenText.color = Color.clear; - hiddenText.fontSize = 14; - hiddenText.raycastTarget = false; - hiddenText.supportRichText = false; - var hiddenFitter = m_hiddenObj.AddComponent(); - hiddenFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize; - UIFactory.SetLayoutElement(m_hiddenObj, minHeight: 25, flexibleHeight: 500, minWidth: 250, flexibleWidth: 9000); - UIFactory.SetLayoutGroup(m_hiddenObj, true, true, true, true); - - var inputObj = UIFactory.CreateInputField(m_hiddenObj, "StringInputField", "...", 14, 3); - UIFactory.SetLayoutElement(inputObj, minWidth: 120, minHeight: 25, flexibleWidth: 5000, flexibleHeight: 5000); - - m_valueInput = inputObj.GetComponent(); - m_valueInput.lineType = InputField.LineType.MultiLineNewline; - - m_placeholderText = m_valueInput.placeholder.GetComponent(); - - m_placeholderText.supportRichText = false; - m_valueInput.textComponent.supportRichText = false; - - m_valueInput.onValueChanged.AddListener((string val) => - { - hiddenText.text = val ?? ""; - LayoutRebuilder.ForceRebuildLayoutImmediate(Owner.m_mainRect); - }); - - if (Owner.CanWrite) - { - var apply = UIFactory.CreateButton(groupObj, "ApplyButton", "Apply", SetValueFromInput, new Color(0.2f, 0.2f, 0.2f)); - UIFactory.SetLayoutElement(apply.gameObject, minWidth: 50, minHeight: 25, flexibleWidth: 0); - } - else - { - m_valueInput.readOnly = true; - } - - RefreshUIForValue(); - } - } -} diff --git a/src/UI/InteractiveValues/InteractiveValue.cs b/src/UI/InteractiveValues/InteractiveValue.cs deleted file mode 100644 index 343a9b7..0000000 --- a/src/UI/InteractiveValues/InteractiveValue.cs +++ /dev/null @@ -1,352 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using UnityEngine; -using UnityEngine.EventSystems; -using UnityEngine.UI; -using UnityExplorer.Core; -using UnityExplorer.Core.Unity; -using UnityExplorer.Core.Runtime; -using UnityExplorer.UI; -using UnityExplorer.UI.Utility; -using UnityExplorer.UI.CacheObject; -using UnityExplorer.UI.Main.Home; -using UnityExplorer.UI.Inspectors; - -namespace UnityExplorer.UI.InteractiveValues -{ - public class InteractiveValue - { - /// - /// Get the subclass which supports the provided . - /// - /// The which you want the Type for. - /// The best subclass of which supports the provided . - public static Type GetIValueForType(Type type) - { - // rather ugly but I couldn't think of a cleaner way that was worth it. - // switch-case doesn't really work here. - - // arbitrarily check some types, fastest methods first. - if (type == typeof(bool)) - return typeof(InteractiveBool); - // if type is primitive then it must be a number if its not a bool. Also check for decimal. - else if (type.IsPrimitive || type == typeof(decimal)) - return typeof(InteractiveNumber); - // check for strings - else if (type == typeof(string)) - return typeof(InteractiveString); - // check for enum/flags - else if (typeof(Enum).IsAssignableFrom(type)) - { - // NET 3.5 doesn't have "GetCustomAttribute", gotta use the multiple version. - if (type.GetCustomAttributes(typeof(FlagsAttribute), true) is object[] fa && fa.Any()) - return typeof(InteractiveFlags); - else - return typeof(InteractiveEnum); - } - // check for unity struct types - else if (typeof(Color).IsAssignableFrom(type)) - return typeof(InteractiveColor); - else if (InteractiveFloatStruct.IsTypeSupported(type)) - return typeof(InteractiveFloatStruct); - // check Transform, force InteractiveValue so they dont become InteractiveEnumerables. - else if (typeof(Transform).IsAssignableFrom(type)) - return typeof(InteractiveValue); - // check Dictionaries before Enumerables - else if (ReflectionUtility.IsDictionary(type)) - return typeof(InteractiveDictionary); - // finally check for Enumerables - else if (ReflectionUtility.IsEnumerable(type)) - return typeof(InteractiveEnumerable); - // fallback to default - else - return typeof(InteractiveValue); - } - - public static InteractiveValue Create(object value, Type fallbackType) - { - var type = ReflectionUtility.GetActualType(value) ?? fallbackType; - var iType = GetIValueForType(type); - - return (InteractiveValue)Activator.CreateInstance(iType, new object[] { value, type }); - } - - // ~~~~~~~~~ Instance ~~~~~~~~~ - - public InteractiveValue(object value, Type valueType) - { - this.Value = value; - this.FallbackType = valueType; - } - - public CacheObjectBase Owner; - - public object Value; - public readonly Type FallbackType; - - public virtual bool HasSubContent => false; - public virtual bool SubContentWanted => false; - public virtual bool WantInspectBtn => true; - - public string DefaultLabel => m_defaultLabel ?? GetDefaultLabel(); - internal string m_defaultLabel; - internal string m_richValueType; - - public bool m_UIConstructed; - - public virtual void OnDestroy() - { - if (this.m_mainContent) - { - m_mainContent.transform.SetParent(null, false); - m_mainContent.SetActive(false); - GameObject.Destroy(this.m_mainContent.gameObject); - } - - DestroySubContent(); - } - - public virtual void DestroySubContent() - { - if (this.m_subContentParent && HasSubContent) - { - for (int i = 0; i < this.m_subContentParent.transform.childCount; i++) - { - var child = m_subContentParent.transform.GetChild(i); - if (child) - GameObject.Destroy(child.gameObject); - } - } - - m_subContentConstructed = false; - } - - public virtual void OnValueUpdated() - { - if (!m_UIConstructed) - ConstructUI(m_mainContentParent, m_subContentParent); - - if (Owner is CacheMember ownerMember && !string.IsNullOrEmpty(ownerMember.ReflectionException)) - OnException(ownerMember); - else - RefreshUIForValue(); - } - - public virtual void OnException(CacheMember member) - { - if (m_UIConstructed) - m_baseLabel.text = "" + member.ReflectionException + ""; - - Value = null; - } - - public virtual void RefreshUIForValue() - { - GetDefaultLabel(); - m_baseLabel.text = DefaultLabel; - } - - public void RefreshElementsAfterUpdate() - { - if (WantInspectBtn) - { - bool shouldShowInspect = !Value.IsNullOrDestroyed(); - - if (m_inspectButton.activeSelf != shouldShowInspect) - m_inspectButton.SetActive(shouldShowInspect); - } - - bool subContentWanted = SubContentWanted; - if (Owner is CacheMember cm && (!cm.HasEvaluated || !string.IsNullOrEmpty(cm.ReflectionException))) - subContentWanted = false; - - if (HasSubContent) - { - if (m_subExpandBtn.gameObject.activeSelf != subContentWanted) - m_subExpandBtn.gameObject.SetActive(subContentWanted); - - if (!subContentWanted && m_subContentParent.activeSelf) - ToggleSubcontent(); - } - } - - public virtual void ConstructSubcontent() - { - m_subContentConstructed = true; - } - - public void ToggleSubcontent() - { - if (!this.m_subContentParent.activeSelf) - { - this.m_subContentParent.SetActive(true); - this.m_subContentParent.transform.SetAsLastSibling(); - m_subExpandBtn.GetComponentInChildren().text = "▼"; - } - else - { - this.m_subContentParent.SetActive(false); - m_subExpandBtn.GetComponentInChildren().text = "▲"; - } - - OnToggleSubcontent(m_subContentParent.activeSelf); - - RefreshElementsAfterUpdate(); - } - - internal virtual void OnToggleSubcontent(bool toggle) - { - if (!m_subContentConstructed) - ConstructSubcontent(); - } - - internal MethodInfo m_toStringMethod; - internal MethodInfo m_toStringFormatMethod; - internal bool m_gotToStringMethods; - - public string GetDefaultLabel(bool updateType = true) - { - var valueType = Value?.GetType() ?? this.FallbackType; - if (updateType) - m_richValueType = SignatureHighlighter.ParseFullSyntax(valueType, true); - - if (!Owner.HasEvaluated) - return m_defaultLabel = $"Not yet evaluated ({m_richValueType})"; - - if (Value.IsNullOrDestroyed()) - return m_defaultLabel = $"null ({m_richValueType})"; - - string label; - - // Two dirty fixes for TextAsset and EventSystem, which can have very long ToString results. - if (Value is TextAsset textAsset) - { - label = textAsset.text; - - if (label.Length > 10) - label = $"{label.Substring(0, 10)}..."; - - label = $"\"{label}\" {textAsset.name} ({m_richValueType})"; - } - else if (Value is EventSystem) - { - label = m_richValueType; - } - else // For everything else... - { - if (!m_gotToStringMethods) - { - m_gotToStringMethods = true; - - m_toStringMethod = valueType.GetMethod("ToString", new Type[0]); - m_toStringFormatMethod = valueType.GetMethod("ToString", new Type[] { typeof(string) }); - - // test format method actually works - try - { - m_toStringFormatMethod.Invoke(Value, new object[] { "F3" }); - } - catch - { - m_toStringFormatMethod = null; - } - } - - string toString; - if (m_toStringFormatMethod != null) - toString = (string)m_toStringFormatMethod.Invoke(Value, new object[] { "F3" }); - else - toString = (string)m_toStringMethod.Invoke(Value, new object[0]); - - toString = toString ?? ""; - - string typeName = valueType.FullName; - if (typeName.StartsWith("Il2CppSystem.")) - typeName = typeName.Substring(6, typeName.Length - 6); - - toString = ReflectionProvider.Instance.ProcessTypeNameInString(valueType, toString, ref typeName); - - // If the ToString is just the type name, use our syntax highlighted type name instead. - if (toString == typeName) - { - label = m_richValueType; - } - else // Otherwise, parse the result and put our highlighted name in. - { - if (toString.Length > 200) - toString = toString.Substring(0, 200) + "..."; - - label = toString; - - var unityType = $"({valueType.FullName})"; - if (Value is UnityEngine.Object && label.Contains(unityType)) - label = label.Replace(unityType, $"({m_richValueType})"); - else - label += $" ({m_richValueType})"; - } - } - - return m_defaultLabel = label; - } - - #region UI CONSTRUCTION - - internal GameObject m_mainContentParent; - internal GameObject m_subContentParent; - - internal GameObject m_mainContent; - internal GameObject m_inspectButton; - internal Text m_baseLabel; - - internal Button m_subExpandBtn; - internal bool m_subContentConstructed; - - public virtual void ConstructUI(GameObject parent, GameObject subGroup) - { - m_UIConstructed = true; - - m_mainContent = UIFactory.CreateHorizontalGroup(parent, $"InteractiveValue_{this.GetType().Name}", false, false, true, true, 4, default, - new Color(1, 1, 1, 0), TextAnchor.UpperLeft); - - var mainRect = m_mainContent.GetComponent(); - mainRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 25); - - UIFactory.SetLayoutElement(m_mainContent, flexibleWidth: 9000, minWidth: 175, minHeight: 25, flexibleHeight: 0); - - // subcontent expand button - if (HasSubContent) - { - m_subExpandBtn = UIFactory.CreateButton(m_mainContent, "ExpandSubcontentButton", "▲", ToggleSubcontent, new Color(0.3f, 0.3f, 0.3f)); - UIFactory.SetLayoutElement(m_subExpandBtn.gameObject, minHeight: 25, minWidth: 25, flexibleWidth: 0, flexibleHeight: 0); - } - - // inspect button - - var inspectBtn = UIFactory.CreateButton(m_mainContent, - "InspectButton", - "Inspect", - () => - { - if (!Value.IsNullOrDestroyed(false)) - InspectorManager.Instance.Inspect(this.Value, this.Owner); - }, - new Color(0.3f, 0.3f, 0.3f, 0.2f)); - - m_inspectButton = inspectBtn.gameObject; - UIFactory.SetLayoutElement(m_inspectButton, minWidth: 60, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0); - - m_inspectButton.SetActive(false); - - // value label - - m_baseLabel = UIFactory.CreateLabel(m_mainContent, "ValueLabel", "", TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(m_baseLabel.gameObject, flexibleWidth: 9000, minHeight: 25); - - m_subContentParent = subGroup; - } - -#endregion - } -} diff --git a/src/UI/Main/BaseMenuPage.cs b/src/UI/Main/BaseMenuPage.cs deleted file mode 100644 index 6ae78bb..0000000 --- a/src/UI/Main/BaseMenuPage.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using UnityEngine; -using UnityEngine.UI; - -namespace UnityExplorer.UI.Main -{ - public enum MenuPages - { - Home, - Search, - CSConsole, - Options - } - - public abstract class BaseMenuPage - { - public abstract string Name { get; } - public abstract MenuPages Type { get; } - public bool WasDisabled { get; internal set; } - - public GameObject Content; - public Button RefNavbarButton { get; set; } - - public bool Enabled - { - get => Content?.activeSelf ?? false; - set => Content?.SetActive(true); - } - - public abstract bool Init(); - public abstract void Update(); - } -} diff --git a/src/UI/Main/CSConsole/AutoCompleter.cs b/src/UI/Main/CSConsole/AutoCompleter.cs deleted file mode 100644 index 281ff12..0000000 --- a/src/UI/Main/CSConsole/AutoCompleter.cs +++ /dev/null @@ -1,302 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.EventSystems; -using UnityEngine.UI; -using UnityExplorer.Core.CSharp; -using UnityExplorer.Core.Input; -using UnityExplorer.Core.Runtime; -using UnityExplorer.Core.Unity; -using UnityExplorer.UI; -using UnityExplorer.UI.Main; - -namespace UnityExplorer.UI.Main.CSConsole -{ - public class AutoCompleter - { - public static AutoCompleter Instance; - - public const int MAX_LABELS = 500; - private const int UPDATES_PER_BATCH = 100; - - public static GameObject m_mainObj; - - private static readonly List m_suggestionButtons = new List(); - private static readonly List m_suggestionTexts = new List(); - private static readonly List m_hiddenSuggestionTexts = new List(); - - private static bool m_suggestionsDirty; - private static Suggestion[] m_suggestions = new Suggestion[0]; - private static int m_lastBatchIndex; - - private static string m_prevInput = "NULL"; - private static int m_lastCaretPos; - - public static void Init() - { - ConstructUI(); - - m_mainObj.SetActive(false); - } - - public static void Update() - { - if (!m_mainObj) - return; - - if (!CSharpConsole.EnableAutocompletes) - { - if (m_mainObj.activeSelf) - m_mainObj.SetActive(false); - - return; - } - - RefreshButtons(); - - UpdatePosition(); - } - - public static void SetSuggestions(Suggestion[] suggestions) - { - m_suggestions = suggestions; - - m_suggestionsDirty = true; - m_lastBatchIndex = 0; - } - - private static void RefreshButtons() - { - if (!m_suggestionsDirty) - { - return; - } - - if (m_suggestions.Length < 1) - { - if (m_mainObj.activeSelf) - { - m_mainObj?.SetActive(false); - } - return; - } - - if (!m_mainObj.activeSelf) - { - m_mainObj.SetActive(true); - } - - if (m_suggestions.Length < 1 || m_lastBatchIndex >= MAX_LABELS) - { - m_suggestionsDirty = false; - return; - } - - int end = m_lastBatchIndex + UPDATES_PER_BATCH; - for (int i = m_lastBatchIndex; i < end && i < MAX_LABELS; i++) - { - if (i >= m_suggestions.Length) - { - if (m_suggestionButtons[i].activeSelf) - { - m_suggestionButtons[i].SetActive(false); - } - } - else - { - if (!m_suggestionButtons[i].activeSelf) - { - m_suggestionButtons[i].SetActive(true); - } - - var suggestion = m_suggestions[i]; - var label = m_suggestionTexts[i]; - var hiddenLabel = m_hiddenSuggestionTexts[i]; - - label.text = suggestion.Full; - hiddenLabel.text = suggestion.Addition; - - label.color = suggestion.TextColor; - } - - m_lastBatchIndex = i; - } - - m_lastBatchIndex++; - } - - private static void UpdatePosition() - { - try - { - var editor = CSharpConsole.Instance; - - if (!editor.InputField.isFocused) - return; - - var textGen = editor.InputText.cachedTextGenerator; - int caretPos = editor.m_lastCaretPos; - - if (caretPos == m_lastCaretPos) - return; - - m_lastCaretPos = caretPos; - - if (caretPos >= 1) - caretPos--; - - var pos = textGen.characters[caretPos].cursorPos; - - pos = editor.InputField.transform.TransformPoint(pos); - - m_mainObj.transform.position = new Vector3(pos.x + 10, pos.y - 20, 0); - } - catch //(Exception e) - { - //ExplorerCore.Log(e.ToString()); - } - } - - private static readonly char[] splitChars = new[] { '{', '}', ',', ';', '<', '>', '(', ')', '[', ']', '=', '|', '&', '?' }; - - public static void CheckAutocomplete() - { - var m_codeEditor = CSharpConsole.Instance; - string input = m_codeEditor.InputField.text; - int caretIndex = m_codeEditor.InputField.caretPosition; - - if (!string.IsNullOrEmpty(input)) - { - try - { - int start = caretIndex <= 0 ? 0 : input.LastIndexOfAny(splitChars, caretIndex - 1) + 1; - input = input.Substring(start, caretIndex - start).Trim(); - } - catch (ArgumentException) { } - } - - if (!string.IsNullOrEmpty(input) && input != m_prevInput) - { - GetAutocompletes(input); - } - else - { - ClearAutocompletes(); - } - - m_prevInput = input; - } - - public static void ClearAutocompletes() - { - if (CSharpConsole.AutoCompletes.Any()) - { - CSharpConsole.AutoCompletes.Clear(); - } - } - - public static void GetAutocompletes(string input) - { - try - { - // Credit ManylMarco - CSharpConsole.AutoCompletes.Clear(); - string[] completions = CSharpConsole.Instance.Evaluator.GetCompletions(input, out string prefix); - if (completions != null) - { - if (prefix == null) - { - prefix = input; - } - - CSharpConsole.AutoCompletes.AddRange(completions - .Where(x => !string.IsNullOrEmpty(x)) - .Select(x => new Suggestion(x, prefix, Suggestion.Contexts.Other)) - ); - } - - string trimmed = input.Trim(); - if (trimmed.StartsWith("using")) - { - trimmed = trimmed.Remove(0, 5).Trim(); - } - - IEnumerable namespaces = Suggestion.Namespaces - .Where(x => x.StartsWith(trimmed) && x.Length > trimmed.Length) - .Select(x => new Suggestion( - x.Substring(trimmed.Length), - x.Substring(0, trimmed.Length), - Suggestion.Contexts.Namespace)); - - CSharpConsole.AutoCompletes.AddRange(namespaces); - - IEnumerable keywords = Suggestion.Keywords - .Where(x => x.StartsWith(trimmed) && x.Length > trimmed.Length) - .Select(x => new Suggestion( - x.Substring(trimmed.Length), - x.Substring(0, trimmed.Length), - Suggestion.Contexts.Keyword)); - - CSharpConsole.AutoCompletes.AddRange(keywords); - } - catch (Exception ex) - { - ExplorerCore.Log("Autocomplete error:\r\n" + ex.ToString()); - ClearAutocompletes(); - } - } - - #region UI Construction - - private static void ConstructUI() - { - var parent = UIManager.CanvasRoot; - - var obj = UIFactory.CreateScrollView(parent, "AutoCompleterScrollView", out GameObject content, out _, new Color(0.1f, 0.1f, 0.1f, 0.95f)); - - m_mainObj = obj; - - var mainRect = obj.GetComponent(); - //m_thisRect = mainRect; - 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; - - var mainGroup = content.GetComponent(); - mainGroup.SetChildControlHeight(false); - mainGroup.SetChildControlWidth(true); - mainGroup.childForceExpandHeight = false; - mainGroup.childForceExpandWidth = true; - - for (int i = 0; i < MAX_LABELS; i++) - { - var btn = UIFactory.CreateButton(content, "AutoCompleteButton", "", null); - RuntimeProvider.Instance.SetColorBlock(btn, new Color(0, 0, 0, 0), highlighted: new Color(0.2f, 0.2f, 0.2f, 1.0f)); - - var nav = btn.navigation; - nav.mode = Navigation.Mode.Vertical; - btn.navigation = nav; - - UIFactory.SetLayoutElement(btn.gameObject, minHeight: 20); - - var text = btn.GetComponentInChildren(); - text.alignment = TextAnchor.MiddleLeft; - text.color = Color.white; - - var hiddenChild = UIFactory.CreateUIObject("HiddenText", btn.gameObject); - hiddenChild.SetActive(false); - var hiddenText = hiddenChild.AddComponent(); - m_hiddenSuggestionTexts.Add(hiddenText); - btn.onClick.AddListener(() => { CSharpConsole.Instance.UseAutocomplete(hiddenText.text); }); - - m_suggestionButtons.Add(btn.gameObject); - m_suggestionTexts.Add(text); - } - } - - #endregion - } -} diff --git a/src/UI/Main/CSConsole/CSLexerHighlighter.cs b/src/UI/Main/CSConsole/CSLexerHighlighter.cs deleted file mode 100644 index 10654bd..0000000 --- a/src/UI/Main/CSConsole/CSLexerHighlighter.cs +++ /dev/null @@ -1,290 +0,0 @@ -using System.Collections.Generic; -using System.Text; -using UnityEngine; -using UnityExplorer.UI.Main.CSConsole.Lexer; - -namespace UnityExplorer.UI.Main.CSConsole -{ - public struct LexerMatchInfo - { - public int startIndex; - public int endIndex; - public string htmlColor; - } - - public enum DelimiterType - { - Start, - End, - }; - - public class CSLexerHighlighter - { - private string inputString; - private readonly Matcher[] matchers; - private readonly HashSet startDelimiters; - private readonly HashSet endDelimiters; - private int currentIndex; - private int currentLookaheadIndex; - - public char Current { get; private set; } - public char Previous { get; private set; } - - public bool EndOfStream => currentLookaheadIndex >= inputString.Length; - - public static char indentOpen = '{'; - public static char indentClose = '}'; - private static StringBuilder indentBuilder = new StringBuilder(); - - public static char[] delimiters = new[] - { - '[', ']', '(', ')', '{', '}', ';', ':', ',', '.' - }; - - public static CommentMatch commentMatcher = new CommentMatch(); - public static SymbolMatch symbolMatcher = new SymbolMatch(); - public static NumberMatch numberMatcher = new NumberMatch(); - public static StringMatch stringMatcher = new StringMatch(); - public static KeywordMatch validKeywordMatcher = new KeywordMatch(); - - // ~~~~~~~ ctor ~~~~~~~ - - public CSLexerHighlighter() - { - startDelimiters = new HashSet(delimiters); - endDelimiters = new HashSet(delimiters); - - this.matchers = new Matcher[] - { - commentMatcher, - symbolMatcher, - numberMatcher, - stringMatcher, - validKeywordMatcher, - }; - - foreach (Matcher lexer in matchers) - { - foreach (char c in lexer.StartChars) - { - if (!startDelimiters.Contains(c)) - startDelimiters.Add(c); - } - - foreach (char c in lexer.EndChars) - { - if (!endDelimiters.Contains(c)) - endDelimiters.Add(c); - } - } - } - - // ~~~~~~~ Lex Matching ~~~~~~~ - - public IEnumerable GetMatches(string input) - { - if (input == null || matchers == null || matchers.Length == 0) - { - yield break; - } - - inputString = input; - Current = ' '; - Previous = ' '; - currentIndex = 0; - currentLookaheadIndex = 0; - - while (!EndOfStream) - { - bool didMatchLexer = false; - - ReadWhiteSpace(); - - foreach (Matcher matcher in matchers) - { - int startIndex = currentIndex; - - bool isMatched = matcher.IsMatch(this); - - if (isMatched) - { - int endIndex = currentIndex; - - didMatchLexer = true; - - yield return new LexerMatchInfo - { - startIndex = startIndex, - endIndex = endIndex, - htmlColor = matcher.HexColor, - }; - - break; - } - } - - if (!didMatchLexer) - { - ReadNext(); - Commit(); - } - } - } - - // ~~~~~~~ Indent ~~~~~~~ - - public static string GetIndentForInput(string input, int indent, out int caretPosition) - { - indentBuilder = new StringBuilder(); - - indent += 1; - - bool stringState = false; - - for (int i = 0; i < input.Length; i++) - { - if (input[i] == '"') - { - stringState = !stringState; - } - - if (input[i] == '\n') - { - indentBuilder.Append('\n'); - for (int j = 0; j < indent; j++) - { - indentBuilder.Append("\t"); - } - } - else if (input[i] == '\t') - { - continue; - } - else if (!stringState && input[i] == indentOpen) - { - indentBuilder.Append(indentOpen); - indent++; - } - else if (!stringState && input[i] == indentClose) - { - indentBuilder.Append(indentClose); - indent--; - } - else - { - indentBuilder.Append(input[i]); - } - } - - string formattedSection = indentBuilder.ToString(); - - caretPosition = formattedSection.Length - 1; - - for (int i = formattedSection.Length - 1; i >= 0; i--) - { - if (formattedSection[i] == '\n') - { - continue; - } - - caretPosition = i; - break; - } - - return formattedSection; - } - - public static int GetIndentLevel(string inputString, int startIndex, int endIndex) - { - int indent = 0; - - for (int i = startIndex; i < endIndex; i++) - { - if (inputString[i] == '\t') - { - indent++; - } - - // Check for end line or other characters - if (inputString[i] == '\n' || inputString[i] != ' ') - { - break; - } - } - - return indent; - } - - // Lexer reading - - public char ReadNext() - { - if (EndOfStream) - { - return '\0'; - } - - Previous = Current; - - Current = inputString[currentLookaheadIndex]; - currentLookaheadIndex++; - - return Current; - } - - public void Rollback(int amount = -1) - { - if (amount == -1) - { - currentLookaheadIndex = currentIndex; - } - else - { - if (currentLookaheadIndex > currentIndex) - { - currentLookaheadIndex -= amount; - } - } - - int previousIndex = currentLookaheadIndex - 1; - - if (previousIndex >= inputString.Length) - { - Previous = inputString[inputString.Length - 1]; - } - else if (previousIndex >= 0) - { - Previous = inputString[previousIndex]; - } - else - { - Previous = ' '; - } - } - - public void Commit() - { - currentIndex = currentLookaheadIndex; - } - - public bool IsSpecialSymbol(char character, DelimiterType position = DelimiterType.Start) - { - if (position == DelimiterType.Start) - { - return startDelimiters.Contains(character); - } - - return endDelimiters.Contains(character); - } - - private void ReadWhiteSpace() - { - while (char.IsWhiteSpace(ReadNext()) == true) - { - Commit(); - } - - Rollback(); - } - } -} \ No newline at end of file diff --git a/src/UI/Main/CSConsole/CSharpConsole.cs b/src/UI/Main/CSConsole/CSharpConsole.cs deleted file mode 100644 index 9a13ba5..0000000 --- a/src/UI/Main/CSConsole/CSharpConsole.cs +++ /dev/null @@ -1,590 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Text; -using UnityExplorer.Core.CSharp; -using System.Linq; -using UnityExplorer.Core.Input; -using UnityEngine; -using UnityEngine.EventSystems; -using UnityEngine.UI; -using UnityExplorer.UI.Main.CSConsole; -using UnityExplorer.Core; -using UnityExplorer.Core.Unity; -using UnityExplorer.UI.Utility; - -namespace UnityExplorer.UI.Main.CSConsole -{ - public class CSharpConsole : BaseMenuPage - { - public override string Name => "C# Console"; - public override MenuPages Type => MenuPages.CSConsole; - - public static CSharpConsole Instance { get; private set; } - - public ScriptEvaluator Evaluator; - internal StringBuilder m_evalLogBuilder; - - public static List UsingDirectives; - - public static readonly string[] DefaultUsing = new string[] - { - "System", - "System.Linq", - "System.Collections", - "System.Collections.Generic", - "System.Reflection", - "UnityEngine", -#if CPP - "UnhollowerBaseLib", - "UnhollowerRuntimeLib", -#endif - }; - - public override bool Init() - { - Instance = this; - - try - { - InitConsole(); - - AutoCompleter.Init(); - - ResetConsole(false); - // Make sure compiler is supported on this platform - Evaluator.Compile("new object();"); - - return true; - } - catch (Exception e) - { - string info = "The C# Console has been disabled because"; - if (e is NotSupportedException && e.TargetSite?.Name == "DefineDynamicAssembly") - info += " Reflection.Emit is not supported."; - else - info += $" of an unknown error.\r\n({e.ReflectionExToString()})"; - - ExplorerCore.LogWarning(info); - - this.RefNavbarButton.GetComponentInChildren().text += " (disabled)"; - - return false; - } - } - - public void ResetConsole(bool log = true) - { - if (Evaluator != null) - Evaluator.Dispose(); - - m_evalLogBuilder = new StringBuilder(); - - Evaluator = new ScriptEvaluator(new StringWriter(m_evalLogBuilder)) { InteractiveBaseClass = typeof(ScriptInteraction) }; - - UsingDirectives = new List(); - - foreach (string use in DefaultUsing) - AddUsing(use); - - if (log) - ExplorerCore.Log($"C# Console reset. Using directives:\r\n{Evaluator.GetUsing()}"); - } - - public override void Update() - { - UpdateConsole(); - - AutoCompleter.Update(); - } - - public void AddUsing(string asm) - { - if (!UsingDirectives.Contains(asm)) - { - Evaluate($"using {asm};", true); - UsingDirectives.Add(asm); - } - } - - public void Evaluate(string code, bool supressLog = false) - { - try - { - Evaluator.Run(code); - - string output = ScriptEvaluator._textWriter.ToString(); - var outputSplit = output.Split('\n'); - if (outputSplit.Length >= 2) - output = outputSplit[outputSplit.Length - 2]; - m_evalLogBuilder.Clear(); - - if (ScriptEvaluator._reportPrinter.ErrorsCount > 0) - throw new FormatException($"Unable to compile the code. Evaluator's last output was:\r\n{output}"); - - if (!supressLog) - ExplorerCore.Log("Code executed successfully."); - } - catch (FormatException fex) - { - if (!supressLog) - ExplorerCore.LogWarning(fex.Message); - } - catch (Exception ex) - { - if (!supressLog) - ExplorerCore.LogWarning(ex); - } - } - - // ================================================================================================= - - // UI stuff - - public InputField InputField { get; internal set; } - public Text InputText { get; internal set; } - public int CurrentIndent { get; private set; } - - public static bool EnableCtrlRShortcut { get; set; } = true; - public static bool EnableAutoIndent { get; set; } = true; - public static bool EnableAutocompletes { get; set; } = true; - public static List AutoCompletes = new List(); - - public string HighlightedText => inputHighlightText.text; - private Text inputHighlightText; - - private CSLexerHighlighter highlightLexer; - - internal int m_lastCaretPos; - internal int m_fixCaretPos; - internal bool m_fixwanted; - internal float m_lastSelectAlpha; - - private static readonly KeyCode[] onFocusKeys = - { - KeyCode.Return, KeyCode.Backspace, KeyCode.UpArrow, - KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow - }; - - internal const string STARTUP_TEXT = @"Welcome to the UnityExplorer C# Console. - -The following helper methods are available: - -* Log(""message"") logs a message to the debug console - -* StartCoroutine(IEnumerator routine) start the IEnumerator as a UnityEngine.Coroutine - -* CurrentTarget() returns the currently inspected target on the Home page - -* AllTargets() returns an object[] array containing all inspected instances - -* Inspect(someObject) to inspect an instance, eg. Inspect(Camera.main); - -* Inspect(typeof(SomeClass)) to inspect a Class with static reflection - -* AddUsing(""SomeNamespace"") adds a using directive to the C# console - -* GetUsing() logs the current using directives to the debug console - -* Reset() resets all using directives and variables -"; - - public void InitConsole() - { - highlightLexer = new CSLexerHighlighter(); - - ConstructUI(); - - InputField.onValueChanged.AddListener((string s) => { OnInputChanged(s); }); - } - - internal static bool IsUserCopyPasting() - { - return (InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl)) - && InputManager.GetKeyDown(KeyCode.V); - } - - public void UpdateConsole() - { - if (s_copyPasteBuffer != null) - { - if (!IsUserCopyPasting()) - { - OnInputChanged(s_copyPasteBuffer); - - s_copyPasteBuffer = null; - } - } - - if (EnableCtrlRShortcut) - { - if ((InputManager.GetKey(KeyCode.LeftControl) || InputManager.GetKey(KeyCode.RightControl)) - && InputManager.GetKeyDown(KeyCode.R)) - { - var text = InputField.text.Trim(); - if (!string.IsNullOrEmpty(text)) - { - Evaluate(text); - return; - } - } - } - - if (EnableAutoIndent && InputManager.GetKeyDown(KeyCode.Return)) - AutoIndentCaret(); - - if (EnableAutocompletes && InputField.isFocused) - { - if (InputManager.GetMouseButton(0) || onFocusKeys.Any(it => InputManager.GetKeyDown(it))) - UpdateAutocompletes(); - } - - if (m_fixCaretPos > 0) - { - if (!m_fixwanted) - { - EventSystem.current.SetSelectedGameObject(InputField.gameObject, null); - m_fixwanted = true; - } - else - { - InputField.caretPosition = m_fixCaretPos; - InputField.selectionFocusPosition = m_fixCaretPos; - - m_fixwanted = false; - m_fixCaretPos = -1; - - var color = InputField.selectionColor; - color.a = m_lastSelectAlpha; - InputField.selectionColor = color; - } - } - else if (InputField.caretPosition > 0) - { - m_lastCaretPos = InputField.caretPosition; - } - } - - internal void UpdateAutocompletes() - { - AutoCompleter.CheckAutocomplete(); - AutoCompleter.SetSuggestions(AutoCompletes.ToArray()); - } - - public void UseAutocomplete(string suggestion) - { - string input = InputField.text; - input = input.Insert(m_lastCaretPos, suggestion); - InputField.text = input; - - m_fixCaretPos = m_lastCaretPos += suggestion.Length; - - var color = InputField.selectionColor; - m_lastSelectAlpha = color.a; - color.a = 0f; - InputField.selectionColor = color; - - AutoCompleter.ClearAutocompletes(); - } - - internal static string s_copyPasteBuffer; - - public void OnInputChanged(string newText, bool forceUpdate = false) - { - if (IsUserCopyPasting()) - { - //Console.WriteLine("Copy+Paste detected!"); - s_copyPasteBuffer = newText; - return; - } - - if (EnableAutoIndent) - UpdateIndent(newText); - - if (!forceUpdate && string.IsNullOrEmpty(newText)) - inputHighlightText.text = string.Empty; - else - inputHighlightText.text = SyntaxHighlightContent(newText); - - if (EnableAutocompletes) - UpdateAutocompletes(); - } - - private void UpdateIndent(string newText) - { - int caret = InputField.caretPosition; - - int len = newText.Length; - if (caret < 0 || caret >= len) - { - while (caret >= 0 && caret >= len) - caret--; - - if (caret < 0) - return; - } - - CurrentIndent = 0; - - bool stringState = false; - - for (int i = 0; i < caret && i < newText.Length; i++) - { - char character = newText[i]; - - if (character == '"') - stringState = !stringState; - else if (!stringState && character == CSLexerHighlighter.indentOpen) - CurrentIndent++; - else if (!stringState && character == CSLexerHighlighter.indentClose) - CurrentIndent--; - } - - if (CurrentIndent < 0) - CurrentIndent = 0; - } - - private const string CLOSE_COLOR_TAG = ""; - - private string SyntaxHighlightContent(string inputText) - { - int offset = 0; - - //Console.WriteLine("Highlighting input text:\r\n" + inputText); - - string ret = ""; - - foreach (var match in highlightLexer.GetMatches(inputText)) - { - for (int i = offset; i < match.startIndex; i++) - ret += inputText[i]; - - ret += $"{match.htmlColor}"; - - for (int i = match.startIndex; i < match.endIndex; i++) - ret += inputText[i]; - - ret += CLOSE_COLOR_TAG; - - offset = match.endIndex; - } - - for (int i = offset; i < inputText.Length; i++) - ret += inputText[i]; - - return ret; - } - - private void AutoIndentCaret() - { - if (CurrentIndent > 0) - { - string indent = GetAutoIndentTab(CurrentIndent); - - if (indent.Length > 0) - { - int caretPos = InputField.caretPosition; - - string indentMinusOne = indent.Substring(0, indent.Length - 1); - - // get last index of { - // chuck it on the next line if its not already - string text = InputField.text; - string sub = InputField.text.Substring(0, InputField.caretPosition); - int lastIndex = sub.LastIndexOf("{"); - int offset = lastIndex - 1; - if (offset >= 0 && text[offset] != '\n' && text[offset] != '\t') - { - string open = "\n" + indentMinusOne; - - InputField.text = text.Insert(offset + 1, open); - - caretPos += open.Length; - } - - // check if should add auto-close } - int numOpen = InputField.text.Where(x => x == CSLexerHighlighter.indentOpen).Count(); - int numClose = InputField.text.Where(x => x == CSLexerHighlighter.indentClose).Count(); - - if (numOpen > numClose) - { - // add auto-indent closing - indentMinusOne = $"\n{indentMinusOne}}}"; - InputField.text = InputField.text.Insert(caretPos, indentMinusOne); - } - - // insert the actual auto indent now - InputField.text = InputField.text.Insert(caretPos, indent); - - //InputField.stringPosition = caretPos + indent.Length; - InputField.caretPosition = caretPos + indent.Length; - } - } - - // Update line column and indent positions - UpdateIndent(InputField.text); - - InputText.text = InputField.text; - //inputText.SetText(InputField.text, true); - InputText.Rebuild(CanvasUpdate.Prelayout); - InputField.ForceLabelUpdate(); - InputField.Rebuild(CanvasUpdate.Prelayout); - - OnInputChanged(InputText.text, true); - } - - private string GetAutoIndentTab(int amount) - { - string tab = string.Empty; - - for (int i = 0; i < amount; i++) - { - tab += "\t"; - } - - return tab; - } - - // ========== UI CONSTRUCTION =========== // - - public void ConstructUI() - { - Content = UIFactory.CreateVerticalGroup(MainMenu.Instance.PageViewport, "CSharpConsole", true, true, true, true); - UIFactory.SetLayoutElement(Content, preferredHeight: 500, flexibleHeight: 9000); - - #region TOP BAR - - // Main group object - - var topBarObj = UIFactory.CreateHorizontalGroup(Content, "TopBar", true, true, true, true, 10, new Vector4(8, 8, 30, 30), - default, TextAnchor.LowerCenter); - UIFactory.SetLayoutElement(topBarObj, minHeight: 50, flexibleHeight: 0); - - // Top label - - var topBarLabel = UIFactory.CreateLabel(topBarObj, "TopLabel", "C# Console", TextAnchor.MiddleLeft, default, true, 25); - UIFactory.SetLayoutElement(topBarLabel.gameObject, preferredWidth: 150, flexibleWidth: 5000); - - // Enable Ctrl+R toggle - - var ctrlRToggleObj = UIFactory.CreateToggle(topBarObj, "CtrlRToggle", out Toggle ctrlRToggle, out Text ctrlRToggleText); - ctrlRToggle.onValueChanged.AddListener((bool val) => { EnableCtrlRShortcut = val; }); - - ctrlRToggleText.text = "Run on Ctrl+R"; - ctrlRToggleText.alignment = TextAnchor.UpperLeft; - UIFactory.SetLayoutElement(ctrlRToggleObj, minWidth: 140, flexibleWidth: 0, minHeight: 25); - - // Enable Suggestions toggle - - var suggestToggleObj = UIFactory.CreateToggle(topBarObj, "SuggestionToggle", out Toggle suggestToggle, out Text suggestToggleText); - suggestToggle.onValueChanged.AddListener((bool val) => - { - EnableAutocompletes = val; - AutoCompleter.Update(); - }); - - suggestToggleText.text = "Suggestions"; - suggestToggleText.alignment = TextAnchor.UpperLeft; - - UIFactory.SetLayoutElement(suggestToggleObj, minWidth: 120, flexibleWidth: 0, minHeight: 25); - - // Enable Auto-indent toggle - - var autoIndentToggleObj = UIFactory.CreateToggle(topBarObj, "IndentToggle", out Toggle autoIndentToggle, out Text autoIndentToggleText); - autoIndentToggle.onValueChanged.AddListener((bool val) => EnableAutoIndent = val); - - autoIndentToggleText.text = "Auto-indent on Enter"; - autoIndentToggleText.alignment = TextAnchor.UpperLeft; - - UIFactory.SetLayoutElement(autoIndentToggleObj, minWidth: 180, flexibleWidth: 0, minHeight: 25); - - #endregion - - #region CONSOLE INPUT - - int fontSize = 16; - - var inputObj = UIFactory.CreateSrollInputField(Content, "ConsoleInput", STARTUP_TEXT, out InputFieldScroller consoleScroll, fontSize); - - var inputField = consoleScroll.inputField; - - var mainTextObj = inputField.textComponent.gameObject; - var mainTextInput = inputField.textComponent; - mainTextInput.supportRichText = false; - mainTextInput.color = new Color(1, 1, 1, 0.5f); - - var placeHolderText = inputField.placeholder.GetComponent(); - placeHolderText.fontSize = fontSize; - - var highlightTextObj = UIFactory.CreateUIObject("HighlightText", mainTextObj.gameObject); - var highlightTextRect = highlightTextObj.GetComponent(); - highlightTextRect.pivot = new Vector2(0, 1); - highlightTextRect.anchorMin = Vector2.zero; - highlightTextRect.anchorMax = Vector2.one; - highlightTextRect.offsetMin = new Vector2(20, 0); - highlightTextRect.offsetMax = new Vector2(14, 0); - - var highlightTextInput = highlightTextObj.AddComponent(); - highlightTextInput.supportRichText = true; - highlightTextInput.fontSize = fontSize; - - #endregion - - #region COMPILE BUTTON BAR - - var horozGroupObj = UIFactory.CreateHorizontalGroup(Content, "BigButtons", true, true, true, true, 0, new Vector4(2,2,2,2), - new Color(1, 1, 1, 0)); - - var resetButton = UIFactory.CreateButton(horozGroupObj, "ResetButton", "Reset", () => ResetConsole(), "666666".ToColor()); - var resetBtnText = resetButton.GetComponentInChildren(); - resetBtnText.fontSize = 18; - UIFactory.SetLayoutElement(resetButton.gameObject, preferredWidth: 80, flexibleWidth: 0, minHeight: 45, flexibleHeight: 0); - - var compileButton = UIFactory.CreateButton(horozGroupObj, "CompileButton", "Compile", CompileCallback, - new Color(14f / 255f, 80f / 255f, 14f / 255f)); - var btnText = compileButton.GetComponentInChildren(); - btnText.fontSize = 18; - UIFactory.SetLayoutElement(compileButton.gameObject, preferredWidth: 80, flexibleWidth: 0, minHeight: 45, flexibleHeight: 0); - - void CompileCallback() - { - if (!string.IsNullOrEmpty(inputField.text)) - Evaluate(inputField.text.Trim()); - else - ExplorerCore.Log("Cannot evaluate empty input!"); - } - - #endregion - - //mainTextInput.supportRichText = false; - - mainTextInput.font = UIManager.ConsoleFont; - placeHolderText.font = UIManager.ConsoleFont; - highlightTextInput.font = UIManager.ConsoleFont; - - // reset this after formatting finalized - highlightTextRect.anchorMin = Vector2.zero; - highlightTextRect.anchorMax = Vector2.one; - highlightTextRect.offsetMin = Vector2.zero; - highlightTextRect.offsetMax = Vector2.zero; - - // assign references - - this.InputField = inputField; - - this.InputText = mainTextInput; - this.inputHighlightText = highlightTextInput; - } - - - - // ================================================================================================ - - private class VoidType - { - public static readonly VoidType Value = new VoidType(); - private VoidType() { } - } - } -} diff --git a/src/UI/Main/CSConsole/Lexer/CommentMatch.cs b/src/UI/Main/CSConsole/Lexer/CommentMatch.cs deleted file mode 100644 index 35fac37..0000000 --- a/src/UI/Main/CSConsole/Lexer/CommentMatch.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace UnityExplorer.UI.Main.CSConsole.Lexer -{ - public class CommentMatch : Matcher - { - public string lineCommentStart = @"//"; - public string blockCommentStart = @"/*"; - public string blockCommentEnd = @"*/"; - - public override Color HighlightColor => new Color(0.34f, 0.65f, 0.29f, 1.0f); - public override IEnumerable StartChars => new char[] { lineCommentStart[0], blockCommentStart[0] }; - public override IEnumerable EndChars => new char[] { blockCommentEnd[0] }; - public override bool IsImplicitMatch(CSLexerHighlighter lexer) => IsMatch(lexer, lineCommentStart) || IsMatch(lexer, blockCommentStart); - - private bool IsMatch(CSLexerHighlighter lexer, string commentType) - { - if (!string.IsNullOrEmpty(commentType)) - { - lexer.Rollback(); - - bool match = true; - for (int i = 0; i < commentType.Length; i++) - { - if (commentType[i] != lexer.ReadNext()) - { - match = false; - break; - } - } - - if (match) - { - // Read until end of line or file - while (!IsEndLineOrEndFile(lexer, lexer.ReadNext())) { } - - return true; - } - } - return false; - } - - private bool IsEndLineOrEndFile(CSLexerHighlighter lexer, char character) => lexer.EndOfStream || character == '\n' || character == '\r'; - } -} diff --git a/src/UI/Main/CSConsole/Lexer/KeywordMatch.cs b/src/UI/Main/CSConsole/Lexer/KeywordMatch.cs deleted file mode 100644 index 08b9c0f..0000000 --- a/src/UI/Main/CSConsole/Lexer/KeywordMatch.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace UnityExplorer.UI.Main.CSConsole.Lexer -{ - // I use two different KeywordMatch instances (valid and invalid). - // This class just contains common implementations. - public class KeywordMatch : Matcher - { - public string[] Keywords = new[] {"add", "as", "ascending", "await", "bool", "break", "by", "byte", -"case", "catch", "char", "checked", "const", "continue", "decimal", "default", "descending", "do", "dynamic", -"else", "equals", "false", "finally", "float", "for", "foreach", "from", "global", "goto", "group", -"if", "in", "int", "into", "is", "join", "let", "lock", "long", "new", "null", "object", "on", "orderby", "out", -"ref", "remove", "return", "sbyte", "select", "short", "sizeof", "stackalloc", "string", -"switch", "throw", "true", "try", "typeof", "uint", "ulong", "ushort", "var", "where", "while", "yield", -"abstract", "async", "base", "class", "delegate", "enum", "explicit", "extern", "fixed", "get", -"implicit", "interface", "internal", "namespace", "operator", "override", "params", "private", "protected", "public", -"using", "partial", "readonly", "sealed", "set", "static", "struct", "this", "unchecked", "unsafe", "value", "virtual", "volatile", "void" }; - - public override Color HighlightColor => highlightColor; - public Color highlightColor = new Color(0.33f, 0.61f, 0.83f, 1.0f); - - private readonly HashSet shortlist = new HashSet(); - private readonly Stack removeList = new Stack(); - - public override bool IsImplicitMatch(CSLexerHighlighter lexer) - { - if (!char.IsWhiteSpace(lexer.Previous) && - !lexer.IsSpecialSymbol(lexer.Previous, DelimiterType.End)) - { - return false; - } - - shortlist.Clear(); - - int currentIndex = 0; - char currentChar = lexer.ReadNext(); - - for (int i = 0; i < Keywords.Length; i++) - { - if (Keywords[i][0] == currentChar) - { - shortlist.Add(Keywords[i]); - } - } - - if (shortlist.Count == 0) - { - return false; - } - - do - { - if (lexer.EndOfStream) - { - RemoveLongStrings(currentIndex + 1); - break; - } - - currentChar = lexer.ReadNext(); - currentIndex++; - - if (char.IsWhiteSpace(currentChar) || - lexer.IsSpecialSymbol(currentChar, DelimiterType.Start)) - { - RemoveLongStrings(currentIndex); - lexer.Rollback(1); - break; - } - - foreach (string keyword in shortlist) - { - if (currentIndex >= keyword.Length || keyword[currentIndex] != currentChar) - { - removeList.Push(keyword); - } - } - - while (removeList.Count > 0) - { - shortlist.Remove(removeList.Pop()); - } - } - while (shortlist.Count > 0); - - return shortlist.Count > 0; - } - - private void RemoveLongStrings(int length) - { - foreach (string keyword in shortlist) - { - if (keyword.Length > length) - { - removeList.Push(keyword); - } - } - - while (removeList.Count > 0) - { - shortlist.Remove(removeList.Pop()); - } - } - } -} diff --git a/src/UI/Main/CSConsole/Lexer/Matcher.cs b/src/UI/Main/CSConsole/Lexer/Matcher.cs deleted file mode 100644 index 0b5b53f..0000000 --- a/src/UI/Main/CSConsole/Lexer/Matcher.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; -using System.Linq; -using UnityExplorer.Core.Unity; - -namespace UnityExplorer.UI.Main.CSConsole.Lexer -{ - public abstract class Matcher - { - public abstract Color HighlightColor { get; } - - public string HexColor => htmlColor ?? (htmlColor = ""); - private string htmlColor; - - public virtual IEnumerable StartChars => Enumerable.Empty(); - public virtual IEnumerable EndChars => Enumerable.Empty(); - - public abstract bool IsImplicitMatch(CSLexerHighlighter lexer); - - public bool IsMatch(CSLexerHighlighter lexer) - { - if (IsImplicitMatch(lexer)) - { - lexer.Commit(); - return true; - } - - lexer.Rollback(); - return false; - } - } -} diff --git a/src/UI/Main/CSConsole/Lexer/NumberMatch.cs b/src/UI/Main/CSConsole/Lexer/NumberMatch.cs deleted file mode 100644 index 75b352d..0000000 --- a/src/UI/Main/CSConsole/Lexer/NumberMatch.cs +++ /dev/null @@ -1,39 +0,0 @@ -using UnityEngine; - -namespace UnityExplorer.UI.Main.CSConsole.Lexer -{ - public class NumberMatch : Matcher - { - public override Color HighlightColor => new Color(0.58f, 0.33f, 0.33f, 1.0f); - - public override bool IsImplicitMatch(CSLexerHighlighter lexer) - { - if (!char.IsWhiteSpace(lexer.Previous) && - !lexer.IsSpecialSymbol(lexer.Previous, DelimiterType.End)) - { - return false; - } - - bool matchedNumber = false; - - while (!lexer.EndOfStream) - { - if (IsNumberOrDecimalPoint(lexer.ReadNext())) - { - matchedNumber = true; - lexer.Commit(); - } - else - { - lexer.Rollback(); - break; - } - } - - return matchedNumber; - } - - private bool IsNumberOrDecimalPoint(char character) => char.IsNumber(character) || character == '.'; - } - -} diff --git a/src/UI/Main/CSConsole/Lexer/StringMatch.cs b/src/UI/Main/CSConsole/Lexer/StringMatch.cs deleted file mode 100644 index 8712ea3..0000000 --- a/src/UI/Main/CSConsole/Lexer/StringMatch.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace UnityExplorer.UI.Main.CSConsole.Lexer -{ - public class StringMatch : Matcher - { - public override Color HighlightColor => new Color(0.79f, 0.52f, 0.32f, 1.0f); - - public override IEnumerable StartChars => new[] { '"' }; - public override IEnumerable EndChars => new[] { '"' }; - - public override bool IsImplicitMatch(CSLexerHighlighter lexer) - { - if (lexer.ReadNext() == '"') - { - while (!IsClosingQuoteOrEndFile(lexer, lexer.ReadNext())) { } - - return true; - } - return false; - } - - private bool IsClosingQuoteOrEndFile(CSLexerHighlighter lexer, char character) => lexer.EndOfStream || character == '"'; - } -} diff --git a/src/UI/Main/CSConsole/Lexer/SymbolMatch.cs b/src/UI/Main/CSConsole/Lexer/SymbolMatch.cs deleted file mode 100644 index 9ba817b..0000000 --- a/src/UI/Main/CSConsole/Lexer/SymbolMatch.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -namespace UnityExplorer.UI.Main.CSConsole.Lexer -{ - public class SymbolMatch : Matcher - { - public override Color HighlightColor => new Color(0.58f, 0.47f, 0.37f, 1.0f); - - private readonly string[] symbols = new[] - { - "[", "]", "(", ")", ".", "?", ":", "+", "-", "*", "/", "%", "&", "|", "^", "~", "=", "<", ">", - "++", "--", "&&", "||", "<<", ">>", "==", "!=", "<=", ">=", "+=", "-=", "*=", "/=", "%=", "&=", - "|=", "^=", "<<=", ">>=", "->", "??", "=>", - }; - - private static readonly List shortlist = new List(); - private static readonly Stack removeList = new Stack(); - - public override IEnumerable StartChars => symbols.Select(s => s[0]); - public override IEnumerable EndChars => symbols.Select(s => s[0]); - - public override bool IsImplicitMatch(CSLexerHighlighter lexer) - { - if (lexer == null) - return false; - - if (!char.IsWhiteSpace(lexer.Previous) && - !char.IsLetter(lexer.Previous) && - !char.IsDigit(lexer.Previous) && - !lexer.IsSpecialSymbol(lexer.Previous, DelimiterType.End)) - { - return false; - } - - shortlist.Clear(); - - int currentIndex = 0; - char currentChar = lexer.ReadNext(); - - for (int i = symbols.Length - 1; i >= 0; i--) - { - if (symbols[i][0] == currentChar) - shortlist.Add(symbols[i]); - } - - if (shortlist.Count == 0) - return false; - - do - { - if (lexer.EndOfStream) - { - RemoveLongStrings(currentIndex + 1); - break; - } - - currentChar = lexer.ReadNext(); - currentIndex++; - - if (char.IsWhiteSpace(currentChar) || - char.IsLetter(currentChar) || - char.IsDigit(currentChar) || - lexer.IsSpecialSymbol(currentChar, DelimiterType.Start)) - { - RemoveLongStrings(currentIndex); - lexer.Rollback(1); - break; - } - - foreach (string symbol in shortlist) - { - if (currentIndex >= symbol.Length || symbol[currentIndex] != currentChar) - { - removeList.Push(symbol); - } - } - - while (removeList.Count > 0) - { - shortlist.Remove(removeList.Pop()); - } - } - while (shortlist.Count > 0); - - return shortlist.Count > 0; - } - - private void RemoveLongStrings(int length) - { - foreach (string keyword in shortlist) - { - if (keyword.Length > length) - { - removeList.Push(keyword); - } - } - - while (removeList.Count > 0) - { - shortlist.Remove(removeList.Pop()); - } - } - } -} diff --git a/src/UI/Main/DebugConsole.cs b/src/UI/Main/DebugConsole.cs deleted file mode 100644 index 3b0c92d..0000000 --- a/src/UI/Main/DebugConsole.cs +++ /dev/null @@ -1,238 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Config; -using System.IO; -using System.Linq; -using UnityExplorer.Core.Unity; -using UnityExplorer.UI.Utility; - -namespace UnityExplorer.UI.Main -{ - public class DebugConsole - { - public static DebugConsole Instance { get; private set; } - - public static bool LogUnity { get; set; } - //public static bool SaveToDisk { get; set; } = ModConfig.Instance.Save_Logs_To_Disk; - - internal static StreamWriter s_streamWriter; - - public static readonly List AllMessages = new List(); - public static readonly List MessageHolders = new List(); - - // logs that occured before the actual UI was ready. - // these ones include the hex color codes. - internal static readonly List s_preInitMessages = new List(); - - private InputField m_textInput; - internal const int MAX_TEXT_LEN = 10000; - - public DebugConsole(GameObject parent) - { - Instance = this; - LogUnity = ConfigManager.Log_Unity_Debug.Value; - - ConstructUI(parent); - - if (!ConfigManager.Last_DebugConsole_State.Value) - ToggleShow(); - - // append messages that logged before we were set up - string preAppend = ""; - for (int i = s_preInitMessages.Count - 1; i >= 0; i--) - { - var msg = s_preInitMessages[i]; - if (preAppend != "") - preAppend += "\r\n"; - preAppend += msg; - } - m_textInput.text = preAppend; - - // set up IO - - var path = Path.Combine(ExplorerCore.Loader.ExplorerFolder, "Logs"); - - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); - - // clean old log(s) - var files = Directory.GetFiles(path); - if (files.Length >= 10) - { - var sorted = files.ToList(); - // sort by 'datetime.ToString("u")' will put the oldest ones first - sorted.Sort(); - for (int i = 0; i < files.Length - 9; i++) - File.Delete(files[i]); - } - - var fileName = "UnityExplorer " + DateTime.Now.ToString("u") + ".txt"; - fileName = RemoveInvalidFilenameChars(fileName); - - var stream = File.Create(path + @"\" + fileName); - s_streamWriter = new StreamWriter(stream) - { - AutoFlush = true - }; - - foreach (var msg in AllMessages) - s_streamWriter.WriteLine(msg); - } - - public static bool Hiding; - - private GameObject m_logAreaObj; - private Text m_hideBtnText; - private LayoutElement m_mainLayout; - - public static Action OnToggleShow; - - public void ToggleShow() - { - if (m_logAreaObj.activeSelf) - { - Hiding = true; - m_logAreaObj.SetActive(false); - m_hideBtnText.text = "Show"; - m_mainLayout.minHeight = 30; - } - else - { - Hiding = false; - m_logAreaObj.SetActive(true); - m_hideBtnText.text = "Hide"; - m_mainLayout.minHeight = 190; - } - - OnToggleShow?.Invoke(!Hiding); - } - - public static string RemoveInvalidFilenameChars(string s) - { - var invalid = Path.GetInvalidFileNameChars(); - foreach (var c in invalid) - { - s = s.Replace(c.ToString(), ""); - } - return s; - } - - public static void Log(string message) - { - Log(message, null); - } - - public static void Log(string message, Color color) - { - Log(message, color.ToHex()); - } - - public static void Log(string message, string hexColor) - { - message = $"{AllMessages.Count}: {message}"; - - AllMessages.Add(message); - s_streamWriter?.WriteLine(message); - - if (hexColor != null) - message = $"{message}"; - - if (Instance?.m_textInput) - { - var input = Instance.m_textInput; - var wanted = $"{message}\n{input.text}"; - - if (wanted.Length > MAX_TEXT_LEN) - wanted = wanted.Substring(0, MAX_TEXT_LEN); - - input.text = wanted; - } - else - s_preInitMessages.Add(message); - } - - public void ConstructUI(GameObject parent) - { - var mainObj = UIFactory.CreateVerticalGroup(parent, "DebugConsole", true, true, true, true, 0, default, new Color(0.1f, 0.1f, 0.1f, 1.0f)); - var mainImage = mainObj.GetComponent(); - mainImage.maskable = true; - var mask = mainObj.AddComponent(); - mask.showMaskGraphic = true; - - m_mainLayout = mainObj.AddComponent(); - m_mainLayout.minHeight = 190; - m_mainLayout.flexibleHeight = 0; - - #region LOG AREA - m_logAreaObj = UIFactory.CreateHorizontalGroup(mainObj, "LogArea", true, true, true, true); - UIFactory.SetLayoutElement(m_logAreaObj, preferredHeight: 190, flexibleHeight: 0); - - var inputScrollerObj = UIFactory.CreateSrollInputField(m_logAreaObj, - "DebugConsoleOutput", - "", - out InputFieldScroller inputScroll, - 14, - new Color(0.05f, 0.05f, 0.05f)); - - inputScroll.inputField.textComponent.font = UIManager.ConsoleFont; - inputScroll.inputField.readOnly = true; - - m_textInput = inputScroll.inputField; - #endregion - - #region BOTTOM BAR - - var bottomBarObj = UIFactory.CreateHorizontalGroup(mainObj, "BottomBar", false, true, true, true, 10, new Vector4(2,2,10,10), - default, TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(bottomBarObj, minHeight: 30, flexibleHeight: 0); - - // Debug Console label - - var bottomLabel = UIFactory.CreateLabel(bottomBarObj, "DebugConsoleLabel", "Debug Console", TextAnchor.MiddleLeft); - bottomLabel.fontStyle = FontStyle.Bold; - UIFactory.SetLayoutElement(bottomLabel.gameObject, minWidth: 100, flexibleWidth: 0); - - // Hide button - - var hideButton = UIFactory.CreateButton(bottomBarObj, "HideButton", "Hide", ToggleShow); - UIFactory.SetLayoutElement(hideButton.gameObject, minWidth: 80, flexibleWidth: 0); - m_hideBtnText = hideButton.GetComponentInChildren(); - - // Clear button - - var clearButton = UIFactory.CreateButton(bottomBarObj, "ClearButton", "Clear", () => - { - m_textInput.text = ""; - AllMessages.Clear(); - }); - UIFactory.SetLayoutElement(clearButton.gameObject, minWidth: 80, flexibleWidth: 0); - - // Unity log toggle - - var unityToggleObj = UIFactory.CreateToggle(bottomBarObj, "UnityLogToggle", out Toggle unityToggle, out Text unityToggleText); - - unityToggle.onValueChanged.AddListener((bool val) => - { - LogUnity = val; - ConfigManager.Log_Unity_Debug.Value = val; - }); - - ConfigManager.Log_Unity_Debug.OnValueChanged += (bool val) => { unityToggle.isOn = val; }; - - unityToggle.isOn = LogUnity; - unityToggleText.text = "Log Unity Debug?"; - unityToggleText.alignment = TextAnchor.MiddleLeft; - - UIFactory.SetLayoutElement(unityToggleObj, minWidth: 170, flexibleWidth: 0); - - var unityToggleRect = unityToggleObj.transform.Find("Background").GetComponent(); - var pos = unityToggleRect.localPosition; - pos.y = -4; - unityToggleRect.localPosition = pos; - - #endregion - } - } -} diff --git a/src/UI/Main/Home/HomePage.cs b/src/UI/Main/Home/HomePage.cs deleted file mode 100644 index 91a0eeb..0000000 --- a/src/UI/Main/Home/HomePage.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.UI.Inspectors; - -namespace UnityExplorer.UI.Main.Home -{ - public class HomePage : BaseMenuPage - { - public override string Name => "Home"; - - public static HomePage Instance { get; internal set; } - - public override MenuPages Type => MenuPages.Home; - - public override bool Init() - { - Instance = this; - - ConstructMenu(); - - new SceneExplorer(); - - new InspectorManager(); - - SceneExplorer.Instance.Init(); - - return true; - } - - public override void Update() - { - SceneExplorer.Instance.Update(); - InspectorManager.Instance.Update(); - } - - private void ConstructMenu() - { - GameObject parent = MainMenu.Instance.PageViewport; - - Content = UIFactory.CreateHorizontalGroup(parent, "HomePage", true, true, true, true, 3, new Vector4(1,1,1,1)).gameObject; - } - } -} diff --git a/src/UI/Main/Home/SceneExplorer.cs b/src/UI/Main/Home/SceneExplorer.cs deleted file mode 100644 index ee6a5f6..0000000 --- a/src/UI/Main/Home/SceneExplorer.cs +++ /dev/null @@ -1,553 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityExplorer.UI; -using UnityExplorer.UI.Main; -using UnityEngine; -using UnityEngine.SceneManagement; -using UnityEngine.UI; -using UnityExplorer.Core.Runtime; -using UnityExplorer.UI.Main.Home; -using UnityExplorer.Core.Config; -using UnityExplorer.UI.Utility; -using UnityExplorer.UI.Main.Search; -using System.IO; -using UnityExplorer.Core; -using UnityExplorer.UI.Inspectors; - -namespace UnityExplorer.UI.Main.Home -{ - public class SceneExplorer - { - public static SceneExplorer Instance; - - internal static Action OnToggleShow; - - public SceneExplorer() - { - Instance = this; - - ConstructScenePane(); - } - - internal bool Hiding; - - private const float UPDATE_INTERVAL = 1f; - private float m_timeOfLastSceneUpdate; - - // private int m_currentSceneHandle = -1; - public static Scene DontDestroyScene => DontDestroyObject.scene; - internal Scene m_currentScene; - internal Scene[] m_currentScenes = new Scene[0]; - - internal GameObject[] m_allObjects = new GameObject[0]; - - internal GameObject m_selectedSceneObject; - internal int m_lastCount; - - private Dropdown m_sceneDropdown; - private Text m_sceneDropdownText; - private Text m_scenePathText; - private GameObject m_mainInspectBtn; - private GameObject m_backButtonObj; - - public PageHandler m_pageHandler; - private GameObject m_pageContent; - private readonly List m_shortListTexts = new List(); - private readonly List m_shortListToggles = new List(); - - internal readonly List m_shortList = new List(); - - private Text m_hideText; - private GameObject m_sceneDropdownObj; - private GameObject m_scenePathGroupObj; - private GameObject m_mainContent; - - internal static GameObject DontDestroyObject - { - get - { - if (!s_dontDestroyObject) - { - s_dontDestroyObject = new GameObject("DontDestroyMe"); - GameObject.DontDestroyOnLoad(s_dontDestroyObject); - } - return s_dontDestroyObject; - } - } - internal static GameObject s_dontDestroyObject; - - public void Init() - { - RefreshSceneSelector(); - - if (!ConfigManager.Last_SceneExplorer_State.Value) - ToggleShow(); - } - - public void ToggleShow() - { - if (!Hiding) - { - Hiding = true; - - m_hideText.text = "►"; - m_mainContent.SetActive(false); - m_pageHandler.Hide(); - } - else - { - Hiding = false; - - m_hideText.text = "◄"; - m_mainContent.SetActive(true); - m_pageHandler.Show(); - - Update(); - } - - InvokeOnToggleShow(); - } - - public void Update() - { - if (Hiding || Time.realtimeSinceStartup - m_timeOfLastSceneUpdate < UPDATE_INTERVAL) - return; - - RefreshSceneSelector(); - - if (!m_selectedSceneObject) - { - if (m_currentScene != default) - { - var rootObjects = RuntimeProvider.Instance.GetRootGameObjects(m_currentScene); - SetSceneObjectList(rootObjects); - } - } - else - { - RefreshSelectedSceneObject(); - } - } - - private void RefreshSceneSelector() - { - var newNames = new List(); - var newScenes = new List(); - - if (m_currentScenes == null) - m_currentScenes = new Scene[0]; - - bool anyChange = SceneManager.sceneCount != m_currentScenes.Length - 1; - - for (int i = 0; i < SceneManager.sceneCount; i++) - { - Scene scene = SceneManager.GetSceneAt(i); - - if (scene == default) - continue; - - int handle = RuntimeProvider.Instance.GetSceneHandle(scene); - - if (!anyChange && !m_currentScenes.Any(it => handle == RuntimeProvider.Instance.GetSceneHandle(it))) - anyChange = true; - - newScenes.Add(scene); - newNames.Add(scene.name); - } - - if (anyChange) - { - newNames.Add("DontDestroyOnLoad"); - newScenes.Add(DontDestroyScene); - m_currentScenes = newScenes.ToArray(); - - OnActiveScenesChanged(newNames); - - SetTargetScene(newScenes[0]); - - SearchPage.Instance.OnSceneChange(); - } - } - - public void SetTargetScene(int index) - => SetTargetScene(m_currentScenes[index]); - - public void SetTargetScene(Scene scene) - { - if (scene == default) - return; - - m_currentScene = scene; - var rootObjs = RuntimeProvider.Instance.GetRootGameObjects(scene); - SetSceneObjectList(rootObjs); - - m_selectedSceneObject = null; - - OnSceneSelected(); - } - - public void SetSceneObjectParent() - { - if (!m_selectedSceneObject || !m_selectedSceneObject.transform.parent?.gameObject) - { - m_selectedSceneObject = null; - SetTargetScene(m_currentScene); - } - else - { - SetTargetObject(m_selectedSceneObject.transform.parent.gameObject); - } - } - - public void SetTargetObject(GameObject obj) - { - if (!obj) - return; - - OnGameObjectSelected(obj); - - m_selectedSceneObject = obj; - - RefreshSelectedSceneObject(); - } - - private void RefreshSelectedSceneObject() - { - GameObject[] list = new GameObject[m_selectedSceneObject.transform.childCount]; - for (int i = 0; i < m_selectedSceneObject.transform.childCount; i++) - { - list[i] = m_selectedSceneObject.transform.GetChild(i).gameObject; - } - - SetSceneObjectList(list); - } - - private void SetSceneObjectList(GameObject[] objects) - { - m_allObjects = objects; - RefreshSceneObjectList(); - } - - internal void RefreshSceneObjectList() - { - m_timeOfLastSceneUpdate = Time.realtimeSinceStartup; - - RefreshSceneObjectList(m_allObjects, out int newCount); - - m_lastCount = newCount; - } - - internal static void InspectSelectedGameObject() - { - InspectorManager.Instance.Inspect(Instance.m_selectedSceneObject); - } - - internal static void InvokeOnToggleShow() - { - OnToggleShow?.Invoke(!Instance.Hiding); - } - - public void OnActiveScenesChanged(List newNames) - { - m_sceneDropdown.options.Clear(); - - foreach (string scene in newNames) - { - m_sceneDropdown.options.Add(new Dropdown.OptionData { text = scene }); - } - - m_sceneDropdown.OnCancel(null); - m_sceneDropdownText.text = newNames[0]; - } - - private void SceneListObjectClicked(int index) - { - if (index >= m_shortList.Count || !m_shortList[index]) - { - return; - } - - var obj = m_shortList[index]; - if (obj.transform.childCount > 0) - SetTargetObject(obj); - else - InspectorManager.Instance.Inspect(obj); - } - - internal void RefreshSceneObjectList(GameObject[] allObjects, out int newCount) - { - var objects = allObjects; - m_pageHandler.ListCount = objects.Length; - - //int startIndex = m_sceneListPageHandler.StartIndex; - - newCount = 0; - - foreach (var itemIndex in m_pageHandler) - { - newCount++; - - // normalized index starting from 0 - var i = itemIndex - m_pageHandler.StartIndex; - - if (itemIndex >= objects.Length) - { - if (i > SceneExplorer.Instance.m_lastCount || i >= m_shortListTexts.Count) - break; - - GameObject label = m_shortListTexts[i].transform.parent.parent.gameObject; - if (label.activeSelf) - label.SetActive(false); - } - else - { - GameObject obj = objects[itemIndex]; - - if (!obj) - continue; - - if (i >= m_shortList.Count) - { - m_shortList.Add(obj); - AddObjectListButton(); - } - else - { - m_shortList[i] = obj; - } - - var text = m_shortListTexts[i]; - - var name = obj.name; - - if (obj.transform.childCount > 0) - name = $"[{obj.transform.childCount}] {name}"; - - text.text = name; - text.color = obj.activeSelf ? Color.green : Color.red; - - var tog = m_shortListToggles[i]; - tog.isOn = obj.activeSelf; - - var label = text.transform.parent.parent.gameObject; - if (!label.activeSelf) - { - label.SetActive(true); - } - } - } - } - - private void OnSceneListPageTurn() - { - RefreshSceneObjectList(); - } - - private void OnToggleClicked(int index, bool val) - { - if (index >= m_shortList.Count || !m_shortList[index]) - return; - - var obj = m_shortList[index]; - obj.SetActive(val); - } - - internal void OnGameObjectSelected(GameObject obj) - { - m_scenePathText.text = obj.name; - if (!m_backButtonObj.activeSelf) - { - m_backButtonObj.SetActive(true); - m_mainInspectBtn.SetActive(true); - } - } - - internal void OnSceneSelected() - { - if (m_backButtonObj.activeSelf) - { - m_backButtonObj.SetActive(false); - m_mainInspectBtn.SetActive(false); - } - - m_scenePathText.text = "Scene root:"; - //m_scenePathText.ForceMeshUpdate(); - } - - #region UI CONSTRUCTION - - public void ConstructScenePane() - { - var coreGroup = UIFactory.CreateHorizontalGroup(HomePage.Instance.Content, "SceneExplorer", true, true, true, true, 4, new Vector4(2, 2, 2, 2), - new Color(0.05f, 0.05f, 0.05f)); - - // hide button - - var hideButton = UIFactory.CreateButton(coreGroup, "HideButton", "◄", ToggleShow, new Color(0.15f, 0.15f, 0.15f)); - hideButton.GetComponentInChildren().fontSize = 13; - m_hideText = hideButton.GetComponentInChildren(); - UIFactory.SetLayoutElement(hideButton.gameObject, minWidth: 20, minHeight: 20, flexibleWidth: 0, flexibleHeight: 9999); - - m_mainContent = UIFactory.CreateVerticalGroup(coreGroup, "SceneGroup", true, false, true, true, 0, default, - new Color(72f / 255f, 72f / 255f, 72f / 255f)); - UIFactory.SetLayoutElement(m_mainContent, minWidth: 350, flexibleWidth: 0); - - UIFactory.SetLayoutGroup(m_mainContent, true, true, true, true, spacing: 4, padTop: 8, 4, 4, 4); - - var titleObj = UIFactory.CreateLabel(m_mainContent, "SceneExplorerTitle", "Scene Explorer", TextAnchor.UpperLeft, default, true, 20).gameObject; - UIFactory.SetLayoutElement(titleObj, minHeight: 30, flexibleHeight: 0); - - m_sceneDropdownObj = UIFactory.CreateDropdown(m_mainContent, out m_sceneDropdown, "", 14, null); - UIFactory.SetLayoutElement(m_sceneDropdownObj, minHeight: 40, minWidth: 320, flexibleWidth: 0, flexibleHeight: 0); - - m_sceneDropdownText = m_sceneDropdown.transform.Find("Label").GetComponent(); - m_sceneDropdown.onValueChanged.AddListener((int val) => { SetTargetScene(val); }); - - m_scenePathGroupObj = UIFactory.CreateHorizontalGroup(m_mainContent, "ScenePathGroup", true, true, true, true, 5, default, new Color(1, 1, 1, 0f)); - UIFactory.SetLayoutElement(m_scenePathGroupObj, minHeight: 20, minWidth: 335); - - var backBtnObj = UIFactory.CreateButton(m_scenePathGroupObj, - "BackButton", - "◄", - () => { SetSceneObjectParent(); }, - new Color(0.12f, 0.12f, 0.12f)); - - m_backButtonObj = backBtnObj.gameObject; - - UIFactory.SetLayoutElement(m_backButtonObj, minWidth: 40, flexibleWidth: 0); - - GameObject scenePathLabel = UIFactory.CreateHorizontalGroup(m_scenePathGroupObj, "ScenePathLabel", false, false, false, false); - Image image = scenePathLabel.GetComponent(); - image.color = Color.white; - scenePathLabel.AddComponent().showMaskGraphic = false; - - UIFactory.SetLayoutElement(scenePathLabel, minWidth: 210, minHeight: 20, flexibleWidth: 120); - - m_scenePathText = UIFactory.CreateLabel(scenePathLabel, "ScenePathLabelText", "Scene root:", TextAnchor.MiddleLeft, default, true, 15); - m_scenePathText.horizontalOverflow = HorizontalWrapMode.Overflow; - - UIFactory.SetLayoutElement(m_scenePathText.gameObject, minWidth: 210, flexibleWidth: 120, minHeight: 20); - - var mainInspectButton = UIFactory.CreateButton(m_scenePathGroupObj, - "MainInspectButton", - "Inspect", - () => { InspectSelectedGameObject(); }, - new Color(0.12f, 0.12f, 0.12f)); - - m_mainInspectBtn = mainInspectButton.gameObject; - UIFactory.SetLayoutElement(m_mainInspectBtn, minWidth: 65); - - var scrollObj = UIFactory.CreateScrollView(m_mainContent, "SceneExplorerScrollView", - out m_pageContent, out SliderScrollbar scroller, new Color(0.1f, 0.1f, 0.1f)); - - m_pageHandler = new PageHandler(scroller); - m_pageHandler.ConstructUI(m_mainContent); - m_pageHandler.OnPageChanged += OnSceneListPageTurn; - - // Scene Loader - try - { - Type sceneUtil = ReflectionUtility.GetTypeByName("UnityEngine.SceneManagement.SceneUtility"); - if (sceneUtil == null) - throw new Exception("This version of Unity does not ship with the 'SceneUtility' class, or it was not unstripped."); - var method = sceneUtil.GetMethod("GetScenePathByBuildIndex", ReflectionUtility.AllFlags); - - var title2 = UIFactory.CreateLabel(m_mainContent, "SceneLoaderLabel", "Scene Loader", TextAnchor.MiddleLeft, Color.white, true, 20); - UIFactory.SetLayoutElement(title2.gameObject, minHeight: 30, flexibleHeight: 0); - - var allSceneDropObj = UIFactory.CreateDropdown(m_mainContent, out Dropdown allSceneDrop, "", 14, null); - UIFactory.SetLayoutElement(allSceneDropObj, minHeight: 40, minWidth: 320, flexibleWidth: 0, flexibleHeight: 0); - - int sceneCount = SceneManager.sceneCountInBuildSettings; - for (int i = 0; i < sceneCount; i++) - { - var scenePath = (string)method.Invoke(null, new object[] { i }); - allSceneDrop.options.Add(new Dropdown.OptionData(Path.GetFileNameWithoutExtension(scenePath))); - } - allSceneDrop.value = 1; - allSceneDrop.value = 0; - - var buttonRow = UIFactory.CreateHorizontalGroup(m_mainContent, "LoadButtons", true, true, true, true, 4); - - var loadButton = UIFactory.CreateButton(buttonRow, "LoadSceneButton", "Load (Single)", () => - { - try - { - SceneManager.LoadScene(allSceneDrop.options[allSceneDrop.value].text); - } - catch (Exception ex) - { - ExplorerCore.LogWarning($"Unable to load the Scene! {ex.ReflectionExToString()}"); - } - }, new Color(0.1f, 0.3f, 0.3f)); - UIFactory.SetLayoutElement(loadButton.gameObject, minHeight: 40, minWidth: 150); - - var loadAdditiveButton = UIFactory.CreateButton(buttonRow, "LoadSceneButton", "Load (Additive)", () => - { - try - { - SceneManager.LoadScene(allSceneDrop.options[allSceneDrop.value].text, LoadSceneMode.Additive); - } - catch (Exception ex) - { - ExplorerCore.LogWarning($"Unable to load the Scene! {ex.ReflectionExToString()}"); - } - }, new Color(0.1f, 0.3f, 0.3f)); - UIFactory.SetLayoutElement(loadAdditiveButton.gameObject, minHeight: 40, minWidth: 150); - } - catch (Exception ex) - { - ExplorerCore.LogWarning($"Could not create the Scene Loader helper! {ex.ReflectionExToString()}"); - } - } - - private void AddObjectListButton() - { - int thisIndex = m_shortListTexts.Count(); - - GameObject btnGroupObj = UIFactory.CreateHorizontalGroup(m_pageContent, "SceneObjectButton", true, false, true, true, - 0, default, new Color(0.1f, 0.1f, 0.1f)); - - UIFactory.SetLayoutElement(btnGroupObj, flexibleWidth: 320, minHeight: 25); - - btnGroupObj.AddComponent(); - - var toggleObj = UIFactory.CreateToggle(btnGroupObj, "ObjectToggleButton", out Toggle toggle, out Text toggleText, new Color(0.1f, 0.1f, 0.1f)); - var toggleLayout = toggleObj.AddComponent(); - toggleLayout.minHeight = 25; - toggleLayout.minWidth = 25; - toggleText.text = ""; - toggle.isOn = false; - m_shortListToggles.Add(toggle); - toggle.onValueChanged.AddListener((bool val) => { OnToggleClicked(thisIndex, val); }); - - var mainButton = UIFactory.CreateButton(btnGroupObj, - "MainButton", - "", - () => { SceneListObjectClicked(thisIndex); }); - - RuntimeProvider.Instance.SetColorBlock(mainButton, new Color(0.1f, 0.1f, 0.1f), - new Color(0.2f, 0.2f, 0.2f), new Color(0.05f, 0.05f, 0.05f)); - - UIFactory.SetLayoutElement(mainButton.gameObject, minHeight: 25, minWidth: 230); - - Text mainText = mainButton.GetComponentInChildren(); - mainText.alignment = TextAnchor.MiddleLeft; - mainText.horizontalOverflow = HorizontalWrapMode.Overflow; - m_shortListTexts.Add(mainText); - - var inspectButton = UIFactory.CreateButton(btnGroupObj, - "InspectButton", - "Inspect", - () => { InspectorManager.Instance.Inspect(m_shortList[thisIndex]); }); - - RuntimeProvider.Instance.SetColorBlock(inspectButton, new Color(0.15f, 0.15f, 0.15f), - new Color(0.2f, 0.2f, 0.2f), new Color(0.1f, 0.1f, 0.1f)); - - UIFactory.SetLayoutElement(inspectButton.gameObject, minWidth: 60, minHeight: 25); - } - - #endregion - } -} diff --git a/src/UI/Main/MainMenu.cs b/src/UI/Main/MainMenu.cs deleted file mode 100644 index cac610b..0000000 --- a/src/UI/Main/MainMenu.cs +++ /dev/null @@ -1,229 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityExplorer.Core.CSharp; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Config; -using UnityExplorer.Core.Unity; -using UnityExplorer.UI.Main; -using UnityExplorer.UI.Main.Home; -using UnityExplorer.UI.Main.Search; -using UnityExplorer.UI.Main.CSConsole; -using UnityExplorer.UI.Main.Options; -using UnityExplorer.Core.Runtime; - -namespace UnityExplorer.UI.Main -{ - public class MainMenu - { - public static MainMenu Instance { get; set; } - - public PanelDragger Dragger { get; private set; } - - public GameObject MainPanel { get; private set; } - public GameObject PageViewport { get; private set; } - - public readonly List Pages = new List(); - private BaseMenuPage m_activePage; - - public static Action OnActiveTabChanged; - - // Navbar buttons - private Button m_lastNavButtonPressed; - private readonly Color m_navButtonNormal = new Color(0.3f, 0.3f, 0.3f, 1); - private readonly Color m_navButtonHighlight = new Color(0.3f, 0.6f, 0.3f); - private readonly Color m_navButtonSelected = new Color(0.2f, 0.5f, 0.2f, 1); - - internal Vector3 initPos; - internal bool pageLayoutInit; - internal int layoutInitIndex; - - public static void Create() - { - if (Instance != null) - { - ExplorerCore.LogWarning("An instance of MainMenu already exists, cannot create another!"); - return; - } - - Instance = new MainMenu(); - Instance.Init(); - } - - private void Init() - { - Pages.Add(new HomePage()); - Pages.Add(new SearchPage()); - Pages.Add(new CSharpConsole()); - Pages.Add(new OptionsPage()); - - ConstructMenu(); - - for (int i = 0; i < Pages.Count; i++) - { - var page = Pages[i]; - - if (!page.Init()) - { - page.WasDisabled = true; - // page init failed. - Pages.RemoveAt(i); - i--; - - if (page.RefNavbarButton) - page.RefNavbarButton.interactable = false; - - if (page.Content) - GameObject.Destroy(page.Content); - } - } - - // hide menu until each page has init layout (bit of a hack) - initPos = MainPanel.transform.position; - MainPanel.transform.position = new Vector3(9999, 9999); - } - - public void Update() - { - if (!pageLayoutInit) - { - if (layoutInitIndex < Pages.Count) - { - SetPage(Pages[layoutInitIndex]); - layoutInitIndex++; - } - else - { - pageLayoutInit = true; - MainPanel.transform.position = initPos; - - SetPage(ConfigManager.Default_Tab.Value); - } - return; - } - - m_activePage?.Update(); - } - - public void SetPage(MenuPages page) - { - var pageObj = Pages.Find(it => it.Type == page); - if (pageObj == null || pageObj.WasDisabled) - return; - SetPage(pageObj); - } - - public void SetPage(BaseMenuPage page) - { - if (page == null || m_activePage == page || page.WasDisabled) - return; - - m_activePage?.Content?.SetActive(false); - - // unique case for console page, at the moment this will just go here - if (m_activePage is CSharpConsole) - AutoCompleter.m_mainObj?.SetActive(false); - - m_activePage = page; - - m_activePage.Content?.SetActive(true); - - Button button = page.RefNavbarButton; - SetButtonActiveColors(button); - - if (m_lastNavButtonPressed && m_lastNavButtonPressed != button) - SetButtonInactiveColors(m_lastNavButtonPressed); - - m_lastNavButtonPressed = button; - - OnActiveTabChanged?.Invoke(m_activePage.Type); - } - - internal void SetButtonActiveColors(Button button) - { - RuntimeProvider.Instance.SetColorBlock(button, m_navButtonSelected); - } - - internal void SetButtonInactiveColors(Button button) - { - RuntimeProvider.Instance.SetColorBlock(button, m_navButtonNormal); - } - - #region UI Construction - - private void ConstructMenu() - { - MainPanel = UIFactory.CreatePanel("MainMenu", out GameObject content, - ConfigManager.Last_Window_Anchors.Value, ConfigManager.Last_Window_Position.Value); - - ConstructTitleBar(content); - - ConstructNavbar(content); - - PageViewport = UIFactory.CreateHorizontalGroup(content, "MainViewPort", true, true, true, true); - - new DebugConsole(content); - } - - private void ConstructTitleBar(GameObject content) - { - // Core title bar holder - - GameObject titleBar = UIFactory.CreateHorizontalGroup(content, "MainTitleBar", true, true, true, true, 0, new Vector4(3,3,15,3)); - UIFactory.SetLayoutElement(titleBar, minWidth: 25, flexibleHeight: 0); - - // Main title label - - var text = UIFactory.CreateLabel(titleBar, "TitleLabel", $"UnityExplorer v{ExplorerCore.VERSION}", TextAnchor.MiddleLeft, - default, true, 15); - UIFactory.SetLayoutElement(text.gameObject, flexibleWidth: 5000); - - // Add PanelDragger using the label object - - Dragger = new PanelDragger(titleBar.GetComponent(), MainPanel.GetComponent()); - - // Hide button - - var hideButton = UIFactory.CreateButton(titleBar, - "HideButton", - $"Hide ({ConfigManager.Main_Menu_Toggle.Value})", - () => { UIManager.ShowMenu = false; }); - - RuntimeProvider.Instance.SetColorBlock(hideButton, new Color(65f / 255f, 23f / 255f, 23f / 255f), - new Color(35f / 255f, 10f / 255f, 10f / 255f), new Color(156f / 255f, 0f, 0f)); - - UIFactory.SetLayoutElement(hideButton.gameObject, minWidth: 90, flexibleWidth: 0); - - Text hideText = hideButton.GetComponentInChildren(); - hideText.color = Color.white; - hideText.resizeTextForBestFit = true; - hideText.resizeTextMinSize = 8; - hideText.resizeTextMaxSize = 14; - - ConfigManager.Main_Menu_Toggle.OnValueChanged += (KeyCode val) => - { - hideText.text = $"Hide ({val})"; - }; - } - - private void ConstructNavbar(GameObject content) - { - GameObject navbarObj = UIFactory.CreateHorizontalGroup(content, "MainNavBar", true, true, true, true, 5); - UIFactory.SetLayoutElement(navbarObj, minHeight: 25, flexibleHeight: 0); - - foreach (var page in Pages) - { - Button btn = UIFactory.CreateButton(navbarObj, - $"Button_{page.Name}", - page.Name, - () => { SetPage(page); }); - - RuntimeProvider.Instance.SetColorBlock(btn, m_navButtonNormal, m_navButtonHighlight, m_navButtonSelected); - - page.RefNavbarButton = btn; - } - } - - #endregion - } -} diff --git a/src/UI/Main/Options/OptionsPage.cs b/src/UI/Main/Options/OptionsPage.cs deleted file mode 100644 index 973685b..0000000 --- a/src/UI/Main/Options/OptionsPage.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.Core.Config; -using UnityExplorer.UI.CacheObject; -using UnityExplorer.UI.Utility; - -namespace UnityExplorer.UI.Main.Options -{ - public class OptionsPage : BaseMenuPage - { - public override string Name => "Options"; - public override MenuPages Type => MenuPages.Options; - - internal static readonly List _cachedConfigEntries = new List(); - - public override bool Init() - { - ConstructUI(); - - return true; - } - - public override void Update() - { - // Not needed - } - - #region UI CONSTRUCTION - - internal GameObject m_contentObj; - - internal void ConstructUI() - { - GameObject parent = MainMenu.Instance.PageViewport; - - Content = UIFactory.CreateVerticalGroup(parent, "OptionsPage", false, true, true, true, 5, new Vector4(4,4,4,4), - new Color(0.15f, 0.15f, 0.15f)); - UIFactory.SetLayoutElement(Content, minHeight: 340, flexibleHeight: 9999); - - // ~~~~~ Title ~~~~~ - - var titleLabel = UIFactory.CreateLabel(Content, "Title", "Options", TextAnchor.UpperLeft, default, true, 25); - UIFactory.SetLayoutElement(titleLabel.gameObject, minHeight: 30, flexibleHeight: 0, flexibleWidth: 9999); - - // Save button - - var btn = UIFactory.CreateButton(Content, - "SaveButton", - "Save Config File", - () => { ConfigManager.Handler.SaveConfig(); }, - new Color(0.25f, 0.6f, 0.25f)); - UIFactory.SetLayoutElement(btn.gameObject, minWidth: 200, flexibleWidth: 0, minHeight: 30, flexibleHeight: 0); - - // ~~~~~ Actual options ~~~~~ - - UIFactory.CreateScrollView(Content, "ConfigList", out m_contentObj, out _, new Color(0.05f, 0.05f, 0.05f)); - UIFactory.SetLayoutGroup(m_contentObj, forceHeight: true, spacing: 3, padLeft: 3, padRight: 3); - - _cachedConfigEntries.AddRange(ConfigManager.ConfigElements.Values - .Where(it => !it.IsInternal) - .Select(it => new CacheConfigEntry(it, m_contentObj))); - - foreach (var entry in _cachedConfigEntries) - entry.Enable(); - } - - - #endregion - } -} diff --git a/src/UI/Main/Search/SearchPage.cs b/src/UI/Main/Search/SearchPage.cs deleted file mode 100644 index 25f43d6..0000000 --- a/src/UI/Main/Search/SearchPage.cs +++ /dev/null @@ -1,460 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.SceneManagement; -using UnityEngine.UI; -using System.Reflection; -using UnityExplorer.Core.Runtime; -using UnityExplorer.Core; -using UnityExplorer.UI.Utility; -using UnityExplorer.Core.Search; -using UnityExplorer.UI.Main.Home; -using UnityExplorer.UI.Inspectors; - -namespace UnityExplorer.UI.Main.Search -{ - public class SearchPage : BaseMenuPage - { - public override string Name => "Search"; - public override MenuPages Type => MenuPages.Search; - - public static SearchPage Instance; - - internal SearchContext m_context; - private SceneFilter m_sceneFilter; - private ChildFilter m_childFilter; - - // ui elements - - private Text m_resultCountText; - - private InputField m_customTypeInput; - - private InputField m_nameInput; - - private Button m_selectedContextButton; - private readonly Dictionary m_contextButtons = new Dictionary(); - - internal Dropdown m_sceneDropdown; - private int m_lastSceneCount = -1; - - private GameObject m_extraFilterRow; - - // Results - - internal object[] m_results; - internal readonly List m_resultShortList = new List(); - - private int m_lastCount; - public PageHandler m_resultListPageHandler; - private GameObject m_resultListContent; - private readonly List m_resultListTexts = new List(); - - public SearchPage() - { - Instance = this; - } - - public override bool Init() - { - ConstructUI(); - - return true; - } - - public void OnSceneChange() - { - m_results = new object[0]; - RefreshResultList(); - } - - public override void Update() - { - if (HaveScenesChanged()) - { - RefreshSceneDropdown(); - } - - if (m_customTypeInput.isFocused && m_context != SearchContext.Custom) - { - OnContextButtonClicked(SearchContext.Custom); - } - } - - // Updating result list content - - private void RefreshResultList() - { - if (m_resultListPageHandler == null || m_results == null) - return; - - m_resultListPageHandler.ListCount = m_results.Length; - - int newCount = 0; - - foreach (var itemIndex in m_resultListPageHandler) - { - newCount++; - - // normalized index starting from 0 - var i = itemIndex - m_resultListPageHandler.StartIndex; - - if (itemIndex >= m_results.Length) - { - if (i > m_lastCount || i >= m_resultListTexts.Count) - break; - - GameObject label = m_resultListTexts[i].transform.parent.parent.gameObject; - if (label.activeSelf) - label.SetActive(false); - } - else - { - var obj = m_results[itemIndex]; - var unityObj = obj as UnityEngine.Object; - - if (obj == null || (unityObj != null && !unityObj)) - continue; - - if (i >= m_resultShortList.Count) - { - m_resultShortList.Add(obj); - AddResultButton(); - } - else - { - m_resultShortList[i] = obj; - } - - var text = m_resultListTexts[i]; - - if (m_context != SearchContext.StaticClass) - { - var name = SignatureHighlighter.ParseFullSyntax(ReflectionUtility.GetActualType(obj), true); - - if (unityObj && m_context != SearchContext.Singleton) - { - if (unityObj && !string.IsNullOrEmpty(unityObj.name)) - name += $": {unityObj.name}"; - else - name += ": untitled"; - } - - text.text = name; - } - else - { - var type = obj as Type; - text.text = SignatureHighlighter.ParseFullSyntax(type, true); - } - - var label = text.transform.parent.parent.gameObject; - if (!label.activeSelf) - label.SetActive(true); - } - } - - m_lastCount = newCount; - } - - // scene dropdown update - - internal bool HaveScenesChanged() - { - if (m_lastSceneCount != SceneManager.sceneCount) - return true; - - for (int i = 0; i < SceneManager.sceneCount; i++) - { - int dropdownIndex = i + 3; - if (dropdownIndex >= m_sceneDropdown.options.Count - || m_sceneDropdown.options[dropdownIndex].text != SceneManager.GetSceneAt(i).name) - return true; - } - - return false; - } - - internal void RefreshSceneDropdown() - { - m_sceneDropdown.OnCancel(null); - - m_sceneDropdown.options.Clear(); - - m_sceneDropdown.options.Add(new Dropdown.OptionData - { - text = "Any" - }); - - m_sceneDropdown.options.Add(new Dropdown.OptionData - { - text = "None (Asset / Resource)" - }); - m_sceneDropdown.options.Add(new Dropdown.OptionData - { - text = "DontDestroyOnLoad" - }); - - m_lastSceneCount = 0; - for (int i = 0; i < SceneManager.sceneCount; i++) - { - m_lastSceneCount++; - - var scene = SceneManager.GetSceneAt(i).name; - m_sceneDropdown.options.Add(new Dropdown.OptionData - { - text = scene - }); - } - - m_sceneDropdown.itemText.text = "Any"; - m_sceneFilter = SceneFilter.Any; - } - - // ~~~~~ UI Callbacks ~~~~~ - - internal void OnSearchClicked() - { - m_resultListPageHandler.CurrentPage = 0; - - if (m_context == SearchContext.StaticClass) - m_results = SearchProvider.StaticClassSearch(m_nameInput.text); - else if (m_context == SearchContext.Singleton) - m_results = SearchProvider.SingletonSearch(m_nameInput.text); - else - m_results = SearchProvider.UnityObjectSearch(m_nameInput.text, m_customTypeInput.text, m_context, m_childFilter, m_sceneFilter); - - if (m_results == null) - m_results = new object[0]; - - RefreshResultList(); - - if (m_results.Length > 0) - m_resultCountText.text = $"{m_results.Length} Results"; - else - m_resultCountText.text = "No results..."; - } - - private void OnResultPageTurn() - { - RefreshResultList(); - } - - internal void OnResultClicked(int index) - { - if (m_context == SearchContext.StaticClass) - InspectorManager.Instance.Inspect((Type)m_resultShortList[index]); - else - InspectorManager.Instance.Inspect(m_resultShortList[index]); - } - - internal void OnContextButtonClicked(SearchContext context) - { - if (m_selectedContextButton && m_context == context) - return; - - if (m_selectedContextButton) - UIFactory.SetDefaultSelectableColors(m_selectedContextButton); - - var button = m_contextButtons[context]; - - m_selectedContextButton = button; - - RuntimeProvider.Instance.SetColorBlock(m_selectedContextButton, - new Color(0.35f, 0.7f, 0.35f), new Color(0.35f, 0.7f, 0.35f)); - - m_context = context; - - // if extra filters are valid - if (context == SearchContext.Component - || context == SearchContext.GameObject - || context == SearchContext.Custom) - { - m_extraFilterRow?.SetActive(true); - } - else - { - m_extraFilterRow?.SetActive(false); - } - } - - #region UI CONSTRUCTION - - internal void ConstructUI() - { - GameObject parent = MainMenu.Instance.PageViewport; - - Content = UIFactory.CreateVerticalGroup(parent, "SearchPage", true, true, true, true, 5, new Vector4(4,4,4,4)); - - ConstructTopArea(); - - ConstructResultsArea(); - } - - internal void ConstructTopArea() - { - var topAreaObj = UIFactory.CreateVerticalGroup(Content, "TitleArea", true, false, true, true, 5, new Vector4(5,5,5,5), - new Color(0.15f, 0.15f, 0.15f)); - - var titleLabel = UIFactory.CreateLabel(topAreaObj, "SearchTitle", "Search", TextAnchor.UpperLeft, Color.white, true, 25); - UIFactory.SetLayoutElement(titleLabel.gameObject, minHeight: 30, flexibleHeight: 0); - - // top area options - - var optionsGroupObj = UIFactory.CreateVerticalGroup(topAreaObj, "OptionsArea", true, false, true, true, 10, new Vector4(4,4,4,4), - new Color(0.1f, 0.1f, 0.1f)); - UIFactory.SetLayoutElement(optionsGroupObj, minWidth: 500, minHeight: 70, flexibleHeight: 100); - - // search context row - - var contextRowObj = UIFactory.CreateHorizontalGroup(optionsGroupObj, "ContextFilters", false, false, true, true, 3, default, - new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(contextRowObj, minHeight: 25); - - var contextLabelObj = UIFactory.CreateLabel(contextRowObj, "ContextLabel", "Searching for:", TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(contextLabelObj.gameObject, minWidth: 125, minHeight: 25); - - // context buttons - - AddContextButton(contextRowObj, "UnityEngine.Object", SearchContext.UnityObject, 140); - AddContextButton(contextRowObj, "GameObject", SearchContext.GameObject); - AddContextButton(contextRowObj, "Component", SearchContext.Component); - AddContextButton(contextRowObj, "Custom...", SearchContext.Custom); - - // custom type input - - var customTypeObj = UIFactory.CreateInputField(contextRowObj, "CustomTypeInput", "eg. UnityEngine.Texture2D, etc..."); - UIFactory.SetLayoutElement(customTypeObj, minWidth: 250, flexibleWidth: 2000, minHeight: 25, flexibleHeight: 0); - m_customTypeInput = customTypeObj.GetComponent(); - - // static class and singleton buttons - - var secondRow = UIFactory.CreateHorizontalGroup(optionsGroupObj, "SecondRow", false, false, true, true, 3, default, new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(secondRow, minHeight: 25); - - var spacer = UIFactory.CreateUIObject("spacer", secondRow); - UIFactory.SetLayoutElement(spacer, minWidth: 25, minHeight: 25); - - AddContextButton(secondRow, "Static Class", SearchContext.StaticClass); - AddContextButton(secondRow, "Singleton", SearchContext.Singleton); - - // search input - - var nameRowObj = UIFactory.CreateHorizontalGroup(optionsGroupObj, "SearchInput", true, false, true, true, 0, default, new Color(1, 1, 1, 0)); - UIFactory.SetLayoutElement(nameRowObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 5000); - - var nameLabel = UIFactory.CreateLabel(nameRowObj, "NameLabel", "Name contains:", TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(nameLabel.gameObject, minWidth: 125, minHeight: 25); - - var nameInputObj = UIFactory.CreateInputField(nameRowObj, "NameInputField", "..."); - m_nameInput = nameInputObj.GetComponent(); - UIFactory.SetLayoutElement(nameInputObj, minWidth: 150, flexibleWidth: 5000, minHeight: 25); - - // extra filter row - - m_extraFilterRow = UIFactory.CreateHorizontalGroup(optionsGroupObj, "ExtraFilterRow", false, true, true, true, 0, default, new Color(1, 1, 1, 0)); - m_extraFilterRow.SetActive(false); - UIFactory.SetLayoutElement(m_extraFilterRow, minHeight: 25, minWidth: 125, flexibleHeight: 0, flexibleWidth: 150); - - // scene filter - - var sceneLabelObj = UIFactory.CreateLabel(m_extraFilterRow, "SceneFilterLabel", "Scene filter:", TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(sceneLabelObj.gameObject, minWidth: 125, minHeight: 25); - - var sceneDropObj = UIFactory.CreateDropdown(m_extraFilterRow, - out m_sceneDropdown, - "Any", - 12, - (int value) => { m_sceneFilter = (SceneFilter)value; } - ); - - UIFactory.SetLayoutElement(sceneDropObj, minWidth: 220, minHeight: 25); - - // invisible space - - var invis = UIFactory.CreateUIObject("spacer", m_extraFilterRow); - UIFactory.SetLayoutElement(invis, minWidth: 25, flexibleWidth: 0); - - // children filter - - var childLabelObj = UIFactory.CreateLabel(m_extraFilterRow, "ChildFilterLabel", "Child filter:", TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(childLabelObj.gameObject, minWidth: 100, minHeight: 25); - - var childDropObj = UIFactory.CreateDropdown(m_extraFilterRow, - out Dropdown childDrop, - "Any", - 12, - (int value) => { m_childFilter = (ChildFilter)value; }, - new[] { "Any", "Root Objects Only", "Children Only" }); - - UIFactory.SetLayoutElement(childDropObj, minWidth: 180, minHeight: 25); - - // search button - - var searchBtnObj = UIFactory.CreateButton(topAreaObj, "SearchButton", "Search", OnSearchClicked); - UIFactory.SetLayoutElement(searchBtnObj.gameObject, minHeight: 30, flexibleHeight: 0); - } - - internal void AddContextButton(GameObject parent, string label, SearchContext context, float width = 110) - { - var btn = UIFactory.CreateButton(parent, $"Context_{context}", label, () => { OnContextButtonClicked(context); }); - UIFactory.SetLayoutElement(btn.gameObject, minHeight: 25, minWidth: (int)width); - - m_contextButtons.Add(context, btn); - - // if first button - if (!m_selectedContextButton) - OnContextButtonClicked(context); - } - - internal void ConstructResultsArea() - { - // Result group holder (NOT actual result list content) - - var resultGroupObj = UIFactory.CreateVerticalGroup(Content, "SearchResults", true, false, true, true, 5, new Vector4(5,5,5,5), - new Color(1, 1, 1, 0)); - - m_resultCountText = UIFactory.CreateLabel(resultGroupObj, "ResultsLabel", "No results...", TextAnchor.MiddleCenter); - - GameObject scrollObj = UIFactory.CreateScrollView(resultGroupObj, - "ResultsScrollView", - out m_resultListContent, - out SliderScrollbar scroller, - new Color(0.07f, 0.07f, 0.07f, 1)); - - m_resultListPageHandler = new PageHandler(scroller); - m_resultListPageHandler.ConstructUI(resultGroupObj); - m_resultListPageHandler.OnPageChanged += OnResultPageTurn; - - UIFactory.SetLayoutGroup(m_resultListContent, forceHeight: false, childControlHeight: true, spacing: 2); - } - - internal void AddResultButton() - { - int thisIndex = m_resultListTexts.Count(); - - GameObject btnGroupObj = UIFactory.CreateHorizontalGroup(m_resultListContent, "ResultButtonGroup", - true, false, true, true, 0, new Vector4(1,1,1,1), new Color(0.1f, 0.1f, 0.1f)); - UIFactory.SetLayoutElement(btnGroupObj, flexibleWidth: 320, minHeight: 25, flexibleHeight: 0); - btnGroupObj.AddComponent(); - - var mainButton = UIFactory.CreateButton(btnGroupObj, - "ResultButton", - "", - () => { OnResultClicked(thisIndex); }); - - RuntimeProvider.Instance.SetColorBlock(mainButton, new Color(0.1f, 0.1f, 0.1f), - new Color(0.2f, 0.2f, 0.2f), new Color(0.05f, 0.05f, 0.05f)); - - UIFactory.SetLayoutElement(mainButton.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 320, flexibleWidth: 0); - - Text text = mainButton.GetComponentInChildren(); - text.alignment = TextAnchor.MiddleLeft; - text.horizontalOverflow = HorizontalWrapMode.Overflow; - m_resultListTexts.Add(text); - } - - #endregion - } -} diff --git a/src/UI/Model/UIBehaviourModel.cs b/src/UI/Model/UIBehaviourModel.cs new file mode 100644 index 0000000..21a812b --- /dev/null +++ b/src/UI/Model/UIBehaviourModel.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace UnityExplorer.UI.Models +{ + public abstract class UIBehaviourModel : UIModel + { + private static readonly List Instances = new List(); + + public static void UpdateInstances() + { + if (!Instances.Any()) + return; + + for (int i = Instances.Count - 1; i >= 0; i--) + { + var instance = Instances[i]; + if (!instance.UIRoot) + Instances.RemoveAt(i); + else if (instance.NeedsUpdate && instance.Visible) + instance.Update(); + } + } + + /// + /// Default false, if true then Update should be implemented. + /// + public virtual bool NeedsUpdate => false; + + public UIBehaviourModel() + { + Instances.Add(this); + } + + /// + /// Default empty method, override and implement if NeedsUpdateTick is true. + /// + public virtual void Update() + { + } + + public override void Destroy() + { + if (Instances.Contains(this)) + Instances.Remove(this); + + base.Destroy(); + } + } +} diff --git a/src/UI/Model/UIModel.cs b/src/UI/Model/UIModel.cs new file mode 100644 index 0000000..fab696f --- /dev/null +++ b/src/UI/Model/UIModel.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace UnityExplorer.UI.Models +{ + public abstract class UIModel + { + public abstract GameObject UIRoot { get; } + + public bool Visible + { + get => UIRoot?.activeInHierarchy ?? false; + set => UIRoot?.SetActive(value); + } + + public abstract void ConstructUI(GameObject parent); + + public virtual void Destroy() + { + if (UIRoot) + GameObject.Destroy(UIRoot); + } + } +} diff --git a/src/UI/Panels/SceneExplorer.cs b/src/UI/Panels/SceneExplorer.cs new file mode 100644 index 0000000..9dcc6ef --- /dev/null +++ b/src/UI/Panels/SceneExplorer.cs @@ -0,0 +1,181 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.UI; +using UnityExplorer.Core; +using UnityExplorer.UI.Models; +using UnityExplorer.UI.Utility; +using UnityExplorer.UI.Widgets; + +namespace UnityExplorer.UI.Panels +{ + public class SceneExplorer : UIBehaviourModel + { + public override GameObject UIRoot => uiRoot; + private GameObject uiRoot; + + public override bool NeedsUpdate => true; + + public TransformTree Tree; + private float timeOfLastUpdate = -1f; + + private Dropdown sceneDropdown; + private readonly Dictionary sceneToDropdownOption = new Dictionary(); + + public SceneExplorer() + { + SceneHandler.OnInspectedSceneChanged += SceneHandler_OnInspectedSceneChanged; + SceneHandler.OnLoadedScenesChanged += SceneHandler_OnLoadedScenesChanged; + } + + private IEnumerable GetRootEntries() => SceneHandler.CurrentRootObjects; + + public override void Update() + { + if (Time.realtimeSinceStartup - timeOfLastUpdate < 1f) + return; + timeOfLastUpdate = Time.realtimeSinceStartup; + + Tree.infiniteScroll.ExternallySetting = true; + SceneHandler.Update(); + Tree.RefreshData(true); + } + + private void OnDropdownChanged(int value) + { + if (value < 0 || SceneHandler.LoadedScenes.Count <= value) + return; + + SceneHandler.SelectedScene = SceneHandler.LoadedScenes[value]; + SceneHandler.Update(); + Tree.RefreshData(true); + } + + private void SceneHandler_OnInspectedSceneChanged(Scene scene) + { + if (!sceneToDropdownOption.ContainsKey(scene.handle)) + PopulateSceneDropdown(); + + if (sceneToDropdownOption.ContainsKey(scene.handle)) + { + int idx = sceneDropdown.value = sceneDropdown.options.IndexOf(sceneToDropdownOption[scene.handle]); + if (sceneDropdown.value != idx) + sceneDropdown.value = idx; + } + } + + private void SceneHandler_OnLoadedScenesChanged(ReadOnlyCollection loadedScenes) + { + PopulateSceneDropdown(); + } + + private void PopulateSceneDropdown() + { + sceneToDropdownOption.Clear(); + sceneDropdown.options.Clear(); + + foreach (var scene in SceneHandler.LoadedScenes) + { + string name = scene.name?.Trim(); + + if (!scene.IsValid()) + name = "HideAndDontSave"; + else if (string.IsNullOrEmpty(name)) + name = ""; + + sceneDropdown.options.Add(new Dropdown.OptionData(name)); + sceneToDropdownOption.Add(scene.handle, sceneDropdown.options.Last()); + } + } + + private void OnFilterInput(string input) + { + Tree.CurrentFilter = input; + Tree.RefreshData(true); + } + + private void SceneExplorer_OnFinishResize(RectTransform obj) + { + int curIdx = Tree.infiniteScroll.currentItemCount; + // Set it to 0 (its going to jump to top anyway) + Tree.infiniteScroll.currentItemCount = 0; + // Need to do complete rebuild so that anchors and offsets can recalculated. + Tree.infiniteScroll.ReloadData(); + // Try jump back to previous idx + RuntimeProvider.Instance.StartCoroutine(DelayedJump(curIdx)); + } + + private IEnumerator DelayedJump(int idx) + { + yield return null; + Tree.infiniteScroll.JumpToIndex(0); + yield return null; + Tree.infiniteScroll.JumpToIndex(idx); + } + + public override void ConstructUI(GameObject parent) + { + var panel = UIFactory.CreatePanel("SceneExplorer", out GameObject panelContent); + uiRoot = panel; + var panelRect = panel.GetComponent(); + panelRect.anchorMin = Vector3.zero; + panelRect.anchorMax = new Vector2(0, 1); + panelRect.sizeDelta = new Vector2(300f, panelRect.sizeDelta.y); + panelRect.anchoredPosition = new Vector2(160, 0); + panelRect.offsetMin = new Vector2(panelRect.offsetMin.x, 10); // bottom + panelRect.offsetMax = new Vector2(panelRect.offsetMax.x, -10); // top + panelRect.pivot = new Vector2(0.5f, 0.5f); + UIFactory.SetLayoutGroup(panel, true, true, true, true, 0,0,0,0,0, TextAnchor.UpperLeft); + UIFactory.SetLayoutGroup(panelContent, true, true, true, true, 2, 2, 2, 2, 2, TextAnchor.UpperLeft); + + Tree = panel.AddComponent(); + Tree.GetRootEntriesMethod = GetRootEntries; + + // Title bar + + var titleBar = UIFactory.CreateLabel(panelContent, "TitleBar", "Scene Explorer", TextAnchor.MiddleLeft); + UIFactory.SetLayoutElement(titleBar.gameObject, minHeight: 25, flexibleHeight: 0); + + new PanelDragger(titleBar.GetComponent(), panelRect) + .OnFinishResize += SceneExplorer_OnFinishResize; + + // Tool bar + + var toolbar = UIFactory.CreateVerticalGroup(panelContent, "Toolbar", true, true, true, true, 2, new Vector4(2, 2, 2, 2), + new Color(0.15f, 0.15f, 0.15f)); + //UIFactory.SetLayoutElement(toolbar, minHeight: 25, flexibleHeight: 0); + + //Scene selector dropdown + var dropdownObj = UIFactory.CreateDropdown(toolbar, out sceneDropdown, "", 13, OnDropdownChanged); + UIFactory.SetLayoutElement(dropdownObj, minHeight: 25, flexibleHeight: 0); + + SceneHandler.Update(); + PopulateSceneDropdown(); + sceneDropdown.itemText.text = sceneToDropdownOption.First().Value.text; + + //Filter input field + var inputFieldObj = UIFactory.CreateInputField(toolbar, "FilterInput", "Search...", out InputField inputField, 13); + UIFactory.SetLayoutElement(inputFieldObj, minHeight: 25); + inputField.onValueChanged.AddListener(OnFilterInput); + + // Transform Tree + + var infiniteScroll = UIFactory.CreateInfiniteScroll(panelContent, "TransformTree", out GameObject scrollContent, + new Color(0.15f, 0.15f, 0.15f)); + UIFactory.SetLayoutElement(infiniteScroll.gameObject, flexibleHeight: 9999); + UIFactory.SetLayoutElement(scrollContent, flexibleHeight: 9999); + + // Prototype tree cell + var prototype = Tree.CreatePrototypeCell(scrollContent, Tree); + infiniteScroll.PrototypeCell = prototype.GetComponent(); + + // Setup references + Tree.infiniteScroll = infiniteScroll; + } + } +} diff --git a/src/UI/UIFactory.cs b/src/UI/UIFactory.cs index 18da679..5095288 100644 --- a/src/UI/UIFactory.cs +++ b/src/UI/UIFactory.cs @@ -5,6 +5,8 @@ using UnityEngine.UI; using UnityExplorer.Core.Config; using UnityExplorer.Core.Runtime; using UnityExplorer.UI.Utility; +using UnityExplorer.UI.Widgets; +using UnityExplorer.UI.Widgets.InfiniteScroll; namespace UnityExplorer.UI { @@ -64,7 +66,7 @@ namespace UnityExplorer.UI /// Get and/or Add a LayoutElement component to the GameObject, and set any of the values on it. /// public static LayoutElement SetLayoutElement(GameObject gameObject, int? minWidth = null, int? minHeight = null, - int? flexibleWidth = null, int? flexibleHeight = null, int? preferredWidth = null, int? preferredHeight = null, + int? flexibleWidth = null, int? flexibleHeight = null, int? preferredWidth = null, int? preferredHeight = null, bool? ignoreLayout = null) { var layout = gameObject.GetComponent(); @@ -99,15 +101,15 @@ namespace UnityExplorer.UI /// Get and/or Add a HorizontalOrVerticalLayoutGroup (must pick one) to the GameObject, and set the values on it. /// public static T SetLayoutGroup(GameObject gameObject, bool? forceWidth = null, bool? forceHeight = null, - bool? childControlWidth = null, bool? childControlHeight = null, int? spacing = null, int? padTop = null, - int? padBottom = null, int? padLeft = null, int? padRight = null, TextAnchor? childAlignment = null) + bool? childControlWidth = null, bool? childControlHeight = null, int? spacing = null, int? padTop = null, + int? padBottom = null, int? padLeft = null, int? padRight = null, TextAnchor? childAlignment = null) where T : HorizontalOrVerticalLayoutGroup { var group = gameObject.GetComponent(); if (!group) group = gameObject.AddComponent(); - return SetLayoutGroup(group, forceWidth, forceHeight, childControlWidth, childControlHeight, spacing, padTop, + return SetLayoutGroup(group, forceWidth, forceHeight, childControlWidth, childControlHeight, spacing, padTop, padBottom, padLeft, padRight, childAlignment); } @@ -116,7 +118,7 @@ namespace UnityExplorer.UI /// public static T SetLayoutGroup(T group, bool? forceWidth = null, bool? forceHeight = null, bool? childControlWidth = null, bool? childControlHeight = null, int? spacing = null, int? padTop = null, - int? padBottom = null, int? padLeft = null, int? padRight = null, TextAnchor? childAlignment = null) + int? padBottom = null, int? padLeft = null, int? padRight = null, TextAnchor? childAlignment = null) where T : HorizontalOrVerticalLayoutGroup { if (forceWidth != null) @@ -146,7 +148,8 @@ namespace UnityExplorer.UI /// /// Create a Panel on the UI Canvas. /// - public static GameObject CreatePanel(string name, out GameObject contentHolder, string anchors = null, string position = null) + public static GameObject CreatePanel(string name, out GameObject contentHolder, Color? bgColor = null, + string anchors = null, string position = null) { var panelObj = CreateUIObject(name, UIManager.CanvasRoot); var rect = panelObj.GetComponent(); @@ -171,7 +174,10 @@ namespace UnityExplorer.UI Image bgImage = contentHolder.AddComponent(); bgImage.type = Image.Type.Filled; - bgImage.color = new Color(0.1f, 0.1f, 0.1f); + if (bgColor == null) + bgImage.color = new Color(0.1f, 0.1f, 0.1f); + else + bgImage.color = (Color)bgColor; SetLayoutGroup(contentHolder, true, true, true, true, 3, 3, 3, 3, 3); @@ -279,7 +285,7 @@ namespace UnityExplorer.UI Image image = buttonObj.AddComponent(); image.type = Image.Type.Sliced; - image.color = new Color(1, 1, 1, 0.75f); + image.color = new Color(1, 1, 1, 1); var button = buttonObj.AddComponent