#if UNITY_EDITOR using UnityEditor; using UnityEngine; using RR.Common.Settings; namespace RR.Common.InspectorOverrides { [CustomPropertyDrawer(typeof(SettingEntry))] public class SettingEntryDrawer : PropertyDrawer { private const float Pad = 6f; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // Чтоб выглядело стабильнее в узких инспекторах bool prevWide = EditorGUIUtility.wideMode; float prevLabelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.wideMode = true; EditorGUIUtility.labelWidth = 110f; EditorGUI.BeginProperty(position, label, property); var keyProp = property.FindPropertyRelative("key"); var nameProp = property.FindPropertyRelative("displayName"); var descProp = property.FindPropertyRelative("description"); var groupProp = property.FindPropertyRelative("group"); var typeProp = property.FindPropertyRelative("valueType"); var defBoolProp = property.FindPropertyRelative("defaultBool"); var defIntProp = property.FindPropertyRelative("defaultInt"); var defFloatProp = property.FindPropertyRelative("defaultFloat"); var defStringProp = property.FindPropertyRelative("defaultString"); var minIntProp = property.FindPropertyRelative("minInt"); var maxIntProp = property.FindPropertyRelative("maxInt"); var minFloatProp = property.FindPropertyRelative("minFloat"); var maxFloatProp = property.FindPropertyRelative("maxFloat"); var applyProp = property.FindPropertyRelative("applyTarget"); var mixerProp = property.FindPropertyRelative("mixer"); var mixerParamProp = property.FindPropertyRelative("mixerParameter"); var minDbProp = property.FindPropertyRelative("minDb"); var maxDbProp = property.FindPropertyRelative("maxDb"); float line = EditorGUIUtility.singleLineHeight; float space = EditorGUIUtility.standardVerticalSpacing; // Card var box = new Rect(position.x, position.y, position.width, position.height); GUI.Box(box, GUIContent.none, EditorStyles.helpBox); var r = new Rect(position.x + Pad, position.y + Pad, position.width - Pad * 2, line); // Header foldout string header = BuildHeader(nameProp.stringValue, keyProp.stringValue); property.isExpanded = EditorGUI.Foldout(r, property.isExpanded, header, true); r.y += line + space; if (!property.isExpanded) { EditorGUI.EndProperty(); EditorGUIUtility.wideMode = prevWide; EditorGUIUtility.labelWidth = prevLabelWidth; return; } DrawSectionTitle(ref r, "Meta"); DrawProp(ref r, nameProp, "Display Name"); DrawProp(ref r, keyProp, "Key"); DrawProp(ref r, groupProp, "Group"); DrawProp(ref r, descProp, "Description", includeChildren: true); DrawSectionTitle(ref r, "Value"); DrawProp(ref r, typeProp, "Value Type"); var t = (SettingValueType)typeProp.enumValueIndex; switch (t) { case SettingValueType.Bool: DrawProp(ref r, defBoolProp, "Default"); break; case SettingValueType.Int: DrawProp(ref r, defIntProp, "Default"); DrawMinMaxRow(ref r, minIntProp, maxIntProp, "Min", "Max"); break; case SettingValueType.Float: DrawProp(ref r, defFloatProp, "Default"); DrawMinMaxRow(ref r, minFloatProp, maxFloatProp, "Min", "Max"); break; case SettingValueType.String: DrawProp(ref r, defStringProp, "Default"); break; case SettingValueType.Button: DrawSectionTitle(ref r, "Button Settings"); var buttonTextProp = property.FindPropertyRelative("buttonText"); var buttonDataProp = property.FindPropertyRelative("buttonData"); var buttonColorProp = property.FindPropertyRelative("buttonColor"); var buttonSpriteProp = property.FindPropertyRelative("buttonSprite"); DrawProp(ref r, buttonTextProp, "Button Text"); DrawProp(ref r, buttonDataProp, "Button Data"); DrawProp(ref r, buttonColorProp, "Button Color"); DrawProp(ref r, buttonSpriteProp, "Button Sprite"); break; case SettingValueType.OptionPicker: DrawSectionTitle(ref r, "Option Picker Settings"); var optionsProp = property.FindPropertyRelative("options"); var defOptionIndexProp = property.FindPropertyRelative("defaultOptionIndex"); DrawProp(ref r, optionsProp, "Options", includeChildren: true); DrawProp(ref r, defOptionIndexProp, "Default Index"); break; } DrawSectionTitle(ref r, "Apply"); DrawProp(ref r, applyProp, "Apply Target"); var apply = (ApplyTarget)applyProp.enumValueIndex; if (apply == ApplyTarget.AudioMixerFloat01ToDb) { DrawProp(ref r, mixerProp, "Audio Mixer"); DrawProp(ref r, mixerParamProp, "Exposed Param"); DrawMinMaxRow(ref r, minDbProp, maxDbProp, "Min dB", "Max dB"); } // Warning if (string.IsNullOrWhiteSpace(keyProp.stringValue)) { var warnH = line * 1.4f; var warn = new Rect(r.x, r.y, r.width, warnH); EditorGUI.HelpBox(warn, "Key is empty - setting won't work.", MessageType.Warning); r.y += warnH + space; } EditorGUI.EndProperty(); // restore EditorGUIUtility.wideMode = prevWide; EditorGUIUtility.labelWidth = prevLabelWidth; } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { float line = EditorGUIUtility.singleLineHeight; float space = EditorGUIUtility.standardVerticalSpacing; float h = 0f; // padding + foldout h += Pad * 2; h += line + space; if (!property.isExpanded) return h + 2f; SerializedProperty keyProp = property.FindPropertyRelative("key"); SerializedProperty nameProp = property.FindPropertyRelative("displayName"); SerializedProperty groupProp = property.FindPropertyRelative("group"); SerializedProperty descProp = property.FindPropertyRelative("description"); SerializedProperty typeProp = property.FindPropertyRelative("valueType"); SerializedProperty applyProp = property.FindPropertyRelative("applyTarget"); // Meta section title h += line + space; h += HeightOf(nameProp) + space; h += HeightOf(keyProp) + space; h += HeightOf(groupProp) + space; h += HeightOf(descProp, true) + space; // Value section title h += line + space; h += HeightOf(typeProp) + space; // Default + optional range row SettingValueType t = (SettingValueType)typeProp.enumValueIndex; switch (t) { case SettingValueType.Bool: case SettingValueType.String: h += line + space; // Default break; case SettingValueType.Int: case SettingValueType.Float: h += line + space; // Default h += line + space; // range row break; case SettingValueType.Button: h += line + space; // section title h += line + space; // buttonText h += line + space; // buttonData h += line + space; // buttonColor h += line + space; // buttonSprite break; case SettingValueType.OptionPicker: h += line + space; // section title var optionsProp = property.FindPropertyRelative("options"); h += HeightOf(optionsProp, true) + space; // options list h += line + space; // defaultOptionIndex break; } // Apply section title h += line + space; h += HeightOf(applyProp) + space; ApplyTarget apply = (ApplyTarget)applyProp.enumValueIndex; if (apply == ApplyTarget.AudioMixerFloat01ToDb) { h += line + space; // mixer h += line + space; // param h += line + space; // db row } if (string.IsNullOrWhiteSpace(keyProp.stringValue)) h += line * 1.4f + space; return h + 6f; } private static float HeightOf(SerializedProperty prop, bool includeChildren = false) => EditorGUI.GetPropertyHeight(prop, includeChildren); private static void DrawProp(ref Rect r, SerializedProperty prop, string label, bool includeChildren = false) { float space = EditorGUIUtility.standardVerticalSpacing; GUIContent gc = new(label); float h = EditorGUI.GetPropertyHeight(prop, gc, includeChildren); Rect rect = new(r.x, r.y, r.width, h); EditorGUI.PropertyField(rect, prop, gc, includeChildren); r.y += h + space; } private static void DrawSectionTitle(ref Rect r, string title) { float line = EditorGUIUtility.singleLineHeight; float space = EditorGUIUtility.standardVerticalSpacing; Rect rect = new(r.x, r.y, r.width, line); EditorGUI.LabelField(rect, title, EditorStyles.boldLabel); r.y += line + space; } private static void DrawMinMaxRow(ref Rect r, SerializedProperty leftProp, SerializedProperty rightProp, string leftLabel, string rightLabel) { float line = EditorGUIUtility.singleLineHeight; float space = EditorGUIUtility.standardVerticalSpacing; float gap = 10f; float half = (r.width - gap) * 0.5f; Rect left = new(r.x, r.y, half, line); Rect right = new(r.x + half + gap, r.y, half, line); EditorGUI.PropertyField(left, leftProp, new GUIContent(leftLabel)); EditorGUI.PropertyField(right, rightProp, new GUIContent(rightLabel)); r.y += line + space; } private static string BuildHeader(string displayName, string key) { if (!string.IsNullOrWhiteSpace(displayName) && !string.IsNullOrWhiteSpace(key)) return $"{displayName} ({key})"; if (!string.IsNullOrWhiteSpace(displayName)) return displayName; return !string.IsNullOrWhiteSpace(key) ? key : "Setting"; } } } #endif