Files

118 lines
4.2 KiB
C#

using EditorAttributes.Editor.Utility;
using System;
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace EditorAttributes.Editor
{
[CustomPropertyDrawer(typeof(UnitFieldAttribute))]
public class UnitFieldDrawer : PropertyDrawerBase
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
var unitFieldAttribute = attribute as UnitFieldAttribute;
var root = CreatePropertyField(property);
var convertedUnit = UnitConverter.GetConversion(unitFieldAttribute.DisplayUnit, unitFieldAttribute.ConversionUnit);
if (convertedUnit == null)
{
var errorBox = new HelpBox
{
text = $"No conversion found for <b>{unitFieldAttribute.DisplayUnit}</b> to <b>{unitFieldAttribute.ConversionUnit}</b>. You can add custom conversions in the <b>ProjectSettings/EditorAttributes</b> window"
};
DisplayErrorBox(root, errorBox);
return root;
}
// Wait for Unity fields to be setup.
root.RegisterCallback<GeometryChangedEvent>(OnGeometryChanged);
void OnGeometryChanged(GeometryChangedEvent changeEvent)
{
root.UnregisterCallback<GeometryChangedEvent>(OnGeometryChanged);
// This will query into all types that implement these numerics.
// For example, the Unit attribute will also work with the three
// float inputs in a Vector3 property drawer.
root.Query<BindableElement>(className: TextInputBaseField<Void>.ussClassName).ForEach((element) =>
{
// We create the field copy after 25ms because otherwise the built
// in property field automatically cleans manually created elements.
ExecuteLater(root, () =>
{
var fieldCopy = CreateFieldCopy(element, property, unitFieldAttribute);
if (fieldCopy == null)
return;
element.style.display = DisplayStyle.None;
element.parent.Add(fieldCopy);
if (CanApplyGlobalColor)
ColorUtils.ApplyColor(fieldCopy, EditorExtension.GLOBAL_COLOR);
fieldCopy.PlaceInFront(element);
fieldCopy.AddToClassList(BaseField<Void>.alignedFieldUssClassName);
var children = element.Query().Build();
var childrenCopies = fieldCopy.Query().Build();
for (int i = 0; i < children.Count(); i++)
CopyStyle(childrenCopies.AtIndex(i), children.AtIndex(i));
var textCopy = fieldCopy.Q(className: TextInputBaseField<Void>.inputUssClassName).Q<TextElement>();
textCopy.style.flexGrow = 0;
textCopy.style.flexShrink = 1;
var suffix = new Label(convertedUnit.unitLabel)
{
focusable = false,
tooltip = unitFieldAttribute.DisplayUnit,
style =
{
color = CanApplyGlobalColor ? EditorExtension.GLOBAL_COLOR : Color.gray,
unityFontDefinition = textCopy.style.unityFontDefinition,
unityTextAlign = TextAnchor.MiddleRight,
flexGrow = 1f,
flexShrink = 1f,
paddingLeft = 1f
},
};
textCopy.parent.Add(suffix);
}, 25L);
});
}
return root;
}
private VisualElement CreateFieldCopy(BindableElement element, SerializedProperty property, UnitFieldAttribute unitFieldAttribute)
{
var convertedUnit = UnitConverter.GetConversion(unitFieldAttribute.DisplayUnit, unitFieldAttribute.ConversionUnit);
var propertyInfo = ReflectionUtility.GetValidMemberInfo(property.name, property);
var propertyType = ReflectionUtility.GetMemberInfoType(propertyInfo);
if (propertyType == null)
return null;
var elementCopy = CreateFieldForType(propertyType, GetFieldLabel(element), Convert.ChangeType(Convert.ToDouble(GetFieldValue(element)) / convertedUnit.conversion, propertyType), property.hasMultipleDifferentValues);
RegisterValueChangedCallbackByType(propertyType, elementCopy, (changeEvent) => SetFieldValue(element, Convert.ChangeType(Convert.ToDouble(GetFieldValue(elementCopy)) * convertedUnit.conversion, propertyType), true));
element.TrackPropertyValue(property, (trackedProperty) => SetFieldValue(elementCopy, Convert.ChangeType(Convert.ToDouble(GetFieldValue(element)) / convertedUnit.conversion, propertyType)));
return elementCopy;
}
}
}