mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-13 07:16:37 +08:00
some early steps remaking the GUI with UnityEngine.UI, working in all tested game so far
This commit is contained in:
@ -1,13 +1,16 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Explorer.Helpers;
|
||||
using ExplorerBeta.Helpers;
|
||||
using UnityEngine.EventSystems;
|
||||
using ExplorerBeta.UI;
|
||||
using ExplorerBeta.Input;
|
||||
#if ML
|
||||
using Harmony;
|
||||
#else
|
||||
using HarmonyLib;
|
||||
#endif
|
||||
|
||||
namespace Explorer.UI
|
||||
namespace ExplorerBeta.UI
|
||||
{
|
||||
public class ForceUnlockCursor
|
||||
{
|
||||
@ -18,6 +21,12 @@ namespace Explorer.UI
|
||||
}
|
||||
private static bool m_forceUnlock;
|
||||
|
||||
private static void SetForceUnlock(bool unlock)
|
||||
{
|
||||
m_forceUnlock = unlock;
|
||||
UpdateCursorControl();
|
||||
}
|
||||
|
||||
public static bool ShouldForceMouse => ExplorerCore.ShowMenu && Unlock;
|
||||
|
||||
private static CursorLockMode m_lastLockMode;
|
||||
@ -25,8 +34,8 @@ namespace Explorer.UI
|
||||
|
||||
private static bool m_currentlySettingCursor = false;
|
||||
|
||||
private static Type CursorType
|
||||
=> m_cursorType
|
||||
private static Type CursorType
|
||||
=> m_cursorType
|
||||
?? (m_cursorType = ReflectionHelpers.GetTypeByName("UnityEngine.Cursor"));
|
||||
private static Type m_cursorType;
|
||||
|
||||
@ -44,11 +53,13 @@ namespace Explorer.UI
|
||||
m_lastVisibleState = Cursor.visible;
|
||||
|
||||
// Setup Harmony Patches
|
||||
TryPatch("lockState", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_lockState))), true);
|
||||
TryPatch("lockState", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Postfix_get_lockState))), false);
|
||||
TryPatch(typeof(EventSystem), "current", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_EventSystem_set_current))), true);
|
||||
|
||||
TryPatch("visible", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_visible))), true);
|
||||
TryPatch("visible", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Postfix_get_visible))), false);
|
||||
TryPatch(typeof(Cursor), "lockState", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_lockState))), true);
|
||||
//TryPatch(typeof(Cursor), "lockState", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Postfix_get_lockState))), false);
|
||||
|
||||
TryPatch(typeof(Cursor), "visible", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_visible))), true);
|
||||
//TryPatch(typeof(Cursor), "visible", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Postfix_get_visible))), false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -58,7 +69,7 @@ namespace Explorer.UI
|
||||
Unlock = true;
|
||||
}
|
||||
|
||||
private static void TryPatch(string property, HarmonyMethod patch, bool setter)
|
||||
private static void TryPatch(Type type, string property, HarmonyMethod patch, bool setter)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -70,7 +81,7 @@ namespace Explorer.UI
|
||||
#endif
|
||||
;
|
||||
|
||||
var prop = typeof(Cursor).GetProperty(property);
|
||||
var prop = type.GetProperty(property);
|
||||
|
||||
if (setter)
|
||||
{
|
||||
@ -85,17 +96,11 @@ namespace Explorer.UI
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string s = setter ? "set_" : "get_" ;
|
||||
ExplorerCore.Log($"Unable to patch Cursor.{s}{property}: {e.Message}");
|
||||
string suf = setter ? "set_" : "get_";
|
||||
ExplorerCore.Log($"Unable to patch {type.Name}.{suf}{property}: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetForceUnlock(bool unlock)
|
||||
{
|
||||
m_forceUnlock = unlock;
|
||||
UpdateCursorControl();
|
||||
}
|
||||
|
||||
public static void Update()
|
||||
{
|
||||
// Check Force-Unlock input
|
||||
@ -128,6 +133,45 @@ namespace Explorer.UI
|
||||
}
|
||||
}
|
||||
|
||||
// Event system
|
||||
|
||||
private static bool m_settingEventSystem;
|
||||
private static EventSystem m_lastEventSystem;
|
||||
private static BaseInputModule m_lastInputModule;
|
||||
|
||||
public static void SetEventSystem()
|
||||
{
|
||||
m_settingEventSystem = true;
|
||||
UIManager.SetEventSystem();
|
||||
m_settingEventSystem = false;
|
||||
}
|
||||
|
||||
public static void ReleaseEventSystem()
|
||||
{
|
||||
if (m_lastEventSystem)
|
||||
{
|
||||
m_settingEventSystem = true;
|
||||
EventSystem.current = m_lastEventSystem;
|
||||
m_lastInputModule?.ActivateModule();
|
||||
m_settingEventSystem = false;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
public static void Prefix_EventSystem_set_current(ref EventSystem value)
|
||||
{
|
||||
if (!m_settingEventSystem)
|
||||
{
|
||||
m_lastEventSystem = value;
|
||||
m_lastInputModule = value?.currentInputModule;
|
||||
|
||||
if (ExplorerCore.ShowMenu)
|
||||
{
|
||||
value = UIManager.EventSys;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Force mouse to stay unlocked and visible while UnlockMouse and ShowMenu are true.
|
||||
// Also keep track of when anything else tries to set Cursor state, this will be the
|
||||
// value that we set back to when we close the menu or disable force-unlock.
|
||||
@ -160,22 +204,22 @@ namespace Explorer.UI
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
public static void Postfix_get_lockState(ref CursorLockMode __result)
|
||||
{
|
||||
if (ShouldForceMouse)
|
||||
{
|
||||
__result = m_lastLockMode;
|
||||
}
|
||||
}
|
||||
//[HarmonyPrefix]
|
||||
//public static void Postfix_get_lockState(ref CursorLockMode __result)
|
||||
//{
|
||||
// if (ShouldForceMouse)
|
||||
// {
|
||||
// __result = m_lastLockMode;
|
||||
// }
|
||||
//}
|
||||
|
||||
[HarmonyPrefix]
|
||||
public static void Postfix_get_visible(ref bool __result)
|
||||
{
|
||||
if (ShouldForceMouse)
|
||||
{
|
||||
__result = m_lastVisibleState;
|
||||
}
|
||||
}
|
||||
//[HarmonyPrefix]
|
||||
//public static void Postfix_get_visible(ref bool __result)
|
||||
//{
|
||||
// if (ShouldForceMouse)
|
||||
// {
|
||||
// __result = m_lastVisibleState;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
@ -1,751 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.UI.Main;
|
||||
using Explorer.Unstrip.LayerMasks;
|
||||
using Explorer.Helpers;
|
||||
#if CPP
|
||||
using UnhollowerRuntimeLib;
|
||||
#endif
|
||||
|
||||
namespace Explorer.UI.Inspectors
|
||||
{
|
||||
public class GameObjectInspector : WindowBase
|
||||
{
|
||||
public override string Title => WindowManager.TabView
|
||||
? $"<color=cyan>[G]</color> {TargetGO.name}"
|
||||
: $"GameObject Inspector ({TargetGO.name})";
|
||||
|
||||
public GameObject TargetGO;
|
||||
|
||||
public bool pendingDestroy;
|
||||
|
||||
private static bool m_hideControls;
|
||||
|
||||
// gui element holders
|
||||
private string m_name;
|
||||
private string m_scene;
|
||||
|
||||
private Transform[] m_children;
|
||||
private Vector2 m_transformScroll = Vector2.zero;
|
||||
private readonly PageHelper ChildPages = new PageHelper();
|
||||
|
||||
private Component[] m_components;
|
||||
private Vector2 m_compScroll = Vector2.zero;
|
||||
private readonly PageHelper CompPages = new PageHelper();
|
||||
|
||||
private readonly Vector3[] m_cachedInput = new Vector3[3];
|
||||
private float m_translateAmount = 0.3f;
|
||||
private float m_rotateAmount = 50f;
|
||||
private float m_scaleAmount = 0.1f;
|
||||
private bool m_freeze;
|
||||
private Vector3 m_frozenPosition;
|
||||
private Quaternion m_frozenRotation;
|
||||
private Vector3 m_frozenScale;
|
||||
private bool m_autoApplyTransform;
|
||||
private bool m_autoUpdateTransform;
|
||||
private bool m_localContext;
|
||||
|
||||
private int m_layer;
|
||||
|
||||
private readonly List<Component> m_cachedDestroyList = new List<Component>();
|
||||
private string m_addComponentInput = "";
|
||||
|
||||
private string m_setParentInput = "Enter a GameObject name or path";
|
||||
|
||||
public bool GetObjectAsGameObject()
|
||||
{
|
||||
var targetType = Target?.GetType();
|
||||
|
||||
if (targetType == typeof(GameObject))
|
||||
{
|
||||
TargetGO = Target as GameObject;
|
||||
return true;
|
||||
}
|
||||
else if (targetType == typeof(Transform))
|
||||
{
|
||||
TargetGO = (Target as Transform).gameObject;
|
||||
return true;
|
||||
}
|
||||
|
||||
ExplorerCore.Log("Error: Target is null or not a GameObject/Transform!");
|
||||
DestroyWindow();
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
if (!GetObjectAsGameObject())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_name = TargetGO.name;
|
||||
m_scene = string.IsNullOrEmpty(TargetGO.scene.name)
|
||||
? "None (Asset/Resource)"
|
||||
: TargetGO.scene.name;
|
||||
|
||||
CacheTransformValues();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
private void CacheTransformValues()
|
||||
{
|
||||
if (m_localContext)
|
||||
{
|
||||
m_cachedInput[0] = TargetGO.transform.localPosition;
|
||||
m_cachedInput[1] = TargetGO.transform.localEulerAngles;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cachedInput[0] = TargetGO.transform.position;
|
||||
m_cachedInput[1] = TargetGO.transform.eulerAngles;
|
||||
}
|
||||
m_cachedInput[2] = TargetGO.transform.localScale;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pendingDestroy) return;
|
||||
|
||||
if (Target == null)
|
||||
{
|
||||
DestroyOnException(new Exception("Target was destroyed."));
|
||||
return;
|
||||
}
|
||||
if (!TargetGO && !GetObjectAsGameObject())
|
||||
{
|
||||
DestroyOnException(new Exception("Target was destroyed."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_freeze)
|
||||
{
|
||||
if (m_localContext)
|
||||
{
|
||||
TargetGO.transform.localPosition = m_frozenPosition;
|
||||
TargetGO.transform.localRotation = m_frozenRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetGO.transform.position = m_frozenPosition;
|
||||
TargetGO.transform.rotation = m_frozenRotation;
|
||||
}
|
||||
TargetGO.transform.localScale = m_frozenScale;
|
||||
}
|
||||
|
||||
m_layer = TargetGO.layer;
|
||||
|
||||
// update child objects
|
||||
var childList = new List<Transform>();
|
||||
for (int i = 0; i < TargetGO.transform.childCount; i++)
|
||||
{
|
||||
childList.Add(TargetGO.transform.GetChild(i));
|
||||
}
|
||||
childList.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
||||
m_children = childList.ToArray();
|
||||
|
||||
ChildPages.ItemCount = m_children.Length;
|
||||
|
||||
// update components
|
||||
#if CPP
|
||||
var compList = new Il2CppSystem.Collections.Generic.List<Component>();
|
||||
TargetGO.GetComponentsInternal(ReflectionHelpers.ComponentType, true, false, true, false, compList);
|
||||
m_components = compList.ToArray();
|
||||
#else
|
||||
m_components = TargetGO.GetComponents<Component>();
|
||||
#endif
|
||||
|
||||
CompPages.ItemCount = m_components.Length;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DestroyOnException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void DestroyOnException(Exception e)
|
||||
{
|
||||
if (pendingDestroy) return;
|
||||
|
||||
ExplorerCore.Log($"Exception drawing GameObject Window: {e.GetType()}, {e.Message}");
|
||||
pendingDestroy = true;
|
||||
DestroyWindow();
|
||||
}
|
||||
|
||||
private void InspectGameObject(Transform obj)
|
||||
{
|
||||
var window = WindowManager.InspectObject(obj, out bool created);
|
||||
|
||||
if (created)
|
||||
{
|
||||
window.m_rect = new Rect(this.m_rect.x, this.m_rect.y, this.m_rect.width, this.m_rect.height);
|
||||
DestroyWindow();
|
||||
}
|
||||
}
|
||||
|
||||
#if CPP
|
||||
private void ReflectObject(Il2CppSystem.Object obj)
|
||||
#else
|
||||
private void ReflectObject(object obj)
|
||||
#endif
|
||||
{
|
||||
var window = WindowManager.InspectObject(obj, out bool created, true);
|
||||
|
||||
if (created)
|
||||
{
|
||||
if (this.m_rect.x <= (Screen.width - this.m_rect.width - 100))
|
||||
{
|
||||
window.m_rect = new Rect(
|
||||
this.m_rect.x + this.m_rect.width + 20,
|
||||
this.m_rect.y,
|
||||
550,
|
||||
700);
|
||||
}
|
||||
else
|
||||
{
|
||||
window.m_rect = new Rect(this.m_rect.x + 50, this.m_rect.y + 50, 550, 700);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void WindowFunction(int windowID)
|
||||
{
|
||||
if (pendingDestroy) return;
|
||||
|
||||
try
|
||||
{
|
||||
var rect = WindowManager.TabView ? TabViewWindow.Instance.m_rect : this.m_rect;
|
||||
|
||||
if (!WindowManager.TabView)
|
||||
{
|
||||
Header();
|
||||
GUIHelper.BeginArea(new Rect(5, 25, rect.width - 10, rect.height - 35), GUI.skin.box);
|
||||
}
|
||||
|
||||
scroll = GUIHelper.BeginScrollView(scroll);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label("Scene: <color=cyan>" + (m_scene == "" ? "n/a" : m_scene) + "</color>", new GUILayoutOption[0]);
|
||||
if (m_scene == UnityHelpers.ActiveSceneName)
|
||||
{
|
||||
if (GUILayout.Button("<color=#00FF00>Send to Scene View</color>", new GUILayoutOption[] { GUILayout.Width(150) }))
|
||||
{
|
||||
ScenePage.Instance.SetTransformTarget(TargetGO.transform);
|
||||
MainMenu.SetCurrentPage(0);
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button("Reflection Inspect", new GUILayoutOption[] { GUILayout.Width(150) }))
|
||||
{
|
||||
WindowManager.InspectObject(Target, out _, true);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label("Path:", new GUILayoutOption[] { GUILayout.Width(50) });
|
||||
string pathlabel = TargetGO.transform.GetGameObjectPath();
|
||||
if (TargetGO.transform.parent != null)
|
||||
{
|
||||
if (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) }))
|
||||
{
|
||||
InspectGameObject(TargetGO.transform.parent);
|
||||
}
|
||||
}
|
||||
GUIHelper.TextArea(pathlabel, new GUILayoutOption[0]);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label("Name:", new GUILayoutOption[] { GUILayout.Width(50) });
|
||||
GUIHelper.TextArea(m_name, new GUILayoutOption[0]);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
LayerControls();
|
||||
|
||||
// --- Horizontal Columns section ---
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
GUIHelper.BeginVertical(new GUILayoutOption[] { GUILayout.Width(rect.width / 2 - 17) });
|
||||
TransformList(rect);
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUIHelper.BeginVertical(new GUILayoutOption[] { GUILayout.Width(rect.width / 2 - 17) });
|
||||
ComponentList(rect);
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUILayout.EndHorizontal(); // end horiz columns
|
||||
|
||||
GameObjectControls();
|
||||
|
||||
GUIHelper.EndScrollView();
|
||||
|
||||
if (!WindowManager.TabView)
|
||||
{
|
||||
m_rect = ResizeDrag.ResizeWindow(rect, windowID);
|
||||
|
||||
GUIHelper.EndArea();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DestroyOnException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void LayerControls()
|
||||
{
|
||||
GUIHelper.BeginHorizontal();
|
||||
GUILayout.Label("Layer:", new GUILayoutOption[] { GUILayout.Width(50) });
|
||||
|
||||
if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(30) }))
|
||||
{
|
||||
if (m_layer > 0)
|
||||
{
|
||||
m_layer--;
|
||||
if (TargetGO) TargetGO.layer = m_layer;
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button(">", new GUILayoutOption[] { GUILayout.Width(30) }))
|
||||
{
|
||||
if (m_layer < 32)
|
||||
{
|
||||
m_layer++;
|
||||
if (TargetGO) TargetGO.layer = m_layer;
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Label($"{m_layer} (<color=cyan>{LayerMaskUnstrip.LayerToName(m_layer)}</color>)",
|
||||
new GUILayoutOption[] { GUILayout.Width(200) });
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private void TransformList(Rect m_rect)
|
||||
{
|
||||
GUIHelper.BeginVertical(GUIContent.none, GUI.skin.box, null);
|
||||
m_transformScroll = GUIHelper.BeginScrollView(m_transformScroll);
|
||||
|
||||
GUILayout.Label("<b><size=15>Children</size></b>", new GUILayoutOption[0]);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
ChildPages.DrawLimitInputArea();
|
||||
|
||||
if (ChildPages.ItemCount > ChildPages.ItemsPerPage)
|
||||
{
|
||||
ChildPages.CurrentPageLabel();
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
ChildPages.TurnPage(Turn.Left, ref this.m_transformScroll);
|
||||
}
|
||||
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
ChildPages.TurnPage(Turn.Right, ref this.m_transformScroll);
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (m_children != null && m_children.Length > 0)
|
||||
{
|
||||
int start = ChildPages.CalculateOffsetIndex();
|
||||
|
||||
for (int j = start; (j < start + ChildPages.ItemsPerPage && j < ChildPages.ItemCount); j++)
|
||||
{
|
||||
var obj = m_children[j];
|
||||
|
||||
if (!obj)
|
||||
{
|
||||
GUILayout.Label("null", new GUILayoutOption[0]);
|
||||
continue;
|
||||
}
|
||||
|
||||
Buttons.GameObjectButton(obj.gameObject, InspectGameObject, false, m_rect.width / 2 - 80);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("<i>None</i>", new GUILayoutOption[0]);
|
||||
}
|
||||
|
||||
GUIHelper.EndScrollView();
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void ComponentList(Rect m_rect)
|
||||
{
|
||||
GUIHelper.BeginVertical(GUIContent.none, GUI.skin.box, null);
|
||||
m_compScroll = GUIHelper.BeginScrollView(m_compScroll);
|
||||
GUILayout.Label("<b><size=15>Components</size></b>", new GUILayoutOption[0]);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
CompPages.DrawLimitInputArea();
|
||||
|
||||
if (CompPages.ItemCount > CompPages.ItemsPerPage)
|
||||
{
|
||||
CompPages.CurrentPageLabel();
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
CompPages.TurnPage(Turn.Left, ref this.m_compScroll);
|
||||
}
|
||||
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
CompPages.TurnPage(Turn.Right, ref this.m_compScroll);
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
var width = m_rect.width / 2 - 135f;
|
||||
m_addComponentInput = GUIHelper.TextField(m_addComponentInput, new GUILayoutOption[] { GUILayout.Width(width) });
|
||||
if (GUILayout.Button("Add Comp", new GUILayoutOption[0]))
|
||||
{
|
||||
if (ReflectionHelpers.GetTypeByName(m_addComponentInput) is Type compType)
|
||||
{
|
||||
if (typeof(Component).IsAssignableFrom(compType))
|
||||
{
|
||||
#if CPP
|
||||
TargetGO.AddComponent(Il2CppType.From(compType));
|
||||
#else
|
||||
TargetGO.AddComponent(compType);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
ExplorerCore.LogWarning($"Type '{compType.Name}' is not assignable from Component!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ExplorerCore.LogWarning($"Could not find a type by the name of '{m_addComponentInput}'!");
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
if (m_cachedDestroyList.Count > 0)
|
||||
{
|
||||
m_cachedDestroyList.Clear();
|
||||
}
|
||||
|
||||
if (m_components != null)
|
||||
{
|
||||
int start = CompPages.CalculateOffsetIndex();
|
||||
|
||||
for (int j = start; (j < start + CompPages.ItemsPerPage && j < CompPages.ItemCount); j++)
|
||||
{
|
||||
var component = m_components[j];
|
||||
|
||||
if (!component) continue;
|
||||
|
||||
var type =
|
||||
#if CPP
|
||||
component.GetIl2CppType();
|
||||
#else
|
||||
component.GetType();
|
||||
#endif
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
if (ReflectionHelpers.BehaviourType.IsAssignableFrom(type))
|
||||
{
|
||||
#if CPP
|
||||
BehaviourEnabledBtn(component.TryCast<Behaviour>());
|
||||
#else
|
||||
BehaviourEnabledBtn(component as Behaviour);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
GUIHelper.Space(26);
|
||||
}
|
||||
if (GUILayout.Button("<color=cyan>" + type.Name + "</color>", new GUILayoutOption[] { GUILayout.Width(m_rect.width / 2 - 100) }))
|
||||
{
|
||||
ReflectObject(component);
|
||||
}
|
||||
if (GUILayout.Button("<color=red>-</color>", new GUILayoutOption[] { GUILayout.Width(20) }))
|
||||
{
|
||||
m_cachedDestroyList.Add(component);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
if (m_cachedDestroyList.Count > 0)
|
||||
{
|
||||
for (int i = m_cachedDestroyList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var comp = m_cachedDestroyList[i];
|
||||
GameObject.Destroy(comp);
|
||||
}
|
||||
}
|
||||
|
||||
GUIHelper.EndScrollView();
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void BehaviourEnabledBtn(Behaviour obj)
|
||||
{
|
||||
var _col = GUI.color;
|
||||
bool _enabled = obj.enabled;
|
||||
if (_enabled)
|
||||
{
|
||||
GUI.color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = Color.red;
|
||||
}
|
||||
|
||||
// ------ toggle active button ------
|
||||
|
||||
_enabled = GUILayout.Toggle(_enabled, "", new GUILayoutOption[] { GUILayout.Width(18) });
|
||||
if (obj.enabled != _enabled)
|
||||
{
|
||||
obj.enabled = _enabled;
|
||||
}
|
||||
GUI.color = _col;
|
||||
}
|
||||
|
||||
private void GameObjectControls()
|
||||
{
|
||||
if (m_hideControls)
|
||||
{
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label("<b><size=15>GameObject Controls</size></b>", new GUILayoutOption[] { GUILayout.Width(200) });
|
||||
if (GUILayout.Button("^ Show ^", new GUILayoutOption[] { GUILayout.Width(75) }))
|
||||
{
|
||||
m_hideControls = false;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
GUIHelper.BeginVertical(GUIContent.none, GUI.skin.box, new GUILayoutOption[] { GUILayout.Width(520) });
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label("<b><size=15>GameObject Controls</size></b>", new GUILayoutOption[] { GUILayout.Width(200) });
|
||||
if (GUILayout.Button("v Hide v", new GUILayoutOption[] { GUILayout.Width(75) }))
|
||||
{
|
||||
m_hideControls = true;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
bool m_active = TargetGO.activeSelf;
|
||||
m_active = GUILayout.Toggle(m_active, (m_active ? "<color=lime>Enabled " : "<color=red>Disabled") + "</color>",
|
||||
new GUILayoutOption[] { GUILayout.Width(80) });
|
||||
if (TargetGO.activeSelf != m_active) { TargetGO.SetActive(m_active); }
|
||||
|
||||
Buttons.InstantiateButton(TargetGO, 100);
|
||||
|
||||
if (GUILayout.Button("Set DontDestroyOnLoad", new GUILayoutOption[] { GUILayout.Width(170) }))
|
||||
{
|
||||
GameObject.DontDestroyOnLoad(TargetGO);
|
||||
TargetGO.hideFlags |= HideFlags.DontUnloadUnusedAsset;
|
||||
}
|
||||
|
||||
var lbl = m_freeze ? "<color=lime>Unfreeze</color>" : "<color=orange>Freeze Pos/Rot</color>";
|
||||
if (GUILayout.Button(lbl, new GUILayoutOption[] { GUILayout.Width(110) }))
|
||||
{
|
||||
m_freeze = !m_freeze;
|
||||
if (m_freeze)
|
||||
{
|
||||
UpdateFreeze();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
m_setParentInput = GUIHelper.TextField(m_setParentInput, new GUILayoutOption[0]);
|
||||
if (GUILayout.Button("Set Parent", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
if (GameObject.Find(m_setParentInput) is GameObject newparent)
|
||||
{
|
||||
TargetGO.transform.parent = newparent.transform;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExplorerCore.LogWarning($"Could not find gameobject '{m_setParentInput}'");
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Detach from parent", new GUILayoutOption[] { GUILayout.Width(160) }))
|
||||
{
|
||||
TargetGO.transform.parent = null;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginVertical(GUIContent.none, GUI.skin.box, null);
|
||||
|
||||
m_cachedInput[0] = TranslateControl(TranslateType.Position, ref m_translateAmount, false);
|
||||
m_cachedInput[1] = TranslateControl(TranslateType.Rotation, ref m_rotateAmount, true);
|
||||
m_cachedInput[2] = TranslateControl(TranslateType.Scale, ref m_scaleAmount, false);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
if (GUILayout.Button("<color=lime>Apply to Transform</color>", new GUILayoutOption[0]) || m_autoApplyTransform)
|
||||
{
|
||||
if (m_localContext)
|
||||
{
|
||||
TargetGO.transform.localPosition = m_cachedInput[0];
|
||||
TargetGO.transform.localEulerAngles = m_cachedInput[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetGO.transform.position = m_cachedInput[0];
|
||||
TargetGO.transform.eulerAngles = m_cachedInput[1];
|
||||
}
|
||||
TargetGO.transform.localScale = m_cachedInput[2];
|
||||
|
||||
if (m_freeze)
|
||||
{
|
||||
UpdateFreeze();
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button("<color=lime>Update from Transform</color>", new GUILayoutOption[0]) || m_autoUpdateTransform)
|
||||
{
|
||||
CacheTransformValues();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
BoolToggle(ref m_autoApplyTransform, "Auto-apply to Transform?");
|
||||
BoolToggle(ref m_autoUpdateTransform, "Auto-update from transform?");
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
bool b = m_localContext;
|
||||
b = GUILayout.Toggle(b, "<color=" + (b ? "lime" : "orange") + ">Use local transform values?</color>", new GUILayoutOption[0]);
|
||||
if (b != m_localContext)
|
||||
{
|
||||
m_localContext = b;
|
||||
CacheTransformValues();
|
||||
if (m_freeze)
|
||||
{
|
||||
UpdateFreeze();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
|
||||
if (GUILayout.Button("<color=red><b>Destroy</b></color>", new GUILayoutOption[] { GUILayout.Width(120) }))
|
||||
{
|
||||
GameObject.Destroy(TargetGO);
|
||||
DestroyWindow();
|
||||
return;
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void UpdateFreeze()
|
||||
{
|
||||
if (m_localContext)
|
||||
{
|
||||
m_frozenPosition = TargetGO.transform.localPosition;
|
||||
m_frozenRotation = TargetGO.transform.localRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_frozenPosition = TargetGO.transform.position;
|
||||
m_frozenRotation = TargetGO.transform.rotation;
|
||||
}
|
||||
m_frozenScale = TargetGO.transform.localScale;
|
||||
}
|
||||
|
||||
private void BoolToggle(ref bool value, string message)
|
||||
{
|
||||
string lbl = "<color=";
|
||||
lbl += value ? "lime" : "orange";
|
||||
lbl += $">{message}</color>";
|
||||
|
||||
value = GUILayout.Toggle(value, lbl, new GUILayoutOption[0]);
|
||||
}
|
||||
|
||||
public enum TranslateType
|
||||
{
|
||||
Position,
|
||||
Rotation,
|
||||
Scale
|
||||
}
|
||||
|
||||
private Vector3 TranslateControl(TranslateType mode, ref float amount, bool multByTime)
|
||||
{
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label($"<color=cyan><b>{(m_localContext ? "Local " : "")}{mode}</b></color>:",
|
||||
new GUILayoutOption[] { GUILayout.Width(m_localContext ? 110 : 65) });
|
||||
|
||||
var transform = TargetGO.transform;
|
||||
switch (mode)
|
||||
{
|
||||
case TranslateType.Position:
|
||||
var pos = m_localContext ? transform.localPosition : transform.position;
|
||||
GUILayout.Label(pos.ToString(), new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
break;
|
||||
case TranslateType.Rotation:
|
||||
var rot = m_localContext ? transform.localEulerAngles : transform.eulerAngles;
|
||||
GUILayout.Label(rot.ToString(), new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
break;
|
||||
case TranslateType.Scale:
|
||||
GUILayout.Label(transform.localScale.ToString(), new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
break;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
Vector3 input = m_cachedInput[(int)mode];
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||
|
||||
GUILayout.Label("<color=cyan>X:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
||||
PlusMinusFloat(ref input.x, amount, multByTime);
|
||||
|
||||
GUILayout.Label("<color=cyan>Y:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
||||
PlusMinusFloat(ref input.y, amount, multByTime);
|
||||
|
||||
GUILayout.Label("<color=cyan>Z:</color>", new GUILayoutOption[] { GUILayout.Width(20) });
|
||||
PlusMinusFloat(ref input.z, amount, multByTime);
|
||||
|
||||
GUILayout.Label("+/-:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
var amountInput = amount.ToString("F3");
|
||||
amountInput = GUIHelper.TextField(amountInput, new GUILayoutOption[] { GUILayout.Width(60) });
|
||||
if (float.TryParse(amountInput, out float f))
|
||||
{
|
||||
amount = f;
|
||||
}
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
private void PlusMinusFloat(ref float f, float amount, bool multByTime)
|
||||
{
|
||||
string s = f.ToString("F3");
|
||||
s = GUIHelper.TextField(s, new GUILayoutOption[] { GUILayout.Width(60) });
|
||||
if (float.TryParse(s, out float f2))
|
||||
{
|
||||
f = f2;
|
||||
}
|
||||
if (GUIHelper.RepeatButton("-", new GUILayoutOption[] { GUILayout.Width(20) }))
|
||||
{
|
||||
f -= multByTime ? amount * Time.deltaTime : amount;
|
||||
}
|
||||
if (GUIHelper.RepeatButton("+", new GUILayoutOption[] { GUILayout.Width(20) }))
|
||||
{
|
||||
f += multByTime ? amount * Time.deltaTime : amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
using UnityEngine;
|
||||
using Explorer.Helpers;
|
||||
|
||||
namespace Explorer.UI.Inspectors
|
||||
{
|
||||
public class InspectUnderMouse
|
||||
{
|
||||
public static bool EnableInspect { get; set; } = false;
|
||||
|
||||
private static string m_objUnderMouseName = "";
|
||||
|
||||
public static void Update()
|
||||
{
|
||||
if (ExplorerCore.ShowMenu)
|
||||
{
|
||||
if (InputManager.GetKey(KeyCode.LeftShift) && InputManager.GetMouseButtonDown(1))
|
||||
{
|
||||
EnableInspect = !EnableInspect;
|
||||
}
|
||||
|
||||
if (EnableInspect)
|
||||
{
|
||||
InspectRaycast();
|
||||
}
|
||||
}
|
||||
else if (EnableInspect)
|
||||
{
|
||||
EnableInspect = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void InspectRaycast()
|
||||
{
|
||||
if (!UnityHelpers.MainCamera)
|
||||
return;
|
||||
|
||||
var ray = UnityHelpers.MainCamera.ScreenPointToRay(InputManager.MousePosition);
|
||||
|
||||
if (Physics.Raycast(ray, out RaycastHit hit, 1000f))
|
||||
{
|
||||
var obj = hit.transform.gameObject;
|
||||
|
||||
m_objUnderMouseName = obj.transform.GetGameObjectPath();
|
||||
|
||||
if (InputManager.GetMouseButtonDown(0))
|
||||
{
|
||||
EnableInspect = false;
|
||||
m_objUnderMouseName = "";
|
||||
|
||||
WindowManager.InspectObject(obj, out _);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_objUnderMouseName = "";
|
||||
}
|
||||
}
|
||||
|
||||
public static void OnGUI()
|
||||
{
|
||||
if (EnableInspect)
|
||||
{
|
||||
if (m_objUnderMouseName != "")
|
||||
{
|
||||
var pos = InputManager.MousePosition;
|
||||
var rect = new Rect(
|
||||
pos.x - (Screen.width / 2), // x
|
||||
Screen.height - pos.y - 50, // y
|
||||
Screen.width, // w
|
||||
50 // h
|
||||
);
|
||||
|
||||
var origAlign = GUI.skin.label.alignment;
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
//shadow text
|
||||
GUI.Label(rect, $"<color=black>{m_objUnderMouseName}</color>");
|
||||
//white text
|
||||
GUI.Label(new Rect(rect.x - 1, rect.y + 1, rect.width, rect.height), m_objUnderMouseName);
|
||||
|
||||
GUI.skin.label.alignment = origAlign;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Explorer.UI;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
#if CPP
|
||||
using UnhollowerBaseLib;
|
||||
#endif
|
||||
|
||||
namespace Explorer.UI.Inspectors
|
||||
{
|
||||
public class InstanceInspector : ReflectionInspector
|
||||
{
|
||||
public override bool IsStaticInspector => false;
|
||||
|
||||
// some extra cast-caching
|
||||
public UnityEngine.Object m_uObj;
|
||||
private Component m_component;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
// cache the extra cast-caching
|
||||
#if CPP
|
||||
if (!IsStaticInspector && Target is Il2CppSystem.Object ilObject)
|
||||
{
|
||||
var unityObj = ilObject.TryCast<UnityEngine.Object>();
|
||||
if (unityObj)
|
||||
{
|
||||
m_uObj = unityObj;
|
||||
|
||||
var component = ilObject.TryCast<Component>();
|
||||
if (component)
|
||||
{
|
||||
m_component = component;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!IsStaticInspector)
|
||||
{
|
||||
m_uObj = Target as UnityEngine.Object;
|
||||
m_component = Target as Component;
|
||||
}
|
||||
#endif
|
||||
|
||||
base.Init();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (Target == null)
|
||||
{
|
||||
ExplorerCore.Log("Target is null!");
|
||||
DestroyWindow();
|
||||
return;
|
||||
}
|
||||
if (Target is UnityEngine.Object uObj)
|
||||
{
|
||||
if (!uObj)
|
||||
{
|
||||
ExplorerCore.Log("Target was destroyed!");
|
||||
DestroyWindow();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
base.Update();
|
||||
}
|
||||
|
||||
public void DrawInstanceControls(Rect rect)
|
||||
{
|
||||
//if (m_uObj)
|
||||
//{
|
||||
// GUILayout.Label("Name: " + m_uObj.name, new GUILayoutOption[0]);
|
||||
//}
|
||||
//GUILayout.EndHorizontal();
|
||||
|
||||
if (m_uObj)
|
||||
{
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label("<b>Tools:</b>", new GUILayoutOption[] { GUILayout.Width(80) });
|
||||
Buttons.InstantiateButton(m_uObj);
|
||||
if (m_component && m_component.gameObject is GameObject obj)
|
||||
{
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||
GUILayout.Label("GameObject:", new GUILayoutOption[] { GUILayout.Width(135) });
|
||||
var charWidth = obj.name.Length * 15;
|
||||
var maxWidth = rect.width - 350;
|
||||
var btnWidth = charWidth < maxWidth ? charWidth : maxWidth;
|
||||
if (GUILayout.Button("<color=#00FF00>" + obj.name + "</color>", new GUILayoutOption[] { GUILayout.Width(btnWidth) }))
|
||||
{
|
||||
WindowManager.InspectObject(obj, out bool _);
|
||||
}
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("Name: " + m_uObj.name, new GUILayoutOption[0]);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Explorer.CacheObject;
|
||||
|
||||
namespace Explorer.UI.Inspectors
|
||||
{
|
||||
public class StaticInspector : ReflectionInspector
|
||||
{
|
||||
public override bool IsStaticInspector => true;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
}
|
||||
|
||||
public override bool ShouldProcessMember(CacheMember holder)
|
||||
{
|
||||
return base.ShouldProcessMember(holder);
|
||||
}
|
||||
|
||||
public override void WindowFunction(int windowID)
|
||||
{
|
||||
base.WindowFunction(windowID);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,431 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Explorer.UI;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
using Explorer.UI.Inspectors;
|
||||
using Explorer.Helpers;
|
||||
#if CPP
|
||||
using UnhollowerBaseLib;
|
||||
#endif
|
||||
|
||||
namespace Explorer.UI.Inspectors
|
||||
{
|
||||
public abstract class ReflectionInspector : WindowBase
|
||||
{
|
||||
public override string Title => WindowManager.TabView
|
||||
? $"<color=cyan>[R]</color> {TargetType.Name}"
|
||||
: $"Reflection Inspector ({TargetType.Name})";
|
||||
|
||||
public virtual bool IsStaticInspector { get; }
|
||||
|
||||
public Type TargetType;
|
||||
|
||||
private CacheMember[] m_allCachedMembers;
|
||||
private CacheMember[] m_cachedMembersFiltered;
|
||||
|
||||
public PageHelper Pages = new PageHelper();
|
||||
|
||||
private bool m_autoUpdate = false;
|
||||
private string m_search = "";
|
||||
public MemberTypes m_typeFilter = MemberTypes.Property;
|
||||
private bool m_hideFailedReflection = false;
|
||||
|
||||
private MemberScopes m_scopeFilter;
|
||||
private enum MemberScopes
|
||||
{
|
||||
Both,
|
||||
Instance,
|
||||
Static
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> _typeAndMemberBlacklist = new HashSet<string>
|
||||
{
|
||||
// Causes a crash
|
||||
"Type.DeclaringMethod",
|
||||
// Causes a crash
|
||||
"Rigidbody2D.Cast",
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> _methodStartsWithBlacklist = new HashSet<string>
|
||||
{
|
||||
// Pointless (handled by Properties)
|
||||
"get_",
|
||||
"set_",
|
||||
};
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
if (!IsStaticInspector)
|
||||
{
|
||||
TargetType = ReflectionHelpers.GetActualType(Target);
|
||||
CacheMembers(ReflectionHelpers.GetAllBaseTypes(Target));
|
||||
}
|
||||
else
|
||||
{
|
||||
CacheMembers(new Type[] { TargetType });
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (m_allCachedMembers == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_cachedMembersFiltered = m_allCachedMembers.Where(x => ShouldProcessMember(x)).ToArray();
|
||||
|
||||
if (m_autoUpdate)
|
||||
{
|
||||
UpdateValues();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateValues()
|
||||
{
|
||||
foreach (var member in m_cachedMembersFiltered)
|
||||
{
|
||||
member.UpdateValue();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool ShouldProcessMember(CacheMember holder)
|
||||
{
|
||||
// check MemberTypes filter
|
||||
if (m_typeFilter != MemberTypes.All && m_typeFilter != holder.MemInfo?.MemberType)
|
||||
return false;
|
||||
|
||||
// check scope filter
|
||||
if (m_scopeFilter == MemberScopes.Instance)
|
||||
{
|
||||
return !holder.IsStatic;
|
||||
}
|
||||
else if (m_scopeFilter == MemberScopes.Static)
|
||||
{
|
||||
return holder.IsStatic;
|
||||
}
|
||||
|
||||
// hide failed reflection
|
||||
if (!string.IsNullOrEmpty(holder.ReflectionException) && m_hideFailedReflection)
|
||||
return false;
|
||||
|
||||
// see if we should do name search
|
||||
if (m_search == "" || holder.MemInfo == null)
|
||||
return true;
|
||||
|
||||
// ok do name search
|
||||
return (holder.MemInfo.DeclaringType.Name + "." + holder.MemInfo.Name)
|
||||
.ToLower()
|
||||
.Contains(m_search.ToLower());
|
||||
}
|
||||
|
||||
private void CacheMembers(Type[] types)
|
||||
{
|
||||
var list = new List<CacheMember>();
|
||||
var cachedSigs = new HashSet<string>();
|
||||
|
||||
foreach (var declaringType in types)
|
||||
{
|
||||
MemberInfo[] infos;
|
||||
try
|
||||
{
|
||||
infos = declaringType.GetMembers(ReflectionHelpers.CommonFlags);
|
||||
}
|
||||
catch
|
||||
{
|
||||
ExplorerCore.Log($"Exception getting members for type: {declaringType.FullName}");
|
||||
continue;
|
||||
}
|
||||
|
||||
object target = Target;
|
||||
string exception = null;
|
||||
|
||||
#if CPP
|
||||
if (!IsStaticInspector && target is Il2CppSystem.Object ilObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
target = ilObject.Il2CppCast(declaringType);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
exception = ReflectionHelpers.ExceptionToString(e);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
foreach (var member in infos)
|
||||
{
|
||||
try
|
||||
{
|
||||
// make sure member type is Field, Method or Property (4 / 8 / 16)
|
||||
int m = (int)member.MemberType;
|
||||
if (m < 4 || m > 16)
|
||||
continue;
|
||||
|
||||
var fi = member as FieldInfo;
|
||||
var pi = member as PropertyInfo;
|
||||
var mi = member as MethodInfo;
|
||||
|
||||
if (IsStaticInspector)
|
||||
{
|
||||
if (fi != null && !fi.IsStatic) continue;
|
||||
else if (pi != null && !pi.GetAccessors()[0].IsStatic) continue;
|
||||
else if (mi != null && !mi.IsStatic) continue;
|
||||
}
|
||||
|
||||
// check blacklisted members
|
||||
var sig = $"{member.DeclaringType.Name}.{member.Name}";
|
||||
if (_typeAndMemberBlacklist.Any(it => it == sig))
|
||||
continue;
|
||||
|
||||
if (_methodStartsWithBlacklist.Any(it => member.Name.StartsWith(it)))
|
||||
continue;
|
||||
|
||||
if (mi != null)
|
||||
{
|
||||
AppendParams(mi.GetParameters());
|
||||
}
|
||||
else if (pi != null)
|
||||
{
|
||||
AppendParams(pi.GetIndexParameters());
|
||||
}
|
||||
|
||||
void AppendParams(ParameterInfo[] _args)
|
||||
{
|
||||
sig += " (";
|
||||
foreach (var param in _args)
|
||||
{
|
||||
sig += $"{param.ParameterType.Name} {param.Name}, ";
|
||||
}
|
||||
sig += ")";
|
||||
}
|
||||
|
||||
if (cachedSigs.Contains(sig))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var cached = CacheFactory.GetCacheObject(member, target);
|
||||
|
||||
if (cached != null)
|
||||
{
|
||||
cachedSigs.Add(sig);
|
||||
list.Add(cached);
|
||||
|
||||
if (string.IsNullOrEmpty(cached.ReflectionException))
|
||||
{
|
||||
cached.ReflectionException = exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Exception caching member {sig}!");
|
||||
ExplorerCore.Log(e.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Exception caching member {member.DeclaringType.FullName}.{member.Name}!");
|
||||
ExplorerCore.Log(e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_allCachedMembers = list.ToArray();
|
||||
}
|
||||
|
||||
// =========== GUI DRAW =========== //
|
||||
|
||||
public override void WindowFunction(int windowID)
|
||||
{
|
||||
try
|
||||
{
|
||||
// ====== HEADER ======
|
||||
|
||||
var rect = WindowManager.TabView ? TabViewWindow.Instance.m_rect : this.m_rect;
|
||||
|
||||
if (!WindowManager.TabView)
|
||||
{
|
||||
Header();
|
||||
GUIHelper.BeginArea(new Rect(5, 25, rect.width - 10, rect.height - 35), GUI.skin.box);
|
||||
}
|
||||
|
||||
var asInstance = this as InstanceInspector;
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
var labelWidth = (asInstance != null && asInstance.m_uObj)
|
||||
? new GUILayoutOption[] { GUILayout.Width(245f) }
|
||||
: new GUILayoutOption[0];
|
||||
GUILayout.Label("<b>Type:</b> <color=cyan>" + TargetType.FullName + "</color>", labelWidth);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (asInstance != null)
|
||||
{
|
||||
asInstance.DrawInstanceControls(rect);
|
||||
}
|
||||
|
||||
UIStyles.HorizontalLine(Color.grey);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label("<b>Search:</b>", new GUILayoutOption[] { GUILayout.Width(75) });
|
||||
m_search = GUIHelper.TextField(m_search, new GUILayoutOption[0]);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label("<b>Filter:</b>", new GUILayoutOption[] { GUILayout.Width(75) });
|
||||
FilterTypeToggle(MemberTypes.All, "All");
|
||||
FilterTypeToggle(MemberTypes.Property, "Properties");
|
||||
FilterTypeToggle(MemberTypes.Field, "Fields");
|
||||
FilterTypeToggle(MemberTypes.Method, "Methods");
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (this is InstanceInspector)
|
||||
{
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label("<b>Scope:</b>", new GUILayoutOption[] { GUILayout.Width(75) });
|
||||
FilterScopeToggle(MemberScopes.Both, "Both");
|
||||
FilterScopeToggle(MemberScopes.Instance, "Instance");
|
||||
FilterScopeToggle(MemberScopes.Static, "Static");
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label("<b>Values:</b>", new GUILayoutOption[] { GUILayout.Width(75) });
|
||||
if (GUILayout.Button("Update", new GUILayoutOption[] { GUILayout.Width(100) }))
|
||||
{
|
||||
UpdateValues();
|
||||
}
|
||||
GUI.color = m_autoUpdate ? Color.green : Color.red;
|
||||
m_autoUpdate = GUILayout.Toggle(m_autoUpdate, "Auto-update?", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||
GUI.color = m_hideFailedReflection ? Color.green : Color.red;
|
||||
m_hideFailedReflection = GUILayout.Toggle(m_hideFailedReflection, "Hide failed Reflection?", new GUILayoutOption[] { GUILayout.Width(150) });
|
||||
GUI.color = Color.white;
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.Space(10);
|
||||
|
||||
Pages.ItemCount = m_cachedMembersFiltered.Length;
|
||||
|
||||
// prev/next page buttons
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
Pages.DrawLimitInputArea();
|
||||
|
||||
if (Pages.ItemCount > Pages.ItemsPerPage)
|
||||
{
|
||||
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
Pages.TurnPage(Turn.Left, ref this.scroll);
|
||||
}
|
||||
|
||||
Pages.CurrentPageLabel();
|
||||
|
||||
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
Pages.TurnPage(Turn.Right, ref this.scroll);
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// ====== BODY ======
|
||||
|
||||
scroll = GUIHelper.BeginScrollView(scroll);
|
||||
|
||||
GUIHelper.Space(10);
|
||||
|
||||
UIStyles.HorizontalLine(Color.grey);
|
||||
|
||||
GUIHelper.BeginVertical(GUIContent.none, GUI.skin.box, null);
|
||||
|
||||
var members = this.m_cachedMembersFiltered;
|
||||
int start = Pages.CalculateOffsetIndex();
|
||||
|
||||
for (int j = start; (j < start + Pages.ItemsPerPage && j < members.Length); j++)
|
||||
{
|
||||
var holder = members[j];
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[] { GUILayout.Height(25) });
|
||||
try
|
||||
{
|
||||
holder.Draw(rect, 180f);
|
||||
}
|
||||
catch
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
continue;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// if not last element
|
||||
if (!(j == (start + Pages.ItemsPerPage - 1) || j == (members.Length - 1)))
|
||||
UIStyles.HorizontalLine(new Color(0.07f, 0.07f, 0.07f), true);
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
GUIHelper.EndScrollView();
|
||||
|
||||
if (!WindowManager.TabView)
|
||||
{
|
||||
m_rect = ResizeDrag.ResizeWindow(rect, windowID);
|
||||
|
||||
GUIHelper.EndArea();
|
||||
}
|
||||
}
|
||||
catch (Exception e) when (e.Message.Contains("in a group with only"))
|
||||
{
|
||||
// suppress
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.LogWarning("Exception drawing ReflectionWindow: " + e.GetType() + ", " + e.Message);
|
||||
DestroyWindow();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void FilterTypeToggle(MemberTypes mode, string label)
|
||||
{
|
||||
if (m_typeFilter == mode)
|
||||
{
|
||||
GUI.color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(100) }))
|
||||
{
|
||||
m_typeFilter = mode;
|
||||
Pages.PageOffset = 0;
|
||||
scroll = Vector2.zero;
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
|
||||
private void FilterScopeToggle(MemberScopes mode, string label)
|
||||
{
|
||||
if (m_scopeFilter == mode)
|
||||
{
|
||||
GUI.color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(100) }))
|
||||
{
|
||||
m_scopeFilter = mode;
|
||||
Pages.PageOffset = 0;
|
||||
scroll = Vector2.zero;
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,258 +1,108 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
using Explorer.Helpers;
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Reflection;
|
||||
//using UnityEngine;
|
||||
//using Explorer.CacheObject;
|
||||
//using Explorer.Helpers;
|
||||
//using Explorer.UI.Shared;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class InteractiveValue
|
||||
{
|
||||
public const float MAX_LABEL_WIDTH = 400f;
|
||||
public const string EVALUATE_LABEL = "<color=lime>Evaluate</color>";
|
||||
//namespace Explorer.UI
|
||||
//{
|
||||
// public class InteractiveValue
|
||||
// {
|
||||
// //public const float MAX_LABEL_WIDTH = 400f;
|
||||
// //public const string EVALUATE_LABEL = "<color=lime>Evaluate</color>";
|
||||
|
||||
public CacheObjectBase OwnerCacheObject;
|
||||
// public CacheObjectBase OwnerCacheObject;
|
||||
|
||||
public object Value { get; set; }
|
||||
public Type ValueType;
|
||||
// public object Value { get; set; }
|
||||
// public Type ValueType;
|
||||
|
||||
public string ButtonLabel => m_btnLabel ?? GetButtonLabel();
|
||||
private string m_btnLabel;
|
||||
// public string ButtonLabel => m_btnLabel ?? GetButtonLabel();
|
||||
// private string m_btnLabel;
|
||||
|
||||
public MethodInfo ToStringMethod => m_toStringMethod ?? GetToStringMethod();
|
||||
private MethodInfo m_toStringMethod;
|
||||
// public MethodInfo ToStringMethod => m_toStringMethod ?? GetToStringMethod();
|
||||
// private MethodInfo m_toStringMethod;
|
||||
|
||||
public virtual void Init()
|
||||
{
|
||||
UpdateValue();
|
||||
}
|
||||
// public virtual void Init()
|
||||
// {
|
||||
// UpdateValue();
|
||||
// }
|
||||
|
||||
public virtual void UpdateValue()
|
||||
{
|
||||
GetButtonLabel();
|
||||
}
|
||||
// public virtual void UpdateValue()
|
||||
// {
|
||||
// GetButtonLabel();
|
||||
// }
|
||||
|
||||
public float CalcWhitespace(Rect window)
|
||||
{
|
||||
if (!(this is IExpandHeight)) return 0f;
|
||||
|
||||
|
||||
float whitespace = (this as IExpandHeight).WhiteSpace;
|
||||
if (whitespace > 0)
|
||||
{
|
||||
ClampLabelWidth(window, ref whitespace);
|
||||
}
|
||||
// private MethodInfo GetToStringMethod()
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// m_toStringMethod = ReflectionHelpers.GetActualType(Value).GetMethod("ToString", new Type[0])
|
||||
// ?? typeof(object).GetMethod("ToString", new Type[0]);
|
||||
|
||||
return whitespace;
|
||||
}
|
||||
// // test invoke
|
||||
// m_toStringMethod.Invoke(Value, null);
|
||||
// }
|
||||
// catch
|
||||
// {
|
||||
// m_toStringMethod = typeof(object).GetMethod("ToString", new Type[0]);
|
||||
// }
|
||||
// return m_toStringMethod;
|
||||
// }
|
||||
|
||||
public static void ClampLabelWidth(Rect window, ref float labelWidth)
|
||||
{
|
||||
float min = window.width * 0.37f;
|
||||
if (min > MAX_LABEL_WIDTH) min = MAX_LABEL_WIDTH;
|
||||
// public string GetButtonLabel()
|
||||
// {
|
||||
// if (Value == null) return null;
|
||||
|
||||
labelWidth = Mathf.Clamp(labelWidth, min, MAX_LABEL_WIDTH);
|
||||
}
|
||||
// var valueType = ReflectionHelpers.GetActualType(Value);
|
||||
|
||||
public void Draw(Rect window, float labelWidth = 215f)
|
||||
{
|
||||
if (labelWidth > 0)
|
||||
{
|
||||
ClampLabelWidth(window, ref labelWidth);
|
||||
}
|
||||
// string label;
|
||||
|
||||
var cacheMember = OwnerCacheObject as CacheMember;
|
||||
// if (valueType == typeof(TextAsset))
|
||||
// {
|
||||
// var textAsset = Value as TextAsset;
|
||||
|
||||
if (cacheMember != null && cacheMember.MemInfo != null)
|
||||
{
|
||||
GUILayout.Label(cacheMember.RichTextName, new GUILayoutOption[] { GUILayout.Width(labelWidth) });
|
||||
}
|
||||
else
|
||||
{
|
||||
GUIHelper.Space(labelWidth);
|
||||
}
|
||||
// label = textAsset.text;
|
||||
|
||||
var cacheMethod = OwnerCacheObject as CacheMethod;
|
||||
// if (label.Length > 10)
|
||||
// {
|
||||
// label = $"{label.Substring(0, 10)}...";
|
||||
// }
|
||||
|
||||
if (cacheMember != null && cacheMember.HasParameters)
|
||||
{
|
||||
GUIHelper.BeginVertical(new GUILayoutOption[] { GUILayout.ExpandHeight(true) } );
|
||||
// label = $"\"{label}\" {textAsset.name} (<color={Syntax.Class_Instance}>UnityEngine.TextAsset</color>)";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString();
|
||||
|
||||
if (cacheMember.m_isEvaluating)
|
||||
{
|
||||
if (cacheMethod != null && cacheMethod.GenericArgs.Length > 0)
|
||||
{
|
||||
cacheMethod.DrawGenericArgsInput();
|
||||
}
|
||||
// var classColor = valueType.IsAbstract && valueType.IsSealed
|
||||
// ? Syntax.Class_Static
|
||||
// : Syntax.Class_Instance;
|
||||
|
||||
if (cacheMember.m_arguments.Length > 0)
|
||||
{
|
||||
cacheMember.DrawArgsInput();
|
||||
}
|
||||
// string typeLabel = $"<color={classColor}>{valueType.FullName}</color>";
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
if (GUILayout.Button(EVALUATE_LABEL, new GUILayoutOption[] { GUILayout.Width(70) }))
|
||||
{
|
||||
if (cacheMethod != null)
|
||||
cacheMethod.Evaluate();
|
||||
else
|
||||
cacheMember.UpdateValue();
|
||||
}
|
||||
if (GUILayout.Button("Cancel", new GUILayoutOption[] { GUILayout.Width(70) }))
|
||||
{
|
||||
cacheMember.m_isEvaluating = false;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
else
|
||||
{
|
||||
var lbl = $"Evaluate (";
|
||||
int len = cacheMember.m_arguments.Length;
|
||||
if (cacheMethod != null) len += cacheMethod.GenericArgs.Length;
|
||||
lbl += len + " params)";
|
||||
// if (Value is UnityEngine.Object)
|
||||
// {
|
||||
// label = label.Replace($"({valueType.FullName})", $"({typeLabel})");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (!label.Contains(valueType.FullName))
|
||||
// {
|
||||
// label += $" ({typeLabel})";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// label = label.Replace(valueType.FullName, typeLabel);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if (GUILayout.Button(lbl, new GUILayoutOption[] { GUILayout.Width(150) }))
|
||||
{
|
||||
cacheMember.m_isEvaluating = true;
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(labelWidth);
|
||||
}
|
||||
else if (cacheMethod != null)
|
||||
{
|
||||
if (GUILayout.Button(EVALUATE_LABEL, new GUILayoutOption[] { GUILayout.Width(70) }))
|
||||
{
|
||||
cacheMethod.Evaluate();
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(labelWidth);
|
||||
}
|
||||
|
||||
string typeName = $"<color={Syntax.Class_Instance}>{ValueType.FullName}</color>";
|
||||
|
||||
if (cacheMember != null && !string.IsNullOrEmpty(cacheMember.ReflectionException))
|
||||
{
|
||||
GUILayout.Label("<color=red>Reflection failed!</color> (" + cacheMember.ReflectionException + ")", new GUILayoutOption[0]);
|
||||
}
|
||||
else if (cacheMember != null && (cacheMember.HasParameters || cacheMember is CacheMethod) && !cacheMember.m_evaluated)
|
||||
{
|
||||
GUILayout.Label($"<color=grey><i>Not yet evaluated</i></color> ({typeName})", new GUILayoutOption[0]);
|
||||
}
|
||||
else if ((Value == null || Value is UnityEngine.Object uObj && !uObj) && !(cacheMember is CacheMethod))
|
||||
{
|
||||
GUILayout.Label($"<i>null ({typeName})</i>", new GUILayoutOption[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
float _width = window.width - labelWidth - 90;
|
||||
if (OwnerCacheObject is CacheMethod cm)
|
||||
{
|
||||
cm.DrawValue(window, _width);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawValue(window, _width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void DrawValue(Rect window, float width)
|
||||
{
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
if (GUILayout.Button(ButtonLabel, new GUILayoutOption[] { GUILayout.Width(width - 15) }))
|
||||
{
|
||||
if (OwnerCacheObject.IsStaticClassSearchResult)
|
||||
{
|
||||
WindowManager.InspectStaticReflection(Value as Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowManager.InspectObject(Value, out bool _);
|
||||
}
|
||||
}
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
}
|
||||
|
||||
private MethodInfo GetToStringMethod()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_toStringMethod = ReflectionHelpers.GetActualType(Value).GetMethod("ToString", new Type[0])
|
||||
?? typeof(object).GetMethod("ToString", new Type[0]);
|
||||
|
||||
// test invoke
|
||||
m_toStringMethod.Invoke(Value, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_toStringMethod = typeof(object).GetMethod("ToString", new Type[0]);
|
||||
}
|
||||
return m_toStringMethod;
|
||||
}
|
||||
|
||||
public string GetButtonLabel()
|
||||
{
|
||||
if (Value == null) return null;
|
||||
|
||||
var valueType = ReflectionHelpers.GetActualType(Value);
|
||||
|
||||
string label;
|
||||
|
||||
if (valueType == typeof(TextAsset))
|
||||
{
|
||||
var textAsset = Value as TextAsset;
|
||||
|
||||
label = textAsset.text;
|
||||
|
||||
if (label.Length > 10)
|
||||
{
|
||||
label = $"{label.Substring(0, 10)}...";
|
||||
}
|
||||
|
||||
label = $"\"{label}\" {textAsset.name} (<color={Syntax.Class_Instance}>UnityEngine.TextAsset</color>)";
|
||||
}
|
||||
else
|
||||
{
|
||||
label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString();
|
||||
|
||||
if (label.Length > 100)
|
||||
{
|
||||
label = label.Substring(0, 99);
|
||||
}
|
||||
|
||||
var classColor = valueType.IsAbstract && valueType.IsSealed
|
||||
? Syntax.Class_Static
|
||||
: Syntax.Class_Instance;
|
||||
|
||||
string typeLabel = $"<color={classColor}>{valueType.FullName}</color>";
|
||||
|
||||
if (Value is UnityEngine.Object)
|
||||
{
|
||||
label = label.Replace($"({valueType.FullName})", $"({typeLabel})");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!label.Contains(valueType.FullName))
|
||||
{
|
||||
label += $" ({typeLabel})";
|
||||
}
|
||||
else
|
||||
{
|
||||
label = label.Replace(valueType.FullName, typeLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_btnLabel = label;
|
||||
}
|
||||
}
|
||||
}
|
||||
// return m_btnLabel = label;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
@ -1,312 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
using Explorer.Helpers;
|
||||
#if CPP
|
||||
using UnhollowerBaseLib;
|
||||
#endif
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
// TODO: Re-work class using InteractiveEnumerable or maybe InteractiveCollection for the Keys/Value lists.
|
||||
// Make the keys and values editable.
|
||||
|
||||
public class InteractiveDictionary : InteractiveValue, IExpandHeight
|
||||
{
|
||||
public bool IsExpanded { get; set; }
|
||||
public float WhiteSpace { get; set; } = 215f;
|
||||
|
||||
public PageHelper Pages = new PageHelper();
|
||||
|
||||
private CacheObjectBase[] m_cachedKeys = new CacheObjectBase[0];
|
||||
private CacheObjectBase[] m_cachedValues = new CacheObjectBase[0];
|
||||
|
||||
public Type TypeOfKeys
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_keysType == null) GetGenericArguments();
|
||||
return m_keysType;
|
||||
}
|
||||
}
|
||||
private Type m_keysType;
|
||||
|
||||
public Type TypeOfValues
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_valuesType == null) GetGenericArguments();
|
||||
return m_valuesType;
|
||||
}
|
||||
}
|
||||
private Type m_valuesType;
|
||||
|
||||
public IDictionary IDict
|
||||
{
|
||||
get => m_iDictionary ?? (m_iDictionary = Value as IDictionary) ?? Il2CppDictionaryToMono();
|
||||
set => m_iDictionary = value;
|
||||
}
|
||||
private IDictionary m_iDictionary;
|
||||
|
||||
// ========== Methods ==========
|
||||
|
||||
// This is a bit janky due to Il2Cpp Dictionary not implementing IDictionary.
|
||||
private IDictionary Il2CppDictionaryToMono()
|
||||
{
|
||||
// note: "ValueType" is the Dictionary itself, TypeOfValues is the 'Dictionary.Values' type.
|
||||
|
||||
// get keys and values
|
||||
var keys = ValueType.GetProperty("Keys").GetValue(Value, null);
|
||||
var values = ValueType.GetProperty("Values").GetValue(Value, null);
|
||||
|
||||
// create lists to hold them
|
||||
var keyList = new List<object>();
|
||||
var valueList = new List<object>();
|
||||
|
||||
// store entries with reflection
|
||||
EnumerateWithReflection(keys, keyList);
|
||||
EnumerateWithReflection(values, valueList);
|
||||
|
||||
// make actual mono dictionary
|
||||
var dict = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>)
|
||||
.MakeGenericType(TypeOfKeys, TypeOfValues));
|
||||
|
||||
// finally iterate into dictionary
|
||||
for (int i = 0; i < keyList.Count; i++)
|
||||
{
|
||||
dict.Add(keyList[i], valueList[i]);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
private void EnumerateWithReflection(object collection, List<object> list)
|
||||
{
|
||||
// invoke GetEnumerator
|
||||
var enumerator = collection.GetType().GetMethod("GetEnumerator").Invoke(collection, null);
|
||||
// get the type of it
|
||||
var enumeratorType = enumerator.GetType();
|
||||
// reflect MoveNext and Current
|
||||
var moveNext = enumeratorType.GetMethod("MoveNext");
|
||||
var current = enumeratorType.GetProperty("Current");
|
||||
// iterate
|
||||
while ((bool)moveNext.Invoke(enumerator, null))
|
||||
{
|
||||
list.Add(current.GetValue(enumerator, null));
|
||||
}
|
||||
}
|
||||
|
||||
private void GetGenericArguments()
|
||||
{
|
||||
if (ValueType.IsGenericType)
|
||||
{
|
||||
var generics = ValueType.GetGenericArguments();
|
||||
m_keysType = generics[0];
|
||||
m_valuesType = generics[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's non-generic, just use System.Object to allow for anything.
|
||||
m_keysType = typeof(object);
|
||||
m_valuesType = typeof(object);
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
// first make sure we won't run into a TypeInitializationException.
|
||||
if (!EnsureDictionaryIsSupported())
|
||||
{
|
||||
if (OwnerCacheObject is CacheMember cacheMember)
|
||||
{
|
||||
cacheMember.ReflectionException = "Dictionary Type not supported with Reflection!";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
base.UpdateValue();
|
||||
|
||||
CacheEntries();
|
||||
}
|
||||
|
||||
public void CacheEntries()
|
||||
{
|
||||
// reset
|
||||
IDict = null;
|
||||
|
||||
if (Value == null || IDict == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var keys = new List<CacheObjectBase>();
|
||||
foreach (var key in IDict.Keys)
|
||||
{
|
||||
Type t = ReflectionHelpers.GetActualType(key) ?? TypeOfKeys;
|
||||
var cache = CacheFactory.GetCacheObject(key, t);
|
||||
keys.Add(cache);
|
||||
}
|
||||
|
||||
var values = new List<CacheObjectBase>();
|
||||
foreach (var val in IDict.Values)
|
||||
{
|
||||
Type t = ReflectionHelpers.GetActualType(val) ?? TypeOfValues;
|
||||
var cache = CacheFactory.GetCacheObject(val, t);
|
||||
values.Add(cache);
|
||||
}
|
||||
|
||||
m_cachedKeys = keys.ToArray();
|
||||
m_cachedValues = values.ToArray();
|
||||
}
|
||||
|
||||
public bool EnsureDictionaryIsSupported()
|
||||
{
|
||||
if (typeof(IDictionary).IsAssignableFrom(ValueType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#if CPP
|
||||
try
|
||||
{
|
||||
return Check(TypeOfKeys) && Check(TypeOfValues);
|
||||
|
||||
bool Check(Type type)
|
||||
{
|
||||
var ptr = (IntPtr)typeof(Il2CppClassPointerStore<>)
|
||||
.MakeGenericType(type)
|
||||
.GetField("NativeClassPtr")
|
||||
.GetValue(null);
|
||||
|
||||
if (ptr == IntPtr.Zero)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Il2CppSystem.Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(ptr)) is Il2CppSystem.Type;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ============= GUI Draw =============
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
if (m_cachedKeys == null || m_cachedValues == null)
|
||||
{
|
||||
GUILayout.Label("Cached keys or values is null!", new GUILayoutOption[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
var whitespace = CalcWhitespace(window);
|
||||
|
||||
if (!IsExpanded)
|
||||
{
|
||||
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = false;
|
||||
}
|
||||
}
|
||||
|
||||
var negativeWhitespace = window.width - (whitespace + 100f);
|
||||
|
||||
int count = m_cachedKeys.Length;
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
string btnLabel = $"[{count}] <color=#2df7b2>Dictionary<{TypeOfKeys.FullName}, {TypeOfValues.FullName}></color>";
|
||||
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.Width(negativeWhitespace) }))
|
||||
{
|
||||
WindowManager.InspectObject(Value, out bool _);
|
||||
}
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
GUIHelper.Space(5);
|
||||
|
||||
if (IsExpanded)
|
||||
{
|
||||
Pages.ItemCount = count;
|
||||
|
||||
if (count > Pages.ItemsPerPage)
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
GUIHelper.Space(whitespace);
|
||||
|
||||
Pages.CurrentPageLabel();
|
||||
|
||||
// prev/next page buttons
|
||||
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||
{
|
||||
Pages.TurnPage(Turn.Left);
|
||||
}
|
||||
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||
{
|
||||
Pages.TurnPage(Turn.Right);
|
||||
}
|
||||
|
||||
Pages.DrawLimitInputArea();
|
||||
|
||||
GUIHelper.Space(5);
|
||||
}
|
||||
|
||||
int offset = Pages.CalculateOffsetIndex();
|
||||
|
||||
for (int i = offset; i < offset + Pages.ItemsPerPage && i < count; i++)
|
||||
{
|
||||
var key = m_cachedKeys[i];
|
||||
var val = m_cachedValues[i];
|
||||
|
||||
//collapsing the BeginHorizontal called from ReflectionWindow.WindowFunction or previous array entry
|
||||
GUILayout.EndHorizontal();
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
//GUIUnstrip.Space(whitespace);
|
||||
|
||||
if (key == null && val == null)
|
||||
{
|
||||
GUILayout.Label($"[{i}] <i><color=grey>(null)</color></i>", new GUILayoutOption[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||
GUILayout.Label($"[{i}]", new GUILayoutOption[] { GUILayout.Width(40) });
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleLeft;
|
||||
GUILayout.Label("Key:", new GUILayoutOption[] { GUILayout.Width(40) });
|
||||
if (key != null)
|
||||
key.IValue.DrawValue(window, (window.width / 2) - 80f);
|
||||
else
|
||||
GUILayout.Label("<i>null</i>", new GUILayoutOption[0]);
|
||||
|
||||
GUILayout.Label("Value:", new GUILayoutOption[] { GUILayout.Width(40) });
|
||||
if (val != null)
|
||||
val.IValue.DrawValue(window, (window.width / 2) - 80f);
|
||||
else
|
||||
GUILayout.Label("<i>null</i>", new GUILayoutOption[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,362 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
using System.Linq;
|
||||
using Explorer.Helpers;
|
||||
#if CPP
|
||||
using UnhollowerBaseLib;
|
||||
#endif
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class InteractiveEnumerable : InteractiveValue, IExpandHeight
|
||||
{
|
||||
public bool IsExpanded { get; set; }
|
||||
public float WhiteSpace { get; set; } = 215f;
|
||||
|
||||
public PageHelper Pages = new PageHelper();
|
||||
|
||||
private CacheEnumerated[] m_cachedEntries = new CacheEnumerated[0];
|
||||
|
||||
// Type of Entries in the Array
|
||||
public Type EntryType
|
||||
{
|
||||
get => GetEntryType();
|
||||
set => m_entryType = value;
|
||||
}
|
||||
private Type m_entryType;
|
||||
|
||||
// Cached IEnumerable object
|
||||
public IEnumerable Enumerable
|
||||
{
|
||||
get => GetEnumerable();
|
||||
}
|
||||
private IEnumerable m_enumerable;
|
||||
|
||||
// Generic Type Definition for Lists
|
||||
public Type GenericTypeDef
|
||||
{
|
||||
get => GetGenericTypeDef();
|
||||
}
|
||||
private Type m_genericTypeDef;
|
||||
|
||||
// Cached ToArray method for Lists
|
||||
public MethodInfo CppListToArrayMethod
|
||||
{
|
||||
get => GetGenericToArrayMethod();
|
||||
}
|
||||
private MethodInfo m_genericToArray;
|
||||
|
||||
// Cached Item Property for ILists
|
||||
public PropertyInfo ItemProperty
|
||||
{
|
||||
get => GetItemProperty();
|
||||
}
|
||||
|
||||
private PropertyInfo m_itemProperty;
|
||||
|
||||
// ========== Methods ==========
|
||||
|
||||
private IEnumerable GetEnumerable()
|
||||
{
|
||||
if (m_enumerable == null && Value != null)
|
||||
{
|
||||
m_enumerable = Value as IEnumerable ?? EnumerateWithReflection();
|
||||
}
|
||||
return m_enumerable;
|
||||
}
|
||||
|
||||
private Type GetGenericTypeDef()
|
||||
{
|
||||
if (m_genericTypeDef == null && Value != null)
|
||||
{
|
||||
var type = Value.GetType();
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
m_genericTypeDef = type.GetGenericTypeDefinition();
|
||||
}
|
||||
}
|
||||
return m_genericTypeDef;
|
||||
}
|
||||
|
||||
private MethodInfo GetGenericToArrayMethod()
|
||||
{
|
||||
if (GenericTypeDef == null) return null;
|
||||
|
||||
if (m_genericToArray == null)
|
||||
{
|
||||
m_genericToArray = GenericTypeDef
|
||||
.MakeGenericType(new Type[] { this.EntryType })
|
||||
.GetMethod("ToArray");
|
||||
}
|
||||
return m_genericToArray;
|
||||
}
|
||||
|
||||
private PropertyInfo GetItemProperty()
|
||||
{
|
||||
if (m_itemProperty == null)
|
||||
{
|
||||
m_itemProperty = Value?.GetType().GetProperty("Item");
|
||||
}
|
||||
return m_itemProperty;
|
||||
}
|
||||
|
||||
private IEnumerable EnumerateWithReflection()
|
||||
{
|
||||
if (Value == null) return null;
|
||||
|
||||
#if CPP
|
||||
if (GenericTypeDef == typeof(Il2CppSystem.Collections.Generic.List<>))
|
||||
{
|
||||
return (IEnumerable)CppListToArrayMethod?.Invoke(Value, new object[0]);
|
||||
}
|
||||
else if (GenericTypeDef == typeof(Il2CppSystem.Collections.Generic.HashSet<>))
|
||||
{
|
||||
return CppHashSetToMono();
|
||||
}
|
||||
else
|
||||
{
|
||||
return CppIListToMono();
|
||||
}
|
||||
#else
|
||||
return Value as IEnumerable;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CPP
|
||||
private IEnumerable CppHashSetToMono()
|
||||
{
|
||||
var set = new HashSet<object>();
|
||||
|
||||
// invoke GetEnumerator
|
||||
var enumerator = Value.GetType().GetMethod("GetEnumerator").Invoke(Value, null);
|
||||
// get the type of it
|
||||
var enumeratorType = enumerator.GetType();
|
||||
// reflect MoveNext and Current
|
||||
var moveNext = enumeratorType.GetMethod("MoveNext");
|
||||
var current = enumeratorType.GetProperty("Current");
|
||||
// iterate
|
||||
while ((bool)moveNext.Invoke(enumerator, null))
|
||||
{
|
||||
set.Add(current.GetValue(enumerator));
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
private IList CppIListToMono()
|
||||
{
|
||||
try
|
||||
{
|
||||
var genericType = typeof(List<>).MakeGenericType(new Type[] { this.EntryType });
|
||||
var list = (IList)Activator.CreateInstance(genericType);
|
||||
|
||||
for (int i = 0; ; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var itm = ItemProperty.GetValue(Value, new object[] { i });
|
||||
list.Add(itm);
|
||||
}
|
||||
catch { break; }
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.Log("Exception converting Il2Cpp IList to Mono IList: " + e.GetType() + ", " + e.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private Type GetEntryType()
|
||||
{
|
||||
if (ValueType.IsGenericType)
|
||||
{
|
||||
var gArgs = ValueType.GetGenericArguments();
|
||||
|
||||
if (ValueType.FullName.Contains("ValueCollection"))
|
||||
{
|
||||
m_entryType = gArgs[gArgs.Length - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_entryType = gArgs[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_entryType = typeof(object);
|
||||
}
|
||||
|
||||
return m_entryType;
|
||||
}
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
|
||||
if (Value == null || Enumerable == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CacheEntries();
|
||||
}
|
||||
|
||||
public void CacheEntries()
|
||||
{
|
||||
var enumerator = Enumerable.GetEnumerator();
|
||||
if (enumerator == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var list = new List<CacheEnumerated>();
|
||||
int index = 0;
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
var obj = enumerator.Current;
|
||||
|
||||
if (obj != null && ReflectionHelpers.GetActualType(obj) is Type t)
|
||||
{
|
||||
#if CPP
|
||||
if (obj is Il2CppSystem.Object iObj)
|
||||
{
|
||||
try
|
||||
{
|
||||
var cast = iObj.Il2CppCast(t);
|
||||
if (cast != null)
|
||||
{
|
||||
obj = cast;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
#endif
|
||||
|
||||
//ExplorerCore.Log("Caching enumeration entry " + obj.ToString() + " as " + EntryType.FullName);
|
||||
|
||||
var cached = new CacheEnumerated() { Index = index, RefIList = Value as IList, ParentEnumeration = this };
|
||||
cached.Init(obj, EntryType);
|
||||
list.Add(cached);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(null);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
m_cachedEntries = list.ToArray();
|
||||
}
|
||||
|
||||
// ============= GUI Draw =============
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
if (m_cachedEntries == null)
|
||||
{
|
||||
GUILayout.Label("m_cachedEntries is null!", new GUILayoutOption[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
var whitespace = CalcWhitespace(window);
|
||||
|
||||
if (!IsExpanded)
|
||||
{
|
||||
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = false;
|
||||
}
|
||||
}
|
||||
|
||||
var negativeWhitespace = window.width - (whitespace + 100f);
|
||||
|
||||
int count = m_cachedEntries.Length;
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
string btnLabel = $"[{count}] <color=#2df7b2>{EntryType.FullName}</color>";
|
||||
if (GUILayout.Button(btnLabel, new GUILayoutOption[] { GUILayout.Width(negativeWhitespace) }))
|
||||
{
|
||||
WindowManager.InspectObject(Value, out bool _);
|
||||
}
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
GUIHelper.Space(5);
|
||||
|
||||
if (IsExpanded)
|
||||
{
|
||||
Pages.ItemCount = count;
|
||||
|
||||
if (count > Pages.ItemsPerPage)
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
GUIHelper.Space(whitespace);
|
||||
|
||||
Pages.CurrentPageLabel();
|
||||
|
||||
// prev/next page buttons
|
||||
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||
{
|
||||
Pages.TurnPage(Turn.Left);
|
||||
}
|
||||
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||
{
|
||||
Pages.TurnPage(Turn.Right);
|
||||
}
|
||||
|
||||
Pages.DrawLimitInputArea();
|
||||
|
||||
GUIHelper.Space(5);
|
||||
}
|
||||
|
||||
int offset = Pages.CalculateOffsetIndex();
|
||||
|
||||
for (int i = offset; i < offset + Pages.ItemsPerPage && i < count; i++)
|
||||
{
|
||||
var entry = m_cachedEntries[i];
|
||||
|
||||
//collapsing the BeginHorizontal called from ReflectionWindow.WindowFunction or previous array entry
|
||||
GUILayout.EndHorizontal();
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
GUIHelper.Space(whitespace);
|
||||
|
||||
if (entry == null || entry.IValue == null)
|
||||
{
|
||||
GUILayout.Label($"[{i}] <i><color=grey>(null)</color></i>", new GUILayoutOption[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||
GUILayout.Label($"[{i}]", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleLeft;
|
||||
entry.IValue.DrawValue(window, window.width - (whitespace + 85));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class InteractiveGameObject : InteractiveValue
|
||||
{
|
||||
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
Buttons.GameObjectButton(Value, null, false, width);
|
||||
}
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Explorer.Helpers;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class InteractiveSprite : InteractiveTexture2D
|
||||
{
|
||||
private Sprite refSprite;
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
#if CPP
|
||||
if (Value != null && Value.Il2CppCast(typeof(Sprite)) is Sprite sprite)
|
||||
{
|
||||
refSprite = sprite;
|
||||
}
|
||||
#else
|
||||
if (Value is Sprite sprite)
|
||||
{
|
||||
refSprite = sprite;
|
||||
}
|
||||
#endif
|
||||
|
||||
base.UpdateValue();
|
||||
}
|
||||
|
||||
public override void GetTexture2D()
|
||||
{
|
||||
if (refSprite)
|
||||
{
|
||||
currentTex = refSprite.texture;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetGUIContent()
|
||||
{
|
||||
// Check if the Sprite.textureRect is just the entire texture
|
||||
if (refSprite.textureRect != new Rect(0, 0, currentTex.width, currentTex.height))
|
||||
{
|
||||
// It's not, do a sub-copy.
|
||||
currentTex = Texture2DHelpers.Copy(refSprite.texture, refSprite.textureRect);
|
||||
}
|
||||
|
||||
base.GetGUIContent();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
// This class is possibly unnecessary.
|
||||
// It's just for CacheMembers that have 'Texture' as the value type, but is actually a Texture2D.
|
||||
|
||||
public class InteractiveTexture : InteractiveTexture2D
|
||||
{
|
||||
public override void GetTexture2D()
|
||||
{
|
||||
#if CPP
|
||||
if (Value != null && Value.Il2CppCast(typeof(Texture2D)) is Texture2D tex)
|
||||
#else
|
||||
if (Value is Texture2D tex)
|
||||
#endif
|
||||
{
|
||||
currentTex = tex;
|
||||
texContent = new GUIContent
|
||||
{
|
||||
image = currentTex
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Explorer.CacheObject;
|
||||
using Explorer.Config;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using Explorer.Helpers;
|
||||
#if CPP
|
||||
using Explorer.Unstrip.ImageConversion;
|
||||
#endif
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class InteractiveTexture2D : InteractiveValue, IExpandHeight
|
||||
{
|
||||
public bool IsExpanded { get; set; }
|
||||
public float WhiteSpace { get; set; } = 215f;
|
||||
|
||||
public Texture2D currentTex;
|
||||
public GUIContent texContent;
|
||||
|
||||
private string saveFolder = ModConfig.Instance.Default_Output_Path;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
}
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
|
||||
GetTexture2D();
|
||||
}
|
||||
|
||||
public virtual void GetTexture2D()
|
||||
{
|
||||
#if CPP
|
||||
if (Value != null && Value.Il2CppCast(typeof(Texture2D)) is Texture2D tex)
|
||||
#else
|
||||
if (Value is Texture2D tex)
|
||||
#endif
|
||||
{
|
||||
currentTex = tex;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void GetGUIContent()
|
||||
{
|
||||
texContent = new GUIContent
|
||||
{
|
||||
image = currentTex
|
||||
};
|
||||
}
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
GUIHelper.BeginVertical();
|
||||
|
||||
GUIHelper.BeginHorizontal();
|
||||
|
||||
if (currentTex && !IsExpanded)
|
||||
{
|
||||
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = true;
|
||||
GetGUIContent();
|
||||
}
|
||||
}
|
||||
else if (currentTex)
|
||||
{
|
||||
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = false;
|
||||
}
|
||||
}
|
||||
|
||||
base.DrawValue(window, width);
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (currentTex && IsExpanded)
|
||||
{
|
||||
DrawTextureControls();
|
||||
DrawTexture();
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
// Temporarily disabled in BepInEx IL2CPP.
|
||||
private void DrawTexture()
|
||||
{
|
||||
#if CPP
|
||||
#if BIE
|
||||
#else
|
||||
GUILayout.Label(texContent, new GUILayoutOption[0]);
|
||||
#endif
|
||||
#else
|
||||
GUILayout.Label(texContent, new GUILayoutOption[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void DrawTextureControls()
|
||||
{
|
||||
GUIHelper.BeginHorizontal();
|
||||
|
||||
GUILayout.Label("Save folder:", new GUILayoutOption[] { GUILayout.Width(80f) });
|
||||
saveFolder = GUIHelper.TextField(saveFolder, new GUILayoutOption[0]);
|
||||
GUIHelper.Space(10f);
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (GUILayout.Button("Save to PNG", new GUILayoutOption[] { GUILayout.Width(100f) }))
|
||||
{
|
||||
var name = RemoveInvalidFilenameChars(currentTex.name ?? "");
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
if (OwnerCacheObject is CacheMember cacheMember)
|
||||
{
|
||||
name = cacheMember.MemInfo.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = "UNTITLED";
|
||||
}
|
||||
}
|
||||
|
||||
Texture2DHelpers.SaveTextureAsPNG(currentTex, saveFolder, name, false);
|
||||
|
||||
ExplorerCore.Log($@"Saved to {saveFolder}\{name}.png!");
|
||||
}
|
||||
}
|
||||
|
||||
private string RemoveInvalidFilenameChars(string s)
|
||||
{
|
||||
var invalid = System.IO.Path.GetInvalidFileNameChars();
|
||||
foreach (var c in invalid)
|
||||
{
|
||||
s = s.Replace(c.ToString(), "");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class InteractiveColor : InteractiveValue, IExpandHeight
|
||||
{
|
||||
private string r = "0";
|
||||
private string g = "0";
|
||||
private string b = "0";
|
||||
private string a = "0";
|
||||
|
||||
public bool IsExpanded { get; set; }
|
||||
public float WhiteSpace { get; set; } = 215f;
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
|
||||
if (Value == null) return;
|
||||
|
||||
var color = (Color)Value;
|
||||
|
||||
r = color.r.ToString();
|
||||
g = color.g.ToString();
|
||||
b = color.b.ToString();
|
||||
a = color.a.ToString();
|
||||
}
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
if (OwnerCacheObject.CanWrite)
|
||||
{
|
||||
if (!IsExpanded)
|
||||
{
|
||||
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//var c = (Color)Value;
|
||||
//GUI.color = c;
|
||||
GUILayout.Label($"<color=#2df7b2>Color:</color> {((Color)Value).ToString()}", new GUILayoutOption[0]);
|
||||
//GUI.color = Color.white;
|
||||
|
||||
if (OwnerCacheObject.CanWrite && IsExpanded)
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
var whitespace = CalcWhitespace(window);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("R:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
r = GUIHelper.TextField(r, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("G:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
g = GUIHelper.TextField(g, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("B:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
b = GUIHelper.TextField(b, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("A:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
a = GUIHelper.TextField(a, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// draw set value button
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
|
||||
{
|
||||
SetValueFromInput();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetValueFromInput()
|
||||
{
|
||||
if (float.TryParse(r, out float fR)
|
||||
&& float.TryParse(g, out float fG)
|
||||
&& float.TryParse(b, out float fB)
|
||||
&& float.TryParse(a, out float fA))
|
||||
{
|
||||
Value = new Color(fR, fG, fB, fA);
|
||||
OwnerCacheObject.SetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class InteractiveEnum : InteractiveValue
|
||||
{
|
||||
internal static Dictionary<Type, string[]> EnumNamesInternalCache = new Dictionary<Type, string[]>();
|
||||
|
||||
// public Type EnumType;
|
||||
public string[] EnumNames = new string[0];
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
if (ValueType == null && Value != null)
|
||||
{
|
||||
ValueType = Value.GetType();
|
||||
}
|
||||
|
||||
if (ValueType != null)
|
||||
{
|
||||
GetNames();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (OwnerCacheObject is CacheMember cacheMember)
|
||||
{
|
||||
cacheMember.ReflectionException = "Unknown, could not get Enum names.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void GetNames()
|
||||
{
|
||||
if (!EnumNamesInternalCache.ContainsKey(ValueType))
|
||||
{
|
||||
// using GetValues not GetNames, to catch instances of weird enums (eg CameraClearFlags)
|
||||
var values = Enum.GetValues(ValueType);
|
||||
|
||||
var set = new HashSet<string>();
|
||||
foreach (var value in values)
|
||||
{
|
||||
var v = value.ToString();
|
||||
if (set.Contains(v)) continue;
|
||||
set.Add(v);
|
||||
}
|
||||
|
||||
EnumNamesInternalCache.Add(ValueType, set.ToArray());
|
||||
}
|
||||
|
||||
EnumNames = EnumNamesInternalCache[ValueType];
|
||||
}
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
if (OwnerCacheObject.CanWrite)
|
||||
{
|
||||
if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
SetEnum(-1);
|
||||
OwnerCacheObject.SetValue();
|
||||
}
|
||||
if (GUILayout.Button(">", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
SetEnum(1);
|
||||
OwnerCacheObject.SetValue();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Label(Value.ToString() + $"<color={Syntax.StructGreen}><i> ({ValueType})</i></color>", new GUILayoutOption[0]);
|
||||
}
|
||||
|
||||
public void SetEnum(int change)
|
||||
{
|
||||
var names = EnumNames.ToList();
|
||||
|
||||
int newindex = names.IndexOf(Value.ToString()) + change;
|
||||
|
||||
if (newindex >= 0 && newindex < names.Count)
|
||||
{
|
||||
Value = Enum.Parse(ValueType, EnumNames[newindex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class InteractiveFlags : InteractiveEnum, IExpandHeight
|
||||
{
|
||||
public bool[] m_enabledFlags = new bool[0];
|
||||
|
||||
public bool IsExpanded { get; set; }
|
||||
public float WhiteSpace { get; set; } = 215f;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
UpdateValue();
|
||||
}
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
|
||||
if (Value == null) return;
|
||||
|
||||
try
|
||||
{
|
||||
var enabledNames = Value.ToString().Split(',').Select(it => it.Trim());
|
||||
|
||||
m_enabledFlags = new bool[EnumNames.Length];
|
||||
|
||||
for (int i = 0; i < EnumNames.Length; i++)
|
||||
{
|
||||
m_enabledFlags[i] = enabledNames.Contains(EnumNames[i]);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.Log(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
if (OwnerCacheObject.CanWrite)
|
||||
{
|
||||
if (!IsExpanded)
|
||||
{
|
||||
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Label(Value.ToString() + "<color=#2df7b2><i> (" + ValueType + ")</i></color>", new GUILayoutOption[0]);
|
||||
|
||||
if (IsExpanded)
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
var whitespace = CalcWhitespace(window);
|
||||
|
||||
for (int i = 0; i < EnumNames.Length; i++)
|
||||
{
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
|
||||
m_enabledFlags[i] = GUILayout.Toggle(m_enabledFlags[i], EnumNames[i], new GUILayoutOption[0]);
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
|
||||
{
|
||||
SetFlagsFromInput();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFlagsFromInput()
|
||||
{
|
||||
string val = "";
|
||||
for (int i = 0; i < EnumNames.Length; i++)
|
||||
{
|
||||
if (m_enabledFlags[i])
|
||||
{
|
||||
if (val != "") val += ", ";
|
||||
val += EnumNames[i];
|
||||
}
|
||||
}
|
||||
Value = Enum.Parse(ValueType, val);
|
||||
OwnerCacheObject.SetValue();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,262 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
#if CPP
|
||||
using UnhollowerRuntimeLib;
|
||||
#endif
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
using Explorer.Config;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class InteractivePrimitive : InteractiveValue
|
||||
{
|
||||
private string m_valueToString;
|
||||
private bool m_isBool;
|
||||
private bool m_isString;
|
||||
|
||||
public MethodInfo ParseMethod => m_parseMethod ?? (m_parseMethod = Value.GetType().GetMethod("Parse", new Type[] { typeof(string) }));
|
||||
private MethodInfo m_parseMethod;
|
||||
|
||||
private bool m_canBitwiseOperate;
|
||||
private bool m_inBitwiseMode;
|
||||
private string m_bitwiseOperatorInput = "0";
|
||||
private string m_binaryInput;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
if (ValueType == null)
|
||||
{
|
||||
ValueType = Value?.GetType();
|
||||
|
||||
// has to be a string at this point
|
||||
if (ValueType == null)
|
||||
{
|
||||
ValueType = typeof(string);
|
||||
}
|
||||
}
|
||||
|
||||
if (ValueType == typeof(string))
|
||||
{
|
||||
m_isString = true;
|
||||
}
|
||||
else if (ValueType == typeof(bool))
|
||||
{
|
||||
m_isBool = true;
|
||||
}
|
||||
|
||||
m_canBitwiseOperate = typeof(int).IsAssignableFrom(ValueType);
|
||||
|
||||
UpdateValue();
|
||||
}
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
|
||||
RefreshToString();
|
||||
}
|
||||
|
||||
private void RefreshToString()
|
||||
{
|
||||
m_valueToString = Value?.ToString();
|
||||
|
||||
if (m_canBitwiseOperate && Value != null)
|
||||
{
|
||||
var _int = (int)Value;
|
||||
m_binaryInput = Convert.ToString(_int, toBase: 2);
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
if (m_isBool)
|
||||
{
|
||||
var b = (bool)Value;
|
||||
var label = $"<color={(b ? "lime" : "red")}>{b}</color>";
|
||||
|
||||
if (OwnerCacheObject.CanWrite)
|
||||
{
|
||||
Value = GUILayout.Toggle(b, label, new GUILayoutOption[] { GUILayout.Width(60) });
|
||||
DrawApplyButton();
|
||||
//if (b != (bool)Value)
|
||||
//{
|
||||
// Value = b;
|
||||
// OwnerCacheObject.SetValue();
|
||||
//}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label(label, new GUILayoutOption[0]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// all other non-bool values use TextField
|
||||
|
||||
GUIHelper.BeginVertical(new GUILayoutOption[0]);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
GUILayout.Label("<color=#2df7b2><i>" + ValueType.Name + "</i></color>", new GUILayoutOption[] { GUILayout.Width(50) });
|
||||
|
||||
m_valueToString = GUIHelper.TextArea(m_valueToString, new GUILayoutOption[] { GUIHelper.ExpandWidth(true) });
|
||||
|
||||
DrawApplyButton();
|
||||
|
||||
if (ModConfig.Instance.Bitwise_Support && m_canBitwiseOperate)
|
||||
{
|
||||
m_inBitwiseMode = GUILayout.Toggle(m_inBitwiseMode, "Bitwise?", new GUILayoutOption[0]);
|
||||
}
|
||||
|
||||
GUIHelper.Space(10);
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (ModConfig.Instance.Bitwise_Support && m_inBitwiseMode)
|
||||
{
|
||||
DrawBitwise();
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void DrawApplyButton()
|
||||
{
|
||||
if (OwnerCacheObject.CanWrite)
|
||||
{
|
||||
if (GUILayout.Button("<color=#00FF00>Apply</color>", new GUILayoutOption[] { GUILayout.Width(60) }))
|
||||
{
|
||||
if (m_isBool)
|
||||
{
|
||||
OwnerCacheObject.SetValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetValueFromInput();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawBitwise()
|
||||
{
|
||||
if (OwnerCacheObject.CanWrite)
|
||||
{
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||
GUILayout.Label("RHS:", new GUILayoutOption[] { GUILayout.Width(35) });
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
|
||||
if (GUILayout.Button("~", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
if (int.TryParse(m_bitwiseOperatorInput, out int bit))
|
||||
{
|
||||
Value = ~bit;
|
||||
RefreshToString();
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button("<<", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
if (int.TryParse(m_bitwiseOperatorInput, out int bit))
|
||||
{
|
||||
Value = (int)Value << bit;
|
||||
RefreshToString();
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button(">>", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
if (int.TryParse(m_bitwiseOperatorInput, out int bit))
|
||||
{
|
||||
Value = (int)Value >> bit;
|
||||
RefreshToString();
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button("|", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
if (int.TryParse(m_bitwiseOperatorInput, out int bit))
|
||||
{
|
||||
Value = (int)Value | bit;
|
||||
RefreshToString();
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button("&", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
if (int.TryParse(m_bitwiseOperatorInput, out int bit))
|
||||
{
|
||||
Value = (int)Value & bit;
|
||||
RefreshToString();
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
if (int.TryParse(m_bitwiseOperatorInput, out int bit))
|
||||
{
|
||||
Value = (int)Value ^ bit;
|
||||
RefreshToString();
|
||||
}
|
||||
}
|
||||
|
||||
m_bitwiseOperatorInput = GUIHelper.TextField(m_bitwiseOperatorInput, new GUILayoutOption[] { GUILayout.Width(55) });
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label($"<color=cyan>Binary:</color>", new GUILayoutOption[] { GUILayout.Width(60) });
|
||||
m_binaryInput = GUIHelper.TextField(m_binaryInput, new GUILayoutOption[0]);
|
||||
if (OwnerCacheObject.CanWrite)
|
||||
{
|
||||
if (GUILayout.Button("Apply", new GUILayoutOption[0]))
|
||||
{
|
||||
SetValueFromBinaryInput();
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void SetValueFromInput()
|
||||
{
|
||||
if (m_isString)
|
||||
{
|
||||
Value = m_valueToString;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
Value = ParseMethod.Invoke(null, new object[] { m_valueToString });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.Log("Exception parsing value: " + e.GetType() + ", " + e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
OwnerCacheObject.SetValue();
|
||||
RefreshToString();
|
||||
}
|
||||
|
||||
private void SetValueFromBinaryInput()
|
||||
{
|
||||
try
|
||||
{
|
||||
var method = typeof(Convert).GetMethod($"To{ValueType.Name}", new Type[] { typeof(string), typeof(int) });
|
||||
Value = method.Invoke(null, new object[] { m_binaryInput, 2 });
|
||||
|
||||
OwnerCacheObject.SetValue();
|
||||
RefreshToString();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.Log("Exception setting value: " + e.GetType() + ", " + e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class InteractiveQuaternion : InteractiveValue, IExpandHeight
|
||||
{
|
||||
private string x = "0";
|
||||
private string y = "0";
|
||||
private string z = "0";
|
||||
|
||||
public bool IsExpanded { get; set; }
|
||||
public float WhiteSpace { get; set; } = 215f;
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
|
||||
if (Value == null) return;
|
||||
|
||||
var euler = ((Quaternion)Value).eulerAngles;
|
||||
|
||||
x = euler.x.ToString();
|
||||
y = euler.y.ToString();
|
||||
z = euler.z.ToString();
|
||||
}
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
if (OwnerCacheObject.CanWrite)
|
||||
{
|
||||
if (!IsExpanded)
|
||||
{
|
||||
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Label($"<color=#2df7b2>Quaternion</color>: {((Quaternion)Value).eulerAngles.ToString()}", new GUILayoutOption[0]);
|
||||
|
||||
if (OwnerCacheObject.CanWrite && IsExpanded)
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
var whitespace = CalcWhitespace(window);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
x = GUIHelper.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
y = GUIHelper.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
z = GUIHelper.TextField(z, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// draw set value button
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
|
||||
{
|
||||
SetValueFromInput();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetValueFromInput()
|
||||
{
|
||||
if (float.TryParse(x, out float fX)
|
||||
&& float.TryParse(y, out float fY)
|
||||
&& float.TryParse(z, out float fZ))
|
||||
{
|
||||
Value = Quaternion.Euler(new Vector3(fX, fY, fZ));
|
||||
OwnerCacheObject.SetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class InteractiveRect : InteractiveValue, IExpandHeight
|
||||
{
|
||||
private string x = "0";
|
||||
private string y = "0";
|
||||
private string w = "0";
|
||||
private string h = "0";
|
||||
|
||||
public bool IsExpanded { get; set; }
|
||||
public float WhiteSpace { get; set; } = 215f;
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
|
||||
if (Value == null) return;
|
||||
|
||||
var rect = (Rect)Value;
|
||||
|
||||
x = rect.x.ToString();
|
||||
y = rect.y.ToString();
|
||||
w = rect.width.ToString();
|
||||
h = rect.height.ToString();
|
||||
}
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
if (OwnerCacheObject.CanWrite)
|
||||
{
|
||||
if (!IsExpanded)
|
||||
{
|
||||
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Label($"<color=#2df7b2>Rect</color>: {((Rect)Value).ToString()}", new GUILayoutOption[0]);
|
||||
|
||||
if (OwnerCacheObject.CanWrite && IsExpanded)
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
var whitespace = CalcWhitespace(window);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
x = GUIHelper.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
y = GUIHelper.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
w = GUIHelper.TextField(w, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("H:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
h = GUIHelper.TextField(h, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// draw set value button
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
|
||||
{
|
||||
SetValueFromInput();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetValueFromInput()
|
||||
{
|
||||
if (float.TryParse(x, out float fX)
|
||||
&& float.TryParse(y, out float fY)
|
||||
&& float.TryParse(w, out float fW)
|
||||
&& float.TryParse(h, out float fH))
|
||||
{
|
||||
Value = new Rect(fX, fY, fW, fH);
|
||||
OwnerCacheObject.SetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,171 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class InteractiveVector : InteractiveValue, IExpandHeight
|
||||
{
|
||||
public int VectorSize = 2;
|
||||
|
||||
private string x = "0";
|
||||
private string y = "0";
|
||||
private string z = "0";
|
||||
private string w = "0";
|
||||
|
||||
//private MethodInfo m_toStringMethod;
|
||||
|
||||
public bool IsExpanded { get; set; }
|
||||
public float WhiteSpace { get; set; } = 215f;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
if (ValueType == null && Value != null)
|
||||
{
|
||||
ValueType = Value.GetType();
|
||||
}
|
||||
|
||||
if (ValueType == typeof(Vector2))
|
||||
{
|
||||
VectorSize = 2;
|
||||
//m_toStringMethod = typeof(Vector2).GetMethod("ToString", new Type[0]);
|
||||
}
|
||||
else if (ValueType == typeof(Vector3))
|
||||
{
|
||||
VectorSize = 3;
|
||||
//m_toStringMethod = typeof(Vector3).GetMethod("ToString", new Type[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSize = 4;
|
||||
//m_toStringMethod = typeof(Vector4).GetMethod("ToString", new Type[0]);
|
||||
}
|
||||
|
||||
base.Init();
|
||||
}
|
||||
|
||||
public override void UpdateValue()
|
||||
{
|
||||
base.UpdateValue();
|
||||
|
||||
if (Value is Vector2 vec2)
|
||||
{
|
||||
x = vec2.x.ToString();
|
||||
y = vec2.y.ToString();
|
||||
}
|
||||
else if (Value is Vector3 vec3)
|
||||
{
|
||||
x = vec3.x.ToString();
|
||||
y = vec3.y.ToString();
|
||||
z = vec3.z.ToString();
|
||||
}
|
||||
else if (Value is Vector4 vec4)
|
||||
{
|
||||
x = vec4.x.ToString();
|
||||
y = vec4.y.ToString();
|
||||
z = vec4.z.ToString();
|
||||
w = vec4.w.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawValue(Rect window, float width)
|
||||
{
|
||||
if (OwnerCacheObject.CanWrite)
|
||||
{
|
||||
if (!IsExpanded)
|
||||
{
|
||||
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||
{
|
||||
IsExpanded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Label($"<color=#2df7b2>Vector{VectorSize}</color>: {(string)ToStringMethod.Invoke(Value, new object[0])}", new GUILayoutOption[0]);
|
||||
|
||||
if (OwnerCacheObject.CanWrite && IsExpanded)
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
var whitespace = CalcWhitespace(window);
|
||||
|
||||
// always draw x and y
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
x = GUIHelper.TextField(x, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
y = GUIHelper.TextField(y, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (VectorSize > 2)
|
||||
{
|
||||
// draw z
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
z = GUIHelper.TextField(z, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
if (VectorSize > 3)
|
||||
{
|
||||
// draw w
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) });
|
||||
w = GUIHelper.TextField(w, new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
// draw set value button
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUIHelper.Space(whitespace);
|
||||
if (GUILayout.Button("<color=lime>Apply</color>", new GUILayoutOption[] { GUILayout.Width(155) }))
|
||||
{
|
||||
SetValueFromInput();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetValueFromInput()
|
||||
{
|
||||
if (float.TryParse(x, out float fX)
|
||||
&& float.TryParse(y, out float fY)
|
||||
&& float.TryParse(z, out float fZ)
|
||||
&& float.TryParse(w, out float fW))
|
||||
{
|
||||
object vector = null;
|
||||
|
||||
switch (VectorSize)
|
||||
{
|
||||
case 2: vector = new Vector2(fX, fY); break;
|
||||
case 3: vector = new Vector3(fX, fY, fZ); break;
|
||||
case 4: vector = new Vector4(fX, fY, fZ, fW); break;
|
||||
}
|
||||
|
||||
if (vector != null)
|
||||
{
|
||||
Value = vector;
|
||||
OwnerCacheObject.SetValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer.UI.Main
|
||||
{
|
||||
public abstract class BaseMainMenuPage
|
||||
{
|
||||
public virtual string Name { get; }
|
||||
|
||||
public Vector2 scroll = Vector2.zero;
|
||||
|
||||
public abstract void Init();
|
||||
|
||||
public abstract void DrawWindow();
|
||||
|
||||
public abstract void Update();
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
// Thanks to ManlyMarco for this
|
||||
|
||||
namespace Explorer.UI.Main
|
||||
{
|
||||
public struct AutoComplete
|
||||
{
|
||||
public string Full => Prefix + Addition;
|
||||
|
||||
public readonly string Prefix;
|
||||
public readonly string Addition;
|
||||
public readonly Contexts Context;
|
||||
|
||||
public Color TextColor => Context == Contexts.Namespace
|
||||
? Color.gray
|
||||
: Color.white;
|
||||
|
||||
public AutoComplete(string addition, string prefix, Contexts type)
|
||||
{
|
||||
Addition = addition;
|
||||
Prefix = prefix;
|
||||
Context = type;
|
||||
}
|
||||
|
||||
public enum Contexts
|
||||
{
|
||||
Namespace,
|
||||
Other
|
||||
}
|
||||
}
|
||||
|
||||
public static class AutoCompleteHelpers
|
||||
{
|
||||
public static HashSet<string> Namespaces => _namespaces ?? GetNamespaces();
|
||||
private static HashSet<string> _namespaces;
|
||||
|
||||
private static HashSet<string> GetNamespaces()
|
||||
{
|
||||
var set = new HashSet<string>(
|
||||
AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(GetTypes)
|
||||
.Where(x => x.IsPublic && !string.IsNullOrEmpty(x.Namespace))
|
||||
.Select(x => x.Namespace));
|
||||
|
||||
return _namespaces = set;
|
||||
|
||||
IEnumerable<Type> GetTypes(Assembly asm) => asm.TryGetTypes();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Mono.CSharp;
|
||||
|
||||
// Thanks to ManlyMarco for this
|
||||
|
||||
namespace Explorer.UI.Main
|
||||
{
|
||||
internal class ScriptEvaluator : Evaluator, IDisposable
|
||||
{
|
||||
private static readonly HashSet<string> StdLib = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
"mscorlib", "System.Core", "System", "System.Xml"
|
||||
};
|
||||
|
||||
private readonly TextWriter _logger;
|
||||
|
||||
public ScriptEvaluator(TextWriter logger) : base(BuildContext(logger))
|
||||
{
|
||||
_logger = logger;
|
||||
|
||||
ImportAppdomainAssemblies(ReferenceAssembly);
|
||||
AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad;
|
||||
_logger.Dispose();
|
||||
}
|
||||
|
||||
private void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args)
|
||||
{
|
||||
string name = args.LoadedAssembly.GetName().Name;
|
||||
if (StdLib.Contains(name))
|
||||
return;
|
||||
ReferenceAssembly(args.LoadedAssembly);
|
||||
}
|
||||
|
||||
private static CompilerContext BuildContext(TextWriter tw)
|
||||
{
|
||||
var reporter = new StreamReportPrinter(tw);
|
||||
|
||||
var settings = new CompilerSettings
|
||||
{
|
||||
Version = LanguageVersion.Experimental,
|
||||
GenerateDebugInfo = false,
|
||||
StdLib = true,
|
||||
Target = Target.Library,
|
||||
WarningLevel = 0,
|
||||
EnhancedWarnings = false
|
||||
};
|
||||
|
||||
return new CompilerContext(settings, reporter);
|
||||
}
|
||||
|
||||
private static void ImportAppdomainAssemblies(Action<Assembly> import)
|
||||
{
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
string name = assembly.GetName().Name;
|
||||
if (StdLib.Contains(name))
|
||||
continue;
|
||||
import(assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Explorer.UI.Inspectors;
|
||||
using Mono.CSharp;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer.UI.Main
|
||||
{
|
||||
public class ScriptInteraction : InteractiveBase
|
||||
{
|
||||
public static void Log(object message)
|
||||
{
|
||||
ExplorerCore.Log(message);
|
||||
}
|
||||
|
||||
public static object CurrentTarget()
|
||||
{
|
||||
if (!WindowManager.TabView)
|
||||
{
|
||||
ExplorerCore.Log("CurrentTarget() is only a valid method when in Tab View mode!");
|
||||
return null;
|
||||
}
|
||||
|
||||
return WindowManager.Windows.ElementAt(TabViewWindow.Instance.TargetTabID).Target;
|
||||
}
|
||||
|
||||
public static object[] AllTargets()
|
||||
{
|
||||
var list = new List<object>();
|
||||
foreach (var window in WindowManager.Windows)
|
||||
{
|
||||
if (window.Target != null)
|
||||
{
|
||||
list.Add(window.Target);
|
||||
}
|
||||
}
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
public static void Inspect(object obj)
|
||||
{
|
||||
WindowManager.InspectObject(obj, out bool _);
|
||||
}
|
||||
|
||||
public static void Inspect(Type type)
|
||||
{
|
||||
WindowManager.InspectStaticReflection(type);
|
||||
}
|
||||
|
||||
public static void Help()
|
||||
{
|
||||
ExplorerCore.Log("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
|
||||
ExplorerCore.Log(" C# Console Help ");
|
||||
ExplorerCore.Log("");
|
||||
ExplorerCore.Log("The following helper methods are available:");
|
||||
ExplorerCore.Log("");
|
||||
ExplorerCore.Log("void Log(object message)");
|
||||
ExplorerCore.Log(" prints a message to the console window and debug log");
|
||||
ExplorerCore.Log(" usage: Log(\"hello world\");");
|
||||
ExplorerCore.Log("");
|
||||
ExplorerCore.Log("object CurrentTarget()");
|
||||
ExplorerCore.Log(" returns the target object of the current tab (in tab view mode only)");
|
||||
ExplorerCore.Log(" usage: var target = CurrentTarget();");
|
||||
ExplorerCore.Log("");
|
||||
ExplorerCore.Log("object[] AllTargets()");
|
||||
ExplorerCore.Log(" returns an object[] array containing all currently inspected objects");
|
||||
ExplorerCore.Log(" usage: var targets = AllTargets();");
|
||||
ExplorerCore.Log("");
|
||||
ExplorerCore.Log("void Inspect(object obj)");
|
||||
ExplorerCore.Log(" inspects the provided object in a new window.");
|
||||
ExplorerCore.Log(" usage: Inspect(Camera.main);");
|
||||
ExplorerCore.Log("");
|
||||
ExplorerCore.Log("void Inspect(Type type)");
|
||||
ExplorerCore.Log(" attempts to inspect the provided type with static-only reflection.");
|
||||
ExplorerCore.Log(" usage: Inspect(typeof(Camera));");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,371 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Mono.CSharp;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
#if CPP
|
||||
using UnhollowerRuntimeLib;
|
||||
using TextEditor = Explorer.Unstrip.IMGUI.TextEditorUnstrip;
|
||||
using Explorer.Unstrip.IMGUI;
|
||||
#endif
|
||||
|
||||
namespace Explorer.UI.Main
|
||||
{
|
||||
public class ConsolePage : BaseMainMenuPage
|
||||
{
|
||||
public static ConsolePage Instance { get; private set; }
|
||||
|
||||
public override string Name { get => "C# Console"; }
|
||||
|
||||
private ScriptEvaluator m_evaluator;
|
||||
|
||||
public const string INPUT_CONTROL_NAME = "consoleInput";
|
||||
private string m_input = "";
|
||||
private string m_prevInput = "";
|
||||
private string m_usingInput = "";
|
||||
|
||||
public static List<AutoComplete> AutoCompletes = new List<AutoComplete>();
|
||||
public static List<string> UsingDirectives;
|
||||
|
||||
private Vector2 inputAreaScroll;
|
||||
private Vector2 autocompleteScroll;
|
||||
public static TextEditor textEditor;
|
||||
private bool shouldRefocus;
|
||||
|
||||
public static GUIStyle AutocompleteStyle => autocompleteStyle ?? GetAutocompleteStyle();
|
||||
private static GUIStyle autocompleteStyle;
|
||||
|
||||
public static readonly string[] DefaultUsing = new string[]
|
||||
{
|
||||
"System",
|
||||
"UnityEngine",
|
||||
"System.Linq",
|
||||
"System.Collections",
|
||||
"System.Collections.Generic",
|
||||
"System.Reflection"
|
||||
};
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
try
|
||||
{
|
||||
m_input = @"// For a list of helper methods, execute the 'Help();' method.
|
||||
// Enable the Console Window with your Mod Loader to see log output.
|
||||
|
||||
Help();";
|
||||
ResetConsole();
|
||||
|
||||
foreach (var use in DefaultUsing)
|
||||
{
|
||||
AddUsing(use);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.LogWarning($"Error setting up console!\r\nMessage: {e.Message}");
|
||||
MainMenu.SetCurrentPage(0);
|
||||
MainMenu.Pages.Remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update() { }
|
||||
|
||||
public string AsmToUsing(string asm, bool richtext = false)
|
||||
{
|
||||
if (richtext)
|
||||
{
|
||||
return $"<color=#569cd6>using</color> {asm};";
|
||||
}
|
||||
return $"using {asm};";
|
||||
}
|
||||
|
||||
public void AddUsing(string asm)
|
||||
{
|
||||
if (!UsingDirectives.Contains(asm))
|
||||
{
|
||||
UsingDirectives.Add(asm);
|
||||
Evaluate(AsmToUsing(asm), true);
|
||||
}
|
||||
}
|
||||
|
||||
public object Evaluate(string str, bool suppressWarning = false)
|
||||
{
|
||||
object ret = VoidType.Value;
|
||||
|
||||
m_evaluator.Compile(str, out var compiled);
|
||||
|
||||
try
|
||||
{
|
||||
if (compiled == null)
|
||||
{
|
||||
throw new Exception("Mono.Csharp Service was unable to compile the code provided.");
|
||||
}
|
||||
|
||||
compiled.Invoke(ref ret);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!suppressWarning)
|
||||
{
|
||||
ExplorerCore.LogWarning(e.GetType() + ", " + e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void ResetConsole()
|
||||
{
|
||||
if (m_evaluator != null)
|
||||
{
|
||||
m_evaluator.Dispose();
|
||||
}
|
||||
|
||||
m_evaluator = new ScriptEvaluator(new StringWriter(new StringBuilder())) { InteractiveBaseClass = typeof(ScriptInteraction) };
|
||||
|
||||
UsingDirectives = new List<string>();
|
||||
}
|
||||
|
||||
|
||||
public override void DrawWindow()
|
||||
{
|
||||
GUILayout.Label("<b><size=15><color=cyan>C# Console</color></size></b>", new GUILayoutOption[0]);
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
|
||||
// SCRIPT INPUT
|
||||
|
||||
GUILayout.Label("Enter code here as though it is a method body:", new GUILayoutOption[0]);
|
||||
|
||||
inputAreaScroll = GUIHelper.BeginScrollView(
|
||||
inputAreaScroll,
|
||||
new GUILayoutOption[] { GUILayout.Height(250), GUIHelper.ExpandHeight(true) }
|
||||
);
|
||||
|
||||
GUI.SetNextControlName(INPUT_CONTROL_NAME);
|
||||
m_input = GUIHelper.TextArea(m_input, new GUILayoutOption[] { GUIHelper.ExpandHeight(true) });
|
||||
|
||||
GUIHelper.EndScrollView();
|
||||
|
||||
// EXECUTE BUTTON
|
||||
|
||||
if (GUILayout.Button("<color=cyan><b>Execute</b></color>", new GUILayoutOption[0]))
|
||||
{
|
||||
try
|
||||
{
|
||||
m_input = m_input.Trim();
|
||||
|
||||
if (!string.IsNullOrEmpty(m_input))
|
||||
{
|
||||
Evaluate(m_input);
|
||||
|
||||
//var result = Evaluate(m_input);
|
||||
|
||||
//if (result != null && !Equals(result, VoidType.Value))
|
||||
//{
|
||||
// ExplorerCore.Log("[Console Output]\r\n" + result.ToString());
|
||||
//}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.LogError("Exception compiling!\r\nMessage: " + e.Message + "\r\nStack: " + e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
// SUGGESTIONS
|
||||
if (AutoCompletes.Count > 0)
|
||||
{
|
||||
autocompleteScroll = GUIHelper.BeginScrollView(autocompleteScroll, new GUILayoutOption[] { GUILayout.Height(150) });
|
||||
|
||||
var origSkin = GUI.skin.button;
|
||||
GUI.skin.button = AutocompleteStyle;
|
||||
|
||||
foreach (var autocomplete in AutoCompletes)
|
||||
{
|
||||
AutocompleteStyle.normal.textColor = autocomplete.TextColor;
|
||||
if (GUILayout.Button(autocomplete.Full, new GUILayoutOption[] { GUILayout.Width(MainMenu.MainRect.width - 50) }))
|
||||
{
|
||||
UseAutocomplete(autocomplete.Addition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GUI.skin.button = origSkin;
|
||||
|
||||
GUIHelper.EndScrollView();
|
||||
}
|
||||
|
||||
if (shouldRefocus)
|
||||
{
|
||||
GUI.FocusControl(INPUT_CONTROL_NAME);
|
||||
shouldRefocus = false;
|
||||
}
|
||||
|
||||
// USING DIRECTIVES
|
||||
|
||||
GUILayout.Label("<b>Using directives:</b>", new GUILayoutOption[0]);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label("Add namespace:", new GUILayoutOption[] { GUILayout.Width(105) });
|
||||
m_usingInput = GUIHelper.TextField(m_usingInput, new GUILayoutOption[] { GUILayout.Width(150) });
|
||||
if (GUILayout.Button("<b><color=lime>Add</color></b>", new GUILayoutOption[] { GUILayout.Width(120) }))
|
||||
{
|
||||
AddUsing(m_usingInput);
|
||||
}
|
||||
if (GUILayout.Button("<b><color=red>Clear All</color></b>", new GUILayoutOption[] { GUILayout.Width(120) }))
|
||||
{
|
||||
ResetConsole();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
foreach (var asm in UsingDirectives)
|
||||
{
|
||||
GUILayout.Label(AsmToUsing(asm, true), new GUILayoutOption[0]);
|
||||
}
|
||||
|
||||
CheckAutocomplete();
|
||||
}
|
||||
|
||||
private void CheckAutocomplete()
|
||||
{
|
||||
// Temporary disabling this check in BepInEx Il2Cpp.
|
||||
#if BIE
|
||||
#if CPP
|
||||
#else
|
||||
if (GUI.GetNameOfFocusedControl() != INPUT_CONTROL_NAME)
|
||||
return;
|
||||
#endif
|
||||
#else
|
||||
if (GUI.GetNameOfFocusedControl() != INPUT_CONTROL_NAME)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#if CPP
|
||||
//textEditor = GUIUtility.GetStateObject(Il2CppType.Of<TextEditor>(), GUIUtility.keyboardControl).TryCast<TextEditor>();
|
||||
textEditor = (TextEditor)GUIUtilityUnstrip.GetMonoStateObject(typeof(TextEditor), GUIUtility.keyboardControl);
|
||||
#else
|
||||
textEditor = (TextEditor)GUIUtility.GetStateObject(typeof(TextEditor), GUIUtility.keyboardControl);
|
||||
#endif
|
||||
|
||||
var input = m_input;
|
||||
|
||||
if (!string.IsNullOrEmpty(input))
|
||||
{
|
||||
try
|
||||
{
|
||||
var splitChars = new[] { ',', ';', '<', '>', '(', ')', '[', ']', '=', '|', '&' };
|
||||
|
||||
// Credit ManlyMarco
|
||||
// Separate input into parts, grab only the part with cursor in it
|
||||
var cursorIndex = textEditor.cursorIndex;
|
||||
var start = cursorIndex <= 0 ? 0 : input.LastIndexOfAny(splitChars, cursorIndex - 1) + 1;
|
||||
var end = cursorIndex <= 0 ? input.Length : input.IndexOfAny(splitChars, cursorIndex - 1);
|
||||
if (end < 0 || end < start) end = input.Length;
|
||||
input = input.Substring(start, end - start);
|
||||
}
|
||||
catch (ArgumentException) { }
|
||||
|
||||
if (!string.IsNullOrEmpty(input) && input != m_prevInput)
|
||||
{
|
||||
GetAutocompletes(input);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearAutocompletes();
|
||||
}
|
||||
|
||||
m_prevInput = input;
|
||||
}
|
||||
|
||||
private void ClearAutocompletes()
|
||||
{
|
||||
if (AutoCompletes.Any())
|
||||
{
|
||||
AutoCompletes.Clear();
|
||||
shouldRefocus = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UseAutocomplete(string suggestion)
|
||||
{
|
||||
int cursorIndex = textEditor.cursorIndex;
|
||||
m_input = m_input.Insert(cursorIndex, suggestion);
|
||||
|
||||
ClearAutocompletes();
|
||||
shouldRefocus = true;
|
||||
}
|
||||
|
||||
private void GetAutocompletes(string input)
|
||||
{
|
||||
try
|
||||
{
|
||||
//ExplorerCore.Log("Fetching suggestions for input " + input);
|
||||
|
||||
// Credit ManylMarco
|
||||
AutoCompletes.Clear();
|
||||
var completions = m_evaluator.GetCompletions(input, out string prefix);
|
||||
if (completions != null)
|
||||
{
|
||||
if (prefix == null)
|
||||
prefix = input;
|
||||
|
||||
AutoCompletes.AddRange(completions
|
||||
.Where(x => !string.IsNullOrEmpty(x))
|
||||
.Select(x => new AutoComplete(x, prefix, AutoComplete.Contexts.Other))
|
||||
);
|
||||
}
|
||||
|
||||
var trimmed = input.Trim();
|
||||
if (trimmed.StartsWith("using"))
|
||||
trimmed = trimmed.Remove(0, 5).Trim();
|
||||
|
||||
var namespaces = AutoCompleteHelpers.Namespaces
|
||||
.Where(x => x.StartsWith(trimmed) && x.Length > trimmed.Length)
|
||||
.Select(x => new AutoComplete(
|
||||
x.Substring(trimmed.Length),
|
||||
x.Substring(0, trimmed.Length),
|
||||
AutoComplete.Contexts.Namespace));
|
||||
|
||||
AutoCompletes.AddRange(namespaces);
|
||||
|
||||
shouldRefocus = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.Log("C# Console error:\r\n" + ex);
|
||||
ClearAutocompletes();
|
||||
}
|
||||
}
|
||||
|
||||
// Credit ManlyMarco
|
||||
private static GUIStyle GetAutocompleteStyle()
|
||||
{
|
||||
var style = new GUIStyle
|
||||
{
|
||||
border = new RectOffset(),
|
||||
margin = new RectOffset(),
|
||||
padding = new RectOffset(),
|
||||
hover = { background = Texture2D.whiteTexture, textColor = Color.black },
|
||||
normal = { background = null },
|
||||
focused = { background = Texture2D.whiteTexture, textColor = Color.black },
|
||||
active = { background = Texture2D.whiteTexture, textColor = Color.black },
|
||||
alignment = TextAnchor.MiddleLeft
|
||||
};
|
||||
|
||||
return autocompleteStyle = style;
|
||||
}
|
||||
|
||||
private class VoidType
|
||||
{
|
||||
public static readonly VoidType Value = new VoidType();
|
||||
private VoidType() { }
|
||||
}
|
||||
}
|
||||
}
|
180
src/UI/Main/MainMenu.cs
Normal file
180
src/UI/Main/MainMenu.cs
Normal file
@ -0,0 +1,180 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ExplorerBeta.UI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
using ExplorerBeta.UI.Shared;
|
||||
|
||||
namespace ExplorerBeta.UI.Main
|
||||
{
|
||||
// TODO REMAKE THIS
|
||||
|
||||
public class MainMenu
|
||||
{
|
||||
public static MainMenu Instance { get; set; }
|
||||
|
||||
public PanelDragger Dragger { get; private set; }
|
||||
public GameObject MainPanel { get; private set; }
|
||||
|
||||
public MainMenu()
|
||||
{
|
||||
if (Instance != null)
|
||||
{
|
||||
ExplorerCore.LogWarning("An instance of MainMenu already exists, cannot create another!");
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
|
||||
MainPanel = CreateBasePanel("MainMenu");
|
||||
CreateTitleBar();
|
||||
CreateNavbar();
|
||||
CreateViewArea();
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void TestButtonCallback()
|
||||
{
|
||||
//if (EventSystem.current != EventSys)
|
||||
// return;
|
||||
|
||||
var go = EventSystem.current.currentSelectedGameObject;
|
||||
if (!go)
|
||||
return;
|
||||
|
||||
var name = go.name;
|
||||
if (go.GetComponentInChildren<Text>() is Text text)
|
||||
{
|
||||
name = text.text;
|
||||
}
|
||||
ExplorerCore.Log($"{Time.time} | Pressed {name ?? "null"}");
|
||||
|
||||
if (name == "X")
|
||||
{
|
||||
ExplorerCore.ShowMenu = false;
|
||||
}
|
||||
}
|
||||
|
||||
#region UI Generator
|
||||
|
||||
public virtual GameObject CreateBasePanel(string name)
|
||||
{
|
||||
var basePanel = UIFactory.CreatePanel(UIManager.CanvasRoot.gameObject, name);
|
||||
var panelRect = basePanel.GetComponent<RectTransform>();
|
||||
panelRect.anchorMin = new Vector2(0.327f, 0.0967f);
|
||||
panelRect.anchorMax = new Vector2(0.672f, 0.904f);
|
||||
panelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 620f);
|
||||
panelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 800f);
|
||||
|
||||
return basePanel;
|
||||
}
|
||||
|
||||
private void CreateTitleBar()
|
||||
{
|
||||
// Make the horizontal group for window title area
|
||||
var titleGroup = UIFactory.CreateHorizontalGroup(MainPanel);
|
||||
var titleRect = titleGroup.GetComponent<RectTransform>();
|
||||
titleRect.anchorMin = new Vector2(0.005f, 0.96f);
|
||||
titleRect.anchorMax = new Vector2(0.995f, 0.994f);
|
||||
titleRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 613);
|
||||
titleRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 30);
|
||||
|
||||
var group = titleGroup.GetComponent<HorizontalLayoutGroup>();
|
||||
group.childControlWidth = true;
|
||||
//group.childScaleWidth = true;
|
||||
group.childForceExpandHeight = true;
|
||||
group.childForceExpandWidth = true;
|
||||
|
||||
// Create window title
|
||||
var titleLabel = UIFactory.CreateLabel(titleGroup, TextAnchor.MiddleCenter);
|
||||
var labelText = titleLabel.GetComponent<Text>();
|
||||
labelText.text = ExplorerCore.NAME;
|
||||
labelText.fontSize = 15;
|
||||
var labelRect = labelText.GetComponent<RectTransform>();
|
||||
labelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 575);
|
||||
labelRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 25);
|
||||
|
||||
// Add drag handler (on Title label)
|
||||
Dragger = new PanelDragger(titleLabel.transform.TryCast<RectTransform>(),
|
||||
MainPanel.GetComponent<RectTransform>());
|
||||
|
||||
// Create X Button
|
||||
var exitBtnObj = UIFactory.CreateButton(titleGroup);
|
||||
var exitBtn = exitBtnObj.GetComponentInChildren<Button>();
|
||||
exitBtn.onClick.AddListener(new Action(TestButtonCallback));
|
||||
var exitBtnText = exitBtnObj.GetComponentInChildren<Text>();
|
||||
exitBtnText.text = "X";
|
||||
exitBtnText.fontSize = 14;
|
||||
var exitBtnRect = exitBtnObj.GetComponent<RectTransform>();
|
||||
exitBtnRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 40f);
|
||||
exitBtnRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 25f);
|
||||
}
|
||||
|
||||
private void CreateNavbar()
|
||||
{
|
||||
// Make the horizontal group for the nav bar
|
||||
var navArea = UIFactory.CreateHorizontalGroup(MainPanel);
|
||||
var group = navArea.GetComponent<HorizontalLayoutGroup>();
|
||||
group.childAlignment = TextAnchor.MiddleLeft;
|
||||
group.spacing = 5;
|
||||
group.childForceExpandWidth = true;
|
||||
group.childForceExpandHeight = true;
|
||||
group.childControlWidth = true;
|
||||
group.spacing = 5;
|
||||
|
||||
var padding = new RectOffset();
|
||||
padding.left = 5;
|
||||
padding.right = 5;
|
||||
padding.top = 3;
|
||||
padding.bottom = 3;
|
||||
group.padding = padding;
|
||||
|
||||
var navRect = navArea.GetComponent<RectTransform>();
|
||||
navRect.anchorMin = new Vector2(0.005f, 0.93f);
|
||||
navRect.anchorMax = new Vector2(0.995f, 0.97f);
|
||||
var pos = navRect.localPosition;
|
||||
pos.y = 348;
|
||||
navRect.localPosition = pos;
|
||||
navRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 613);
|
||||
navRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 30);
|
||||
|
||||
// Add the buttons for pages (this should be done programmatically)
|
||||
var names = new string[] { "Scenes", "Search", "C# Console", "Options" };
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
var btn = UIFactory.CreateButton(navArea);
|
||||
var text = btn.GetComponentInChildren<Text>();
|
||||
text.text = names[i];
|
||||
|
||||
btn.GetComponent<Button>().onClick.AddListener(new Action(TestButtonCallback));
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
var image = btn.GetComponentInChildren<Image>();
|
||||
image.color = new Color(0.1f, 0.35f, 0.1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateViewArea()
|
||||
{
|
||||
// Make the vertical group for the viewport
|
||||
var viewGroup = UIFactory.CreateVerticalGroup(MainPanel);
|
||||
var viewRect = viewGroup.GetComponent<RectTransform>();
|
||||
viewRect.anchorMin = new Vector2(0.005f, -0.038f);
|
||||
viewRect.anchorMax = new Vector2(0.995f, 0.954f);
|
||||
viewRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 613);
|
||||
viewRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 720f);
|
||||
viewRect.localPosition = new Vector3(0, -35f, 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.Config;
|
||||
using Explorer.CacheObject;
|
||||
|
||||
namespace Explorer.UI.Main
|
||||
{
|
||||
public class OptionsPage : BaseMainMenuPage
|
||||
{
|
||||
public override string Name => "Options";
|
||||
|
||||
public string toggleKeyInputString = "";
|
||||
public Vector2 defaultSizeInputVector;
|
||||
public int defaultPageLimit;
|
||||
public bool bitwiseSupport;
|
||||
public bool tabView;
|
||||
public string defaultOutputPath;
|
||||
|
||||
private CacheObjectBase toggleKeyInput;
|
||||
private CacheObjectBase defaultSizeInput;
|
||||
private CacheObjectBase defaultPageLimitInput;
|
||||
private CacheObjectBase bitwiseSupportInput;
|
||||
private CacheObjectBase tabViewInput;
|
||||
private CacheObjectBase defaultOutputPathInput;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
toggleKeyInputString = ModConfig.Instance.Main_Menu_Toggle.ToString();
|
||||
toggleKeyInput = CacheFactory.GetCacheObject(typeof(OptionsPage).GetField("toggleKeyInputString"), this);
|
||||
|
||||
defaultSizeInputVector = ModConfig.Instance.Default_Window_Size;
|
||||
defaultSizeInput = CacheFactory.GetCacheObject(typeof(OptionsPage).GetField("defaultSizeInputVector"), this);
|
||||
|
||||
defaultPageLimit = ModConfig.Instance.Default_Page_Limit;
|
||||
defaultPageLimitInput = CacheFactory.GetCacheObject(typeof(OptionsPage).GetField("defaultPageLimit"), this);
|
||||
|
||||
bitwiseSupport = ModConfig.Instance.Bitwise_Support;
|
||||
bitwiseSupportInput = CacheFactory.GetCacheObject(typeof(OptionsPage).GetField("bitwiseSupport"), this);
|
||||
|
||||
tabView = ModConfig.Instance.Tab_View;
|
||||
tabViewInput = CacheFactory.GetCacheObject(typeof(OptionsPage).GetField("tabView"), this);
|
||||
|
||||
defaultOutputPath = ModConfig.Instance.Default_Output_Path;
|
||||
defaultOutputPathInput = CacheFactory.GetCacheObject(typeof(OptionsPage).GetField("defaultOutputPath"), this);
|
||||
}
|
||||
|
||||
public override void Update() { }
|
||||
|
||||
public override void DrawWindow()
|
||||
{
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||
GUILayout.Label("<color=orange><size=16><b>Options</b></size></color>", new GUILayoutOption[0]);
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleLeft;
|
||||
|
||||
GUIHelper.BeginVertical(GUIContent.none, GUI.skin.box, new GUILayoutOption[0]);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label($"Menu Toggle Key:", new GUILayoutOption[] { GUILayout.Width(215f) });
|
||||
toggleKeyInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
UIStyles.HorizontalLine(Color.black, true);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label($"Default Window Size:", new GUILayoutOption[] { GUILayout.Width(215f) });
|
||||
defaultSizeInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
UIStyles.HorizontalLine(Color.black, true);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label($"Default Items per Page:", new GUILayoutOption[] { GUILayout.Width(215f) });
|
||||
defaultPageLimitInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
UIStyles.HorizontalLine(Color.black, true);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label($"Enable Bitwise Editing:", new GUILayoutOption[] { GUILayout.Width(215f) });
|
||||
bitwiseSupportInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
UIStyles.HorizontalLine(Color.black, true);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label($"Enable Tab View:", new GUILayoutOption[] { GUILayout.Width(215f) });
|
||||
tabViewInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
UIStyles.HorizontalLine(Color.black, true);
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label($"Default Output Path:", new GUILayoutOption[] { GUILayout.Width(215f) });
|
||||
defaultOutputPathInput.IValue.DrawValue(MainMenu.MainRect, MainMenu.MainRect.width - 215f);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (GUILayout.Button("<color=lime><b>Apply and Save</b></color>", new GUILayoutOption[0]))
|
||||
{
|
||||
ApplyAndSave();
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUIHelper.Space(10f);
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||
GUILayout.Label("<color=orange><size=16><b>Other</b></size></color>", new GUILayoutOption[0]);
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleLeft;
|
||||
|
||||
GUIHelper.BeginVertical(GUIContent.none, GUI.skin.box, new GUILayoutOption[0]);
|
||||
|
||||
if (GUILayout.Button("Inspect Test Class", new GUILayoutOption[0]))
|
||||
{
|
||||
WindowManager.InspectObject(Tests.TestClass.Instance, out bool _);
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void ApplyAndSave()
|
||||
{
|
||||
if (Enum.Parse(typeof(KeyCode), toggleKeyInputString) is KeyCode key)
|
||||
{
|
||||
ModConfig.Instance.Main_Menu_Toggle = key;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExplorerCore.LogWarning($"Could not parse '{toggleKeyInputString}' to KeyCode!");
|
||||
}
|
||||
|
||||
ModConfig.Instance.Default_Window_Size = defaultSizeInputVector;
|
||||
ModConfig.Instance.Default_Page_Limit = defaultPageLimit;
|
||||
ModConfig.Instance.Bitwise_Support = bitwiseSupport;
|
||||
|
||||
ModConfig.Instance.Tab_View = tabView;
|
||||
WindowManager.TabView = tabView;
|
||||
|
||||
ModConfig.SaveSettings();
|
||||
}
|
||||
}
|
||||
}
|
390
src/UI/Main/PanelDragger.cs
Normal file
390
src/UI/Main/PanelDragger.cs
Normal file
@ -0,0 +1,390 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
using ExplorerBeta.Input;
|
||||
using ExplorerBeta.Helpers;
|
||||
using ExplorerBeta.Unstrip.ImageConversion;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace ExplorerBeta.UI
|
||||
{
|
||||
// Handles dragging and resizing for the main explorer window.
|
||||
|
||||
public class PanelDragger
|
||||
{
|
||||
public static PanelDragger Instance { get; private set; }
|
||||
|
||||
public RectTransform Panel { get; set; }
|
||||
|
||||
public PanelDragger(RectTransform dragArea, RectTransform panelToDrag)
|
||||
{
|
||||
Instance = this;
|
||||
DragableArea = dragArea;
|
||||
Panel = panelToDrag;
|
||||
|
||||
UpdateResizeCache();
|
||||
|
||||
try
|
||||
{
|
||||
var path = @"Mods\Explorer\cursor.png";
|
||||
var data = File.ReadAllBytes(path);
|
||||
|
||||
var tex = new Texture2D(32, 32);
|
||||
tex.LoadImage(data, false);
|
||||
UnityEngine.Object.DontDestroyOnLoad(tex);
|
||||
|
||||
var size = new Rect();
|
||||
size.width = 32;
|
||||
size.height = 32;
|
||||
var sprite = UIManager.CreateSprite(tex, size);
|
||||
UnityEngine.Object.DontDestroyOnLoad(sprite);
|
||||
|
||||
m_resizeCursorImage = new GameObject("ResizeCursorImage");
|
||||
m_resizeCursorImage.transform.SetParent(UIManager.CanvasRoot.transform);
|
||||
|
||||
var image = m_resizeCursorImage.AddComponent<Image>();
|
||||
image.sprite = sprite;
|
||||
var rect = image.transform.TryCast<RectTransform>();
|
||||
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 32);
|
||||
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 32);
|
||||
|
||||
m_resizeCursorImage.SetActive(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.Log("Exception loading resize cursor: " + e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
var rawMousePos = InputManager.MousePosition;
|
||||
|
||||
var resizePos = Panel.InverseTransformPoint(rawMousePos);
|
||||
var dragPos = DragableArea.InverseTransformPoint(rawMousePos);
|
||||
|
||||
if (m_wasHoveringResize)
|
||||
{
|
||||
UpdateHoverImagePos();
|
||||
}
|
||||
|
||||
// If Mouse pressed this frame
|
||||
if (InputManager.GetMouseButtonDown(0))
|
||||
{
|
||||
if (DragableArea.rect.Contains(dragPos))
|
||||
{
|
||||
OnBeginDrag();
|
||||
return;
|
||||
}
|
||||
else if (MouseInResizeArea(resizePos))
|
||||
{
|
||||
var type = GetResizeType(resizePos);
|
||||
OnBeginResize(type);
|
||||
}
|
||||
}
|
||||
// If mouse still pressed from last frame
|
||||
else if (InputManager.GetMouseButton(0))
|
||||
{
|
||||
if (WasDragging)
|
||||
{
|
||||
OnDrag();
|
||||
}
|
||||
else if (WasResizing)
|
||||
{
|
||||
OnResize();
|
||||
}
|
||||
}
|
||||
// If mouse not pressed
|
||||
else
|
||||
{
|
||||
if (WasDragging)
|
||||
{
|
||||
OnEndDrag();
|
||||
}
|
||||
else if (WasResizing)
|
||||
{
|
||||
OnEndResize();
|
||||
}
|
||||
else if (MouseInResizeArea(resizePos))
|
||||
{
|
||||
var type = GetResizeType(resizePos);
|
||||
OnHoverResize(type);
|
||||
}
|
||||
else if (m_wasHoveringResize)
|
||||
{
|
||||
OnHoverResizeEnd();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#region DRAGGING
|
||||
|
||||
public RectTransform DragableArea { get; set; }
|
||||
public bool WasDragging { get; set; }
|
||||
private Vector3 m_lastDragPosition;
|
||||
|
||||
public void OnBeginDrag()
|
||||
{
|
||||
WasDragging = true;
|
||||
m_lastDragPosition = InputManager.MousePosition;
|
||||
}
|
||||
|
||||
public void OnDrag()
|
||||
{
|
||||
var diff = InputManager.MousePosition - m_lastDragPosition;
|
||||
m_lastDragPosition = InputManager.MousePosition;
|
||||
|
||||
var pos = Panel.localPosition;
|
||||
var z = pos.z;
|
||||
pos += diff;
|
||||
pos.z = z;
|
||||
Panel.localPosition = pos;
|
||||
}
|
||||
|
||||
public void OnEndDrag()
|
||||
{
|
||||
WasDragging = false;
|
||||
UpdateResizeCache();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RESIZE
|
||||
|
||||
private const int RESIZE_THICKNESS = 10;
|
||||
private bool WasResizing { get; set; }
|
||||
private ResizeTypes m_currentResizeType = ResizeTypes.NONE;
|
||||
private Vector2 m_lastMousePos;
|
||||
|
||||
private bool m_wasHoveringResize;
|
||||
private ResizeTypes m_lastResizeHoverType;
|
||||
private GameObject m_resizeCursorImage;
|
||||
|
||||
private Rect m_outerResize;
|
||||
private Rect m_innerResize;
|
||||
private readonly Dictionary<ResizeTypes, Rect> m_cachedResizeAreas = new Dictionary<ResizeTypes, Rect>
|
||||
{
|
||||
{ ResizeTypes.Top, Rect.zero },
|
||||
{ ResizeTypes.Left, Rect.zero },
|
||||
{ ResizeTypes.Right, Rect.zero },
|
||||
{ ResizeTypes.Bottom, Rect.zero },
|
||||
{ ResizeTypes.TopLeft, Rect.zero },
|
||||
{ ResizeTypes.TopRight, Rect.zero },
|
||||
{ ResizeTypes.BottomLeft, Rect.zero },
|
||||
{ ResizeTypes.BottomRight, Rect.zero },
|
||||
};
|
||||
|
||||
[Flags]
|
||||
public enum ResizeTypes
|
||||
{
|
||||
NONE = 0,
|
||||
Top = 1,
|
||||
Left = 2,
|
||||
Right = 4,
|
||||
Bottom = 8,
|
||||
TopLeft = Top | Left,
|
||||
TopRight = Top | Right,
|
||||
BottomLeft = Bottom | Left,
|
||||
BottomRight = Bottom | Right,
|
||||
}
|
||||
|
||||
private void UpdateHoverImagePos()
|
||||
{
|
||||
if (!m_resizeCursorImage)
|
||||
return;
|
||||
|
||||
m_resizeCursorImage.transform.localPosition = UIManager.CanvasRoot.transform.TryCast<RectTransform>()
|
||||
.InverseTransformPoint(InputManager.MousePosition);
|
||||
}
|
||||
|
||||
private void UpdateResizeCache()
|
||||
{
|
||||
int halfThick = RESIZE_THICKNESS / 2;
|
||||
|
||||
// calculate main two rects
|
||||
|
||||
this.m_outerResize = new Rect();
|
||||
m_outerResize.x = Panel.rect.x - halfThick;
|
||||
m_outerResize.y = Panel.rect.y - halfThick;
|
||||
m_outerResize.width = Panel.rect.width + (RESIZE_THICKNESS * 2);
|
||||
m_outerResize.height = Panel.rect.height + (RESIZE_THICKNESS * 2);
|
||||
|
||||
this.m_innerResize = new Rect();
|
||||
m_innerResize.x = m_outerResize.x + RESIZE_THICKNESS;
|
||||
m_innerResize.y = m_outerResize.y + RESIZE_THICKNESS;
|
||||
m_innerResize.width = Panel.rect.width - RESIZE_THICKNESS;
|
||||
m_innerResize.height = Panel.rect.height - RESIZE_THICKNESS;
|
||||
|
||||
// calculate resize areas
|
||||
|
||||
var left = m_cachedResizeAreas[ResizeTypes.Left];
|
||||
left.x = m_outerResize.x;
|
||||
left.y = m_outerResize.y + RESIZE_THICKNESS;
|
||||
left.width = RESIZE_THICKNESS;
|
||||
left.height = m_innerResize.height - RESIZE_THICKNESS;
|
||||
m_cachedResizeAreas[ResizeTypes.Left] = left;
|
||||
|
||||
var topLeft = m_cachedResizeAreas[ResizeTypes.TopLeft];
|
||||
topLeft.x = m_outerResize.x;
|
||||
topLeft.y = m_innerResize.y + m_innerResize.height;
|
||||
topLeft.width = RESIZE_THICKNESS;
|
||||
topLeft.height = RESIZE_THICKNESS;
|
||||
m_cachedResizeAreas[ResizeTypes.TopLeft] = topLeft;
|
||||
|
||||
var top = m_cachedResizeAreas[ResizeTypes.Top];
|
||||
top.x = m_innerResize.x;
|
||||
top.y = m_innerResize.y + m_innerResize.height;
|
||||
top.width = m_innerResize.width;
|
||||
top.height = RESIZE_THICKNESS;
|
||||
m_cachedResizeAreas[ResizeTypes.Top] = top;
|
||||
|
||||
var topRight = m_cachedResizeAreas[ResizeTypes.TopRight];
|
||||
topRight.x = m_innerResize.x + m_innerResize.width;
|
||||
topRight.y = m_innerResize.y + m_innerResize.height;
|
||||
topRight.width = RESIZE_THICKNESS;
|
||||
topRight.height = RESIZE_THICKNESS;
|
||||
m_cachedResizeAreas[ResizeTypes.TopRight] = topRight;
|
||||
|
||||
var right = m_cachedResizeAreas[ResizeTypes.Right];
|
||||
right.x = m_innerResize.x + m_innerResize.width;
|
||||
right.y = m_innerResize.y + halfThick;
|
||||
right.width = RESIZE_THICKNESS;
|
||||
right.height = m_innerResize.height - RESIZE_THICKNESS;
|
||||
m_cachedResizeAreas[ResizeTypes.Right] = right;
|
||||
|
||||
var bottomRight = m_cachedResizeAreas[ResizeTypes.BottomRight];
|
||||
bottomRight.x = m_innerResize.x + m_innerResize.width;
|
||||
bottomRight.y = m_outerResize.y;
|
||||
bottomRight.width = RESIZE_THICKNESS;
|
||||
bottomRight.height = RESIZE_THICKNESS;
|
||||
m_cachedResizeAreas[ResizeTypes.BottomRight] = bottomRight;
|
||||
|
||||
var bottom = m_cachedResizeAreas[ResizeTypes.Bottom];
|
||||
bottom.x = m_innerResize.x;
|
||||
bottom.y = m_outerResize.y;
|
||||
bottom.width = m_innerResize.width;
|
||||
bottom.height = RESIZE_THICKNESS;
|
||||
m_cachedResizeAreas[ResizeTypes.Bottom] = bottom;
|
||||
|
||||
var bottomLeft = m_cachedResizeAreas[ResizeTypes.BottomLeft];
|
||||
bottomLeft.x = m_outerResize.x;
|
||||
bottomLeft.y = m_outerResize.y;
|
||||
bottomLeft.width = RESIZE_THICKNESS;
|
||||
bottomLeft.height = RESIZE_THICKNESS;
|
||||
m_cachedResizeAreas[ResizeTypes.BottomLeft] = bottomLeft;
|
||||
}
|
||||
|
||||
private bool MouseInResizeArea(Vector2 mousePos)
|
||||
{
|
||||
return m_outerResize.Contains(mousePos) && !m_innerResize.Contains(mousePos);
|
||||
}
|
||||
|
||||
private ResizeTypes GetResizeType(Vector2 mousePos)
|
||||
{
|
||||
foreach (var entry in m_cachedResizeAreas)
|
||||
{
|
||||
if (entry.Value.Contains(mousePos))
|
||||
{
|
||||
return entry.Key;
|
||||
}
|
||||
}
|
||||
return ResizeTypes.NONE;
|
||||
}
|
||||
|
||||
public void OnHoverResize(ResizeTypes resizeType)
|
||||
{
|
||||
if (m_wasHoveringResize && m_lastResizeHoverType == resizeType)
|
||||
return;
|
||||
|
||||
// we are entering resize, or the resize type has changed.
|
||||
|
||||
m_wasHoveringResize = true;
|
||||
m_lastResizeHoverType = resizeType;
|
||||
|
||||
m_resizeCursorImage.SetActive(true);
|
||||
|
||||
float rotation = 0;
|
||||
switch (resizeType)
|
||||
{
|
||||
case ResizeTypes.TopRight:
|
||||
case ResizeTypes.BottomLeft:
|
||||
rotation = 45f; break;
|
||||
case ResizeTypes.Top:
|
||||
case ResizeTypes.Bottom:
|
||||
rotation = 90f; break;
|
||||
case ResizeTypes.TopLeft:
|
||||
case ResizeTypes.BottomRight:
|
||||
rotation = 135f; break;
|
||||
}
|
||||
|
||||
var rot = m_resizeCursorImage.transform.rotation;
|
||||
rot.eulerAngles = new Vector3(0, 0, rotation);
|
||||
m_resizeCursorImage.transform.rotation = rot;
|
||||
|
||||
UpdateHoverImagePos();
|
||||
}
|
||||
|
||||
public void OnHoverResizeEnd()
|
||||
{
|
||||
m_wasHoveringResize = false;
|
||||
m_resizeCursorImage.SetActive(false);
|
||||
}
|
||||
|
||||
public void OnBeginResize(ResizeTypes resizeType)
|
||||
{
|
||||
m_currentResizeType = resizeType;
|
||||
m_lastMousePos = InputManager.MousePosition;
|
||||
WasResizing = true;
|
||||
}
|
||||
|
||||
public void OnResize()
|
||||
{
|
||||
var mousePos = InputManager.MousePosition;
|
||||
var diff = m_lastMousePos - (Vector2)mousePos;
|
||||
m_lastMousePos = mousePos;
|
||||
|
||||
var diffX = (float)((decimal)diff.x / Screen.width);
|
||||
var diffY = (float)((decimal)diff.y / Screen.height);
|
||||
|
||||
if (m_currentResizeType.HasFlag(ResizeTypes.Left))
|
||||
{
|
||||
var anch = Panel.anchorMin;
|
||||
anch.x -= diffX;
|
||||
Panel.anchorMin = anch;
|
||||
}
|
||||
else if (m_currentResizeType.HasFlag(ResizeTypes.Right))
|
||||
{
|
||||
var anch = Panel.anchorMax;
|
||||
anch.x -= diffX;
|
||||
Panel.anchorMax = anch;
|
||||
}
|
||||
|
||||
if (m_currentResizeType.HasFlag(ResizeTypes.Top))
|
||||
{
|
||||
var anch = Panel.anchorMax;
|
||||
anch.y -= diffY;
|
||||
Panel.anchorMax = anch;
|
||||
}
|
||||
else if (m_currentResizeType.HasFlag(ResizeTypes.Bottom))
|
||||
{
|
||||
var anch = Panel.anchorMin;
|
||||
anch.y -= diffY;
|
||||
Panel.anchorMin = anch;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnEndResize()
|
||||
{
|
||||
WasResizing = false;
|
||||
UpdateResizeCache();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,374 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
using Explorer.Helpers;
|
||||
using Explorer.Unstrip.Resources;
|
||||
|
||||
namespace Explorer.UI.Main
|
||||
{
|
||||
public class ScenePage : BaseMainMenuPage
|
||||
{
|
||||
public static ScenePage Instance;
|
||||
|
||||
public override string Name { get => "Scenes"; }
|
||||
|
||||
public PageHelper Pages = new PageHelper();
|
||||
|
||||
private float m_timeOfLastUpdate = -1f;
|
||||
private const int PASSIVE_UPDATE_INTERVAL = 1;
|
||||
|
||||
private static string m_currentScene = "";
|
||||
|
||||
// gameobject list
|
||||
private Transform m_currentTransform;
|
||||
private readonly List<CacheObjectBase> m_objectList = new List<CacheObjectBase>();
|
||||
|
||||
// search bar
|
||||
private bool m_searching = false;
|
||||
private string m_searchInput = "";
|
||||
private List<CacheObjectBase> m_searchResults = new List<CacheObjectBase>();
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public void OnSceneChange()
|
||||
{
|
||||
m_currentScene = UnityHelpers.ActiveSceneName;
|
||||
SetTransformTarget(null);
|
||||
}
|
||||
|
||||
public void SetTransformTarget(Transform t)
|
||||
{
|
||||
m_currentTransform = t;
|
||||
|
||||
if (m_searching)
|
||||
CancelSearch();
|
||||
|
||||
Update_Impl();
|
||||
}
|
||||
|
||||
public void TraverseUp()
|
||||
{
|
||||
if (m_currentTransform.parent != null)
|
||||
{
|
||||
SetTransformTarget(m_currentTransform.parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetTransformTarget(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void Search()
|
||||
{
|
||||
m_searchResults = SearchSceneObjects(m_searchInput);
|
||||
m_searching = true;
|
||||
Pages.ItemCount = m_searchResults.Count;
|
||||
}
|
||||
|
||||
public void CancelSearch()
|
||||
{
|
||||
m_searching = false;
|
||||
}
|
||||
|
||||
public List<CacheObjectBase> SearchSceneObjects(string _search)
|
||||
{
|
||||
var matches = new List<CacheObjectBase>();
|
||||
|
||||
foreach (var obj in ResourcesUnstrip.FindObjectsOfTypeAll(ReflectionHelpers.GameObjectType))
|
||||
{
|
||||
#if CPP
|
||||
var go = obj.TryCast<GameObject>();
|
||||
#else
|
||||
var go = obj as GameObject;
|
||||
#endif
|
||||
if (go.name.ToLower().Contains(_search.ToLower()) && go.scene.name == m_currentScene)
|
||||
{
|
||||
matches.Add(CacheFactory.GetCacheObject(go));
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (m_searching) return;
|
||||
|
||||
if (Time.time - m_timeOfLastUpdate < PASSIVE_UPDATE_INTERVAL) return;
|
||||
m_timeOfLastUpdate = Time.time;
|
||||
|
||||
Update_Impl();
|
||||
}
|
||||
|
||||
private void Update_Impl()
|
||||
{
|
||||
List<Transform> allTransforms = new List<Transform>();
|
||||
|
||||
// get current list of all transforms (either scene root or our current transform children)
|
||||
if (m_currentTransform)
|
||||
{
|
||||
for (int i = 0; i < m_currentTransform.childCount; i++)
|
||||
{
|
||||
allTransforms.Add(m_currentTransform.GetChild(i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
var scene = SceneManager.GetSceneAt(i);
|
||||
|
||||
if (scene.name == m_currentScene)
|
||||
{
|
||||
var rootObjects =
|
||||
#if CPP
|
||||
Unstrip.Scenes.SceneUnstrip.GetRootGameObjects(scene)
|
||||
.Select(it => it.transform);
|
||||
#else
|
||||
scene.GetRootGameObjects().Select(it => it.transform);
|
||||
#endif
|
||||
allTransforms.AddRange(rootObjects);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pages.ItemCount = allTransforms.Count;
|
||||
|
||||
int offset = Pages.CalculateOffsetIndex();
|
||||
|
||||
// sort by childcount
|
||||
allTransforms.Sort((a, b) => b.childCount.CompareTo(a.childCount));
|
||||
|
||||
m_objectList.Clear();
|
||||
|
||||
for (int i = offset; i < offset + Pages.ItemsPerPage && i < Pages.ItemCount; i++)
|
||||
{
|
||||
var child = allTransforms[i];
|
||||
m_objectList.Add(CacheFactory.GetCacheObject(child));
|
||||
}
|
||||
}
|
||||
|
||||
// --------- GUI Draw Function --------- //
|
||||
|
||||
public override void DrawWindow()
|
||||
{
|
||||
try
|
||||
{
|
||||
DrawHeaderArea();
|
||||
|
||||
GUIHelper.BeginVertical(GUIContent.none, GUI.skin.box, null);
|
||||
|
||||
DrawPageButtons();
|
||||
|
||||
if (!m_searching)
|
||||
{
|
||||
DrawGameObjectList();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSearchResultsList();
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!e.Message.Contains("in a group with only"))
|
||||
{
|
||||
ExplorerCore.Log(e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawHeaderArea()
|
||||
{
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
// Current Scene label
|
||||
GUILayout.Label("Current Scene:", new GUILayoutOption[] { GUILayout.Width(120) });
|
||||
SceneChangeButtons();
|
||||
GUILayout.Label("<color=cyan>" + m_currentScene + "</color>", new GUILayoutOption[0]);
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// ----- GameObject Search -----
|
||||
GUIHelper.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
|
||||
GUILayout.Label("<b>Search Scene:</b>", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||
|
||||
m_searchInput = GUIHelper.TextField(m_searchInput, new GUILayoutOption[0]);
|
||||
|
||||
if (GUILayout.Button("Search", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
Search();
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.Space(5);
|
||||
}
|
||||
|
||||
private void SceneChangeButtons()
|
||||
{
|
||||
var scenes = new List<Scene>();
|
||||
var names = new List<string>();
|
||||
for (int i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
var scene = SceneManager.GetSceneAt(i);
|
||||
names.Add(scene.name);
|
||||
scenes.Add(scene);
|
||||
}
|
||||
|
||||
if (scenes.Count > 1)
|
||||
{
|
||||
int changeWanted = 0;
|
||||
if (GUILayout.Button("<", new GUILayoutOption[] { GUILayout.Width(30) }))
|
||||
{
|
||||
changeWanted = -1;
|
||||
}
|
||||
if (GUILayout.Button(">", new GUILayoutOption[] { GUILayout.Width(30) }))
|
||||
{
|
||||
changeWanted = 1;
|
||||
}
|
||||
if (changeWanted != 0)
|
||||
{
|
||||
int index = names.IndexOf(m_currentScene);
|
||||
index += changeWanted;
|
||||
|
||||
if (index >= 0 && index < SceneManager.sceneCount)
|
||||
{
|
||||
m_currentScene = scenes[index].name;
|
||||
Update_Impl();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPageButtons()
|
||||
{
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
Pages.DrawLimitInputArea();
|
||||
|
||||
if (Pages.ItemCount > Pages.ItemsPerPage)
|
||||
{
|
||||
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
Pages.TurnPage(Turn.Left, ref this.scroll);
|
||||
|
||||
Update_Impl();
|
||||
}
|
||||
|
||||
Pages.CurrentPageLabel();
|
||||
|
||||
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
Pages.TurnPage(Turn.Right, ref this.scroll);
|
||||
|
||||
Update_Impl();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
}
|
||||
|
||||
private void DrawGameObjectList()
|
||||
{
|
||||
if (m_currentTransform != null)
|
||||
{
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
if (GUILayout.Button("<-", new GUILayoutOption[] { GUILayout.Width(35) }))
|
||||
{
|
||||
TraverseUp();
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("<color=cyan>" + m_currentTransform.GetGameObjectPath() + "</color>",
|
||||
new GUILayoutOption[] { GUILayout.Width(MainMenu.MainRect.width - 187f) });
|
||||
}
|
||||
|
||||
Buttons.InspectButton(m_currentTransform);
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("Scene Root GameObjects:", new GUILayoutOption[0]);
|
||||
}
|
||||
|
||||
if (m_objectList.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < m_objectList.Count; i++)
|
||||
{
|
||||
var obj = m_objectList[i];
|
||||
|
||||
if (obj == null) continue;
|
||||
|
||||
try
|
||||
{
|
||||
var go = obj.IValue.Value as GameObject ?? (obj.IValue.Value as Transform)?.gameObject;
|
||||
|
||||
if (!go)
|
||||
{
|
||||
string label = "<color=red><i>null";
|
||||
|
||||
if (go != null)
|
||||
{
|
||||
label += " (Destroyed)";
|
||||
}
|
||||
|
||||
label += "</i></color>";
|
||||
GUILayout.Label(label, new GUILayoutOption[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buttons.GameObjectButton(go, SetTransformTarget, true, MainMenu.MainRect.width - 170f);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSearchResultsList()
|
||||
{
|
||||
if (GUILayout.Button("<- Cancel Search", new GUILayoutOption[] { GUILayout.Width(150) }))
|
||||
{
|
||||
CancelSearch();
|
||||
}
|
||||
|
||||
GUILayout.Label("Search Results:", new GUILayoutOption[0]);
|
||||
|
||||
if (m_searchResults.Count > 0)
|
||||
{
|
||||
int offset = Pages.CalculateOffsetIndex();
|
||||
|
||||
for (int i = offset; i < offset + Pages.ItemsPerPage && i < m_searchResults.Count; i++)
|
||||
{
|
||||
var obj = m_searchResults[i].IValue.Value as GameObject;
|
||||
|
||||
if (obj)
|
||||
{
|
||||
Buttons.GameObjectButton(obj, SetTransformTarget, true, MainMenu.MainRect.width - 170);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("<i><color=red>Null or destroyed!</color></i>", new GUILayoutOption[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("<color=red><i>No results found!</i></color>", new GUILayoutOption[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,544 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.CacheObject;
|
||||
using Explorer.Helpers;
|
||||
using Explorer.Unstrip.Resources;
|
||||
|
||||
namespace Explorer.UI.Main
|
||||
{
|
||||
public class SearchPage : BaseMainMenuPage
|
||||
{
|
||||
public static SearchPage Instance;
|
||||
|
||||
public override string Name { get => "Search"; }
|
||||
|
||||
private int MaxSearchResults = 5000;
|
||||
|
||||
private string m_searchInput = "";
|
||||
private string m_typeInput = "";
|
||||
|
||||
//private bool m_cachingResults;
|
||||
|
||||
private Vector2 resultsScroll = Vector2.zero;
|
||||
|
||||
public PageHelper Pages = new PageHelper();
|
||||
|
||||
private List<CacheObjectBase> m_searchResults = new List<CacheObjectBase>();
|
||||
|
||||
public SceneFilter SceneMode = SceneFilter.Any;
|
||||
public TypeFilter TypeMode = TypeFilter.Object;
|
||||
|
||||
public enum SceneFilter
|
||||
{
|
||||
Any,
|
||||
This,
|
||||
DontDestroy,
|
||||
None
|
||||
}
|
||||
|
||||
public enum TypeFilter
|
||||
{
|
||||
Object,
|
||||
GameObject,
|
||||
Component,
|
||||
Custom
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public void OnSceneChange()
|
||||
{
|
||||
m_searchResults.Clear();
|
||||
Pages.PageOffset = 0;
|
||||
}
|
||||
|
||||
public override void Update() { }
|
||||
|
||||
private void CacheResults(IEnumerable results, bool isStaticClasses = false)
|
||||
{
|
||||
//m_cachingResults = true;
|
||||
|
||||
m_searchResults = new List<CacheObjectBase>();
|
||||
|
||||
foreach (var obj in results)
|
||||
{
|
||||
var toCache = obj;
|
||||
|
||||
#if CPP
|
||||
if (toCache is Il2CppSystem.Object ilObject)
|
||||
{
|
||||
var type = ReflectionHelpers.GetActualType(ilObject);
|
||||
ilObject = (Il2CppSystem.Object)ilObject.Il2CppCast(type);
|
||||
|
||||
toCache = ilObject.TryCast<GameObject>() ?? ilObject.TryCast<Transform>()?.gameObject ?? ilObject;
|
||||
}
|
||||
#else
|
||||
if (toCache is GameObject || toCache is Transform)
|
||||
{
|
||||
toCache = toCache as GameObject ?? (toCache as Transform).gameObject;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (toCache is TextAsset textAsset)
|
||||
{
|
||||
if (string.IsNullOrEmpty(textAsset.text))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var cache = CacheFactory.GetCacheObject(toCache);
|
||||
cache.IsStaticClassSearchResult = isStaticClasses;
|
||||
m_searchResults.Add(cache);
|
||||
}
|
||||
|
||||
Pages.ItemCount = m_searchResults.Count;
|
||||
Pages.PageOffset = 0;
|
||||
|
||||
results = null;
|
||||
|
||||
//m_cachingResults = false;
|
||||
}
|
||||
|
||||
private void Search()
|
||||
{
|
||||
//if (m_cachingResults)
|
||||
//{
|
||||
// ExplorerCore.Log("Cannot search now, we are already caching results...");
|
||||
// return;
|
||||
//}
|
||||
|
||||
Pages.PageOffset = 0;
|
||||
|
||||
#if CPP
|
||||
Il2CppSystem.Type searchType = null;
|
||||
|
||||
#else
|
||||
Type searchType = null;
|
||||
#endif
|
||||
if (TypeMode == TypeFilter.Custom)
|
||||
{
|
||||
if (ReflectionHelpers.GetTypeByName(m_typeInput) is Type t)
|
||||
{
|
||||
#if CPP
|
||||
searchType = Il2CppSystem.Type.GetType(t.AssemblyQualifiedName);
|
||||
#else
|
||||
searchType = t;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
ExplorerCore.Log($"Could not find a Type by the name of '{m_typeInput}'!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (TypeMode == TypeFilter.Object)
|
||||
{
|
||||
searchType = ReflectionHelpers.ObjectType;
|
||||
}
|
||||
else if (TypeMode == TypeFilter.GameObject)
|
||||
{
|
||||
searchType = ReflectionHelpers.GameObjectType;
|
||||
}
|
||||
else if (TypeMode == TypeFilter.Component)
|
||||
{
|
||||
searchType = ReflectionHelpers.ComponentType;
|
||||
}
|
||||
|
||||
if (!ReflectionHelpers.ObjectType.IsAssignableFrom(searchType))
|
||||
{
|
||||
if (searchType != null)
|
||||
{
|
||||
ExplorerCore.LogWarning("Your Custom Class Type must inherit from UnityEngine.Object!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var matches = new List<object>();
|
||||
|
||||
var allObjectsOfType = ResourcesUnstrip.FindObjectsOfTypeAll(searchType);
|
||||
|
||||
//ExplorerCore.Log("Found count: " + allObjectsOfType.Length);
|
||||
|
||||
int i = 0;
|
||||
foreach (var obj in allObjectsOfType)
|
||||
{
|
||||
if (i >= MaxSearchResults) break;
|
||||
|
||||
if (m_searchInput != "" && !obj.name.ToLower().Contains(m_searchInput.ToLower()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (searchType.FullName == ReflectionHelpers.ComponentType.FullName
|
||||
#if CPP
|
||||
&& ReflectionHelpers.TransformType.IsAssignableFrom(obj.GetIl2CppType()))
|
||||
#else
|
||||
&& ReflectionHelpers.TransformType.IsAssignableFrom(obj.GetType()))
|
||||
#endif
|
||||
{
|
||||
// Transforms shouldn't really be counted as Components, skip them.
|
||||
// They're more akin to GameObjects.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (SceneMode != SceneFilter.Any && !FilterScene(obj, this.SceneMode))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!matches.Contains(obj))
|
||||
{
|
||||
matches.Add(obj);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
CacheResults(matches);
|
||||
}
|
||||
|
||||
public static bool FilterScene(object obj, SceneFilter filter)
|
||||
{
|
||||
GameObject go = null;
|
||||
#if CPP
|
||||
if (obj is Il2CppSystem.Object ilObject)
|
||||
{
|
||||
go = ilObject.TryCast<GameObject>() ?? ilObject.TryCast<Component>().gameObject;
|
||||
}
|
||||
#else
|
||||
if (obj is GameObject || obj is Component)
|
||||
{
|
||||
go = (obj as GameObject) ?? (obj as Component).gameObject;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!go)
|
||||
{
|
||||
// object is not on a GameObject, cannot perform scene filter operation.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filter == SceneFilter.None)
|
||||
{
|
||||
return string.IsNullOrEmpty(go.scene.name);
|
||||
}
|
||||
else if (filter == SceneFilter.This)
|
||||
{
|
||||
return go.scene.name == UnityHelpers.ActiveSceneName;
|
||||
}
|
||||
else if (filter == SceneFilter.DontDestroy)
|
||||
{
|
||||
return go.scene.name == "DontDestroyOnLoad";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool FilterName(string name)
|
||||
{
|
||||
// Don't really want these instances.
|
||||
return !name.StartsWith("Mono")
|
||||
&& !name.StartsWith("System")
|
||||
&& !name.StartsWith("Il2CppSystem")
|
||||
&& !name.StartsWith("Iced");
|
||||
}
|
||||
|
||||
// credit: ManlyMarco (RuntimeUnityEditor)
|
||||
public static IEnumerable<object> GetStaticInstances()
|
||||
{
|
||||
var query = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(t => t.TryGetTypes())
|
||||
.Where(t => t.IsClass && !t.IsAbstract && !t.ContainsGenericParameters);
|
||||
|
||||
var flags = BindingFlags.Public | BindingFlags.Static;
|
||||
var flatFlags = flags | BindingFlags.FlattenHierarchy;
|
||||
|
||||
foreach (var type in query)
|
||||
{
|
||||
object obj = null;
|
||||
try
|
||||
{
|
||||
var pi = type.GetProperty("Instance", flags);
|
||||
|
||||
if (pi == null)
|
||||
{
|
||||
pi = type.GetProperty("Instance", flatFlags);
|
||||
}
|
||||
|
||||
if (pi != null)
|
||||
{
|
||||
obj = pi.GetValue(null, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
var fi = type.GetField("Instance", flags);
|
||||
|
||||
if (fi == null)
|
||||
{
|
||||
fi = type.GetField("Instance", flatFlags);
|
||||
}
|
||||
|
||||
if (fi != null)
|
||||
{
|
||||
obj = fi.GetValue(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (obj != null)
|
||||
{
|
||||
var t = ReflectionHelpers.GetActualType(obj);
|
||||
|
||||
if (!FilterName(t.FullName) || ReflectionHelpers.IsEnumerable(t))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable GetStaticClasses()
|
||||
{
|
||||
var list = new List<Type>();
|
||||
|
||||
var input = m_searchInput?.ToLower() ?? "";
|
||||
|
||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var type in asm.TryGetTypes())
|
||||
{
|
||||
if (!type.IsAbstract || !type.IsSealed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(input))
|
||||
{
|
||||
var typename = type.FullName.ToLower();
|
||||
|
||||
if (!typename.Contains(input))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
list.Add(type);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// =========== GUI DRAW ============= //
|
||||
|
||||
public override void DrawWindow()
|
||||
{
|
||||
try
|
||||
{
|
||||
// helpers
|
||||
GUIHelper.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
|
||||
GUILayout.Label("<b><color=orange>Helpers</color></b>", new GUILayoutOption[] { GUILayout.Width(70) });
|
||||
if (GUILayout.Button("Find Static Instances", new GUILayoutOption[] { GUILayout.Width(180) }))
|
||||
{
|
||||
CacheResults(GetStaticInstances());
|
||||
}
|
||||
if (GUILayout.Button("Find Static Classes", new GUILayoutOption[] { GUILayout.Width(180) }))
|
||||
{
|
||||
CacheResults(GetStaticClasses(), true);
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
// search box
|
||||
SearchBox();
|
||||
|
||||
// results
|
||||
GUIHelper.BeginVertical(GUIContent.none, GUI.skin.box, null);
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||
GUILayout.Label("<b><color=orange>Results </color></b>" + " (" + m_searchResults.Count + ")", new GUILayoutOption[0]);
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
|
||||
int count = m_searchResults.Count;
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
Pages.DrawLimitInputArea();
|
||||
|
||||
if (count > Pages.ItemsPerPage)
|
||||
{
|
||||
// prev/next page buttons
|
||||
|
||||
if (Pages.ItemCount > Pages.ItemsPerPage)
|
||||
{
|
||||
if (GUILayout.Button("< Prev", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
Pages.TurnPage(Turn.Left, ref this.resultsScroll);
|
||||
}
|
||||
|
||||
Pages.CurrentPageLabel();
|
||||
|
||||
if (GUILayout.Button("Next >", new GUILayoutOption[] { GUILayout.Width(80) }))
|
||||
{
|
||||
Pages.TurnPage(Turn.Right, ref this.resultsScroll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
resultsScroll = GUIHelper.BeginScrollView(resultsScroll);
|
||||
|
||||
var _temprect = new Rect(MainMenu.MainRect.x, MainMenu.MainRect.y, MainMenu.MainRect.width + 160, MainMenu.MainRect.height);
|
||||
|
||||
if (m_searchResults.Count > 0)
|
||||
{
|
||||
int offset = Pages.CalculateOffsetIndex();
|
||||
|
||||
for (int i = offset; i < offset + Pages.ItemsPerPage && i < count; i++)
|
||||
{
|
||||
if (i >= m_searchResults.Count) break;
|
||||
|
||||
m_searchResults[i].Draw(MainMenu.MainRect, 0f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUILayout.Label("<color=red><i>No results found!</i></color>", new GUILayoutOption[0]);
|
||||
}
|
||||
|
||||
GUIHelper.EndScrollView();
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!e.Message.Contains("in a group with only"))
|
||||
{
|
||||
ExplorerCore.Log("Exception drawing search results!");
|
||||
while (e != null)
|
||||
{
|
||||
ExplorerCore.Log(e);
|
||||
e = e.InnerException;
|
||||
}
|
||||
m_searchResults.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SearchBox()
|
||||
{
|
||||
GUIHelper.BeginVertical(GUIContent.none, GUI.skin.box, null);
|
||||
|
||||
// ----- GameObject Search -----
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||
GUILayout.Label("<b><color=orange>Search</color></b>", new GUILayoutOption[0]);
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
GUILayout.Label("Name Contains:", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||
m_searchInput = GUIHelper.TextField(m_searchInput, new GUILayoutOption[] { GUILayout.Width(200) });
|
||||
|
||||
GUILayout.Label("Max Results:", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||
var s = MaxSearchResults.ToString();
|
||||
s = GUIHelper.TextField(s, new GUILayoutOption[] { GUILayout.Width(80) });
|
||||
if (int.TryParse(s, out int i))
|
||||
{
|
||||
MaxSearchResults = i;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
GUILayout.Label("Class Filter:", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||
ClassFilterToggle(TypeFilter.Object, "Object");
|
||||
ClassFilterToggle(TypeFilter.GameObject, "GameObject");
|
||||
ClassFilterToggle(TypeFilter.Component, "Component");
|
||||
ClassFilterToggle(TypeFilter.Custom, "Custom");
|
||||
GUILayout.EndHorizontal();
|
||||
if (TypeMode == TypeFilter.Custom)
|
||||
{
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||
GUILayout.Label("Custom Class:", new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
GUI.skin.label.alignment = TextAnchor.UpperLeft;
|
||||
m_typeInput = GUIHelper.TextField(m_typeInput, new GUILayoutOption[] { GUILayout.Width(250) });
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUILayout.Label("Scene Filter:", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||
SceneFilterToggle(SceneFilter.Any, "Any", 60);
|
||||
SceneFilterToggle(SceneFilter.This, "This Scene", 100);
|
||||
SceneFilterToggle(SceneFilter.DontDestroy, "DontDestroyOnLoad", 140);
|
||||
SceneFilterToggle(SceneFilter.None, "No Scene", 80);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
if (GUILayout.Button("<b><color=cyan>Search</color></b>", new GUILayoutOption[0]))
|
||||
{
|
||||
Search();
|
||||
}
|
||||
//if (m_cachingResults)
|
||||
//{
|
||||
// GUILayout.Label("Searching...", new GUILayoutOption[0]);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// if (GUILayout.Button("<b><color=cyan>Search</color></b>", new GUILayoutOption[0]))
|
||||
// {
|
||||
// Search();
|
||||
// }
|
||||
//}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
private void ClassFilterToggle(TypeFilter mode, string label)
|
||||
{
|
||||
if (TypeMode == mode)
|
||||
{
|
||||
GUI.color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(100) }))
|
||||
{
|
||||
TypeMode = mode;
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
|
||||
private void SceneFilterToggle(SceneFilter mode, string label, float width)
|
||||
{
|
||||
if (SceneMode == mode)
|
||||
{
|
||||
GUI.color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Width(width) }))
|
||||
{
|
||||
SceneMode = mode;
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Explorer.Config;
|
||||
using Explorer.UI.Main;
|
||||
using Explorer.UI.Shared;
|
||||
using Explorer.UI.Inspectors;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class MainMenu
|
||||
{
|
||||
public static MainMenu Instance;
|
||||
|
||||
public MainMenu()
|
||||
{
|
||||
Instance = this;
|
||||
|
||||
Pages.Add(new ScenePage());
|
||||
Pages.Add(new SearchPage());
|
||||
Pages.Add(new ConsolePage());
|
||||
Pages.Add(new OptionsPage());
|
||||
|
||||
for (int i = 0; i < Pages.Count; i++)
|
||||
{
|
||||
var page = Pages[i];
|
||||
page.Init();
|
||||
|
||||
// If page failed to init, it will remove itself from the list. Lower the iterate counter.
|
||||
if (!Pages.Contains(page)) i--;
|
||||
}
|
||||
}
|
||||
|
||||
public const int MainWindowID = 5000;
|
||||
public static Rect MainRect = new Rect(5, 5, ModConfig.Instance.Default_Window_Size.x, ModConfig.Instance.Default_Window_Size.y);
|
||||
|
||||
public static readonly List<BaseMainMenuPage> Pages = new List<BaseMainMenuPage>();
|
||||
private static int m_currentPage = 0;
|
||||
|
||||
public static void SetCurrentPage(int index)
|
||||
{
|
||||
if (index < 0 || Pages.Count <= index)
|
||||
{
|
||||
ExplorerCore.Log("cannot set page " + index);
|
||||
return;
|
||||
}
|
||||
m_currentPage = index;
|
||||
GUIHelper.BringWindowToFront(MainWindowID);
|
||||
GUI.FocusWindow(MainWindowID);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
Pages[m_currentPage].Update();
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
MainRect = GUIHelper.Window(MainWindowID, MainRect, (GUI.WindowFunction)MainWindow, ExplorerCore.NAME);
|
||||
}
|
||||
|
||||
private void MainWindow(int id)
|
||||
{
|
||||
GUI.DragWindow(new Rect(0, 0, MainRect.width - 90, 20));
|
||||
|
||||
if (GUIHelper.Button(new Rect(MainRect.width - 90, 2, 80, 20), $"Hide ({ModConfig.Instance.Main_Menu_Toggle})"))
|
||||
{
|
||||
ExplorerCore.ShowMenu = false;
|
||||
return;
|
||||
}
|
||||
|
||||
GUIHelper.BeginArea(new Rect(5, 25, MainRect.width - 10, MainRect.height - 35), GUI.skin.box);
|
||||
|
||||
MainHeader();
|
||||
|
||||
var page = Pages[m_currentPage];
|
||||
|
||||
page.scroll = GUIHelper.BeginScrollView(page.scroll);
|
||||
|
||||
page.DrawWindow();
|
||||
|
||||
GUIHelper.EndScrollView();
|
||||
|
||||
MainRect = ResizeDrag.ResizeWindow(MainRect, MainWindowID);
|
||||
|
||||
GUIHelper.EndArea();
|
||||
}
|
||||
|
||||
private void MainHeader()
|
||||
{
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
for (int i = 0; i < Pages.Count; i++)
|
||||
{
|
||||
if (m_currentPage == i)
|
||||
GUI.color = Color.green;
|
||||
else
|
||||
GUI.color = Color.white;
|
||||
|
||||
if (GUILayout.Button(Pages[i].Name, new GUILayoutOption[0]))
|
||||
{
|
||||
m_currentPage = i;
|
||||
}
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUI.color = Color.white;
|
||||
InspectUnderMouse.EnableInspect = GUILayout.Toggle(InspectUnderMouse.EnableInspect, "Inspect Under Mouse (Shift + RMB)", new GUILayoutOption[0]);
|
||||
|
||||
bool mouseState = ForceUnlockCursor.Unlock;
|
||||
bool setMouse = GUILayout.Toggle(mouseState, "Force Unlock Mouse (Left Alt)", new GUILayoutOption[0]);
|
||||
if (setMouse != mouseState) ForceUnlockCursor.Unlock = setMouse;
|
||||
|
||||
//WindowManager.TabView = GUILayout.Toggle(WindowManager.TabView, "Tab View", new GUILayoutOption[0]);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
//GUIUnstrip.Space(10);
|
||||
GUIHelper.Space(10);
|
||||
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Explorer.UI.Shared
|
||||
{
|
||||
public class Buttons
|
||||
{
|
||||
public static void InstantiateButton(Object obj, float width = 100)
|
||||
{
|
||||
if (GUILayout.Button("Instantiate", new GUILayoutOption[] { GUILayout.Width(width) }))
|
||||
{
|
||||
var newobj = Object.Instantiate(obj);
|
||||
WindowManager.InspectObject(newobj, out _);
|
||||
}
|
||||
}
|
||||
|
||||
public static void InspectButton(object obj)
|
||||
{
|
||||
if (GUILayout.Button("Inspect", new GUILayoutOption[0]))
|
||||
{
|
||||
WindowManager.InspectObject(obj, out bool _);
|
||||
}
|
||||
}
|
||||
|
||||
public static void GameObjectButton(object _obj, Action<Transform> inspectOverride = null, bool showSmallInspect = true, float width = 380)
|
||||
{
|
||||
var go = (_obj as GameObject) ?? (_obj as Transform).gameObject;
|
||||
|
||||
if (!go) return;
|
||||
|
||||
bool hasChild = go.transform.childCount > 0;
|
||||
|
||||
string label = hasChild ? $"[{go.transform.childCount} children] " : "";
|
||||
label += go.name;
|
||||
|
||||
bool enabled = go.activeSelf;
|
||||
int childCount = go.transform.childCount;
|
||||
Color color;
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
if (childCount > 0)
|
||||
{
|
||||
color = Color.green;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = UIStyles.LightGreen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color = Color.red;
|
||||
}
|
||||
|
||||
// ------ toggle active button ------
|
||||
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUI.skin.button.alignment = TextAnchor.UpperLeft;
|
||||
|
||||
GUI.color = color;
|
||||
|
||||
enabled = GUILayout.Toggle(enabled, "", new GUILayoutOption[] { GUILayout.Width(18) });
|
||||
if (go.activeSelf != enabled)
|
||||
{
|
||||
go.SetActive(enabled);
|
||||
}
|
||||
|
||||
// ------- actual button ---------
|
||||
|
||||
if (GUILayout.Button(label, new GUILayoutOption[] { GUILayout.Height(22), GUILayout.Width(width) }))
|
||||
{
|
||||
if (inspectOverride != null)
|
||||
{
|
||||
inspectOverride(go.transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
WindowManager.InspectObject(_obj, out bool _);
|
||||
}
|
||||
}
|
||||
|
||||
// ------ small "Inspect" button on the right ------
|
||||
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
GUI.color = Color.white;
|
||||
|
||||
if (showSmallInspect)
|
||||
{
|
||||
InspectButton(_obj);
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
namespace Explorer
|
||||
{
|
||||
interface IExpandHeight
|
||||
{
|
||||
bool IsExpanded { get; set; }
|
||||
float WhiteSpace { get; set; }
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer.UI.Shared
|
||||
{
|
||||
public enum Turn
|
||||
{
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
|
||||
public class PageHelper
|
||||
{
|
||||
public int PageOffset { get; set; }
|
||||
|
||||
public int ItemsPerPage
|
||||
{
|
||||
get => m_itemsPerPage;
|
||||
set
|
||||
{
|
||||
m_itemsPerPage = value;
|
||||
CalculateMaxOffset();
|
||||
}
|
||||
}
|
||||
private int m_itemsPerPage = Config.ModConfig.Instance.Default_Page_Limit;
|
||||
|
||||
public int ItemCount
|
||||
{
|
||||
get => m_count;
|
||||
set
|
||||
{
|
||||
m_count = value;
|
||||
CalculateMaxOffset();
|
||||
}
|
||||
}
|
||||
private int m_count;
|
||||
|
||||
public int MaxPageOffset { get; private set; } = -1;
|
||||
|
||||
private int CalculateMaxOffset()
|
||||
{
|
||||
return MaxPageOffset = (int)Math.Ceiling((float)(ItemCount / (decimal)ItemsPerPage)) - 1;
|
||||
}
|
||||
|
||||
public void CurrentPageLabel()
|
||||
{
|
||||
var orig = GUI.skin.label.alignment;
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
GUILayout.Label($"Page {PageOffset + 1}/{MaxPageOffset + 1}", new GUILayoutOption[] { GUILayout.Width(80) });
|
||||
|
||||
GUI.skin.label.alignment = orig;
|
||||
}
|
||||
|
||||
public void TurnPage(Turn direction)
|
||||
{
|
||||
var _ = Vector2.zero;
|
||||
TurnPage(direction, ref _);
|
||||
}
|
||||
|
||||
public void TurnPage(Turn direction, ref Vector2 scroll)
|
||||
{
|
||||
if (direction == Turn.Left)
|
||||
{
|
||||
if (PageOffset > 0)
|
||||
{
|
||||
PageOffset--;
|
||||
scroll = Vector2.zero;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PageOffset < MaxPageOffset)
|
||||
{
|
||||
PageOffset++;
|
||||
scroll = Vector2.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int CalculateOffsetIndex()
|
||||
{
|
||||
int offset = PageOffset * ItemsPerPage;
|
||||
|
||||
if (offset >= ItemCount)
|
||||
{
|
||||
offset = 0;
|
||||
PageOffset = 0;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void DrawLimitInputArea()
|
||||
{
|
||||
GUILayout.Label("Limit: ", new GUILayoutOption[] { GUILayout.Width(50) });
|
||||
var limit = this.ItemsPerPage.ToString();
|
||||
limit = GUIHelper.TextField(limit, new GUILayoutOption[] { GUILayout.Width(50) });
|
||||
if (limit != ItemsPerPage.ToString() && int.TryParse(limit, out int i))
|
||||
{
|
||||
ItemsPerPage = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
using System;
|
||||
#if CPP
|
||||
using UnhollowerBaseLib;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
namespace Explorer.UI.Shared
|
||||
{
|
||||
public class ResizeDrag
|
||||
{
|
||||
private static bool RESIZE_FAILED = false;
|
||||
|
||||
public static bool IsResizing = false;
|
||||
public static bool IsMouseInResizeArea = false;
|
||||
|
||||
private static readonly GUIContent gcDrag = new GUIContent("<-- Drag to resize -->");
|
||||
private static Rect m_currentResize;
|
||||
private static int m_currentWindow;
|
||||
|
||||
public static Rect ResizeWindow(Rect _rect, int ID)
|
||||
{
|
||||
if (!RESIZE_FAILED)
|
||||
{
|
||||
var origRect = _rect;
|
||||
|
||||
try
|
||||
{
|
||||
GUIHelper.BeginHorizontal(GUIContent.none, GUI.skin.box, null);
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
|
||||
#if BIE
|
||||
#if CPP // Temporary for BepInEx IL2CPP
|
||||
GUILayout.Button("<-- Drag to resize -->", new GUILayoutOption[] { GUILayout.Height(15) });
|
||||
#else
|
||||
GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) });
|
||||
#endif
|
||||
#else
|
||||
GUILayout.Button(gcDrag, GUI.skin.label, new GUILayoutOption[] { GUILayout.Height(15) });
|
||||
#endif
|
||||
|
||||
var resizeDragArea = GUIHelper.GetLastRect();
|
||||
var mousePos = InputManager.MousePosition;
|
||||
|
||||
try
|
||||
{
|
||||
var mouse = GUIHelper.ScreenToGUIPoint(new Vector2(mousePos.x, Screen.height - mousePos.y));
|
||||
if (resizeDragArea.Contains(mouse))
|
||||
{
|
||||
IsMouseInResizeArea = true;
|
||||
|
||||
if (InputManager.GetMouseButtonDown(0))
|
||||
{
|
||||
IsResizing = true;
|
||||
m_currentWindow = ID;
|
||||
m_currentResize = new Rect(mouse.x, mouse.y, _rect.width, _rect.height);
|
||||
}
|
||||
}
|
||||
else if (!InputManager.GetMouseButton(0))
|
||||
{
|
||||
IsMouseInResizeArea = false;
|
||||
IsResizing = false;
|
||||
}
|
||||
|
||||
if (IsResizing && ID == m_currentWindow)
|
||||
{
|
||||
_rect.width = Mathf.Max(100, m_currentResize.width + (mouse.x - m_currentResize.x));
|
||||
_rect.height = Mathf.Max(100, m_currentResize.height + (mouse.y - m_currentResize.y));
|
||||
_rect.xMax = Mathf.Min(Screen.width, _rect.xMax); // modifying xMax affects width, not x
|
||||
_rect.yMax = Mathf.Min(Screen.height, _rect.yMax); // modifying yMax affects height, not y
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// throw safe Managed exception
|
||||
throw new Exception("");
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
catch (Exception e) when (e.Message.StartsWith("System.ArgumentException"))
|
||||
{
|
||||
// suppress
|
||||
return origRect;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
RESIZE_FAILED = true;
|
||||
ExplorerCore.Log("Exception on GuiResize: " + e.GetType() + ", " + e.Message);
|
||||
//ExplorerCore.Log(e.StackTrace);
|
||||
return origRect;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
|
||||
GUILayout.Label("Resize window:", new GUILayoutOption[] { GUILayout.Width(100) });
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleRight;
|
||||
GUILayout.Label("<color=cyan>Width:</color>", new GUILayoutOption[] { GUILayout.Width(60) });
|
||||
if (GUIHelper.RepeatButton("-", new GUILayoutOption[] { GUILayout.Width(20) }))
|
||||
{
|
||||
_rect.width -= 5f;
|
||||
}
|
||||
if (GUIHelper.RepeatButton("+", new GUILayoutOption[] { GUILayout.Width(20) }))
|
||||
{
|
||||
_rect.width += 5f;
|
||||
}
|
||||
GUILayout.Label("<color=cyan>Height:</color>", new GUILayoutOption[] { GUILayout.Width(60) });
|
||||
if (GUIHelper.RepeatButton("-", new GUILayoutOption[] { GUILayout.Width(20) }))
|
||||
{
|
||||
_rect.height -= 5f;
|
||||
}
|
||||
if (GUIHelper.RepeatButton("+", new GUILayoutOption[] { GUILayout.Width(20) }))
|
||||
{
|
||||
_rect.height += 5f;
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUI.skin.label.alignment = TextAnchor.MiddleLeft;
|
||||
|
||||
return _rect;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Explorer.UI.Shared
|
||||
namespace ExplorerBeta.UI.Shared
|
||||
{
|
||||
public class Syntax
|
||||
{
|
||||
|
@ -1,118 +0,0 @@
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Explorer.UI.Shared
|
||||
{
|
||||
public class UIStyles
|
||||
{
|
||||
public static Color LightGreen = new Color(Color.green.r - 0.3f, Color.green.g - 0.3f, Color.green.b - 0.3f);
|
||||
|
||||
public static GUISkin WindowSkin
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_customSkin == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_customSkin = CreateWindowSkin();
|
||||
}
|
||||
catch
|
||||
{
|
||||
_customSkin = GUI.skin;
|
||||
}
|
||||
}
|
||||
|
||||
return _customSkin;
|
||||
}
|
||||
}
|
||||
|
||||
public static void HorizontalLine(Color _color, bool small = false)
|
||||
{
|
||||
var orig = GUI.color;
|
||||
|
||||
GUI.color = _color;
|
||||
GUILayout.Box(GUIContent.none, !small ? HorizontalBar : HorizontalBarSmall, null);
|
||||
|
||||
GUI.color = orig;
|
||||
}
|
||||
|
||||
private static GUISkin _customSkin;
|
||||
|
||||
public static Texture2D m_nofocusTex;
|
||||
public static Texture2D m_focusTex;
|
||||
|
||||
private static GUIStyle HorizontalBar
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_horizBarStyle == null)
|
||||
{
|
||||
_horizBarStyle = new GUIStyle();
|
||||
_horizBarStyle.normal.background = Texture2D.whiteTexture;
|
||||
var rectOffset = new RectOffset();
|
||||
rectOffset.top = 4;
|
||||
rectOffset.bottom = 4;
|
||||
_horizBarStyle.margin = rectOffset;
|
||||
_horizBarStyle.fixedHeight = 2;
|
||||
}
|
||||
|
||||
return _horizBarStyle;
|
||||
}
|
||||
}
|
||||
private static GUIStyle _horizBarStyle;
|
||||
|
||||
private static GUIStyle HorizontalBarSmall
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_horizBarSmallStyle == null)
|
||||
{
|
||||
_horizBarSmallStyle = new GUIStyle();
|
||||
_horizBarSmallStyle.normal.background = Texture2D.whiteTexture;
|
||||
var rectOffset = new RectOffset();
|
||||
rectOffset.top = 2;
|
||||
rectOffset.bottom = 2;
|
||||
_horizBarSmallStyle.margin = rectOffset;
|
||||
_horizBarSmallStyle.fixedHeight = 1;
|
||||
}
|
||||
|
||||
return _horizBarSmallStyle;
|
||||
}
|
||||
}
|
||||
private static GUIStyle _horizBarSmallStyle;
|
||||
|
||||
private static GUISkin CreateWindowSkin()
|
||||
{
|
||||
var newSkin = Object.Instantiate(GUI.skin);
|
||||
Object.DontDestroyOnLoad(newSkin);
|
||||
|
||||
m_nofocusTex = MakeTex(1, 1, new Color(0.1f, 0.1f, 0.1f, 0.7f));
|
||||
m_focusTex = MakeTex(1, 1, new Color(0.3f, 0.3f, 0.3f, 1f));
|
||||
|
||||
newSkin.window.normal.background = m_nofocusTex;
|
||||
newSkin.window.onNormal.background = m_focusTex;
|
||||
|
||||
newSkin.box.normal.textColor = Color.white;
|
||||
newSkin.window.normal.textColor = Color.white;
|
||||
newSkin.button.normal.textColor = Color.white;
|
||||
newSkin.textField.normal.textColor = Color.white;
|
||||
newSkin.label.normal.textColor = Color.white;
|
||||
|
||||
return newSkin;
|
||||
}
|
||||
|
||||
public static Texture2D MakeTex(int width, int height, Color col)
|
||||
{
|
||||
Color[] pix = new Color[width * height];
|
||||
for (int i = 0; i < pix.Length; ++i)
|
||||
{
|
||||
pix[i] = col;
|
||||
}
|
||||
Texture2D result = new Texture2D(width, height);
|
||||
result.SetPixels(pix);
|
||||
result.Apply();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Shared;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class TabViewWindow : WindowBase
|
||||
{
|
||||
public override string Title => $"Tabs ({WindowManager.Windows.Count})";
|
||||
|
||||
public static TabViewWindow Instance => m_instance ?? (m_instance = new TabViewWindow());
|
||||
private static TabViewWindow m_instance;
|
||||
|
||||
private WindowBase m_targetWindow;
|
||||
public int TargetTabID = 0;
|
||||
|
||||
public override bool IsTabViewWindow => true;
|
||||
|
||||
public TabViewWindow()
|
||||
{
|
||||
m_rect = new Rect(570, 0, 550, 700);
|
||||
}
|
||||
|
||||
public override void Init() { }
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
while (TargetTabID >= WindowManager.Windows.Count)
|
||||
{
|
||||
TargetTabID--;
|
||||
}
|
||||
|
||||
if (TargetTabID == -1 && WindowManager.Windows.Count > 0)
|
||||
{
|
||||
TargetTabID = 0;
|
||||
}
|
||||
|
||||
if (TargetTabID >= 0)
|
||||
{
|
||||
m_targetWindow = WindowManager.Windows[TargetTabID];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_targetWindow = null;
|
||||
}
|
||||
|
||||
m_targetWindow?.Update();
|
||||
}
|
||||
|
||||
public override void WindowFunction(int windowID)
|
||||
{
|
||||
try
|
||||
{
|
||||
GUI.DragWindow(new Rect(0, 0, m_rect.width - 90, 20));
|
||||
if (GUIHelper.Button(new Rect(m_rect.width - 90, 2, 80, 20), "<color=red>Close All</color>"))
|
||||
{
|
||||
foreach (var window in WindowManager.Windows)
|
||||
{
|
||||
window.DestroyWindow();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
GUIHelper.BeginArea(new Rect(5, 25, m_rect.width - 10, m_rect.height - 35), GUI.skin.box);
|
||||
|
||||
GUIHelper.BeginVertical(GUIContent.none, GUI.skin.box, null);
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleLeft;
|
||||
int tabPerRow = (int)Math.Floor(m_rect.width / 238);
|
||||
int rowCount = 0;
|
||||
for (int i = 0; i < WindowManager.Windows.Count; i++)
|
||||
{
|
||||
var window = WindowManager.Windows[i];
|
||||
|
||||
// Prevent trying to draw destroyed UnityEngine.Objects
|
||||
// before the WindowManager removes them.
|
||||
if (window.Target is UnityEngine.Object uObj && !uObj)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rowCount >= tabPerRow)
|
||||
{
|
||||
rowCount = 0;
|
||||
GUILayout.EndHorizontal();
|
||||
GUIHelper.BeginHorizontal(new GUILayoutOption[0]);
|
||||
}
|
||||
rowCount++;
|
||||
|
||||
bool focused = i == TargetTabID;
|
||||
string color = focused ? "<color=lime>" : "<color=orange>";
|
||||
GUI.color = focused ? Color.green : Color.white;
|
||||
|
||||
if (GUILayout.Button(color + window.Title + "</color>", new GUILayoutOption[] { GUILayout.Width(200) }))
|
||||
{
|
||||
TargetTabID = i;
|
||||
}
|
||||
if (GUILayout.Button("<color=red><b>X</b></color>", new GUILayoutOption[] { GUILayout.Width(22) }))
|
||||
{
|
||||
window.DestroyWindow();
|
||||
}
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
GUILayout.EndHorizontal();
|
||||
GUILayout.EndVertical();
|
||||
GUI.skin.button.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
m_targetWindow.WindowFunction(m_targetWindow.windowID);
|
||||
|
||||
m_rect = ResizeDrag.ResizeWindow(m_rect, windowID);
|
||||
|
||||
GUIHelper.EndArea();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!e.Message.Contains("in a group with only"))
|
||||
{
|
||||
ExplorerCore.Log("Exception drawing Tab View window: " + e.GetType() + ", " + e.Message);
|
||||
ExplorerCore.Log(e.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
570
src/UI/UIFactory.cs
Normal file
570
src/UI/UIFactory.cs
Normal file
@ -0,0 +1,570 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace ExplorerBeta.UI
|
||||
{
|
||||
public static class UIFactory
|
||||
{
|
||||
//private const float kWidth = 160f;
|
||||
//private const float kThickHeight = 30f;
|
||||
//private const float kThinHeight = 20f;
|
||||
|
||||
private static Vector2 s_ThickElementSize = new Vector2(160f, 30f);
|
||||
private static Vector2 s_ThinElementSize = new Vector2(160f, 20f);
|
||||
//private static Vector2 s_ImageElementSize = new Vector2(100f, 100f);
|
||||
private static Color s_DefaultSelectableColor = new Color(0.3f, 0.3f, 0.3f, 1f);
|
||||
private static Color s_PanelColor = new Color(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
private static Color s_TextColor = new Color(0.95f, 0.95f, 0.95f, 1f);
|
||||
|
||||
public static Resources UIResources { get; set; }
|
||||
|
||||
public struct Resources
|
||||
{
|
||||
public Sprite standard;
|
||||
public Sprite background;
|
||||
public Sprite inputField;
|
||||
public Sprite knob;
|
||||
public Sprite checkmark;
|
||||
public Sprite dropdown;
|
||||
public Sprite mask;
|
||||
}
|
||||
|
||||
private static GameObject CreateUIObject(string name, GameObject parent, Vector2 size = default)
|
||||
{
|
||||
GameObject obj = new GameObject(name);
|
||||
|
||||
var rect = obj.AddComponent<RectTransform>();
|
||||
if (size != default)
|
||||
{
|
||||
rect.sizeDelta = size;
|
||||
}
|
||||
|
||||
SetParentAndAlign(obj, parent);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static void SetDefaultTextValues(Text lbl)
|
||||
{
|
||||
lbl.color = s_TextColor;
|
||||
lbl.AssignDefaultFont();
|
||||
//lbl.alignment = alignment;
|
||||
//lbl.resizeTextForBestFit = true;
|
||||
}
|
||||
|
||||
private static void SetDefaultColorTransitionValues(Selectable slider)
|
||||
{
|
||||
ColorBlock colors = slider.colors;
|
||||
colors.highlightedColor = new Color(0.4f, 0.4f, 0.4f);
|
||||
colors.pressedColor = new Color(0.05f, 0.05f, 0.05f);
|
||||
colors.disabledColor = new Color(0.7f, 0.7f, 0.7f);
|
||||
}
|
||||
|
||||
private static void SetParentAndAlign(GameObject child, GameObject parent)
|
||||
{
|
||||
if (parent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
child.transform.SetParent(parent.transform, false);
|
||||
SetLayerRecursively(child);
|
||||
}
|
||||
|
||||
private static void SetLayerRecursively(GameObject go)
|
||||
{
|
||||
go.layer = 5;
|
||||
Transform transform = go.transform;
|
||||
for (int i = 0; i < transform.childCount; i++)
|
||||
{
|
||||
DefaultControls.SetLayerRecursively(transform.GetChild(i).gameObject, 5);
|
||||
}
|
||||
}
|
||||
|
||||
public static GameObject CreatePanel(GameObject parent, string name)
|
||||
{
|
||||
GameObject panelObj = CreateUIObject($"Panel_{name}", parent, s_ThickElementSize);
|
||||
|
||||
RectTransform rect = panelObj.GetComponent<RectTransform>();
|
||||
rect.anchorMin = Vector2.zero;
|
||||
rect.anchorMax = Vector2.one;
|
||||
rect.anchoredPosition = Vector2.zero;
|
||||
rect.sizeDelta = Vector2.zero;
|
||||
|
||||
Image image = panelObj.AddComponent<Image>();
|
||||
image.sprite = UIResources.background;
|
||||
image.type = Image.Type.Sliced;
|
||||
image.color = s_PanelColor;
|
||||
|
||||
return panelObj;
|
||||
}
|
||||
|
||||
public static GameObject CreateVerticalGroup(GameObject parent, Color color = default)
|
||||
{
|
||||
var groupObj = CreateUIObject("HorizontalLayout", parent);
|
||||
|
||||
var horiGroup = groupObj.AddComponent<VerticalLayoutGroup>();
|
||||
horiGroup.childAlignment = TextAnchor.UpperLeft;
|
||||
horiGroup.childControlWidth = false;
|
||||
|
||||
var image = groupObj.AddComponent<Image>();
|
||||
if (color != default)
|
||||
image.color = color;
|
||||
else
|
||||
image.color = new Color(44f / 255f, 44f / 255f, 44f / 255f);
|
||||
|
||||
return groupObj;
|
||||
}
|
||||
|
||||
public static GameObject CreateHorizontalGroup(GameObject parent, Color color = default)
|
||||
{
|
||||
var groupObj = CreateUIObject("HorizontalLayout", parent);
|
||||
|
||||
var horiGroup = groupObj.AddComponent<HorizontalLayoutGroup>();
|
||||
horiGroup.childAlignment = TextAnchor.UpperLeft;
|
||||
horiGroup.childControlWidth = false;
|
||||
|
||||
var image = groupObj.AddComponent<Image>();
|
||||
if (color != default)
|
||||
image.color = color;
|
||||
else
|
||||
image.color = new Color(44f / 255f, 44f / 255f, 44f / 255f);
|
||||
|
||||
return groupObj;
|
||||
}
|
||||
|
||||
public static GameObject CreateLabel(GameObject parent, TextAnchor alignment)
|
||||
{
|
||||
GameObject labelObj = CreateUIObject("Label", parent, s_ThinElementSize);
|
||||
|
||||
var text = labelObj.AddComponent<Text>();
|
||||
SetDefaultTextValues(text);
|
||||
text.alignment = alignment;
|
||||
|
||||
return labelObj;
|
||||
}
|
||||
|
||||
public static GameObject CreateButton(GameObject parent)
|
||||
{
|
||||
GameObject buttonObj = CreateUIObject("Button", parent, s_ThinElementSize);
|
||||
|
||||
GameObject textObj = new GameObject("Text");
|
||||
textObj.AddComponent<RectTransform>();
|
||||
SetParentAndAlign(textObj, buttonObj);
|
||||
|
||||
Image image = buttonObj.AddComponent<Image>();
|
||||
image.sprite = UIResources.standard;
|
||||
image.type = Image.Type.Sliced;
|
||||
image.color = s_DefaultSelectableColor;
|
||||
|
||||
SetDefaultColorTransitionValues(buttonObj.AddComponent<Button>());
|
||||
|
||||
Text text = textObj.AddComponent<Text>();
|
||||
text.text = "Button";
|
||||
SetDefaultTextValues(text);
|
||||
text.alignment = TextAnchor.MiddleCenter;
|
||||
|
||||
RectTransform rect = textObj.GetComponent<RectTransform>();
|
||||
rect.anchorMin = Vector2.zero;
|
||||
rect.anchorMax = Vector2.one;
|
||||
rect.sizeDelta = Vector2.zero;
|
||||
|
||||
return buttonObj;
|
||||
}
|
||||
|
||||
public static GameObject CreateSlider(GameObject parent)
|
||||
{
|
||||
GameObject sliderObj = CreateUIObject("Slider", parent, s_ThinElementSize);
|
||||
|
||||
GameObject bgObj = CreateUIObject("Background", sliderObj);
|
||||
GameObject fillAreaObj = CreateUIObject("Fill Area", sliderObj);
|
||||
GameObject fillObj = CreateUIObject("Fill", fillAreaObj);
|
||||
GameObject handleSlideAreaObj = CreateUIObject("Handle Slide Area", sliderObj);
|
||||
GameObject handleObj = CreateUIObject("Handle", handleSlideAreaObj);
|
||||
|
||||
Image bgImage = bgObj.AddComponent<Image>();
|
||||
bgImage.sprite = UIResources.background;
|
||||
bgImage.type = Image.Type.Sliced;
|
||||
bgImage.color = s_DefaultSelectableColor;
|
||||
|
||||
RectTransform bgRect = bgObj.GetComponent<RectTransform>();
|
||||
bgRect.anchorMin = new Vector2(0f, 0.25f);
|
||||
bgRect.anchorMax = new Vector2(1f, 0.75f);
|
||||
bgRect.sizeDelta = new Vector2(0f, 0f);
|
||||
|
||||
RectTransform fillAreaRect = fillAreaObj.GetComponent<RectTransform>();
|
||||
fillAreaRect.anchorMin = new Vector2(0f, 0.25f);
|
||||
fillAreaRect.anchorMax = new Vector2(1f, 0.75f);
|
||||
fillAreaRect.anchoredPosition = new Vector2(-5f, 0f);
|
||||
fillAreaRect.sizeDelta = new Vector2(-20f, 0f);
|
||||
|
||||
Image fillImage = fillObj.AddComponent<Image>();
|
||||
fillImage.sprite = UIResources.standard;
|
||||
fillImage.type = Image.Type.Sliced;
|
||||
fillImage.color = s_DefaultSelectableColor;
|
||||
|
||||
fillObj.GetComponent<RectTransform>().sizeDelta = new Vector2(10f, 0f);
|
||||
|
||||
RectTransform handleSlideRect = handleSlideAreaObj.GetComponent<RectTransform>();
|
||||
handleSlideRect.sizeDelta = new Vector2(-20f, 0f);
|
||||
handleSlideRect.anchorMin = new Vector2(0f, 0f);
|
||||
handleSlideRect.anchorMax = new Vector2(1f, 1f);
|
||||
|
||||
Image handleImage = handleObj.AddComponent<Image>();
|
||||
handleImage.sprite = UIResources.knob;
|
||||
handleImage.color = s_DefaultSelectableColor;
|
||||
|
||||
handleObj.GetComponent<RectTransform>().sizeDelta = new Vector2(20f, 0f);
|
||||
|
||||
Slider slider = sliderObj.AddComponent<Slider>();
|
||||
slider.fillRect = fillObj.GetComponent<RectTransform>();
|
||||
slider.handleRect = handleObj.GetComponent<RectTransform>();
|
||||
slider.targetGraphic = handleImage;
|
||||
slider.direction = Slider.Direction.LeftToRight;
|
||||
SetDefaultColorTransitionValues(slider);
|
||||
|
||||
return sliderObj;
|
||||
}
|
||||
|
||||
public static GameObject CreateScrollbar(GameObject parent)
|
||||
{
|
||||
GameObject scrollObj = CreateUIObject("Scrollbar", parent, s_ThinElementSize);
|
||||
|
||||
GameObject slideAreaObj = CreateUIObject("Sliding Area", scrollObj);
|
||||
GameObject handleObj = CreateUIObject("Handle", slideAreaObj);
|
||||
|
||||
Image scrollImage = scrollObj.AddComponent<Image>();
|
||||
scrollImage.sprite = UIResources.background;
|
||||
scrollImage.type = Image.Type.Sliced;
|
||||
scrollImage.color = s_DefaultSelectableColor;
|
||||
|
||||
Image handleImage = handleObj.AddComponent<Image>();
|
||||
handleImage.sprite = UIResources.standard;
|
||||
handleImage.type = Image.Type.Sliced;
|
||||
handleImage.color = s_DefaultSelectableColor;
|
||||
|
||||
RectTransform slideAreaRect = slideAreaObj.GetComponent<RectTransform>();
|
||||
slideAreaRect.sizeDelta = new Vector2(-20f, -20f);
|
||||
slideAreaRect.anchorMin = Vector2.zero;
|
||||
slideAreaRect.anchorMax = Vector2.one;
|
||||
|
||||
RectTransform handleRect = handleObj.GetComponent<RectTransform>();
|
||||
handleRect.sizeDelta = new Vector2(20f, 20f);
|
||||
|
||||
Scrollbar scrollbar = scrollObj.AddComponent<Scrollbar>();
|
||||
scrollbar.handleRect = handleRect;
|
||||
scrollbar.targetGraphic = handleImage;
|
||||
SetDefaultColorTransitionValues(scrollbar);
|
||||
|
||||
return scrollObj;
|
||||
}
|
||||
|
||||
public static GameObject CreateToggle(GameObject parent)
|
||||
{
|
||||
GameObject toggleObj = CreateUIObject("Toggle", parent, s_ThinElementSize);
|
||||
|
||||
GameObject bgObj = CreateUIObject("Background", toggleObj);
|
||||
GameObject checkObj = CreateUIObject("Checkmark", bgObj);
|
||||
GameObject labelObj = CreateUIObject("Label", toggleObj);
|
||||
|
||||
Toggle toggle = toggleObj.AddComponent<Toggle>();
|
||||
toggle.isOn = true;
|
||||
|
||||
Image bgImage = bgObj.AddComponent<Image>();
|
||||
bgImage.sprite = UIResources.standard;
|
||||
bgImage.type = Image.Type.Sliced;
|
||||
bgImage.color = s_DefaultSelectableColor;
|
||||
|
||||
Image checkImage = checkObj.AddComponent<Image>();
|
||||
checkImage.sprite = UIResources.checkmark;
|
||||
|
||||
Text text = labelObj.AddComponent<Text>();
|
||||
text.text = "Toggle";
|
||||
SetDefaultTextValues(text);
|
||||
|
||||
toggle.graphic = checkImage;
|
||||
toggle.targetGraphic = bgImage;
|
||||
SetDefaultColorTransitionValues(toggle);
|
||||
|
||||
RectTransform bgRect = bgObj.GetComponent<RectTransform>();
|
||||
bgRect.anchorMin = new Vector2(0f, 1f);
|
||||
bgRect.anchorMax = new Vector2(0f, 1f);
|
||||
bgRect.anchoredPosition = new Vector2(10f, -10f);
|
||||
bgRect.sizeDelta = new Vector2(20f, 20f);
|
||||
|
||||
RectTransform checkRect = checkObj.GetComponent<RectTransform>();
|
||||
checkRect.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
checkRect.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
checkRect.anchoredPosition = Vector2.zero;
|
||||
checkRect.sizeDelta = new Vector2(20f, 20f);
|
||||
|
||||
RectTransform labelRect = labelObj.GetComponent<RectTransform>();
|
||||
labelRect.anchorMin = new Vector2(0f, 0f);
|
||||
labelRect.anchorMax = new Vector2(1f, 1f);
|
||||
labelRect.offsetMin = new Vector2(23f, 1f);
|
||||
labelRect.offsetMax = new Vector2(-5f, -2f);
|
||||
return toggleObj;
|
||||
}
|
||||
|
||||
public static GameObject CreateInputField(GameObject parent)
|
||||
{
|
||||
GameObject inputObj = CreateUIObject("InputField", parent, s_ThickElementSize);
|
||||
|
||||
GameObject placeholderObj = CreateUIObject("Placeholder", inputObj);
|
||||
GameObject textObj = CreateUIObject("Text", inputObj);
|
||||
|
||||
Image inputImage = inputObj.AddComponent<Image>();
|
||||
inputImage.sprite = UIResources.inputField;
|
||||
inputImage.type = Image.Type.Sliced;
|
||||
inputImage.color = s_DefaultSelectableColor;
|
||||
|
||||
InputField inputField = inputObj.AddComponent<InputField>();
|
||||
SetDefaultColorTransitionValues(inputField);
|
||||
|
||||
Text text = textObj.AddComponent<Text>();
|
||||
text.text = "";
|
||||
text.supportRichText = false;
|
||||
SetDefaultTextValues(text);
|
||||
|
||||
Text placeholderText = placeholderObj.AddComponent<Text>();
|
||||
placeholderText.text = "Enter text...";
|
||||
placeholderText.fontStyle = FontStyle.Italic;
|
||||
Color color = text.color;
|
||||
color.a *= 0.5f;
|
||||
placeholderText.color = color;
|
||||
|
||||
RectTransform textRect = textObj.GetComponent<RectTransform>();
|
||||
textRect.anchorMin = Vector2.zero;
|
||||
textRect.anchorMax = Vector2.one;
|
||||
textRect.sizeDelta = Vector2.zero;
|
||||
textRect.offsetMin = new Vector2(10f, 6f);
|
||||
textRect.offsetMax = new Vector2(-10f, -7f);
|
||||
|
||||
RectTransform placeholderRect = placeholderObj.GetComponent<RectTransform>();
|
||||
placeholderRect.anchorMin = Vector2.zero;
|
||||
placeholderRect.anchorMax = Vector2.one;
|
||||
placeholderRect.sizeDelta = Vector2.zero;
|
||||
placeholderRect.offsetMin = new Vector2(10f, 6f);
|
||||
placeholderRect.offsetMax = new Vector2(-10f, -7f);
|
||||
inputField.textComponent = text;
|
||||
inputField.placeholder = placeholderText;
|
||||
|
||||
return inputObj;
|
||||
}
|
||||
|
||||
public static GameObject CreateDropdown(GameObject parent)
|
||||
{
|
||||
GameObject dropdownObj = CreateUIObject("Dropdown", parent, s_ThickElementSize);
|
||||
|
||||
GameObject labelObj = CreateUIObject("Label", dropdownObj);
|
||||
GameObject arrowObj = CreateUIObject("Arrow", dropdownObj);
|
||||
GameObject templateObj = CreateUIObject("Template", dropdownObj);
|
||||
GameObject viewportObj = CreateUIObject("Viewport", templateObj);
|
||||
GameObject contentObj = CreateUIObject("Content", viewportObj);
|
||||
GameObject itemObj = CreateUIObject("Item", contentObj);
|
||||
GameObject itemBgObj = CreateUIObject("Item Background", itemObj);
|
||||
GameObject itemCheckObj = CreateUIObject("Item Checkmark", itemObj);
|
||||
GameObject itemLabelObj = CreateUIObject("Item Label", itemObj);
|
||||
|
||||
GameObject scrollbarObj = CreateScrollbar(templateObj);
|
||||
scrollbarObj.name = "Scrollbar";
|
||||
Scrollbar scrollbar = scrollbarObj.GetComponent<Scrollbar>();
|
||||
scrollbar.SetDirection(Scrollbar.Direction.BottomToTop, true);
|
||||
|
||||
RectTransform scrollRectTransform = scrollbarObj.GetComponent<RectTransform>();
|
||||
scrollRectTransform.anchorMin = Vector2.right;
|
||||
scrollRectTransform.anchorMax = Vector2.one;
|
||||
scrollRectTransform.pivot = Vector2.one;
|
||||
scrollRectTransform.sizeDelta = new Vector2(scrollRectTransform.sizeDelta.x, 0f);
|
||||
|
||||
Text itemLabelText = itemLabelObj.AddComponent<Text>();
|
||||
SetDefaultTextValues(itemLabelText);
|
||||
itemLabelText.alignment = TextAnchor.MiddleLeft;
|
||||
|
||||
Image itemBgImage = itemBgObj.AddComponent<Image>();
|
||||
itemBgImage.color = new Color32(245, 245, 245, byte.MaxValue);
|
||||
|
||||
Image itemCheckImage = itemCheckObj.AddComponent<Image>();
|
||||
itemCheckImage.sprite = UIResources.checkmark;
|
||||
|
||||
Toggle itemToggle = itemObj.AddComponent<Toggle>();
|
||||
itemToggle.targetGraphic = itemBgImage;
|
||||
itemToggle.graphic = itemCheckImage;
|
||||
itemToggle.isOn = true;
|
||||
|
||||
Image templateImage = templateObj.AddComponent<Image>();
|
||||
templateImage.sprite = UIResources.standard;
|
||||
templateImage.type = Image.Type.Sliced;
|
||||
|
||||
ScrollRect scrollRect = templateObj.AddComponent<ScrollRect>();
|
||||
scrollRect.content = (RectTransform)contentObj.transform;
|
||||
scrollRect.viewport = (RectTransform)viewportObj.transform;
|
||||
scrollRect.horizontal = false;
|
||||
scrollRect.movementType = ScrollRect.MovementType.Clamped;
|
||||
scrollRect.verticalScrollbar = scrollbar;
|
||||
scrollRect.verticalScrollbarVisibility = ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport;
|
||||
scrollRect.verticalScrollbarSpacing = -3f;
|
||||
|
||||
viewportObj.AddComponent<Mask>().showMaskGraphic = false;
|
||||
|
||||
Image viewportImage = viewportObj.AddComponent<Image>();
|
||||
viewportImage.sprite = UIResources.mask;
|
||||
viewportImage.type = Image.Type.Sliced;
|
||||
|
||||
Text labelText = labelObj.AddComponent<Text>();
|
||||
SetDefaultTextValues(labelText);
|
||||
labelText.alignment = TextAnchor.MiddleLeft;
|
||||
|
||||
arrowObj.AddComponent<Image>().sprite = UIResources.dropdown;
|
||||
Image dropdownImage = dropdownObj.AddComponent<Image>();
|
||||
dropdownImage.sprite = UIResources.standard;
|
||||
dropdownImage.color = s_DefaultSelectableColor;
|
||||
dropdownImage.type = Image.Type.Sliced;
|
||||
|
||||
Dropdown dropdown = dropdownObj.AddComponent<Dropdown>();
|
||||
dropdown.targetGraphic = dropdownImage;
|
||||
SetDefaultColorTransitionValues(dropdown);
|
||||
dropdown.template = templateObj.GetComponent<RectTransform>();
|
||||
dropdown.captionText = labelText;
|
||||
dropdown.itemText = itemLabelText;
|
||||
itemLabelText.text = "Option A";
|
||||
dropdown.options.Add(new Dropdown.OptionData
|
||||
{
|
||||
text = "Option A"
|
||||
});
|
||||
//dropdown.options.Add(new Dropdown.OptionData
|
||||
//{
|
||||
// text = "Option B"
|
||||
//});
|
||||
//dropdown.options.Add(new Dropdown.OptionData
|
||||
//{
|
||||
// text = "Option C"
|
||||
//});
|
||||
|
||||
dropdown.RefreshShownValue();
|
||||
|
||||
RectTransform labelRect = labelObj.GetComponent<RectTransform>();
|
||||
labelRect.anchorMin = Vector2.zero;
|
||||
labelRect.anchorMax = Vector2.one;
|
||||
labelRect.offsetMin = new Vector2(10f, 6f);
|
||||
labelRect.offsetMax = new Vector2(-25f, -7f);
|
||||
|
||||
RectTransform arrowRect = arrowObj.GetComponent<RectTransform>();
|
||||
arrowRect.anchorMin = new Vector2(1f, 0.5f);
|
||||
arrowRect.anchorMax = new Vector2(1f, 0.5f);
|
||||
arrowRect.sizeDelta = new Vector2(20f, 20f);
|
||||
arrowRect.anchoredPosition = new Vector2(-15f, 0f);
|
||||
|
||||
RectTransform templateRect = templateObj.GetComponent<RectTransform>();
|
||||
templateRect.anchorMin = new Vector2(0f, 0f);
|
||||
templateRect.anchorMax = new Vector2(1f, 0f);
|
||||
templateRect.pivot = new Vector2(0.5f, 1f);
|
||||
templateRect.anchoredPosition = new Vector2(0f, 2f);
|
||||
templateRect.sizeDelta = new Vector2(0f, 150f);
|
||||
|
||||
RectTransform viewportRect = viewportObj.GetComponent<RectTransform>();
|
||||
viewportRect.anchorMin = new Vector2(0f, 0f);
|
||||
viewportRect.anchorMax = new Vector2(1f, 1f);
|
||||
viewportRect.sizeDelta = new Vector2(-18f, 0f);
|
||||
viewportRect.pivot = new Vector2(0f, 1f);
|
||||
|
||||
RectTransform contentRect = contentObj.GetComponent<RectTransform>();
|
||||
contentRect.anchorMin = new Vector2(0f, 1f);
|
||||
contentRect.anchorMax = new Vector2(1f, 1f);
|
||||
contentRect.pivot = new Vector2(0.5f, 1f);
|
||||
contentRect.anchoredPosition = new Vector2(0f, 0f);
|
||||
contentRect.sizeDelta = new Vector2(0f, 28f);
|
||||
|
||||
RectTransform itemRect = itemObj.GetComponent<RectTransform>();
|
||||
itemRect.anchorMin = new Vector2(0f, 0.5f);
|
||||
itemRect.anchorMax = new Vector2(1f, 0.5f);
|
||||
itemRect.sizeDelta = new Vector2(0f, 20f);
|
||||
|
||||
RectTransform itemBgRect = itemBgObj.GetComponent<RectTransform>();
|
||||
itemBgRect.anchorMin = Vector2.zero;
|
||||
itemBgRect.anchorMax = Vector2.one;
|
||||
itemBgRect.sizeDelta = Vector2.zero;
|
||||
|
||||
RectTransform itemCheckRect = itemCheckObj.GetComponent<RectTransform>();
|
||||
itemCheckRect.anchorMin = new Vector2(0f, 0.5f);
|
||||
itemCheckRect.anchorMax = new Vector2(0f, 0.5f);
|
||||
itemCheckRect.sizeDelta = new Vector2(20f, 20f);
|
||||
itemCheckRect.anchoredPosition = new Vector2(10f, 0f);
|
||||
|
||||
RectTransform itemLabelRect = itemLabelObj.GetComponent<RectTransform>();
|
||||
itemLabelRect.anchorMin = Vector2.zero;
|
||||
itemLabelRect.anchorMax = Vector2.one;
|
||||
itemLabelRect.offsetMin = new Vector2(20f, 1f);
|
||||
itemLabelRect.offsetMax = new Vector2(-10f, -2f);
|
||||
templateObj.SetActive(false);
|
||||
|
||||
return dropdownObj;
|
||||
}
|
||||
|
||||
public static GameObject CreateScrollView(GameObject parent)
|
||||
{
|
||||
GameObject scrollObj = CreateUIObject("Scroll View", parent, new Vector2(200f, 200f));
|
||||
|
||||
GameObject viewportObj = CreateUIObject("Viewport", scrollObj);
|
||||
GameObject contentObj = CreateUIObject("Content", viewportObj);
|
||||
|
||||
GameObject horiScroll = CreateScrollbar(scrollObj);
|
||||
horiScroll.name = "Scrollbar Horizontal";
|
||||
//SetParentAndAlign(scrollbarObj, scrollObj);
|
||||
|
||||
RectTransform horiRect = horiScroll.GetComponent<RectTransform>();
|
||||
horiRect.anchorMin = Vector2.zero;
|
||||
horiRect.anchorMax = Vector2.right;
|
||||
horiRect.pivot = Vector2.zero;
|
||||
horiRect.sizeDelta = new Vector2(0f, horiRect.sizeDelta.y);
|
||||
|
||||
GameObject vertScroll = CreateScrollbar(scrollObj);
|
||||
vertScroll.name = "Scrollbar Vertical";
|
||||
//SetParentAndAlign(vertScroll, scrollObj);
|
||||
vertScroll.GetComponent<Scrollbar>().SetDirection(Scrollbar.Direction.BottomToTop, true);
|
||||
|
||||
RectTransform vertRect = vertScroll.GetComponent<RectTransform>();
|
||||
vertRect.anchorMin = Vector2.right;
|
||||
vertRect.anchorMax = Vector2.one;
|
||||
vertRect.pivot = Vector2.one;
|
||||
vertRect.sizeDelta = new Vector2(vertRect.sizeDelta.x, 0f);
|
||||
|
||||
RectTransform viewportRect = viewportObj.GetComponent<RectTransform>();
|
||||
viewportRect.anchorMin = Vector2.zero;
|
||||
viewportRect.anchorMax = Vector2.one;
|
||||
viewportRect.sizeDelta = Vector2.zero;
|
||||
viewportRect.pivot = Vector2.up;
|
||||
|
||||
RectTransform contentRect = contentObj.GetComponent<RectTransform>();
|
||||
contentRect.anchorMin = Vector2.up;
|
||||
contentRect.anchorMax = Vector2.one;
|
||||
contentRect.sizeDelta = new Vector2(0f, 300f);
|
||||
contentRect.pivot = Vector2.up;
|
||||
|
||||
ScrollRect scrollRect = scrollObj.AddComponent<ScrollRect>();
|
||||
scrollRect.content = contentRect;
|
||||
scrollRect.viewport = viewportRect;
|
||||
scrollRect.horizontalScrollbar = horiScroll.GetComponent<Scrollbar>();
|
||||
scrollRect.verticalScrollbar = vertScroll.GetComponent<Scrollbar>();
|
||||
scrollRect.horizontalScrollbarVisibility = ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport;
|
||||
scrollRect.verticalScrollbarVisibility = ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport;
|
||||
scrollRect.horizontalScrollbarSpacing = -3f;
|
||||
scrollRect.verticalScrollbarSpacing = -3f;
|
||||
|
||||
Image scrollImage = scrollObj.AddComponent<Image>();
|
||||
scrollImage.sprite = UIResources.background;
|
||||
scrollImage.type = Image.Type.Sliced;
|
||||
scrollImage.color = s_PanelColor;
|
||||
viewportObj.AddComponent<Mask>().showMaskGraphic = false;
|
||||
|
||||
Image viewportImage = viewportObj.AddComponent<Image>();
|
||||
viewportImage.sprite = UIResources.mask;
|
||||
viewportImage.type = Image.Type.Sliced;
|
||||
|
||||
return scrollObj;
|
||||
}
|
||||
}
|
||||
}
|
126
src/UI/UIManager.cs
Normal file
126
src/UI/UIManager.cs
Normal file
@ -0,0 +1,126 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ExplorerBeta.Input;
|
||||
using ExplorerBeta.UI.Main;
|
||||
using ExplorerBeta.UI.Shared;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace ExplorerBeta.UI
|
||||
{
|
||||
// This class itself is fine.
|
||||
|
||||
public static class UIManager
|
||||
{
|
||||
public static GameObject CanvasRoot { get; private set; }
|
||||
public static EventSystem EventSys { get; private set; }
|
||||
public static StandaloneInputModule InputModule { get; private set; }
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
var res = UIFactory.UIResources = new UIFactory.Resources();
|
||||
var bg = CreateSprite(MakeSolidTexture(new Color(0.1f, 0.1f, 0.1f), 1, 1), new Rect(0, 0, 1, 1));
|
||||
res.background = bg;
|
||||
|
||||
// Create core UI Canvas and Event System handler
|
||||
CreateRootCanvas();
|
||||
|
||||
// Create submodules
|
||||
new MainMenu();
|
||||
}
|
||||
|
||||
public static void SetEventSystem()
|
||||
{
|
||||
EventSystem.current = EventSys;
|
||||
InputModule.ActivateModule();
|
||||
}
|
||||
|
||||
private static GameObject CreateRootCanvas()
|
||||
{
|
||||
var rootObj = new GameObject("ExplorerCanvas");
|
||||
UnityEngine.Object.DontDestroyOnLoad(rootObj);
|
||||
rootObj.layer = 5;
|
||||
|
||||
CanvasRoot = rootObj;
|
||||
CanvasRoot.transform.position = new Vector3(0f, 0f, 1f);
|
||||
|
||||
EventSys = rootObj.AddComponent<EventSystem>();
|
||||
InputModule = rootObj.AddComponent<StandaloneInputModule>();
|
||||
InputModule.ActivateModule();
|
||||
|
||||
var canvas = rootObj.AddComponent<Canvas>();
|
||||
canvas.renderMode = RenderMode.ScreenSpaceCamera;
|
||||
canvas.referencePixelsPerUnit = 100;
|
||||
canvas.sortingOrder = 999;
|
||||
|
||||
var scaler = rootObj.AddComponent<CanvasScaler>();
|
||||
scaler.referenceResolution = new Vector2(1920, 1080);
|
||||
scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.Expand;
|
||||
|
||||
rootObj.AddComponent<GraphicRaycaster>();
|
||||
|
||||
return rootObj;
|
||||
}
|
||||
|
||||
public static void Update()
|
||||
{
|
||||
if (EventSys && InputModule)
|
||||
{
|
||||
if (EventSystem.current != EventSys)
|
||||
{
|
||||
ForceUnlockCursor.SetEventSystem();
|
||||
//ForceUnlockCursor.Unlock = true;
|
||||
}
|
||||
|
||||
// Fix for games which override the InputModule pointer events (eg, VRChat)
|
||||
if (InputModule.m_InputPointerEvent != null)
|
||||
{
|
||||
var evt = InputModule.m_InputPointerEvent;
|
||||
if (!evt.eligibleForClick && evt.selectedObject)
|
||||
{
|
||||
evt.eligibleForClick = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PanelDragger.Instance != null)
|
||||
{
|
||||
PanelDragger.Instance.Update();
|
||||
}
|
||||
}
|
||||
|
||||
public static void OnSceneChange()
|
||||
{
|
||||
// todo
|
||||
}
|
||||
|
||||
public static Sprite CreateSprite(Texture2D tex, Rect size)
|
||||
{
|
||||
#if CPP
|
||||
var pivot = Vector2.zero;
|
||||
var border = Vector4.zero;
|
||||
return Sprite.CreateSprite_Injected(tex, ref size, ref pivot, 100f, 0u, SpriteMeshType.Tight, ref border, false);
|
||||
#else
|
||||
return Sprite.Create(tex, size, Vector2.zero);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static Texture2D MakeSolidTexture(Color color, int width, int height)
|
||||
{
|
||||
var pixels = new Color[width * height];
|
||||
for (int i = 0; i < pixels.Length; i++)
|
||||
{
|
||||
pixels[i] = color;
|
||||
}
|
||||
|
||||
var tex = new Texture2D(width, height);
|
||||
tex.SetPixels(pixels);
|
||||
tex.Apply();
|
||||
|
||||
return tex;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Explorer.Config;
|
||||
using Explorer.UI.Inspectors;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public abstract class WindowBase
|
||||
{
|
||||
public abstract string Title { get; }
|
||||
|
||||
public object Target;
|
||||
|
||||
public int windowID;
|
||||
public Rect m_rect = new Rect(0, 0, ModConfig.Instance.Default_Window_Size.x, ModConfig.Instance.Default_Window_Size.y);
|
||||
|
||||
public Vector2 scroll = Vector2.zero;
|
||||
|
||||
public virtual bool IsTabViewWindow => false;
|
||||
|
||||
public abstract void Init();
|
||||
public abstract void WindowFunction(int windowID);
|
||||
public abstract void Update();
|
||||
|
||||
public static WindowBase CreateWindow<T>(object target) where T : WindowBase
|
||||
{
|
||||
var window = Activator.CreateInstance<T>();
|
||||
|
||||
window.Target = target;
|
||||
window.windowID = WindowManager.NextWindowID();
|
||||
window.m_rect = WindowManager.GetNewWindowRect();
|
||||
|
||||
WindowManager.Windows.Add(window);
|
||||
|
||||
window.Init();
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
public static StaticInspector CreateWindowStatic(Type type)
|
||||
{
|
||||
var window = new StaticInspector
|
||||
{
|
||||
TargetType = type,
|
||||
windowID = WindowManager.NextWindowID(),
|
||||
m_rect = WindowManager.GetNewWindowRect()
|
||||
};
|
||||
|
||||
WindowManager.Windows.Add(window);
|
||||
|
||||
window.Init();
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
public void DestroyWindow()
|
||||
{
|
||||
WindowManager.DestroyWindow(this);
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
#if CPP
|
||||
m_rect = GUI.Window(windowID, m_rect, (GUI.WindowFunction)WindowFunction, GUIContent.Temp(Title), GUI.skin.window);
|
||||
#else
|
||||
m_rect = GUI.Window(windowID, m_rect, WindowFunction, Title);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Header()
|
||||
{
|
||||
if (!WindowManager.TabView)
|
||||
{
|
||||
GUI.DragWindow(new Rect(0, 0, m_rect.width - 90, 20));
|
||||
|
||||
#if CPP
|
||||
if (GUI.Button(new Rect(m_rect.width - 90, 2, 80, 20), GUIContent.Temp("<color=red><b>X</b></color>"), GUI.skin.button))
|
||||
#else
|
||||
if (GUI.Button(new Rect(m_rect.width - 90, 2, 80, 20), "<color=red><b>X</b></color>", GUI.skin.button))
|
||||
#endif
|
||||
{
|
||||
DestroyWindow();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,234 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Explorer.UI.Inspectors;
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class WindowManager
|
||||
{
|
||||
public static WindowManager Instance;
|
||||
|
||||
public static bool TabView = Config.ModConfig.Instance.Tab_View;
|
||||
|
||||
public static bool IsMouseInWindow
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!ExplorerCore.ShowMenu)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var window in Windows)
|
||||
{
|
||||
if (RectContainsMouse(window.m_rect))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return RectContainsMouse(MainMenu.MainRect);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<WindowBase> Windows = new List<WindowBase>();
|
||||
public static int CurrentWindowID { get; set; } = 500000;
|
||||
private static Rect m_lastWindowRect;
|
||||
|
||||
private static readonly List<WindowBase> m_windowsToDestroy = new List<WindowBase>();
|
||||
|
||||
public WindowManager()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public static void DestroyWindow(WindowBase window)
|
||||
{
|
||||
m_windowsToDestroy.Add(window);
|
||||
}
|
||||
|
||||
public static WindowBase InspectObject(object obj, out bool createdNew, bool forceReflection = false)
|
||||
{
|
||||
createdNew = false;
|
||||
|
||||
//if (InputManager.GetKey(KeyCode.LeftShift))
|
||||
//{
|
||||
// forceReflection = true;
|
||||
//}
|
||||
|
||||
#if CPP
|
||||
Il2CppSystem.Object iObj = null;
|
||||
if (obj is Il2CppSystem.Object isObj)
|
||||
{
|
||||
iObj = isObj;
|
||||
}
|
||||
#else
|
||||
var iObj = obj;
|
||||
#endif
|
||||
|
||||
if (!forceReflection)
|
||||
{
|
||||
foreach (var window in Windows)
|
||||
{
|
||||
bool equals = ReferenceEquals(obj, window.Target);
|
||||
|
||||
#if CPP
|
||||
if (!equals && iObj is Il2CppSystem.Object iCurrent && window.Target is Il2CppSystem.Object iTarget)
|
||||
{
|
||||
if (iCurrent.GetIl2CppType().FullName != iTarget.GetIl2CppType().FullName)
|
||||
{
|
||||
if (iCurrent is Transform transform)
|
||||
{
|
||||
iCurrent = transform.gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
equals = iCurrent.Pointer == iTarget.Pointer;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (equals)
|
||||
{
|
||||
FocusWindow(window);
|
||||
return window;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createdNew = true;
|
||||
if (!forceReflection && (obj is GameObject || obj is Transform))
|
||||
{
|
||||
return InspectGameObject(obj as GameObject ?? (obj as Transform).gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
return InspectReflection(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private static void FocusWindow(WindowBase window)
|
||||
{
|
||||
if (!TabView)
|
||||
{
|
||||
GUIHelper.BringWindowToFront(window.windowID);
|
||||
GUI.FocusWindow(window.windowID);
|
||||
}
|
||||
else
|
||||
{
|
||||
TabViewWindow.Instance.TargetTabID = Windows.IndexOf(window);
|
||||
}
|
||||
}
|
||||
|
||||
private static WindowBase InspectGameObject(GameObject obj)
|
||||
{
|
||||
var new_window = WindowBase.CreateWindow<GameObjectInspector>(obj);
|
||||
FocusWindow(new_window);
|
||||
|
||||
return new_window;
|
||||
}
|
||||
|
||||
private static WindowBase InspectReflection(object obj)
|
||||
{
|
||||
var new_window = WindowBase.CreateWindow<InstanceInspector>(obj);
|
||||
FocusWindow(new_window);
|
||||
|
||||
return new_window;
|
||||
}
|
||||
|
||||
public static StaticInspector InspectStaticReflection(Type type)
|
||||
{
|
||||
var new_window = WindowBase.CreateWindowStatic(type);
|
||||
FocusWindow(new_window);
|
||||
|
||||
return new_window;
|
||||
}
|
||||
|
||||
private static bool RectContainsMouse(Rect rect)
|
||||
{
|
||||
var mousePos = InputManager.MousePosition;
|
||||
return rect.Contains(new Vector2(mousePos.x, Screen.height - mousePos.y));
|
||||
}
|
||||
|
||||
public static int NextWindowID()
|
||||
{
|
||||
return CurrentWindowID++;
|
||||
}
|
||||
|
||||
public static Rect GetNewWindowRect()
|
||||
{
|
||||
return GetNewWindowRect(ref m_lastWindowRect);
|
||||
}
|
||||
|
||||
public static Rect GetNewWindowRect(ref Rect lastRect)
|
||||
{
|
||||
Rect rect = new Rect(0, 0, 550, 700);
|
||||
|
||||
var mainrect = MainMenu.MainRect;
|
||||
if (mainrect.x <= (Screen.width - mainrect.width - 100))
|
||||
{
|
||||
rect = new Rect(mainrect.x + mainrect.width + 20, mainrect.y, rect.width, rect.height);
|
||||
}
|
||||
|
||||
if (lastRect.x == rect.x)
|
||||
{
|
||||
rect = new Rect(rect.x + 25, rect.y + 25, rect.width, rect.height);
|
||||
}
|
||||
|
||||
lastRect = rect;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
// ============= instance methods ===============
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (m_windowsToDestroy.Count > 0)
|
||||
{
|
||||
foreach (var window in m_windowsToDestroy)
|
||||
{
|
||||
if (Windows.Contains(window))
|
||||
{
|
||||
Windows.Remove(window);
|
||||
}
|
||||
}
|
||||
|
||||
m_windowsToDestroy.Clear();
|
||||
}
|
||||
|
||||
if (TabView)
|
||||
{
|
||||
TabViewWindow.Instance.Update();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < Windows.Count; i++)
|
||||
{
|
||||
var window = Windows[i];
|
||||
if (window != null)
|
||||
{
|
||||
window.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnGUI()
|
||||
{
|
||||
if (TabView)
|
||||
{
|
||||
if (Windows.Count > 0)
|
||||
{
|
||||
TabViewWindow.Instance.OnGUI();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var window in Windows)
|
||||
{
|
||||
window.OnGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user