More progress

This commit is contained in:
Sinai
2021-04-30 21:34:50 +10:00
parent 0bc14b2f76
commit 2378925a8b
27 changed files with 1401 additions and 846 deletions

View File

@ -12,9 +12,9 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
public override bool ShouldAutoEvaluate => true;
public override void Initialize(ReflectionInspector inspector, Type declaringType, MemberInfo member, Type returnType)
public override void SetInspectorOwner(ReflectionInspector inspector, MemberInfo member)
{
base.Initialize(inspector, declaringType, member, returnType);
base.SetInspectorOwner(inspector, member);
// not constant
CanWrite = !(FieldInfo.IsLiteral && !FieldInfo.IsInitOnly);

View File

@ -15,98 +15,26 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
public abstract class CacheMember : CacheObjectBase
{
public ReflectionInspector ParentInspector { get; internal set; }
public CacheMemberCell CurrentView { get; internal set; }
public bool AutoUpdateWanted { get; internal set; }
public Type DeclaringType { get; protected set; }
public string NameForFiltering { get; protected set; }
public Type DeclaringType { get; private set; }
public string NameForFiltering { get; private set; }
public object Value { get; protected set; }
public Type FallbackType { get; private set; }
public abstract bool ShouldAutoEvaluate { get; }
public bool HasArguments => Arguments?.Length > 0;
public override 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; }
public Exception LastException { get; protected set; }
public string MemberLabelText { get; private set; }
public string TypeLabelText { get; protected set; }
public string ValueLabelText { get; protected set; }
private static readonly Dictionary<string, MethodInfo> numberParseMethods = new Dictionary<string, MethodInfo>();
public enum ValueState
public virtual void SetInspectorOwner(ReflectionInspector inspector, MemberInfo member)
{
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;
this.ParentInspector = inspector;
this.FallbackType = returnType;
this.MemberLabelText = SignatureHighlighter.ParseFullSyntax(declaringType, false, member);
this.NameForFiltering = $"{declaringType.Name}.{member.Name}";
this.TypeLabelText = SignatureHighlighter.ParseFullType(FallbackType, false);
this.ValueLabelText = GetValueLabel();
}
public virtual void OnDestroyed()
{
// TODO release IValue / Evaluate back to pool, etc
this.NameLabelText = SignatureHighlighter.ParseFullSyntax(member.DeclaringType, false, member);
this.NameForFiltering = $"{member.DeclaringType.Name}.{member.Name}";
}
protected abstract void TryEvaluate();
public void SetValue(object value)
{
// TODO unbox string, cast, etc
TrySetValue(value);
Evaluate();
}
protected abstract void TrySetValue(object value);
public void OnCellApplyClicked()
{
if (CurrentView == null)
{
ExplorerCore.LogWarning("Trying to apply CacheMember but current cell reference is null!");
return;
}
if (State == ValueState.Boolean)
SetValue(this.CurrentView.Toggle.isOn);
else
{
if (!numberParseMethods.ContainsKey(FallbackType.AssemblyQualifiedName))
{
var method = FallbackType.GetMethod("Parse", new Type[] { typeof(string) });
numberParseMethods.Add(FallbackType.AssemblyQualifiedName, method);
}
var val = numberParseMethods[FallbackType.AssemblyQualifiedName]
.Invoke(null, new object[] { CurrentView.InputField.text });
SetValue(val);
}
SetCell(this.CurrentView);
}
/// <summary>
/// Evaluate when first shown (if ShouldAutoEvaluate), or else when Evaluate button is clicked.
/// </summary>
@ -120,79 +48,27 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
ProcessOnEvaluate();
}
/// <summary>
/// Process the CacheMember state when the value has been evaluated (or re-evaluated)
/// </summary>
protected virtual void ProcessOnEvaluate()
public override void SetUserValue(object value)
{
var prevState = State;
// TODO unbox string, cast, etc
if (HadException)
State = ValueState.Exception;
else if (Value.IsNullOrDestroyed())
State = ValueState.NullValue;
else
{
var type = Value.GetActualType();
TrySetValue(value);
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;
}
// Set label text
ValueLabelText = GetValueLabel();
if (State != prevState)
{
// TODO handle if subcontent / evaluate shown, check type change, etc
}
Evaluate();
}
private string GetValueLabel()
protected override void SetValueState(CacheObjectCell cell, bool valueActive, bool valueRichText, Color valueColor,
bool typeLabelActive, bool toggleActive, bool inputActive, bool applyActive, bool inspectActive, bool subContentActive)
{
switch (State)
{
case ValueState.NotEvaluated:
return $"<i>{NOT_YET_EVAL} ({SignatureHighlighter.ParseFullType(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);
}
base.SetValueState(cell, valueActive, valueRichText, valueColor, typeLabelActive, toggleActive, inputActive, applyActive,
inspectActive, subContentActive);
(cell as CacheMemberCell).UpdateToggle.gameObject.SetActive(ShouldAutoEvaluate);
}
/// <summary>
/// Set the cell view for an enabled cell based on this CacheMember model.
/// </summary>
public void SetCell(CacheMemberCell cell)
protected override bool SetCellEvaluateState(CacheObjectCell objectcell)
{
cell.MemberLabel.text = MemberLabelText;
cell.ValueLabel.gameObject.SetActive(true);
var cell = objectcell as CacheMemberCell;
cell.EvaluateHolder.SetActive(!ShouldAutoEvaluate);
if (!ShouldAutoEvaluate)
@ -205,7 +81,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
cell.EvaluateButton.ButtonText.text = "Evaluate";
}
else
{
{
cell.UpdateToggle.gameObject.SetActive(true);
cell.UpdateToggle.isOn = AutoUpdateWanted;
}
@ -215,79 +91,15 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
// todo evaluate buttons etc
SetValueState(cell, true, true, Color.white, false, false, false, false, false, false);
return;
return true;
}
if (State == ValueState.NotEvaluated)
Evaluate();
switch (State)
{
case ValueState.Exception:
case ValueState.NullValue:
SetValueState(cell, true, true, Color.white, false, false, false, false, false, false);
break;
case ValueState.Boolean:
SetValueState(cell, false, false, default, true, toggleActive: true, false, CanWrite, false, false);
break;
case ValueState.Number:
SetValueState(cell, false, true, Color.white, true, false, inputActive: true, CanWrite, false, false);
break;
case ValueState.String:
SetValueState(cell, true, false, SignatureHighlighter.StringOrange, false, false, false, false, false, true);
break;
case ValueState.Enum:
SetValueState(cell, true, true, Color.white, false, false, false, false, false, true);
break;
case ValueState.Collection:
case ValueState.ValueStruct:
SetValueState(cell, true, true, Color.white, false, false, false, false, true, true);
break;
case ValueState.Unsupported:
SetValueState(cell, true, true, Color.white, false, false, false, false, true, false);
break;
}
return false;
}
private void SetValueState(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.InputField.readOnly = !CanWrite;
}
cell.ApplyButton.Button.gameObject.SetActive(applyActive);
cell.InspectButton.Button.gameObject.SetActive(inspectActive);
cell.SubContentButton.Button.gameObject.SetActive(subContentActive);
cell.UpdateToggle.gameObject.SetActive(ShouldAutoEvaluate);
}
#region Cache Member Util
public static bool CanProcessArgs(ParameterInfo[] parameters)
@ -430,7 +242,9 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
cachedSigs.Add(sig);
cached.Initialize(_inspector, declaringType, member, returnType);
//cached.Initialize(_inspector, declaringType, member, returnType);
cached.Initialize(returnType);
cached.SetInspectorOwner(_inspector, member);
list.Add(cached);
}

