You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
CrowdControl/Assets/Plugins/NaughtyAttributes/Scripts/Editor/PropertyDrawers/DropdownPropertyDrawer.cs

177 lines
5.2 KiB
C#

2 months ago
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Reflection;
using System;
using System.Collections.Generic;
namespace NaughtyAttributes.Editor
{
[CustomPropertyDrawer(typeof(DropdownAttribute))]
public class DropdownPropertyDrawer : PropertyDrawerBase
{
protected override float GetPropertyHeight_Internal(SerializedProperty property, GUIContent label)
{
DropdownAttribute dropdownAttribute = (DropdownAttribute)attribute;
object values = GetValues(property, dropdownAttribute.ValuesName);
FieldInfo fieldInfo = ReflectionUtility.GetField(PropertyUtility.GetTargetObjectWithProperty(property), property.name);
float propertyHeight = AreValuesValid(values, fieldInfo)
? GetPropertyHeight(property)
: GetPropertyHeight(property) + GetHelpBoxHeight();
return propertyHeight;
}
protected override void OnGUI_Internal(Rect rect, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(rect, label, property);
DropdownAttribute dropdownAttribute = (DropdownAttribute)attribute;
object target = PropertyUtility.GetTargetObjectWithProperty(property);
object valuesObject = GetValues(property, dropdownAttribute.ValuesName);
FieldInfo dropdownField = ReflectionUtility.GetField(target, property.name);
if (AreValuesValid(valuesObject, dropdownField))
{
if (valuesObject is IList && dropdownField.FieldType == GetElementType(valuesObject))
{
// Selected value
object selectedValue = dropdownField.GetValue(target);
// Values and display options
IList valuesList = (IList)valuesObject;
object[] values = new object[valuesList.Count];
string[] displayOptions = new string[valuesList.Count];
for (int i = 0; i < values.Length; i++)
{
object value = valuesList[i];
values[i] = value;
displayOptions[i] = value == null ? "<null>" : value.ToString();
}
// Selected value index
int selectedValueIndex = Array.IndexOf(values, selectedValue);
if (selectedValueIndex < 0)
{
selectedValueIndex = 0;
}
NaughtyEditorGUI.Dropdown(
rect, property.serializedObject, target, dropdownField, label.text, selectedValueIndex, values, displayOptions);
}
else if (valuesObject is IDropdownList)
{
// Current value
object selectedValue = dropdownField.GetValue(target);
// Current value index, values and display options
int index = -1;
int selectedValueIndex = -1;
List<object> values = new List<object>();
List<string> displayOptions = new List<string>();
IDropdownList dropdown = (IDropdownList)valuesObject;
using (IEnumerator<KeyValuePair<string, object>> dropdownEnumerator = dropdown.GetEnumerator())
{
while (dropdownEnumerator.MoveNext())
{
index++;
KeyValuePair<string, object> current = dropdownEnumerator.Current;
if (current.Value?.Equals(selectedValue) == true)
{
selectedValueIndex = index;
}
values.Add(current.Value);
if (current.Key == null)
{
displayOptions.Add("<null>");
}
else if (string.IsNullOrWhiteSpace(current.Key))
{
displayOptions.Add("<empty>");
}
else
{
displayOptions.Add(current.Key);
}
}
}
if (selectedValueIndex < 0)
{
selectedValueIndex = 0;
}
NaughtyEditorGUI.Dropdown(
rect, property.serializedObject, target, dropdownField, label.text, selectedValueIndex, values.ToArray(), displayOptions.ToArray());
}
}
else
{
string message = string.Format("Invalid values with name '{0}' provided to '{1}'. Either the values name is incorrect or the types of the target field and the values field/property/method don't match",
dropdownAttribute.ValuesName, dropdownAttribute.GetType().Name);
DrawDefaultPropertyAndHelpBox(rect, property, message, MessageType.Warning);
}
EditorGUI.EndProperty();
}
private object GetValues(SerializedProperty property, string valuesName)
{
object target = PropertyUtility.GetTargetObjectWithProperty(property);
FieldInfo valuesFieldInfo = ReflectionUtility.GetField(target, valuesName);
if (valuesFieldInfo != null)
{
return valuesFieldInfo.GetValue(target);
}
PropertyInfo valuesPropertyInfo = ReflectionUtility.GetProperty(target, valuesName);
if (valuesPropertyInfo != null)
{
return valuesPropertyInfo.GetValue(target);
}
MethodInfo methodValuesInfo = ReflectionUtility.GetMethod(target, valuesName);
if (methodValuesInfo != null &&
methodValuesInfo.ReturnType != typeof(void) &&
methodValuesInfo.GetParameters().Length == 0)
{
return methodValuesInfo.Invoke(target, null);
}
return null;
}
private bool AreValuesValid(object values, FieldInfo dropdownField)
{
if (values == null || dropdownField == null)
{
return false;
}
if ((values is IList && dropdownField.FieldType == GetElementType(values)) ||
(values is IDropdownList))
{
return true;
}
return false;
}
private Type GetElementType(object values)
{
Type valuesType = values.GetType();
Type elementType = ReflectionUtility.GetListElementType(valuesType);
return elementType;
}
}
}