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

@ -7,17 +7,41 @@ namespace UnityExplorer.Tests
{
public static class TestClass
{
public static List<string> List;
public static List<object> List
{
get
{
var list = new List<object>();
int count = UnityEngine.Random.Range(0, 100);
for (int i = 0; i < count; i++)
list.Add(GetRandomObject());
return list;
}
}
private static object GetRandomObject()
{
object ret = null;
int ran = UnityEngine.Random.Range(0, 7);
switch (ran)
{
case 0: return null;
case 1: return 123;
case 2: return true;
case 3: return "hello";
case 4: return 50.5f;
case 5: return UnityEngine.CameraClearFlags.Color;
case 6: return new List<string> { "sub list", "lol" };
}
return ret;
}
public const int ConstantInt = 5;
public static byte[] ByteArray = new byte[16];
public static string LongString = @"#######################################################################################################
###############################################################################################################################
#####################################################################################################################################
#########################################################################################################################
######################################################################################################";
public static string LongString = new string('#', 10000);
#if CPP
public static string testStringOne = "Test";
@ -31,10 +55,6 @@ namespace UnityExplorer.Tests
static TestClass()
{
List = new List<string>();
for (int i = 0; i < 10000; i++)
List.Add(i.ToString());
#if CPP
testHashset = new Il2CppSystem.Collections.Hashtable();
testHashset.Add("key1", "itemOne");

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;
}
}
}

View File