View File

@ -12,9 +12,9 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
public override bool ShouldAutoEvaluate => false;
public override void Initialize(ReflectionInspector inspector, Type declaringType, MemberInfo member, Type returnType)
public override void SetInspectorOwner(ReflectionInspector inspector, MemberInfo member)
{
base.Initialize(inspector, declaringType, member, returnType);
base.SetInspectorOwner(inspector, member);
Arguments = MethodInfo.GetParameters();
}

View File

@ -1,12 +1,307 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityExplorer.UI.Inspectors.CacheObject.Views;
using UnityExplorer.UI.Inspectors.IValues;
using UnityExplorer.UI.ObjectPool;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.Inspectors.CacheObject
{
public abstract class CacheObjectBase
{
public CacheObjectCell CellView { get; internal set; }
public InteractiveValue IValue { get; private set; }
public Type CurrentIValueType { get; private set; }
public bool SubContentState { get; private set; }
public object Value { get; protected set; }
public Type FallbackType { get; protected set; }
public string NameLabelText { get; protected set; }
public string TypeLabelText { get; protected set; }
public string ValueLabelText { get; protected set; }
public abstract bool ShouldAutoEvaluate { get; }
public abstract bool HasArguments { get; }
public bool CanWrite { get; protected set; }
public bool HadException { get; protected set; }
public Exception LastException { get; protected set; }
public virtual void Initialize(Type fallbackType)
{
this.FallbackType = fallbackType;
this.TypeLabelText = SignatureHighlighter.ParseFullType(FallbackType, false);
this.ValueLabelText = GetValueLabel();
}
// internals
private static readonly Dictionary<string, MethodInfo> numberParseMethods = new Dictionary<string, MethodInfo>();
public enum ValueState
{
NotEvaluated, Exception, NullValue,
Boolean, Number, String, Enum,
Collection, ValueStruct, Unsupported
}
public ValueState State = ValueState.NotEvaluated;
protected const string NOT_YET_EVAL = "<color=grey>Not yet evaluated</color>";
internal static GameObject InactiveIValueHolder
{
get
{
if (!inactiveIValueHolder)
{
inactiveIValueHolder = new GameObject("InactiveIValueHolder");
GameObject.DontDestroyOnLoad(inactiveIValueHolder);
inactiveIValueHolder.transform.parent = UIManager.PoolHolder.transform;
inactiveIValueHolder.SetActive(false);
}
return inactiveIValueHolder;
}
}
private static GameObject inactiveIValueHolder;
// On parent destroying this
public virtual void OnDestroyed()
{
// TODO release IValue / Evaluate back to pool, etc
ReleaseIValue();
}
// Updating and applying values
public abstract void SetUserValue(object value);
/// <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
{
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;
}
// Set label text
ValueLabelText = GetValueLabel();
if (State != prevState)
{
// TODO handle if subcontent / evaluate shown, check type change, etc
}
}
protected string GetValueLabel()
{
switch (State)
{
case ValueState.NotEvaluated:
return $"<i>{NOT_YET_EVAL} ({SignatureHighlighter.ParseFullType(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);
}
}
protected abstract bool SetCellEvaluateState(CacheObjectCell cell);
public virtual void SetCell(CacheObjectCell cell)
{
cell.NameLabel.text = NameLabelText;
cell.ValueLabel.gameObject.SetActive(true);
cell.SubContentHolder.gameObject.SetActive(SubContentState);
if (IValue != null)
IValue.UIRoot.transform.SetParent(cell.SubContentHolder.transform, false);
if (SetCellEvaluateState(cell))
return;
switch (State)
{
case ValueState.Exception:
case ValueState.NullValue:
ReleaseIValue();
SetValueState(cell, true, true, Color.white, false, false, false, false, false, false);
break;
case ValueState.Boolean:
SetValueState(cell, false, false, default, false, toggleActive: true, false, CanWrite, false, false);
break;
case ValueState.Number:
SetValueState(cell, false, true, Color.white, true, false, inputActive: true, CanWrite, false, false);
break;
case ValueState.String:
UpdateIValueOnValueUpdate();
SetValueState(cell, true, false, SignatureHighlighter.StringOrange, false, false, false, false, false, true);
break;
case ValueState.Enum:
UpdateIValueOnValueUpdate();
SetValueState(cell, true, true, Color.white, false, false, false, false, false, true);
break;
case ValueState.Collection:
case ValueState.ValueStruct:
UpdateIValueOnValueUpdate();
SetValueState(cell, true, true, Color.white, false, false, false, false, true, true);
break;
case ValueState.Unsupported:
SetValueState(cell, true, true, Color.white, false, false, false, false, true, false);
break;
}
}
protected virtual void SetValueState(CacheObjectCell 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.InputField.readOnly = !CanWrite;
}
cell.ApplyButton.Button.gameObject.SetActive(applyActive);
cell.InspectButton.Button.gameObject.SetActive(inspectActive);
cell.SubContentButton.Button.gameObject.SetActive(subContentActive);
}
// IValues
public virtual void OnCellSubContentToggle()
{
if (this.IValue == null)
{
IValue = (InteractiveValue)Pool.Borrow(typeof(InteractiveValue));
IValue.SetOwner(this);
IValue.UIRoot.transform.SetParent(CellView.SubContentHolder.transform, false);
CellView.SubContentHolder.SetActive(true);
SubContentState = true;
}
else
{
SubContentState = !SubContentState;
CellView.SubContentHolder.SetActive(SubContentState);
}
}
public virtual void ReleaseIValue()
{
if (IValue == null)
return;
IValue.OnOwnerReleased();
Pool.Return(CurrentIValueType, IValue);
IValue = null;
}
internal void HideIValue()
{
if (this.IValue == null)
return;
this.IValue.UIRoot.transform.SetParent(InactiveIValueHolder.transform, false);
}
public void UpdateIValueOnValueUpdate()
{
if (this.IValue == null)
return;
IValue.SetValue(Value);
}
// CacheObjectCell Apply
public virtual void OnCellApplyClicked()
{
if (CellView == null)
{
ExplorerCore.LogWarning("Trying to apply CacheMember but current cell reference is null!");
return;
}
if (State == ValueState.Boolean)
SetUserValue(this.CellView.Toggle.isOn);
else
{
if (!numberParseMethods.ContainsKey(FallbackType.AssemblyQualifiedName))
{
var method = FallbackType.GetMethod("Parse", new Type[] { typeof(string) });
numberParseMethods.Add(FallbackType.AssemblyQualifiedName, method);
}
var val = numberParseMethods[FallbackType.AssemblyQualifiedName]
.Invoke(null, new object[] { CellView.InputField.text });
SetUserValue(val);
}
SetCell(this.CellView);
}
}
}

