mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-16 22:27:45 +08:00
Allow editing null strings, remove "null" ValueState
This commit is contained in:
parent
f080379e8a
commit
00c28f781a
@ -18,7 +18,7 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
{
|
{
|
||||||
NotEvaluated,
|
NotEvaluated,
|
||||||
Exception,
|
Exception,
|
||||||
NullValue,
|
//NullValue,
|
||||||
Boolean,
|
Boolean,
|
||||||
Number,
|
Number,
|
||||||
String,
|
String,
|
||||||
@ -38,6 +38,7 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
|
|
||||||
public object Value { get; protected set; }
|
public object Value { get; protected set; }
|
||||||
public Type FallbackType { get; protected set; }
|
public Type FallbackType { get; protected set; }
|
||||||
|
public bool LastValueWasNull { get; private set; }
|
||||||
|
|
||||||
public InteractiveValue IValue { get; private set; }
|
public InteractiveValue IValue { get; private set; }
|
||||||
public Type CurrentIValueType { get; private set; }
|
public Type CurrentIValueType { get; private set; }
|
||||||
@ -55,7 +56,7 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
public virtual void SetFallbackType(Type fallbackType)
|
public virtual void SetFallbackType(Type fallbackType)
|
||||||
{
|
{
|
||||||
this.FallbackType = fallbackType;
|
this.FallbackType = fallbackType;
|
||||||
GetValueLabel();
|
this.ValueLabelText = GetValueLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
// internals
|
// internals
|
||||||
@ -104,6 +105,7 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
|
|
||||||
public abstract void TrySetUserValue(object value);
|
public abstract void TrySetUserValue(object value);
|
||||||
|
|
||||||
|
// The only method which sets the CacheObjectBase.Value
|
||||||
public virtual void SetValueFromSource(object value)
|
public virtual void SetValueFromSource(object value)
|
||||||
{
|
{
|
||||||
this.Value = value;
|
this.Value = value;
|
||||||
@ -111,88 +113,122 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
if (!Value.IsNullOrDestroyed())
|
if (!Value.IsNullOrDestroyed())
|
||||||
Value = Value.TryCast();
|
Value = Value.TryCast();
|
||||||
|
|
||||||
var prevState = State;
|
|
||||||
ProcessOnEvaluate();
|
ProcessOnEvaluate();
|
||||||
|
|
||||||
if (State != prevState)
|
|
||||||
{
|
|
||||||
if (this.IValue != null)
|
|
||||||
{
|
|
||||||
// State has changed, need to return IValue
|
|
||||||
ReleaseIValue();
|
|
||||||
SubContentShowWanted = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.IValue != null)
|
if (this.IValue != null)
|
||||||
this.IValue.SetValue(Value);
|
this.IValue.SetValue(Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Process the CacheMember state when the value has been evaluated (or re-evaluated)
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void ProcessOnEvaluate()
|
protected virtual void ProcessOnEvaluate()
|
||||||
{
|
{
|
||||||
|
var prevState = State;
|
||||||
|
|
||||||
if (HadException)
|
if (HadException)
|
||||||
|
{
|
||||||
|
LastValueWasNull = true;
|
||||||
State = ValueState.Exception;
|
State = ValueState.Exception;
|
||||||
|
}
|
||||||
else if (Value.IsNullOrDestroyed())
|
else if (Value.IsNullOrDestroyed())
|
||||||
State = ValueState.NullValue;
|
{
|
||||||
|
LastValueWasNull = true;
|
||||||
|
State = GetStateForType(FallbackType);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var type = Value.GetActualType();
|
LastValueWasNull = false;
|
||||||
|
State = GetStateForType(Value.GetActualType());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IValue != null)
|
||||||
|
{
|
||||||
|
// If we changed states (always needs IValue change)
|
||||||
|
// or if the value is null, and the fallback type isnt string (we always want to edit strings).
|
||||||
|
if (State != prevState || (State != ValueState.String && Value.IsNullOrDestroyed()))
|
||||||
|
{
|
||||||
|
// need to return IValue
|
||||||
|
ReleaseIValue();
|
||||||
|
SubContentShowWanted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set label text
|
||||||
|
this.ValueLabelText = GetValueLabel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueState GetStateForType(Type type)
|
||||||
|
{
|
||||||
if (type == typeof(bool))
|
if (type == typeof(bool))
|
||||||
State = ValueState.Boolean;
|
return ValueState.Boolean;
|
||||||
else if (type.IsPrimitive || type == typeof(decimal))
|
else if (type.IsPrimitive || type == typeof(decimal))
|
||||||
State = ValueState.Number;
|
return ValueState.Number;
|
||||||
else if (type == typeof(string))
|
else if (type == typeof(string))
|
||||||
State = ValueState.String;
|
return ValueState.String;
|
||||||
else if (type.IsEnum)
|
else if (type.IsEnum)
|
||||||
State = ValueState.Enum;
|
return ValueState.Enum;
|
||||||
|
|
||||||
// todo Color and ValueStruct
|
// todo Color and ValueStruct
|
||||||
|
|
||||||
else if (typeof(IDictionary).IsAssignableFrom(type))
|
else if (typeof(IDictionary).IsAssignableFrom(type))
|
||||||
State = ValueState.Dictionary;
|
return ValueState.Dictionary;
|
||||||
else if (typeof(IEnumerable).IsAssignableFrom(type))
|
else if (typeof(IEnumerable).IsAssignableFrom(type))
|
||||||
State = ValueState.Collection;
|
return ValueState.Collection;
|
||||||
else
|
else
|
||||||
State = ValueState.Unsupported;
|
return ValueState.Unsupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set label text
|
protected string GetValueLabel()
|
||||||
GetValueLabel();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void GetValueLabel()
|
|
||||||
{
|
{
|
||||||
string label;
|
string label = "";
|
||||||
|
|
||||||
switch (State)
|
switch (State)
|
||||||
{
|
{
|
||||||
case ValueState.NotEvaluated:
|
// bool and number dont want the label for the value at all
|
||||||
label = $"<i>{NOT_YET_EVAL} ({SignatureHighlighter.Parse(FallbackType, true)})</i>"; break;
|
|
||||||
case ValueState.Exception:
|
|
||||||
label = $"<i><color=red>{LastException.ReflectionExToString()}</color></i>"; break;
|
|
||||||
case ValueState.Boolean:
|
case ValueState.Boolean:
|
||||||
case ValueState.Number:
|
case ValueState.Number:
|
||||||
label = null; break;
|
return null;
|
||||||
|
|
||||||
|
case ValueState.NotEvaluated:
|
||||||
|
return $"<i>{NOT_YET_EVAL} ({SignatureHighlighter.Parse(FallbackType, true)})</i>";
|
||||||
|
|
||||||
|
case ValueState.Exception:
|
||||||
|
return $"<i><color=red>{LastException.ReflectionExToString()}</color></i>";
|
||||||
|
|
||||||
case ValueState.String:
|
case ValueState.String:
|
||||||
|
if (!LastValueWasNull)
|
||||||
|
{
|
||||||
string s = Value as string;
|
string s = Value as string;
|
||||||
if (s.Length > 200)
|
if (s.Length > 200)
|
||||||
s = $"{s.Substring(0, 200)}...";
|
s = $"{s.Substring(0, 200)}...";
|
||||||
label = $"\"{s}\""; break;
|
return $"\"{s}\"";
|
||||||
case ValueState.NullValue:
|
|
||||||
label = $"<i>{ToStringUtility.ToStringWithType(Value, FallbackType, true)}</i>"; break;
|
|
||||||
case ValueState.Enum:
|
|
||||||
case ValueState.Collection:
|
|
||||||
case ValueState.Dictionary:
|
|
||||||
case ValueState.ValueStruct:
|
|
||||||
case ValueState.Color:
|
|
||||||
case ValueState.Unsupported:
|
|
||||||
default:
|
|
||||||
label = ToStringUtility.ToStringWithType(Value, FallbackType, true); break;
|
|
||||||
}
|
}
|
||||||
this.ValueLabelText = label;
|
break;
|
||||||
|
|
||||||
|
case ValueState.Collection:
|
||||||
|
if (!LastValueWasNull)
|
||||||
|
{
|
||||||
|
if (Value is IList iList)
|
||||||
|
label = $"[{iList.Count}] ";
|
||||||
|
else if (Value is ICollection iCol)
|
||||||
|
label = $"[{iCol.Count}] ";
|
||||||
|
else
|
||||||
|
label = "[?] ";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ValueState.Dictionary:
|
||||||
|
if (!LastValueWasNull)
|
||||||
|
{
|
||||||
|
if (Value is IDictionary iDict)
|
||||||
|
label = $"[{iDict.Count}] ";
|
||||||
|
else
|
||||||
|
label = "[?] ";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cases which dont return will append to ToStringWithType
|
||||||
|
|
||||||
|
return label += ToStringUtility.ToStringWithType(Value, FallbackType, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setting cell state from our model
|
// Setting cell state from our model
|
||||||
@ -218,16 +254,19 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
switch (State)
|
switch (State)
|
||||||
{
|
{
|
||||||
case ValueState.Exception:
|
case ValueState.Exception:
|
||||||
case ValueState.NullValue:
|
//case ValueState.NullValue:
|
||||||
SetValueState(cell, ValueStateArgs.Default);
|
SetValueState(cell, ValueStateArgs.Default);
|
||||||
break;
|
break;
|
||||||
case ValueState.Boolean:
|
case ValueState.Boolean:
|
||||||
SetValueState(cell, new ValueStateArgs(false, toggleActive:true, applyActive: CanWrite));
|
SetValueState(cell, new ValueStateArgs(false, toggleActive: true, applyActive: CanWrite));
|
||||||
break;
|
break;
|
||||||
case ValueState.Number:
|
case ValueState.Number:
|
||||||
SetValueState(cell, new ValueStateArgs(false, typeLabelActive: true, inputActive: true, applyActive: CanWrite));
|
SetValueState(cell, new ValueStateArgs(false, typeLabelActive: true, inputActive: true, applyActive: CanWrite));
|
||||||
break;
|
break;
|
||||||
case ValueState.String:
|
case ValueState.String:
|
||||||
|
if (LastValueWasNull)
|
||||||
|
SetValueState(cell, new ValueStateArgs(true, subContentButtonActive: true));
|
||||||
|
else
|
||||||
SetValueState(cell, new ValueStateArgs(true, false, SignatureHighlighter.StringOrange, subContentButtonActive: true));
|
SetValueState(cell, new ValueStateArgs(true, false, SignatureHighlighter.StringOrange, subContentButtonActive: true));
|
||||||
break;
|
break;
|
||||||
case ValueState.Enum:
|
case ValueState.Enum:
|
||||||
@ -237,10 +276,10 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
case ValueState.Dictionary:
|
case ValueState.Dictionary:
|
||||||
case ValueState.ValueStruct:
|
case ValueState.ValueStruct:
|
||||||
case ValueState.Color:
|
case ValueState.Color:
|
||||||
SetValueState(cell, new ValueStateArgs(true, inspectActive: true, subContentButtonActive: true));
|
SetValueState(cell, new ValueStateArgs(true, inspectActive: !LastValueWasNull, subContentButtonActive: !LastValueWasNull));
|
||||||
break;
|
break;
|
||||||
case ValueState.Unsupported:
|
case ValueState.Unsupported:
|
||||||
SetValueState(cell, new ValueStateArgs(true, inspectActive: true));
|
SetValueState(cell, new ValueStateArgs(true, inspectActive: !LastValueWasNull));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,6 +288,7 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
|
|
||||||
protected virtual void SetValueState(CacheObjectCell cell, ValueStateArgs args)
|
protected virtual void SetValueState(CacheObjectCell cell, ValueStateArgs args)
|
||||||
{
|
{
|
||||||
|
// main value label
|
||||||
if (args.valueActive)
|
if (args.valueActive)
|
||||||
{
|
{
|
||||||
cell.ValueLabel.text = ValueLabelText;
|
cell.ValueLabel.text = ValueLabelText;
|
||||||
@ -258,10 +298,12 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
else
|
else
|
||||||
cell.ValueLabel.text = "";
|
cell.ValueLabel.text = "";
|
||||||
|
|
||||||
|
// Type label (for primitives)
|
||||||
cell.TypeLabel.gameObject.SetActive(args.typeLabelActive);
|
cell.TypeLabel.gameObject.SetActive(args.typeLabelActive);
|
||||||
if (args.typeLabelActive)
|
if (args.typeLabelActive)
|
||||||
cell.TypeLabel.text = SignatureHighlighter.Parse(Value.GetActualType(), false);
|
cell.TypeLabel.text = SignatureHighlighter.Parse(Value.GetActualType(), false);
|
||||||
|
|
||||||
|
// toggle for bools
|
||||||
cell.Toggle.gameObject.SetActive(args.toggleActive);
|
cell.Toggle.gameObject.SetActive(args.toggleActive);
|
||||||
if (args.toggleActive)
|
if (args.toggleActive)
|
||||||
{
|
{
|
||||||
@ -270,6 +312,7 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
cell.ToggleText.text = Value.ToString();
|
cell.ToggleText.text = Value.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// inputfield for numbers
|
||||||
cell.InputField.gameObject.SetActive(args.inputActive);
|
cell.InputField.gameObject.SetActive(args.inputActive);
|
||||||
if (args.inputActive)
|
if (args.inputActive)
|
||||||
{
|
{
|
||||||
@ -277,9 +320,13 @@ namespace UnityExplorer.UI.CacheObject
|
|||||||
cell.InputField.readOnly = !CanWrite;
|
cell.InputField.readOnly = !CanWrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply for bool and numbers
|
||||||
cell.ApplyButton.Button.gameObject.SetActive(args.applyActive);
|
cell.ApplyButton.Button.gameObject.SetActive(args.applyActive);
|
||||||
cell.InspectButton.Button.gameObject.SetActive(args.inspectActive);
|
|
||||||
cell.SubContentButton.Button.gameObject.SetActive(args.subContentButtonActive);
|
// Inspect and IValue (subcontent) buttons - only if last value not null.
|
||||||
|
cell.InspectButton.Button.gameObject.SetActive(args.inspectActive && !LastValueWasNull);
|
||||||
|
// allow IValue for null strings though.
|
||||||
|
cell.SubContentButton.Button.gameObject.SetActive(args.subContentButtonActive && (!LastValueWasNull || State == ValueState.String));
|
||||||
}
|
}
|
||||||
|
|
||||||
// CacheObjectCell Apply
|
// CacheObjectCell Apply
|
||||||
|
@ -16,8 +16,8 @@ namespace UnityExplorer.UI.Utility
|
|||||||
internal static Dictionary<string, MethodInfo> toStringFormattedMethods = new Dictionary<string, MethodInfo>();
|
internal static Dictionary<string, MethodInfo> toStringFormattedMethods = new Dictionary<string, MethodInfo>();
|
||||||
|
|
||||||
// string allocs
|
// string allocs
|
||||||
private static readonly StringBuilder _stringBuilder = new StringBuilder(16384);
|
|
||||||
private const string nullString = "<color=grey>null</color>";
|
private const string nullString = "<color=grey>null</color>";
|
||||||
|
private const string nullUnknown = nullString + " (?)";
|
||||||
private const string destroyedString = "<color=red>Destroyed</color>";
|
private const string destroyedString = "<color=red>Destroyed</color>";
|
||||||
private const string untitledString = "<i><color=grey>untitled</color></i>";
|
private const string untitledString = "<i><color=grey>untitled</color></i>";
|
||||||
|
|
||||||
@ -25,28 +25,28 @@ namespace UnityExplorer.UI.Utility
|
|||||||
|
|
||||||
public static string ToStringWithType(object value, Type fallbackType, bool includeNamespace = true)
|
public static string ToStringWithType(object value, Type fallbackType, bool includeNamespace = true)
|
||||||
{
|
{
|
||||||
if (value == null && fallbackType == null)
|
if (value.IsNullOrDestroyed() && fallbackType == null)
|
||||||
return nullString;
|
return nullUnknown;
|
||||||
|
|
||||||
Type type = value?.GetActualType() ?? fallbackType;
|
Type type = value?.GetActualType() ?? fallbackType;
|
||||||
|
|
||||||
string richType = SignatureHighlighter.Parse(type, includeNamespace);
|
string richType = SignatureHighlighter.Parse(type, includeNamespace);
|
||||||
|
|
||||||
_stringBuilder.Clear();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
if (value.IsNullOrDestroyed())
|
if (value.IsNullOrDestroyed())
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
_stringBuilder.Append(nullString);
|
sb.Append(nullString);
|
||||||
AppendRichType(_stringBuilder, richType);
|
AppendRichType(sb, richType);
|
||||||
return _stringBuilder.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
else // destroyed unity object
|
else // destroyed unity object
|
||||||
{
|
{
|
||||||
_stringBuilder.Append(destroyedString);
|
sb.Append(destroyedString);
|
||||||
AppendRichType(_stringBuilder, richType);
|
AppendRichType(sb, richType);
|
||||||
return _stringBuilder.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,57 +58,39 @@ namespace UnityExplorer.UI.Utility
|
|||||||
else if (name.Length > 50)
|
else if (name.Length > 50)
|
||||||
name = $"{name.Substring(0, 50)}...";
|
name = $"{name.Substring(0, 50)}...";
|
||||||
|
|
||||||
_stringBuilder.Append($"\"{name}\"");
|
sb.Append($"\"{name}\"");
|
||||||
AppendRichType(_stringBuilder, richType);
|
AppendRichType(sb, richType);
|
||||||
}
|
}
|
||||||
else if (type.FullName.StartsWith(eventSystemNamespace))
|
else if (type.FullName.StartsWith(eventSystemNamespace))
|
||||||
{
|
{
|
||||||
// UnityEngine.EventSystem classes can have some obnoxious ToString results with rich text.
|
// UnityEngine.EventSystem classes can have some obnoxious ToString results with rich text.
|
||||||
_stringBuilder.Append(richType);
|
sb.Append(richType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var toString = ToString(value);
|
var toString = ToString(value);
|
||||||
|
|
||||||
if (typeof(IEnumerable).IsAssignableFrom(type))
|
|
||||||
{
|
|
||||||
if (value is IList iList)
|
|
||||||
_stringBuilder.Append($"[{iList.Count}] ");
|
|
||||||
else
|
|
||||||
if (value is ICollection iCol)
|
|
||||||
_stringBuilder.Append($"[{iCol.Count}] ");
|
|
||||||
else
|
|
||||||
_stringBuilder.Append("[?] ");
|
|
||||||
}
|
|
||||||
else if (typeof(IDictionary).IsAssignableFrom(type))
|
|
||||||
{
|
|
||||||
if (value is IDictionary iDict)
|
|
||||||
_stringBuilder.Append($"[{iDict.Count}] ");
|
|
||||||
else
|
|
||||||
_stringBuilder.Append("[?] ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type.IsGenericType
|
if (type.IsGenericType
|
||||||
|| toString == type.FullName
|
|| toString == type.FullName
|
||||||
|| toString == $"{type.FullName} {type.FullName}"
|
|| toString == $"{type.FullName} {type.FullName}"
|
||||||
|| toString == $"Il2Cpp{type.FullName}" || type.FullName == $"Il2Cpp{toString}")
|
|| toString == $"Il2Cpp{type.FullName}" || type.FullName == $"Il2Cpp{toString}")
|
||||||
{
|
{
|
||||||
_stringBuilder.Append(richType);
|
sb.Append(richType);
|
||||||
}
|
}
|
||||||
else // the ToString contains some actual implementation, use that value.
|
else // the ToString contains some actual implementation, use that value.
|
||||||
{
|
{
|
||||||
// prune long strings unless they're unity structs
|
// prune long strings unless they're unity structs
|
||||||
// (Matrix4x4 and Rect can have some longs ones that we want to display fully)
|
// (Matrix4x4 and Rect can have some longs ones that we want to display fully)
|
||||||
if (toString.Length > 100 && !(type.IsValueType && type.FullName.StartsWith("UnityEngine")))
|
if (toString.Length > 100 && !(type.IsValueType && type.FullName.StartsWith("UnityEngine")))
|
||||||
_stringBuilder.Append(toString.Substring(0, 100));
|
sb.Append(toString.Substring(0, 100));
|
||||||
else
|
else
|
||||||
_stringBuilder.Append(toString);
|
sb.Append(toString);
|
||||||
|
|
||||||
AppendRichType(_stringBuilder, richType);
|
AppendRichType(sb, richType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _stringBuilder.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AppendRichType(StringBuilder sb, string richType)
|
private static void AppendRichType(StringBuilder sb, string richType)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user