mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-01-04 00:23:29 +08:00
Rewrite EvaluateWidget, add BaseArgumentHandler, use autocomplete for InteractiveEnum
This commit is contained in:
parent
e585fc6da0
commit
7b477a8b0e
@ -11,6 +11,7 @@ using UniverseLib.UI.Models;
|
||||
using UnityExplorer.UI;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
using UnityExplorer.UI.Widgets;
|
||||
|
||||
namespace UnityExplorer.CacheObject
|
||||
{
|
||||
|
@ -7,6 +7,8 @@ using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.CacheObject;
|
||||
using UnityExplorer.UI;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
|
||||
namespace UnityExplorer.CacheObject.IValues
|
||||
@ -20,10 +22,10 @@ namespace UnityExplorer.CacheObject.IValues
|
||||
|
||||
public OrderedDictionary CurrentValues;
|
||||
|
||||
public CachedEnumValue ValueAtIdx(int idx) => (CachedEnumValue)CurrentValues[idx];
|
||||
public CachedEnumValue ValueAtKey(object key) => (CachedEnumValue)CurrentValues[key];
|
||||
private InputFieldRef inputField;
|
||||
private ButtonRef enumHelperButton;
|
||||
private EnumCompleter enumCompleter;
|
||||
|
||||
private Dropdown enumDropdown;
|
||||
private GameObject toggleHolder;
|
||||
private readonly List<Toggle> flagToggles = new List<Toggle>();
|
||||
private readonly List<Text> flagTexts = new List<Text>();
|
||||
@ -35,38 +37,68 @@ namespace UnityExplorer.CacheObject.IValues
|
||||
|
||||
if (lastType != EnumType)
|
||||
{
|
||||
CurrentValues = GetEnumValues(EnumType, out IsFlags);
|
||||
CurrentValues = GetEnumValues(EnumType);
|
||||
|
||||
IsFlags = EnumType.GetCustomAttributes(typeof(FlagsAttribute), true) is object[] fa && fa.Any();
|
||||
if (IsFlags)
|
||||
SetupTogglesForEnumType();
|
||||
else
|
||||
SetupDropdownForEnumType();
|
||||
{
|
||||
inputField.Component.gameObject.SetActive(true);
|
||||
enumHelperButton.Component.gameObject.SetActive(true);
|
||||
toggleHolder.SetActive(false);
|
||||
}
|
||||
|
||||
enumCompleter.EnumType = EnumType;
|
||||
enumCompleter.CacheEnumValues();
|
||||
|
||||
lastType = EnumType;
|
||||
}
|
||||
|
||||
// setup ui for changes
|
||||
if (IsFlags)
|
||||
SetTogglesForValue(value);
|
||||
if (!IsFlags)
|
||||
inputField.Text = value.ToString();
|
||||
else
|
||||
SetDropdownForValue(value);
|
||||
SetTogglesForValue(value);
|
||||
|
||||
this.enumCompleter.chosenSuggestion = value.ToString();
|
||||
AutoCompleteModal.Instance.ReleaseOwnership(this.enumCompleter);
|
||||
}
|
||||
|
||||
private void SetTogglesForValue(object value)
|
||||
{
|
||||
try
|
||||
{
|
||||
var split = value.ToString().Split(',');
|
||||
var set = new HashSet<string>();
|
||||
foreach (var s in split)
|
||||
set.Add(s.Trim());
|
||||
|
||||
for (int i = 0; i < CurrentValues.Count; i++)
|
||||
flagToggles[i].isOn = set.Contains(ValueAtIdx(i).Name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning("Exception setting flag toggles: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Setting value to owner
|
||||
|
||||
private void OnApplyClicked()
|
||||
{
|
||||
if (IsFlags)
|
||||
SetValueFromFlags();
|
||||
else
|
||||
SetValueFromDropdown();
|
||||
}
|
||||
|
||||
private void SetValueFromDropdown()
|
||||
{
|
||||
try
|
||||
{
|
||||
CurrentOwner.SetUserValue(ValueAtIdx(enumDropdown.value).ActualValue);
|
||||
if (!IsFlags)
|
||||
{
|
||||
if (ParseUtility.TryParse(this.inputField.Text, EnumType, out object value, out Exception ex))
|
||||
CurrentOwner.SetUserValue(value);
|
||||
else
|
||||
throw ex;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetValueFromFlags();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -93,59 +125,53 @@ namespace UnityExplorer.CacheObject.IValues
|
||||
}
|
||||
}
|
||||
|
||||
// setting UI state for value
|
||||
// UI Construction
|
||||
|
||||
private void SetDropdownForValue(object value)
|
||||
private void EnumHelper_OnClick()
|
||||
{
|
||||
if (CurrentValues.Contains(value))
|
||||
{
|
||||
var cached = ValueAtKey(value);
|
||||
enumDropdown.value = cached.EnumIndex;
|
||||
enumDropdown.RefreshShownValue();
|
||||
}
|
||||
else
|
||||
ExplorerCore.LogWarning("CurrentValues does not contain key '" + value?.ToString() ?? "<null>" + "'");
|
||||
enumCompleter.HelperButtonClicked();
|
||||
}
|
||||
|
||||
private void SetTogglesForValue(object value)
|
||||
public override GameObject CreateContent(GameObject parent)
|
||||
{
|
||||
try
|
||||
{
|
||||
var split = value.ToString().Split(',');
|
||||
var set = new HashSet<string>();
|
||||
foreach (var s in split)
|
||||
set.Add(s.Trim());
|
||||
UIRoot = UIFactory.CreateVerticalGroup(parent, "InteractiveEnum", false, false, true, true, 3, new Vector4(4, 4, 4, 4),
|
||||
new Color(0.06f, 0.06f, 0.06f));
|
||||
UIFactory.SetLayoutElement(UIRoot, minHeight: 25, flexibleHeight: 9999, flexibleWidth: 9999);
|
||||
|
||||
for (int i = 0; i < CurrentValues.Count; i++)
|
||||
flagToggles[i].isOn = set.Contains(ValueAtIdx(i).Name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExplorerCore.LogWarning("Exception setting flag toggles: " + ex);
|
||||
}
|
||||
var hori = UIFactory.CreateUIObject("Hori", UIRoot);
|
||||
UIFactory.SetLayoutElement(hori, minHeight: 25, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(hori, false, false, true, true, 2);
|
||||
|
||||
var applyButton = UIFactory.CreateButton(hori, "ApplyButton", "Apply", new Color(0.2f, 0.27f, 0.2f));
|
||||
UIFactory.SetLayoutElement(applyButton.Component.gameObject, minHeight: 25, minWidth: 100);
|
||||
applyButton.OnClick += OnApplyClicked;
|
||||
|
||||
inputField = UIFactory.CreateInputField(hori, "InputField", "Enter name or underlying value...");
|
||||
UIFactory.SetLayoutElement(inputField.UIRoot, minHeight: 25, flexibleHeight: 50, minWidth: 100, flexibleWidth: 1000);
|
||||
inputField.Component.lineType = InputField.LineType.MultiLineNewline;
|
||||
inputField.UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
enumHelperButton = UIFactory.CreateButton(hori, "EnumHelper", "▼");
|
||||
UIFactory.SetLayoutElement(enumHelperButton.Component.gameObject, minWidth: 25, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0);
|
||||
enumHelperButton.OnClick += EnumHelper_OnClick;
|
||||
|
||||
enumCompleter = new EnumCompleter(this.EnumType, this.inputField);
|
||||
|
||||
toggleHolder = UIFactory.CreateUIObject("ToggleHolder", UIRoot);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(toggleHolder, false, false, true, true, 4);
|
||||
UIFactory.SetLayoutElement(toggleHolder, minHeight: 25, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||
|
||||
return UIRoot;
|
||||
}
|
||||
|
||||
// Setting up the UI for the enum type when it changes or is first set
|
||||
|
||||
private void SetupDropdownForEnumType()
|
||||
{
|
||||
toggleHolder.SetActive(false);
|
||||
enumDropdown.gameObject.SetActive(true);
|
||||
|
||||
// create dropdown entries
|
||||
enumDropdown.options.Clear();
|
||||
|
||||
foreach (CachedEnumValue entry in CurrentValues.Values)
|
||||
enumDropdown.options.Add(new Dropdown.OptionData(entry.Name));
|
||||
|
||||
enumDropdown.value = 0;
|
||||
enumDropdown.RefreshShownValue();
|
||||
}
|
||||
public CachedEnumValue ValueAtIdx(int idx) => (CachedEnumValue)CurrentValues[idx];
|
||||
public CachedEnumValue ValueAtKey(object key) => (CachedEnumValue)CurrentValues[key];
|
||||
|
||||
private void SetupTogglesForEnumType()
|
||||
{
|
||||
toggleHolder.SetActive(true);
|
||||
enumDropdown.gameObject.SetActive(false);
|
||||
inputField.Component.gameObject.SetActive(false);
|
||||
enumHelperButton.Component.gameObject.SetActive(false);
|
||||
|
||||
// create / set / hide toggles
|
||||
for (int i = 0; i < CurrentValues.Count || i < flagToggles.Count; i++)
|
||||
@ -180,54 +206,13 @@ namespace UnityExplorer.CacheObject.IValues
|
||||
flagTexts.Add(toggleText);
|
||||
}
|
||||
|
||||
// UI Construction
|
||||
|
||||
public override GameObject CreateContent(GameObject parent)
|
||||
{
|
||||
UIRoot = UIFactory.CreateVerticalGroup(parent, "InteractiveEnum", false, false, true, true, 3, new Vector4(4, 4, 4, 4),
|
||||
new Color(0.06f, 0.06f, 0.06f));
|
||||
UIFactory.SetLayoutElement(UIRoot, minHeight: 25, flexibleHeight: 9999, flexibleWidth: 9999);
|
||||
|
||||
var hori = UIFactory.CreateUIObject("Hori", UIRoot);
|
||||
UIFactory.SetLayoutElement(hori, minHeight: 25, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(hori, false, false, true, true, 2);
|
||||
|
||||
var applyButton = UIFactory.CreateButton(hori, "ApplyButton", "Apply", new Color(0.2f, 0.27f, 0.2f));
|
||||
UIFactory.SetLayoutElement(applyButton.Component.gameObject, minHeight: 25, minWidth: 100);
|
||||
applyButton.OnClick += OnApplyClicked;
|
||||
|
||||
var dropdownObj = UIFactory.CreateDropdown(hori, out enumDropdown, "not set", 14, null);
|
||||
UIFactory.SetLayoutElement(dropdownObj, minHeight: 25, flexibleWidth: 600);
|
||||
|
||||
toggleHolder = UIFactory.CreateUIObject("ToggleHolder", UIRoot);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(toggleHolder, false, false, true, true, 4);
|
||||
UIFactory.SetLayoutElement(toggleHolder, minHeight: 25, flexibleWidth: 9999, flexibleHeight: 9999);
|
||||
|
||||
return UIRoot;
|
||||
}
|
||||
|
||||
|
||||
#region Enum cache
|
||||
|
||||
public struct CachedEnumValue
|
||||
{
|
||||
public CachedEnumValue(object value, int index, string name)
|
||||
{
|
||||
EnumIndex = index;
|
||||
Name = name;
|
||||
ActualValue = value;
|
||||
}
|
||||
|
||||
public readonly object ActualValue;
|
||||
public int EnumIndex;
|
||||
public readonly string Name;
|
||||
}
|
||||
|
||||
internal static readonly Dictionary<string, OrderedDictionary> enumCache = new Dictionary<string, OrderedDictionary>();
|
||||
|
||||
internal static OrderedDictionary GetEnumValues(Type enumType, out bool isFlags)
|
||||
internal static OrderedDictionary GetEnumValues(Type enumType)
|
||||
{
|
||||
isFlags = enumType.GetCustomAttributes(typeof(FlagsAttribute), true) is object[] fa && fa.Any();
|
||||
//isFlags = enumType.GetCustomAttributes(typeof(FlagsAttribute), true) is object[] fa && fa.Any();
|
||||
|
||||
if (!enumCache.ContainsKey(enumType.AssemblyQualifiedName))
|
||||
{
|
||||
@ -254,4 +239,18 @@ namespace UnityExplorer.CacheObject.IValues
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public struct CachedEnumValue
|
||||
{
|
||||
public CachedEnumValue(object value, int index, string name)
|
||||
{
|
||||
EnumIndex = index;
|
||||
Name = name;
|
||||
ActualValue = value;
|
||||
}
|
||||
|
||||
public readonly object ActualValue;
|
||||
public int EnumIndex;
|
||||
public readonly string Name;
|
||||
}
|
||||
}
|
||||
|
@ -1,374 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib;
|
||||
|
||||
namespace UnityExplorer.CacheObject.Views
|
||||
{
|
||||
public class EvaluateWidget : IPooledObject
|
||||
{
|
||||
public CacheMember Owner { get; set; }
|
||||
|
||||
public GameObject UIRoot { get; set; }
|
||||
public float DefaultHeight => -1f;
|
||||
|
||||
private ParameterInfo[] arguments;
|
||||
private string[] argumentInput;
|
||||
|
||||
private GameObject argHolder;
|
||||
private readonly List<GameObject> argRows = new List<GameObject>();
|
||||
private readonly List<Text> argLabels = new List<Text>();
|
||||
private readonly List<InputFieldRef> argInputFields = new List<InputFieldRef>();
|
||||
private readonly List<Dropdown> argDropdowns = new List<Dropdown>();
|
||||
|
||||
private Type[] genericArguments;
|
||||
private string[] genericInput;
|
||||
|
||||
private GameObject genericArgHolder;
|
||||
private readonly List<GameObject> genericArgRows = new List<GameObject>();
|
||||
private readonly List<Text> genericArgLabels = new List<Text>();
|
||||
private readonly List<TypeCompleter> genericAutocompleters = new List<TypeCompleter>();
|
||||
private readonly List<InputFieldRef> genericInputFields = new List<InputFieldRef>();
|
||||
|
||||
public void OnBorrowedFromPool(CacheMember owner)
|
||||
{
|
||||
this.Owner = owner;
|
||||
|
||||
arguments = owner.Arguments;
|
||||
argumentInput = new string[arguments.Length];
|
||||
|
||||
genericArguments = owner.GenericArguments;
|
||||
genericInput = new string[genericArguments.Length];
|
||||
|
||||
SetArgRows();
|
||||
|
||||
this.UIRoot.SetActive(true);
|
||||
|
||||
InspectorManager.OnInspectedTabsChanged += InspectorManager_OnInspectedTabsChanged;
|
||||
}
|
||||
|
||||
public void OnReturnToPool()
|
||||
{
|
||||
foreach (var input in argInputFields)
|
||||
input.Text = "";
|
||||
foreach (var input in genericInputFields)
|
||||
input.Text = "";
|
||||
|
||||
this.Owner = null;
|
||||
|
||||
InspectorManager.OnInspectedTabsChanged -= InspectorManager_OnInspectedTabsChanged;
|
||||
}
|
||||
|
||||
private void InspectorManager_OnInspectedTabsChanged()
|
||||
{
|
||||
for (int i = 0; i < argDropdowns.Count; i++)
|
||||
{
|
||||
var drop = argDropdowns[i];
|
||||
PopulateNonPrimitiveArgumentDropdown(drop, i);
|
||||
}
|
||||
}
|
||||
|
||||
public Type[] TryParseGenericArguments()
|
||||
{
|
||||
Type[] outArgs = new Type[genericArguments.Length];
|
||||
|
||||
for (int i = 0; i < genericArguments.Length; i++)
|
||||
{
|
||||
outArgs[i] = ReflectionUtility.GetTypeByName(genericInput[i])
|
||||
?? throw new Exception($"Could not find any type by name '{genericInput[i]}'!");
|
||||
}
|
||||
|
||||
return outArgs;
|
||||
}
|
||||
|
||||
public object[] TryParseArguments()
|
||||
{
|
||||
object[] outArgs = new object[arguments.Length];
|
||||
|
||||
for (int i = 0; i < arguments.Length; i++)
|
||||
{
|
||||
var paramInfo = arguments[i];
|
||||
|
||||
var argType = paramInfo.ParameterType;
|
||||
if (argType.IsByRef)
|
||||
argType = argType.GetElementType();
|
||||
|
||||
if (ParseUtility.CanParse(argType))
|
||||
{
|
||||
var input = argumentInput[i];
|
||||
|
||||
if (argType == typeof(string))
|
||||
{
|
||||
outArgs[i] = input;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
if (paramInfo.IsOptional)
|
||||
outArgs[i] = paramInfo.DefaultValue;
|
||||
else
|
||||
outArgs[i] = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ParseUtility.TryParse(input, argType, out outArgs[i], out Exception ex))
|
||||
{
|
||||
outArgs[i] = null;
|
||||
ExplorerCore.LogWarning($"Cannot parse argument '{paramInfo.Name}' ({paramInfo.ParameterType.Name})" +
|
||||
$"{(ex == null ? "" : $", {ex.GetType().Name}: {ex.Message}")}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var dropdown = argDropdowns[i];
|
||||
if (dropdown.value == 0)
|
||||
{
|
||||
outArgs[i] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Probably should do this in a better way...
|
||||
// Parse the text of the dropdown option to get the inspector tab index.
|
||||
string tabIndexString = "";
|
||||
for (int j = 4; ; j++)
|
||||
{
|
||||
char c = dropdown.options[dropdown.value].text[j];
|
||||
if (c == ':')
|
||||
break;
|
||||
tabIndexString += c;
|
||||
}
|
||||
int tabIndex = int.Parse(tabIndexString);
|
||||
var tab = InspectorManager.Inspectors[tabIndex - 1];
|
||||
|
||||
outArgs[i] = tab.Target;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outArgs;
|
||||
}
|
||||
|
||||
private void SetArgRows()
|
||||
{
|
||||
if (genericArguments.Any())
|
||||
{
|
||||
genericArgHolder.SetActive(true);
|
||||
SetGenericRows();
|
||||
}
|
||||
else
|
||||
genericArgHolder.SetActive(false);
|
||||
|
||||
if (arguments.Any())
|
||||
{
|
||||
argHolder.SetActive(true);
|
||||
SetNormalArgRows();
|
||||
}
|
||||
else
|
||||
argHolder.SetActive(false);
|
||||
}
|
||||
|
||||
private void SetGenericRows()
|
||||
{
|
||||
for (int i = 0; i < genericArguments.Length || i < genericArgRows.Count; i++)
|
||||
{
|
||||
if (i >= genericArguments.Length)
|
||||
{
|
||||
if (i >= genericArgRows.Count)
|
||||
break;
|
||||
else
|
||||
// exceeded actual args, but still iterating so there must be views left, disable them
|
||||
genericArgRows[i].SetActive(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
var arg = genericArguments[i];
|
||||
|
||||
if (i >= genericArgRows.Count)
|
||||
AddArgRow(i, true);
|
||||
|
||||
genericArgRows[i].SetActive(true);
|
||||
|
||||
var autoCompleter = genericAutocompleters[i];
|
||||
autoCompleter.BaseType = arg;
|
||||
autoCompleter.CacheTypes();
|
||||
|
||||
var constraints = arg.GetGenericParameterConstraints();
|
||||
autoCompleter.GenericConstraints = constraints;
|
||||
|
||||
var sb = new StringBuilder($"<color={SignatureHighlighter.CONST}>{arg.Name}</color>");
|
||||
|
||||
for (int j = 0; j < constraints.Length; j++)
|
||||
{
|
||||
if (j == 0) sb.Append(' ').Append('(');
|
||||
else sb.Append(',').Append(' ');
|
||||
|
||||
sb.Append(SignatureHighlighter.Parse(constraints[j], false));
|
||||
|
||||
if (j + 1 == constraints.Length)
|
||||
sb.Append(')');
|
||||
}
|
||||
|
||||
genericArgLabels[i].text = sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetNormalArgRows()
|
||||
{
|
||||
for (int i = 0; i < arguments.Length || i < argRows.Count; i++)
|
||||
{
|
||||
if (i >= arguments.Length)
|
||||
{
|
||||
if (i >= argRows.Count)
|
||||
break;
|
||||
else
|
||||
// exceeded actual args, but still iterating so there must be views left, disable them
|
||||
argRows[i].SetActive(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
var arg = arguments[i];
|
||||
var argType = arg.ParameterType;
|
||||
if (argType.IsByRef)
|
||||
argType = argType.GetElementType();
|
||||
|
||||
if (i >= argRows.Count)
|
||||
AddArgRow(i, false);
|
||||
|
||||
argRows[i].SetActive(true);
|
||||
argLabels[i].text =
|
||||
$"{SignatureHighlighter.Parse(argType, false)} <color={SignatureHighlighter.LOCAL_ARG}>{arg.Name}</color>";
|
||||
|
||||
if (ParseUtility.CanParse(argType))
|
||||
{
|
||||
argInputFields[i].Component.gameObject.SetActive(true);
|
||||
argDropdowns[i].gameObject.SetActive(false);
|
||||
|
||||
if (arg.ParameterType == typeof(string))
|
||||
argInputFields[i].PlaceholderText.text = "";
|
||||
else
|
||||
argInputFields[i].PlaceholderText.text = $"eg. {ParseUtility.GetExampleInput(argType)}";
|
||||
}
|
||||
else
|
||||
{
|
||||
argInputFields[i].Component.gameObject.SetActive(false);
|
||||
argDropdowns[i].gameObject.SetActive(true);
|
||||
|
||||
PopulateNonPrimitiveArgumentDropdown(argDropdowns[i], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateNonPrimitiveArgumentDropdown(Dropdown dropdown, int argIndex)
|
||||
{
|
||||
dropdown.options.Clear();
|
||||
dropdown.options.Add(new Dropdown.OptionData("null"));
|
||||
|
||||
var argType = arguments[argIndex].ParameterType;
|
||||
|
||||
int tabIndex = 0;
|
||||
foreach (var tab in InspectorManager.Inspectors)
|
||||
{
|
||||
tabIndex++;
|
||||
|
||||
if (argType.IsAssignableFrom(tab.Target.GetActualType()))
|
||||
dropdown.options.Add(new Dropdown.OptionData($"Tab {tabIndex}: {tab.Tab.TabText.text}"));
|
||||
}
|
||||
}
|
||||
|
||||
private void AddArgRow(int index, bool generic)
|
||||
{
|
||||
if (!generic)
|
||||
AddArgRow(index, argHolder, argRows, argLabels, argumentInput, false);
|
||||
else
|
||||
AddArgRow(index, genericArgHolder, genericArgRows, genericArgLabels, genericInput, true);
|
||||
}
|
||||
|
||||
private void AddArgRow(int index, GameObject parent, List<GameObject> objectList, List<Text> labelList, string[] inputArray, bool generic)
|
||||
{
|
||||
var horiGroup = UIFactory.CreateUIObject("ArgRow_" + index, parent);
|
||||
UIFactory.SetLayoutElement(horiGroup, minHeight: 25, flexibleHeight: 50, minWidth: 50, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(horiGroup, false, false, true, true, 5);
|
||||
horiGroup.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
objectList.Add(horiGroup);
|
||||
|
||||
var label = UIFactory.CreateLabel(horiGroup, "ArgLabel", "not set", TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(label.gameObject, minWidth: 40, flexibleWidth: 90, minHeight: 25, flexibleHeight: 50);
|
||||
labelList.Add(label);
|
||||
label.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
|
||||
var inputField = UIFactory.CreateInputField(horiGroup, "InputField", "...");
|
||||
UIFactory.SetLayoutElement(inputField.UIRoot, minHeight: 25, flexibleHeight: 50, minWidth: 100, flexibleWidth: 1000);
|
||||
inputField.Component.lineType = InputField.LineType.MultiLineNewline;
|
||||
inputField.UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
inputField.OnValueChanged += (string val) => { inputArray[index] = val; };
|
||||
|
||||
if (!generic)
|
||||
{
|
||||
var dropdownObj = UIFactory.CreateDropdown(horiGroup, out Dropdown dropdown, "Select argument...", 14, (int val) =>
|
||||
{
|
||||
ArgDropdownChanged(index, val);
|
||||
});
|
||||
UIFactory.SetLayoutElement(dropdownObj, minHeight: 25, flexibleHeight: 50, minWidth: 100, flexibleWidth: 1000);
|
||||
dropdownObj.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
argInputFields.Add(inputField);
|
||||
argDropdowns.Add(dropdown);
|
||||
}
|
||||
else
|
||||
genericInputFields.Add(inputField);
|
||||
|
||||
if (generic)
|
||||
genericAutocompleters.Add(new TypeCompleter(null, inputField));
|
||||
}
|
||||
|
||||
private void ArgDropdownChanged(int argIndex, int value)
|
||||
{
|
||||
// not sure if necessary
|
||||
}
|
||||
|
||||
public GameObject CreateContent(GameObject parent)
|
||||
{
|
||||
UIRoot = UIFactory.CreateVerticalGroup(parent, "EvaluateWidget", false, false, true, true, 3, new Vector4(2, 2, 2, 2),
|
||||
new Color(0.15f, 0.15f, 0.15f));
|
||||
UIFactory.SetLayoutElement(UIRoot, minWidth: 50, flexibleWidth: 9999, minHeight: 50, flexibleHeight: 800);
|
||||
//UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
// generic args
|
||||
this.genericArgHolder = UIFactory.CreateUIObject("GenericHolder", UIRoot);
|
||||
UIFactory.SetLayoutElement(genericArgHolder, flexibleWidth: 1000);
|
||||
var genericsTitle = UIFactory.CreateLabel(genericArgHolder, "GenericsTitle", "Generic Arguments", TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(genericsTitle.gameObject, minHeight: 25, flexibleWidth: 1000);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(genericArgHolder, false, false, true, true, 3);
|
||||
UIFactory.SetLayoutElement(genericArgHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999);
|
||||
//genericArgHolder.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
// args
|
||||
this.argHolder = UIFactory.CreateUIObject("ArgHolder", UIRoot);
|
||||
UIFactory.SetLayoutElement(argHolder, flexibleWidth: 1000);
|
||||
var argsTitle = UIFactory.CreateLabel(argHolder, "ArgsTitle", "Arguments", TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(argsTitle.gameObject, minHeight: 25, flexibleWidth: 1000);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(argHolder, false, false, true, true, 3);
|
||||
UIFactory.SetLayoutElement(argHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999);
|
||||
//argHolder.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
// evaluate button
|
||||
var evalButton = UIFactory.CreateButton(UIRoot, "EvaluateButton", "Evaluate", new Color(0.2f, 0.2f, 0.2f));
|
||||
UIFactory.SetLayoutElement(evalButton.Component.gameObject, minHeight: 25, minWidth: 150, flexibleWidth: 0);
|
||||
evalButton.OnClick += () =>
|
||||
{
|
||||
Owner.EvaluateAndSetCell();
|
||||
};
|
||||
|
||||
return UIRoot;
|
||||
}
|
||||
}
|
||||
}
|
@ -36,6 +36,8 @@ namespace UnityExplorer.Tests
|
||||
public const int ConstantInt5 = 5;
|
||||
|
||||
// Testing other InteractiveValues
|
||||
public static BindingFlags EnumTest;
|
||||
public static CameraClearFlags EnumTest2;
|
||||
public static Color Color = Color.magenta;
|
||||
public static Color32 Color32 = Color.red;
|
||||
public static string ALongString = new string('#', 10000);
|
||||
@ -78,9 +80,9 @@ namespace UnityExplorer.Tests
|
||||
ExplorerCore.Log($"Test3 {typeof(T).FullName}");
|
||||
}
|
||||
|
||||
public static void TestArgumentParse(string s, int i, Color color, CameraClearFlags flags, Vector3 vector, Quaternion quaternion)
|
||||
public static void TestArgumentParse(string s, int i, Color color, CameraClearFlags flags, Vector3 vector, Quaternion quaternion, object obj)
|
||||
{
|
||||
ExplorerCore.Log($"{s}, {i}, {color.ToString()}, {flags}, {vector.ToString()}, {quaternion.ToString()}");
|
||||
ExplorerCore.Log($"{s}, {i}, {color.ToString()}, {flags}, {vector.ToString()}, {quaternion.ToString()}, {obj?.ToString() ?? "null"}");
|
||||
}
|
||||
|
||||
private static void Init_Mono()
|
||||
|
@ -164,9 +164,7 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
if (!CurrentHandler.InputField.UIRoot.activeInHierarchy)
|
||||
ReleaseOwnership(CurrentHandler);
|
||||
else
|
||||
{
|
||||
UpdatePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,9 +226,9 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
private int lastCaretPosition;
|
||||
private Vector3 lastInputPosition;
|
||||
|
||||
private void UpdatePosition()
|
||||
internal void UpdatePosition()
|
||||
{
|
||||
if (CurrentHandler == null || !CurrentHandler.InputField.Component.isFocused)
|
||||
if (CurrentHandler == null)
|
||||
return;
|
||||
|
||||
var input = CurrentHandler.InputField;
|
||||
@ -255,9 +253,10 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
}
|
||||
else
|
||||
{
|
||||
var textGen = input.Component.textComponent.cachedTextGenerator;
|
||||
var pos = input.UIRoot.transform.TransformPoint(textGen.characters[0].cursorPos);
|
||||
uiRoot.transform.position = new Vector3(pos.x + 10, pos.y - 20, 0);
|
||||
uiRoot.transform.position = input.Rect.position + new Vector3(-(input.Rect.rect.width / 2) + 10, -20, 0);
|
||||
//var textGen = input.Component.textComponent.cachedTextGenerator;
|
||||
//var pos = input.UIRoot.transform.TransformPoint(textGen.characters[0].cursorPos);
|
||||
//uiRoot.transform.position = new Vector3(pos.x + 10, pos.y - 20, 0);
|
||||
}
|
||||
|
||||
this.Dragger.OnEndResize();
|
||||
|
160
src/UI/Widgets/AutoComplete/EnumCompleter.cs
Normal file
160
src/UI/Widgets/AutoComplete/EnumCompleter.cs
Normal file
@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
{
|
||||
public class EnumCompleter : ISuggestionProvider
|
||||
{
|
||||
public bool Enabled
|
||||
{
|
||||
get => _enabled;
|
||||
set
|
||||
{
|
||||
_enabled = value;
|
||||
if (!_enabled)
|
||||
AutoCompleteModal.Instance.ReleaseOwnership(this);
|
||||
}
|
||||
}
|
||||
private bool _enabled = true;
|
||||
|
||||
public event Action<Suggestion> SuggestionClicked;
|
||||
|
||||
public Type EnumType { get; set; }
|
||||
|
||||
public InputFieldRef InputField { get; }
|
||||
public bool AnchorToCaretPosition => false;
|
||||
|
||||
private readonly List<Suggestion> suggestions = new List<Suggestion>();
|
||||
private readonly HashSet<string> suggestedValues = new HashSet<string>();
|
||||
|
||||
private OrderedDictionary enumValues;
|
||||
|
||||
internal string chosenSuggestion;
|
||||
|
||||
bool ISuggestionProvider.AllowNavigation => false;
|
||||
|
||||
public EnumCompleter(Type enumType, InputFieldRef inputField)
|
||||
{
|
||||
EnumType = enumType;
|
||||
InputField = inputField;
|
||||
|
||||
inputField.OnValueChanged += OnInputFieldChanged;
|
||||
|
||||
if (EnumType != null)
|
||||
CacheEnumValues();
|
||||
}
|
||||
|
||||
public void CacheEnumValues()
|
||||
{
|
||||
enumValues = InteractiveEnum.GetEnumValues(EnumType);
|
||||
}
|
||||
|
||||
private string GetLastSplitInput(string fullInput)
|
||||
{
|
||||
string ret = fullInput;
|
||||
|
||||
int lastSplit = fullInput.LastIndexOf(',');
|
||||
if (lastSplit >= 0)
|
||||
{
|
||||
lastSplit++;
|
||||
if (lastSplit == fullInput.Length)
|
||||
ret = "";
|
||||
else
|
||||
ret = fullInput.Substring(lastSplit);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void OnSuggestionClicked(Suggestion suggestion)
|
||||
{
|
||||
chosenSuggestion = suggestion.UnderlyingValue;
|
||||
|
||||
string lastInput = GetLastSplitInput(InputField.Text);
|
||||
|
||||
if (lastInput != suggestion.UnderlyingValue)
|
||||
{
|
||||
string valueToSet = InputField.Text;
|
||||
|
||||
if (valueToSet.Length > 0)
|
||||
valueToSet = valueToSet.Substring(0, InputField.Text.Length - lastInput.Length);
|
||||
|
||||
valueToSet += suggestion.UnderlyingValue;
|
||||
|
||||
InputField.Text = valueToSet;
|
||||
|
||||
//InputField.Text += suggestion.UnderlyingValue.Substring(lastInput.Length);
|
||||
}
|
||||
|
||||
SuggestionClicked?.Invoke(suggestion);
|
||||
|
||||
suggestions.Clear();
|
||||
AutoCompleteModal.Instance.SetSuggestions(suggestions);
|
||||
}
|
||||
|
||||
public void HelperButtonClicked()
|
||||
{
|
||||
GetSuggestions("");
|
||||
AutoCompleteModal.Instance.TakeOwnership(this);
|
||||
AutoCompleteModal.Instance.SetSuggestions(suggestions);
|
||||
}
|
||||
|
||||
private void OnInputFieldChanged(string value)
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrEmpty(value) || GetLastSplitInput(value) == chosenSuggestion)
|
||||
{
|
||||
chosenSuggestion = null;
|
||||
AutoCompleteModal.Instance.ReleaseOwnership(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetSuggestions(value);
|
||||
|
||||
AutoCompleteModal.Instance.TakeOwnership(this);
|
||||
AutoCompleteModal.Instance.SetSuggestions(suggestions);
|
||||
}
|
||||
}
|
||||
|
||||
private void GetSuggestions(string value)
|
||||
{
|
||||
suggestions.Clear();
|
||||
suggestedValues.Clear();
|
||||
|
||||
if (EnumType == null)
|
||||
{
|
||||
ExplorerCore.LogWarning("Autocompleter Base enum type is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
value = GetLastSplitInput(value);
|
||||
|
||||
for (int i = 0; i < this.enumValues.Count; i++)
|
||||
{
|
||||
var enumValue = (CachedEnumValue)enumValues[i];
|
||||
if (enumValue.Name.ContainsIgnoreCase(value))
|
||||
AddSuggestion(enumValue.Name);
|
||||
}
|
||||
}
|
||||
|
||||
internal static readonly Dictionary<string, string> sharedValueToLabel = new Dictionary<string, string>(4096);
|
||||
|
||||
void AddSuggestion(string value)
|
||||
{
|
||||
if (suggestedValues.Contains(value))
|
||||
return;
|
||||
suggestedValues.Add(value);
|
||||
|
||||
if (!sharedValueToLabel.ContainsKey(value))
|
||||
sharedValueToLabel.Add(value, $"<color={SignatureHighlighter.CONST}>{value}</color>");
|
||||
|
||||
suggestions.Add(new Suggestion(sharedValueToLabel[value], value));
|
||||
}
|
||||
}
|
||||
}
|
@ -12,8 +12,6 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
public readonly string DisplayText;
|
||||
public readonly string UnderlyingValue;
|
||||
|
||||
public string Combined => DisplayText + UnderlyingValue;
|
||||
|
||||
public Suggestion(string displayText, string underlyingValue)
|
||||
{
|
||||
DisplayText = displayText;
|
||||
|
@ -9,12 +9,24 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
{
|
||||
internal static readonly Dictionary<string, string> sharedTypeToLabel = new Dictionary<string, string>(4096);
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get => _enabled;
|
||||
set
|
||||
{
|
||||
_enabled = value;
|
||||
if (!_enabled)
|
||||
AutoCompleteModal.Instance.ReleaseOwnership(this);
|
||||
}
|
||||
}
|
||||
private bool _enabled = true;
|
||||
|
||||
public event Action<Suggestion> SuggestionClicked;
|
||||
|
||||
public Type BaseType { get; set; }
|
||||
public Type[] GenericConstraints { get; set; }
|
||||
private bool allowAbstract;
|
||||
private bool allowEnum;
|
||||
private readonly bool allowAbstract;
|
||||
private readonly bool allowEnum;
|
||||
|
||||
public InputFieldRef InputField { get; }
|
||||
public bool AnchorToCaretPosition => false;
|
||||
@ -61,6 +73,9 @@ namespace UnityExplorer.UI.Widgets.AutoComplete
|
||||
|
||||
private void OnInputFieldChanged(string value)
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrEmpty(value) || value == chosenSuggestion)
|
||||
{
|
||||
chosenSuggestion = null;
|
||||
|
51
src/UI/Widgets/EvaluateWidget/BaseArgumentHandler.cs
Normal file
51
src/UI/Widgets/EvaluateWidget/BaseArgumentHandler.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
public abstract class BaseArgumentHandler : IPooledObject
|
||||
{
|
||||
protected EvaluateWidget evaluator;
|
||||
|
||||
internal Text argNameLabel;
|
||||
internal InputFieldRef inputField;
|
||||
internal TypeCompleter typeCompleter;
|
||||
|
||||
// IPooledObject
|
||||
public float DefaultHeight => 25f;
|
||||
public GameObject UIRoot { get; set; }
|
||||
|
||||
public abstract void CreateSpecialContent();
|
||||
|
||||
public GameObject CreateContent(GameObject parent)
|
||||
{
|
||||
UIRoot = UIFactory.CreateUIObject("ArgRow", parent);
|
||||
UIFactory.SetLayoutElement(UIRoot, minHeight: 25, flexibleHeight: 50, minWidth: 50, flexibleWidth: 9999);
|
||||
UIFactory.SetLayoutGroup<HorizontalLayoutGroup>(UIRoot, false, false, true, true, 5);
|
||||
UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
argNameLabel = UIFactory.CreateLabel(UIRoot, "ArgLabel", "not set", TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(argNameLabel.gameObject, minWidth: 40, flexibleWidth: 90, minHeight: 25, flexibleHeight: 50);
|
||||
argNameLabel.horizontalOverflow = HorizontalWrapMode.Wrap;
|
||||
|
||||
inputField = UIFactory.CreateInputField(UIRoot, "InputField", "...");
|
||||
UIFactory.SetLayoutElement(inputField.UIRoot, minHeight: 25, flexibleHeight: 50, minWidth: 100, flexibleWidth: 1000);
|
||||
inputField.Component.lineType = InputField.LineType.MultiLineNewline;
|
||||
inputField.UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
typeCompleter = new TypeCompleter(typeof(object), this.inputField);
|
||||
typeCompleter.Enabled = false;
|
||||
|
||||
CreateSpecialContent();
|
||||
|
||||
return UIRoot;
|
||||
}
|
||||
}
|
||||
}
|
176
src/UI/Widgets/EvaluateWidget/EvaluateWidget.cs
Normal file
176
src/UI/Widgets/EvaluateWidget/EvaluateWidget.cs
Normal file
@ -0,0 +1,176 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.UI;
|
||||
using UniverseLib.UI.Models;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UniverseLib.UI;
|
||||
using UniverseLib;
|
||||
using UnityExplorer.CacheObject;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
public class EvaluateWidget : IPooledObject
|
||||
{
|
||||
public CacheMember Owner { get; set; }
|
||||
|
||||
public GameObject UIRoot { get; set; }
|
||||
public float DefaultHeight => -1f;
|
||||
|
||||
private ParameterInfo[] parameters;
|
||||
internal GameObject parametersHolder;
|
||||
private ParameterHandler[] paramHandlers;
|
||||
|
||||
private Type[] genericArguments;
|
||||
internal GameObject genericArgumentsHolder;
|
||||
private GenericArgumentHandler[] genericHandlers;
|
||||
|
||||
public void OnBorrowedFromPool(CacheMember owner)
|
||||
{
|
||||
this.Owner = owner;
|
||||
|
||||
parameters = owner.Arguments;
|
||||
paramHandlers = new ParameterHandler[parameters.Length];
|
||||
|
||||
genericArguments = owner.GenericArguments;
|
||||
genericHandlers = new GenericArgumentHandler[genericArguments.Length];
|
||||
|
||||
SetArgRows();
|
||||
|
||||
this.UIRoot.SetActive(true);
|
||||
|
||||
InspectorManager.OnInspectedTabsChanged += InspectorManager_OnInspectedTabsChanged;
|
||||
}
|
||||
|
||||
public void OnReturnToPool()
|
||||
{
|
||||
foreach (var widget in paramHandlers)
|
||||
{
|
||||
widget.OnReturned();
|
||||
Pool<ParameterHandler>.Return(widget);
|
||||
}
|
||||
paramHandlers = null;
|
||||
|
||||
foreach (var widget in genericHandlers)
|
||||
{
|
||||
widget.OnReturned();
|
||||
Pool<GenericArgumentHandler>.Return(widget);
|
||||
}
|
||||
genericHandlers = null;
|
||||
|
||||
this.Owner = null;
|
||||
|
||||
InspectorManager.OnInspectedTabsChanged -= InspectorManager_OnInspectedTabsChanged;
|
||||
}
|
||||
|
||||
private void InspectorManager_OnInspectedTabsChanged()
|
||||
{
|
||||
foreach (var handler in this.paramHandlers)
|
||||
handler.PopulateDropdown();
|
||||
}
|
||||
|
||||
public Type[] TryParseGenericArguments()
|
||||
{
|
||||
Type[] outArgs = new Type[genericArguments.Length];
|
||||
|
||||
for (int i = 0; i < genericArguments.Length; i++)
|
||||
outArgs[i] = genericHandlers[i].Evaluate();
|
||||
|
||||
return outArgs;
|
||||
}
|
||||
|
||||
public object[] TryParseArguments()
|
||||
{
|
||||
object[] outArgs = new object[parameters.Length];
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
outArgs[i] = paramHandlers[i].Evaluate();
|
||||
|
||||
return outArgs;
|
||||
}
|
||||
|
||||
private void SetArgRows()
|
||||
{
|
||||
if (genericArguments.Any())
|
||||
{
|
||||
genericArgumentsHolder.SetActive(true);
|
||||
SetGenericRows();
|
||||
}
|
||||
else
|
||||
genericArgumentsHolder.SetActive(false);
|
||||
|
||||
if (parameters.Any())
|
||||
{
|
||||
parametersHolder.SetActive(true);
|
||||
SetNormalArgRows();
|
||||
}
|
||||
else
|
||||
parametersHolder.SetActive(false);
|
||||
}
|
||||
|
||||
private void SetGenericRows()
|
||||
{
|
||||
for (int i = 0; i < genericArguments.Length; i++)
|
||||
{
|
||||
var type = genericArguments[i];
|
||||
|
||||
var holder = genericHandlers[i] = Pool<GenericArgumentHandler>.Borrow();
|
||||
holder.UIRoot.transform.SetParent(this.genericArgumentsHolder.transform, false);
|
||||
holder.OnBorrowed(this, type);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetNormalArgRows()
|
||||
{
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var param = parameters[i];
|
||||
|
||||
var holder = paramHandlers[i] = Pool<ParameterHandler>.Borrow();
|
||||
holder.UIRoot.transform.SetParent(this.parametersHolder.transform, false);
|
||||
holder.OnBorrowed(this, param);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public GameObject CreateContent(GameObject parent)
|
||||
{
|
||||
UIRoot = UIFactory.CreateVerticalGroup(parent, "EvaluateWidget", false, false, true, true, 3, new Vector4(2, 2, 2, 2),
|
||||
new Color(0.15f, 0.15f, 0.15f));
|
||||
UIFactory.SetLayoutElement(UIRoot, minWidth: 50, flexibleWidth: 9999, minHeight: 50, flexibleHeight: 800);
|
||||
//UIRoot.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
// generic args
|
||||
this.genericArgumentsHolder = UIFactory.CreateUIObject("GenericHolder", UIRoot);
|
||||
UIFactory.SetLayoutElement(genericArgumentsHolder, flexibleWidth: 1000);
|
||||
var genericsTitle = UIFactory.CreateLabel(genericArgumentsHolder, "GenericsTitle", "Generic Arguments", TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(genericsTitle.gameObject, minHeight: 25, flexibleWidth: 1000);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(genericArgumentsHolder, false, false, true, true, 3);
|
||||
UIFactory.SetLayoutElement(genericArgumentsHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999);
|
||||
//genericArgHolder.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
// args
|
||||
this.parametersHolder = UIFactory.CreateUIObject("ArgHolder", UIRoot);
|
||||
UIFactory.SetLayoutElement(parametersHolder, flexibleWidth: 1000);
|
||||
var argsTitle = UIFactory.CreateLabel(parametersHolder, "ArgsTitle", "Arguments", TextAnchor.MiddleLeft);
|
||||
UIFactory.SetLayoutElement(argsTitle.gameObject, minHeight: 25, flexibleWidth: 1000);
|
||||
UIFactory.SetLayoutGroup<VerticalLayoutGroup>(parametersHolder, false, false, true, true, 3);
|
||||
UIFactory.SetLayoutElement(parametersHolder, minHeight: 25, flexibleHeight: 750, minWidth: 50, flexibleWidth: 9999);
|
||||
//argHolder.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
// evaluate button
|
||||
var evalButton = UIFactory.CreateButton(UIRoot, "EvaluateButton", "Evaluate", new Color(0.2f, 0.2f, 0.2f));
|
||||
UIFactory.SetLayoutElement(evalButton.Component.gameObject, minHeight: 25, minWidth: 150, flexibleWidth: 0);
|
||||
evalButton.OnClick += () =>
|
||||
{
|
||||
Owner.EvaluateAndSetCell();
|
||||
};
|
||||
|
||||
return UIRoot;
|
||||
}
|
||||
}
|
||||
}
|
61
src/UI/Widgets/EvaluateWidget/GenericArgumentHandler.cs
Normal file
61
src/UI/Widgets/EvaluateWidget/GenericArgumentHandler.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UniverseLib;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
public class GenericArgumentHandler : BaseArgumentHandler
|
||||
{
|
||||
private Type genericType;
|
||||
|
||||
public void OnBorrowed(EvaluateWidget evaluator, Type genericConstraint)
|
||||
{
|
||||
this.evaluator = evaluator;
|
||||
this.genericType = genericConstraint;
|
||||
|
||||
typeCompleter.Enabled = true;
|
||||
typeCompleter.BaseType = genericType;
|
||||
typeCompleter.CacheTypes();
|
||||
|
||||
var constraints = genericType.GetGenericParameterConstraints();
|
||||
typeCompleter.GenericConstraints = constraints;
|
||||
|
||||
var sb = new StringBuilder($"<color={SignatureHighlighter.CONST}>{genericType.Name}</color>");
|
||||
|
||||
for (int j = 0; j < constraints.Length; j++)
|
||||
{
|
||||
if (j == 0) sb.Append(' ').Append('(');
|
||||
else sb.Append(',').Append(' ');
|
||||
|
||||
sb.Append(SignatureHighlighter.Parse(constraints[j], false));
|
||||
|
||||
if (j + 1 == constraints.Length)
|
||||
sb.Append(')');
|
||||
}
|
||||
|
||||
argNameLabel.text = sb.ToString();
|
||||
}
|
||||
|
||||
public void OnReturned()
|
||||
{
|
||||
this.evaluator = null;
|
||||
this.genericType = null;
|
||||
|
||||
this.typeCompleter.Enabled = false;
|
||||
|
||||
this.inputField.Text = "";
|
||||
}
|
||||
|
||||
public Type Evaluate()
|
||||
{
|
||||
return ReflectionUtility.GetTypeByName(this.inputField.Text)
|
||||
?? throw new Exception($"Could not find any type by name '{this.inputField.Text}'!");
|
||||
}
|
||||
|
||||
public override void CreateSpecialContent()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
186
src/UI/Widgets/EvaluateWidget/ParameterHandler.cs
Normal file
186
src/UI/Widgets/EvaluateWidget/ParameterHandler.cs
Normal file
@ -0,0 +1,186 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Reflection;
|
||||
using UnityEngine.UI;
|
||||
using UnityExplorer.CacheObject.IValues;
|
||||
using UnityExplorer.UI.Widgets.AutoComplete;
|
||||
using UniverseLib;
|
||||
using UniverseLib.UI;
|
||||
|
||||
namespace UnityExplorer.UI.Widgets
|
||||
{
|
||||
public class ParameterHandler : BaseArgumentHandler
|
||||
{
|
||||
private ParameterInfo paramInfo;
|
||||
private Type paramType;
|
||||
|
||||
internal Dropdown dropdown;
|
||||
private bool usingDropdown;
|
||||
internal EnumCompleter enumCompleter;
|
||||
private ButtonRef enumHelperButton;
|
||||
|
||||
public void OnBorrowed(EvaluateWidget evaluator, ParameterInfo paramInfo)
|
||||
{
|
||||
this.evaluator = evaluator;
|
||||
this.paramInfo = paramInfo;
|
||||
|
||||
this.paramType = paramInfo.ParameterType;
|
||||
if (paramType.IsByRef)
|
||||
paramType = paramType.GetElementType();
|
||||
|
||||
this.argNameLabel.text =
|
||||
$"{SignatureHighlighter.Parse(paramType, false)} <color={SignatureHighlighter.LOCAL_ARG}>{paramInfo.Name}</color>";
|
||||
|
||||
if (ParseUtility.CanParse(paramType) || typeof(Type).IsAssignableFrom(paramType))
|
||||
{
|
||||
this.inputField.Component.gameObject.SetActive(true);
|
||||
this.dropdown.gameObject.SetActive(false);
|
||||
this.typeCompleter.Enabled = typeof(Type).IsAssignableFrom(paramType);
|
||||
this.enumCompleter.Enabled = paramType.IsEnum;
|
||||
this.enumHelperButton.Component.gameObject.SetActive(paramType.IsEnum);
|
||||
|
||||
if (!typeCompleter.Enabled)
|
||||
{
|
||||
if (paramType == typeof(string))
|
||||
inputField.PlaceholderText.text = "...";
|
||||
else
|
||||
inputField.PlaceholderText.text = $"eg. {ParseUtility.GetExampleInput(paramType)}";
|
||||
}
|
||||
else
|
||||
{
|
||||
inputField.PlaceholderText.text = "Enter a Type name...";
|
||||
this.typeCompleter.BaseType = typeof(object);
|
||||
this.typeCompleter.CacheTypes();
|
||||
}
|
||||
|
||||
if (enumCompleter.Enabled)
|
||||
{
|
||||
enumCompleter.EnumType = paramType;
|
||||
enumCompleter.CacheEnumValues();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// non-parsable, and not a Type
|
||||
this.inputField.Component.gameObject.SetActive(false);
|
||||
this.dropdown.gameObject.SetActive(true);
|
||||
this.typeCompleter.Enabled = false;
|
||||
this.enumCompleter.Enabled = false;
|
||||
this.enumHelperButton.Component.gameObject.SetActive(false);
|
||||
|
||||
usingDropdown = true;
|
||||
PopulateDropdown();
|
||||
|
||||
InspectorManager.OnInspectedTabsChanged += PopulateDropdown;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReturned()
|
||||
{
|
||||
this.evaluator = null;
|
||||
this.paramInfo = null;
|
||||
|
||||
usingDropdown = false;
|
||||
|
||||
this.enumCompleter.Enabled = false;
|
||||
this.typeCompleter.Enabled = false;
|
||||
|
||||
this.inputField.Text = "";
|
||||
|
||||
InspectorManager.OnInspectedTabsChanged -= PopulateDropdown;
|
||||
}
|
||||
|
||||
public object Evaluate()
|
||||
{
|
||||
if (!usingDropdown)
|
||||
{
|
||||
var input = this.inputField.Text;
|
||||
|
||||
if (paramType == typeof(string))
|
||||
return input;
|
||||
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
if (paramInfo.IsOptional)
|
||||
return paramInfo.DefaultValue;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!ParseUtility.TryParse(input, paramType, out object parsed, out Exception ex))
|
||||
{
|
||||
ExplorerCore.LogWarning($"Cannot parse argument '{paramInfo.Name}' ({paramInfo.ParameterType.Name})" +
|
||||
$"{(ex == null ? "" : $", {ex.GetType().Name}: {ex.Message}")}");
|
||||
return null;
|
||||
}
|
||||
else
|
||||
return parsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dropdown.value == 0)
|
||||
return null;
|
||||
else
|
||||
return dropdownUnderlyingValues[dropdown.value];
|
||||
}
|
||||
}
|
||||
|
||||
private object[] dropdownUnderlyingValues;
|
||||
|
||||
internal void PopulateDropdown()
|
||||
{
|
||||
if (!usingDropdown)
|
||||
return;
|
||||
|
||||
dropdown.options.Clear();
|
||||
var underlyingValues = new List<object>();
|
||||
|
||||
dropdown.options.Add(new Dropdown.OptionData("null"));
|
||||
underlyingValues.Add(null);
|
||||
|
||||
var argType = paramType;
|
||||
|
||||
int tabIndex = 0;
|
||||
foreach (var tab in InspectorManager.Inspectors)
|
||||
{
|
||||
tabIndex++;
|
||||
|
||||
if (argType.IsAssignableFrom(tab.Target.GetActualType()))
|
||||
{
|
||||
dropdown.options.Add(new Dropdown.OptionData($"Tab {tabIndex}: {tab.Tab.TabText.text}"));
|
||||
underlyingValues.Add(tab.Target);
|
||||
}
|
||||
}
|
||||
|
||||
dropdownUnderlyingValues = underlyingValues.ToArray();
|
||||
}
|
||||
|
||||
private void EnumHelper_OnClick()
|
||||
{
|
||||
enumCompleter.HelperButtonClicked();
|
||||
}
|
||||
|
||||
public override void CreateSpecialContent()
|
||||
{
|
||||
enumHelperButton = UIFactory.CreateButton(UIRoot, "EnumHelper", "▼");
|
||||
UIFactory.SetLayoutElement(enumHelperButton.Component.gameObject, minWidth: 25, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0);
|
||||
enumHelperButton.OnClick += EnumHelper_OnClick;
|
||||
|
||||
var dropdownObj = UIFactory.CreateDropdown(UIRoot, out dropdown, "Select argument...", 14, (int val) =>
|
||||
{
|
||||
//ArgDropdownChanged(val);
|
||||
});
|
||||
UIFactory.SetLayoutElement(dropdownObj, minHeight: 25, flexibleHeight: 50, minWidth: 100, flexibleWidth: 1000);
|
||||
dropdownObj.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
enumCompleter = new EnumCompleter(paramType, this.inputField);
|
||||
enumCompleter.Enabled = false;
|
||||
}
|
||||
|
||||
//private void ArgDropdownChanged(int value)
|
||||
//{
|
||||
// // not needed
|
||||
//}
|
||||
}
|
||||
}
|
@ -255,7 +255,8 @@
|
||||
<Compile Include="CacheObject\Views\CacheListEntryCell.cs" />
|
||||
<Compile Include="CacheObject\Views\CacheMemberCell.cs" />
|
||||
<Compile Include="CacheObject\Views\CacheObjectCell.cs" />
|
||||
<Compile Include="CacheObject\Views\EvaluateWidget.cs" />
|
||||
<Compile Include="UI\Widgets\AutoComplete\EnumCompleter.cs" />
|
||||
<Compile Include="UI\Widgets\EvaluateWidget\EvaluateWidget.cs" />
|
||||
<Compile Include="Inspectors\GameObjectInspector.cs" />
|
||||
<Compile Include="CacheObject\ICacheObjectController.cs" />
|
||||
<Compile Include="Inspectors\InspectorManager.cs" />
|
||||
@ -307,6 +308,9 @@
|
||||
<Compile Include="UI\Widgets\AutoComplete\TypeCompleter.cs" />
|
||||
<Compile Include="ObjectExplorer\ObjectSearch.cs" />
|
||||
<Compile Include="ObjectExplorer\SceneExplorer.cs" />
|
||||
<Compile Include="UI\Widgets\EvaluateWidget\BaseArgumentHandler.cs" />
|
||||
<Compile Include="UI\Widgets\EvaluateWidget\GenericArgumentHandler.cs" />
|
||||
<Compile Include="UI\Widgets\EvaluateWidget\ParameterHandler.cs" />
|
||||
<Compile Include="UI\Widgets\TransformTree\CachedTransform.cs" />
|
||||
<Compile Include="UI\Widgets\TransformTree\TransformCell.cs" />
|
||||
<Compile Include="UI\Widgets\TransformTree\TransformTree.cs" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user