Update with recovered code from VM binaries (Jan 1)
Recovered from decompiled OpenMaui.Controls.Linux.dll: - SkiaShell.cs: FlyoutHeader, FlyoutFooter, scroll support (918 -> 1325 lines) - X11Window.cs: Cursor support (XCreateFontCursor, XDefineCursor) - All handlers with dark mode support - All services with latest implementations - LinuxApplication with theme change handling
This commit is contained in:
@@ -1,216 +1,98 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
using Microsoft.Maui.Controls;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
/// <summary>
|
||||
/// Visual State Manager for Skia-rendered controls.
|
||||
/// Provides state-based styling through XAML VisualStateGroups.
|
||||
/// </summary>
|
||||
public static class SkiaVisualStateManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Common visual state names.
|
||||
/// </summary>
|
||||
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";
|
||||
}
|
||||
public static class CommonStates
|
||||
{
|
||||
public const string Normal = "Normal";
|
||||
|
||||
/// <summary>
|
||||
/// Attached property for VisualStateGroups.
|
||||
/// </summary>
|
||||
public static readonly BindableProperty VisualStateGroupsProperty =
|
||||
BindableProperty.CreateAttached(
|
||||
"VisualStateGroups",
|
||||
typeof(SkiaVisualStateGroupList),
|
||||
typeof(SkiaVisualStateManager),
|
||||
null,
|
||||
propertyChanged: OnVisualStateGroupsChanged);
|
||||
public const string Disabled = "Disabled";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the visual state groups for the specified view.
|
||||
/// </summary>
|
||||
public static SkiaVisualStateGroupList? GetVisualStateGroups(SkiaView view)
|
||||
{
|
||||
return (SkiaVisualStateGroupList?)view.GetValue(VisualStateGroupsProperty);
|
||||
}
|
||||
public const string Focused = "Focused";
|
||||
|
||||
/// <summary>
|
||||
/// Sets the visual state groups for the specified view.
|
||||
/// </summary>
|
||||
public static void SetVisualStateGroups(SkiaView view, SkiaVisualStateGroupList? value)
|
||||
{
|
||||
view.SetValue(VisualStateGroupsProperty, value);
|
||||
}
|
||||
public const string PointerOver = "PointerOver";
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
public const string Pressed = "Pressed";
|
||||
|
||||
/// <summary>
|
||||
/// Transitions the view to the specified visual state.
|
||||
/// </summary>
|
||||
/// <param name="view">The view to transition.</param>
|
||||
/// <param name="stateName">The name of the state to transition to.</param>
|
||||
/// <returns>True if the state was found and applied, false otherwise.</returns>
|
||||
public static bool GoToState(SkiaView view, string stateName)
|
||||
{
|
||||
var groups = GetVisualStateGroups(view);
|
||||
if (groups == null || groups.Count == 0)
|
||||
return false;
|
||||
public const string Selected = "Selected";
|
||||
|
||||
bool stateFound = false;
|
||||
public const string Checked = "Checked";
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
public const string Unchecked = "Unchecked";
|
||||
|
||||
if (targetState != null)
|
||||
{
|
||||
// Unapply current state if different
|
||||
if (group.CurrentState != null && group.CurrentState != targetState)
|
||||
{
|
||||
UnapplyState(view, group.CurrentState);
|
||||
}
|
||||
public const string On = "On";
|
||||
|
||||
// Apply new state
|
||||
ApplyState(view, targetState);
|
||||
group.CurrentState = targetState;
|
||||
stateFound = true;
|
||||
}
|
||||
}
|
||||
public const string Off = "Off";
|
||||
}
|
||||
|
||||
return stateFound;
|
||||
}
|
||||
public static readonly BindableProperty VisualStateGroupsProperty = BindableProperty.CreateAttached("VisualStateGroups", typeof(SkiaVisualStateGroupList), typeof(SkiaVisualStateManager), (object)null, (BindingMode)2, (ValidateValueDelegate)null, new BindingPropertyChangedDelegate(OnVisualStateGroupsChanged), (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
|
||||
|
||||
private static void ApplyState(SkiaView view, SkiaVisualState state)
|
||||
{
|
||||
foreach (var setter in state.Setters)
|
||||
{
|
||||
setter.Apply(view);
|
||||
}
|
||||
}
|
||||
public static SkiaVisualStateGroupList? GetVisualStateGroups(SkiaView view)
|
||||
{
|
||||
return (SkiaVisualStateGroupList)((BindableObject)view).GetValue(VisualStateGroupsProperty);
|
||||
}
|
||||
|
||||
private static void UnapplyState(SkiaView view, SkiaVisualState state)
|
||||
{
|
||||
foreach (var setter in state.Setters)
|
||||
{
|
||||
setter.Unapply(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A list of visual state groups.
|
||||
/// </summary>
|
||||
public class SkiaVisualStateGroupList : List<SkiaVisualStateGroup>
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A group of mutually exclusive visual states.
|
||||
/// </summary>
|
||||
public class SkiaVisualStateGroup
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of this group.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of states in this group.
|
||||
/// </summary>
|
||||
public List<SkiaVisualState> States { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the currently active state.
|
||||
/// </summary>
|
||||
public SkiaVisualState? CurrentState { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single visual state with its setters.
|
||||
/// </summary>
|
||||
public class SkiaVisualState
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of this state.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of setters for this state.
|
||||
/// </summary>
|
||||
public List<SkiaVisualStateSetter> Setters { get; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a property value when a visual state is active.
|
||||
/// </summary>
|
||||
public class SkiaVisualStateSetter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the property to set.
|
||||
/// </summary>
|
||||
public BindableProperty? Property { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value to set.
|
||||
/// </summary>
|
||||
public object? Value { get; set; }
|
||||
|
||||
// Store original value for unapply
|
||||
private object? _originalValue;
|
||||
private bool _hasOriginalValue;
|
||||
|
||||
/// <summary>
|
||||
/// Applies this setter to the target view.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unapplies this setter, restoring the original value.
|
||||
/// </summary>
|
||||
public void Unapply(SkiaView view)
|
||||
{
|
||||
if (Property == null || !_hasOriginalValue) return;
|
||||
|
||||
view.SetValue(Property, _originalValue);
|
||||
}
|
||||
public static void SetVisualStateGroups(SkiaView view, SkiaVisualStateGroupList? value)
|
||||
{
|
||||
((BindableObject)view).SetValue(VisualStateGroupsProperty, (object)value);
|
||||
}
|
||||
|
||||
private static void OnVisualStateGroupsChanged(BindableObject bindable, object? oldValue, object? newValue)
|
||||
{
|
||||
if (bindable is SkiaView view && newValue is SkiaVisualStateGroupList)
|
||||
{
|
||||
GoToState(view, "Normal");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GoToState(SkiaView view, string stateName)
|
||||
{
|
||||
SkiaVisualStateGroupList visualStateGroups = GetVisualStateGroups(view);
|
||||
if (visualStateGroups == null || visualStateGroups.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool result = false;
|
||||
foreach (SkiaVisualStateGroup item in visualStateGroups)
|
||||
{
|
||||
SkiaVisualState skiaVisualState = null;
|
||||
foreach (SkiaVisualState state in item.States)
|
||||
{
|
||||
if (state.Name == stateName)
|
||||
{
|
||||
skiaVisualState = state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skiaVisualState != null)
|
||||
{
|
||||
if (item.CurrentState != null && item.CurrentState != skiaVisualState)
|
||||
{
|
||||
UnapplyState(view, item.CurrentState);
|
||||
}
|
||||
ApplyState(view, skiaVisualState);
|
||||
item.CurrentState = skiaVisualState;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void ApplyState(SkiaView view, SkiaVisualState state)
|
||||
{
|
||||
foreach (SkiaVisualStateSetter setter in state.Setters)
|
||||
{
|
||||
setter.Apply(view);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UnapplyState(SkiaView view, SkiaVisualState state)
|
||||
{
|
||||
foreach (SkiaVisualStateSetter setter in state.Setters)
|
||||
{
|
||||
setter.Unapply(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user