// 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
}