3.3.0 rewrite

* Huge restructure/rewrite. No real changes to any functionality, just a cleaner and more manageable project.
This commit is contained in:
Sinai
2021-03-30 19:50:04 +11:00
parent f66a04c93f
commit 0555a644b7
90 changed files with 4184 additions and 5635 deletions

View File

@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.UI.InteractiveValues;
namespace UnityExplorer.UI.CacheObject
{
public class CacheConfigEntry : CacheObjectBase
{
public IConfigElement RefConfig { get; }
public override Type FallbackType => RefConfig.ElementType;
public override bool HasEvaluated => true;
public override bool HasParameters => false;
public override bool IsMember => false;
public override bool CanWrite => true;
public CacheConfigEntry(IConfigElement config, GameObject parent)
{
RefConfig = config;
m_parentContent = parent;
config.OnValueChangedNotify += () => { UpdateValue(); };
CreateIValue(config.BoxedValue, config.ElementType);
}
public override void CreateIValue(object value, Type fallbackType)
{
IValue = InteractiveValue.Create(value, fallbackType);
IValue.Owner = this;
IValue.m_mainContentParent = m_rightGroup;
IValue.m_subContentParent = this.m_subContent;
}
public override void UpdateValue()
{
IValue.Value = RefConfig.BoxedValue;
base.UpdateValue();
}
public override void SetValue()
{
RefConfig.BoxedValue = IValue.Value;
ConfigManager.Handler.SaveConfig();
}
internal GameObject m_leftGroup;
internal GameObject m_rightGroup;
internal override void ConstructUI()
{
base.ConstructUI();
var horiGroup = UIFactory.CreateHorizontalGroup(m_mainContent, "ConfigEntryHolder", true, false, true, true, 5, new Vector4(2,2,2,2));
UIFactory.SetLayoutElement(horiGroup, minHeight: 30, flexibleHeight: 0);
// left group
m_leftGroup = UIFactory.CreateHorizontalGroup(horiGroup, "ConfigTitleGroup", false, false, true, true, 4, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(m_leftGroup, minHeight: 25, flexibleHeight: 0, minWidth: 125, flexibleWidth: 200);
// config entry label
var configLabel = UIFactory.CreateLabel(m_leftGroup, "ConfigLabel", this.RefConfig.Name, TextAnchor.MiddleLeft);
var leftRect = configLabel.GetComponent<RectTransform>();
leftRect.anchorMin = Vector2.zero;
leftRect.anchorMax = Vector2.one;
leftRect.offsetMin = Vector2.zero;
leftRect.offsetMax = Vector2.zero;
leftRect.sizeDelta = Vector2.zero;
UIFactory.SetLayoutElement(configLabel.gameObject, minWidth: 250, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0);
// right group
m_rightGroup = UIFactory.CreateVerticalGroup(horiGroup, "ConfigValueGroup", false, false, true, true, 2, new Vector4(4,2,0,0),
new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(m_rightGroup, minHeight: 25, minWidth: 150, flexibleHeight: 0, flexibleWidth: 5000);
if (IValue != null)
{
IValue.m_mainContentParent = m_rightGroup;
IValue.m_subContentParent = this.m_subContent;
}
}
}
}

View File

@ -0,0 +1,57 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.UI;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.InteractiveValues;
namespace UnityExplorer.UI.CacheObject
{
public class CacheEnumerated : CacheObjectBase
{
public override Type FallbackType => ParentEnumeration.m_baseEntryType;
public override bool CanWrite => RefIList != null && ParentEnumeration.Owner.CanWrite;
public int Index { get; set; }
public IList RefIList { get; set; }
public InteractiveEnumerable ParentEnumeration { get; set; }
public CacheEnumerated(int index, InteractiveEnumerable parentEnumeration, IList refIList, GameObject parentContent)
{
this.ParentEnumeration = parentEnumeration;
this.Index = index;
this.RefIList = refIList;
this.m_parentContent = parentContent;
}
public override void CreateIValue(object value, Type fallbackType)
{
IValue = InteractiveValue.Create(value, fallbackType);
IValue.Owner = this;
}
public override void SetValue()
{
RefIList[Index] = IValue.Value;
ParentEnumeration.Value = RefIList;
ParentEnumeration.Owner.SetValue();
}
internal override void ConstructUI()
{
base.ConstructUI();
var rowObj = UIFactory.CreateHorizontalGroup(m_mainContent, "CacheEnumeratedGroup", false, true, true, true, 0, new Vector4(0,0,5,2),
new Color(1, 1, 1, 0));
var indexLabel = UIFactory.CreateLabel(rowObj, "IndexLabel", $"{this.Index}:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(indexLabel.gameObject, minWidth: 20, flexibleWidth: 30, minHeight: 25);
IValue.m_mainContentParent = rowObj;
}
}
}

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using UnityExplorer.UI;
using UnityEngine;
namespace UnityExplorer.UI.CacheObject
{
public class CacheField : CacheMember
{
public override bool IsStatic => (MemInfo as FieldInfo).IsStatic;
public override Type FallbackType => (MemInfo as FieldInfo).FieldType;
public CacheField(FieldInfo fieldInfo, object declaringInstance, GameObject parent) : base(fieldInfo, declaringInstance, parent)
{
CreateIValue(null, fieldInfo.FieldType);
}
public override void UpdateReflection()
{
var fi = MemInfo as FieldInfo;
IValue.Value = fi.GetValue(fi.IsStatic ? null : DeclaringInstance);
m_evaluated = true;
ReflectionException = null;
}
public override void SetValue()
{
var fi = MemInfo as FieldInfo;
fi.SetValue(fi.IsStatic ? null : DeclaringInstance, IValue.Value);
if (this.ParentInspector?.ParentMember != null)
this.ParentInspector.ParentMember.SetValue();
}
}
}

View File

@ -0,0 +1,392 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.Core.Unity;
using UnityExplorer.Core.Runtime;
using UnityExplorer.Core;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.InteractiveValues;
using UnityExplorer.UI.Main.Home.Inspectors.Reflection;
namespace UnityExplorer.UI.CacheObject
{
public abstract class CacheMember : CacheObjectBase
{
public override bool IsMember => true;
public override Type FallbackType { get; }
public ReflectionInspector ParentInspector { get; set; }
public MemberInfo MemInfo { get; set; }
public Type DeclaringType { get; set; }
public object DeclaringInstance { get; set; }
public virtual bool IsStatic { get; private set; }
public string ReflectionException { get; set; }
public override bool CanWrite => m_canWrite ?? GetCanWrite();
private bool? m_canWrite;
public override bool HasParameters => ParamCount > 0;
public virtual int ParamCount => m_arguments.Length;
public override bool HasEvaluated => m_evaluated;
public bool m_evaluated = false;
public bool m_isEvaluating;
public ParameterInfo[] m_arguments = new ParameterInfo[0];
public string[] m_argumentInput = new string[0];
public string NameForFiltering => m_nameForFilter ?? (m_nameForFilter = $"{MemInfo.DeclaringType.Name}.{MemInfo.Name}".ToLower());
private string m_nameForFilter;
public string RichTextName => m_richTextName ?? GetRichTextName();
private string m_richTextName;
public CacheMember(MemberInfo memberInfo, object declaringInstance, GameObject parentContent)
{
MemInfo = memberInfo;
DeclaringType = memberInfo.DeclaringType;
DeclaringInstance = declaringInstance;
this.m_parentContent = parentContent;
DeclaringInstance = ReflectionProvider.Instance.Cast(declaringInstance, DeclaringType);
}
public static bool CanProcessArgs(ParameterInfo[] parameters)
{
foreach (var param in parameters)
{
var pType = param.ParameterType;
if (pType.IsByRef && pType.HasElementType)
pType = pType.GetElementType();
if (pType != null && (pType.IsPrimitive || pType == typeof(string)))
continue;
else
return false;
}
return true;
}
public override void CreateIValue(object value, Type fallbackType)
{
IValue = InteractiveValue.Create(value, fallbackType);
IValue.Owner = this;
IValue.m_mainContentParent = this.m_rightGroup;
IValue.m_subContentParent = this.m_subContent;
}
public override void UpdateValue()
{
if (!HasParameters || m_isEvaluating)
{
try
{
Type baseType = ReflectionUtility.GetType(IValue.Value) ?? FallbackType;
if (!ReflectionProvider.Instance.IsReflectionSupported(baseType))
throw new Exception("Type not supported with reflection");
UpdateReflection();
if (IValue.Value != null)
IValue.Value = IValue.Value.Cast(ReflectionUtility.GetType(IValue.Value));
}
catch (Exception e)
{
ReflectionException = e.ReflectionExToString(true);
}
}
base.UpdateValue();
}
public abstract void UpdateReflection();
public override void SetValue()
{
// no implementation for base class
}
public object[] ParseArguments()
{
if (m_arguments.Length < 1)
return new object[0];
var parsedArgs = new List<object>();
for (int i = 0; i < m_arguments.Length; i++)
{
var input = m_argumentInput[i];
var type = m_arguments[i].ParameterType;
if (type.IsByRef)
type = type.GetElementType();
if (!string.IsNullOrEmpty(input))
{
if (type == typeof(string))
{
parsedArgs.Add(input);
continue;
}
else
{
try
{
var arg = type.GetMethod("Parse", new Type[] { typeof(string) })
.Invoke(null, new object[] { input });
parsedArgs.Add(arg);
continue;
}
catch
{
ExplorerCore.Log($"Could not parse input '{input}' for argument #{i} '{m_arguments[i].Name}' ({type.FullName})");
}
}
}
// No input, see if there is a default value.
if (m_arguments[i].IsOptional)
{
parsedArgs.Add(m_arguments[i].DefaultValue);
continue;
}
// Try add a null arg I guess
parsedArgs.Add(null);
}
return parsedArgs.ToArray();
}
private bool GetCanWrite()
{
if (MemInfo is FieldInfo fi)
m_canWrite = !(fi.IsLiteral && !fi.IsInitOnly);
else if (MemInfo is PropertyInfo pi)
m_canWrite = pi.CanWrite;
else
m_canWrite = false;
return (bool)m_canWrite;
}
private string GetRichTextName()
{
return m_richTextName = SignatureHighlighter.ParseFullSyntax(MemInfo.DeclaringType, false, MemInfo);
}
#region UI
internal float GetMemberLabelWidth(RectTransform scrollRect)
{
var textGenSettings = m_memLabelText.GetGenerationSettings(m_topRowRect.rect.size);
textGenSettings.scaleFactor = InputFieldScroller.canvasScaler.scaleFactor;
var textGen = m_memLabelText.cachedTextGeneratorForLayout;
float preferredWidth = textGen.GetPreferredWidth(RichTextName, textGenSettings);
float max = scrollRect.rect.width * 0.4f;
if (preferredWidth > max) preferredWidth = max;
return preferredWidth < 125f ? 125f : preferredWidth;
}
internal void SetWidths(float labelWidth, float valueWidth)
{
m_leftLayout.preferredWidth = labelWidth;
m_rightLayout.preferredWidth = valueWidth;
}
internal RectTransform m_topRowRect;
internal Text m_memLabelText;
internal GameObject m_leftGroup;
internal LayoutElement m_leftLayout;
internal GameObject m_rightGroup;
internal LayoutElement m_rightLayout;
internal override void ConstructUI()
{
base.ConstructUI();
var topGroupObj = UIFactory.CreateHorizontalGroup(m_mainContent, "CacheMemberGroup", false, false, true, true, 10, new Vector4(0, 0, 3, 3),
new Color(1, 1, 1, 0));
m_topRowRect = topGroupObj.GetComponent<RectTransform>();
UIFactory.SetLayoutElement(topGroupObj, minHeight: 25, flexibleHeight: 0, minWidth: 300, flexibleWidth: 5000);
// left group
m_leftGroup = UIFactory.CreateHorizontalGroup(topGroupObj, "LeftGroup", false, true, true, true, 4, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(m_leftGroup, minHeight: 25, flexibleHeight: 0, minWidth: 125, flexibleWidth: 200);
// member label
m_memLabelText = UIFactory.CreateLabel(m_leftGroup, "MemLabelText", RichTextName, TextAnchor.MiddleLeft);
m_memLabelText.horizontalOverflow = HorizontalWrapMode.Wrap;
var leftRect = m_memLabelText.GetComponent<RectTransform>();
leftRect.anchorMin = Vector2.zero;
leftRect.anchorMax = Vector2.one;
leftRect.offsetMin = Vector2.zero;
leftRect.offsetMax = Vector2.zero;
leftRect.sizeDelta = Vector2.zero;
m_leftLayout = m_memLabelText.gameObject.AddComponent<LayoutElement>();
m_leftLayout.preferredWidth = 125;
m_leftLayout.minHeight = 25;
m_leftLayout.flexibleHeight = 100;
var labelFitter = m_memLabelText.gameObject.AddComponent<ContentSizeFitter>();
labelFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
labelFitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
// right group
m_rightGroup = UIFactory.CreateVerticalGroup(topGroupObj, "RightGroup", false, true, true, true, 2, new Vector4(4,2,0,0),
new Color(1, 1, 1, 0));
m_rightLayout = m_rightGroup.AddComponent<LayoutElement>();
m_rightLayout.minHeight = 25;
m_rightLayout.flexibleHeight = 480;
m_rightLayout.minWidth = 125;
m_rightLayout.flexibleWidth = 5000;
ConstructArgInput(out GameObject argsHolder);
ConstructEvaluateButtons(argsHolder);
IValue.m_mainContentParent = m_rightGroup;
}
internal void ConstructArgInput(out GameObject argsHolder)
{
argsHolder = null;
if (HasParameters)
{
argsHolder = UIFactory.CreateVerticalGroup(m_rightGroup, "ArgsHolder", true, false, true, true, 4, new Color(1, 1, 1, 0));
if (this is CacheMethod cm && cm.GenericArgs.Length > 0)
cm.ConstructGenericArgInput(argsHolder);
if (m_arguments.Length > 0)
{
UIFactory.CreateLabel(argsHolder, "ArgumentsLabel", "Arguments:", TextAnchor.MiddleLeft);
for (int i = 0; i < m_arguments.Length; i++)
AddArgRow(i, argsHolder);
}
argsHolder.SetActive(false);
}
}
internal void AddArgRow(int i, GameObject parent)
{
var arg = m_arguments[i];
var rowObj = UIFactory.CreateHorizontalGroup(parent, "ArgRow", true, false, true, true, 4, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleWidth: 5000);
var argTypeTxt = SignatureHighlighter.ParseFullSyntax(arg.ParameterType, false);
var argLabel = UIFactory.CreateLabel(rowObj, "ArgLabel", $"{argTypeTxt} <color={SignatureHighlighter.LOCAL_ARG}>{arg.Name}</color>",
TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(argLabel.gameObject, minHeight: 25);
var argInputObj = UIFactory.CreateInputField(rowObj, "ArgInput", "...", 14, (int)TextAnchor.MiddleLeft, 1);
UIFactory.SetLayoutElement(argInputObj, flexibleWidth: 1200, preferredWidth: 150, minWidth: 20, minHeight: 25, flexibleHeight: 0);
var argInput = argInputObj.GetComponent<InputField>();
argInput.onValueChanged.AddListener((string val) => { m_argumentInput[i] = val; });
if (arg.IsOptional)
{
var phInput = argInput.placeholder.GetComponent<Text>();
phInput.text = " = " + arg.DefaultValue?.ToString() ?? "null";
}
}
internal void ConstructEvaluateButtons(GameObject argsHolder)
{
if (HasParameters)
{
var evalGroupObj = UIFactory.CreateHorizontalGroup(m_rightGroup, "EvalGroup", false, false, true, true, 5,
default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(evalGroupObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 5000);
var colors = new ColorBlock();
colors.normalColor = new Color(0.4f, 0.4f, 0.4f);
colors.highlightedColor = new Color(0.4f, 0.7f, 0.4f);
colors.pressedColor = new Color(0.3f, 0.3f, 0.3f);
var evalButton = UIFactory.CreateButton(evalGroupObj,
"EvalButton",
$"Evaluate ({ParamCount})",
null,
colors);
UIFactory.SetLayoutElement(evalButton.gameObject, minWidth: 100, minHeight: 22, flexibleWidth: 0);
var evalText = evalButton.GetComponentInChildren<Text>();
var cancelButton = UIFactory.CreateButton(evalGroupObj, "CancelButton", "Close", null, new Color(0.3f, 0.3f, 0.3f));
UIFactory.SetLayoutElement(cancelButton.gameObject, minWidth: 100, minHeight: 22, flexibleWidth: 0);
cancelButton.gameObject.SetActive(false);
evalButton.onClick.AddListener(() =>
{
if (!m_isEvaluating)
{
argsHolder.SetActive(true);
m_isEvaluating = true;
evalText.text = "Evaluate";
colors = evalButton.colors;
colors.normalColor = new Color(0.3f, 0.6f, 0.3f);
evalButton.colors = colors;
cancelButton.gameObject.SetActive(true);
}
else
{
if (this is CacheMethod cm)
cm.Evaluate();
else
UpdateValue();
}
});
cancelButton.onClick.AddListener(() =>
{
cancelButton.gameObject.SetActive(false);
argsHolder.SetActive(false);
m_isEvaluating = false;
evalText.text = $"Evaluate ({ParamCount})";
colors = evalButton.colors;
colors.normalColor = new Color(0.4f, 0.4f, 0.4f);
evalButton.colors = colors;
});
}
else if (this is CacheMethod)
{
// simple method evaluate button
var colors = new ColorBlock();
colors.normalColor = new Color(0.4f, 0.4f, 0.4f);
colors.highlightedColor = new Color(0.4f, 0.7f, 0.4f);
colors.pressedColor = new Color(0.3f, 0.3f, 0.3f);
var evalButton = UIFactory.CreateButton(m_rightGroup, "EvalButton", "Evaluate", () => { (this as CacheMethod).Evaluate(); }, colors);
UIFactory.SetLayoutElement(evalButton.gameObject, minWidth: 100, minHeight: 22, flexibleWidth: 0);
}
}
#endregion
}
}

View File

@ -0,0 +1,173 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI;
using UnityExplorer.Core.Unity;
using UnityExplorer.Core;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.CacheObject
{
public class CacheMethod : CacheMember
{
//private CacheObjectBase m_cachedReturnValue;
public override Type FallbackType => (MemInfo as MethodInfo).ReturnType;
public override bool HasParameters => base.HasParameters || GenericArgs.Length > 0;
public override bool IsStatic => (MemInfo as MethodInfo).IsStatic;
public override int ParamCount => base.ParamCount + m_genericArgInput.Length;
public Type[] GenericArgs { get; private set; }
public Type[][] GenericConstraints { get; private set; }
public string[] m_genericArgInput = new string[0];
public CacheMethod(MethodInfo methodInfo, object declaringInstance, GameObject parent) : base(methodInfo, declaringInstance, parent)
{
GenericArgs = methodInfo.GetGenericArguments();
GenericConstraints = GenericArgs.Select(x => x.GetGenericParameterConstraints())
.Where(x => x != null)
.ToArray();
m_genericArgInput = new string[GenericArgs.Length];
m_arguments = methodInfo.GetParameters();
m_argumentInput = new string[m_arguments.Length];
CreateIValue(null, methodInfo.ReturnType);
}
public override void UpdateReflection()
{
// CacheMethod cannot UpdateValue directly. Need to Evaluate.
}
public void Evaluate()
{
MethodInfo mi;
if (GenericArgs.Length > 0)
{
mi = MakeGenericMethodFromInput();
if (mi == null) return;
}
else
{
mi = MemInfo as MethodInfo;
}
object ret = null;
try
{
ret = mi.Invoke(mi.IsStatic ? null : DeclaringInstance, ParseArguments());
m_evaluated = true;
m_isEvaluating = false;
ReflectionException = null;
}
catch (Exception e)
{
while (e.InnerException != null)
e = e.InnerException;
ExplorerCore.LogWarning($"Exception evaluating: {e.GetType()}, {e.Message}");
ReflectionException = ReflectionUtility.ReflectionExToString(e);
}
IValue.Value = ret;
UpdateValue();
}
private MethodInfo MakeGenericMethodFromInput()
{
var mi = MemInfo as MethodInfo;
var list = new List<Type>();
for (int i = 0; i < GenericArgs.Length; i++)
{
var input = m_genericArgInput[i];
if (ReflectionUtility.GetTypeByName(input) is Type t)
{
if (GenericConstraints[i].Length == 0)
{
list.Add(t);
}
else
{
foreach (var constraint in GenericConstraints[i].Where(x => x != null))
{
if (!constraint.IsAssignableFrom(t))
{
ExplorerCore.LogWarning($"Generic argument #{i}, '{input}' is not assignable from the constraint '{constraint}'!");
return null;
}
}
list.Add(t);
}
}
else
{
ExplorerCore.LogWarning($"Generic argument #{i}, could not get any type by the name of '{input}'!" +
$" Make sure you use the full name including the namespace.");
return null;
}
}
// make into a generic with type list
mi = mi.MakeGenericMethod(list.ToArray());
return mi;
}
#region UI CONSTRUCTION
internal void ConstructGenericArgInput(GameObject parent)
{
UIFactory.CreateLabel(parent, "GenericArgLabel", "Generic Arguments:", TextAnchor.MiddleLeft);
for (int i = 0; i < GenericArgs.Length; i++)
AddGenericArgRow(i, parent);
}
internal void AddGenericArgRow(int i, GameObject parent)
{
var arg = GenericArgs[i];
string constrainTxt = "";
if (this.GenericConstraints[i].Length > 0)
{
foreach (var constraint in this.GenericConstraints[i])
{
if (constrainTxt != "")
constrainTxt += ", ";
constrainTxt += $"{SignatureHighlighter.ParseFullSyntax(constraint, false)}";
}
}
else
constrainTxt = $"Any";
var rowObj = UIFactory.CreateHorizontalGroup(parent, "ArgRowObj", false, true, true, true, 4, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleWidth: 5000);
var argLabelObj = UIFactory.CreateLabel(rowObj, "ArgLabelObj", $"{constrainTxt} <color={SignatureHighlighter.CONST_VAR}>{arg.Name}</color>",
TextAnchor.MiddleLeft);
var argInputObj = UIFactory.CreateInputField(rowObj, "ArgInput", "...", 14, (int)TextAnchor.MiddleLeft, 1);
UIFactory.SetLayoutElement(argInputObj, flexibleWidth: 1200);
var argInput = argInputObj.GetComponent<InputField>();
argInput.onValueChanged.AddListener((string val) => { m_genericArgInput[i] = val; });
}
#endregion
}
}

View File

@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityExplorer.UI;
using UnityExplorer.Core.Unity;
using UnityEngine.UI;
using UnityExplorer.Core;
using UnityExplorer.UI.InteractiveValues;
namespace UnityExplorer.UI.CacheObject
{
public abstract class CacheObjectBase
{
public InteractiveValue IValue;
public virtual bool CanWrite => false;
public virtual bool HasParameters => false;
public virtual bool IsMember => false;
public virtual bool HasEvaluated => true;
public abstract Type FallbackType { get; }
public abstract void CreateIValue(object value, Type fallbackType);
public virtual void Enable()
{
if (!m_constructedUI)
{
ConstructUI();
UpdateValue();
}
m_mainContent.SetActive(true);
m_mainContent.transform.SetAsLastSibling();
}
public virtual void Disable()
{
if (m_mainContent)
m_mainContent.SetActive(false);
}
public void Destroy()
{
if (this.m_mainContent)
GameObject.Destroy(this.m_mainContent);
}
public virtual void UpdateValue()
{
var value = IValue.Value;
// if the type has changed fundamentally, make a new interactivevalue for it
var type = value == null
? FallbackType
: ReflectionUtility.GetType(value);
var ivalueType = InteractiveValue.GetIValueForType(type);
if (ivalueType != IValue.GetType())
{
IValue.OnDestroy();
CreateIValue(value, FallbackType);
m_subContent.SetActive(false);
}
IValue.OnValueUpdated();
IValue.RefreshElementsAfterUpdate();
}
public virtual void SetValue() => throw new NotImplementedException();
#region UI CONSTRUCTION
internal bool m_constructedUI;
internal GameObject m_parentContent;
internal RectTransform m_mainRect;
internal GameObject m_mainContent;
internal GameObject m_subContent;
// Make base UI holder for CacheObject, this doesnt actually display anything.
internal virtual void ConstructUI()
{
m_constructedUI = true;
m_mainContent = UIFactory.CreateVerticalGroup(m_parentContent, "CacheObjectBase.MainContent", true, true, true, true, 0, default,
new Color(0.1f, 0.1f, 0.1f));
m_mainRect = m_mainContent.GetComponent<RectTransform>();
m_mainRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 25);
UIFactory.SetLayoutElement(m_mainContent, minHeight: 25, flexibleHeight: 9999, minWidth: 200, flexibleWidth: 5000);
// subcontent
m_subContent = UIFactory.CreateVerticalGroup(m_mainContent, "CacheObjectBase.SubContent", true, false, true, true, 0, default,
new Color(0.085f, 0.085f, 0.085f));
UIFactory.SetLayoutElement(m_subContent, minHeight: 30, flexibleHeight: 9999, minWidth: 125, flexibleWidth: 9000);
m_subContent.SetActive(false);
IValue.m_subContentParent = m_subContent;
}
#endregion
}
}

View File

@ -0,0 +1,64 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityExplorer.UI;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.UI.InteractiveValues;
namespace UnityExplorer.UI.CacheObject
{
public enum PairTypes
{
Key,
Value
}
public class CachePaired : CacheObjectBase
{
public override Type FallbackType => PairType == PairTypes.Key
? ParentDictionary.m_typeOfKeys
: ParentDictionary.m_typeofValues;
public override bool CanWrite => false; // todo?
public PairTypes PairType;
public int Index { get; private set; }
public InteractiveDictionary ParentDictionary { get; private set; }
internal IDictionary RefIDict;
public CachePaired(int index, InteractiveDictionary parentDict, IDictionary refIDict, PairTypes pairType, GameObject parentContent)
{
Index = index;
ParentDictionary = parentDict;
RefIDict = refIDict;
this.PairType = pairType;
this.m_parentContent = parentContent;
}
public override void CreateIValue(object value, Type fallbackType)
{
IValue = InteractiveValue.Create(value, fallbackType);
IValue.Owner = this;
}
#region UI CONSTRUCTION
internal override void ConstructUI()
{
base.ConstructUI();
var rowObj = UIFactory.CreateHorizontalGroup(m_mainContent, "PairedGroup", false, false, true, true, 0, new Vector4(0,0,5,2),
new Color(1, 1, 1, 0));
var indexLabel = UIFactory.CreateLabel(rowObj, "IndexLabel", $"{this.PairType} {this.Index}:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(indexLabel.gameObject, minWidth: 80, flexibleWidth: 30, minHeight: 25);
IValue.m_mainContentParent = rowObj;
}
#endregion
}
}

View File

@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using UnityExplorer.UI;
using UnityExplorer.Core.Unity;
using UnityEngine;
namespace UnityExplorer.UI.CacheObject
{
public class CacheProperty : CacheMember
{
public override Type FallbackType => (MemInfo as PropertyInfo).PropertyType;
public override bool IsStatic => (MemInfo as PropertyInfo).GetAccessors(true)[0].IsStatic;
public CacheProperty(PropertyInfo propertyInfo, object declaringInstance, GameObject parent) : base(propertyInfo, declaringInstance, parent)
{
this.m_arguments = propertyInfo.GetIndexParameters();
this.m_argumentInput = new string[m_arguments.Length];
CreateIValue(null, propertyInfo.PropertyType);
}
public override void UpdateReflection()
{
if (HasParameters && !m_isEvaluating)
{
// Need to enter parameters first.
return;
}
var pi = MemInfo as PropertyInfo;
if (pi.CanRead)
{
var target = pi.GetAccessors(true)[0].IsStatic ? null : DeclaringInstance;
IValue.Value = pi.GetValue(target, ParseArguments());
m_evaluated = true;
ReflectionException = null;
}
else
{
if (FallbackType == typeof(string))
{
IValue.Value = "";
}
else if (FallbackType.IsPrimitive)
{
IValue.Value = Activator.CreateInstance(FallbackType);
}
m_evaluated = true;
ReflectionException = null;
}
}
public override void SetValue()
{
var pi = MemInfo as PropertyInfo;
var target = pi.GetAccessors()[0].IsStatic ? null : DeclaringInstance;
pi.SetValue(target, IValue.Value, ParseArguments());
if (this.ParentInspector?.ParentMember != null)
this.ParentInspector.ParentMember.SetValue();
}
}
}

View File

@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI;
using UnityExplorer.UI.CacheObject;
namespace UnityExplorer.UI.InteractiveValues
{
public class InteractiveBool : InteractiveValue
{
public InteractiveBool(object value, Type valueType) : base(value, valueType) { }
public override bool HasSubContent => false;
public override bool SubContentWanted => false;
public override bool WantInspectBtn => false;
internal Toggle m_toggle;
internal Button m_applyBtn;
public override void OnValueUpdated()
{
base.OnValueUpdated();
}
public override void RefreshUIForValue()
{
GetDefaultLabel();
if (Owner.HasEvaluated)
{
var val = (bool)Value;
if (Owner.CanWrite)
{
if (!m_toggle.gameObject.activeSelf)
m_toggle.gameObject.SetActive(true);
if (!m_applyBtn.gameObject.activeSelf)
m_applyBtn.gameObject.SetActive(true);
if (val != m_toggle.isOn)
m_toggle.isOn = val;
}
var color = val
? "6bc981" // on
: "c96b6b"; // off
m_baseLabel.text = $"<color=#{color}>{val}</color>";
}
else
{
m_baseLabel.text = DefaultLabel;
}
}
public override void OnException(CacheMember member)
{
base.OnException(member);
if (Owner.CanWrite)
{
if (m_toggle.gameObject.activeSelf)
m_toggle.gameObject.SetActive(false);
if (m_applyBtn.gameObject.activeSelf)
m_applyBtn.gameObject.SetActive(false);
}
}
internal void OnToggleValueChanged(bool val)
{
Value = val;
RefreshUIForValue();
}
public override void ConstructUI(GameObject parent, GameObject subGroup)
{
base.ConstructUI(parent, subGroup);
var baseLayout = m_baseLabel.gameObject.GetComponent<LayoutElement>();
baseLayout.flexibleWidth = 0;
baseLayout.minWidth = 50;
if (Owner.CanWrite)
{
var toggleObj = UIFactory.CreateToggle(m_valueContent, "InteractiveBoolToggle", out m_toggle, out _, new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutElement(toggleObj, minWidth: 24);
m_toggle.onValueChanged.AddListener(OnToggleValueChanged);
m_baseLabel.transform.SetAsLastSibling();
m_applyBtn = UIFactory.CreateButton(m_valueContent,
"ApplyButton",
"Apply",
() => { Owner.SetValue(); },
new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(m_applyBtn.gameObject, minWidth: 50, minHeight: 25, flexibleWidth: 0);
toggleObj.SetActive(false);
m_applyBtn.gameObject.SetActive(false);
}
}
}
}

View File

@ -0,0 +1,306 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI;
using System.Reflection;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.Core;
using UnityExplorer.UI.Utility;
#if CPP
using CppDictionary = Il2CppSystem.Collections.IDictionary;
#endif
namespace UnityExplorer.UI.InteractiveValues
{
public class InteractiveDictionary : InteractiveValue
{
public InteractiveDictionary(object value, Type valueType) : base(value, valueType)
{
if (valueType.IsGenericType)
{
var gArgs = valueType.GetGenericArguments();
m_typeOfKeys = gArgs[0];
m_typeofValues = gArgs[1];
}
else
{
m_typeOfKeys = typeof(object);
m_typeofValues = typeof(object);
}
}
public override bool WantInspectBtn => false;
public override bool HasSubContent => true;
public override bool SubContentWanted
{
get
{
if (m_recacheWanted)
return true;
else return m_entries.Count > 0;
}
}
internal IDictionary RefIDictionary;
#if CPP
internal CppDictionary RefCppDictionary;
#else
internal IDictionary RefCppDictionary = null;
#endif
internal Type m_typeOfKeys;
internal Type m_typeofValues;
internal readonly List<KeyValuePair<CachePaired, CachePaired>> m_entries
= new List<KeyValuePair<CachePaired, CachePaired>>();
internal readonly KeyValuePair<CachePaired, CachePaired>[] m_displayedEntries
= new KeyValuePair<CachePaired, CachePaired>[ConfigManager.Default_Page_Limit.Value];
internal bool m_recacheWanted = true;
public override void OnDestroy()
{
base.OnDestroy();
}
public override void OnValueUpdated()
{
RefIDictionary = Value as IDictionary;
#if CPP
try { RefCppDictionary = (Value as Il2CppSystem.Object).TryCast<CppDictionary>(); }
catch { }
#endif
if (m_subContentParent.activeSelf)
{
GetCacheEntries();
RefreshDisplay();
}
else
m_recacheWanted = true;
base.OnValueUpdated();
}
internal void OnPageTurned()
{
RefreshDisplay();
}
public override void RefreshUIForValue()
{
GetDefaultLabel();
if (Value != null)
{
string count = "?";
if (m_recacheWanted && RefIDictionary != null)
count = RefIDictionary.Count.ToString();
else if (!m_recacheWanted)
count = m_entries.Count.ToString();
m_baseLabel.text = $"[{count}] {m_richValueType}";
}
else
{
m_baseLabel.text = DefaultLabel;
}
}
public void GetCacheEntries()
{
if (m_entries.Any())
{
// maybe improve this, probably could be more efficient i guess
foreach (var pair in m_entries)
{
pair.Key.Destroy();
pair.Value.Destroy();
}
m_entries.Clear();
}
#if CPP
if (RefIDictionary == null && Value != null)
RefIDictionary = EnumerateWithReflection();
#endif
if (RefIDictionary != null)
{
int index = 0;
foreach (var key in RefIDictionary.Keys)
{
var value = RefIDictionary[key];
var cacheKey = new CachePaired(index, this, this.RefIDictionary, PairTypes.Key, m_listContent);
cacheKey.CreateIValue(key, this.m_typeOfKeys);
cacheKey.Disable();
var cacheValue = new CachePaired(index, this, this.RefIDictionary, PairTypes.Value, m_listContent);
cacheValue.CreateIValue(value, this.m_typeofValues);
cacheValue.Disable();
//holder.SetActive(false);
m_entries.Add(new KeyValuePair<CachePaired, CachePaired>(cacheKey, cacheValue));
index++;
}
}
RefreshDisplay();
}
public void RefreshDisplay()
{
var entries = m_entries;
m_pageHandler.ListCount = entries.Count;
for (int i = 0; i < m_displayedEntries.Length; i++)
{
var entry = m_displayedEntries[i];
if (entry.Key != null && entry.Value != null)
{
//m_rowHolders[i].SetActive(false);
entry.Key.Disable();
entry.Value.Disable();
}
else
break;
}
if (entries.Count < 1)
return;
foreach (var itemIndex in m_pageHandler)
{
if (itemIndex >= entries.Count)
break;
var entry = entries[itemIndex];
m_displayedEntries[itemIndex - m_pageHandler.StartIndex] = entry;
//m_rowHolders[itemIndex].SetActive(true);
entry.Key.Enable();
entry.Value.Enable();
}
//UpdateSubcontentHeight();
}
internal override void OnToggleSubcontent(bool active)
{
base.OnToggleSubcontent(active);
if (active && m_recacheWanted)
{
m_recacheWanted = false;
GetCacheEntries();
RefreshUIForValue();
}
RefreshDisplay();
}
#region CPP fixes
#if CPP
// temp fix for Il2Cpp IDictionary until interfaces are fixed
private IDictionary EnumerateWithReflection()
{
var valueType = ReflectionUtility.GetType(Value);
// get keys and values
var keys = valueType.GetProperty("Keys").GetValue(Value, null);
var values = valueType.GetProperty("Values").GetValue(Value, null);
// create lists to hold them
var keyList = new List<object>();
var valueList = new List<object>();
// store entries with reflection
EnumerateCollection(keys, keyList);
EnumerateCollection(values, valueList);
// make actual mono dictionary
var dict = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>)
.MakeGenericType(m_typeOfKeys, m_typeofValues));
// finally iterate into mono dictionary
for (int i = 0; i < keyList.Count; i++)
dict.Add(keyList[i], valueList[i]);
return dict;
}
private void EnumerateCollection(object collection, List<object> list)
{
// invoke GetEnumerator
var enumerator = collection.GetType().GetMethod("GetEnumerator").Invoke(collection, null);
// get the type of it
var enumeratorType = enumerator.GetType();
// reflect MoveNext and Current
var moveNext = enumeratorType.GetMethod("MoveNext");
var current = enumeratorType.GetProperty("Current");
// iterate
while ((bool)moveNext.Invoke(enumerator, null))
{
list.Add(current.GetValue(enumerator, null));
}
}
#endif
#endregion
#region UI CONSTRUCTION
internal GameObject m_listContent;
internal LayoutElement m_listLayout;
internal PageHandler m_pageHandler;
//internal List<GameObject> m_rowHolders = new List<GameObject>();
public override void ConstructUI(GameObject parent, GameObject subGroup)
{
base.ConstructUI(parent, subGroup);
}
public override void ConstructSubcontent()
{
base.ConstructSubcontent();
m_pageHandler = new PageHandler(null);
m_pageHandler.ConstructUI(m_subContentParent);
m_pageHandler.OnPageChanged += OnPageTurned;
m_listContent = UIFactory.CreateVerticalGroup(m_subContentParent, "DictionaryContent", true, true, true, true, 2, new Vector4(5,5,5,5),
new Color(0.08f, 0.08f, 0.08f));
var scrollRect = m_listContent.GetComponent<RectTransform>();
scrollRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 0);
m_listLayout = Owner.m_mainContent.GetComponent<LayoutElement>();
m_listLayout.minHeight = 25;
m_listLayout.flexibleHeight = 0;
Owner.m_mainRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 25);
var contentFitter = m_listContent.AddComponent<ContentSizeFitter>();
contentFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
}
#endregion
}
}

View File

@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI;
namespace UnityExplorer.UI.InteractiveValues
{
public class InteractiveEnum : InteractiveValue
{
internal static Dictionary<Type, KeyValuePair<int,string>[]> s_enumNamesCache = new Dictionary<Type, KeyValuePair<int, string>[]>();
public InteractiveEnum(object value, Type valueType) : base(value, valueType)
{
GetNames();
}
public override bool HasSubContent => true;
public override bool SubContentWanted => Owner.CanWrite;
public override bool WantInspectBtn => false;
internal KeyValuePair<int,string>[] m_values = new KeyValuePair<int, string>[0];
internal Type m_lastEnumType;
internal void GetNames()
{
var type = Value?.GetType() ?? FallbackType;
if (m_lastEnumType == type)
return;
m_lastEnumType = type;
if (m_subContentConstructed)
{
DestroySubContent();
}
if (!s_enumNamesCache.ContainsKey(type))
{
// using GetValues not GetNames, to catch instances of weird enums (eg CameraClearFlags)
var values = Enum.GetValues(type);
var list = new List<KeyValuePair<int, string>>();
var set = new HashSet<string>();
foreach (var value in values)
{
var name = value.ToString();
if (set.Contains(name))
continue;
set.Add(name);
var backingType = Enum.GetUnderlyingType(type);
int intValue;
try
{
// this approach is necessary, a simple '(int)value' is not sufficient.
var unbox = Convert.ChangeType(value, backingType);
intValue = (int)Convert.ChangeType(unbox, typeof(int));
}
catch (Exception ex)
{
ExplorerCore.LogWarning("[InteractiveEnum] Could not Unbox underlying type " + backingType.Name + " from " + type.FullName);
ExplorerCore.Log(ex.ToString());
continue;
}
list.Add(new KeyValuePair<int, string>(intValue, name));
}
s_enumNamesCache.Add(type, list.ToArray());
}
m_values = s_enumNamesCache[type];
}
public override void OnValueUpdated()
{
GetNames();
base.OnValueUpdated();
}
public override void RefreshUIForValue()
{
base.RefreshUIForValue();
if (m_subContentConstructed)
{
m_dropdownText.text = Value?.ToString() ?? "<no value set>";
}
}
internal override void OnToggleSubcontent(bool toggle)
{
base.OnToggleSubcontent(toggle);
RefreshUIForValue();
}
private void SetValueFromDropdown()
{
var type = Value?.GetType() ?? FallbackType;
var index = m_dropdown.value;
var value = Enum.Parse(type, s_enumNamesCache[type][index].Value);
if (value != null)
{
Value = value;
Owner.SetValue();
RefreshUIForValue();
}
}
internal Dropdown m_dropdown;
internal Text m_dropdownText;
public override void ConstructUI(GameObject parent, GameObject subGroup)
{
base.ConstructUI(parent, subGroup);
}
public override void ConstructSubcontent()
{
base.ConstructSubcontent();
if (Owner.CanWrite)
{
var groupObj = UIFactory.CreateHorizontalGroup(m_subContentParent, "InteractiveEnumGroup", false, true, true, true, 5,
new Vector4(3,3,3,3),new Color(1, 1, 1, 0));
// apply button
var apply = UIFactory.CreateButton(groupObj, "ApplyButton", "Apply", SetValueFromDropdown, new Color(0.3f, 0.3f, 0.3f));
UIFactory.SetLayoutElement(apply.gameObject, minHeight: 25, minWidth: 50);
// dropdown
var dropdownObj = UIFactory.CreateDropdown(groupObj, out m_dropdown, "<notset>", 14, null);
UIFactory.SetLayoutElement(dropdownObj, minWidth: 150, minHeight: 25, flexibleWidth: 120);
foreach (var kvp in m_values)
{
m_dropdown.options.Add(new Dropdown.OptionData
{
text = $"{kvp.Key}: {kvp.Value}"
});
}
m_dropdownText = m_dropdown.transform.Find("Label").GetComponent<Text>();
}
}
}
}

View File

@ -0,0 +1,279 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.InteractiveValues
{
public class InteractiveEnumerable : InteractiveValue
{
public InteractiveEnumerable(object value, Type valueType) : base(value, valueType)
{
if (valueType.IsGenericType)
m_baseEntryType = valueType.GetGenericArguments()[0];
else
m_baseEntryType = typeof(object);
}
public override bool WantInspectBtn => false;
public override bool HasSubContent => true;
public override bool SubContentWanted
{
get
{
if (m_recacheWanted)
return true;
else return m_entries.Count > 0;
}
}
internal IEnumerable RefIEnumerable;
internal IList RefIList;
#if CPP
internal Il2CppSystem.Collections.ICollection CppICollection;
#else
internal ICollection CppICollection = null;
#endif
internal readonly Type m_baseEntryType;
internal readonly List<CacheEnumerated> m_entries = new List<CacheEnumerated>();
internal readonly CacheEnumerated[] m_displayedEntries = new CacheEnumerated[ConfigManager.Default_Page_Limit.Value];
internal bool m_recacheWanted = true;
public override void OnValueUpdated()
{
RefIEnumerable = Value as IEnumerable;
RefIList = Value as IList;
#if CPP
if (Value != null && RefIList == null)
{
try { CppICollection = (Value as Il2CppSystem.Object).TryCast<Il2CppSystem.Collections.ICollection>(); }
catch { }
}
#endif
if (m_subContentParent.activeSelf)
{
GetCacheEntries();
RefreshDisplay();
}
else
m_recacheWanted = true;
base.OnValueUpdated();
}
public override void OnException(CacheMember member)
{
base.OnException(member);
}
private void OnPageTurned()
{
RefreshDisplay();
}
public override void RefreshUIForValue()
{
GetDefaultLabel();
if (Value != null)
{
string count = "?";
if (m_recacheWanted && (RefIList != null || CppICollection != null))
count = RefIList?.Count.ToString() ?? CppICollection.Count.ToString();
else if (!m_recacheWanted)
count = m_entries.Count.ToString();
m_baseLabel.text = $"[{count}] {m_richValueType}";
}
else
{
m_baseLabel.text = DefaultLabel;
}
}
public void GetCacheEntries()
{
if (m_entries.Any())
{
// maybe improve this, probably could be more efficient i guess
foreach (var entry in m_entries)
entry.Destroy();
m_entries.Clear();
}
#if CPP
if (RefIEnumerable == null && Value != null)
RefIEnumerable = EnumerateWithReflection();
#endif
if (RefIEnumerable != null)
{
int index = 0;
foreach (var entry in RefIEnumerable)
{
var cache = new CacheEnumerated(index, this, RefIList, this.m_listContent);
cache.CreateIValue(entry, m_baseEntryType);
m_entries.Add(cache);
cache.Disable();
index++;
}
}
RefreshDisplay();
}
public void RefreshDisplay()
{
var entries = m_entries;
m_pageHandler.ListCount = entries.Count;
for (int i = 0; i < m_displayedEntries.Length; i++)
{
var entry = m_displayedEntries[i];
if (entry != null)
entry.Disable();
else
break;
}
if (entries.Count < 1)
return;
foreach (var itemIndex in m_pageHandler)
{
if (itemIndex >= entries.Count)
break;
CacheEnumerated entry = entries[itemIndex];
m_displayedEntries[itemIndex - m_pageHandler.StartIndex] = entry;
entry.Enable();
}
//UpdateSubcontentHeight();
}
internal override void OnToggleSubcontent(bool active)
{
base.OnToggleSubcontent(active);
if (active && m_recacheWanted)
{
m_recacheWanted = false;
GetCacheEntries();
RefreshUIForValue();
}
RefreshDisplay();
}
#region CPP Helpers
#if CPP
// some temp fixes for Il2Cpp IEnumerables until interfaces are fixed
internal static readonly Dictionary<Type, MethodInfo> s_getEnumeratorMethods = new Dictionary<Type, MethodInfo>();
internal static readonly Dictionary<Type, EnumeratorInfo> s_enumeratorInfos = new Dictionary<Type, EnumeratorInfo>();
internal class EnumeratorInfo
{
internal MethodInfo moveNext;
internal PropertyInfo current;
}
private IEnumerable EnumerateWithReflection()
{
if (Value == null)
return null;
// new test
var CppEnumerable = (Value as Il2CppSystem.Object)?.TryCast<Il2CppSystem.Collections.IEnumerable>();
if (CppEnumerable != null)
{
var type = Value.GetType();
if (!s_getEnumeratorMethods.ContainsKey(type))
s_getEnumeratorMethods.Add(type, type.GetMethod("GetEnumerator"));
var enumerator = s_getEnumeratorMethods[type].Invoke(Value, null);
var enumeratorType = enumerator.GetType();
if (!s_enumeratorInfos.ContainsKey(enumeratorType))
{
s_enumeratorInfos.Add(enumeratorType, new EnumeratorInfo
{
current = enumeratorType.GetProperty("Current"),
moveNext = enumeratorType.GetMethod("MoveNext"),
});
}
var info = s_enumeratorInfos[enumeratorType];
// iterate
var list = new List<object>();
while ((bool)info.moveNext.Invoke(enumerator, null))
list.Add(info.current.GetValue(enumerator));
return list;
}
return null;
}
#endif
#endregion
#region UI CONSTRUCTION
internal GameObject m_listContent;
internal LayoutElement m_listLayout;
internal PageHandler m_pageHandler;
public override void ConstructUI(GameObject parent, GameObject subGroup)
{
base.ConstructUI(parent, subGroup);
}
public override void ConstructSubcontent()
{
base.ConstructSubcontent();
m_pageHandler = new PageHandler(null);
m_pageHandler.ConstructUI(m_subContentParent);
m_pageHandler.OnPageChanged += OnPageTurned;
m_listContent = UIFactory.CreateVerticalGroup(this.m_subContentParent, "EnumerableContent", true, true, true, true, 2, new Vector4(5,5,5,5),
new Color(0.08f, 0.08f, 0.08f));
var scrollRect = m_listContent.GetComponent<RectTransform>();
scrollRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 0);
m_listLayout = Owner.m_mainContent.GetComponent<LayoutElement>();
m_listLayout.minHeight = 25;
m_listLayout.flexibleHeight = 0;
Owner.m_mainRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 25);
var contentFitter = m_listContent.AddComponent<ContentSizeFitter>();
contentFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
}
#endregion
}
}

View File

@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI;
namespace UnityExplorer.UI.InteractiveValues
{
public class InteractiveFlags : InteractiveEnum
{
public InteractiveFlags(object value, Type valueType) : base(value, valueType)
{
m_toggles = new Toggle[m_values.Length];
m_enabledFlags = new bool[m_values.Length];
}
public override bool HasSubContent => true;
public override bool SubContentWanted => Owner.CanWrite;
public override bool WantInspectBtn => false;
internal bool[] m_enabledFlags;
internal Toggle[] m_toggles;
public override void OnValueUpdated()
{
base.OnValueUpdated();
if (Owner.CanWrite)
{
var enabledNames = new List<string>();
var enabled = Value?.ToString().Split(',').Select(it => it.Trim());
if (enabled != null)
enabledNames.AddRange(enabled);
for (int i = 0; i < m_values.Length; i++)
{
m_enabledFlags[i] = enabledNames.Contains(m_values[i].Value);
}
}
}
public override void RefreshUIForValue()
{
GetDefaultLabel();
m_baseLabel.text = DefaultLabel;
if (m_subContentConstructed)
{
for (int i = 0; i < m_values.Length; i++)
{
var toggle = m_toggles[i];
if (toggle.isOn != m_enabledFlags[i])
toggle.isOn = m_enabledFlags[i];
}
}
}
private void SetValueFromToggles()
{
string val = "";
for (int i = 0; i < m_values.Length; i++)
{
if (m_enabledFlags[i])
{
if (val != "") val += ", ";
val += m_values[i].Value;
}
}
var type = Value?.GetType() ?? FallbackType;
Value = Enum.Parse(type, val);
RefreshUIForValue();
Owner.SetValue();
}
internal override void OnToggleSubcontent(bool toggle)
{
base.OnToggleSubcontent(toggle);
RefreshUIForValue();
}
public override void ConstructUI(GameObject parent, GameObject subGroup)
{
base.ConstructUI(parent, subGroup);
}
public override void ConstructSubcontent()
{
m_subContentConstructed = true;
if (Owner.CanWrite)
{
var groupObj = UIFactory.CreateVerticalGroup(m_subContentParent, "InteractiveFlagsContent", false, true, true, true, 5,
new Vector4(3,3,3,3), new Color(1, 1, 1, 0));
// apply button
var apply = UIFactory.CreateButton(groupObj, "ApplyButton", "Apply", SetValueFromToggles, new Color(0.3f, 0.3f, 0.3f));
UIFactory.SetLayoutElement(apply.gameObject, minWidth: 50, minHeight: 25);
// toggles
for (int i = 0; i < m_values.Length; i++)
AddToggle(i, groupObj);
}
}
internal void AddToggle(int index, GameObject groupObj)
{
var value = m_values[index];
var toggleObj = UIFactory.CreateToggle(groupObj, "FlagToggle", out Toggle toggle, out Text text, new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutElement(toggleObj, minWidth: 100, flexibleWidth: 2000, minHeight: 25);
m_toggles[index] = toggle;
toggle.onValueChanged.AddListener((bool val) => { m_enabledFlags[index] = val; });
text.text = $"{value.Key}: {value.Value}";
}
}
}

View File

@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI;
using UnityExplorer.Core;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.CacheObject;
namespace UnityExplorer.UI.InteractiveValues
{
public class InteractiveNumber : InteractiveValue
{
public InteractiveNumber(object value, Type valueType) : base(value, valueType) { }
public override bool HasSubContent => false;
public override bool SubContentWanted => false;
public override bool WantInspectBtn => false;
public override void OnValueUpdated()
{
base.OnValueUpdated();
}
public override void OnException(CacheMember member)
{
base.OnException(member);
if (m_valueInput.gameObject.activeSelf)
m_valueInput.gameObject.SetActive(false);
if (Owner.CanWrite)
{
if (m_applyBtn.gameObject.activeSelf)
m_applyBtn.gameObject.SetActive(false);
}
}
public override void RefreshUIForValue()
{
if (!Owner.HasEvaluated)
{
GetDefaultLabel();
m_baseLabel.text = DefaultLabel;
return;
}
m_baseLabel.text = SignatureHighlighter.ParseFullSyntax(FallbackType, false);
m_valueInput.text = Value.ToString();
var type = Value.GetType();
if (type == typeof(float)
|| type == typeof(double)
|| type == typeof(decimal))
{
m_valueInput.characterValidation = InputField.CharacterValidation.Decimal;
}
else
{
m_valueInput.characterValidation = InputField.CharacterValidation.Integer;
}
if (Owner.CanWrite)
{
if (!m_applyBtn.gameObject.activeSelf)
m_applyBtn.gameObject.SetActive(true);
}
if (!m_valueInput.gameObject.activeSelf)
m_valueInput.gameObject.SetActive(true);
}
public MethodInfo ParseMethod => m_parseMethod ?? (m_parseMethod = Value.GetType().GetMethod("Parse", new Type[] { typeof(string) }));
private MethodInfo m_parseMethod;
internal void OnApplyClicked()
{
try
{
Value = ParseMethod.Invoke(null, new object[] { m_valueInput.text });
Owner.SetValue();
RefreshUIForValue();
}
catch (Exception e)
{
ExplorerCore.LogWarning("Could not parse input! " + ReflectionUtility.ReflectionExToString(e, true));
}
}
internal InputField m_valueInput;
internal Button m_applyBtn;
public override void ConstructUI(GameObject parent, GameObject subGroup)
{
base.ConstructUI(parent, subGroup);
var labelLayout = m_baseLabel.gameObject.GetComponent<LayoutElement>();
labelLayout.minWidth = 50;
labelLayout.flexibleWidth = 0;
var inputObj = UIFactory.CreateInputField(m_valueContent, "InteractiveNumberInput", "...");
UIFactory.SetLayoutElement(inputObj, minWidth: 120, minHeight: 25, flexibleWidth: 0);
m_valueInput = inputObj.GetComponent<InputField>();
m_valueInput.gameObject.SetActive(false);
if (Owner.CanWrite)
{
m_applyBtn = UIFactory.CreateButton(m_valueContent, "ApplyButton", "Apply", OnApplyClicked, new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(m_applyBtn.gameObject, minWidth: 50, minHeight: 25, flexibleWidth: 0);
}
}
}
}

View File

@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.CacheObject;
namespace UnityExplorer.UI.InteractiveValues
{
public class InteractiveString : InteractiveValue
{
public InteractiveString(object value, Type valueType) : base(value, valueType) { }
public override bool HasSubContent => true;
public override bool SubContentWanted => true;
public override bool WantInspectBtn => false;
public override void OnValueUpdated()
{
base.OnValueUpdated();
}
public override void OnException(CacheMember member)
{
base.OnException(member);
if (m_subContentConstructed && m_hiddenObj.gameObject.activeSelf)
m_hiddenObj.gameObject.SetActive(false);
m_labelLayout.minWidth = 200;
m_labelLayout.flexibleWidth = 5000;
}
public override void RefreshUIForValue()
{
GetDefaultLabel(false);
if (!Owner.HasEvaluated)
{
m_baseLabel.text = DefaultLabel;
return;
}
m_baseLabel.text = m_richValueType;
if (m_subContentConstructed)
{
if (!m_hiddenObj.gameObject.activeSelf)
m_hiddenObj.gameObject.SetActive(true);
}
if (!string.IsNullOrEmpty((string)Value))
{
var toString = (string)Value;
if (toString.Length > 15000)
toString = toString.Substring(0, 15000);
m_readonlyInput.text = toString;
if (m_subContentConstructed)
{
m_valueInput.text = toString;
m_placeholderText.text = toString;
}
}
else
{
string s = Value == null
? "null"
: "empty";
m_readonlyInput.text = $"<i><color=grey>{s}</color></i>";
if (m_subContentConstructed)
{
m_valueInput.text = "";
m_placeholderText.text = s;
}
}
m_labelLayout.minWidth = 50;
m_labelLayout.flexibleWidth = 0;
}
internal void OnApplyClicked()
{
Value = m_valueInput.text;
Owner.SetValue();
RefreshUIForValue();
}
// for the default label
internal LayoutElement m_labelLayout;
//internal InputField m_readonlyInput;
internal Text m_readonlyInput;
// for input
internal InputField m_valueInput;
internal GameObject m_hiddenObj;
internal Text m_placeholderText;
public override void ConstructUI(GameObject parent, GameObject subGroup)
{
base.ConstructUI(parent, subGroup);
GetDefaultLabel(false);
m_richValueType = SignatureHighlighter.ParseFullSyntax(FallbackType, false);
m_labelLayout = m_baseLabel.gameObject.GetComponent<LayoutElement>();
m_readonlyInput = UIFactory.CreateLabel(m_valueContent, "ReadonlyLabel", "<notset>", TextAnchor.MiddleLeft);
m_readonlyInput.horizontalOverflow = HorizontalWrapMode.Overflow;
var testFitter = m_readonlyInput.gameObject.AddComponent<ContentSizeFitter>();
testFitter.verticalFit = ContentSizeFitter.FitMode.MinSize;
UIFactory.SetLayoutElement(m_readonlyInput.gameObject, minHeight: 25, preferredHeight: 25, flexibleHeight: 0);
}
public override void ConstructSubcontent()
{
base.ConstructSubcontent();
var groupObj = UIFactory.CreateVerticalGroup(m_subContentParent, "SubContent", true, false, true, true, 4, new Vector4(3,3,3,3),
new Color(1, 1, 1, 0));
m_hiddenObj = UIFactory.CreateLabel(groupObj, "HiddenLabel", "", TextAnchor.MiddleLeft).gameObject;
m_hiddenObj.SetActive(false);
var hiddenText = m_hiddenObj.GetComponent<Text>();
hiddenText.color = Color.clear;
hiddenText.fontSize = 14;
hiddenText.raycastTarget = false;
hiddenText.supportRichText = false;
var hiddenFitter = m_hiddenObj.AddComponent<ContentSizeFitter>();
hiddenFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
UIFactory.SetLayoutElement(m_hiddenObj, minHeight: 25, flexibleHeight: 500, minWidth: 250, flexibleWidth: 9000);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(m_hiddenObj, true, true, true, true);
var inputObj = UIFactory.CreateInputField(m_hiddenObj, "StringInputField", "...", 14, 3);
UIFactory.SetLayoutElement(inputObj, minWidth: 120, minHeight: 25, flexibleWidth: 5000, flexibleHeight: 5000);
m_valueInput = inputObj.GetComponent<InputField>();
m_valueInput.lineType = InputField.LineType.MultiLineNewline;
m_placeholderText = m_valueInput.placeholder.GetComponent<Text>();
m_placeholderText.supportRichText = false;
m_valueInput.textComponent.supportRichText = false;
m_valueInput.onValueChanged.AddListener((string val) =>
{
hiddenText.text = val ?? "";
LayoutRebuilder.ForceRebuildLayoutImmediate(Owner.m_mainRect);
});
if (Owner.CanWrite)
{
var apply = UIFactory.CreateButton(groupObj, "ApplyButton", "Apply", OnApplyClicked, new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(apply.gameObject, minWidth: 50, minHeight: 25, flexibleWidth: 0);
}
else
{
m_valueInput.readOnly = true;
}
RefreshUIForValue();
}
}
}

View File

@ -0,0 +1,298 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI;
namespace UnityExplorer.UI.InteractiveValues
{
#region IStructInfo helper
public interface IStructInfo
{
string[] FieldNames { get; }
object SetValue(ref object value, int fieldIndex, float val);
void RefreshUI(InputField[] inputs, object value);
}
public class StructInfo<T> : IStructInfo where T : struct
{
public string[] FieldNames { get; set; }
public delegate void SetMethod(ref T value, int fieldIndex, float val);
public SetMethod SetValueMethod;
public delegate void UpdateMethod(InputField[] inputs, object value);
public UpdateMethod UpdateUIMethod;
public object SetValue(ref object value, int fieldIndex, float val)
{
var box = (T)value;
SetValueMethod.Invoke(ref box, fieldIndex, val);
return box;
}
public void RefreshUI(InputField[] inputs, object value)
{
UpdateUIMethod.Invoke(inputs, value);
}
}
// This part is a bit ugly, but everything else is generalized above.
// I could generalize it more with reflection, but it would be different for
// mono/il2cpp and also slower.
public static class StructInfoFactory
{
public static IStructInfo Create(Type type)
{
if (type == typeof(Vector2))
{
return new StructInfo<Vector2>()
{
FieldNames = new[] { "x", "y", },
SetValueMethod = (ref Vector2 vec, int fieldIndex, float val) =>
{
switch (fieldIndex)
{
case 0: vec.x = val; break;
case 1: vec.y = val; break;
}
},
UpdateUIMethod = (InputField[] inputs, object value) =>
{
Vector2 vec = (Vector2)value;
inputs[0].text = vec.x.ToString();
inputs[1].text = vec.y.ToString();
}
};
}
else if (type == typeof(Vector3))
{
return new StructInfo<Vector3>()
{
FieldNames = new[] { "x", "y", "z" },
SetValueMethod = (ref Vector3 vec, int fieldIndex, float val) =>
{
switch (fieldIndex)
{
case 0: vec.x = val; break;
case 1: vec.y = val; break;
case 2: vec.z = val; break;
}
},
UpdateUIMethod = (InputField[] inputs, object value) =>
{
Vector3 vec = (Vector3)value;
inputs[0].text = vec.x.ToString();
inputs[1].text = vec.y.ToString();
inputs[2].text = vec.z.ToString();
}
};
}
else if (type == typeof(Vector4))
{
return new StructInfo<Vector4>()
{
FieldNames = new[] { "x", "y", "z", "w" },
SetValueMethod = (ref Vector4 vec, int fieldIndex, float val) =>
{
switch (fieldIndex)
{
case 0: vec.x = val; break;
case 1: vec.y = val; break;
case 2: vec.z = val; break;
case 3: vec.w = val; break;
}
},
UpdateUIMethod = (InputField[] inputs, object value) =>
{
Vector4 vec = (Vector4)value;
inputs[0].text = vec.x.ToString();
inputs[1].text = vec.y.ToString();
inputs[2].text = vec.z.ToString();
inputs[3].text = vec.w.ToString();
}
};
}
else if (type == typeof(Rect))
{
return new StructInfo<Rect>()
{
FieldNames = new[] { "x", "y", "width", "height" },
SetValueMethod = (ref Rect vec, int fieldIndex, float val) =>
{
switch (fieldIndex)
{
case 0: vec.x = val; break;
case 1: vec.y = val; break;
case 2: vec.width = val; break;
case 3: vec.height = val; break;
}
},
UpdateUIMethod = (InputField[] inputs, object value) =>
{
Rect vec = (Rect)value;
inputs[0].text = vec.x.ToString();
inputs[1].text = vec.y.ToString();
inputs[2].text = vec.width.ToString();
inputs[3].text = vec.height.ToString();
}
};
}
else if (type == typeof(Color))
{
return new StructInfo<Color>()
{
FieldNames = new[] { "r", "g", "b", "a" },
SetValueMethod = (ref Color vec, int fieldIndex, float val) =>
{
switch (fieldIndex)
{
case 0: vec.r = val; break;
case 1: vec.g = val; break;
case 2: vec.b = val; break;
case 3: vec.a = val; break;
}
},
UpdateUIMethod = (InputField[] inputs, object value) =>
{
Color vec = (Color)value;
inputs[0].text = vec.r.ToString();
inputs[1].text = vec.g.ToString();
inputs[2].text = vec.b.ToString();
inputs[3].text = vec.a.ToString();
}
};
}
else
throw new NotImplementedException();
}
}
#endregion
public class InteractiveUnityStruct : InteractiveValue
{
public static bool SupportsType(Type type) => s_supportedTypes.Contains(type);
private static readonly HashSet<Type> s_supportedTypes = new HashSet<Type>
{
typeof(Vector2),
typeof(Vector3),
typeof(Vector4),
typeof(Rect),
typeof(Color) // todo might make a special editor for colors
};
//~~~~~~~~~ Instance ~~~~~~~~~~
public InteractiveUnityStruct(object value, Type valueType) : base(value, valueType) { }
public override bool HasSubContent => true;
public override bool SubContentWanted => true;
public override bool WantInspectBtn => true;
public IStructInfo StructInfo;
public override void RefreshUIForValue()
{
InitializeStructInfo();
base.RefreshUIForValue();
if (m_subContentConstructed)
StructInfo.RefreshUI(m_inputs, this.Value);
}
internal override void OnToggleSubcontent(bool toggle)
{
InitializeStructInfo();
base.OnToggleSubcontent(toggle);
StructInfo.RefreshUI(m_inputs, this.Value);
}
internal Type m_lastStructType;
internal void InitializeStructInfo()
{
var type = Value?.GetType() ?? FallbackType;
if (StructInfo != null && type == m_lastStructType)
return;
if (StructInfo != null)
DestroySubContent();
m_lastStructType = type;
StructInfo = StructInfoFactory.Create(type);
if (m_subContentParent.activeSelf)
{
ConstructSubcontent();
}
}
#region UI CONSTRUCTION
internal InputField[] m_inputs;
public override void ConstructUI(GameObject parent, GameObject subGroup)
{
base.ConstructUI(parent, subGroup);
}
public override void ConstructSubcontent()
{
base.ConstructSubcontent();
if (StructInfo == null)
{
ExplorerCore.LogWarning("Setting up subcontent but structinfo is null");
return;
}
var editorContainer = UIFactory.CreateVerticalGroup(m_subContentParent, "EditorContent", false, true, true, true, 2, new Vector4(4,4,4,4),
new Color(0.08f, 0.08f, 0.08f));
m_inputs = new InputField[StructInfo.FieldNames.Length];
for (int i = 0; i < StructInfo.FieldNames.Length; i++)
AddEditorRow(i, editorContainer);
if (Owner.CanWrite)
{
var applyBtn = UIFactory.CreateButton(editorContainer, "ApplyButton", "Apply", OnSetValue, new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(applyBtn.gameObject, minWidth: 175, minHeight: 25, flexibleWidth: 0);
void OnSetValue()
{
Owner.SetValue();
RefreshUIForValue();
}
}
}
internal void AddEditorRow(int index, GameObject groupObj)
{
var rowObj = UIFactory.CreateHorizontalGroup(groupObj, "EditorRow", false, true, true, true, 5, default, new Color(1, 1, 1, 0));
var label = UIFactory.CreateLabel(rowObj, "RowLabel", $"{StructInfo.FieldNames[index]}:", TextAnchor.MiddleRight, Color.cyan);
UIFactory.SetLayoutElement(label.gameObject, minWidth: 50, flexibleWidth: 0, minHeight: 25);
var inputFieldObj = UIFactory.CreateInputField(rowObj, "InputField", "...", 14, 3, 1);
UIFactory.SetLayoutElement(inputFieldObj, minWidth: 120, minHeight: 25, flexibleWidth: 0);
var inputField = inputFieldObj.GetComponent<InputField>();
m_inputs[index] = inputField;
inputField.onValueChanged.AddListener((string val) => { Value = StructInfo.SetValue(ref this.Value, index, float.Parse(val)); });
}
#endregion
}
}

View File

@ -0,0 +1,349 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer.Core;
using UnityExplorer.Core.Unity;
using UnityExplorer.Core.Runtime;
using UnityExplorer.UI;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.Main.Home;
namespace UnityExplorer.UI.InteractiveValues
{
public class InteractiveValue
{
/// <summary>
/// Get the <see cref="InteractiveValue"/> subclass which supports the provided <paramref name="type"/>.
/// </summary>
/// <param name="type">The <see cref="Type"/> which you want the <see cref="InteractiveValue"/> Type for.</param>
/// <returns>The best subclass of <see cref="InteractiveValue"/> which supports the provided <paramref name="type"/>.</returns>
public static Type GetIValueForType(Type type)
{
// rather ugly but I couldn't think of a cleaner way that was worth it.
// switch-case doesn't really work here.
// arbitrarily check some types, fastest methods first.
if (type == typeof(bool))
return typeof(InteractiveBool);
// if type is primitive then it must be a number if its not a bool
else if (type.IsPrimitive)
return typeof(InteractiveNumber);
// check for strings
else if (type == typeof(string))
return typeof(InteractiveString);
// check for enum/flags
else if (typeof(Enum).IsAssignableFrom(type))
{
// NET 3.5 doesn't have "GetCustomAttribute", gotta use the multiple version.
if (type.GetCustomAttributes(typeof(FlagsAttribute), true) is object[] fa && fa.Any())
return typeof(InteractiveFlags);
else
return typeof(InteractiveEnum);
}
// check for unity struct types
else if (InteractiveUnityStruct.SupportsType(type))
return typeof(InteractiveUnityStruct);
// check Transform, force InteractiveValue so they dont become InteractiveEnumerables.
else if (typeof(Transform).IsAssignableFrom(type))
return typeof(InteractiveValue);
// check Dictionaries before Enumerables
else if (ReflectionUtility.IsDictionary(type))
return typeof(InteractiveDictionary);
// finally check for Enumerables
else if (ReflectionUtility.IsEnumerable(type))
return typeof(InteractiveEnumerable);
// fallback to default
else
return typeof(InteractiveValue);
}
public static InteractiveValue Create(object value, Type fallbackType)
{
var type = ReflectionUtility.GetType(value) ?? fallbackType;
var iType = GetIValueForType(type);
return (InteractiveValue)Activator.CreateInstance(iType, new object[] { value, type });
}
// ~~~~~~~~~ Instance ~~~~~~~~~
public InteractiveValue(object value, Type valueType)
{
this.Value = value;
this.FallbackType = valueType;
}
public CacheObjectBase Owner;
public object Value;
public readonly Type FallbackType;
public virtual bool HasSubContent => false;
public virtual bool SubContentWanted => false;
public virtual bool WantInspectBtn => true;
public string DefaultLabel => m_defaultLabel ?? GetDefaultLabel();
internal string m_defaultLabel;
internal string m_richValueType;
public bool m_UIConstructed;
public virtual void OnDestroy()
{
if (this.m_valueContent)
{
m_valueContent.transform.SetParent(null, false);
m_valueContent.SetActive(false);
GameObject.Destroy(this.m_valueContent.gameObject);
}
DestroySubContent();
}
public virtual void DestroySubContent()
{
if (this.m_subContentParent && HasSubContent)
{
for (int i = 0; i < this.m_subContentParent.transform.childCount; i++)
{
var child = m_subContentParent.transform.GetChild(i);
if (child)
GameObject.Destroy(child.gameObject);
}
}
m_subContentConstructed = false;
}
public virtual void OnValueUpdated()
{
if (!m_UIConstructed)
ConstructUI(m_mainContentParent, m_subContentParent);
if (Owner is CacheMember ownerMember && !string.IsNullOrEmpty(ownerMember.ReflectionException))
OnException(ownerMember);
else
RefreshUIForValue();
}
public virtual void OnException(CacheMember member)
{
if (m_UIConstructed)
m_baseLabel.text = "<color=red>" + member.ReflectionException + "</color>";
Value = null;
}
public virtual void RefreshUIForValue()
{
GetDefaultLabel();
m_baseLabel.text = DefaultLabel;
}
public void RefreshElementsAfterUpdate()
{
if (WantInspectBtn)
{
bool shouldShowInspect = !Value.IsNullOrDestroyed();
if (m_inspectButton.activeSelf != shouldShowInspect)
m_inspectButton.SetActive(shouldShowInspect);
}
bool subContentWanted = SubContentWanted;
if (Owner is CacheMember cm && (!cm.HasEvaluated || !string.IsNullOrEmpty(cm.ReflectionException)))
subContentWanted = false;
if (HasSubContent)
{
if (m_subExpandBtn.gameObject.activeSelf != subContentWanted)
m_subExpandBtn.gameObject.SetActive(subContentWanted);
if (!subContentWanted && m_subContentParent.activeSelf)
ToggleSubcontent();
}
}
public virtual void ConstructSubcontent()
{
m_subContentConstructed = true;
}
public void ToggleSubcontent()
{
if (!this.m_subContentParent.activeSelf)
{
this.m_subContentParent.SetActive(true);
this.m_subContentParent.transform.SetAsLastSibling();
m_subExpandBtn.GetComponentInChildren<Text>().text = "▼";
}
else
{
this.m_subContentParent.SetActive(false);
m_subExpandBtn.GetComponentInChildren<Text>().text = "▲";
}
OnToggleSubcontent(m_subContentParent.activeSelf);
RefreshElementsAfterUpdate();
}
internal virtual void OnToggleSubcontent(bool toggle)
{
if (!m_subContentConstructed)
ConstructSubcontent();
}
internal MethodInfo m_toStringMethod;
internal MethodInfo m_toStringFormatMethod;
internal bool m_gotToStringMethods;
public string GetDefaultLabel(bool updateType = true)
{
var valueType = Value?.GetType() ?? this.FallbackType;
if (updateType)
m_richValueType = SignatureHighlighter.ParseFullSyntax(valueType, true);
if (!Owner.HasEvaluated)
return m_defaultLabel = $"<i><color=grey>Not yet evaluated</color> ({m_richValueType})</i>";
if (Value.IsNullOrDestroyed())
return m_defaultLabel = $"<color=grey>null</color> ({m_richValueType})";
string label;
// Two dirty fixes for TextAsset and EventSystem, which can have very long ToString results.
if (Value is TextAsset textAsset)
{
label = textAsset.text;
if (label.Length > 10)
label = $"{label.Substring(0, 10)}...";
label = $"\"{label}\" {textAsset.name} ({m_richValueType})";
}
else if (Value is EventSystem)
{
label = m_richValueType;
}
else // For everything else...
{
if (!m_gotToStringMethods)
{
m_gotToStringMethods = true;
m_toStringMethod = valueType.GetMethod("ToString", new Type[0]);
m_toStringFormatMethod = valueType.GetMethod("ToString", new Type[] { typeof(string) });
// test format method actually works
try
{
m_toStringFormatMethod.Invoke(Value, new object[] { "F3" });
}
catch
{
m_toStringFormatMethod = null;
}
}
string toString;
if (m_toStringFormatMethod != null)
toString = (string)m_toStringFormatMethod.Invoke(Value, new object[] { "F3" });
else
toString = (string)m_toStringMethod.Invoke(Value, new object[0]);
toString = toString ?? "";
string typeName = valueType.FullName;
if (typeName.StartsWith("Il2CppSystem."))
typeName = typeName.Substring(6, typeName.Length - 6);
toString = ReflectionProvider.Instance.ProcessTypeNameInString(valueType, toString, ref typeName);
// If the ToString is just the type name, use our syntax highlighted type name instead.
if (toString == typeName)
{
label = m_richValueType;
}
else // Otherwise, parse the result and put our highlighted name in.
{
if (toString.Length > 200)
toString = toString.Substring(0, 200) + "...";
label = toString;
var unityType = $"({valueType.FullName})";
if (Value is UnityEngine.Object && label.Contains(unityType))
label = label.Replace(unityType, $"({m_richValueType})");
else
label += $" ({m_richValueType})";
}
}
return m_defaultLabel = label;
}
#region UI CONSTRUCTION
internal GameObject m_mainContentParent;
internal GameObject m_subContentParent;
internal GameObject m_valueContent;
internal GameObject m_inspectButton;
internal Text m_baseLabel;
internal Button m_subExpandBtn;
internal bool m_subContentConstructed;
public virtual void ConstructUI(GameObject parent, GameObject subGroup)
{
m_UIConstructed = true;
m_valueContent = UIFactory.CreateHorizontalGroup(parent, $"InteractiveValue_{this.GetType().Name}", false, false, true, true, 4, default,
new Color(1, 1, 1, 0), TextAnchor.UpperLeft);
var mainRect = m_valueContent.GetComponent<RectTransform>();
mainRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 25);
UIFactory.SetLayoutElement(m_valueContent, flexibleWidth: 9000, minWidth: 175, minHeight: 25, flexibleHeight: 0);
// subcontent expand button
if (HasSubContent)
{
m_subExpandBtn = UIFactory.CreateButton(m_valueContent, "ExpandSubcontentButton", "▲", ToggleSubcontent, new Color(0.3f, 0.3f, 0.3f));
UIFactory.SetLayoutElement(m_subExpandBtn.gameObject, minHeight: 25, minWidth: 25, flexibleWidth: 0, flexibleHeight: 0);
}
// inspect button
var inspectBtn = UIFactory.CreateButton(m_valueContent,
"InspectButton",
"Inspect",
() =>
{
if (!Value.IsNullOrDestroyed(false))
InspectorManager.Instance.Inspect(this.Value, this.Owner);
},
new Color(0.3f, 0.3f, 0.3f, 0.2f));
m_inspectButton = inspectBtn.gameObject;
UIFactory.SetLayoutElement(m_inspectButton, minWidth: 60, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0);
m_inspectButton.SetActive(false);
// value label
m_baseLabel = UIFactory.CreateLabel(m_valueContent, "ValueLabel", "<not set>", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(m_baseLabel.gameObject, flexibleWidth: 9000, minHeight: 25);
m_subContentParent = subGroup;
}
#endregion
}
}

View File

@ -19,7 +19,6 @@ namespace UnityExplorer.UI.Main.CSConsole
private const int UPDATES_PER_BATCH = 100;
public static GameObject m_mainObj;
//private static RectTransform m_thisRect;
private static readonly List<GameObject> m_suggestionButtons = new List<GameObject>();
private static readonly List<Text> m_suggestionTexts = new List<Text>();
@ -137,7 +136,7 @@ namespace UnityExplorer.UI.Main.CSConsole
if (!editor.InputField.isFocused)
return;
var textGen = editor.InputText.cachedTextGenerator;
int caretPos = editor.m_lastCaretPos;
@ -256,7 +255,7 @@ namespace UnityExplorer.UI.Main.CSConsole
{
var parent = UIManager.CanvasRoot;
var obj = UIFactory.CreateScrollView(parent, out GameObject content, out _, new Color(0.1f, 0.1f, 0.1f, 0.95f));
var obj = UIFactory.CreateScrollView(parent, "AutoCompleterScrollView", out GameObject content, out _, new Color(0.1f, 0.1f, 0.1f, 0.95f));
m_mainObj = obj;
@ -274,38 +273,31 @@ namespace UnityExplorer.UI.Main.CSConsole
mainGroup.childForceExpandHeight = false;
mainGroup.childForceExpandWidth = true;
ColorBlock btnColors = new ColorBlock();
btnColors.normalColor = new Color(0f, 0f, 0f, 0f);
btnColors.highlightedColor = new Color(0.2f, 0.2f, 0.2f, 1.0f);
for (int i = 0; i < MAX_LABELS; i++)
{
var buttonObj = UIFactory.CreateButton(content);
Button btn = buttonObj.GetComponent<Button>();
ColorBlock btnColors = btn.colors;
btnColors.normalColor = new Color(0f, 0f, 0f, 0f);
btnColors.highlightedColor = new Color(0.2f, 0.2f, 0.2f, 1.0f);
btn.colors = btnColors;
var btn = UIFactory.CreateButton(content, "AutoCompleteButton", "", null, btnColors);
var nav = btn.navigation;
nav.mode = Navigation.Mode.Vertical;
btn.navigation = nav;
var btnLayout = buttonObj.AddComponent<LayoutElement>();
btnLayout.minHeight = 20;
UIFactory.SetLayoutElement(btn.gameObject, minHeight: 20);
var text = btn.GetComponentInChildren<Text>();
text.alignment = TextAnchor.MiddleLeft;
text.color = Color.white;
var hiddenChild = UIFactory.CreateUIObject("HiddenText", buttonObj);
var hiddenChild = UIFactory.CreateUIObject("HiddenText", btn.gameObject);
hiddenChild.SetActive(false);
var hiddenText = hiddenChild.AddComponent<Text>();
m_hiddenSuggestionTexts.Add(hiddenText);
btn.onClick.AddListener(UseAutocompleteButton);
btn.onClick.AddListener(() => { CSharpConsole.Instance.UseAutocomplete(hiddenText.text); });
void UseAutocompleteButton()
{
CSharpConsole.Instance.UseAutocomplete(hiddenText.text);
}
m_suggestionButtons.Add(buttonObj);
m_suggestionButtons.Add(btn.gameObject);
m_suggestionTexts.Add(text);
}
}

View File

@ -40,24 +40,12 @@ namespace UnityExplorer.UI.Main.CSConsole
{
'[', ']', '(', ')', '{', '}', ';', ':', ',', '.'
};
public static CommentMatch commentMatcher = new CommentMatch();
public static SymbolMatch symbolMatcher = new SymbolMatch();
public static NumberMatch numberMatcher = new NumberMatch();
public static StringMatch stringMatcher = new StringMatch();
public static KeywordMatch validKeywordMatcher = new KeywordMatch
{
highlightColor = new Color(0.33f, 0.61f, 0.83f, 1.0f),
Keywords = new[] { "add", "as", "ascending", "await", "bool", "break", "by", "byte",
"case", "catch", "char", "checked", "const", "continue", "decimal", "default", "descending", "do", "dynamic",
"else", "equals", "false", "finally", "float", "for", "foreach", "from", "global", "goto", "group",
"if", "in", "int", "into", "is", "join", "let", "lock", "long", "new", "null", "object", "on", "orderby", "out",
"ref", "remove", "return", "sbyte", "select", "short", "sizeof", "stackalloc", "string",
"switch", "throw", "true", "try", "typeof", "uint", "ulong", "ushort", "var", "where", "while", "yield",
"abstract", "async", "base", "class", "delegate", "enum", "explicit", "extern", "fixed", "get",
"implicit", "interface", "internal", "namespace", "operator", "override", "params", "private", "protected", "public",
"using", "partial", "readonly", "sealed", "set", "static", "struct", "this", "unchecked", "unsafe", "value", "virtual", "volatile", "void"}
};
public static KeywordMatch validKeywordMatcher = new KeywordMatch();
// ~~~~~~~ ctor ~~~~~~~

View File

@ -9,10 +9,10 @@ using UnityExplorer.Core.Input;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer.UI.Reusable;
using UnityExplorer.UI.Main.CSConsole;
using UnityExplorer.Core;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI.Utility;
#if CPP
using UnityExplorer.Core.Runtime.Il2Cpp;
#endif
@ -361,7 +361,7 @@ The following helper methods are available:
string ret = "";
foreach (LexerMatchInfo match in highlightLexer.GetMatches(inputText))
foreach (var match in highlightLexer.GetMatches(inputText))
{
for (int i = offset; i < match.startIndex; i++)
ret += inputText[i];
@ -456,101 +456,62 @@ The following helper methods are available:
public void ConstructUI()
{
Content = UIFactory.CreateUIObject("C# Console", MainMenu.Instance.PageViewport);
Content = UIFactory.CreateVerticalGroup(MainMenu.Instance.PageViewport, "CSharpConsole", true, true, true, true);
UIFactory.SetLayoutElement(Content, preferredHeight: 500, flexibleHeight: 9000);
var mainLayout = Content.AddComponent<LayoutElement>();
mainLayout.preferredHeight = 500;
mainLayout.flexibleHeight = 9000;
var mainGroup = Content.AddComponent<VerticalLayoutGroup>();
mainGroup.SetChildControlHeight(true);
mainGroup.SetChildControlWidth(true);
mainGroup.childForceExpandHeight = true;
mainGroup.childForceExpandWidth = true;
#region TOP BAR
#region TOP BAR
// Main group object
var topBarObj = UIFactory.CreateHorizontalGroup(Content);
LayoutElement topBarLayout = topBarObj.AddComponent<LayoutElement>();
topBarLayout.minHeight = 50;
topBarLayout.flexibleHeight = 0;
var topBarObj = UIFactory.CreateHorizontalGroup(Content, "TopBar", true, true, true, true, 10, new Vector4(8, 8, 30, 30),
default, TextAnchor.LowerCenter);
UIFactory.SetLayoutElement(topBarObj, minHeight: 50, flexibleHeight: 0);
var topBarGroup = topBarObj.GetComponent<HorizontalLayoutGroup>();
topBarGroup.padding.left = 30;
topBarGroup.padding.right = 30;
topBarGroup.padding.top = 8;
topBarGroup.padding.bottom = 8;
topBarGroup.spacing = 10;
topBarGroup.childForceExpandHeight = true;
topBarGroup.childForceExpandWidth = true;
topBarGroup.SetChildControlWidth(true);
topBarGroup.SetChildControlHeight(true);
topBarGroup.childAlignment = TextAnchor.LowerCenter;
// Top label
var topBarLabel = UIFactory.CreateLabel(topBarObj, TextAnchor.MiddleLeft);
var topBarLabelLayout = topBarLabel.AddComponent<LayoutElement>();
topBarLabelLayout.preferredWidth = 150;
topBarLabelLayout.flexibleWidth = 5000;
var topBarText = topBarLabel.GetComponent<Text>();
topBarText.text = "C# Console";
topBarText.fontSize = 20;
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, out Toggle ctrlRToggle, out Text ctrlRToggleText);
ctrlRToggle.onValueChanged.AddListener(CtrlRToggleCallback);
void CtrlRToggleCallback(bool val)
{
EnableCtrlRShortcut = val;
}
var ctrlRToggleObj = UIFactory.CreateToggle(topBarObj, "CtrlRToggle", out Toggle ctrlRToggle, out Text ctrlRToggleText);
ctrlRToggle.onValueChanged.AddListener((bool val) => { EnableCtrlRShortcut = val; });
ctrlRToggleText.text = "Run on Ctrl+R";
ctrlRToggleText.alignment = TextAnchor.UpperLeft;
var ctrlRLayout = ctrlRToggleObj.AddComponent<LayoutElement>();
ctrlRLayout.minWidth = 140;
ctrlRLayout.flexibleWidth = 0;
ctrlRLayout.minHeight = 25;
UIFactory.SetLayoutElement(ctrlRToggleObj, minWidth: 140, flexibleWidth: 0, minHeight: 25);
// Enable Suggestions toggle
var suggestToggleObj = UIFactory.CreateToggle(topBarObj, out Toggle suggestToggle, out Text suggestToggleText);
suggestToggle.onValueChanged.AddListener(SuggestToggleCallback);
void SuggestToggleCallback(bool val)
var suggestToggleObj = UIFactory.CreateToggle(topBarObj, "SuggestionToggle", out Toggle suggestToggle, out Text suggestToggleText);
suggestToggle.onValueChanged.AddListener((bool val) =>
{
EnableAutocompletes = val;
AutoCompleter.Update();
}
});
suggestToggleText.text = "Suggestions";
suggestToggleText.alignment = TextAnchor.UpperLeft;
var suggestLayout = suggestToggleObj.AddComponent<LayoutElement>();
suggestLayout.minWidth = 120;
suggestLayout.flexibleWidth = 0;
suggestLayout.minHeight = 25;
UIFactory.SetLayoutElement(suggestToggleObj, minWidth: 120, flexibleWidth: 0, minHeight: 25);
// Enable Auto-indent toggle
var autoIndentToggleObj = UIFactory.CreateToggle(topBarObj, out Toggle autoIndentToggle, out Text autoIndentToggleText);
autoIndentToggle.onValueChanged.AddListener(OnIndentChanged);
void OnIndentChanged(bool val) => EnableAutoIndent = val;
var autoIndentToggleObj = UIFactory.CreateToggle(topBarObj, "IndentToggle", out Toggle autoIndentToggle, out Text autoIndentToggleText);
autoIndentToggle.onValueChanged.AddListener((bool val) => EnableAutoIndent = val);
autoIndentToggleText.text = "Auto-indent on Enter";
autoIndentToggleText.alignment = TextAnchor.UpperLeft;
var autoIndentLayout = autoIndentToggleObj.AddComponent<LayoutElement>();
autoIndentLayout.minWidth = 180;
autoIndentLayout.flexibleWidth = 0;
autoIndentLayout.minHeight = 25;
UIFactory.SetLayoutElement(autoIndentToggleObj, minWidth: 180, flexibleWidth: 0, minHeight: 25);
#endregion
#endregion
#region CONSOLE INPUT
#region CONSOLE INPUT
int fontSize = 16;
var inputObj = UIFactory.CreateSrollInputField(Content, out InputFieldScroller consoleScroll, fontSize);
var inputObj = UIFactory.CreateSrollInputField(Content, "ConsoleInput", STARTUP_TEXT, out InputFieldScroller consoleScroll, fontSize);
var inputField = consoleScroll.inputField;
@ -560,7 +521,6 @@ The following helper methods are available:
mainTextInput.color = new Color(1, 1, 1, 0.5f);
var placeHolderText = inputField.placeholder.GetComponent<Text>();
placeHolderText.text = STARTUP_TEXT;
placeHolderText.fontSize = fontSize;
var highlightTextObj = UIFactory.CreateUIObject("HighlightText", mainTextObj.gameObject);
@ -579,58 +539,26 @@ The following helper methods are available:
#region COMPILE BUTTON BAR
var horozGroupObj = UIFactory.CreateHorizontalGroup(Content, new Color(1, 1, 1, 0));
var horozGroup = horozGroupObj.GetComponent<HorizontalLayoutGroup>();
horozGroup.padding.left = 2;
horozGroup.padding.top = 2;
horozGroup.padding.right = 2;
horozGroup.padding.bottom = 2;
var horozGroupObj = UIFactory.CreateHorizontalGroup(Content, "BigButtons", true, true, true, true, 0, new Vector4(2,2,2,2),
new Color(1, 1, 1, 0));
var resetBtnObj = UIFactory.CreateButton(horozGroupObj);
var resetBtnLayout = resetBtnObj.AddComponent<LayoutElement>();
resetBtnLayout.preferredWidth = 80;
resetBtnLayout.flexibleWidth = 0;
resetBtnLayout.minHeight = 45;
resetBtnLayout.flexibleHeight = 0;
var resetButton = resetBtnObj.GetComponent<Button>();
var resetBtnColors = resetButton.colors;
resetBtnColors.normalColor = "666666".ToColor();
resetButton.colors = resetBtnColors;
var resetBtnText = resetBtnObj.GetComponentInChildren<Text>();
resetBtnText.text = "Reset";
var resetButton = UIFactory.CreateButton(horozGroupObj, "ResetButton", "Reset", () => ResetConsole(), "666666".ToColor());
var resetBtnText = resetButton.GetComponentInChildren<Text>();
resetBtnText.fontSize = 18;
resetBtnText.color = Color.white;
UIFactory.SetLayoutElement(resetButton.gameObject, preferredWidth: 80, flexibleWidth: 0, minHeight: 45, flexibleHeight: 0);
// Set compile button callback now that we have the Input Field reference
resetButton.onClick.AddListener(ResetCallback);
void ResetCallback()
{
ResetConsole();
}
var compileBtnObj = UIFactory.CreateButton(horozGroupObj);
var compileBtnLayout = compileBtnObj.AddComponent<LayoutElement>();
compileBtnLayout.preferredWidth = 80;
compileBtnLayout.flexibleWidth = 0;
compileBtnLayout.minHeight = 45;
compileBtnLayout.flexibleHeight = 0;
var compileButton = compileBtnObj.GetComponent<Button>();
var compileBtnColors = compileButton.colors;
compileBtnColors.normalColor = new Color(14f / 255f, 80f / 255f, 14f / 255f);
compileButton.colors = compileBtnColors;
var btnText = compileBtnObj.GetComponentInChildren<Text>();
btnText.text = "Run";
var compileButton = UIFactory.CreateButton(horozGroupObj, "CompileButton", "Compile", CompileCallback,
new Color(14f / 255f, 80f / 255f, 14f / 255f));
var btnText = compileButton.GetComponentInChildren<Text>();
btnText.fontSize = 18;
btnText.color = Color.white;
UIFactory.SetLayoutElement(compileButton.gameObject, preferredWidth: 80, flexibleWidth: 0, minHeight: 45, flexibleHeight: 0);
// Set compile button callback now that we have the Input Field reference
compileButton.onClick.AddListener(CompileCallback);
void CompileCallback()
{
if (!string.IsNullOrEmpty(inputField.text))
{
Evaluate(inputField.text.Trim());
}
else
ExplorerCore.Log("Cannot evaluate empty input!");
}
#endregion

View File

@ -7,10 +7,18 @@ namespace UnityExplorer.UI.Main.CSConsole.Lexer
// This class just contains common implementations.
public class KeywordMatch : Matcher
{
public string[] Keywords;
public string[] Keywords = new[] {"add", "as", "ascending", "await", "bool", "break", "by", "byte",
"case", "catch", "char", "checked", "const", "continue", "decimal", "default", "descending", "do", "dynamic",
"else", "equals", "false", "finally", "float", "for", "foreach", "from", "global", "goto", "group",
"if", "in", "int", "into", "is", "join", "let", "lock", "long", "new", "null", "object", "on", "orderby", "out",
"ref", "remove", "return", "sbyte", "select", "short", "sizeof", "stackalloc", "string",
"switch", "throw", "true", "try", "typeof", "uint", "ulong", "ushort", "var", "where", "while", "yield",
"abstract", "async", "base", "class", "delegate", "enum", "explicit", "extern", "fixed", "get",
"implicit", "interface", "internal", "namespace", "operator", "override", "params", "private", "protected", "public",
"using", "partial", "readonly", "sealed", "set", "static", "struct", "this", "unchecked", "unsafe", "value", "virtual", "volatile", "void" };
public override Color HighlightColor => highlightColor;
public Color highlightColor;
public Color highlightColor = new Color(0.33f, 0.61f, 0.83f, 1.0f);
private readonly HashSet<string> shortlist = new HashSet<string>();
private readonly Stack<string> removeList = new Stack<string>();

View File

@ -3,10 +3,10 @@ using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.UI.Reusable;
using System.IO;
using System.Linq;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.Main
{
@ -32,11 +32,11 @@ namespace UnityExplorer.UI.Main
public DebugConsole(GameObject parent)
{
Instance = this;
LogUnity = ExplorerConfig.Instance.Log_Unity_Debug;
LogUnity = ConfigManager.Log_Unity_Debug.Value;
ConstructUI(parent);
if (ExplorerConfig.Instance.DebugConsole_Hidden)
if (!ConfigManager.Last_DebugConsole_State.Value)
ToggleShow();
// append messages that logged before we were set up
@ -52,7 +52,7 @@ namespace UnityExplorer.UI.Main
// set up IO
var path = ExplorerCore.EXPLORER_FOLDER + @"\Logs";
var path = Path.Combine(ExplorerCore.Loader.ExplorerFolder, "Logs");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
@ -87,7 +87,7 @@ namespace UnityExplorer.UI.Main
private Text m_hideBtnText;
private LayoutElement m_mainLayout;
public static Action OnToggleShow;
public static Action<bool> OnToggleShow;
public void ToggleShow()
{
@ -106,7 +106,7 @@ namespace UnityExplorer.UI.Main
m_mainLayout.minHeight = 190;
}
OnToggleShow?.Invoke();
OnToggleShow?.Invoke(!Hiding);
}
public static string RemoveInvalidFilenameChars(string s)
@ -138,7 +138,7 @@ namespace UnityExplorer.UI.Main
if (hexColor != null)
message = $"<color=#{hexColor}>{message}</color>";
if (Instance?.m_textInput)
{
var input = Instance.m_textInput;
@ -155,17 +155,9 @@ namespace UnityExplorer.UI.Main
public void ConstructUI(GameObject parent)
{
var mainObj = UIFactory.CreateVerticalGroup(parent, new Color(0.1f, 0.1f, 0.1f, 1.0f));
var mainGroup = mainObj.GetComponent<VerticalLayoutGroup>();
mainGroup.SetChildControlHeight(true);
mainGroup.SetChildControlWidth(true);
mainGroup.childForceExpandHeight = true;
mainGroup.childForceExpandWidth = true;
var mainObj = UIFactory.CreateVerticalGroup(parent, "DebugConsole", true, true, true, true, 0, default, new Color(0.1f, 0.1f, 0.1f, 1.0f));
var mainImage = mainObj.GetComponent<Image>();
mainImage.maskable = true;
var mask = mainObj.AddComponent<Mask>();
mask.showMaskGraphic = true;
@ -174,154 +166,71 @@ namespace UnityExplorer.UI.Main
m_mainLayout.flexibleHeight = 0;
#region LOG AREA
m_logAreaObj = UIFactory.CreateHorizontalGroup(mainObj);
var logAreaGroup = m_logAreaObj.GetComponent<HorizontalLayoutGroup>();
logAreaGroup.SetChildControlHeight(true);
logAreaGroup.SetChildControlWidth(true);
logAreaGroup.childForceExpandHeight = true;
logAreaGroup.childForceExpandWidth = true;
m_logAreaObj = UIFactory.CreateHorizontalGroup(mainObj, "LogArea", true, true, true, true);
UIFactory.SetLayoutElement(m_logAreaObj, preferredHeight: 190, flexibleHeight: 0);
var logAreaLayout = m_logAreaObj.AddComponent<LayoutElement>();
logAreaLayout.preferredHeight = 190;
logAreaLayout.flexibleHeight = 0;
var inputScrollerObj = UIFactory.CreateSrollInputField(m_logAreaObj, out InputFieldScroller inputScroll, 14, new Color(0.05f, 0.05f, 0.05f));
var inputScrollerObj = UIFactory.CreateSrollInputField(m_logAreaObj,
"DebugConsoleOutput",
"<no output>",
out InputFieldScroller inputScroll,
14,
new Color(0.05f, 0.05f, 0.05f));
inputScroll.inputField.textComponent.font = UIManager.ConsoleFont;
inputScroll.inputField.readOnly = true;
m_textInput = inputScroll.inputField;
#endregion
#endregion
#region BOTTOM BAR
var bottomBarObj = UIFactory.CreateHorizontalGroup(mainObj);
LayoutElement topBarLayout = bottomBarObj.AddComponent<LayoutElement>();
topBarLayout.minHeight = 30;
topBarLayout.flexibleHeight = 0;
var bottomGroup = bottomBarObj.GetComponent<HorizontalLayoutGroup>();
bottomGroup.padding.left = 10;
bottomGroup.padding.right = 10;
bottomGroup.padding.top = 2;
bottomGroup.padding.bottom = 2;
bottomGroup.spacing = 10;
bottomGroup.childForceExpandHeight = true;
bottomGroup.childForceExpandWidth = false;
bottomGroup.SetChildControlWidth(true);
bottomGroup.SetChildControlHeight(true);
bottomGroup.childAlignment = TextAnchor.MiddleLeft;
var bottomBarObj = UIFactory.CreateHorizontalGroup(mainObj, "BottomBar", false, true, true, true, 10, new Vector4(2,2,10,10),
default, TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(bottomBarObj, minHeight: 30, flexibleHeight: 0);
// Debug Console label
var bottomLabel = UIFactory.CreateLabel(bottomBarObj, TextAnchor.MiddleLeft);
var topBarLabelLayout = bottomLabel.AddComponent<LayoutElement>();
topBarLabelLayout.minWidth = 100;
topBarLabelLayout.flexibleWidth = 0;
var topBarText = bottomLabel.GetComponent<Text>();
topBarText.fontStyle = FontStyle.Bold;
topBarText.text = "Debug Console";
topBarText.fontSize = 14;
var bottomLabel = UIFactory.CreateLabel(bottomBarObj, "DebugConsoleLabel", "Debug Console", TextAnchor.MiddleLeft);
bottomLabel.fontStyle = FontStyle.Bold;
UIFactory.SetLayoutElement(bottomLabel.gameObject, minWidth: 100, flexibleWidth: 0);
// Hide button
var hideButtonObj = UIFactory.CreateButton(bottomBarObj);
m_hideBtnText = hideButtonObj.GetComponentInChildren<Text>();
m_hideBtnText.text = "Hide";
var hideButton = hideButtonObj.GetComponent<Button>();
hideButton.onClick.AddListener(HideCallback);
void HideCallback()
{
ToggleShow();
}
var hideBtnColors = hideButton.colors;
//hideBtnColors.normalColor = new Color(160f / 255f, 140f / 255f, 40f / 255f);
hideButton.colors = hideBtnColors;
var hideBtnLayout = hideButtonObj.AddComponent<LayoutElement>();
hideBtnLayout.minWidth = 80;
hideBtnLayout.flexibleWidth = 0;
var hideButton = UIFactory.CreateButton(bottomBarObj, "HideButton", "Hide", ToggleShow);
UIFactory.SetLayoutElement(hideButton.gameObject, minWidth: 80, flexibleWidth: 0);
m_hideBtnText = hideButton.GetComponentInChildren<Text>();
// Clear button
var clearButtonObj = UIFactory.CreateButton(bottomBarObj);
var clearBtnText = clearButtonObj.GetComponentInChildren<Text>();
clearBtnText.text = "Clear";
var clearButton = clearButtonObj.GetComponent<Button>();
clearButton.onClick.AddListener(ClearCallback);
void ClearCallback()
var clearButton = UIFactory.CreateButton(bottomBarObj, "ClearButton", "Clear", () =>
{
m_textInput.text = "";
AllMessages.Clear();
}
var clearBtnColors = clearButton.colors;
//clearBtnColors.normalColor = new Color(160f/255f, 140f/255f, 40f/255f);
clearButton.colors = clearBtnColors;
var clearBtnLayout = clearButtonObj.AddComponent<LayoutElement>();
clearBtnLayout.minWidth = 80;
clearBtnLayout.flexibleWidth = 0;
});
UIFactory.SetLayoutElement(clearButton.gameObject, minWidth: 80, flexibleWidth: 0);
// Unity log toggle
var unityToggleObj = UIFactory.CreateToggle(bottomBarObj, out Toggle unityToggle, out Text unityToggleText);
var unityToggleObj = UIFactory.CreateToggle(bottomBarObj, "UnityLogToggle", out Toggle unityToggle, out Text unityToggleText);
unityToggle.onValueChanged.AddListener(ToggleLogUnity);
unityToggle.onValueChanged.AddListener((bool val) =>
{
LogUnity = val;
ConfigManager.Log_Unity_Debug.Value = val;
ConfigManager.Handler.SaveConfig();
});
unityToggle.isOn = LogUnity;
unityToggleText.text = "Print Unity Debug?";
unityToggleText.alignment = TextAnchor.MiddleLeft;
void ToggleLogUnity(bool val)
{
LogUnity = val;
ExplorerConfig.Instance.Log_Unity_Debug = val;
ExplorerConfig.SaveSettings();
}
var unityToggleLayout = unityToggleObj.AddComponent<LayoutElement>();
unityToggleLayout.minWidth = 170;
unityToggleLayout.flexibleWidth = 0;
UIFactory.SetLayoutElement(unityToggleObj, minWidth: 170, flexibleWidth: 0);
var unityToggleRect = unityToggleObj.transform.Find("Background").GetComponent<RectTransform>();
var pos = unityToggleRect.localPosition;
pos.y = -4;
unityToggleRect.localPosition = pos;
// // Save to disk button
// var saveToDiskObj = UIFactory.CreateToggle(bottomBarObj, out Toggle diskToggle, out Text diskToggleText);
// diskToggle.onValueChanged.AddListener(ToggleDisk);
// diskToggle.isOn = SaveToDisk;
// diskToggleText.text = "Save logs to 'Mods\\UnityExplorer\\Logs'?";
// diskToggleText.alignment = TextAnchor.MiddleLeft;
// void ToggleDisk(bool val)
// {
// SaveToDisk = val;
// ModConfig.Instance.Save_Logs_To_Disk = val;
// ModConfig.SaveSettings();
// }
// var diskToggleLayout = saveToDiskObj.AddComponent<LayoutElement>();
// diskToggleLayout.minWidth = 340;
// diskToggleLayout.flexibleWidth = 0;
// var saveToDiskRect = saveToDiskObj.transform.Find("Background").GetComponent<RectTransform>();
// pos = unityToggleRect.localPosition;
// pos.y = -8;
// saveToDiskRect.localPosition = pos;
#endregion
}
}

View File

@ -3,9 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Inspectors;
namespace UnityExplorer.UI.Main
namespace UnityExplorer.UI.Main.Home
{
public class HomePage : BaseMenuPage
{
@ -38,17 +37,7 @@ namespace UnityExplorer.UI.Main
{
GameObject parent = MainMenu.Instance.PageViewport;
Content = UIFactory.CreateHorizontalGroup(parent);
var mainGroup = Content.GetComponent<HorizontalLayoutGroup>();
mainGroup.padding.left = 1;
mainGroup.padding.right = 1;
mainGroup.padding.top = 1;
mainGroup.padding.bottom = 1;
mainGroup.spacing = 3;
mainGroup.childForceExpandHeight = true;
mainGroup.childForceExpandWidth = true;
mainGroup.SetChildControlHeight(true);
mainGroup.SetChildControlWidth(true);
Content = UIFactory.CreateHorizontalGroup(parent, "HomePage", true, true, true, true, 3, new Vector4(1,1,1,1)).gameObject;
}
}
}

View File

@ -0,0 +1,333 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer.Core;
using UnityExplorer.Core.Unity;
using UnityExplorer.Core.Input;
using UnityExplorer.Core.Runtime;
using UnityExplorer.UI;
using UnityExplorer.UI.Main;
namespace UnityExplorer.UI.Main.Home
{
public class InspectUnderMouse
{
public enum MouseInspectMode
{
World,
UI
}
public static bool Inspecting { get; set; }
public static MouseInspectMode Mode { get; set; }
private static GameObject s_lastHit;
private static Vector3 s_lastMousePos;
private static readonly List<Graphic> _wasDisabledGraphics = new List<Graphic>();
private static readonly List<CanvasGroup> _wasDisabledCanvasGroups = new List<CanvasGroup>();
private static readonly List<GameObject> _objectsAddedCastersTo = new List<GameObject>();
internal static Camera MainCamera;
internal static GraphicRaycaster[] graphicRaycasters;
public static void Init()
{
ConstructUI();
}
public static void StartInspect(MouseInspectMode mode)
{
MainCamera = Camera.main;
if (!MainCamera)
return;
Mode = mode;
Inspecting = true;
MainMenu.Instance.MainPanel.SetActive(false);
s_UIContent.SetActive(true);
if (mode == MouseInspectMode.UI)
SetupUIRaycast();
}
internal static void ClearHitData()
{
s_lastHit = null;
s_objNameLabel.text = "No hits...";
s_objPathLabel.text = "";
}
public static void StopInspect()
{
Inspecting = false;
MainMenu.Instance.MainPanel.SetActive(true);
s_UIContent.SetActive(false);
if (Mode == MouseInspectMode.UI)
StopUIInspect();
ClearHitData();
}
public static void UpdateInspect()
{
if (InputManager.GetKeyDown(KeyCode.Escape))
{
StopInspect();
return;
}
var mousePos = InputManager.MousePosition;
if (mousePos != s_lastMousePos)
UpdatePosition(mousePos);
// actual inspect raycast
switch (Mode)
{
case MouseInspectMode.UI:
RaycastUI(mousePos); break;
case MouseInspectMode.World:
RaycastWorld(mousePos); break;
}
}
internal static void UpdatePosition(Vector2 mousePos)
{
s_lastMousePos = mousePos;
var inversePos = UIManager.CanvasRoot.transform.InverseTransformPoint(mousePos);
s_mousePosLabel.text = $"<color=grey>Mouse Position:</color> {mousePos.ToString()}";
float yFix = mousePos.y < 120 ? 80 : -80;
s_UIContent.transform.localPosition = new Vector3(inversePos.x, inversePos.y + yFix, 0);
}
internal static void OnHitGameObject(GameObject obj)
{
if (obj != s_lastHit)
{
s_lastHit = obj;
s_objNameLabel.text = $"<b>Click to Inspect:</b> <color=cyan>{obj.name}</color>";
s_objPathLabel.text = $"Path: {obj.transform.GetTransformPath(true)}";
}
if (InputManager.GetMouseButtonDown(0))
{
StopInspect();
InspectorManager.Instance.Inspect(obj);
}
}
// Collider raycasting
internal static void RaycastWorld(Vector2 mousePos)
{
var ray = MainCamera.ScreenPointToRay(mousePos);
Physics.Raycast(ray, out RaycastHit hit, 1000f);
if (hit.transform)
{
var obj = hit.transform.gameObject;
OnHitGameObject(obj);
}
else
{
if (s_lastHit)
ClearHitData();
}
}
// UI Graphic raycasting
private static void SetupUIRaycast()
{
foreach (var obj in RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(Canvas)))
{
var canvas = obj.Cast(typeof(Canvas)) as Canvas;
if (!canvas || !canvas.enabled || !canvas.gameObject.activeInHierarchy)
continue;
if (!canvas.GetComponent<GraphicRaycaster>())
{
canvas.gameObject.AddComponent<GraphicRaycaster>();
//ExplorerCore.Log("Added raycaster to " + canvas.name);
_objectsAddedCastersTo.Add(canvas.gameObject);
}
}
// recache Graphic Raycasters each time we start
var casters = RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(GraphicRaycaster));
graphicRaycasters = new GraphicRaycaster[casters.Length];
for (int i = 0; i < casters.Length; i++)
{
graphicRaycasters[i] = casters[i].Cast(typeof(GraphicRaycaster)) as GraphicRaycaster;
}
// enable raycastTarget on Graphics
foreach (var obj in RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(Graphic)))
{
var graphic = obj.Cast(typeof(Graphic)) as Graphic;
if (!graphic || !graphic.enabled || graphic.raycastTarget || !graphic.gameObject.activeInHierarchy)
continue;
graphic.raycastTarget = true;
//ExplorerCore.Log("Enabled raycastTarget on " + graphic.name);
_wasDisabledGraphics.Add(graphic);
}
// enable blocksRaycasts on CanvasGroups
foreach (var obj in RuntimeProvider.Instance.FindObjectsOfTypeAll(typeof(CanvasGroup)))
{
var canvas = obj.Cast(typeof(CanvasGroup)) as CanvasGroup;
if (!canvas || !canvas.gameObject.activeInHierarchy || canvas.blocksRaycasts)
continue;
canvas.blocksRaycasts = true;
//ExplorerCore.Log("Enabled raycasts on " + canvas.name);
_wasDisabledCanvasGroups.Add(canvas);
}
}
internal static void RaycastUI(Vector2 mousePos)
{
var ped = new PointerEventData(null)
{
position = mousePos
};
#if MONO
var list = new List<RaycastResult>();
#else
var list = new Il2CppSystem.Collections.Generic.List<RaycastResult>();
#endif
//ExplorerCore.Log("~~~~~~~~~ begin raycast ~~~~~~~~");
GameObject hitObject = null;
int highestLayer = int.MinValue;
int highestOrder = int.MinValue;
int highestDepth = int.MinValue;
foreach (var gr in graphicRaycasters)
{
gr.Raycast(ped, list);
if (list.Count > 0)
{
foreach (var hit in list)
{
// Manual trying to determine which object is "on top".
// Not perfect, but not terrible.
if (!hit.gameObject)
continue;
if (hit.gameObject.GetComponent<CanvasGroup>() is CanvasGroup group && group.alpha == 0)
continue;
if (hit.gameObject.GetComponent<Graphic>() is Graphic graphic && graphic.color.a == 0f)
continue;
if (hit.sortingLayer < highestLayer)
continue;
if (hit.sortingLayer > highestLayer)
{
highestLayer = hit.sortingLayer;
highestDepth = int.MinValue;
}
if (hit.depth < highestDepth)
continue;
if (hit.depth > highestDepth)
{
highestDepth = hit.depth;
highestOrder = int.MinValue;
}
if (hit.sortingOrder <= highestOrder)
continue;
highestOrder = hit.sortingOrder;
hitObject = hit.gameObject;
}
}
else
{
if (s_lastHit)
ClearHitData();
}
}
if (hitObject)
OnHitGameObject(hitObject);
//ExplorerCore.Log("~~~~~~~~~ end raycast ~~~~~~~~");
}
private static void StopUIInspect()
{
foreach (var obj in _objectsAddedCastersTo)
{
if (obj.GetComponent<GraphicRaycaster>() is GraphicRaycaster raycaster)
GameObject.Destroy(raycaster);
}
foreach (var graphic in _wasDisabledGraphics)
graphic.raycastTarget = false;
foreach (var canvas in _wasDisabledCanvasGroups)
canvas.blocksRaycasts = false;
_objectsAddedCastersTo.Clear();
_wasDisabledCanvasGroups.Clear();
_wasDisabledGraphics.Clear();
}
#region UI
internal static Text s_objNameLabel;
internal static Text s_objPathLabel;
internal static Text s_mousePosLabel;
internal static GameObject s_UIContent;
internal static void ConstructUI()
{
s_UIContent = UIFactory.CreatePanel("InspectUnderMouse_UI", out GameObject content);
var baseRect = s_UIContent.GetComponent<RectTransform>();
var half = new Vector2(0.5f, 0.5f);
baseRect.anchorMin = half;
baseRect.anchorMax = half;
baseRect.pivot = half;
baseRect.sizeDelta = new Vector2(700, 150);
var group = content.GetComponent<VerticalLayoutGroup>();
group.childForceExpandHeight = true;
// Title text
UIFactory.CreateLabel(content, "InspectLabel", "<b>Mouse Inspector</b> (press <b>ESC</b> to cancel)", TextAnchor.MiddleCenter);
s_mousePosLabel = UIFactory.CreateLabel(content, "MousePosLabel", "Mouse Position:", TextAnchor.MiddleCenter);
s_objNameLabel = UIFactory.CreateLabel(content, "HitLabelObj", "No hits...", TextAnchor.MiddleLeft);
s_objNameLabel.horizontalOverflow = HorizontalWrapMode.Overflow;
s_objPathLabel = UIFactory.CreateLabel(content, "PathLabel", "", TextAnchor.MiddleLeft);
s_objPathLabel.fontStyle = FontStyle.Italic;
s_objPathLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
UIFactory.SetLayoutElement(s_objPathLabel.gameObject, minHeight: 75);
s_UIContent.SetActive(false);
}
#endregion
}
}

View File

@ -0,0 +1,222 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI;
using UnityExplorer.UI.Main;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.Main.Home;
using UnityExplorer.UI.Main.Home.Inspectors;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.Main.Home.Inspectors.GameObjects;
using UnityExplorer.UI.Main.Home.Inspectors.Reflection;
namespace UnityExplorer.UI.Main.Home
{
public class InspectorManager
{
public static InspectorManager Instance { get; private set; }
public InspectorManager()
{
Instance = this;
ConstructInspectorPane();
}
public InspectorBase m_activeInspector;
public readonly List<InspectorBase> m_currentInspectors = new List<InspectorBase>();
public void Update()
{
for (int i = 0; i < m_currentInspectors.Count; i++)
{
if (i >= m_currentInspectors.Count)
break;
m_currentInspectors[i].Update();
}
}
public void Inspect(object obj, CacheObjectBase parentMember = null)
{
obj = ReflectionProvider.Instance.Cast(obj, ReflectionProvider.Instance.GetActualType(obj));
UnityEngine.Object unityObj = obj as UnityEngine.Object;
if (obj.IsNullOrDestroyed(false))
{
return;
}
// check if currently inspecting this object
foreach (InspectorBase tab in m_currentInspectors)
{
if (ReferenceEquals(obj, tab.Target))
{
SetInspectorTab(tab);
return;
}
#if CPP
else if (unityObj && tab.Target is UnityEngine.Object uTabObj)
{
if (unityObj.m_CachedPtr == uTabObj.m_CachedPtr)
{
SetInspectorTab(tab);
return;
}
}
#endif
}
InspectorBase inspector;
if (obj is GameObject go)
inspector = new GameObjectInspector(go);
else
inspector = new InstanceInspector(obj);
if (inspector is ReflectionInspector ri)
ri.ParentMember = parentMember;
m_currentInspectors.Add(inspector);
SetInspectorTab(inspector);
}
public void Inspect(Type type)
{
if (type == null)
{
ExplorerCore.LogWarning("The provided type was null!");
return;
}
foreach (var tab in m_currentInspectors.Where(x => x is StaticInspector))
{
if (ReferenceEquals(tab.Target as Type, type))
{
SetInspectorTab(tab);
return;
}
}
var inspector = new StaticInspector(type);
m_currentInspectors.Add(inspector);
SetInspectorTab(inspector);
}
public void SetInspectorTab(InspectorBase inspector)
{
MainMenu.Instance.SetPage(HomePage.Instance);
if (m_activeInspector == inspector)
return;
UnsetInspectorTab();
m_activeInspector = inspector;
inspector.SetActive();
OnSetInspectorTab(inspector);
}
public void UnsetInspectorTab()
{
if (m_activeInspector == null)
return;
m_activeInspector.SetInactive();
OnUnsetInspectorTab();
m_activeInspector = null;
}
public static GameObject m_tabBarContent;
public static GameObject m_inspectorContent;
public void OnSetInspectorTab(InspectorBase inspector)
{
Color activeColor = new Color(0, 0.25f, 0, 1);
ColorBlock colors = inspector.m_tabButton.colors;
colors.normalColor = activeColor;
colors.highlightedColor = activeColor;
inspector.m_tabButton.colors = colors;
}
public void OnUnsetInspectorTab()
{
ColorBlock colors = m_activeInspector.m_tabButton.colors;
colors.normalColor = new Color(0.2f, 0.2f, 0.2f, 1);
colors.highlightedColor = new Color(0.1f, 0.3f, 0.1f, 1);
m_activeInspector.m_tabButton.colors = colors;
}
public void ConstructInspectorPane()
{
var mainObj = UIFactory.CreateVerticalGroup(HomePage.Instance.Content,
"InspectorManager_Root",
true, true, true, true,
4,
new Vector4(4,4,4,4));
UIFactory.SetLayoutElement(mainObj, preferredHeight: 400, flexibleHeight: 9000, preferredWidth: 620, flexibleWidth: 9000);
var topRowObj = UIFactory.CreateHorizontalGroup(mainObj, "TopRow", false, true, true, true, 15);
var inspectorTitle = UIFactory.CreateLabel(topRowObj, "Title", "Inspector", TextAnchor.MiddleLeft, default, true, 25);
UIFactory.SetLayoutElement(inspectorTitle.gameObject, minHeight: 30, flexibleHeight: 0, minWidth: 90, flexibleWidth: 20000);
ConstructToolbar(topRowObj);
// inspector tab bar
m_tabBarContent = UIFactory.CreateGridGroup(mainObj, "TabHolder", new Vector2(185, 20), new Vector2(5, 2), new Color(0.1f, 0.1f, 0.1f, 1));
var gridGroup = m_tabBarContent.GetComponent<GridLayoutGroup>();
gridGroup.padding.top = 3;
gridGroup.padding.left = 3;
gridGroup.padding.right = 3;
gridGroup.padding.bottom = 3;
// inspector content area
m_inspectorContent = UIFactory.CreateVerticalGroup(mainObj, "InspectorContent",
true, true, true, true,
0,
new Vector4(2,2,2,2),
new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutElement(m_inspectorContent, preferredHeight: 900, flexibleHeight: 10000, preferredWidth: 600, flexibleWidth: 10000);
}
private static void ConstructToolbar(GameObject topRowObj)
{
// invisible group
UIFactory.CreateHorizontalGroup(topRowObj, "Toolbar", false, false, true, true, 10, new Vector4(2, 2, 2, 2), new Color(1,1,1,0));
// inspect under mouse button
AddMouseInspectButton(topRowObj, InspectUnderMouse.MouseInspectMode.UI);
AddMouseInspectButton(topRowObj, InspectUnderMouse.MouseInspectMode.World);
}
private static void AddMouseInspectButton(GameObject topRowObj, InspectUnderMouse.MouseInspectMode mode)
{
string lbl = "Mouse Inspect";
if (mode == InspectUnderMouse.MouseInspectMode.UI)
lbl += " (UI)";
var inspectObj = UIFactory.CreateButton(topRowObj,
lbl,
lbl,
() => { InspectUnderMouse.StartInspect(mode); },
new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(inspectObj.gameObject, minWidth: 120, flexibleWidth: 0);
}
}
}

View File

@ -1,158 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Inspectors;
using UnityExplorer.UI.Main;
namespace UnityExplorer.UI.Main.Home
{
public class InspectorManagerUI
{
public GameObject m_tabBarContent;
public GameObject m_inspectorContent;
public void OnSetInspectorTab(InspectorBase inspector)
{
Color activeColor = new Color(0, 0.25f, 0, 1);
ColorBlock colors = inspector.BaseUI.tabButton.colors;
colors.normalColor = activeColor;
colors.highlightedColor = activeColor;
inspector.BaseUI.tabButton.colors = colors;
}
public void OnUnsetInspectorTab()
{
ColorBlock colors = InspectorManager.Instance.m_activeInspector.BaseUI.tabButton.colors;
colors.normalColor = new Color(0.2f, 0.2f, 0.2f, 1);
colors.highlightedColor = new Color(0.1f, 0.3f, 0.1f, 1);
InspectorManager.Instance.m_activeInspector.BaseUI.tabButton.colors = colors;
}
public void ConstructInspectorPane()
{
var mainObj = UIFactory.CreateVerticalGroup(HomePage.Instance.Content, new Color(72f / 255f, 72f / 255f, 72f / 255f));
LayoutElement mainLayout = mainObj.AddComponent<LayoutElement>();
mainLayout.preferredHeight = 400;
mainLayout.flexibleHeight = 9000;
mainLayout.preferredWidth = 620;
mainLayout.flexibleWidth = 9000;
var mainGroup = mainObj.GetComponent<VerticalLayoutGroup>();
mainGroup.childForceExpandHeight = true;
mainGroup.childForceExpandWidth = true;
mainGroup.SetChildControlHeight(true);
mainGroup.SetChildControlWidth(true);
mainGroup.spacing = 4;
mainGroup.padding.left = 4;
mainGroup.padding.right = 4;
mainGroup.padding.top = 4;
mainGroup.padding.bottom = 4;
var topRowObj = UIFactory.CreateHorizontalGroup(mainObj, new Color(1, 1, 1, 0));
var topRowGroup = topRowObj.GetComponent<HorizontalLayoutGroup>();
topRowGroup.childForceExpandWidth = false;
topRowGroup.SetChildControlWidth(true);
topRowGroup.childForceExpandHeight = true;
topRowGroup.SetChildControlHeight(true);
topRowGroup.spacing = 15;
var inspectorTitle = UIFactory.CreateLabel(topRowObj, TextAnchor.MiddleLeft);
Text title = inspectorTitle.GetComponent<Text>();
title.text = "Inspector";
title.fontSize = 20;
var titleLayout = inspectorTitle.AddComponent<LayoutElement>();
titleLayout.minHeight = 30;
titleLayout.flexibleHeight = 0;
titleLayout.minWidth = 90;
titleLayout.flexibleWidth = 20000;
ConstructToolbar(topRowObj);
// inspector tab bar
m_tabBarContent = UIFactory.CreateGridGroup(mainObj, new Vector2(185, 20), new Vector2(5, 2), new Color(0.1f, 0.1f, 0.1f, 1));
var gridGroup = m_tabBarContent.GetComponent<GridLayoutGroup>();
gridGroup.padding.top = 3;
gridGroup.padding.left = 3;
gridGroup.padding.right = 3;
gridGroup.padding.bottom = 3;
// inspector content area
m_inspectorContent = UIFactory.CreateVerticalGroup(mainObj, new Color(0.1f, 0.1f, 0.1f));
var inspectorGroup = m_inspectorContent.GetComponent<VerticalLayoutGroup>();
inspectorGroup.childForceExpandHeight = true;
inspectorGroup.childForceExpandWidth = true;
inspectorGroup.SetChildControlHeight(true);
inspectorGroup.SetChildControlWidth(true);
m_inspectorContent = UIFactory.CreateVerticalGroup(mainObj, new Color(0.1f, 0.1f, 0.1f));
var contentGroup = m_inspectorContent.GetComponent<VerticalLayoutGroup>();
contentGroup.childForceExpandHeight = true;
contentGroup.childForceExpandWidth = true;
contentGroup.SetChildControlHeight(true);
contentGroup.SetChildControlWidth(true);
contentGroup.padding.top = 2;
contentGroup.padding.left = 2;
contentGroup.padding.right = 2;
contentGroup.padding.bottom = 2;
var contentLayout = m_inspectorContent.AddComponent<LayoutElement>();
contentLayout.preferredHeight = 900;
contentLayout.flexibleHeight = 10000;
contentLayout.preferredWidth = 600;
contentLayout.flexibleWidth = 10000;
}
private static void ConstructToolbar(GameObject topRowObj)
{
var invisObj = UIFactory.CreateHorizontalGroup(topRowObj, new Color(1, 1, 1, 0));
var invisGroup = invisObj.GetComponent<HorizontalLayoutGroup>();
invisGroup.childForceExpandWidth = false;
invisGroup.childForceExpandHeight = false;
invisGroup.SetChildControlWidth(true);
invisGroup.SetChildControlHeight(true);
invisGroup.padding.top = 2;
invisGroup.padding.bottom = 2;
invisGroup.padding.left = 2;
invisGroup.padding.right = 2;
invisGroup.spacing = 10;
// inspect under mouse button
AddMouseInspectButton(topRowObj, InspectUnderMouse.MouseInspectMode.UI);
AddMouseInspectButton(topRowObj, InspectUnderMouse.MouseInspectMode.World);
}
private static void AddMouseInspectButton(GameObject topRowObj, InspectUnderMouse.MouseInspectMode mode)
{
var inspectObj = UIFactory.CreateButton(topRowObj);
var inspectLayout = inspectObj.AddComponent<LayoutElement>();
inspectLayout.minWidth = 120;
inspectLayout.flexibleWidth = 0;
var inspectText = inspectObj.GetComponentInChildren<Text>();
inspectText.text = "Mouse Inspect";
inspectText.fontSize = 13;
if (mode == InspectUnderMouse.MouseInspectMode.UI)
inspectText.text += " (UI)";
var inspectBtn = inspectObj.GetComponent<Button>();
var inspectColors = inspectBtn.colors;
inspectColors.normalColor = new Color(0.2f, 0.2f, 0.2f);
inspectBtn.colors = inspectColors;
inspectBtn.onClick.AddListener(OnInspectMouseClicked);
void OnInspectMouseClicked()
{
InspectUnderMouse.StartInspect(mode);
}
}
}
}

View File

@ -1,15 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI;
using UnityExplorer.UI.Reusable;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Input;
using UnityExplorer.Core.Inspectors;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.Main.Home.Inspectors
namespace UnityExplorer.UI.Main.Home.Inspectors.GameObjects
{
public class ChildList
{
@ -139,29 +136,15 @@ namespace UnityExplorer.UI.Main.Home.Inspectors
internal void ConstructChildList(GameObject parent)
{
var vertGroupObj = UIFactory.CreateVerticalGroup(parent, new Color(1, 1, 1, 0));
var vertGroup = vertGroupObj.GetComponent<VerticalLayoutGroup>();
vertGroup.childForceExpandHeight = true;
vertGroup.childForceExpandWidth = false;
vertGroup.SetChildControlWidth(true);
vertGroup.spacing = 5;
var vertLayout = vertGroupObj.AddComponent<LayoutElement>();
vertLayout.minWidth = 120;
vertLayout.flexibleWidth = 25000;
vertLayout.minHeight = 200;
vertLayout.flexibleHeight = 5000;
var vertGroupObj = UIFactory.CreateVerticalGroup(parent, "ChildListGroup", false, true, true, true, 5, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(vertGroupObj, minWidth: 120, flexibleWidth: 25000, minHeight: 200, flexibleHeight: 5000);
var childTitleObj = UIFactory.CreateLabel(vertGroupObj, TextAnchor.MiddleLeft);
var childTitleText = childTitleObj.GetComponent<Text>();
childTitleText.text = "Children";
childTitleText.color = Color.grey;
childTitleText.fontSize = 14;
var childTitleLayout = childTitleObj.AddComponent<LayoutElement>();
childTitleLayout.minHeight = 30;
var childTitle = UIFactory.CreateLabel(vertGroupObj, "ChildListTitle", "Children:", TextAnchor.MiddleLeft, Color.grey, true, 14);
UIFactory.SetLayoutElement(childTitle.gameObject, minHeight: 30);
var childrenScrollObj = UIFactory.CreateScrollView(vertGroupObj, out s_childListContent, out SliderScrollbar scroller, new Color(0.07f, 0.07f, 0.07f));
var contentLayout = childrenScrollObj.GetComponent<LayoutElement>();
contentLayout.minHeight = 50;
var childrenScrollObj = UIFactory.CreateScrollView(vertGroupObj, "ChildListScrollView", out s_childListContent,
out SliderScrollbar scroller, new Color(0.07f, 0.07f, 0.07f));
UIFactory.SetLayoutElement(childrenScrollObj, minHeight: 50);
s_childListPageHandler = new PageHandler(scroller);
s_childListPageHandler.ConstructUI(vertGroupObj);
@ -172,46 +155,38 @@ namespace UnityExplorer.UI.Main.Home.Inspectors
{
int thisIndex = s_childListTexts.Count;
GameObject btnGroupObj = UIFactory.CreateHorizontalGroup(s_childListContent, new Color(0.07f, 0.07f, 0.07f));
HorizontalLayoutGroup btnGroup = btnGroupObj.GetComponent<HorizontalLayoutGroup>();
btnGroup.childForceExpandWidth = true;
btnGroup.SetChildControlWidth(true);
btnGroup.childForceExpandHeight = false;
btnGroup.SetChildControlHeight(true);
LayoutElement btnLayout = btnGroupObj.AddComponent<LayoutElement>();
btnLayout.flexibleWidth = 320;
btnLayout.minHeight = 25;
btnLayout.flexibleHeight = 0;
var btnGroupObj = UIFactory.CreateHorizontalGroup(s_childListContent, "ChildButtonGroup", true, false, true, true,
0, default, new Color(0.07f, 0.07f, 0.07f));
UIFactory.SetLayoutElement(btnGroupObj, flexibleWidth: 320, minHeight: 25, flexibleHeight: 0);
btnGroupObj.AddComponent<Mask>();
var toggleObj = UIFactory.CreateToggle(btnGroupObj, out Toggle toggle, out Text toggleText, new Color(0.3f, 0.3f, 0.3f));
var toggleLayout = toggleObj.AddComponent<LayoutElement>();
toggleLayout.minHeight = 25;
toggleLayout.minWidth = 25;
var toggleObj = UIFactory.CreateToggle(btnGroupObj, "Toggle", out Toggle toggle, out Text toggleText, new Color(0.3f, 0.3f, 0.3f));
UIFactory.SetLayoutElement(toggleObj, minHeight: 25, minWidth: 25);
toggleText.text = "";
toggle.isOn = false;
s_childListToggles.Add(toggle);
toggle.onValueChanged.AddListener((bool val) => { OnToggleClicked(thisIndex, val); });
GameObject mainButtonObj = UIFactory.CreateButton(btnGroupObj);
LayoutElement mainBtnLayout = mainButtonObj.AddComponent<LayoutElement>();
mainBtnLayout.minHeight = 25;
mainBtnLayout.flexibleHeight = 0;
mainBtnLayout.minWidth = 25;
mainBtnLayout.flexibleWidth = 999;
Button mainBtn = mainButtonObj.GetComponent<Button>();
ColorBlock mainColors = mainBtn.colors;
ColorBlock mainColors = new ColorBlock();
mainColors.normalColor = new Color(0.07f, 0.07f, 0.07f);
mainColors.highlightedColor = new Color(0.2f, 0.2f, 0.2f, 1);
mainBtn.colors = mainColors;
mainBtn.onClick.AddListener(() => { OnChildListObjectClicked(thisIndex); });
mainColors.pressedColor = new Color(0.05f, 0.05f, 0.05f);
Text mainText = mainButtonObj.GetComponentInChildren<Text>();
var mainBtn = UIFactory.CreateButton(btnGroupObj,
"MainButton",
"<notset>",
() => { OnChildListObjectClicked(thisIndex); },
mainColors);
UIFactory.SetLayoutElement(mainBtn.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 25, flexibleWidth: 9999);
Text mainText = mainBtn.GetComponentInChildren<Text>();
mainText.alignment = TextAnchor.MiddleLeft;
mainText.horizontalOverflow = HorizontalWrapMode.Overflow;
mainText.resizeTextForBestFit = true;
mainText.resizeTextMaxSize = 14;
mainText.resizeTextMinSize = 10;
s_childListTexts.Add(mainText);
}

View File

@ -1,16 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityExplorer.UI;
using UnityExplorer.UI.Reusable;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Input;
using UnityExplorer.Core;
using UnityExplorer.UI.Utility;
using UnityExplorer.Core.Inspectors;
namespace UnityExplorer.UI.Main.Home.Inspectors
namespace UnityExplorer.UI.Main.Home.Inspectors.GameObjects
{
public class ComponentList
{
@ -137,34 +134,20 @@ namespace UnityExplorer.UI.Main.Home.Inspectors
}
#region UI CONSTRUCTION
#region UI CONSTRUCTION
internal void ConstructCompList(GameObject parent)
{
var vertGroupObj = UIFactory.CreateVerticalGroup(parent, new Color(1, 1, 1, 0));
var vertGroup = vertGroupObj.GetComponent<VerticalLayoutGroup>();
vertGroup.childForceExpandHeight = true;
vertGroup.childForceExpandWidth = false;
vertGroup.SetChildControlWidth(true);
vertGroup.spacing = 5;
var vertLayout = vertGroupObj.AddComponent<LayoutElement>();
vertLayout.minWidth = 120;
vertLayout.flexibleWidth = 25000;
vertLayout.minHeight = 200;
vertLayout.flexibleHeight = 5000;
var vertGroupObj = UIFactory.CreateVerticalGroup(parent, "ComponentList", false, true, true, true, 5, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(vertGroupObj, minWidth: 120, flexibleWidth: 25000, minHeight: 200, flexibleHeight: 5000);
var compTitleObj = UIFactory.CreateLabel(vertGroupObj, TextAnchor.MiddleLeft);
var compTitleText = compTitleObj.GetComponent<Text>();
compTitleText.text = "Components";
compTitleText.color = Color.grey;
compTitleText.fontSize = 14;
var childTitleLayout = compTitleObj.AddComponent<LayoutElement>();
childTitleLayout.minHeight = 30;
var compTitle = UIFactory.CreateLabel(vertGroupObj, "ComponentsTitle", "Components:", TextAnchor.MiddleLeft, Color.grey);
UIFactory.SetLayoutElement(compTitle.gameObject, minHeight: 30);
var compScrollObj = UIFactory.CreateScrollView(vertGroupObj, out s_compListContent, out SliderScrollbar scroller, new Color(0.07f, 0.07f, 0.07f));
var contentLayout = compScrollObj.AddComponent<LayoutElement>();
contentLayout.minHeight = 50;
contentLayout.flexibleHeight = 5000;
var compScrollObj = UIFactory.CreateScrollView(vertGroupObj, "ComponentListScrollView", out s_compListContent,
out SliderScrollbar scroller, new Color(0.07f, 0.07f, 0.07f));
UIFactory.SetLayoutElement(compScrollObj, minHeight: 50, flexibleHeight: 5000);
s_compListPageHandler = new PageHandler(scroller);
s_compListPageHandler.ConstructUI(vertGroupObj);
@ -175,26 +158,15 @@ namespace UnityExplorer.UI.Main.Home.Inspectors
{
int thisIndex = s_compListTexts.Count;
GameObject groupObj = UIFactory.CreateHorizontalGroup(s_compListContent, new Color(0.07f, 0.07f, 0.07f));
HorizontalLayoutGroup group = groupObj.GetComponent<HorizontalLayoutGroup>();
group.childForceExpandWidth = true;
group.SetChildControlWidth(true);
group.childForceExpandHeight = false;
group.SetChildControlHeight(true);
group.childAlignment = TextAnchor.MiddleLeft;
LayoutElement groupLayout = groupObj.AddComponent<LayoutElement>();
groupLayout.minWidth = 25;
groupLayout.flexibleWidth = 999;
groupLayout.minHeight = 25;
groupLayout.flexibleHeight = 0;
GameObject groupObj = UIFactory.CreateHorizontalGroup(s_compListContent, "CompListButton", true, false, true, true, 0, default,
new Color(0.07f, 0.07f, 0.07f), TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(groupObj, minWidth: 25, flexibleWidth: 999, minHeight: 25, flexibleHeight: 0);
groupObj.AddComponent<Mask>();
// Behaviour enabled toggle
var toggleObj = UIFactory.CreateToggle(groupObj, out Toggle toggle, out Text toggleText, new Color(0.3f, 0.3f, 0.3f));
var toggleLayout = toggleObj.AddComponent<LayoutElement>();
toggleLayout.minHeight = 25;
toggleLayout.minWidth = 25;
var toggleObj = UIFactory.CreateToggle(groupObj, "EnabledToggle", out Toggle toggle, out Text toggleText, new Color(0.3f, 0.3f, 0.3f));
UIFactory.SetLayoutElement(toggleObj, minWidth: 25, minHeight: 25);
toggleText.text = "";
toggle.isOn = true;
s_compToggles.Add(toggle);
@ -202,35 +174,31 @@ namespace UnityExplorer.UI.Main.Home.Inspectors
// Main component button
GameObject mainButtonObj = UIFactory.CreateButton(groupObj);
LayoutElement mainBtnLayout = mainButtonObj.AddComponent<LayoutElement>();
mainBtnLayout.minHeight = 25;
mainBtnLayout.flexibleHeight = 0;
mainBtnLayout.minWidth = 25;
mainBtnLayout.flexibleWidth = 999;
Button mainBtn = mainButtonObj.GetComponent<Button>();
ColorBlock mainColors = mainBtn.colors;
ColorBlock mainColors = new ColorBlock();
mainColors.normalColor = new Color(0.07f, 0.07f, 0.07f);
mainColors.highlightedColor = new Color(0.2f, 0.2f, 0.2f, 1);
mainBtn.colors = mainColors;
mainBtn.onClick.AddListener(() => { OnCompListObjectClicked(thisIndex); });
mainColors.pressedColor = new Color(0.05f, 0.05f, 0.05f);
var mainBtn = UIFactory.CreateButton(groupObj,
"MainButton",
"<notset>",
() => { OnCompListObjectClicked(thisIndex); },
mainColors);
UIFactory.SetLayoutElement(mainBtn.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 25, flexibleWidth: 999);
// Component button text
Text mainText = mainButtonObj.GetComponentInChildren<Text>();
Text mainText = mainBtn.GetComponentInChildren<Text>();
mainText.alignment = TextAnchor.MiddleLeft;
mainText.horizontalOverflow = HorizontalWrapMode.Overflow;
//mainText.color = SyntaxColors.Class_Instance.ToColor();
mainText.resizeTextForBestFit = true;
mainText.resizeTextMaxSize = 14;
mainText.resizeTextMinSize = 8;
s_compListTexts.Add(mainText);
// TODO remove component button
}
#endregion
#endregion
}
}

View File

@ -1,14 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityExplorer.UI;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Input;
using UnityExplorer.Core.Unity;
using UnityExplorer.Core.Inspectors;
namespace UnityExplorer.UI.Main.Home.Inspectors
namespace UnityExplorer.UI.Main.Home.Inspectors.GameObjects
{
public class GameObjectControls
{
@ -19,6 +18,24 @@ namespace UnityExplorer.UI.Main.Home.Inspectors
Instance = this;
}
internal static bool Showing;
internal static void ToggleVisibility() => SetVisibility(!Showing);
internal static void SetVisibility(bool show)
{
if (show == Showing)
return;
Showing = show;
m_hideShowLabel.text = show ? "Hide" : "Show";
m_contentObj.SetActive(show);
}
internal static GameObject m_contentObj;
internal static Text m_hideShowLabel;
private static InputField s_setParentInput;
private static ControlEditor s_positionControl;
@ -59,22 +76,22 @@ namespace UnityExplorer.UI.Main.Home.Inspectors
{
var go = GameObjectInspector.ActiveInstance.TargetGO;
s_positionControl.fullValue.text = go.transform.position.ToStringLong();
s_positionControl.fullValue.text = go.transform.position.ToStringPretty();
s_positionControl.values[0].text = go.transform.position.x.ToString("F3");
s_positionControl.values[1].text = go.transform.position.y.ToString("F3");
s_positionControl.values[2].text = go.transform.position.z.ToString("F3");
s_localPosControl.fullValue.text = go.transform.localPosition.ToStringLong();
s_localPosControl.fullValue.text = go.transform.localPosition.ToStringPretty();
s_localPosControl.values[0].text = go.transform.localPosition.x.ToString("F3");
s_localPosControl.values[1].text = go.transform.localPosition.y.ToString("F3");
s_localPosControl.values[2].text = go.transform.localPosition.z.ToString("F3");
s_rotationControl.fullValue.text = go.transform.eulerAngles.ToStringLong();
s_rotationControl.fullValue.text = go.transform.eulerAngles.ToStringPretty();
s_rotationControl.values[0].text = go.transform.eulerAngles.x.ToString("F3");
s_rotationControl.values[1].text = go.transform.eulerAngles.y.ToString("F3");
s_rotationControl.values[2].text = go.transform.eulerAngles.z.ToString("F3");
s_scaleControl.fullValue.text = go.transform.localScale.ToStringLong();
s_scaleControl.fullValue.text = go.transform.localScale.ToStringPretty();
s_scaleControl.values[0].text = go.transform.localScale.x.ToString("F3");
s_scaleControl.values[1].text = go.transform.localScale.y.ToString("F3");
s_scaleControl.values[2].text = go.transform.localScale.z.ToString("F3");
@ -244,184 +261,79 @@ namespace UnityExplorer.UI.Main.Home.Inspectors
internal void ConstructControls(GameObject parent)
{
var controlsObj = UIFactory.CreateVerticalGroup(parent, new Color(0.07f, 0.07f, 0.07f));
var controlsGroup = controlsObj.GetComponent<VerticalLayoutGroup>();
controlsGroup.childForceExpandWidth = false;
controlsGroup.SetChildControlWidth(true);
controlsGroup.childForceExpandHeight = false;
controlsGroup.spacing = 5;
controlsGroup.padding.top = 4;
controlsGroup.padding.left = 4;
controlsGroup.padding.right = 4;
controlsGroup.padding.bottom = 4;
var mainGroup = UIFactory.CreateVerticalGroup(parent, "ControlsGroup", false, false, true, true, 5, new Vector4(4,4,4,4),
new Color(0.07f, 0.07f, 0.07f));
// ~~~~~~ Top row ~~~~~~
var topRow = UIFactory.CreateHorizontalGroup(controlsObj, new Color(1, 1, 1, 0));
var topRowGroup = topRow.GetComponent<HorizontalLayoutGroup>();
topRowGroup.childForceExpandWidth = false;
topRowGroup.SetChildControlWidth(true);
topRowGroup.childForceExpandHeight = false;
topRowGroup.SetChildControlHeight(true);
topRowGroup.spacing = 5;
var topRow = UIFactory.CreateHorizontalGroup(mainGroup, "TopRow", false, false, true, true, 5, default, new Color(1, 1, 1, 0));
var hideButtonObj = UIFactory.CreateButton(topRow);
var hideButton = hideButtonObj.GetComponent<Button>();
var hideColors = hideButton.colors;
hideColors.normalColor = new Color(0.16f, 0.16f, 0.16f);
hideButton.colors = hideColors;
var hideText = hideButtonObj.GetComponentInChildren<Text>();
hideText.text = "Show";
hideText.fontSize = 14;
var hideButtonLayout = hideButtonObj.AddComponent<LayoutElement>();
hideButtonLayout.minWidth = 40;
hideButtonLayout.flexibleWidth = 0;
hideButtonLayout.minHeight = 25;
hideButtonLayout.flexibleHeight = 0;
var hideButton = UIFactory.CreateButton(topRow, "ToggleShowButton", "Show", ToggleVisibility, new Color(0.16f, 0.16f, 0.16f));
UIFactory.SetLayoutElement(hideButton.gameObject, minWidth: 40, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0);
m_hideShowLabel = hideButton.GetComponentInChildren<Text>();
var topTitle = UIFactory.CreateLabel(topRow, TextAnchor.MiddleLeft);
var topText = topTitle.GetComponent<Text>();
topText.text = "Controls";
var titleLayout = topTitle.AddComponent<LayoutElement>();
titleLayout.minWidth = 100;
titleLayout.flexibleWidth = 9500;
titleLayout.minHeight = 25;
var topTitle = UIFactory.CreateLabel(topRow, "ControlsLabel", "Controls", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(topTitle.gameObject, minWidth: 100, flexibleWidth: 9500, minHeight: 25);
//// ~~~~~~~~ Content ~~~~~~~~ //
var contentObj = UIFactory.CreateVerticalGroup(controlsObj, new Color(1, 1, 1, 0));
var contentGroup = contentObj.GetComponent<VerticalLayoutGroup>();
contentGroup.childForceExpandHeight = false;
contentGroup.SetChildControlHeight(true);
contentGroup.spacing = 5;
contentGroup.childForceExpandWidth = true;
contentGroup.SetChildControlWidth(true);
// ~~ add hide button callback now that we have scroll reference ~~
hideButton.onClick.AddListener(OnHideClicked);
void OnHideClicked()
{
if (hideText.text == "Show")
{
hideText.text = "Hide";
contentObj.SetActive(true);
}
else
{
hideText.text = "Show";
contentObj.SetActive(false);
}
}
m_contentObj = UIFactory.CreateVerticalGroup(mainGroup, "ContentGroup", true, false, true, true, 5, default, new Color(1, 1, 1, 0));
// transform controls
ConstructVector3Editor(contentObj, "Position", ControlType.position, out s_positionControl);
ConstructVector3Editor(contentObj, "Local Position", ControlType.localPosition, out s_localPosControl);
ConstructVector3Editor(contentObj, "Rotation", ControlType.eulerAngles, out s_rotationControl);
ConstructVector3Editor(contentObj, "Scale", ControlType.localScale, out s_scaleControl);
ConstructVector3Editor(m_contentObj, "Position", ControlType.position, out s_positionControl);
ConstructVector3Editor(m_contentObj, "Local Position", ControlType.localPosition, out s_localPosControl);
ConstructVector3Editor(m_contentObj, "Rotation", ControlType.eulerAngles, out s_rotationControl);
ConstructVector3Editor(m_contentObj, "Scale", ControlType.localScale, out s_scaleControl);
// set parent
ConstructSetParent(contentObj);
ConstructSetParent(m_contentObj);
// bottom row buttons
ConstructBottomButtons(contentObj);
ConstructBottomButtons(m_contentObj);
// set controls content inactive now that content is made (otherwise TMP font size goes way too big?)
contentObj.SetActive(false);
m_contentObj.SetActive(false);
}
internal void ConstructSetParent(GameObject contentObj)
{
var setParentGroupObj = UIFactory.CreateHorizontalGroup(contentObj, new Color(1, 1, 1, 0));
var setParentGroup = setParentGroupObj.GetComponent<HorizontalLayoutGroup>();
setParentGroup.childForceExpandHeight = false;
setParentGroup.SetChildControlHeight(true);
setParentGroup.childForceExpandWidth = false;
setParentGroup.SetChildControlWidth(true);
setParentGroup.spacing = 5;
var setParentLayout = setParentGroupObj.AddComponent<LayoutElement>();
setParentLayout.minHeight = 25;
setParentLayout.flexibleHeight = 0;
var setParentGroupObj = UIFactory.CreateHorizontalGroup(contentObj, "SetParentRow", false, false, true, true, 5, default,
new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(setParentGroupObj, minHeight: 25, flexibleHeight: 0);
var setParentLabelObj = UIFactory.CreateLabel(setParentGroupObj, TextAnchor.MiddleLeft);
var setParentLabel = setParentLabelObj.GetComponent<Text>();
setParentLabel.text = "Set Parent:";
setParentLabel.color = Color.grey;
setParentLabel.fontSize = 14;
var setParentLabelLayout = setParentLabelObj.AddComponent<LayoutElement>();
setParentLabelLayout.minWidth = 110;
setParentLabelLayout.minHeight = 25;
setParentLabelLayout.flexibleWidth = 0;
var title = UIFactory.CreateLabel(setParentGroupObj, "SetParentLabel", "Set Parent:", TextAnchor.MiddleLeft, Color.grey);
UIFactory.SetLayoutElement(title.gameObject, minWidth: 110, minHeight: 25, flexibleHeight: 0);
var setParentInputObj = UIFactory.CreateInputField(setParentGroupObj);
s_setParentInput = setParentInputObj.GetComponent<InputField>();
var placeholderInput = s_setParentInput.placeholder.GetComponent<Text>();
placeholderInput.text = "Enter a GameObject name or path...";
var setParentInputLayout = setParentInputObj.AddComponent<LayoutElement>();
setParentInputLayout.minHeight = 25;
setParentInputLayout.preferredWidth = 400;
setParentInputLayout.flexibleWidth = 9999;
var inputFieldObj = UIFactory.CreateInputField(setParentGroupObj, "SetParentInputField", "Enter a GameObject name or path...");
s_setParentInput = inputFieldObj.GetComponent<InputField>();
UIFactory.SetLayoutElement(inputFieldObj, minHeight: 25, preferredWidth: 400, flexibleWidth: 9999);
var applyButtonObj = UIFactory.CreateButton(setParentGroupObj);
var applyButton = applyButtonObj.GetComponent<Button>();
applyButton.onClick.AddListener(OnSetParentClicked);
var applyText = applyButtonObj.GetComponentInChildren<Text>();
applyText.text = "Apply";
var applyLayout = applyButtonObj.AddComponent<LayoutElement>();
applyLayout.minWidth = 55;
applyLayout.flexibleWidth = 0;
applyLayout.minHeight = 25;
applyLayout.flexibleHeight = 0;
var applyButton = UIFactory.CreateButton(setParentGroupObj, "SetParentButton", "Apply", OnSetParentClicked);
UIFactory.SetLayoutElement(applyButton.gameObject, minWidth: 55, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0);
}
internal void ConstructVector3Editor(GameObject parent, string title, ControlType type, out ControlEditor editor)
internal void ConstructVector3Editor(GameObject parent, string titleText, ControlType type, out ControlEditor editor)
{
editor = new ControlEditor();
var topBarObj = UIFactory.CreateHorizontalGroup(parent, new Color(1, 1, 1, 0));
var topGroup = topBarObj.GetComponent<HorizontalLayoutGroup>();
topGroup.childForceExpandWidth = false;
topGroup.SetChildControlWidth(true);
topGroup.childForceExpandHeight = false;
topGroup.SetChildControlHeight(true);
topGroup.spacing = 5;
var topLayout = topBarObj.AddComponent<LayoutElement>();
topLayout.minHeight = 25;
topLayout.flexibleHeight = 0;
var topBarObj = UIFactory.CreateHorizontalGroup(parent, "Vector3Editor", false, false, true, true, 5, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(topBarObj, minHeight: 25, flexibleHeight: 0);
var titleObj = UIFactory.CreateLabel(topBarObj, TextAnchor.MiddleLeft);
var titleText = titleObj.GetComponent<Text>();
titleText.text = title;
titleText.color = Color.grey;
titleText.fontSize = 14;
var titleLayout = titleObj.AddComponent<LayoutElement>();
titleLayout.minWidth = 110;
titleLayout.flexibleWidth = 0;
titleLayout.minHeight = 25;
var title = UIFactory.CreateLabel(topBarObj, "Title", titleText, TextAnchor.MiddleLeft, Color.grey);
UIFactory.SetLayoutElement(title.gameObject, minWidth: 110, flexibleWidth: 0, minHeight: 25);
// expand button
var expandButtonObj = UIFactory.CreateButton(topBarObj);
var expandButton = expandButtonObj.GetComponent<Button>();
var expandText = expandButtonObj.GetComponentInChildren<Text>();
expandText.text = "▼";
var expandButton = UIFactory.CreateButton(topBarObj, "ExpandArrow", "▼");
var expandText = expandButton.GetComponentInChildren<Text>();
expandText.fontSize = 12;
var btnLayout = expandButtonObj.AddComponent<LayoutElement>();
btnLayout.minWidth = 35;
btnLayout.flexibleWidth = 0;
btnLayout.minHeight = 25;
btnLayout.flexibleHeight = 0;
UIFactory.SetLayoutElement(expandButton.gameObject, minWidth: 35, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0);
// readonly value input
var valueInputObj = UIFactory.CreateInputField(topBarObj);
var valueInputObj = UIFactory.CreateInputField(topBarObj, "ValueInput", "...");
var valueInput = valueInputObj.GetComponent<InputField>();
valueInput.readOnly = true;
//valueInput.richText = true;
//valueInput.isRichTextEditingAllowed = true;
var valueInputLayout = valueInputObj.AddComponent<LayoutElement>();
valueInputLayout.minHeight = 25;
valueInputLayout.flexibleHeight = 0;
valueInputLayout.preferredWidth = 400;
valueInputLayout.flexibleWidth = 9999;
UIFactory.SetLayoutElement(valueInputObj, minHeight: 25, flexibleHeight: 0, preferredWidth: 400, flexibleWidth: 9999);
editor.fullValue = valueInput;
@ -459,86 +371,42 @@ namespace UnityExplorer.UI.Main.Home.Inspectors
internal GameObject ConstructEditorRow(GameObject parent, ControlEditor editor, ControlType type, VectorValue vectorValue)
{
var rowObject = UIFactory.CreateHorizontalGroup(parent, new Color(1, 1, 1, 0));
var rowGroup = rowObject.GetComponent<HorizontalLayoutGroup>();
rowGroup.childForceExpandWidth = false;
rowGroup.SetChildControlWidth(true);
rowGroup.childForceExpandHeight = false;
rowGroup.SetChildControlHeight(true);
rowGroup.spacing = 5;
var rowLayout = rowObject.AddComponent<LayoutElement>();
rowLayout.minHeight = 25;
rowLayout.flexibleHeight = 0;
rowLayout.minWidth = 100;
var rowObject = UIFactory.CreateHorizontalGroup(parent, "EditorRow", false, false, true, true, 5, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(rowObject, minHeight: 25, flexibleHeight: 0, minWidth: 100);
// Value labels
var labelObj = UIFactory.CreateLabel(rowObject, TextAnchor.MiddleLeft);
var labelText = labelObj.GetComponent<Text>();
labelText.color = Color.cyan;
labelText.text = $"{vectorValue.ToString().ToUpper()}:";
labelText.fontSize = 14;
labelText.resizeTextMaxSize = 14;
labelText.resizeTextForBestFit = true;
var labelLayout = labelObj.AddComponent<LayoutElement>();
labelLayout.minHeight = 25;
labelLayout.flexibleHeight = 0;
labelLayout.minWidth = 25;
labelLayout.flexibleWidth = 0;
var valueTitle = UIFactory.CreateLabel(rowObject, "ValueTitle", $"{vectorValue.ToString().ToUpper()}:", TextAnchor.MiddleLeft, Color.cyan);
UIFactory.SetLayoutElement(valueTitle.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 25, flexibleWidth: 0);
// actual value label
var valueLabelObj = UIFactory.CreateLabel(rowObject, TextAnchor.MiddleLeft);
var valueLabel = valueLabelObj.GetComponent<Text>();
var valueLabel = UIFactory.CreateLabel(rowObject, "ValueLabel", "<notset>", TextAnchor.MiddleLeft);
editor.values[(int)vectorValue] = valueLabel;
var valueLabelLayout = valueLabelObj.AddComponent<LayoutElement>();
valueLabelLayout.minWidth = 85;
valueLabelLayout.flexibleWidth = 0;
valueLabelLayout.minHeight = 25;
UIFactory.SetLayoutElement(valueLabel.gameObject, minWidth: 85, flexibleWidth: 0, minHeight: 25);
// input field
var inputHolder = UIFactory.CreateVerticalGroup(rowObject, new Color(1, 1, 1, 0));
var inputHolderGroup = inputHolder.GetComponent<VerticalLayoutGroup>();
inputHolderGroup.childForceExpandHeight = false;
inputHolderGroup.SetChildControlHeight(true);
inputHolderGroup.childForceExpandWidth = false;
inputHolderGroup.SetChildControlWidth(true);
var inputHolder = UIFactory.CreateVerticalGroup(rowObject, "InputFieldGroup", false, false, true, true, 0, default, new Color(1, 1, 1, 0));
var inputObj = UIFactory.CreateInputField(inputHolder);
var inputObj = UIFactory.CreateInputField(inputHolder, "InputField", "...");
var input = inputObj.GetComponent<InputField>();
input.characterValidation = InputField.CharacterValidation.Decimal;
//input.characterValidation = InputField.CharacterValidation.Decimal;
var inputLayout = inputObj.AddComponent<LayoutElement>();
inputLayout.minHeight = 25;
inputLayout.flexibleHeight = 0;
inputLayout.minWidth = 90;
inputLayout.flexibleWidth = 50;
UIFactory.SetLayoutElement(inputObj, minHeight: 25, flexibleHeight: 0, minWidth: 90, flexibleWidth: 50);
editor.inputs[(int)vectorValue] = input;
// apply button
var applyBtnObj = UIFactory.CreateButton(rowObject);
var applyBtn = applyBtnObj.GetComponent<Button>();
var applyText = applyBtnObj.GetComponentInChildren<Text>();
applyText.text = "Apply";
applyText.fontSize = 14;
var applyLayout = applyBtnObj.AddComponent<LayoutElement>();
applyLayout.minWidth = 60;
applyLayout.minHeight = 25;
var applyBtn = UIFactory.CreateButton(rowObject, "ApplyButton", "Apply", () => { OnVectorControlInputApplied(type, vectorValue); });
UIFactory.SetLayoutElement(applyBtn.gameObject, minWidth: 60, minHeight: 25);
applyBtn.onClick.AddListener(() => { OnVectorControlInputApplied(type, vectorValue); });
// Slider
var sliderObj = UIFactory.CreateSlider(rowObject);
var sliderObj = UIFactory.CreateSlider(rowObject, "VectorSlider", out Slider slider);
UIFactory.SetLayoutElement(sliderObj, minHeight: 20, flexibleHeight: 0, minWidth: 200, flexibleWidth: 9000);
sliderObj.transform.Find("Fill Area").gameObject.SetActive(false);
var sliderLayout = sliderObj.AddComponent<LayoutElement>();
sliderLayout.minHeight = 20;
sliderLayout.flexibleHeight = 0;
sliderLayout.minWidth = 200;
sliderLayout.flexibleWidth = 9000;
var slider = sliderObj.GetComponent<Slider>();
var sliderColors = slider.colors;
sliderColors.normalColor = new Color(0.65f, 0.65f, 0.65f);
slider.colors = sliderColors;
@ -553,24 +421,10 @@ namespace UnityExplorer.UI.Main.Home.Inspectors
internal void ConstructBottomButtons(GameObject contentObj)
{
var bottomRow = UIFactory.CreateHorizontalGroup(contentObj, new Color(1, 1, 1, 0));
var bottomGroup = bottomRow.GetComponent<HorizontalLayoutGroup>();
bottomGroup.childForceExpandWidth = true;
bottomGroup.SetChildControlWidth(true);
bottomGroup.spacing = 4;
var bottomLayout = bottomRow.AddComponent<LayoutElement>();
bottomLayout.minHeight = 25;
var bottomRow = UIFactory.CreateHorizontalGroup(contentObj, "BottomButtons", true, true, false, false, 4, default, new Color(1, 1, 1, 0));
var instantiateBtnObj = UIFactory.CreateButton(bottomRow, new Color(0.2f, 0.2f, 0.2f));
var instantiateBtn = instantiateBtnObj.GetComponent<Button>();
instantiateBtn.onClick.AddListener(InstantiateBtn);
var instantiateText = instantiateBtnObj.GetComponentInChildren<Text>();
instantiateText.text = "Instantiate";
instantiateText.fontSize = 14;
var instantiateLayout = instantiateBtnObj.AddComponent<LayoutElement>();
instantiateLayout.minWidth = 150;
var instantiateBtn = UIFactory.CreateButton(bottomRow, "InstantiateBtn", "Instantiate", InstantiateBtn, new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(instantiateBtn.gameObject, minWidth: 150);
void InstantiateBtn()
{
@ -582,16 +436,9 @@ namespace UnityExplorer.UI.Main.Home.Inspectors
InspectorManager.Instance.Inspect(clone);
}
var dontDestroyBtnObj = UIFactory.CreateButton(bottomRow, new Color(0.2f, 0.2f, 0.2f));
var dontDestroyBtn = dontDestroyBtnObj.GetComponent<Button>();
dontDestroyBtn.onClick.AddListener(DontDestroyOnLoadBtn);
var dontDestroyText = dontDestroyBtnObj.GetComponentInChildren<Text>();
dontDestroyText.text = "Set DontDestroyOnLoad";
dontDestroyText.fontSize = 14;
var dontDestroyLayout = dontDestroyBtnObj.AddComponent<LayoutElement>();
dontDestroyLayout.flexibleWidth = 5000;
var dontDestroyBtn = UIFactory.CreateButton(bottomRow, "DontDestroyButton", "Set DontDestroyOnLoad", DontDestroyOnLoadBtn,
new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(dontDestroyBtn.gameObject, flexibleWidth: 5000);
void DontDestroyOnLoadBtn()
{
@ -602,17 +449,10 @@ namespace UnityExplorer.UI.Main.Home.Inspectors
GameObject.DontDestroyOnLoad(go);
}
var destroyBtnObj = UIFactory.CreateButton(bottomRow, new Color(0.2f, 0.2f, 0.2f));
var destroyBtn = destroyBtnObj.GetComponent<Button>();
destroyBtn.onClick.AddListener(DestroyBtn);
var destroyText = destroyBtnObj.GetComponentInChildren<Text>();
destroyText.text = "Destroy";
destroyText.fontSize = 14;
var destroyBtn = UIFactory.CreateButton(bottomRow, "DestroyButton", "Destroy", DestroyBtn, new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(destroyBtn.gameObject, minWidth: 150);
var destroyText = destroyBtn.GetComponentInChildren<Text>();
destroyText.color = Color.red;
var destroyLayout = destroyBtnObj.AddComponent<LayoutElement>();
destroyLayout.minWidth = 150;
void DestroyBtn()
{
@ -624,6 +464,6 @@ namespace UnityExplorer.UI.Main.Home.Inspectors
}
}
#endregion
#endregion
}
}

View File

@ -0,0 +1,350 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Runtime;
using UnityExplorer.Core.Unity;
namespace UnityExplorer.UI.Main.Home.Inspectors.GameObjects
{
public class GameObjectInspector : InspectorBase
{
public override string TabLabel => $" <color=cyan>[G]</color> {TargetGO?.name}";
public static GameObjectInspector ActiveInstance { get; private set; }
public GameObject TargetGO;
// sub modules
internal static ChildList s_childList;
internal static ComponentList s_compList;
internal static GameObjectControls s_controls;
internal static bool m_UIConstructed;
public GameObjectInspector(GameObject target) : base(target)
{
ActiveInstance = this;
TargetGO = target;
if (!TargetGO)
{
ExplorerCore.LogWarning("Target GameObject is null!");
return;
}
// one UI is used for all gameobject inspectors. no point recreating it.
if (!m_UIConstructed)
{
m_UIConstructed = true;
s_childList = new ChildList();
s_compList = new ComponentList();
s_controls = new GameObjectControls();
ConstructUI();
}
}
public override void SetActive()
{
base.SetActive();
ActiveInstance = this;
}
public override void SetInactive()
{
base.SetInactive();
ActiveInstance = null;
}
internal void ChangeInspectorTarget(GameObject newTarget)
{
if (!newTarget)
return;
this.Target = this.TargetGO = newTarget;
}
// Update
public override void Update()
{
base.Update();
if (m_pendingDestroy || !this.IsActive)
return;
RefreshTopInfo();
s_childList.RefreshChildObjectList();
s_compList.RefreshComponentList();
s_controls.RefreshControls();
if (GameObjectControls.s_sliderChangedWanted)
GameObjectControls.UpdateSliderControl();
}
private static GameObject s_content;
public override GameObject Content
{
get => s_content;
set => s_content = value;
}
private static string m_lastName;
public static InputField m_nameInput;
private static string m_lastPath;
public static InputField m_pathInput;
private static RectTransform m_pathInputRect;
private static GameObject m_pathGroupObj;
private static Text m_hiddenPathText;
private static RectTransform m_hiddenPathRect;
private static Toggle m_enabledToggle;
private static Text m_enabledText;
private static bool? m_lastEnabledState;
private static Dropdown m_layerDropdown;
private static int m_lastLayer = -1;
private static Text m_sceneText;
private static string m_lastScene;
internal void RefreshTopInfo()
{
var target = TargetGO;
string name = target.name;
if (m_lastName != name)
{
m_lastName = name;
m_nameInput.text = m_lastName;
}
if (target.transform.parent)
{
if (!m_pathGroupObj.activeSelf)
m_pathGroupObj.SetActive(true);
var path = target.transform.GetTransformPath(true);
if (m_lastPath != path)
{
m_lastPath = path;
m_pathInput.text = path;
m_hiddenPathText.text = path;
LayoutRebuilder.ForceRebuildLayoutImmediate(m_pathInputRect);
LayoutRebuilder.ForceRebuildLayoutImmediate(m_hiddenPathRect);
}
}
else if (m_pathGroupObj.activeSelf)
m_pathGroupObj.SetActive(false);
if (m_lastEnabledState != target.activeSelf)
{
m_lastEnabledState = target.activeSelf;
m_enabledToggle.isOn = target.activeSelf;
m_enabledText.text = target.activeSelf ? "Enabled" : "Disabled";
m_enabledText.color = target.activeSelf ? Color.green : Color.red;
}
if (m_lastLayer != target.layer)
{
m_lastLayer = target.layer;
m_layerDropdown.value = target.layer;
}
if (string.IsNullOrEmpty(m_lastScene) || m_lastScene != target.scene.name)
{
m_lastScene = target.scene.name;
if (!string.IsNullOrEmpty(target.scene.name))
m_sceneText.text = m_lastScene;
else
m_sceneText.text = "None (Asset/Resource)";
}
}
// UI Callbacks
private static void OnApplyNameClicked()
{
if (ActiveInstance == null)
return;
ActiveInstance.TargetGO.name = m_nameInput.text;
}
private static void OnEnableToggled(bool enabled)
{
if (ActiveInstance == null)
return;
ActiveInstance.TargetGO.SetActive(enabled);
}
private static void OnLayerSelected(int layer)
{
if (ActiveInstance == null)
return;
ActiveInstance.TargetGO.layer = layer;
}
internal static void OnBackButtonClicked()
{
if (ActiveInstance == null)
return;
ActiveInstance.ChangeInspectorTarget(ActiveInstance.TargetGO.transform.parent.gameObject);
}
#region UI CONSTRUCTION
internal void ConstructUI()
{
var parent = InspectorManager.m_inspectorContent;
s_content = UIFactory.CreateScrollView(parent, "GameObjectInspector_Content", out GameObject scrollContent, out _,
new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(scrollContent.transform.parent.gameObject, true, true, true, true);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(scrollContent, true, true, true, true, 5);
var contentFitter = scrollContent.GetComponent<ContentSizeFitter>();
contentFitter.verticalFit = ContentSizeFitter.FitMode.Unconstrained;
ConstructTopArea(scrollContent);
s_controls.ConstructControls(scrollContent);
var midGroupObj = ConstructMidGroup(scrollContent);
s_childList.ConstructChildList(midGroupObj);
s_compList.ConstructCompList(midGroupObj);
LayoutRebuilder.ForceRebuildLayoutImmediate(s_content.GetComponent<RectTransform>());
Canvas.ForceUpdateCanvases();
}
private void ConstructTopArea(GameObject scrollContent)
{
// path row
m_pathGroupObj = UIFactory.CreateHorizontalGroup(scrollContent, "TopArea", false, false, true, true, 5, default, new Color(0.1f, 0.1f, 0.1f));
var pathRect = m_pathGroupObj.GetComponent<RectTransform>();
pathRect.sizeDelta = new Vector2(pathRect.sizeDelta.x, 20);
UIFactory.SetLayoutElement(m_pathGroupObj, minHeight: 20, flexibleHeight: 75);
// Back button
var backButton = UIFactory.CreateButton(m_pathGroupObj, "BackButton", "◄", OnBackButtonClicked, new Color(0.15f, 0.15f, 0.15f));
UIFactory.SetLayoutElement(backButton.gameObject, minWidth: 55, flexibleWidth: 0, minHeight: 25, flexibleHeight: 0);
m_hiddenPathText = UIFactory.CreateLabel(m_pathGroupObj, "HiddenPathText", "", TextAnchor.MiddleLeft);
m_hiddenPathText.color = Color.clear;
m_hiddenPathText.fontSize = 14;
m_hiddenPathText.raycastTarget = false;
var hiddenFitter = m_hiddenPathText.gameObject.AddComponent<ContentSizeFitter>();
hiddenFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
UIFactory.SetLayoutElement(m_hiddenPathText.gameObject, minHeight: 25, flexibleHeight: 125, minWidth: 250, flexibleWidth: 9000);
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(m_hiddenPathText.gameObject, true, true, true, true);
// Path input
var pathInputObj = UIFactory.CreateInputField(m_hiddenPathText.gameObject, "PathInputField", "...");
UIFactory.SetLayoutElement(pathInputObj, minHeight: 25, flexibleHeight: 75, preferredWidth: 400, flexibleWidth: 9999);
var pathInputRect = pathInputObj.GetComponent<RectTransform>();
pathInputRect.sizeDelta = new Vector2(pathInputRect.sizeDelta.x, 25);
m_pathInput = pathInputObj.GetComponent<InputField>();
m_pathInput.text = ActiveInstance.TargetGO.transform.GetTransformPath();
m_pathInput.readOnly = true;
m_pathInput.lineType = InputField.LineType.MultiLineNewline;
m_pathInput.textComponent.color = new Color(0.75f, 0.75f, 0.75f);
var textRect = m_pathInput.textComponent.GetComponent<RectTransform>();
textRect.offsetMin = new Vector2(3, 3);
textRect.offsetMax = new Vector2(3, 3);
m_pathInputRect = m_pathInput.GetComponent<RectTransform>();
m_hiddenPathRect = m_hiddenPathText.GetComponent<RectTransform>();
// name and enabled row
var nameRowObj = UIFactory.CreateHorizontalGroup(scrollContent, "NameGroup", false, false, true, true, 5, default, new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutElement(nameRowObj, minHeight: 25, flexibleHeight: 0);
var nameRect = nameRowObj.GetComponent<RectTransform>();
nameRect.sizeDelta = new Vector2(nameRect.sizeDelta.x, 25);
var nameLabel = UIFactory.CreateLabel(nameRowObj, "NameLabel", "Name:", TextAnchor.MiddleCenter, Color.grey, true, 14);
UIFactory.SetLayoutElement(nameLabel.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 55, flexibleWidth: 0);
var nameInputObj = UIFactory.CreateInputField(nameRowObj, "NameInput", "...");
var nameInputRect = nameInputObj.GetComponent<RectTransform>();
nameInputRect.sizeDelta = new Vector2(nameInputRect.sizeDelta.x, 25);
m_nameInput = nameInputObj.GetComponent<InputField>();
m_nameInput.text = ActiveInstance.TargetGO.name;
var applyNameBtn = UIFactory.CreateButton(nameRowObj, "ApplyNameButton", "Apply", OnApplyNameClicked);
UIFactory.SetLayoutElement(applyNameBtn.gameObject, minWidth: 65, minHeight: 25, flexibleHeight: 0);
var applyNameRect = applyNameBtn.GetComponent<RectTransform>();
applyNameRect.sizeDelta = new Vector2(applyNameRect.sizeDelta.x, 25);
var activeLabel = UIFactory.CreateLabel(nameRowObj, "ActiveLabel", "Active:", TextAnchor.MiddleCenter, Color.grey, true, 14);
UIFactory.SetLayoutElement(activeLabel.gameObject, minWidth: 55, minHeight: 25);
var enabledToggleObj = UIFactory.CreateToggle(nameRowObj, "EnabledToggle", out m_enabledToggle, out m_enabledText);
UIFactory.SetLayoutElement(enabledToggleObj, minHeight: 25, minWidth: 100, flexibleWidth: 0);
m_enabledText.text = "Enabled";
m_enabledText.color = Color.green;
m_enabledToggle.onValueChanged.AddListener(OnEnableToggled);
// layer and scene row
var sceneLayerRow = UIFactory.CreateHorizontalGroup(scrollContent, "SceneLayerRow", false, true, true, true, 5, default, new Color(0.1f, 0.1f, 0.1f));
// layer
var layerLabel = UIFactory.CreateLabel(sceneLayerRow, "LayerLabel", "Layer:", TextAnchor.MiddleCenter, Color.grey, true, 14);
UIFactory.SetLayoutElement(layerLabel.gameObject, minWidth: 55, flexibleWidth: 0);
var layerDropdownObj = UIFactory.CreateDropdown(sceneLayerRow, out m_layerDropdown, "<notset>", 14, OnLayerSelected);
m_layerDropdown.options.Clear();
for (int i = 0; i < 32; i++)
{
var layer = RuntimeProvider.Instance.LayerToName(i);
m_layerDropdown.options.Add(new Dropdown.OptionData { text = $"{i}: {layer}" });
}
UIFactory.SetLayoutElement(layerDropdownObj, minWidth: 120, flexibleWidth: 2000, minHeight: 25);
// scene
var sceneLabel = UIFactory.CreateLabel(sceneLayerRow, "SceneLabel", "Scene:", TextAnchor.MiddleCenter, Color.grey, true, 14);
UIFactory.SetLayoutElement(sceneLabel.gameObject, minWidth: 55, flexibleWidth: 0);
m_sceneText = UIFactory.CreateLabel(sceneLayerRow, "SceneText", "<notset>", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(m_sceneText.gameObject, minWidth: 120, flexibleWidth: 2000);
}
private GameObject ConstructMidGroup(GameObject parent)
{
var midGroupObj = UIFactory.CreateHorizontalGroup(parent, "MidGroup", true, true, true, true, 5, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(midGroupObj, minHeight: 300, flexibleHeight: 3000);
return midGroupObj;
}
#endregion
}
}

View File

@ -1,378 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Unity;
using UnityExplorer.Core.Inspectors;
using UnityExplorer.Core.Runtime;
namespace UnityExplorer.UI.Main.Home.Inspectors
{
public class GameObjectInspectorUI : InspectorBaseUI
{
private static GameObject s_content;
public override GameObject Content
{
get => s_content;
set => s_content = value;
}
private static string m_lastName;
public static InputField m_nameInput;
private static string m_lastPath;
public static InputField m_pathInput;
private static RectTransform m_pathInputRect;
private static GameObject m_pathGroupObj;
private static Text m_hiddenPathText;
private static RectTransform m_hiddenPathRect;
private static Toggle m_enabledToggle;
private static Text m_enabledText;
private static bool? m_lastEnabledState;
private static Dropdown m_layerDropdown;
private static int m_lastLayer = -1;
private static Text m_sceneText;
private static string m_lastScene;
internal void RefreshTopInfo()
{
var target = GameObjectInspector.ActiveInstance.TargetGO;
string name = target.name;
if (m_lastName != name)
{
m_lastName = name;
m_nameInput.text = m_lastName;
}
if (target.transform.parent)
{
if (!m_pathGroupObj.activeSelf)
m_pathGroupObj.SetActive(true);
var path = target.transform.GetTransformPath(true);
if (m_lastPath != path)
{
m_lastPath = path;
m_pathInput.text = path;
m_hiddenPathText.text = path;
LayoutRebuilder.ForceRebuildLayoutImmediate(m_pathInputRect);
LayoutRebuilder.ForceRebuildLayoutImmediate(m_hiddenPathRect);
}
}
else if (m_pathGroupObj.activeSelf)
m_pathGroupObj.SetActive(false);
if (m_lastEnabledState != target.activeSelf)
{
m_lastEnabledState = target.activeSelf;
m_enabledToggle.isOn = target.activeSelf;
m_enabledText.text = target.activeSelf ? "Enabled" : "Disabled";
m_enabledText.color = target.activeSelf ? Color.green : Color.red;
}
if (m_lastLayer != target.layer)
{
m_lastLayer = target.layer;
m_layerDropdown.value = target.layer;
}
if (string.IsNullOrEmpty(m_lastScene) || m_lastScene != target.scene.name)
{
m_lastScene = target.scene.name;
if (!string.IsNullOrEmpty(target.scene.name))
m_sceneText.text = m_lastScene;
else
m_sceneText.text = "None (Asset/Resource)";
}
}
// UI Callbacks
private static void OnApplyNameClicked()
{
if (GameObjectInspector.ActiveInstance == null)
return;
GameObjectInspector.ActiveInstance.TargetGO.name = m_nameInput.text;
}
private static void OnEnableToggled(bool enabled)
{
if (GameObjectInspector.ActiveInstance == null)
return;
GameObjectInspector.ActiveInstance.TargetGO.SetActive(enabled);
}
private static void OnLayerSelected(int layer)
{
if (GameObjectInspector.ActiveInstance == null)
return;
GameObjectInspector.ActiveInstance.TargetGO.layer = layer;
}
internal static void OnBackButtonClicked()
{
if (GameObjectInspector.ActiveInstance == null)
return;
GameObjectInspector.ActiveInstance.ChangeInspectorTarget(
GameObjectInspector.ActiveInstance.TargetGO.transform.parent.gameObject);
}
#region UI CONSTRUCTION
internal void ConstructUI()
{
var parent = InspectorManager.UI.m_inspectorContent;
s_content = UIFactory.CreateScrollView(parent, out GameObject scrollContent, out _, new Color(0.1f, 0.1f, 0.1f));
var parentLayout = scrollContent.transform.parent.gameObject.AddComponent<VerticalLayoutGroup>();
parentLayout.childForceExpandWidth = true;
parentLayout.SetChildControlWidth(true);
parentLayout.childForceExpandHeight = true;
parentLayout.SetChildControlHeight(true);
var scrollGroup = scrollContent.GetComponent<VerticalLayoutGroup>();
scrollGroup.childForceExpandHeight = true;
scrollGroup.SetChildControlHeight(true);
scrollGroup.childForceExpandWidth = true;
scrollGroup.SetChildControlWidth(true);
scrollGroup.spacing = 5;
var contentFitter = scrollContent.GetComponent<ContentSizeFitter>();
contentFitter.verticalFit = ContentSizeFitter.FitMode.Unconstrained;
ConstructTopArea(scrollContent);
GameObjectInspector.s_controls.ConstructControls(scrollContent);
var midGroupObj = ConstructMidGroup(scrollContent);
GameObjectInspector.s_childList.ConstructChildList(midGroupObj);
GameObjectInspector.s_compList.ConstructCompList(midGroupObj);
LayoutRebuilder.ForceRebuildLayoutImmediate(s_content.GetComponent<RectTransform>());
Canvas.ForceUpdateCanvases();
}
private void ConstructTopArea(GameObject scrollContent)
{
// path row
m_pathGroupObj = UIFactory.CreateHorizontalGroup(scrollContent, new Color(0.1f, 0.1f, 0.1f));
var pathGroup = m_pathGroupObj.GetComponent<HorizontalLayoutGroup>();
pathGroup.childForceExpandHeight = false;
pathGroup.childForceExpandWidth = false;
pathGroup.SetChildControlHeight(false);
pathGroup.SetChildControlWidth(true);
pathGroup.spacing = 5;
var pathRect = m_pathGroupObj.GetComponent<RectTransform>();
pathRect.sizeDelta = new Vector2(pathRect.sizeDelta.x, 20);
var pathLayout = m_pathGroupObj.AddComponent<LayoutElement>();
pathLayout.minHeight = 20;
pathLayout.flexibleHeight = 75;
var backButtonObj = UIFactory.CreateButton(m_pathGroupObj);
var backButton = backButtonObj.GetComponent<Button>();
backButton.onClick.AddListener(OnBackButtonClicked);
var backColors = backButton.colors;
backColors.normalColor = new Color(0.15f, 0.15f, 0.15f);
backButton.colors = backColors;
var backText = backButtonObj.GetComponentInChildren<Text>();
backText.text = "◄";
var backLayout = backButtonObj.AddComponent<LayoutElement>();
backLayout.minWidth = 55;
backLayout.flexibleWidth = 0;
backLayout.minHeight = 25;
backLayout.flexibleHeight = 0;
var pathHiddenTextObj = UIFactory.CreateLabel(m_pathGroupObj, TextAnchor.MiddleLeft);
m_hiddenPathText = pathHiddenTextObj.GetComponent<Text>();
m_hiddenPathText.color = Color.clear;
m_hiddenPathText.fontSize = 14;
//m_hiddenPathText.lineSpacing = 1.5f;
m_hiddenPathText.raycastTarget = false;
var hiddenFitter = pathHiddenTextObj.AddComponent<ContentSizeFitter>();
hiddenFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
var hiddenLayout = pathHiddenTextObj.AddComponent<LayoutElement>();
hiddenLayout.minHeight = 25;
hiddenLayout.flexibleHeight = 125;
hiddenLayout.minWidth = 250;
hiddenLayout.flexibleWidth = 9000;
var hiddenGroup = pathHiddenTextObj.AddComponent<HorizontalLayoutGroup>();
hiddenGroup.childForceExpandWidth = true;
hiddenGroup.SetChildControlWidth(true);
hiddenGroup.childForceExpandHeight = true;
hiddenGroup.SetChildControlHeight(true);
var pathInputObj = UIFactory.CreateInputField(pathHiddenTextObj);
var pathInputRect = pathInputObj.GetComponent<RectTransform>();
pathInputRect.sizeDelta = new Vector2(pathInputRect.sizeDelta.x, 25);
m_pathInput = pathInputObj.GetComponent<InputField>();
m_pathInput.text = GameObjectInspector.ActiveInstance.TargetGO.transform.GetTransformPath();
m_pathInput.readOnly = true;
m_pathInput.lineType = InputField.LineType.MultiLineNewline;
var pathInputLayout = pathInputObj.AddComponent<LayoutElement>();
pathInputLayout.minHeight = 25;
pathInputLayout.flexibleHeight = 75;
pathInputLayout.preferredWidth = 400;
pathInputLayout.flexibleWidth = 9999;
var textRect = m_pathInput.textComponent.GetComponent<RectTransform>();
textRect.offsetMin = new Vector2(3, 3);
textRect.offsetMax = new Vector2(3, 3);
m_pathInput.textComponent.color = new Color(0.75f, 0.75f, 0.75f);
//m_pathInput.textComponent.lineSpacing = 1.5f;
m_pathInputRect = m_pathInput.GetComponent<RectTransform>();
m_hiddenPathRect = m_hiddenPathText.GetComponent<RectTransform>();
// name row
var nameRowObj = UIFactory.CreateHorizontalGroup(scrollContent, new Color(0.1f, 0.1f, 0.1f));
var nameGroup = nameRowObj.GetComponent<HorizontalLayoutGroup>();
nameGroup.childForceExpandHeight = false;
nameGroup.childForceExpandWidth = false;
nameGroup.SetChildControlHeight(true);
nameGroup.SetChildControlWidth(true);
nameGroup.spacing = 5;
var nameRect = nameRowObj.GetComponent<RectTransform>();
nameRect.sizeDelta = new Vector2(nameRect.sizeDelta.x, 25);
var nameLayout = nameRowObj.AddComponent<LayoutElement>();
nameLayout.minHeight = 25;
nameLayout.flexibleHeight = 0;
var nameTextObj = UIFactory.CreateLabel(nameRowObj, TextAnchor.MiddleCenter);
var nameTextText = nameTextObj.GetComponent<Text>();
nameTextText.text = "Name:";
nameTextText.fontSize = 14;
nameTextText.color = Color.grey;
var nameTextLayout = nameTextObj.AddComponent<LayoutElement>();
nameTextLayout.minHeight = 25;
nameTextLayout.flexibleHeight = 0;
nameTextLayout.minWidth = 55;
nameTextLayout.flexibleWidth = 0;
var nameInputObj = UIFactory.CreateInputField(nameRowObj);
var nameInputRect = nameInputObj.GetComponent<RectTransform>();
nameInputRect.sizeDelta = new Vector2(nameInputRect.sizeDelta.x, 25);
m_nameInput = nameInputObj.GetComponent<InputField>();
m_nameInput.text = GameObjectInspector.ActiveInstance.TargetGO.name;
var applyNameBtnObj = UIFactory.CreateButton(nameRowObj);
var applyNameBtn = applyNameBtnObj.GetComponent<Button>();
applyNameBtn.onClick.AddListener(OnApplyNameClicked);
var applyNameText = applyNameBtnObj.GetComponentInChildren<Text>();
applyNameText.text = "Apply";
applyNameText.fontSize = 14;
var applyNameLayout = applyNameBtnObj.AddComponent<LayoutElement>();
applyNameLayout.minWidth = 65;
applyNameLayout.minHeight = 25;
applyNameLayout.flexibleHeight = 0;
var applyNameRect = applyNameBtnObj.GetComponent<RectTransform>();
applyNameRect.sizeDelta = new Vector2(applyNameRect.sizeDelta.x, 25);
var activeLabel = UIFactory.CreateLabel(nameRowObj, TextAnchor.MiddleCenter);
var activeLabelLayout = activeLabel.AddComponent<LayoutElement>();
activeLabelLayout.minWidth = 55;
activeLabelLayout.minHeight = 25;
var activeText = activeLabel.GetComponent<Text>();
activeText.text = "Active:";
activeText.color = Color.grey;
activeText.fontSize = 14;
var enabledToggleObj = UIFactory.CreateToggle(nameRowObj, out m_enabledToggle, out m_enabledText);
var toggleLayout = enabledToggleObj.AddComponent<LayoutElement>();
toggleLayout.minHeight = 25;
toggleLayout.minWidth = 100;
toggleLayout.flexibleWidth = 0;
m_enabledText.text = "Enabled";
m_enabledText.color = Color.green;
m_enabledToggle.onValueChanged.AddListener(OnEnableToggled);
// layer and scene row
var sceneLayerRow = UIFactory.CreateHorizontalGroup(scrollContent, new Color(0.1f, 0.1f, 0.1f));
var sceneLayerGroup = sceneLayerRow.GetComponent<HorizontalLayoutGroup>();
sceneLayerGroup.childForceExpandWidth = false;
sceneLayerGroup.SetChildControlWidth(true);
sceneLayerGroup.spacing = 5;
var layerLabel = UIFactory.CreateLabel(sceneLayerRow, TextAnchor.MiddleCenter);
var layerText = layerLabel.GetComponent<Text>();
layerText.text = "Layer:";
layerText.fontSize = 14;
layerText.color = Color.grey;
var layerTextLayout = layerLabel.AddComponent<LayoutElement>();
layerTextLayout.minWidth = 55;
layerTextLayout.flexibleWidth = 0;
var layerDropdownObj = UIFactory.CreateDropdown(sceneLayerRow, out m_layerDropdown);
m_layerDropdown.options.Clear();
for (int i = 0; i < 32; i++)
{
var layer = RuntimeProvider.Instance.LayerToName(i);
m_layerDropdown.options.Add(new Dropdown.OptionData { text = $"{i}: {layer}" });
}
//var itemText = layerDropdownObj.transform.Find("Label").GetComponent<Text>();
//itemText.resizeTextForBestFit = true;
var layerDropdownLayout = layerDropdownObj.AddComponent<LayoutElement>();
layerDropdownLayout.minWidth = 120;
layerDropdownLayout.flexibleWidth = 2000;
layerDropdownLayout.minHeight = 25;
m_layerDropdown.onValueChanged.AddListener(OnLayerSelected);
var scenelabelObj = UIFactory.CreateLabel(sceneLayerRow, TextAnchor.MiddleCenter);
var sceneLabel = scenelabelObj.GetComponent<Text>();
sceneLabel.text = "Scene:";
sceneLabel.color = Color.grey;
sceneLabel.fontSize = 14;
var sceneLabelLayout = scenelabelObj.AddComponent<LayoutElement>();
sceneLabelLayout.minWidth = 55;
sceneLabelLayout.flexibleWidth = 0;
var objectSceneText = UIFactory.CreateLabel(sceneLayerRow, TextAnchor.MiddleLeft);
m_sceneText = objectSceneText.GetComponent<Text>();
m_sceneText.fontSize = 14;
m_sceneText.horizontalOverflow = HorizontalWrapMode.Overflow;
var sceneTextLayout = objectSceneText.AddComponent<LayoutElement>();
sceneTextLayout.minWidth = 120;
sceneTextLayout.flexibleWidth = 2000;
}
private GameObject ConstructMidGroup(GameObject parent)
{
var midGroupObj = UIFactory.CreateHorizontalGroup(parent, new Color(1, 1, 1, 0));
var midGroup = midGroupObj.GetComponent<HorizontalLayoutGroup>();
midGroup.spacing = 5;
midGroup.childForceExpandWidth = true;
midGroup.SetChildControlWidth(true);
midGroup.childForceExpandHeight = true;
midGroup.SetChildControlHeight(true);
var midLayout = midGroupObj.AddComponent<LayoutElement>();
midLayout.minHeight = 300;
midLayout.flexibleHeight = 5000;
return midGroupObj;
}
#endregion
}
}

View File

@ -0,0 +1,120 @@
using System;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Unity;
namespace UnityExplorer.UI.Main.Home.Inspectors
{
public abstract class InspectorBase
{
public object Target;
public bool IsActive { get; private set; }
public abstract string TabLabel { get; }
internal bool m_pendingDestroy;
public InspectorBase(object target)
{
Target = target;
if (Target.IsNullOrDestroyed(false))
{
Destroy();
return;
}
AddInspectorTab(this);
}
public virtual void SetActive()
{
this.IsActive = true;
Content?.SetActive(true);
}
public virtual void SetInactive()
{
this.IsActive = false;
Content?.SetActive(false);
}
public virtual void Update()
{
if (Target.IsNullOrDestroyed(false))
{
Destroy();
return;
}
m_tabText.text = TabLabel;
}
public virtual void Destroy()
{
m_pendingDestroy = true;
GameObject tabGroup = m_tabButton?.transform.parent.gameObject;
if (tabGroup)
GameObject.Destroy(tabGroup);
int thisIndex = -1;
if (InspectorManager.Instance.m_currentInspectors.Contains(this))
{
thisIndex = InspectorManager.Instance.m_currentInspectors.IndexOf(this);
InspectorManager.Instance.m_currentInspectors.Remove(this);
}
if (ReferenceEquals(InspectorManager.Instance.m_activeInspector, this))
{
InspectorManager.Instance.UnsetInspectorTab();
if (InspectorManager.Instance.m_currentInspectors.Count > 0)
{
var prevTab = InspectorManager.Instance.m_currentInspectors[thisIndex > 0 ? thisIndex - 1 : 0];
InspectorManager.Instance.SetInspectorTab(prevTab);
}
}
}
#region UI
public abstract GameObject Content { get; set; }
public Button m_tabButton;
public Text m_tabText;
public void AddInspectorTab(InspectorBase parent)
{
var tabContent = InspectorManager.m_tabBarContent;
var tabGroupObj = UIFactory.CreateHorizontalGroup(tabContent, "TabObject", true, true, true, true);
UIFactory.SetLayoutElement(tabGroupObj, minWidth: 185, flexibleWidth: 0);
tabGroupObj.AddComponent<Mask>();
m_tabButton = UIFactory.CreateButton(tabGroupObj,
"TabButton",
"<notset>",
() => { InspectorManager.Instance.SetInspectorTab(parent); });
UIFactory.SetLayoutElement(m_tabButton.gameObject, minWidth: 165, flexibleWidth: 0);
m_tabText = m_tabButton.GetComponentInChildren<Text>();
m_tabText.horizontalOverflow = HorizontalWrapMode.Overflow;
m_tabText.alignment = TextAnchor.MiddleLeft;
var closeBtn = UIFactory.CreateButton(tabGroupObj,
"CloseButton",
"X",
parent.Destroy,
new Color(0.2f, 0.2f, 0.2f, 1));
UIFactory.SetLayoutElement(closeBtn.gameObject, minWidth: 20, flexibleWidth: 0);
var closeBtnText = closeBtn.GetComponentInChildren<Text>();
closeBtnText.color = new Color(1, 0, 0, 1);
}
#endregion
}
}

View File

@ -1,61 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Inspectors;
namespace UnityExplorer.UI.Main.Home.Inspectors
{
public abstract class InspectorBaseUI
{
public abstract GameObject Content { get; set; }
public Button tabButton;
public Text tabText;
public void AddInspectorTab(InspectorBase parent)
{
var tabContent = InspectorManager.UI.m_tabBarContent;
var tabGroupObj = UIFactory.CreateHorizontalGroup(tabContent);
var tabGroup = tabGroupObj.GetComponent<HorizontalLayoutGroup>();
tabGroup.childForceExpandWidth = true;
tabGroup.SetChildControlWidth(true);
var tabLayout = tabGroupObj.AddComponent<LayoutElement>();
tabLayout.minWidth = 185;
tabLayout.flexibleWidth = 0;
tabGroupObj.AddComponent<Mask>();
var targetButtonObj = UIFactory.CreateButton(tabGroupObj);
targetButtonObj.AddComponent<Mask>();
var targetButtonLayout = targetButtonObj.AddComponent<LayoutElement>();
targetButtonLayout.minWidth = 165;
targetButtonLayout.flexibleWidth = 0;
tabText = targetButtonObj.GetComponentInChildren<Text>();
tabText.horizontalOverflow = HorizontalWrapMode.Overflow;
tabText.alignment = TextAnchor.MiddleLeft;
tabButton = targetButtonObj.GetComponent<Button>();
tabButton.onClick.AddListener(() => { InspectorManager.Instance.SetInspectorTab(parent); });
var closeBtnObj = UIFactory.CreateButton(tabGroupObj);
var closeBtnLayout = closeBtnObj.AddComponent<LayoutElement>();
closeBtnLayout.minWidth = 20;
closeBtnLayout.flexibleWidth = 0;
var closeBtnText = closeBtnObj.GetComponentInChildren<Text>();
closeBtnText.text = "X";
closeBtnText.color = new Color(1, 0, 0, 1);
var closeBtn = closeBtnObj.GetComponent<Button>();
closeBtn.onClick.AddListener(parent.Destroy);
var closeColors = closeBtn.colors;
closeColors.normalColor = new Color(0.2f, 0.2f, 0.2f, 1);
closeBtn.colors = closeColors;
}
}
}

View File

@ -1,69 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
namespace UnityExplorer.UI.Main.Home.Inspectors
{
public class MouseInspectorUI
{
internal Text s_objNameLabel;
internal Text s_objPathLabel;
internal Text s_mousePosLabel;
internal GameObject s_UIContent;
public MouseInspectorUI()
{
ConstructUI();
}
#region UI Construction
internal void ConstructUI()
{
s_UIContent = UIFactory.CreatePanel(UIManager.CanvasRoot, "MouseInspect", out GameObject content);
s_UIContent.AddComponent<Mask>();
var baseRect = s_UIContent.GetComponent<RectTransform>();
var half = new Vector2(0.5f, 0.5f);
baseRect.anchorMin = half;
baseRect.anchorMax = half;
baseRect.pivot = half;
baseRect.sizeDelta = new Vector2(700, 150);
var group = content.GetComponent<VerticalLayoutGroup>();
group.childForceExpandHeight = true;
// Title text
var titleObj = UIFactory.CreateLabel(content, TextAnchor.MiddleCenter);
var titleText = titleObj.GetComponent<Text>();
titleText.text = "<b>Mouse Inspector</b> (press <b>ESC</b> to cancel)";
var mousePosObj = UIFactory.CreateLabel(content, TextAnchor.MiddleCenter);
s_mousePosLabel = mousePosObj.GetComponent<Text>();
s_mousePosLabel.text = "Mouse Position:";
var hitLabelObj = UIFactory.CreateLabel(content, TextAnchor.MiddleLeft);
s_objNameLabel = hitLabelObj.GetComponent<Text>();
s_objNameLabel.text = "No hits...";
s_objNameLabel.horizontalOverflow = HorizontalWrapMode.Overflow;
var pathLabelObj = UIFactory.CreateLabel(content, TextAnchor.MiddleLeft);
s_objPathLabel = pathLabelObj.GetComponent<Text>();
s_objPathLabel.fontStyle = FontStyle.Italic;
s_objPathLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
var pathLayout = pathLabelObj.AddComponent<LayoutElement>();
pathLayout.minHeight = 75;
pathLayout.flexibleHeight = 0;
s_UIContent.SetActive(false);
}
#endregion
}
}

View File

@ -0,0 +1,262 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core;
using UnityExplorer.Core.Config;
using UnityExplorer.Core.Runtime;
namespace UnityExplorer.UI.Main.Home.Inspectors.Reflection
{
public enum MemberScopes
{
All,
Instance,
Static
}
public class InstanceInspector : ReflectionInspector
{
public override string TabLabel => $" <color=cyan>[R]</color> {base.TabLabel}";
internal MemberScopes m_scopeFilter;
internal Button m_lastActiveScopeButton;
public InstanceInspector(object target) : base(target) { }
internal void OnScopeFilterClicked(MemberScopes type, Button button)
{
if (m_lastActiveScopeButton)
{
var lastColors = m_lastActiveScopeButton.colors;
lastColors.normalColor = new Color(0.2f, 0.2f, 0.2f);
m_lastActiveScopeButton.colors = lastColors;
}
m_scopeFilter = type;
m_lastActiveScopeButton = button;
var colors = m_lastActiveScopeButton.colors;
colors.normalColor = new Color(0.2f, 0.6f, 0.2f);
m_lastActiveScopeButton.colors = colors;
FilterMembers(null, true);
m_sliderScroller.m_slider.value = 1f;
}
public void ConstructUnityInstanceHelpers()
{
if (!typeof(UnityEngine.Object).IsAssignableFrom(m_targetType))
return;
var rowObj = UIFactory.CreateHorizontalGroup(Content, "InstanceHelperRow", true, true, true, true, 5, new Vector4(2,2,2,2),
new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleWidth: 5000);
if (typeof(Component).IsAssignableFrom(m_targetType))
ConstructCompHelper(rowObj);
ConstructUnityObjHelper(rowObj);
if (m_targetType == typeof(Texture2D))
ConstructTextureHelper();
}
internal void ConstructCompHelper(GameObject rowObj)
{
var gameObjectLabel = UIFactory.CreateLabel(rowObj, "GameObjectLabel", "GameObject:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(gameObjectLabel.gameObject, minWidth: 90, minHeight: 25, flexibleWidth: 0);
var comp = Target.Cast(typeof(Component)) as Component;
var btn = UIFactory.CreateButton(rowObj,
"GameObjectButton",
comp.name,
() => { InspectorManager.Instance.Inspect(comp.gameObject); },
new Color(0.2f, 0.5f, 0.2f));
UIFactory.SetLayoutElement(btn.gameObject, minHeight: 25, minWidth: 200, flexibleWidth: 0);
}
internal void ConstructUnityObjHelper(GameObject rowObj)
{
var label = UIFactory.CreateLabel(rowObj, "NameLabel", "Name:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(label.gameObject, minWidth: 60, minHeight: 25, flexibleWidth: 0);
var uObj = Target.Cast(typeof(UnityEngine.Object)) as UnityEngine.Object;
var inputObj = UIFactory.CreateInputField(rowObj, "NameInput", "...", 14, 3, 1);
UIFactory.SetLayoutElement(inputObj, minHeight: 25, flexibleWidth: 2000);
var inputField = inputObj.GetComponent<InputField>();
inputField.readOnly = true;
inputField.text = uObj.name;
}
internal bool showingTextureHelper;
internal bool constructedTextureViewer;
internal GameObject m_textureViewerObj;
internal void ConstructTextureHelper()
{
var rowObj = UIFactory.CreateHorizontalGroup(Content, "TextureHelper", true, false, true, true, 5, new Vector4(3,3,3,3),
new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleHeight: 0);
var showBtn = UIFactory.CreateButton(rowObj, "ShowButton", "Show", null, new Color(0.2f, 0.6f, 0.2f));
UIFactory.SetLayoutElement(showBtn.gameObject, minWidth: 50, flexibleWidth: 0);
UIFactory.CreateLabel(rowObj, "TextureViewerLabel", "Texture Viewer", TextAnchor.MiddleLeft);
var textureViewerObj = UIFactory.CreateScrollView(Content, "TextureViewerContent", out GameObject scrollContent, out _, new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(textureViewerObj, false, false, true, true);
UIFactory.SetLayoutElement(textureViewerObj, minHeight: 100, flexibleHeight: 9999, flexibleWidth: 9999);
textureViewerObj.SetActive(false);
m_textureViewerObj = textureViewerObj;
var showText = showBtn.GetComponentInChildren<Text>();
showBtn.onClick.AddListener(() =>
{
showingTextureHelper = !showingTextureHelper;
if (showingTextureHelper)
{
if (!constructedTextureViewer)
ConstructTextureViewerArea(scrollContent);
showText.text = "Hide";
ToggleTextureViewer(true);
}
else
{
showText.text = "Show";
ToggleTextureViewer(false);
}
});
}
internal void ConstructTextureViewerArea(GameObject parent)
{
constructedTextureViewer = true;
var tex = Target.Cast(typeof(Texture2D)) as Texture2D;
if (!tex)
{
ExplorerCore.LogWarning("Could not cast the target instance to Texture2D! Maybe its null or destroyed?");
return;
}
// Save helper
var saveRowObj = UIFactory.CreateHorizontalGroup(parent, "SaveRow", true, true, true, true, 2, new Vector4(2,2,2,2),
new Color(0.1f, 0.1f, 0.1f));
var saveBtn = UIFactory.CreateButton(saveRowObj, "SaveButton", "Save .PNG", null, new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(saveBtn.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 0);
var inputObj = UIFactory.CreateInputField(saveRowObj, "SaveInput", "...");
UIFactory.SetLayoutElement(inputObj, minHeight: 25, minWidth: 100, flexibleWidth: 9999);
var inputField = inputObj.GetComponent<InputField>();
var name = tex.name;
if (string.IsNullOrEmpty(name))
name = "untitled";
inputField.text = Path.Combine(ConfigManager.Default_Output_Path.Value, $"{name}.png");
saveBtn.onClick.AddListener(() =>
{
if (tex && !string.IsNullOrEmpty(inputField.text))
{
var path = inputField.text;
if (!path.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase))
{
ExplorerCore.LogWarning("Desired save path must end with '.png'!");
return;
}
var dir = Path.GetDirectoryName(path);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
if (File.Exists(path))
File.Delete(path);
if (!TextureUtilProvider.IsReadable(tex))
tex = TextureUtilProvider.ForceReadTexture(tex);
byte[] data = TextureUtilProvider.Instance.EncodeToPNG(tex);
File.WriteAllBytes(path, data);
}
});
// Actual texture viewer
var imageObj = UIFactory.CreateUIObject("TextureViewerImage", parent);
var image = imageObj.AddComponent<Image>();
var sprite = TextureUtilProvider.Instance.CreateSprite(tex);
image.sprite = sprite;
var fitter = imageObj.AddComponent<ContentSizeFitter>();
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
var imageLayout = imageObj.AddComponent<LayoutElement>();
imageLayout.preferredHeight = sprite.rect.height;
imageLayout.preferredWidth = sprite.rect.width;
}
internal void ToggleTextureViewer(bool enabled)
{
m_textureViewerObj.SetActive(enabled);
m_filterAreaObj.SetActive(!enabled);
m_memberListObj.SetActive(!enabled);
m_updateRowObj.SetActive(!enabled);
}
public void ConstructInstanceFilters(GameObject parent)
{
var memberFilterRowObj = UIFactory.CreateHorizontalGroup(parent, "InstanceFilterRow", false, false, true, true, 5, default,
new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(memberFilterRowObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 5000);
var memLabel = UIFactory.CreateLabel(memberFilterRowObj, "MemberLabel", "Filter scope:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(memLabel.gameObject, minWidth: 100, minHeight: 25, flexibleWidth: 0);
AddFilterButton(memberFilterRowObj, MemberScopes.All, true);
AddFilterButton(memberFilterRowObj, MemberScopes.Instance);
AddFilterButton(memberFilterRowObj, MemberScopes.Static);
}
private void AddFilterButton(GameObject parent, MemberScopes type, bool setEnabled = false)
{
var btn = UIFactory.CreateButton(parent,
"ScopeFilterButton_" + type,
type.ToString(),
null,
new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(btn.gameObject, minHeight: 25, minWidth: 70);
btn.onClick.AddListener(() => { OnScopeFilterClicked(type, btn); });
var colors = btn.colors;
colors.highlightedColor = new Color(0.3f, 0.7f, 0.3f);
if (setEnabled)
{
colors.normalColor = new Color(0.2f, 0.6f, 0.2f);
m_scopeFilter = type;
m_lastActiveScopeButton = btn;
}
btn.colors = colors;
}
}
}

View File

@ -1,328 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Inspectors;
using UnityExplorer.Core.Inspectors.Reflection;
using UnityExplorer.Core.Runtime;
namespace UnityExplorer.UI.Main.Home.Inspectors
{
public class InstanceInspectorUI
{
public InstanceInspectorUI(InstanceInspector parent)
{
Parent = parent;
}
internal InstanceInspector Parent;
public void ConstructInstanceHelpers()
{
if (!typeof(Component).IsAssignableFrom(Parent.m_targetType) && !typeof(UnityEngine.Object).IsAssignableFrom(Parent.m_targetType))
return;
var rowObj = UIFactory.CreateHorizontalGroup(Parent.ReflectionUI.Content, new Color(0.1f, 0.1f, 0.1f));
var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
rowGroup.childForceExpandWidth = true;
rowGroup.SetChildControlWidth(true);
rowGroup.spacing = 5;
rowGroup.padding.top = 2;
rowGroup.padding.bottom = 2;
rowGroup.padding.right = 2;
rowGroup.padding.left = 2;
var rowLayout = rowObj.AddComponent<LayoutElement>();
rowLayout.minHeight = 25;
rowLayout.flexibleWidth = 5000;
if (typeof(Component).IsAssignableFrom(Parent.m_targetType))
{
ConstructCompHelper(rowObj);
}
ConstructUObjHelper(rowObj);
if (Parent.m_targetType == typeof(Texture2D))
ConstructTextureHelper();
}
internal void ConstructCompHelper(GameObject rowObj)
{
var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
var labelLayout = labelObj.AddComponent<LayoutElement>();
labelLayout.minWidth = 90;
labelLayout.minHeight = 25;
labelLayout.flexibleWidth = 0;
var labelText = labelObj.GetComponent<Text>();
labelText.text = "GameObject:";
#if MONO
var comp = Parent.Target as Component;
#else
var comp = (Parent.Target as Il2CppSystem.Object).TryCast<Component>();
#endif
var goBtnObj = UIFactory.CreateButton(rowObj, new Color(0.2f, 0.5f, 0.2f));
var goBtnLayout = goBtnObj.AddComponent<LayoutElement>();
goBtnLayout.minHeight = 25;
goBtnLayout.minWidth = 200;
goBtnLayout.flexibleWidth = 0;
var text = goBtnObj.GetComponentInChildren<Text>();
text.text = comp.name;
var btn = goBtnObj.GetComponent<Button>();
btn.onClick.AddListener(() => { InspectorManager.Instance.Inspect(comp.gameObject); });
}
internal void ConstructUObjHelper(GameObject rowObj)
{
var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
var labelLayout = labelObj.AddComponent<LayoutElement>();
labelLayout.minWidth = 60;
labelLayout.minHeight = 25;
labelLayout.flexibleWidth = 0;
var labelText = labelObj.GetComponent<Text>();
labelText.text = "Name:";
#if MONO
var uObj = Parent.Target as UnityEngine.Object;
#else
var uObj = (Parent.Target as Il2CppSystem.Object).TryCast<UnityEngine.Object>();
#endif
var inputObj = UIFactory.CreateInputField(rowObj, 14, 3, 1);
var inputLayout = inputObj.AddComponent<LayoutElement>();
inputLayout.minHeight = 25;
inputLayout.flexibleWidth = 2000;
var inputField = inputObj.GetComponent<InputField>();
inputField.readOnly = true;
inputField.text = uObj.name;
}
internal bool showingTextureHelper;
internal bool constructedTextureViewer;
internal GameObject m_textureViewerObj;
internal void ConstructTextureHelper()
{
var rowObj = UIFactory.CreateHorizontalGroup(Parent.ReflectionUI.Content, new Color(0.1f, 0.1f, 0.1f));
var rowLayout = rowObj.AddComponent<LayoutElement>();
rowLayout.minHeight = 25;
rowLayout.flexibleHeight = 0;
var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
rowGroup.childForceExpandHeight = true;
rowGroup.childForceExpandWidth = false;
rowGroup.padding.top = 3;
rowGroup.padding.left = 3;
rowGroup.padding.bottom = 3;
rowGroup.padding.right = 3;
rowGroup.spacing = 5;
var showBtnObj = UIFactory.CreateButton(rowObj, new Color(0.2f, 0.6f, 0.2f));
var showBtnLayout = showBtnObj.AddComponent<LayoutElement>();
showBtnLayout.minWidth = 50;
showBtnLayout.flexibleWidth = 0;
var showText = showBtnObj.GetComponentInChildren<Text>();
showText.text = "Show";
var showBtn = showBtnObj.GetComponent<Button>();
var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
var labelText = labelObj.GetComponent<Text>();
labelText.text = "Texture Viewer";
var textureViewerObj = UIFactory.CreateScrollView(Parent.ReflectionUI.Content, out GameObject scrollContent, out _, new Color(0.1f, 0.1f, 0.1f));
var viewerGroup = scrollContent.GetComponent<VerticalLayoutGroup>();
viewerGroup.childForceExpandHeight = false;
viewerGroup.childForceExpandWidth = false;
viewerGroup.SetChildControlHeight(true);
viewerGroup.SetChildControlWidth(true);
var mainLayout = textureViewerObj.GetComponent<LayoutElement>();
mainLayout.flexibleHeight = 9999;
mainLayout.flexibleWidth = 9999;
mainLayout.minHeight = 100;
textureViewerObj.SetActive(false);
m_textureViewerObj = textureViewerObj;
showBtn.onClick.AddListener(() =>
{
showingTextureHelper = !showingTextureHelper;
if (showingTextureHelper)
{
if (!constructedTextureViewer)
ConstructTextureViewerArea(scrollContent);
showText.text = "Hide";
ToggleTextureViewer(true);
}
else
{
showText.text = "Show";
ToggleTextureViewer(false);
}
});
}
internal void ConstructTextureViewerArea(GameObject parent)
{
constructedTextureViewer = true;
var tex = Parent.Target as Texture2D;
#if CPP
if (!tex)
tex = (Parent.Target as Il2CppSystem.Object).TryCast<Texture2D>();
#endif
if (!tex)
{
ExplorerCore.LogWarning("Could not cast the target instance to Texture2D! Maybe its null or destroyed?");
return;
}
// Save helper
var saveRowObj = UIFactory.CreateHorizontalGroup(parent, new Color(0.1f, 0.1f, 0.1f));
var saveRow = saveRowObj.GetComponent<HorizontalLayoutGroup>();
saveRow.childForceExpandHeight = true;
saveRow.childForceExpandWidth = true;
saveRow.padding = new RectOffset() { left = 2, bottom = 2, right = 2, top = 2 };
saveRow.spacing = 2;
var btnObj = UIFactory.CreateButton(saveRowObj, new Color(0.2f, 0.2f, 0.2f));
var btnLayout = btnObj.AddComponent<LayoutElement>();
btnLayout.minHeight = 25;
btnLayout.minWidth = 100;
btnLayout.flexibleWidth = 0;
var saveBtn = btnObj.GetComponent<Button>();
var saveBtnText = btnObj.GetComponentInChildren<Text>();
saveBtnText.text = "Save .PNG";
var inputObj = UIFactory.CreateInputField(saveRowObj);
var inputLayout = inputObj.AddComponent<LayoutElement>();
inputLayout.minHeight = 25;
inputLayout.minWidth = 100;
inputLayout.flexibleWidth = 9999;
var inputField = inputObj.GetComponent<InputField>();
var name = tex.name;
if (string.IsNullOrEmpty(name))
name = "untitled";
var savePath = $@"{Core.Config.ExplorerConfig.Instance.Default_Output_Path}\{name}.png";
inputField.text = savePath;
saveBtn.onClick.AddListener(() =>
{
if (tex && !string.IsNullOrEmpty(inputField.text))
{
var path = inputField.text;
if (!path.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase))
{
ExplorerCore.LogWarning("Desired save path must end with '.png'!");
return;
}
var dir = Path.GetDirectoryName(path);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
if (File.Exists(path))
File.Delete(path);
if (TextureUtilProvider.IsReadable(tex))
tex = TextureUtilProvider.ForceReadTexture(tex);
byte[] data = TextureUtilProvider.Instance.EncodeToPNG(tex);
File.WriteAllBytes(path, data);
}
});
// Actual texture viewer
var imageObj = UIFactory.CreateUIObject("TextureViewerImage", parent);
var image = imageObj.AddComponent<Image>();
var sprite = TextureUtilProvider.Instance.CreateSprite(tex);
image.sprite = sprite;
var fitter = imageObj.AddComponent<ContentSizeFitter>();
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
//fitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
var imageLayout = imageObj.AddComponent<LayoutElement>();
imageLayout.preferredHeight = sprite.rect.height;
imageLayout.preferredWidth = sprite.rect.width;
}
internal void ToggleTextureViewer(bool enabled)
{
m_textureViewerObj.SetActive(enabled);
Parent.ReflectionUI.m_filterAreaObj.SetActive(!enabled);
Parent.ReflectionUI.m_memberListObj.SetActive(!enabled);
Parent.ReflectionUI.m_updateRowObj.SetActive(!enabled);
}
public void ConstructInstanceFilters(GameObject parent)
{
var memberFilterRowObj = UIFactory.CreateHorizontalGroup(parent, new Color(1, 1, 1, 0));
var memFilterGroup = memberFilterRowObj.GetComponent<HorizontalLayoutGroup>();
memFilterGroup.childForceExpandHeight = false;
memFilterGroup.childForceExpandWidth = false;
memFilterGroup.SetChildControlWidth(true);
memFilterGroup.SetChildControlHeight(true);
memFilterGroup.spacing = 5;
var memFilterLayout = memberFilterRowObj.AddComponent<LayoutElement>();
memFilterLayout.minHeight = 25;
memFilterLayout.flexibleHeight = 0;
memFilterLayout.flexibleWidth = 5000;
var memLabelObj = UIFactory.CreateLabel(memberFilterRowObj, TextAnchor.MiddleLeft);
var memLabelLayout = memLabelObj.AddComponent<LayoutElement>();
memLabelLayout.minWidth = 100;
memLabelLayout.minHeight = 25;
memLabelLayout.flexibleWidth = 0;
var memLabelText = memLabelObj.GetComponent<Text>();
memLabelText.text = "Filter scope:";
memLabelText.color = Color.grey;
AddFilterButton(memberFilterRowObj, MemberScopes.All, true);
AddFilterButton(memberFilterRowObj, MemberScopes.Instance);
AddFilterButton(memberFilterRowObj, MemberScopes.Static);
}
private void AddFilterButton(GameObject parent, MemberScopes type, bool setEnabled = false)
{
var btnObj = UIFactory.CreateButton(parent, new Color(0.2f, 0.2f, 0.2f));
var btnLayout = btnObj.AddComponent<LayoutElement>();
btnLayout.minHeight = 25;
btnLayout.minWidth = 70;
var text = btnObj.GetComponentInChildren<Text>();
text.text = type.ToString();
var btn = btnObj.GetComponent<Button>();
btn.onClick.AddListener(() => { Parent.OnScopeFilterClicked(type, btn); });
var colors = btn.colors;
colors.highlightedColor = new Color(0.3f, 0.7f, 0.3f);
if (setEnabled)
{
colors.normalColor = new Color(0.2f, 0.6f, 0.2f);
Parent.m_scopeFilter = type;
Parent.m_lastActiveScopeButton = btn;
}
btn.colors = colors;
}
}
}

View File

@ -0,0 +1,524 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core;
using UnityExplorer.Core.Config;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.Main.Home.Inspectors.Reflection
{
public class ReflectionInspector : InspectorBase
{
#region STATIC
public static ReflectionInspector ActiveInstance { get; private set; }
static ReflectionInspector()
{
PanelDragger.OnFinishResize += (RectTransform _) => OnContainerResized();
SceneExplorer.OnToggleShow += OnContainerResized;
}
private static void OnContainerResized(bool _ = false)
{
if (ActiveInstance == null)
return;
ActiveInstance.m_widthUpdateWanted = true;
}
// Blacklists
private static readonly HashSet<string> bl_typeAndMember = new HashSet<string>
{
#if CPP
// these cause a crash in IL2CPP
"Type.DeclaringMethod",
"Rigidbody2D.Cast",
"Collider2D.Cast",
"Collider2D.Raycast",
"Texture2D.SetPixelDataImpl",
"Camera.CalculateProjectionMatrixFromPhysicalProperties",
#endif
};
private static readonly HashSet<string> bl_memberNameStartsWith = new HashSet<string>
{
// these are redundant
"get_",
"set_",
};
#endregion
#region INSTANCE
public override string TabLabel => m_targetTypeShortName;
internal CacheObjectBase ParentMember { get; set; }
internal readonly Type m_targetType;
internal readonly string m_targetTypeShortName;
// all cached members of the target
internal CacheMember[] m_allMembers;
// filtered members based on current filters
internal readonly List<CacheMember> m_membersFiltered = new List<CacheMember>();
// actual shortlist of displayed members
internal readonly CacheMember[] m_displayedMembers = new CacheMember[ConfigManager.Default_Page_Limit.Value];
internal bool m_autoUpdate;
public ReflectionInspector(object target) : base(target)
{
if (this is StaticInspector)
m_targetType = target as Type;
else
m_targetType = ReflectionUtility.GetType(target);
m_targetTypeShortName = SignatureHighlighter.ParseFullSyntax(m_targetType, false);
ConstructUI();
CacheMembers(m_targetType);
FilterMembers();
}
public override void SetActive()
{
base.SetActive();
ActiveInstance = this;
}
public override void SetInactive()
{
base.SetInactive();
ActiveInstance = null;
}
public override void Destroy()
{
base.Destroy();
if (this.Content)
GameObject.Destroy(this.Content);
}
internal void OnPageTurned()
{
RefreshDisplay();
}
internal bool IsBlacklisted(string sig) => bl_typeAndMember.Any(it => sig.Contains(it));
internal bool IsBlacklisted(MethodInfo method) => bl_memberNameStartsWith.Any(it => method.Name.StartsWith(it));
internal string GetSig(MemberInfo member) => $"{member.DeclaringType.Name}.{member.Name}";
internal string AppendArgsToSig(ParameterInfo[] args)
{
string ret = " (";
foreach (var param in args)
ret += $"{param.ParameterType.Name} {param.Name}, ";
ret += ")";
return ret;
}
public void CacheMembers(Type type)
{
var list = new List<CacheMember>();
var cachedSigs = new HashSet<string>();
var types = ReflectionUtility.GetAllBaseTypes(type);
var flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static;
if (this is InstanceInspector)
flags |= BindingFlags.Instance;
foreach (var declaringType in types)
{
var target = Target;
target = target.Cast(declaringType);
IEnumerable<MemberInfo> infos = declaringType.GetMethods(flags);
infos = infos.Concat(declaringType.GetProperties(flags));
infos = infos.Concat(declaringType.GetFields(flags));
foreach (var member in infos)
{
try
{
var sig = GetSig(member);
//ExplorerCore.Log($"Trying to cache member {sig}...");
//ExplorerCore.Log(member.DeclaringType.FullName + "." + member.Name);
var mi = member as MethodInfo;
var pi = member as PropertyInfo;
var fi = member as FieldInfo;
if (IsBlacklisted(sig) || (mi != null && IsBlacklisted(mi)))
continue;
var args = mi?.GetParameters() ?? pi?.GetIndexParameters();
if (args != null)
{
if (!CacheMember.CanProcessArgs(args))
continue;
sig += AppendArgsToSig(args);
}
if (cachedSigs.Contains(sig))
continue;
cachedSigs.Add(sig);
if (mi != null)
list.Add(new CacheMethod(mi, target, m_scrollContent));
else if (pi != null)
list.Add(new CacheProperty(pi, target, m_scrollContent));
else
list.Add(new CacheField(fi, target, m_scrollContent));
list.Last().ParentInspector = this;
}
catch (Exception e)
{
ExplorerCore.LogWarning($"Exception caching member {member.DeclaringType.FullName}.{member.Name}!");
ExplorerCore.Log(e.ToString());
}
}
}
var typeList = types.ToList();
var sorted = new List<CacheMember>();
sorted.AddRange(list.Where(it => it is CacheMethod)
.OrderBy(it => typeList.IndexOf(it.DeclaringType))
.ThenBy(it => it.NameForFiltering));
sorted.AddRange(list.Where(it => it is CacheProperty)
.OrderBy(it => typeList.IndexOf(it.DeclaringType))
.ThenBy(it => it.NameForFiltering));
sorted.AddRange(list.Where(it => it is CacheField)
.OrderBy(it => typeList.IndexOf(it.DeclaringType))
.ThenBy(it => it.NameForFiltering));
m_allMembers = sorted.ToArray();
}
public override void Update()
{
base.Update();
if (m_autoUpdate)
{
foreach (var member in m_displayedMembers)
{
if (member == null) break;
member.UpdateValue();
}
}
if (m_widthUpdateWanted)
{
if (!m_widthUpdateWaiting)
m_widthUpdateWaiting = true;
else
{
UpdateWidths();
m_widthUpdateWaiting = false;
m_widthUpdateWanted = false;
}
}
}
internal void OnMemberFilterClicked(MemberTypes type, Button button)
{
if (m_lastActiveMemButton)
{
var lastColors = m_lastActiveMemButton.colors;
lastColors.normalColor = new Color(0.2f, 0.2f, 0.2f);
m_lastActiveMemButton.colors = lastColors;
}
m_memberFilter = type;
m_lastActiveMemButton = button;
var colors = m_lastActiveMemButton.colors;
colors.normalColor = new Color(0.2f, 0.6f, 0.2f);
m_lastActiveMemButton.colors = colors;
FilterMembers(null, true);
m_sliderScroller.m_slider.value = 1f;
}
public void FilterMembers(string nameFilter = null, bool force = false)
{
int lastCount = m_membersFiltered.Count;
m_membersFiltered.Clear();
nameFilter = nameFilter?.ToLower() ?? m_nameFilterText.text.ToLower();
foreach (var mem in m_allMembers)
{
// membertype filter
if (m_memberFilter != MemberTypes.All && mem.MemInfo.MemberType != m_memberFilter)
continue;
if (this is InstanceInspector ii && ii.m_scopeFilter != MemberScopes.All)
{
if (mem.IsStatic && ii.m_scopeFilter != MemberScopes.Static)
continue;
else if (!mem.IsStatic && ii.m_scopeFilter != MemberScopes.Instance)
continue;
}
// name filter
if (!string.IsNullOrEmpty(nameFilter) && !mem.NameForFiltering.Contains(nameFilter))
continue;
m_membersFiltered.Add(mem);
}
if (force || lastCount != m_membersFiltered.Count)
RefreshDisplay();
}
public void RefreshDisplay()
{
var members = m_membersFiltered;
m_pageHandler.ListCount = members.Count;
// disable current members
for (int i = 0; i < m_displayedMembers.Length; i++)
{
var mem = m_displayedMembers[i];
if (mem != null)
mem.Disable();
else
break;
}
if (members.Count < 1)
return;
foreach (var itemIndex in m_pageHandler)
{
if (itemIndex >= members.Count)
break;
CacheMember member = members[itemIndex];
m_displayedMembers[itemIndex - m_pageHandler.StartIndex] = member;
member.Enable();
}
m_widthUpdateWanted = true;
}
internal void UpdateWidths()
{
float labelWidth = 125;
foreach (var cache in m_displayedMembers)
{
if (cache == null)
break;
var width = cache.GetMemberLabelWidth(m_scrollContentRect);
if (width > labelWidth)
labelWidth = width;
}
float valueWidth = m_scrollContentRect.rect.width - labelWidth - 20;
foreach (var cache in m_displayedMembers)
{
if (cache == null)
break;
cache.SetWidths(labelWidth, valueWidth);
}
}
#endregion // end instance
#region UI
private GameObject m_content;
public override GameObject Content
{
get => m_content;
set => m_content = value;
}
internal Text m_nameFilterText;
internal MemberTypes m_memberFilter;
internal Button m_lastActiveMemButton;
internal PageHandler m_pageHandler;
internal SliderScrollbar m_sliderScroller;
internal GameObject m_scrollContent;
internal RectTransform m_scrollContentRect;
internal bool m_widthUpdateWanted;
internal bool m_widthUpdateWaiting;
internal GameObject m_filterAreaObj;
internal GameObject m_updateRowObj;
internal GameObject m_memberListObj;
internal void ConstructUI()
{
var parent = InspectorManager.m_inspectorContent;
this.Content = UIFactory.CreateVerticalGroup(parent, "ReflectionInspector", true, false, true, true, 5, new Vector4(4,4,4,4),
new Color(0.15f, 0.15f, 0.15f));
ConstructTopArea();
ConstructMemberList();
}
internal void ConstructTopArea()
{
var nameRowObj = UIFactory.CreateHorizontalGroup(Content, "NameRowObj", true, true, true, true, 2, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(nameRowObj, minHeight: 25, flexibleHeight: 0, minWidth: 200, flexibleWidth: 5000);
var typeLabelText = UIFactory.CreateLabel(nameRowObj, "TypeLabel", "Type:", TextAnchor.MiddleLeft);
typeLabelText.horizontalOverflow = HorizontalWrapMode.Overflow;
UIFactory.SetLayoutElement(typeLabelText.gameObject, minWidth: 40, flexibleWidth: 0, minHeight: 25);
var typeDisplay = UIFactory.CreateLabel(nameRowObj, "TypeDisplayText", SignatureHighlighter.ParseFullSyntax(m_targetType, true),
TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(typeDisplay.gameObject, minHeight: 25, flexibleWidth: 5000);
// instance helper tools
if (this is InstanceInspector instanceInspector)
{
instanceInspector.ConstructUnityInstanceHelpers();
}
ConstructFilterArea();
ConstructUpdateRow();
}
internal void ConstructFilterArea()
{
// Filters
m_filterAreaObj = UIFactory.CreateVerticalGroup(Content, "FilterGroup", true, true, true, true, 4, new Vector4(4,4,4,4),
new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutElement(m_filterAreaObj, minHeight: 60);
// name filter
var nameFilterRowObj = UIFactory.CreateHorizontalGroup(m_filterAreaObj, "NameFilterRow", false, false, true, true, 5, default,
new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(nameFilterRowObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 5000);
var nameLabel = UIFactory.CreateLabel(nameFilterRowObj, "NameLabel", "Filter names:", TextAnchor.MiddleLeft, Color.grey);
UIFactory.SetLayoutElement(nameLabel.gameObject, minWidth: 100, minHeight: 25, flexibleWidth: 0);
var nameInputObj = UIFactory.CreateInputField(nameFilterRowObj, "NameInput", "...", 14, (int)TextAnchor.MiddleLeft, (int)HorizontalWrapMode.Overflow);
UIFactory.SetLayoutElement(nameInputObj, flexibleWidth: 5000, minWidth: 100, minHeight: 25);
var nameInput = nameInputObj.GetComponent<InputField>();
nameInput.onValueChanged.AddListener((string val) => { FilterMembers(val); });
m_nameFilterText = nameInput.textComponent;
// membertype filter
var memberFilterRowObj = UIFactory.CreateHorizontalGroup(m_filterAreaObj, "MemberFilter", false, false, true, true, 5, default,
new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(memberFilterRowObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 5000);
var memLabel = UIFactory.CreateLabel(memberFilterRowObj, "MemberFilterLabel", "Filter members:", TextAnchor.MiddleLeft, Color.grey);
UIFactory.SetLayoutElement(memLabel.gameObject, minWidth: 100, minHeight: 25, flexibleWidth: 0);
AddFilterButton(memberFilterRowObj, MemberTypes.All);
AddFilterButton(memberFilterRowObj, MemberTypes.Method);
AddFilterButton(memberFilterRowObj, MemberTypes.Property, true);
AddFilterButton(memberFilterRowObj, MemberTypes.Field);
// Instance filters
if (this is InstanceInspector instanceInspector)
{
instanceInspector.ConstructInstanceFilters(m_filterAreaObj);
}
}
private void AddFilterButton(GameObject parent, MemberTypes type, bool setEnabled = false)
{
var btn = UIFactory.CreateButton(parent,
"FilterButton_" + type,
type.ToString(),
null,
new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(btn.gameObject, minHeight: 25, minWidth: 70);
btn.onClick.AddListener(() => { OnMemberFilterClicked(type, btn); });
var colors = btn.colors;
colors.highlightedColor = new Color(0.3f, 0.7f, 0.3f);
if (setEnabled)
{
colors.normalColor = new Color(0.2f, 0.6f, 0.2f);
m_memberFilter = type;
m_lastActiveMemButton = btn;
}
btn.colors = colors;
}
internal void ConstructUpdateRow()
{
m_updateRowObj = UIFactory.CreateHorizontalGroup(Content, "UpdateRow", false, true, true, true, 10, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(m_updateRowObj, minHeight: 25);
// update button
var updateBtn = UIFactory.CreateButton(m_updateRowObj, "UpdateButton", "Update Values", null, new Color(0.2f, 0.2f, 0.2f));
UIFactory.SetLayoutElement(updateBtn.gameObject, minWidth: 110, flexibleWidth: 0);
updateBtn.onClick.AddListener(() =>
{
bool orig = m_autoUpdate;
m_autoUpdate = true;
Update();
if (!orig)
m_autoUpdate = orig;
});
// auto update
var autoUpdateObj = UIFactory.CreateToggle(m_updateRowObj, "UpdateToggle", out Toggle autoUpdateToggle, out Text autoUpdateText);
var autoUpdateLayout = autoUpdateObj.AddComponent<LayoutElement>();
autoUpdateLayout.minWidth = 150;
autoUpdateLayout.minHeight = 25;
autoUpdateText.text = "Auto-update?";
autoUpdateToggle.isOn = false;
autoUpdateToggle.onValueChanged.AddListener((bool val) => { m_autoUpdate = val; });
}
internal void ConstructMemberList()
{
m_memberListObj = UIFactory.CreateScrollView(Content, "MemberList", out m_scrollContent, out m_sliderScroller, new Color(0.05f, 0.05f, 0.05f));
m_scrollContentRect = m_scrollContent.GetComponent<RectTransform>();
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(m_scrollContent, forceHeight: true, spacing: 3, padLeft: 0, padRight: 0);
m_pageHandler = new PageHandler(m_sliderScroller);
m_pageHandler.ConstructUI(Content);
m_pageHandler.OnPageChanged += OnPageTurned;
}
}
#endregion
}

View File

@ -1,288 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Inspectors;
using UnityExplorer.Core.Inspectors.Reflection;
using UnityExplorer.UI.Reusable;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.Main.Home.Inspectors
{
public class ReflectionInspectorUI : InspectorBaseUI
{
public ReflectionInspectorUI(ReflectionInspector parent)
{
this.Parent = parent;
}
public ReflectionInspector Parent;
// UI members
private GameObject m_content;
public override GameObject Content
{
get => m_content;
set => m_content = value;
}
internal Text m_nameFilterText;
internal MemberTypes m_memberFilter;
internal Button m_lastActiveMemButton;
internal PageHandler m_pageHandler;
internal SliderScrollbar m_sliderScroller;
internal GameObject m_scrollContent;
internal RectTransform m_scrollContentRect;
internal bool m_widthUpdateWanted;
internal bool m_widthUpdateWaiting;
internal GameObject m_filterAreaObj;
internal GameObject m_updateRowObj;
internal GameObject m_memberListObj;
internal void ConstructUI()
{
var parent = InspectorManager.UI.m_inspectorContent;
this.Content = UIFactory.CreateVerticalGroup(parent, new Color(0.15f, 0.15f, 0.15f));
var mainGroup = Content.GetComponent<VerticalLayoutGroup>();
mainGroup.childForceExpandHeight = false;
mainGroup.childForceExpandWidth = true;
mainGroup.SetChildControlHeight(true);
mainGroup.SetChildControlWidth(true);
mainGroup.spacing = 5;
mainGroup.padding.top = 4;
mainGroup.padding.left = 4;
mainGroup.padding.right = 4;
mainGroup.padding.bottom = 4;
ConstructTopArea();
ConstructMemberList();
}
internal void ConstructTopArea()
{
var nameRowObj = UIFactory.CreateHorizontalGroup(Content, new Color(1, 1, 1, 0));
var nameRow = nameRowObj.GetComponent<HorizontalLayoutGroup>();
nameRow.childForceExpandWidth = true;
nameRow.childForceExpandHeight = true;
nameRow.SetChildControlHeight(true);
nameRow.SetChildControlWidth(true);
nameRow.padding.top = 2;
var nameRowLayout = nameRowObj.AddComponent<LayoutElement>();
nameRowLayout.minHeight = 25;
nameRowLayout.flexibleHeight = 0;
nameRowLayout.minWidth = 200;
nameRowLayout.flexibleWidth = 5000;
var typeLabel = UIFactory.CreateLabel(nameRowObj, TextAnchor.MiddleLeft);
var typeLabelText = typeLabel.GetComponent<Text>();
typeLabelText.text = "Type:";
typeLabelText.horizontalOverflow = HorizontalWrapMode.Overflow;
var typeLabelTextLayout = typeLabel.AddComponent<LayoutElement>();
typeLabelTextLayout.minWidth = 40;
typeLabelTextLayout.flexibleWidth = 0;
typeLabelTextLayout.minHeight = 25;
var typeDisplayObj = UIFactory.CreateLabel(nameRowObj, TextAnchor.MiddleLeft);
var typeDisplayText = typeDisplayObj.GetComponent<Text>();
typeDisplayText.text = SignatureHighlighter.ParseFullSyntax(Parent.m_targetType, true);
var typeDisplayLayout = typeDisplayObj.AddComponent<LayoutElement>();
typeDisplayLayout.minHeight = 25;
typeDisplayLayout.flexibleWidth = 5000;
// instance helper tools
if (Parent is InstanceInspector instanceInspector)
{
instanceInspector.CreateInstanceUIModule();
instanceInspector.InstanceUI.ConstructInstanceHelpers();
}
ConstructFilterArea();
ConstructUpdateRow();
}
internal void ConstructFilterArea()
{
// Filters
var filterAreaObj = UIFactory.CreateVerticalGroup(Content, new Color(0.1f, 0.1f, 0.1f));
var filterLayout = filterAreaObj.AddComponent<LayoutElement>();
filterLayout.minHeight = 60;
var filterGroup = filterAreaObj.GetComponent<VerticalLayoutGroup>();
filterGroup.childForceExpandWidth = true;
filterGroup.childForceExpandHeight = true;
filterGroup.SetChildControlWidth(true);
filterGroup.SetChildControlHeight(true);
filterGroup.spacing = 4;
filterGroup.padding.left = 4;
filterGroup.padding.right = 4;
filterGroup.padding.top = 4;
filterGroup.padding.bottom = 4;
m_filterAreaObj = filterAreaObj;
// name filter
var nameFilterRowObj = UIFactory.CreateHorizontalGroup(filterAreaObj, new Color(1, 1, 1, 0));
var nameFilterGroup = nameFilterRowObj.GetComponent<HorizontalLayoutGroup>();
nameFilterGroup.childForceExpandHeight = false;
nameFilterGroup.childForceExpandWidth = false;
nameFilterGroup.SetChildControlWidth(true);
nameFilterGroup.SetChildControlHeight(true);
nameFilterGroup.spacing = 5;
var nameFilterLayout = nameFilterRowObj.AddComponent<LayoutElement>();
nameFilterLayout.minHeight = 25;
nameFilterLayout.flexibleHeight = 0;
nameFilterLayout.flexibleWidth = 5000;
var nameLabelObj = UIFactory.CreateLabel(nameFilterRowObj, TextAnchor.MiddleLeft);
var nameLabelLayout = nameLabelObj.AddComponent<LayoutElement>();
nameLabelLayout.minWidth = 100;
nameLabelLayout.minHeight = 25;
nameLabelLayout.flexibleWidth = 0;
var nameLabelText = nameLabelObj.GetComponent<Text>();
nameLabelText.text = "Filter names:";
nameLabelText.color = Color.grey;
var nameInputObj = UIFactory.CreateInputField(nameFilterRowObj, 14, (int)TextAnchor.MiddleLeft, (int)HorizontalWrapMode.Overflow);
var nameInputLayout = nameInputObj.AddComponent<LayoutElement>();
nameInputLayout.flexibleWidth = 5000;
nameInputLayout.minWidth = 100;
nameInputLayout.minHeight = 25;
var nameInput = nameInputObj.GetComponent<InputField>();
nameInput.onValueChanged.AddListener((string val) => { Parent.FilterMembers(val); });
m_nameFilterText = nameInput.textComponent;
// membertype filter
var memberFilterRowObj = UIFactory.CreateHorizontalGroup(filterAreaObj, new Color(1, 1, 1, 0));
var memFilterGroup = memberFilterRowObj.GetComponent<HorizontalLayoutGroup>();
memFilterGroup.childForceExpandHeight = false;
memFilterGroup.childForceExpandWidth = false;
memFilterGroup.SetChildControlWidth(true);
memFilterGroup.SetChildControlHeight(true);
memFilterGroup.spacing = 5;
var memFilterLayout = memberFilterRowObj.AddComponent<LayoutElement>();
memFilterLayout.minHeight = 25;
memFilterLayout.flexibleHeight = 0;
memFilterLayout.flexibleWidth = 5000;
var memLabelObj = UIFactory.CreateLabel(memberFilterRowObj, TextAnchor.MiddleLeft);
var memLabelLayout = memLabelObj.AddComponent<LayoutElement>();
memLabelLayout.minWidth = 100;
memLabelLayout.minHeight = 25;
memLabelLayout.flexibleWidth = 0;
var memLabelText = memLabelObj.GetComponent<Text>();
memLabelText.text = "Filter members:";
memLabelText.color = Color.grey;
AddFilterButton(memberFilterRowObj, MemberTypes.All);
AddFilterButton(memberFilterRowObj, MemberTypes.Method);
AddFilterButton(memberFilterRowObj, MemberTypes.Property, true);
AddFilterButton(memberFilterRowObj, MemberTypes.Field);
// Instance filters
if (Parent is InstanceInspector instanceInspector)
{
instanceInspector.InstanceUI.ConstructInstanceFilters(filterAreaObj);
}
}
private void AddFilterButton(GameObject parent, MemberTypes type, bool setEnabled = false)
{
var btnObj = UIFactory.CreateButton(parent, new Color(0.2f, 0.2f, 0.2f));
var btnLayout = btnObj.AddComponent<LayoutElement>();
btnLayout.minHeight = 25;
btnLayout.minWidth = 70;
var text = btnObj.GetComponentInChildren<Text>();
text.text = type.ToString();
var btn = btnObj.GetComponent<Button>();
btn.onClick.AddListener(() => { Parent.OnMemberFilterClicked(type, btn); });
var colors = btn.colors;
colors.highlightedColor = new Color(0.3f, 0.7f, 0.3f);
if (setEnabled)
{
colors.normalColor = new Color(0.2f, 0.6f, 0.2f);
m_memberFilter = type;
m_lastActiveMemButton = btn;
}
btn.colors = colors;
}
internal void ConstructUpdateRow()
{
var optionsRowObj = UIFactory.CreateHorizontalGroup(Content, new Color(1, 1, 1, 0));
var optionsLayout = optionsRowObj.AddComponent<LayoutElement>();
optionsLayout.minHeight = 25;
var optionsGroup = optionsRowObj.GetComponent<HorizontalLayoutGroup>();
optionsGroup.childForceExpandHeight = true;
optionsGroup.childForceExpandWidth = false;
optionsGroup.childAlignment = TextAnchor.MiddleLeft;
optionsGroup.spacing = 10;
m_updateRowObj = optionsRowObj;
// update button
var updateButtonObj = UIFactory.CreateButton(optionsRowObj, new Color(0.2f, 0.2f, 0.2f));
var updateBtnLayout = updateButtonObj.AddComponent<LayoutElement>();
updateBtnLayout.minWidth = 110;
updateBtnLayout.flexibleWidth = 0;
var updateText = updateButtonObj.GetComponentInChildren<Text>();
updateText.text = "Update Values";
var updateBtn = updateButtonObj.GetComponent<Button>();
updateBtn.onClick.AddListener(() =>
{
bool orig = Parent.m_autoUpdate;
Parent.m_autoUpdate = true;
Parent.Update();
if (!orig) Parent.m_autoUpdate = orig;
});
// auto update
var autoUpdateObj = UIFactory.CreateToggle(optionsRowObj, out Toggle autoUpdateToggle, out Text autoUpdateText);
var autoUpdateLayout = autoUpdateObj.AddComponent<LayoutElement>();
autoUpdateLayout.minWidth = 150;
autoUpdateLayout.minHeight = 25;
autoUpdateText.text = "Auto-update?";
autoUpdateToggle.isOn = false;
autoUpdateToggle.onValueChanged.AddListener((bool val) => { Parent.m_autoUpdate = val; });
}
internal void ConstructMemberList()
{
var scrollobj = UIFactory.CreateScrollView(Content, out m_scrollContent, out m_sliderScroller, new Color(0.05f, 0.05f, 0.05f));
m_memberListObj = scrollobj;
m_scrollContentRect = m_scrollContent.GetComponent<RectTransform>();
var scrollGroup = m_scrollContent.GetComponent<VerticalLayoutGroup>();
scrollGroup.spacing = 3;
scrollGroup.padding.left = 0;
scrollGroup.padding.right = 0;
scrollGroup.childForceExpandHeight = true;
m_pageHandler = new PageHandler(m_sliderScroller);
m_pageHandler.ConstructUI(Content);
m_pageHandler.OnPageChanged += Parent.OnPageTurned;
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace UnityExplorer.UI.Main.Home.Inspectors.Reflection
{
public class StaticInspector : ReflectionInspector
{
public override string TabLabel => $" <color=cyan>[S]</color> {base.TabLabel}";
public StaticInspector(Type type) : base(type) { }
}
}

View File

@ -0,0 +1,512 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityExplorer.UI;
using UnityExplorer.UI.Main;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.Main.Home;
using UnityExplorer.Core.Config;
using UnityExplorer.UI.Utility;
using UnityExplorer.UI.Main.Search;
namespace UnityExplorer.UI.Main.Home
{
public class SceneExplorer
{
public static SceneExplorer Instance;
internal static Action<bool> OnToggleShow;
public SceneExplorer()
{
Instance = this;
ConstructScenePane();
}
internal bool Hiding;
private const float UPDATE_INTERVAL = 1f;
private float m_timeOfLastSceneUpdate;
// private int m_currentSceneHandle = -1;
public static Scene DontDestroyScene => DontDestroyObject.scene;
internal Scene m_currentScene;
internal Scene[] m_currentScenes = new Scene[0];
internal GameObject[] m_allObjects = new GameObject[0];
internal GameObject m_selectedSceneObject;
internal int m_lastCount;
private Dropdown m_sceneDropdown;
private Text m_sceneDropdownText;
private Text m_scenePathText;
private GameObject m_mainInspectBtn;
private GameObject m_backButtonObj;
public PageHandler m_pageHandler;
private GameObject m_pageContent;
private readonly List<Text> m_shortListTexts = new List<Text>();
private readonly List<Toggle> m_shortListToggles = new List<Toggle>();
internal readonly List<GameObject> m_shortList = new List<GameObject>();
private Text m_hideText;
private GameObject m_titleObj;
private GameObject m_sceneDropdownObj;
private GameObject m_scenePathGroupObj;
private GameObject m_scrollObj;
private LayoutElement m_leftLayout;
internal static GameObject DontDestroyObject
{
get
{
if (!s_dontDestroyObject)
{
s_dontDestroyObject = new GameObject("DontDestroyMe");
GameObject.DontDestroyOnLoad(s_dontDestroyObject);
}
return s_dontDestroyObject;
}
}
internal static GameObject s_dontDestroyObject;
public void Init()
{
RefreshSceneSelector();
if (!ConfigManager.Last_SceneExplorer_State.Value)
ToggleShow();
}
public void Update()
{
if (Hiding || Time.realtimeSinceStartup - m_timeOfLastSceneUpdate < UPDATE_INTERVAL)
return;
RefreshSceneSelector();
if (!m_selectedSceneObject)
{
if (m_currentScene != default)
{
var rootObjects = RuntimeProvider.Instance.GetRootGameObjects(m_currentScene);
SetSceneObjectList(rootObjects);
}
}
else
{
RefreshSelectedSceneObject();
}
}
private void RefreshSceneSelector()
{
var newNames = new List<string>();
var newScenes = new List<Scene>();
if (m_currentScenes == null)
m_currentScenes = new Scene[0];
bool anyChange = SceneManager.sceneCount != m_currentScenes.Length - 1;
for (int i = 0; i < SceneManager.sceneCount; i++)
{
Scene scene = SceneManager.GetSceneAt(i);
if (scene == default)
continue;
int handle = RuntimeProvider.Instance.GetSceneHandle(scene);
if (!anyChange && !m_currentScenes.Any(it => handle == RuntimeProvider.Instance.GetSceneHandle(it)))
anyChange = true;
newScenes.Add(scene);
newNames.Add(scene.name);
}
if (anyChange)
{
newNames.Add("DontDestroyOnLoad");
newScenes.Add(DontDestroyScene);
m_currentScenes = newScenes.ToArray();
OnActiveScenesChanged(newNames);
SetTargetScene(newScenes[0]);
SearchPage.Instance.OnSceneChange();
}
}
public void SetTargetScene(int index)
=> SetTargetScene(m_currentScenes[index]);
public void SetTargetScene(Scene scene)
{
if (scene == default)
return;
m_currentScene = scene;
var rootObjs = RuntimeProvider.Instance.GetRootGameObjects(scene);
SetSceneObjectList(rootObjs);
m_selectedSceneObject = null;
OnSceneSelected();
}
public void SetSceneObjectParent()
{
if (!m_selectedSceneObject || !m_selectedSceneObject.transform.parent?.gameObject)
{
m_selectedSceneObject = null;
SetTargetScene(m_currentScene);
}
else
{
SetTargetObject(m_selectedSceneObject.transform.parent.gameObject);
}
}
public void SetTargetObject(GameObject obj)
{
if (!obj)
return;
OnGameObjectSelected(obj);
m_selectedSceneObject = obj;
RefreshSelectedSceneObject();
}
private void RefreshSelectedSceneObject()
{
GameObject[] list = new GameObject[m_selectedSceneObject.transform.childCount];
for (int i = 0; i < m_selectedSceneObject.transform.childCount; i++)
{
list[i] = m_selectedSceneObject.transform.GetChild(i).gameObject;
}
SetSceneObjectList(list);
}
private void SetSceneObjectList(GameObject[] objects)
{
m_allObjects = objects;
RefreshSceneObjectList();
}
internal void RefreshSceneObjectList()
{
m_timeOfLastSceneUpdate = Time.realtimeSinceStartup;
RefreshSceneObjectList(m_allObjects, out int newCount);
m_lastCount = newCount;
}
internal static void InspectSelectedGameObject()
{
InspectorManager.Instance.Inspect(Instance.m_selectedSceneObject);
}
internal static void InvokeOnToggleShow()
{
OnToggleShow?.Invoke(!Instance.Hiding);
}
public void ToggleShow()
{
if (!Hiding)
{
Hiding = true;
m_hideText.text = "►";
m_titleObj.SetActive(false);
m_sceneDropdownObj.SetActive(false);
m_scenePathGroupObj.SetActive(false);
m_scrollObj.SetActive(false);
m_pageHandler.Hide();
m_leftLayout.minWidth = 15;
}
else
{
Hiding = false;
m_hideText.text = "Hide Scene Explorer";
m_titleObj.SetActive(true);
m_sceneDropdownObj.SetActive(true);
m_scenePathGroupObj.SetActive(true);
m_scrollObj.SetActive(true);
m_leftLayout.minWidth = 350;
Update();
}
InvokeOnToggleShow();
}
public void OnActiveScenesChanged(List<string> newNames)
{
m_sceneDropdown.options.Clear();
foreach (string scene in newNames)
{
m_sceneDropdown.options.Add(new Dropdown.OptionData { text = scene });
}
m_sceneDropdown.OnCancel(null);
m_sceneDropdownText.text = newNames[0];
}
private void SceneListObjectClicked(int index)
{
if (index >= m_shortList.Count || !m_shortList[index])
{
return;
}
var obj = m_shortList[index];
if (obj.transform.childCount > 0)
SetTargetObject(obj);
else
InspectorManager.Instance.Inspect(obj);
}
internal void RefreshSceneObjectList(GameObject[] allObjects, out int newCount)
{
var objects = allObjects;
m_pageHandler.ListCount = objects.Length;
//int startIndex = m_sceneListPageHandler.StartIndex;
newCount = 0;
foreach (var itemIndex in m_pageHandler)
{
newCount++;
// normalized index starting from 0
var i = itemIndex - m_pageHandler.StartIndex;
if (itemIndex >= objects.Length)
{
if (i > SceneExplorer.Instance.m_lastCount || i >= m_shortListTexts.Count)
break;
GameObject label = m_shortListTexts[i].transform.parent.parent.gameObject;
if (label.activeSelf)
label.SetActive(false);
}
else
{
GameObject obj = objects[itemIndex];
if (!obj)
continue;
if (i >= m_shortList.Count)
{
m_shortList.Add(obj);
AddObjectListButton();
}
else
{
m_shortList[i] = obj;
}
var text = m_shortListTexts[i];
var name = obj.name;
if (obj.transform.childCount > 0)
name = $"<color=grey>[{obj.transform.childCount}]</color> {name}";
text.text = name;
text.color = obj.activeSelf ? Color.green : Color.red;
var tog = m_shortListToggles[i];
tog.isOn = obj.activeSelf;
var label = text.transform.parent.parent.gameObject;
if (!label.activeSelf)
{
label.SetActive(true);
}
}
}
}
private void OnSceneListPageTurn()
{
RefreshSceneObjectList();
}
private void OnToggleClicked(int index, bool val)
{
if (index >= m_shortList.Count || !m_shortList[index])
return;
var obj = m_shortList[index];
obj.SetActive(val);
}
internal void OnGameObjectSelected(GameObject obj)
{
m_scenePathText.text = obj.name;
if (!m_backButtonObj.activeSelf)
{
m_backButtonObj.SetActive(true);
m_mainInspectBtn.SetActive(true);
}
}
internal void OnSceneSelected()
{
if (m_backButtonObj.activeSelf)
{
m_backButtonObj.SetActive(false);
m_mainInspectBtn.SetActive(false);
}
m_scenePathText.text = "Scene root:";
//m_scenePathText.ForceMeshUpdate();
}
#region UI CONSTRUCTION
public void ConstructScenePane()
{
GameObject leftPane = UIFactory.CreateVerticalGroup(HomePage.Instance.Content, "SceneGroup", true, false, true, true, 0, default,
new Color(72f / 255f, 72f / 255f, 72f / 255f));
m_leftLayout = leftPane.AddComponent<LayoutElement>();
m_leftLayout.minWidth = 350;
m_leftLayout.flexibleWidth = 0;
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(leftPane, true, true, true, true, spacing: 4, padTop: 8, 4, 4, 4);
m_titleObj = UIFactory.CreateLabel(leftPane, "SceneExplorerTitle", "Scene Explorer", TextAnchor.UpperLeft, default, true, 20).gameObject;
UIFactory.SetLayoutElement(m_titleObj, minHeight: 30, flexibleHeight: 0);
m_sceneDropdownObj = UIFactory.CreateDropdown(leftPane, out m_sceneDropdown, "<notset>", 14, null);
UIFactory.SetLayoutElement(m_sceneDropdownObj, minHeight: 40, minWidth: 320, flexibleWidth: 0, flexibleHeight: 0);
m_sceneDropdownText = m_sceneDropdown.transform.Find("Label").GetComponent<Text>();
m_sceneDropdown.onValueChanged.AddListener((int val) => { SetTargetScene(val); });
m_scenePathGroupObj = UIFactory.CreateHorizontalGroup(leftPane, "ScenePathGroup", true, true, true, true, 5, default, new Color(1, 1, 1, 0f));
UIFactory.SetLayoutElement(m_scenePathGroupObj, minHeight: 20, minWidth: 335);
var backBtnObj = UIFactory.CreateButton(m_scenePathGroupObj,
"BackButton",
"◄",
() => { SetSceneObjectParent(); },
new Color(0.12f, 0.12f, 0.12f));
m_backButtonObj = backBtnObj.gameObject;
UIFactory.SetLayoutElement(m_backButtonObj, minWidth: 40, flexibleWidth: 0);
GameObject scenePathLabel = UIFactory.CreateHorizontalGroup(m_scenePathGroupObj, "ScenePathLabel", false, false, false, false);
Image image = scenePathLabel.GetComponent<Image>();
image.color = Color.white;
scenePathLabel.AddComponent<Mask>().showMaskGraphic = false;
UIFactory.SetLayoutElement(scenePathLabel, minWidth: 210, minHeight: 20, flexibleWidth: 120);
m_scenePathText = UIFactory.CreateLabel(scenePathLabel, "ScenePathLabelText", "Scene root:", TextAnchor.MiddleLeft, default, true, 15);
m_scenePathText.horizontalOverflow = HorizontalWrapMode.Overflow;
UIFactory.SetLayoutElement(m_scenePathText.gameObject, minWidth: 210, flexibleWidth: 120, minHeight: 20);
var mainInspectButton = UIFactory.CreateButton(m_scenePathGroupObj,
"MainInspectButton",
"Inspect",
() => { InspectSelectedGameObject(); },
new Color(0.12f, 0.12f, 0.12f));
m_mainInspectBtn = mainInspectButton.gameObject;
UIFactory.SetLayoutElement(m_mainInspectBtn, minWidth: 65);
m_scrollObj = UIFactory.CreateScrollView(leftPane, "SceneExplorerScrollView",
out m_pageContent, out SliderScrollbar scroller, new Color(0.1f, 0.1f, 0.1f));
m_pageHandler = new PageHandler(scroller);
m_pageHandler.ConstructUI(leftPane);
m_pageHandler.OnPageChanged += OnSceneListPageTurn;
// hide button
var hideButton = UIFactory.CreateButton(leftPane, "HideButton", "Hide Scene Explorer", ToggleShow, new Color(0.15f, 0.15f, 0.15f));
hideButton.GetComponentInChildren<Text>().fontSize = 13;
m_hideText = hideButton.GetComponentInChildren<Text>();
UIFactory.SetLayoutElement(hideButton.gameObject, minWidth: 20, minHeight: 20);
}
private void AddObjectListButton()
{
int thisIndex = m_shortListTexts.Count();
GameObject btnGroupObj = UIFactory.CreateHorizontalGroup(m_pageContent, "SceneObjectButton", true, false, true, true,
0, default, new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutElement(btnGroupObj, flexibleWidth: 320, minHeight: 25);
btnGroupObj.AddComponent<Mask>();
var toggleObj = UIFactory.CreateToggle(btnGroupObj, "ObjectToggleButton", out Toggle toggle, out Text toggleText, new Color(0.1f, 0.1f, 0.1f));
var toggleLayout = toggleObj.AddComponent<LayoutElement>();
toggleLayout.minHeight = 25;
toggleLayout.minWidth = 25;
toggleText.text = "";
toggle.isOn = false;
m_shortListToggles.Add(toggle);
toggle.onValueChanged.AddListener((bool val) => { OnToggleClicked(thisIndex, val); });
ColorBlock mainColors = new ColorBlock();
mainColors.normalColor = new Color(0.1f, 0.1f, 0.1f);
mainColors.highlightedColor = new Color(0.2f, 0.2f, 0.2f);
mainColors.pressedColor = new Color(0.05f, 0.05f, 0.05f);
var mainButton = UIFactory.CreateButton(btnGroupObj,
"MainButton",
"",
() => { SceneListObjectClicked(thisIndex); },
mainColors);
UIFactory.SetLayoutElement(mainButton.gameObject, minHeight: 25, minWidth: 230);
Text mainText = mainButton.GetComponentInChildren<Text>();
mainText.alignment = TextAnchor.MiddleLeft;
mainText.horizontalOverflow = HorizontalWrapMode.Overflow;
m_shortListTexts.Add(mainText);
ColorBlock inspectColors = new ColorBlock();
inspectColors.normalColor = new Color(0.15f, 0.15f, 0.15f);
inspectColors.highlightedColor = new Color(0.2f, 0.2f, 0.2f);
inspectColors.pressedColor = new Color(0.1f, 0.1f, 0.1f);
var inspectButton = UIFactory.CreateButton(btnGroupObj,
"InspectButton",
"Inspect",
() => { InspectorManager.Instance.Inspect(m_shortList[thisIndex]); },
inspectColors);
UIFactory.SetLayoutElement(inspectButton.gameObject, minWidth: 60, minHeight: 25);
}
#endregion
}
}

View File

@ -1,400 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Inspectors;
using UnityExplorer.UI.Main;
using UnityExplorer.UI.Reusable;
namespace UnityExplorer.UI.Main.Home
{
public class SceneExplorerUI
{
public static SceneExplorerUI Instance;
public SceneExplorerUI()
{
Instance = this;
}
internal bool Hiding;
private Dropdown m_sceneDropdown;
private Text m_sceneDropdownText;
private Text m_scenePathText;
private GameObject m_mainInspectBtn;
private GameObject m_backButtonObj;
public PageHandler m_pageHandler;
private GameObject m_pageContent;
private readonly List<Text> m_shortListTexts = new List<Text>();
private readonly List<Toggle> m_shortListToggles = new List<Toggle>();
internal readonly List<GameObject> m_shortList = new List<GameObject>();
private Text hideText;
private GameObject m_titleObj;
private GameObject m_sceneDropdownObj;
private GameObject m_scenePathGroupObj;
private GameObject m_scrollObj;
private LayoutElement m_leftLayout;
public void ToggleShow()
{
if (!Hiding)
{
Hiding = true;
hideText.text = "►";
m_titleObj.SetActive(false);
m_sceneDropdownObj.SetActive(false);
m_scenePathGroupObj.SetActive(false);
m_scrollObj.SetActive(false);
m_pageHandler.Hide();
m_leftLayout.minWidth = 15;
}
else
{
Hiding = false;
hideText.text = "Hide Scene Explorer";
m_titleObj.SetActive(true);
m_sceneDropdownObj.SetActive(true);
m_scenePathGroupObj.SetActive(true);
m_scrollObj.SetActive(true);
m_leftLayout.minWidth = 350;
SceneExplorer.Instance.Update();
}
SceneExplorer.InvokeOnToggleShow();
}
public void OnActiveScenesChanged(List<string> newNames)
{
m_sceneDropdown.options.Clear();
foreach (string scene in newNames)
{
m_sceneDropdown.options.Add(new Dropdown.OptionData { text = scene });
}
m_sceneDropdown.OnCancel(null);
m_sceneDropdownText.text = newNames[0];
}
private void SceneListObjectClicked(int index)
{
if (index >= m_shortList.Count || !m_shortList[index])
{
return;
}
var obj = m_shortList[index];
if (obj.transform.childCount > 0)
SceneExplorer.Instance.SetTargetObject(obj);
else
InspectorManager.Instance.Inspect(obj);
}
internal void RefreshSceneObjectList(GameObject[] allObjects, out int newCount)
{
var objects = allObjects;
m_pageHandler.ListCount = objects.Length;
//int startIndex = m_sceneListPageHandler.StartIndex;
newCount = 0;
foreach (var itemIndex in m_pageHandler)
{
newCount++;
// normalized index starting from 0
var i = itemIndex - m_pageHandler.StartIndex;
if (itemIndex >= objects.Length)
{
if (i > SceneExplorer.Instance.m_lastCount || i >= m_shortListTexts.Count)
break;
GameObject label = m_shortListTexts[i].transform.parent.parent.gameObject;
if (label.activeSelf)
label.SetActive(false);
}
else
{
GameObject obj = objects[itemIndex];
if (!obj)
continue;
if (i >= m_shortList.Count)
{
m_shortList.Add(obj);
AddObjectListButton();
}
else
{
m_shortList[i] = obj;
}
var text = m_shortListTexts[i];
var name = obj.name;
if (obj.transform.childCount > 0)
name = $"<color=grey>[{obj.transform.childCount}]</color> {name}";
text.text = name;
text.color = obj.activeSelf ? Color.green : Color.red;
var tog = m_shortListToggles[i];
tog.isOn = obj.activeSelf;
var label = text.transform.parent.parent.gameObject;
if (!label.activeSelf)
{
label.SetActive(true);
}
}
}
}
private void OnSceneListPageTurn()
{
SceneExplorer.Instance.RefreshSceneObjectList();
}
private void OnToggleClicked(int index, bool val)
{
if (index >= m_shortList.Count || !m_shortList[index])
return;
var obj = m_shortList[index];
obj.SetActive(val);
}
internal void OnGameObjectSelected(GameObject obj)
{
m_scenePathText.text = obj.name;
//m_scenePathText.ForceMeshUpdate();
if (!m_backButtonObj.activeSelf)
{
m_backButtonObj.SetActive(true);
m_mainInspectBtn.SetActive(true);
}
}
internal void OnSceneSelected()
{
if (m_backButtonObj.activeSelf)
{
m_backButtonObj.SetActive(false);
m_mainInspectBtn.SetActive(false);
}
m_scenePathText.text = "Scene root:";
//m_scenePathText.ForceMeshUpdate();
}
#region UI CONSTRUCTION
public void ConstructScenePane()
{
GameObject leftPane = UIFactory.CreateVerticalGroup(HomePage.Instance.Content, new Color(72f / 255f, 72f / 255f, 72f / 255f));
m_leftLayout = leftPane.AddComponent<LayoutElement>();
m_leftLayout.minWidth = 350;
m_leftLayout.flexibleWidth = 0;
VerticalLayoutGroup leftGroup = leftPane.GetComponent<VerticalLayoutGroup>();
leftGroup.padding.left = 4;
leftGroup.padding.right = 4;
leftGroup.padding.top = 8;
leftGroup.padding.bottom = 4;
leftGroup.spacing = 4;
leftGroup.SetChildControlWidth(true);
leftGroup.SetChildControlHeight(true);
leftGroup.childForceExpandWidth = true;
leftGroup.childForceExpandHeight = true;
m_titleObj = UIFactory.CreateLabel(leftPane, TextAnchor.UpperLeft);
Text titleLabel = m_titleObj.GetComponent<Text>();
titleLabel.text = "Scene Explorer";
titleLabel.fontSize = 20;
LayoutElement titleLayout = m_titleObj.AddComponent<LayoutElement>();
titleLayout.minHeight = 30;
titleLayout.flexibleHeight = 0;
m_sceneDropdownObj = UIFactory.CreateDropdown(leftPane, out m_sceneDropdown);
LayoutElement dropdownLayout = m_sceneDropdownObj.AddComponent<LayoutElement>();
dropdownLayout.minHeight = 40;
dropdownLayout.flexibleHeight = 0;
dropdownLayout.minWidth = 320;
dropdownLayout.flexibleWidth = 2;
m_sceneDropdownText = m_sceneDropdown.transform.Find("Label").GetComponent<Text>();
m_sceneDropdown.onValueChanged.AddListener((int val) => { SetSceneFromDropdown(val); });
void SetSceneFromDropdown(int val)
{
//string scene = m_sceneDropdown.options[val].text;
SceneExplorer.Instance.SetTargetScene(val);
}
m_scenePathGroupObj = UIFactory.CreateHorizontalGroup(leftPane, new Color(1, 1, 1, 0f));
HorizontalLayoutGroup scenePathGroup = m_scenePathGroupObj.GetComponent<HorizontalLayoutGroup>();
scenePathGroup.SetChildControlHeight(true);
scenePathGroup.SetChildControlWidth(true);
scenePathGroup.childForceExpandHeight = true;
scenePathGroup.childForceExpandWidth = true;
scenePathGroup.spacing = 5;
LayoutElement scenePathLayout = m_scenePathGroupObj.AddComponent<LayoutElement>();
scenePathLayout.minHeight = 20;
scenePathLayout.minWidth = 335;
scenePathLayout.flexibleWidth = 0;
m_backButtonObj = UIFactory.CreateButton(m_scenePathGroupObj);
Text backButtonText = m_backButtonObj.GetComponentInChildren<Text>();
backButtonText.text = "◄";
LayoutElement backButtonLayout = m_backButtonObj.AddComponent<LayoutElement>();
backButtonLayout.minWidth = 40;
backButtonLayout.flexibleWidth = 0;
Button backButton = m_backButtonObj.GetComponent<Button>();
var colors = backButton.colors;
colors.normalColor = new Color(0.12f, 0.12f, 0.12f);
backButton.colors = colors;
backButton.onClick.AddListener(() => { SceneExplorer.Instance.SetSceneObjectParent(); });
GameObject scenePathLabel = UIFactory.CreateHorizontalGroup(m_scenePathGroupObj);
Image image = scenePathLabel.GetComponent<Image>();
image.color = Color.white;
LayoutElement scenePathLabelLayout = scenePathLabel.AddComponent<LayoutElement>();
scenePathLabelLayout.minWidth = 210;
scenePathLabelLayout.minHeight = 20;
scenePathLabelLayout.flexibleHeight = 0;
scenePathLabelLayout.flexibleWidth = 120;
scenePathLabel.AddComponent<Mask>().showMaskGraphic = false;
GameObject scenePathLabelText = UIFactory.CreateLabel(scenePathLabel, TextAnchor.MiddleLeft);
m_scenePathText = scenePathLabelText.GetComponent<Text>();
m_scenePathText.text = "Scene root:";
m_scenePathText.fontSize = 15;
m_scenePathText.horizontalOverflow = HorizontalWrapMode.Overflow;
LayoutElement textLayout = scenePathLabelText.gameObject.AddComponent<LayoutElement>();
textLayout.minWidth = 210;
textLayout.flexibleWidth = 120;
textLayout.minHeight = 20;
textLayout.flexibleHeight = 0;
m_mainInspectBtn = UIFactory.CreateButton(m_scenePathGroupObj);
Text inspectButtonText = m_mainInspectBtn.GetComponentInChildren<Text>();
inspectButtonText.text = "Inspect";
LayoutElement inspectButtonLayout = m_mainInspectBtn.AddComponent<LayoutElement>();
inspectButtonLayout.minWidth = 65;
inspectButtonLayout.flexibleWidth = 0;
Button inspectButton = m_mainInspectBtn.GetComponent<Button>();
colors = inspectButton.colors;
colors.normalColor = new Color(0.12f, 0.12f, 0.12f);
inspectButton.colors = colors;
inspectButton.onClick.AddListener(() => { SceneExplorer.InspectSelectedGameObject(); });
m_scrollObj = UIFactory.CreateScrollView(leftPane, out m_pageContent, out SliderScrollbar scroller, new Color(0.1f, 0.1f, 0.1f));
m_pageHandler = new PageHandler(scroller);
m_pageHandler.ConstructUI(leftPane);
m_pageHandler.OnPageChanged += OnSceneListPageTurn;
// hide button
var hideButtonObj = UIFactory.CreateButton(leftPane);
var hideBtn = hideButtonObj.GetComponent<Button>();
var hideColors = hideBtn.colors;
hideColors.normalColor = new Color(0.15f, 0.15f, 0.15f);
hideBtn.colors = hideColors;
hideText = hideButtonObj.GetComponentInChildren<Text>();
hideText.text = "Hide Scene Explorer";
hideText.fontSize = 13;
var hideLayout = hideButtonObj.AddComponent<LayoutElement>();
hideLayout.minWidth = 20;
hideLayout.minHeight = 20;
hideBtn.onClick.AddListener(ToggleShow);
}
private void AddObjectListButton()
{
int thisIndex = m_shortListTexts.Count();
GameObject btnGroupObj = UIFactory.CreateHorizontalGroup(m_pageContent, new Color(0.1f, 0.1f, 0.1f));
HorizontalLayoutGroup btnGroup = btnGroupObj.GetComponent<HorizontalLayoutGroup>();
btnGroup.childForceExpandWidth = true;
btnGroup.SetChildControlWidth(true);
btnGroup.childForceExpandHeight = false;
btnGroup.SetChildControlHeight(true);
LayoutElement btnLayout = btnGroupObj.AddComponent<LayoutElement>();
btnLayout.flexibleWidth = 320;
btnLayout.minHeight = 25;
btnLayout.flexibleHeight = 0;
btnGroupObj.AddComponent<Mask>();
var toggleObj = UIFactory.CreateToggle(btnGroupObj, out Toggle toggle, out Text toggleText, new Color(0.1f, 0.1f, 0.1f));
var toggleLayout = toggleObj.AddComponent<LayoutElement>();
toggleLayout.minHeight = 25;
toggleLayout.minWidth = 25;
toggleText.text = "";
toggle.isOn = false;
m_shortListToggles.Add(toggle);
toggle.onValueChanged.AddListener((bool val) => { OnToggleClicked(thisIndex, val); });
GameObject mainButtonObj = UIFactory.CreateButton(btnGroupObj);
LayoutElement mainBtnLayout = mainButtonObj.AddComponent<LayoutElement>();
mainBtnLayout.minHeight = 25;
mainBtnLayout.flexibleHeight = 0;
mainBtnLayout.minWidth = 230;
mainBtnLayout.flexibleWidth = 0;
Button mainBtn = mainButtonObj.GetComponent<Button>();
ColorBlock mainColors = mainBtn.colors;
mainColors.normalColor = new Color(0.1f, 0.1f, 0.1f);
mainColors.highlightedColor = new Color(0.2f, 0.2f, 0.2f, 1);
mainBtn.colors = mainColors;
mainBtn.onClick.AddListener(() => { SceneListObjectClicked(thisIndex); });
Text mainText = mainButtonObj.GetComponentInChildren<Text>();
mainText.alignment = TextAnchor.MiddleLeft;
mainText.horizontalOverflow = HorizontalWrapMode.Overflow;
m_shortListTexts.Add(mainText);
GameObject inspectBtnObj = UIFactory.CreateButton(btnGroupObj);
LayoutElement inspectBtnLayout = inspectBtnObj.AddComponent<LayoutElement>();
inspectBtnLayout.minWidth = 60;
inspectBtnLayout.flexibleWidth = 0;
inspectBtnLayout.minHeight = 25;
inspectBtnLayout.flexibleHeight = 0;
Text inspectText = inspectBtnObj.GetComponentInChildren<Text>();
inspectText.text = "Inspect";
inspectText.color = Color.white;
Button inspectBtn = inspectBtnObj.GetComponent<Button>();
ColorBlock inspectColors = inspectBtn.colors;
inspectColors.normalColor = new Color(0.15f, 0.15f, 0.15f);
mainColors.highlightedColor = new Color(0.2f, 0.2f, 0.2f, 0.5f);
inspectBtn.colors = inspectColors;
inspectBtn.onClick.AddListener(() => { InspectorManager.Instance.Inspect(m_shortList[thisIndex]); });
}
#endregion
}
}

View File

@ -6,7 +6,10 @@ using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI.Main;
using UnityExplorer.UI.Main.Home;
using UnityExplorer.UI.Main.Search;
using UnityExplorer.UI.Main.CSConsole;
using UnityExplorer.UI.Main.Options;
namespace UnityExplorer.UI.Main
{
@ -28,9 +31,15 @@ namespace UnityExplorer.UI.Main
private Button m_lastNavButtonPressed;
private readonly Color m_navButtonNormal = new Color(0.3f, 0.3f, 0.3f, 1);
private readonly Color m_navButtonHighlight = new Color(0.3f, 0.6f, 0.3f);
private readonly Color m_navButtonSelected = new Color(0.2f, 0.5f, 0.2f, 1);
private readonly Color m_navButtonSelected = new Color(0.2f, 0.5f, 0.2f, 1);
public MainMenu()
internal Vector3 initPos;
internal bool pageLayoutInit;
internal int layoutInitIndex;
private int origDesiredPage = -1;
public static void Create()
{
if (Instance != null)
{
@ -38,8 +47,12 @@ namespace UnityExplorer.UI.Main
return;
}
Instance = this;
Instance = new MainMenu();
Instance.Init();
}
private void Init()
{
Pages.Add(new HomePage());
Pages.Add(new SearchPage());
Pages.Add(new CSharpConsole());
@ -50,7 +63,7 @@ namespace UnityExplorer.UI.Main
for (int i = 0; i < Pages.Count; i++)
{
var page = Pages[i];
if (!page.Init())
{
// page init failed.
@ -59,7 +72,7 @@ namespace UnityExplorer.UI.Main
if (page.RefNavbarButton)
page.RefNavbarButton.interactable = false;
if (page.Content)
GameObject.Destroy(page.Content);
}
@ -70,18 +83,12 @@ namespace UnityExplorer.UI.Main
MainPanel.transform.position = new Vector3(9999, 9999);
}
internal Vector3 initPos;
internal bool pageLayoutInit;
internal int layoutInitIndex;
private int origDesiredPage = -1;
public void Update()
{
if (!pageLayoutInit)
{
if (origDesiredPage == -1)
origDesiredPage = ExplorerConfig.Instance?.Active_Tab ?? 0;
origDesiredPage = ConfigManager.Last_Active_Tab?.Value ?? 0;
if (layoutInitIndex < Pages.Count)
{
@ -144,64 +151,29 @@ namespace UnityExplorer.UI.Main
private void ConstructMenu()
{
MainPanel = UIFactory.CreatePanel(UIManager.CanvasRoot, "MainMenu", out GameObject content);
RectTransform panelRect = MainPanel.GetComponent<RectTransform>();
var anchors = ExplorerConfig.Instance.GetWindowAnchorsVector();
SetPanelAnchors(panelRect, anchors);
if (panelRect.rect.width < 400 || panelRect.rect.height < 400)
{
anchors = ExplorerConfig.DefaultWindowAnchors();
SetPanelAnchors(panelRect, anchors);
}
MainPanel.AddComponent<Mask>();
MainPanel = UIFactory.CreatePanel("MainMenu", out GameObject content, ConfigManager.Last_Window_Anchors.Value);
ConstructTitleBar(content);
ConstructNavbar(content);
ConstructMainViewport(content);
PageViewport = UIFactory.CreateHorizontalGroup(content, "MainViewPort", true, true, true, true);
new DebugConsole(content);
}
private void SetPanelAnchors(RectTransform panelRect, Vector4 anchors)
{
panelRect.anchorMin = new Vector2(anchors.x, anchors.y);
panelRect.anchorMax = new Vector2(anchors.z, anchors.w);
}
private void ConstructTitleBar(GameObject content)
{
// Core title bar holder
GameObject titleBar = UIFactory.CreateHorizontalGroup(content);
GameObject titleBar = UIFactory.CreateHorizontalGroup(content, "MainTitleBar", true, true, true, true, 0, new Vector4(3,3,15,3));
UIFactory.SetLayoutElement(titleBar, minWidth: 25, flexibleHeight: 0);
HorizontalLayoutGroup titleGroup = titleBar.GetComponent<HorizontalLayoutGroup>();
titleGroup.SetChildControlHeight(true);
titleGroup.SetChildControlWidth(true);
titleGroup.childForceExpandHeight = true;
titleGroup.childForceExpandWidth = true;
titleGroup.padding.left = 15;
titleGroup.padding.right = 3;
titleGroup.padding.top = 3;
titleGroup.padding.bottom = 3;
// Main title label
LayoutElement titleLayout = titleBar.AddComponent<LayoutElement>();
titleLayout.minHeight = 25;
titleLayout.flexibleHeight = 0;
// Explorer label
GameObject textObj = UIFactory.CreateLabel(titleBar, TextAnchor.MiddleLeft);
Text text = textObj.GetComponent<Text>();
text.text = $"<b>UnityExplorer</b> <i>v{ExplorerCore.VERSION}</i>";
text.fontSize = 15;
LayoutElement textLayout = textObj.AddComponent<LayoutElement>();
textLayout.flexibleWidth = 5000;
var text = UIFactory.CreateLabel(titleBar, "TitleLabel", $"<b>UnityExplorer</b> <i>v{ExplorerCore.VERSION}</i>", TextAnchor.MiddleLeft,
default, true, 15);
UIFactory.SetLayoutElement(text.gameObject, flexibleWidth: 5000);
// Add PanelDragger using the label object
@ -209,84 +181,53 @@ namespace UnityExplorer.UI.Main
// Hide button
GameObject hideBtnObj = UIFactory.CreateButton(titleBar);
Button hideBtn = hideBtnObj.GetComponent<Button>();
hideBtn.onClick.AddListener(() => { UIManager.ShowMenu = false; });
ColorBlock colorBlock = hideBtn.colors;
ColorBlock colorBlock = new ColorBlock();
colorBlock.normalColor = new Color(65f / 255f, 23f / 255f, 23f / 255f);
colorBlock.pressedColor = new Color(35f / 255f, 10f / 255f, 10f / 255f);
colorBlock.highlightedColor = new Color(156f / 255f, 0f, 0f);
hideBtn.colors = colorBlock;
LayoutElement btnLayout = hideBtnObj.AddComponent<LayoutElement>();
btnLayout.minWidth = 90;
btnLayout.flexibleWidth = 2;
var hideButton = UIFactory.CreateButton(titleBar,
"HideButton",
$"Hide ({ConfigManager.Main_Menu_Toggle.Value})",
() => { UIManager.ShowMenu = false; },
colorBlock);
Text hideText = hideBtnObj.GetComponentInChildren<Text>();
UIFactory.SetLayoutElement(hideButton.gameObject, minWidth: 90, flexibleWidth: 0);
Text hideText = hideButton.GetComponentInChildren<Text>();
hideText.color = Color.white;
hideText.resizeTextForBestFit = true;
hideText.resizeTextMinSize = 8;
hideText.resizeTextMaxSize = 14;
hideText.text = $"Hide ({ExplorerConfig.Instance.Main_Menu_Toggle})";
ExplorerConfig.OnConfigChanged += ModConfig_OnConfigChanged;
void ModConfig_OnConfigChanged()
ConfigManager.Main_Menu_Toggle.OnValueChanged += (KeyCode val) =>
{
hideText.text = $"Hide ({ExplorerConfig.Instance.Main_Menu_Toggle})";
}
hideText.text = $"Hide ({val})";
};
}
private void ConstructNavbar(GameObject content)
{
GameObject navbarObj = UIFactory.CreateHorizontalGroup(content);
GameObject navbarObj = UIFactory.CreateHorizontalGroup(content, "MainNavBar", true, true, true, true, 5);
UIFactory.SetLayoutElement(navbarObj, minHeight: 25, flexibleHeight: 0);
HorizontalLayoutGroup navGroup = navbarObj.GetComponent<HorizontalLayoutGroup>();
navGroup.spacing = 5;
navGroup.SetChildControlHeight(true);
navGroup.SetChildControlWidth(true);
navGroup.childForceExpandHeight = true;
navGroup.childForceExpandWidth = true;
ColorBlock colorBlock = new ColorBlock();
colorBlock.normalColor = m_navButtonNormal;
colorBlock.highlightedColor = m_navButtonHighlight;
colorBlock.pressedColor = m_navButtonSelected;
LayoutElement navLayout = navbarObj.AddComponent<LayoutElement>();
navLayout.minHeight = 25;
navLayout.flexibleHeight = 0;
foreach (BaseMenuPage page in Pages)
foreach (var page in Pages)
{
GameObject btnObj = UIFactory.CreateButton(navbarObj);
Button btn = btnObj.GetComponent<Button>();
Button btn = UIFactory.CreateButton(navbarObj,
$"Button_{page.Name}",
page.Name,
() => { SetPage(page); },
colorBlock);
page.RefNavbarButton = btn;
btn.onClick.AddListener(() => { SetPage(page); });
Text text = btnObj.GetComponentInChildren<Text>();
text.text = page.Name;
// Set button colors
ColorBlock colorBlock = btn.colors;
colorBlock.normalColor = m_navButtonNormal;
//try { colorBlock.selectedColor = colorBlock.normalColor; } catch { }
colorBlock.highlightedColor = m_navButtonHighlight;
colorBlock.pressedColor = m_navButtonSelected;
btn.colors = colorBlock;
}
}
private void ConstructMainViewport(GameObject content)
{
GameObject mainObj = UIFactory.CreateHorizontalGroup(content);
HorizontalLayoutGroup mainGroup = mainObj.GetComponent<HorizontalLayoutGroup>();
mainGroup.SetChildControlHeight(true);
mainGroup.SetChildControlWidth(true);
mainGroup.childForceExpandHeight = true;
mainGroup.childForceExpandWidth = true;
PageViewport = mainObj;
}
#endregion
}
}

View File

@ -4,254 +4,64 @@ using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Config;
using UnityExplorer.UI.Reusable;
using UnityExplorer.UI.CacheObject;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI.Main
namespace UnityExplorer.UI.Main.Options
{
public class OptionsPage : BaseMenuPage
{
public override string Name => "Options";
private InputField m_keycodeInput;
private Toggle m_unlockMouseToggle;
private InputField m_pageLimitInput;
private InputField m_defaultOutputInput;
private Toggle m_hideOnStartupToggle;
internal static readonly List<CacheConfigEntry> _cachedConfigEntries = new List<CacheConfigEntry>();
public override bool Init()
{
ConstructUI();
_cachedConfigEntries.AddRange(ConfigManager.ConfigElements.Values
.Where(it => !it.IsInternal)
.Select(it => new CacheConfigEntry(it, m_contentObj)));
foreach (var entry in _cachedConfigEntries)
entry.Enable();
return true;
}
public override void Update()
{
}
internal void OnApply()
{
if (!string.IsNullOrEmpty(m_keycodeInput.text) && Enum.Parse(typeof(KeyCode), m_keycodeInput.text) is KeyCode keyCode)
ExplorerConfig.Instance.Main_Menu_Toggle = keyCode;
ExplorerConfig.Instance.Force_Unlock_Mouse = m_unlockMouseToggle.isOn;
if (!string.IsNullOrEmpty(m_pageLimitInput.text) && int.TryParse(m_pageLimitInput.text, out int lim))
ExplorerConfig.Instance.Default_Page_Limit = lim;
ExplorerConfig.Instance.Default_Output_Path = m_defaultOutputInput.text;
ExplorerConfig.Instance.Hide_On_Startup = m_hideOnStartupToggle.isOn;
ExplorerConfig.SaveSettings();
ExplorerConfig.InvokeConfigChanged();
// Not needed
}
#region UI CONSTRUCTION
internal GameObject m_contentObj;
internal void ConstructUI()
{
GameObject parent = MainMenu.Instance.PageViewport;
Content = UIFactory.CreateVerticalGroup(parent, new Color(0.15f, 0.15f, 0.15f));
var mainGroup = Content.GetComponent<VerticalLayoutGroup>();
mainGroup.padding.left = 4;
mainGroup.padding.right = 4;
mainGroup.padding.top = 4;
mainGroup.padding.bottom = 4;
mainGroup.spacing = 5;
mainGroup.childForceExpandHeight = false;
mainGroup.childForceExpandWidth = true;
mainGroup.SetChildControlHeight(true);
mainGroup.SetChildControlWidth(true);
Content = UIFactory.CreateVerticalGroup(parent, "OptionsPage", true, true, true, true, 5, new Vector4(4,4,4,4),
new Color(0.15f, 0.15f, 0.15f));
UIFactory.SetLayoutElement(Content, minHeight: 340, flexibleHeight: 9999);
// ~~~~~ Title ~~~~~
GameObject titleObj = UIFactory.CreateLabel(Content, TextAnchor.UpperLeft);
Text titleLabel = titleObj.GetComponent<Text>();
titleLabel.text = "Options";
titleLabel.fontSize = 20;
LayoutElement titleLayout = titleObj.AddComponent<LayoutElement>();
titleLayout.minHeight = 30;
titleLayout.flexibleHeight = 0;
var titleLabel = UIFactory.CreateLabel(Content, "Title", "Options", TextAnchor.UpperLeft, default, true, 25);
UIFactory.SetLayoutElement(titleLabel.gameObject, minHeight: 30, flexibleHeight: 0);
// ~~~~~ Actual options ~~~~~
var optionsGroupObj = UIFactory.CreateVerticalGroup(Content, new Color(0.1f, 0.1f, 0.1f));
var optionsGroup = optionsGroupObj.GetComponent<VerticalLayoutGroup>();
optionsGroup.childForceExpandHeight = false;
optionsGroup.childForceExpandWidth = true;
optionsGroup.SetChildControlWidth(true);
optionsGroup.SetChildControlHeight(true);
optionsGroup.spacing = 5;
optionsGroup.padding.top = 5;
optionsGroup.padding.left = 5;
optionsGroup.padding.right = 5;
optionsGroup.padding.bottom = 5;
UIFactory.CreateScrollView(Content, "ConfigList", out m_contentObj, out _, new Color(0.05f, 0.05f, 0.05f));
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(m_contentObj, forceHeight: true, spacing: 3, padLeft: 3, padRight: 3);
ConstructKeycodeOpt(optionsGroupObj);
ConstructMouseUnlockOpt(optionsGroupObj);
ConstructPageLimitOpt(optionsGroupObj);
ConstructOutputPathOpt(optionsGroupObj);
ConstructHideOnStartupOpt(optionsGroupObj);
var applyBtnObj = UIFactory.CreateButton(Content, new Color(0.2f, 0.2f, 0.2f));
var applyText = applyBtnObj.GetComponentInChildren<Text>();
applyText.text = "Apply and Save";
var applyLayout = applyBtnObj.AddComponent<LayoutElement>();
applyLayout.minHeight = 30;
applyLayout.flexibleWidth = 1000;
var applyBtn = applyBtnObj.GetComponent<Button>();
var applyColors = applyBtn.colors;
applyColors.normalColor = new Color(0.3f, 0.7f, 0.3f);
applyBtn.colors = applyColors;
applyBtn.onClick.AddListener(OnApply);
//m_contentObj = UIFactory.CreateVerticalGroup(Content, "OptionsGroup", true, false, true, false, 5, new Vector4(5,5,5,5),
// new Color(0.1f, 0.1f, 0.1f));
//UIFactory.SetLayoutElement(m_contentObj, minHeight: 340, flexibleHeight: 9999);
}
private void ConstructHideOnStartupOpt(GameObject optionsGroupObj)
{
var rowObj = UIFactory.CreateHorizontalGroup(optionsGroupObj, new Color(1, 1, 1, 0));
var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
rowGroup.SetChildControlWidth(true);
rowGroup.childForceExpandWidth = false;
rowGroup.SetChildControlHeight(true);
rowGroup.childForceExpandHeight = true;
var groupLayout = rowObj.AddComponent<LayoutElement>();
groupLayout.minHeight = 25;
groupLayout.flexibleHeight = 0;
groupLayout.minWidth = 200;
groupLayout.flexibleWidth = 1000;
var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
var labelText = labelObj.GetComponent<Text>();
labelText.text = "Hide UI on startup:";
var labelLayout = labelObj.AddComponent<LayoutElement>();
labelLayout.minWidth = 150;
labelLayout.minHeight = 25;
UIFactory.CreateToggle(rowObj, out m_hideOnStartupToggle, out Text toggleText);
m_hideOnStartupToggle.isOn = ExplorerConfig.Instance.Hide_On_Startup;
toggleText.text = "";
}
internal void ConstructKeycodeOpt(GameObject parent)
{
var rowObj = UIFactory.CreateHorizontalGroup(parent, new Color(1, 1, 1, 0));
var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
rowGroup.SetChildControlWidth(true);
rowGroup.childForceExpandWidth = false;
rowGroup.SetChildControlHeight(true);
rowGroup.childForceExpandHeight = true;
var groupLayout = rowObj.AddComponent<LayoutElement>();
groupLayout.minHeight = 25;
groupLayout.flexibleHeight = 0;
groupLayout.minWidth = 200;
groupLayout.flexibleWidth = 1000;
var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
var labelText = labelObj.GetComponent<Text>();
labelText.text = "Main Menu Toggle:";
var labelLayout = labelObj.AddComponent<LayoutElement>();
labelLayout.minWidth = 150;
labelLayout.minHeight = 25;
var keycodeInputObj = UIFactory.CreateInputField(rowObj);
m_keycodeInput = keycodeInputObj.GetComponent<InputField>();
m_keycodeInput.text = ExplorerConfig.Instance.Main_Menu_Toggle.ToString();
m_keycodeInput.placeholder.gameObject.GetComponent<Text>().text = "KeyCode, eg. F7";
}
internal void ConstructMouseUnlockOpt(GameObject parent)
{
var rowObj = UIFactory.CreateHorizontalGroup(parent, new Color(1, 1, 1, 0));
var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
rowGroup.SetChildControlWidth(true);
rowGroup.childForceExpandWidth = false;
rowGroup.SetChildControlHeight(true);
rowGroup.childForceExpandHeight = true;
var groupLayout = rowObj.AddComponent<LayoutElement>();
groupLayout.minHeight = 25;
groupLayout.flexibleHeight = 0;
groupLayout.minWidth = 200;
groupLayout.flexibleWidth = 1000;
var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
var labelText = labelObj.GetComponent<Text>();
labelText.text = "Force Unlock Mouse:";
var labelLayout = labelObj.AddComponent<LayoutElement>();
labelLayout.minWidth = 150;
labelLayout.minHeight = 25;
UIFactory.CreateToggle(rowObj, out m_unlockMouseToggle, out Text toggleText);
m_unlockMouseToggle.isOn = ExplorerConfig.Instance.Force_Unlock_Mouse;
toggleText.text = "";
}
internal void ConstructPageLimitOpt(GameObject parent)
{
//public int Default_Page_Limit = 20;
var rowObj = UIFactory.CreateHorizontalGroup(parent, new Color(1, 1, 1, 0));
var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
rowGroup.SetChildControlWidth(true);
rowGroup.childForceExpandWidth = false;
rowGroup.SetChildControlHeight(true);
rowGroup.childForceExpandHeight = true;
var groupLayout = rowObj.AddComponent<LayoutElement>();
groupLayout.minHeight = 25;
groupLayout.flexibleHeight = 0;
groupLayout.minWidth = 200;
groupLayout.flexibleWidth = 1000;
var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
var labelText = labelObj.GetComponent<Text>();
labelText.text = "Default Page Limit:";
var labelLayout = labelObj.AddComponent<LayoutElement>();
labelLayout.minWidth = 150;
labelLayout.minHeight = 25;
var inputObj = UIFactory.CreateInputField(rowObj);
m_pageLimitInput = inputObj.GetComponent<InputField>();
m_pageLimitInput.text = ExplorerConfig.Instance.Default_Page_Limit.ToString();
m_pageLimitInput.placeholder.gameObject.GetComponent<Text>().text = "Integer, eg. 20";
}
internal void ConstructOutputPathOpt(GameObject parent)
{
//public string Default_Output_Path = ExplorerCore.EXPLORER_FOLDER;
var rowObj = UIFactory.CreateHorizontalGroup(parent, new Color(1, 1, 1, 0));
var rowGroup = rowObj.GetComponent<HorizontalLayoutGroup>();
rowGroup.SetChildControlWidth(true);
rowGroup.childForceExpandWidth = false;
rowGroup.SetChildControlHeight(true);
rowGroup.childForceExpandHeight = true;
var groupLayout = rowObj.AddComponent<LayoutElement>();
groupLayout.minHeight = 25;
groupLayout.flexibleHeight = 0;
groupLayout.minWidth = 200;
groupLayout.flexibleWidth = 1000;
var labelObj = UIFactory.CreateLabel(rowObj, TextAnchor.MiddleLeft);
var labelText = labelObj.GetComponent<Text>();
labelText.text = "Default Output Path:";
var labelLayout = labelObj.AddComponent<LayoutElement>();
labelLayout.minWidth = 150;
labelLayout.minHeight = 25;
var inputObj = UIFactory.CreateInputField(rowObj);
m_defaultOutputInput = inputObj.GetComponent<InputField>();
m_defaultOutputInput.text = ExplorerConfig.Instance.Default_Output_Path.ToString();
m_defaultOutputInput.placeholder.gameObject.GetComponent<Text>().text = @"Directory, eg. Mods\UnityExplorer";
}
#endregion
#endregion
}
}

View File

@ -4,10 +4,10 @@ using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Input;
using System.IO;
using UnityExplorer.Core.Inspectors;
using System.Diagnostics;
using UnityExplorer.UI.Main.Home;
namespace UnityExplorer.UI
namespace UnityExplorer.UI.Main
{
// Handles dragging and resizing for the main explorer window.
@ -17,7 +17,7 @@ namespace UnityExplorer.UI
public RectTransform Panel { get; set; }
public static event Action OnFinishResize;
public static event Action<RectTransform> OnFinishResize;
public PanelDragger(RectTransform dragArea, RectTransform panelToDrag)
{
@ -169,14 +169,13 @@ namespace UnityExplorer.UI
}
private const int HALF_THICKESS = RESIZE_THICKNESS / 2;
private const int DBL_THICKNESS = RESIZE_THICKNESS* 2;
private void UpdateResizeCache()
{
m_resizeRect = new Rect(Panel.rect.x - HALF_THICKESS,
Panel.rect.y - HALF_THICKESS,
Panel.rect.width + DBL_THICKNESS,
Panel.rect.height + DBL_THICKNESS);
Panel.rect.width + RESIZE_THICKNESS,
Panel.rect.height + RESIZE_THICKNESS);
// calculate the four cross sections to use as flags
@ -316,25 +315,21 @@ namespace UnityExplorer.UI
}
}
public void OnEndResize()
public void OnEndResize(bool showing = false)
{
WasResizing = false;
UpdateResizeCache();
OnFinishResize?.Invoke();
OnFinishResize?.Invoke(Panel);
}
internal static void LoadCursorImage()
internal static void CreateCursorUI()
{
try
{
s_resizeCursorObj = UIFactory.CreateLabel(UIManager.CanvasRoot.gameObject, TextAnchor.MiddleCenter);
var text = UIFactory.CreateLabel(UIManager.CanvasRoot.gameObject, "ResizeCursor", "↔", TextAnchor.MiddleCenter, Color.white, true, 35);
s_resizeCursorObj = text.gameObject;
var text = s_resizeCursorObj.GetComponent<Text>();
text.text = "↔";
text.fontSize = 35;
text.color = Color.white;
RectTransform rect = s_resizeCursorObj.transform.GetComponent<RectTransform>();
RectTransform rect = s_resizeCursorObj.GetComponent<RectTransform>();
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 64);
rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 64);
@ -342,7 +337,7 @@ namespace UnityExplorer.UI
}
catch (Exception e)
{
ExplorerCore.LogWarning("Exception loading cursor image!\r\n" + e.ToString());
ExplorerCore.LogWarning("Exception creating Resize Cursor UI!\r\n" + e.ToString());
}
}

View File

@ -4,15 +4,14 @@ using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityExplorer.Core.Inspectors;
using UnityExplorer.UI.Reusable;
using System.Reflection;
using UnityExplorer.Core.Runtime;
using UnityExplorer.Core;
using UnityExplorer.Search;
using UnityExplorer.UI.Utility;
using UnityExplorer.Core.Search;
using UnityExplorer.UI.Main.Home;
namespace UnityExplorer.UI.Main
namespace UnityExplorer.UI.Main.Search
{
public class SearchPage : BaseMenuPage
{
@ -207,7 +206,7 @@ namespace UnityExplorer.UI.Main
});
}
m_sceneDropdown.transform.Find("Label").GetComponent<Text>().text = "Any";
m_sceneDropdown.itemText.text = "Any";
m_sceneFilter = SceneFilter.Any;
}
@ -254,7 +253,7 @@ namespace UnityExplorer.UI.Main
return;
if (m_selectedContextButton)
UIFactory.SetDefaultColorTransitionValues(m_selectedContextButton);
UIFactory.SetDefaultSelectableColors(m_selectedContextButton);
var button = m_contextButtons[context];
@ -268,8 +267,8 @@ namespace UnityExplorer.UI.Main
m_context = context;
// if extra filters are valid
if (context == SearchContext.Component
|| context == SearchContext.GameObject
if (context == SearchContext.Component
|| context == SearchContext.GameObject
|| context == SearchContext.Custom)
{
m_extraFilterRow?.SetActive(true);
@ -280,23 +279,13 @@ namespace UnityExplorer.UI.Main
}
}
#region UI CONSTRUCTION
#region UI CONSTRUCTION
internal void ConstructUI()
{
GameObject parent = MainMenu.Instance.PageViewport;
Content = UIFactory.CreateVerticalGroup(parent);
var mainGroup = Content.GetComponent<VerticalLayoutGroup>();
mainGroup.padding.left = 4;
mainGroup.padding.right = 4;
mainGroup.padding.top = 4;
mainGroup.padding.bottom = 4;
mainGroup.spacing = 5;
mainGroup.childForceExpandHeight = true;
mainGroup.childForceExpandWidth = true;
mainGroup.SetChildControlHeight(true);
mainGroup.SetChildControlWidth(true);
Content = UIFactory.CreateVerticalGroup(parent, "SearchPage", true, true, true, true, 5, new Vector4(4,4,4,4));
ConstructTopArea();
@ -305,312 +294,172 @@ namespace UnityExplorer.UI.Main
internal void ConstructTopArea()
{
var topAreaObj = UIFactory.CreateVerticalGroup(Content, new Color(0.15f, 0.15f, 0.15f));
var topGroup = topAreaObj.GetComponent<VerticalLayoutGroup>();
topGroup.childForceExpandHeight = false;
topGroup.SetChildControlHeight(true);
topGroup.childForceExpandWidth = true;
topGroup.SetChildControlWidth(true);
topGroup.padding.top = 5;
topGroup.padding.left = 5;
topGroup.padding.right = 5;
topGroup.padding.bottom = 5;
topGroup.spacing = 5;
var topAreaObj = UIFactory.CreateVerticalGroup(Content, "TitleArea", true, false, true, true, 5, new Vector4(5,5,5,5),
new Color(0.15f, 0.15f, 0.15f));
GameObject titleObj = UIFactory.CreateLabel(topAreaObj, TextAnchor.UpperLeft);
Text titleLabel = titleObj.GetComponent<Text>();
titleLabel.text = "Search";
titleLabel.fontSize = 20;
LayoutElement titleLayout = titleObj.AddComponent<LayoutElement>();
titleLayout.minHeight = 30;
titleLayout.flexibleHeight = 0;
var titleLabel = UIFactory.CreateLabel(topAreaObj, "SearchTitle", "Search", TextAnchor.UpperLeft, Color.white, true, 25);
UIFactory.SetLayoutElement(titleLabel.gameObject, minHeight: 30, flexibleHeight: 0);
// top area options
var optionsGroupObj = UIFactory.CreateVerticalGroup(topAreaObj, new Color(0.1f, 0.1f, 0.1f));
var optionsGroup = optionsGroupObj.GetComponent<VerticalLayoutGroup>();
optionsGroup.childForceExpandHeight = false;
optionsGroup.SetChildControlHeight(true);
optionsGroup.childForceExpandWidth = true;
optionsGroup.SetChildControlWidth(true);
optionsGroup.spacing = 10;
optionsGroup.padding.top = 4;
optionsGroup.padding.right = 4;
optionsGroup.padding.left = 4;
optionsGroup.padding.bottom = 4;
var optionsLayout = optionsGroupObj.AddComponent<LayoutElement>();
optionsLayout.minWidth = 500;
optionsLayout.minHeight = 70;
optionsLayout.flexibleHeight = 100;
var optionsGroupObj = UIFactory.CreateVerticalGroup(topAreaObj, "OptionsArea", true, false, true, true, 10, new Vector4(4,4,4,4),
new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutElement(optionsGroupObj, minWidth: 500, minHeight: 70, flexibleHeight: 100);
// search context row
var contextRowObj = UIFactory.CreateHorizontalGroup(optionsGroupObj, new Color(1, 1, 1, 0));
var contextGroup = contextRowObj.GetComponent<HorizontalLayoutGroup>();
contextGroup.childForceExpandWidth = false;
contextGroup.SetChildControlWidth(true);
contextGroup.childForceExpandHeight = false;
contextGroup.SetChildControlHeight(true);
contextGroup.spacing = 3;
var contextLayout = contextRowObj.AddComponent<LayoutElement>();
contextLayout.minHeight = 25;
var contextRowObj = UIFactory.CreateHorizontalGroup(optionsGroupObj, "ContextFilters", false, false, true, true, 3, default,
new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(contextRowObj, minHeight: 25);
var contextLabelObj = UIFactory.CreateLabel(contextRowObj, TextAnchor.MiddleLeft);
var contextText = contextLabelObj.GetComponent<Text>();
contextText.text = "Searching for:";
var contextLabelLayout = contextLabelObj.AddComponent<LayoutElement>();
contextLabelLayout.minWidth = 125;
contextLabelLayout.minHeight = 25;
var contextLabelObj = UIFactory.CreateLabel(contextRowObj, "ContextLabel", "Searching for:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(contextLabelObj.gameObject, minWidth: 125, minHeight: 25);
// context buttons
AddContextButton(contextRowObj, "UnityEngine.Object", SearchContext.UnityObject, 140);
AddContextButton(contextRowObj, "GameObject", SearchContext.GameObject);
AddContextButton(contextRowObj, "Component", SearchContext.Component);
AddContextButton(contextRowObj, "Custom...", SearchContext.Custom);
AddContextButton(contextRowObj, "UnityEngine.Object", SearchContext.UnityObject, 140);
AddContextButton(contextRowObj, "GameObject", SearchContext.GameObject);
AddContextButton(contextRowObj, "Component", SearchContext.Component);
AddContextButton(contextRowObj, "Custom...", SearchContext.Custom);
// custom type input
var customTypeObj = UIFactory.CreateInputField(contextRowObj);
var customTypeLayout = customTypeObj.AddComponent<LayoutElement>();
customTypeLayout.minWidth = 250;
customTypeLayout.flexibleWidth = 2000;
customTypeLayout.minHeight = 25;
customTypeLayout.flexibleHeight = 0;
var customTypeObj = UIFactory.CreateInputField(contextRowObj, "CustomTypeInput", "eg. UnityEngine.Texture2D, etc...");
UIFactory.SetLayoutElement(customTypeObj, minWidth: 250, flexibleWidth: 2000, minHeight: 25, flexibleHeight: 0);
m_customTypeInput = customTypeObj.GetComponent<InputField>();
m_customTypeInput.placeholder.gameObject.GetComponent<Text>().text = "eg. UnityEngine.Texture2D, etc...";
// static class and singleton buttons
var secondRow = UIFactory.CreateHorizontalGroup(optionsGroupObj, new Color(1, 1, 1, 0));
var secondGroup = secondRow.GetComponent<HorizontalLayoutGroup>();
secondGroup.childForceExpandWidth = false;
secondGroup.childForceExpandHeight = false;
secondGroup.spacing = 3;
var secondLayout = secondRow.AddComponent<LayoutElement>();
secondLayout.minHeight = 25;
var secondRow = UIFactory.CreateHorizontalGroup(optionsGroupObj, "SecondRow", false, false, true, true, 3, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(secondRow, minHeight: 25);
var spacer = UIFactory.CreateUIObject("spacer", secondRow);
var spaceLayout = spacer.AddComponent<LayoutElement>();
spaceLayout.minWidth = 125;
spaceLayout.minHeight = 25;
UIFactory.SetLayoutElement(spacer, minWidth: 25, minHeight: 25);
AddContextButton(secondRow, "Static Class", SearchContext.StaticClass);
AddContextButton(secondRow, "Singleton", SearchContext.Singleton);
// search input
var nameRowObj = UIFactory.CreateHorizontalGroup(optionsGroupObj, new Color(1, 1, 1, 0));
var nameRowGroup = nameRowObj.GetComponent<HorizontalLayoutGroup>();
nameRowGroup.childForceExpandWidth = true;
nameRowGroup.SetChildControlWidth(true);
nameRowGroup.childForceExpandHeight = false;
nameRowGroup.SetChildControlHeight(true);
var nameRowLayout = nameRowObj.AddComponent<LayoutElement>();
nameRowLayout.minHeight = 25;
nameRowLayout.flexibleHeight = 0;
nameRowLayout.flexibleWidth = 5000;
var nameRowObj = UIFactory.CreateHorizontalGroup(optionsGroupObj, "SearchInput", true, false, true, true, 0, default, new Color(1, 1, 1, 0));
UIFactory.SetLayoutElement(nameRowObj, minHeight: 25, flexibleHeight: 0, flexibleWidth: 5000);
var nameLabelObj = UIFactory.CreateLabel(nameRowObj, TextAnchor.MiddleLeft);
var nameLabelText = nameLabelObj.GetComponent<Text>();
nameLabelText.text = "Name contains:";
var nameLabelLayout = nameLabelObj.AddComponent<LayoutElement>();
nameLabelLayout.minWidth = 125;
nameLabelLayout.minHeight = 25;
var nameLabel = UIFactory.CreateLabel(nameRowObj, "NameLabel", "Name contains:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(nameLabel.gameObject, minWidth: 125, minHeight: 25);
var nameInputObj = UIFactory.CreateInputField(nameRowObj);
var nameInputObj = UIFactory.CreateInputField(nameRowObj, "NameInputField", "...");
m_nameInput = nameInputObj.GetComponent<InputField>();
//m_nameInput.placeholder.gameObject.GetComponent<TextMeshProUGUI>().text = "";
var nameInputLayout = nameInputObj.AddComponent<LayoutElement>();
nameInputLayout.minWidth = 150;
nameInputLayout.flexibleWidth = 5000;
nameInputLayout.minHeight = 25;
UIFactory.SetLayoutElement(nameInputObj, minWidth: 150, flexibleWidth: 5000, minHeight: 25);
// extra filter row
m_extraFilterRow = UIFactory.CreateHorizontalGroup(optionsGroupObj, new Color(1, 1, 1, 0));
m_extraFilterRow = UIFactory.CreateHorizontalGroup(optionsGroupObj, "ExtraFilterRow", false, true, true, true, 0, default, new Color(1, 1, 1, 0));
m_extraFilterRow.SetActive(false);
var extraGroup = m_extraFilterRow.GetComponent<HorizontalLayoutGroup>();
extraGroup.childForceExpandHeight = true;
extraGroup.SetChildControlHeight(true);
extraGroup.childForceExpandWidth = false;
extraGroup.SetChildControlWidth(true);
var filterRowLayout = m_extraFilterRow.AddComponent<LayoutElement>();
filterRowLayout.minHeight = 25;
filterRowLayout.flexibleHeight = 0;
filterRowLayout.minWidth = 125;
filterRowLayout.flexibleWidth = 150;
UIFactory.SetLayoutElement(m_extraFilterRow, minHeight: 25, minWidth: 125, flexibleHeight: 0, flexibleWidth: 150);
// scene filter
var sceneLabelObj = UIFactory.CreateLabel(m_extraFilterRow, TextAnchor.MiddleLeft);
var sceneLabel = sceneLabelObj.GetComponent<Text>();
sceneLabel.text = "Scene Filter:";
var sceneLayout = sceneLabelObj.AddComponent<LayoutElement>();
sceneLayout.minWidth = 125;
sceneLayout.minHeight = 25;
var sceneLabelObj = UIFactory.CreateLabel(m_extraFilterRow, "SceneFilterLabel", "Scene filter:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(sceneLabelObj.gameObject, minWidth: 125, minHeight: 25);
var sceneDropObj = UIFactory.CreateDropdown(m_extraFilterRow, out m_sceneDropdown);
m_sceneDropdown.itemText.text = "Any";
m_sceneDropdown.itemText.fontSize = 12;
var sceneDropLayout = sceneDropObj.AddComponent<LayoutElement>();
sceneDropLayout.minWidth = 220;
sceneDropLayout.minHeight = 25;
var sceneDropObj = UIFactory.CreateDropdown(m_extraFilterRow,
out m_sceneDropdown,
"Any",
12,
(int value) => { m_sceneFilter = (SceneFilter)value; }
);
m_sceneDropdown.onValueChanged.AddListener(OnSceneDropdownChanged);
void OnSceneDropdownChanged(int value)
{
if (value < 4)
m_sceneFilter = (SceneFilter)value;
else
m_sceneFilter = SceneFilter.Explicit;
}
UIFactory.SetLayoutElement(sceneDropObj, minWidth: 220, minHeight: 25);
// invisible space
var invis = UIFactory.CreateUIObject("spacer", m_extraFilterRow);
var invisLayout = invis.AddComponent<LayoutElement>();
invisLayout.minWidth = 25;
invisLayout.flexibleWidth = 0;
UIFactory.SetLayoutElement(invis, minWidth: 25, flexibleWidth: 0);
// children filter
var childLabelObj = UIFactory.CreateLabel(m_extraFilterRow, TextAnchor.MiddleLeft);
var childLabel = childLabelObj.GetComponent<Text>();
childLabel.text = "Child Filter:";
var childLayout = childLabelObj.AddComponent<LayoutElement>();
childLayout.minWidth = 100;
childLayout.minHeight = 25;
var childLabelObj = UIFactory.CreateLabel(m_extraFilterRow, "ChildFilterLabel", "Child filter:", TextAnchor.MiddleLeft);
UIFactory.SetLayoutElement(childLabelObj.gameObject, minWidth: 100, minHeight: 25);
var childDropObj = UIFactory.CreateDropdown(m_extraFilterRow, out Dropdown childDrop);
childDrop.itemText.text = "Any";
childDrop.itemText.fontSize = 12;
var childDropLayout = childDropObj.AddComponent<LayoutElement>();
childDropLayout.minWidth = 180;
childDropLayout.minHeight = 25;
var childDropObj = UIFactory.CreateDropdown(m_extraFilterRow,
out Dropdown childDrop,
"Any",
12,
(int value) => { m_childFilter = (ChildFilter)value; },
new[] { "Any", "Root Objects Only", "Children Only" });
childDrop.options.Add(new Dropdown.OptionData { text = "Any" });
childDrop.options.Add(new Dropdown.OptionData { text = "Root Objects Only" });
childDrop.options.Add(new Dropdown.OptionData { text = "Children Only" });
childDrop.onValueChanged.AddListener(OnChildDropdownChanged);
void OnChildDropdownChanged(int value)
{
m_childFilter = (ChildFilter)value;
}
UIFactory.SetLayoutElement(childDropObj, minWidth: 180, minHeight: 25);
// search button
var searchBtnObj = UIFactory.CreateButton(topAreaObj);
var searchText = searchBtnObj.GetComponentInChildren<Text>();
searchText.text = "Search";
LayoutElement searchBtnLayout = searchBtnObj.AddComponent<LayoutElement>();
searchBtnLayout.minHeight = 30;
searchBtnLayout.flexibleHeight = 0;
var searchBtn = searchBtnObj.GetComponent<Button>();
searchBtn.onClick.AddListener(OnSearchClicked);
var searchBtnObj = UIFactory.CreateButton(topAreaObj, "SearchButton", "Search", OnSearchClicked);
UIFactory.SetLayoutElement(searchBtnObj.gameObject, minHeight: 30, flexibleHeight: 0);
}
internal void AddContextButton(GameObject parent, string label, SearchContext context, float width = 110)
{
var btnObj = UIFactory.CreateButton(parent);
var btn = btnObj.GetComponent<Button>();
var btn = UIFactory.CreateButton(parent, $"Context_{context}", label, () => { OnContextButtonClicked(context); });
UIFactory.SetLayoutElement(btn.gameObject, minHeight: 25, minWidth: (int)width);
m_contextButtons.Add(context, btn);
btn.onClick.AddListener(() => { OnContextButtonClicked(context); });
var btnLayout = btnObj.AddComponent<LayoutElement>();
btnLayout.minHeight = 25;
btnLayout.minWidth = width;
var btnText = btnObj.GetComponentInChildren<Text>();
btnText.text = label;
// if first button
if (!m_selectedContextButton)
{
OnContextButtonClicked(context);
}
}
internal void ConstructResultsArea()
{
// Result group holder (NOT actual result list content)
var resultGroupObj = UIFactory.CreateVerticalGroup(Content, new Color(1,1,1,0));
var resultGroup = resultGroupObj.GetComponent<VerticalLayoutGroup>();
resultGroup.childForceExpandHeight = false;
resultGroup.childForceExpandWidth = true;
resultGroup.SetChildControlHeight(true);
resultGroup.SetChildControlWidth(true);
resultGroup.spacing = 5;
resultGroup.padding.top = 5;
resultGroup.padding.right = 5;
resultGroup.padding.left = 5;
resultGroup.padding.bottom = 5;
var resultGroupObj = UIFactory.CreateVerticalGroup(Content, "SearchResults", true, false, true, true, 5, new Vector4(5,5,5,5),
new Color(1, 1, 1, 0));
var resultCountObj = UIFactory.CreateLabel(resultGroupObj, TextAnchor.MiddleCenter);
m_resultCountText = resultCountObj.GetComponent<Text>();
m_resultCountText.text = "No results...";
m_resultCountText = UIFactory.CreateLabel(resultGroupObj, "ResultsLabel", "No results...", TextAnchor.MiddleCenter);
GameObject scrollObj = UIFactory.CreateScrollView(resultGroupObj,
out m_resultListContent,
out SliderScrollbar scroller,
GameObject scrollObj = UIFactory.CreateScrollView(resultGroupObj,
"ResultsScrollView",
out m_resultListContent,
out SliderScrollbar scroller,
new Color(0.07f, 0.07f, 0.07f, 1));
m_resultListPageHandler = new PageHandler(scroller);
m_resultListPageHandler.ConstructUI(resultGroupObj);
m_resultListPageHandler.OnPageChanged += OnResultPageTurn;
// actual result list content
var contentGroup = m_resultListContent.GetComponent<VerticalLayoutGroup>();
contentGroup.spacing = 2;
contentGroup.childForceExpandHeight = false;
contentGroup.SetChildControlHeight(true);
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(m_resultListContent, forceHeight: false, childControlHeight: true, spacing: 2);
}
internal void AddResultButton()
{
int thisIndex = m_resultListTexts.Count();
GameObject btnGroupObj = UIFactory.CreateHorizontalGroup(m_resultListContent, new Color(0.1f, 0.1f, 0.1f));
HorizontalLayoutGroup btnGroup = btnGroupObj.GetComponent<HorizontalLayoutGroup>();
btnGroup.childForceExpandWidth = true;
btnGroup.SetChildControlWidth(true);
btnGroup.childForceExpandHeight = false;
btnGroup.SetChildControlHeight(true);
btnGroup.padding.top = 1;
btnGroup.padding.left = 1;
btnGroup.padding.right = 1;
btnGroup.padding.bottom = 1;
LayoutElement btnLayout = btnGroupObj.AddComponent<LayoutElement>();
btnLayout.flexibleWidth = 320;
btnLayout.minHeight = 25;
btnLayout.flexibleHeight = 0;
GameObject btnGroupObj = UIFactory.CreateHorizontalGroup(m_resultListContent, "ResultButtonGroup",
true, false, true, true, 0, new Vector4(1,1,1,1), new Color(0.1f, 0.1f, 0.1f));
UIFactory.SetLayoutElement(btnGroupObj, flexibleWidth: 320, minHeight: 25, flexibleHeight: 0);
btnGroupObj.AddComponent<Mask>();
GameObject mainButtonObj = UIFactory.CreateButton(btnGroupObj);
LayoutElement mainBtnLayout = mainButtonObj.AddComponent<LayoutElement>();
mainBtnLayout.minHeight = 25;
mainBtnLayout.flexibleHeight = 0;
mainBtnLayout.minWidth = 230;
mainBtnLayout.flexibleWidth = 0;
Button mainBtn = mainButtonObj.GetComponent<Button>();
ColorBlock mainColors = mainBtn.colors;
mainColors.normalColor = new Color(0.1f, 0.1f, 0.1f);
mainColors.highlightedColor = new Color(0.2f, 0.2f, 0.2f, 1);
mainBtn.colors = mainColors;
var mainColors = new ColorBlock
{
normalColor = new Color(0.1f, 0.1f, 0.1f),
highlightedColor = new Color(0.2f, 0.2f, 0.2f, 1),
pressedColor = new Color(0.05f, 0.05f, 0.05f)
};
mainBtn.onClick.AddListener(() => { OnResultClicked(thisIndex); });
var mainButton = UIFactory.CreateButton(btnGroupObj,
"ResultButton",
"<not set>",
() => { OnResultClicked(thisIndex); },
mainColors);
Text mainText = mainButtonObj.GetComponentInChildren<Text>();
mainText.alignment = TextAnchor.MiddleLeft;
mainText.horizontalOverflow = HorizontalWrapMode.Overflow;
m_resultListTexts.Add(mainText);
UIFactory.SetLayoutElement(mainButton.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 320, flexibleWidth: 0);
Text text = mainButton.GetComponentInChildren<Text>();
text.alignment = TextAnchor.MiddleLeft;
text.horizontalOverflow = HorizontalWrapMode.Overflow;
m_resultListTexts.Add(text);
}
#endregion
#endregion
}
}

View File

@ -1,131 +1,230 @@
using System;
//using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI.Reusable;
using UnityExplorer.Core.Config;
using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI
{
public static class UIFactory
{
internal static Vector2 thickSize = new Vector2(160f, 30f);
internal static Vector2 thinSize = new Vector2(160f, 20f);
internal static Color defaultTextColor = new Color(0.95f, 0.95f, 0.95f, 1f);
internal static Font s_defaultFont;
internal static Vector2 _largeElementSize = new Vector2(160f, 30f);
internal static Vector2 _smallElementSize = new Vector2(160f, 20f);
internal static Color _defaultTextColor = Color.white;
internal static Font _defaultFont;
public static GameObject CreateUIObject(string name, GameObject parent, Vector2 size = default)
public static void Init()
{
GameObject obj = new GameObject(name);
_defaultFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
}
RectTransform rect = obj.AddComponent<RectTransform>();
if (size != default)
public static GameObject CreateUIObject(string name, GameObject parent = null, Vector2 size = default)
{
if (!parent)
{
rect.sizeDelta = size;
ExplorerCore.LogWarning("Cannot create UI object as the parent is null or destroyed! (" + name + ")");
return null;
}
SetParentAndAlign(obj, parent);
var obj = new GameObject(name)
{
layer = 5,
hideFlags = HideFlags.HideAndDontSave
};
obj.transform.SetParent(parent.transform, false);
RectTransform rect = obj.AddComponent<RectTransform>();
rect.sizeDelta = size == default
? _smallElementSize
: size;
return obj;
}
private static void SetParentAndAlign(GameObject child, GameObject parent)
internal static void SetDefaultTextValues(Text text)
{
if (parent == null)
{
return;
}
child.transform.SetParent(parent.transform, false);
SetLayerRecursively(child);
text.color = _defaultTextColor;
text.font = _defaultFont;
text.fontSize = 14;
}
public static void SetLayerRecursively(GameObject go)
{
go.layer = 5;
Transform transform = go.transform;
for (int i = 0; i < transform.childCount; i++)
{
SetLayerRecursively(transform.GetChild(i).gameObject);
}
}
private static void SetDefaultTextValues(Text lbl)
{
lbl.color = defaultTextColor;
if (!s_defaultFont)
s_defaultFont = Resources.GetBuiltinResource<Font>("Arial.ttf");
if (s_defaultFont)
lbl.font = s_defaultFont;
}
public static void SetDefaultColorTransitionValues(Selectable selectable)
internal static void SetDefaultSelectableColors(Selectable selectable)
{
ColorBlock colors = selectable.colors;
colors.normalColor = new Color(0.35f, 0.35f, 0.35f);
colors.highlightedColor = new Color(0.45f, 0.45f, 0.45f);
colors.pressedColor = new Color(0.25f, 0.25f, 0.25f);
//colors.disabledColor = new Color(0.6f, 0.6f, 0.6f);
// fix to make all buttons become de-selected after being clicked.
// this is because i'm not setting any ColorBlock.selectedColor, because it is commonly stripped.
if (selectable is Button button)
{
button.onClick.AddListener(Deselect);
void Deselect()
{
button.OnDeselect(null);
}
}
SetColorBlockValues(ref colors, new Color(0.2f, 0.2f, 0.2f), new Color(0.3f, 0.3f, 0.3f), new Color(0.15f, 0.15f, 0.15f));
selectable.colors = colors;
// Deselect all Buttons after they are clicked.
if (selectable is Button button)
button.onClick.AddListener(() => { button.OnDeselect(null); });
}
public static GameObject CreatePanel(GameObject parent, string name, out GameObject content)
public static void SetColorBlockValues(ref this ColorBlock colorBlock, Color? normal = null, Color? highlighted = null,
Color? pressed = null)
{
GameObject panelObj = CreateUIObject($"Panel_{name}", parent, thickSize);
RuntimeProvider.Instance.SetColorBlockColors(ref colorBlock, normal, highlighted, pressed);
}
RectTransform rect = panelObj.GetComponent<RectTransform>();
/// <summary>
/// Get and/or Add a LayoutElement component to the GameObject, and set any of the values on it.
/// </summary>
public static LayoutElement SetLayoutElement(GameObject gameObject, int? minWidth = null, int? minHeight = null,
int? flexibleWidth = null, int? flexibleHeight = null, int? preferredWidth = null, int? preferredHeight = null,
bool? ignoreLayout = null)
{
var layout = gameObject.GetComponent<LayoutElement>();
if (!layout)
layout = gameObject.AddComponent<LayoutElement>();
if (minWidth != null)
layout.minWidth = (int)minWidth;
if (minHeight != null)
layout.minHeight = (int)minHeight;
if (flexibleWidth != null)
layout.flexibleWidth = (int)flexibleWidth;
if (flexibleHeight != null)
layout.flexibleHeight = (int)flexibleHeight;
if (preferredWidth != null)
layout.preferredWidth = (int)preferredWidth;
if (preferredHeight != null)
layout.preferredHeight = (int)preferredHeight;
if (ignoreLayout != null)
layout.ignoreLayout = (bool)ignoreLayout;
return layout;
}
/// <summary>
/// Get and/or Add a HorizontalOrVerticalLayoutGroup (must pick one) to the GameObject, and set the values on it.
/// </summary>
public static T SetLayoutGroup<T>(GameObject gameObject, bool? forceWidth = null, bool? forceHeight = null,
bool? childControlWidth = null, bool? childControlHeight = null, int? spacing = null, int? padTop = null,
int? padBottom = null, int? padLeft = null, int? padRight = null, TextAnchor? childAlignment = null) where T : HorizontalOrVerticalLayoutGroup
{
var group = gameObject.GetComponent<T>();
if (!group)
group = gameObject.AddComponent<T>();
return SetLayoutGroup(group, forceWidth, forceHeight, childControlWidth, childControlHeight, spacing, padTop, padBottom, padLeft, padRight);
}
/// <summary>
/// Set the values on a HorizontalOrVerticalLayoutGroup.
/// </summary>
public static T SetLayoutGroup<T>(T group, bool? forceWidth = null, bool? forceHeight = null,
bool? childControlWidth = null, bool? childControlHeight = null, int? spacing = null, int? padTop = null,
int? padBottom = null, int? padLeft = null, int? padRight = null, TextAnchor? childAlignment = null) where T : HorizontalOrVerticalLayoutGroup
{
if (forceWidth != null)
group.childForceExpandWidth = (bool)forceWidth;
if (forceHeight != null)
group.childForceExpandHeight = (bool)forceHeight;
if (childControlWidth != null)
group.SetChildControlWidth((bool)childControlWidth);
if (childControlHeight != null)
group.SetChildControlHeight((bool)childControlHeight);
if (spacing != null)
group.spacing = (int)spacing;
if (padTop != null)
group.padding.top = (int)padTop;
if (padBottom != null)
group.padding.bottom = (int)padBottom;
if (padLeft != null)
group.padding.left = (int)padLeft;
if (padRight != null)
group.padding.right = (int)padRight;
if (childAlignment != null)
group.childAlignment = (TextAnchor)childAlignment;
return group;
}
/// <summary>
/// Create a Panel on the UI Canvas.
/// </summary>
public static GameObject CreatePanel(string name, out GameObject contentHolder, string anchors = null)
{
var panelObj = CreateUIObject(name, UIManager.CanvasRoot);
var rect = panelObj.GetComponent<RectTransform>();
rect.anchorMin = Vector2.zero;
rect.anchorMax = Vector2.one;
rect.anchoredPosition = Vector2.zero;
rect.sizeDelta = Vector2.zero;
var img = panelObj.AddComponent<Image>();
img.color = Color.white;
if (anchors != null)
rect.SetAnchorsFromString(anchors);
VerticalLayoutGroup group = panelObj.AddComponent<VerticalLayoutGroup>();
group.SetChildControlHeight(true);
group.SetChildControlWidth(true);
group.childForceExpandHeight = true;
group.childForceExpandWidth = true;
var maskImg = panelObj.AddComponent<Image>();
maskImg.color = Color.white;
panelObj.AddComponent<Mask>().showMaskGraphic = false;
content = new GameObject("Content");
content.transform.parent = panelObj.transform;
SetLayoutGroup<VerticalLayoutGroup>(panelObj, true, true, true, true);
Image image2 = content.AddComponent<Image>();
image2.type = Image.Type.Filled;
image2.color = new Color(0.1f, 0.1f, 0.1f);
contentHolder = CreateUIObject("Content", panelObj);
VerticalLayoutGroup group2 = content.AddComponent<VerticalLayoutGroup>();
group2.padding.left = 3;
group2.padding.right = 3;
group2.padding.bottom = 3;
group2.padding.top = 3;
group2.spacing = 3;
group2.SetChildControlHeight(true);
group2.SetChildControlWidth(true);
group2.childForceExpandHeight = false;
group2.childForceExpandWidth = true;
Image bgImage = contentHolder.AddComponent<Image>();
bgImage.type = Image.Type.Filled;
bgImage.color = new Color(0.1f, 0.1f, 0.1f);
SetLayoutGroup<VerticalLayoutGroup>(contentHolder, true, true, true, true, 3, 3, 3, 3, 3);
return panelObj;
}
public static GameObject CreateGridGroup(GameObject parent, Vector2 cellSize, Vector2 spacing, Color color = default)
/// <summary>
/// Create a VerticalLayoutGroup object.
/// </summary>
public static GameObject CreateVerticalGroup(GameObject parent, string name, bool forceWidth, bool forceHeight,
bool childControlWidth, bool childControlHeight, int spacing = 0, Vector4 padding = default, Color bgColor = default,
TextAnchor? childAlignment = null)
{
GameObject groupObj = CreateUIObject("GridLayout", parent);
GameObject groupObj = CreateUIObject(name, parent);
SetLayoutGroup<VerticalLayoutGroup>(groupObj, forceWidth, forceHeight, childControlWidth, childControlHeight,
spacing, (int)padding.x, (int)padding.y, (int)padding.z, (int)padding.w, childAlignment);
Image image = groupObj.AddComponent<Image>();
image.color = bgColor == default
? new Color(0.17f, 0.17f, 0.17f)
: bgColor;
return groupObj;
}
/// <summary>
/// Create a HorizontalLayoutGroup object.
/// </summary>
public static GameObject CreateHorizontalGroup(GameObject parent, string name, bool forceExpandWidth, bool forceExpandHeight,
bool childControlWidth, bool childControlHeight, int spacing = 0, Vector4 padding = default, Color bgColor = default,
TextAnchor? childAlignment = null)
{
GameObject groupObj = CreateUIObject(name, parent);
SetLayoutGroup<HorizontalLayoutGroup>(groupObj, forceExpandWidth, forceExpandHeight, childControlWidth, childControlHeight,
spacing, (int)padding.x, (int)padding.y, (int)padding.z, (int)padding.w, childAlignment);
Image image = groupObj.AddComponent<Image>();
image.color = bgColor == default
? new Color(0.17f, 0.17f, 0.17f)
: bgColor;
return groupObj;
}
/// <summary>
/// Create a GridLayoutGroup object.
/// </summary>
public static GameObject CreateGridGroup(GameObject parent, string name, Vector2 cellSize, Vector2 spacing, Color bgColor = default)
{
var groupObj = CreateUIObject(name, parent);
GridLayoutGroup gridGroup = groupObj.AddComponent<GridLayoutGroup>();
gridGroup.childAlignment = TextAnchor.UpperLeft;
@ -133,120 +232,131 @@ namespace UnityExplorer.UI
gridGroup.spacing = spacing;
Image image = groupObj.AddComponent<Image>();
if (color != default)
{
image.color = color;
}
else
{
image.color = new Color(44f / 255f, 44f / 255f, 44f / 255f);
}
image.color = bgColor == default
? new Color(0.17f, 0.17f, 0.17f)
: bgColor;
return groupObj;
}
public static GameObject CreateVerticalGroup(GameObject parent, Color color = default)
/// <summary>
/// Create a Label object.
/// </summary>
public static Text CreateLabel(GameObject parent, string name, string text, TextAnchor alignment,
Color color = default, bool supportRichText = true, int fontSize = 14)
{
GameObject groupObj = CreateUIObject("VerticalLayout", parent);
var obj = CreateUIObject(name, parent);
var textComp = obj.AddComponent<Text>();
VerticalLayoutGroup horiGroup = groupObj.AddComponent<VerticalLayoutGroup>();
horiGroup.childAlignment = TextAnchor.UpperLeft;
horiGroup.SetChildControlWidth(true);
horiGroup.SetChildControlHeight(true);
SetDefaultTextValues(textComp);
Image image = groupObj.AddComponent<Image>();
if (color != default)
{
image.color = color;
}
textComp.text = text;
textComp.color = color == default ? _defaultTextColor : color;
textComp.supportRichText = supportRichText;
textComp.alignment = alignment;
textComp.fontSize = fontSize;
return textComp;
}
public static Button CreateButton(GameObject parent, string name, string text, Action onClick = null, Color? normalColor = null)
{
var colors = new ColorBlock();
if (normalColor != null)
colors.normalColor = (Color)normalColor;
else
{
image.color = new Color(44f / 255f, 44f / 255f, 44f / 255f);
}
colors.normalColor = new Color(0.25f, 0.25f, 0.25f);
return groupObj;
colors.pressedColor = new Color(0.15f, 0.15f, 0.15f);
colors.highlightedColor = new Color(0.4f, 0.4f, 0.4f);
return CreateButton(parent, name, text, onClick, colors);
}
public static GameObject CreateHorizontalGroup(GameObject parent, Color color = default)
public static Button CreateButton(GameObject parent, string name, string text, Action onClick, ColorBlock colors)
{
GameObject groupObj = CreateUIObject("HorizontalLayout", parent);
GameObject buttonObj = CreateUIObject(name, parent, _smallElementSize);
HorizontalLayoutGroup horiGroup = groupObj.AddComponent<HorizontalLayoutGroup>();
horiGroup.childAlignment = TextAnchor.UpperLeft;
horiGroup.SetChildControlWidth(true);
horiGroup.SetChildControlHeight(true);
Image image = groupObj.AddComponent<Image>();
if (color != default)
image.color = color;
else
image.color = new Color(44f / 255f, 44f / 255f, 44f / 255f);
return groupObj;
}
//public static GameObject CreateTMPLabel(GameObject parent, TextAlignmentOptions alignment)
//{
// GameObject labelObj = CreateUIObject("Label", parent, thinSize);
// TextMeshProUGUI text = labelObj.AddComponent<TextMeshProUGUI>();
// text.alignment = alignment;
// text.richText = true;
// return labelObj;
//}
public static GameObject CreateLabel(GameObject parent, TextAnchor alignment)
{
GameObject labelObj = CreateUIObject("Label", parent, thinSize);
Text text = labelObj.AddComponent<Text>();
SetDefaultTextValues(text);
text.alignment = alignment;
text.supportRichText = true;
return labelObj;
}
public static GameObject CreateButton(GameObject parent, Color normalColor = default)
{
GameObject buttonObj = CreateUIObject("Button", parent, thinSize);
GameObject textObj = new GameObject("Text");
textObj.AddComponent<RectTransform>();
SetParentAndAlign(textObj, buttonObj);
var textObj = CreateUIObject("Text", buttonObj);
Image image = buttonObj.AddComponent<Image>();
image.type = Image.Type.Sliced;
image.color = new Color(1, 1, 1, 0.75f);
SetDefaultColorTransitionValues(buttonObj.AddComponent<Button>());
var button = buttonObj.AddComponent<Button>();
SetDefaultSelectableColors(button);
if (normalColor != default)
{
var btn = buttonObj.GetComponent<Button>();
var colors = btn.colors;
colors.normalColor = normalColor;
btn.colors = colors;
}
colors.colorMultiplier = 1;
button.colors = colors;
Text text = textObj.AddComponent<Text>();
text.text = "Button";
SetDefaultTextValues(text);
text.alignment = TextAnchor.MiddleCenter;
Text textComp = textObj.AddComponent<Text>();
textComp.text = text;
SetDefaultTextValues(textComp);
textComp.alignment = TextAnchor.MiddleCenter;
RectTransform rect = textObj.GetComponent<RectTransform>();
rect.anchorMin = Vector2.zero;
rect.anchorMax = Vector2.one;
rect.sizeDelta = Vector2.zero;
return buttonObj;
if (onClick != null)
button.onClick.AddListener(onClick);
return button;
}
public static GameObject CreateSlider(GameObject parent)
///// <summary>
///// Create a Button and specify only the Normal color.
///// </summary>
//public static Button CreateButton(GameObject parent, string name, string text, Action onClick = null, Color? normalColor = null)
//{
// var colors = new ColorBlock
// {
// normalColor = normalColor ?? new Color(0.25f, 0.25f, 0.25f),
// highlightedColor = new Color(0.3f, 0.3f, 0.3f),
// pressedColor = new Color(0.15f, 0.15f, 0.15f)
// };
// return CreateButton(parent, name, text, onClick, colors);
//}
///// <summary>
///// Create a Button and specify the entire ColorBlock for the transition values.
///// </summary>
//public static Button CreateButton(GameObject parent, string name, string text, Action onClick, ColorBlock? colors)
//{
// var buttonObj = CreateUIObject(name, parent);
// Image bgImage = buttonObj.AddComponent<Image>();
// bgImage.type = Image.Type.Sliced;
// bgImage.color = new Color(1, 1, 1, 0.75f);
// Button button = buttonObj.AddComponent<Button>();
// SetDefaultSelectableColors(button);
// if (onClick != null)
// button.onClick.AddListener(onClick);
// if (colors != null)
// button.colors = (ColorBlock)colors;
// var textObj = CreateLabel(buttonObj, "Text", text, TextAnchor.MiddleCenter);
// RectTransform rect = textObj.GetComponent<RectTransform>();
// rect.anchorMin = Vector2.zero;
// rect.anchorMax = Vector2.one;
// rect.sizeDelta = Vector2.zero;
// return button;
//}
/// <summary>
/// Create a Slider control.
/// </summary>
public static GameObject CreateSlider(GameObject parent, string name, out Slider slider)
{
GameObject sliderObj = CreateUIObject("Slider", parent, thinSize);
GameObject sliderObj = CreateUIObject(name, parent, _smallElementSize);
GameObject bgObj = CreateUIObject("Background", sliderObj);
GameObject fillAreaObj = CreateUIObject("Fill Area", sliderObj);
@ -285,19 +395,23 @@ namespace UnityExplorer.UI
handleObj.GetComponent<RectTransform>().sizeDelta = new Vector2(20f, 0f);
Slider slider = sliderObj.AddComponent<Slider>();
slider = sliderObj.AddComponent<Slider>();
slider.fillRect = fillObj.GetComponent<RectTransform>();
slider.handleRect = handleObj.GetComponent<RectTransform>();
slider.targetGraphic = handleImage;
slider.direction = Slider.Direction.LeftToRight;
SetDefaultColorTransitionValues(slider);
SetDefaultSelectableColors(slider);
return sliderObj;
}
public static GameObject CreateScrollbar(GameObject parent)
/// <summary>
/// Create a Scrollbar control.
/// </summary>
public static GameObject CreateScrollbar(GameObject parent, string name, out Scrollbar scrollbar)
{
GameObject scrollObj = CreateUIObject("Scrollbar", parent, thinSize);
GameObject scrollObj = CreateUIObject(name, parent, _smallElementSize);
GameObject slideAreaObj = CreateUIObject("Sliding Area", scrollObj);
GameObject handleObj = CreateUIObject("Handle", slideAreaObj);
@ -318,17 +432,21 @@ namespace UnityExplorer.UI
RectTransform handleRect = handleObj.GetComponent<RectTransform>();
handleRect.sizeDelta = new Vector2(20f, 20f);
Scrollbar scrollbar = scrollObj.AddComponent<Scrollbar>();
scrollbar = scrollObj.AddComponent<Scrollbar>();
scrollbar.handleRect = handleRect;
scrollbar.targetGraphic = handleImage;
SetDefaultColorTransitionValues(scrollbar);
SetDefaultSelectableColors(scrollbar);
return scrollObj;
}
public static GameObject CreateToggle(GameObject parent, out Toggle toggle, out Text text, Color bgColor = default)
/// <summary>
/// Create a Toggle control.
/// </summary>
public static GameObject CreateToggle(GameObject parent, string name, out Toggle toggle, out Text text, Color bgColor = default)
{
GameObject toggleObj = CreateUIObject("Toggle", parent, thinSize);
GameObject toggleObj = CreateUIObject(name, parent, _smallElementSize);
GameObject bgObj = CreateUIObject("Background", toggleObj);
GameObject checkObj = CreateUIObject("Checkmark", bgObj);
@ -345,8 +463,8 @@ namespace UnityExplorer.UI
}
Image bgImage = bgObj.AddComponent<Image>();
bgImage.color = bgColor == default
? new Color(0.2f, 0.2f, 0.2f, 1.0f)
bgImage.color = bgColor == default
? new Color(0.2f, 0.2f, 0.2f, 1.0f)
: bgColor;
Image checkImage = checkObj.AddComponent<Image>();
@ -358,7 +476,7 @@ namespace UnityExplorer.UI
toggle.graphic = checkImage;
toggle.targetGraphic = bgImage;
SetDefaultColorTransitionValues(toggle);
SetDefaultSelectableColors(toggle);
RectTransform bgRect = bgObj.GetComponent<RectTransform>();
bgRect.anchorMin = new Vector2(0f, 1f);
@ -380,14 +498,18 @@ namespace UnityExplorer.UI
return toggleObj;
}
public static GameObject CreateSrollInputField(GameObject parent, out InputFieldScroller inputScroll, int fontSize = 14, Color color = default)
/// <summary>
/// Create a Scrollable Input Field control (custom InputFieldScroller).
/// </summary>
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, out GameObject scrollContent, out SliderScrollbar scroller, color);
var mainObj = CreateScrollView(parent, "InputFieldScrollView", out GameObject scrollContent, out SliderScrollbar scroller, color);
var inputObj = CreateInputField(scrollContent, fontSize, 0);
var inputObj = CreateInputField(scrollContent, name, placeHolderText ?? "...", fontSize, 0);
var inputField = inputObj.GetComponent<InputField>();
inputField.lineType = InputField.LineType.MultiLineNewline;
@ -398,9 +520,12 @@ namespace UnityExplorer.UI
return mainObj;
}
public static GameObject CreateInputField(GameObject parent, int fontSize = 14, int alignment = 3, int wrap = 0)
/// <summary>
/// Create a standard InputField control.
/// </summary>
public static GameObject CreateInputField(GameObject parent, string name, string placeHolderText, int fontSize = 14, int alignment = 3, int wrap = 0)
{
GameObject mainObj = CreateUIObject("InputField", parent);
GameObject mainObj = CreateUIObject(name, parent);
Image mainImage = mainObj.AddComponent<Image>();
mainImage.type = Image.Type.Sliced;
@ -417,16 +542,12 @@ namespace UnityExplorer.UI
ColorBlock mainColors = mainInput.colors;
mainColors.normalColor = new Color(1, 1, 1, 1);
mainColors.highlightedColor = new Color(245f / 255f, 245f / 255f, 245f / 255f, 1.0f);
mainColors.pressedColor = new Color(200f / 255f, 200f / 255f, 200f / 255f, 1.0f);
mainColors.highlightedColor = new Color(245f / 255f, 245f / 255f, 245f / 255f, 1.0f);
mainColors.highlightedColor = new Color(0.95f, 0.95f, 0.95f, 1.0f);
mainColors.pressedColor = new Color(0.78f, 0.78f, 0.78f, 1.0f);
mainColors.highlightedColor = new Color(0.95f, 0.95f, 0.95f, 1.0f);
mainInput.colors = mainColors;
VerticalLayoutGroup mainGroup = mainObj.AddComponent<VerticalLayoutGroup>();
mainGroup.SetChildControlHeight(true);
mainGroup.SetChildControlWidth(true);
mainGroup.childForceExpandWidth = true;
mainGroup.childForceExpandHeight = true;
SetLayoutGroup<VerticalLayoutGroup>(mainObj, true, true, true, true);
GameObject textArea = CreateUIObject("TextArea", mainObj);
textArea.AddComponent<RectMask2D>();
@ -442,7 +563,7 @@ namespace UnityExplorer.UI
GameObject placeHolderObj = CreateUIObject("Placeholder", textArea);
Text placeholderText = placeHolderObj.AddComponent<Text>();
SetDefaultTextValues(placeholderText);
placeholderText.text = "...";
placeholderText.text = placeHolderText ?? "...";
placeholderText.color = new Color(0.5f, 0.5f, 0.5f, 1.0f);
placeholderText.horizontalOverflow = (HorizontalWrapMode)wrap;
placeholderText.alignment = (TextAnchor)alignment;
@ -454,9 +575,7 @@ namespace UnityExplorer.UI
placeHolderRect.offsetMin = Vector2.zero;
placeHolderRect.offsetMax = Vector2.zero;
LayoutElement placeholderLayout = placeHolderObj.AddComponent<LayoutElement>();
placeholderLayout.minWidth = 500;
placeholderLayout.flexibleWidth = 5000;
SetLayoutElement(placeHolderObj, minWidth: 500, flexibleWidth: 5000);
mainInput.placeholder = placeholderText;
@ -475,18 +594,20 @@ namespace UnityExplorer.UI
inputTextRect.offsetMin = Vector2.zero;
inputTextRect.offsetMax = Vector2.zero;
LayoutElement inputTextLayout = inputTextObj.AddComponent<LayoutElement>();
inputTextLayout.minWidth = 500;
inputTextLayout.flexibleWidth = 5000;
SetLayoutElement(inputTextObj, minWidth: 500, flexibleWidth: 5000);
mainInput.textComponent = inputText;
return mainObj;
}
public static GameObject CreateDropdown(GameObject parent, out Dropdown dropdown)
/// <summary>
/// Create a DropDown control.
/// </summary>
public static GameObject CreateDropdown(GameObject parent, out Dropdown dropdown, string defaultItemText, int itemFontSize,
Action<int> onValueChanged, string[] defaultOptions = null)
{
GameObject dropdownObj = CreateUIObject("Dropdown", parent, thickSize);
GameObject dropdownObj = CreateUIObject("Dropdown", parent, _largeElementSize);
GameObject labelObj = CreateUIObject("Label", dropdownObj);
GameObject arrowObj = CreateUIObject("Arrow", dropdownObj);
@ -498,9 +619,7 @@ namespace UnityExplorer.UI
GameObject itemCheckObj = CreateUIObject("Item Checkmark", itemObj);
GameObject itemLabelObj = CreateUIObject("Item Label", itemObj);
GameObject scrollbarObj = CreateScrollbar(templateObj);
scrollbarObj.name = "Scrollbar";
Scrollbar scrollbar = scrollbarObj.GetComponent<Scrollbar>();
GameObject scrollbarObj = CreateScrollbar(templateObj, "DropdownScroll", out Scrollbar scrollbar);
scrollbar.SetDirection(Scrollbar.Direction.BottomToTop, true);
RectTransform scrollRectTransform = scrollbarObj.GetComponent<RectTransform>();
@ -512,6 +631,8 @@ namespace UnityExplorer.UI
Text itemLabelText = itemLabelObj.AddComponent<Text>();
SetDefaultTextValues(itemLabelText);
itemLabelText.alignment = TextAnchor.MiddleLeft;
itemLabelText.text = defaultItemText;
itemLabelText.fontSize = itemFontSize;
var arrowText = arrowObj.AddComponent<Text>();
SetDefaultTextValues(arrowText);
@ -566,7 +687,7 @@ namespace UnityExplorer.UI
dropdown.template = templateObj.GetComponent<RectTransform>();
dropdown.captionText = labelText;
dropdown.itemText = itemLabelText;
itemLabelText.text = "DEFAULT";
//itemLabelText.text = "DEFAULT";
dropdown.RefreshShownValue();
@ -613,18 +734,27 @@ namespace UnityExplorer.UI
itemLabelRect.offsetMax = new Vector2(-10f, -2f);
templateObj.SetActive(false);
if (onValueChanged != null)
dropdown.onValueChanged.AddListener(onValueChanged);
if (defaultOptions != null)
{
foreach (var option in defaultOptions)
dropdown.options.Add(new Dropdown.OptionData(option));
}
return dropdownObj;
}
public static GameObject CreateScrollView(GameObject parent, out GameObject content, out SliderScrollbar scroller, Color color = default)
/// <summary>
/// Create a ScrollView element.
/// </summary>
public static GameObject CreateScrollView(GameObject parent, string name, out GameObject content, out SliderScrollbar scroller,
Color color = default)
{
GameObject mainObj = CreateUIObject("DynamicScrollView", parent);
var mainLayout = mainObj.AddComponent<LayoutElement>();
mainLayout.minWidth = 100;
mainLayout.minHeight = 30;
mainLayout.flexibleWidth = 5000;
mainLayout.flexibleHeight = 5000;
SetLayoutElement(mainObj, minWidth: 100, minHeight: 30, flexibleWidth: 5000, flexibleHeight: 5000);
Image mainImage = mainObj.AddComponent<Image>();
mainImage.type = Image.Type.Filled;
@ -637,7 +767,7 @@ namespace UnityExplorer.UI
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.offsetMax = new Vector2(-20.0f, 0.0f);
viewportObj.AddComponent<Image>().color = Color.white;
viewportObj.AddComponent<Mask>().showMaskGraphic = false;
@ -653,16 +783,7 @@ namespace UnityExplorer.UI
contentFitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
contentFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
var contentGroup = content.AddComponent<VerticalLayoutGroup>();
contentGroup.childForceExpandHeight = true;
contentGroup.SetChildControlHeight(true);
contentGroup.childForceExpandWidth = true;
contentGroup.SetChildControlWidth(true);
contentGroup.padding.left = 5;
contentGroup.padding.right = 5;
contentGroup.padding.top = 5;
contentGroup.padding.bottom = 5;
contentGroup.spacing = 5;
SetLayoutGroup<VerticalLayoutGroup>(content, true, true, true, true, 5, 5, 5, 5, 5);
GameObject scrollBarObj = CreateUIObject("DynamicScrollbar", mainObj);
@ -676,8 +797,7 @@ namespace UnityExplorer.UI
scrollBarRect.sizeDelta = new Vector2(15.0f, 0.0f);
scrollBarRect.offsetMin = new Vector2(-15.0f, 0.0f);
GameObject hiddenBar = CreateScrollbar(scrollBarObj);
var hiddenScroll = hiddenBar.GetComponent<Scrollbar>();
GameObject hiddenBar = CreateScrollbar(scrollBarObj, "HiddenScrollviewScroller", out Scrollbar hiddenScroll);
hiddenScroll.SetDirection(Scrollbar.Direction.BottomToTop, true);
for (int i = 0; i < hiddenBar.transform.childCount; i++)
@ -705,8 +825,6 @@ namespace UnityExplorer.UI
// Create a custom DynamicScrollbar module
scroller = new SliderScrollbar(hiddenScroll, scrollSlider);
//scrollRect.sliderScrollbar = scroller;
return mainObj;
}
}

View File

@ -1,14 +1,16 @@
using UnityEngine;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityExplorer.Core.Inspectors;
using UnityExplorer.UI.Main;
using System.IO;
using System.Reflection;
using UnityExplorer.UI.Reusable;
using UnityExplorer.Core.Input;
using System;
using UnityExplorer.Core.Config;
using UnityExplorer.Core.Input;
using UnityExplorer.Core.Runtime;
using UnityExplorer.UI.Main;
using UnityExplorer.UI.Main.Home;
using UnityExplorer.UI.Utility;
namespace UnityExplorer.UI
@ -19,157 +21,95 @@ namespace UnityExplorer.UI
public static EventSystem EventSys { get; private set; }
internal static Font ConsoleFont { get; private set; }
//internal static Sprite ResizeCursor { get; private set; }
internal static Shader BackupShader { get; private set; }
public static bool ShowMenu
{
get => s_showMenu;
set => SetShowMenu(value);
}
public static bool s_showMenu;
private static bool s_doneUIInit;
private static float s_timeSinceStartup;
internal static void CheckUIInit()
{
if (s_doneUIInit)
return;
s_timeSinceStartup += Time.deltaTime;
if (s_timeSinceStartup > 0.1f)
set
{
s_doneUIInit = true;
try
{
Init();
ExplorerCore.Log("Initialized UnityExplorer UI.");
if (s_showMenu == value || !CanvasRoot)
return;
if (ExplorerConfig.Instance.Hide_On_Startup)
ShowMenu = false;
// InspectorManager.Instance.Inspect(Tests.TestClass.Instance);
}
catch (Exception e)
{
ExplorerCore.LogWarning($"Exception setting up UI: {e}");
}
s_showMenu = value;
CanvasRoot.SetActive(value);
CursorUnlocker.UpdateCursorControl();
}
}
public static bool s_showMenu = true;
public static void Init()
internal static void Init()
{
LoadBundle();
// Create core UI Canvas and Event System handler
CreateRootCanvas();
// Create submodules
new MainMenu();
InspectUnderMouse.UI.ConstructUI();
PanelDragger.LoadCursorImage();
LoadBundle();
// Force refresh of anchors
UIFactory.Init();
MainMenu.Create();
InspectUnderMouse.ConstructUI();
PanelDragger.CreateCursorUI();
// Force refresh of anchors etc
Canvas.ForceUpdateCanvases();
if (!ConfigManager.Hide_On_Startup.Value)
ShowMenu = true;
ExplorerCore.Log("UI initialized.");
}
private static GameObject CreateRootCanvas()
internal static void Update()
{
GameObject rootObj = new GameObject("ExplorerCanvas");
UnityEngine.Object.DontDestroyOnLoad(rootObj);
rootObj.layer = 5;
if (!CanvasRoot)
return;
CanvasRoot = rootObj;
if (InspectUnderMouse.Inspecting)
{
InspectUnderMouse.UpdateInspect();
return;
}
if (InputManager.GetKeyDown(ConfigManager.Main_Menu_Toggle.Value))
ShowMenu = !ShowMenu;
if (!ShowMenu)
return;
MainMenu.Instance.Update();
if (EventSystem.current != EventSys)
CursorUnlocker.SetEventSystem();
RuntimeProvider.Instance.CheckInputPointerEvent();
PanelDragger.Instance.Update();
SliderScrollbar.UpdateInstances();
InputFieldScroller.UpdateInstances();
}
private static void CreateRootCanvas()
{
CanvasRoot = new GameObject("ExplorerCanvas");
UnityEngine.Object.DontDestroyOnLoad(CanvasRoot);
CanvasRoot.hideFlags |= HideFlags.HideAndDontSave;
CanvasRoot.layer = 5;
CanvasRoot.transform.position = new Vector3(0f, 0f, 1f);
EventSys = rootObj.AddComponent<EventSystem>();
EventSys = CanvasRoot.AddComponent<EventSystem>();
InputManager.AddUIModule();
Canvas canvas = rootObj.AddComponent<Canvas>();
Canvas canvas = CanvasRoot.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceCamera;
canvas.referencePixelsPerUnit = 100;
canvas.sortingOrder = 999;
//canvas.pixelPerfect = false;
CanvasScaler scaler = rootObj.AddComponent<CanvasScaler>();
CanvasScaler scaler = CanvasRoot.AddComponent<CanvasScaler>();
scaler.referenceResolution = new Vector2(1920, 1080);
scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.Expand;
rootObj.AddComponent<GraphicRaycaster>();
return rootObj;
}
private static void SetShowMenu(bool show)
{
if (s_showMenu == show)
return;
s_showMenu = show;
if (CanvasRoot)
{
CanvasRoot.SetActive(show);
if (show)
CursorUnlocker.SetEventSystem();
else
CursorUnlocker.ReleaseEventSystem();
}
CursorUnlocker.UpdateCursorControl();
}
public static void Update()
{
if (InputManager.GetKeyDown(ExplorerConfig.Instance.Main_Menu_Toggle))
ShowMenu = !ShowMenu;
if (!ShowMenu || !s_doneUIInit || !CanvasRoot)
return;
MainMenu.Instance?.Update();
if (EventSys)
{
if (EventSystem.current != EventSys)
CursorUnlocker.SetEventSystem();
#if CPP
// Some IL2CPP games behave weird with multiple UI Input Systems, some fixes for them.
var evt = InputManager.InputPointerEvent;
if (evt != null)
{
if (!evt.eligibleForClick && evt.selectedObject)
evt.eligibleForClick = true;
}
#endif
}
if (PanelDragger.Instance != null)
PanelDragger.Instance.Update();
for (int i = 0; i < SliderScrollbar.Instances.Count; i++)
{
var slider = SliderScrollbar.Instances[i];
if (slider.CheckDestroyed())
i--;
else
slider.Update();
}
for (int i = 0; i < InputFieldScroller.Instances.Count; i++)
{
var input = InputFieldScroller.Instances[i];
if (input.CheckDestroyed())
i--;
else
input.Update();
}
CanvasRoot.AddComponent<GraphicRaycaster>();
}
private static void LoadBundle()
@ -179,21 +119,13 @@ namespace UnityExplorer.UI
try
{
bundle = LoadExplorerUi("modern");
if (bundle == null)
throw new Exception();
bundle = LoadExplorerUi("legacy");
}
catch
{
ExplorerCore.Log("Failed to load Unity 2017 ExplorerUI Bundle, falling back to legacy");
try
{
bundle = LoadExplorerUi("legacy");
}
catch
{
// ignored
}
// ignored
}
if (bundle == null)
@ -212,20 +144,21 @@ namespace UnityExplorer.UI
Graphic.defaultGraphicMaterial.shader = BackupShader;
}
//ResizeCursor = bundle.LoadAsset<Sprite>("cursor");
ConsoleFont = bundle.LoadAsset<Font>("CONSOLA");
ExplorerCore.Log("Loaded UI bundle");
ExplorerCore.Log("Loaded UI AssetBundle");
}
private static AssetBundle LoadExplorerUi(string id)
{
var data = ReadFully(typeof(ExplorerCore).Assembly.GetManifestResourceStream($"UnityExplorer.Resources.explorerui.{id}.bundle"));
var data = ReadFully(typeof(ExplorerCore)
.Assembly
.GetManifestResourceStream($"UnityExplorer.Resources.explorerui.{id}.bundle"));
return AssetBundle.LoadFromMemory(data);
}
private static byte[] ReadFully(this Stream input)
private static byte[] ReadFully(Stream input)
{
using (var ms = new MemoryStream())
{

View File

@ -1,244 +0,0 @@
using System;
using UnityEngine;
using UnityExplorer.Core.Unity;
using UnityEngine.EventSystems;
using UnityExplorer.Core.Input;
using BF = System.Reflection.BindingFlags;
using UnityExplorer.Core.Config;
using UnityExplorer.Core;
#if ML
using Harmony;
#else
using HarmonyLib;
#endif
namespace UnityExplorer.UI.Utility
{
public class CursorUnlocker
{
public static bool Unlock
{
get => m_forceUnlock;
set => SetForceUnlock(value);
}
private static bool m_forceUnlock;
private static void SetForceUnlock(bool unlock)
{
m_forceUnlock = unlock;
UpdateCursorControl();
}
public static bool ShouldForceMouse => UIManager.ShowMenu && Unlock;
private static CursorLockMode m_lastLockMode;
private static bool m_lastVisibleState;
private static bool m_currentlySettingCursor = false;
private static Type CursorType
=> m_cursorType
?? (m_cursorType = ReflectionUtility.GetTypeByName("UnityEngine.Cursor"));
private static Type m_cursorType;
public static void Init()
{
ExplorerConfig.OnConfigChanged += ModConfig_OnConfigChanged;
SetupPatches();
Unlock = true;
}
internal static void ModConfig_OnConfigChanged()
{
Unlock = ExplorerConfig.Instance.Force_Unlock_Mouse;
}
private static void SetupPatches()
{
try
{
if (CursorType == null)
{
throw new Exception("Could not find Type 'UnityEngine.Cursor'!");
}
// Get current cursor state and enable cursor
try
{
//m_lastLockMode = Cursor.lockState;
m_lastLockMode = (CursorLockMode?)typeof(Cursor).GetProperty("lockState", BF.Public | BF.Static)?.GetValue(null, null)
?? CursorLockMode.None;
//m_lastVisibleState = Cursor.visible;
m_lastVisibleState = (bool?)typeof(Cursor).GetProperty("visible", BF.Public | BF.Static)?.GetValue(null, null)
?? false;
}
catch { }
// Setup Harmony Patches
TryPatch(typeof(Cursor),
"lockState",
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(Prefix_set_lockState))),
true);
TryPatch(typeof(Cursor),
"visible",
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(Prefix_set_visible))),
true);
TryPatch(typeof(EventSystem),
"current",
new HarmonyMethod(typeof(CursorUnlocker).GetMethod(nameof(Prefix_EventSystem_set_current))),
true);
}
catch (Exception e)
{
ExplorerCore.Log($"Exception on ForceUnlockCursor.Init! {e.GetType()}, {e.Message}");
}
}
private static void TryPatch(Type type, string property, HarmonyMethod patch, bool setter)
{
try
{
var harmony = ExplorerCore.Loader.HarmonyInstance;
System.Reflection.PropertyInfo prop = type.GetProperty(property);
if (setter) // setter is prefix
{
harmony.Patch(prop.GetSetMethod(), prefix: patch);
}
else // getter is postfix
{
harmony.Patch(prop.GetGetMethod(), postfix: patch);
}
}
catch (Exception e)
{
string suf = setter ? "set_" : "get_";
ExplorerCore.Log($"Unable to patch {type.Name}.{suf}{property}: {e.Message}");
}
}
public static void UpdateCursorControl()
{
try
{
m_currentlySettingCursor = true;
if (ShouldForceMouse)
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
else
{
Cursor.lockState = m_lastLockMode;
Cursor.visible = m_lastVisibleState;
}
m_currentlySettingCursor = false;
}
catch (Exception e)
{
ExplorerCore.Log($"Exception setting Cursor state: {e.GetType()}, {e.Message}");
}
}
// Event system overrides
private static bool m_settingEventSystem;
private static EventSystem m_lastEventSystem;
private static BaseInputModule m_lastInputModule;
public static void SetEventSystem()
{
// temp disabled for new InputSystem
if (InputManager.CurrentType == InputType.InputSystem)
return;
// Disable current event system object
if (m_lastEventSystem || EventSystem.current)
{
if (!m_lastEventSystem)
m_lastEventSystem = EventSystem.current;
//ExplorerCore.Log("Disabling current event system...");
m_lastEventSystem.enabled = false;
//m_lastEventSystem.gameObject.SetActive(false);
}
// Set to our current system
m_settingEventSystem = true;
EventSystem.current = UIManager.EventSys;
UIManager.EventSys.enabled = true;
InputManager.ActivateUIModule();
m_settingEventSystem = false;
}
public static void ReleaseEventSystem()
{
if (InputManager.CurrentType == InputType.InputSystem)
return;
if (m_lastEventSystem)
{
m_lastEventSystem.enabled = true;
//m_lastEventSystem.gameObject.SetActive(true);
m_settingEventSystem = true;
EventSystem.current = m_lastEventSystem;
m_lastInputModule?.ActivateModule();
m_settingEventSystem = false;
}
}
[HarmonyPrefix]
public static void Prefix_EventSystem_set_current(ref EventSystem value)
{
if (!m_settingEventSystem)
{
m_lastEventSystem = value;
m_lastInputModule = value?.currentInputModule;
if (UIManager.ShowMenu)
{
value = UIManager.EventSys;
}
}
}
// Force mouse to stay unlocked and visible while UnlockMouse and ShowMenu are true.
// Also keep track of when anything else tries to set Cursor state, this will be the
// value that we set back to when we close the menu or disable force-unlock.
[HarmonyPrefix]
public static void Prefix_set_lockState(ref CursorLockMode value)
{
if (!m_currentlySettingCursor)
{
m_lastLockMode = value;
if (ShouldForceMouse)
{
value = CursorLockMode.None;
}
}
}
[HarmonyPrefix]
public static void Prefix_set_visible(ref bool value)
{
if (!m_currentlySettingCursor)
{
m_lastVisibleState = value;
if (ShouldForceMouse)
{
value = true;
}
}
}
}
}

View File

@ -9,7 +9,7 @@ using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityExplorer.Core.Unity;
namespace UnityExplorer.UI.Reusable
namespace UnityExplorer.UI.Utility
{
// To fix an issue with Input Fields and allow them to go inside a ScrollRect nicely.
@ -17,6 +17,22 @@ namespace UnityExplorer.UI.Reusable
{
public static readonly List<InputFieldScroller> Instances = new List<InputFieldScroller>();
public static void UpdateInstances()
{
if (!Instances.Any())
return;
for (int i = 0; i < Instances.Count; i++)
{
var input = Instances[i];
if (input.CheckDestroyed())
i--;
else
input.Update();
}
}
internal SliderScrollbar sliderScroller;
internal InputField inputField;

View File

@ -6,7 +6,7 @@ using UnityEngine;
using UnityEngine.UI;
using UnityExplorer.Core.Unity;
namespace UnityExplorer.UI.Reusable
namespace UnityExplorer.UI.Utility
{
public enum Turn
{
@ -14,14 +14,11 @@ namespace UnityExplorer.UI.Reusable
Right
}
// TODO:
// - Input for setting page directly
public class PageHandler : IEnumerator
{
public PageHandler(SliderScrollbar scroll)
{
ItemsPerPage = ExplorerConfig.Instance?.Default_Page_Limit ?? 20;
ItemsPerPage = ConfigManager.Default_Page_Limit?.Value ?? 20;
m_scrollbar = scroll;
}
@ -168,55 +165,32 @@ namespace UnityExplorer.UI.Reusable
public void ConstructUI(GameObject parent)
{
m_pageUIHolder = UIFactory.CreateHorizontalGroup(parent);
m_pageUIHolder = UIFactory.CreateHorizontalGroup(parent, "PageHandlerButtons", false, true, true, true);
Image image = m_pageUIHolder.GetComponent<Image>();
image.color = new Color(0.2f, 0.2f, 0.2f, 0.5f);
HorizontalLayoutGroup mainGroup = m_pageUIHolder.GetComponent<HorizontalLayoutGroup>();
mainGroup.childForceExpandHeight = true;
mainGroup.childForceExpandWidth = false;
mainGroup.SetChildControlWidth(true);
mainGroup.SetChildControlHeight(true);
UIFactory.SetLayoutElement(m_pageUIHolder, minHeight: 25, minWidth: 100, flexibleWidth: 5000);
LayoutElement mainLayout = m_pageUIHolder.AddComponent<LayoutElement>();
mainLayout.minHeight = 25;
mainLayout.flexibleHeight = 0;
mainLayout.minWidth = 100;
mainLayout.flexibleWidth = 5000;
var leftBtnObj = UIFactory.CreateButton(m_pageUIHolder,
"BackBtn",
"◄",
() => { TurnPage(Turn.Left); },
new Color(0.15f, 0.15f, 0.15f));
GameObject leftBtnObj = UIFactory.CreateButton(m_pageUIHolder, new Color(0.15f, 0.15f, 0.15f));
Button leftBtn = leftBtnObj.GetComponent<Button>();
UIFactory.SetLayoutElement(leftBtnObj.gameObject, flexibleWidth: 1500, minWidth: 25, minHeight: 25);
leftBtn.onClick.AddListener(() => { TurnPage(Turn.Left); });
m_currentPageLabel = UIFactory.CreateLabel(m_pageUIHolder, "PageLabel", "Page 1 / TODO", TextAnchor.MiddleCenter);
Text leftBtnText = leftBtnObj.GetComponentInChildren<Text>();
leftBtnText.text = "◄";
LayoutElement leftBtnLayout = leftBtnObj.AddComponent<LayoutElement>();
leftBtnLayout.flexibleHeight = 0f;
leftBtnLayout.flexibleWidth = 1500f;
leftBtnLayout.minWidth = 25f;
leftBtnLayout.minHeight = 25f;
UIFactory.SetLayoutElement(m_currentPageLabel.gameObject, minWidth: 100, flexibleWidth: 40);
GameObject labelObj = UIFactory.CreateLabel(m_pageUIHolder, TextAnchor.MiddleCenter);
m_currentPageLabel = labelObj.GetComponent<Text>();
m_currentPageLabel.text = "Page 1 / TODO";
LayoutElement textLayout = labelObj.AddComponent<LayoutElement>();
textLayout.minWidth = 100f;
textLayout.flexibleWidth = 40f;
Button rightBtn = UIFactory.CreateButton(m_pageUIHolder,
"RightBtn",
"►",
() => { TurnPage(Turn.Right); },
new Color(0.15f, 0.15f, 0.15f));
GameObject rightBtnObj = UIFactory.CreateButton(m_pageUIHolder, new Color(0.15f, 0.15f, 0.15f));
Button rightBtn = rightBtnObj.GetComponent<Button>();
rightBtn.onClick.AddListener(() => { TurnPage(Turn.Right); });
Text rightBtnText = rightBtnObj.GetComponentInChildren<Text>();
rightBtnText.text = "►";
LayoutElement rightBtnLayout = rightBtnObj.AddComponent<LayoutElement>();
rightBtnLayout.flexibleHeight = 0;
rightBtnLayout.flexibleWidth = 1500f;
rightBtnLayout.minWidth = 25f;
rightBtnLayout.minHeight = 25;
UIFactory.SetLayoutElement(rightBtn.gameObject, flexibleWidth: 1500, minWidth: 25, minHeight: 25);
ListCount = 0;
}

View File

@ -130,7 +130,7 @@ namespace UnityExplorer.UI.Utility
var args = "<";
for (int i = 0; i < gArgs.Length; i++)
{
if (i > 0)
if (i > 0)
args += ", ";
var arg = gArgs[i];

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.Events;
@ -9,13 +10,29 @@ using UnityExplorer.Core;
using UnityExplorer.Core.Unity;
using UnityExplorer.UI;
namespace UnityExplorer.UI.Reusable
namespace UnityExplorer.UI.Utility
{
// Basically just to fix an issue with Scrollbars, instead we use a Slider as the scrollbar.
public class SliderScrollbar
{
internal static readonly List<SliderScrollbar> Instances = new List<SliderScrollbar>();
public static void UpdateInstances()
{
if (!Instances.Any())
return;
for (int i = 0; i < Instances.Count; i++)
{
var slider = Instances[i];
if (slider.CheckDestroyed())
i--;
else
slider.Update();
}
}
public bool IsActive { get; private set; }
internal readonly Scrollbar m_scrollbar;
@ -93,7 +110,7 @@ namespace UnityExplorer.UI.Reusable
public static GameObject CreateSliderScrollbar(GameObject parent, out Slider slider)
{
GameObject sliderObj = UIFactory.CreateUIObject("Slider", parent, UIFactory.thinSize);
GameObject sliderObj = UIFactory.CreateUIObject("SliderScrollbar", parent, UIFactory._smallElementSize);
GameObject bgObj = UIFactory.CreateUIObject("Background", sliderObj);
GameObject fillAreaObj = UIFactory.CreateUIObject("Fill Area", sliderObj);
@ -149,7 +166,7 @@ namespace UnityExplorer.UI.Reusable
slider.handleRect = handleObj.GetComponent<RectTransform>();
slider.targetGraphic = handleImage;
slider.direction = Slider.Direction.BottomToTop;
UIFactory.SetDefaultColorTransitionValues(slider);
UIFactory.SetDefaultSelectableColors(slider);
return sliderObj;
}