From 2378925a8b2424d1d65ea682f692062578327262 Mon Sep 17 00:00:00 2001
From: Sinai
Date: Fri, 30 Apr 2021 21:34:50 +1000
Subject: [PATCH] More progress
---
README.md | 4 +
src/Core/Config/ConfigManager.cs | 2 +
src/Core/Input/CursorUnlocker.cs | 2 +-
src/ExplorerCore.cs | 36 +--
src/UI/CSConsole/CSConsoleManager.cs | 34 ++
src/UI/Inspectors/CacheObject/CacheField.cs | 4 +-
src/UI/Inspectors/CacheObject/CacheMember.cs | 238 ++------------
src/UI/Inspectors/CacheObject/CacheMethod.cs | 4 +-
.../Inspectors/CacheObject/CacheObjectBase.cs | 295 ++++++++++++++++++
.../Inspectors/CacheObject/CacheProperty.cs | 4 +-
.../CacheObject/Views/CacheMemberCell.cs | 184 +----------
.../CacheObject/Views/CacheObjectCell.cs | 181 ++++++++++-
src/UI/Inspectors/IValues/IValueTest.cs | 28 --
src/UI/Inspectors/IValues/InteractiveValue.cs | 60 ++++
src/UI/Inspectors/ReflectionInspector.cs | 72 +++--
src/UI/Models/UIModel.cs | 2 +-
src/UI/Panels/CSConsolePanel.cs | 220 +++++++++++++
src/UI/Panels/ObjectExplorer.cs | 1 +
src/UI/Panels/UIPanel.cs | 16 +-
src/UI/UIFactory.cs | 243 ++++++++++-----
src/UI/UIManager.cs | 41 ++-
src/UI/Widgets/AutoSliderScrollbar.cs | 138 ++++++++
src/UI/Widgets/InputFieldScroller.cs | 109 +++----
src/UI/Widgets/ScrollPool/DataHeightCache.cs | 17 +-
src/UI/Widgets/ScrollPool/ScrollPool.cs | 151 +++++----
src/UI/Widgets/SliderScrollbar.cs | 155 ---------
src/UnityExplorer.csproj | 6 +-
27 files changed, 1401 insertions(+), 846 deletions(-)
create mode 100644 src/UI/CSConsole/CSConsoleManager.cs
delete mode 100644 src/UI/Inspectors/IValues/IValueTest.cs
create mode 100644 src/UI/Inspectors/IValues/InteractiveValue.cs
create mode 100644 src/UI/Panels/CSConsolePanel.cs
create mode 100644 src/UI/Widgets/AutoSliderScrollbar.cs
delete mode 100644 src/UI/Widgets/SliderScrollbar.cs
diff --git a/README.md b/README.md
index 7fc463e..41ed3e7 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,10 @@
An in-game explorer and a suite of debugging tools for IL2CPP and Mono Unity games, to aid with modding development.
+
+ Supports most Unity games from versions 5.2 to 2020+.
+
+
## Releases [](../../releases/latest) [](../../releases) [](../../releases/latest)
| Mod Loader | IL2CPP | Mono |
diff --git a/src/Core/Config/ConfigManager.cs b/src/Core/Config/ConfigManager.cs
index 84bde0a..c7a90cd 100644
--- a/src/Core/Config/ConfigManager.cs
+++ b/src/Core/Config/ConfigManager.cs
@@ -31,6 +31,7 @@ namespace UnityExplorer.Core.Config
public static ConfigElement ObjectExplorerData;
public static ConfigElement InspectorData;
+ public static ConfigElement CSConsoleData;
internal static readonly Dictionary ConfigElements = new Dictionary();
internal static readonly Dictionary InternalConfigs = new Dictionary();
@@ -107,6 +108,7 @@ namespace UnityExplorer.Core.Config
ObjectExplorerData = new ConfigElement("ObjectExplorer", "", "", true);
InspectorData = new ConfigElement("Inspector", "", "", true);
+ CSConsoleData = new ConfigElement("CSConsole", "", "", true);
}
}
}
diff --git a/src/Core/Input/CursorUnlocker.cs b/src/Core/Input/CursorUnlocker.cs
index 72ee097..01caa29 100644
--- a/src/Core/Input/CursorUnlocker.cs
+++ b/src/Core/Input/CursorUnlocker.cs
@@ -61,7 +61,7 @@ namespace UnityExplorer.Core.Input
}
catch (Exception ex)
{
- ExplorerCore.LogWarning($"Exception setting up Camera.onPostRender callback: {ex}");
+ ExplorerCore.LogWarning($"Exception setting up Aggressive Mouse Unlock: {ex}");
}
}
diff --git a/src/ExplorerCore.cs b/src/ExplorerCore.cs
index 07da4f2..55d52fd 100644
--- a/src/ExplorerCore.cs
+++ b/src/ExplorerCore.cs
@@ -35,22 +35,6 @@ namespace UnityExplorer
return;
}
- // TEMP DEBUG TEST FOR TRANSFORM TREE
-
- var stressTest = new GameObject("StressTest");
- for (int i = 0; i < 100; i++)
- {
- var obj = new GameObject($"Parent_{i}");
- obj.transform.parent = stressTest.transform;
- for (int j = 0; j < 100; j++)
- {
- var obj2 = new GameObject($"Child_{j}");
- obj2.transform.parent = obj.transform;
- }
- }
-
- // END
-
Loader = loader;
if (!Directory.Exists(Loader.ExplorerFolder))
@@ -81,8 +65,24 @@ namespace UnityExplorer
UIManager.InitUI();
- InspectorManager.Inspect(typeof(TestClass));
- //InspectorManager.Inspect(UIManager.CanvasRoot.gameObject.GetComponent());
+ // TEMP DEBUG TEST FOR TRANSFORM TREE
+
+ var stressTest = new GameObject("StressTest");
+ for (int i = 0; i < 100; i++)
+ {
+ var obj = new GameObject($"Parent_{i}");
+ obj.transform.parent = stressTest.transform;
+ for (int j = 0; j < 100; j++)
+ {
+ var obj2 = new GameObject($"Child_{j}");
+ obj2.transform.parent = obj.transform;
+ }
+ }
+
+ // END
+
+ //InspectorManager.Inspect(typeof(TestClass));
+ InspectorManager.Inspect(UIManager.CanvasRoot.gameObject.GetComponent());
//InspectorManager.InspectType(typeof(ReflectionUtility));
}
diff --git a/src/UI/CSConsole/CSConsoleManager.cs b/src/UI/CSConsole/CSConsoleManager.cs
new file mode 100644
index 0000000..d72d33e
--- /dev/null
+++ b/src/UI/CSConsole/CSConsoleManager.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace UnityExplorer.UI.CSConsole
+{
+ public static class CSConsoleManager
+ {
+ internal const string STARTUP_TEXT = @"Welcome to the UnityExplorer C# Console.
+
+The following helper methods are available:
+
+* Log(""message"") logs a message to the debug console
+
+* StartCoroutine(IEnumerator routine) start the IEnumerator as a UnityEngine.Coroutine
+
+* CurrentTarget() returns the currently inspected target on the Home page
+
+* AllTargets() returns an object[] array containing all inspected instances
+
+* Inspect(someObject) to inspect an instance, eg. Inspect(Camera.main);
+
+* Inspect(typeof(SomeClass)) to inspect a Class with static reflection
+
+* AddUsing(""SomeNamespace"") adds a using directive to the C# console
+
+* GetUsing() logs the current using directives to the debug console
+
+* Reset() resets all using directives and variables
+";
+
+ }
+}
diff --git a/src/UI/Inspectors/CacheObject/CacheField.cs b/src/UI/Inspectors/CacheObject/CacheField.cs
index 59ce3a4..c302ce4 100644
--- a/src/UI/Inspectors/CacheObject/CacheField.cs
+++ b/src/UI/Inspectors/CacheObject/CacheField.cs
@@ -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);
diff --git a/src/UI/Inspectors/CacheObject/CacheMember.cs b/src/UI/Inspectors/CacheObject/CacheMember.cs
index 4a10e72..7530c2f 100644
--- a/src/UI/Inspectors/CacheObject/CacheMember.cs
+++ b/src/UI/Inspectors/CacheObject/CacheMember.cs
@@ -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 numberParseMethods = new Dictionary();
-
- 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 = "Not yet evaluated";
-
- ///
- /// Initialize the CacheMember when an Inspector is opened and caches the member
- ///
- 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);
- }
-
///
/// Evaluate when first shown (if ShouldAutoEvaluate), or else when Evaluate button is clicked.
///
@@ -120,79 +48,27 @@ namespace UnityExplorer.UI.Inspectors.CacheObject
ProcessOnEvaluate();
}
- ///
- /// Process the CacheMember state when the value has been evaluated (or re-evaluated)
- ///
- 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 $"{NOT_YET_EVAL} ({SignatureHighlighter.ParseFullType(FallbackType, true)})";
- case ValueState.Exception:
- return $"{ReflectionUtility.ReflectionExToString(LastException)}";
- 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 $"{ToStringUtility.ToStringWithType(Value, FallbackType, true)}";
- 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);
}
- ///
- /// Set the cell view for an enabled cell based on this CacheMember model.
- ///
- 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);
}
diff --git a/src/UI/Inspectors/CacheObject/CacheMethod.cs b/src/UI/Inspectors/CacheObject/CacheMethod.cs
index 7221450..1d727ef 100644
--- a/src/UI/Inspectors/CacheObject/CacheMethod.cs
+++ b/src/UI/Inspectors/CacheObject/CacheMethod.cs
@@ -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();
}
diff --git a/src/UI/Inspectors/CacheObject/CacheObjectBase.cs b/src/UI/Inspectors/CacheObject/CacheObjectBase.cs
index 1409e81..65d3247 100644
--- a/src/UI/Inspectors/CacheObject/CacheObjectBase.cs
+++ b/src/UI/Inspectors/CacheObject/CacheObjectBase.cs
@@ -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 numberParseMethods = new Dictionary();
+
+ public enum ValueState
+ {
+ NotEvaluated, Exception, NullValue,
+ Boolean, Number, String, Enum,
+ Collection, ValueStruct, Unsupported
+ }
+
+ public ValueState State = ValueState.NotEvaluated;
+
+ protected const string NOT_YET_EVAL = "Not yet evaluated";
+
+ 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);
+
+ ///
+ /// Process the CacheMember state when the value has been evaluated (or re-evaluated)
+ ///
+ 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 $"{NOT_YET_EVAL} ({SignatureHighlighter.ParseFullType(FallbackType, true)})";
+ case ValueState.Exception:
+ return $"{ReflectionUtility.ReflectionExToString(LastException)}";
+ 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 $"{ToStringUtility.ToStringWithType(Value, FallbackType, true)}";
+ 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);
+ }
}
}
diff --git a/src/UI/Inspectors/CacheObject/CacheProperty.cs b/src/UI/Inspectors/CacheObject/CacheProperty.cs
index a775087..9915987 100644
--- a/src/UI/Inspectors/CacheObject/CacheProperty.cs
+++ b/src/UI/Inspectors/CacheObject/CacheProperty.cs
@@ -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();
diff --git a/src/UI/Inspectors/CacheObject/Views/CacheMemberCell.cs b/src/UI/Inspectors/CacheObject/Views/CacheMemberCell.cs
index 0bc8847..79d5d7f 100644
--- a/src/UI/Inspectors/CacheObject/Views/CacheMemberCell.cs
+++ b/src/UI/Inspectors/CacheObject/Views/CacheMemberCell.cs
@@ -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();
- UIFactory.SetLayoutGroup(uiRoot, true, false, true, true, 2, 0);
- UIFactory.SetLayoutElement(uiRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 600);
- UIRoot.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
-
- var separator = UIFactory.CreateUIObject("TopSeperator", uiRoot);
- UIFactory.SetLayoutElement(separator, minHeight: 1, flexibleHeight: 0, flexibleWidth: 9999);
- separator.AddComponent().color = Color.black;
-
- var horiRow = UIFactory.CreateUIObject("HoriGroup", uiRoot);
- UIFactory.SetLayoutElement(horiRow, minHeight: 29, flexibleHeight: 150, flexibleWidth: 9999);
- UIFactory.SetLayoutGroup(horiRow, false, false, true, true, 5, 2, childAlignment: TextAnchor.UpperLeft);
- horiRow.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
-
- // Left member label
-
- MemberLabel = UIFactory.CreateLabel(horiRow, "MemberLabel", "", TextAnchor.MiddleLeft);
- MemberLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
- UIFactory.SetLayoutElement(MemberLabel.gameObject, minHeight: 25, minWidth: 20, flexibleHeight: 300, flexibleWidth: 0);
- MemberLayout = MemberLabel.GetComponent();
-
- // Right vertical group
-
- var rightGroupHolder = UIFactory.CreateUIObject("RightGroup", horiRow);
- UIFactory.SetLayoutGroup(rightGroupHolder, false, false, true, true, 4, childAlignment: TextAnchor.UpperLeft);
- UIFactory.SetLayoutElement(rightGroupHolder, minHeight: 25, minWidth: 200, flexibleWidth: 9999, flexibleHeight: 800);
- RightGroupLayout = rightGroupHolder.GetComponent();
-
// Evaluate vert group
- EvaluateHolder = UIFactory.CreateUIObject("EvalGroup", rightGroupHolder);
+ EvaluateHolder = UIFactory.CreateUIObject("EvalGroup", parent);
UIFactory.SetLayoutGroup(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(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", "", 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(SubContentHolder, true, false, true, true, 2, childAlignment: TextAnchor.UpperLeft);
-
- SubContentHolder.SetActive(false);
-
- return uiRoot;
+ UpdateToggle.onValueChanged.AddListener((bool val) => { MemberOccupant.AutoUpdateWanted = val; });
}
}
}
diff --git a/src/UI/Inspectors/CacheObject/Views/CacheObjectCell.cs b/src/UI/Inspectors/CacheObject/Views/CacheObjectCell.cs
index 1625fd1..9eb93b8 100644
--- a/src/UI/Inspectors/CacheObject/Views/CacheObjectCell.cs
+++ b/src/UI/Inspectors/CacheObject/Views/CacheObjectCell.cs
@@ -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();
+ UIFactory.SetLayoutGroup(uiRoot, true, false, true, true, 2, 0);
+ UIFactory.SetLayoutElement(uiRoot, minWidth: 100, flexibleWidth: 9999, minHeight: 30, flexibleHeight: 600);
+ UIRoot.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
+
+ var separator = UIFactory.CreateUIObject("TopSeperator", uiRoot);
+ UIFactory.SetLayoutElement(separator, minHeight: 1, flexibleHeight: 0, flexibleWidth: 9999);
+ separator.AddComponent().color = Color.black;
+
+ var horiRow = UIFactory.CreateUIObject("HoriGroup", uiRoot);
+ UIFactory.SetLayoutElement(horiRow, minHeight: 29, flexibleHeight: 150, flexibleWidth: 9999);
+ UIFactory.SetLayoutGroup(horiRow, false, false, true, true, 5, 2, childAlignment: TextAnchor.UpperLeft);
+ horiRow.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
+
+ // Left member label
+
+ NameLabel = UIFactory.CreateLabel(horiRow, "MemberLabel", "", TextAnchor.MiddleLeft);
+ NameLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
+ UIFactory.SetLayoutElement(NameLabel.gameObject, minHeight: 25, minWidth: 20, flexibleHeight: 300, flexibleWidth: 0);
+ MemberLayout = NameLabel.GetComponent();
+
+ // Right vertical group
+
+ var rightGroupHolder = UIFactory.CreateUIObject("RightGroup", horiRow);
+ UIFactory.SetLayoutGroup(rightGroupHolder, false, false, true, true, 4, childAlignment: TextAnchor.UpperLeft);
+ UIFactory.SetLayoutElement(rightGroupHolder, minHeight: 25, minWidth: 200, flexibleWidth: 9999, flexibleHeight: 800);
+ RightGroupLayout = rightGroupHolder.GetComponent();
+
+ ConstructEvaluateHolder(rightGroupHolder);
+
+ // Right horizontal group
+
+ var rightHoriGroup = UIFactory.CreateUIObject("RightHoriGroup", rightGroupHolder);
+ UIFactory.SetLayoutGroup(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", "", 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(SubContentHolder, true, false, true, true, 2, childAlignment: TextAnchor.UpperLeft);
+
+ SubContentHolder.SetActive(false);
+
+ return uiRoot;
+ }
}
}
diff --git a/src/UI/Inspectors/IValues/IValueTest.cs b/src/UI/Inspectors/IValues/IValueTest.cs
deleted file mode 100644
index fa73fce..0000000
--- a/src/UI/Inspectors/IValues/IValueTest.cs
+++ /dev/null
@@ -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(uiRoot, true, true, true, true, 3, childAlignment: TextAnchor.MiddleLeft);
-
-
-
- return uiRoot;
- }
- }
-}
diff --git a/src/UI/Inspectors/IValues/InteractiveValue.cs b/src/UI/Inspectors/IValues/InteractiveValue.cs
new file mode 100644
index 0000000..6c64a94
--- /dev/null
+++ b/src/UI/Inspectors/IValues/InteractiveValue.cs
@@ -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(uiRoot, true, true, true, true, 3, childAlignment: TextAnchor.MiddleLeft);
+
+ UIFactory.CreateLabel(uiRoot, "Label", "this is an ivalue", TextAnchor.MiddleLeft);
+
+ return uiRoot;
+ }
+ }
+}
diff --git a/src/UI/Inspectors/ReflectionInspector.cs b/src/UI/Inspectors/ReflectionInspector.cs
index d26e6c2..27c037b 100644
--- a/src/UI/Inspectors/ReflectionInspector.cs
+++ b/src/UI/Inspectors/ReflectionInspector.cs
@@ -19,7 +19,6 @@ namespace UnityExplorer.UI.Inspectors
public class ReflectionInspector : InspectorBase, IPoolDataSource
{
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();
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(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().enabled = false;
- MemberScrollPool.Viewport.GetComponent().enabled = false;
- MemberScrollPool.Viewport.GetComponent().color = new Color(0.12f, 0.12f, 0.12f);
+ //InspectorPanel.Instance.UIRoot.GetComponent().enabled = false;
+ //MemberScrollPool.Viewport.GetComponent().enabled = false;
+ //MemberScrollPool.Viewport.GetComponent().color = new Color(0.12f, 0.12f, 0.12f);
return uiRoot;
}
diff --git a/src/UI/Models/UIModel.cs b/src/UI/Models/UIModel.cs
index 1046d08..bb1c885 100644
--- a/src/UI/Models/UIModel.cs
+++ b/src/UI/Models/UIModel.cs
@@ -12,7 +12,7 @@ namespace UnityExplorer.UI.Models
public bool Enabled
{
- get => UIRoot && UIRoot.activeSelf;
+ get => UIRoot && UIRoot.activeInHierarchy;
set
{
if (!UIRoot || Enabled == value)
diff --git a/src/UI/Panels/CSConsolePanel.cs b/src/UI/Panels/CSConsolePanel.cs
new file mode 100644
index 0000000..7114ee0
--- /dev/null
+++ b/src/UI/Panels/CSConsolePanel.cs
@@ -0,0 +1,220 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+using UnityExplorer.Core.Config;
+using UnityExplorer.UI.CSConsole;
+using UnityExplorer.UI.Utility;
+
+namespace UnityExplorer.UI.Panels
+{
+ public class CSConsolePanel : UIPanel
+ {
+ public override string Name => "C# Console";
+ public override UIManager.Panels PanelType => UIManager.Panels.CSConsole;
+
+ public static CSConsolePanel Instance { get; private set; }
+
+ public InputField InputField { get; private set; }
+ public Text InputText { get; private set; }
+ public Text HighlightText { get; private set; }
+
+ public Action OnInputChanged;
+ private float m_timeOfLastInputInvoke;
+
+ public Action OnResetClicked;
+ public Action OnCompileClicked;
+ public Action OnCtrlRToggled;
+ public Action OnSuggestionsToggled;
+ public Action OnAutoIndentToggled;
+
+ private int m_lastCaretPosition;
+ private int m_desiredCaretFix;
+ private bool m_fixWaiting;
+ private float m_defaultInputFieldAlpha;
+
+ public void UseSuggestion(string suggestion)
+ {
+ string input = InputField.text;
+ input = input.Insert(m_lastCaretPosition, suggestion);
+ InputField.text = input;
+
+ m_desiredCaretFix = m_lastCaretPosition += suggestion.Length;
+
+ var color = InputField.selectionColor;
+ color.a = 0f;
+ InputField.selectionColor = color;
+ }
+
+ private void InvokeOnValueChanged(string value)
+ {
+ if (Time.time - m_timeOfLastInputInvoke <= 0f)
+ return;
+
+ m_timeOfLastInputInvoke = Time.time;
+ OnInputChanged?.Invoke(value);
+ }
+
+ public override void Update()
+ {
+ base.Update();
+
+ if (m_desiredCaretFix >= 0)
+ {
+ if (!m_fixWaiting)
+ {
+ EventSystem.current.SetSelectedGameObject(InputField.gameObject, null);
+ m_fixWaiting = true;
+ }
+ else
+ {
+ InputField.caretPosition = m_desiredCaretFix;
+ InputField.selectionFocusPosition = m_desiredCaretFix;
+ var color = InputField.selectionColor;
+ color.a = m_defaultInputFieldAlpha;
+ InputField.selectionColor = color;
+
+ m_fixWaiting = false;
+ m_desiredCaretFix = -1;
+ }
+ }
+ else if (InputField.caretPosition > 0)
+ m_lastCaretPosition = InputField.caretPosition;
+ }
+
+ // Saving
+
+ public override void DoSaveToConfigElement()
+ {
+ ConfigManager.CSConsoleData.Value = this.ToSaveData();
+ }
+
+ public override void LoadSaveData()
+ {
+ this.ApplySaveData(ConfigManager.CSConsoleData.Value);
+ }
+
+ public override void SetDefaultPosAndAnchors()
+ {
+ mainPanelRect.localPosition = Vector2.zero;
+ mainPanelRect.pivot = new Vector2(0.5f, 0.5f);
+ mainPanelRect.anchorMin = new Vector2(0.5f, 0);
+ mainPanelRect.anchorMax = new Vector2(0.5f, 1);
+ mainPanelRect.offsetMin = new Vector2(mainPanelRect.offsetMin.x, 100); // bottom
+ mainPanelRect.offsetMax = new Vector2(mainPanelRect.offsetMax.x, -50); // top
+ mainPanelRect.sizeDelta = new Vector2(700f, mainPanelRect.sizeDelta.y);
+ mainPanelRect.anchoredPosition = new Vector2(-150, 0);
+ }
+
+ // UI Construction
+
+ public override void ConstructPanelContent()
+ {
+ //Content = UIFactory.CreateVerticalGroup(MainMenu.Instance.PageViewport, "CSharpConsole", true, true, true, true);
+ //UIFactory.SetLayoutElement(Content, preferredHeight: 500, flexibleHeight: 9000);
+
+ #region TOP BAR
+
+ // Main group object
+
+ var topBarObj = UIFactory.CreateHorizontalGroup(this.content, "TopBar", true, true, true, true, 10, new Vector4(8, 8, 30, 30),
+ default, TextAnchor.LowerCenter);
+ UIFactory.SetLayoutElement(topBarObj, minHeight: 50, flexibleHeight: 0);
+
+ // Top label
+
+ var topBarLabel = UIFactory.CreateLabel(topBarObj, "TopLabel", "C# Console", TextAnchor.MiddleLeft, default, true, 25);
+ UIFactory.SetLayoutElement(topBarLabel.gameObject, preferredWidth: 150, flexibleWidth: 5000);
+
+ // Enable Ctrl+R toggle
+
+ var ctrlRToggleObj = UIFactory.CreateToggle(topBarObj, "CtrlRToggle", out var CtrlRToggle, out Text ctrlRToggleText);
+ UIFactory.SetLayoutElement(ctrlRToggleObj, minWidth: 140, flexibleWidth: 0, minHeight: 25);
+ ctrlRToggleText.alignment = TextAnchor.UpperLeft;
+ ctrlRToggleText.text = "Run on Ctrl+R";
+ CtrlRToggle.onValueChanged.AddListener((bool val) => { OnCtrlRToggled?.Invoke(val); });
+
+ // Enable Suggestions toggle
+
+ var suggestToggleObj = UIFactory.CreateToggle(topBarObj, "SuggestionToggle", out var SuggestionsToggle, out Text suggestToggleText);
+ UIFactory.SetLayoutElement(suggestToggleObj, minWidth: 120, flexibleWidth: 0, minHeight: 25);
+ suggestToggleText.alignment = TextAnchor.UpperLeft;
+ suggestToggleText.text = "Suggestions";
+ SuggestionsToggle.onValueChanged.AddListener((bool val) => { OnSuggestionsToggled?.Invoke(val); });
+
+ // Enable Auto-indent toggle
+
+ var autoIndentToggleObj = UIFactory.CreateToggle(topBarObj, "IndentToggle", out var AutoIndentToggle, out Text autoIndentToggleText);
+ UIFactory.SetLayoutElement(autoIndentToggleObj, minWidth: 180, flexibleWidth: 0, minHeight: 25);
+ autoIndentToggleText.alignment = TextAnchor.UpperLeft;
+ autoIndentToggleText.text = "Auto-indent on Enter";
+ AutoIndentToggle.onValueChanged.AddListener((bool val) => { OnAutoIndentToggled?.Invoke(val); });
+
+ #endregion
+
+ #region CONSOLE INPUT
+
+ int fontSize = 16;
+
+ //var inputObj = UIFactory.CreateSrollInputField(this.content, "ConsoleInput", CSConsoleManager.STARTUP_TEXT,
+ // out InputFieldScroller consoleScroll, fontSize);
+
+ var inputObj = UIFactory.CreateSrollInputField(this.content, "ConsoleInput", CSConsoleManager.STARTUP_TEXT, out var inputField, fontSize);
+ InputField = inputField.InputField;
+ m_defaultInputFieldAlpha = InputField.selectionColor.a;
+ InputField.onValueChanged.AddListener(InvokeOnValueChanged);
+
+ var placeHolderText = InputField.placeholder.GetComponent();
+ placeHolderText.fontSize = fontSize;
+
+ InputText = InputField.textComponent;
+ InputText.supportRichText = false;
+ InputText.color = new Color(1, 1, 1, 0.5f);
+
+ var mainTextObj = InputText.gameObject;
+ var highlightTextObj = UIFactory.CreateUIObject("HighlightText", mainTextObj.gameObject);
+ var highlightTextRect = highlightTextObj.GetComponent();
+ highlightTextRect.pivot = new Vector2(0, 1);
+ highlightTextRect.anchorMin = Vector2.zero;
+ highlightTextRect.anchorMax = Vector2.one;
+ highlightTextRect.offsetMin = new Vector2(20, 0);
+ highlightTextRect.offsetMax = new Vector2(14, 0);
+
+ HighlightText = highlightTextObj.AddComponent();
+ HighlightText.supportRichText = true;
+ HighlightText.fontSize = fontSize;
+
+ #endregion
+
+ #region COMPILE BUTTON BAR
+
+ var horozGroupObj = UIFactory.CreateHorizontalGroup(this.content, "BigButtons", true, true, true, true, 0, new Vector4(2, 2, 2, 2),
+ new Color(1, 1, 1, 0));
+
+ var resetButton = UIFactory.CreateButton(horozGroupObj, "ResetButton", "Reset", new Color(0.33f, 0.33f, 0.33f));
+ UIFactory.SetLayoutElement(resetButton.Button.gameObject, minHeight: 45, minWidth: 80, flexibleHeight: 0);
+ resetButton.ButtonText.fontSize = 18;
+ resetButton.OnClick += OnResetClicked;
+
+ var compileButton = UIFactory.CreateButton(horozGroupObj, "CompileButton", "Compile", new Color(0.33f, 0.5f, 0.33f));
+ UIFactory.SetLayoutElement(compileButton.Button.gameObject, minHeight: 45, minWidth: 80, flexibleHeight: 0);
+ compileButton.ButtonText.fontSize = 18;
+ compileButton.OnClick += OnCompileClicked;
+
+ #endregion
+
+ InputText.font = UIManager.ConsoleFont;
+ placeHolderText.font = UIManager.ConsoleFont;
+ HighlightText.font = UIManager.ConsoleFont;
+
+ // reset this after formatting finalized
+ highlightTextRect.anchorMin = Vector2.zero;
+ highlightTextRect.anchorMax = Vector2.one;
+ highlightTextRect.offsetMin = Vector2.zero;
+ highlightTextRect.offsetMax = Vector2.zero;
+ }
+ }
+}
diff --git a/src/UI/Panels/ObjectExplorer.cs b/src/UI/Panels/ObjectExplorer.cs
index c3bda6d..d55a966 100644
--- a/src/UI/Panels/ObjectExplorer.cs
+++ b/src/UI/Panels/ObjectExplorer.cs
@@ -24,6 +24,7 @@ namespace UnityExplorer.UI.Panels
public SceneExplorer SceneExplorer;
public ObjectSearch ObjectSearch;
+ public override bool ShowByDefault => true;
public override bool ShouldSaveActiveState => true;
public int SelectedTab = 0;
diff --git a/src/UI/Panels/UIPanel.cs b/src/UI/Panels/UIPanel.cs
index f19bfbc..f992390 100644
--- a/src/UI/Panels/UIPanel.cs
+++ b/src/UI/Panels/UIPanel.cs
@@ -76,6 +76,7 @@ namespace UnityExplorer.UI.Panels
public abstract UIManager.Panels PanelType { get; }
public abstract string Name { get; }
+ public virtual bool ShowByDefault => false;
public virtual bool ShouldSaveActiveState => true;
public virtual bool CanDragAndResize => true;
public virtual bool NavButtonWanted => true;
@@ -127,6 +128,8 @@ namespace UnityExplorer.UI.Panels
public void ConstructUI()
{
+ //this.Enabled = true;
+
if (NavButtonWanted)
{
// create navbar button
@@ -143,12 +146,12 @@ namespace UnityExplorer.UI.Panels
// create core canvas
uiRoot = UIFactory.CreatePanel(Name, out GameObject panelContent);
mainPanelRect = this.uiRoot.GetComponent();
- content = panelContent;
+ UIFactory.SetLayoutGroup(this.uiRoot, true, true, true, true, 0, 2, 2, 2, 2, TextAnchor.UpperLeft);
int id = this.uiRoot.transform.GetInstanceID();
transformToPanelDict.Add(id, this);
- UIFactory.SetLayoutGroup(this.uiRoot, true, true, true, true, 0, 0, 0, 0, 0, TextAnchor.UpperLeft);
+ content = panelContent;
UIFactory.SetLayoutGroup(this.content, true, true, true, true, 2, 2, 2, 2, 2, TextAnchor.UpperLeft);
// always apply default pos and anchors (save data may only be partial)
@@ -166,10 +169,9 @@ namespace UnityExplorer.UI.Panels
// close button
- var closeBtn = UIFactory.CreateButton(titleGroup, "CloseButton", "X");
+ var closeBtn = UIFactory.CreateButton(titleGroup, "CloseButton", "—");
UIFactory.SetLayoutElement(closeBtn.Button.gameObject, minHeight: 25, minWidth: 25, flexibleWidth: 0);
- RuntimeProvider.Instance.SetColorBlock(closeBtn.Button, new Color(0.63f, 0.32f, 0.31f),
- new Color(0.81f, 0.25f, 0.2f), new Color(0.6f, 0.18f, 0.16f));
+ RuntimeProvider.Instance.SetColorBlock(closeBtn.Button, new Color(0.33f, 0.32f, 0.31f));
closeBtn.OnClick += () =>
{
@@ -186,12 +188,14 @@ namespace UnityExplorer.UI.Panels
Dragger.OnFinishResize += OnFinishResize;
Dragger.OnFinishDrag += OnFinishDrag;
Dragger.AllowDragAndResize = this.CanDragAndResize;
- //Dragger.CanResize = this.CanResize;
// content (abstract)
ConstructPanelContent();
+ UIManager.SetPanelActive(this.PanelType, false);
+ UIManager.SetPanelActive(this.PanelType, ShowByDefault);
+
ApplyingSaveData = true;
// apply panel save data or revert to default
try
diff --git a/src/UI/UIFactory.cs b/src/UI/UIFactory.cs
index 401232e..59d916d 100644
--- a/src/UI/UIFactory.cs
+++ b/src/UI/UIFactory.cs
@@ -148,6 +148,8 @@ namespace UnityExplorer.UI
public static GameObject CreatePanel(string name, out GameObject contentHolder, Color? bgColor = null)
{
var panelObj = CreateUIObject(name, UIManager.PanelHolder);
+ SetLayoutGroup(panelObj, true, true, true, true);
+
var rect = panelObj.GetComponent();
rect.anchorMin = Vector2.zero;
rect.anchorMax = Vector2.one;
@@ -155,17 +157,15 @@ namespace UnityExplorer.UI
rect.sizeDelta = Vector2.zero;
var maskImg = panelObj.AddComponent();
- maskImg.color = Color.white;
- panelObj.AddComponent().showMaskGraphic = false;
-
- SetLayoutGroup(panelObj, true, true, true, true);
+ maskImg.color = Color.black;
+ panelObj.AddComponent().showMaskGraphic = true;
contentHolder = CreateUIObject("Content", panelObj);
Image bgImage = contentHolder.AddComponent();
bgImage.type = Image.Type.Filled;
if (bgColor == null)
- bgImage.color = new Color(0.06f, 0.06f, 0.06f);
+ bgImage.color = new Color(0.07f, 0.07f, 0.07f);
else
bgImage.color = (Color)bgColor;
@@ -454,27 +454,6 @@ namespace UnityExplorer.UI
return toggleObj;
}
- ///
- /// Create a Scrollable Input Field control (custom InputFieldScroller).
- ///
- public static GameObject CreateSrollInputField(GameObject parent, string name, string placeHolderText,
- out InputFieldScroller inputScroll, int fontSize = 14, Color color = default)
- {
- if (color == default)
- color = new Color(0.15f, 0.15f, 0.15f);
-
- var mainObj = CreateScrollView(parent, "InputFieldScrollView", out GameObject scrollContent, out SliderScrollbar scroller, color);
-
- CreateInputField(scrollContent, name, placeHolderText ?? "...", out InputField inputField, fontSize, 0);
-
- inputField.lineType = InputField.LineType.MultiLineNewline;
- inputField.targetGraphic.color = color;
-
- inputScroll = new InputFieldScroller(scroller, inputField);
-
- return mainObj;
- }
-
// Little helper class to force rebuild of an input field's layout on value change.
// This is limited to once per frame per input field, so its not too expensive.
private class InputFieldRefresher
@@ -507,6 +486,7 @@ namespace UnityExplorer.UI
int fontSize = 14, int alignment = 3, int wrap = 0)
{
GameObject mainObj = CreateUIObject(name, parent);
+ //SetLayoutGroup(mainObj, true, true, true, true);
Image mainImage = mainObj.AddComponent();
mainImage.type = Image.Type.Sliced;
@@ -524,10 +504,9 @@ namespace UnityExplorer.UI
RuntimeProvider.Instance.SetColorBlock(inputField, new Color(1, 1, 1, 1),
new Color(0.95f, 0.95f, 0.95f, 1.0f), new Color(0.78f, 0.78f, 0.78f, 1.0f));
- SetLayoutGroup(mainObj, true, true, true, true);
-
GameObject textArea = CreateUIObject("TextArea", mainObj);
textArea.AddComponent();
+ //textArea.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
RectTransform textAreaRect = textArea.GetComponent();
textAreaRect.anchorMin = Vector2.zero;
@@ -552,7 +531,7 @@ namespace UnityExplorer.UI
placeHolderRect.offsetMin = Vector2.zero;
placeHolderRect.offsetMax = Vector2.zero;
- SetLayoutElement(placeHolderObj, minWidth: 500, flexibleWidth: 5000);
+ SetLayoutElement(placeHolderObj, minWidth: 200, flexibleWidth: 5000);
inputField.placeholder = placeholderText;
@@ -571,7 +550,7 @@ namespace UnityExplorer.UI
inputTextRect.offsetMin = Vector2.zero;
inputTextRect.offsetMax = Vector2.zero;
- SetLayoutElement(inputTextObj, minWidth: 500, flexibleWidth: 5000);
+ SetLayoutElement(inputTextObj, minWidth: 200, flexibleWidth: 5000);
inputField.textComponent = inputText;
@@ -773,73 +752,130 @@ namespace UnityExplorer.UI
SetLayoutElement(sliderContainer, minWidth: 25, flexibleWidth:0, flexibleHeight: 9999);
sliderContainer.AddComponent();
- var sliderObj = SliderScrollbar.CreateSliderScrollbar(sliderContainer, out Slider slider);
- slider.direction = Slider.Direction.TopToBottom;
- SetLayoutElement(sliderObj, minWidth: 25, flexibleWidth: 0, flexibleHeight: 9999);
+ CreateSliderScrollbar(sliderContainer, out Slider slider);
RuntimeProvider.Instance.SetColorBlock(slider, disabled: new Color(0.1f, 0.1f, 0.1f));
- slider.handleRect.offsetMin = new Vector2(slider.handleRect.offsetMin.x, 0);
- slider.handleRect.offsetMax = new Vector2(slider.handleRect.offsetMax.x, 0);
- slider.handleRect.pivot = new Vector2(0.5f, 0.5f);
-
- var container = slider.m_HandleContainerRect;
- container.anchorMin = Vector3.zero;
- container.anchorMax = Vector3.one;
- container.pivot = new Vector3(0.5f, 0.5f);
-
// finalize and create ScrollPool
uiRoot = mainObj;
var scrollPool = new ScrollPool(scrollRect);
- //viewportObj.GetComponent().enabled = false;
-
return scrollPool;
}
+ public static GameObject CreateSliderScrollbar(GameObject parent, out Slider slider)
+ {
+ GameObject mainObj = CreateUIObject("SliderScrollbar", parent, UIFactory._smallElementSize);
+
+ GameObject bgImageObj = CreateUIObject("Background", mainObj);
+ GameObject handleSlideAreaObj = CreateUIObject("Handle Slide Area", mainObj);
+ GameObject handleObj = CreateUIObject("Handle", handleSlideAreaObj);
+
+ Image bgImage = bgImageObj.AddComponent();
+ bgImage.type = Image.Type.Sliced;
+ bgImage.color = new Color(0.05f, 0.05f, 0.05f, 1.0f);
+
+ RectTransform bgRect = bgImageObj.GetComponent();
+ bgRect.pivot = new Vector2(0, 1);
+ bgRect.anchorMin = Vector2.zero;
+ bgRect.anchorMax = Vector2.one;
+ bgRect.sizeDelta = Vector2.zero;
+ bgRect.offsetMax = new Vector2(0f, 0f);
+
+ RectTransform handleSlideRect = handleSlideAreaObj.GetComponent();
+ handleSlideRect.anchorMin = Vector3.zero;
+ handleSlideRect.anchorMax = Vector3.one;
+ handleSlideRect.pivot = new Vector3(0.5f, 0.5f);
+
+ Image handleImage = handleObj.AddComponent();
+ handleImage.color = new Color(0.5f, 0.5f, 0.5f, 1.0f);
+
+ var handleRect = handleObj.GetComponent();
+ handleRect.pivot = new Vector2(0.5f, 0.5f);
+ UIFactory.SetLayoutElement(handleObj, minWidth: 21, flexibleWidth: 0);
+
+ var sliderBarLayout = mainObj.AddComponent();
+ sliderBarLayout.minWidth = 25;
+ sliderBarLayout.flexibleWidth = 0;
+ sliderBarLayout.minHeight = 30;
+ sliderBarLayout.flexibleHeight = 5000;
+
+ slider = mainObj.AddComponent();
+ slider.handleRect = handleObj.GetComponent();
+ slider.targetGraphic = handleImage;
+ slider.direction = Slider.Direction.TopToBottom;
+
+ SetLayoutElement(mainObj, minWidth: 25, flexibleWidth: 0, flexibleHeight: 9999);
+
+ RuntimeProvider.Instance.SetColorBlock(slider,
+ new Color(0.4f, 0.4f, 0.4f),
+ new Color(0.5f, 0.5f, 0.5f),
+ new Color(0.3f, 0.3f, 0.3f),
+ new Color(0.5f, 0.5f, 0.5f));
+
+ return mainObj;
+ }
+
///
/// Create a ScrollView element.
///
- public static GameObject CreateScrollView(GameObject parent, string name, out GameObject content, out SliderScrollbar scroller,
+ public static GameObject CreateAutoScrollView(GameObject parent, string name, out GameObject content, out AutoSliderScrollbar autoScrollbar,
Color color = default)
{
- GameObject mainObj = CreateUIObject("DynamicScrollView", parent);
-
+ GameObject mainObj = CreateUIObject(name, parent);
SetLayoutElement(mainObj, minWidth: 100, minHeight: 30, flexibleWidth: 5000, flexibleHeight: 5000);
-
+ SetLayoutGroup(mainObj, false, true, true, true, 2);
Image mainImage = mainObj.AddComponent();
mainImage.type = Image.Type.Filled;
mainImage.color = (color == default) ? new Color(0.3f, 0.3f, 0.3f, 1f) : color;
GameObject viewportObj = CreateUIObject("Viewport", mainObj);
-
+ UIFactory.SetLayoutElement(viewportObj, minWidth: 1, flexibleWidth: 9999, flexibleHeight: 9999);
var viewportRect = viewportObj.GetComponent();
viewportRect.anchorMin = Vector2.zero;
viewportRect.anchorMax = Vector2.one;
viewportRect.pivot = new Vector2(0.0f, 1.0f);
- viewportRect.sizeDelta = new Vector2(-15.0f, 0.0f);
- viewportRect.offsetMax = new Vector2(-20.0f, 0.0f);
-
+ //viewportRect.sizeDelta = new Vector2(-15.0f, 0.0f);
+ //viewportRect.offsetMax = new Vector2(-25.0f, 0.0f);
viewportObj.AddComponent().color = Color.white;
viewportObj.AddComponent().showMaskGraphic = false;
content = CreateUIObject("Content", viewportObj);
var contentRect = content.GetComponent();
+ SetLayoutGroup(content, true, true, true, true);//, 5, 5, 5, 5, 5);
contentRect.anchorMin = new Vector2(0.0f, 1.0f);
contentRect.anchorMax = new Vector2(1.0f, 1.0f);
contentRect.pivot = new Vector2(0.0f, 1.0f);
- contentRect.sizeDelta = new Vector2(5f, 0f);
- contentRect.offsetMax = new Vector2(0f, 0f);
- var contentFitter = content.AddComponent();
- contentFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
- contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
+ //contentRect.sizeDelta = new Vector2(5f, 0f);
+ //contentRect.offsetMax = new Vector2(0f, 0f);
- SetLayoutGroup(content, true, true, true, true, 5, 5, 5, 5, 5);
+ // Slider
- CreateSliderScrollbar(mainObj, out scroller, out Scrollbar hiddenScrollbar);
+ GameObject scrollBarObj = CreateUIObject("AutoSliderScrollbar", mainObj);
+ SetLayoutGroup(scrollBarObj, true, true, true, true);
+ SetLayoutElement(scrollBarObj, minWidth: 25, flexibleWidth: 0, flexibleHeight: 9999);
+ scrollBarObj.AddComponent().color = Color.white;
+ scrollBarObj.AddComponent().showMaskGraphic = false;
+
+ GameObject hiddenBar = CreateScrollbar(scrollBarObj, "HiddenScrollviewScroller", out var hiddenScrollbar);
+ hiddenScrollbar.SetDirection(Scrollbar.Direction.BottomToTop, true);
- // Back to the main scrollview ScrollRect, setting it up now that we have all references.
+ for (int i = 0; i < hiddenBar.transform.childCount; i++)
+ {
+ var child = hiddenBar.transform.GetChild(i);
+ child.gameObject.SetActive(false);
+ }
+
+ CreateSliderScrollbar(scrollBarObj, out Slider scrollSlider);
+
+ autoScrollbar = new AutoSliderScrollbar(hiddenScrollbar, scrollSlider, contentRect, viewportRect);
+
+ //var sliderContainer = autoScrollbar.Slider.m_HandleContainerRect.gameObject;
+ //SetLayoutElement(sliderContainer, minWidth: 25, flexibleWidth: 0, flexibleHeight: 9999);
+ //sliderContainer.AddComponent();
+
+ // Set up the ScrollRect component
var scrollRect = mainObj.AddComponent();
scrollRect.horizontal = false;
@@ -856,21 +892,54 @@ namespace UnityExplorer.UI
return mainObj;
}
- public static GameObject CreateSliderScrollbar(GameObject mainObj, out SliderScrollbar scroller, out Scrollbar hiddenScrollbar)
+
+ ///
+ /// Create a Scrollable Input Field control (custom InputFieldScroller).
+ ///
+ public static GameObject CreateSrollInputField(GameObject parent, string name, string placeHolderText, out InputFieldScroller inputScroll,
+ int fontSize = 14, Color color = default)
{
- GameObject scrollBarObj = CreateUIObject("DynamicScrollbar", mainObj);
+ if (color == default)
+ color = new Color(0.12f, 0.12f, 0.12f);
- var scrollbarLayout = scrollBarObj.AddComponent();
- scrollbarLayout.childForceExpandHeight = true;
- scrollbarLayout.SetChildControlHeight(true);
+ GameObject mainObj = CreateUIObject(name, parent);
+ SetLayoutElement(mainObj, minWidth: 100, minHeight: 30, flexibleWidth: 5000, flexibleHeight: 5000);
+ SetLayoutGroup(mainObj, false, true, true, true, 2);
+ Image mainImage = mainObj.AddComponent();
+ mainImage.type = Image.Type.Filled;
+ mainImage.color = (color == default) ? new Color(0.3f, 0.3f, 0.3f, 1f) : color;
- RectTransform scrollBarRect = scrollBarObj.GetComponent();
- scrollBarRect.anchorMin = new Vector2(1.0f, 0.0f);
- scrollBarRect.anchorMax = new Vector2(1.0f, 1.0f);
- scrollBarRect.sizeDelta = new Vector2(15.0f, 0.0f);
- scrollBarRect.offsetMin = new Vector2(-15.0f, 0.0f);
+ GameObject viewportObj = CreateUIObject("Viewport", mainObj);
+ SetLayoutElement(viewportObj, minWidth: 1, flexibleWidth: 9999, flexibleHeight: 9999);
+ var viewportRect = viewportObj.GetComponent();
+ viewportRect.anchorMin = Vector2.zero;
+ viewportRect.anchorMax = Vector2.one;
+ viewportRect.pivot = new Vector2(0.0f, 1.0f);
+ viewportObj.AddComponent().color = Color.white;
+ viewportObj.AddComponent().showMaskGraphic = false;
- GameObject hiddenBar = CreateScrollbar(scrollBarObj, "HiddenScrollviewScroller", out hiddenScrollbar);
+ // Input Field
+
+ var content = CreateInputField(viewportObj, name, placeHolderText ?? "...", out InputField inputField, fontSize, 0);
+ SetLayoutElement(content, flexibleHeight: 9999, flexibleWidth: 9999);
+ var contentRect = content.GetComponent();
+ contentRect.pivot = new Vector2(0, 1);
+ contentRect.anchorMin = new Vector2(0, 1);
+ contentRect.anchorMax = new Vector2(1, 1);
+ contentRect.offsetMin = new Vector2(2, 0);
+ contentRect.offsetMax = new Vector2(2, 0);
+ inputField.lineType = InputField.LineType.MultiLineNewline;
+ inputField.targetGraphic.color = color;
+
+ // Slider
+
+ GameObject scrollBarObj = CreateUIObject("AutoSliderScrollbar", mainObj);
+ SetLayoutGroup(scrollBarObj, true, true, true, true);
+ SetLayoutElement(scrollBarObj, minWidth: 25, flexibleWidth: 0, flexibleHeight: 9999);
+ scrollBarObj.AddComponent().color = Color.white;
+ scrollBarObj.AddComponent().showMaskGraphic = false;
+
+ GameObject hiddenBar = CreateScrollbar(scrollBarObj, "HiddenScrollviewScroller", out var hiddenScrollbar);
hiddenScrollbar.SetDirection(Scrollbar.Direction.BottomToTop, true);
for (int i = 0; i < hiddenBar.transform.childCount; i++)
@@ -879,11 +948,37 @@ namespace UnityExplorer.UI
child.gameObject.SetActive(false);
}
- SliderScrollbar.CreateSliderScrollbar(scrollBarObj, out Slider scrollSlider);
+ CreateSliderScrollbar(scrollBarObj, out Slider scrollSlider);
- scroller = new SliderScrollbar(hiddenScrollbar, scrollSlider);
+ // Set up the AutoSliderScrollbar module
- return scrollBarObj;
+ var autoScroller = new AutoSliderScrollbar(hiddenScrollbar, scrollSlider, contentRect, viewportRect);
+
+ var sliderContainer = autoScroller.Slider.m_HandleContainerRect.gameObject;
+ SetLayoutElement(sliderContainer, minWidth: 25, flexibleWidth: 0, flexibleHeight: 9999);
+ sliderContainer.AddComponent();
+
+ // Set up the InputFieldScroller module
+
+ inputScroll = new InputFieldScroller(autoScroller, inputField);
+ inputScroll.ProcessInputText();
+
+ // Set up the ScrollRect component
+
+ var scrollRect = mainObj.AddComponent();
+ scrollRect.horizontal = false;
+ scrollRect.vertical = true;
+ scrollRect.verticalScrollbar = hiddenScrollbar;
+ scrollRect.movementType = ScrollRect.MovementType.Clamped;
+ scrollRect.scrollSensitivity = 35;
+ scrollRect.horizontalScrollbarVisibility = ScrollRect.ScrollbarVisibility.AutoHideAndExpandViewport;
+ scrollRect.verticalScrollbarVisibility = ScrollRect.ScrollbarVisibility.Permanent;
+
+ scrollRect.viewport = viewportRect;
+ scrollRect.content = contentRect;
+
+
+ return mainObj;
}
}
}
diff --git a/src/UI/UIManager.cs b/src/UI/UIManager.cs
index fee3f7c..aa6eaa6 100644
--- a/src/UI/UIManager.cs
+++ b/src/UI/UIManager.cs
@@ -41,6 +41,8 @@ namespace UnityExplorer.UI
public static ObjectExplorer Explorer { get; private set; }
public static InspectorPanel Inspector { get; private set; }
+ public static CSConsolePanel CSConsole { get; private set; }
+
public static AutoCompleter AutoCompleter { get; private set; }
// other
@@ -50,6 +52,23 @@ namespace UnityExplorer.UI
internal static readonly Color navButtonEnabledColor = new Color(0.2f, 0.4f, 0.28f);
internal static readonly Color navButtonDisabledColor = new Color(0.25f, 0.25f, 0.25f);
+ public static UIPanel GetPanel(Panels panel)
+ {
+ switch (panel)
+ {
+ case Panels.ObjectExplorer:
+ return Explorer;
+ case Panels.Inspector:
+ return Inspector;
+ case Panels.AutoCompleter:
+ return AutoCompleter;
+ case Panels.CSConsole:
+ return CSConsole;
+ default:
+ throw new NotImplementedException($"TODO GetPanel: {panel}");
+ }
+ }
+
// main menu toggle
public static bool ShowMenu
{
@@ -96,21 +115,6 @@ namespace UnityExplorer.UI
AutoCompleter.Update();
}
- public static UIPanel GetPanel(Panels panel)
- {
- switch (panel)
- {
- case Panels.ObjectExplorer:
- return Explorer;
- case Panels.Inspector:
- return Inspector;
- case Panels.AutoCompleter:
- return AutoCompleter;
- default:
- throw new NotImplementedException($"TODO GetPanel: {panel}");
- }
- }
-
public static void TogglePanel(Panels panel)
{
var uiPanel = GetPanel(panel);
@@ -153,17 +157,20 @@ namespace UnityExplorer.UI
CreateTopNavBar();
+ //InspectUnderMouse.ConstructUI();
+
AutoCompleter = new AutoCompleter();
AutoCompleter.ConstructUI();
- //InspectUnderMouse.ConstructUI();
-
Explorer = new ObjectExplorer();
Explorer.ConstructUI();
Inspector = new InspectorPanel();
Inspector.ConstructUI();
+ CSConsole = new CSConsolePanel();
+ CSConsole.ConstructUI();
+
ShowMenu = !ConfigManager.Hide_On_Startup.Value;
ExplorerCore.Log("UI initialized.");
diff --git a/src/UI/Widgets/AutoSliderScrollbar.cs b/src/UI/Widgets/AutoSliderScrollbar.cs
new file mode 100644
index 0000000..6117602
--- /dev/null
+++ b/src/UI/Widgets/AutoSliderScrollbar.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using UnityEngine;
+using UnityEngine.Events;
+using UnityEngine.UI;
+using UnityExplorer;
+using UnityExplorer.Core;
+using UnityExplorer.UI;
+using UnityExplorer.UI.Models;
+
+namespace UnityExplorer.UI.Utility
+{
+ // A Slider Scrollbar which automatically resizes for the content size (no pooling).
+ // Currently just used for the C# Console input field.
+
+ public class AutoSliderScrollbar : UIBehaviourModel
+ {
+ public override GameObject UIRoot
+ {
+ get
+ {
+ if (Slider)
+ return Slider.gameObject;
+ return null;
+ }
+ }
+
+ //public event Action OnValueChanged;
+
+ internal readonly Scrollbar Scrollbar;
+ internal readonly Slider Slider;
+ internal RectTransform ContentRect;
+ internal RectTransform ViewportRect;
+
+ //internal InputFieldScroller m_parentInputScroller;
+
+ public AutoSliderScrollbar(Scrollbar scrollbar, Slider slider, RectTransform contentRect, RectTransform viewportRect)
+ {
+ this.Scrollbar = scrollbar;
+ this.Slider = slider;
+ this.ContentRect = contentRect;
+ this.ViewportRect = viewportRect;
+
+ this.Scrollbar.onValueChanged.AddListener(this.OnScrollbarValueChanged);
+ this.Slider.onValueChanged.AddListener(this.OnSliderValueChanged);
+
+ //this.RefreshVisibility();
+ this.Slider.Set(0f, false);
+ }
+
+ private float lastAnchorPosition;
+ private float lastContentHeight;
+ private float lastViewportHeight;
+ private bool _refreshWanted;
+
+ public override void Update()
+ {
+ if (!Enabled)
+ return;
+
+ _refreshWanted = false;
+ if (ContentRect.localPosition.y != lastAnchorPosition)
+ {
+ lastAnchorPosition = ContentRect.localPosition.y;
+ _refreshWanted = true;
+ }
+ if (ContentRect.rect.height != lastContentHeight)
+ {
+ lastContentHeight = ContentRect.rect.height;
+ _refreshWanted = true;
+ }
+ if (ViewportRect.rect.height != lastViewportHeight)
+ {
+ lastViewportHeight = ViewportRect.rect.height;
+ _refreshWanted = true;
+ }
+
+ if (_refreshWanted)
+ UpdateSliderHandle();
+ }
+
+ public void UpdateSliderHandle()
+ {
+ // calculate handle size based on viewport / total data height
+ var totalHeight = ContentRect.rect.height;
+ var viewportHeight = ViewportRect.rect.height;
+
+ if (totalHeight <= viewportHeight)
+ {
+ Slider.value = 0f;
+ Slider.interactable = false;
+ return;
+ }
+
+ var handleHeight = viewportHeight * Math.Min(1, viewportHeight / totalHeight);
+ handleHeight = Math.Max(15f, handleHeight);
+
+ // resize the handle container area for the size of the handle (bigger handle = smaller container)
+ var container = Slider.m_HandleContainerRect;
+ container.offsetMax = new Vector2(container.offsetMax.x, -(handleHeight * 0.5f));
+ container.offsetMin = new Vector2(container.offsetMin.x, handleHeight * 0.5f);
+
+ // set handle size
+ Slider.handleRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, handleHeight);
+
+ // if slider is 100% height then make it not interactable
+ Slider.interactable = !Mathf.Approximately(handleHeight, viewportHeight);
+
+ float val = 0f;
+ if (totalHeight > 0f)
+ val = (float)((decimal)ContentRect.localPosition.y / (decimal)(totalHeight - ViewportRect.rect.height));
+
+ Slider.value = val;
+ }
+
+ public void OnScrollbarValueChanged(float value)
+ {
+ value = 1f - value;
+ if (this.Slider.value != value)
+ this.Slider.Set(value, false);
+ //OnValueChanged?.Invoke(value);
+ }
+
+ public void OnSliderValueChanged(float value)
+ {
+ value = 1f - value;
+ this.Scrollbar.value = value;
+ //OnValueChanged?.Invoke(value);
+ }
+
+ public override void ConstructUI(GameObject parent)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/UI/Widgets/InputFieldScroller.cs b/src/UI/Widgets/InputFieldScroller.cs
index 16db052..11a3861 100644
--- a/src/UI/Widgets/InputFieldScroller.cs
+++ b/src/UI/Widgets/InputFieldScroller.cs
@@ -19,106 +19,93 @@ namespace UnityExplorer.UI.Utility
{
get
{
- if (inputField)
- return inputField.gameObject;
+ if (InputField)
+ return InputField.gameObject;
return null;
}
}
- internal SliderScrollbar sliderScroller;
- internal InputField inputField;
+ internal AutoSliderScrollbar Slider;
+ internal InputField InputField;
- internal RectTransform inputRect;
- internal LayoutElement layoutElement;
- internal VerticalLayoutGroup parentLayoutGroup;
+ internal RectTransform ContentRect;
+ internal RectTransform ViewportRect;
- internal static CanvasScaler canvasScaler;
+ internal static CanvasScaler RootScaler;
- public InputFieldScroller(SliderScrollbar sliderScroller, InputField inputField)
+ public InputFieldScroller(AutoSliderScrollbar sliderScroller, InputField inputField)
{
- //Instances.Add(this);
-
- this.sliderScroller = sliderScroller;
- this.inputField = inputField;
-
- sliderScroller.m_parentInputScroller = this;
+ this.Slider = sliderScroller;
+ this.InputField = inputField;
inputField.onValueChanged.AddListener(OnTextChanged);
- inputRect = inputField.GetComponent();
- layoutElement = inputField.gameObject.AddComponent();
- parentLayoutGroup = inputField.transform.parent.GetComponent();
+ ContentRect = inputField.GetComponent();
+ ViewportRect = ContentRect.transform.parent.GetComponent();
- layoutElement.minHeight = 25;
- layoutElement.minWidth = 100;
-
- if (!canvasScaler)
- canvasScaler = UIManager.CanvasRoot.GetComponent();
+ if (!RootScaler)
+ RootScaler = UIManager.CanvasRoot.GetComponent();
}
internal string m_lastText;
internal bool m_updateWanted;
-
- // only done once, to fix height on creation.
- internal bool heightInitAfterLayout;
+ internal bool m_wantJumpToBottom;
+ private float m_desiredContentHeight;
public override void Update()
{
- if (!heightInitAfterLayout)
- {
- heightInitAfterLayout = true;
- var height = sliderScroller.m_scrollRect.parent.parent.GetComponent().rect.height;
- layoutElement.preferredHeight = height;
- }
-
- if (m_updateWanted && inputField.gameObject.activeInHierarchy)
+ if (m_updateWanted)
{
m_updateWanted = false;
- RefreshUI();
+ ProcessInputText();
+ }
+
+ float desiredHeight = Math.Max(m_desiredContentHeight, ViewportRect.rect.height);
+
+ if (ContentRect.rect.height < desiredHeight)
+ {
+ ContentRect.sizeDelta = new Vector2(0, desiredHeight);
+ this.Slider.UpdateSliderHandle();
+ }
+ else if (ContentRect.rect.height > desiredHeight)
+ {
+ ContentRect.sizeDelta = new Vector2(0, desiredHeight);
+ this.Slider.UpdateSliderHandle();
+ }
+
+ if (m_wantJumpToBottom)
+ {
+ Slider.Slider.value = 1f;
+ m_wantJumpToBottom = false;
}
}
- //internal bool CheckDestroyed()
- //{
- // if (sliderScroller == null || sliderScroller.CheckDestroyed())
- // {
- // Instances.Remove(this);
- // return true;
- // }
-
- // return false;
- //}
-
internal void OnTextChanged(string text)
{
m_lastText = text;
m_updateWanted = true;
}
- internal void RefreshUI()
+ internal void ProcessInputText()
{
- var curInputRect = inputField.textComponent.rectTransform.rect;
- var scaleFactor = canvasScaler.scaleFactor;
+ var curInputRect = InputField.textComponent.rectTransform.rect;
+ var scaleFactor = RootScaler.scaleFactor;
// Current text settings
- var texGenSettings = inputField.textComponent.GetGenerationSettings(curInputRect.size);
+ var texGenSettings = InputField.textComponent.GetGenerationSettings(curInputRect.size);
texGenSettings.generateOutOfBounds = false;
texGenSettings.scaleFactor = scaleFactor;
// Preferred text rect height
- var textGen = inputField.textComponent.cachedTextGeneratorForLayout;
- float preferredHeight = textGen.GetPreferredHeight(m_lastText, texGenSettings) + 10;
+ var textGen = InputField.textComponent.cachedTextGeneratorForLayout;
+ m_desiredContentHeight = textGen.GetPreferredHeight(m_lastText, texGenSettings) + 10;
- // Default text rect height (fit to scroll parent or expand to fit text)
- float minHeight = Mathf.Max(preferredHeight, sliderScroller.m_scrollRect.rect.height - 25);
-
- layoutElement.preferredHeight = minHeight;
-
- if (inputField.caretPosition == inputField.text.Length
- && inputField.text.Length > 0
- && inputField.text[inputField.text.Length - 1] == '\n')
+ // jump to bottom
+ if (InputField.caretPosition == InputField.text.Length
+ && InputField.text.Length > 0
+ && InputField.text[InputField.text.Length - 1] == '\n')
{
- sliderScroller.m_slider.value = 0f;
+ m_wantJumpToBottom = true;
}
}
diff --git a/src/UI/Widgets/ScrollPool/DataHeightCache.cs b/src/UI/Widgets/ScrollPool/DataHeightCache.cs
index 8412cd4..7e61c80 100644
--- a/src/UI/Widgets/ScrollPool/DataHeightCache.cs
+++ b/src/UI/Widgets/ScrollPool/DataHeightCache.cs
@@ -67,7 +67,7 @@ namespace UnityExplorer.UI.Widgets
// our first cell and they take priority, so reduce our height by
// (minHeight - remainder) to account for that. We need to fill that
// gap and reach the next cell before we take priority.
- if (!Mathf.Approximately(rem, 0f))
+ if (rem != 0.0f)
height -= (DefaultHeight - rem);
return (int)Math.Ceiling((decimal)height / (decimal)DefaultHeight);
@@ -139,8 +139,11 @@ namespace UnityExplorer.UI.Widgets
{
if (dataIndex >= ScrollPool.DataSource.ItemCount)
{
- while (heightCache.Count > dataIndex)
- RemoveLast();
+ if (heightCache.Count > dataIndex)
+ {
+ while (heightCache.Count > dataIndex)
+ RemoveLast();
+ }
return;
}
@@ -249,14 +252,6 @@ namespace UnityExplorer.UI.Widgets
}
}
}
-
- //// if sister cache is set, then update it too.
- //if (SisterCache != null)
- //{
- // var realIdx = ScrollPool.DataSource.GetRealIndexOfTempIndex(dataIndex);
- // if (realIdx >= 0)
- // SisterCache.SetIndex(realIdx, height, true);
- //}
}
private void RebuildCache()
diff --git a/src/UI/Widgets/ScrollPool/ScrollPool.cs b/src/UI/Widgets/ScrollPool/ScrollPool.cs
index 97befb4..5abf911 100644
--- a/src/UI/Widgets/ScrollPool/ScrollPool.cs
+++ b/src/UI/Widgets/ScrollPool/ScrollPool.cs
@@ -115,7 +115,7 @@ namespace UnityExplorer.UI.Widgets
if (writingLocked && timeofLastWriteLock < Time.time)
writingLocked = false;
- if (prevContentHeight <= 1f && Content?.rect.height > 1f)
+ if (prevContentHeight <= 1f && Content.rect.height > 1f)
{
prevContentHeight = Content.rect.height;
}
@@ -131,10 +131,12 @@ namespace UnityExplorer.UI.Widgets
public void Rebuild()
{
+ HeightCache = new DataHeightCache(this);
+
SetRecycleViewBounds(false);
SetScrollBounds();
- ExtendCellPool();
+ CheckExtendCellPool();
writingLocked = false;
Content.anchoredPosition = Vector2.zero;
UpdateSliderHandle(true);
@@ -163,6 +165,7 @@ namespace UnityExplorer.UI.Widgets
// Initialize
+ private bool m_doneFirstInit;
private bool m_initialized;
public void Initialize(IPoolDataSource dataSource)
@@ -173,12 +176,16 @@ namespace UnityExplorer.UI.Widgets
HeightCache = new DataHeightCache(this);
DataSource = dataSource;
- this.contentLayout = ScrollRect.content.GetComponent();
- this.slider = ScrollRect.GetComponentInChildren();
- slider.onValueChanged.AddListener(OnSliderValueChanged);
+ if (!m_doneFirstInit)
+ {
+ m_doneFirstInit = true;
+ this.contentLayout = ScrollRect.content.GetComponent();
+ this.slider = ScrollRect.GetComponentInChildren();
+ slider.onValueChanged.AddListener(OnSliderValueChanged);
- ScrollRect.vertical = true;
- ScrollRect.horizontal = false;
+ ScrollRect.vertical = true;
+ ScrollRect.horizontal = false;
+ }
ScrollRect.onValueChanged.RemoveListener(OnValueChangedListener);
RuntimeProvider.Instance.StartCoroutine(InitCoroutine());
@@ -224,12 +231,18 @@ namespace UnityExplorer.UI.Widgets
}
CellPool.Clear();
}
+
+ bottomDataIndex = -1;
+ topPoolIndex = 0;
+ bottomPoolIndex = 0;
}
- private void CreateCellPool(bool andResetDataIndex = true)
+ private void CreateCellPool()
{
ReturnCells();
+ CheckDataSourceCountChange(out _);
+
float currentPoolCoverage = 0f;
float requiredCoverage = ScrollRect.viewport.rect.height + RecycleThreshold;
@@ -250,8 +263,7 @@ namespace UnityExplorer.UI.Widgets
currentPoolCoverage += PrototypeHeight;
}
- if (andResetDataIndex)
- bottomDataIndex = CellPool.Count - 1;
+ bottomDataIndex = CellPool.Count - 1;
LayoutRebuilder.ForceRebuildLayoutImmediate(Content);
@@ -266,13 +278,12 @@ namespace UnityExplorer.UI.Widgets
RecycleViewBounds = new Vector2(Viewport.MinY() + HalfThreshold, Viewport.MaxY() - HalfThreshold);
if (extendPoolIfGrown && prevViewportHeight < Viewport.rect.height && prevViewportHeight != 0.0f)
- ExtendCellPool();
+ CheckExtendCellPool();
prevViewportHeight = Viewport.rect.height;
-
}
- private bool ExtendCellPool()
+ private bool CheckExtendCellPool()
{
CheckDataSourceCountChange(out _);
@@ -285,6 +296,7 @@ namespace UnityExplorer.UI.Widgets
bottomDataIndex += cellsRequired;
+ // TODO sometimes still jumps a litte bit, need to figure out why.
float prevAnchor = Content.localPosition.y;
float prevHeight = Content.rect.height;
@@ -299,21 +311,29 @@ namespace UnityExplorer.UI.Widgets
{
int index = CellPool.Count - 1 - (topPoolIndex % (CellPool.Count - 1));
cell.Rect.SetSiblingIndex(index);
+
+ if (bottomPoolIndex == index - 1)
+ bottomPoolIndex++;
}
}
RefreshCells(true);
+ //ExplorerCore.Log("Anchor: " + Content.localPosition.y + ", prev: " + prevAnchor);
+ //ExplorerCore.Log("Height: " + Content.rect.height + ", prev:" + prevHeight);
+
if (Content.localPosition.y != prevAnchor)
{
var diff = Content.localPosition.y - prevAnchor;
Content.localPosition = new Vector3(Content.localPosition.x, Content.localPosition.y - diff);
}
- ScrollRect.UpdatePrevData();
-
- SetScrollBounds();
- UpdateSliderHandle(true);
+ if (Content.rect.height != prevHeight)
+ {
+ var diff = Content.rect.height - prevHeight;
+ //ExplorerCore.Log("Height diff: " + diff);
+ //Content.localPosition = new Vector3(Content.localPosition.x, Content.localPosition.y - diff);
+ }
return true;
}
@@ -413,6 +433,16 @@ namespace UnityExplorer.UI.Widgets
ScrollRect.UpdatePrevData();
}
+ private void RefreshCellHeightsFast()
+ {
+ var enumerator = GetPoolEnumerator();
+ while (enumerator.MoveNext())
+ {
+ var curr = enumerator.Current;
+ HeightCache.SetIndex(curr.dataIndex, CellPool[curr.cellIndex].Rect.rect.height);
+ }
+ }
+
private void SetCell(T cachedCell, int dataIndex)
{
cachedCell.Enable();
@@ -432,6 +462,8 @@ namespace UnityExplorer.UI.Widgets
if (InputManager.MouseScrollDelta != Vector2.zero)
ScrollRect.StopMovement();
+ RefreshCellHeightsFast();
+
SetRecycleViewBounds(true);
float yChange = ((Vector2)ScrollRect.content.localPosition - prevAnchoredPos).y;
@@ -458,7 +490,7 @@ namespace UnityExplorer.UI.Widgets
SetScrollBounds();
//WritingLocked = true;
- UpdateSliderHandle();
+ UpdateSliderHandle(true);
}
private bool ShouldRecycleTop => GetCellExtent(CellPool[topPoolIndex].Rect) > RecycleViewBounds.x
@@ -598,6 +630,8 @@ namespace UnityExplorer.UI.Widgets
ScrollRect.StopMovement();
+ RefreshCellHeightsFast();
+
// normalize the scroll position for the scroll bounds.
// this translates the value into saying "point at the center of the height of the viewport"
var scrollHeight = NormalizedScrollBounds.y - NormalizedScrollBounds.x;
@@ -630,52 +664,49 @@ namespace UnityExplorer.UI.Widgets
// check if our pool indices contain the desired index. If so, rotate and set
if (bottomDataIndex == desiredBottomIndex)
{
- // cells will be the same, do nothing?
+ // cells will be the same, do nothing
+ }
+ else if (TopDataIndex > poolStartIndex && TopDataIndex < desiredBottomIndex)
+ {
+ // top cell falls within the new range, rotate around that
+ int rotate = TopDataIndex - poolStartIndex;
+ for (int i = 0; i < rotate; i++)
+ {
+ CellPool[bottomPoolIndex].Rect.SetAsFirstSibling();
+
+ //set new indices
+ topPoolIndex = bottomPoolIndex;
+ bottomPoolIndex = (bottomPoolIndex - 1 + CellPool.Count) % CellPool.Count;
+ bottomDataIndex--;
+
+ SetCell(CellPool[topPoolIndex], TopDataIndex);
+ }
+ }
+ else if (bottomDataIndex > poolStartIndex && bottomDataIndex < desiredBottomIndex)
+ {
+ // bottom cells falls within the new range, rotate around that
+ int rotate = desiredBottomIndex - bottomDataIndex;
+ for (int i = 0; i < rotate; i++)
+ {
+ CellPool[topPoolIndex].Rect.SetAsLastSibling();
+
+ //set new indices
+ bottomPoolIndex = topPoolIndex;
+ topPoolIndex = (topPoolIndex + 1) % CellPool.Count;
+ bottomDataIndex++;
+
+ SetCell(CellPool[bottomPoolIndex], bottomDataIndex);
+ }
}
else
{
- if (TopDataIndex > poolStartIndex && TopDataIndex < desiredBottomIndex)
+ bottomDataIndex = desiredBottomIndex;
+ var enumerator = GetPoolEnumerator();
+ while (enumerator.MoveNext())
{
- // top cell falls within the new range, rotate around that
- int rotate = TopDataIndex - poolStartIndex;
- for (int i = 0; i < rotate; i++)
- {
- CellPool[bottomPoolIndex].Rect.SetAsFirstSibling();
-
- //set new indices
- topPoolIndex = bottomPoolIndex;
- bottomPoolIndex = (bottomPoolIndex - 1 + CellPool.Count) % CellPool.Count;
- bottomDataIndex--;
-
- SetCell(CellPool[topPoolIndex], TopDataIndex);
- }
- }
- else if (bottomDataIndex > poolStartIndex && bottomDataIndex < desiredBottomIndex)
- {
- // bottom cells falls within the new range, rotate around that
- int rotate = desiredBottomIndex - bottomDataIndex;
- for (int i = 0; i < rotate; i++)
- {
- CellPool[topPoolIndex].Rect.SetAsLastSibling();
-
- //set new indices
- bottomPoolIndex = topPoolIndex;
- topPoolIndex = (topPoolIndex + 1) % CellPool.Count;
- bottomDataIndex++;
-
- SetCell(CellPool[bottomPoolIndex], bottomDataIndex);
- }
- }
- else
- {
- bottomDataIndex = desiredBottomIndex;
- var enumerator = GetPoolEnumerator();
- while (enumerator.MoveNext())
- {
- var curr = enumerator.Current;
- var cell = CellPool[curr.cellIndex];
- SetCell(cell, curr.dataIndex);
- }
+ var curr = enumerator.Current;
+ var cell = CellPool[curr.cellIndex];
+ SetCell(cell, curr.dataIndex);
}
}
diff --git a/src/UI/Widgets/SliderScrollbar.cs b/src/UI/Widgets/SliderScrollbar.cs
deleted file mode 100644
index f2c4e43..0000000
--- a/src/UI/Widgets/SliderScrollbar.cs
+++ /dev/null
@@ -1,155 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using UnityEngine;
-using UnityEngine.Events;
-using UnityEngine.UI;
-using UnityExplorer;
-using UnityExplorer.Core;
-using UnityExplorer.UI;
-using UnityExplorer.UI.Models;
-
-namespace UnityExplorer.UI.Utility
-{
- // Basically just to fix an issue with Scrollbars, instead we use a Slider as the scrollbar.
- public class SliderScrollbar : UIBehaviourModel
- {
- public bool IsActive { get; private set; }
-
- public override GameObject UIRoot
- {
- get
- {
- if (m_slider)
- return m_slider.gameObject;
- return null;
- }
- }
-
- public event Action OnValueChanged;
-
- internal readonly Scrollbar m_scrollbar;
- internal readonly Slider m_slider;
- internal readonly RectTransform m_scrollRect;
-
- internal InputFieldScroller m_parentInputScroller;
-
- public SliderScrollbar(Scrollbar scrollbar, Slider slider)
- {
- this.m_scrollbar = scrollbar;
- this.m_slider = slider;
- this.m_scrollRect = scrollbar.transform.parent.GetComponent();
-
- this.m_scrollbar.onValueChanged.AddListener(this.OnScrollbarValueChanged);
- this.m_slider.onValueChanged.AddListener(this.OnSliderValueChanged);
-
- this.RefreshVisibility();
- this.m_slider.Set(1f, false);
- }
-
- public override void Update()
- {
- this.RefreshVisibility();
- }
-
- internal void RefreshVisibility()
- {
- if (!m_slider.gameObject.activeInHierarchy)
- {
- IsActive = false;
- return;
- }
-
- bool shouldShow = !Mathf.Approximately(this.m_scrollbar.size, 1);
- //var obj = this.m_slider.handleRect.gameObject;
-
- if (IsActive != shouldShow)
- {
- IsActive = shouldShow;
- m_slider.interactable = shouldShow;
-
- if (IsActive)
- this.m_slider.Set(this.m_scrollbar.value, false);
- else
- m_slider.Set(1f, false);
- }
- }
-
- public void OnScrollbarValueChanged(float _value)
- {
- if (this.m_slider.value != _value)
- this.m_slider.Set(_value, false);
- OnValueChanged?.Invoke(_value);
- }
-
- public void OnSliderValueChanged(float _value)
- {
- this.m_scrollbar.value = _value;
- OnValueChanged?.Invoke(_value);
- }
-
- #region UI CONSTRUCTION
-
- public static GameObject CreateSliderScrollbar(GameObject parent, out Slider slider)
- {
- GameObject sliderObj = UIFactory.CreateUIObject("SliderScrollbar", parent, UIFactory._smallElementSize);
-
- GameObject bgObj = UIFactory.CreateUIObject("Background", sliderObj);
- GameObject handleSlideAreaObj = UIFactory.CreateUIObject("Handle Slide Area", sliderObj);
- GameObject handleObj = UIFactory.CreateUIObject("Handle", handleSlideAreaObj);
-
- Image bgImage = bgObj.AddComponent();
- bgImage.type = Image.Type.Sliced;
- bgImage.color = new Color(0.1f, 0.1f, 0.1f, 1.0f);
-
- RectTransform bgRect = bgObj.GetComponent();
- bgRect.anchorMin = Vector2.zero;
- bgRect.anchorMax = Vector2.one;
- bgRect.sizeDelta = Vector2.zero;
- bgRect.offsetMax = new Vector2(0f, 0f);
-
- RectTransform handleSlideRect = handleSlideAreaObj.GetComponent();
- handleSlideRect.anchorMin = new Vector2(0f, 0f);
- handleSlideRect.anchorMax = new Vector2(1f, 1f);
- handleSlideRect.pivot = new Vector2(0.5f, 0.5f);
- handleSlideRect.offsetMin = new Vector2(25f, 30f);
- handleSlideRect.offsetMax = new Vector2(-15f, 0f);
- handleSlideRect.sizeDelta = new Vector2(-20f, -30f);
-
- Image handleImage = handleObj.AddComponent();
- handleImage.color = new Color(0.5f, 0.5f, 0.5f, 1.0f);
-
- var handleRect = handleObj.GetComponent();
- handleRect.sizeDelta = new Vector2(15f, 30f);
- handleRect.offsetMin = new Vector2(-13f, -28f);
- handleRect.offsetMax = new Vector2(2f, -2f);
-
- var sliderBarLayout = sliderObj.AddComponent();
- sliderBarLayout.minWidth = 25;
- sliderBarLayout.flexibleWidth = 0;
- sliderBarLayout.minHeight = 30;
- sliderBarLayout.flexibleHeight = 5000;
-
- slider = sliderObj.AddComponent();
- slider.handleRect = handleObj.GetComponent();
- slider.targetGraphic = handleImage;
- slider.direction = Slider.Direction.BottomToTop;
-
- RuntimeProvider.Instance.SetColorBlock(slider,
- new Color(0.4f, 0.4f, 0.4f),
- new Color(0.5f, 0.5f, 0.5f),
- new Color(0.3f, 0.3f, 0.3f),
- new Color(0.2f, 0.2f, 0.2f));
-
- return sliderObj;
- }
-
- public override void ConstructUI(GameObject parent)
- {
- throw new NotImplementedException();
- }
-
- #endregion
- }
-}
\ No newline at end of file
diff --git a/src/UnityExplorer.csproj b/src/UnityExplorer.csproj
index 4707f44..d46ba31 100644
--- a/src/UnityExplorer.csproj
+++ b/src/UnityExplorer.csproj
@@ -230,6 +230,7 @@
+
@@ -241,10 +242,11 @@
-
+
+
@@ -330,7 +332,7 @@
-
+