// 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 && newValue is SkiaVisualStateGroupList groups) { // 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); } } } /// /// A list of visual state groups. /// public class SkiaVisualStateGroupList : List { } /// /// A group of mutually exclusive visual states. /// public class SkiaVisualStateGroup { /// /// Gets or sets the name of this group. /// public string Name { get; set; } = ""; /// /// Gets the collection of states in this group. /// public List States { get; } = new(); /// /// Gets or sets the currently active state. /// public SkiaVisualState? CurrentState { get; set; } } /// /// Represents a single visual state with its setters. /// public class SkiaVisualState { /// /// Gets or sets the name of this state. /// public string Name { get; set; } = ""; /// /// Gets the collection of setters for this state. /// public List Setters { get; } = new(); } /// /// Sets a property value when a visual state is active. /// public class SkiaVisualStateSetter { /// /// Gets or sets the property to set. /// public BindableProperty? Property { get; set; } /// /// Gets or sets the value to set. /// public object? Value { get; set; } // Store original value for unapply private object? _originalValue; private bool _hasOriginalValue; /// /// Applies this setter to the target view. /// public void Apply(SkiaView view) { if (Property == null) return; // Store original value if not already stored if (!_hasOriginalValue) { _originalValue = view.GetValue(Property); _hasOriginalValue = true; } view.SetValue(Property, Value); } /// /// Unapplies this setter, restoring the original value. /// public void Unapply(SkiaView view) { if (Property == null || !_hasOriginalValue) return; view.SetValue(Property, _originalValue); } }