namespace Sandbox.UI; public partial class Panel { /// /// A list of CSS classes applied to this panel. /// [Hide] public IEnumerable Class => _class ?? Enumerable.Empty(); /// internal HashSet _class; internal string _classes; /// /// All CSS classes applied to this panel, separated with spaces. /// [Property] public string Classes { get { if ( _classes == null ) _classes = string.Join( " ", Class ); return _classes; } set { _class?.Clear(); AddClass( value ); } } /// /// Adds CSS class(es) separated by spaces to this panel. /// public void AddClass( string classname ) { if ( string.IsNullOrWhiteSpace( classname ) ) return; if ( classname.Contains( ' ' ) ) { AddClasses( classname ); return; } classname = classname.ToLowerInvariant(); _class ??= new HashSet( StringComparer.OrdinalIgnoreCase ); if ( _class.Contains( classname ) ) return; _class.Add( classname ); _classes = null; // Adding a class changes the selector so children // may have rules that now match - need to update those too. StyleSelectorsChanged( true, true ); } /// /// Sets a specific CSS class active or not. /// public void SetClass( string classname, bool active ) { if ( string.IsNullOrWhiteSpace( classname ) ) return; if ( active ) AddClass( classname ); else RemoveClass( classname ); } /// /// Add a class for a set amount of seconds. If called multiple times, we will stomp the earlier call. /// public void FlashClass( string classname, float seconds ) { if ( string.IsNullOrWhiteSpace( classname ) ) return; AddClass( classname ); InvokeOnce( $"FlashClass;{classname}", seconds, () => RemoveClass( classname ) ); } /// /// Add a class if we don't have it, remove a class if we do have it /// public void ToggleClass( string classname ) { if ( string.IsNullOrWhiteSpace( classname ) ) return; SetClass( classname, !HasClass( classname ) ); } /// /// Add multiple CSS classes separated by spaces to this panel. /// void AddClasses( string classname ) { if ( string.IsNullOrWhiteSpace( classname ) ) return; foreach ( var cname in classname.Split( new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries ) ) { AddClass( cname ); } } /// /// Removes given CSS class from this panel. /// public void RemoveClass( string classname ) { if ( _class == null ) return; if ( string.IsNullOrWhiteSpace( classname ) ) return; if ( classname.Contains( ' ' ) ) { foreach ( var cname in classname.Split( new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries ) ) { RemoveClass( cname ); } return; } classname = classname.ToLowerInvariant(); if ( _class.Remove( classname ) ) { // Removing a class changes the selector so children // may have rules that now match - need to update those too. StyleSelectorsChanged( true, true ); _classes = null; } } /// /// Whether we have the given CSS class or not. /// public bool HasClass( string classname ) { if ( _class == null ) return false; if ( string.IsNullOrWhiteSpace( classname ) ) return false; if ( _class.Contains( classname ) ) return true; return false; } /// /// Whether if we have all of these CSS classes. /// internal bool HasClasses( string[] classes ) { if ( _class == null ) return false; for ( int i = 0; i < classes.Length; i++ ) { if ( !_class.Contains( classes[i] ) ) return false; } return true; } /// /// Dirty the styles on this panel /// internal void DirtyStylesRecursive() { StyleSelectorsChanged( true, true ); Style.InvalidateBroadphase(); } /// /// Dirty the styles of this class and its children recursively. /// internal void DirtyStylesWithStyle( Styles withStyles, bool skipTransitions = false ) { if ( Style.ContainsStyle( withStyles ) ) { Style.UnderlyingStyleHasChanged(); StyleSelectorsChanged( false, false ); if ( skipTransitions ) SkipTransitions(); } foreach ( var child in Children ) { child.DirtyStylesWithStyle( withStyles, skipTransitions ); } } Dictionary> classBinds; /// /// Switch the class on or off depending on the value of the bool. /// public void BindClass( string className, Func func ) { classBinds ??= new(); classBinds[className] = func; } private void RunClassBinds() { if ( classBinds is null ) return; foreach ( var c in classBinds ) { SetClass( c.Key, c.Value() ); } } }