Progress on inspector, interactive list basically done

This commit is contained in:
Sinai
2021-05-01 20:55:27 +10:00
parent ab8b736f7e
commit 15ec64b106
26 changed files with 695 additions and 309 deletions

View File

@ -9,6 +9,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
public class CacheField : CacheMember
{
public FieldInfo FieldInfo { get; internal set; }
public override Type DeclaringType => FieldInfo.DeclaringType;
public override bool ShouldAutoEvaluate => true;

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.UI.Inspectors.CacheObject.Views;
using UnityExplorer.UI.Inspectors.IValues;
namespace UnityExplorer.UI.Inspectors.CacheObject
{
public class CacheListEntry : CacheObjectBase
{
public InteractiveList CurrentList { get; set; }
public int ListIndex;
public override bool ShouldAutoEvaluate => true;
public override bool HasArguments => false;
public void SetListOwner(InteractiveList iList, int listIndex)
{
this.CurrentList = iList;
this.ListIndex = listIndex;
}
public override void SetCell(CacheObjectCell cell)
{
base.SetCell(cell);
var listCell = cell as CacheListEntryCell;
listCell.NameLabel.text = $"{ListIndex}:";
}
public override void SetUserValue(object value)
{
throw new NotImplementedException("TODO");
}
protected override bool SetCellEvaluateState(CacheObjectCell cell)
{
// not needed
return false;
}
}
}

View File

@ -9,15 +9,12 @@ 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; }
public bool AutoUpdateWanted { get; internal set; }
//public bool AutoUpdateWanted { get; internal set; }
public Type DeclaringType { get; protected set; }
public abstract Type DeclaringType { get; }
public string NameForFiltering { get; protected set; }
public override bool HasArguments => Arguments?.Length > 0;
@ -36,16 +33,12 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
protected abstract void TrySetValue(object value);
/// <summary>
/// Evaluate when first shown (if ShouldAutoEvaluate), or else when Evaluate button is clicked.
/// Evaluate when first shown (if ShouldAutoEvaluate), or else when Evaluate button is clicked, or auto-updated.
/// </summary>
public void Evaluate()
{
TryEvaluate();
if (!Value.IsNullOrDestroyed())
Value = Value.TryCast();
ProcessOnEvaluate();
SetValueFromSource(Value);
}
public override void SetUserValue(object value)
@ -57,13 +50,12 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
Evaluate();
}
protected override void SetValueState(CacheObjectCell cell, bool valueActive, bool valueRichText, Color valueColor,
bool typeLabelActive, bool toggleActive, bool inputActive, bool applyActive, bool inspectActive, bool subContentActive)
protected override void SetValueState(CacheObjectCell cell, ValueStateArgs args)
{
base.SetValueState(cell, valueActive, valueRichText, valueColor, typeLabelActive, toggleActive, inputActive, applyActive,
inspectActive, subContentActive);
base.SetValueState(cell, args);
(cell as CacheMemberCell).UpdateToggle.gameObject.SetActive(ShouldAutoEvaluate);
//var memCell = cell as CacheMemberCell;
//memCell.UpdateToggle.gameObject.SetActive(ShouldAutoEvaluate);
}
protected override bool SetCellEvaluateState(CacheObjectCell objectcell)
@ -73,7 +65,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
cell.EvaluateHolder.SetActive(!ShouldAutoEvaluate);
if (!ShouldAutoEvaluate)
{
cell.UpdateToggle.gameObject.SetActive(false);
//cell.UpdateToggle.gameObject.SetActive(false);
cell.EvaluateButton.Button.gameObject.SetActive(true);
if (HasArguments)
cell.EvaluateButton.ButtonText.text = $"Evaluate ({Arguments.Length})";
@ -82,14 +74,14 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
}
else
{
cell.UpdateToggle.gameObject.SetActive(true);
cell.UpdateToggle.isOn = AutoUpdateWanted;
//cell.UpdateToggle.gameObject.SetActive(true);
//cell.UpdateToggle.isOn = AutoUpdateWanted;
}
if (State == ValueState.NotEvaluated && !ShouldAutoEvaluate)
{
// todo evaluate buttons etc
SetValueState(cell, true, true, Color.white, false, false, false, false, false, false);
SetValueState(cell, ValueStateArgs.Default);
return true;
}

View File

