Transform selection controls from dropdowns to designer-friendly interfaces.
Unity Helpers provides four powerful selection attributes that replace standard dropdowns with toggle buttons, searchable lists, and type-safe selection controls. Perfect for flags, enums, predefined values, and dynamic option lists.
// Automatic layout (fits to inspector width)[WEnumToggleButtons]publicPermissionsautoLayout;// Force 2 columns[WEnumToggleButtons(buttonsPerRow: 2)]publicPermissionstwoColumns;// Force single column[WEnumToggleButtons(buttonsPerRow: 1)]publicPermissionssingleColumn;
Visual Reference
Different column layouts: automatic, 2 columns, and single column
// Works with IntDropDown/StringInList/WValueDropDown![IntDropDown(0, 30, 60, 120)][WEnumToggleButtons]publicintframeRate=60;// Shows as toggle buttons instead of dropdown
The drawer intentionally filters out composite flag values (e.g., ReadWrite = Read | Write). This keeps the UI focused on atomic toggles and avoids ambiguous interactions. Use the "Select All" and "Select None" buttons for bulk operations.
publicclassDynamicOptions:MonoBehaviour{publicstringprefix="Option";publicintoptionCount=5;// Instance method - uses object state to build options[WValueDropDown(nameof(GetAvailableOptions), typeof(string))]publicstringselectedOption;privateIEnumerable<string>GetAvailableOptions(){for(inti=1;i<=optionCount;i++){yieldreturn$"{prefix}_{i}";}}}
Passing only a method name instructs the drawer to search the decorated type for a parameterless method. Instance methods run on the serialized object; static methods are also supported. The second parameter specifies the value type for proper dropdown rendering.
// Form 1: Instance method with explicit value type[WValueDropDown(nameof(GetOptions), typeof(int))]publicintselection;// Form 2: Static provider from external type[WValueDropDown(typeof(DataProvider), nameof(DataProvider.GetItems))]publicItemselected;// Form 3: Static provider with explicit value type conversion[WValueDropDown(typeof(DataProvider), nameof(DataProvider.GetIds), typeof(int))]publicintselectedId;
usingSystem;usingSystem.Collections.Generic;usingUnityEngine;usingWallstopStudios.UnityHelpers.Core.Attributes;[Serializable]publicclassPreset{publicstringname;publicfloatvalue;publicoverridestringToString()=>name;// Used for dropdown label}publicclassConfig:MonoBehaviour{[WValueDropDown(typeof(Config), nameof(GetPresets))]publicPresetselectedPreset;publicstaticIEnumerable<Preset>GetPresets(){returnnew[]{newPreset{name="Low",value=0.5f},newPreset{name="Medium",value=1.0f},newPreset{name="High",value=2.0f},};}}
Visual Reference
Dropdown showing custom serializable class options using ToString() for labels
publicclassStateMachine:MonoBehaviour{[StringInList(nameof(BuildAvailableStates))]publicstringcurrentState;privateIEnumerable<string>BuildAvailableStates(){// Instance data drives the dropdownyieldreturn$"{gameObject.name}_Idle";yieldreturn$"{gameObject.name}_Run";}publicstaticIEnumerable<string>StaticStates(){// Static helpers still work when referenced by namereturnnew[]{"Global_A","Global_B"};}}
Passing only a method name instructs the drawer to search the decorated type for a parameterless method. Instance methods run on the serialized object; static methods are also supported.
[StringInList(typeof(SceneLibrary), nameof(SceneLibrary.GetAllSceneNames))]publicstringtargetScene;publicstaticclassSceneLibrary{publicstaticIEnumerable<string>GetAllSceneNames(){// Return 100+ scene namesreturnEditorBuildSettings.scenes.Select(s=>s.path);}}
When the menu contains more entries than the configured limit, clicking the field opens a popup that embeds the search bar and pagination controls directly in the dropdown itself. The inspector row remains single-line, but the popup still supports fast filtering and page navigation.
Visual Reference
Popup window with a search box filtering results in real-time
Features:
Dedicated popup hosts search + pagination when the option count exceeds UnityHelpersSettings.StringInListPageLimit
Inspector row stays single-line; the popup includes filtering, paging, and keyboard navigation
Works in both IMGUI and UI Toolkit inspectors (including SerializableTypeDrawer)
Accepts fixed lists, static provider methods, or instance provider methods resolved on the component
// ✅ GOOD: WEnumToggleButtons for flags (visual toggle state)[System.Flags]publicenumFeatures{None=0,Feature1=1,Feature2=2,Feature3=4}[WEnumToggleButtons]publicFeaturesenabledFeatures;// ✅ GOOD: WValueDropDown for fixed type-safe options[WValueDropDown(0.5f, 1.0f, 1.5f, 2.0f)]publicfloatspeedMultiplier;// ✅ GOOD: IntDropDown for integer-specific options[IntDropDown(30, 60, 120, 240)]publicintframeRate;// ✅ GOOD: StringInList for string validation[StringInList("Easy", "Normal", "Hard")]publicstringdifficulty;// ❌ BAD: Using strings when enum would be better[StringInList("Easy", "Normal", "Hard")]publicstringdifficulty;// Should be an enum!
// ✅ GOOD: Provider method for data that changes[WValueDropDown(typeof(AssetDatabase), nameof(GetAllPrefabs))]publicGameObjectprefab;publicstaticIEnumerable<GameObject>GetAllPrefabs(){returnResources.LoadAll<GameObject>("Prefabs");}// ❌ BAD: Hardcoded values for dynamic data[WValueDropDown/* hardcoded list of 50 prefabs */]publicGameObjectprefab;// Nightmare to maintain!
// ✅ GOOD: Select All/None for flag enums[System.Flags]publicenumPermissions{None=0,Read=1,Write=2,Execute=4}[WEnumToggleButtons(showSelectAll: true, showSelectNone: true)]publicPermissionspermissions;// ✅ GOOD: Pagination for many options[WEnumToggleButtons(enablePagination: true, pageSize: 10)]publicManyOptionsEnumoptions;// ❌ BAD: No pagination with 50 options (cluttered inspector!)[WEnumToggleButtons(enablePagination: false)]publicManyOptionsEnumoptions;