mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-15 07:56:41 +08:00
Rewrite EvaluateWidget, add BaseArgumentHandler, use autocomplete for InteractiveEnum
This commit is contained in:
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user