@ -9,6 +9,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
public class CacheMethod : CacheMember
{
public MethodInfo MethodInfo { get; internal set; }
public override Type DeclaringType => MethodInfo.DeclaringType;
public override bool ShouldAutoEvaluate => false;

View File

@ -11,6 +11,22 @@ using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.Inspectors.CacheObject
{
public enum ValueState
{
NotEvaluated,
Exception,
NullValue,
Boolean,
Number,
String,
Enum,
Collection,
Dictionary,
ValueStruct,
Color,
Unsupported
}
public abstract class CacheObjectBase
{
public CacheObjectCell CellView { get; internal set; }
@ -23,7 +39,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
public Type FallbackType { get; protected set; }
public string NameLabelText { get; protected set; }
public string TypeLabelText { get; protected set; }
//public string TypeLabelText { get; set; }
public string ValueLabelText { get; protected set; }
public abstract bool ShouldAutoEvaluate { get; }
@ -35,7 +51,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
public virtual void Initialize(Type fallbackType)
{
this.FallbackType = fallbackType;
this.TypeLabelText = SignatureHighlighter.ParseFullType(FallbackType, false);
//this.TypeLabelText = SignatureHighlighter.ParseFullType(FallbackType, false);
this.ValueLabelText = GetValueLabel();
}
@ -43,13 +59,6 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
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>";
@ -74,12 +83,43 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
public virtual void ReleasePooledObjects()
{
// TODO release IValue / Evaluate back to pool, etc
ReleaseIValue();
if (this.IValue != null)
ReleaseIValue();
// TODO release Evaluate
if (this.CellView != null)
{
this.CellView.Occupant = null;
this.CellView.SubContentHolder.SetActive(false);
this.CellView = null;
}
}
// Updating and applying values
public virtual void SetValueFromSource(object value)
{
this.Value = value;
if (!Value.IsNullOrDestroyed())
Value = Value.TryCast();
var prevState = State;
ProcessOnEvaluate();
if (State != prevState)
{
// TODO handle if subcontent / evaluate shown, check type change, etc
}
if (this.IValue != null)
{
this.IValue.SetValue(Value);
}
}
public abstract void SetUserValue(object value);
/// <summary>
@ -87,7 +127,6 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
/// </summary>
protected virtual void ProcessOnEvaluate()
{
var prevState = State;
if (HadException)
State = ValueState.Exception;
@ -105,8 +144,10 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
State = ValueState.String;
else if (type.IsEnum)
State = ValueState.Enum;
else if (type.IsEnumerable() || type.IsDictionary())
else if (type.IsEnumerable())
State = ValueState.Collection;
else if (type.IsDictionary())
State = ValueState.Dictionary;
// todo Color and ValueStruct
else
State = ValueState.Unsupported;
@ -114,11 +155,6 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
// Set label text
ValueLabelText = GetValueLabel();
if (State != prevState)
{
// TODO handle if subcontent / evaluate shown, check type change, etc
}
}
protected string GetValueLabel()
@ -148,6 +184,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
}
}
/// <summary>Return true if SetCell should abort, false if it should continue.</summary>
protected abstract bool SetCellEvaluateState(CacheObjectCell cell);
public virtual void SetCell(CacheObjectCell cell)
@ -167,81 +204,96 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
case ValueState.Exception:
case ValueState.NullValue:
ReleaseIValue();
SetValueState(cell, true, true, Color.white, false, false, false, false, false, false);
SetValueState(cell, ValueStateArgs.Default);
break;
case ValueState.Boolean:
SetValueState(cell, false, false, default, false, toggleActive: true, false, CanWrite, false, false);
SetValueState(cell, new ValueStateArgs(false, toggleActive:true, applyActive: CanWrite));
break;
case ValueState.Number:
SetValueState(cell, false, true, Color.white, true, false, inputActive: true, CanWrite, false, false);
SetValueState(cell, new ValueStateArgs(false, typeLabelActive: true, inputActive: true, applyActive: CanWrite));
break;
case ValueState.String:
UpdateIValueOnValueUpdate();
SetValueState(cell, true, false, SignatureHighlighter.StringOrange, false, false, false, false, false, true);
SetIValueState();
SetValueState(cell, new ValueStateArgs(true, false, SignatureHighlighter.StringOrange, subContentButtonActive: true));
break;
case ValueState.Enum:
UpdateIValueOnValueUpdate();
SetValueState(cell, true, true, Color.white, false, false, false, false, false, true);
SetIValueState();
SetValueState(cell, new ValueStateArgs(true, subContentButtonActive: true));
break;
case ValueState.Collection:
case ValueState.ValueStruct:
UpdateIValueOnValueUpdate();
SetValueState(cell, true, true, Color.white, false, false, false, false, true, true);
SetIValueState();
SetValueState(cell, new ValueStateArgs(true, inspectActive: true, subContentButtonActive: true));
break;
case ValueState.Unsupported:
SetValueState(cell, true, true, Color.white, false, false, false, false, true, false);
SetValueState(cell, new ValueStateArgs(true, inspectActive: true));
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)
protected virtual void SetValueState(CacheObjectCell cell, ValueStateArgs args)
{
//cell.ValueLabel.gameObject.SetActive(valueActive);
if (valueActive)
if (args.valueActive)
{
cell.ValueLabel.text = ValueLabelText;
cell.ValueLabel.supportRichText = valueRichText;
cell.ValueLabel.color = valueColor;
cell.ValueLabel.supportRichText = args.valueRichText;
cell.ValueLabel.color = args.valueColor;
}
else
cell.ValueLabel.text = "";
cell.TypeLabel.gameObject.SetActive(typeLabelActive);
if (typeLabelActive)
cell.TypeLabel.text = TypeLabelText;
cell.TypeLabel.gameObject.SetActive(args.typeLabelActive);
if (args.typeLabelActive)
cell.TypeLabel.text = SignatureHighlighter.ParseFullType(Value.GetActualType(), false);
cell.Toggle.gameObject.SetActive(toggleActive);
if (toggleActive)
cell.Toggle.gameObject.SetActive(args.toggleActive);
if (args.toggleActive)
{
cell.Toggle.isOn = (bool)Value;
cell.ToggleText.text = Value.ToString();
}
cell.InputField.gameObject.SetActive(inputActive);
if (inputActive)
cell.InputField.gameObject.SetActive(args.inputActive);
if (args.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.ApplyButton.Button.gameObject.SetActive(args.applyActive);
cell.InspectButton.Button.gameObject.SetActive(args.inspectActive);
cell.SubContentButton.Button.gameObject.SetActive(args.subContentButtonActive);
}
// IValues
/// <summary>Called from SetCellState if SubContent button is wanted.</summary>
public void SetIValueState()
{
if (this.IValue == null)
return;
// TODO ?
}
// temp for testing
public virtual void OnCellSubContentToggle()
{
if (this.IValue == null)
{
IValue = (InteractiveValue)Pool.Borrow(typeof(InteractiveValue));
CurrentIValueType = IValue.GetType();
var ivalueType = InteractiveValue.GetIValueTypeForState(State);
IValue = (InteractiveValue)Pool.Borrow(ivalueType);
CurrentIValueType = ivalueType;
IValue.SetOwner(this);
IValue.SetValue(this.Value);
IValue.UIRoot.transform.SetParent(CellView.SubContentHolder.transform, false);
CellView.SubContentHolder.SetActive(true);
SubContentState = true;
// update our cell after creating the ivalue (the value may have updated, make sure its consistent)
this.ProcessOnEvaluate();
this.SetCell(this.CellView);
}
else
{
@ -255,7 +307,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
if (IValue == null)
return;
IValue.OnOwnerReleased();
IValue.ReleaseFromOwner();
Pool.Return(CurrentIValueType, IValue);
IValue = null;
@ -269,14 +321,6 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
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()
@ -304,5 +348,31 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
SetCell(this.CellView);
}
public struct ValueStateArgs
{
public ValueStateArgs(bool valueActive = true, bool valueRichText = true, Color? valueColor = null,
bool typeLabelActive = false, bool toggleActive = false, bool inputActive = false, bool applyActive = false,
bool inspectActive = false, bool subContentButtonActive = false)
{
this.valueActive = valueActive;
this.valueRichText = valueRichText;
this.valueColor = valueColor == null ? Color.white : (Color)valueColor;
this.typeLabelActive = typeLabelActive;
this.toggleActive = toggleActive;
this.inputActive = inputActive;
this.applyActive = applyActive;
this.inspectActive = inspectActive;
this.subContentButtonActive = subContentButtonActive;
}
public static ValueStateArgs Default => _default;
private static ValueStateArgs _default = new ValueStateArgs(true);
public bool valueActive, valueRichText, typeLabelActive, toggleActive,
inputActive, applyActive, inspectActive, subContentButtonActive;
public Color valueColor;
}
}
}

