You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
8.4 KiB
207 lines
8.4 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
using System.Reflection; |
|
using UnityEditor; |
|
using UnityEngine; |
|
|
|
namespace UnityTest |
|
{ |
|
public class PropertyPathSelector |
|
{ |
|
private readonly DropDownControl<string> m_ThisDropDown = new DropDownControl<string>(); |
|
private readonly Func<string, string> m_ReplaceDotWithSlashAndAddGoGroup = s => s.Replace('.', '/'); |
|
|
|
private readonly string m_Name; |
|
private bool m_FocusBackToEdit; |
|
private SelectedPathError m_Error; |
|
|
|
public PropertyPathSelector(string name) |
|
{ |
|
m_Name = name; |
|
m_ThisDropDown.convertForGUIContent = m_ReplaceDotWithSlashAndAddGoGroup; |
|
m_ThisDropDown.tooltip = "Select the path to the value you want to use for comparison."; |
|
} |
|
|
|
public void Draw(GameObject go, ActionBase comparer, string propertPath, Type[] accepatbleTypes, Action<GameObject> onSelectedGo, Action<string> onSelectedPath) |
|
{ |
|
var newGo = (GameObject)EditorGUILayout.ObjectField(m_Name, go, typeof(GameObject), true); |
|
if (newGo != go) |
|
onSelectedGo(newGo); |
|
|
|
if (go != null) |
|
{ |
|
var newPath = DrawListOfMethods(go, comparer, propertPath, accepatbleTypes, m_ThisDropDown); |
|
|
|
if (newPath != propertPath) |
|
onSelectedPath(newPath); |
|
} |
|
} |
|
|
|
private string DrawListOfMethods(GameObject go, ActionBase comparer, string propertPath, Type[] accepatbleTypes, DropDownControl<string> dropDown) |
|
{ |
|
string result = propertPath; |
|
if (accepatbleTypes == null) |
|
{ |
|
result = DrawManualPropertyEditField(go, propertPath, accepatbleTypes, dropDown); |
|
} |
|
else |
|
{ |
|
bool isPropertyOrFieldFound = true; |
|
if (string.IsNullOrEmpty(result)) |
|
{ |
|
var options = GetFieldsAndProperties(go, comparer, result, accepatbleTypes); |
|
isPropertyOrFieldFound = options.Any(); |
|
if (isPropertyOrFieldFound) |
|
{ |
|
result = options.First(); |
|
} |
|
} |
|
|
|
if (isPropertyOrFieldFound) |
|
{ |
|
dropDown.Draw(go.name + '.', result, |
|
() => |
|
{ |
|
try |
|
{ |
|
var options = GetFieldsAndProperties(go, comparer, result, accepatbleTypes); |
|
return options.ToArray(); |
|
} |
|
catch (Exception) |
|
{ |
|
Debug.LogWarning("An exception was thrown while resolving a property list. Resetting property path."); |
|
result = ""; |
|
return new string[0]; |
|
} |
|
}, s => result = s); |
|
} |
|
else |
|
{ |
|
result = DrawManualPropertyEditField(go, propertPath, accepatbleTypes, dropDown); |
|
} |
|
} |
|
return result; |
|
} |
|
|
|
private static List<string> GetFieldsAndProperties(GameObject go, ActionBase comparer, string extendPath, Type[] accepatbleTypes) |
|
{ |
|
var propertyResolver = new PropertyResolver {AllowedTypes = accepatbleTypes, ExcludedFieldNames = comparer.GetExcludedFieldNames()}; |
|
var options = propertyResolver.GetFieldsAndPropertiesFromGameObject(go, comparer.GetDepthOfSearch(), extendPath).ToList(); |
|
options.Sort((x, y) => |
|
{ |
|
if (char.IsLower(x[0])) |
|
return -1; |
|
if (char.IsLower(y[0])) |
|
return 1; |
|
return x.CompareTo(y); |
|
}); |
|
return options; |
|
} |
|
|
|
private string DrawManualPropertyEditField(GameObject go, string propertPath, Type[] acceptableTypes, DropDownControl<string> dropDown) |
|
{ |
|
var propertyResolver = new PropertyResolver { AllowedTypes = acceptableTypes }; |
|
IList<string> list; |
|
|
|
var loadProps = new Func<string[]>(() => |
|
{ |
|
try |
|
{ |
|
list = propertyResolver.GetFieldsAndPropertiesUnderPath(go, propertPath); |
|
} |
|
catch (ArgumentException) |
|
{ |
|
list = propertyResolver.GetFieldsAndPropertiesUnderPath(go, ""); |
|
} |
|
return list.ToArray(); |
|
}); |
|
|
|
EditorGUILayout.BeginHorizontal(); |
|
|
|
var labelSize = EditorStyles.label.CalcSize(new GUIContent(go.name + '.')); |
|
GUILayout.Label(go.name + (propertPath.Length > 0 ? "." : ""), EditorStyles.label, GUILayout.Width(labelSize.x)); |
|
|
|
string btnName = "hintBtn"; |
|
if (GUI.GetNameOfFocusedControl() == btnName |
|
&& Event.current.type == EventType.KeyDown |
|
&& Event.current.keyCode == KeyCode.DownArrow) |
|
{ |
|
Event.current.Use(); |
|
dropDown.PrintMenu(loadProps()); |
|
GUI.FocusControl(""); |
|
m_FocusBackToEdit = true; |
|
} |
|
|
|
EditorGUI.BeginChangeCheck(); |
|
GUI.SetNextControlName(btnName); |
|
var result = GUILayout.TextField(propertPath, EditorStyles.textField); |
|
if (EditorGUI.EndChangeCheck()) |
|
{ |
|
m_Error = DoesPropertyExist(go, result); |
|
} |
|
|
|
if (m_FocusBackToEdit) |
|
{ |
|
m_FocusBackToEdit = false; |
|
GUI.FocusControl(btnName); |
|
} |
|
|
|
if (GUILayout.Button("Clear", EditorStyles.miniButton, GUILayout.Width(38))) |
|
{ |
|
result = ""; |
|
GUI.FocusControl(null); |
|
m_FocusBackToEdit = true; |
|
m_Error = DoesPropertyExist(go, result); |
|
} |
|
EditorGUILayout.EndHorizontal(); |
|
EditorGUILayout.BeginHorizontal(); |
|
GUILayout.Label("", GUILayout.Width(labelSize.x)); |
|
|
|
dropDown.Draw("", result ?? "", loadProps, s => |
|
{ |
|
result = s; |
|
GUI.FocusControl(null); |
|
m_FocusBackToEdit = true; |
|
m_Error = DoesPropertyExist(go, result); |
|
}); |
|
EditorGUILayout.EndHorizontal(); |
|
|
|
switch (m_Error) |
|
{ |
|
case SelectedPathError.InvalidPath: |
|
EditorGUILayout.HelpBox("This property does not exist", MessageType.Error); |
|
break; |
|
case SelectedPathError.MissingComponent: |
|
EditorGUILayout.HelpBox("This property or field is not attached or set. It will fail unless it will be attached before the check is perfomed.", MessageType.Warning); |
|
break; |
|
} |
|
|
|
return result; |
|
} |
|
|
|
private SelectedPathError DoesPropertyExist(GameObject go, string propertPath) |
|
{ |
|
try |
|
{ |
|
object obj; |
|
if (MemberResolver.TryGetValue(go, propertPath, out obj)) |
|
return SelectedPathError.None; |
|
return SelectedPathError.InvalidPath; |
|
} |
|
catch (TargetInvocationException e) |
|
{ |
|
if (e.InnerException is MissingComponentException) |
|
return SelectedPathError.MissingComponent; |
|
throw; |
|
} |
|
} |
|
|
|
private enum SelectedPathError |
|
{ |
|
None, |
|
MissingComponent, |
|
InvalidPath |
|
} |
|
} |
|
}
|
|
|