View File

@ -12,9 +12,9 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
public override bool ShouldAutoEvaluate => !HasArguments;
public override void Initialize(ReflectionInspector inspector, Type declaringType, MemberInfo member, Type returnType)
public override void SetInspectorOwner(ReflectionInspector inspector, MemberInfo member)
{
base.Initialize(inspector, declaringType, member, returnType);
base.SetInspectorOwner(inspector, member);
this.CanWrite = PropertyInfo.CanWrite;
Arguments = PropertyInfo.GetIndexParameters();

View File

@ -4,207 +4,57 @@ 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
{
public class CacheMemberCell : ICell
public class CacheMemberCell : CacheObjectCell
{
#region ICell
public float DefaultHeight => 30f;
public GameObject UIRoot => uiRoot;
public GameObject uiRoot;
public bool Enabled => m_enabled;
private bool m_enabled;
public RectTransform Rect => m_rect;
private RectTransform m_rect;
public void Disable()
{
m_enabled = false;
uiRoot.SetActive(false);
}
public void Enable()
{
m_enabled = true;
uiRoot.SetActive(true);
}
#endregion
public ReflectionInspector CurrentOwner { get; set; }
public CacheMember CurrentOccupant { get; set; }
public LayoutElement MemberLayout;
public LayoutElement RightGroupLayout;
public Text MemberLabel;
public Text TypeLabel;
public Text ValueLabel;
public Toggle Toggle;
public Text ToggleText;
public InputField InputField;
public CacheMember MemberOccupant => Occupant as CacheMember;
public GameObject EvaluateHolder;
public ButtonRef EvaluateButton;
public ButtonRef InspectButton;
public ButtonRef SubContentButton;
public ButtonRef ApplyButton;
public Toggle UpdateToggle;
public GameObject SubContentHolder;
public void OnReturnToPool()
protected virtual void EvaluateClicked()
{
if (CurrentOccupant != null)
{
// TODO
// TODO
}
CurrentOccupant = null;
}
public override void OnReturnToPool()
{
base.OnReturnToPool();
// TODO ?
CurrentOwner = null;
}
private void ApplyClicked()
protected override void ConstructEvaluateHolder(GameObject parent)
{
CurrentOccupant.OnCellApplyClicked();
}
private void InspectClicked()
{
InspectorManager.Inspect(CurrentOccupant.Value);
}
private void EvaluateClicked()
{
// TODO
}
private void SubContentClicked()
{
// TODO
}
private void ToggleClicked(bool value)
{
ToggleText.text = value.ToString();
}
// Todo could create these as needed maybe, just need to make sure the transform order is correct.
public GameObject CreateContent(GameObject parent)
{
// Main layout
uiRoot = UIFactory.CreateUIObject("CacheMemberCell", parent, new Vector2(100, 30));
m_rect = uiRoot.GetComponent<RectTransform>();
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;
var separator = UIFactory.CreateUIObject("TopSeperator", uiRoot);
UIFactory.SetLayoutElement(separator, minHeight: 1, flexibleHeight: 0, flexibleWidth: 9999);
separator.AddComponent<Image>().color = Color.black;
var horiRow = UIFactory.CreateUIObject("HoriGroup", uiRoot);
UIFactory.SetLayoutElement(horiRow, minHeight: 29, flexibleHeight: 150, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(horiRow, false, false, true, true, 5, 2, childAlignment: TextAnchor.UpperLeft);
horiRow.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// Left member label
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>();
// Right vertical group
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>();
// Evaluate vert group
EvaluateHolder = UIFactory.CreateUIObject("EvalGroup", rightGroupHolder);
EvaluateHolder = UIFactory.CreateUIObject("EvalGroup", parent);
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;
}
// Right horizontal group
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: 70, flexibleWidth: 0);
// Bool and number value interaction
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);
var inputObj = UIFactory.CreateInputField(rightHoriGroup, "InputField", "...", out InputField);
UIFactory.SetLayoutElement(inputObj, minWidth: 150, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0);
// Inspect and apply buttons
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;
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;
// Main value label
ValueLabel = UIFactory.CreateLabel(rightHoriGroup, "ValueLabel", "Value goes here", TextAnchor.MiddleLeft);
ValueLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
UIFactory.SetLayoutElement(ValueLabel.gameObject, minHeight: 25, flexibleHeight: 150, flexibleWidth: 9999);
protected override void ConstructUpdateToggle(GameObject parent)
{
// Auto-update toggle
var updateToggle = UIFactory.CreateToggle(rightHoriGroup, "AutoUpdate", out UpdateToggle, out Text autoText);
var updateToggle = UIFactory.CreateToggle(parent, "AutoUpdate", out UpdateToggle, out Text autoText);
UIFactory.SetLayoutElement(updateToggle, minHeight: 25, minWidth: 30, flexibleWidth: 0, flexibleHeight: 0);
GameObject.Destroy(autoText);
UpdateToggle.isOn = false;
UpdateToggle.onValueChanged.AddListener((bool val) => { CurrentOccupant.AutoUpdateWanted = val; });
//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);
UIFactory.SetLayoutElement(SubContentHolder.gameObject, minHeight: 30, flexibleHeight: 500, minWidth: 100, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(SubContentHolder, true, false, true, true, 2, childAlignment: TextAnchor.UpperLeft);
SubContentHolder.SetActive(false);
return uiRoot;
UpdateToggle.onValueChanged.AddListener((bool val) => { MemberOccupant.AutoUpdateWanted = val; });
}
}
}

View File

@ -2,10 +2,189 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.Inspectors.IValues;
using UnityExplorer.UI.ObjectPool;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Inspectors.CacheObject.Views
{
class CacheObjectCell
public abstract class CacheObjectCell : ICell
{
#region ICell
public float DefaultHeight => 30f;
public GameObject UIRoot => uiRoot;
public GameObject uiRoot;
public bool Enabled => m_enabled;
private bool m_enabled;
public RectTransform Rect => m_rect;
private RectTransform m_rect;
public void Disable()
{
m_enabled = false;
uiRoot.SetActive(false);
}
public void Enable()
{
m_enabled = true;
uiRoot.SetActive(true);
}
#endregion
public CacheObjectBase Occupant { get; set; }
public bool SubContentActive => SubContentHolder.activeSelf;
public LayoutElement MemberLayout;
public LayoutElement RightGroupLayout;
public Text NameLabel;
public Text TypeLabel;
public Text ValueLabel;
public Toggle Toggle;
public Text ToggleText;
public InputField InputField;
public ButtonRef InspectButton;
public ButtonRef SubContentButton;
public ButtonRef ApplyButton;
public GameObject SubContentHolder;
public virtual void OnReturnToPool()
{
if (Occupant != null)
{
// TODO ?
SubContentHolder.SetActive(false);
Occupant = null;
}
}
protected virtual void ApplyClicked()
{
Occupant.OnCellApplyClicked();
}
protected virtual void InspectClicked()
{
InspectorManager.Inspect(Occupant.Value);
}
protected virtual void ToggleClicked(bool value)
{
ToggleText.text = value.ToString();
}
protected virtual void SubContentClicked()
{
this.Occupant.OnCellSubContentToggle();
}
protected abstract void ConstructEvaluateHolder(GameObject parent);
protected abstract void ConstructUpdateToggle(GameObject parent);
// Todo could create these as needed maybe, just need to make sure the transform order is correct.
public GameObject CreateContent(GameObject parent)
{
// Main layout
uiRoot = UIFactory.CreateUIObject("CacheMemberCell", parent, new Vector2(100, 30));
m_rect = uiRoot.GetComponent<RectTransform>();
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;
var separator = UIFactory.CreateUIObject("TopSeperator", uiRoot);
UIFactory.SetLayoutElement(separator, minHeight: 1, flexibleHeight: 0, flexibleWidth: 9999);
separator.AddComponent<Image>().color = Color.black;
var horiRow = UIFactory.CreateUIObject("HoriGroup", uiRoot);
UIFactory.SetLayoutElement(horiRow, minHeight: 29, flexibleHeight: 150, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(horiRow, false, false, true, true, 5, 2, childAlignment: TextAnchor.UpperLeft);
horiRow.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// Left member label
NameLabel = UIFactory.CreateLabel(horiRow, "MemberLabel", "<notset>", TextAnchor.MiddleLeft);
NameLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
UIFactory.SetLayoutElement(NameLabel.gameObject, minHeight: 25, minWidth: 20, flexibleHeight: 300, flexibleWidth: 0);
MemberLayout = NameLabel.GetComponent<LayoutElement>();
// Right vertical group
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>();
ConstructEvaluateHolder(rightGroupHolder);
// Right horizontal group
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;
// Type label
TypeLabel = UIFactory.CreateLabel(rightHoriGroup, "ReturnLabel", "<notset>", TextAnchor.MiddleLeft);
TypeLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
UIFactory.SetLayoutElement(TypeLabel.gameObject, minHeight: 25, flexibleHeight: 150, minWidth: 60, flexibleWidth: 0);
// Bool and number value interaction
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);
var inputObj = UIFactory.CreateInputField(rightHoriGroup, "InputField", "...", out InputField);
UIFactory.SetLayoutElement(inputObj, minWidth: 150, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0);
// Inspect and apply buttons
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;
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;
// Main value label
ValueLabel = UIFactory.CreateLabel(rightHoriGroup, "ValueLabel", "Value goes here", TextAnchor.MiddleLeft);
ValueLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
UIFactory.SetLayoutElement(ValueLabel.gameObject, minHeight: 25, flexibleHeight: 150, flexibleWidth: 9999);
ConstructUpdateToggle(rightHoriGroup);
// Subcontent (todo?)
SubContentHolder = UIFactory.CreateUIObject("SubContent", uiRoot);
UIFactory.SetLayoutElement(SubContentHolder.gameObject, minHeight: 30, flexibleHeight: 500, minWidth: 100, flexibleWidth: 9999);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(SubContentHolder, true, false, true, true, 2, childAlignment: TextAnchor.UpperLeft);
SubContentHolder.SetActive(false);
return uiRoot;
}
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.ObjectPool;
namespace UnityExplorer.UI.Inspectors.IValues
{
public class IValueTest : IPooledObject
{
public GameObject UIRoot => uiRoot;
private GameObject uiRoot;
public float DefaultHeight => -1f;
public GameObject CreateContent(GameObject parent)
{
uiRoot = UIFactory.CreateUIObject(this.GetType().Name, parent);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(uiRoot, true, true, true, true, 3, childAlignment: TextAnchor.MiddleLeft);
return uiRoot;
}
}
}

View File

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.Inspectors.CacheObject;
using UnityExplorer.UI.ObjectPool;
namespace UnityExplorer.UI.Inspectors.IValues
{
public class InteractiveValue : IPooledObject
{
public GameObject UIRoot => uiRoot;
private GameObject uiRoot;
public float DefaultHeight => -1f;
public CacheObjectBase CurrentOwner { get; }
private CacheObjectBase m_owner;
public object EditedValue { get; private set; }
public virtual void SetOwner(CacheObjectBase owner)
{
if (this.m_owner != null)
{
ExplorerCore.LogWarning("Setting an IValue's owner but there is already one set. Maybe it wasn't cleaned up?");
OnOwnerReleased();
}
this.m_owner = owner;
// ...
}
public virtual void SetValue(object value)
{
this.EditedValue = value;
}
public virtual void OnOwnerReleased()
{
if (this.m_owner == null)
return;
// ...
this.m_owner = null;
}
public GameObject CreateContent(GameObject parent)
{
uiRoot = UIFactory.CreateUIObject(this.GetType().Name, parent);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(uiRoot, true, true, true, true, 3, childAlignment: TextAnchor.MiddleLeft);
UIFactory.CreateLabel(uiRoot, "Label", "this is an ivalue", TextAnchor.MiddleLeft);
return uiRoot;
}
}
}

View File

@ -19,7 +19,6 @@ namespace UnityExplorer.UI.Inspectors
public class ReflectionInspector : InspectorBase, IPoolDataSource<CacheMemberCell>
{
public bool StaticOnly { get; internal set; }
//public bool AutoUpdate { get; internal set; }
public object Target { get; private set; }
public Type TargetType { get; private set; }
@ -38,6 +37,8 @@ namespace UnityExplorer.UI.Inspectors
private LayoutElement memberTitleLayout;
private Toggle autoUpdateToggle;
public override void OnBorrowedFromPool(object target)
{
base.OnBorrowedFromPool(target);
@ -45,6 +46,7 @@ namespace UnityExplorer.UI.Inspectors
SetTitleLayouts();
SetTarget(target);
MemberScrollPool.Initialize(this);
RuntimeProvider.Instance.StartCoroutine(InitCoroutine());
}
@ -53,9 +55,6 @@ namespace UnityExplorer.UI.Inspectors
yield return null;
LayoutRebuilder.ForceRebuildLayoutImmediate(InspectorPanel.Instance.ContentRect);
MemberScrollPool.RecreateHeightCache();
MemberScrollPool.Rebuild();
}
public override void OnReturnToPool()
@ -71,6 +70,8 @@ namespace UnityExplorer.UI.Inspectors
filteredMembers.Clear();
displayedMembers.Clear();
autoUpdateToggle.isOn = false;
base.OnReturnToPool();
}
@ -113,6 +114,8 @@ namespace UnityExplorer.UI.Inspectors
var member = members[i];
filteredMembers.Add(member);
}
//MemberScrollPool.RecreateHeightCache();
}
public override void OnSetActive()
@ -161,11 +164,11 @@ namespace UnityExplorer.UI.Inspectors
bool shouldRefresh = false;
foreach (var member in displayedMembers)
{
if (!onlyAutoUpdate || member.AutoUpdateWanted)
if (member.ShouldAutoEvaluate && (!onlyAutoUpdate || member.AutoUpdateWanted))
{
shouldRefresh = true;
member.Evaluate();
member.SetCell(member.CurrentView);
member.SetCell(member.CellView);
}
}
@ -191,12 +194,12 @@ namespace UnityExplorer.UI.Inspectors
{
if (index < 0 || index >= filteredMembers.Count)
{
if (cell.CurrentOccupant != null)
if (cell.Occupant != null)
{
if (displayedMembers.Contains(cell.CurrentOccupant))
displayedMembers.Remove(cell.CurrentOccupant);
if (displayedMembers.Contains(cell.MemberOccupant))
displayedMembers.Remove(cell.MemberOccupant);
cell.CurrentOccupant.CurrentView = null;
cell.Occupant.CellView = null;
}
cell.Disable();
@ -205,19 +208,17 @@ namespace UnityExplorer.UI.Inspectors
var member = filteredMembers[index];
if (member != cell.CurrentOccupant)
if (member != cell.Occupant)
{
if (cell.CurrentOccupant != null)
if (cell.Occupant != null)
{
// TODO
// changing occupant, put subcontent/evaluator on temp holder, etc
displayedMembers.Remove(cell.CurrentOccupant);
cell.CurrentOccupant.CurrentView = null;
cell.Occupant.HideIValue();
displayedMembers.Remove(cell.MemberOccupant);
cell.Occupant.CellView = null;
}
cell.CurrentOccupant = member;
member.CurrentView = cell;
cell.Occupant = member;
member.CellView = cell;
displayedMembers.Add(member);
}
@ -226,6 +227,18 @@ namespace UnityExplorer.UI.Inspectors
SetCellLayout(cell);
}
private void ToggleAllAutoUpdateStates(bool state)
{
if (members == null || !members.Any())
return;
foreach (var member in members)
member.AutoUpdateWanted = state;
foreach (var cell in MemberScrollPool.CellPool)
cell.UpdateToggle.isOn = state;
}
// Cell layout (fake table alignment)
private static float MemLabelWidth { get; set; }
@ -240,7 +253,7 @@ namespace UnityExplorer.UI.Inspectors
memberTitleLayout.minWidth = MemLabelWidth;
}
private void SetCellLayout(CacheMemberCell cell)
private void SetCellLayout(CacheObjectCell cell)
{
cell.MemberLayout.minWidth = MemLabelWidth;
cell.RightGroupLayout.minWidth = RightGroupWidth;
@ -279,7 +292,7 @@ namespace UnityExplorer.UI.Inspectors
memberTitleLayout = memberTitle.gameObject.AddComponent<LayoutElement>();
var valueTitle = UIFactory.CreateLabel(listTitles, "ValueTitle", "Value", TextAnchor.LowerLeft, Color.grey, fontSize: 15);
UIFactory.SetLayoutElement(valueTitle.gameObject, minWidth: 150, flexibleWidth: 9999);
UIFactory.SetLayoutElement(valueTitle.gameObject, minWidth: 50, flexibleWidth: 9999);
var updateButton = UIFactory.CreateButton(listTitles, "UpdateButton", "Update values", new Color(0.22f, 0.28f, 0.22f));
UIFactory.SetLayoutElement(updateButton.Button.gameObject, minHeight: 25, minWidth: 130, flexibleWidth: 0);
@ -288,17 +301,24 @@ namespace UnityExplorer.UI.Inspectors
var updateText = UIFactory.CreateLabel(listTitles, "AutoUpdateLabel", "Auto-update", TextAnchor.MiddleRight, Color.grey);
UIFactory.SetLayoutElement(updateText.gameObject, minHeight: 25, minWidth: 80, flexibleWidth: 0);
var toggleObj = UIFactory.CreateToggle(listTitles, "AutoUpdateToggle", out autoUpdateToggle, out Text toggleText);
GameObject.DestroyImmediate(toggleText);
UIFactory.SetLayoutElement(toggleObj, minHeight: 25, minWidth: 25);
autoUpdateToggle.isOn = false;
autoUpdateToggle.onValueChanged.AddListener((bool val) => { ToggleAllAutoUpdateStates(val); });
var spacer = UIFactory.CreateUIObject("spacer", listTitles);
UIFactory.SetLayoutElement(spacer, minWidth: 25, flexibleWidth: 0);
// Member scroll pool
MemberScrollPool = UIFactory.CreateScrollPool<CacheMemberCell>(uiRoot, "MemberList", out GameObject scrollObj,
out GameObject _, new Color(0.09f, 0.09f, 0.09f));
UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999);
MemberScrollPool.Initialize(this);
InspectorPanel.Instance.UIRoot.GetComponent<Mask>().enabled = false;
MemberScrollPool.Viewport.GetComponent<Mask>().enabled = false;
MemberScrollPool.Viewport.GetComponent<Image>().color = new Color(0.12f, 0.12f, 0.12f);
//InspectorPanel.Instance.UIRoot.GetComponent<Mask>().enabled = false;
//MemberScrollPool.Viewport.GetComponent<Mask>().enabled = false;
//MemberScrollPool.Viewport.GetComponent<Image>().color = new Color(0.12f, 0.12f, 0.12f);
return uiRoot;
}