View File

@ -9,6 +9,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
public class CacheProperty : CacheMember
{
public PropertyInfo PropertyInfo { get; internal set; }
public override Type DeclaringType => PropertyInfo.DeclaringType;
public override bool ShouldAutoEvaluate => !HasArguments;

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityExplorer.UI.Inspectors.IValues;
namespace UnityExplorer.UI.Inspectors.CacheObject.Views
{
public class CacheListEntryCell : CacheObjectCell
{
public InteractiveList ListOwner { get; set; }
public override GameObject CreateContent(GameObject parent)
{
var root = base.CreateContent(parent);
this.NameLayout.minWidth = 50;
this.NameLayout.flexibleWidth = 50f;
return root;
}
protected override void ConstructEvaluateHolder(GameObject parent)
{
// not used
}
//protected override void ConstructUpdateToggle(GameObject parent)
//{
// // not used
//}
}
}

View File

@ -17,7 +17,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject.Views
public GameObject EvaluateHolder;
public ButtonRef EvaluateButton;
public Toggle UpdateToggle;
//public Toggle UpdateToggle;
protected virtual void EvaluateClicked()
{
@ -37,15 +37,15 @@ namespace UnityExplorer.UI.Inspectors.CacheObject.Views
EvaluateButton.OnClick += EvaluateClicked;
}
protected override void ConstructUpdateToggle(GameObject parent)
{
// Auto-update toggle
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) => { MemberOccupant.AutoUpdateWanted = val; });
}
//protected override void ConstructUpdateToggle(GameObject parent)
//{
// // Auto-update toggle
//
// 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) => { MemberOccupant.AutoUpdateWanted = val; });
//}
}
}

