using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityEngine.UI; namespace Plugins.Animate_UI_Materials.Editor { using PropertyType = ShaderUtil.ShaderPropertyType; [CustomEditor(typeof(GraphicPropertyOverride), true)] [CanEditMultipleObjects] public class GraphicPropertyOverrideEditor : UnityEditor.Editor { SerializedProperty _propertyName; SerializedProperty _propertyValue; void OnEnable() { // Get the serializedProperty of the shader property name _propertyName = serializedObject.FindProperty("propertyName"); // Get the serializedProperty of the shader property propertyValue _propertyValue = serializedObject.FindProperty("propertyValue"); } public override void OnInspectorGUI() { serializedObject.Update(); // Draw the script header using (new EditorGUI.DisabledScope(true)) EditorGUILayout.PropertyField(serializedObject.FindProperty("m_Script")); // Start change check using EditorGUI.ChangeCheckScope scope = new(); // If single target (not multi-editing) if (targets.Length == 1) { // Draw a warning if the material cannot be found if (!GetTargetMaterial()) EditorGUILayout.HelpBox( "The parent doesn't contain a GraphicMaterialOverride. Add one to continue", MessageType.Error); string[] properties = GetPropertyNames().ToArray(); // Draw a dropdown list of float properties in the material EditorGUI.BeginChangeCheck(); int currentIndex = GetPropertyIndexDropdown(); int index = EditorGUILayout.Popup("Property Name", currentIndex, properties); if (EditorGUI.EndChangeCheck()) _propertyName.stringValue = properties[index]; } else { EditorGUILayout.LabelField("Cannot multi-edit property name"); } DrawPropertiesExcluding(serializedObject, "m_Script", "propertyName", "propertyValue"); DrawValueProperty(_propertyValue); // If change happened, apply modified properties if (scope.changed) serializedObject.ApplyModifiedProperties(); } /// /// Overridable method to draw the value property /// Overriden by GraphicPropertyOverrideRange to display ranges /// protected virtual void DrawValueProperty(SerializedProperty property) { EditorGUILayout.PropertyField(property); } /// /// Try to get the material of the associated Graphic object /// /// The material being overriden or null protected Material GetTargetMaterial() { GraphicPropertyOverride animated = (GraphicPropertyOverride)target; return animated.transform.parent.TryGetComponent(out Graphic graphic) ? graphic.material : null; } /// /// Get the property type from the target object /// /// protected PropertyType GetPropertyType() { GraphicPropertyOverride animated = (GraphicPropertyOverride)target; return animated switch { GraphicPropertyOverrideColor => PropertyType.Color, GraphicPropertyOverrideFloat => PropertyType.Float, GraphicPropertyOverrideVector => PropertyType.Vector, GraphicPropertyOverrideInt => PropertyType.Int, GraphicPropertyOverrideRange => PropertyType.Range, GraphicPropertyOverrideTexture => PropertyType.TexEnv, GraphicPropertyOverrideScaleAndOffset => PropertyType.TexEnv, _ when target != null => throw new Exception($"Unknown type {target.GetType()}"), _ => throw new Exception($"Target is null"), }; } /// /// Get the index inside the filtered dropdown /// /// The index, or -1 in case of invalid property int GetPropertyIndexDropdown() { string propertyName = _propertyName.stringValue; return GetPropertyNames() .FindIndex(dropdownOptionName => dropdownOptionName == propertyName); } /// /// Get the index of the property in the shade /// /// The index of the property or -1 in vase of invalid property protected int GetPropertyIndex() { Material material = GetTargetMaterial(); string propertyName = _propertyName.stringValue; return ShaderPropertyInfo.GetMaterialProperties(material) .Find(p => p.name == propertyName) ?.index ?? -1; } /// /// Get all matching properties from the shader /// /// List GetPropertyNames() { Material material = GetTargetMaterial(); PropertyType type = GetPropertyType(); return ShaderPropertyInfo.GetMaterialProperties(material) .Where(p => p.type == type) .Select(p => p.name) .ToList(); } /// /// Override the reset context menu to implement the reset function /// Needed instead of "MonoBehavior.Reset" on GraphicMaterialOverride because Reset is called in other contexts /// [MenuItem("CONTEXT/GraphicPropertyOverride/Reset")] static void ResetPropertyValue(MenuCommand b) { if (b.context is not GraphicPropertyOverride propertyOverride) return; Undo.RecordObject(propertyOverride, "Reset material override"); propertyOverride.ResetPropertyToDefault(); PrefabUtility.RecordPrefabInstancePropertyModifications(propertyOverride); } } }