mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-15 22:07:48 +08:00
Progress on ReflectionInspector, framework mostly done
This commit is contained in:
parent
a2ff37e36d
commit
b0d54b1d80
@ -20,7 +20,6 @@ namespace UnityExplorer.Core.Config
|
||||
public static ConfigElement<bool> Force_Unlock_Mouse;
|
||||
public static ConfigElement<KeyCode> Force_Unlock_Keybind;
|
||||
public static ConfigElement<bool> Aggressive_Force_Unlock;
|
||||
//public static ConfigElement<MenuPages> Default_Tab;
|
||||
public static ConfigElement<int> Default_Page_Limit;
|
||||
public static ConfigElement<string> Default_Output_Path;
|
||||
public static ConfigElement<bool> Log_Unity_Debug;
|
||||
@ -84,7 +83,7 @@ namespace UnityExplorer.Core.Config
|
||||
|
||||
Force_Unlock_Keybind = new ConfigElement<KeyCode>("Force Unlock Keybind",
|
||||
"The keybind to toggle the 'Force Unlock Mouse' setting. Only usable when UnityExplorer is open.",
|
||||
KeyCode.F6);
|
||||
KeyCode.None);
|
||||
|
||||
Aggressive_Force_Unlock = new ConfigElement<bool>("Aggressive Mouse Unlock",
|
||||
"Use Camera.onPostRender callback to aggressively force the Mouse to be unlocked (requires game restart).",
|
||||
|
@ -20,8 +20,19 @@ namespace UnityExplorer.Core.Input
|
||||
|
||||
public static Vector3 MousePosition => m_inputModule.MousePosition;
|
||||
|
||||
public static bool GetKeyDown(KeyCode key) => m_inputModule.GetKeyDown(key);
|
||||
public static bool GetKey(KeyCode key) => m_inputModule.GetKey(key);
|
||||
public static bool GetKeyDown(KeyCode key)
|
||||
{
|
||||
if (key == KeyCode.None)
|
||||
return false;
|
||||
return m_inputModule.GetKeyDown(key);
|
||||
}
|
||||
|
||||
public static bool GetKey(KeyCode key)
|
||||
{
|
||||
if (key == KeyCode.None)
|
||||
return false;
|
||||
return m_inputModule.GetKey(key);
|
||||
}
|
||||
|
||||
public static bool GetMouseButtonDown(int btn) => m_inputModule.GetMouseButtonDown(btn);
|
||||
public static bool GetMouseButton(int btn) => m_inputModule.GetMouseButton(btn);
|
||||
|
@ -69,7 +69,8 @@ namespace UnityExplorer
|
||||
/// <param name="t">The Type to check</param>
|
||||
/// <returns>True if the Type is assignable to IEnumerable, otherwise false.</returns>
|
||||
public static bool IsEnumerable(this Type t)
|
||||
=> ReflectionProvider.Instance.IsAssignableFrom(typeof(IEnumerable), t);
|
||||
=> !typeof(UnityEngine.Transform).IsAssignableFrom(t)
|
||||
&& ReflectionProvider.Instance.IsAssignableFrom(typeof(IEnumerable), t);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the provided Type is assignable to IDictionary.
|
||||
|
@ -7,15 +7,16 @@ namespace UnityExplorer.Tests
|
||||
{
|
||||
public static class TestClass
|
||||
{
|
||||
static TestClass()
|
||||
{
|
||||
List = new List<string>();
|
||||
for (int i = 0; i < 10000; i++)
|
||||
List.Add(i.ToString());
|
||||
}
|
||||
|
||||
public static List<string> List;
|
||||
|
||||
public const int ConstantInt = 5;
|
||||
|
||||
public static string LongString = @"#######################################################################################################
|
||||
###############################################################################################################################
|
||||
#####################################################################################################################################
|
||||
#########################################################################################################################
|
||||
######################################################################################################";
|
||||
|
||||
#if CPP
|
||||
public static string testStringOne = "Test";
|
||||
public static Il2CppSystem.Object testStringTwo = "string boxed as cpp object";
|
||||
@ -24,9 +25,15 @@ namespace UnityExplorer.Tests
|
||||
|
||||
public static Il2CppSystem.Collections.Hashtable testHashset;
|
||||
public static Il2CppSystem.Collections.Generic.List<Il2CppSystem.Object> testList;
|
||||
#endif
|
||||
|
||||
static TestClass()
|
||||
{
|
||||
List = new List<string>();
|
||||
for (int i = 0; i < 10000; i++)
|
||||
List.Add(i.ToString());
|
||||
|
||||
#if CPP
|
||||
testHashset = new Il2CppSystem.Collections.Hashtable();
|
||||
testHashset.Add("key1", "itemOne");
|
||||
testHashset.Add("key2", "itemTwo");
|
||||
@ -36,8 +43,7 @@ namespace UnityExplorer.Tests
|
||||
testList.Add("One");
|
||||
testList.Add("Two");
|
||||
testList.Add("Three");
|
||||
//testIList = list.TryCast<Il2CppSystem.Collections.IList>();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,44 +2,40 @@
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.Core.Config;
|
||||
using UnityExplorer.Core.Input;
|
||||
using UnityExplorer.Core.Runtime;
|
||||
using UnityExplorer.Tests;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.UI.Panels;
|
||||
|
||||
namespace UnityExplorer
|
||||
{
|
||||
public class ExplorerCore
|
||||
public static class ExplorerCore
|
||||
{
|
||||
public const string NAME = "UnityExplorer";
|
||||
public const string VERSION = "3.4.0";
|
||||
public const string AUTHOR = "Sinai";
|
||||
public const string GUID = "com.sinai.unityexplorer";
|
||||
|
||||
public static ExplorerCore Instance { get; private set; }
|
||||
|
||||
public static IExplorerLoader Loader { get; private set; }
|
||||
public static RuntimeContext Context { get; internal set; }
|
||||
|
||||
// Prevent using ctor, must use Init method.
|
||||
private ExplorerCore() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize UnityExplorer with the provided Loader implementation.
|
||||
/// </summary>
|
||||
public static void Init(IExplorerLoader loader)
|
||||
{
|
||||
if (Instance != null)
|
||||
if (Loader != null)
|
||||
{
|
||||
Log("An instance of UnityExplorer is already active!");
|
||||
LogWarning("UnityExplorer is already loaded!");
|
||||
return;
|
||||
}
|
||||
|
||||
Loader = loader;
|
||||
Instance = new ExplorerCore();
|
||||
|
||||
if (!Directory.Exists(Loader.ExplorerFolder))
|
||||
Directory.CreateDirectory(Loader.ExplorerFolder);
|
||||
@ -69,7 +65,9 @@ namespace UnityExplorer
|
||||
|
||||
UIManager.InitUI();
|
||||
|
||||
//InspectorManager.Inspect(typeof(TestClass));
|
||||
InspectorManager.Inspect(typeof(TestClass));
|
||||
//InspectorManager.Inspect(UIManager.CanvasRoot.gameObject.GetComponent<GraphicRaycaster>());
|
||||
//InspectorManager.InspectType(typeof(ReflectionUtility));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -10,11 +10,14 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
|
||||
{
|
||||
public FieldInfo FieldInfo { get; internal set; }
|
||||
|
||||
public override bool ShouldAutoEvaluate => true;
|
||||
|
||||
public override void Initialize(ReflectionInspector inspector, Type declaringType, MemberInfo member, Type returnType)
|
||||
{
|
||||
base.Initialize(inspector, declaringType, member, returnType);
|
||||
|
||||
CanWrite = true;
|
||||
// not constant
|
||||
CanWrite = !(FieldInfo.IsLiteral && !FieldInfo.IsInitOnly);
|
||||
}
|
||||
|
||||
protected override void TryEvaluate()
|
||||
|
@ -3,11 +3,15 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityExplorer.UI.Inspectors.CacheObject.Views;
|
||||
using UnityExplorer.UI.Utility;
|
||||
|
||||
namespace UnityExplorer.UI.Inspectors.CacheObject
|
||||
{
|
||||
// TODO some of this can be reused for CacheEnumerated / CacheKVP as well, just doing members for now.
|
||||
// Will put shared stuff in CacheObjectBase.
|
||||
|
||||
public abstract class CacheMember : CacheObjectBase
|
||||
{
|
||||
public ReflectionInspector ParentInspector { get; internal set; }
|
||||
@ -18,8 +22,9 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
|
||||
public object Value { get; protected set; }
|
||||
public Type FallbackType { get; private set; }
|
||||
|
||||
public bool HasEvaluated { get; protected set; }
|
||||
public bool HasArguments { get; protected set; }
|
||||
public abstract bool ShouldAutoEvaluate { get; }
|
||||
public bool HasArguments => Arguments?.Length > 0;
|
||||
public ParameterInfo[] Arguments { get; protected set; }
|
||||
public bool Evaluating { get; protected set; }
|
||||
public bool CanWrite { get; protected set; }
|
||||
public bool HadException { get; protected set; }
|
||||
@ -29,6 +34,20 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
|
||||
public string TypeLabelText { get; protected set; }
|
||||
public string ValueLabelText { get; protected set; }
|
||||
|
||||
public enum ValueState
|
||||
{
|
||||
NotEvaluated, Exception, NullValue,
|
||||
Boolean, Number, String, Enum,
|
||||
Collection, ValueStruct, Unsupported
|
||||
}
|
||||
|
||||
protected ValueState State = ValueState.NotEvaluated;
|
||||
|
||||
private const string NOT_YET_EVAL = "<color=grey>Not yet evaluated</color>";
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the CacheMember when an Inspector is opened and caches the member
|
||||
/// </summary>
|
||||
public virtual void Initialize(ReflectionInspector inspector, Type declaringType, MemberInfo member, Type returnType)
|
||||
{
|
||||
this.DeclaringType = declaringType;
|
||||
@ -36,72 +55,183 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
|
||||
this.FallbackType = returnType;
|
||||
this.MemberLabelText = SignatureHighlighter.ParseFullSyntax(declaringType, false, member);
|
||||
this.NameForFiltering = $"{declaringType.Name}.{member.Name}";
|
||||
this.TypeLabelText = SignatureHighlighter.HighlightTypeName(returnType);
|
||||
this.TypeLabelText = SignatureHighlighter.HighlightTypeName(FallbackType, false);
|
||||
this.ValueLabelText = GetValueLabel();
|
||||
}
|
||||
|
||||
public void SetCell(CacheMemberCell cell)
|
||||
public virtual void OnDestroyed()
|
||||
{
|
||||
cell.MemberLabel.text = MemberLabelText;
|
||||
cell.TypeLabel.text = TypeLabelText;
|
||||
|
||||
if (HasArguments && !HasEvaluated)
|
||||
{
|
||||
// todo
|
||||
cell.ValueLabel.text = "Not yet evalulated";
|
||||
}
|
||||
else if (!HasEvaluated)
|
||||
Evaluate();
|
||||
|
||||
if (HadException)
|
||||
{
|
||||
cell.InspectButton.Button.gameObject.SetActive(false);
|
||||
cell.ValueLabel.gameObject.SetActive(true);
|
||||
cell.ValueLabel.supportRichText = true;
|
||||
cell.ValueLabel.text = $"<color=red>{ReflectionUtility.ReflectionExToString(LastException)}</color>";
|
||||
}
|
||||
else if (Value.IsNullOrDestroyed())
|
||||
{
|
||||
cell.InspectButton.Button.gameObject.SetActive(false);
|
||||
cell.ValueLabel.gameObject.SetActive(true);
|
||||
cell.ValueLabel.supportRichText = true;
|
||||
cell.ValueLabel.text = ValueLabelText;
|
||||
}
|
||||
else
|
||||
{
|
||||
cell.ValueLabel.supportRichText = false;
|
||||
cell.ValueLabel.text = ValueLabelText;
|
||||
|
||||
var valueType = Value.GetActualType();
|
||||
if (valueType.IsPrimitive || valueType == typeof(decimal))
|
||||
{
|
||||
cell.InspectButton.Button.gameObject.SetActive(false);
|
||||
cell.ValueLabel.gameObject.SetActive(true);
|
||||
}
|
||||
else if (valueType == typeof(string))
|
||||
{
|
||||
cell.InspectButton.Button.gameObject.SetActive(false);
|
||||
cell.ValueLabel.gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
cell.InspectButton.Button.gameObject.SetActive(true);
|
||||
cell.ValueLabel.gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
// TODO release IValue / Evaluate back to pool, etc
|
||||
}
|
||||
|
||||
protected abstract void TryEvaluate();
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate when first shown (if ShouldAutoEvaluate), or else when Evaluate button is clicked.
|
||||
/// </summary>
|
||||
public void Evaluate()
|
||||
{
|
||||
TryEvaluate();
|
||||
|
||||
if (!HadException)
|
||||
ProcessOnEvaluate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process the CacheMember state when the value has been evaluated (or re-evaluated)
|
||||
/// </summary>
|
||||
protected virtual void ProcessOnEvaluate()
|
||||
{
|
||||
var prevState = State;
|
||||
|
||||
if (HadException)
|
||||
State = ValueState.Exception;
|
||||
else if (Value.IsNullOrDestroyed())
|
||||
State = ValueState.NullValue;
|
||||
else
|
||||
{
|
||||
ValueLabelText = ToStringUtility.ToString(Value, FallbackType);
|
||||
var type = Value.GetActualType();
|
||||
|
||||
if (type == typeof(bool))
|
||||
State = ValueState.Boolean;
|
||||
else if (type.IsPrimitive || type == typeof(decimal))
|
||||
State = ValueState.Number;
|
||||
else if (type == typeof(string))
|
||||
State = ValueState.String;
|
||||
else if (type.IsEnum)
|
||||
State = ValueState.Enum;
|
||||
else if (type.IsEnumerable() || type.IsDictionary())
|
||||
State = ValueState.Collection;
|
||||
// todo Color and ValueStruct
|
||||
else
|
||||
State = ValueState.Unsupported;
|
||||
}
|
||||
|
||||
HasEvaluated = true;
|
||||
// Set label text
|
||||
ValueLabelText = GetValueLabel();
|
||||
|
||||
if (State != prevState)
|
||||
{
|
||||
// TODO handle if subcontent / evaluate shown, check type change, etc
|
||||
}
|
||||
}
|
||||
|
||||
private string GetValueLabel()
|
||||
{
|
||||
switch (State)
|
||||
{
|
||||
case ValueState.NotEvaluated:
|
||||
return $"<i>{NOT_YET_EVAL} ({SignatureHighlighter.HighlightTypeName(FallbackType, true)})</i>";
|
||||
case ValueState.Exception:
|
||||
return $"<i><color=red>{ReflectionUtility.ReflectionExToString(LastException)}</color></i>";
|
||||
case ValueState.Boolean:
|
||||
case ValueState.Number:
|
||||
return null;
|
||||
case ValueState.String:
|
||||
string s = Value as string;
|
||||
if (s.Length > 200)
|
||||
s = $"{s.Substring(0, 200)}...";
|
||||
return $"\"{s}\"";
|
||||
case ValueState.NullValue:
|
||||
return $"<i>{ToStringUtility.ToStringWithType(Value, FallbackType, true)}</i>";
|
||||
case ValueState.Enum:
|
||||
case ValueState.Collection:
|
||||
case ValueState.ValueStruct:
|
||||
case ValueState.Unsupported:
|
||||
default:
|
||||
return ToStringUtility.ToStringWithType(Value, FallbackType, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the cell view for an enabled cell based on this CacheMember model.
|
||||
/// </summary>
|
||||
public void SetCell(CacheMemberCell cell)
|
||||
{
|
||||
cell.MemberLabel.text = MemberLabelText;
|
||||
cell.ValueLabel.gameObject.SetActive(true);
|
||||
|
||||
cell.EvaluateHolder.SetActive(!ShouldAutoEvaluate);
|
||||
if (!ShouldAutoEvaluate)
|
||||
{
|
||||
cell.EvaluateButton.Button.gameObject.SetActive(true);
|
||||
if (HasArguments)
|
||||
cell.EvaluateButton.ButtonText.text = $"Evaluate ({Arguments.Length})";
|
||||
else
|
||||
cell.EvaluateButton.ButtonText.text = "Evaluate";
|
||||
}
|
||||
|
||||
if (State == ValueState.NotEvaluated && !ShouldAutoEvaluate)
|
||||
{
|
||||
// todo evaluate buttons etc
|
||||
SetCellState(cell, true, true, Color.white, false, false, false, false, false, false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (State == ValueState.NotEvaluated)
|
||||
Evaluate();
|
||||
|
||||
switch (State)
|
||||
{
|
||||
case ValueState.Exception:
|
||||
case ValueState.NullValue:
|
||||
SetCellState(cell, true, true, Color.white, false, false, false, false, false, false);
|
||||
break;
|
||||
case ValueState.Boolean:
|
||||
SetCellState(cell, false, false, default, true, toggleActive: true, false, CanWrite, false, false);
|
||||
break;
|
||||
case ValueState.Number:
|
||||
SetCellState(cell, false, true, Color.white, true, false, inputActive: true, CanWrite, false, false);
|
||||
break;
|
||||
case ValueState.String:
|
||||
SetCellState(cell, true, false, SignatureHighlighter.StringOrange, false, false, false, false, false, true);
|
||||
break;
|
||||
case ValueState.Enum:
|
||||
SetCellState(cell, true, true, Color.white, false, false, false, false, false, true);
|
||||
break;
|
||||
case ValueState.Collection:
|
||||
case ValueState.ValueStruct:
|
||||
SetCellState(cell, true, true, Color.white, false, false, false, false, true, true);
|
||||
break;
|
||||
case ValueState.Unsupported:
|
||||
SetCellState(cell, true, true, Color.white, false, false, false, false, true, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetCellState(CacheMemberCell cell, bool valueActive, bool valueRichText, Color valueColor,
|
||||
bool typeLabelActive, bool toggleActive, bool inputActive, bool applyActive, bool inspectActive, bool subContentActive)
|
||||
{
|
||||
//cell.ValueLabel.gameObject.SetActive(valueActive);
|
||||
if (valueActive)
|
||||
{
|
||||
cell.ValueLabel.text = ValueLabelText;
|
||||
cell.ValueLabel.supportRichText = valueRichText;
|
||||
cell.ValueLabel.color = valueColor;
|
||||
}
|
||||
else
|
||||
cell.ValueLabel.text = "";
|
||||
|
||||
cell.TypeLabel.gameObject.SetActive(typeLabelActive);
|
||||
if (typeLabelActive)
|
||||
cell.TypeLabel.text = TypeLabelText;
|
||||
|
||||
cell.Toggle.gameObject.SetActive(toggleActive);
|
||||
if (toggleActive)
|
||||
{
|
||||
cell.Toggle.isOn = (bool)Value;
|
||||
cell.ToggleText.text = Value.ToString();
|
||||
}
|
||||
|
||||
cell.InputField.gameObject.SetActive(inputActive);
|
||||
if (inputActive)
|
||||
cell.InputField.text = Value.ToString();
|
||||
|
||||
cell.ApplyButton.Button.gameObject.SetActive(applyActive);
|
||||
cell.InspectButton.Button.gameObject.SetActive(inspectActive);
|
||||
cell.SubContentButton.Button.gameObject.SetActive(subContentActive);
|
||||
|
||||
cell.UpdateButton.Button.gameObject.SetActive(ShouldAutoEvaluate);
|
||||
}
|
||||
|
||||
|
||||
@ -144,9 +274,10 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
|
||||
target = target.TryCast(declaringType);
|
||||
|
||||
infos.Clear();
|
||||
infos.AddRange(declaringType.GetMethods(flags));
|
||||
infos.AddRange(declaringType.GetProperties(flags));
|
||||
infos.AddRange(declaringType.GetFields(flags));
|
||||
infos.AddRange(declaringType.GetEvents(flags));
|
||||
infos.AddRange(declaringType.GetMethods(flags));
|
||||
|
||||
foreach (var member in infos)
|
||||
{
|
||||
|
@ -10,11 +10,13 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
|
||||
{
|
||||
public MethodInfo MethodInfo { get; internal set; }
|
||||
|
||||
public override bool ShouldAutoEvaluate => false;
|
||||
|
||||
public override void Initialize(ReflectionInspector inspector, Type declaringType, MemberInfo member, Type returnType)
|
||||
{
|
||||
base.Initialize(inspector, declaringType, member, returnType);
|
||||
|
||||
|
||||
Arguments = MethodInfo.GetParameters();
|
||||
}
|
||||
|
||||
protected override void TryEvaluate()
|
||||
|
@ -10,11 +10,14 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
|
||||
{
|
||||
public PropertyInfo PropertyInfo { get; internal set; }
|
||||
|
||||
public override bool ShouldAutoEvaluate => !HasArguments;
|
||||
|
||||
public override void Initialize(ReflectionInspector inspector, Type declaringType, MemberInfo member, Type returnType)
|
||||
{
|
||||
base.Initialize(inspector, declaringType, member, returnType);
|
||||
|
||||
|
||||
this.CanWrite = PropertyInfo.CanWrite;
|
||||
Arguments = PropertyInfo.GetIndexParameters();
|
||||
}
|
||||
|
||||
protected override void TryEvaluate()
|
||||
|
@ -4,10 +4,13 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.Inspectors.CacheObject.Views
|
||||
{
|
||||
// Todo add C# events for the unity UI listeners
|
||||
|
||||
public class CacheMemberCell : ICell
|
||||
{
|
||||
#region ICell
|
||||
@ -38,26 +41,83 @@ namespace UnityExplorer.UI.Inspectors.CacheObject.Views
|
||||
#endregion
|
||||
|
||||
public ReflectionInspector CurrentOwner { get; set; }
|
||||
public int CurrentDataIndex { get; set; }
|
||||
public CacheMember CurrentOccupant { get; set; }
|
||||
|
||||
public Action<CacheMember> OnApplyClicked;
|
||||
public Action<CacheMember> OnInspectClicked;
|
||||
public Action<CacheMember> OnSubContentClicked;
|
||||
public Action<CacheMember> OnUpdateClicked;
|
||||
public Action<CacheMember> OnEvaluateClicked;
|
||||
|
||||
public LayoutElement MemberLayout;
|
||||
public LayoutElement ReturnTypeLayout;
|
||||
public LayoutElement RightGroupLayout;
|
||||
|
||||
public Text MemberLabel;
|
||||
public Text TypeLabel;
|
||||
|
||||
public GameObject RightGroupHolder;
|
||||
public ButtonRef InspectButton;
|
||||
//public GameObject RightGroupHolder;
|
||||
public Text TypeLabel;
|
||||
public Text ValueLabel;
|
||||
public Toggle Toggle;
|
||||
public Text ToggleText;
|
||||
public InputField InputField;
|
||||
|
||||
public GameObject EvaluateHolder;
|
||||
public ButtonRef EvaluateButton;
|
||||
|
||||
public ButtonRef InspectButton;
|
||||
public ButtonRef SubContentButton;
|
||||
public ButtonRef ApplyButton;
|
||||
public ButtonRef UpdateButton;
|
||||
|
||||
public GameObject SubContentHolder;
|
||||
|
||||
public void OnReturnToPool()
|
||||
{
|
||||
// remove listeners
|
||||
OnApplyClicked = null;
|
||||
OnInspectClicked = null;
|
||||
OnSubContentClicked = null;
|
||||
OnUpdateClicked = null;
|
||||
OnEvaluateClicked = null;
|
||||
|
||||
CurrentOwner = null;
|
||||
}
|
||||
|
||||
private void ApplyClicked()
|
||||
{
|
||||
OnApplyClicked?.Invoke(CurrentOccupant);
|
||||
}
|
||||
|
||||
private void InspectClicked()
|
||||
{
|
||||
OnInspectClicked?.Invoke(CurrentOccupant);
|
||||
}
|
||||
|
||||
private void SubContentClicked()
|
||||
{
|
||||
OnSubContentClicked?.Invoke(CurrentOccupant);
|
||||
}
|
||||
|
||||
private void UpdateClicked()
|
||||
{
|
||||
OnUpdateClicked?.Invoke(CurrentOccupant);
|
||||
}
|
||||
|
||||
private void EvaluateClicked()
|
||||
{
|
||||
OnEvaluateClicked?.Invoke(CurrentOccupant);
|
||||
}
|
||||
|
||||
private void ToggleClicked(bool value)
|
||||
{
|
||||
ToggleText.text = value.ToString();
|
||||
}
|
||||
|
||||
public GameObject CreateContent(GameObject parent)
|
||||
{
|
||||
uiRoot = UIFactory.CreateUIObject("CacheMemberCell", parent, new Vector2(100, 30));
|
||||
m_rect = uiRoot.GetComponent<RectTransform>();
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(uiRoot, true, true, true, true, 2, 0);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(uiRoot, true, false, true, true, 2, 0);
|
||||
UIFactory.SetLayoutElement(uiRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 600);
|
||||
UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
@ -67,31 +127,64 @@ namespace UnityExplorer.UI.Inspectors.CacheObject.Views
|
||||
|
||||
var horiRow = UIFactory.CreateUIObject("HoriGroup", uiRoot);
|
||||
UIFactory.SetLayoutElement(horiRow, minHeight: 29, flexibleHeight: 150, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(horiRow, false, true, true, true, 5, 2, childAlignment: TextAnchor.UpperLeft);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(horiRow, false, false, true, true, 5, 2, childAlignment: TextAnchor.UpperLeft);
|
||||
horiRow.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
MemberLabel = UIFactory.CreateLabel(horiRow, "MemberLabel", "<notset>", TextAnchor.UpperLeft);
|
||||
MemberLabel = UIFactory.CreateLabel(horiRow, "MemberLabel", "<notset>", TextAnchor.MiddleLeft);
|
||||
MemberLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
UIFactory.SetLayoutElement(MemberLabel.gameObject, minHeight: 25, minWidth: 20, flexibleHeight: 300, flexibleWidth: 0);
|
||||
MemberLayout = MemberLabel.GetComponent<LayoutElement>();
|
||||
|
||||
TypeLabel = UIFactory.CreateLabel(horiRow, "ReturnLabel", "<notset>", TextAnchor.UpperLeft);
|
||||
var rightGroupHolder = UIFactory.CreateUIObject("RightGroup", horiRow);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(rightGroupHolder, false, false, true, true, 4, childAlignment: TextAnchor.UpperLeft);
|
||||
UIFactory.SetLayoutElement(rightGroupHolder, minHeight: 25, minWidth: 200, flexibleWidth: 9999, flexibleHeight: 800);
|
||||
RightGroupLayout = rightGroupHolder.GetComponent<LayoutElement>();
|
||||
|
||||
EvaluateHolder = UIFactory.CreateUIObject("EvalGroup", rightGroupHolder);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(EvaluateHolder, false, false, true, true, 3);
|
||||
UIFactory.SetLayoutElement(EvaluateHolder, minHeight: 25, flexibleWidth: 9999, flexibleHeight: 775);
|
||||
|
||||
EvaluateButton = UIFactory.CreateButton(EvaluateHolder, "EvaluateButton", "Evaluate", new Color(0.15f, 0.15f, 0.15f));
|
||||
UIFactory.SetLayoutElement(EvaluateButton.Button.gameObject, minWidth: 100, minHeight: 25);
|
||||
EvaluateButton.OnClick += EvaluateClicked;
|
||||
|
||||
var rightHoriGroup = UIFactory.CreateUIObject("RightHoriGroup", rightGroupHolder);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(rightHoriGroup, false, false, true, true, 4, childAlignment: TextAnchor.UpperLeft);
|
||||
UIFactory.SetLayoutElement(rightHoriGroup, minHeight: 25, minWidth: 200, flexibleWidth: 9999, flexibleHeight: 800);
|
||||
|
||||
SubContentButton = UIFactory.CreateButton(rightHoriGroup, "SubContentButton", "▲");
|
||||
UIFactory.SetLayoutElement(SubContentButton.Button.gameObject, minWidth: 25, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0);
|
||||
SubContentButton.OnClick += SubContentClicked;
|
||||
|
||||
TypeLabel = UIFactory.CreateLabel(rightHoriGroup, "ReturnLabel", "<notset>", TextAnchor.MiddleLeft);
|
||||
TypeLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
UIFactory.SetLayoutElement(TypeLabel.gameObject, minHeight: 25, flexibleHeight: 150, minWidth: 20, flexibleWidth: 0);
|
||||
ReturnTypeLayout = TypeLabel.GetComponent<LayoutElement>();
|
||||
UIFactory.SetLayoutElement(TypeLabel.gameObject, minHeight: 25, flexibleHeight: 150, minWidth: 70, flexibleWidth: 0);
|
||||
//ReturnTypeLayout = TypeLabel.GetComponent<LayoutElement>();
|
||||
|
||||
RightGroupHolder = UIFactory.CreateUIObject("RightGroup", horiRow);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(RightGroupHolder, false, false, true, true, 4, childAlignment: TextAnchor.UpperLeft);
|
||||
UIFactory.SetLayoutElement(RightGroupHolder, minHeight: 25, minWidth: 200, flexibleWidth: 9999, flexibleHeight: 150);
|
||||
RightGroupLayout = RightGroupHolder.GetComponent<LayoutElement>();
|
||||
var toggleObj = UIFactory.CreateToggle(rightHoriGroup, "Toggle", out Toggle, out ToggleText);
|
||||
UIFactory.SetLayoutElement(toggleObj, minWidth: 70, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0);
|
||||
ToggleText.color = SignatureHighlighter.KeywordBlue;
|
||||
Toggle.onValueChanged.AddListener(ToggleClicked);
|
||||
|
||||
InspectButton = UIFactory.CreateButton(RightGroupHolder, "InspectButton", "Inspect", new Color(0.23f, 0.23f, 0.23f));
|
||||
var inputObj = UIFactory.CreateInputField(rightHoriGroup, "InputField", "...", out InputField);
|
||||
UIFactory.SetLayoutElement(inputObj, minWidth: 150, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0);
|
||||
|
||||
InspectButton = UIFactory.CreateButton(rightHoriGroup, "InspectButton", "Inspect", new Color(0.15f, 0.15f, 0.15f));
|
||||
UIFactory.SetLayoutElement(InspectButton.Button.gameObject, minWidth: 60, flexibleWidth: 0, minHeight: 25);
|
||||
InspectButton.OnClick += InspectClicked;
|
||||
|
||||
ValueLabel = UIFactory.CreateLabel(RightGroupHolder, "ValueLabel", "Value goes here", TextAnchor.MiddleLeft);
|
||||
ApplyButton = UIFactory.CreateButton(rightHoriGroup, "ApplyButton", "Apply", new Color(0.15f, 0.15f, 0.15f));
|
||||
UIFactory.SetLayoutElement(ApplyButton.Button.gameObject, minWidth: 70, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0);
|
||||
ApplyButton.OnClick += ApplyClicked;
|
||||
|
||||
ValueLabel = UIFactory.CreateLabel(rightHoriGroup, "ValueLabel", "Value goes here", TextAnchor.MiddleLeft);
|
||||
ValueLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
UIFactory.SetLayoutElement(ValueLabel.gameObject, minHeight: 25, flexibleHeight: 150, flexibleWidth: 9999);
|
||||
|
||||
UpdateButton = UIFactory.CreateButton(rightHoriGroup, "UpdateButton", "Update", new Color(0.15f, 0.2f, 0.15f));
|
||||
UIFactory.SetLayoutElement(UpdateButton.Button.gameObject, minWidth: 65, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0);
|
||||
UpdateButton.OnClick += UpdateClicked;
|
||||
|
||||
// Subcontent (todo?)
|
||||
|
||||
SubContentHolder = UIFactory.CreateUIObject("SubContent", uiRoot);
|
||||
|
@ -29,7 +29,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
CreateInspector<ReflectionInspector>(obj);
|
||||
}
|
||||
|
||||
public static void InspectStatic(Type type)
|
||||
public static void Inspect(Type type)
|
||||
{
|
||||
CreateInspector<ReflectionInspector>(type, true);
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
private List<CacheMember> members = new List<CacheMember>();
|
||||
private readonly List<CacheMember> filteredMembers = new List<CacheMember>();
|
||||
private readonly List<int> filteredIndices = new List<int>();
|
||||
|
||||
public override GameObject UIRoot => uiRoot;
|
||||
private GameObject uiRoot;
|
||||
@ -37,7 +36,6 @@ namespace UnityExplorer.UI.Inspectors
|
||||
public Text AssemblyText;
|
||||
|
||||
private LayoutElement memberTitleLayout;
|
||||
private LayoutElement typeTitleLayout;
|
||||
|
||||
public override void OnBorrowedFromPool(object target)
|
||||
{
|
||||
@ -97,21 +95,22 @@ namespace UnityExplorer.UI.Inspectors
|
||||
{
|
||||
var member = members[i];
|
||||
filteredMembers.Add(member);
|
||||
filteredIndices.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnReturnToPool()
|
||||
{
|
||||
base.OnReturnToPool();
|
||||
foreach (var member in members)
|
||||
member.OnDestroyed();
|
||||
|
||||
members.Clear();
|
||||
filteredMembers.Clear();
|
||||
filteredIndices.Clear();
|
||||
|
||||
// release all cachememberviews
|
||||
MemberScrollPool.ReturnCells();
|
||||
MemberScrollPool.SetUninitialized();
|
||||
|
||||
base.OnReturnToPool();
|
||||
}
|
||||
|
||||
public override void OnSetActive()
|
||||
@ -141,6 +140,7 @@ namespace UnityExplorer.UI.Inspectors
|
||||
{
|
||||
timeOfLastUpdate = Time.time;
|
||||
|
||||
// Update displayed values (TODO)
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,33 +154,54 @@ namespace UnityExplorer.UI.Inspectors
|
||||
|
||||
public int ItemCount => filteredMembers.Count;
|
||||
|
||||
public int GetRealIndexOfTempIndex(int tempIndex)
|
||||
{
|
||||
if (filteredIndices.Count <= tempIndex)
|
||||
return -1;
|
||||
|
||||
return filteredIndices[tempIndex];
|
||||
}
|
||||
|
||||
public void OnCellBorrowed(CacheMemberCell cell)
|
||||
{
|
||||
cell.CurrentOwner = this;
|
||||
|
||||
// todo add listeners
|
||||
cell.OnInspectClicked += OnCellInspect;
|
||||
cell.OnApplyClicked += OnCellApply;
|
||||
cell.OnSubContentClicked += OnCellSubContentToggle;
|
||||
cell.OnUpdateClicked += OnCellUpdateClicked;
|
||||
cell.OnEvaluateClicked += OnCellEvaluateClicked;
|
||||
}
|
||||
|
||||
private void OnCellInspect(CacheMember occupant)
|
||||
{
|
||||
InspectorManager.Inspect(occupant.Value);
|
||||
}
|
||||
|
||||
private void OnCellApply(CacheMember occupant)
|
||||
{
|
||||
ExplorerCore.Log($"TODO OnApply: {occupant.NameForFiltering}");
|
||||
}
|
||||
|
||||
private void OnCellSubContentToggle(CacheMember occupant)
|
||||
{
|
||||
ExplorerCore.Log($"TODO SubContentToggle: {occupant.NameForFiltering}");
|
||||
}
|
||||
|
||||
private void OnCellUpdateClicked(CacheMember occupant)
|
||||
{
|
||||
ExplorerCore.Log("TODO Update: " + occupant.NameForFiltering);
|
||||
}
|
||||
|
||||
private void OnCellEvaluateClicked(CacheMember occupant)
|
||||
{
|
||||
ExplorerCore.Log("TODO Evaluate or toggle: " + occupant);
|
||||
}
|
||||
|
||||
public void OnCellReturned(CacheMemberCell cell)
|
||||
{
|
||||
// todo remove listeners
|
||||
|
||||
// return ivalue
|
||||
|
||||
cell.CurrentOwner = null;
|
||||
cell.OnReturnToPool();
|
||||
}
|
||||
|
||||
public void SetCell(CacheMemberCell cell, int index)
|
||||
{
|
||||
index = GetRealIndexOfTempIndex(index);
|
||||
if (cell.CurrentOccupant != null)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
if (index < 0 || index >= filteredMembers.Count)
|
||||
{
|
||||
@ -188,7 +209,9 @@ namespace UnityExplorer.UI.Inspectors
|
||||
return;
|
||||
}
|
||||
|
||||
members[index].SetCell(cell);
|
||||
var member = filteredMembers[index];
|
||||
cell.CurrentOccupant = member;
|
||||
member.SetCell(cell);
|
||||
|
||||
SetCellLayout(cell);
|
||||
}
|
||||
@ -198,20 +221,25 @@ namespace UnityExplorer.UI.Inspectors
|
||||
// need to do anything?
|
||||
}
|
||||
|
||||
private static float MemLabelWidth => Math.Min(400f, 0.35f * InspectorManager.PanelWidth - 5);
|
||||
private static float ReturnLabelWidth => Math.Min(225f, 0.25f * InspectorManager.PanelWidth - 5);
|
||||
private static float RightGroupWidth => InspectorManager.PanelWidth - MemLabelWidth - ReturnLabelWidth - 50;
|
||||
#endregion
|
||||
|
||||
// Cell layout (fake table alignment)
|
||||
|
||||
private static float MemLabelWidth { get; set; }
|
||||
private static float RightGroupWidth { get; set; }
|
||||
|
||||
private void SetTitleLayouts()
|
||||
{
|
||||
// Calculate sizes
|
||||
MemLabelWidth = Math.Max(200, Math.Min(450f, 0.4f * InspectorManager.PanelWidth - 5));
|
||||
RightGroupWidth = Math.Max(200, InspectorManager.PanelWidth - MemLabelWidth - 55);
|
||||
|
||||
memberTitleLayout.minWidth = MemLabelWidth;
|
||||
typeTitleLayout.minWidth = ReturnLabelWidth;
|
||||
}
|
||||
|
||||
private void SetCellLayout(CacheMemberCell cell)
|
||||
{
|
||||
cell.MemberLayout.minWidth = MemLabelWidth;
|
||||
cell.ReturnTypeLayout.minWidth = ReturnLabelWidth;
|
||||
cell.RightGroupLayout.minWidth = RightGroupWidth;
|
||||
}
|
||||
|
||||
@ -223,8 +251,6 @@ namespace UnityExplorer.UI.Inspectors
|
||||
SetCellLayout(cell);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override GameObject CreateContent(GameObject parent)
|
||||
{
|
||||
uiRoot = UIFactory.CreateVerticalGroup(parent, "ReflectionInspector", true, true, true, true, 5,
|
||||
@ -243,16 +269,16 @@ namespace UnityExplorer.UI.Inspectors
|
||||
var memberTitle = UIFactory.CreateLabel(listTitles, "MemberTitle", "Member Name", TextAnchor.LowerLeft, Color.grey, fontSize: 15);
|
||||
memberTitleLayout = memberTitle.gameObject.AddComponent<LayoutElement>();
|
||||
|
||||
var typeTitle = UIFactory.CreateLabel(listTitles, "TypeTitle", "Type", TextAnchor.LowerLeft, Color.grey, fontSize: 15);
|
||||
typeTitleLayout = typeTitle.gameObject.AddComponent<LayoutElement>();
|
||||
//var typeTitle = UIFactory.CreateLabel(listTitles, "TypeTitle", "Type", TextAnchor.LowerLeft, Color.grey, fontSize: 15);
|
||||
//typeTitleLayout = typeTitle.gameObject.AddComponent<LayoutElement>();
|
||||
|
||||
var valueTitle = UIFactory.CreateLabel(listTitles, "ValueTitle", "Value", TextAnchor.LowerLeft, Color.grey, fontSize: 15);
|
||||
UIFactory.SetLayoutElement(valueTitle.gameObject, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutElement(valueTitle.gameObject, minWidth: 150, flexibleWidth: 9999);
|
||||
|
||||
MemberScrollPool = UIFactory.CreateScrollPool<CacheMemberCell>(uiRoot, "MemberList", out GameObject scrollObj,
|
||||
out GameObject scrollContent, new Color(0.09f, 0.09f, 0.09f));
|
||||
UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999);
|
||||
UIFactory.SetLayoutElement(scrollContent, flexibleHeight: 9999);
|
||||
//UIFactory.SetLayoutElement(scrollContent, flexibleHeight: 9999);
|
||||
|
||||
MemberScrollPool.Initialize(this);
|
||||
|
||||
|
@ -8,11 +8,11 @@ using UnityExplorer.Core.Search;
|
||||
using UnityExplorer.UI.Inspectors;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.ObjectPool;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Utility;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
public class ObjectSearch : UIModel
|
||||
{
|
||||
@ -110,7 +110,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
private void OnCellClicked(int dataIndex)
|
||||
{
|
||||
if (m_context == SearchContext.StaticClass)
|
||||
InspectorManager.InspectStatic(currentResults[dataIndex] as Type);
|
||||
InspectorManager.Inspect(currentResults[dataIndex] as Type);
|
||||
else
|
||||
InspectorManager.Inspect(currentResults[dataIndex]);
|
||||
}
|
@ -9,9 +9,9 @@ using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.Core;
|
||||
using UnityExplorer.UI.Models;
|
||||
using UnityExplorer.UI.Panels;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
namespace UnityExplorer.UI.Panels
|
||||
{
|
||||
public class SceneExplorer : UIModel
|
||||
{
|
@ -14,6 +14,16 @@ namespace UnityExplorer.UI.Utility
|
||||
/// </summary>
|
||||
public class SignatureHighlighter
|
||||
{
|
||||
public const string NAMESPACE = "#a8a8a8";
|
||||
|
||||
public const string CONST = "#92c470";
|
||||
|
||||
public const string CLASS_STATIC = "#3a8d71";
|
||||
public const string CLASS_INSTANCE = "#2df7b2";
|
||||
|
||||
public const string STRUCT = "#0fba3a";
|
||||
public const string INTERFACE = "#9b9b82";
|
||||
|
||||
public const string FIELD_STATIC = "#8d8dc6";
|
||||
public const string FIELD_INSTANCE = "#c266ff";
|
||||
|
||||
@ -23,30 +33,28 @@ namespace UnityExplorer.UI.Utility
|
||||
public const string PROP_STATIC = "#588075";
|
||||
public const string PROP_INSTANCE = "#55a38e";
|
||||
|
||||
public const string CLASS_STATIC = "#3a8d71";
|
||||
public const string CLASS_INSTANCE = "#2df7b2";
|
||||
|
||||
public const string CLASS_STRUCT = "#0fba3a";
|
||||
|
||||
public const string LOCAL_ARG = "#a6e9e9";
|
||||
|
||||
public static string CONST_VAR = "#92c470";
|
||||
|
||||
public static string NAMESPACE = "#a8a8a8";
|
||||
public static readonly Color StringOrange = new Color(0.83f, 0.61f, 0.52f);
|
||||
public static readonly Color EnumGreen = new Color(0.57f, 0.76f, 0.43f);
|
||||
public static readonly Color KeywordBlue = new Color(0.3f, 0.61f, 0.83f);
|
||||
public static readonly Color NumberGreen = new Color(0.71f, 0.8f, 0.65f);
|
||||
|
||||
internal static string GetClassColor(Type type)
|
||||
{
|
||||
if (type.IsAbstract && type.IsSealed)
|
||||
return CLASS_STATIC;
|
||||
else if (type.IsEnum || type.IsGenericParameter)
|
||||
return CONST_VAR;
|
||||
return CONST;
|
||||
else if (type.IsValueType)
|
||||
return CLASS_STRUCT;
|
||||
return STRUCT;
|
||||
else if (type.IsInterface)
|
||||
return INTERFACE;
|
||||
else
|
||||
return CLASS_INSTANCE;
|
||||
}
|
||||
|
||||
private static readonly StringBuilder syntaxBuilder = new StringBuilder(8192);
|
||||
private static readonly StringBuilder syntaxBuilder = new StringBuilder(2156);
|
||||
|
||||
public static string ParseFullSyntax(Type type, bool includeNamespace, MemberInfo memberInfo = null)
|
||||
{
|
||||
@ -82,7 +90,11 @@ namespace UnityExplorer.UI.Utility
|
||||
syntaxBuilder.Append("</i>");
|
||||
|
||||
if (memberInfo is MethodInfo method)
|
||||
syntaxBuilder.Append(ParseGenericArgs(method.GetGenericArguments(), true));
|
||||
{
|
||||
var args = method.GetGenericArguments();
|
||||
if (args.Length > 0)
|
||||
syntaxBuilder.Append($"<{ParseGenericArgs(args, true)}>");
|
||||
}
|
||||
}
|
||||
|
||||
return syntaxBuilder.ToString();
|
||||
@ -125,7 +137,7 @@ namespace UnityExplorer.UI.Utility
|
||||
|
||||
if (type.IsGenericParameter || (type.HasElementType && type.GetElementType().IsGenericParameter))
|
||||
{
|
||||
typeName = $"<color={CONST_VAR}>{typeName}</color>";
|
||||
typeName = $"<color={CONST}>{typeName}</color>";
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -150,7 +162,9 @@ namespace UnityExplorer.UI.Utility
|
||||
|
||||
// parse the generic args, if any
|
||||
if (args.Length > 0)
|
||||
typeName += ParseGenericArgs(args);
|
||||
{
|
||||
typeName += $"<{ParseGenericArgs(args)}>";
|
||||
}
|
||||
}
|
||||
|
||||
if (isArray)
|
||||
@ -161,33 +175,29 @@ namespace UnityExplorer.UI.Utility
|
||||
return typeName;
|
||||
}
|
||||
|
||||
private static readonly StringBuilder genericBuilder = new StringBuilder(4096);
|
||||
|
||||
public static string ParseGenericArgs(Type[] args, bool isGenericParams = false)
|
||||
{
|
||||
if (args.Length < 1)
|
||||
return string.Empty;
|
||||
|
||||
genericBuilder.Clear();
|
||||
genericBuilder.Append('<');
|
||||
string ret = "";
|
||||
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
genericBuilder.Append(',');
|
||||
ret += ",";
|
||||
|
||||
if (isGenericParams)
|
||||
{
|
||||
genericBuilder.Append($"<color={CONST_VAR}>{args[i].Name}</color>");
|
||||
ret += $"<color={CONST}>{args[i].Name}</color>";
|
||||
continue;
|
||||
}
|
||||
|
||||
// using HighlightTypeName makes it recursive, so we can parse nested generic args.
|
||||
genericBuilder.Append(HighlightTypeName(args[i]));
|
||||
ret += HighlightTypeName(args[i]);
|
||||
}
|
||||
|
||||
genericBuilder.Append('>');
|
||||
return genericBuilder.ToString();
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static string GetMemberInfoColor(MemberInfo memberInfo, out bool isStatic)
|
||||
@ -200,8 +210,8 @@ namespace UnityExplorer.UI.Utility
|
||||
isStatic = true;
|
||||
return FIELD_STATIC;
|
||||
}
|
||||
else
|
||||
return FIELD_INSTANCE;
|
||||
|
||||
return FIELD_INSTANCE;
|
||||
}
|
||||
else if (memberInfo is MethodInfo mi)
|
||||
{
|
||||
@ -210,8 +220,8 @@ namespace UnityExplorer.UI.Utility
|
||||
isStatic = true;
|
||||
return METHOD_STATIC;
|
||||
}
|
||||
else
|
||||
return METHOD_INSTANCE;
|
||||
|
||||
return METHOD_INSTANCE;
|
||||
}
|
||||
else if (memberInfo is PropertyInfo pi)
|
||||
{
|
||||
@ -220,9 +230,19 @@ namespace UnityExplorer.UI.Utility
|
||||
isStatic = true;
|
||||
return PROP_STATIC;
|
||||
}
|
||||
else
|
||||
return PROP_INSTANCE;
|
||||
|
||||
return PROP_INSTANCE;
|
||||
}
|
||||
//else if (memberInfo is EventInfo ei)
|
||||
//{
|
||||
// if (ei.GetAddMethod().IsStatic)
|
||||
// {
|
||||
// isStatic = true;
|
||||
// return EVENT_STATIC;
|
||||
// }
|
||||
|
||||
// return EVENT_INSTANCE;
|
||||
//}
|
||||
|
||||
throw new NotImplementedException(memberInfo.GetType().Name + " is not supported");
|
||||
}
|
||||
|
@ -16,11 +16,11 @@ namespace UnityExplorer.UI.Utility
|
||||
|
||||
// string allocs
|
||||
private static readonly StringBuilder _stringBuilder = new StringBuilder(16384);
|
||||
private const string unknownString = "<unknown>";
|
||||
private const string nullString = "<color=grey>[null]</color>";
|
||||
private const string destroyedString = "<color=red>[Destroyed]</color>";
|
||||
private const string nullString = "<color=grey>null</color>";
|
||||
private const string destroyedString = "<color=red>Destroyed</color>";
|
||||
private const string untitledString = "<i><color=grey>untitled</color></i>";
|
||||
|
||||
public static string ToString(object value, Type type)
|
||||
public static string ToString(object value)
|
||||
{
|
||||
if (value.IsNullOrDestroyed())
|
||||
{
|
||||
@ -30,6 +30,10 @@ namespace UnityExplorer.UI.Utility
|
||||
return destroyedString;
|
||||
}
|
||||
|
||||
var type = value.GetActualType();
|
||||
|
||||
// Find and cache the relevant ToString method for this Type, if haven't already.
|
||||
|
||||
if (!toStringMethods.ContainsKey(type.AssemblyQualifiedName))
|
||||
{
|
||||
try
|
||||
@ -46,6 +50,8 @@ namespace UnityExplorer.UI.Utility
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke the ToString method on the object
|
||||
|
||||
value = value.TryCast(type);
|
||||
|
||||
string toString;
|
||||
@ -60,7 +66,7 @@ namespace UnityExplorer.UI.Utility
|
||||
public static string ToStringWithType(object value, Type fallbackType, bool includeNamespace = true)
|
||||
{
|
||||
if (value == null && fallbackType == null)
|
||||
return unknownString;
|
||||
return nullString;
|
||||
|
||||
Type type = value?.GetActualType() ?? fallbackType;
|
||||
|
||||
@ -89,17 +95,18 @@ namespace UnityExplorer.UI.Utility
|
||||
|
||||
if (value is UnityEngine.Object obj)
|
||||
{
|
||||
_stringBuilder.Append(obj.name);
|
||||
_stringBuilder.Append(string.IsNullOrEmpty(obj.name) ? untitledString : obj.name);
|
||||
AppendRichType(_stringBuilder, richType);
|
||||
}
|
||||
else
|
||||
{
|
||||
var toString = ToString(value, type);
|
||||
var toString = ToString(value);
|
||||
|
||||
if (toString == type.FullName || toString == $"Il2Cpp{type.FullName}" || type.FullName == $"Il2Cpp{toString}")
|
||||
if (type.IsGenericType
|
||||
|| toString == type.FullName
|
||||
|| toString == $"{type.FullName} {type.FullName}"
|
||||
|| toString == $"Il2Cpp{type.FullName}" || type.FullName == $"Il2Cpp{toString}")
|
||||
{
|
||||
// the ToString was just the default object.ToString(), use our
|
||||
// syntax highlighted type name instead.
|
||||
_stringBuilder.Append(richType);
|
||||
}
|
||||
else // the ToString contains some actual implementation, use that value.
|
||||
@ -116,8 +123,6 @@ namespace UnityExplorer.UI.Utility
|
||||
return _stringBuilder.ToString();
|
||||
}
|
||||
|
||||
// Just a little optimization, append chars directly instead of allocating every time
|
||||
// we want to do this.
|
||||
private static void AppendRichType(StringBuilder sb, string richType)
|
||||
{
|
||||
sb.Append(' ');
|
||||
|
@ -12,8 +12,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
public class ButtonListSource<T> : IPoolDataSource<ButtonCell>
|
||||
{
|
||||
public int GetRealIndexOfTempIndex(int index) => throw new NotImplementedException("TODO");
|
||||
|
||||
internal ScrollPool<ButtonCell> ScrollPool;
|
||||
|
||||
public int ItemCount => currentEntries.Count;
|
||||
|
@ -24,8 +24,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
ScrollPool = scrollPool;
|
||||
}
|
||||
|
||||
// initialize with a reasonably sized pool, most caches will allocate a fair bit.
|
||||
private readonly List<DataViewInfo> heightCache = new List<DataViewInfo>(16384);
|
||||
private readonly List<DataViewInfo> heightCache = new List<DataViewInfo>();
|
||||
|
||||
public DataViewInfo this[int index]
|
||||
{
|
||||
@ -104,12 +103,8 @@ namespace UnityExplorer.UI.Widgets
|
||||
heightCache.RemoveAt(heightCache.Count - 1);
|
||||
|
||||
int idx = heightCache.Count;
|
||||
if (idx > 0)
|
||||
{
|
||||
while (rangeCache[rangeCache.Count - 1] == idx)
|
||||
rangeCache.RemoveAt(rangeCache.Count - 1);
|
||||
}
|
||||
|
||||
while (rangeCache.Count > 0 && rangeCache[rangeCache.Count - 1] == idx)
|
||||
rangeCache.RemoveAt(rangeCache.Count - 1);
|
||||
}
|
||||
|
||||
/// <summary>Get the data index at the specific position of the total height cache.</summary>
|
||||
@ -119,31 +114,29 @@ namespace UnityExplorer.UI.Widgets
|
||||
public int GetDataIndexAtPosition(float desiredHeight, out DataViewInfo cache)
|
||||
{
|
||||
cache = default;
|
||||
|
||||
if (!heightCache.Any())
|
||||
return 0;
|
||||
|
||||
int rangeIndex = GetRangeIndexOfPosition(desiredHeight);
|
||||
|
||||
if (rangeIndex < 0)
|
||||
return 0;
|
||||
if (rangeIndex >= rangeCache.Count)
|
||||
{
|
||||
ExplorerCore.LogWarning("RangeIndex < 0? " + rangeIndex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rangeCache.Count <= rangeIndex)
|
||||
{
|
||||
ExplorerCore.LogWarning("Want range index " + rangeIndex + " but count is " + rangeCache.Count);
|
||||
RebuildCache();
|
||||
rangeIndex = GetRangeIndexOfPosition(desiredHeight);
|
||||
if (rangeCache.Count <= rangeIndex)
|
||||
throw new Exception("Range index (" + rangeIndex + ") exceeded rangeCache count (" + rangeCache.Count + ")");
|
||||
ExplorerCore.Log("desiredHeight is " + desiredHeight + ", but our total height is " + totalHeight + ", clamping to data count");
|
||||
ExplorerCore.Log("highest data index: " + (ScrollPool.DataSource.ItemCount - 1) + ", rangeIndex was " + rangeIndex + ", actual range limit is " + (rangeCache.Count - 1));
|
||||
cache = heightCache[heightCache.Count - 1];
|
||||
return ScrollPool.DataSource.ItemCount - 1;
|
||||
}
|
||||
|
||||
int dataIndex = rangeCache[rangeIndex];
|
||||
cache = heightCache[dataIndex];
|
||||
|
||||
return dataIndex;
|
||||
}
|
||||
|
||||
/// <summary>Set a given data index with the specified value.</summary>
|
||||
public void SetIndex(int dataIndex, float height)
|
||||
public void SetIndex(int dataIndex, float height, bool inRebuild = false)
|
||||
{
|
||||
if (dataIndex >= ScrollPool.DataSource.ItemCount)
|
||||
{
|
||||
@ -166,7 +159,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
var diff = height - prevHeight;
|
||||
if (diff != 0.0f)
|
||||
{
|
||||
// LogWarning("Height for data index " + dataIndex + " changed by " + diff);
|
||||
totalHeight += diff;
|
||||
cache.height = height;
|
||||
}
|
||||
@ -183,8 +175,16 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
if (rangeCache.Count <= rangeIndex)
|
||||
{
|
||||
RebuildCache();
|
||||
return;
|
||||
if (rangeCache[rangeCache.Count - 1] != dataIndex - 1)
|
||||
{
|
||||
// The previous index in the range cache is not the previous data index for the data we were given.
|
||||
// Need to rebuild.
|
||||
if (!inRebuild)
|
||||
RebuildCache();
|
||||
else
|
||||
throw new Exception($"DataHeightCache rebuild failed. Trying to set {rangeIndex} but current count is {rangeCache.Count}!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (spread != cache.normalizedSpread)
|
||||
@ -199,6 +199,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
// In some rare cases we may not find our data index at the expected range index.
|
||||
// We can make some educated guesses and find the real index pretty quickly.
|
||||
int minStart = GetRangeIndexOfPosition(dataIndex * DefaultHeight);
|
||||
if (minStart < 0) minStart = 0;
|
||||
for (int i = minStart; i < rangeCache.Count; i++)
|
||||
{
|
||||
if (rangeCache[i] == dataIndex)
|
||||
@ -218,10 +219,8 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
// our data index is further down. add the min difference and try again.
|
||||
// the iterator will add 1 on the next loop so account for that.
|
||||
// also, add the (spread - 1) of the cell we found at this index to skip it.
|
||||
var spreadCurr = heightCache[rangeCache[i]].normalizedSpread;
|
||||
|
||||
int jmp = dataIndex - rangeCache[i] - 1;
|
||||
jmp += spreadCurr - 2;
|
||||
i = (jmp < 1 ? i : i + jmp);
|
||||
}
|
||||
}
|
||||
@ -263,7 +262,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
//start at 1 because 0's start pos is always 0
|
||||
for (int i = 1; i < heightCache.Count; i++)
|
||||
SetIndex(i, heightCache[i].height);
|
||||
SetIndex(i, heightCache[i].height, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
public interface IPoolDataSource<T> where T : ICell
|
||||
{
|
||||
int ItemCount { get; }
|
||||
int GetRealIndexOfTempIndex(int tempIndex);
|
||||
|
||||
void OnCellBorrowed(T cell);
|
||||
void OnCellReturned(T cell);
|
||||
|
@ -100,7 +100,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
private bool writingLocked;
|
||||
private float timeofLastWriteLock;
|
||||
|
||||
private float prevContentHeight;
|
||||
private float prevContentHeight = 1.0f;
|
||||
|
||||
public void SetUninitialized()
|
||||
{
|
||||
@ -115,8 +115,10 @@ namespace UnityExplorer.UI.Widgets
|
||||
if (writingLocked && timeofLastWriteLock < Time.time)
|
||||
writingLocked = false;
|
||||
|
||||
if (prevContentHeight == 0.0f && Content?.rect.height != 0.0f)
|
||||
if (prevContentHeight <= 1f && Content?.rect.height > 1f)
|
||||
{
|
||||
prevContentHeight = Content.rect.height;
|
||||
}
|
||||
else if (Content.rect.height != prevContentHeight)
|
||||
{
|
||||
prevContentHeight = Content.rect.height;
|
||||
@ -240,21 +242,13 @@ namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
bottomPoolIndex++;
|
||||
|
||||
////Instantiate and add to Pool
|
||||
//RectTransform rect = GameObject.Instantiate(PrototypeCell.gameObject).GetComponent<RectTransform>();
|
||||
//rect.gameObject.SetActive(true);
|
||||
//rect.name = $"Cell_{CellPool.Count}";
|
||||
//var cell = DataSource.CreateCell(rect);
|
||||
//CellPool.Add(cell);
|
||||
//rect.SetParent(ScrollRect.content, false);
|
||||
|
||||
var cell = Pool<T>.Borrow();
|
||||
DataSource.OnCellBorrowed(cell);
|
||||
var rect = cell.Rect;
|
||||
//var rect = cell.Rect;
|
||||
CellPool.Add(cell);
|
||||
rect.SetParent(ScrollRect.content, false);
|
||||
cell.Rect.SetParent(ScrollRect.content, false);
|
||||
|
||||
currentPoolCoverage += rect.rect.height;
|
||||
currentPoolCoverage += PrototypeHeight;
|
||||
}
|
||||
|
||||
if (andResetDataIndex)
|
||||
@ -289,30 +283,29 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
var requiredCoverage = Math.Abs(RecycleViewBounds.y - RecycleViewBounds.x);
|
||||
var currentCoverage = CellPool.Count * PrototypeHeight;
|
||||
int cellsRequired = (int)Math.Ceiling((decimal)(requiredCoverage - currentCoverage) / (decimal)PrototypeHeight);
|
||||
int cellsRequired = (int)Math.Floor((decimal)(requiredCoverage - currentCoverage) / (decimal)PrototypeHeight);
|
||||
if (cellsRequired > 0 || forceRecreate)
|
||||
{
|
||||
WritingLocked = true;
|
||||
|
||||
//// Disable cells so DataSource can handle its content if need be
|
||||
//var enumerator = GetPoolEnumerator();
|
||||
//while (enumerator.MoveNext())
|
||||
//{
|
||||
// var curr = enumerator.Current;
|
||||
// DataSource.DisableCell(CellPool[curr.cellIndex], curr.dataIndex);
|
||||
//}
|
||||
|
||||
bottomDataIndex += cellsRequired;
|
||||
int maxDataIndex = Math.Max(CellPool.Count + cellsRequired - 1, DataSource.ItemCount - 1);
|
||||
if (bottomDataIndex > maxDataIndex)
|
||||
bottomDataIndex = maxDataIndex;
|
||||
|
||||
// CreateCellPool will destroy existing cells and recreate list.
|
||||
float curAnchor = Content.localPosition.y;
|
||||
float curHeight = Content.rect.height;
|
||||
|
||||
CreateCellPool(resetDataIndex);
|
||||
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
||||
// fix slight jumping when resizing panel and size increases
|
||||
|
||||
if (Content.rect.height != curHeight)
|
||||
{
|
||||
var diff = Content.rect.height - curHeight;
|
||||
Content.localPosition = new Vector3(Content.localPosition.x, Content.localPosition.y + (diff * 0.5f));
|
||||
}
|
||||
|
||||
//Content.anchoredPosition = new Vector2(0, pos);
|
||||
ScrollRect.UpdatePrevData();
|
||||
|
||||
SetScrollBounds();
|
||||
@ -437,10 +430,7 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
SetRecycleViewBounds(true);
|
||||
|
||||
//if (!SetRecycleViewBounds(true))
|
||||
// RefreshCells(false);
|
||||
|
||||
float yChange = (ScrollRect.content.anchoredPosition - prevAnchoredPos).y;
|
||||
float yChange = ((Vector2)ScrollRect.content.localPosition - prevAnchoredPos).y;
|
||||
float adjust = 0f;
|
||||
|
||||
if (yChange > 0) // Scrolling down
|
||||
@ -642,7 +632,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
if (TopDataIndex > poolStartIndex && TopDataIndex < desiredBottomIndex)
|
||||
{
|
||||
//ExplorerCore.Log("Scroll bottom to top");
|
||||
// top cell falls within the new range, rotate around that
|
||||
int rotate = TopDataIndex - poolStartIndex;
|
||||
for (int i = 0; i < rotate; i++)
|
||||
@ -659,7 +648,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
}
|
||||
else if (bottomDataIndex > poolStartIndex && bottomDataIndex < desiredBottomIndex)
|
||||
{
|
||||
//ExplorerCore.Log("Scroll top to bottom");
|
||||
// bottom cells falls within the new range, rotate around that
|
||||
int rotate = desiredBottomIndex - bottomDataIndex;
|
||||
for (int i = 0; i < rotate; i++)
|
||||
@ -676,9 +664,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
}
|
||||
else
|
||||
{
|
||||
// new cells are completely different, set all cells
|
||||
//ExplorerCore.Log("Scroll jump");
|
||||
|
||||
bottomDataIndex = desiredBottomIndex;
|
||||
var enumerator = GetPoolEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
@ -692,17 +677,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
|
||||
SetRecycleViewBounds(true);
|
||||
|
||||
//CheckDataSourceCountChange(out bool jumpToBottom);
|
||||
|
||||
//// force check recycles
|
||||
//if (andReloadFromDataSource)
|
||||
//{
|
||||
// RecycleBottomToTop();
|
||||
// RecycleTopToBottom();
|
||||
//}
|
||||
|
||||
//LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
|
||||
|
||||
SetScrollBounds();
|
||||
ScrollRect.UpdatePrevData();
|
||||
|
||||
|
@ -55,8 +55,6 @@ namespace UnityExplorer.UI.Widgets
|
||||
ScrollPool.Initialize(this);
|
||||
}
|
||||
|
||||
public int GetRealIndexOfTempIndex(int index) => -1;// not needed
|
||||
|
||||
public void DisableCell(TransformCell cell, int index) => cell.Disable();
|
||||
|
||||
|
||||
|
@ -319,8 +319,8 @@
|
||||
<Compile Include="Inspectors_OLD\InteractiveValues\InteractiveString.cs" />
|
||||
<Compile Include="Inspectors_OLD\InteractiveValues\InteractiveValue.cs" />
|
||||
<Compile Include="UI\Widgets\ButtonRef.cs" />
|
||||
<Compile Include="UI\Widgets\ObjectExplorer\ObjectSearch.cs" />
|
||||
<Compile Include="UI\Widgets\ObjectExplorer\SceneExplorer.cs" />
|
||||
<Compile Include="UI\Panels\ObjectExplorer\ObjectSearch.cs" />
|
||||
<Compile Include="UI\Panels\ObjectExplorer\SceneExplorer.cs" />
|
||||
<Compile Include="UI\Widgets\ScrollPool\DataHeightCache.cs" />
|
||||
<Compile Include="UI\Widgets\ScrollPool\CellViewHolder.cs" />
|
||||
<Compile Include="UI\Widgets\ScrollPool\ICell.cs" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user