View File

@ -17,25 +17,23 @@ namespace UnityExplorer.UI.Inspectors.CacheObject.Views
public float DefaultHeight => 30f;
public GameObject UIRoot => uiRoot;
public GameObject uiRoot;
public GameObject UIRoot { get; set; }
public bool Enabled => m_enabled;
private bool m_enabled;
public RectTransform Rect => m_rect;
private RectTransform m_rect;
public RectTransform Rect { get; set; }
public void Disable()
{
m_enabled = false;
uiRoot.SetActive(false);
UIRoot.SetActive(false);
}
public void Enable()
{
m_enabled = true;
uiRoot.SetActive(true);
UIRoot.SetActive(true);
}
#endregion
@ -43,7 +41,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject.Views
public CacheObjectBase Occupant { get; set; }
public bool SubContentActive => SubContentHolder.activeSelf;
public LayoutElement MemberLayout;
public LayoutElement NameLayout;
public LayoutElement RightGroupLayout;
public Text NameLabel;
@ -81,25 +79,26 @@ namespace UnityExplorer.UI.Inspectors.CacheObject.Views
protected abstract void ConstructEvaluateHolder(GameObject parent);
protected abstract void ConstructUpdateToggle(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)
public virtual 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 = UIFactory.CreateUIObject(this.GetType().Name, parent, new Vector2(100, 30));
Rect = UIRoot.GetComponent<RectTransform>();
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(UIRoot, true, false, true, true, 0, 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 content = UIFactory.CreateUIObject("Content", UIRoot);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(content, true, false, true, true, 2, 0);
UIFactory.SetLayoutElement(content, minWidth: 100, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 600);
content.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
var horiRow = UIFactory.CreateUIObject("HoriGroup", uiRoot);
var horiRow = UIFactory.CreateUIObject("HoriGroup", content);
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;
@ -109,7 +108,7 @@ namespace UnityExplorer.UI.Inspectors.CacheObject.Views
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>();
NameLayout = NameLabel.GetComponent<LayoutElement>();
// Right vertical group
@ -162,17 +161,20 @@ namespace UnityExplorer.UI.Inspectors.CacheObject.Views
ValueLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
UIFactory.SetLayoutElement(ValueLabel.gameObject, minHeight: 25, flexibleHeight: 150, flexibleWidth: 9999);
ConstructUpdateToggle(rightHoriGroup);
// Subcontent
// Subcontent (todo?)
SubContentHolder = UIFactory.CreateUIObject("SubContent", uiRoot);
SubContentHolder = UIFactory.CreateUIObject("SubContent", content);
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;
// Bottom separator
var separator = UIFactory.CreateUIObject("BottomSeperator", UIRoot);
UIFactory.SetLayoutElement(separator, minHeight: 1, flexibleHeight: 0, flexibleWidth: 9999);
separator.AddComponent<Image>().color = Color.black;
return UIRoot;
}
}
}

View File

