// MIT License - Copyright (c) 2025 wallstop // Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE namespace WallstopStudios.UnityHelpers.Editor.Styles { #if UNITY_EDITOR using UnityEditor; using UnityEngine; using UnityEngine.UIElements; using WallstopStudios.UnityHelpers.Core.Helper; /// /// Provides lazy loading and caching of USS stylesheets for dropdown components. /// Stylesheets are loaded on first access and cached for the editor session. /// public static class WDropDownStyleLoader { private const string StylesRelativePath = "Editor/Styles/DropDowns/"; private const string VariablesFileName = "WDropDownVariables.uss"; private const string StylesFileName = "WDropDownStyles.uss"; private const string LightThemeFileName = "WDropDownLight.uss"; private static StyleSheet _variablesStyleSheet; private static StyleSheet _stylesStyleSheet; private static StyleSheet _lightThemeStyleSheet; private static bool _initialized; /// /// Gets the variables stylesheet containing CSS custom properties. /// public static StyleSheet Variables { get { EnsureInitialized(); return _variablesStyleSheet; } } /// /// Gets the main styles stylesheet. /// public static StyleSheet Styles { get { EnsureInitialized(); return _stylesStyleSheet; } } /// /// Gets the light theme override stylesheet. /// public static StyleSheet LightTheme { get { EnsureInitialized(); return _lightThemeStyleSheet; } } /// /// Returns true if the current editor is using the Pro (dark) skin. /// public static bool IsProSkin => EditorGUIUtility.isProSkin; /// /// Applies all dropdown stylesheets to a visual element in the correct order. /// Automatically selects the appropriate theme based on the current editor skin. /// /// The element to apply styles to. public static void ApplyStyles(VisualElement element) { if (element == null) { return; } EnsureInitialized(); // Apply base variables first if (_variablesStyleSheet != null && !element.styleSheets.Contains(_variablesStyleSheet)) { element.styleSheets.Add(_variablesStyleSheet); } // Apply main styles if (_stylesStyleSheet != null && !element.styleSheets.Contains(_stylesStyleSheet)) { element.styleSheets.Add(_stylesStyleSheet); } // Apply theme override if using light theme if ( !IsProSkin && _lightThemeStyleSheet != null && !element.styleSheets.Contains(_lightThemeStyleSheet) ) { element.styleSheets.Add(_lightThemeStyleSheet); } } /// /// Removes all dropdown stylesheets from a visual element. /// /// The element to remove styles from. public static void RemoveStyles(VisualElement element) { if (element == null) { return; } if (_variablesStyleSheet != null && element.styleSheets.Contains(_variablesStyleSheet)) { element.styleSheets.Remove(_variablesStyleSheet); } if (_stylesStyleSheet != null && element.styleSheets.Contains(_stylesStyleSheet)) { element.styleSheets.Remove(_stylesStyleSheet); } if ( _lightThemeStyleSheet != null && element.styleSheets.Contains(_lightThemeStyleSheet) ) { element.styleSheets.Remove(_lightThemeStyleSheet); } } /// /// Forces a reload of all stylesheets. Call this if styles are modified at runtime. /// public static void ReloadStyles() { _initialized = false; _variablesStyleSheet = null; _stylesStyleSheet = null; _lightThemeStyleSheet = null; EnsureInitialized(); } private static void EnsureInitialized() { if (_initialized) { return; } _variablesStyleSheet = LoadStyleSheet(VariablesFileName); _stylesStyleSheet = LoadStyleSheet(StylesFileName); _lightThemeStyleSheet = LoadStyleSheet(LightThemeFileName); _initialized = true; } private static StyleSheet LoadStyleSheet(string fileName) { // Use DirectoryHelper to resolve the path regardless of package installation location string path = DirectoryHelper.ResolvePackageAssetPath(StylesRelativePath + fileName); StyleSheet styleSheet = null; if (!string.IsNullOrEmpty(path)) { styleSheet = AssetDatabase.LoadAssetAtPath(path); } if (styleSheet == null) { Debug.LogWarning( $"[WDropDownStyleLoader] Could not load stylesheet: '{StylesRelativePath + fileName}' (resolved path: '{path}')" ); } return styleSheet; } /// /// USS class names for dropdown components. /// Use these constants when adding/removing classes from visual elements. /// public static class ClassNames { // Container public const string Popup = "w-dropdown-popup"; // Search public const string SearchContainer = "w-dropdown-search-container"; public const string SearchWrapper = "w-dropdown-search-wrapper"; public const string Search = "w-dropdown-search"; public const string SearchIcon = "w-dropdown-search-icon"; public const string ClearButton = "w-dropdown-clear-button"; // Options public const string OptionsContainer = "w-dropdown-options-container"; public const string Option = "w-dropdown-option"; public const string OptionSelected = "w-dropdown-option--selected"; public const string OptionHover = "w-dropdown-option--hover"; public const string OptionFocused = "w-dropdown-option--focused"; public const string OptionLabel = "w-dropdown-option-label"; public const string OptionIndicator = "w-dropdown-option-indicator"; // Pagination public const string Pagination = "w-dropdown-pagination"; public const string PaginationButton = "w-dropdown-pagination-button"; public const string PaginationLabel = "w-dropdown-pagination-label"; // Misc public const string Suggestion = "w-dropdown-suggestion"; public const string NoResults = "w-dropdown-no-results"; public const string Button = "w-dropdown-button"; public const string ButtonLabel = "w-dropdown-button-label"; public const string ButtonArrow = "w-dropdown-button-arrow"; // Animation public const string FadeIn = "w-dropdown-fade-in"; public const string FadeOut = "w-dropdown-fade-out"; } } #endif }