// MIT License - Copyright (c) 2025 wallstop // Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE namespace WallstopStudios.UnityHelpers.Editor.CustomDrawers.Base { #if UNITY_EDITOR using UnityEditor; using UnityEngine; using UnityEngine.UIElements; using WallstopStudios.UnityHelpers.Editor.Settings; /// /// Base class for UI Toolkit popup dropdown selectors that use IMGUI rendering /// via IMGUIContainer for displaying large option lists with a popup window. /// /// The type of the field value (string, int, etc.). public abstract class WDropDownPopupSelectorBase : BaseField { private SerializedObject _serializedObject; private string _propertyPath = string.Empty; private GUIContent _labelContent = GUIContent.none; private readonly GUIContent _buttonContent = new(); private int _pageSize; /// /// Gets the total number of options available. /// protected abstract int OptionCount { get; } /// /// Gets the display value to show on the popup button for the current property state. /// /// The serialized property. /// The display string for the button. protected abstract string GetDisplayValue(SerializedProperty property); /// /// Gets the value to set via SetValueWithoutNotify. /// /// The serialized property. /// The value to set on the field. protected abstract TValue GetFieldValue(SerializedProperty property); /// /// Shows the popup window for selecting from the options. /// /// The rect of the control that triggered the popup. /// The serialized property being edited. /// The page size for pagination. protected abstract void ShowPopup( Rect controlRect, SerializedProperty property, int pageSize ); private static VisualElement CreateInputElement(out IMGUIContainer container) { container = new IMGUIContainer(); return container; } protected WDropDownPopupSelectorBase() : base(string.Empty, CreateInputElement(out IMGUIContainer container)) { AddToClassList("unity-base-field"); AddToClassList("unity-base-field__aligned"); labelElement.AddToClassList("unity-base-field__label"); labelElement.AddToClassList("unity-label"); _pageSize = Mathf.Max(1, UnityHelpersSettings.GetStringInListPageLimit()); container.style.flexGrow = 1f; container.style.marginLeft = 0f; container.style.paddingLeft = 0f; container.onGUIHandler = OnGUIHandler; } /// /// Binds this selector to a serialized property. /// /// The property to bind. /// The label text to display. public void BindProperty(SerializedProperty property, string labelText) { _serializedObject = property?.serializedObject; _propertyPath = property?.propertyPath ?? string.Empty; string resolvedLabel = labelText ?? property?.displayName ?? property?.name ?? string.Empty; label = resolvedLabel; _labelContent = new GUIContent(resolvedLabel); } /// /// Unbinds this selector from any property. /// public void UnbindProperty() { _serializedObject = null; _propertyPath = string.Empty; } private void OnGUIHandler() { if (_serializedObject == null || string.IsNullOrEmpty(_propertyPath)) { return; } _serializedObject.UpdateIfRequiredOrScript(); SerializedProperty property = _serializedObject.FindProperty(_propertyPath); if (property == null) { return; } string displayValue = GetDisplayValue(property); SetValueWithoutNotify(GetFieldValue(property)); Rect controlRect = EditorGUILayout.GetControlRect(); int resolvedPageSize = Mathf.Max(1, UnityHelpersSettings.GetStringInListPageLimit()); if (resolvedPageSize != _pageSize) { _pageSize = resolvedPageSize; } _buttonContent.text = displayValue; if (EditorGUI.DropdownButton(controlRect, _buttonContent, FocusType.Keyboard)) { ShowPopup(controlRect, property, _pageSize); } _serializedObject.ApplyModifiedProperties(); } } #endif }