@ -16,9 +16,6 @@ namespace UnityExplorer.UI.Inspectors
{
public GameObject Target;
public override GameObject UIRoot => uiRoot;
private GameObject uiRoot;
private Text NameText;
public TransformTree TransformTree;
@ -123,8 +120,7 @@ namespace UnityExplorer.UI.Inspectors
if (!compToStringCache.ContainsKey(type.AssemblyQualifiedName))
{
compToStringCache.Add(type.AssemblyQualifiedName,
$"<color={SignatureHighlighter.NAMESPACE}>{type.Namespace}</color>.{SignatureHighlighter.ParseFullType(type)}");
compToStringCache.Add(type.AssemblyQualifiedName, SignatureHighlighter.ParseFullType(type, true));
}
cell.Button.ButtonText.text = compToStringCache[type.AssemblyQualifiedName];
@ -160,13 +156,13 @@ namespace UnityExplorer.UI.Inspectors
public override GameObject CreateContent(GameObject parent)
{
uiRoot = UIFactory.CreateVerticalGroup(Pool<GameObjectInspector>.Instance.InactiveHolder,
UIRoot = UIFactory.CreateVerticalGroup(Pool<GameObjectInspector>.Instance.InactiveHolder,
"GameObjectInspector", true, true, true, true, 5, new Vector4(4, 4, 4, 4), new Color(0.12f, 0.12f, 0.12f));
NameText = UIFactory.CreateLabel(uiRoot, "Title", "not set", TextAnchor.MiddleLeft, fontSize: 20);
NameText = UIFactory.CreateLabel(UIRoot, "Title", "not set", TextAnchor.MiddleLeft, fontSize: 20);
UIFactory.SetLayoutElement(NameText.gameObject, minHeight: 30, flexibleHeight: 0);
var listHolder = UIFactory.CreateHorizontalGroup(uiRoot, "ListHolder", true, true, true, true, 5, new Vector4(2, 2, 2, 2));
var listHolder = UIFactory.CreateHorizontalGroup(UIRoot, "ListHolder", true, true, true, true, 5, new Vector4(2, 2, 2, 2));
UIFactory.SetLayoutElement(listHolder, flexibleWidth: 9999, flexibleHeight: 9999);
transformScroll = UIFactory.CreateScrollPool<TransformCell>(listHolder, "TransformTree", out GameObject transformObj,
@ -185,7 +181,7 @@ namespace UnityExplorer.UI.Inspectors
ComponentList = new ButtonListSource<Component>(componentScroll, GetComponentEntries, SetComponentCell, ShouldDisplay, OnComponentClicked);
componentScroll.Initialize(ComponentList);
return uiRoot;
return UIRoot;
}
}
}

View File

@ -0,0 +1,199 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.Inspectors.CacheObject;
using UnityExplorer.UI.Inspectors.CacheObject.Views;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Widgets;
namespace UnityExplorer.UI.Inspectors.IValues
{
// TODO
// - set fallback type from generic arguments
// - handle setting through IList
// - handle il2cpp lists
public class InteractiveList : InteractiveValue, IPoolDataSource<CacheListEntryCell>
{
public override bool CanWrite => base.CanWrite && RefIList != null;
public Type FallbackEntryType;
public IEnumerable RefIEnumerable;
public IList RefIList;
public int ItemCount => values.Count;
private readonly List<object> values = new List<object>();
private readonly List<CacheListEntry> cachedEntries = new List<CacheListEntry>();
public ScrollPool<CacheListEntryCell> ListScrollPool { get; private set; }
public LayoutElement ScrollPoolLayout;
public Text TopLabel;
public override void SetOwner(CacheObjectBase owner)
{
base.SetOwner(owner);
}
public override void ReleaseFromOwner()
{
base.ReleaseFromOwner();
ClearAndRelease();
}
private void ClearAndRelease()
{
values.Clear();
foreach (var entry in cachedEntries)
entry.ReleasePooledObjects();
cachedEntries.Clear();
}
// TODO temp for testing, needs improvement
public override void SetValue(object value)
{
//// TEMP
//if (values.Any())
// ClearAndRelease();
if (value == null)
{
if (values.Any())
ClearAndRelease();
}
else
{
// todo can improve this
var type = value.GetActualType();
if (type.IsGenericType)
FallbackEntryType = type.GetGenericArguments()[0];
else
FallbackEntryType = typeof(object);
CacheEntries(value);
}
TopLabel.text = $"{cachedEntries.Count} entries";
this.ScrollPoolLayout.minHeight = Math.Min(400f, 35f * values.Count);
this.ListScrollPool.Refresh(true, false);
}
private void CacheEntries(object value)
{
RefIEnumerable = value as IEnumerable;
RefIList = value as IList;
if (RefIEnumerable == null)
{
// todo il2cpp ...?
}
values.Clear();
int idx = 0;
foreach (var entry in RefIEnumerable)
{
values.Add(entry);
// If list count increased, create new cache entries
CacheListEntry cache;
if (idx >= cachedEntries.Count)
{
cache = new CacheListEntry();
cache.SetListOwner(this, idx);
cachedEntries.Add(cache);
}
else
cache = cachedEntries[idx];
cache.Initialize(this.FallbackEntryType);
cache.SetValueFromSource(entry);
idx++;
}
// Remove excess cached entries if list count decreased
if (cachedEntries.Count > values.Count)
{
for (int i = cachedEntries.Count - 1; i >= values.Count; i--)
{
var cache = cachedEntries[i];
if (cache.CellView != null)
{
cache.CellView.Occupant = null;
cache.CellView = null;
}
cache.ReleasePooledObjects();
cachedEntries.RemoveAt(i);
}
}
}
// List entry scroll pool
public void OnCellBorrowed(CacheListEntryCell cell)
{
cell.ListOwner = this;
}
public void SetCell(CacheListEntryCell cell, int index)
{
if (index < 0 || index >= cachedEntries.Count)
{
if (cell.Occupant != null)
{
cell.Occupant.CellView = null;
cell.Occupant = null;
}
cell.Disable();
return;
}
var entry = cachedEntries[index];
if (entry != cell.Occupant)
{
if (cell.Occupant != null)
{
cell.Occupant.HideIValue();
cell.Occupant.CellView = null;
cell.Occupant = null;
}
cell.Occupant = entry;
entry.CellView = cell;
}
entry.SetCell(cell);
}
public override GameObject CreateContent(GameObject parent)
{
UIRoot = UIFactory.CreateVerticalGroup(parent, "InteractiveList", true, true, true, true, 2, new Vector4(4, 4, 4, 4),
new Color(0.05f, 0.05f, 0.05f));
UIFactory.SetLayoutElement(UIRoot, flexibleWidth: 9999, minHeight: 25, flexibleHeight: 600);
// Entries label
TopLabel = UIFactory.CreateLabel(UIRoot, "EntryLabel", "not set", TextAnchor.MiddleLeft);
// entry scroll pool
ListScrollPool = UIFactory.CreateScrollPool<CacheListEntryCell>(UIRoot, "EntryList", out GameObject scrollObj,
out GameObject _, new Color(0.09f, 0.09f, 0.09f));
UIFactory.SetLayoutElement(scrollObj, minHeight: 25, flexibleHeight: 0);
ListScrollPool.Initialize(this);
ScrollPoolLayout = scrollObj.GetComponent<LayoutElement>();
return UIRoot;
}
}
}

View File

@ -11,22 +11,43 @@ namespace UnityExplorer.UI.Inspectors.IValues
{
public class InteractiveValue : IPooledObject
{
public GameObject UIRoot => uiRoot;
private GameObject uiRoot;
public GameObject UIRoot { get; set; }
public float DefaultHeight => -1f;
public virtual bool CanWrite => this.CurrentOwner.CanWrite;
public CacheObjectBase CurrentOwner { get; }
private CacheObjectBase m_owner;
public object EditedValue { get; private set; }
public static Type GetIValueTypeForState(ValueState state)
{
switch (state)
{
//case ValueState.String:
// return null;
//case ValueState.Enum:
// return null;
case ValueState.Collection:
return typeof(InteractiveList);
//case ValueState.Dictionary:
// return null;
//case ValueState.ValueStruct:
// return null;
//case ValueState.Color:
// return null;
default: return typeof(InteractiveValue);
}
}
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();
ReleaseFromOwner();
}
this.m_owner = owner;
@ -38,23 +59,22 @@ namespace UnityExplorer.UI.Inspectors.IValues
this.EditedValue = value;
}
public virtual void OnOwnerReleased()
public virtual void ReleaseFromOwner()
{
if (this.m_owner == null)
return;
// ...
this.m_owner = null;
}
public GameObject CreateContent(GameObject parent)
public virtual GameObject CreateContent(GameObject parent)
{
uiRoot = UIFactory.CreateUIObject(this.GetType().Name, parent);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(uiRoot, true, true, true, true, 3, childAlignment: TextAnchor.MiddleLeft);
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);
UIFactory.CreateLabel(UIRoot, "Label", "this is an ivalue", TextAnchor.MiddleLeft);
return uiRoot;
return UIRoot;
}
}
}