@ -8,7 +8,7 @@ namespace UnityExplorer.UI.ObjectPool
{
public interface IPooledObject
{
GameObject UIRoot { get; }
GameObject UIRoot { get; set; }
GameObject CreateContent(GameObject parent);

View File

@ -66,9 +66,9 @@ namespace UnityExplorer.UI.ObjectPool
{
s_instance = this;
ExplorerCore.LogWarning("Creating Pool<" + typeof(T).Name + ">");
//ExplorerCore.LogWarning("Creating Pool<" + typeof(T).Name + ">");
InactiveHolder = new GameObject($"InactiveHolder_{typeof(T).Name}");
InactiveHolder = new GameObject($"PoolHolder_{typeof(T).Name}");
InactiveHolder.transform.parent = UIManager.PoolHolder.transform;
InactiveHolder.hideFlags |= HideFlags.HideAndDontSave;
InactiveHolder.SetActive(false);

View File

@ -51,7 +51,7 @@ namespace UnityExplorer.UI.Panels
private void InvokeOnValueChanged(string value)
{
if (Time.time - m_timeOfLastInputInvoke <= 0f)
if (Time.time <= m_timeOfLastInputInvoke)
return;
m_timeOfLastInputInvoke = Time.time;

View File

@ -12,7 +12,7 @@ namespace UnityExplorer.UI.Utility
/// <summary>
/// Syntax-highlights a member's signature, by either the Type name or a Type and Member together.
/// </summary>
public class SignatureHighlighter
public static class SignatureHighlighter
{
public const string NAMESPACE = "#a8a8a8";
@ -56,6 +56,12 @@ namespace UnityExplorer.UI.Utility
private static readonly StringBuilder syntaxBuilder = new StringBuilder(2156);
private static bool GetNamespace(Type type, out string ns)
{
var ret = !string.IsNullOrEmpty(ns = type.Namespace?.Trim());
return ret;
}
public static string ParseFullSyntax(Type type, bool includeNamespace, MemberInfo memberInfo = null)
{
if (type == null)
@ -67,8 +73,8 @@ namespace UnityExplorer.UI.Utility
bool isGeneric = type.IsGenericParameter || (type.HasElementType && type.GetElementType().IsGenericParameter);
if (!isGeneric && includeNamespace && !string.IsNullOrEmpty(type.Namespace))
syntaxBuilder.Append($"<color={NAMESPACE}>{type.Namespace}</color>.");
if (!isGeneric && includeNamespace && GetNamespace(type, out string ns))
syntaxBuilder.Append($"<color={NAMESPACE}>{ns}</color>.");
// Declaring type
@ -117,8 +123,8 @@ namespace UnityExplorer.UI.Utility
bool isGeneric = type.IsGenericParameter || (type.HasElementType && type.GetElementType().IsGenericParameter);
if (!isGeneric && includeNamespace && !string.IsNullOrEmpty(type.Namespace))
ret = $"<color={NAMESPACE}>{type.Namespace}</color>.{ret}";
if (!isGeneric && includeNamespace && GetNamespace(type, out string ns))
ret = $"<color={NAMESPACE}>{ns}</color>.{ret}";
if (includeDllName)
{

View File

@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
@ -20,7 +21,93 @@ namespace UnityExplorer.UI.Utility
private const string destroyedString = "<color=red>Destroyed</color>";
private const string untitledString = "<i><color=grey>untitled</color></i>";
public static string ToString(object value)
public static string ToStringWithType(object value, Type fallbackType, bool includeNamespace = true)
{
if (value == null && fallbackType == null)
return nullString;
Type type = value?.GetActualType() ?? fallbackType;
string richType = SignatureHighlighter.ParseFullSyntax(type, includeNamespace);
//if (!includeName)
// return richType;
_stringBuilder.Clear();
if (value.IsNullOrDestroyed())
{
if (value == null)
{
_stringBuilder.Append(nullString);
AppendRichType(_stringBuilder, richType);
return _stringBuilder.ToString();
}
else // destroyed unity object
{
_stringBuilder.Append(destroyedString);
AppendRichType(_stringBuilder, richType);
return _stringBuilder.ToString();
}
}
if (value is UnityEngine.Object obj)
{
_stringBuilder.Append(string.IsNullOrEmpty(obj.name) ? untitledString : obj.name);
AppendRichType(_stringBuilder, richType);
}
else
{
var toString = ToString(value);
if (type.IsEnumerable())
{
if (value is IList iList)
_stringBuilder.Append($"[{iList.Count}] ");
else
if (value is ICollection iCol)
_stringBuilder.Append($"[{iCol.Count}] ");
else
_stringBuilder.Append("[?] ");
}
else if (type.IsDictionary())
{
if (value is IDictionary iDict)
_stringBuilder.Append($"[{iDict.Count}] ");
else
_stringBuilder.Append("[?] ");
}
if (type.IsGenericType
|| toString == type.FullName
|| toString == $"{type.FullName} {type.FullName}"
|| toString == $"Il2Cpp{type.FullName}" || type.FullName == $"Il2Cpp{toString}")
{
_stringBuilder.Append(richType);
}
else // the ToString contains some actual implementation, use that value.
{
if (toString.Length > 200)
_stringBuilder.Append(toString.Substring(0, 200));
else
_stringBuilder.Append(toString);
AppendRichType(_stringBuilder, richType);
}
}
return _stringBuilder.ToString();
}
private static void AppendRichType(StringBuilder sb, string richType)
{
sb.Append(' ');
sb.Append('(');
sb.Append(richType);
sb.Append(')');
}
private static string ToString(object value)
{
if (value.IsNullOrDestroyed())
{
@ -62,73 +149,5 @@ namespace UnityExplorer.UI.Utility
return toString;
}
public static string ToStringWithType(object value, Type fallbackType, bool includeNamespace = true)
{
if (value == null && fallbackType == null)
return nullString;
Type type = value?.GetActualType() ?? fallbackType;
string richType = SignatureHighlighter.ParseFullSyntax(type, includeNamespace);
//if (!includeName)
// return richType;
_stringBuilder.Clear();
if (value.IsNullOrDestroyed())
{
if (value == null)
{
_stringBuilder.Append(nullString);
AppendRichType(_stringBuilder, richType);
return _stringBuilder.ToString();
}
else // destroyed unity object
{
_stringBuilder.Append(destroyedString);
AppendRichType(_stringBuilder, richType);
return _stringBuilder.ToString();
}
}
if (value is UnityEngine.Object obj)
{
_stringBuilder.Append(string.IsNullOrEmpty(obj.name) ? untitledString : obj.name);
AppendRichType(_stringBuilder, richType);
}
else
{
var toString = ToString(value);
if (type.IsGenericType
|| toString == type.FullName
|| toString == $"{type.FullName} {type.FullName}"
|| toString == $"Il2Cpp{type.FullName}" || type.FullName == $"Il2Cpp{toString}")
{
_stringBuilder.Append(richType);
}
else // the ToString contains some actual implementation, use that value.
{
if (toString.Length > 200)
_stringBuilder.Append(toString.Substring(0, 200));
else
_stringBuilder.Append(toString);
AppendRichType(_stringBuilder, richType);
}
}
return _stringBuilder.ToString();
}
private static void AppendRichType(StringBuilder sb, string richType)
{
sb.Append(' ');
sb.Append('(');
sb.Append(richType);
sb.Append(')');
}
}
}

View File

@ -89,6 +89,7 @@ namespace UnityExplorer.UI.Utility
if (totalHeight <= viewportHeight)
{
Slider.handleRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 0f);
Slider.value = 0f;
Slider.interactable = false;
return;

View File

@ -19,43 +19,40 @@ namespace UnityExplorer.UI.Widgets
#region ICell
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 GameObject UIRoot { get; set; }
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
public GameObject CreateContent(GameObject parent)
{
uiRoot = UIFactory.CreateHorizontalGroup(parent, "ButtonCell", true, true, true, true, 2, default,
UIRoot = UIFactory.CreateHorizontalGroup(parent, "ButtonCell", true, true, true, true, 2, default,
new Color(0.11f, 0.11f, 0.11f), TextAnchor.MiddleCenter);
m_rect = uiRoot.GetComponent<RectTransform>();
m_rect.anchorMin = new Vector2(0, 1);
m_rect.anchorMax = new Vector2(0, 1);
m_rect.pivot = new Vector2(0.5f, 1);
m_rect.sizeDelta = new Vector2(25, 25);
UIFactory.SetLayoutElement(uiRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 25, flexibleHeight: 0);
Rect = UIRoot.GetComponent<RectTransform>();
Rect.anchorMin = new Vector2(0, 1);
Rect.anchorMax = new Vector2(0, 1);
Rect.pivot = new Vector2(0.5f, 1);
Rect.sizeDelta = new Vector2(25, 25);
UIFactory.SetLayoutElement(UIRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 25, flexibleHeight: 0);
uiRoot.SetActive(false);
UIRoot.SetActive(false);
this.Button = UIFactory.CreateButton(uiRoot, "NameButton", "Name");
this.Button = UIFactory.CreateButton(UIRoot, "NameButton", "Name");
UIFactory.SetLayoutElement(Button.Button.gameObject, flexibleWidth: 9999, minHeight: 25, flexibleHeight: 0);
var buttonText = Button.Button.GetComponentInChildren<Text>();
buttonText.horizontalOverflow = HorizontalWrapMode.Overflow;
@ -69,7 +66,7 @@ namespace UnityExplorer.UI.Widgets
Button.OnClick += () => { OnClick?.Invoke(CurrentDataIndex); };
return uiRoot;
return UIRoot;
}
}
}

View File

@ -11,7 +11,7 @@ namespace UnityExplorer.UI.Widgets
{
bool Enabled { get; }
RectTransform Rect { get; }
RectTransform Rect { get; set; }
void Enable();
void Disable();

View File

@ -114,7 +114,8 @@ namespace UnityExplorer.UI.Widgets
else if (Content.rect.height != prevContentHeight)
{
prevContentHeight = Content.rect.height;
OnValueChangedListener(Vector2.zero);
if (!writingLocked)
OnValueChangedListener(Vector2.zero);
}
}
#endregion
@ -152,7 +153,7 @@ namespace UnityExplorer.UI.Widgets
ScrollRect.vertical = true;
ScrollRect.horizontal = false;
//ScrollRect.onValueChanged.RemoveListener(OnValueChangedListener);
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
RuntimeProvider.Instance.StartCoroutine(InitCoroutine());
}
@ -182,6 +183,8 @@ namespace UnityExplorer.UI.Widgets
// add onValueChanged listener after setup
ScrollRect.onValueChanged.AddListener(OnValueChangedListener);
ExplorerCore.Log("ScrollPool Init finished");
}
private void SetScrollBounds()

View File

@ -21,10 +21,8 @@ namespace UnityExplorer.UI.Widgets
public CachedTransform cachedTransform;
public int _cellIndex;
public GameObject UIRoot => uiRoot;
public GameObject uiRoot;
public RectTransform Rect => m_rect;
private RectTransform m_rect;
public GameObject UIRoot { get; set; }
public RectTransform Rect { get; set; }
public ButtonRef ExpandButton;
public ButtonRef NameButton;
@ -78,13 +76,13 @@ namespace UnityExplorer.UI.Widgets
public void Disable()
{
m_enabled = false;
uiRoot.SetActive(false);
UIRoot.SetActive(false);
}
public void Enable()
{
m_enabled = true;
uiRoot.SetActive(true);
UIRoot.SetActive(true);
}
public void OnExpandClicked()
@ -102,23 +100,23 @@ namespace UnityExplorer.UI.Widgets
public GameObject CreateContent(GameObject parent)
{
uiRoot = UIFactory.CreateUIObject("TransformCell", parent);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(uiRoot, true, true, true, true, 2, childAlignment: TextAnchor.MiddleCenter);
m_rect = uiRoot.GetComponent<RectTransform>();
m_rect.anchorMin = new Vector2(0, 1);
m_rect.anchorMax = new Vector2(0, 1);
m_rect.pivot = new Vector2(0.5f, 1);
m_rect.sizeDelta = new Vector2(25, 25);
UIFactory.SetLayoutElement(uiRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 25, flexibleHeight: 0);
UIRoot = UIFactory.CreateUIObject("TransformCell", parent);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(UIRoot, true, true, true, true, 2, childAlignment: TextAnchor.MiddleCenter);
Rect = UIRoot.GetComponent<RectTransform>();
Rect.anchorMin = new Vector2(0, 1);
Rect.anchorMax = new Vector2(0, 1);
Rect.pivot = new Vector2(0.5f, 1);
Rect.sizeDelta = new Vector2(25, 25);
UIFactory.SetLayoutElement(UIRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 25, flexibleHeight: 0);
var spacerObj = UIFactory.CreateUIObject("Spacer", uiRoot, new Vector2(0, 0));
var spacerObj = UIFactory.CreateUIObject("Spacer", UIRoot, new Vector2(0, 0));
UIFactory.SetLayoutElement(spacerObj, minWidth: 0, flexibleWidth: 0, minHeight: 0, flexibleHeight: 0);
this.spacer = spacerObj.GetComponent<LayoutElement>();
ExpandButton = UIFactory.CreateButton(this.uiRoot, "ExpandButton", "►");
ExpandButton = UIFactory.CreateButton(this.UIRoot, "ExpandButton", "►");
UIFactory.SetLayoutElement(ExpandButton.Button.gameObject, minWidth: 15, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0);
NameButton = UIFactory.CreateButton(this.uiRoot, "NameButton", "Name", null);
NameButton = UIFactory.CreateButton(this.UIRoot, "NameButton", "Name", null);
UIFactory.SetLayoutElement(NameButton.Button.gameObject, flexibleWidth: 9999, minHeight: 25, flexibleHeight: 0);
var nameLabel = NameButton.Button.GetComponentInChildren<Text>();
nameLabel.horizontalOverflow = HorizontalWrapMode.Overflow;
@ -134,9 +132,9 @@ namespace UnityExplorer.UI.Widgets
NameButton.OnClick += OnMainButtonClicked;
ExpandButton.OnClick += OnExpandClicked;
uiRoot.SetActive(false);
UIRoot.SetActive(false);
return this.uiRoot;
return this.UIRoot;
}
}
}