// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Microsoft.Maui.Platform; /// /// Visual State Manager for Skia-rendered controls. /// Provides state-based styling through XAML VisualStateGroups. /// public static class SkiaVisualStateManager { /// /// Common visual state names. /// public static class CommonStates { public const string Normal = "Normal"; public const string Disabled = "Disabled"; public const string Focused = "Focused"; public const string PointerOver = "PointerOver"; public const string Pressed = "Pressed"; public const string Selected = "Selected"; public const string Checked = "Checked"; public const string Unchecked = "Unchecked"; public const string On = "On"; public const string Off = "Off"; } /// /// Attached property for VisualStateGroups. /// public static readonly BindableProperty VisualStateGroupsProperty = BindableProperty.CreateAttached( "VisualStateGroups", typeof(SkiaVisualStateGroupList), typeof(SkiaVisualStateManager), null, propertyChanged: OnVisualStateGroupsChanged); /// /// Gets the visual state groups for the specified view. /// public static SkiaVisualStateGroupList? GetVisualStateGroups(SkiaView view) { return (SkiaVisualStateGroupList?)view.GetValue(VisualStateGroupsProperty); } /// /// Sets the visual state groups for the specified view. /// public static void SetVisualStateGroups(SkiaView view, SkiaVisualStateGroupList? value) { view.SetValue(VisualStateGroupsProperty, value); } private static void OnVisualStateGroupsChanged(BindableObject bindable, object? oldValue, object? newValue) { if (bindable is SkiaView view) { // Detach old triggers if (oldValue is SkiaVisualStateGroupList oldGroups) { foreach (var group in oldGroups) { foreach (var state in group.States) { state.DetachTriggers(); } } } // Attach new triggers if (newValue is SkiaVisualStateGroupList groups) { foreach (var group in groups) { foreach (var state in group.States) { state.AttachTriggers(view); } } // Initialize to default state GoToState(view, CommonStates.Normal); } } } /// /// Transitions the view to the specified visual state. /// /// The view to transition. /// The name of the state to transition to. /// True if the state was found and applied, false otherwise. public static bool GoToState(SkiaView view, string stateName) { var groups = GetVisualStateGroups(view); if (groups == null || groups.Count == 0) return false; bool stateFound = false; foreach (var group in groups) { // Find the state in this group SkiaVisualState? targetState = null; foreach (var state in group.States) { if (state.Name == stateName) { targetState = state; break; } } if (targetState != null) { // Unapply current state if different if (group.CurrentState != null && group.CurrentState != targetState) { UnapplyState(view, group.CurrentState); } // Apply new state ApplyState(view, targetState); group.CurrentState = targetState; stateFound = true; } } return stateFound; } private static void ApplyState(SkiaView view, SkiaVisualState state) { foreach (var setter in state.Setters) { setter.Apply(view); } } private static void UnapplyState(SkiaView view, SkiaVisualState state) { foreach (var setter in state.Setters) { setter.Unapply(view); } } }