View File

@ -15,7 +15,7 @@ namespace UnityExplorer.UI.Inspectors
public InspectorTab Tab { get; internal set; }
public abstract GameObject UIRoot { get; }
public GameObject UIRoot { get; set; }
public float DefaultHeight => -1f;
public abstract GameObject CreateContent(GameObject parent);

View File

@ -11,8 +11,7 @@ namespace UnityExplorer.UI.Inspectors
{
public class InspectorTab : IPooledObject
{
public GameObject UIRoot => uiRoot;
private GameObject uiRoot;
public GameObject UIRoot { get; set; }
public float DefaultHeight => 25f;
@ -34,12 +33,12 @@ namespace UnityExplorer.UI.Inspectors
public GameObject CreateContent(GameObject parent)
{
uiRoot = UIFactory.CreateHorizontalGroup(parent, "TabObject", true, true, true, true, 0,
UIRoot = UIFactory.CreateHorizontalGroup(parent, "TabObject", true, true, true, true, 0,
new Vector4(0, 0, 3, 0), new Color(0.13f, 0.13f, 0.13f));
UIFactory.SetLayoutElement(uiRoot, minWidth: 185, flexibleWidth: 0);
uiRoot.AddComponent<Mask>();
UIFactory.SetLayoutElement(UIRoot, minWidth: 185, flexibleWidth: 0);
UIRoot.AddComponent<Mask>();
TabButton = UIFactory.CreateButton(uiRoot, "TabButton", "");
TabButton = UIFactory.CreateButton(UIRoot, "TabButton", "");
UIFactory.SetLayoutElement(TabButton.Button.gameObject, minWidth: 165, flexibleWidth: 0);
@ -47,12 +46,12 @@ namespace UnityExplorer.UI.Inspectors
TabText.horizontalOverflow = HorizontalWrapMode.Overflow;
TabText.alignment = TextAnchor.MiddleLeft;
CloseButton = UIFactory.CreateButton(uiRoot, "CloseButton", "X", new Color(0.2f, 0.2f, 0.2f, 1));
CloseButton = UIFactory.CreateButton(UIRoot, "CloseButton", "X", new Color(0.2f, 0.2f, 0.2f, 1));
UIFactory.SetLayoutElement(CloseButton.Button.gameObject, minWidth: 20, flexibleWidth: 0);
var closeBtnText = CloseButton.Button.GetComponentInChildren<Text>();
closeBtnText.color = Color.red;
return uiRoot;
return UIRoot;
}
}
}

View File

@ -29,14 +29,12 @@ namespace UnityExplorer.UI.Inspectors
private readonly List<CacheMember> filteredMembers = new List<CacheMember>();
private readonly HashSet<CacheMember> displayedMembers = new HashSet<CacheMember>();
public override GameObject UIRoot => uiRoot;
private GameObject uiRoot;
public Text NameText;
public Text AssemblyText;
private LayoutElement memberTitleLayout;
public bool AutoUpdateWanted { get; set; }
private Toggle autoUpdateToggle;
public override void OnBorrowedFromPool(object target)
@ -46,7 +44,6 @@ namespace UnityExplorer.UI.Inspectors
SetTitleLayouts();
SetTarget(target);
// MemberScrollPool.SetDataSource(this);
MemberScrollPool.Refresh(true, true);
RuntimeProvider.Instance.StartCoroutine(InitCoroutine());
}
@ -68,6 +65,7 @@ namespace UnityExplorer.UI.Inspectors
displayedMembers.Clear();
autoUpdateToggle.isOn = false;
AutoUpdateWanted = false;
base.OnReturnToPool();
}
@ -112,7 +110,7 @@ namespace UnityExplorer.UI.Inspectors
filteredMembers.Add(member);
}
//MemberScrollPool.RecreateHeightCache();
//MemberScrollPool.Refresh
}
public override void OnSetActive()
@ -147,21 +145,17 @@ namespace UnityExplorer.UI.Inspectors
{
timeOfLastUpdate = Time.time;
UpdateDisplayedMembers(true);
if (AutoUpdateWanted)
UpdateDisplayedMembers();// true);
}
}
private void UpdateDisplayedMembers()
{
UpdateDisplayedMembers(false);
}
private void UpdateDisplayedMembers(bool onlyAutoUpdate)
private void UpdateDisplayedMembers()// bool onlyAutoUpdate)
{
bool shouldRefresh = false;
foreach (var member in displayedMembers)
{
if (member.ShouldAutoEvaluate && (!onlyAutoUpdate || member.AutoUpdateWanted))
if (member.ShouldAutoEvaluate) // && (!onlyAutoUpdate || member.AutoUpdateWanted))
{
shouldRefresh = true;
member.Evaluate();
@ -192,6 +186,7 @@ namespace UnityExplorer.UI.Inspectors
displayedMembers.Remove(cell.MemberOccupant);
cell.Occupant.CellView = null;
cell.Occupant = null;
}
cell.Disable();
@ -207,6 +202,7 @@ namespace UnityExplorer.UI.Inspectors
cell.Occupant.HideIValue();
displayedMembers.Remove(cell.MemberOccupant);
cell.Occupant.CellView = null;
cell.Occupant = null;
}
cell.Occupant = member;
@ -219,18 +215,6 @@ 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; }
@ -247,7 +231,7 @@ namespace UnityExplorer.UI.Inspectors
private void SetCellLayout(CacheObjectCell cell)
{
cell.MemberLayout.minWidth = MemLabelWidth;
cell.NameLayout.minWidth = MemLabelWidth;
cell.RightGroupLayout.minWidth = RightGroupWidth;
}
@ -261,22 +245,24 @@ namespace UnityExplorer.UI.Inspectors
public override GameObject CreateContent(GameObject parent)
{
uiRoot = UIFactory.CreateVerticalGroup(parent, "ReflectionInspector", true, true, true, true, 5,
UIRoot = UIFactory.CreateVerticalGroup(parent, "ReflectionInspector", true, true, true, true, 5,
new Vector4(4, 4, 4, 4), new Color(0.12f, 0.12f, 0.12f));
// Class name, assembly. TODO more details
NameText = UIFactory.CreateLabel(uiRoot, "Title", "not set", TextAnchor.MiddleLeft, fontSize: 20);
NameText = UIFactory.CreateLabel(UIRoot, "Title", "not set", TextAnchor.MiddleLeft, fontSize: 20);
UIFactory.SetLayoutElement(NameText.gameObject, minHeight: 25, flexibleHeight: 0);
AssemblyText = UIFactory.CreateLabel(uiRoot, "AssemblyLabel", "not set", TextAnchor.MiddleLeft);
AssemblyText = UIFactory.CreateLabel(UIRoot, "AssemblyLabel", "not set", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(AssemblyText.gameObject, minHeight: 25, flexibleWidth: 9999);
// TODO filter row
// Member list
var listTitles = UIFactory.CreateUIObject("ListTitles", uiRoot);
// Member list titles
var listTitles = UIFactory.CreateUIObject("ListTitles", UIRoot);
UIFactory.SetLayoutElement(listTitles, minHeight: 25);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(listTitles, true, true, true, true, 5, 1, 1, 1, 1);
@ -286,25 +272,20 @@ namespace UnityExplorer.UI.Inspectors
var valueTitle = UIFactory.CreateLabel(listTitles, "ValueTitle", "Value", TextAnchor.LowerLeft, Color.grey, fontSize: 15);
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);
var updateButton = UIFactory.CreateButton(listTitles, "UpdateButton", "Update displayed values", new Color(0.22f, 0.28f, 0.22f));
UIFactory.SetLayoutElement(updateButton.Button.gameObject, minHeight: 25, minWidth: 160, flexibleWidth: 0);
updateButton.OnClick += UpdateDisplayedMembers;
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);
//GameObject.DestroyImmediate(toggleText);
UIFactory.SetLayoutElement(toggleObj, minWidth: 185, minHeight: 25);
autoUpdateToggle.isOn = false;
autoUpdateToggle.onValueChanged.AddListener((bool val) => { ToggleAllAutoUpdateStates(val); });
var spacer = UIFactory.CreateUIObject("spacer", listTitles);
UIFactory.SetLayoutElement(spacer, minWidth: 25, flexibleWidth: 0);
autoUpdateToggle.onValueChanged.AddListener((bool val) => { AutoUpdateWanted = val; });
toggleText.text = "Auto-update displayed";
// Member scroll pool
MemberScrollPool = UIFactory.CreateScrollPool<CacheMemberCell>(uiRoot, "MemberList", out GameObject scrollObj,
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);
@ -313,7 +294,7 @@ namespace UnityExplorer.UI.Inspectors
//MemberScrollPool.Viewport.GetComponent<Mask>().enabled = false;
//MemberScrollPool.Viewport.GetComponent<Image>().color = new Color(0.12f, 0.12f, 0.12f);
return uiRoot;
return UIRoot;
}
}
}