Fix compilation: restore clean RC1 codebase

- Restore clean BindableProperty.Create syntax from RC1 commit
- Remove decompiler artifacts with mangled delegate types
- Add Svg.Skia package reference for icon support
- Fix duplicate type definitions
- Library now compiles successfully (0 errors)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-01 07:43:44 -05:00
parent 33914bf572
commit 2a4e35cd39
258 changed files with 35256 additions and 49900 deletions

View File

@@ -1,490 +0,0 @@
// 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.Platform.Linux.Interop;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Linux platform WebView using WebKitGTK.
/// This is a native widget overlay that renders on top of the Skia surface.
/// </summary>
public class LinuxWebView : SkiaView
{
private IntPtr _webView;
private IntPtr _gtkWindow;
private bool _initialized;
private bool _isVisible = true;
private string? _currentUrl;
private string? _userAgent;
// Signal handler IDs for cleanup
private ulong _loadChangedHandlerId;
private ulong _decidePolicyHandlerId;
private ulong _titleChangedHandlerId;
// Keep delegates alive to prevent GC
private WebKitGtk.LoadChangedCallback? _loadChangedCallback;
private WebKitGtk.DecidePolicyCallback? _decidePolicyCallback;
private WebKitGtk.NotifyCallback? _titleChangedCallback;
/// <summary>
/// Event raised when navigation starts.
/// </summary>
public event EventHandler<WebViewNavigatingEventArgs>? Navigating;
/// <summary>
/// Event raised when navigation completes.
/// </summary>
public event EventHandler<WebViewNavigatedEventArgs>? Navigated;
/// <summary>
/// Event raised when the page title changes.
/// </summary>
public event EventHandler<string?>? TitleChanged;
/// <summary>
/// Gets whether the WebView can navigate back.
/// </summary>
public bool CanGoBack => _webView != IntPtr.Zero && WebKitGtk.webkit_web_view_can_go_back(_webView);
/// <summary>
/// Gets whether the WebView can navigate forward.
/// </summary>
public bool CanGoForward => _webView != IntPtr.Zero && WebKitGtk.webkit_web_view_can_go_forward(_webView);
/// <summary>
/// Gets the current URL.
/// </summary>
public string? CurrentUrl
{
get
{
if (_webView == IntPtr.Zero)
return _currentUrl;
var uriPtr = WebKitGtk.webkit_web_view_get_uri(_webView);
return WebKitGtk.PtrToStringUtf8(uriPtr) ?? _currentUrl;
}
}
/// <summary>
/// Gets or sets the user agent string.
/// </summary>
public string? UserAgent
{
get => _userAgent;
set
{
_userAgent = value;
if (_webView != IntPtr.Zero && value != null)
{
var settings = WebKitGtk.webkit_web_view_get_settings(_webView);
WebKitGtk.webkit_settings_set_user_agent(settings, value);
}
}
}
public LinuxWebView()
{
// WebView will be initialized when first shown or when source is set
}
/// <summary>
/// Initializes the WebKitGTK WebView.
/// </summary>
private void EnsureInitialized()
{
if (_initialized)
return;
try
{
// Initialize GTK if not already done
int argc = 0;
IntPtr argv = IntPtr.Zero;
WebKitGtk.gtk_init_check(ref argc, ref argv);
// Create a top-level window to host the WebView
// GTK_WINDOW_TOPLEVEL = 0
_gtkWindow = WebKitGtk.gtk_window_new(0);
if (_gtkWindow == IntPtr.Zero)
{
Console.WriteLine("[LinuxWebView] Failed to create GTK window");
return;
}
// Configure the window
WebKitGtk.gtk_window_set_decorated(_gtkWindow, false);
WebKitGtk.gtk_widget_set_can_focus(_gtkWindow, true);
// Create the WebKit WebView
_webView = WebKitGtk.webkit_web_view_new();
if (_webView == IntPtr.Zero)
{
Console.WriteLine("[LinuxWebView] Failed to create WebKit WebView");
WebKitGtk.gtk_widget_destroy(_gtkWindow);
_gtkWindow = IntPtr.Zero;
return;
}
// Configure settings
var settings = WebKitGtk.webkit_web_view_get_settings(_webView);
WebKitGtk.webkit_settings_set_enable_javascript(settings, true);
WebKitGtk.webkit_settings_set_enable_webgl(settings, true);
WebKitGtk.webkit_settings_set_enable_developer_extras(settings, true);
WebKitGtk.webkit_settings_set_javascript_can_access_clipboard(settings, true);
if (_userAgent != null)
{
WebKitGtk.webkit_settings_set_user_agent(settings, _userAgent);
}
// Connect signals
ConnectSignals();
// Add WebView to window
WebKitGtk.gtk_container_add(_gtkWindow, _webView);
_initialized = true;
Console.WriteLine("[LinuxWebView] WebKitGTK WebView initialized successfully");
}
catch (Exception ex)
{
Console.WriteLine($"[LinuxWebView] Initialization failed: {ex.Message}");
Console.WriteLine($"[LinuxWebView] Make sure WebKitGTK is installed: sudo apt install libwebkit2gtk-4.1-0");
}
}
private void ConnectSignals()
{
// Keep callbacks alive
_loadChangedCallback = OnLoadChanged;
_decidePolicyCallback = OnDecidePolicy;
_titleChangedCallback = OnTitleChanged;
// Connect load-changed signal
_loadChangedHandlerId = WebKitGtk.g_signal_connect_data(
_webView, "load-changed", _loadChangedCallback, IntPtr.Zero, IntPtr.Zero, 0);
// Connect decide-policy signal for navigation control
_decidePolicyHandlerId = WebKitGtk.g_signal_connect_data(
_webView, "decide-policy", _decidePolicyCallback, IntPtr.Zero, IntPtr.Zero, 0);
// Connect notify::title for title changes
_titleChangedHandlerId = WebKitGtk.g_signal_connect_data(
_webView, "notify::title", _titleChangedCallback, IntPtr.Zero, IntPtr.Zero, 0);
}
private void OnLoadChanged(IntPtr webView, int loadEvent, IntPtr userData)
{
var url = CurrentUrl ?? "";
switch (loadEvent)
{
case WebKitGtk.WEBKIT_LOAD_STARTED:
case WebKitGtk.WEBKIT_LOAD_REDIRECTED:
Navigating?.Invoke(this, new WebViewNavigatingEventArgs(url));
break;
case WebKitGtk.WEBKIT_LOAD_FINISHED:
Navigated?.Invoke(this, new WebViewNavigatedEventArgs(url, true));
break;
case WebKitGtk.WEBKIT_LOAD_COMMITTED:
// Page content has started loading
break;
}
}
private bool OnDecidePolicy(IntPtr webView, IntPtr decision, int decisionType, IntPtr userData)
{
if (decisionType == WebKitGtk.WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION)
{
var action = WebKitGtk.webkit_navigation_action_get_request(decision);
var uriPtr = WebKitGtk.webkit_uri_request_get_uri(action);
var url = WebKitGtk.PtrToStringUtf8(uriPtr) ?? "";
var args = new WebViewNavigatingEventArgs(url);
Navigating?.Invoke(this, args);
if (args.Cancel)
{
WebKitGtk.webkit_policy_decision_ignore(decision);
return true;
}
}
WebKitGtk.webkit_policy_decision_use(decision);
return true;
}
private void OnTitleChanged(IntPtr webView, IntPtr paramSpec, IntPtr userData)
{
var titlePtr = WebKitGtk.webkit_web_view_get_title(_webView);
var title = WebKitGtk.PtrToStringUtf8(titlePtr);
TitleChanged?.Invoke(this, title);
}
/// <summary>
/// Navigates to the specified URL.
/// </summary>
public void LoadUrl(string url)
{
EnsureInitialized();
if (_webView == IntPtr.Zero)
return;
_currentUrl = url;
WebKitGtk.webkit_web_view_load_uri(_webView, url);
UpdateWindowPosition();
ShowWebView();
}
/// <summary>
/// Loads HTML content.
/// </summary>
public void LoadHtml(string html, string? baseUrl = null)
{
EnsureInitialized();
if (_webView == IntPtr.Zero)
return;
WebKitGtk.webkit_web_view_load_html(_webView, html, baseUrl);
UpdateWindowPosition();
ShowWebView();
}
/// <summary>
/// Navigates back in history.
/// </summary>
public void GoBack()
{
if (_webView != IntPtr.Zero && CanGoBack)
{
WebKitGtk.webkit_web_view_go_back(_webView);
}
}
/// <summary>
/// Navigates forward in history.
/// </summary>
public void GoForward()
{
if (_webView != IntPtr.Zero && CanGoForward)
{
WebKitGtk.webkit_web_view_go_forward(_webView);
}
}
/// <summary>
/// Reloads the current page.
/// </summary>
public void Reload()
{
if (_webView != IntPtr.Zero)
{
WebKitGtk.webkit_web_view_reload(_webView);
}
}
/// <summary>
/// Stops loading the current page.
/// </summary>
public void Stop()
{
if (_webView != IntPtr.Zero)
{
WebKitGtk.webkit_web_view_stop_loading(_webView);
}
}
/// <summary>
/// Evaluates JavaScript and returns the result.
/// </summary>
public Task<string?> EvaluateJavaScriptAsync(string script)
{
var tcs = new TaskCompletionSource<string?>();
if (_webView == IntPtr.Zero)
{
tcs.SetResult(null);
return tcs.Task;
}
// For now, use fire-and-forget JavaScript execution
// Full async result handling requires GAsyncReadyCallback marshaling
WebKitGtk.webkit_web_view_run_javascript(_webView, script, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
tcs.SetResult(null); // Return null for now, full implementation needs async callback
return tcs.Task;
}
/// <summary>
/// Evaluates JavaScript without waiting for result.
/// </summary>
public void Eval(string script)
{
if (_webView != IntPtr.Zero)
{
WebKitGtk.webkit_web_view_run_javascript(_webView, script, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
}
}
private void ShowWebView()
{
if (_gtkWindow != IntPtr.Zero && _isVisible)
{
WebKitGtk.gtk_widget_show_all(_gtkWindow);
}
}
private void HideWebView()
{
if (_gtkWindow != IntPtr.Zero)
{
WebKitGtk.gtk_widget_hide(_gtkWindow);
}
}
private void UpdateWindowPosition()
{
if (_gtkWindow == IntPtr.Zero)
return;
// Get the screen position of this view's bounds
var bounds = Bounds;
var screenX = (int)bounds.Left;
var screenY = (int)bounds.Top;
var width = (int)bounds.Width;
var height = (int)bounds.Height;
if (width > 0 && height > 0)
{
WebKitGtk.gtk_window_move(_gtkWindow, screenX, screenY);
WebKitGtk.gtk_window_resize(_gtkWindow, width, height);
}
}
protected override void OnBoundsChanged()
{
base.OnBoundsChanged();
UpdateWindowPosition();
}
protected override void OnVisibilityChanged()
{
base.OnVisibilityChanged();
_isVisible = IsVisible;
if (_isVisible)
{
ShowWebView();
}
else
{
HideWebView();
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Draw a placeholder rectangle where the WebView will be overlaid
using var paint = new SKPaint
{
Color = new SKColor(240, 240, 240),
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, paint);
// Draw border
using var borderPaint = new SKPaint
{
Color = new SKColor(200, 200, 200),
Style = SKPaintStyle.Stroke,
StrokeWidth = 1
};
canvas.DrawRect(bounds, borderPaint);
// Draw "WebView" label if not yet initialized
if (!_initialized)
{
using var textPaint = new SKPaint
{
Color = SKColors.Gray,
TextSize = 14,
IsAntialias = true
};
var text = "WebView (WebKitGTK)";
var textBounds = new SKRect();
textPaint.MeasureText(text, ref textBounds);
var x = bounds.MidX - textBounds.MidX;
var y = bounds.MidY - textBounds.MidY;
canvas.DrawText(text, x, y, textPaint);
}
// Process GTK events to keep WebView responsive
WebKitGtk.ProcessGtkEvents();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Disconnect signals
if (_webView != IntPtr.Zero)
{
if (_loadChangedHandlerId != 0)
WebKitGtk.g_signal_handler_disconnect(_webView, _loadChangedHandlerId);
if (_decidePolicyHandlerId != 0)
WebKitGtk.g_signal_handler_disconnect(_webView, _decidePolicyHandlerId);
if (_titleChangedHandlerId != 0)
WebKitGtk.g_signal_handler_disconnect(_webView, _titleChangedHandlerId);
}
// Destroy widgets
if (_gtkWindow != IntPtr.Zero)
{
WebKitGtk.gtk_widget_destroy(_gtkWindow);
_gtkWindow = IntPtr.Zero;
_webView = IntPtr.Zero; // WebView is destroyed with window
}
_loadChangedCallback = null;
_decidePolicyCallback = null;
_titleChangedCallback = null;
}
base.Dispose(disposing);
}
}
/// <summary>
/// Event args for WebView navigation starting.
/// </summary>
public class WebViewNavigatingEventArgs : EventArgs
{
public string Url { get; }
public bool Cancel { get; set; }
public WebViewNavigatingEventArgs(string url)
{
Url = url;
}
}
/// <summary>
/// Event args for WebView navigation completed.
/// </summary>
public class WebViewNavigatedEventArgs : EventArgs
{
public string Url { get; }
public bool Success { get; }
public WebViewNavigatedEventArgs(string url, bool success)
{
Url = url;
Success = success;
}
}

View File

@@ -1,143 +0,0 @@
using System;
using System.Collections.Generic;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaAbsoluteLayout : SkiaLayoutView
{
private readonly Dictionary<SkiaView, AbsoluteLayoutBounds> _childBounds = new Dictionary<SkiaView, AbsoluteLayoutBounds>();
public void AddChild(SkiaView child, SKRect bounds, AbsoluteLayoutFlags flags = AbsoluteLayoutFlags.None)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
base.AddChild(child);
_childBounds[child] = new AbsoluteLayoutBounds(bounds, flags);
}
public override void RemoveChild(SkiaView child)
{
base.RemoveChild(child);
_childBounds.Remove(child);
}
public AbsoluteLayoutBounds GetLayoutBounds(SkiaView child)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
if (!_childBounds.TryGetValue(child, out var value))
{
return new AbsoluteLayoutBounds(SKRect.Empty, AbsoluteLayoutFlags.None);
}
return value;
}
public void SetLayoutBounds(SkiaView child, SKRect bounds, AbsoluteLayoutFlags flags = AbsoluteLayoutFlags.None)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
_childBounds[child] = new AbsoluteLayoutBounds(bounds, flags);
InvalidateMeasure();
Invalidate();
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
float num = 0f;
float num2 = 0f;
foreach (SkiaView child in base.Children)
{
if (child.IsVisible)
{
SKRect bounds = GetLayoutBounds(child).Bounds;
child.Measure(new SKSize(((SKRect)(ref bounds)).Width, ((SKRect)(ref bounds)).Height));
num = Math.Max(num, ((SKRect)(ref bounds)).Right);
num2 = Math.Max(num2, ((SKRect)(ref bounds)).Bottom);
}
}
float num3 = num;
SKRect padding = base.Padding;
float num4 = num3 + ((SKRect)(ref padding)).Left;
padding = base.Padding;
float num5 = num4 + ((SKRect)(ref padding)).Right;
float num6 = num2;
padding = base.Padding;
float num7 = num6 + ((SKRect)(ref padding)).Top;
padding = base.Padding;
return new SKSize(num5, num7 + ((SKRect)(ref padding)).Bottom);
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
SKRect contentBounds = GetContentBounds(bounds);
SKRect bounds3 = default(SKRect);
foreach (SkiaView child in base.Children)
{
if (child.IsVisible)
{
AbsoluteLayoutBounds layoutBounds = GetLayoutBounds(child);
SKRect bounds2 = layoutBounds.Bounds;
AbsoluteLayoutFlags flags = layoutBounds.Flags;
float num = ((!flags.HasFlag(AbsoluteLayoutFlags.XProportional)) ? (((SKRect)(ref contentBounds)).Left + ((SKRect)(ref bounds2)).Left) : (((SKRect)(ref contentBounds)).Left + ((SKRect)(ref bounds2)).Left * ((SKRect)(ref contentBounds)).Width));
float num2 = ((!flags.HasFlag(AbsoluteLayoutFlags.YProportional)) ? (((SKRect)(ref contentBounds)).Top + ((SKRect)(ref bounds2)).Top) : (((SKRect)(ref contentBounds)).Top + ((SKRect)(ref bounds2)).Top * ((SKRect)(ref contentBounds)).Height));
float num3;
SKSize desiredSize;
if (flags.HasFlag(AbsoluteLayoutFlags.WidthProportional))
{
num3 = ((SKRect)(ref bounds2)).Width * ((SKRect)(ref contentBounds)).Width;
}
else if (((SKRect)(ref bounds2)).Width < 0f)
{
desiredSize = child.DesiredSize;
num3 = ((SKSize)(ref desiredSize)).Width;
}
else
{
num3 = ((SKRect)(ref bounds2)).Width;
}
float num4;
if (flags.HasFlag(AbsoluteLayoutFlags.HeightProportional))
{
num4 = ((SKRect)(ref bounds2)).Height * ((SKRect)(ref contentBounds)).Height;
}
else if (((SKRect)(ref bounds2)).Height < 0f)
{
desiredSize = child.DesiredSize;
num4 = ((SKSize)(ref desiredSize)).Height;
}
else
{
num4 = ((SKRect)(ref bounds2)).Height;
}
Thickness margin = child.Margin;
((SKRect)(ref bounds3))._002Ector(num + (float)((Thickness)(ref margin)).Left, num2 + (float)((Thickness)(ref margin)).Top, num + num3 - (float)((Thickness)(ref margin)).Right, num2 + num4 - (float)((Thickness)(ref margin)).Bottom);
child.Arrange(bounds3);
}
}
return bounds;
}
}

View File

@@ -1,222 +1,238 @@
using System;
using Microsoft.Maui.Controls;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered activity indicator (spinner) control with full XAML styling support.
/// </summary>
public class SkiaActivityIndicator : SkiaView
{
public static readonly BindableProperty IsRunningProperty = BindableProperty.Create("IsRunning", typeof(bool), typeof(SkiaActivityIndicator), (object)false, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaActivityIndicator)(object)b).OnIsRunningChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
#region BindableProperties
public static readonly BindableProperty ColorProperty = BindableProperty.Create("Color", typeof(SKColor), typeof(SkiaActivityIndicator), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaActivityIndicator)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for IsRunning.
/// </summary>
public static readonly BindableProperty IsRunningProperty =
BindableProperty.Create(
nameof(IsRunning),
typeof(bool),
typeof(SkiaActivityIndicator),
false,
propertyChanged: (b, o, n) => ((SkiaActivityIndicator)b).OnIsRunningChanged());
public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create("DisabledColor", typeof(SKColor), typeof(SkiaActivityIndicator), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaActivityIndicator)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for Color.
/// </summary>
public static readonly BindableProperty ColorProperty =
BindableProperty.Create(
nameof(Color),
typeof(SKColor),
typeof(SkiaActivityIndicator),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaActivityIndicator)b).Invalidate());
public static readonly BindableProperty SizeProperty = BindableProperty.Create("Size", typeof(float), typeof(SkiaActivityIndicator), (object)32f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaActivityIndicator)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for DisabledColor.
/// </summary>
public static readonly BindableProperty DisabledColorProperty =
BindableProperty.Create(
nameof(DisabledColor),
typeof(SKColor),
typeof(SkiaActivityIndicator),
new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaActivityIndicator)b).Invalidate());
public static readonly BindableProperty StrokeWidthProperty = BindableProperty.Create("StrokeWidth", typeof(float), typeof(SkiaActivityIndicator), (object)3f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaActivityIndicator)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for Size.
/// </summary>
public static readonly BindableProperty SizeProperty =
BindableProperty.Create(
nameof(Size),
typeof(float),
typeof(SkiaActivityIndicator),
32f,
propertyChanged: (b, o, n) => ((SkiaActivityIndicator)b).InvalidateMeasure());
public static readonly BindableProperty RotationSpeedProperty = BindableProperty.Create("RotationSpeed", typeof(float), typeof(SkiaActivityIndicator), (object)360f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for StrokeWidth.
/// </summary>
public static readonly BindableProperty StrokeWidthProperty =
BindableProperty.Create(
nameof(StrokeWidth),
typeof(float),
typeof(SkiaActivityIndicator),
3f,
propertyChanged: (b, o, n) => ((SkiaActivityIndicator)b).InvalidateMeasure());
public static readonly BindableProperty ArcCountProperty = BindableProperty.Create("ArcCount", typeof(int), typeof(SkiaActivityIndicator), (object)12, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaActivityIndicator)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for RotationSpeed.
/// </summary>
public static readonly BindableProperty RotationSpeedProperty =
BindableProperty.Create(
nameof(RotationSpeed),
typeof(float),
typeof(SkiaActivityIndicator),
360f);
private float _rotationAngle;
/// <summary>
/// Bindable property for ArcCount.
/// </summary>
public static readonly BindableProperty ArcCountProperty =
BindableProperty.Create(
nameof(ArcCount),
typeof(int),
typeof(SkiaActivityIndicator),
12,
propertyChanged: (b, o, n) => ((SkiaActivityIndicator)b).Invalidate());
private DateTime _lastUpdateTime = DateTime.UtcNow;
#endregion
public bool IsRunning
{
get
{
return (bool)((BindableObject)this).GetValue(IsRunningProperty);
}
set
{
((BindableObject)this).SetValue(IsRunningProperty, (object)value);
}
}
#region Properties
public SKColor Color
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets whether the indicator is running.
/// </summary>
public bool IsRunning
{
get => (bool)GetValue(IsRunningProperty);
set => SetValue(IsRunningProperty, value);
}
public SKColor DisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(DisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(DisabledColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the indicator color.
/// </summary>
public SKColor Color
{
get => (SKColor)GetValue(ColorProperty);
set => SetValue(ColorProperty, value);
}
public float Size
{
get
{
return (float)((BindableObject)this).GetValue(SizeProperty);
}
set
{
((BindableObject)this).SetValue(SizeProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the disabled color.
/// </summary>
public SKColor DisabledColor
{
get => (SKColor)GetValue(DisabledColorProperty);
set => SetValue(DisabledColorProperty, value);
}
public float StrokeWidth
{
get
{
return (float)((BindableObject)this).GetValue(StrokeWidthProperty);
}
set
{
((BindableObject)this).SetValue(StrokeWidthProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the indicator size.
/// </summary>
public float Size
{
get => (float)GetValue(SizeProperty);
set => SetValue(SizeProperty, value);
}
public float RotationSpeed
{
get
{
return (float)((BindableObject)this).GetValue(RotationSpeedProperty);
}
set
{
((BindableObject)this).SetValue(RotationSpeedProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the stroke width.
/// </summary>
public float StrokeWidth
{
get => (float)GetValue(StrokeWidthProperty);
set => SetValue(StrokeWidthProperty, value);
}
public int ArcCount
{
get
{
return (int)((BindableObject)this).GetValue(ArcCountProperty);
}
set
{
((BindableObject)this).SetValue(ArcCountProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the rotation speed in degrees per second.
/// </summary>
public float RotationSpeed
{
get => (float)GetValue(RotationSpeedProperty);
set => SetValue(RotationSpeedProperty, value);
}
private void OnIsRunningChanged()
{
if (IsRunning)
{
_lastUpdateTime = DateTime.UtcNow;
}
Invalidate();
}
/// <summary>
/// Gets or sets the number of arcs.
/// </summary>
public int ArcCount
{
get => (int)GetValue(ArcCountProperty);
set => SetValue(ArcCountProperty, value);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: Expected O, but got Unknown
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
//IL_015e: Expected O, but got Unknown
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
if (!IsRunning && !base.IsEnabled)
{
return;
}
float midX = ((SKRect)(ref bounds)).MidX;
float midY = ((SKRect)(ref bounds)).MidY;
float num = Math.Min(Size / 2f, Math.Min(((SKRect)(ref bounds)).Width, ((SKRect)(ref bounds)).Height) / 2f) - StrokeWidth;
if (IsRunning)
{
DateTime utcNow = DateTime.UtcNow;
double totalSeconds = (utcNow - _lastUpdateTime).TotalSeconds;
_lastUpdateTime = utcNow;
_rotationAngle = (_rotationAngle + (float)((double)RotationSpeed * totalSeconds)) % 360f;
}
canvas.Save();
canvas.Translate(midX, midY);
canvas.RotateDegrees(_rotationAngle);
SKColor val = (base.IsEnabled ? Color : DisabledColor);
for (int i = 0; i < ArcCount; i++)
{
byte b = (byte)(255f * (1f - (float)i / (float)ArcCount));
SKColor color = ((SKColor)(ref val)).WithAlpha(b);
SKPaint val2 = new SKPaint
{
Color = color,
IsAntialias = true,
Style = (SKPaintStyle)1,
StrokeWidth = StrokeWidth,
StrokeCap = (SKStrokeCap)1
};
try
{
float num2 = 360f / (float)ArcCount * (float)i;
float num3 = 360f / (float)ArcCount / 2f;
SKPath val3 = new SKPath();
try
{
val3.AddArc(new SKRect(0f - num, 0f - num, num, num), num2, num3);
canvas.DrawPath(val3, val2);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
canvas.Restore();
if (IsRunning)
{
Invalidate();
}
}
#endregion
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(Size + StrokeWidth * 2f, Size + StrokeWidth * 2f);
}
private float _rotationAngle;
private DateTime _lastUpdateTime = DateTime.UtcNow;
private void OnIsRunningChanged()
{
if (IsRunning)
{
_lastUpdateTime = DateTime.UtcNow;
}
Invalidate();
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
if (!IsRunning && !IsEnabled)
{
return;
}
var centerX = bounds.MidX;
var centerY = bounds.MidY;
var radius = Math.Min(Size / 2, Math.Min(bounds.Width, bounds.Height) / 2) - StrokeWidth;
// Update rotation
if (IsRunning)
{
var now = DateTime.UtcNow;
var elapsed = (now - _lastUpdateTime).TotalSeconds;
_lastUpdateTime = now;
_rotationAngle = (_rotationAngle + (float)(RotationSpeed * elapsed)) % 360;
}
canvas.Save();
canvas.Translate(centerX, centerY);
canvas.RotateDegrees(_rotationAngle);
var color = IsEnabled ? Color : DisabledColor;
// Draw arcs with varying opacity
for (int i = 0; i < ArcCount; i++)
{
var alpha = (byte)(255 * (1 - (float)i / ArcCount));
var arcColor = color.WithAlpha(alpha);
using var paint = new SKPaint
{
Color = arcColor,
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = StrokeWidth,
StrokeCap = SKStrokeCap.Round
};
var startAngle = (360f / ArcCount) * i;
var sweepAngle = 360f / ArcCount / 2;
using var path = new SKPath();
path.AddArc(
new SKRect(-radius, -radius, radius, radius),
startAngle,
sweepAngle);
canvas.DrawPath(path, paint);
}
canvas.Restore();
// Request redraw for animation
if (IsRunning)
{
Invalidate();
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(Size + StrokeWidth * 2, Size + StrokeWidth * 2);
}
}

View File

@@ -1,440 +1,385 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A modal alert dialog rendered with Skia.
/// Supports title, message, and up to two buttons (cancel/accept).
/// </summary>
public class SkiaAlertDialog : SkiaView
{
private readonly string _title;
private readonly string _title;
private readonly string _message;
private readonly string? _cancel;
private readonly string? _accept;
private readonly TaskCompletionSource<bool> _tcs;
private readonly string _message;
private SKRect _cancelButtonBounds;
private SKRect _acceptButtonBounds;
private bool _cancelHovered;
private bool _acceptHovered;
private readonly string? _cancel;
// Dialog styling
private static readonly SKColor OverlayColor = new SKColor(0, 0, 0, 128);
private static readonly SKColor DialogBackground = SKColors.White;
private static readonly SKColor TitleColor = new SKColor(0x21, 0x21, 0x21);
private static readonly SKColor MessageColor = new SKColor(0x61, 0x61, 0x61);
private static readonly SKColor ButtonColor = new SKColor(0x21, 0x96, 0xF3);
private static readonly SKColor ButtonHoverColor = new SKColor(0x19, 0x76, 0xD2);
private static readonly SKColor ButtonTextColor = SKColors.White;
private static readonly SKColor CancelButtonColor = new SKColor(0x9E, 0x9E, 0x9E);
private static readonly SKColor CancelButtonHoverColor = new SKColor(0x75, 0x75, 0x75);
private static readonly SKColor BorderColor = new SKColor(0xE0, 0xE0, 0xE0);
private readonly string? _accept;
private const float DialogWidth = 400;
private const float DialogPadding = 24;
private const float ButtonHeight = 44;
private const float ButtonSpacing = 12;
private const float CornerRadius = 12;
private readonly TaskCompletionSource<bool> _tcs;
/// <summary>
/// Creates a new alert dialog.
/// </summary>
public SkiaAlertDialog(string title, string message, string? accept, string? cancel)
{
_title = title;
_message = message;
_accept = accept;
_cancel = cancel;
_tcs = new TaskCompletionSource<bool>();
IsFocusable = true;
}
private SKRect _cancelButtonBounds;
/// <summary>
/// Gets the task that completes when the dialog is dismissed.
/// Returns true if accept was clicked, false if cancel was clicked.
/// </summary>
public Task<bool> Result => _tcs.Task;
private SKRect _acceptButtonBounds;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Draw semi-transparent overlay covering entire screen
using var overlayPaint = new SKPaint
{
Color = OverlayColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, overlayPaint);
private bool _cancelHovered;
// Calculate dialog dimensions
var messageLines = WrapText(_message, DialogWidth - DialogPadding * 2, 16);
var dialogHeight = CalculateDialogHeight(messageLines.Count);
private bool _acceptHovered;
var dialogLeft = bounds.MidX - DialogWidth / 2;
var dialogTop = bounds.MidY - dialogHeight / 2;
var dialogBounds = new SKRect(dialogLeft, dialogTop, dialogLeft + DialogWidth, dialogTop + dialogHeight);
private static readonly SKColor OverlayColor = new SKColor((byte)0, (byte)0, (byte)0, (byte)128);
// Draw dialog shadow
using var shadowPaint = new SKPaint
{
Color = new SKColor(0, 0, 0, 60),
MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, 8),
Style = SKPaintStyle.Fill
};
var shadowRect = new SKRect(dialogBounds.Left + 4, dialogBounds.Top + 4,
dialogBounds.Right + 4, dialogBounds.Bottom + 4);
canvas.DrawRoundRect(shadowRect, CornerRadius, CornerRadius, shadowPaint);
private static readonly SKColor DialogBackground = SKColors.White;
// Draw dialog background
using var bgPaint = new SKPaint
{
Color = DialogBackground,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawRoundRect(dialogBounds, CornerRadius, CornerRadius, bgPaint);
private static readonly SKColor TitleColor = new SKColor((byte)33, (byte)33, (byte)33);
// Draw title
var yOffset = dialogBounds.Top + DialogPadding;
if (!string.IsNullOrEmpty(_title))
{
using var titleFont = new SKFont(SKTypeface.Default, 20) { Embolden = true };
using var titlePaint = new SKPaint(titleFont)
{
Color = TitleColor,
IsAntialias = true
};
canvas.DrawText(_title, dialogBounds.Left + DialogPadding, yOffset + 20, titlePaint);
yOffset += 36;
}
private static readonly SKColor MessageColor = new SKColor((byte)97, (byte)97, (byte)97);
// Draw message
if (!string.IsNullOrEmpty(_message))
{
using var messageFont = new SKFont(SKTypeface.Default, 16);
using var messagePaint = new SKPaint(messageFont)
{
Color = MessageColor,
IsAntialias = true
};
private static readonly SKColor ButtonColor = new SKColor((byte)33, (byte)150, (byte)243);
foreach (var line in messageLines)
{
canvas.DrawText(line, dialogBounds.Left + DialogPadding, yOffset + 16, messagePaint);
yOffset += 22;
}
yOffset += 8;
}
private static readonly SKColor ButtonHoverColor = new SKColor((byte)25, (byte)118, (byte)210);
// Draw buttons
yOffset = dialogBounds.Bottom - DialogPadding - ButtonHeight;
var buttonY = yOffset;
private static readonly SKColor ButtonTextColor = SKColors.White;
var buttonCount = (_accept != null ? 1 : 0) + (_cancel != null ? 1 : 0);
var totalButtonWidth = DialogWidth - DialogPadding * 2;
private static readonly SKColor CancelButtonColor = new SKColor((byte)158, (byte)158, (byte)158);
if (buttonCount == 2)
{
var singleButtonWidth = (totalButtonWidth - ButtonSpacing) / 2;
private static readonly SKColor CancelButtonHoverColor = new SKColor((byte)117, (byte)117, (byte)117);
// Cancel button (left)
_cancelButtonBounds = new SKRect(
dialogBounds.Left + DialogPadding,
buttonY,
dialogBounds.Left + DialogPadding + singleButtonWidth,
buttonY + ButtonHeight);
DrawButton(canvas, _cancelButtonBounds, _cancel!,
_cancelHovered ? CancelButtonHoverColor : CancelButtonColor);
private static readonly SKColor BorderColor = new SKColor((byte)224, (byte)224, (byte)224);
// Accept button (right)
_acceptButtonBounds = new SKRect(
dialogBounds.Right - DialogPadding - singleButtonWidth,
buttonY,
dialogBounds.Right - DialogPadding,
buttonY + ButtonHeight);
DrawButton(canvas, _acceptButtonBounds, _accept!,
_acceptHovered ? ButtonHoverColor : ButtonColor);
}
else if (_accept != null)
{
_acceptButtonBounds = new SKRect(
dialogBounds.Left + DialogPadding,
buttonY,
dialogBounds.Right - DialogPadding,
buttonY + ButtonHeight);
DrawButton(canvas, _acceptButtonBounds, _accept,
_acceptHovered ? ButtonHoverColor : ButtonColor);
}
else if (_cancel != null)
{
_cancelButtonBounds = new SKRect(
dialogBounds.Left + DialogPadding,
buttonY,
dialogBounds.Right - DialogPadding,
buttonY + ButtonHeight);
DrawButton(canvas, _cancelButtonBounds, _cancel,
_cancelHovered ? CancelButtonHoverColor : CancelButtonColor);
}
}
private const float DialogWidth = 400f;
private void DrawButton(SKCanvas canvas, SKRect bounds, string text, SKColor bgColor)
{
// Button background
using var bgPaint = new SKPaint
{
Color = bgColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawRoundRect(bounds, 8, 8, bgPaint);
private const float DialogPadding = 24f;
// Button text
using var font = new SKFont(SKTypeface.Default, 16) { Embolden = true };
using var textPaint = new SKPaint(font)
{
Color = ButtonTextColor,
IsAntialias = true
};
private const float ButtonHeight = 44f;
var textBounds = new SKRect();
textPaint.MeasureText(text, ref textBounds);
private const float ButtonSpacing = 12f;
var x = bounds.MidX - textBounds.MidX;
var y = bounds.MidY - textBounds.MidY;
canvas.DrawText(text, x, y, textPaint);
}
private const float CornerRadius = 12f;
private float CalculateDialogHeight(int messageLineCount)
{
var height = DialogPadding * 2; // Top and bottom padding
public Task<bool> Result => _tcs.Task;
if (!string.IsNullOrEmpty(_title))
height += 36; // Title height
public SkiaAlertDialog(string title, string message, string? accept, string? cancel)
{
_title = title;
_message = message;
_accept = accept;
_cancel = cancel;
_tcs = new TaskCompletionSource<bool>();
base.IsFocusable = true;
}
if (!string.IsNullOrEmpty(_message))
height += messageLineCount * 22 + 8; // Message lines + spacing
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Expected O, but got Unknown
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Expected O, but got Unknown
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Expected O, but got Unknown
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Unknown result type (might be due to invalid IL or missing references)
//IL_016b: Expected O, but got Unknown
//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
//IL_01f8: Expected O, but got Unknown
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_0173: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0186: Expected O, but got Unknown
//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0302: Unknown result type (might be due to invalid IL or missing references)
//IL_030a: Unknown result type (might be due to invalid IL or missing references)
//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0200: Unknown result type (might be due to invalid IL or missing references)
//IL_020a: Unknown result type (might be due to invalid IL or missing references)
//IL_0213: Expected O, but got Unknown
//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
//IL_03be: Unknown result type (might be due to invalid IL or missing references)
//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
//IL_0324: Unknown result type (might be due to invalid IL or missing references)
//IL_031d: Unknown result type (might be due to invalid IL or missing references)
//IL_041c: Unknown result type (might be due to invalid IL or missing references)
//IL_0421: Unknown result type (might be due to invalid IL or missing references)
//IL_0429: Unknown result type (might be due to invalid IL or missing references)
//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
//IL_0356: Unknown result type (might be due to invalid IL or missing references)
//IL_035b: Unknown result type (might be due to invalid IL or missing references)
//IL_0363: Unknown result type (might be due to invalid IL or missing references)
//IL_0443: Unknown result type (might be due to invalid IL or missing references)
//IL_043c: Unknown result type (might be due to invalid IL or missing references)
//IL_037d: Unknown result type (might be due to invalid IL or missing references)
//IL_0376: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = OverlayColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
List<string> list = WrapText(_message, 352f, 16f);
float num = CalculateDialogHeight(list.Count);
float num2 = ((SKRect)(ref bounds)).MidX - 200f;
float num3 = ((SKRect)(ref bounds)).MidY - num / 2f;
SKRect val2 = new SKRect(num2, num3, num2 + 400f, num3 + num);
SKPaint val3 = new SKPaint
{
Color = new SKColor((byte)0, (byte)0, (byte)0, (byte)60),
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, 8f),
Style = (SKPaintStyle)0
};
try
{
SKRect val4 = new SKRect(((SKRect)(ref val2)).Left + 4f, ((SKRect)(ref val2)).Top + 4f, ((SKRect)(ref val2)).Right + 4f, ((SKRect)(ref val2)).Bottom + 4f);
canvas.DrawRoundRect(val4, 12f, 12f, val3);
SKPaint val5 = new SKPaint
{
Color = DialogBackground,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
canvas.DrawRoundRect(val2, 12f, 12f, val5);
float num4 = ((SKRect)(ref val2)).Top + 24f;
if (!string.IsNullOrEmpty(_title))
{
SKFont val6 = new SKFont(SKTypeface.Default, 20f, 1f, 0f)
{
Embolden = true
};
try
{
SKPaint val7 = new SKPaint(val6)
{
Color = TitleColor,
IsAntialias = true
};
try
{
canvas.DrawText(_title, ((SKRect)(ref val2)).Left + 24f, num4 + 20f, val7);
num4 += 36f;
}
finally
{
((IDisposable)val7)?.Dispose();
}
}
finally
{
((IDisposable)val6)?.Dispose();
}
}
if (!string.IsNullOrEmpty(_message))
{
SKFont val8 = new SKFont(SKTypeface.Default, 16f, 1f, 0f);
try
{
SKPaint val9 = new SKPaint(val8)
{
Color = MessageColor,
IsAntialias = true
};
try
{
foreach (string item in list)
{
canvas.DrawText(item, ((SKRect)(ref val2)).Left + 24f, num4 + 16f, val9);
num4 += 22f;
}
num4 += 8f;
}
finally
{
((IDisposable)val9)?.Dispose();
}
}
finally
{
((IDisposable)val8)?.Dispose();
}
}
num4 = ((SKRect)(ref val2)).Bottom - 24f - 44f;
float num5 = num4;
int num6 = ((_accept != null) ? 1 : 0) + ((_cancel != null) ? 1 : 0);
float num7 = 352f;
if (num6 == 2)
{
float num8 = (num7 - 12f) / 2f;
_cancelButtonBounds = new SKRect(((SKRect)(ref val2)).Left + 24f, num5, ((SKRect)(ref val2)).Left + 24f + num8, num5 + 44f);
DrawButton(canvas, _cancelButtonBounds, _cancel, _cancelHovered ? CancelButtonHoverColor : CancelButtonColor);
_acceptButtonBounds = new SKRect(((SKRect)(ref val2)).Right - 24f - num8, num5, ((SKRect)(ref val2)).Right - 24f, num5 + 44f);
DrawButton(canvas, _acceptButtonBounds, _accept, _acceptHovered ? ButtonHoverColor : ButtonColor);
}
else if (_accept != null)
{
_acceptButtonBounds = new SKRect(((SKRect)(ref val2)).Left + 24f, num5, ((SKRect)(ref val2)).Right - 24f, num5 + 44f);
DrawButton(canvas, _acceptButtonBounds, _accept, _acceptHovered ? ButtonHoverColor : ButtonColor);
}
else if (_cancel != null)
{
_cancelButtonBounds = new SKRect(((SKRect)(ref val2)).Left + 24f, num5, ((SKRect)(ref val2)).Right - 24f, num5 + 44f);
DrawButton(canvas, _cancelButtonBounds, _cancel, _cancelHovered ? CancelButtonHoverColor : CancelButtonColor);
}
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
height += ButtonHeight; // Buttons
private void DrawButton(SKCanvas canvas, SKRect bounds, string text, SKColor bgColor)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Expected O, but got Unknown
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Expected O, but got Unknown
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = bgColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
canvas.DrawRoundRect(bounds, 8f, 8f, val);
SKFont val2 = new SKFont(SKTypeface.Default, 16f, 1f, 0f)
{
Embolden = true
};
try
{
SKPaint val3 = new SKPaint(val2)
{
Color = ButtonTextColor,
IsAntialias = true
};
try
{
SKRect val4 = default(SKRect);
val3.MeasureText(text, ref val4);
float num = ((SKRect)(ref bounds)).MidX - ((SKRect)(ref val4)).MidX;
float num2 = ((SKRect)(ref bounds)).MidY - ((SKRect)(ref val4)).MidY;
canvas.DrawText(text, num, num2, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
return Math.Max(height, 180); // Minimum height
}
private float CalculateDialogHeight(int messageLineCount)
{
float num = 48f;
if (!string.IsNullOrEmpty(_title))
{
num += 36f;
}
if (!string.IsNullOrEmpty(_message))
{
num += (float)(messageLineCount * 22 + 8);
}
num += 44f;
return Math.Max(num, 180f);
}
private List<string> WrapText(string text, float maxWidth, float fontSize)
{
var lines = new List<string>();
if (string.IsNullOrEmpty(text))
return lines;
private List<string> WrapText(string text, float maxWidth, float fontSize)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Expected O, but got Unknown
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Expected O, but got Unknown
List<string> list = new List<string>();
if (string.IsNullOrEmpty(text))
{
return list;
}
SKFont val = new SKFont(SKTypeface.Default, fontSize, 1f, 0f);
try
{
SKPaint val2 = new SKPaint(val);
try
{
string[] array = text.Split(' ');
string text2 = "";
string[] array2 = array;
foreach (string text3 in array2)
{
string text4 = (string.IsNullOrEmpty(text2) ? text3 : (text2 + " " + text3));
if (val2.MeasureText(text4) > maxWidth && !string.IsNullOrEmpty(text2))
{
list.Add(text2);
text2 = text3;
}
else
{
text2 = text4;
}
}
if (!string.IsNullOrEmpty(text2))
{
list.Add(text2);
}
return list;
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
using var font = new SKFont(SKTypeface.Default, fontSize);
using var paint = new SKPaint(font);
public override void OnPointerMoved(PointerEventArgs e)
{
bool num = _cancelHovered || _acceptHovered;
_cancelHovered = _cancel != null && ((SKRect)(ref _cancelButtonBounds)).Contains(e.X, e.Y);
_acceptHovered = _accept != null && ((SKRect)(ref _acceptButtonBounds)).Contains(e.X, e.Y);
if (num != (_cancelHovered || _acceptHovered))
{
Invalidate();
}
}
var words = text.Split(' ');
var currentLine = "";
public override void OnPointerPressed(PointerEventArgs e)
{
if (_cancel != null && ((SKRect)(ref _cancelButtonBounds)).Contains(e.X, e.Y))
{
Dismiss(result: false);
}
else if (_accept != null && ((SKRect)(ref _acceptButtonBounds)).Contains(e.X, e.Y))
{
Dismiss(result: true);
}
}
foreach (var word in words)
{
var testLine = string.IsNullOrEmpty(currentLine) ? word : currentLine + " " + word;
var width = paint.MeasureText(testLine);
public override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Escape && _cancel != null)
{
Dismiss(result: false);
e.Handled = true;
}
else if (e.Key == Key.Enter && _accept != null)
{
Dismiss(result: true);
e.Handled = true;
}
}
if (width > maxWidth && !string.IsNullOrEmpty(currentLine))
{
lines.Add(currentLine);
currentLine = word;
}
else
{
currentLine = testLine;
}
}
private void Dismiss(bool result)
{
LinuxDialogService.HideDialog(this);
_tcs.TrySetResult(result);
}
if (!string.IsNullOrEmpty(currentLine))
lines.Add(currentLine);
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
return availableSize;
}
return lines;
}
public override SkiaView? HitTest(float x, float y)
{
return this;
}
public override void OnPointerMoved(PointerEventArgs e)
{
var wasHovered = _cancelHovered || _acceptHovered;
_cancelHovered = _cancel != null && _cancelButtonBounds.Contains(e.X, e.Y);
_acceptHovered = _accept != null && _acceptButtonBounds.Contains(e.X, e.Y);
if (wasHovered != (_cancelHovered || _acceptHovered))
Invalidate();
}
public override void OnPointerPressed(PointerEventArgs e)
{
// Check if clicking on buttons
if (_cancel != null && _cancelButtonBounds.Contains(e.X, e.Y))
{
Dismiss(false);
return;
}
if (_accept != null && _acceptButtonBounds.Contains(e.X, e.Y))
{
Dismiss(true);
return;
}
// Clicking outside dialog doesn't dismiss it (it's modal)
}
public override void OnKeyDown(KeyEventArgs e)
{
// Handle Escape to cancel
if (e.Key == Key.Escape && _cancel != null)
{
Dismiss(false);
e.Handled = true;
return;
}
// Handle Enter to accept
if (e.Key == Key.Enter && _accept != null)
{
Dismiss(true);
e.Handled = true;
return;
}
}
private void Dismiss(bool result)
{
// Remove from dialog system
LinuxDialogService.HideDialog(this);
_tcs.TrySetResult(result);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
// Dialog takes full screen for the overlay
return availableSize;
}
public override SkiaView? HitTest(float x, float y)
{
// Modal dialogs capture all input
return this;
}
}
/// <summary>
/// Service for showing modal dialogs in OpenMaui Linux.
/// </summary>
public static class LinuxDialogService
{
private static readonly List<SkiaAlertDialog> _activeDialogs = new();
private static Action? _invalidateCallback;
/// <summary>
/// Registers the invalidation callback (called by LinuxApplication).
/// </summary>
public static void SetInvalidateCallback(Action callback)
{
_invalidateCallback = callback;
}
/// <summary>
/// Shows an alert dialog and returns when dismissed.
/// </summary>
public static Task<bool> ShowAlertAsync(string title, string message, string? accept, string? cancel)
{
var dialog = new SkiaAlertDialog(title, message, accept, cancel);
_activeDialogs.Add(dialog);
_invalidateCallback?.Invoke();
return dialog.Result;
}
/// <summary>
/// Hides a dialog.
/// </summary>
internal static void HideDialog(SkiaAlertDialog dialog)
{
_activeDialogs.Remove(dialog);
_invalidateCallback?.Invoke();
}
/// <summary>
/// Gets whether there are active dialogs.
/// </summary>
public static bool HasActiveDialog => _activeDialogs.Count > 0;
/// <summary>
/// Gets the topmost dialog.
/// </summary>
public static SkiaAlertDialog? TopDialog => _activeDialogs.Count > 0 ? _activeDialogs[^1] : null;
/// <summary>
/// Draws all active dialogs.
/// </summary>
public static void DrawDialogs(SKCanvas canvas, SKRect bounds)
{
foreach (var dialog in _activeDialogs)
{
dialog.Measure(new SKSize(bounds.Width, bounds.Height));
dialog.Arrange(bounds);
dialog.Draw(canvas);
}
}
}

View File

@@ -1,483 +1,310 @@
using System;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Platform.Linux.Handlers;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered border/frame container control with full XAML styling support.
/// </summary>
public class SkiaBorder : SkiaLayoutView
{
public static readonly BindableProperty StrokeThicknessProperty = BindableProperty.Create("StrokeThickness", typeof(float), typeof(SkiaBorder), (object)1f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
#region BindableProperties
public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(float), typeof(SkiaBorder), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty StrokeThicknessProperty =
BindableProperty.Create(nameof(StrokeThickness), typeof(float), typeof(SkiaBorder), 1f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public static readonly BindableProperty StrokeProperty = BindableProperty.Create("Stroke", typeof(SKColor), typeof(SkiaBorder), (object)SKColors.Black, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.Create(nameof(CornerRadius), typeof(float), typeof(SkiaBorder), 0f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public static readonly BindableProperty PaddingLeftProperty = BindableProperty.Create("PaddingLeft", typeof(float), typeof(SkiaBorder), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty StrokeProperty =
BindableProperty.Create(nameof(Stroke), typeof(SKColor), typeof(SkiaBorder), SKColors.Black,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public static readonly BindableProperty PaddingTopProperty = BindableProperty.Create("PaddingTop", typeof(float), typeof(SkiaBorder), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty PaddingLeftProperty =
BindableProperty.Create(nameof(PaddingLeft), typeof(float), typeof(SkiaBorder), 0f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).InvalidateMeasure());
public static readonly BindableProperty PaddingRightProperty = BindableProperty.Create("PaddingRight", typeof(float), typeof(SkiaBorder), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty PaddingTopProperty =
BindableProperty.Create(nameof(PaddingTop), typeof(float), typeof(SkiaBorder), 0f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).InvalidateMeasure());
public static readonly BindableProperty PaddingBottomProperty = BindableProperty.Create("PaddingBottom", typeof(float), typeof(SkiaBorder), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty PaddingRightProperty =
BindableProperty.Create(nameof(PaddingRight), typeof(float), typeof(SkiaBorder), 0f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).InvalidateMeasure());
public static readonly BindableProperty HasShadowProperty = BindableProperty.Create("HasShadow", typeof(bool), typeof(SkiaBorder), (object)false, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty PaddingBottomProperty =
BindableProperty.Create(nameof(PaddingBottom), typeof(float), typeof(SkiaBorder), 0f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).InvalidateMeasure());
public static readonly BindableProperty ShadowColorProperty = BindableProperty.Create("ShadowColor", typeof(SKColor), typeof(SkiaBorder), (object)new SKColor((byte)0, (byte)0, (byte)0, (byte)40), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty HasShadowProperty =
BindableProperty.Create(nameof(HasShadow), typeof(bool), typeof(SkiaBorder), false,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public static readonly BindableProperty ShadowBlurRadiusProperty = BindableProperty.Create("ShadowBlurRadius", typeof(float), typeof(SkiaBorder), (object)4f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ShadowColorProperty =
BindableProperty.Create(nameof(ShadowColor), typeof(SKColor), typeof(SkiaBorder), new SKColor(0, 0, 0, 40),
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public static readonly BindableProperty ShadowOffsetXProperty = BindableProperty.Create("ShadowOffsetX", typeof(float), typeof(SkiaBorder), (object)2f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ShadowBlurRadiusProperty =
BindableProperty.Create(nameof(ShadowBlurRadius), typeof(float), typeof(SkiaBorder), 4f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public static readonly BindableProperty ShadowOffsetYProperty = BindableProperty.Create("ShadowOffsetY", typeof(float), typeof(SkiaBorder), (object)2f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBorder)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ShadowOffsetXProperty =
BindableProperty.Create(nameof(ShadowOffsetX), typeof(float), typeof(SkiaBorder), 2f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
private bool _isPressed;
public static readonly BindableProperty ShadowOffsetYProperty =
BindableProperty.Create(nameof(ShadowOffsetY), typeof(float), typeof(SkiaBorder), 2f,
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
public float StrokeThickness
{
get
{
return (float)((BindableObject)this).GetValue(StrokeThicknessProperty);
}
set
{
((BindableObject)this).SetValue(StrokeThicknessProperty, (object)value);
}
}
#endregion
public float CornerRadius
{
get
{
return (float)((BindableObject)this).GetValue(CornerRadiusProperty);
}
set
{
((BindableObject)this).SetValue(CornerRadiusProperty, (object)value);
}
}
#region Properties
public SKColor Stroke
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(StrokeProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(StrokeProperty, (object)value);
}
}
public float StrokeThickness
{
get => (float)GetValue(StrokeThicknessProperty);
set => SetValue(StrokeThicknessProperty, value);
}
public float PaddingLeft
{
get
{
return (float)((BindableObject)this).GetValue(PaddingLeftProperty);
}
set
{
((BindableObject)this).SetValue(PaddingLeftProperty, (object)value);
}
}
public float CornerRadius
{
get => (float)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
public float PaddingTop
{
get
{
return (float)((BindableObject)this).GetValue(PaddingTopProperty);
}
set
{
((BindableObject)this).SetValue(PaddingTopProperty, (object)value);
}
}
public SKColor Stroke
{
get => (SKColor)GetValue(StrokeProperty);
set => SetValue(StrokeProperty, value);
}
public float PaddingRight
{
get
{
return (float)((BindableObject)this).GetValue(PaddingRightProperty);
}
set
{
((BindableObject)this).SetValue(PaddingRightProperty, (object)value);
}
}
public float PaddingLeft
{
get => (float)GetValue(PaddingLeftProperty);
set => SetValue(PaddingLeftProperty, value);
}
public float PaddingBottom
{
get
{
return (float)((BindableObject)this).GetValue(PaddingBottomProperty);
}
set
{
((BindableObject)this).SetValue(PaddingBottomProperty, (object)value);
}
}
public float PaddingTop
{
get => (float)GetValue(PaddingTopProperty);
set => SetValue(PaddingTopProperty, value);
}
public bool HasShadow
{
get
{
return (bool)((BindableObject)this).GetValue(HasShadowProperty);
}
set
{
((BindableObject)this).SetValue(HasShadowProperty, (object)value);
}
}
public float PaddingRight
{
get => (float)GetValue(PaddingRightProperty);
set => SetValue(PaddingRightProperty, value);
}
public SKColor ShadowColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ShadowColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ShadowColorProperty, (object)value);
}
}
public float PaddingBottom
{
get => (float)GetValue(PaddingBottomProperty);
set => SetValue(PaddingBottomProperty, value);
}
public float ShadowBlurRadius
{
get
{
return (float)((BindableObject)this).GetValue(ShadowBlurRadiusProperty);
}
set
{
((BindableObject)this).SetValue(ShadowBlurRadiusProperty, (object)value);
}
}
public bool HasShadow
{
get => (bool)GetValue(HasShadowProperty);
set => SetValue(HasShadowProperty, value);
}
public float ShadowOffsetX
{
get
{
return (float)((BindableObject)this).GetValue(ShadowOffsetXProperty);
}
set
{
((BindableObject)this).SetValue(ShadowOffsetXProperty, (object)value);
}
}
public SKColor ShadowColor
{
get => (SKColor)GetValue(ShadowColorProperty);
set => SetValue(ShadowColorProperty, value);
}
public float ShadowOffsetY
{
get
{
return (float)((BindableObject)this).GetValue(ShadowOffsetYProperty);
}
set
{
((BindableObject)this).SetValue(ShadowOffsetYProperty, (object)value);
}
}
public float ShadowBlurRadius
{
get => (float)GetValue(ShadowBlurRadiusProperty);
set => SetValue(ShadowBlurRadiusProperty, value);
}
public event EventHandler? Tapped;
public float ShadowOffsetX
{
get => (float)GetValue(ShadowOffsetXProperty);
set => SetValue(ShadowOffsetXProperty, value);
}
public void SetPadding(float all)
{
float num = (PaddingBottom = all);
float num3 = (PaddingRight = num);
float paddingLeft = (PaddingTop = num3);
PaddingLeft = paddingLeft;
}
public float ShadowOffsetY
{
get => (float)GetValue(ShadowOffsetYProperty);
set => SetValue(ShadowOffsetYProperty, value);
}
public void SetPadding(float horizontal, float vertical)
{
float paddingLeft = (PaddingRight = horizontal);
PaddingLeft = paddingLeft;
paddingLeft = (PaddingBottom = vertical);
PaddingTop = paddingLeft;
}
#endregion
public void SetPadding(float left, float top, float right, float bottom)
{
PaddingLeft = left;
PaddingTop = top;
PaddingRight = right;
PaddingBottom = bottom;
}
/// <summary>
/// Sets uniform padding on all sides.
/// </summary>
public void SetPadding(float all)
{
PaddingLeft = PaddingTop = PaddingRight = PaddingBottom = all;
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Expected O, but got Unknown
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Expected O, but got Unknown
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Expected O, but got Unknown
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Expected O, but got Unknown
//IL_011b: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_013a: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Expected O, but got Unknown
//IL_0144: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: Unknown result type (might be due to invalid IL or missing references)
//IL_0152: Expected O, but got Unknown
float strokeThickness = StrokeThickness;
float cornerRadius = CornerRadius;
SKRect val = default(SKRect);
((SKRect)(ref val))._002Ector(((SKRect)(ref bounds)).Left + strokeThickness / 2f, ((SKRect)(ref bounds)).Top + strokeThickness / 2f, ((SKRect)(ref bounds)).Right - strokeThickness / 2f, ((SKRect)(ref bounds)).Bottom - strokeThickness / 2f);
if (HasShadow)
{
SKPaint val2 = new SKPaint
{
Color = ShadowColor,
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, ShadowBlurRadius),
Style = (SKPaintStyle)0
};
try
{
SKRect val3 = new SKRect(((SKRect)(ref val)).Left + ShadowOffsetX, ((SKRect)(ref val)).Top + ShadowOffsetY, ((SKRect)(ref val)).Right + ShadowOffsetX, ((SKRect)(ref val)).Bottom + ShadowOffsetY);
canvas.DrawRoundRect(new SKRoundRect(val3, cornerRadius), val2);
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
SKPaint val4 = new SKPaint
{
Color = base.BackgroundColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
canvas.DrawRoundRect(new SKRoundRect(val, cornerRadius), val4);
if (strokeThickness > 0f)
{
SKPaint val5 = new SKPaint
{
Color = Stroke,
Style = (SKPaintStyle)1,
StrokeWidth = strokeThickness,
IsAntialias = true
};
try
{
canvas.DrawRoundRect(new SKRoundRect(val, cornerRadius), val5);
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
foreach (SkiaView child in base.Children)
{
if (child.IsVisible)
{
child.Draw(canvas);
}
}
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
/// <summary>
/// Sets padding with horizontal and vertical values.
/// </summary>
public void SetPadding(float horizontal, float vertical)
{
PaddingLeft = PaddingRight = horizontal;
PaddingTop = PaddingBottom = vertical;
}
protected override SKRect GetContentBounds()
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
return GetContentBounds(base.Bounds);
}
/// <summary>
/// Sets padding with individual values for each side.
/// </summary>
public void SetPadding(float left, float top, float right, float bottom)
{
PaddingLeft = left;
PaddingTop = top;
PaddingRight = right;
PaddingBottom = bottom;
}
protected new SKRect GetContentBounds(SKRect bounds)
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
float strokeThickness = StrokeThickness;
return new SKRect(((SKRect)(ref bounds)).Left + PaddingLeft + strokeThickness, ((SKRect)(ref bounds)).Top + PaddingTop + strokeThickness, ((SKRect)(ref bounds)).Right - PaddingRight - strokeThickness, ((SKRect)(ref bounds)).Bottom - PaddingBottom - strokeThickness);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var strokeThickness = StrokeThickness;
var cornerRadius = CornerRadius;
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
float strokeThickness = StrokeThickness;
float num = PaddingLeft + PaddingRight + strokeThickness * 2f;
float num2 = PaddingTop + PaddingBottom + strokeThickness * 2f;
float num3 = ((base.WidthRequest >= 0.0) ? ((float)base.WidthRequest) : ((SKSize)(ref availableSize)).Width);
float num4 = ((base.HeightRequest >= 0.0) ? ((float)base.HeightRequest) : ((SKSize)(ref availableSize)).Height);
SKSize availableSize2 = default(SKSize);
((SKSize)(ref availableSize2))._002Ector(Math.Max(0f, num3 - num), Math.Max(0f, num4 - num2));
SKSize val = SKSize.Empty;
foreach (SkiaView child in base.Children)
{
SKSize val2 = child.Measure(availableSize2);
val = new SKSize(Math.Max(((SKSize)(ref val)).Width, ((SKSize)(ref val2)).Width), Math.Max(((SKSize)(ref val)).Height, ((SKSize)(ref val2)).Height));
}
float num5 = ((base.WidthRequest >= 0.0) ? ((float)base.WidthRequest) : (((SKSize)(ref val)).Width + num));
float num6 = ((base.HeightRequest >= 0.0) ? ((float)base.HeightRequest) : (((SKSize)(ref val)).Height + num2));
return new SKSize(num5, num6);
}
var borderRect = new SKRect(
bounds.Left + strokeThickness / 2,
bounds.Top + strokeThickness / 2,
bounds.Right - strokeThickness / 2,
bounds.Bottom - strokeThickness / 2);
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
SKRect contentBounds = GetContentBounds(bounds);
SKRect bounds2 = default(SKRect);
foreach (SkiaView child in base.Children)
{
Thickness margin = child.Margin;
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref contentBounds)).Left + (float)((Thickness)(ref margin)).Left, ((SKRect)(ref contentBounds)).Top + (float)((Thickness)(ref margin)).Top, ((SKRect)(ref contentBounds)).Right - (float)((Thickness)(ref margin)).Right, ((SKRect)(ref contentBounds)).Bottom - (float)((Thickness)(ref margin)).Bottom);
child.Arrange(bounds2);
}
return bounds;
}
// Draw shadow if enabled
if (HasShadow)
{
using var shadowPaint = new SKPaint
{
Color = ShadowColor,
MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, ShadowBlurRadius),
Style = SKPaintStyle.Fill
};
var shadowRect = new SKRect(
borderRect.Left + ShadowOffsetX,
borderRect.Top + ShadowOffsetY,
borderRect.Right + ShadowOffsetX,
borderRect.Bottom + ShadowOffsetY);
canvas.DrawRoundRect(new SKRoundRect(shadowRect, cornerRadius), shadowPaint);
}
private bool HasTapGestureRecognizers()
{
View? mauiView = base.MauiView;
if (((mauiView != null) ? mauiView.GestureRecognizers : null) == null)
{
return false;
}
foreach (IGestureRecognizer gestureRecognizer in base.MauiView.GestureRecognizers)
{
if (gestureRecognizer is TapGestureRecognizer)
{
return true;
}
}
return false;
}
// Draw background
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawRoundRect(new SKRoundRect(borderRect, cornerRadius), bgPaint);
public override SkiaView? HitTest(float x, float y)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible && base.IsEnabled)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(new SKPoint(x, y)))
{
if (HasTapGestureRecognizers())
{
Console.WriteLine("[SkiaBorder.HitTest] Intercepting for gesture - returning self");
return this;
}
return base.HitTest(x, y);
}
}
return null;
}
// Draw border
if (strokeThickness > 0)
{
using var borderPaint = new SKPaint
{
Color = Stroke,
Style = SKPaintStyle.Stroke,
StrokeWidth = strokeThickness,
IsAntialias = true
};
canvas.DrawRoundRect(new SKRoundRect(borderRect, cornerRadius), borderPaint);
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (HasTapGestureRecognizers())
{
_isPressed = true;
e.Handled = true;
Console.WriteLine("[SkiaBorder] OnPointerPressed INTERCEPTED for gesture, MauiView=" + ((object)base.MauiView)?.GetType().Name);
if (base.MauiView != null)
{
GestureManager.ProcessPointerDown(base.MauiView, e.X, e.Y);
}
}
else
{
base.OnPointerPressed(e);
}
}
// Draw children
foreach (var child in Children)
{
if (child.IsVisible)
{
child.Draw(canvas);
}
}
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isPressed)
{
_isPressed = false;
e.Handled = true;
Console.WriteLine("[SkiaBorder] OnPointerReleased - processing gesture recognizers, MauiView=" + ((object)base.MauiView)?.GetType().Name);
if (base.MauiView != null)
{
GestureManager.ProcessPointerUp(base.MauiView, e.X, e.Y);
}
this.Tapped?.Invoke(this, EventArgs.Empty);
}
else
{
base.OnPointerReleased(e);
}
}
protected override SKRect GetContentBounds()
{
return GetContentBounds(Bounds);
}
public override void OnPointerExited(PointerEventArgs e)
{
base.OnPointerExited(e);
_isPressed = false;
}
protected new SKRect GetContentBounds(SKRect bounds)
{
var strokeThickness = StrokeThickness;
return new SKRect(
bounds.Left + PaddingLeft + strokeThickness,
bounds.Top + PaddingTop + strokeThickness,
bounds.Right - PaddingRight - strokeThickness,
bounds.Bottom - PaddingBottom - strokeThickness);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
var strokeThickness = StrokeThickness;
var paddingWidth = PaddingLeft + PaddingRight + strokeThickness * 2;
var paddingHeight = PaddingTop + PaddingBottom + strokeThickness * 2;
// Respect explicit size requests
var requestedWidth = WidthRequest >= 0 ? (float)WidthRequest : availableSize.Width;
var requestedHeight = HeightRequest >= 0 ? (float)HeightRequest : availableSize.Height;
var childAvailable = new SKSize(
Math.Max(0, requestedWidth - paddingWidth),
Math.Max(0, requestedHeight - paddingHeight));
var maxChildSize = SKSize.Empty;
foreach (var child in Children)
{
var childSize = child.Measure(childAvailable);
maxChildSize = new SKSize(
Math.Max(maxChildSize.Width, childSize.Width),
Math.Max(maxChildSize.Height, childSize.Height));
}
// Use requested size if set, otherwise use child size + padding
var width = WidthRequest >= 0 ? (float)WidthRequest : maxChildSize.Width + paddingWidth;
var height = HeightRequest >= 0 ? (float)HeightRequest : maxChildSize.Height + paddingHeight;
return new SKSize(width, height);
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
var contentBounds = GetContentBounds(bounds);
foreach (var child in Children)
{
// Apply child's margin
var margin = child.Margin;
var marginedBounds = new SKRect(
contentBounds.Left + (float)margin.Left,
contentBounds.Top + (float)margin.Top,
contentBounds.Right - (float)margin.Right,
contentBounds.Bottom - (float)margin.Bottom);
child.Arrange(marginedBounds);
}
return bounds;
}
}
/// <summary>
/// Frame control - a Border with shadow enabled by default.
/// Mimics the MAUI Frame control appearance.
/// </summary>
public class SkiaFrame : SkiaBorder
{
public SkiaFrame()
{
HasShadow = true;
CornerRadius = 4;
SetPadding(10);
BackgroundColor = SKColors.White;
Stroke = SKColors.Transparent;
StrokeThickness = 0;
}
}

View File

@@ -1,93 +1,66 @@
using System;
using Microsoft.Maui.Controls;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered BoxView - a simple colored rectangle.
/// </summary>
public class SkiaBoxView : SkiaView
{
public static readonly BindableProperty ColorProperty = BindableProperty.Create("Color", typeof(SKColor), typeof(SkiaBoxView), (object)SKColors.Transparent, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBoxView)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ColorProperty =
BindableProperty.Create(nameof(Color), typeof(SKColor), typeof(SkiaBoxView), SKColors.Transparent,
propertyChanged: (b, o, n) => ((SkiaBoxView)b).Invalidate());
public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(float), typeof(SkiaBoxView), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaBoxView)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.Create(nameof(CornerRadius), typeof(float), typeof(SkiaBoxView), 0f,
propertyChanged: (b, o, n) => ((SkiaBoxView)b).Invalidate());
public SKColor Color
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ColorProperty, (object)value);
}
}
public SKColor Color
{
get => (SKColor)GetValue(ColorProperty);
set => SetValue(ColorProperty, value);
}
public float CornerRadius
{
get
{
return (float)((BindableObject)this).GetValue(CornerRadiusProperty);
}
set
{
((BindableObject)this).SetValue(CornerRadiusProperty, (object)value);
}
}
public float CornerRadius
{
get => (float)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = Color,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
if (CornerRadius > 0f)
{
canvas.DrawRoundRect(bounds, CornerRadius, CornerRadius, val);
}
else
{
canvas.DrawRect(bounds, val);
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
using var paint = new SKPaint
{
Color = Color,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
float num = ((base.WidthRequest >= 0.0) ? ((float)base.WidthRequest) : (float.IsInfinity(((SKSize)(ref availableSize)).Width) ? 40f : ((SKSize)(ref availableSize)).Width));
float num2 = ((base.HeightRequest >= 0.0) ? ((float)base.HeightRequest) : (float.IsInfinity(((SKSize)(ref availableSize)).Height) ? 40f : ((SKSize)(ref availableSize)).Height));
if (float.IsNaN(num))
{
num = 40f;
}
if (float.IsNaN(num2))
{
num2 = 40f;
}
return new SKSize(num, num2);
}
if (CornerRadius > 0)
{
canvas.DrawRoundRect(bounds, CornerRadius, CornerRadius, paint);
}
else
{
canvas.DrawRect(bounds, paint);
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
// BoxView uses explicit size or a default size when in unbounded context
var width = WidthRequest >= 0 ? (float)WidthRequest :
(float.IsInfinity(availableSize.Width) ? 40f : availableSize.Width);
var height = HeightRequest >= 0 ? (float)HeightRequest :
(float.IsInfinity(availableSize.Height) ? 40f : availableSize.Height);
// Ensure no NaN values
if (float.IsNaN(width)) width = 40f;
if (float.IsNaN(height)) height = 40f;
return new SKSize(width, height);
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,381 +1,403 @@
using System;
using System.Collections.Generic;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A horizontally scrolling carousel view with snap-to-item behavior.
/// </summary>
public class SkiaCarouselView : SkiaLayoutView
{
private readonly List<SkiaView> _items = new List<SkiaView>();
private readonly List<SkiaView> _items = new();
private int _currentPosition = 0;
private float _scrollOffset = 0f;
private float _targetScrollOffset = 0f;
private bool _isDragging = false;
private float _dragStartX;
private float _dragStartOffset;
private float _velocity = 0f;
private DateTime _lastDragTime;
private float _lastDragX;
private int _currentPosition;
// Animation
private bool _isAnimating = false;
private float _animationStartOffset;
private float _animationTargetOffset;
private DateTime _animationStartTime;
private const float AnimationDurationMs = 300f;
private float _scrollOffset;
/// <summary>
/// Gets or sets the current position (item index).
/// </summary>
public int Position
{
get => _currentPosition;
set
{
if (value >= 0 && value < _items.Count && value != _currentPosition)
{
int oldPosition = _currentPosition;
_currentPosition = value;
AnimateToPosition(value);
PositionChanged?.Invoke(this, new PositionChangedEventArgs(oldPosition, value));
}
}
}
private float _targetScrollOffset;
/// <summary>
/// Gets the item count.
/// </summary>
public int ItemCount => _items.Count;
private bool _isDragging;
/// <summary>
/// Gets or sets whether looping is enabled.
/// </summary>
public bool Loop { get; set; } = false;
private float _dragStartX;
/// <summary>
/// Gets or sets the peek amount (how much of adjacent items to show).
/// </summary>
public float PeekAreaInsets { get; set; } = 0f;
private float _dragStartOffset;
/// <summary>
/// Gets or sets the spacing between items.
/// </summary>
public float ItemSpacing { get; set; } = 0f;
private float _velocity;
/// <summary>
/// Gets or sets whether swipe gestures are enabled.
/// </summary>
public bool IsSwipeEnabled { get; set; } = true;
private DateTime _lastDragTime;
/// <summary>
/// Gets or sets the indicator visibility.
/// </summary>
public bool ShowIndicators { get; set; } = true;
private float _lastDragX;
/// <summary>
/// Gets or sets the indicator color.
/// </summary>
public SKColor IndicatorColor { get; set; } = new SKColor(180, 180, 180);
private bool _isAnimating;
/// <summary>
/// Gets or sets the selected indicator color.
/// </summary>
public SKColor SelectedIndicatorColor { get; set; } = new SKColor(33, 150, 243);
private float _animationStartOffset;
/// <summary>
/// Event raised when position changes.
/// </summary>
public event EventHandler<PositionChangedEventArgs>? PositionChanged;
private float _animationTargetOffset;
/// <summary>
/// Event raised when scrolling.
/// </summary>
public event EventHandler? Scrolled;
private DateTime _animationStartTime;
/// <summary>
/// Adds an item to the carousel.
/// </summary>
public void AddItem(SkiaView item)
{
_items.Add(item);
AddChild(item);
InvalidateMeasure();
Invalidate();
}
private const float AnimationDurationMs = 300f;
/// <summary>
/// Removes an item from the carousel.
/// </summary>
public void RemoveItem(SkiaView item)
{
if (_items.Remove(item))
{
RemoveChild(item);
if (_currentPosition >= _items.Count)
{
_currentPosition = Math.Max(0, _items.Count - 1);
}
InvalidateMeasure();
Invalidate();
}
}
public int Position
{
get
{
return _currentPosition;
}
set
{
if (value >= 0 && value < _items.Count && value != _currentPosition)
{
int currentPosition = _currentPosition;
_currentPosition = value;
AnimateToPosition(value);
this.PositionChanged?.Invoke(this, new PositionChangedEventArgs(currentPosition, value));
}
}
}
/// <summary>
/// Clears all items.
/// </summary>
public void ClearItems()
{
foreach (var item in _items)
{
RemoveChild(item);
}
_items.Clear();
_currentPosition = 0;
_scrollOffset = 0;
_targetScrollOffset = 0;
InvalidateMeasure();
Invalidate();
}
public int ItemCount => _items.Count;
/// <summary>
/// Scrolls to the specified position.
/// </summary>
public void ScrollTo(int position, bool animate = true)
{
if (position < 0 || position >= _items.Count) return;
public bool Loop { get; set; }
int oldPosition = _currentPosition;
_currentPosition = position;
public float PeekAreaInsets { get; set; }
if (animate)
{
AnimateToPosition(position);
}
else
{
_scrollOffset = GetOffsetForPosition(position);
_targetScrollOffset = _scrollOffset;
Invalidate();
}
public float ItemSpacing { get; set; }
if (oldPosition != position)
{
PositionChanged?.Invoke(this, new PositionChangedEventArgs(oldPosition, position));
}
}
public bool IsSwipeEnabled { get; set; } = true;
private void AnimateToPosition(int position)
{
_animationStartOffset = _scrollOffset;
_animationTargetOffset = GetOffsetForPosition(position);
_animationStartTime = DateTime.UtcNow;
_isAnimating = true;
Invalidate();
}
public bool ShowIndicators { get; set; } = true;
private float GetOffsetForPosition(int position)
{
float itemWidth = Bounds.Width - PeekAreaInsets * 2;
return position * (itemWidth + ItemSpacing);
}
public SKColor IndicatorColor { get; set; } = new SKColor((byte)180, (byte)180, (byte)180);
private int GetPositionForOffset(float offset)
{
float itemWidth = Bounds.Width - PeekAreaInsets * 2;
if (itemWidth <= 0) return 0;
return Math.Clamp((int)Math.Round(offset / (itemWidth + ItemSpacing)), 0, Math.Max(0, _items.Count - 1));
}
public SKColor SelectedIndicatorColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
protected override SKSize MeasureOverride(SKSize availableSize)
{
float itemWidth = availableSize.Width - PeekAreaInsets * 2;
float itemHeight = availableSize.Height - (ShowIndicators ? 30 : 0);
public event EventHandler<PositionChangedEventArgs>? PositionChanged;
foreach (var item in _items)
{
item.Measure(new SKSize(itemWidth, itemHeight));
}
public event EventHandler? Scrolled;
return availableSize;
}
public void AddItem(SkiaView item)
{
_items.Add(item);
AddChild(item);
InvalidateMeasure();
Invalidate();
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
float itemWidth = bounds.Width - PeekAreaInsets * 2;
float itemHeight = bounds.Height - (ShowIndicators ? 30 : 0);
public void RemoveItem(SkiaView item)
{
if (_items.Remove(item))
{
RemoveChild(item);
if (_currentPosition >= _items.Count)
{
_currentPosition = Math.Max(0, _items.Count - 1);
}
InvalidateMeasure();
Invalidate();
}
}
for (int i = 0; i < _items.Count; i++)
{
float x = bounds.Left + PeekAreaInsets + i * (itemWidth + ItemSpacing) - _scrollOffset;
var itemBounds = new SKRect(x, bounds.Top, x + itemWidth, bounds.Top + itemHeight);
_items[i].Arrange(itemBounds);
}
public void ClearItems()
{
foreach (SkiaView item in _items)
{
RemoveChild(item);
}
_items.Clear();
_currentPosition = 0;
_scrollOffset = 0f;
_targetScrollOffset = 0f;
InvalidateMeasure();
Invalidate();
}
return bounds;
}
public void ScrollTo(int position, bool animate = true)
{
if (position >= 0 && position < _items.Count)
{
int currentPosition = _currentPosition;
_currentPosition = position;
if (animate)
{
AnimateToPosition(position);
}
else
{
_scrollOffset = GetOffsetForPosition(position);
_targetScrollOffset = _scrollOffset;
Invalidate();
}
if (currentPosition != position)
{
this.PositionChanged?.Invoke(this, new PositionChangedEventArgs(currentPosition, position));
}
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Update animation
if (_isAnimating)
{
float elapsed = (float)(DateTime.UtcNow - _animationStartTime).TotalMilliseconds;
float progress = Math.Clamp(elapsed / AnimationDurationMs, 0f, 1f);
private void AnimateToPosition(int position)
{
_animationStartOffset = _scrollOffset;
_animationTargetOffset = GetOffsetForPosition(position);
_animationStartTime = DateTime.UtcNow;
_isAnimating = true;
Invalidate();
}
// Ease out cubic
float t = 1f - (1f - progress) * (1f - progress) * (1f - progress);
private float GetOffsetForPosition(int position)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
SKRect bounds = base.Bounds;
float num = ((SKRect)(ref bounds)).Width - PeekAreaInsets * 2f;
return (float)position * (num + ItemSpacing);
}
_scrollOffset = _animationStartOffset + (_animationTargetOffset - _animationStartOffset) * t;
private int GetPositionForOffset(float offset)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
SKRect bounds = base.Bounds;
float num = ((SKRect)(ref bounds)).Width - PeekAreaInsets * 2f;
if (num <= 0f)
{
return 0;
}
return Math.Clamp((int)Math.Round(offset / (num + ItemSpacing)), 0, Math.Max(0, _items.Count - 1));
}
if (progress >= 1f)
{
_isAnimating = false;
_scrollOffset = _animationTargetOffset;
}
else
{
Invalidate(); // Continue animation
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
float num = ((SKSize)(ref availableSize)).Width - PeekAreaInsets * 2f;
float num2 = ((SKSize)(ref availableSize)).Height - (float)(ShowIndicators ? 30 : 0);
foreach (SkiaView item in _items)
{
item.Measure(new SKSize(num, num2));
}
return availableSize;
}
canvas.Save();
canvas.ClipRect(bounds);
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
float num = ((SKRect)(ref bounds)).Width - PeekAreaInsets * 2f;
float num2 = ((SKRect)(ref bounds)).Height - (float)(ShowIndicators ? 30 : 0);
SKRect bounds2 = default(SKRect);
for (int i = 0; i < _items.Count; i++)
{
float num3 = ((SKRect)(ref bounds)).Left + PeekAreaInsets + (float)i * (num + ItemSpacing) - _scrollOffset;
((SKRect)(ref bounds2))._002Ector(num3, ((SKRect)(ref bounds)).Top, num3 + num, ((SKRect)(ref bounds)).Top + num2);
_items[i].Arrange(bounds2);
}
return bounds;
}
// Draw visible items
float itemWidth = bounds.Width - PeekAreaInsets * 2;
float contentHeight = bounds.Height - (ShowIndicators ? 30 : 0);
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
if (_isAnimating)
{
float num = Math.Clamp((float)(DateTime.UtcNow - _animationStartTime).TotalMilliseconds / 300f, 0f, 1f);
float num2 = 1f - (1f - num) * (1f - num) * (1f - num);
_scrollOffset = _animationStartOffset + (_animationTargetOffset - _animationStartOffset) * num2;
if (num >= 1f)
{
_isAnimating = false;
_scrollOffset = _animationTargetOffset;
}
else
{
Invalidate();
}
}
canvas.Save();
canvas.ClipRect(bounds, (SKClipOperation)1, false);
float num3 = ((SKRect)(ref bounds)).Width - PeekAreaInsets * 2f;
_ = ((SKRect)(ref bounds)).Height;
_ = ShowIndicators;
for (int i = 0; i < _items.Count; i++)
{
float num4 = ((SKRect)(ref bounds)).Left + PeekAreaInsets + (float)i * (num3 + ItemSpacing) - _scrollOffset;
if (num4 + num3 > ((SKRect)(ref bounds)).Left && num4 < ((SKRect)(ref bounds)).Right)
{
_items[i].Draw(canvas);
}
}
if (ShowIndicators && _items.Count > 1)
{
DrawIndicators(canvas, bounds);
}
canvas.Restore();
}
for (int i = 0; i < _items.Count; i++)
{
float x = bounds.Left + PeekAreaInsets + i * (itemWidth + ItemSpacing) - _scrollOffset;
private void DrawIndicators(SKCanvas canvas, SKRect bounds)
{
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Expected O, but got Unknown
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Expected O, but got Unknown
float num = 8f;
float num2 = 12f;
float num3 = (float)_items.Count * num + (float)(_items.Count - 1) * (num2 - num);
float num4 = ((SKRect)(ref bounds)).MidX - num3 / 2f;
float num5 = ((SKRect)(ref bounds)).Bottom - 15f;
SKPaint val = new SKPaint
{
Color = IndicatorColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
SKPaint val2 = new SKPaint
{
Color = SelectedIndicatorColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
for (int i = 0; i < _items.Count; i++)
{
float num6 = num4 + (float)i * num2;
SKPaint val3 = ((i == _currentPosition) ? val2 : val);
canvas.DrawCircle(num6, num5, num / 2f, val3);
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
// Only draw visible items
if (x + itemWidth > bounds.Left && x < bounds.Right)
{
_items[i].Draw(canvas);
}
}
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
{
foreach (SkiaView item in _items)
{
SkiaView skiaView = item.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
}
}
return null;
}
// Draw indicators
if (ShowIndicators && _items.Count > 1)
{
DrawIndicators(canvas, bounds);
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (base.IsEnabled && IsSwipeEnabled)
{
_isDragging = true;
_dragStartX = e.X;
_dragStartOffset = _scrollOffset;
_lastDragX = e.X;
_lastDragTime = DateTime.UtcNow;
_velocity = 0f;
_isAnimating = false;
e.Handled = true;
base.OnPointerPressed(e);
}
}
canvas.Restore();
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (_isDragging)
{
float num = _dragStartX - e.X;
_scrollOffset = _dragStartOffset + num;
float offsetForPosition = GetOffsetForPosition(_items.Count - 1);
_scrollOffset = Math.Clamp(_scrollOffset, 0f, offsetForPosition);
DateTime utcNow = DateTime.UtcNow;
float num2 = (float)(utcNow - _lastDragTime).TotalSeconds;
if (num2 > 0f)
{
_velocity = (_lastDragX - e.X) / num2;
}
_lastDragX = e.X;
_lastDragTime = utcNow;
this.Scrolled?.Invoke(this, EventArgs.Empty);
Invalidate();
e.Handled = true;
base.OnPointerMoved(e);
}
}
private void DrawIndicators(SKCanvas canvas, SKRect bounds)
{
float indicatorSize = 8f;
float indicatorSpacing = 12f;
float totalWidth = _items.Count * indicatorSize + (_items.Count - 1) * (indicatorSpacing - indicatorSize);
float startX = bounds.MidX - totalWidth / 2;
float y = bounds.Bottom - 15;
public override void OnPointerReleased(PointerEventArgs e)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
if (!_isDragging)
{
return;
}
_isDragging = false;
SKRect bounds = base.Bounds;
_ = ((SKRect)(ref bounds)).Width;
_ = PeekAreaInsets;
int num = GetPositionForOffset(_scrollOffset);
if (Math.Abs(_velocity) > 500f)
{
if (_velocity > 0f && num < _items.Count - 1)
{
num++;
}
else if (_velocity < 0f && num > 0)
{
num--;
}
}
ScrollTo(num);
e.Handled = true;
base.OnPointerReleased(e);
}
using var normalPaint = new SKPaint
{
Color = IndicatorColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
using var selectedPaint = new SKPaint
{
Color = SelectedIndicatorColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
for (int i = 0; i < _items.Count; i++)
{
float x = startX + i * indicatorSpacing;
var paint = i == _currentPosition ? selectedPaint : normalPaint;
canvas.DrawCircle(x, y, indicatorSize / 2, paint);
}
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y)) return null;
// Check items
foreach (var item in _items)
{
var hit = item.HitTest(x, y);
if (hit != null) return hit;
}
return this;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled || !IsSwipeEnabled) return;
_isDragging = true;
_dragStartX = e.X;
_dragStartOffset = _scrollOffset;
_lastDragX = e.X;
_lastDragTime = DateTime.UtcNow;
_velocity = 0;
_isAnimating = false;
e.Handled = true;
base.OnPointerPressed(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!_isDragging) return;
float delta = _dragStartX - e.X;
_scrollOffset = _dragStartOffset + delta;
// Clamp scrolling
float maxOffset = GetOffsetForPosition(_items.Count - 1);
_scrollOffset = Math.Clamp(_scrollOffset, 0, maxOffset);
// Calculate velocity
var now = DateTime.UtcNow;
float timeDelta = (float)(now - _lastDragTime).TotalSeconds;
if (timeDelta > 0)
{
_velocity = (_lastDragX - e.X) / timeDelta;
}
_lastDragX = e.X;
_lastDragTime = now;
Scrolled?.Invoke(this, EventArgs.Empty);
Invalidate();
e.Handled = true;
base.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (!_isDragging) return;
_isDragging = false;
// Determine target position based on velocity and position
float itemWidth = Bounds.Width - PeekAreaInsets * 2;
int targetPosition = GetPositionForOffset(_scrollOffset);
// Apply velocity influence
if (Math.Abs(_velocity) > 500)
{
if (_velocity > 0 && targetPosition < _items.Count - 1)
{
targetPosition++;
}
else if (_velocity < 0 && targetPosition > 0)
{
targetPosition--;
}
}
ScrollTo(targetPosition, true);
e.Handled = true;
base.OnPointerReleased(e);
}
}
/// <summary>
/// Event args for position changed events.
/// </summary>
public class PositionChangedEventArgs : EventArgs
{
public int PreviousPosition { get; }
public int CurrentPosition { get; }
public PositionChangedEventArgs(int previousPosition, int currentPosition)
{
PreviousPosition = previousPosition;
CurrentPosition = currentPosition;
}
}

View File

@@ -1,454 +1,413 @@
using System;
using System.Runtime.CompilerServices;
using Microsoft.Maui.Controls;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
using Microsoft.Maui.Platform.Linux.Rendering;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered checkbox control with full XAML styling support.
/// </summary>
public class SkiaCheckBox : SkiaView
{
public static readonly BindableProperty IsCheckedProperty = BindableProperty.Create("IsChecked", typeof(bool), typeof(SkiaCheckBox), (object)false, (BindingMode)1, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).OnIsCheckedChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
#region BindableProperties
public static readonly BindableProperty CheckColorProperty = BindableProperty.Create("CheckColor", typeof(SKColor), typeof(SkiaCheckBox), (object)SKColors.White, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for IsChecked.
/// </summary>
public static readonly BindableProperty IsCheckedProperty =
BindableProperty.Create(
nameof(IsChecked),
typeof(bool),
typeof(SkiaCheckBox),
false,
BindingMode.TwoWay,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).OnIsCheckedChanged());
public static readonly BindableProperty BoxColorProperty = BindableProperty.Create("BoxColor", typeof(SKColor), typeof(SkiaCheckBox), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for CheckColor.
/// </summary>
public static readonly BindableProperty CheckColorProperty =
BindableProperty.Create(
nameof(CheckColor),
typeof(SKColor),
typeof(SkiaCheckBox),
SKColors.White,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty UncheckedBoxColorProperty = BindableProperty.Create("UncheckedBoxColor", typeof(SKColor), typeof(SkiaCheckBox), (object)SKColors.White, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for BoxColor.
/// </summary>
public static readonly BindableProperty BoxColorProperty =
BindableProperty.Create(
nameof(BoxColor),
typeof(SKColor),
typeof(SkiaCheckBox),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty BorderColorProperty = BindableProperty.Create("BorderColor", typeof(SKColor), typeof(SkiaCheckBox), (object)new SKColor((byte)117, (byte)117, (byte)117), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for UncheckedBoxColor.
/// </summary>
public static readonly BindableProperty UncheckedBoxColorProperty =
BindableProperty.Create(
nameof(UncheckedBoxColor),
typeof(SKColor),
typeof(SkiaCheckBox),
SKColors.White,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create("DisabledColor", typeof(SKColor), typeof(SkiaCheckBox), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for BorderColor.
/// </summary>
public static readonly BindableProperty BorderColorProperty =
BindableProperty.Create(
nameof(BorderColor),
typeof(SKColor),
typeof(SkiaCheckBox),
new SKColor(0x75, 0x75, 0x75),
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty HoveredBorderColorProperty = BindableProperty.Create("HoveredBorderColor", typeof(SKColor), typeof(SkiaCheckBox), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for DisabledColor.
/// </summary>
public static readonly BindableProperty DisabledColorProperty =
BindableProperty.Create(
nameof(DisabledColor),
typeof(SKColor),
typeof(SkiaCheckBox),
new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty BoxSizeProperty = BindableProperty.Create("BoxSize", typeof(float), typeof(SkiaCheckBox), (object)20f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for HoveredBorderColor.
/// </summary>
public static readonly BindableProperty HoveredBorderColorProperty =
BindableProperty.Create(
nameof(HoveredBorderColor),
typeof(SKColor),
typeof(SkiaCheckBox),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(float), typeof(SkiaCheckBox), (object)3f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for BoxSize.
/// </summary>
public static readonly BindableProperty BoxSizeProperty =
BindableProperty.Create(
nameof(BoxSize),
typeof(float),
typeof(SkiaCheckBox),
20f,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).InvalidateMeasure());
public static readonly BindableProperty BorderWidthProperty = BindableProperty.Create("BorderWidth", typeof(float), typeof(SkiaCheckBox), (object)2f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for CornerRadius.
/// </summary>
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.Create(
nameof(CornerRadius),
typeof(float),
typeof(SkiaCheckBox),
3f,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public static readonly BindableProperty CheckStrokeWidthProperty = BindableProperty.Create("CheckStrokeWidth", typeof(float), typeof(SkiaCheckBox), (object)2.5f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaCheckBox)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for BorderWidth.
/// </summary>
public static readonly BindableProperty BorderWidthProperty =
BindableProperty.Create(
nameof(BorderWidth),
typeof(float),
typeof(SkiaCheckBox),
2f,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public bool IsChecked
{
get
{
return (bool)((BindableObject)this).GetValue(IsCheckedProperty);
}
set
{
((BindableObject)this).SetValue(IsCheckedProperty, (object)value);
}
}
/// <summary>
/// Bindable property for CheckStrokeWidth.
/// </summary>
public static readonly BindableProperty CheckStrokeWidthProperty =
BindableProperty.Create(
nameof(CheckStrokeWidth),
typeof(float),
typeof(SkiaCheckBox),
2.5f,
propertyChanged: (b, o, n) => ((SkiaCheckBox)b).Invalidate());
public SKColor CheckColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(CheckColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(CheckColorProperty, (object)value);
}
}
#endregion
public SKColor BoxColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(BoxColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(BoxColorProperty, (object)value);
}
}
#region Properties
public SKColor UncheckedBoxColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(UncheckedBoxColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(UncheckedBoxColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets whether the checkbox is checked.
/// </summary>
public bool IsChecked
{
get => (bool)GetValue(IsCheckedProperty);
set => SetValue(IsCheckedProperty, value);
}
public SKColor BorderColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(BorderColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(BorderColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the check color.
/// </summary>
public SKColor CheckColor
{
get => (SKColor)GetValue(CheckColorProperty);
set => SetValue(CheckColorProperty, value);
}
public SKColor DisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(DisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(DisabledColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the box color when checked.
/// </summary>
public SKColor BoxColor
{
get => (SKColor)GetValue(BoxColorProperty);
set => SetValue(BoxColorProperty, value);
}
public SKColor HoveredBorderColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(HoveredBorderColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(HoveredBorderColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the box color when unchecked.
/// </summary>
public SKColor UncheckedBoxColor
{
get => (SKColor)GetValue(UncheckedBoxColorProperty);
set => SetValue(UncheckedBoxColorProperty, value);
}
public float BoxSize
{
get
{
return (float)((BindableObject)this).GetValue(BoxSizeProperty);
}
set
{
((BindableObject)this).SetValue(BoxSizeProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the border color.
/// </summary>
public SKColor BorderColor
{
get => (SKColor)GetValue(BorderColorProperty);
set => SetValue(BorderColorProperty, value);
}
public float CornerRadius
{
get
{
return (float)((BindableObject)this).GetValue(CornerRadiusProperty);
}
set
{
((BindableObject)this).SetValue(CornerRadiusProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the disabled color.
/// </summary>
public SKColor DisabledColor
{
get => (SKColor)GetValue(DisabledColorProperty);
set => SetValue(DisabledColorProperty, value);
}
public float BorderWidth
{
get
{
return (float)((BindableObject)this).GetValue(BorderWidthProperty);
}
set
{
((BindableObject)this).SetValue(BorderWidthProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the hovered border color.
/// </summary>
public SKColor HoveredBorderColor
{
get => (SKColor)GetValue(HoveredBorderColorProperty);
set => SetValue(HoveredBorderColorProperty, value);
}
public float CheckStrokeWidth
{
get
{
return (float)((BindableObject)this).GetValue(CheckStrokeWidthProperty);
}
set
{
((BindableObject)this).SetValue(CheckStrokeWidthProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the box size.
/// </summary>
public float BoxSize
{
get => (float)GetValue(BoxSizeProperty);
set => SetValue(BoxSizeProperty, value);
}
public bool IsHovered { get; private set; }
/// <summary>
/// Gets or sets the corner radius.
/// </summary>
public float CornerRadius
{
get => (float)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
public event EventHandler<CheckedChangedEventArgs>? CheckedChanged;
/// <summary>
/// Gets or sets the border width.
/// </summary>
public float BorderWidth
{
get => (float)GetValue(BorderWidthProperty);
set => SetValue(BorderWidthProperty, value);
}
public SkiaCheckBox()
{
base.IsFocusable = true;
}
/// <summary>
/// Gets or sets the check stroke width.
/// </summary>
public float CheckStrokeWidth
{
get => (float)GetValue(CheckStrokeWidthProperty);
set => SetValue(CheckStrokeWidthProperty, value);
}
private void OnIsCheckedChanged()
{
this.CheckedChanged?.Invoke(this, new CheckedChangedEventArgs(IsChecked));
SkiaVisualStateManager.GoToState(this, IsChecked ? "Checked" : "Unchecked");
Invalidate();
}
/// <summary>
/// Gets whether the pointer is over the checkbox.
/// </summary>
public bool IsHovered { get; private set; }
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Expected O, but got Unknown
//IL_018b: Unknown result type (might be due to invalid IL or missing references)
//IL_0190: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_0165: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
//IL_01cb: Expected O, but got Unknown
//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
//IL_020a: Unknown result type (might be due to invalid IL or missing references)
//IL_0214: Unknown result type (might be due to invalid IL or missing references)
//IL_021b: Unknown result type (might be due to invalid IL or missing references)
//IL_0222: Unknown result type (might be due to invalid IL or missing references)
//IL_022f: Expected O, but got Unknown
//IL_0202: Unknown result type (might be due to invalid IL or missing references)
//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
//IL_023f: Unknown result type (might be due to invalid IL or missing references)
//IL_0244: Unknown result type (might be due to invalid IL or missing references)
//IL_0246: Unknown result type (might be due to invalid IL or missing references)
//IL_024b: Unknown result type (might be due to invalid IL or missing references)
//IL_0251: Unknown result type (might be due to invalid IL or missing references)
//IL_025b: Unknown result type (might be due to invalid IL or missing references)
//IL_0262: Unknown result type (might be due to invalid IL or missing references)
//IL_0269: Unknown result type (might be due to invalid IL or missing references)
//IL_0276: Expected O, but got Unknown
//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
//IL_0276: Unknown result type (might be due to invalid IL or missing references)
//IL_027d: Unknown result type (might be due to invalid IL or missing references)
//IL_0284: Expected O, but got Unknown
SKRect val = default(SKRect);
((SKRect)(ref val))._002Ector(((SKRect)(ref bounds)).Left + (((SKRect)(ref bounds)).Width - BoxSize) / 2f, ((SKRect)(ref bounds)).Top + (((SKRect)(ref bounds)).Height - BoxSize) / 2f, ((SKRect)(ref bounds)).Left + (((SKRect)(ref bounds)).Width - BoxSize) / 2f + BoxSize, ((SKRect)(ref bounds)).Top + (((SKRect)(ref bounds)).Height - BoxSize) / 2f + BoxSize);
SKRoundRect val2 = new SKRoundRect(val, CornerRadius);
SKColor val3;
if (IsChecked)
{
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(69, 6);
defaultInterpolatedStringHandler.AppendLiteral("[SkiaCheckBox] OnDraw CHECKED - BoxColor=(");
val3 = BoxColor;
defaultInterpolatedStringHandler.AppendFormatted(((SKColor)(ref val3)).Red);
defaultInterpolatedStringHandler.AppendLiteral(",");
val3 = BoxColor;
defaultInterpolatedStringHandler.AppendFormatted(((SKColor)(ref val3)).Green);
defaultInterpolatedStringHandler.AppendLiteral(",");
val3 = BoxColor;
defaultInterpolatedStringHandler.AppendFormatted(((SKColor)(ref val3)).Blue);
defaultInterpolatedStringHandler.AppendLiteral("), UncheckedBoxColor=(");
val3 = UncheckedBoxColor;
defaultInterpolatedStringHandler.AppendFormatted(((SKColor)(ref val3)).Red);
defaultInterpolatedStringHandler.AppendLiteral(",");
val3 = UncheckedBoxColor;
defaultInterpolatedStringHandler.AppendFormatted(((SKColor)(ref val3)).Green);
defaultInterpolatedStringHandler.AppendLiteral(",");
val3 = UncheckedBoxColor;
defaultInterpolatedStringHandler.AppendFormatted(((SKColor)(ref val3)).Blue);
defaultInterpolatedStringHandler.AppendLiteral(")");
Console.WriteLine(defaultInterpolatedStringHandler.ToStringAndClear());
}
SKPaint val4 = new SKPaint
{
Color = ((!base.IsEnabled) ? DisabledColor : (IsChecked ? BoxColor : UncheckedBoxColor)),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRoundRect(val2, val4);
SKPaint val5 = new SKPaint
{
Color = ((!base.IsEnabled) ? DisabledColor : (IsChecked ? BoxColor : (IsHovered ? HoveredBorderColor : BorderColor))),
IsAntialias = true,
Style = (SKPaintStyle)1,
StrokeWidth = BorderWidth
};
try
{
canvas.DrawRoundRect(val2, val5);
if (base.IsFocused)
{
SKPaint val6 = new SKPaint();
val3 = BoxColor;
val6.Color = ((SKColor)(ref val3)).WithAlpha((byte)80);
val6.IsAntialias = true;
val6.Style = (SKPaintStyle)1;
val6.StrokeWidth = 3f;
SKPaint val7 = val6;
try
{
SKRoundRect val8 = new SKRoundRect(val, CornerRadius);
val8.Inflate(4f, 4f);
canvas.DrawRoundRect(val8, val7);
}
finally
{
((IDisposable)val7)?.Dispose();
}
}
if (IsChecked)
{
DrawCheckmark(canvas, val);
}
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
#endregion
private void DrawCheckmark(SKCanvas canvas, SKRect boxRect)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Expected O, but got Unknown
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Expected O, but got Unknown
SKPaint val = new SKPaint
{
Color = SKColors.White,
IsAntialias = true,
Style = (SKPaintStyle)1,
StrokeWidth = CheckStrokeWidth,
StrokeCap = (SKStrokeCap)1,
StrokeJoin = (SKStrokeJoin)1
};
try
{
float num = BoxSize * 0.2f;
float num2 = ((SKRect)(ref boxRect)).Left + num;
float num3 = ((SKRect)(ref boxRect)).Right - num;
float num4 = ((SKRect)(ref boxRect)).Top + num;
float num5 = ((SKRect)(ref boxRect)).Bottom - num;
SKPath val2 = new SKPath();
try
{
val2.MoveTo(num2, ((SKRect)(ref boxRect)).MidY);
val2.LineTo(((SKRect)(ref boxRect)).MidX - num * 0.3f, num5 - num * 0.5f);
val2.LineTo(num3, num4 + num * 0.3f);
canvas.DrawPath(val2, val);
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
/// <summary>
/// Event raised when checked state changes.
/// </summary>
public event EventHandler<CheckedChangedEventArgs>? CheckedChanged;
public override void OnPointerEntered(PointerEventArgs e)
{
if (base.IsEnabled)
{
IsHovered = true;
SkiaVisualStateManager.GoToState(this, "PointerOver");
Invalidate();
}
}
public SkiaCheckBox()
{
IsFocusable = true;
}
public override void OnPointerExited(PointerEventArgs e)
{
IsHovered = false;
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
Invalidate();
}
private void OnIsCheckedChanged()
{
CheckedChanged?.Invoke(this, new CheckedChangedEventArgs(IsChecked));
SkiaVisualStateManager.GoToState(this, IsChecked ? SkiaVisualStateManager.CommonStates.Checked : SkiaVisualStateManager.CommonStates.Unchecked);
Invalidate();
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (base.IsEnabled)
{
IsChecked = !IsChecked;
e.Handled = true;
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Center the checkbox box in bounds
var boxRect = new SKRect(
bounds.Left + (bounds.Width - BoxSize) / 2,
bounds.Top + (bounds.Height - BoxSize) / 2,
bounds.Left + (bounds.Width - BoxSize) / 2 + BoxSize,
bounds.Top + (bounds.Height - BoxSize) / 2 + BoxSize);
public override void OnPointerReleased(PointerEventArgs e)
{
}
var roundRect = new SKRoundRect(boxRect, CornerRadius);
public override void OnKeyDown(KeyEventArgs e)
{
if (base.IsEnabled && e.Key == Key.Space)
{
IsChecked = !IsChecked;
e.Handled = true;
}
}
// Draw background
using var bgPaint = new SKPaint
{
Color = !IsEnabled ? DisabledColor
: IsChecked ? BoxColor
: UncheckedBoxColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
canvas.DrawRoundRect(roundRect, bgPaint);
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
}
// Draw border
using var borderPaint = new SKPaint
{
Color = !IsEnabled ? DisabledColor
: IsChecked ? BoxColor
: IsHovered ? HoveredBorderColor
: BorderColor,
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = BorderWidth
};
canvas.DrawRoundRect(roundRect, borderPaint);
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(BoxSize + 8f, BoxSize + 8f);
}
// Draw focus ring
if (IsFocused)
{
using var focusPaint = new SKPaint
{
Color = BoxColor.WithAlpha(80),
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = 3
};
var focusRect = new SKRoundRect(boxRect, CornerRadius);
focusRect.Inflate(4, 4);
canvas.DrawRoundRect(focusRect, focusPaint);
}
// Draw checkmark
if (IsChecked)
{
DrawCheckmark(canvas, boxRect);
}
}
private void DrawCheckmark(SKCanvas canvas, SKRect boxRect)
{
using var paint = new SKPaint
{
Color = CheckColor,
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = CheckStrokeWidth,
StrokeCap = SKStrokeCap.Round,
StrokeJoin = SKStrokeJoin.Round
};
// Checkmark path - a simple check
var padding = BoxSize * 0.2f;
var left = boxRect.Left + padding;
var right = boxRect.Right - padding;
var top = boxRect.Top + padding;
var bottom = boxRect.Bottom - padding;
// Check starts from bottom-left, goes to middle-bottom, then to top-right
using var path = new SKPath();
path.MoveTo(left, boxRect.MidY);
path.LineTo(boxRect.MidX - padding * 0.3f, bottom - padding * 0.5f);
path.LineTo(right, top + padding * 0.3f);
canvas.DrawPath(path, paint);
}
public override void OnPointerEntered(PointerEventArgs e)
{
if (!IsEnabled) return;
IsHovered = true;
SkiaVisualStateManager.GoToState(this, SkiaVisualStateManager.CommonStates.PointerOver);
Invalidate();
}
public override void OnPointerExited(PointerEventArgs e)
{
IsHovered = false;
SkiaVisualStateManager.GoToState(this, IsEnabled ? SkiaVisualStateManager.CommonStates.Normal : SkiaVisualStateManager.CommonStates.Disabled);
Invalidate();
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
IsChecked = !IsChecked;
e.Handled = true;
}
public override void OnPointerReleased(PointerEventArgs e)
{
// Toggle handled in OnPointerPressed
}
public override void OnKeyDown(KeyEventArgs e)
{
if (!IsEnabled) return;
// Toggle on Space
if (e.Key == Key.Space)
{
IsChecked = !IsChecked;
e.Handled = true;
}
}
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, IsEnabled ? SkiaVisualStateManager.CommonStates.Normal : SkiaVisualStateManager.CommonStates.Disabled);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
// Add some padding around the box for touch targets
return new SKSize(BoxSize + 8, BoxSize + 8);
}
}
/// <summary>
/// Event args for checked changed events.
/// </summary>
public class CheckedChangedEventArgs : EventArgs
{
public bool IsChecked { get; }
public CheckedChangedEventArgs(bool isChecked)
{
IsChecked = isChecked;
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,207 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaContentPage : SkiaPage
{
private readonly List<SkiaToolbarItem> _toolbarItems = new List<SkiaToolbarItem>();
public IList<SkiaToolbarItem> ToolbarItems => _toolbarItems;
protected override void DrawNavigationBar(SKCanvas canvas, SKRect bounds)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Expected O, but got Unknown
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Expected O, but got Unknown
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Expected O, but got Unknown
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Expected O, but got Unknown
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = base.TitleBarColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
if (!string.IsNullOrEmpty(base.Title))
{
SKFont val2 = new SKFont(SKTypeface.Default, 20f, 1f, 0f);
try
{
SKPaint val3 = new SKPaint(val2)
{
Color = base.TitleTextColor,
IsAntialias = true
};
try
{
SKRect val4 = default(SKRect);
val3.MeasureText(base.Title, ref val4);
float num = ((SKRect)(ref bounds)).Left + 56f;
float num2 = ((SKRect)(ref bounds)).MidY - ((SKRect)(ref val4)).MidY;
canvas.DrawText(base.Title, num, num2, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
DrawToolbarItems(canvas, bounds);
SKPaint val5 = new SKPaint
{
Color = new SKColor((byte)0, (byte)0, (byte)0, (byte)30),
Style = (SKPaintStyle)0,
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, 2f)
};
try
{
canvas.DrawRect(new SKRect(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Bottom, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom + 4f), val5);
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
private void DrawToolbarItems(SKCanvas canvas, SKRect navBarBounds)
{
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Expected O, but got Unknown
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Expected O, but got Unknown
//IL_0183: Unknown result type (might be due to invalid IL or missing references)
//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0156: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Expected O, but got Unknown
//IL_022c: Unknown result type (might be due to invalid IL or missing references)
//IL_0167: Unknown result type (might be due to invalid IL or missing references)
List<SkiaToolbarItem> list = _toolbarItems.Where((SkiaToolbarItem t) => t.Order == SkiaToolbarItemOrder.Primary).ToList();
Console.WriteLine($"[SkiaContentPage] DrawToolbarItems: {list.Count} primary items, navBarBounds={navBarBounds}");
if (list.Count == 0)
{
return;
}
SKFont val = new SKFont(SKTypeface.Default, 14f, 1f, 0f);
try
{
SKPaint val2 = new SKPaint(val)
{
Color = base.TitleTextColor,
IsAntialias = true
};
try
{
float num = ((SKRect)(ref navBarBounds)).Right - 16f;
SKRect val3 = default(SKRect);
foreach (SkiaToolbarItem item in list.AsEnumerable().Reverse())
{
float num3;
if (item.Icon != null)
{
float num2 = 40f;
num3 = num - num2;
item.HitBounds = new SKRect(num3, ((SKRect)(ref navBarBounds)).Top, num, ((SKRect)(ref navBarBounds)).Bottom);
float num4 = num3 + (num2 - 24f) / 2f;
float num5 = ((SKRect)(ref navBarBounds)).MidY - 12f;
((SKRect)(ref val3))._002Ector(num4, num5, num4 + 24f, num5 + 24f);
SKPaint val4 = new SKPaint
{
IsAntialias = true
};
try
{
canvas.DrawBitmap(item.Icon, val3, val4);
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
else
{
SKRect val5 = default(SKRect);
val2.MeasureText(item.Text, ref val5);
float num2 = ((SKRect)(ref val5)).Width + 24f;
num3 = num - num2;
item.HitBounds = new SKRect(num3, ((SKRect)(ref navBarBounds)).Top, num, ((SKRect)(ref navBarBounds)).Bottom);
float num6 = num3 + 12f;
float num7 = ((SKRect)(ref navBarBounds)).MidY - ((SKRect)(ref val5)).MidY;
canvas.DrawText(item.Text, num6, num7, val2);
}
Console.WriteLine($"[SkiaContentPage] Toolbar item '{item.Text}' HitBounds set to {item.HitBounds}");
num = num3 - 8f;
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
Console.WriteLine($"[SkiaContentPage] OnPointerPressed at ({e.X}, {e.Y}), ShowNavigationBar={base.ShowNavigationBar}, NavigationBarHeight={base.NavigationBarHeight}");
Console.WriteLine($"[SkiaContentPage] ToolbarItems count: {_toolbarItems.Count}");
if (base.ShowNavigationBar && e.Y < base.NavigationBarHeight)
{
Console.WriteLine("[SkiaContentPage] In navigation bar area, checking toolbar items");
foreach (SkiaToolbarItem item in _toolbarItems.Where((SkiaToolbarItem t) => t.Order == SkiaToolbarItemOrder.Primary))
{
SKRect hitBounds = item.HitBounds;
bool flag = ((SKRect)(ref hitBounds)).Contains(e.X, e.Y);
Console.WriteLine($"[SkiaContentPage] Checking item '{item.Text}', HitBounds=({((SKRect)(ref hitBounds)).Left},{((SKRect)(ref hitBounds)).Top},{((SKRect)(ref hitBounds)).Right},{((SKRect)(ref hitBounds)).Bottom}), Click=({e.X},{e.Y}), Contains={flag}, Command={item.Command != null}");
if (flag)
{
Console.WriteLine("[SkiaContentPage] Toolbar item clicked: " + item.Text);
item.Command?.Execute(null);
return;
}
}
Console.WriteLine("[SkiaContentPage] No toolbar item hit");
}
base.OnPointerPressed(e);
}
}

View File

@@ -1,242 +1,257 @@
using System;
using Microsoft.Maui.Controls;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Presents content within a ControlTemplate.
/// This control acts as a placeholder that gets replaced with the actual content
/// when the template is applied to a control.
/// </summary>
public class SkiaContentPresenter : SkiaView
{
public static readonly BindableProperty ContentProperty = BindableProperty.Create("Content", typeof(SkiaView), typeof(SkiaContentPresenter), (object)null, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaContentPresenter)(object)b).OnContentChanged((SkiaView)o, (SkiaView)n);
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
#region BindableProperties
public static readonly BindableProperty HorizontalContentAlignmentProperty = BindableProperty.Create("HorizontalContentAlignment", typeof(LayoutAlignment), typeof(SkiaContentPresenter), (object)LayoutAlignment.Fill, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaContentPresenter)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ContentProperty =
BindableProperty.Create(nameof(Content), typeof(SkiaView), typeof(SkiaContentPresenter), null,
propertyChanged: (b, o, n) => ((SkiaContentPresenter)b).OnContentChanged((SkiaView?)o, (SkiaView?)n));
public static readonly BindableProperty VerticalContentAlignmentProperty = BindableProperty.Create("VerticalContentAlignment", typeof(LayoutAlignment), typeof(SkiaContentPresenter), (object)LayoutAlignment.Fill, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaContentPresenter)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty HorizontalContentAlignmentProperty =
BindableProperty.Create(nameof(HorizontalContentAlignment), typeof(LayoutAlignment), typeof(SkiaContentPresenter), LayoutAlignment.Fill,
propertyChanged: (b, o, n) => ((SkiaContentPresenter)b).InvalidateMeasure());
public static readonly BindableProperty PaddingProperty = BindableProperty.Create("Padding", typeof(SKRect), typeof(SkiaContentPresenter), (object)SKRect.Empty, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaContentPresenter)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty VerticalContentAlignmentProperty =
BindableProperty.Create(nameof(VerticalContentAlignment), typeof(LayoutAlignment), typeof(SkiaContentPresenter), LayoutAlignment.Fill,
propertyChanged: (b, o, n) => ((SkiaContentPresenter)b).InvalidateMeasure());
public SkiaView? Content
{
get
{
return (SkiaView)((BindableObject)this).GetValue(ContentProperty);
}
set
{
((BindableObject)this).SetValue(ContentProperty, (object)value);
}
}
public static readonly BindableProperty PaddingProperty =
BindableProperty.Create(nameof(Padding), typeof(SKRect), typeof(SkiaContentPresenter), SKRect.Empty,
propertyChanged: (b, o, n) => ((SkiaContentPresenter)b).InvalidateMeasure());
public LayoutAlignment HorizontalContentAlignment
{
get
{
return (LayoutAlignment)((BindableObject)this).GetValue(HorizontalContentAlignmentProperty);
}
set
{
((BindableObject)this).SetValue(HorizontalContentAlignmentProperty, (object)value);
}
}
#endregion
public LayoutAlignment VerticalContentAlignment
{
get
{
return (LayoutAlignment)((BindableObject)this).GetValue(VerticalContentAlignmentProperty);
}
set
{
((BindableObject)this).SetValue(VerticalContentAlignmentProperty, (object)value);
}
}
#region Properties
public SKRect Padding
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKRect)((BindableObject)this).GetValue(PaddingProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(PaddingProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the content to present.
/// </summary>
public SkiaView? Content
{
get => (SkiaView?)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
private void OnContentChanged(SkiaView? oldContent, SkiaView? newContent)
{
if (oldContent != null)
{
oldContent.Parent = null;
}
if (newContent != null)
{
newContent.Parent = this;
if (((BindableObject)this).BindingContext != null)
{
BindableObject.SetInheritedBindingContext((BindableObject)(object)newContent, ((BindableObject)this).BindingContext);
}
}
InvalidateMeasure();
}
/// <summary>
/// Gets or sets the horizontal alignment of the content.
/// </summary>
public LayoutAlignment HorizontalContentAlignment
{
get => (LayoutAlignment)GetValue(HorizontalContentAlignmentProperty);
set => SetValue(HorizontalContentAlignmentProperty, value);
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (Content != null)
{
BindableObject.SetInheritedBindingContext((BindableObject)(object)Content, ((BindableObject)this).BindingContext);
}
}
/// <summary>
/// Gets or sets the vertical alignment of the content.
/// </summary>
public LayoutAlignment VerticalContentAlignment
{
get => (LayoutAlignment)GetValue(VerticalContentAlignmentProperty);
set => SetValue(VerticalContentAlignmentProperty, value);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
if (base.BackgroundColor != SKColors.Transparent)
{
SKPaint val = new SKPaint
{
Color = base.BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
Content?.Draw(canvas);
}
/// <summary>
/// Gets or sets the padding around the content.
/// </summary>
public SKRect Padding
{
get => (SKRect)GetValue(PaddingProperty);
set => SetValue(PaddingProperty, value);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
SKRect padding = Padding;
if (Content == null)
{
return new SKSize(((SKRect)(ref padding)).Left + ((SKRect)(ref padding)).Right, ((SKRect)(ref padding)).Top + ((SKRect)(ref padding)).Bottom);
}
float num = ((HorizontalContentAlignment == LayoutAlignment.Fill) ? Math.Max(0f, ((SKSize)(ref availableSize)).Width - ((SKRect)(ref padding)).Left - ((SKRect)(ref padding)).Right) : float.PositiveInfinity);
float num2 = ((VerticalContentAlignment == LayoutAlignment.Fill) ? Math.Max(0f, ((SKSize)(ref availableSize)).Height - ((SKRect)(ref padding)).Top - ((SKRect)(ref padding)).Bottom) : float.PositiveInfinity);
SKSize val = Content.Measure(new SKSize(num, num2));
return new SKSize(((SKSize)(ref val)).Width + ((SKRect)(ref padding)).Left + ((SKRect)(ref padding)).Right, ((SKSize)(ref val)).Height + ((SKRect)(ref padding)).Top + ((SKRect)(ref padding)).Bottom);
}
#endregion
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
if (Content != null)
{
SKRect padding = Padding;
SKRect availableBounds = new SKRect(((SKRect)(ref bounds)).Left + ((SKRect)(ref padding)).Left, ((SKRect)(ref bounds)).Top + ((SKRect)(ref padding)).Top, ((SKRect)(ref bounds)).Right - ((SKRect)(ref padding)).Right, ((SKRect)(ref bounds)).Bottom - ((SKRect)(ref padding)).Bottom);
SKSize desiredSize = Content.DesiredSize;
SKRect bounds2 = ApplyAlignment(availableBounds, desiredSize, HorizontalContentAlignment, VerticalContentAlignment);
Content.Arrange(bounds2);
}
return bounds;
}
private void OnContentChanged(SkiaView? oldContent, SkiaView? newContent)
{
if (oldContent != null)
{
oldContent.Parent = null;
}
private static SKRect ApplyAlignment(SKRect availableBounds, SKSize contentSize, LayoutAlignment horizontal, LayoutAlignment vertical)
{
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
float num = ((SKRect)(ref availableBounds)).Left;
float num2 = ((SKRect)(ref availableBounds)).Top;
float num3 = ((horizontal == LayoutAlignment.Fill) ? ((SKRect)(ref availableBounds)).Width : ((SKSize)(ref contentSize)).Width);
float num4 = ((vertical == LayoutAlignment.Fill) ? ((SKRect)(ref availableBounds)).Height : ((SKSize)(ref contentSize)).Height);
switch (horizontal)
{
case LayoutAlignment.Center:
num = ((SKRect)(ref availableBounds)).Left + (((SKRect)(ref availableBounds)).Width - num3) / 2f;
break;
case LayoutAlignment.End:
num = ((SKRect)(ref availableBounds)).Right - num3;
break;
}
switch (vertical)
{
case LayoutAlignment.Center:
num2 = ((SKRect)(ref availableBounds)).Top + (((SKRect)(ref availableBounds)).Height - num4) / 2f;
break;
case LayoutAlignment.End:
num2 = ((SKRect)(ref availableBounds)).Bottom - num4;
break;
}
return new SKRect(num, num2, num + num3, num2 + num4);
}
if (newContent != null)
{
newContent.Parent = this;
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
if (Content != null)
{
SkiaView skiaView = Content.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
}
return null;
}
// Propagate binding context to new content
if (BindingContext != null)
{
SetInheritedBindingContext(newContent, BindingContext);
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
Content?.OnPointerPressed(e);
}
InvalidateMeasure();
}
public override void OnPointerMoved(PointerEventArgs e)
{
Content?.OnPointerMoved(e);
}
/// <summary>
/// Called when binding context changes. Propagates to content.
/// </summary>
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
public override void OnPointerReleased(PointerEventArgs e)
{
Content?.OnPointerReleased(e);
}
// Propagate binding context to content
if (Content != null)
{
SetInheritedBindingContext(Content, BindingContext);
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Draw background if set
if (BackgroundColor != SKColors.Transparent)
{
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, bgPaint);
}
// Draw content
Content?.Draw(canvas);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
var padding = Padding;
if (Content == null)
return new SKSize(padding.Left + padding.Right, padding.Top + padding.Bottom);
// When alignment is not Fill, give content unlimited size in that dimension
// so it can measure its natural size without truncation
var measureWidth = HorizontalContentAlignment == LayoutAlignment.Fill
? Math.Max(0, availableSize.Width - padding.Left - padding.Right)
: float.PositiveInfinity;
var measureHeight = VerticalContentAlignment == LayoutAlignment.Fill
? Math.Max(0, availableSize.Height - padding.Top - padding.Bottom)
: float.PositiveInfinity;
var contentSize = Content.Measure(new SKSize(measureWidth, measureHeight));
return new SKSize(
contentSize.Width + padding.Left + padding.Right,
contentSize.Height + padding.Top + padding.Bottom);
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
if (Content != null)
{
var padding = Padding;
var contentBounds = new SKRect(
bounds.Left + padding.Left,
bounds.Top + padding.Top,
bounds.Right - padding.Right,
bounds.Bottom - padding.Bottom);
// Apply alignment
var contentSize = Content.DesiredSize;
var arrangedBounds = ApplyAlignment(contentBounds, contentSize, HorizontalContentAlignment, VerticalContentAlignment);
Content.Arrange(arrangedBounds);
}
return bounds;
}
private static SKRect ApplyAlignment(SKRect availableBounds, SKSize contentSize, LayoutAlignment horizontal, LayoutAlignment vertical)
{
float x = availableBounds.Left;
float y = availableBounds.Top;
float width = horizontal == LayoutAlignment.Fill ? availableBounds.Width : contentSize.Width;
float height = vertical == LayoutAlignment.Fill ? availableBounds.Height : contentSize.Height;
// Horizontal alignment
switch (horizontal)
{
case LayoutAlignment.Center:
x = availableBounds.Left + (availableBounds.Width - width) / 2;
break;
case LayoutAlignment.End:
x = availableBounds.Right - width;
break;
}
// Vertical alignment
switch (vertical)
{
case LayoutAlignment.Center:
y = availableBounds.Top + (availableBounds.Height - height) / 2;
break;
case LayoutAlignment.End:
y = availableBounds.Bottom - height;
break;
}
return new SKRect(x, y, x + width, y + height);
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y))
return null;
// Check content first
if (Content != null)
{
var hit = Content.HitTest(x, y);
if (hit != null)
return hit;
}
return this;
}
public override void OnPointerPressed(PointerEventArgs e)
{
Content?.OnPointerPressed(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
Content?.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
Content?.OnPointerReleased(e);
}
}
/// <summary>
/// Layout alignment options.
/// </summary>
public enum LayoutAlignment
{
/// <summary>
/// Fill the available space.
/// </summary>
Fill,
/// <summary>
/// Align to the start (left or top).
/// </summary>
Start,
/// <summary>
/// Align to the center.
/// </summary>
Center,
/// <summary>
/// Align to the end (right or bottom).
/// </summary>
End
}

View File

@@ -1,312 +0,0 @@
using System;
using System.Collections.Generic;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaContextMenu : SkiaView
{
private readonly List<ContextMenuItem> _items;
private readonly float _x;
private readonly float _y;
private int _hoveredIndex = -1;
private SKRect[] _itemBounds = Array.Empty<SKRect>();
private static readonly SKColor MenuBackground = new SKColor(byte.MaxValue, byte.MaxValue, byte.MaxValue);
private static readonly SKColor MenuBackgroundDark = new SKColor((byte)48, (byte)48, (byte)48);
private static readonly SKColor ItemHoverBackground = new SKColor((byte)227, (byte)242, (byte)253);
private static readonly SKColor ItemHoverBackgroundDark = new SKColor((byte)80, (byte)80, (byte)80);
private static readonly SKColor ItemTextColor = new SKColor((byte)33, (byte)33, (byte)33);
private static readonly SKColor ItemTextColorDark = new SKColor((byte)224, (byte)224, (byte)224);
private static readonly SKColor DisabledTextColor = new SKColor((byte)158, (byte)158, (byte)158);
private static readonly SKColor SeparatorColor = new SKColor((byte)224, (byte)224, (byte)224);
private static readonly SKColor ShadowColor = new SKColor((byte)0, (byte)0, (byte)0, (byte)40);
private const float MenuPadding = 4f;
private const float ItemHeight = 32f;
private const float ItemPaddingH = 16f;
private const float SeparatorHeight = 9f;
private const float CornerRadius = 4f;
private const float MinWidth = 120f;
private bool _isDarkTheme;
public SkiaContextMenu(float x, float y, List<ContextMenuItem> items, bool isDarkTheme = false)
{
_x = x;
_y = y;
_items = items;
_isDarkTheme = isDarkTheme;
base.IsFocusable = true;
}
public override void Draw(SKCanvas canvas)
{
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Expected O, but got Unknown
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Expected O, but got Unknown
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_0128: Expected O, but got Unknown
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_0222: Unknown result type (might be due to invalid IL or missing references)
//IL_0224: Unknown result type (might be due to invalid IL or missing references)
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
//IL_018b: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Expected O, but got Unknown
//IL_0286: Unknown result type (might be due to invalid IL or missing references)
//IL_028b: Unknown result type (might be due to invalid IL or missing references)
//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
//IL_0295: Unknown result type (might be due to invalid IL or missing references)
//IL_023c: Unknown result type (might be due to invalid IL or missing references)
//IL_0241: Unknown result type (might be due to invalid IL or missing references)
//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
//IL_02d4: Expected O, but got Unknown
//IL_0251: Unknown result type (might be due to invalid IL or missing references)
//IL_024a: Unknown result type (might be due to invalid IL or missing references)
//IL_025b: Unknown result type (might be due to invalid IL or missing references)
//IL_0264: Expected O, but got Unknown
//IL_0265: Unknown result type (might be due to invalid IL or missing references)
float num = CalculateMenuWidth();
float num2 = CalculateMenuHeight();
float num3 = _x;
float num4 = _y;
SKRectI val = default(SKRectI);
canvas.GetDeviceClipBounds(ref val);
if (num3 + num > (float)((SKRectI)(ref val)).Right)
{
num3 = (float)((SKRectI)(ref val)).Right - num - 4f;
}
if (num4 + num2 > (float)((SKRectI)(ref val)).Bottom)
{
num4 = (float)((SKRectI)(ref val)).Bottom - num2 - 4f;
}
SKRect val2 = default(SKRect);
((SKRect)(ref val2))._002Ector(num3, num4, num3 + num, num4 + num2);
SKPaint val3 = new SKPaint
{
Color = ShadowColor,
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, 4f)
};
try
{
canvas.DrawRoundRect(((SKRect)(ref val2)).Left + 2f, ((SKRect)(ref val2)).Top + 2f, num, num2, 4f, 4f, val3);
SKPaint val4 = new SKPaint
{
Color = (_isDarkTheme ? MenuBackgroundDark : MenuBackground),
IsAntialias = true
};
try
{
canvas.DrawRoundRect(val2, 4f, 4f, val4);
SKPaint val5 = new SKPaint
{
Color = SeparatorColor,
Style = (SKPaintStyle)1,
StrokeWidth = 1f,
IsAntialias = true
};
try
{
canvas.DrawRoundRect(val2, 4f, 4f, val5);
_itemBounds = (SKRect[])(object)new SKRect[_items.Count];
float num5 = num4 + 4f;
SKRect val7 = default(SKRect);
for (int i = 0; i < _items.Count; i++)
{
ContextMenuItem contextMenuItem = _items[i];
if (contextMenuItem.IsSeparator)
{
float num6 = num5 + 4.5f;
SKPaint val6 = new SKPaint
{
Color = SeparatorColor,
StrokeWidth = 1f
};
try
{
canvas.DrawLine(num3 + 8f, num6, num3 + num - 8f, num6, val6);
_itemBounds[i] = new SKRect(num3, num5, num3 + num, num5 + 9f);
num5 += 9f;
}
finally
{
((IDisposable)val6)?.Dispose();
}
continue;
}
((SKRect)(ref val7))._002Ector(num3 + 4f, num5, num3 + num - 4f, num5 + 32f);
_itemBounds[i] = val7;
if (i == _hoveredIndex && contextMenuItem.IsEnabled)
{
SKPaint val8 = new SKPaint
{
Color = (_isDarkTheme ? ItemHoverBackgroundDark : ItemHoverBackground),
IsAntialias = true
};
try
{
canvas.DrawRoundRect(val7, 4f, 4f, val8);
}
finally
{
((IDisposable)val8)?.Dispose();
}
}
SKPaint val9 = new SKPaint
{
Color = ((!contextMenuItem.IsEnabled) ? DisabledTextColor : (_isDarkTheme ? ItemTextColorDark : ItemTextColor)),
TextSize = 14f,
IsAntialias = true,
Typeface = SKTypeface.Default
};
try
{
float num7 = ((SKRect)(ref val7)).MidY + val9.TextSize / 3f;
canvas.DrawText(contextMenuItem.Text, ((SKRect)(ref val7)).Left + 16f, num7, val9);
num5 += 32f;
}
finally
{
((IDisposable)val9)?.Dispose();
}
}
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
private float CalculateMenuWidth()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Expected O, but got Unknown
float num = 120f;
SKPaint val = new SKPaint
{
TextSize = 14f,
Typeface = SKTypeface.Default
};
try
{
foreach (ContextMenuItem item in _items)
{
if (!item.IsSeparator)
{
float val2 = val.MeasureText(item.Text) + 32f;
num = Math.Max(num, val2);
}
}
return num + 8f;
}
finally
{
((IDisposable)val)?.Dispose();
}
}
private float CalculateMenuHeight()
{
float num = 8f;
foreach (ContextMenuItem item in _items)
{
num += (item.IsSeparator ? 9f : 32f);
}
return num;
}
public override void OnPointerMoved(PointerEventArgs e)
{
int hoveredIndex = _hoveredIndex;
_hoveredIndex = -1;
for (int i = 0; i < _itemBounds.Length; i++)
{
if (((SKRect)(ref _itemBounds[i])).Contains(e.X, e.Y) && !_items[i].IsSeparator)
{
_hoveredIndex = i;
break;
}
}
if (hoveredIndex != _hoveredIndex)
{
Invalidate();
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
for (int i = 0; i < _itemBounds.Length; i++)
{
if (((SKRect)(ref _itemBounds[i])).Contains(e.X, e.Y))
{
ContextMenuItem contextMenuItem = _items[i];
if (contextMenuItem.IsEnabled && !contextMenuItem.IsSeparator && contextMenuItem.Action != null)
{
LinuxDialogService.HideContextMenu();
contextMenuItem.Action();
return;
}
}
}
LinuxDialogService.HideContextMenu();
}
public override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
LinuxDialogService.HideContextMenu();
e.Handled = true;
}
}
}

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,346 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaFlexLayout : SkiaLayoutView
{
public static readonly BindableProperty DirectionProperty = BindableProperty.Create("Direction", typeof(FlexDirection), typeof(SkiaFlexLayout), (object)FlexDirection.Row, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaFlexLayout)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty WrapProperty = BindableProperty.Create("Wrap", typeof(FlexWrap), typeof(SkiaFlexLayout), (object)FlexWrap.NoWrap, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaFlexLayout)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty JustifyContentProperty = BindableProperty.Create("JustifyContent", typeof(FlexJustify), typeof(SkiaFlexLayout), (object)FlexJustify.Start, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaFlexLayout)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty AlignItemsProperty = BindableProperty.Create("AlignItems", typeof(FlexAlignItems), typeof(SkiaFlexLayout), (object)FlexAlignItems.Stretch, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaFlexLayout)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty AlignContentProperty = BindableProperty.Create("AlignContent", typeof(FlexAlignContent), typeof(SkiaFlexLayout), (object)FlexAlignContent.Stretch, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaFlexLayout)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty OrderProperty = BindableProperty.CreateAttached("Order", typeof(int), typeof(SkiaFlexLayout), (object)0, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty GrowProperty = BindableProperty.CreateAttached("Grow", typeof(float), typeof(SkiaFlexLayout), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ShrinkProperty = BindableProperty.CreateAttached("Shrink", typeof(float), typeof(SkiaFlexLayout), (object)1f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty BasisProperty = BindableProperty.CreateAttached("Basis", typeof(FlexBasis), typeof(SkiaFlexLayout), (object)FlexBasis.Auto, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty AlignSelfProperty = BindableProperty.CreateAttached("AlignSelf", typeof(FlexAlignSelf), typeof(SkiaFlexLayout), (object)FlexAlignSelf.Auto, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public FlexDirection Direction
{
get
{
return (FlexDirection)((BindableObject)this).GetValue(DirectionProperty);
}
set
{
((BindableObject)this).SetValue(DirectionProperty, (object)value);
}
}
public FlexWrap Wrap
{
get
{
return (FlexWrap)((BindableObject)this).GetValue(WrapProperty);
}
set
{
((BindableObject)this).SetValue(WrapProperty, (object)value);
}
}
public FlexJustify JustifyContent
{
get
{
return (FlexJustify)((BindableObject)this).GetValue(JustifyContentProperty);
}
set
{
((BindableObject)this).SetValue(JustifyContentProperty, (object)value);
}
}
public FlexAlignItems AlignItems
{
get
{
return (FlexAlignItems)((BindableObject)this).GetValue(AlignItemsProperty);
}
set
{
((BindableObject)this).SetValue(AlignItemsProperty, (object)value);
}
}
public FlexAlignContent AlignContent
{
get
{
return (FlexAlignContent)((BindableObject)this).GetValue(AlignContentProperty);
}
set
{
((BindableObject)this).SetValue(AlignContentProperty, (object)value);
}
}
public static int GetOrder(SkiaView view)
{
return (int)((BindableObject)view).GetValue(OrderProperty);
}
public static void SetOrder(SkiaView view, int value)
{
((BindableObject)view).SetValue(OrderProperty, (object)value);
}
public static float GetGrow(SkiaView view)
{
return (float)((BindableObject)view).GetValue(GrowProperty);
}
public static void SetGrow(SkiaView view, float value)
{
((BindableObject)view).SetValue(GrowProperty, (object)value);
}
public static float GetShrink(SkiaView view)
{
return (float)((BindableObject)view).GetValue(ShrinkProperty);
}
public static void SetShrink(SkiaView view, float value)
{
((BindableObject)view).SetValue(ShrinkProperty, (object)value);
}
public static FlexBasis GetBasis(SkiaView view)
{
return (FlexBasis)((BindableObject)view).GetValue(BasisProperty);
}
public static void SetBasis(SkiaView view, FlexBasis value)
{
((BindableObject)view).SetValue(BasisProperty, (object)value);
}
public static FlexAlignSelf GetAlignSelf(SkiaView view)
{
return (FlexAlignSelf)((BindableObject)view).GetValue(AlignSelfProperty);
}
public static void SetAlignSelf(SkiaView view, FlexAlignSelf value)
{
((BindableObject)view).SetValue(AlignSelfProperty, (object)value);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
bool flag = Direction == FlexDirection.Row || Direction == FlexDirection.RowReverse;
float num = 0f;
float num2 = 0f;
foreach (SkiaView child in base.Children)
{
if (child.IsVisible)
{
SKSize val = child.Measure(availableSize);
if (flag)
{
num += ((SKSize)(ref val)).Width;
num2 = Math.Max(num2, ((SKSize)(ref val)).Height);
}
else
{
num += ((SKSize)(ref val)).Height;
num2 = Math.Max(num2, ((SKSize)(ref val)).Width);
}
}
}
if (!flag)
{
return new SKSize(num2, num);
}
return new SKSize(num, num2);
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_0127: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0173: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
//IL_0489: Unknown result type (might be due to invalid IL or missing references)
if (base.Children.Count == 0)
{
return bounds;
}
bool flag = Direction == FlexDirection.Row || Direction == FlexDirection.RowReverse;
bool flag2 = Direction == FlexDirection.RowReverse || Direction == FlexDirection.ColumnReverse;
List<SkiaView> list = (from c in base.Children
where c.IsVisible
orderby GetOrder(c)
select c).ToList();
if (list.Count == 0)
{
return bounds;
}
float num = (flag ? ((SKRect)(ref bounds)).Width : ((SKRect)(ref bounds)).Height);
float num2 = (flag ? ((SKRect)(ref bounds)).Height : ((SKRect)(ref bounds)).Width);
List<(SkiaView, SKSize, float, float)> list2 = new List<(SkiaView, SKSize, float, float)>();
float num3 = 0f;
float num4 = 0f;
float num5 = 0f;
foreach (SkiaView item10 in list)
{
FlexBasis basis = GetBasis(item10);
float grow = GetGrow(item10);
float shrink = GetShrink(item10);
SKSize item;
if (basis.IsAuto)
{
item = item10.Measure(new SKSize(((SKRect)(ref bounds)).Width, ((SKRect)(ref bounds)).Height));
}
else
{
float length = basis.Length;
item = (flag ? item10.Measure(new SKSize(length, ((SKRect)(ref bounds)).Height)) : item10.Measure(new SKSize(((SKRect)(ref bounds)).Width, length)));
}
list2.Add((item10, item, grow, shrink));
num3 += (flag ? ((SKSize)(ref item)).Width : ((SKSize)(ref item)).Height);
num4 += grow;
num5 += shrink;
}
float num6 = num - num3;
List<(SkiaView, float, float)> list3 = new List<(SkiaView, float, float)>();
foreach (var item11 in list2)
{
SkiaView item2 = item11.Item1;
SKSize item3 = item11.Item2;
float item4 = item11.Item3;
float item5 = item11.Item4;
float num7 = (flag ? ((SKSize)(ref item3)).Width : ((SKSize)(ref item3)).Height);
float item6 = (flag ? ((SKSize)(ref item3)).Height : ((SKSize)(ref item3)).Width);
if (num6 > 0f && num4 > 0f)
{
num7 += num6 * (item4 / num4);
}
else if (num6 < 0f && num5 > 0f)
{
num7 += num6 * (item5 / num5);
}
list3.Add((item2, Math.Max(0f, num7), item6));
}
float num8 = list3.Sum<(SkiaView, float, float)>(((SkiaView child, float mainSize, float crossSize) s) => s.mainSize);
float num9 = Math.Max(0f, num - num8);
float num10 = (flag ? ((SKRect)(ref bounds)).Left : ((SKRect)(ref bounds)).Top);
float num11 = 0f;
switch (JustifyContent)
{
case FlexJustify.Center:
num10 += num9 / 2f;
break;
case FlexJustify.End:
num10 += num9;
break;
case FlexJustify.SpaceBetween:
if (list3.Count > 1)
{
num11 = num9 / (float)(list3.Count - 1);
}
break;
case FlexJustify.SpaceAround:
if (list3.Count > 0)
{
num11 = num9 / (float)list3.Count;
num10 += num11 / 2f;
}
break;
case FlexJustify.SpaceEvenly:
if (list3.Count > 0)
{
num11 = num9 / (float)(list3.Count + 1);
num10 += num11;
}
break;
}
float num12 = num10;
IEnumerable<(SkiaView, float, float)> enumerable2;
if (!flag2)
{
IEnumerable<(SkiaView, float, float)> enumerable = list3;
enumerable2 = enumerable;
}
else
{
enumerable2 = list3.AsEnumerable().Reverse();
}
SKRect bounds2 = default(SKRect);
foreach (var item12 in enumerable2)
{
SkiaView item7 = item12.Item1;
float item8 = item12.Item2;
float item9 = item12.Item3;
FlexAlignSelf alignSelf = GetAlignSelf(item7);
FlexAlignItems flexAlignItems = ((alignSelf == FlexAlignSelf.Auto) ? AlignItems : ((FlexAlignItems)alignSelf));
float num13 = (flag ? ((SKRect)(ref bounds)).Top : ((SKRect)(ref bounds)).Left);
float num14 = item9;
switch (flexAlignItems)
{
case FlexAlignItems.End:
num13 = (flag ? ((SKRect)(ref bounds)).Bottom : ((SKRect)(ref bounds)).Right) - num14;
break;
case FlexAlignItems.Center:
num13 += (num2 - num14) / 2f;
break;
case FlexAlignItems.Stretch:
num14 = num2;
break;
}
if (flag)
{
((SKRect)(ref bounds2))._002Ector(num12, num13, num12 + item8, num13 + num14);
}
else
{
((SKRect)(ref bounds2))._002Ector(num13, num12, num13 + num14, num12 + item8);
}
item7.Arrange(bounds2);
num12 += item8 + num11;
}
return bounds;
}
}

View File

@@ -1,360 +1,381 @@
using System;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A page that displays a flyout menu and detail content.
/// </summary>
public class SkiaFlyoutPage : SkiaLayoutView
{
private SkiaView? _flyout;
private SkiaView? _flyout;
private SkiaView? _detail;
private bool _isPresented = false;
private float _flyoutWidth = 300f;
private float _flyoutAnimationProgress = 0f;
private bool _gestureEnabled = true;
private SkiaView? _detail;
// Gesture tracking
private bool _isDragging = false;
private float _dragStartX;
private float _dragCurrentX;
private bool _isPresented;
/// <summary>
/// Gets or sets the flyout content (menu).
/// </summary>
public SkiaView? Flyout
{
get => _flyout;
set
{
if (_flyout != value)
{
if (_flyout != null)
{
RemoveChild(_flyout);
}
private float _flyoutWidth = 300f;
_flyout = value;
private float _flyoutAnimationProgress;
if (_flyout != null)
{
AddChild(_flyout);
}
private bool _gestureEnabled = true;
Invalidate();
}
}
}
private bool _isDragging;
/// <summary>
/// Gets or sets the detail content (main content).
/// </summary>
public SkiaView? Detail
{
get => _detail;
set
{
if (_detail != value)
{
if (_detail != null)
{
RemoveChild(_detail);
}
private float _dragStartX;
_detail = value;
private float _dragCurrentX;
if (_detail != null)
{
AddChild(_detail);
}
public SkiaView? Flyout
{
get
{
return _flyout;
}
set
{
if (_flyout != value)
{
if (_flyout != null)
{
RemoveChild(_flyout);
}
_flyout = value;
if (_flyout != null)
{
AddChild(_flyout);
}
Invalidate();
}
}
}
Invalidate();
}
}
}
public SkiaView? Detail
{
get
{
return _detail;
}
set
{
if (_detail != value)
{
if (_detail != null)
{
RemoveChild(_detail);
}
_detail = value;
if (_detail != null)
{
AddChild(_detail);
}
Invalidate();
}
}
}
/// <summary>
/// Gets or sets whether the flyout is currently presented.
/// </summary>
public bool IsPresented
{
get => _isPresented;
set
{
if (_isPresented != value)
{
_isPresented = value;
_flyoutAnimationProgress = value ? 1f : 0f;
IsPresentedChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
}
}
public bool IsPresented
{
get
{
return _isPresented;
}
set
{
if (_isPresented != value)
{
_isPresented = value;
_flyoutAnimationProgress = (value ? 1f : 0f);
this.IsPresentedChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
}
}
/// <summary>
/// Gets or sets the width of the flyout panel.
/// </summary>
public float FlyoutWidth
{
get => _flyoutWidth;
set
{
if (_flyoutWidth != value)
{
_flyoutWidth = Math.Max(100, value);
InvalidateMeasure();
Invalidate();
}
}
}
public float FlyoutWidth
{
get
{
return _flyoutWidth;
}
set
{
if (_flyoutWidth != value)
{
_flyoutWidth = Math.Max(100f, value);
InvalidateMeasure();
Invalidate();
}
}
}
/// <summary>
/// Gets or sets whether swipe gestures are enabled.
/// </summary>
public bool GestureEnabled
{
get => _gestureEnabled;
set => _gestureEnabled = value;
}
public bool GestureEnabled
{
get
{
return _gestureEnabled;
}
set
{
_gestureEnabled = value;
}
}
/// <summary>
/// The flyout layout behavior.
/// </summary>
public FlyoutLayoutBehavior FlyoutLayoutBehavior { get; set; } = FlyoutLayoutBehavior.Default;
public FlyoutLayoutBehavior FlyoutLayoutBehavior { get; set; }
/// <summary>
/// Background color of the scrim when flyout is open.
/// </summary>
public SKColor ScrimColor { get; set; } = new SKColor(0, 0, 0, 100);
public SKColor ScrimColor { get; set; } = new SKColor((byte)0, (byte)0, (byte)0, (byte)100);
/// <summary>
/// Shadow width for the flyout.
/// </summary>
public float ShadowWidth { get; set; } = 8f;
public float ShadowWidth { get; set; } = 8f;
/// <summary>
/// Event raised when IsPresented changes.
/// </summary>
public event EventHandler? IsPresentedChanged;
public event EventHandler? IsPresentedChanged;
protected override SKSize MeasureOverride(SKSize availableSize)
{
// Measure flyout
if (_flyout != null)
{
_flyout.Measure(new SKSize(FlyoutWidth, availableSize.Height));
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
if (_flyout != null)
{
_flyout.Measure(new SKSize(FlyoutWidth, ((SKSize)(ref availableSize)).Height));
}
if (_detail != null)
{
_detail.Measure(availableSize);
}
return availableSize;
}
// Measure detail to full size
if (_detail != null)
{
_detail.Measure(availableSize);
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
if (_detail != null)
{
_detail.Arrange(bounds);
}
if (_flyout != null)
{
float num = ((SKRect)(ref bounds)).Left - FlyoutWidth + FlyoutWidth * _flyoutAnimationProgress;
SKRect bounds2 = default(SKRect);
((SKRect)(ref bounds2))._002Ector(num, ((SKRect)(ref bounds)).Top, num + FlyoutWidth, ((SKRect)(ref bounds)).Bottom);
_flyout.Arrange(bounds2);
}
return bounds;
}
return availableSize;
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Expected O, but got Unknown
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
canvas.Save();
canvas.ClipRect(bounds, (SKClipOperation)1, false);
_detail?.Draw(canvas);
if (_flyoutAnimationProgress > 0f)
{
SKPaint val = new SKPaint();
SKColor scrimColor = ScrimColor;
SKColor scrimColor2 = ScrimColor;
val.Color = ((SKColor)(ref scrimColor)).WithAlpha((byte)((float)(int)((SKColor)(ref scrimColor2)).Alpha * _flyoutAnimationProgress));
val.Style = (SKPaintStyle)0;
SKPaint val2 = val;
try
{
canvas.DrawRect(base.Bounds, val2);
if (_flyout != null && ShadowWidth > 0f)
{
DrawFlyoutShadow(canvas);
}
_flyout?.Draw(canvas);
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
canvas.Restore();
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
// Arrange detail to fill the entire area
if (_detail != null)
{
_detail.Arrange(bounds);
}
private void DrawFlyoutShadow(SKCanvas canvas)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Expected O, but got Unknown
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
if (_flyout == null)
{
return;
}
SKRect bounds = _flyout.Bounds;
float right = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
float top = ((SKRect)(ref bounds)).Top;
float num = right + ShadowWidth;
bounds = base.Bounds;
SKRect val = default(SKRect);
((SKRect)(ref val))._002Ector(right, top, num, ((SKRect)(ref bounds)).Bottom);
SKPaint val2 = new SKPaint();
val2.Shader = SKShader.CreateLinearGradient(new SKPoint(((SKRect)(ref val)).Left, ((SKRect)(ref val)).MidY), new SKPoint(((SKRect)(ref val)).Right, ((SKRect)(ref val)).MidY), (SKColor[])(object)new SKColor[2]
{
new SKColor((byte)0, (byte)0, (byte)0, (byte)60),
SKColors.Transparent
}, (float[])null, (SKShaderTileMode)0);
SKPaint val3 = val2;
try
{
canvas.DrawRect(val, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
// Arrange flyout (positioned based on animation progress)
if (_flyout != null)
{
float flyoutX = bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress);
var flyoutBounds = new SKRect(
flyoutX,
bounds.Top,
flyoutX + FlyoutWidth,
bounds.Bottom);
_flyout.Arrange(flyoutBounds);
}
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
if (_flyoutAnimationProgress > 0f && _flyout != null)
{
SkiaView skiaView = _flyout.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
if (_isPresented)
{
return this;
}
}
if (_detail != null)
{
SkiaView skiaView2 = _detail.HitTest(x, y);
if (skiaView2 != null)
{
return skiaView2;
}
}
return this;
}
}
return null;
}
return bounds;
}
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled)
{
return;
}
if (_isPresented && _flyout != null)
{
SKRect bounds = _flyout.Bounds;
if (!((SKRect)(ref bounds)).Contains(e.X, e.Y))
{
IsPresented = false;
e.Handled = true;
return;
}
}
if (_gestureEnabled)
{
_isDragging = true;
_dragStartX = e.X;
_dragCurrentX = e.X;
}
base.OnPointerPressed(e);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
canvas.Save();
canvas.ClipRect(bounds);
public override void OnPointerMoved(PointerEventArgs e)
{
if (_isDragging && _gestureEnabled)
{
_dragCurrentX = e.X;
float num = _dragCurrentX - _dragStartX;
if (_isPresented)
{
_flyoutAnimationProgress = Math.Clamp(1f + num / FlyoutWidth, 0f, 1f);
}
else if (_dragStartX < 30f)
{
_flyoutAnimationProgress = Math.Clamp(num / FlyoutWidth, 0f, 1f);
}
Invalidate();
e.Handled = true;
}
base.OnPointerMoved(e);
}
// Draw detail content first
_detail?.Draw(canvas);
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isDragging)
{
_isDragging = false;
if (_flyoutAnimationProgress > 0.5f)
{
_isPresented = true;
_flyoutAnimationProgress = 1f;
}
else
{
_isPresented = false;
_flyoutAnimationProgress = 0f;
}
this.IsPresentedChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
base.OnPointerReleased(e);
}
// If flyout is visible, draw scrim and flyout
if (_flyoutAnimationProgress > 0)
{
// Draw scrim (semi-transparent overlay)
using var scrimPaint = new SKPaint
{
Color = ScrimColor.WithAlpha((byte)(ScrimColor.Alpha * _flyoutAnimationProgress)),
Style = SKPaintStyle.Fill
};
canvas.DrawRect(Bounds, scrimPaint);
public void ToggleFlyout()
{
IsPresented = !IsPresented;
}
// Draw flyout shadow
if (_flyout != null && ShadowWidth > 0)
{
DrawFlyoutShadow(canvas);
}
// Draw flyout
_flyout?.Draw(canvas);
}
canvas.Restore();
}
private void DrawFlyoutShadow(SKCanvas canvas)
{
if (_flyout == null) return;
float shadowRight = _flyout.Bounds.Right;
var shadowRect = new SKRect(
shadowRight,
Bounds.Top,
shadowRight + ShadowWidth,
Bounds.Bottom);
using var shadowPaint = new SKPaint
{
Shader = SKShader.CreateLinearGradient(
new SKPoint(shadowRect.Left, shadowRect.MidY),
new SKPoint(shadowRect.Right, shadowRect.MidY),
new SKColor[] { new SKColor(0, 0, 0, 60), SKColors.Transparent },
null,
SKShaderTileMode.Clamp)
};
canvas.DrawRect(shadowRect, shadowPaint);
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y)) return null;
// If flyout is presented, check if hit is in flyout
if (_flyoutAnimationProgress > 0 && _flyout != null)
{
var flyoutHit = _flyout.HitTest(x, y);
if (flyoutHit != null) return flyoutHit;
// Hit on scrim closes flyout
if (_isPresented)
{
return this; // Return self to handle scrim tap
}
}
// Check detail content
if (_detail != null)
{
var detailHit = _detail.HitTest(x, y);
if (detailHit != null) return detailHit;
}
return this;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
// Check if tap is on scrim (outside flyout but flyout is open)
if (_isPresented && _flyout != null && !_flyout.Bounds.Contains(e.X, e.Y))
{
IsPresented = false;
e.Handled = true;
return;
}
// Start drag gesture
if (_gestureEnabled)
{
_isDragging = true;
_dragStartX = e.X;
_dragCurrentX = e.X;
}
base.OnPointerPressed(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (_isDragging && _gestureEnabled)
{
_dragCurrentX = e.X;
float delta = _dragCurrentX - _dragStartX;
// Calculate new animation progress
if (_isPresented)
{
// Dragging to close
_flyoutAnimationProgress = Math.Clamp(1f + (delta / FlyoutWidth), 0f, 1f);
}
else
{
// Dragging to open (only from left edge)
if (_dragStartX < 30)
{
_flyoutAnimationProgress = Math.Clamp(delta / FlyoutWidth, 0f, 1f);
}
}
Invalidate();
e.Handled = true;
}
base.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isDragging)
{
_isDragging = false;
// Determine final state based on progress
if (_flyoutAnimationProgress > 0.5f)
{
_isPresented = true;
_flyoutAnimationProgress = 1f;
}
else
{
_isPresented = false;
_flyoutAnimationProgress = 0f;
}
IsPresentedChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
base.OnPointerReleased(e);
}
/// <summary>
/// Toggles the flyout presentation state.
/// </summary>
public void ToggleFlyout()
{
IsPresented = !IsPresented;
}
}
/// <summary>
/// Defines how the flyout behaves.
/// </summary>
public enum FlyoutLayoutBehavior
{
/// <summary>
/// Default behavior based on device/window size.
/// </summary>
Default,
/// <summary>
/// Flyout slides over the detail content.
/// </summary>
Popover,
/// <summary>
/// Flyout and detail are shown side by side.
/// </summary>
Split,
/// <summary>
/// Flyout pushes the detail content.
/// </summary>
SplitOnLandscape,
/// <summary>
/// Flyout is always shown in portrait, side by side in landscape.
/// </summary>
SplitOnPortrait
}

View File

@@ -1,18 +0,0 @@
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaFrame : SkiaBorder
{
public SkiaFrame()
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
base.HasShadow = true;
base.CornerRadius = 4f;
SetPadding(10f);
base.BackgroundColor = SKColors.White;
base.Stroke = SKColors.Transparent;
base.StrokeThickness = 0f;
}
}

View File

@@ -1,81 +1,65 @@
using System;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Graphics.Skia;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered graphics view that supports IDrawable for custom drawing.
/// </summary>
public class SkiaGraphicsView : SkiaView
{
private IDrawable? _drawable;
private IDrawable? _drawable;
public IDrawable? Drawable
{
get
{
return _drawable;
}
set
{
_drawable = value;
Invalidate();
}
}
public IDrawable? Drawable
{
get => _drawable;
set
{
_drawable = value;
Invalidate();
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Expected O, but got Unknown
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
if (base.BackgroundColor != SKColors.Transparent)
{
SKPaint val = new SKPaint
{
Color = base.BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
if (_drawable != null)
{
RectF val2 = default(RectF);
((RectF)(ref val2))._002Ector(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Width, ((SKRect)(ref bounds)).Height);
SkiaCanvas val3 = new SkiaCanvas();
try
{
val3.Canvas = canvas;
_drawable.Draw((ICanvas)(object)val3, val2);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Draw background
if (BackgroundColor != SKColors.Transparent)
{
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, bgPaint);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
if (((SKSize)(ref availableSize)).Width < float.MaxValue && ((SKSize)(ref availableSize)).Height < float.MaxValue)
{
return availableSize;
}
return new SKSize((((SKSize)(ref availableSize)).Width < float.MaxValue) ? ((SKSize)(ref availableSize)).Width : 100f, (((SKSize)(ref availableSize)).Height < float.MaxValue) ? ((SKSize)(ref availableSize)).Height : 100f);
}
// Draw using IDrawable
if (_drawable != null)
{
var dirtyRect = new RectF(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
using var skiaCanvas = new SkiaCanvas();
skiaCanvas.Canvas = canvas;
_drawable.Draw(skiaCanvas, dirtyRect);
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
// Graphics view takes all available space by default
if (availableSize.Width < float.MaxValue && availableSize.Height < float.MaxValue)
{
return availableSize;
}
// Return a reasonable default size
return new SKSize(
availableSize.Width < float.MaxValue ? availableSize.Width : 100,
availableSize.Height < float.MaxValue ? availableSize.Height : 100);
}
}

View File

@@ -1,406 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaGrid : SkiaLayoutView
{
public static readonly BindableProperty RowSpacingProperty = BindableProperty.Create("RowSpacing", typeof(float), typeof(SkiaGrid), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaGrid)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ColumnSpacingProperty = BindableProperty.Create("ColumnSpacing", typeof(float), typeof(SkiaGrid), (object)0f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaGrid)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
private readonly List<GridLength> _rowDefinitions = new List<GridLength>();
private readonly List<GridLength> _columnDefinitions = new List<GridLength>();
private readonly Dictionary<SkiaView, GridPosition> _childPositions = new Dictionary<SkiaView, GridPosition>();
private float[] _rowHeights = Array.Empty<float>();
private float[] _columnWidths = Array.Empty<float>();
public IList<GridLength> RowDefinitions => _rowDefinitions;
public IList<GridLength> ColumnDefinitions => _columnDefinitions;
public float RowSpacing
{
get
{
return (float)((BindableObject)this).GetValue(RowSpacingProperty);
}
set
{
((BindableObject)this).SetValue(RowSpacingProperty, (object)value);
}
}
public float ColumnSpacing
{
get
{
return (float)((BindableObject)this).GetValue(ColumnSpacingProperty);
}
set
{
((BindableObject)this).SetValue(ColumnSpacingProperty, (object)value);
}
}
public void AddChild(SkiaView child, int row, int column, int rowSpan = 1, int columnSpan = 1)
{
base.AddChild(child);
_childPositions[child] = new GridPosition(row, column, rowSpan, columnSpan);
}
public override void RemoveChild(SkiaView child)
{
base.RemoveChild(child);
_childPositions.Remove(child);
}
public GridPosition GetPosition(SkiaView child)
{
if (!_childPositions.TryGetValue(child, out var value))
{
return new GridPosition(0, 0);
}
return value;
}
public void SetPosition(SkiaView child, int row, int column, int rowSpan = 1, int columnSpan = 1)
{
_childPositions[child] = new GridPosition(row, column, rowSpan, columnSpan);
InvalidateMeasure();
Invalidate();
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_022a: Unknown result type (might be due to invalid IL or missing references)
//IL_022f: Unknown result type (might be due to invalid IL or missing references)
//IL_0234: Unknown result type (might be due to invalid IL or missing references)
//IL_0333: Unknown result type (might be due to invalid IL or missing references)
//IL_0338: Unknown result type (might be due to invalid IL or missing references)
//IL_0392: Unknown result type (might be due to invalid IL or missing references)
//IL_0397: Unknown result type (might be due to invalid IL or missing references)
//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
//IL_03b4: Unknown result type (might be due to invalid IL or missing references)
//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
//IL_03c4: Unknown result type (might be due to invalid IL or missing references)
//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
float width = ((SKSize)(ref availableSize)).Width;
SKRect padding = base.Padding;
float num = width - ((SKRect)(ref padding)).Left;
padding = base.Padding;
float num2 = num - ((SKRect)(ref padding)).Right;
float height = ((SKSize)(ref availableSize)).Height;
padding = base.Padding;
float num3 = height - ((SKRect)(ref padding)).Top;
padding = base.Padding;
float num4 = num3 - ((SKRect)(ref padding)).Bottom;
if (float.IsNaN(num2) || float.IsInfinity(num2))
{
num2 = 800f;
}
if (float.IsNaN(num4) || float.IsInfinity(num4))
{
num4 = float.PositiveInfinity;
}
int num5 = Math.Max(1, (_rowDefinitions.Count > 0) ? _rowDefinitions.Count : (GetMaxRow() + 1));
int num6 = Math.Max(1, (_columnDefinitions.Count > 0) ? _columnDefinitions.Count : (GetMaxColumn() + 1));
float[] array = new float[num6];
float[] array2 = new float[num5];
foreach (SkiaView child in base.Children)
{
if (child.IsVisible)
{
GridPosition position = GetPosition(child);
if (((position.Column < _columnDefinitions.Count) ? _columnDefinitions[position.Column] : GridLength.Star).IsAuto && position.ColumnSpan == 1)
{
SKSize val = child.Measure(new SKSize(float.PositiveInfinity, float.PositiveInfinity));
float val2 = (float.IsNaN(((SKSize)(ref val)).Width) ? 0f : ((SKSize)(ref val)).Width);
array[position.Column] = Math.Max(array[position.Column], val2);
}
}
}
_columnWidths = CalculateSizesWithAuto(_columnDefinitions, num2, ColumnSpacing, num6, array);
foreach (SkiaView child2 in base.Children)
{
if (child2.IsVisible)
{
GridPosition position2 = GetPosition(child2);
float cellWidth = GetCellWidth(position2.Column, position2.ColumnSpan);
SKSize val3 = child2.Measure(new SKSize(cellWidth, float.PositiveInfinity));
float num7 = ((SKSize)(ref val3)).Height;
if (float.IsNaN(num7) || float.IsInfinity(num7) || num7 > 100000f)
{
num7 = 44f;
}
if (position2.RowSpan == 1)
{
array2[position2.Row] = Math.Max(array2[position2.Row], num7);
}
}
}
if (float.IsInfinity(num4) || num4 > 100000f)
{
_rowHeights = array2;
}
else
{
_rowHeights = CalculateSizesWithAuto(_rowDefinitions, num4, RowSpacing, num5, array2);
}
foreach (SkiaView child3 in base.Children)
{
if (child3.IsVisible)
{
GridPosition position3 = GetPosition(child3);
float cellWidth2 = GetCellWidth(position3.Column, position3.ColumnSpan);
float cellHeight = GetCellHeight(position3.Row, position3.RowSpan);
child3.Measure(new SKSize(cellWidth2, cellHeight));
}
}
float num8 = _columnWidths.Sum() + (float)Math.Max(0, num6 - 1) * ColumnSpacing;
float num9 = _rowHeights.Sum() + (float)Math.Max(0, num5 - 1) * RowSpacing;
padding = base.Padding;
float num10 = num8 + ((SKRect)(ref padding)).Left;
padding = base.Padding;
float num11 = num10 + ((SKRect)(ref padding)).Right;
padding = base.Padding;
float num12 = num9 + ((SKRect)(ref padding)).Top;
padding = base.Padding;
return new SKSize(num11, num12 + ((SKRect)(ref padding)).Bottom);
}
private int GetMaxRow()
{
int num = 0;
foreach (GridPosition value in _childPositions.Values)
{
num = Math.Max(num, value.Row + value.RowSpan - 1);
}
return num;
}
private int GetMaxColumn()
{
int num = 0;
foreach (GridPosition value in _childPositions.Values)
{
num = Math.Max(num, value.Column + value.ColumnSpan - 1);
}
return num;
}
private float[] CalculateSizesWithAuto(List<GridLength> definitions, float available, float spacing, int count, float[] naturalSizes)
{
if (count == 0)
{
return new float[1] { available };
}
float[] array = new float[count];
float num = (float)Math.Max(0, count - 1) * spacing;
float num2 = available - num;
float num3 = 0f;
for (int i = 0; i < count; i++)
{
GridLength gridLength = ((i < definitions.Count) ? definitions[i] : GridLength.Star);
if (gridLength.IsAbsolute)
{
array[i] = gridLength.Value;
num2 -= gridLength.Value;
}
else if (gridLength.IsAuto)
{
array[i] = naturalSizes[i];
num2 -= array[i];
}
else if (gridLength.IsStar)
{
num3 += gridLength.Value;
}
}
if (num3 > 0f && num2 > 0f)
{
for (int j = 0; j < count; j++)
{
GridLength gridLength2 = ((j < definitions.Count) ? definitions[j] : GridLength.Star);
if (gridLength2.IsStar)
{
array[j] = gridLength2.Value / num3 * num2;
}
}
}
return array;
}
private float GetCellWidth(int column, int span)
{
float num = 0f;
for (int i = column; i < Math.Min(column + span, _columnWidths.Length); i++)
{
num += _columnWidths[i];
if (i > column)
{
num += ColumnSpacing;
}
}
return num;
}
private float GetCellHeight(int row, int span)
{
float num = 0f;
for (int i = row; i < Math.Min(row + span, _rowHeights.Length); i++)
{
num += _rowHeights[i];
if (i > row)
{
num += RowSpacing;
}
}
return num;
}
private float GetColumnOffset(int column)
{
float num = 0f;
for (int i = 0; i < Math.Min(column, _columnWidths.Length); i++)
{
num += _columnWidths[i] + ColumnSpacing;
}
return num;
}
private float GetRowOffset(int row)
{
float num = 0f;
for (int i = 0; i < Math.Min(row, _rowHeights.Length); i++)
{
num += _rowHeights[i] + RowSpacing;
}
return num;
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0349: Unknown result type (might be due to invalid IL or missing references)
//IL_0300: Unknown result type (might be due to invalid IL or missing references)
//IL_0301: Unknown result type (might be due to invalid IL or missing references)
//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
//IL_029d: Unknown result type (might be due to invalid IL or missing references)
//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
//IL_02df: Unknown result type (might be due to invalid IL or missing references)
try
{
SKRect contentBounds = GetContentBounds(bounds);
int num = ((_rowHeights.Length == 0) ? 1 : _rowHeights.Length);
if (_columnWidths.Length != 0)
{
_ = _columnWidths.Length;
}
float[] array = _rowHeights;
if (((SKRect)(ref contentBounds)).Height > 0f && !float.IsInfinity(((SKRect)(ref contentBounds)).Height))
{
float num2 = _rowHeights.Sum() + (float)Math.Max(0, num - 1) * RowSpacing;
if (((SKRect)(ref contentBounds)).Height > num2 + 1f)
{
array = new float[num];
float num3 = ((SKRect)(ref contentBounds)).Height - num2;
float num4 = 0f;
for (int i = 0; i < num; i++)
{
GridLength gridLength = ((i < _rowDefinitions.Count) ? _rowDefinitions[i] : GridLength.Star);
if (gridLength.IsStar)
{
num4 += gridLength.Value;
}
}
for (int j = 0; j < num; j++)
{
GridLength gridLength2 = ((j < _rowDefinitions.Count) ? _rowDefinitions[j] : GridLength.Star);
array[j] = ((j < _rowHeights.Length) ? _rowHeights[j] : 0f);
if (gridLength2.IsStar && num4 > 0f)
{
array[j] += num3 * (gridLength2.Value / num4);
}
}
}
else
{
array = _rowHeights;
}
}
SKRect bounds2 = default(SKRect);
foreach (SkiaView child in base.Children)
{
if (!child.IsVisible)
{
continue;
}
GridPosition position = GetPosition(child);
float num5 = ((SKRect)(ref contentBounds)).Left + GetColumnOffset(position.Column);
float num6 = ((SKRect)(ref contentBounds)).Top;
for (int k = 0; k < Math.Min(position.Row, array.Length); k++)
{
num6 += array[k] + RowSpacing;
}
float num7 = GetCellWidth(position.Column, position.ColumnSpan);
float num8 = 0f;
for (int l = position.Row; l < Math.Min(position.Row + position.RowSpan, array.Length); l++)
{
num8 += array[l];
if (l > position.Row)
{
num8 += RowSpacing;
}
}
if (float.IsInfinity(num7) || float.IsNaN(num7))
{
num7 = ((SKRect)(ref contentBounds)).Width;
}
if (float.IsInfinity(num8) || float.IsNaN(num8) || num8 <= 0f)
{
num8 = ((SKRect)(ref contentBounds)).Height;
}
Thickness margin = child.Margin;
((SKRect)(ref bounds2))._002Ector(num5 + (float)((Thickness)(ref margin)).Left, num6 + (float)((Thickness)(ref margin)).Top, num5 + num7 - (float)((Thickness)(ref margin)).Right, num6 + num8 - (float)((Thickness)(ref margin)).Bottom);
child.Arrange(bounds2);
}
return bounds;
}
catch (Exception ex)
{
Console.WriteLine("[SkiaGrid] EXCEPTION in ArrangeOverride: " + ex.GetType().Name + ": " + ex.Message);
Console.WriteLine($"[SkiaGrid] Bounds: {bounds}, RowHeights: {_rowHeights.Length}, RowDefs: {_rowDefinitions.Count}, Children: {base.Children.Count}");
Console.WriteLine("[SkiaGrid] Stack trace: " + ex.StackTrace);
throw;
}
}
}

View File

@@ -1,553 +1,263 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
using Svg.Skia;
using Microsoft.Maui.Graphics;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered image control.
/// </summary>
public class SkiaImage : SkiaView
{
private SKBitmap? _bitmap;
private SKBitmap? _bitmap;
private SKImage? _image;
private bool _isLoading;
private SKImage? _image;
public SKBitmap? Bitmap
{
get => _bitmap;
set
{
_bitmap?.Dispose();
_bitmap = value;
_image?.Dispose();
_image = value != null ? SKImage.FromBitmap(value) : null;
Invalidate();
}
}
private bool _isLoading;
public Aspect Aspect { get; set; } = Aspect.AspectFit;
public bool IsOpaque { get; set; }
public bool IsLoading => _isLoading;
public bool IsAnimationPlaying { get; set; }
private string? _currentFilePath;
public event EventHandler? ImageLoaded;
public event EventHandler<ImageLoadingErrorEventArgs>? ImageLoadingError;
private bool _isSvg;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Draw background if not opaque
if (!IsOpaque && BackgroundColor != SKColors.Transparent)
{
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, bgPaint);
}
private CancellationTokenSource? _loadCts;
if (_image == null) return;
private readonly object _loadLock = new object();
var imageWidth = _image.Width;
var imageHeight = _image.Height;
private double _svgLoadedWidth;
if (imageWidth <= 0 || imageHeight <= 0) return;
private double _svgLoadedHeight;
var destRect = CalculateDestRect(bounds, imageWidth, imageHeight);
private bool _pendingSvgReload;
using var paint = new SKPaint
{
IsAntialias = true,
FilterQuality = SKFilterQuality.High
};
private SKRect _lastArrangedBounds;
canvas.DrawImage(_image, destRect, paint);
}
public SKBitmap? Bitmap
{
get
{
return _bitmap;
}
set
{
SKBitmap? bitmap = _bitmap;
if (bitmap != null)
{
((SKNativeObject)bitmap).Dispose();
}
_bitmap = value;
SKImage? image = _image;
if (image != null)
{
((SKNativeObject)image).Dispose();
}
_image = ((value != null) ? SKImage.FromBitmap(value) : null);
Invalidate();
}
}
private SKRect CalculateDestRect(SKRect bounds, float imageWidth, float imageHeight)
{
float destX, destY, destWidth, destHeight;
public Aspect Aspect { get; set; }
switch (Aspect)
{
case Aspect.Fill:
// Stretch to fill entire bounds
return bounds;
public bool IsOpaque { get; set; }
case Aspect.AspectFit:
// Scale to fit while maintaining aspect ratio
var fitScale = Math.Min(bounds.Width / imageWidth, bounds.Height / imageHeight);
destWidth = imageWidth * fitScale;
destHeight = imageHeight * fitScale;
destX = bounds.Left + (bounds.Width - destWidth) / 2;
destY = bounds.Top + (bounds.Height - destHeight) / 2;
return new SKRect(destX, destY, destX + destWidth, destY + destHeight);
public bool IsLoading => _isLoading;
case Aspect.AspectFill:
// Scale to fill while maintaining aspect ratio (may crop)
var fillScale = Math.Max(bounds.Width / imageWidth, bounds.Height / imageHeight);
destWidth = imageWidth * fillScale;
destHeight = imageHeight * fillScale;
destX = bounds.Left + (bounds.Width - destWidth) / 2;
destY = bounds.Top + (bounds.Height - destHeight) / 2;
return new SKRect(destX, destY, destX + destWidth, destY + destHeight);
public bool IsAnimationPlaying { get; set; }
case Aspect.Center:
// Center without scaling
destX = bounds.Left + (bounds.Width - imageWidth) / 2;
destY = bounds.Top + (bounds.Height - imageHeight) / 2;
return new SKRect(destX, destY, destX + imageWidth, destY + imageHeight);
public new double WidthRequest
{
get
{
return base.WidthRequest;
}
set
{
base.WidthRequest = value;
ScheduleSvgReloadIfNeeded();
}
}
default:
return bounds;
}
}
public new double HeightRequest
{
get
{
return base.HeightRequest;
}
set
{
base.HeightRequest = value;
ScheduleSvgReloadIfNeeded();
}
}
public async Task LoadFromFileAsync(string filePath)
{
_isLoading = true;
Invalidate();
public event EventHandler? ImageLoaded;
try
{
await Task.Run(() =>
{
using var stream = File.OpenRead(filePath);
var bitmap = SKBitmap.Decode(stream);
if (bitmap != null)
{
Bitmap = bitmap;
}
});
public event EventHandler<ImageLoadingErrorEventArgs>? ImageLoadingError;
_isLoading = false;
ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception ex)
{
_isLoading = false;
ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(ex));
}
private void ScheduleSvgReloadIfNeeded()
{
if (_isSvg && !string.IsNullOrEmpty(_currentFilePath))
{
double widthRequest = WidthRequest;
double heightRequest = HeightRequest;
if (widthRequest > 0.0 && heightRequest > 0.0 && (Math.Abs(_svgLoadedWidth - widthRequest) > 0.5 || Math.Abs(_svgLoadedHeight - heightRequest) > 0.5) && !_pendingSvgReload)
{
_pendingSvgReload = true;
ReloadSvgDebounced();
}
}
}
Invalidate();
}
private async Task ReloadSvgDebounced()
{
await Task.Delay(10);
_pendingSvgReload = false;
if (!string.IsNullOrEmpty(_currentFilePath) && WidthRequest > 0.0 && HeightRequest > 0.0)
{
Console.WriteLine($"[SkiaImage] Reloading SVG at {WidthRequest}x{HeightRequest} (was {_svgLoadedWidth}x{_svgLoadedHeight})");
await LoadSvgAtSizeAsync(_currentFilePath, WidthRequest, HeightRequest);
}
}
public async Task LoadFromStreamAsync(Stream stream)
{
_isLoading = true;
Invalidate();
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected O, but got Unknown
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Expected O, but got Unknown
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
if (!IsOpaque && base.BackgroundColor != SKColors.Transparent)
{
SKPaint val = new SKPaint
{
Color = base.BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
if (_image == null)
{
return;
}
int width = _image.Width;
int height = _image.Height;
if (width <= 0 || height <= 0)
{
return;
}
SKRect val2 = CalculateDestRect(bounds, width, height);
SKPaint val3 = new SKPaint
{
IsAntialias = true,
FilterQuality = (SKFilterQuality)3
};
try
{
canvas.DrawImage(_image, val2, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
try
{
await Task.Run(() =>
{
var bitmap = SKBitmap.Decode(stream);
if (bitmap != null)
{
Bitmap = bitmap;
}
});
private SKRect CalculateDestRect(SKRect bounds, float imageWidth, float imageHeight)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Expected I4, but got Unknown
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
Aspect aspect = Aspect;
switch ((int)aspect)
{
case 2:
return bounds;
case 0:
{
float num6 = Math.Min(((SKRect)(ref bounds)).Width / imageWidth, ((SKRect)(ref bounds)).Height / imageHeight);
float num4 = imageWidth * num6;
float num5 = imageHeight * num6;
float num = ((SKRect)(ref bounds)).Left + (((SKRect)(ref bounds)).Width - num4) / 2f;
float num2 = ((SKRect)(ref bounds)).Top + (((SKRect)(ref bounds)).Height - num5) / 2f;
return new SKRect(num, num2, num + num4, num2 + num5);
}
case 1:
{
float num3 = Math.Max(((SKRect)(ref bounds)).Width / imageWidth, ((SKRect)(ref bounds)).Height / imageHeight);
float num4 = imageWidth * num3;
float num5 = imageHeight * num3;
float num = ((SKRect)(ref bounds)).Left + (((SKRect)(ref bounds)).Width - num4) / 2f;
float num2 = ((SKRect)(ref bounds)).Top + (((SKRect)(ref bounds)).Height - num5) / 2f;
return new SKRect(num, num2, num + num4, num2 + num5);
}
case 3:
{
float num = ((SKRect)(ref bounds)).Left + (((SKRect)(ref bounds)).Width - imageWidth) / 2f;
float num2 = ((SKRect)(ref bounds)).Top + (((SKRect)(ref bounds)).Height - imageHeight) / 2f;
return new SKRect(num, num2, num + imageWidth, num2 + imageHeight);
}
default:
return bounds;
}
}
_isLoading = false;
ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception ex)
{
_isLoading = false;
ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(ex));
}
public async Task LoadFromFileAsync(string filePath)
{
_isLoading = true;
Invalidate();
Console.WriteLine($"[SkiaImage] LoadFromFileAsync: {filePath}, WidthRequest={WidthRequest}, HeightRequest={HeightRequest}");
try
{
List<string> list = new List<string>
{
filePath,
Path.Combine(AppContext.BaseDirectory, filePath),
Path.Combine(AppContext.BaseDirectory, "Resources", "Images", filePath),
Path.Combine(AppContext.BaseDirectory, "Resources", filePath)
};
if (filePath.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
{
string text = Path.ChangeExtension(filePath, ".svg");
list.Add(text);
list.Add(Path.Combine(AppContext.BaseDirectory, text));
list.Add(Path.Combine(AppContext.BaseDirectory, "Resources", "Images", text));
list.Add(Path.Combine(AppContext.BaseDirectory, "Resources", text));
}
string foundPath = null;
foreach (string item in list)
{
if (File.Exists(item))
{
foundPath = item;
Console.WriteLine("[SkiaImage] Found file at: " + item);
break;
}
}
if (foundPath == null)
{
Console.WriteLine("[SkiaImage] File not found: " + filePath);
_isLoading = false;
_isSvg = false;
_currentFilePath = null;
this.ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(new FileNotFoundException(filePath)));
return;
}
_isSvg = foundPath.EndsWith(".svg", StringComparison.OrdinalIgnoreCase);
_currentFilePath = foundPath;
if (!_isSvg)
{
await Task.Run(delegate
{
using FileStream fileStream = File.OpenRead(foundPath);
SKBitmap val = SKBitmap.Decode((Stream)fileStream);
if (val != null)
{
Bitmap = val;
Console.WriteLine("[SkiaImage] Loaded image: " + foundPath);
}
});
}
else
{
await LoadSvgAtSizeAsync(foundPath, WidthRequest, HeightRequest);
}
_isLoading = false;
this.ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception exception)
{
_isLoading = false;
this.ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(exception));
}
Invalidate();
}
Invalidate();
}
private async Task LoadSvgAtSizeAsync(string svgPath, double targetWidth, double targetHeight)
{
_loadCts?.Cancel();
CancellationTokenSource cts = new CancellationTokenSource();
_loadCts = cts;
try
{
SKBitmap newBitmap = null;
await Task.Run(delegate
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Expected O, but got Unknown
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Expected O, but got Unknown
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
if (cts.Token.IsCancellationRequested)
{
return;
}
SKSvg val = new SKSvg();
try
{
val.Load(svgPath);
if (val.Picture != null && !cts.Token.IsCancellationRequested)
{
SKRect cullRect = val.Picture.CullRect;
float num = ((targetWidth > 0.0) ? ((float)targetWidth) : ((((SKRect)(ref cullRect)).Width <= 24f) ? 24f : ((SKRect)(ref cullRect)).Width));
float num2 = Math.Min(val2: ((targetHeight > 0.0) ? ((float)targetHeight) : ((((SKRect)(ref cullRect)).Height <= 24f) ? 24f : ((SKRect)(ref cullRect)).Height)) / ((SKRect)(ref cullRect)).Height, val1: num / ((SKRect)(ref cullRect)).Width);
int num3 = Math.Max(1, (int)(((SKRect)(ref cullRect)).Width * num2));
int num4 = Math.Max(1, (int)(((SKRect)(ref cullRect)).Height * num2));
newBitmap = new SKBitmap(num3, num4, false);
SKCanvas val2 = new SKCanvas(newBitmap);
try
{
val2.Clear(SKColors.Transparent);
val2.Scale(num2);
val2.DrawPicture(val.Picture, (SKPaint)null);
Console.WriteLine($"[SkiaImage] Loaded SVG: {svgPath} at {num3}x{num4} (requested {targetWidth}x{targetHeight})");
return;
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}, cts.Token);
if (!cts.Token.IsCancellationRequested && newBitmap != null)
{
_svgLoadedWidth = ((targetWidth > 0.0) ? targetWidth : ((double)newBitmap.Width));
_svgLoadedHeight = ((targetHeight > 0.0) ? targetHeight : ((double)newBitmap.Height));
Bitmap = newBitmap;
return;
}
SKBitmap obj = newBitmap;
if (obj != null)
{
((SKNativeObject)obj).Dispose();
}
}
catch (OperationCanceledException)
{
}
}
public async Task LoadFromUriAsync(Uri uri)
{
_isLoading = true;
Invalidate();
public async Task LoadFromStreamAsync(Stream stream)
{
_isLoading = true;
Invalidate();
try
{
await Task.Run(delegate
{
SKBitmap val = SKBitmap.Decode(stream);
if (val != null)
{
Bitmap = val;
}
});
_isLoading = false;
this.ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception exception)
{
_isLoading = false;
this.ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(exception));
}
Invalidate();
}
try
{
using var httpClient = new HttpClient();
var data = await httpClient.GetByteArrayAsync(uri);
public async Task LoadFromUriAsync(Uri uri)
{
_isLoading = true;
Invalidate();
try
{
using HttpClient httpClient = new HttpClient();
using MemoryStream memoryStream = new MemoryStream(await httpClient.GetByteArrayAsync(uri));
SKBitmap val = SKBitmap.Decode((Stream)memoryStream);
if (val != null)
{
Bitmap = val;
}
_isLoading = false;
this.ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception exception)
{
_isLoading = false;
this.ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(exception));
}
Invalidate();
}
using var stream = new MemoryStream(data);
var bitmap = SKBitmap.Decode(stream);
if (bitmap != null)
{
Bitmap = bitmap;
}
public void LoadFromData(byte[] data)
{
try
{
using MemoryStream memoryStream = new MemoryStream(data);
SKBitmap val = SKBitmap.Decode((Stream)memoryStream);
if (val != null)
{
Bitmap = val;
}
this.ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception exception)
{
this.ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(exception));
}
}
_isLoading = false;
ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception ex)
{
_isLoading = false;
ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(ex));
}
public void LoadFromBitmap(SKBitmap bitmap)
{
try
{
_isSvg = false;
_currentFilePath = null;
Bitmap = bitmap;
_isLoading = false;
this.ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception exception)
{
_isLoading = false;
this.ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(exception));
}
Invalidate();
}
Invalidate();
}
public override void Arrange(SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
base.Arrange(bounds);
if ((!(base.WidthRequest > 0.0) || !(base.HeightRequest > 0.0)) && _isSvg && !string.IsNullOrEmpty(_currentFilePath) && !_isLoading)
{
float width = ((SKRect)(ref bounds)).Width;
float height = ((SKRect)(ref bounds)).Height;
if (((double)width > _svgLoadedWidth * 1.1 || (double)height > _svgLoadedHeight * 1.1) && width > 0f && height > 0f && (width != ((SKRect)(ref _lastArrangedBounds)).Width || height != ((SKRect)(ref _lastArrangedBounds)).Height))
{
_lastArrangedBounds = bounds;
Console.WriteLine($"[SkiaImage] Arrange detected larger bounds: {width}x{height} vs loaded {_svgLoadedWidth}x{_svgLoadedHeight}");
LoadSvgAtSizeAsync(_currentFilePath, width, height);
}
}
}
public void LoadFromData(byte[] data)
{
try
{
using var stream = new MemoryStream(data);
var bitmap = SKBitmap.Decode(stream);
if (bitmap != null)
{
Bitmap = bitmap;
}
ImageLoaded?.Invoke(this, EventArgs.Empty);
}
catch (Exception ex)
{
ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(ex));
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0107: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
double widthRequest = base.WidthRequest;
double heightRequest = base.HeightRequest;
if (widthRequest > 0.0 && heightRequest > 0.0)
{
return new SKSize((float)widthRequest, (float)heightRequest);
}
if (_image == null)
{
if (widthRequest > 0.0)
{
return new SKSize((float)widthRequest, (float)widthRequest);
}
if (heightRequest > 0.0)
{
return new SKSize((float)heightRequest, (float)heightRequest);
}
return new SKSize(100f, 100f);
}
float num = _image.Width;
float num2 = _image.Height;
if (widthRequest > 0.0)
{
float num3 = (float)widthRequest / num;
return new SKSize((float)widthRequest, num2 * num3);
}
if (heightRequest > 0.0)
{
float num4 = (float)heightRequest / num2;
return new SKSize(num * num4, (float)heightRequest);
}
if (((SKSize)(ref availableSize)).Width < float.MaxValue && ((SKSize)(ref availableSize)).Height < float.MaxValue)
{
float num5 = Math.Min(((SKSize)(ref availableSize)).Width / num, ((SKSize)(ref availableSize)).Height / num2);
return new SKSize(num * num5, num2 * num5);
}
if (((SKSize)(ref availableSize)).Width < float.MaxValue)
{
float num6 = ((SKSize)(ref availableSize)).Width / num;
return new SKSize(((SKSize)(ref availableSize)).Width, num2 * num6);
}
if (((SKSize)(ref availableSize)).Height < float.MaxValue)
{
float num7 = ((SKSize)(ref availableSize)).Height / num2;
return new SKSize(num * num7, ((SKSize)(ref availableSize)).Height);
}
return new SKSize(num, num2);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
if (_image == null)
return new SKSize(100, 100); // Default size
protected override void Dispose(bool disposing)
{
if (disposing)
{
SKBitmap? bitmap = _bitmap;
if (bitmap != null)
{
((SKNativeObject)bitmap).Dispose();
}
SKImage? image = _image;
if (image != null)
{
((SKNativeObject)image).Dispose();
}
}
base.Dispose(disposing);
}
var imageWidth = _image.Width;
var imageHeight = _image.Height;
// If we have constraints, respect them
if (availableSize.Width < float.MaxValue && availableSize.Height < float.MaxValue)
{
var scale = Math.Min(availableSize.Width / imageWidth, availableSize.Height / imageHeight);
return new SKSize(imageWidth * scale, imageHeight * scale);
}
else if (availableSize.Width < float.MaxValue)
{
var scale = availableSize.Width / imageWidth;
return new SKSize(availableSize.Width, imageHeight * scale);
}
else if (availableSize.Height < float.MaxValue)
{
var scale = availableSize.Height / imageHeight;
return new SKSize(imageWidth * scale, availableSize.Height);
}
return new SKSize(imageWidth, imageHeight);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_bitmap?.Dispose();
_image?.Dispose();
}
base.Dispose(disposing);
}
}
/// <summary>
/// Event args for image loading errors.
/// </summary>
public class ImageLoadingErrorEventArgs : EventArgs
{
public Exception Exception { get; }
public ImageLoadingErrorEventArgs(Exception exception)
{
Exception = exception;
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,325 +1,316 @@
using System;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A view that displays indicators for a collection of items.
/// Used to show page indicators for CarouselView or similar controls.
/// </summary>
public class SkiaIndicatorView : SkiaView
{
private int _count;
private int _count = 0;
private int _position = 0;
private int _position;
/// <summary>
/// Gets or sets the number of indicators to display.
/// </summary>
public int Count
{
get => _count;
set
{
if (_count != value)
{
_count = Math.Max(0, value);
if (_position >= _count)
{
_position = Math.Max(0, _count - 1);
}
InvalidateMeasure();
Invalidate();
}
}
}
public int Count
{
get
{
return _count;
}
set
{
if (_count != value)
{
_count = Math.Max(0, value);
if (_position >= _count)
{
_position = Math.Max(0, _count - 1);
}
InvalidateMeasure();
Invalidate();
}
}
}
/// <summary>
/// Gets or sets the selected position.
/// </summary>
public int Position
{
get => _position;
set
{
int newValue = Math.Clamp(value, 0, Math.Max(0, _count - 1));
if (_position != newValue)
{
_position = newValue;
Invalidate();
}
}
}
public int Position
{
get
{
return _position;
}
set
{
int num = Math.Clamp(value, 0, Math.Max(0, _count - 1));
if (_position != num)
{
_position = num;
Invalidate();
}
}
}
/// <summary>
/// Gets or sets the indicator color.
/// </summary>
public SKColor IndicatorColor { get; set; } = new SKColor(180, 180, 180);
public SKColor IndicatorColor { get; set; } = new SKColor((byte)180, (byte)180, (byte)180);
/// <summary>
/// Gets or sets the selected indicator color.
/// </summary>
public SKColor SelectedIndicatorColor { get; set; } = new SKColor(33, 150, 243);
public SKColor SelectedIndicatorColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
/// <summary>
/// Gets or sets the indicator size.
/// </summary>
public float IndicatorSize { get; set; } = 10f;
public float IndicatorSize { get; set; } = 10f;
/// <summary>
/// Gets or sets the selected indicator size.
/// </summary>
public float SelectedIndicatorSize { get; set; } = 10f;
public float SelectedIndicatorSize { get; set; } = 10f;
/// <summary>
/// Gets or sets the spacing between indicators.
/// </summary>
public float IndicatorSpacing { get; set; } = 8f;
public float IndicatorSpacing { get; set; } = 8f;
/// <summary>
/// Gets or sets the indicator shape.
/// </summary>
public IndicatorShape IndicatorShape { get; set; } = IndicatorShape.Circle;
public IndicatorShape IndicatorShape { get; set; }
/// <summary>
/// Gets or sets whether indicators should have a border.
/// </summary>
public bool ShowBorder { get; set; } = false;
public bool ShowBorder { get; set; }
/// <summary>
/// Gets or sets the border color.
/// </summary>
public SKColor BorderColor { get; set; } = new SKColor(100, 100, 100);
public SKColor BorderColor { get; set; } = new SKColor((byte)100, (byte)100, (byte)100);
/// <summary>
/// Gets or sets the border width.
/// </summary>
public float BorderWidth { get; set; } = 1f;
public float BorderWidth { get; set; } = 1f;
/// <summary>
/// Gets or sets the maximum visible indicators.
/// </summary>
public int MaximumVisible { get; set; } = 10;
public int MaximumVisible { get; set; } = 10;
/// <summary>
/// Gets or sets whether to hide indicators when count is 1 or less.
/// </summary>
public bool HideSingle { get; set; } = true;
public bool HideSingle { get; set; } = true;
protected override SKSize MeasureOverride(SKSize availableSize)
{
if (_count <= 0 || (HideSingle && _count <= 1))
{
return SKSize.Empty;
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
if (_count <= 0 || (HideSingle && _count <= 1))
{
return SKSize.Empty;
}
int num = Math.Min(_count, MaximumVisible);
float num2 = (float)num * IndicatorSize + (float)(num - 1) * IndicatorSpacing;
float num3 = Math.Max(IndicatorSize, SelectedIndicatorSize);
return new SKSize(num2, num3);
}
int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * IndicatorSize + (visibleCount - 1) * IndicatorSpacing;
float height = Math.Max(IndicatorSize, SelectedIndicatorSize);
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Expected O, but got Unknown
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Unknown result type (might be due to invalid IL or missing references)
//IL_012d: Expected O, but got Unknown
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Unknown result type (might be due to invalid IL or missing references)
//IL_0134: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_0145: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_015a: Expected O, but got Unknown
if (_count <= 0 || (HideSingle && _count <= 1))
{
return;
}
canvas.Save();
canvas.ClipRect(base.Bounds, (SKClipOperation)1, false);
int num = Math.Min(_count, MaximumVisible);
float num2 = (float)num * IndicatorSize + (float)(num - 1) * IndicatorSpacing;
SKRect bounds2 = base.Bounds;
float num3 = ((SKRect)(ref bounds2)).MidX - num2 / 2f + IndicatorSize / 2f;
bounds2 = base.Bounds;
float midY = ((SKRect)(ref bounds2)).MidY;
int num4 = 0;
int num5 = num;
if (_count > MaximumVisible)
{
int num6 = MaximumVisible / 2;
num4 = Math.Max(0, _position - num6);
num5 = Math.Min(_count, num4 + MaximumVisible);
if (num5 == _count)
{
num4 = _count - MaximumVisible;
}
}
SKPaint val = new SKPaint
{
Color = IndicatorColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
SKPaint val2 = new SKPaint
{
Color = SelectedIndicatorColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
SKPaint val3 = new SKPaint
{
Color = BorderColor,
Style = (SKPaintStyle)1,
StrokeWidth = BorderWidth,
IsAntialias = true
};
try
{
for (int i = num4; i < num5; i++)
{
int num7 = i - num4;
float x = num3 + (float)num7 * (IndicatorSize + IndicatorSpacing);
bool num8 = i == _position;
SKPaint fillPaint = (num8 ? val2 : val);
float size = (num8 ? SelectedIndicatorSize : IndicatorSize);
DrawIndicator(canvas, x, midY, size, fillPaint, val3);
}
canvas.Restore();
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
return new SKSize(totalWidth, height);
}
private void DrawIndicator(SKCanvas canvas, float x, float y, float size, SKPaint fillPaint, SKPaint borderPaint)
{
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Expected O, but got Unknown
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
float num = size / 2f;
switch (IndicatorShape)
{
case IndicatorShape.Circle:
canvas.DrawCircle(x, y, num, fillPaint);
if (ShowBorder)
{
canvas.DrawCircle(x, y, num, borderPaint);
}
break;
case IndicatorShape.Square:
{
SKRect val3 = default(SKRect);
((SKRect)(ref val3))._002Ector(x - num, y - num, x + num, y + num);
canvas.DrawRect(val3, fillPaint);
if (ShowBorder)
{
canvas.DrawRect(val3, borderPaint);
}
break;
}
case IndicatorShape.RoundedSquare:
{
SKRect val2 = default(SKRect);
((SKRect)(ref val2))._002Ector(x - num, y - num, x + num, y + num);
float num2 = num * 0.3f;
canvas.DrawRoundRect(val2, num2, num2, fillPaint);
if (ShowBorder)
{
canvas.DrawRoundRect(val2, num2, num2, borderPaint);
}
break;
}
case IndicatorShape.Diamond:
{
SKPath val = new SKPath();
try
{
val.MoveTo(x, y - num);
val.LineTo(x + num, y);
val.LineTo(x, y + num);
val.LineTo(x - num, y);
val.Close();
canvas.DrawPath(val, fillPaint);
if (ShowBorder)
{
canvas.DrawPath(val, borderPaint);
}
break;
}
finally
{
((IDisposable)val)?.Dispose();
}
}
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
if (_count <= 0 || (HideSingle && _count <= 1)) return;
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
if (_count > 0)
{
int num = Math.Min(_count, MaximumVisible);
float num2 = (float)num * IndicatorSize + (float)(num - 1) * IndicatorSpacing;
bounds = base.Bounds;
float num3 = ((SKRect)(ref bounds)).MidX - num2 / 2f;
if (_count > MaximumVisible)
{
int num4 = MaximumVisible / 2;
if (Math.Max(0, _position - num4) + MaximumVisible > _count)
{
_ = _count;
_ = MaximumVisible;
}
}
for (int i = 0; i < num; i++)
{
float num5 = num3 + (float)i * (IndicatorSize + IndicatorSpacing);
if (x >= num5 && x <= num5 + IndicatorSize)
{
return this;
}
}
}
return null;
}
}
return null;
}
canvas.Save();
canvas.ClipRect(Bounds);
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled || _count <= 0)
{
return;
}
int num = Math.Min(_count, MaximumVisible);
float num2 = (float)num * IndicatorSize + (float)(num - 1) * IndicatorSpacing;
SKRect bounds = base.Bounds;
float num3 = ((SKRect)(ref bounds)).MidX - num2 / 2f;
int num4 = 0;
if (_count > MaximumVisible)
{
int num5 = MaximumVisible / 2;
num4 = Math.Max(0, _position - num5);
if (num4 + MaximumVisible > _count)
{
num4 = _count - MaximumVisible;
}
}
int num6 = (int)((e.X - num3) / (IndicatorSize + IndicatorSpacing));
if (num6 >= 0 && num6 < num)
{
Position = num4 + num6;
e.Handled = true;
}
base.OnPointerPressed(e);
}
int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * IndicatorSize + (visibleCount - 1) * IndicatorSpacing;
float startX = Bounds.MidX - totalWidth / 2 + IndicatorSize / 2;
float centerY = Bounds.MidY;
// Determine visible range if count > MaximumVisible
int startIndex = 0;
int endIndex = visibleCount;
if (_count > MaximumVisible)
{
int halfVisible = MaximumVisible / 2;
startIndex = Math.Max(0, _position - halfVisible);
endIndex = Math.Min(_count, startIndex + MaximumVisible);
if (endIndex == _count)
{
startIndex = _count - MaximumVisible;
}
}
using var normalPaint = new SKPaint
{
Color = IndicatorColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
using var selectedPaint = new SKPaint
{
Color = SelectedIndicatorColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
using var borderPaint = new SKPaint
{
Color = BorderColor,
Style = SKPaintStyle.Stroke,
StrokeWidth = BorderWidth,
IsAntialias = true
};
for (int i = startIndex; i < endIndex; i++)
{
int visualIndex = i - startIndex;
float x = startX + visualIndex * (IndicatorSize + IndicatorSpacing);
bool isSelected = i == _position;
var paint = isSelected ? selectedPaint : normalPaint;
float size = isSelected ? SelectedIndicatorSize : IndicatorSize;
DrawIndicator(canvas, x, centerY, size, paint, borderPaint);
}
canvas.Restore();
}
private void DrawIndicator(SKCanvas canvas, float x, float y, float size, SKPaint fillPaint, SKPaint borderPaint)
{
float radius = size / 2;
switch (IndicatorShape)
{
case IndicatorShape.Circle:
canvas.DrawCircle(x, y, radius, fillPaint);
if (ShowBorder)
{
canvas.DrawCircle(x, y, radius, borderPaint);
}
break;
case IndicatorShape.Square:
var rect = new SKRect(x - radius, y - radius, x + radius, y + radius);
canvas.DrawRect(rect, fillPaint);
if (ShowBorder)
{
canvas.DrawRect(rect, borderPaint);
}
break;
case IndicatorShape.RoundedSquare:
var roundRect = new SKRect(x - radius, y - radius, x + radius, y + radius);
float cornerRadius = radius * 0.3f;
canvas.DrawRoundRect(roundRect, cornerRadius, cornerRadius, fillPaint);
if (ShowBorder)
{
canvas.DrawRoundRect(roundRect, cornerRadius, cornerRadius, borderPaint);
}
break;
case IndicatorShape.Diamond:
using (var path = new SKPath())
{
path.MoveTo(x, y - radius);
path.LineTo(x + radius, y);
path.LineTo(x, y + radius);
path.LineTo(x - radius, y);
path.Close();
canvas.DrawPath(path, fillPaint);
if (ShowBorder)
{
canvas.DrawPath(path, borderPaint);
}
}
break;
}
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y)) return null;
// Check if click is on an indicator
if (_count > 0)
{
int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * IndicatorSize + (visibleCount - 1) * IndicatorSpacing;
float startX = Bounds.MidX - totalWidth / 2;
int startIndex = 0;
if (_count > MaximumVisible)
{
int halfVisible = MaximumVisible / 2;
startIndex = Math.Max(0, _position - halfVisible);
if (startIndex + MaximumVisible > _count)
{
startIndex = _count - MaximumVisible;
}
}
for (int i = 0; i < visibleCount; i++)
{
float indicatorX = startX + i * (IndicatorSize + IndicatorSpacing);
if (x >= indicatorX && x <= indicatorX + IndicatorSize)
{
return this;
}
}
}
return null;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled || _count <= 0) return;
// Calculate which indicator was clicked
int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * IndicatorSize + (visibleCount - 1) * IndicatorSpacing;
float startX = Bounds.MidX - totalWidth / 2;
int startIndex = 0;
if (_count > MaximumVisible)
{
int halfVisible = MaximumVisible / 2;
startIndex = Math.Max(0, _position - halfVisible);
if (startIndex + MaximumVisible > _count)
{
startIndex = _count - MaximumVisible;
}
}
float relativeX = e.X - startX;
int visualIndex = (int)(relativeX / (IndicatorSize + IndicatorSpacing));
if (visualIndex >= 0 && visualIndex < visibleCount)
{
Position = startIndex + visualIndex;
e.Handled = true;
}
base.OnPointerPressed(e);
}
}
/// <summary>
/// Shape of indicator dots.
/// </summary>
public enum IndicatorShape
{
Circle,
Square,
RoundedSquare,
Diamond
}

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,335 +1,598 @@
using System;
using System.Collections.Generic;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A horizontal menu bar control.
/// </summary>
public class SkiaMenuBar : SkiaView
{
private readonly List<MenuBarItem> _items = new List<MenuBarItem>();
private readonly List<MenuBarItem> _items = new();
private int _hoveredIndex = -1;
private int _openIndex = -1;
private SkiaMenuFlyout? _openFlyout;
private int _hoveredIndex = -1;
/// <summary>
/// Gets the menu bar items.
/// </summary>
public IList<MenuBarItem> Items => _items;
private int _openIndex = -1;
/// <summary>
/// Gets or sets the background color.
/// </summary>
public SKColor BackgroundColor { get; set; } = new SKColor(240, 240, 240);
private SkiaMenuFlyout? _openFlyout;
/// <summary>
/// Gets or sets the text color.
/// </summary>
public SKColor TextColor { get; set; } = new SKColor(33, 33, 33);
public IList<MenuBarItem> Items => _items;
/// <summary>
/// Gets or sets the hover background color.
/// </summary>
public SKColor HoverBackgroundColor { get; set; } = new SKColor(220, 220, 220);
public new SKColor BackgroundColor { get; set; } = new SKColor((byte)240, (byte)240, (byte)240);
/// <summary>
/// Gets or sets the active background color.
/// </summary>
public SKColor ActiveBackgroundColor { get; set; } = new SKColor(200, 200, 200);
public SKColor TextColor { get; set; } = new SKColor((byte)33, (byte)33, (byte)33);
/// <summary>
/// Gets or sets the bar height.
/// </summary>
public float BarHeight { get; set; } = 28f;
public SKColor HoverBackgroundColor { get; set; } = new SKColor((byte)220, (byte)220, (byte)220);
/// <summary>
/// Gets or sets the font size.
/// </summary>
public float FontSize { get; set; } = 13f;
public SKColor ActiveBackgroundColor { get; set; } = new SKColor((byte)200, (byte)200, (byte)200);
/// <summary>
/// Gets or sets the item padding.
/// </summary>
public float ItemPadding { get; set; } = 12f;
public float BarHeight { get; set; } = 28f;
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(availableSize.Width, BarHeight);
}
public float FontSize { get; set; } = 13f;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
canvas.Save();
public float ItemPadding { get; set; } = 12f;
// Draw background
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(Bounds, bgPaint);
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(((SKSize)(ref availableSize)).Width, BarHeight);
}
// Draw bottom border
using var borderPaint = new SKPaint
{
Color = new SKColor(200, 200, 200),
Style = SKPaintStyle.Stroke,
StrokeWidth = 1
};
canvas.DrawLine(Bounds.Left, Bounds.Bottom, Bounds.Right, Bounds.Bottom, borderPaint);
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Expected O, but got Unknown
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Expected O, but got Unknown
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: Unknown result type (might be due to invalid IL or missing references)
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_016a: Expected O, but got Unknown
//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
//IL_018c: Unknown result type (might be due to invalid IL or missing references)
//IL_0191: Unknown result type (might be due to invalid IL or missing references)
//IL_0193: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Unknown result type (might be due to invalid IL or missing references)
//IL_01a6: Expected O, but got Unknown
//IL_016b: Unknown result type (might be due to invalid IL or missing references)
//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
canvas.Save();
SKPaint val = new SKPaint
{
Color = BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(base.Bounds, val);
SKPaint val2 = new SKPaint
{
Color = new SKColor((byte)200, (byte)200, (byte)200),
Style = (SKPaintStyle)1,
StrokeWidth = 1f
};
try
{
SKRect bounds2 = base.Bounds;
float left = ((SKRect)(ref bounds2)).Left;
bounds2 = base.Bounds;
float bottom = ((SKRect)(ref bounds2)).Bottom;
bounds2 = base.Bounds;
float right = ((SKRect)(ref bounds2)).Right;
bounds2 = base.Bounds;
canvas.DrawLine(left, bottom, right, ((SKRect)(ref bounds2)).Bottom, val2);
SKPaint val3 = new SKPaint
{
Color = TextColor,
TextSize = FontSize,
IsAntialias = true
};
try
{
bounds2 = base.Bounds;
float num = ((SKRect)(ref bounds2)).Left;
SKRect val5 = default(SKRect);
for (int i = 0; i < _items.Count; i++)
{
MenuBarItem menuBarItem = _items[i];
SKRect val4 = default(SKRect);
val3.MeasureText(menuBarItem.Text, ref val4);
float num2 = ((SKRect)(ref val4)).Width + ItemPadding * 2f;
float num3 = num;
bounds2 = base.Bounds;
float top = ((SKRect)(ref bounds2)).Top;
float num4 = num + num2;
bounds2 = base.Bounds;
((SKRect)(ref val5))._002Ector(num3, top, num4, ((SKRect)(ref bounds2)).Bottom);
if (i == _openIndex)
{
SKPaint val6 = new SKPaint
{
Color = ActiveBackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(val5, val6);
}
finally
{
((IDisposable)val6)?.Dispose();
}
}
else if (i == _hoveredIndex)
{
SKPaint val7 = new SKPaint
{
Color = HoverBackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(val5, val7);
}
finally
{
((IDisposable)val7)?.Dispose();
}
}
float num5 = num + ItemPadding;
bounds2 = base.Bounds;
float num6 = ((SKRect)(ref bounds2)).MidY - ((SKRect)(ref val4)).MidY;
canvas.DrawText(menuBarItem.Text, num5, num6, val3);
menuBarItem.Bounds = val5;
num += num2;
}
_openFlyout?.Draw(canvas);
canvas.Restore();
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
// Draw menu items
using var textPaint = new SKPaint
{
Color = TextColor,
TextSize = FontSize,
IsAntialias = true
};
public override SkiaView? HitTest(float x, float y)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsVisible)
{
return null;
}
if (_openFlyout != null)
{
SkiaView skiaView = _openFlyout.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
return this;
}
if (_openFlyout != null)
{
CloseFlyout();
}
return null;
}
float x = Bounds.Left;
public override void OnPointerMoved(PointerEventArgs e)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled)
{
return;
}
int num = -1;
for (int i = 0; i < _items.Count; i++)
{
SKRect bounds = _items[i].Bounds;
if (((SKRect)(ref bounds)).Contains(e.X, e.Y))
{
num = i;
break;
}
}
if (num != _hoveredIndex)
{
_hoveredIndex = num;
if (_openIndex >= 0 && num >= 0 && num != _openIndex)
{
OpenFlyout(num);
}
Invalidate();
}
base.OnPointerMoved(e);
}
for (int i = 0; i < _items.Count; i++)
{
var item = _items[i];
var textBounds = new SKRect();
textPaint.MeasureText(item.Text, ref textBounds);
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled)
{
return;
}
if (_openFlyout != null)
{
_openFlyout.OnPointerPressed(e);
if (e.Handled)
{
CloseFlyout();
return;
}
}
for (int i = 0; i < _items.Count; i++)
{
SKRect bounds = _items[i].Bounds;
if (((SKRect)(ref bounds)).Contains(e.X, e.Y))
{
if (_openIndex == i)
{
CloseFlyout();
}
else
{
OpenFlyout(i);
}
e.Handled = true;
return;
}
}
if (_openFlyout != null)
{
CloseFlyout();
e.Handled = true;
}
base.OnPointerPressed(e);
}
float itemWidth = textBounds.Width + ItemPadding * 2;
var itemBounds = new SKRect(x, Bounds.Top, x + itemWidth, Bounds.Bottom);
private void OpenFlyout(int index)
{
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
if (index >= 0 && index < _items.Count)
{
MenuBarItem menuBarItem = _items[index];
_openIndex = index;
_openFlyout = new SkiaMenuFlyout
{
Items = menuBarItem.Items
};
SKRect bounds = menuBarItem.Bounds;
float left = ((SKRect)(ref bounds)).Left;
bounds = menuBarItem.Bounds;
float bottom = ((SKRect)(ref bounds)).Bottom;
_openFlyout.Position = new SKPoint(left, bottom);
_openFlyout.ItemClicked += OnFlyoutItemClicked;
Invalidate();
}
}
// Draw item background
if (i == _openIndex)
{
using var activePaint = new SKPaint { Color = ActiveBackgroundColor, Style = SKPaintStyle.Fill };
canvas.DrawRect(itemBounds, activePaint);
}
else if (i == _hoveredIndex)
{
using var hoverPaint = new SKPaint { Color = HoverBackgroundColor, Style = SKPaintStyle.Fill };
canvas.DrawRect(itemBounds, hoverPaint);
}
private void CloseFlyout()
{
if (_openFlyout != null)
{
_openFlyout.ItemClicked -= OnFlyoutItemClicked;
_openFlyout = null;
}
_openIndex = -1;
Invalidate();
}
// Draw text
float textX = x + ItemPadding;
float textY = Bounds.MidY - textBounds.MidY;
canvas.DrawText(item.Text, textX, textY, textPaint);
private void OnFlyoutItemClicked(object? sender, MenuItemClickedEventArgs e)
{
CloseFlyout();
}
item.Bounds = itemBounds;
x += itemWidth;
}
// Draw open flyout
_openFlyout?.Draw(canvas);
canvas.Restore();
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible) return null;
// Check flyout first
if (_openFlyout != null)
{
var flyoutHit = _openFlyout.HitTest(x, y);
if (flyoutHit != null) return flyoutHit;
}
if (Bounds.Contains(x, y))
{
return this;
}
// Close flyout if clicking outside
if (_openFlyout != null)
{
CloseFlyout();
}
return null;
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!IsEnabled) return;
int newHovered = -1;
for (int i = 0; i < _items.Count; i++)
{
if (_items[i].Bounds.Contains(e.X, e.Y))
{
newHovered = i;
break;
}
}
if (newHovered != _hoveredIndex)
{
_hoveredIndex = newHovered;
// If a menu is open and we hover another item, open that one
if (_openIndex >= 0 && newHovered >= 0 && newHovered != _openIndex)
{
OpenFlyout(newHovered);
}
Invalidate();
}
base.OnPointerMoved(e);
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
// Check if clicking on flyout
if (_openFlyout != null)
{
_openFlyout.OnPointerPressed(e);
if (e.Handled)
{
CloseFlyout();
return;
}
}
// Check menu bar items
for (int i = 0; i < _items.Count; i++)
{
if (_items[i].Bounds.Contains(e.X, e.Y))
{
if (_openIndex == i)
{
CloseFlyout();
}
else
{
OpenFlyout(i);
}
e.Handled = true;
return;
}
}
// Click outside - close flyout
if (_openFlyout != null)
{
CloseFlyout();
e.Handled = true;
}
base.OnPointerPressed(e);
}
private void OpenFlyout(int index)
{
if (index < 0 || index >= _items.Count) return;
var item = _items[index];
_openIndex = index;
_openFlyout = new SkiaMenuFlyout
{
Items = item.Items
};
// Position below the menu item
float x = item.Bounds.Left;
float y = item.Bounds.Bottom;
_openFlyout.Position = new SKPoint(x, y);
_openFlyout.ItemClicked += OnFlyoutItemClicked;
Invalidate();
}
private void CloseFlyout()
{
if (_openFlyout != null)
{
_openFlyout.ItemClicked -= OnFlyoutItemClicked;
_openFlyout = null;
}
_openIndex = -1;
Invalidate();
}
private void OnFlyoutItemClicked(object? sender, MenuItemClickedEventArgs e)
{
CloseFlyout();
}
}
/// <summary>
/// Represents a top-level menu bar item.
/// </summary>
public class MenuBarItem
{
/// <summary>
/// Gets or sets the display text.
/// </summary>
public string Text { get; set; } = string.Empty;
/// <summary>
/// Gets the menu items.
/// </summary>
public List<MenuItem> Items { get; } = new();
/// <summary>
/// Gets or sets the bounds (set during rendering).
/// </summary>
internal SKRect Bounds { get; set; }
}
/// <summary>
/// Represents a menu item.
/// </summary>
public class MenuItem
{
/// <summary>
/// Gets or sets the display text.
/// </summary>
public string Text { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the keyboard shortcut text.
/// </summary>
public string? Shortcut { get; set; }
/// <summary>
/// Gets or sets whether this is a separator.
/// </summary>
public bool IsSeparator { get; set; }
/// <summary>
/// Gets or sets whether this item is enabled.
/// </summary>
public bool IsEnabled { get; set; } = true;
/// <summary>
/// Gets or sets whether this item is checked.
/// </summary>
public bool IsChecked { get; set; }
/// <summary>
/// Gets or sets the icon source.
/// </summary>
public string? IconSource { get; set; }
/// <summary>
/// Gets the sub-menu items.
/// </summary>
public List<MenuItem> SubItems { get; } = new();
/// <summary>
/// Event raised when the item is clicked.
/// </summary>
public event EventHandler? Clicked;
internal void OnClicked()
{
Clicked?.Invoke(this, EventArgs.Empty);
}
}
/// <summary>
/// A dropdown menu flyout.
/// </summary>
public class SkiaMenuFlyout : SkiaView
{
private int _hoveredIndex = -1;
private SKRect _bounds;
/// <summary>
/// Gets or sets the menu items.
/// </summary>
public List<MenuItem> Items { get; set; } = new();
/// <summary>
/// Gets or sets the position.
/// </summary>
public SKPoint Position { get; set; }
/// <summary>
/// Gets or sets the background color.
/// </summary>
public SKColor BackgroundColor { get; set; } = SKColors.White;
/// <summary>
/// Gets or sets the text color.
/// </summary>
public SKColor TextColor { get; set; } = new SKColor(33, 33, 33);
/// <summary>
/// Gets or sets the disabled text color.
/// </summary>
public SKColor DisabledTextColor { get; set; } = new SKColor(160, 160, 160);
/// <summary>
/// Gets or sets the hover background color.
/// </summary>
public SKColor HoverBackgroundColor { get; set; } = new SKColor(230, 230, 230);
/// <summary>
/// Gets or sets the separator color.
/// </summary>
public SKColor SeparatorColor { get; set; } = new SKColor(220, 220, 220);
/// <summary>
/// Gets or sets the font size.
/// </summary>
public float FontSize { get; set; } = 13f;
/// <summary>
/// Gets or sets the item height.
/// </summary>
public float ItemHeight { get; set; } = 28f;
/// <summary>
/// Gets or sets the separator height.
/// </summary>
public float SeparatorHeight { get; set; } = 9f;
/// <summary>
/// Gets or sets the minimum width.
/// </summary>
public float MinWidth { get; set; } = 180f;
/// <summary>
/// Event raised when an item is clicked.
/// </summary>
public event EventHandler<MenuItemClickedEventArgs>? ItemClicked;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
if (Items.Count == 0) return;
// Calculate bounds
float width = MinWidth;
float height = 0;
using var textPaint = new SKPaint
{
TextSize = FontSize,
IsAntialias = true
};
foreach (var item in Items)
{
if (item.IsSeparator)
{
height += SeparatorHeight;
}
else
{
height += ItemHeight;
var textBounds = new SKRect();
textPaint.MeasureText(item.Text, ref textBounds);
float itemWidth = textBounds.Width + 50; // Padding + icon space
if (!string.IsNullOrEmpty(item.Shortcut))
{
textPaint.MeasureText(item.Shortcut, ref textBounds);
itemWidth += textBounds.Width + 20;
}
width = Math.Max(width, itemWidth);
}
}
_bounds = new SKRect(Position.X, Position.Y, Position.X + width, Position.Y + height);
// Draw shadow
using var shadowPaint = new SKPaint
{
ImageFilter = SKImageFilter.CreateDropShadow(0, 2, 8, 8, new SKColor(0, 0, 0, 40))
};
canvas.DrawRect(_bounds, shadowPaint);
// Draw background
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(_bounds, bgPaint);
// Draw border
using var borderPaint = new SKPaint
{
Color = new SKColor(200, 200, 200),
Style = SKPaintStyle.Stroke,
StrokeWidth = 1
};
canvas.DrawRect(_bounds, borderPaint);
// Draw items
float y = _bounds.Top;
textPaint.Color = TextColor;
for (int i = 0; i < Items.Count; i++)
{
var item = Items[i];
if (item.IsSeparator)
{
float separatorY = y + SeparatorHeight / 2;
using var sepPaint = new SKPaint { Color = SeparatorColor, StrokeWidth = 1 };
canvas.DrawLine(_bounds.Left + 8, separatorY, _bounds.Right - 8, separatorY, sepPaint);
y += SeparatorHeight;
}
else
{
var itemBounds = new SKRect(_bounds.Left, y, _bounds.Right, y + ItemHeight);
// Draw hover background
if (i == _hoveredIndex && item.IsEnabled)
{
using var hoverPaint = new SKPaint { Color = HoverBackgroundColor, Style = SKPaintStyle.Fill };
canvas.DrawRect(itemBounds, hoverPaint);
}
// Draw check mark
if (item.IsChecked)
{
using var checkPaint = new SKPaint
{
Color = item.IsEnabled ? TextColor : DisabledTextColor,
TextSize = FontSize,
IsAntialias = true
};
canvas.DrawText("✓", _bounds.Left + 8, y + ItemHeight / 2 + 5, checkPaint);
}
// Draw text
textPaint.Color = item.IsEnabled ? TextColor : DisabledTextColor;
canvas.DrawText(item.Text, _bounds.Left + 28, y + ItemHeight / 2 + 5, textPaint);
// Draw shortcut
if (!string.IsNullOrEmpty(item.Shortcut))
{
textPaint.Color = DisabledTextColor;
var shortcutBounds = new SKRect();
textPaint.MeasureText(item.Shortcut, ref shortcutBounds);
canvas.DrawText(item.Shortcut, _bounds.Right - shortcutBounds.Width - 12, y + ItemHeight / 2 + 5, textPaint);
}
// Draw submenu arrow
if (item.SubItems.Count > 0)
{
canvas.DrawText("▸", _bounds.Right - 16, y + ItemHeight / 2 + 5, textPaint);
}
y += ItemHeight;
}
}
}
public override SkiaView? HitTest(float x, float y)
{
if (_bounds.Contains(x, y))
{
return this;
}
return null;
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!_bounds.Contains(e.X, e.Y))
{
_hoveredIndex = -1;
Invalidate();
return;
}
float y = _bounds.Top;
int newHovered = -1;
for (int i = 0; i < Items.Count; i++)
{
var item = Items[i];
float itemHeight = item.IsSeparator ? SeparatorHeight : ItemHeight;
if (e.Y >= y && e.Y < y + itemHeight && !item.IsSeparator)
{
newHovered = i;
break;
}
y += itemHeight;
}
if (newHovered != _hoveredIndex)
{
_hoveredIndex = newHovered;
Invalidate();
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (_hoveredIndex >= 0 && _hoveredIndex < Items.Count)
{
var item = Items[_hoveredIndex];
if (item.IsEnabled && !item.IsSeparator)
{
item.OnClicked();
ItemClicked?.Invoke(this, new MenuItemClickedEventArgs(item));
e.Handled = true;
}
}
}
}
/// <summary>
/// Event args for menu item clicked.
/// </summary>
public class MenuItemClickedEventArgs : EventArgs
{
public MenuItem Item { get; }
public MenuItemClickedEventArgs(MenuItem item)
{
Item = item;
}
}

View File

@@ -1,304 +0,0 @@
using System;
using System.Collections.Generic;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaMenuFlyout : SkiaView
{
private int _hoveredIndex = -1;
private SKRect _bounds;
public List<MenuItem> Items { get; set; } = new List<MenuItem>();
public SKPoint Position { get; set; }
public new SKColor BackgroundColor { get; set; } = SKColors.White;
public SKColor TextColor { get; set; } = new SKColor((byte)33, (byte)33, (byte)33);
public SKColor DisabledTextColor { get; set; } = new SKColor((byte)160, (byte)160, (byte)160);
public SKColor HoverBackgroundColor { get; set; } = new SKColor((byte)230, (byte)230, (byte)230);
public SKColor SeparatorColor { get; set; } = new SKColor((byte)220, (byte)220, (byte)220);
public float FontSize { get; set; } = 13f;
public float ItemHeight { get; set; } = 28f;
public float SeparatorHeight { get; set; } = 9f;
public float MinWidth { get; set; } = 180f;
public event EventHandler<MenuItemClickedEventArgs>? ItemClicked;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected O, but got Unknown
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_012e: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
//IL_0152: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Expected O, but got Unknown
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Unknown result type (might be due to invalid IL or missing references)
//IL_0176: Unknown result type (might be due to invalid IL or missing references)
//IL_0180: Unknown result type (might be due to invalid IL or missing references)
//IL_0189: Expected O, but got Unknown
//IL_018b: Unknown result type (might be due to invalid IL or missing references)
//IL_0197: Unknown result type (might be due to invalid IL or missing references)
//IL_019c: Unknown result type (might be due to invalid IL or missing references)
//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
//IL_01ca: Expected O, but got Unknown
//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
//IL_0222: Unknown result type (might be due to invalid IL or missing references)
//IL_0227: Unknown result type (might be due to invalid IL or missing references)
//IL_0229: Unknown result type (might be due to invalid IL or missing references)
//IL_0233: Unknown result type (might be due to invalid IL or missing references)
//IL_0240: Expected O, but got Unknown
//IL_0300: Unknown result type (might be due to invalid IL or missing references)
//IL_0305: Unknown result type (might be due to invalid IL or missing references)
//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
//IL_02df: Expected O, but got Unknown
//IL_038b: Unknown result type (might be due to invalid IL or missing references)
//IL_0383: Unknown result type (might be due to invalid IL or missing references)
//IL_0318: Unknown result type (might be due to invalid IL or missing references)
//IL_0310: Unknown result type (might be due to invalid IL or missing references)
//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
//IL_0322: Unknown result type (might be due to invalid IL or missing references)
//IL_032e: Unknown result type (might be due to invalid IL or missing references)
//IL_0337: Expected O, but got Unknown
//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
if (Items.Count == 0)
{
return;
}
float num = MinWidth;
float num2 = 0f;
SKPaint val = new SKPaint
{
TextSize = FontSize,
IsAntialias = true
};
try
{
foreach (MenuItem item in Items)
{
if (item.IsSeparator)
{
num2 += SeparatorHeight;
continue;
}
num2 += ItemHeight;
SKRect val2 = default(SKRect);
val.MeasureText(item.Text, ref val2);
float num3 = ((SKRect)(ref val2)).Width + 50f;
if (!string.IsNullOrEmpty(item.Shortcut))
{
val.MeasureText(item.Shortcut, ref val2);
num3 += ((SKRect)(ref val2)).Width + 20f;
}
num = Math.Max(num, num3);
}
SKPoint position = Position;
float x = ((SKPoint)(ref position)).X;
position = Position;
float y = ((SKPoint)(ref position)).Y;
position = Position;
float num4 = ((SKPoint)(ref position)).X + num;
position = Position;
_bounds = new SKRect(x, y, num4, ((SKPoint)(ref position)).Y + num2);
SKPaint val3 = new SKPaint
{
ImageFilter = SKImageFilter.CreateDropShadow(0f, 2f, 8f, 8f, new SKColor((byte)0, (byte)0, (byte)0, (byte)40))
};
try
{
canvas.DrawRect(_bounds, val3);
SKPaint val4 = new SKPaint
{
Color = BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(_bounds, val4);
SKPaint val5 = new SKPaint
{
Color = new SKColor((byte)200, (byte)200, (byte)200),
Style = (SKPaintStyle)1,
StrokeWidth = 1f
};
try
{
canvas.DrawRect(_bounds, val5);
float num5 = ((SKRect)(ref _bounds)).Top;
val.Color = TextColor;
SKRect val7 = default(SKRect);
for (int i = 0; i < Items.Count; i++)
{
MenuItem menuItem = Items[i];
if (menuItem.IsSeparator)
{
float num6 = num5 + SeparatorHeight / 2f;
SKPaint val6 = new SKPaint
{
Color = SeparatorColor,
StrokeWidth = 1f
};
try
{
canvas.DrawLine(((SKRect)(ref _bounds)).Left + 8f, num6, ((SKRect)(ref _bounds)).Right - 8f, num6, val6);
num5 += SeparatorHeight;
}
finally
{
((IDisposable)val6)?.Dispose();
}
continue;
}
((SKRect)(ref val7))._002Ector(((SKRect)(ref _bounds)).Left, num5, ((SKRect)(ref _bounds)).Right, num5 + ItemHeight);
if (i == _hoveredIndex && menuItem.IsEnabled)
{
SKPaint val8 = new SKPaint
{
Color = HoverBackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(val7, val8);
}
finally
{
((IDisposable)val8)?.Dispose();
}
}
if (menuItem.IsChecked)
{
SKPaint val9 = new SKPaint
{
Color = (menuItem.IsEnabled ? TextColor : DisabledTextColor),
TextSize = FontSize,
IsAntialias = true
};
try
{
canvas.DrawText("✓", ((SKRect)(ref _bounds)).Left + 8f, num5 + ItemHeight / 2f + 5f, val9);
}
finally
{
((IDisposable)val9)?.Dispose();
}
}
val.Color = (menuItem.IsEnabled ? TextColor : DisabledTextColor);
canvas.DrawText(menuItem.Text, ((SKRect)(ref _bounds)).Left + 28f, num5 + ItemHeight / 2f + 5f, val);
if (!string.IsNullOrEmpty(menuItem.Shortcut))
{
val.Color = DisabledTextColor;
SKRect val10 = default(SKRect);
val.MeasureText(menuItem.Shortcut, ref val10);
canvas.DrawText(menuItem.Shortcut, ((SKRect)(ref _bounds)).Right - ((SKRect)(ref val10)).Width - 12f, num5 + ItemHeight / 2f + 5f, val);
}
if (menuItem.SubItems.Count > 0)
{
canvas.DrawText("▸", ((SKRect)(ref _bounds)).Right - 16f, num5 + ItemHeight / 2f + 5f, val);
}
num5 += ItemHeight;
}
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
public override SkiaView? HitTest(float x, float y)
{
if (((SKRect)(ref _bounds)).Contains(x, y))
{
return this;
}
return null;
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!((SKRect)(ref _bounds)).Contains(e.X, e.Y))
{
_hoveredIndex = -1;
Invalidate();
return;
}
float num = ((SKRect)(ref _bounds)).Top;
int num2 = -1;
for (int i = 0; i < Items.Count; i++)
{
MenuItem menuItem = Items[i];
float num3 = (menuItem.IsSeparator ? SeparatorHeight : ItemHeight);
if (e.Y >= num && e.Y < num + num3 && !menuItem.IsSeparator)
{
num2 = i;
break;
}
num += num3;
}
if (num2 != _hoveredIndex)
{
_hoveredIndex = num2;
Invalidate();
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (_hoveredIndex >= 0 && _hoveredIndex < Items.Count)
{
MenuItem menuItem = Items[_hoveredIndex];
if (menuItem.IsEnabled && !menuItem.IsSeparator)
{
menuItem.OnClicked();
this.ItemClicked?.Invoke(this, new MenuItemClickedEventArgs(menuItem));
e.Handled = true;
}
}
}
}

View File

@@ -1,513 +1,451 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Maui.Platform.Linux;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
using Microsoft.Maui.Graphics;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered navigation page with back stack support.
/// </summary>
public class SkiaNavigationPage : SkiaView
{
private readonly Stack<SkiaPage> _navigationStack = new Stack<SkiaPage>();
private readonly Stack<SkiaPage> _navigationStack = new();
private SkiaPage? _currentPage;
private bool _isAnimating;
private float _animationProgress;
private SkiaPage? _incomingPage;
private bool _isPushAnimation;
private SkiaPage? _currentPage;
// Navigation bar styling
private SKColor _barBackgroundColor = new SKColor(0x21, 0x96, 0xF3);
private SKColor _barTextColor = SKColors.White;
private float _navigationBarHeight = 56;
private bool _showBackButton = true;
private bool _isAnimating;
public SKColor BarBackgroundColor
{
get => _barBackgroundColor;
set
{
_barBackgroundColor = value;
UpdatePageNavigationBar();
Invalidate();
}
}
private float _animationProgress;
public SKColor BarTextColor
{
get => _barTextColor;
set
{
_barTextColor = value;
UpdatePageNavigationBar();
Invalidate();
}
}
private SkiaPage? _incomingPage;
public float NavigationBarHeight
{
get => _navigationBarHeight;
set
{
_navigationBarHeight = value;
UpdatePageNavigationBar();
Invalidate();
}
}
private bool _isPushAnimation;
public SkiaPage? CurrentPage => _currentPage;
public SkiaPage? RootPage => _navigationStack.Count > 0 ? _navigationStack.Last() : _currentPage;
public int StackDepth => _navigationStack.Count + (_currentPage != null ? 1 : 0);
private SKColor _barBackgroundColor = new SKColor((byte)33, (byte)150, (byte)243);
public event EventHandler<NavigationEventArgs>? Pushed;
public event EventHandler<NavigationEventArgs>? Popped;
public event EventHandler<NavigationEventArgs>? PoppedToRoot;
private SKColor _barTextColor = SKColors.White;
public SkiaNavigationPage()
{
}
private float _navigationBarHeight = 56f;
public SkiaNavigationPage(SkiaPage rootPage)
{
SetRootPage(rootPage);
}
private bool _showBackButton = true;
public void SetRootPage(SkiaPage page)
{
_navigationStack.Clear();
_currentPage?.OnDisappearing();
_currentPage = page;
_currentPage.Parent = this;
ConfigurePage(_currentPage, false);
_currentPage.OnAppearing();
Invalidate();
}
public SKColor BarBackgroundColor
{
get
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return _barBackgroundColor;
}
set
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
_barBackgroundColor = value;
UpdatePageNavigationBar();
Invalidate();
}
}
public void Push(SkiaPage page, bool animated = true)
{
if (_isAnimating) return;
public SKColor BarTextColor
{
get
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return _barTextColor;
}
set
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
_barTextColor = value;
UpdatePageNavigationBar();
Invalidate();
}
}
if (_currentPage != null)
{
_currentPage.OnDisappearing();
_navigationStack.Push(_currentPage);
}
public float NavigationBarHeight
{
get
{
return _navigationBarHeight;
}
set
{
_navigationBarHeight = value;
UpdatePageNavigationBar();
Invalidate();
}
}
ConfigurePage(page, true);
page.Parent = this;
public SkiaPage? CurrentPage => _currentPage;
if (animated)
{
_incomingPage = page;
_isPushAnimation = true;
_animationProgress = 0;
_isAnimating = true;
AnimatePush();
}
else
{
_currentPage = page;
_currentPage.OnAppearing();
Invalidate();
}
public SkiaPage? RootPage
{
get
{
if (_navigationStack.Count <= 0)
{
return _currentPage;
}
return _navigationStack.Last();
}
}
Pushed?.Invoke(this, new NavigationEventArgs(page));
}
public int StackDepth => _navigationStack.Count + ((_currentPage != null) ? 1 : 0);
public SkiaPage? Pop(bool animated = true)
{
if (_isAnimating || _navigationStack.Count == 0) return null;
public event EventHandler<NavigationEventArgs>? Pushed;
var poppedPage = _currentPage;
poppedPage?.OnDisappearing();
public event EventHandler<NavigationEventArgs>? Popped;
var previousPage = _navigationStack.Pop();
public event EventHandler<NavigationEventArgs>? PoppedToRoot;
if (animated && poppedPage != null)
{
_incomingPage = previousPage;
_isPushAnimation = false;
_animationProgress = 0;
_isAnimating = true;
AnimatePop(poppedPage);
}
else
{
_currentPage = previousPage;
_currentPage?.OnAppearing();
Invalidate();
}
public SkiaNavigationPage()
{
}//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
if (poppedPage != null)
{
Popped?.Invoke(this, new NavigationEventArgs(poppedPage));
}
return poppedPage;
}
public SkiaNavigationPage(SkiaPage rootPage)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
SetRootPage(rootPage);
}
public void PopToRoot(bool animated = true)
{
if (_isAnimating || _navigationStack.Count == 0) return;
public void SetRootPage(SkiaPage page)
{
_navigationStack.Clear();
_currentPage?.OnDisappearing();
_currentPage = page;
_currentPage.Parent = this;
ConfigurePage(_currentPage, showBackButton: false);
_currentPage.OnAppearing();
Invalidate();
}
_currentPage?.OnDisappearing();
public void Push(SkiaPage page, bool animated = true)
{
if (!_isAnimating)
{
if (LinuxApplication.IsGtkMode)
{
animated = false;
}
if (_currentPage != null)
{
_currentPage.OnDisappearing();
_navigationStack.Push(_currentPage);
}
ConfigurePage(page, showBackButton: true);
page.Parent = this;
if (animated)
{
_incomingPage = page;
_isPushAnimation = true;
_animationProgress = 0f;
_isAnimating = true;
AnimatePush();
}
else
{
Console.WriteLine("[SkiaNavigationPage] Push (no animation): setting _currentPage to " + page.Title);
_currentPage = page;
_currentPage.OnAppearing();
Console.WriteLine("[SkiaNavigationPage] Push: calling Invalidate");
Invalidate();
Console.WriteLine("[SkiaNavigationPage] Push: Invalidate called, _currentPage is now " + _currentPage?.Title);
}
this.Pushed?.Invoke(this, new NavigationEventArgs(page));
}
}
// Get root page
SkiaPage? rootPage = null;
while (_navigationStack.Count > 0)
{
rootPage = _navigationStack.Pop();
}
public SkiaPage? Pop(bool animated = true)
{
if (_isAnimating || _navigationStack.Count == 0)
{
return null;
}
if (LinuxApplication.IsGtkMode)
{
animated = false;
}
SkiaPage currentPage = _currentPage;
currentPage?.OnDisappearing();
SkiaPage skiaPage = _navigationStack.Pop();
if (animated && currentPage != null)
{
_incomingPage = skiaPage;
_isPushAnimation = false;
_animationProgress = 0f;
_isAnimating = true;
AnimatePop(currentPage);
}
else
{
_currentPage = skiaPage;
_currentPage?.OnAppearing();
Invalidate();
}
if (currentPage != null)
{
this.Popped?.Invoke(this, new NavigationEventArgs(currentPage));
}
return currentPage;
}
if (rootPage != null)
{
_currentPage = rootPage;
ConfigurePage(_currentPage, false);
_currentPage.OnAppearing();
Invalidate();
}
public void PopToRoot(bool animated = true)
{
if (!_isAnimating && _navigationStack.Count != 0)
{
_currentPage?.OnDisappearing();
SkiaPage skiaPage = null;
while (_navigationStack.Count > 0)
{
skiaPage = _navigationStack.Pop();
}
if (skiaPage != null)
{
_currentPage = skiaPage;
ConfigurePage(_currentPage, showBackButton: false);
_currentPage.OnAppearing();
Invalidate();
}
this.PoppedToRoot?.Invoke(this, new NavigationEventArgs(_currentPage));
}
}
PoppedToRoot?.Invoke(this, new NavigationEventArgs(_currentPage!));
}
private void ConfigurePage(SkiaPage page, bool showBackButton)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
page.ShowNavigationBar = true;
page.TitleBarColor = _barBackgroundColor;
page.TitleTextColor = _barTextColor;
page.NavigationBarHeight = _navigationBarHeight;
_showBackButton = showBackButton && _navigationStack.Count > 0;
}
private void ConfigurePage(SkiaPage page, bool showBackButton)
{
page.ShowNavigationBar = true;
page.TitleBarColor = _barBackgroundColor;
page.TitleTextColor = _barTextColor;
page.NavigationBarHeight = _navigationBarHeight;
_showBackButton = showBackButton && _navigationStack.Count > 0;
}
private void UpdatePageNavigationBar()
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
if (_currentPage != null)
{
_currentPage.TitleBarColor = _barBackgroundColor;
_currentPage.TitleTextColor = _barTextColor;
_currentPage.NavigationBarHeight = _navigationBarHeight;
}
}
private void UpdatePageNavigationBar()
{
if (_currentPage != null)
{
_currentPage.TitleBarColor = _barBackgroundColor;
_currentPage.TitleTextColor = _barTextColor;
_currentPage.NavigationBarHeight = _navigationBarHeight;
}
}
private async void AnimatePush()
{
DateTime startTime = DateTime.Now;
while (_animationProgress < 1f)
{
await Task.Delay(16);
double totalMilliseconds = (DateTime.Now - startTime).TotalMilliseconds;
_animationProgress = Math.Min(1f, (float)(totalMilliseconds / 250.0));
Invalidate();
}
_currentPage = _incomingPage;
_incomingPage = null;
_isAnimating = false;
_currentPage?.OnAppearing();
Invalidate();
}
private async void AnimatePush()
{
const int durationMs = 250;
const int frameMs = 16;
var startTime = DateTime.Now;
private async void AnimatePop(SkiaPage outgoingPage)
{
DateTime startTime = DateTime.Now;
while (_animationProgress < 1f)
{
await Task.Delay(16);
double totalMilliseconds = (DateTime.Now - startTime).TotalMilliseconds;
_animationProgress = Math.Min(1f, (float)(totalMilliseconds / 250.0));
Invalidate();
}
_currentPage = _incomingPage;
_incomingPage = null;
_isAnimating = false;
_currentPage?.OnAppearing();
outgoingPage.Parent = null;
Invalidate();
}
while (_animationProgress < 1)
{
await Task.Delay(frameMs);
var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
_animationProgress = Math.Min(1, (float)(elapsed / durationMs));
Invalidate();
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
if (base.BackgroundColor != SKColors.Transparent)
{
SKPaint val = new SKPaint
{
Color = base.BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
if (_isAnimating && _incomingPage != null)
{
float num = EaseOutCubic(_animationProgress);
if (_isPushAnimation)
{
float num2 = (0f - ((SKRect)(ref bounds)).Width) * num;
float num3 = ((SKRect)(ref bounds)).Width * (1f - num);
if (_currentPage != null)
{
canvas.Save();
canvas.Translate(num2, 0f);
_currentPage.Bounds = bounds;
_currentPage.Draw(canvas);
canvas.Restore();
}
canvas.Save();
canvas.Translate(num3, 0f);
_incomingPage.Bounds = bounds;
_incomingPage.Draw(canvas);
canvas.Restore();
}
else
{
float num4 = (0f - ((SKRect)(ref bounds)).Width) * (1f - num);
float num5 = ((SKRect)(ref bounds)).Width * num;
canvas.Save();
canvas.Translate(num4, 0f);
_incomingPage.Bounds = bounds;
_incomingPage.Draw(canvas);
canvas.Restore();
if (_currentPage != null)
{
canvas.Save();
canvas.Translate(num5, 0f);
_currentPage.Bounds = bounds;
_currentPage.Draw(canvas);
canvas.Restore();
}
}
}
else if (_currentPage != null)
{
Console.WriteLine("[SkiaNavigationPage] OnDraw: drawing _currentPage=" + _currentPage.Title);
_currentPage.Bounds = bounds;
_currentPage.Draw(canvas);
if (_showBackButton && _navigationStack.Count > 0)
{
DrawBackButton(canvas, bounds);
}
}
}
_currentPage = _incomingPage;
_incomingPage = null;
_isAnimating = false;
_currentPage?.OnAppearing();
Invalidate();
}
private void DrawBackButton(SKCanvas canvas, SKRect bounds)
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Expected O, but got Unknown
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Expected O, but got Unknown
SKRect val = default(SKRect);
((SKRect)(ref val))._002Ector(((SKRect)(ref bounds)).Left + 8f, ((SKRect)(ref bounds)).Top + 12f, ((SKRect)(ref bounds)).Left + 48f, ((SKRect)(ref bounds)).Top + _navigationBarHeight - 12f);
SKPaint val2 = new SKPaint
{
Color = _barTextColor,
Style = (SKPaintStyle)1,
StrokeWidth = 2.5f,
IsAntialias = true,
StrokeCap = (SKStrokeCap)1
};
try
{
float midY = ((SKRect)(ref val)).MidY;
float num = 10f;
float num2 = ((SKRect)(ref val)).Left + 8f;
SKPath val3 = new SKPath();
try
{
val3.MoveTo(num2 + num, midY - num);
val3.LineTo(num2, midY);
val3.LineTo(num2 + num, midY + num);
canvas.DrawPath(val3, val2);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
private async void AnimatePop(SkiaPage outgoingPage)
{
const int durationMs = 250;
const int frameMs = 16;
var startTime = DateTime.Now;
private static float EaseOutCubic(float t)
{
return 1f - (float)Math.Pow(1f - t, 3.0);
}
while (_animationProgress < 1)
{
await Task.Delay(frameMs);
var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
_animationProgress = Math.Min(1, (float)(elapsed / durationMs));
Invalidate();
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
return availableSize;
}
_currentPage = _incomingPage;
_incomingPage = null;
_isAnimating = false;
_currentPage?.OnAppearing();
outgoingPage.Parent = null;
Invalidate();
}
public override void OnPointerPressed(PointerEventArgs e)
{
Console.WriteLine($"[SkiaNavigationPage] OnPointerPressed at ({e.X}, {e.Y}), _isAnimating={_isAnimating}");
if (!_isAnimating)
{
if (_showBackButton && _navigationStack.Count > 0 && e.X < 56f && e.Y < _navigationBarHeight)
{
Console.WriteLine("[SkiaNavigationPage] Back button clicked");
Pop();
}
else
{
Console.WriteLine("[SkiaNavigationPage] Forwarding to _currentPage: " + ((object)_currentPage)?.GetType().Name);
_currentPage?.OnPointerPressed(e);
}
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Draw background
if (BackgroundColor != SKColors.Transparent)
{
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, bgPaint);
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!_isAnimating)
{
_currentPage?.OnPointerMoved(e);
}
}
if (_isAnimating && _incomingPage != null)
{
// Draw animation
var eased = EaseOutCubic(_animationProgress);
public override void OnPointerReleased(PointerEventArgs e)
{
if (!_isAnimating)
{
_currentPage?.OnPointerReleased(e);
}
}
if (_isPushAnimation)
{
// Push: current page slides left, incoming slides from right
var currentOffset = -bounds.Width * eased;
var incomingOffset = bounds.Width * (1 - eased);
public override void OnKeyDown(KeyEventArgs e)
{
if (!_isAnimating)
{
if ((e.Key == Key.Escape || e.Key == Key.Backspace) && _navigationStack.Count > 0)
{
Pop();
e.Handled = true;
}
else
{
_currentPage?.OnKeyDown(e);
}
}
}
// Draw current page (sliding out)
if (_currentPage != null)
{
canvas.Save();
canvas.Translate(currentOffset, 0);
_currentPage.Bounds = bounds;
_currentPage.Draw(canvas);
canvas.Restore();
}
public override void OnKeyUp(KeyEventArgs e)
{
if (!_isAnimating)
{
_currentPage?.OnKeyUp(e);
}
}
// Draw incoming page
canvas.Save();
canvas.Translate(incomingOffset, 0);
_incomingPage.Bounds = bounds;
_incomingPage.Draw(canvas);
canvas.Restore();
}
else
{
// Pop: incoming slides from left, current slides right
var incomingOffset = -bounds.Width * (1 - eased);
var currentOffset = bounds.Width * eased;
public override void OnScroll(ScrollEventArgs e)
{
if (!_isAnimating)
{
_currentPage?.OnScroll(e);
}
}
// Draw incoming page (sliding in)
canvas.Save();
canvas.Translate(incomingOffset, 0);
_incomingPage.Bounds = bounds;
_incomingPage.Draw(canvas);
canvas.Restore();
public override SkiaView? HitTest(float x, float y)
{
if (!base.IsVisible)
{
return null;
}
if (_showBackButton && _navigationStack.Count > 0 && x < 56f && y < _navigationBarHeight)
{
return this;
}
if (_currentPage != null)
{
try
{
SkiaView skiaView = _currentPage.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
catch (Exception ex)
{
Console.WriteLine("[SkiaNavigationPage] HitTest error: " + ex.Message);
}
}
return this;
}
// Draw current page (sliding out)
if (_currentPage != null)
{
canvas.Save();
canvas.Translate(currentOffset, 0);
_currentPage.Bounds = bounds;
_currentPage.Draw(canvas);
canvas.Restore();
}
}
}
else if (_currentPage != null)
{
// Draw current page normally
_currentPage.Bounds = bounds;
_currentPage.Draw(canvas);
// Draw back button if applicable
if (_showBackButton && _navigationStack.Count > 0)
{
DrawBackButton(canvas, bounds);
}
}
}
private void DrawBackButton(SKCanvas canvas, SKRect bounds)
{
var buttonBounds = new SKRect(bounds.Left + 8, bounds.Top + 12, bounds.Left + 48, bounds.Top + _navigationBarHeight - 12);
using var paint = new SKPaint
{
Color = _barTextColor,
Style = SKPaintStyle.Stroke,
StrokeWidth = 2.5f,
IsAntialias = true,
StrokeCap = SKStrokeCap.Round
};
// Draw back arrow
var centerY = buttonBounds.MidY;
var arrowSize = 10f;
var left = buttonBounds.Left + 8;
using var path = new SKPath();
path.MoveTo(left + arrowSize, centerY - arrowSize);
path.LineTo(left, centerY);
path.LineTo(left + arrowSize, centerY + arrowSize);
canvas.DrawPath(path, paint);
}
private static float EaseOutCubic(float t)
{
return 1 - (float)Math.Pow(1 - t, 3);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return availableSize;
}
public override void OnPointerPressed(PointerEventArgs e)
{
Console.WriteLine($"[SkiaNavigationPage] OnPointerPressed at ({e.X}, {e.Y}), _isAnimating={_isAnimating}");
if (_isAnimating) return;
// Check for back button click
if (_showBackButton && _navigationStack.Count > 0)
{
if (e.X < 56 && e.Y < _navigationBarHeight)
{
Console.WriteLine($"[SkiaNavigationPage] Back button clicked");
Pop();
return;
}
}
Console.WriteLine($"[SkiaNavigationPage] Forwarding to _currentPage: {_currentPage?.GetType().Name}");
_currentPage?.OnPointerPressed(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (_isAnimating) return;
_currentPage?.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isAnimating) return;
_currentPage?.OnPointerReleased(e);
}
public override void OnKeyDown(KeyEventArgs e)
{
if (_isAnimating) return;
// Handle back navigation with Escape or Backspace
if ((e.Key == Key.Escape || e.Key == Key.Backspace) && _navigationStack.Count > 0)
{
Pop();
e.Handled = true;
return;
}
_currentPage?.OnKeyDown(e);
}
public override void OnKeyUp(KeyEventArgs e)
{
if (_isAnimating) return;
_currentPage?.OnKeyUp(e);
}
public override void OnScroll(ScrollEventArgs e)
{
if (_isAnimating) return;
_currentPage?.OnScroll(e);
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible)
return null;
// Back button area - return self so OnPointerPressed handles it
if (_showBackButton && _navigationStack.Count > 0 && x < 56 && y < _navigationBarHeight)
{
return this;
}
// Check current page
if (_currentPage != null)
{
try
{
var hit = _currentPage.HitTest(x, y);
if (hit != null)
return hit;
}
catch (Exception ex)
{
Console.WriteLine($"[SkiaNavigationPage] HitTest error: {ex.Message}");
}
}
return this;
}
}
/// <summary>
/// Event args for navigation events.
/// </summary>
public class NavigationEventArgs : EventArgs
{
public SkiaPage Page { get; }
public NavigationEventArgs(SkiaPage page)
{
Page = page;
}
}

View File

@@ -1,458 +1,464 @@
using System;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
using Microsoft.Maui.Graphics;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Base class for Skia-rendered pages.
/// </summary>
public class SkiaPage : SkiaView
{
private SkiaView? _content;
private SkiaView? _content;
private string _title = "";
private SKColor _titleBarColor = new SKColor(0x21, 0x96, 0xF3); // Material Blue
private SKColor _titleTextColor = SKColors.White;
private bool _showNavigationBar = false;
private float _navigationBarHeight = 56;
private string _title = "";
// Padding
private float _paddingLeft;
private float _paddingTop;
private float _paddingRight;
private float _paddingBottom;
private SKColor _titleBarColor = new SKColor((byte)33, (byte)150, (byte)243);
public SkiaView? Content
{
get => _content;
set
{
if (_content != null)
{
_content.Parent = null;
}
_content = value;
if (_content != null)
{
_content.Parent = this;
}
Invalidate();
}
}
private SKColor _titleTextColor = SKColors.White;
public string Title
{
get => _title;
set
{
_title = value;
Invalidate();
}
}
private bool _showNavigationBar;
public SKColor TitleBarColor
{
get => _titleBarColor;
set
{
_titleBarColor = value;
Invalidate();
}
}
private float _navigationBarHeight = 56f;
public SKColor TitleTextColor
{
get => _titleTextColor;
set
{
_titleTextColor = value;
Invalidate();
}
}
private float _paddingLeft;
public bool ShowNavigationBar
{
get => _showNavigationBar;
set
{
_showNavigationBar = value;
Invalidate();
}
}
private float _paddingTop;
public float NavigationBarHeight
{
get => _navigationBarHeight;
set
{
_navigationBarHeight = value;
Invalidate();
}
}
private float _paddingRight;
public float PaddingLeft
{
get => _paddingLeft;
set { _paddingLeft = value; Invalidate(); }
}
private float _paddingBottom;
public float PaddingTop
{
get => _paddingTop;
set { _paddingTop = value; Invalidate(); }
}
public SkiaView? Content
{
get
{
return _content;
}
set
{
if (_content != null)
{
_content.Parent = null;
}
_content = value;
if (_content != null)
{
_content.Parent = this;
}
Invalidate();
}
}
public float PaddingRight
{
get => _paddingRight;
set { _paddingRight = value; Invalidate(); }
}
public string Title
{
get
{
return _title;
}
set
{
_title = value;
Invalidate();
}
}
public float PaddingBottom
{
get => _paddingBottom;
set { _paddingBottom = value; Invalidate(); }
}
public SKColor TitleBarColor
{
get
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return _titleBarColor;
}
set
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
_titleBarColor = value;
Invalidate();
}
}
public bool IsBusy { get; set; }
public SKColor TitleTextColor
{
get
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return _titleTextColor;
}
set
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
_titleTextColor = value;
Invalidate();
}
}
public event EventHandler? Appearing;
public event EventHandler? Disappearing;
public bool ShowNavigationBar
{
get
{
return _showNavigationBar;
}
set
{
_showNavigationBar = value;
Invalidate();
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
// Draw background
if (BackgroundColor != SKColors.Transparent)
{
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, bgPaint);
}
public float NavigationBarHeight
{
get
{
return _navigationBarHeight;
}
set
{
_navigationBarHeight = value;
Invalidate();
}
}
var contentTop = bounds.Top;
public float PaddingLeft
{
get
{
return _paddingLeft;
}
set
{
_paddingLeft = value;
Invalidate();
}
}
// Draw navigation bar if visible
if (_showNavigationBar)
{
DrawNavigationBar(canvas, new SKRect(bounds.Left, bounds.Top, bounds.Right, bounds.Top + _navigationBarHeight));
contentTop = bounds.Top + _navigationBarHeight;
}
public float PaddingTop
{
get
{
return _paddingTop;
}
set
{
_paddingTop = value;
Invalidate();
}
}
// Calculate content bounds with padding
var contentBounds = new SKRect(
bounds.Left + _paddingLeft,
contentTop + _paddingTop,
bounds.Right - _paddingRight,
bounds.Bottom - _paddingBottom);
public float PaddingRight
{
get
{
return _paddingRight;
}
set
{
_paddingRight = value;
Invalidate();
}
}
// Draw content
if (_content != null)
{
// Apply content's margin to the content bounds
var margin = _content.Margin;
var adjustedBounds = new SKRect(
contentBounds.Left + (float)margin.Left,
contentBounds.Top + (float)margin.Top,
contentBounds.Right - (float)margin.Right,
contentBounds.Bottom - (float)margin.Bottom);
public float PaddingBottom
{
get
{
return _paddingBottom;
}
set
{
_paddingBottom = value;
Invalidate();
}
}
// Measure and arrange the content before drawing
var availableSize = new SKSize(adjustedBounds.Width, adjustedBounds.Height);
_content.Measure(availableSize);
_content.Arrange(adjustedBounds);
Console.WriteLine($"[SkiaPage] Drawing content: {_content.GetType().Name}, Bounds={_content.Bounds}, IsVisible={_content.IsVisible}");
_content.Draw(canvas);
}
public bool IsBusy { get; set; }
// Draw busy indicator overlay
if (IsBusy)
{
DrawBusyIndicator(canvas, bounds);
}
}
public event EventHandler? Appearing;
protected virtual void DrawNavigationBar(SKCanvas canvas, SKRect bounds)
{
// Draw navigation bar background
using var barPaint = new SKPaint
{
Color = _titleBarColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, barPaint);
public event EventHandler? Disappearing;
// Draw title
if (!string.IsNullOrEmpty(_title))
{
using var font = new SKFont(SKTypeface.Default, 20);
using var textPaint = new SKPaint(font)
{
Color = _titleTextColor,
IsAntialias = true
};
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Expected O, but got Unknown
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_013f: Unknown result type (might be due to invalid IL or missing references)
//IL_0141: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Unknown result type (might be due to invalid IL or missing references)
//IL_01df: Unknown result type (might be due to invalid IL or missing references)
if (base.BackgroundColor != SKColors.Transparent)
{
SKPaint val = new SKPaint
{
Color = base.BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
float num = ((SKRect)(ref bounds)).Top;
if (_showNavigationBar)
{
DrawNavigationBar(canvas, new SKRect(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Top + _navigationBarHeight));
num = ((SKRect)(ref bounds)).Top + _navigationBarHeight;
}
SKRect val2 = default(SKRect);
((SKRect)(ref val2))._002Ector(((SKRect)(ref bounds)).Left + _paddingLeft, num + _paddingTop, ((SKRect)(ref bounds)).Right - _paddingRight, ((SKRect)(ref bounds)).Bottom - _paddingBottom);
if (_content != null)
{
Thickness margin = _content.Margin;
SKRect bounds2 = default(SKRect);
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref val2)).Left + (float)((Thickness)(ref margin)).Left, ((SKRect)(ref val2)).Top + (float)((Thickness)(ref margin)).Top, ((SKRect)(ref val2)).Right - (float)((Thickness)(ref margin)).Right, ((SKRect)(ref val2)).Bottom - (float)((Thickness)(ref margin)).Bottom);
SKSize availableSize = default(SKSize);
((SKSize)(ref availableSize))._002Ector(((SKRect)(ref bounds2)).Width, ((SKRect)(ref bounds2)).Height);
_content.Measure(availableSize);
_content.Arrange(bounds2);
Console.WriteLine($"[SkiaPage] Drawing content: {((object)_content).GetType().Name}, Bounds={_content.Bounds}, IsVisible={_content.IsVisible}");
_content.Draw(canvas);
}
if (IsBusy)
{
DrawBusyIndicator(canvas, bounds);
}
}
var textBounds = new SKRect();
textPaint.MeasureText(_title, ref textBounds);
protected virtual void DrawNavigationBar(SKCanvas canvas, SKRect bounds)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Expected O, but got Unknown
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Expected O, but got Unknown
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Expected O, but got Unknown
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Expected O, but got Unknown
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = _titleBarColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
if (!string.IsNullOrEmpty(_title))
{
SKFont val2 = new SKFont(SKTypeface.Default, 20f, 1f, 0f);
try
{
SKPaint val3 = new SKPaint(val2)
{
Color = _titleTextColor,
IsAntialias = true
};
try
{
SKRect val4 = default(SKRect);
val3.MeasureText(_title, ref val4);
float num = ((SKRect)(ref bounds)).Left + 16f;
float num2 = ((SKRect)(ref bounds)).MidY - ((SKRect)(ref val4)).MidY;
canvas.DrawText(_title, num, num2, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
SKPaint val5 = new SKPaint
{
Color = new SKColor((byte)0, (byte)0, (byte)0, (byte)30),
Style = (SKPaintStyle)0,
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, 2f)
};
try
{
canvas.DrawRect(new SKRect(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Bottom, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom + 4f), val5);
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
var x = bounds.Left + 16;
var y = bounds.MidY - textBounds.MidY;
canvas.DrawText(_title, x, y, textPaint);
}
private void DrawBusyIndicator(SKCanvas canvas, SKRect bounds)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Expected O, but got Unknown
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Expected O, but got Unknown
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = new SKColor(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)180),
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(bounds, val);
SKPaint val2 = new SKPaint
{
Color = _titleBarColor,
Style = (SKPaintStyle)1,
StrokeWidth = 4f,
IsAntialias = true,
StrokeCap = (SKStrokeCap)1
};
try
{
float midX = ((SKRect)(ref bounds)).MidX;
float midY = ((SKRect)(ref bounds)).MidY;
float num = 20f;
SKPath val3 = new SKPath();
try
{
val3.AddArc(new SKRect(midX - num, midY - num, midX + num, midY + num), 0f, 270f);
canvas.DrawPath(val3, val2);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
// Draw shadow
using var shadowPaint = new SKPaint
{
Color = new SKColor(0, 0, 0, 30),
Style = SKPaintStyle.Fill,
MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, 2)
};
canvas.DrawRect(new SKRect(bounds.Left, bounds.Bottom, bounds.Right, bounds.Bottom + 4), shadowPaint);
}
public void OnAppearing()
{
Console.WriteLine($"[SkiaPage] OnAppearing called for: {Title}, HasListeners={this.Appearing != null}");
this.Appearing?.Invoke(this, EventArgs.Empty);
}
private void DrawBusyIndicator(SKCanvas canvas, SKRect bounds)
{
// Draw semi-transparent overlay
using var overlayPaint = new SKPaint
{
Color = new SKColor(255, 255, 255, 180),
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, overlayPaint);
public void OnDisappearing()
{
this.Disappearing?.Invoke(this, EventArgs.Empty);
}
// Draw spinning indicator (simplified - would animate in real impl)
using var indicatorPaint = new SKPaint
{
Color = _titleBarColor,
Style = SKPaintStyle.Stroke,
StrokeWidth = 4,
IsAntialias = true,
StrokeCap = SKStrokeCap.Round
};
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
return availableSize;
}
var centerX = bounds.MidX;
var centerY = bounds.MidY;
var radius = 20f;
public override void OnPointerPressed(PointerEventArgs e)
{
float num = (_showNavigationBar ? _navigationBarHeight : 0f);
if (e.Y > num && _content != null)
{
PointerEventArgs e2 = new PointerEventArgs(e.X - _paddingLeft, e.Y - num - _paddingTop, e.Button);
_content.OnPointerPressed(e2);
}
}
using var path = new SKPath();
path.AddArc(new SKRect(centerX - radius, centerY - radius, centerX + radius, centerY + radius), 0, 270);
canvas.DrawPath(path, indicatorPaint);
}
public override void OnPointerMoved(PointerEventArgs e)
{
float num = (_showNavigationBar ? _navigationBarHeight : 0f);
if (e.Y > num && _content != null)
{
PointerEventArgs e2 = new PointerEventArgs(e.X - _paddingLeft, e.Y - num - _paddingTop, e.Button);
_content.OnPointerMoved(e2);
}
}
public void OnAppearing()
{
Console.WriteLine($"[SkiaPage] OnAppearing called for: {Title}, HasListeners={Appearing != null}");
Appearing?.Invoke(this, EventArgs.Empty);
}
public override void OnPointerReleased(PointerEventArgs e)
{
float num = (_showNavigationBar ? _navigationBarHeight : 0f);
if (e.Y > num && _content != null)
{
PointerEventArgs e2 = new PointerEventArgs(e.X - _paddingLeft, e.Y - num - _paddingTop, e.Button);
_content.OnPointerReleased(e2);
}
}
public void OnDisappearing()
{
Disappearing?.Invoke(this, EventArgs.Empty);
}
public override void OnKeyDown(KeyEventArgs e)
{
_content?.OnKeyDown(e);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
// Page takes all available space
return availableSize;
}
public override void OnKeyUp(KeyEventArgs e)
{
_content?.OnKeyUp(e);
}
public override void OnPointerPressed(PointerEventArgs e)
{
// Adjust coordinates for content
var contentTop = _showNavigationBar ? _navigationBarHeight : 0;
if (e.Y > contentTop && _content != null)
{
var contentE = new PointerEventArgs(e.X - _paddingLeft, e.Y - contentTop - _paddingTop, e.Button);
_content.OnPointerPressed(contentE);
}
}
public override void OnScroll(ScrollEventArgs e)
{
_content?.OnScroll(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
var contentTop = _showNavigationBar ? _navigationBarHeight : 0;
if (e.Y > contentTop && _content != null)
{
var contentE = new PointerEventArgs(e.X - _paddingLeft, e.Y - contentTop - _paddingTop, e.Button);
_content.OnPointerMoved(contentE);
}
}
public override SkiaView? HitTest(float x, float y)
{
if (!base.IsVisible)
{
return null;
}
if (_content != null)
{
SkiaView skiaView = _content.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
public override void OnPointerReleased(PointerEventArgs e)
{
var contentTop = _showNavigationBar ? _navigationBarHeight : 0;
if (e.Y > contentTop && _content != null)
{
var contentE = new PointerEventArgs(e.X - _paddingLeft, e.Y - contentTop - _paddingTop, e.Button);
_content.OnPointerReleased(contentE);
}
}
public override void OnKeyDown(KeyEventArgs e)
{
_content?.OnKeyDown(e);
}
public override void OnKeyUp(KeyEventArgs e)
{
_content?.OnKeyUp(e);
}
public override void OnScroll(ScrollEventArgs e)
{
_content?.OnScroll(e);
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible)
return null;
// Don't check Bounds.Contains for page - it may not be set
// Just forward to content
// Check content
if (_content != null)
{
var hit = _content.HitTest(x, y);
if (hit != null)
return hit;
}
return this;
}
}
/// <summary>
/// Simple content page view with toolbar items support.
/// </summary>
public class SkiaContentPage : SkiaPage
{
private readonly List<SkiaToolbarItem> _toolbarItems = new();
/// <summary>
/// Gets the toolbar items for this page.
/// </summary>
public IList<SkiaToolbarItem> ToolbarItems => _toolbarItems;
protected override void DrawNavigationBar(SKCanvas canvas, SKRect bounds)
{
// Draw navigation bar background
using var barPaint = new SKPaint
{
Color = TitleBarColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(bounds, barPaint);
// Draw title
if (!string.IsNullOrEmpty(Title))
{
using var font = new SKFont(SKTypeface.Default, 20);
using var textPaint = new SKPaint(font)
{
Color = TitleTextColor,
IsAntialias = true
};
var textBounds = new SKRect();
textPaint.MeasureText(Title, ref textBounds);
var x = bounds.Left + 56; // Leave space for back button
var y = bounds.MidY - textBounds.MidY;
canvas.DrawText(Title, x, y, textPaint);
}
// Draw toolbar items on the right
DrawToolbarItems(canvas, bounds);
// Draw shadow
using var shadowPaint = new SKPaint
{
Color = new SKColor(0, 0, 0, 30),
Style = SKPaintStyle.Fill,
MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, 2)
};
canvas.DrawRect(new SKRect(bounds.Left, bounds.Bottom, bounds.Right, bounds.Bottom + 4), shadowPaint);
}
private void DrawToolbarItems(SKCanvas canvas, SKRect navBarBounds)
{
var primaryItems = _toolbarItems.Where(t => t.Order == SkiaToolbarItemOrder.Primary).ToList();
Console.WriteLine($"[SkiaContentPage] DrawToolbarItems: {primaryItems.Count} primary items, navBarBounds={navBarBounds}");
if (primaryItems.Count == 0) return;
using var font = new SKFont(SKTypeface.Default, 14);
using var textPaint = new SKPaint(font)
{
Color = TitleTextColor,
IsAntialias = true
};
float rightEdge = navBarBounds.Right - 16;
foreach (var item in primaryItems.AsEnumerable().Reverse())
{
var textBounds = new SKRect();
textPaint.MeasureText(item.Text, ref textBounds);
var itemWidth = textBounds.Width + 24; // Padding
var itemLeft = rightEdge - itemWidth;
// Store hit area for click handling
item.HitBounds = new SKRect(itemLeft, navBarBounds.Top, rightEdge, navBarBounds.Bottom);
Console.WriteLine($"[SkiaContentPage] Toolbar item '{item.Text}' HitBounds set to {item.HitBounds}");
// Draw text
var x = itemLeft + 12;
var y = navBarBounds.MidY - textBounds.MidY;
canvas.DrawText(item.Text, x, y, textPaint);
rightEdge = itemLeft - 8; // Gap between items
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
Console.WriteLine($"[SkiaContentPage] OnPointerPressed at ({e.X}, {e.Y}), ShowNavigationBar={ShowNavigationBar}, NavigationBarHeight={NavigationBarHeight}");
Console.WriteLine($"[SkiaContentPage] ToolbarItems count: {_toolbarItems.Count}");
// Check toolbar item clicks
if (ShowNavigationBar && e.Y < NavigationBarHeight)
{
Console.WriteLine($"[SkiaContentPage] In navigation bar area, checking toolbar items");
foreach (var item in _toolbarItems.Where(t => t.Order == SkiaToolbarItemOrder.Primary))
{
var bounds = item.HitBounds;
var contains = bounds.Contains(e.X, e.Y);
Console.WriteLine($"[SkiaContentPage] Checking item '{item.Text}', HitBounds=({bounds.Left},{bounds.Top},{bounds.Right},{bounds.Bottom}), Click=({e.X},{e.Y}), Contains={contains}, Command={item.Command != null}");
if (contains)
{
Console.WriteLine($"[SkiaContentPage] Toolbar item clicked: {item.Text}");
item.Command?.Execute(null);
return;
}
}
Console.WriteLine($"[SkiaContentPage] No toolbar item hit");
}
base.OnPointerPressed(e);
}
}
/// <summary>
/// Represents a toolbar item in the navigation bar.
/// </summary>
public class SkiaToolbarItem
{
public string Text { get; set; } = "";
public SkiaToolbarItemOrder Order { get; set; } = SkiaToolbarItemOrder.Primary;
public System.Windows.Input.ICommand? Command { get; set; }
public SKRect HitBounds { get; set; }
}
/// <summary>
/// Order of toolbar items.
/// </summary>
public enum SkiaToolbarItemOrder
{
Primary,
Secondary
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,192 +1,205 @@
using System;
using Microsoft.Maui.Controls;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered progress bar control with full XAML styling support.
/// </summary>
public class SkiaProgressBar : SkiaView
{
public static readonly BindableProperty ProgressProperty = BindableProperty.Create("Progress", typeof(double), typeof(SkiaProgressBar), (object)0.0, (BindingMode)1, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaProgressBar)(object)b).OnProgressChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)((BindableObject b, object v) => Math.Clamp((double)v, 0.0, 1.0)), (CreateDefaultValueDelegate)null);
#region BindableProperties
public static readonly BindableProperty TrackColorProperty = BindableProperty.Create("TrackColor", typeof(SKColor), typeof(SkiaProgressBar), (object)new SKColor((byte)224, (byte)224, (byte)224), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaProgressBar)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for Progress.
/// </summary>
public static readonly BindableProperty ProgressProperty =
BindableProperty.Create(
nameof(Progress),
typeof(double),
typeof(SkiaProgressBar),
0.0,
BindingMode.TwoWay,
coerceValue: (b, v) => Math.Clamp((double)v, 0, 1),
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).OnProgressChanged());
public static readonly BindableProperty ProgressColorProperty = BindableProperty.Create("ProgressColor", typeof(SKColor), typeof(SkiaProgressBar), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaProgressBar)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for TrackColor.
/// </summary>
public static readonly BindableProperty TrackColorProperty =
BindableProperty.Create(
nameof(TrackColor),
typeof(SKColor),
typeof(SkiaProgressBar),
new SKColor(0xE0, 0xE0, 0xE0),
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate());
public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create("DisabledColor", typeof(SKColor), typeof(SkiaProgressBar), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaProgressBar)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for ProgressColor.
/// </summary>
public static readonly BindableProperty ProgressColorProperty =
BindableProperty.Create(
nameof(ProgressColor),
typeof(SKColor),
typeof(SkiaProgressBar),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate());
public static readonly BindableProperty BarHeightProperty = BindableProperty.Create("BarHeight", typeof(float), typeof(SkiaProgressBar), (object)4f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaProgressBar)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for DisabledColor.
/// </summary>
public static readonly BindableProperty DisabledColorProperty =
BindableProperty.Create(
nameof(DisabledColor),
typeof(SKColor),
typeof(SkiaProgressBar),
new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate());
public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(float), typeof(SkiaProgressBar), (object)2f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaProgressBar)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for BarHeight.
/// </summary>
public static readonly BindableProperty BarHeightProperty =
BindableProperty.Create(
nameof(BarHeight),
typeof(float),
typeof(SkiaProgressBar),
4f,
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).InvalidateMeasure());
public double Progress
{
get
{
return (double)((BindableObject)this).GetValue(ProgressProperty);
}
set
{
((BindableObject)this).SetValue(ProgressProperty, (object)value);
}
}
/// <summary>
/// Bindable property for CornerRadius.
/// </summary>
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.Create(
nameof(CornerRadius),
typeof(float),
typeof(SkiaProgressBar),
2f,
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate());
public SKColor TrackColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(TrackColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(TrackColorProperty, (object)value);
}
}
#endregion
public SKColor ProgressColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ProgressColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ProgressColorProperty, (object)value);
}
}
#region Properties
public SKColor DisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(DisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(DisabledColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the progress value (0.0 to 1.0).
/// </summary>
public double Progress
{
get => (double)GetValue(ProgressProperty);
set => SetValue(ProgressProperty, value);
}
public float BarHeight
{
get
{
return (float)((BindableObject)this).GetValue(BarHeightProperty);
}
set
{
((BindableObject)this).SetValue(BarHeightProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the track color.
/// </summary>
public SKColor TrackColor
{
get => (SKColor)GetValue(TrackColorProperty);
set => SetValue(TrackColorProperty, value);
}
public float CornerRadius
{
get
{
return (float)((BindableObject)this).GetValue(CornerRadiusProperty);
}
set
{
((BindableObject)this).SetValue(CornerRadiusProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the progress color.
/// </summary>
public SKColor ProgressColor
{
get => (SKColor)GetValue(ProgressColorProperty);
set => SetValue(ProgressColorProperty, value);
}
public event EventHandler<ProgressChangedEventArgs>? ProgressChanged;
/// <summary>
/// Gets or sets the disabled color.
/// </summary>
public SKColor DisabledColor
{
get => (SKColor)GetValue(DisabledColorProperty);
set => SetValue(DisabledColorProperty, value);
}
private void OnProgressChanged()
{
this.ProgressChanged?.Invoke(this, new ProgressChangedEventArgs(Progress));
Invalidate();
}
/// <summary>
/// Gets or sets the bar height.
/// </summary>
public float BarHeight
{
get => (float)GetValue(BarHeightProperty);
set => SetValue(BarHeightProperty, value);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Expected O, but got Unknown
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Expected O, but got Unknown
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Expected O, but got Unknown
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: Expected O, but got Unknown
float midY = ((SKRect)(ref bounds)).MidY;
float num = midY - BarHeight / 2f;
float num2 = midY + BarHeight / 2f;
SKPaint val = new SKPaint
{
Color = (base.IsEnabled ? TrackColor : DisabledColor),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
SKRoundRect val2 = new SKRoundRect(new SKRect(((SKRect)(ref bounds)).Left, num, ((SKRect)(ref bounds)).Right, num2), CornerRadius);
canvas.DrawRoundRect(val2, val);
if (Progress > 0.0)
{
float num3 = ((SKRect)(ref bounds)).Width * (float)Progress;
SKPaint val3 = new SKPaint
{
Color = (base.IsEnabled ? ProgressColor : DisabledColor),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
SKRoundRect val4 = new SKRoundRect(new SKRect(((SKRect)(ref bounds)).Left, num, ((SKRect)(ref bounds)).Left + num3, num2), CornerRadius);
canvas.DrawRoundRect(val4, val3);
return;
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
/// <summary>
/// Gets or sets the corner radius.
/// </summary>
public float CornerRadius
{
get => (float)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(200f, BarHeight + 8f);
}
#endregion
/// <summary>
/// Event raised when progress changes.
/// </summary>
public event EventHandler<ProgressChangedEventArgs>? ProgressChanged;
private void OnProgressChanged()
{
ProgressChanged?.Invoke(this, new ProgressChangedEventArgs(Progress));
Invalidate();
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var trackY = bounds.MidY;
var trackTop = trackY - BarHeight / 2;
var trackBottom = trackY + BarHeight / 2;
// Draw track
using var trackPaint = new SKPaint
{
Color = IsEnabled ? TrackColor : DisabledColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
var trackRect = new SKRoundRect(
new SKRect(bounds.Left, trackTop, bounds.Right, trackBottom),
CornerRadius);
canvas.DrawRoundRect(trackRect, trackPaint);
// Draw progress
if (Progress > 0)
{
var progressWidth = bounds.Width * (float)Progress;
using var progressPaint = new SKPaint
{
Color = IsEnabled ? ProgressColor : DisabledColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
var progressRect = new SKRoundRect(
new SKRect(bounds.Left, trackTop, bounds.Left + progressWidth, trackBottom),
CornerRadius);
canvas.DrawRoundRect(progressRect, progressPaint);
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(200, BarHeight + 8);
}
}
/// <summary>
/// Event args for progress changed events.
/// </summary>
public class ProgressChangedEventArgs : EventArgs
{
public double Progress { get; }
public ProgressChangedEventArgs(double progress) => Progress = progress;
}

View File

@@ -1,442 +1,284 @@
using System;
using System.Collections.Generic;
using Microsoft.Maui.Controls;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered radio button control with full XAML styling support.
/// </summary>
public class SkiaRadioButton : SkiaView
{
public static readonly BindableProperty IsCheckedProperty = BindableProperty.Create("IsChecked", typeof(bool), typeof(SkiaRadioButton), (object)false, (BindingMode)1, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).OnIsCheckedChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
#region BindableProperties
public static readonly BindableProperty ContentProperty = BindableProperty.Create("Content", typeof(string), typeof(SkiaRadioButton), (object)"", (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty IsCheckedProperty =
BindableProperty.Create(nameof(IsChecked), typeof(bool), typeof(SkiaRadioButton), false, BindingMode.TwoWay,
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).OnIsCheckedChanged());
public static readonly BindableProperty ValueProperty = BindableProperty.Create("Value", typeof(object), typeof(SkiaRadioButton), (object)null, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ContentProperty =
BindableProperty.Create(nameof(Content), typeof(string), typeof(SkiaRadioButton), "",
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).InvalidateMeasure());
public static readonly BindableProperty GroupNameProperty = BindableProperty.Create("GroupName", typeof(string), typeof(SkiaRadioButton), (object)null, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).OnGroupNameChanged((string)o, (string)n);
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ValueProperty =
BindableProperty.Create(nameof(Value), typeof(object), typeof(SkiaRadioButton), null);
public static readonly BindableProperty RadioColorProperty = BindableProperty.Create("RadioColor", typeof(SKColor), typeof(SkiaRadioButton), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty GroupNameProperty =
BindableProperty.Create(nameof(GroupName), typeof(string), typeof(SkiaRadioButton), null,
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).OnGroupNameChanged((string?)o, (string?)n));
public static readonly BindableProperty UncheckedColorProperty = BindableProperty.Create("UncheckedColor", typeof(SKColor), typeof(SkiaRadioButton), (object)new SKColor((byte)117, (byte)117, (byte)117), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty RadioColorProperty =
BindableProperty.Create(nameof(RadioColor), typeof(SKColor), typeof(SkiaRadioButton), new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).Invalidate());
public static readonly BindableProperty TextColorProperty = BindableProperty.Create("TextColor", typeof(SKColor), typeof(SkiaRadioButton), (object)SKColors.Black, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty UncheckedColorProperty =
BindableProperty.Create(nameof(UncheckedColor), typeof(SKColor), typeof(SkiaRadioButton), new SKColor(0x75, 0x75, 0x75),
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).Invalidate());
public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create("DisabledColor", typeof(SKColor), typeof(SkiaRadioButton), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty TextColorProperty =
BindableProperty.Create(nameof(TextColor), typeof(SKColor), typeof(SkiaRadioButton), SKColors.Black,
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).Invalidate());
public static readonly BindableProperty FontSizeProperty = BindableProperty.Create("FontSize", typeof(float), typeof(SkiaRadioButton), (object)14f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty DisabledColorProperty =
BindableProperty.Create(nameof(DisabledColor), typeof(SKColor), typeof(SkiaRadioButton), new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).Invalidate());
public static readonly BindableProperty RadioSizeProperty = BindableProperty.Create("RadioSize", typeof(float), typeof(SkiaRadioButton), (object)20f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty FontSizeProperty =
BindableProperty.Create(nameof(FontSize), typeof(float), typeof(SkiaRadioButton), 14f,
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).InvalidateMeasure());
public static readonly BindableProperty SpacingProperty = BindableProperty.Create("Spacing", typeof(float), typeof(SkiaRadioButton), (object)8f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaRadioButton)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty RadioSizeProperty =
BindableProperty.Create(nameof(RadioSize), typeof(float), typeof(SkiaRadioButton), 20f,
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).InvalidateMeasure());
private static readonly Dictionary<string, List<WeakReference<SkiaRadioButton>>> _groups = new Dictionary<string, List<WeakReference<SkiaRadioButton>>>();
public static readonly BindableProperty SpacingProperty =
BindableProperty.Create(nameof(Spacing), typeof(float), typeof(SkiaRadioButton), 8f,
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).InvalidateMeasure());
public bool IsChecked
{
get
{
return (bool)((BindableObject)this).GetValue(IsCheckedProperty);
}
set
{
((BindableObject)this).SetValue(IsCheckedProperty, (object)value);
}
}
#endregion
public string Content
{
get
{
return (string)((BindableObject)this).GetValue(ContentProperty);
}
set
{
((BindableObject)this).SetValue(ContentProperty, (object)value);
}
}
#region Properties
public object? Value
{
get
{
return ((BindableObject)this).GetValue(ValueProperty);
}
set
{
((BindableObject)this).SetValue(ValueProperty, value);
}
}
public bool IsChecked
{
get => (bool)GetValue(IsCheckedProperty);
set => SetValue(IsCheckedProperty, value);
}
public string? GroupName
{
get
{
return (string)((BindableObject)this).GetValue(GroupNameProperty);
}
set
{
((BindableObject)this).SetValue(GroupNameProperty, (object)value);
}
}
public string Content
{
get => (string)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
public SKColor RadioColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(RadioColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(RadioColorProperty, (object)value);
}
}
public object? Value
{
get => GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public SKColor UncheckedColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(UncheckedColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(UncheckedColorProperty, (object)value);
}
}
public string? GroupName
{
get => (string?)GetValue(GroupNameProperty);
set => SetValue(GroupNameProperty, value);
}
public SKColor TextColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(TextColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(TextColorProperty, (object)value);
}
}
public SKColor RadioColor
{
get => (SKColor)GetValue(RadioColorProperty);
set => SetValue(RadioColorProperty, value);
}
public SKColor DisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(DisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(DisabledColorProperty, (object)value);
}
}
public SKColor UncheckedColor
{
get => (SKColor)GetValue(UncheckedColorProperty);
set => SetValue(UncheckedColorProperty, value);
}
public float FontSize
{
get
{
return (float)((BindableObject)this).GetValue(FontSizeProperty);
}
set
{
((BindableObject)this).SetValue(FontSizeProperty, (object)value);
}
}
public SKColor TextColor
{
get => (SKColor)GetValue(TextColorProperty);
set => SetValue(TextColorProperty, value);
}
public float RadioSize
{
get
{
return (float)((BindableObject)this).GetValue(RadioSizeProperty);
}
set
{
((BindableObject)this).SetValue(RadioSizeProperty, (object)value);
}
}
public SKColor DisabledColor
{
get => (SKColor)GetValue(DisabledColorProperty);
set => SetValue(DisabledColorProperty, value);
}
public float Spacing
{
get
{
return (float)((BindableObject)this).GetValue(SpacingProperty);
}
set
{
((BindableObject)this).SetValue(SpacingProperty, (object)value);
}
}
public float FontSize
{
get => (float)GetValue(FontSizeProperty);
set => SetValue(FontSizeProperty, value);
}
public event EventHandler? CheckedChanged;
public float RadioSize
{
get => (float)GetValue(RadioSizeProperty);
set => SetValue(RadioSizeProperty, value);
}
public SkiaRadioButton()
{
base.IsFocusable = true;
}
public float Spacing
{
get => (float)GetValue(SpacingProperty);
set => SetValue(SpacingProperty, value);
}
private void OnIsCheckedChanged()
{
if (IsChecked && !string.IsNullOrEmpty(GroupName))
{
UncheckOthersInGroup();
}
this.CheckedChanged?.Invoke(this, EventArgs.Empty);
SkiaVisualStateManager.GoToState(this, IsChecked ? "Checked" : "Unchecked");
Invalidate();
}
#endregion
private void OnGroupNameChanged(string? oldValue, string? newValue)
{
RemoveFromGroup(oldValue);
AddToGroup(newValue);
}
private static readonly Dictionary<string, List<WeakReference<SkiaRadioButton>>> _groups = new();
private void AddToGroup(string? groupName)
{
if (!string.IsNullOrEmpty(groupName))
{
if (!_groups.TryGetValue(groupName, out List<WeakReference<SkiaRadioButton>> value))
{
value = new List<WeakReference<SkiaRadioButton>>();
_groups[groupName] = value;
}
value.RemoveAll((WeakReference<SkiaRadioButton> wr) => !wr.TryGetTarget(out SkiaRadioButton _));
value.Add(new WeakReference<SkiaRadioButton>(this));
}
}
public event EventHandler? CheckedChanged;
private void RemoveFromGroup(string? groupName)
{
if (!string.IsNullOrEmpty(groupName) && _groups.TryGetValue(groupName, out List<WeakReference<SkiaRadioButton>> value))
{
value.RemoveAll((WeakReference<SkiaRadioButton> wr) => !wr.TryGetTarget(out SkiaRadioButton target) || target == this);
if (value.Count == 0)
{
_groups.Remove(groupName);
}
}
}
public SkiaRadioButton()
{
IsFocusable = true;
}
private void UncheckOthersInGroup()
{
if (string.IsNullOrEmpty(GroupName) || !_groups.TryGetValue(GroupName, out List<WeakReference<SkiaRadioButton>> value))
{
return;
}
foreach (WeakReference<SkiaRadioButton> item in value)
{
if (item.TryGetTarget(out var target) && target != this && target.IsChecked)
{
((BindableObject)target).SetValue(IsCheckedProperty, (object)false);
}
}
}
private void OnIsCheckedChanged()
{
if (IsChecked && !string.IsNullOrEmpty(GroupName))
{
UncheckOthersInGroup();
}
CheckedChanged?.Invoke(this, EventArgs.Empty);
SkiaVisualStateManager.GoToState(this, IsChecked ? SkiaVisualStateManager.CommonStates.Checked : SkiaVisualStateManager.CommonStates.Unchecked);
Invalidate();
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Expected O, but got Unknown
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Expected O, but got Unknown
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_014a: Unknown result type (might be due to invalid IL or missing references)
//IL_0151: Expected O, but got Unknown
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Expected O, but got Unknown
//IL_0153: Unknown result type (might be due to invalid IL or missing references)
//IL_0158: Unknown result type (might be due to invalid IL or missing references)
//IL_016a: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: Expected O, but got Unknown
//IL_0196: Unknown result type (might be due to invalid IL or missing references)
float num = RadioSize / 2f;
float num2 = ((SKRect)(ref bounds)).Left + num;
float midY = ((SKRect)(ref bounds)).MidY;
SKPaint val = new SKPaint
{
Color = ((!base.IsEnabled) ? DisabledColor : (IsChecked ? RadioColor : UncheckedColor)),
Style = (SKPaintStyle)1,
StrokeWidth = 2f,
IsAntialias = true
};
try
{
canvas.DrawCircle(num2, midY, num - 1f, val);
if (IsChecked)
{
SKPaint val2 = new SKPaint
{
Color = (base.IsEnabled ? RadioColor : DisabledColor),
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
canvas.DrawCircle(num2, midY, num - 5f, val2);
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
if (base.IsFocused)
{
SKPaint val3 = new SKPaint();
SKColor radioColor = RadioColor;
val3.Color = ((SKColor)(ref radioColor)).WithAlpha((byte)80);
val3.Style = (SKPaintStyle)0;
val3.IsAntialias = true;
SKPaint val4 = val3;
try
{
canvas.DrawCircle(num2, midY, num + 4f, val4);
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
if (string.IsNullOrEmpty(Content))
{
return;
}
SKFont val5 = new SKFont(SKTypeface.Default, FontSize, 1f, 0f);
try
{
SKPaint val6 = new SKPaint(val5)
{
Color = (base.IsEnabled ? TextColor : DisabledColor),
IsAntialias = true
};
try
{
float num3 = ((SKRect)(ref bounds)).Left + RadioSize + Spacing;
SKRect val7 = default(SKRect);
val6.MeasureText(Content, ref val7);
canvas.DrawText(Content, num3, ((SKRect)(ref bounds)).MidY - ((SKRect)(ref val7)).MidY, val6);
}
finally
{
((IDisposable)val6)?.Dispose();
}
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
private void OnGroupNameChanged(string? oldValue, string? newValue)
{
RemoveFromGroup(oldValue);
AddToGroup(newValue);
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (base.IsEnabled && !IsChecked)
{
IsChecked = true;
}
}
private void AddToGroup(string? groupName)
{
if (string.IsNullOrEmpty(groupName)) return;
public override void OnKeyDown(KeyEventArgs e)
{
if (base.IsEnabled && (e.Key == Key.Space || e.Key == Key.Enter))
{
if (!IsChecked)
{
IsChecked = true;
}
e.Handled = true;
}
}
if (!_groups.TryGetValue(groupName, out var group))
{
group = new List<WeakReference<SkiaRadioButton>>();
_groups[groupName] = group;
}
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
}
group.RemoveAll(wr => !wr.TryGetTarget(out _));
group.Add(new WeakReference<SkiaRadioButton>(this));
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Expected O, but got Unknown
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Expected O, but got Unknown
float num = 0f;
if (!string.IsNullOrEmpty(Content))
{
SKFont val = new SKFont(SKTypeface.Default, FontSize, 1f, 0f);
try
{
SKPaint val2 = new SKPaint(val);
try
{
num = val2.MeasureText(Content) + Spacing;
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
return new SKSize(RadioSize + num, Math.Max(RadioSize, FontSize * 1.5f));
}
private void RemoveFromGroup(string? groupName)
{
if (string.IsNullOrEmpty(groupName)) return;
if (_groups.TryGetValue(groupName, out var group))
{
group.RemoveAll(wr => !wr.TryGetTarget(out var target) || target == this);
if (group.Count == 0) _groups.Remove(groupName);
}
}
private void UncheckOthersInGroup()
{
if (string.IsNullOrEmpty(GroupName)) return;
if (_groups.TryGetValue(GroupName, out var group))
{
foreach (var weakRef in group)
{
if (weakRef.TryGetTarget(out var radioButton) && radioButton != this && radioButton.IsChecked)
{
radioButton.SetValue(IsCheckedProperty, false);
}
}
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var radioRadius = RadioSize / 2;
var radioCenterX = bounds.Left + radioRadius;
var radioCenterY = bounds.MidY;
using var outerPaint = new SKPaint
{
Color = IsEnabled ? (IsChecked ? RadioColor : UncheckedColor) : DisabledColor,
Style = SKPaintStyle.Stroke,
StrokeWidth = 2,
IsAntialias = true
};
canvas.DrawCircle(radioCenterX, radioCenterY, radioRadius - 1, outerPaint);
if (IsChecked)
{
using var innerPaint = new SKPaint
{
Color = IsEnabled ? RadioColor : DisabledColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawCircle(radioCenterX, radioCenterY, radioRadius - 5, innerPaint);
}
if (IsFocused)
{
using var focusPaint = new SKPaint
{
Color = RadioColor.WithAlpha(80),
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawCircle(radioCenterX, radioCenterY, radioRadius + 4, focusPaint);
}
if (!string.IsNullOrEmpty(Content))
{
using var font = new SKFont(SKTypeface.Default, FontSize);
using var textPaint = new SKPaint(font)
{
Color = IsEnabled ? TextColor : DisabledColor,
IsAntialias = true
};
var textX = bounds.Left + RadioSize + Spacing;
var textBounds = new SKRect();
textPaint.MeasureText(Content, ref textBounds);
canvas.DrawText(Content, textX, bounds.MidY - textBounds.MidY, textPaint);
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
if (!IsChecked) IsChecked = true;
}
public override void OnKeyDown(KeyEventArgs e)
{
if (!IsEnabled) return;
if (e.Key == Key.Space || e.Key == Key.Enter)
{
if (!IsChecked) IsChecked = true;
e.Handled = true;
}
}
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, IsEnabled ? SkiaVisualStateManager.CommonStates.Normal : SkiaVisualStateManager.CommonStates.Disabled);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
var textWidth = 0f;
if (!string.IsNullOrEmpty(Content))
{
using var font = new SKFont(SKTypeface.Default, FontSize);
using var paint = new SKPaint(font);
textWidth = paint.MeasureText(Content) + Spacing;
}
return new SKSize(RadioSize + textWidth, Math.Max(RadioSize, FontSize * 1.5f));
}
}

View File

@@ -1,315 +1,278 @@
using System;
using System.Windows.Input;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A pull-to-refresh container view.
/// </summary>
public class SkiaRefreshView : SkiaLayoutView
{
private SkiaView? _content;
private SkiaView? _content;
private bool _isRefreshing = false;
private float _pullDistance = 0f;
private float _refreshThreshold = 80f;
private bool _isPulling = false;
private float _pullStartY;
private float _spinnerRotation = 0f;
private DateTime _lastSpinnerUpdate;
private bool _isRefreshing;
/// <summary>
/// Gets or sets the content view.
/// </summary>
public SkiaView? Content
{
get => _content;
set
{
if (_content != value)
{
if (_content != null)
{
RemoveChild(_content);
}
private float _pullDistance;
_content = value;
private float _refreshThreshold = 80f;
if (_content != null)
{
AddChild(_content);
}
private bool _isPulling;
InvalidateMeasure();
Invalidate();
}
}
}
private float _pullStartY;
/// <summary>
/// Gets or sets whether the view is currently refreshing.
/// </summary>
public bool IsRefreshing
{
get => _isRefreshing;
set
{
if (_isRefreshing != value)
{
_isRefreshing = value;
if (!value)
{
_pullDistance = 0;
}
Invalidate();
}
}
}
private float _spinnerRotation;
/// <summary>
/// Gets or sets the pull distance required to trigger refresh.
/// </summary>
public float RefreshThreshold
{
get => _refreshThreshold;
set => _refreshThreshold = Math.Max(40, value);
}
private DateTime _lastSpinnerUpdate;
/// <summary>
/// Gets or sets the refresh indicator color.
/// </summary>
public SKColor RefreshColor { get; set; } = new SKColor(33, 150, 243);
public SkiaView? Content
{
get
{
return _content;
}
set
{
if (_content != value)
{
if (_content != null)
{
RemoveChild(_content);
}
_content = value;
if (_content != null)
{
AddChild(_content);
}
InvalidateMeasure();
Invalidate();
}
}
}
/// <summary>
/// Gets or sets the background color of the refresh indicator.
/// </summary>
public SKColor RefreshBackgroundColor { get; set; } = SKColors.White;
public bool IsRefreshing
{
get
{
return _isRefreshing;
}
set
{
if (_isRefreshing != value)
{
_isRefreshing = value;
if (!value)
{
_pullDistance = 0f;
}
Invalidate();
}
}
}
/// <summary>
/// Event raised when refresh is triggered.
/// </summary>
public event EventHandler? Refreshing;
public float RefreshThreshold
{
get
{
return _refreshThreshold;
}
set
{
_refreshThreshold = Math.Max(40f, value);
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
if (_content != null)
{
_content.Measure(availableSize);
}
return availableSize;
}
public SKColor RefreshColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
protected override SKRect ArrangeOverride(SKRect bounds)
{
if (_content != null)
{
float offset = _isRefreshing ? _refreshThreshold : _pullDistance;
var contentBounds = new SKRect(
bounds.Left,
bounds.Top + offset,
bounds.Right,
bounds.Bottom + offset);
_content.Arrange(contentBounds);
}
return bounds;
}
public SKColor RefreshBackgroundColor { get; set; } = SKColors.White;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
canvas.Save();
canvas.ClipRect(bounds);
public ICommand? Command { get; set; }
// Draw refresh indicator
float indicatorY = bounds.Top + (_isRefreshing ? _refreshThreshold : _pullDistance) / 2;
public object? CommandParameter { get; set; }
if (_pullDistance > 0 || _isRefreshing)
{
DrawRefreshIndicator(canvas, bounds.MidX, indicatorY);
}
public event EventHandler? Refreshing;
// Draw content
_content?.Draw(canvas);
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
if (_content != null)
{
_content.Measure(availableSize);
}
return availableSize;
}
canvas.Restore();
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
if (_content != null)
{
float num = (_isRefreshing ? _refreshThreshold : _pullDistance);
SKRect bounds2 = default(SKRect);
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top + num, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom + num);
_content.Arrange(bounds2);
}
return bounds;
}
private void DrawRefreshIndicator(SKCanvas canvas, float x, float y)
{
float size = 36f;
float progress = Math.Clamp(_pullDistance / _refreshThreshold, 0f, 1f);
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
canvas.Save();
canvas.ClipRect(bounds, (SKClipOperation)1, false);
float y = ((SKRect)(ref bounds)).Top + (_isRefreshing ? _refreshThreshold : _pullDistance) / 2f;
if (_pullDistance > 0f || _isRefreshing)
{
DrawRefreshIndicator(canvas, ((SKRect)(ref bounds)).MidX, y);
}
_content?.Draw(canvas);
canvas.Restore();
}
// Draw background circle
using var bgPaint = new SKPaint
{
Color = RefreshBackgroundColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
private void DrawRefreshIndicator(SKCanvas canvas, float x, float y)
{
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Expected O, but got Unknown
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Expected O, but got Unknown
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
//IL_018c: Expected O, but got Unknown
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0118: Expected O, but got Unknown
//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
//IL_01af: Unknown result type (might be due to invalid IL or missing references)
//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
//IL_0136: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_013f: Unknown result type (might be due to invalid IL or missing references)
float num = 36f;
float num2 = Math.Clamp(_pullDistance / _refreshThreshold, 0f, 1f);
SKPaint val = new SKPaint
{
Color = RefreshBackgroundColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
val.ImageFilter = SKImageFilter.CreateDropShadow(0f, 2f, 4f, 4f, new SKColor((byte)0, (byte)0, (byte)0, (byte)40));
canvas.DrawCircle(x, y, num / 2f, val);
SKPaint val2 = new SKPaint
{
Color = RefreshColor,
Style = (SKPaintStyle)1,
StrokeWidth = 3f,
IsAntialias = true,
StrokeCap = (SKStrokeCap)1
};
try
{
if (_isRefreshing)
{
DateTime utcNow = DateTime.UtcNow;
float num3 = (float)(utcNow - _lastSpinnerUpdate).TotalMilliseconds;
_spinnerRotation += num3 * 0.36f;
_lastSpinnerUpdate = utcNow;
canvas.Save();
canvas.Translate(x, y);
canvas.RotateDegrees(_spinnerRotation);
SKPath val3 = new SKPath();
try
{
SKRect val4 = new SKRect((0f - num) / 3f, (0f - num) / 3f, num / 3f, num / 3f);
val3.AddArc(val4, 0f, 270f);
canvas.DrawPath(val3, val2);
canvas.Restore();
Invalidate();
return;
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
canvas.Save();
canvas.Translate(x, y);
SKPath val5 = new SKPath();
try
{
SKRect val6 = new SKRect((0f - num) / 3f, (0f - num) / 3f, num / 3f, num / 3f);
float num4 = 270f * num2;
val5.AddArc(val6, -90f, num4);
canvas.DrawPath(val5, val2);
canvas.Restore();
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
// Add shadow
bgPaint.ImageFilter = SKImageFilter.CreateDropShadow(0, 2, 4, 4, new SKColor(0, 0, 0, 40));
canvas.DrawCircle(x, y, size / 2, bgPaint);
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
if (_content != null)
{
SkiaView skiaView = _content.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
}
return null;
}
// Draw spinner
using var spinnerPaint = new SKPaint
{
Color = RefreshColor,
Style = SKPaintStyle.Stroke,
StrokeWidth = 3,
IsAntialias = true,
StrokeCap = SKStrokeCap.Round
};
public override void OnPointerPressed(PointerEventArgs e)
{
if (base.IsEnabled && !_isRefreshing)
{
bool flag = true;
if (_content is SkiaScrollView skiaScrollView)
{
flag = skiaScrollView.ScrollY <= 0f;
}
if (flag)
{
_isPulling = true;
_pullStartY = e.Y;
_pullDistance = 0f;
}
base.OnPointerPressed(e);
}
}
if (_isRefreshing)
{
// Animate spinner
var now = DateTime.UtcNow;
float elapsed = (float)(now - _lastSpinnerUpdate).TotalMilliseconds;
_spinnerRotation += elapsed * 0.36f; // 360 degrees per second
_lastSpinnerUpdate = now;
public override void OnPointerMoved(PointerEventArgs e)
{
if (_isPulling)
{
float num = e.Y - _pullStartY;
if (num > 0f)
{
_pullDistance = num * 0.5f;
_pullDistance = Math.Min(_pullDistance, _refreshThreshold * 1.5f);
Invalidate();
e.Handled = true;
}
else
{
_pullDistance = 0f;
}
base.OnPointerMoved(e);
}
}
canvas.Save();
canvas.Translate(x, y);
canvas.RotateDegrees(_spinnerRotation);
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isPulling)
{
_isPulling = false;
if (_pullDistance >= _refreshThreshold)
{
_isRefreshing = true;
_pullDistance = _refreshThreshold;
_lastSpinnerUpdate = DateTime.UtcNow;
this.Refreshing?.Invoke(this, EventArgs.Empty);
Command?.Execute(CommandParameter);
}
else
{
_pullDistance = 0f;
}
Invalidate();
base.OnPointerReleased(e);
}
}
// Draw spinning arc
using var path = new SKPath();
var rect = new SKRect(-size / 3, -size / 3, size / 3, size / 3);
path.AddArc(rect, 0, 270);
canvas.DrawPath(path, spinnerPaint);
canvas.Restore();
Invalidate(); // Continue animation
}
else
{
// Draw progress arc
canvas.Save();
canvas.Translate(x, y);
using var path = new SKPath();
var rect = new SKRect(-size / 3, -size / 3, size / 3, size / 3);
float sweepAngle = 270 * progress;
path.AddArc(rect, -90, sweepAngle);
canvas.DrawPath(path, spinnerPaint);
canvas.Restore();
}
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y)) return null;
if (_content != null)
{
var hit = _content.HitTest(x, y);
if (hit != null) return hit;
}
return this;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled || _isRefreshing) return;
// Check if content is at top (can pull to refresh)
bool canPull = true;
if (_content is SkiaScrollView scrollView)
{
canPull = scrollView.ScrollY <= 0;
}
if (canPull)
{
_isPulling = true;
_pullStartY = e.Y;
_pullDistance = 0;
}
base.OnPointerPressed(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!_isPulling) return;
float delta = e.Y - _pullStartY;
if (delta > 0)
{
// Apply resistance
_pullDistance = delta * 0.5f;
_pullDistance = Math.Min(_pullDistance, _refreshThreshold * 1.5f);
Invalidate();
e.Handled = true;
}
else
{
_pullDistance = 0;
}
base.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (!_isPulling) return;
_isPulling = false;
if (_pullDistance >= _refreshThreshold)
{
_isRefreshing = true;
_pullDistance = _refreshThreshold;
_lastSpinnerUpdate = DateTime.UtcNow;
Refreshing?.Invoke(this, EventArgs.Empty);
}
else
{
_pullDistance = 0;
}
Invalidate();
base.OnPointerReleased(e);
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,356 +1,242 @@
using System;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
using Microsoft.Maui.Platform.Linux.Rendering;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered search bar control.
/// </summary>
public class SkiaSearchBar : SkiaView
{
private readonly SkiaEntry _entry;
private readonly SkiaEntry _entry;
private bool _showClearButton;
private bool _showClearButton;
public string Text
{
get => _entry.Text;
set => _entry.Text = value;
}
public string Text
{
get
{
return _entry.Text;
}
set
{
_entry.Text = value;
}
}
public string Placeholder
{
get => _entry.Placeholder;
set => _entry.Placeholder = value;
}
public string Placeholder
{
get
{
return _entry.Placeholder;
}
set
{
_entry.Placeholder = value;
}
}
public SKColor TextColor
{
get => _entry.TextColor;
set => _entry.TextColor = value;
}
public SKColor TextColor
{
get
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
return _entry.TextColor;
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
_entry.TextColor = value;
}
}
public SKColor PlaceholderColor
{
get => _entry.PlaceholderColor;
set => _entry.PlaceholderColor = value;
}
public SKColor PlaceholderColor
{
get
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
return _entry.PlaceholderColor;
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
_entry.PlaceholderColor = value;
}
}
public new SKColor BackgroundColor { get; set; } = new SKColor(0xF5, 0xF5, 0xF5);
public SKColor IconColor { get; set; } = new SKColor(0x75, 0x75, 0x75);
public SKColor ClearButtonColor { get; set; } = new SKColor(0x9E, 0x9E, 0x9E);
public SKColor FocusedBorderColor { get; set; } = new SKColor(0x21, 0x96, 0xF3);
public string FontFamily { get; set; } = "Sans";
public float FontSize { get; set; } = 14;
public float CornerRadius { get; set; } = 8;
public float IconSize { get; set; } = 20;
public new SKColor BackgroundColor { get; set; } = new SKColor((byte)245, (byte)245, (byte)245);
public event EventHandler<TextChangedEventArgs>? TextChanged;
public event EventHandler? SearchButtonPressed;
public SKColor IconColor { get; set; } = new SKColor((byte)117, (byte)117, (byte)117);
public SkiaSearchBar()
{
_entry = new SkiaEntry
{
Placeholder = "Search...",
EntryBackgroundColor = SKColors.Transparent,
BackgroundColor = SKColors.Transparent,
BorderColor = SKColors.Transparent,
FocusedBorderColor = SKColors.Transparent,
BorderWidth = 0
};
public SKColor ClearButtonColor { get; set; } = new SKColor((byte)158, (byte)158, (byte)158);
_entry.TextChanged += (s, e) =>
{
_showClearButton = !string.IsNullOrEmpty(e.NewTextValue);
TextChanged?.Invoke(this, e);
Invalidate();
};
public SKColor FocusedBorderColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
_entry.Completed += (s, e) => SearchButtonPressed?.Invoke(this, EventArgs.Empty);
public string FontFamily { get; set; } = "Sans";
IsFocusable = true;
}
public float FontSize { get; set; } = 14f;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var iconPadding = 12f;
var clearButtonSize = 20f;
public float CornerRadius { get; set; } = 8f;
// Draw background
using var bgPaint = new SKPaint
{
Color = BackgroundColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
public float IconSize { get; set; } = 20f;
var bgRect = new SKRoundRect(bounds, CornerRadius);
canvas.DrawRoundRect(bgRect, bgPaint);
public event EventHandler<TextChangedEventArgs>? TextChanged;
// Draw focus border
if (IsFocused || _entry.IsFocused)
{
using var borderPaint = new SKPaint
{
Color = FocusedBorderColor,
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = 2
};
canvas.DrawRoundRect(bgRect, borderPaint);
}
public event EventHandler? SearchButtonPressed;
// Draw search icon
var iconX = bounds.Left + iconPadding;
var iconY = bounds.MidY;
DrawSearchIcon(canvas, iconX, iconY, IconSize);
public SkiaSearchBar()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
_entry = new SkiaEntry
{
Placeholder = "Search...",
EntryBackgroundColor = SKColors.Transparent,
BackgroundColor = SKColors.Transparent,
BorderColor = SKColors.Transparent,
FocusedBorderColor = SKColors.Transparent,
BorderWidth = 0f
};
_entry.TextChanged += delegate(object? s, TextChangedEventArgs e)
{
_showClearButton = !string.IsNullOrEmpty(e.NewTextValue);
this.TextChanged?.Invoke(this, e);
Invalidate();
};
_entry.Completed += delegate
{
this.SearchButtonPressed?.Invoke(this, EventArgs.Empty);
};
base.IsFocusable = true;
}
// Calculate entry bounds - leave space for clear button
var entryLeft = iconX + IconSize + iconPadding;
var entryRight = _showClearButton
? bounds.Right - clearButtonSize - iconPadding * 2
: bounds.Right - iconPadding;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Expected O, but got Unknown
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Expected O, but got Unknown
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
float num = 12f;
float num2 = 20f;
SKPaint val = new SKPaint
{
Color = BackgroundColor,
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
SKRoundRect val2 = new SKRoundRect(bounds, CornerRadius);
canvas.DrawRoundRect(val2, val);
if (base.IsFocused || _entry.IsFocused)
{
SKPaint val3 = new SKPaint
{
Color = FocusedBorderColor,
IsAntialias = true,
Style = (SKPaintStyle)1,
StrokeWidth = 2f
};
try
{
canvas.DrawRoundRect(val2, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
float num3 = ((SKRect)(ref bounds)).Left + num;
float midY = ((SKRect)(ref bounds)).MidY;
DrawSearchIcon(canvas, num3, midY, IconSize);
float num4 = num3 + IconSize + num;
float num5 = (_showClearButton ? (((SKRect)(ref bounds)).Right - num2 - num * 2f) : (((SKRect)(ref bounds)).Right - num));
SKRect bounds2 = new SKRect(num4, ((SKRect)(ref bounds)).Top, num5, ((SKRect)(ref bounds)).Bottom);
_entry.Arrange(bounds2);
_entry.Draw(canvas);
if (_showClearButton)
{
float x = ((SKRect)(ref bounds)).Right - num - num2 / 2f;
float midY2 = ((SKRect)(ref bounds)).MidY;
DrawClearButton(canvas, x, midY2, num2 / 2f);
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
var entryBounds = new SKRect(entryLeft, bounds.Top, entryRight, bounds.Bottom);
_entry.Arrange(entryBounds);
_entry.Draw(canvas);
private void DrawSearchIcon(SKCanvas canvas, float x, float y, float size)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = IconColor,
IsAntialias = true,
Style = (SKPaintStyle)1,
StrokeWidth = 2f,
StrokeCap = (SKStrokeCap)1
};
try
{
float num = size * 0.35f;
SKPoint val2 = new SKPoint(x + num, y - num * 0.3f);
canvas.DrawCircle(val2, num, val);
SKPoint val3 = new SKPoint(((SKPoint)(ref val2)).X + num * 0.7f, ((SKPoint)(ref val2)).Y + num * 0.7f);
SKPoint val4 = new SKPoint(x + size * 0.8f, y + size * 0.3f);
canvas.DrawLine(val3, val4, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
// Draw clear button
if (_showClearButton)
{
var clearX = bounds.Right - iconPadding - clearButtonSize / 2;
var clearY = bounds.MidY;
DrawClearButton(canvas, clearX, clearY, clearButtonSize / 2);
}
}
private void DrawClearButton(SKCanvas canvas, float x, float y, float radius)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Expected O, but got Unknown
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Expected O, but got Unknown
SKPaint val = new SKPaint();
SKColor clearButtonColor = ClearButtonColor;
val.Color = ((SKColor)(ref clearButtonColor)).WithAlpha((byte)80);
val.IsAntialias = true;
val.Style = (SKPaintStyle)0;
SKPaint val2 = val;
try
{
canvas.DrawCircle(x, y, radius + 2f, val2);
SKPaint val3 = new SKPaint
{
Color = ClearButtonColor,
IsAntialias = true,
Style = (SKPaintStyle)1,
StrokeWidth = 2f,
StrokeCap = (SKStrokeCap)1
};
try
{
float num = radius * 0.5f;
canvas.DrawLine(x - num, y - num, x + num, y + num, val3);
canvas.DrawLine(x + num, y - num, x - num, y + num, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
private void DrawSearchIcon(SKCanvas canvas, float x, float y, float size)
{
using var paint = new SKPaint
{
Color = IconColor,
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = 2,
StrokeCap = SKStrokeCap.Round
};
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled)
{
return;
}
float x = e.X;
SKRect bounds = base.Bounds;
float num = x - ((SKRect)(ref bounds)).Left;
if (_showClearButton)
{
bounds = base.Bounds;
if (num >= ((SKRect)(ref bounds)).Width - 40f)
{
Text = "";
Invalidate();
return;
}
}
_entry.IsFocused = true;
base.IsFocused = true;
_entry.OnPointerPressed(e);
Invalidate();
}
var circleRadius = size * 0.35f;
var circleCenter = new SKPoint(x + circleRadius, y - circleRadius * 0.3f);
public override void OnPointerMoved(PointerEventArgs e)
{
if (base.IsEnabled)
{
_entry.OnPointerMoved(e);
}
}
// Draw magnifying glass circle
canvas.DrawCircle(circleCenter, circleRadius, paint);
public override void OnPointerReleased(PointerEventArgs e)
{
_entry.OnPointerReleased(e);
}
// Draw handle
var handleStart = new SKPoint(
circleCenter.X + circleRadius * 0.7f,
circleCenter.Y + circleRadius * 0.7f);
var handleEnd = new SKPoint(
x + size * 0.8f,
y + size * 0.3f);
canvas.DrawLine(handleStart, handleEnd, paint);
}
public override void OnTextInput(TextInputEventArgs e)
{
_entry.OnTextInput(e);
}
private void DrawClearButton(SKCanvas canvas, float x, float y, float radius)
{
// Draw circle background
using var bgPaint = new SKPaint
{
Color = ClearButtonColor.WithAlpha(80),
IsAntialias = true,
Style = SKPaintStyle.Fill
};
canvas.DrawCircle(x, y, radius + 2, bgPaint);
public override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Escape && _showClearButton)
{
Text = "";
e.Handled = true;
}
else
{
_entry.OnKeyDown(e);
}
}
// Draw X
using var paint = new SKPaint
{
Color = ClearButtonColor,
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = 2,
StrokeCap = SKStrokeCap.Round
};
public override void OnKeyUp(KeyEventArgs e)
{
_entry.OnKeyUp(e);
}
var offset = radius * 0.5f;
canvas.DrawLine(x - offset, y - offset, x + offset, y + offset, paint);
canvas.DrawLine(x + offset, y - offset, x - offset, y + offset, paint);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(250f, 40f);
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
// Convert to local coordinates (relative to this view's bounds)
var localX = e.X - Bounds.Left;
// Check if clear button was clicked (in the rightmost 40 pixels)
if (_showClearButton && localX >= Bounds.Width - 40)
{
Text = "";
Invalidate();
return;
}
// Forward to entry for text input focus and selection
_entry.IsFocused = true;
IsFocused = true;
_entry.OnPointerPressed(e);
Invalidate();
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!IsEnabled) return;
_entry.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
_entry.OnPointerReleased(e);
}
public override void OnTextInput(TextInputEventArgs e)
{
_entry.OnTextInput(e);
}
public override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Escape && _showClearButton)
{
Text = "";
e.Handled = true;
return;
}
_entry.OnKeyDown(e);
}
public override void OnKeyUp(KeyEventArgs e)
{
_entry.OnKeyUp(e);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(250, 40);
}
}

View File

@@ -1,8 +0,0 @@
namespace Microsoft.Maui.Platform;
public enum SkiaSelectionMode
{
None,
Single,
Multiple
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,415 +1,398 @@
using System;
using Microsoft.Maui.Controls;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered slider control with full XAML styling support.
/// </summary>
public class SkiaSlider : SkiaView
{
public static readonly BindableProperty MinimumProperty = BindableProperty.Create("Minimum", typeof(double), typeof(SkiaSlider), (object)0.0, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).OnRangeChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
#region BindableProperties
public static readonly BindableProperty MaximumProperty = BindableProperty.Create("Maximum", typeof(double), typeof(SkiaSlider), (object)100.0, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).OnRangeChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for Minimum.
/// </summary>
public static readonly BindableProperty MinimumProperty =
BindableProperty.Create(
nameof(Minimum),
typeof(double),
typeof(SkiaSlider),
0.0,
propertyChanged: (b, o, n) => ((SkiaSlider)b).OnRangeChanged());
public static readonly BindableProperty ValueProperty = BindableProperty.Create("Value", typeof(double), typeof(SkiaSlider), (object)0.0, (BindingMode)1, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).OnValuePropertyChanged((double)o, (double)n);
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for Maximum.
/// </summary>
public static readonly BindableProperty MaximumProperty =
BindableProperty.Create(
nameof(Maximum),
typeof(double),
typeof(SkiaSlider),
100.0,
propertyChanged: (b, o, n) => ((SkiaSlider)b).OnRangeChanged());
public static readonly BindableProperty TrackColorProperty = BindableProperty.Create("TrackColor", typeof(SKColor), typeof(SkiaSlider), (object)new SKColor((byte)224, (byte)224, (byte)224), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for Value.
/// </summary>
public static readonly BindableProperty ValueProperty =
BindableProperty.Create(
nameof(Value),
typeof(double),
typeof(SkiaSlider),
0.0,
BindingMode.TwoWay,
propertyChanged: (b, o, n) => ((SkiaSlider)b).OnValuePropertyChanged((double)o, (double)n));
public static readonly BindableProperty ActiveTrackColorProperty = BindableProperty.Create("ActiveTrackColor", typeof(SKColor), typeof(SkiaSlider), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for TrackColor.
/// </summary>
public static readonly BindableProperty TrackColorProperty =
BindableProperty.Create(
nameof(TrackColor),
typeof(SKColor),
typeof(SkiaSlider),
new SKColor(0xE0, 0xE0, 0xE0),
propertyChanged: (b, o, n) => ((SkiaSlider)b).Invalidate());
public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create("ThumbColor", typeof(SKColor), typeof(SkiaSlider), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for ActiveTrackColor.
/// </summary>
public static readonly BindableProperty ActiveTrackColorProperty =
BindableProperty.Create(
nameof(ActiveTrackColor),
typeof(SKColor),
typeof(SkiaSlider),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaSlider)b).Invalidate());
public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create("DisabledColor", typeof(SKColor), typeof(SkiaSlider), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for ThumbColor.
/// </summary>
public static readonly BindableProperty ThumbColorProperty =
BindableProperty.Create(
nameof(ThumbColor),
typeof(SKColor),
typeof(SkiaSlider),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaSlider)b).Invalidate());
public static readonly BindableProperty TrackHeightProperty = BindableProperty.Create("TrackHeight", typeof(float), typeof(SkiaSlider), (object)4f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for DisabledColor.
/// </summary>
public static readonly BindableProperty DisabledColorProperty =
BindableProperty.Create(
nameof(DisabledColor),
typeof(SKColor),
typeof(SkiaSlider),
new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaSlider)b).Invalidate());
public static readonly BindableProperty ThumbRadiusProperty = BindableProperty.Create("ThumbRadius", typeof(float), typeof(SkiaSlider), (object)10f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSlider)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for TrackHeight.
/// </summary>
public static readonly BindableProperty TrackHeightProperty =
BindableProperty.Create(
nameof(TrackHeight),
typeof(float),
typeof(SkiaSlider),
4f,
propertyChanged: (b, o, n) => ((SkiaSlider)b).Invalidate());
private bool _isDragging;
/// <summary>
/// Bindable property for ThumbRadius.
/// </summary>
public static readonly BindableProperty ThumbRadiusProperty =
BindableProperty.Create(
nameof(ThumbRadius),
typeof(float),
typeof(SkiaSlider),
10f,
propertyChanged: (b, o, n) => ((SkiaSlider)b).InvalidateMeasure());
public double Minimum
{
get
{
return (double)((BindableObject)this).GetValue(MinimumProperty);
}
set
{
((BindableObject)this).SetValue(MinimumProperty, (object)value);
}
}
#endregion
public double Maximum
{
get
{
return (double)((BindableObject)this).GetValue(MaximumProperty);
}
set
{
((BindableObject)this).SetValue(MaximumProperty, (object)value);
}
}
#region Properties
public double Value
{
get
{
return (double)((BindableObject)this).GetValue(ValueProperty);
}
set
{
((BindableObject)this).SetValue(ValueProperty, (object)Math.Clamp(value, Minimum, Maximum));
}
}
/// <summary>
/// Gets or sets the minimum value.
/// </summary>
public double Minimum
{
get => (double)GetValue(MinimumProperty);
set => SetValue(MinimumProperty, value);
}
public SKColor TrackColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(TrackColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(TrackColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the maximum value.
/// </summary>
public double Maximum
{
get => (double)GetValue(MaximumProperty);
set => SetValue(MaximumProperty, value);
}
public SKColor ActiveTrackColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ActiveTrackColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ActiveTrackColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the current value.
/// </summary>
public double Value
{
get => (double)GetValue(ValueProperty);
set => SetValue(ValueProperty, Math.Clamp(value, Minimum, Maximum));
}
public SKColor ThumbColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ThumbColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ThumbColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the track color.
/// </summary>
public SKColor TrackColor
{
get => (SKColor)GetValue(TrackColorProperty);
set => SetValue(TrackColorProperty, value);
}
public SKColor DisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(DisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(DisabledColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the active track color.
/// </summary>
public SKColor ActiveTrackColor
{
get => (SKColor)GetValue(ActiveTrackColorProperty);
set => SetValue(ActiveTrackColorProperty, value);
}
public float TrackHeight
{
get
{
return (float)((BindableObject)this).GetValue(TrackHeightProperty);
}
set
{
((BindableObject)this).SetValue(TrackHeightProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the thumb color.
/// </summary>
public SKColor ThumbColor
{
get => (SKColor)GetValue(ThumbColorProperty);
set => SetValue(ThumbColorProperty, value);
}
public float ThumbRadius
{
get
{
return (float)((BindableObject)this).GetValue(ThumbRadiusProperty);
}
set
{
((BindableObject)this).SetValue(ThumbRadiusProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the disabled color.
/// </summary>
public SKColor DisabledColor
{
get => (SKColor)GetValue(DisabledColorProperty);
set => SetValue(DisabledColorProperty, value);
}
public event EventHandler<SliderValueChangedEventArgs>? ValueChanged;
/// <summary>
/// Gets or sets the track height.
/// </summary>
public float TrackHeight
{
get => (float)GetValue(TrackHeightProperty);
set => SetValue(TrackHeightProperty, value);
}
public event EventHandler? DragStarted;
/// <summary>
/// Gets or sets the thumb radius.
/// </summary>
public float ThumbRadius
{
get => (float)GetValue(ThumbRadiusProperty);
set => SetValue(ThumbRadiusProperty, value);
}
public event EventHandler? DragCompleted;
#endregion
public SkiaSlider()
{
base.IsFocusable = true;
}
private bool _isDragging;
private void OnRangeChanged()
{
double num = Math.Clamp(Value, Minimum, Maximum);
if (Value != num)
{
Value = num;
}
Invalidate();
}
/// <summary>
/// Event raised when the value changes.
/// </summary>
public event EventHandler<SliderValueChangedEventArgs>? ValueChanged;
private void OnValuePropertyChanged(double oldValue, double newValue)
{
this.ValueChanged?.Invoke(this, new SliderValueChangedEventArgs(newValue));
Invalidate();
}
/// <summary>
/// Event raised when drag starts.
/// </summary>
public event EventHandler? DragStarted;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Expected O, but got Unknown
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Expected O, but got Unknown
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
//IL_0173: Unknown result type (might be due to invalid IL or missing references)
//IL_0178: Unknown result type (might be due to invalid IL or missing references)
//IL_017e: Unknown result type (might be due to invalid IL or missing references)
//IL_0188: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Expected O, but got Unknown
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Expected O, but got Unknown
//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
//IL_01fe: Expected O, but got Unknown
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_0153: Expected O, but got Unknown
//IL_0217: Unknown result type (might be due to invalid IL or missing references)
//IL_021c: Unknown result type (might be due to invalid IL or missing references)
//IL_021e: Unknown result type (might be due to invalid IL or missing references)
//IL_0223: Unknown result type (might be due to invalid IL or missing references)
//IL_0229: Unknown result type (might be due to invalid IL or missing references)
//IL_0233: Unknown result type (might be due to invalid IL or missing references)
//IL_023a: Unknown result type (might be due to invalid IL or missing references)
//IL_0243: Expected O, but got Unknown
float midY = ((SKRect)(ref bounds)).MidY;
float num = ((SKRect)(ref bounds)).Left + ThumbRadius;
float num2 = ((SKRect)(ref bounds)).Right - ThumbRadius;
float num3 = num2 - num;
double num4 = ((Maximum > Minimum) ? ((Value - Minimum) / (Maximum - Minimum)) : 0.0);
float num5 = num + (float)(num4 * (double)num3);
SKPaint val = new SKPaint
{
Color = (base.IsEnabled ? TrackColor : DisabledColor),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
SKRoundRect val2 = new SKRoundRect(new SKRect(num, midY - TrackHeight / 2f, num2, midY + TrackHeight / 2f), TrackHeight / 2f);
canvas.DrawRoundRect(val2, val);
if (num4 > 0.0)
{
SKPaint val3 = new SKPaint
{
Color = (base.IsEnabled ? ActiveTrackColor : DisabledColor),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
SKRoundRect val4 = new SKRoundRect(new SKRect(num, midY - TrackHeight / 2f, num5, midY + TrackHeight / 2f), TrackHeight / 2f);
canvas.DrawRoundRect(val4, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
if (base.IsEnabled)
{
SKPaint val5 = new SKPaint
{
Color = new SKColor((byte)0, (byte)0, (byte)0, (byte)30),
IsAntialias = true,
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, 3f)
};
try
{
canvas.DrawCircle(num5 + 1f, midY + 2f, ThumbRadius, val5);
}
finally
{
((IDisposable)val5)?.Dispose();
}
}
SKPaint val6 = new SKPaint
{
Color = (base.IsEnabled ? ThumbColor : DisabledColor),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawCircle(num5, midY, ThumbRadius, val6);
if (base.IsFocused)
{
SKPaint val7 = new SKPaint();
SKColor thumbColor = ThumbColor;
val7.Color = ((SKColor)(ref thumbColor)).WithAlpha((byte)60);
val7.IsAntialias = true;
val7.Style = (SKPaintStyle)0;
SKPaint val8 = val7;
try
{
canvas.DrawCircle(num5, midY, ThumbRadius + 8f, val8);
return;
}
finally
{
((IDisposable)val8)?.Dispose();
}
}
}
finally
{
((IDisposable)val6)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
/// <summary>
/// Event raised when drag completes.
/// </summary>
public event EventHandler? DragCompleted;
public override void OnPointerPressed(PointerEventArgs e)
{
if (base.IsEnabled)
{
_isDragging = true;
UpdateValueFromPosition(e.X);
this.DragStarted?.Invoke(this, EventArgs.Empty);
SkiaVisualStateManager.GoToState(this, "Pressed");
}
}
public SkiaSlider()
{
IsFocusable = true;
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (base.IsEnabled && _isDragging)
{
UpdateValueFromPosition(e.X);
}
}
private void OnRangeChanged()
{
// Clamp value to new range
var clamped = Math.Clamp(Value, Minimum, Maximum);
if (Value != clamped)
{
Value = clamped;
}
Invalidate();
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isDragging)
{
_isDragging = false;
this.DragCompleted?.Invoke(this, EventArgs.Empty);
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
}
}
private void OnValuePropertyChanged(double oldValue, double newValue)
{
ValueChanged?.Invoke(this, new SliderValueChangedEventArgs(newValue));
Invalidate();
}
private void UpdateValueFromPosition(float x)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
SKRect bounds = base.Bounds;
float num = ((SKRect)(ref bounds)).Left + ThumbRadius;
bounds = base.Bounds;
float num2 = ((SKRect)(ref bounds)).Right - ThumbRadius - num;
float num3 = Math.Clamp((x - num) / num2, 0f, 1f);
Value = Minimum + (double)num3 * (Maximum - Minimum);
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var trackY = bounds.MidY;
var trackLeft = bounds.Left + ThumbRadius;
var trackRight = bounds.Right - ThumbRadius;
var trackWidth = trackRight - trackLeft;
public override void OnKeyDown(KeyEventArgs e)
{
if (base.IsEnabled)
{
double num = (Maximum - Minimum) / 100.0;
switch (e.Key)
{
case Key.Left:
case Key.Down:
Value -= num * 10.0;
e.Handled = true;
break;
case Key.Up:
case Key.Right:
Value += num * 10.0;
e.Handled = true;
break;
case Key.Home:
Value = Minimum;
e.Handled = true;
break;
case Key.End:
Value = Maximum;
e.Handled = true;
break;
}
}
}
var percentage = Maximum > Minimum ? (Value - Minimum) / (Maximum - Minimum) : 0;
var thumbX = trackLeft + (float)(percentage * trackWidth);
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
}
// Draw inactive track
using var inactiveTrackPaint = new SKPaint
{
Color = IsEnabled ? TrackColor : DisabledColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(200f, ThumbRadius * 2f + 16f);
}
var inactiveRect = new SKRoundRect(
new SKRect(trackLeft, trackY - TrackHeight / 2, trackRight, trackY + TrackHeight / 2),
TrackHeight / 2);
canvas.DrawRoundRect(inactiveRect, inactiveTrackPaint);
// Draw active track
if (percentage > 0)
{
using var activeTrackPaint = new SKPaint
{
Color = IsEnabled ? ActiveTrackColor : DisabledColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
var activeRect = new SKRoundRect(
new SKRect(trackLeft, trackY - TrackHeight / 2, thumbX, trackY + TrackHeight / 2),
TrackHeight / 2);
canvas.DrawRoundRect(activeRect, activeTrackPaint);
}
// Draw thumb shadow
if (IsEnabled)
{
using var shadowPaint = new SKPaint
{
Color = new SKColor(0, 0, 0, 30),
IsAntialias = true,
MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, 3)
};
canvas.DrawCircle(thumbX + 1, trackY + 2, ThumbRadius, shadowPaint);
}
// Draw thumb
using var thumbPaint = new SKPaint
{
Color = IsEnabled ? ThumbColor : DisabledColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
canvas.DrawCircle(thumbX, trackY, ThumbRadius, thumbPaint);
// Draw focus ring
if (IsFocused)
{
using var focusPaint = new SKPaint
{
Color = ThumbColor.WithAlpha(60),
IsAntialias = true,
Style = SKPaintStyle.Fill
};
canvas.DrawCircle(thumbX, trackY, ThumbRadius + 8, focusPaint);
}
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
_isDragging = true;
UpdateValueFromPosition(e.X);
DragStarted?.Invoke(this, EventArgs.Empty);
SkiaVisualStateManager.GoToState(this, SkiaVisualStateManager.CommonStates.Pressed);
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!IsEnabled || !_isDragging) return;
UpdateValueFromPosition(e.X);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (_isDragging)
{
_isDragging = false;
DragCompleted?.Invoke(this, EventArgs.Empty);
SkiaVisualStateManager.GoToState(this, IsEnabled ? SkiaVisualStateManager.CommonStates.Normal : SkiaVisualStateManager.CommonStates.Disabled);
}
}
private void UpdateValueFromPosition(float x)
{
var trackLeft = Bounds.Left + ThumbRadius;
var trackRight = Bounds.Right - ThumbRadius;
var trackWidth = trackRight - trackLeft;
var percentage = Math.Clamp((x - trackLeft) / trackWidth, 0, 1);
Value = Minimum + percentage * (Maximum - Minimum);
}
public override void OnKeyDown(KeyEventArgs e)
{
if (!IsEnabled) return;
var step = (Maximum - Minimum) / 100; // 1% steps
switch (e.Key)
{
case Key.Left:
case Key.Down:
Value -= step * 10;
e.Handled = true;
break;
case Key.Right:
case Key.Up:
Value += step * 10;
e.Handled = true;
break;
case Key.Home:
Value = Minimum;
e.Handled = true;
break;
case Key.End:
Value = Maximum;
e.Handled = true;
break;
}
}
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, IsEnabled ? SkiaVisualStateManager.CommonStates.Normal : SkiaVisualStateManager.CommonStates.Disabled);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(200, ThumbRadius * 2 + 16);
}
}
/// <summary>
/// Event args for slider value changed events.
/// </summary>
public class SliderValueChangedEventArgs : EventArgs
{
public double NewValue { get; }
public SliderValueChangedEventArgs(double newValue) => NewValue = newValue;
}

View File

@@ -1,213 +0,0 @@
using System;
using System.Linq;
using Microsoft.Maui.Controls;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaStackLayout : SkiaLayoutView
{
public static readonly BindableProperty OrientationProperty = BindableProperty.Create("Orientation", typeof(StackOrientation), typeof(SkiaStackLayout), (object)StackOrientation.Vertical, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStackLayout)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public StackOrientation Orientation
{
get
{
return (StackOrientation)((BindableObject)this).GetValue(OrientationProperty);
}
set
{
((BindableObject)this).SetValue(OrientationProperty, (object)value);
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Unknown result type (might be due to invalid IL or missing references)
//IL_014f: Unknown result type (might be due to invalid IL or missing references)
//IL_0154: Unknown result type (might be due to invalid IL or missing references)
//IL_024e: Unknown result type (might be due to invalid IL or missing references)
//IL_0235: Unknown result type (might be due to invalid IL or missing references)
SKRect padding = base.Padding;
float num;
if (!float.IsNaN(((SKRect)(ref padding)).Left))
{
padding = base.Padding;
num = ((SKRect)(ref padding)).Left;
}
else
{
num = 0f;
}
float num2 = num;
padding = base.Padding;
float num3;
if (!float.IsNaN(((SKRect)(ref padding)).Right))
{
padding = base.Padding;
num3 = ((SKRect)(ref padding)).Right;
}
else
{
num3 = 0f;
}
float num4 = num3;
padding = base.Padding;
float num5;
if (!float.IsNaN(((SKRect)(ref padding)).Top))
{
padding = base.Padding;
num5 = ((SKRect)(ref padding)).Top;
}
else
{
num5 = 0f;
}
float num6 = num5;
padding = base.Padding;
float num7;
if (!float.IsNaN(((SKRect)(ref padding)).Bottom))
{
padding = base.Padding;
num7 = ((SKRect)(ref padding)).Bottom;
}
else
{
num7 = 0f;
}
float num8 = num7;
float num9 = ((SKSize)(ref availableSize)).Width - num2 - num4;
float num10 = ((SKSize)(ref availableSize)).Height - num6 - num8;
if (num9 < 0f || float.IsNaN(num9))
{
num9 = 0f;
}
if (num10 < 0f || float.IsNaN(num10))
{
num10 = 0f;
}
float num11 = 0f;
float num12 = 0f;
float num13 = 0f;
float num14 = 0f;
SKSize availableSize2 = default(SKSize);
((SKSize)(ref availableSize2))._002Ector(num9, num10);
foreach (SkiaView child in base.Children)
{
if (child.IsVisible)
{
SKSize val = child.Measure(availableSize2);
float num15 = (float.IsNaN(((SKSize)(ref val)).Width) ? 0f : ((SKSize)(ref val)).Width);
float num16 = (float.IsNaN(((SKSize)(ref val)).Height) ? 0f : ((SKSize)(ref val)).Height);
if (Orientation == StackOrientation.Vertical)
{
num12 += num16;
num13 = Math.Max(num13, num15);
}
else
{
num11 += num15;
num14 = Math.Max(num14, num16);
}
}
}
int num17 = base.Children.Count((SkiaView c) => c.IsVisible);
float num18 = (float)Math.Max(0, num17 - 1) * base.Spacing;
if (Orientation == StackOrientation.Vertical)
{
num12 += num18;
return new SKSize(num13 + num2 + num4, num12 + num6 + num8);
}
num11 += num18;
return new SKSize(num11 + num2 + num4, num14 + num6 + num8);
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
//IL_01c2: Expected I4, but got Unknown
//IL_024b: Unknown result type (might be due to invalid IL or missing references)
//IL_0250: Unknown result type (might be due to invalid IL or missing references)
//IL_029b: Unknown result type (might be due to invalid IL or missing references)
SKRect contentBounds = GetContentBounds(bounds);
float num = ((float.IsInfinity(((SKRect)(ref contentBounds)).Width) || float.IsNaN(((SKRect)(ref contentBounds)).Width)) ? 800f : ((SKRect)(ref contentBounds)).Width);
float num2 = ((float.IsInfinity(((SKRect)(ref contentBounds)).Height) || float.IsNaN(((SKRect)(ref contentBounds)).Height)) ? 600f : ((SKRect)(ref contentBounds)).Height);
float num3 = 0f;
SKRect val = default(SKRect);
SKRect bounds2 = default(SKRect);
foreach (SkiaView child in base.Children)
{
if (!child.IsVisible)
{
continue;
}
SKSize desiredSize = child.DesiredSize;
float num4 = ((float.IsNaN(((SKSize)(ref desiredSize)).Width) || float.IsInfinity(((SKSize)(ref desiredSize)).Width)) ? num : ((SKSize)(ref desiredSize)).Width);
float num5 = ((float.IsNaN(((SKSize)(ref desiredSize)).Height) || float.IsInfinity(((SKSize)(ref desiredSize)).Height)) ? num2 : ((SKSize)(ref desiredSize)).Height);
if (Orientation == StackOrientation.Vertical)
{
float num6 = Math.Max(0f, num2 - num3);
float num7 = ((child is SkiaScrollView) ? num6 : Math.Min(num5, (num6 > 0f) ? num6 : num5));
((SKRect)(ref val))._002Ector(((SKRect)(ref contentBounds)).Left, ((SKRect)(ref contentBounds)).Top + num3, ((SKRect)(ref contentBounds)).Left + num, ((SKRect)(ref contentBounds)).Top + num3 + num7);
num3 += num7 + base.Spacing;
}
else
{
float num8 = Math.Max(0f, num - num3);
float num9 = ((child is SkiaScrollView) ? num8 : Math.Min(num4, (num8 > 0f) ? num8 : num4));
float num10 = Math.Min(num5, num2);
float num11 = ((SKRect)(ref contentBounds)).Top;
float num12 = ((SKRect)(ref contentBounds)).Top + num10;
LayoutOptions verticalOptions = child.VerticalOptions;
switch ((int)((LayoutOptions)(ref verticalOptions)).Alignment)
{
case 1:
num11 = ((SKRect)(ref contentBounds)).Top + (num2 - num10) / 2f;
num12 = num11 + num10;
break;
case 2:
num11 = ((SKRect)(ref contentBounds)).Top + num2 - num10;
num12 = ((SKRect)(ref contentBounds)).Top + num2;
break;
case 3:
num11 = ((SKRect)(ref contentBounds)).Top;
num12 = ((SKRect)(ref contentBounds)).Top + num2;
break;
}
((SKRect)(ref val))._002Ector(((SKRect)(ref contentBounds)).Left + num3, num11, ((SKRect)(ref contentBounds)).Left + num3 + num9, num12);
num3 += num9 + base.Spacing;
}
Thickness margin = child.Margin;
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref val)).Left + (float)((Thickness)(ref margin)).Left, ((SKRect)(ref val)).Top + (float)((Thickness)(ref margin)).Top, ((SKRect)(ref val)).Right - (float)((Thickness)(ref margin)).Right, ((SKRect)(ref val)).Bottom - (float)((Thickness)(ref margin)).Bottom);
child.Arrange(bounds2);
}
return bounds;
}
}

View File

@@ -1,439 +1,261 @@
using System;
using Microsoft.Maui.Controls;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered stepper control with increment/decrement buttons.
/// </summary>
public class SkiaStepper : SkiaView
{
public static readonly BindableProperty ValueProperty = BindableProperty.Create("Value", typeof(double), typeof(SkiaStepper), (object)0.0, (BindingMode)1, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).OnValuePropertyChanged((double)o, (double)n);
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
#region BindableProperties
public static readonly BindableProperty MinimumProperty = BindableProperty.Create("Minimum", typeof(double), typeof(SkiaStepper), (object)0.0, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).OnRangeChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ValueProperty =
BindableProperty.Create(nameof(Value), typeof(double), typeof(SkiaStepper), 0.0, BindingMode.TwoWay,
propertyChanged: (b, o, n) => ((SkiaStepper)b).OnValuePropertyChanged((double)o, (double)n));
public static readonly BindableProperty MaximumProperty = BindableProperty.Create("Maximum", typeof(double), typeof(SkiaStepper), (object)100.0, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).OnRangeChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty MinimumProperty =
BindableProperty.Create(nameof(Minimum), typeof(double), typeof(SkiaStepper), 0.0,
propertyChanged: (b, o, n) => ((SkiaStepper)b).OnRangeChanged());
public static readonly BindableProperty IncrementProperty = BindableProperty.Create("Increment", typeof(double), typeof(SkiaStepper), (object)1.0, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)null, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty MaximumProperty =
BindableProperty.Create(nameof(Maximum), typeof(double), typeof(SkiaStepper), 100.0,
propertyChanged: (b, o, n) => ((SkiaStepper)b).OnRangeChanged());
public static readonly BindableProperty ButtonBackgroundColorProperty = BindableProperty.Create("ButtonBackgroundColor", typeof(SKColor), typeof(SkiaStepper), (object)new SKColor((byte)224, (byte)224, (byte)224), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty IncrementProperty =
BindableProperty.Create(nameof(Increment), typeof(double), typeof(SkiaStepper), 1.0);
public static readonly BindableProperty ButtonPressedColorProperty = BindableProperty.Create("ButtonPressedColor", typeof(SKColor), typeof(SkiaStepper), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ButtonBackgroundColorProperty =
BindableProperty.Create(nameof(ButtonBackgroundColor), typeof(SKColor), typeof(SkiaStepper), new SKColor(0xE0, 0xE0, 0xE0),
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
public static readonly BindableProperty ButtonDisabledColorProperty = BindableProperty.Create("ButtonDisabledColor", typeof(SKColor), typeof(SkiaStepper), (object)new SKColor((byte)245, (byte)245, (byte)245), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ButtonPressedColorProperty =
BindableProperty.Create(nameof(ButtonPressedColor), typeof(SKColor), typeof(SkiaStepper), new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
public static readonly BindableProperty BorderColorProperty = BindableProperty.Create("BorderColor", typeof(SKColor), typeof(SkiaStepper), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ButtonDisabledColorProperty =
BindableProperty.Create(nameof(ButtonDisabledColor), typeof(SKColor), typeof(SkiaStepper), new SKColor(0xF5, 0xF5, 0xF5),
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
public static readonly BindableProperty SymbolColorProperty = BindableProperty.Create("SymbolColor", typeof(SKColor), typeof(SkiaStepper), (object)SKColors.Black, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty BorderColorProperty =
BindableProperty.Create(nameof(BorderColor), typeof(SKColor), typeof(SkiaStepper), new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
public static readonly BindableProperty SymbolDisabledColorProperty = BindableProperty.Create("SymbolDisabledColor", typeof(SKColor), typeof(SkiaStepper), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty SymbolColorProperty =
BindableProperty.Create(nameof(SymbolColor), typeof(SKColor), typeof(SkiaStepper), SKColors.Black,
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(float), typeof(SkiaStepper), (object)4f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty SymbolDisabledColorProperty =
BindableProperty.Create(nameof(SymbolDisabledColor), typeof(SKColor), typeof(SkiaStepper), new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
public static readonly BindableProperty ButtonWidthProperty = BindableProperty.Create("ButtonWidth", typeof(float), typeof(SkiaStepper), (object)40f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaStepper)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty CornerRadiusProperty =
BindableProperty.Create(nameof(CornerRadius), typeof(float), typeof(SkiaStepper), 4f,
propertyChanged: (b, o, n) => ((SkiaStepper)b).Invalidate());
private bool _isMinusPressed;
public static readonly BindableProperty ButtonWidthProperty =
BindableProperty.Create(nameof(ButtonWidth), typeof(float), typeof(SkiaStepper), 40f,
propertyChanged: (b, o, n) => ((SkiaStepper)b).InvalidateMeasure());
private bool _isPlusPressed;
#endregion
public double Value
{
get
{
return (double)((BindableObject)this).GetValue(ValueProperty);
}
set
{
((BindableObject)this).SetValue(ValueProperty, (object)Math.Clamp(value, Minimum, Maximum));
}
}
#region Properties
public double Minimum
{
get
{
return (double)((BindableObject)this).GetValue(MinimumProperty);
}
set
{
((BindableObject)this).SetValue(MinimumProperty, (object)value);
}
}
public double Value
{
get => (double)GetValue(ValueProperty);
set => SetValue(ValueProperty, Math.Clamp(value, Minimum, Maximum));
}
public double Maximum
{
get
{
return (double)((BindableObject)this).GetValue(MaximumProperty);
}
set
{
((BindableObject)this).SetValue(MaximumProperty, (object)value);
}
}
public double Minimum
{
get => (double)GetValue(MinimumProperty);
set => SetValue(MinimumProperty, value);
}
public double Increment
{
get
{
return (double)((BindableObject)this).GetValue(IncrementProperty);
}
set
{
((BindableObject)this).SetValue(IncrementProperty, (object)Math.Max(0.001, value));
}
}
public double Maximum
{
get => (double)GetValue(MaximumProperty);
set => SetValue(MaximumProperty, value);
}
public SKColor ButtonBackgroundColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ButtonBackgroundColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ButtonBackgroundColorProperty, (object)value);
}
}
public double Increment
{
get => (double)GetValue(IncrementProperty);
set => SetValue(IncrementProperty, Math.Max(0.001, value));
}
public SKColor ButtonPressedColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ButtonPressedColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ButtonPressedColorProperty, (object)value);
}
}
public SKColor ButtonBackgroundColor
{
get => (SKColor)GetValue(ButtonBackgroundColorProperty);
set => SetValue(ButtonBackgroundColorProperty, value);
}
public SKColor ButtonDisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ButtonDisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ButtonDisabledColorProperty, (object)value);
}
}
public SKColor ButtonPressedColor
{
get => (SKColor)GetValue(ButtonPressedColorProperty);
set => SetValue(ButtonPressedColorProperty, value);
}
public SKColor BorderColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(BorderColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(BorderColorProperty, (object)value);
}
}
public SKColor ButtonDisabledColor
{
get => (SKColor)GetValue(ButtonDisabledColorProperty);
set => SetValue(ButtonDisabledColorProperty, value);
}
public SKColor SymbolColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(SymbolColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(SymbolColorProperty, (object)value);
}
}
public SKColor BorderColor
{
get => (SKColor)GetValue(BorderColorProperty);
set => SetValue(BorderColorProperty, value);
}
public SKColor SymbolDisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(SymbolDisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(SymbolDisabledColorProperty, (object)value);
}
}
public SKColor SymbolColor
{
get => (SKColor)GetValue(SymbolColorProperty);
set => SetValue(SymbolColorProperty, value);
}
public float CornerRadius
{
get
{
return (float)((BindableObject)this).GetValue(CornerRadiusProperty);
}
set
{
((BindableObject)this).SetValue(CornerRadiusProperty, (object)value);
}
}
public SKColor SymbolDisabledColor
{
get => (SKColor)GetValue(SymbolDisabledColorProperty);
set => SetValue(SymbolDisabledColorProperty, value);
}
public float ButtonWidth
{
get
{
return (float)((BindableObject)this).GetValue(ButtonWidthProperty);
}
set
{
((BindableObject)this).SetValue(ButtonWidthProperty, (object)value);
}
}
public float CornerRadius
{
get => (float)GetValue(CornerRadiusProperty);
set => SetValue(CornerRadiusProperty, value);
}
public event EventHandler? ValueChanged;
public float ButtonWidth
{
get => (float)GetValue(ButtonWidthProperty);
set => SetValue(ButtonWidthProperty, value);
}
public SkiaStepper()
{
base.IsFocusable = true;
}
#endregion
private void OnValuePropertyChanged(double oldValue, double newValue)
{
this.ValueChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
private bool _isMinusPressed;
private bool _isPlusPressed;
private void OnRangeChanged()
{
double num = Math.Clamp(Value, Minimum, Maximum);
if (Value != num)
{
Value = num;
}
Invalidate();
}
public event EventHandler? ValueChanged;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Expected O, but got Unknown
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Expected O, but got Unknown
SKRect rect = default(SKRect);
((SKRect)(ref rect))._002Ector(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Left + ButtonWidth, ((SKRect)(ref bounds)).Bottom);
SKRect rect2 = default(SKRect);
((SKRect)(ref rect2))._002Ector(((SKRect)(ref bounds)).Right - ButtonWidth, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom);
DrawButton(canvas, rect, "-", _isMinusPressed, !CanDecrement());
DrawButton(canvas, rect2, "+", _isPlusPressed, !CanIncrement());
SKPaint val = new SKPaint
{
Color = BorderColor,
Style = (SKPaintStyle)1,
StrokeWidth = 1f,
IsAntialias = true
};
try
{
SKRect val2 = new SKRect(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom);
canvas.DrawRoundRect(new SKRoundRect(val2, CornerRadius), val);
float midX = ((SKRect)(ref bounds)).MidX;
canvas.DrawLine(midX, ((SKRect)(ref bounds)).Top, midX, ((SKRect)(ref bounds)).Bottom, val);
}
finally
{
((IDisposable)val)?.Dispose();
}
}
public SkiaStepper()
{
IsFocusable = true;
}
private void DrawButton(SKCanvas canvas, SKRect rect, string symbol, bool isPressed, bool isDisabled)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Expected O, but got Unknown
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Expected O, but got Unknown
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Expected O, but got Unknown
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
SKPaint val = new SKPaint
{
Color = (isDisabled ? ButtonDisabledColor : (isPressed ? ButtonPressedColor : ButtonBackgroundColor)),
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
canvas.DrawRect(rect, val);
SKFont val2 = new SKFont(SKTypeface.Default, 20f, 1f, 0f);
try
{
SKPaint val3 = new SKPaint(val2)
{
Color = (isDisabled ? SymbolDisabledColor : SymbolColor),
IsAntialias = true
};
try
{
SKRect val4 = default(SKRect);
val3.MeasureText(symbol, ref val4);
canvas.DrawText(symbol, ((SKRect)(ref rect)).MidX - ((SKRect)(ref val4)).MidX, ((SKRect)(ref rect)).MidY - ((SKRect)(ref val4)).MidY, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
private void OnValuePropertyChanged(double oldValue, double newValue)
{
ValueChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
private bool CanIncrement()
{
if (base.IsEnabled)
{
return Value < Maximum;
}
return false;
}
private void OnRangeChanged()
{
var clamped = Math.Clamp(Value, Minimum, Maximum);
if (Value != clamped)
{
Value = clamped;
}
Invalidate();
}
private bool CanDecrement()
{
if (base.IsEnabled)
{
return Value > Minimum;
}
return false;
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var minusRect = new SKRect(bounds.Left, bounds.Top, bounds.Left + ButtonWidth, bounds.Bottom);
var plusRect = new SKRect(bounds.Right - ButtonWidth, bounds.Top, bounds.Right, bounds.Bottom);
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled)
{
return;
}
if (e.X < ButtonWidth)
{
_isMinusPressed = true;
if (CanDecrement())
{
Value -= Increment;
}
}
else
{
float x = e.X;
SKRect bounds = base.Bounds;
if (x > ((SKRect)(ref bounds)).Width - ButtonWidth)
{
_isPlusPressed = true;
if (CanIncrement())
{
Value += Increment;
}
}
}
Invalidate();
}
DrawButton(canvas, minusRect, "-", _isMinusPressed, !CanDecrement());
DrawButton(canvas, plusRect, "+", _isPlusPressed, !CanIncrement());
public override void OnPointerReleased(PointerEventArgs e)
{
_isMinusPressed = false;
_isPlusPressed = false;
Invalidate();
}
using var borderPaint = new SKPaint
{
Color = BorderColor,
Style = SKPaintStyle.Stroke,
StrokeWidth = 1,
IsAntialias = true
};
public override void OnKeyDown(KeyEventArgs e)
{
if (!base.IsEnabled)
{
return;
}
switch (e.Key)
{
case Key.Up:
case Key.Right:
if (CanIncrement())
{
Value += Increment;
}
e.Handled = true;
break;
case Key.Left:
case Key.Down:
if (CanDecrement())
{
Value -= Increment;
}
e.Handled = true;
break;
}
}
var totalRect = new SKRect(bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
canvas.DrawRoundRect(new SKRoundRect(totalRect, CornerRadius), borderPaint);
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(ButtonWidth * 2f + 1f, 32f);
}
var centerX = bounds.MidX;
canvas.DrawLine(centerX, bounds.Top, centerX, bounds.Bottom, borderPaint);
}
private void DrawButton(SKCanvas canvas, SKRect rect, string symbol, bool isPressed, bool isDisabled)
{
using var bgPaint = new SKPaint
{
Color = isDisabled ? ButtonDisabledColor : (isPressed ? ButtonPressedColor : ButtonBackgroundColor),
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawRect(rect, bgPaint);
using var font = new SKFont(SKTypeface.Default, 20);
using var textPaint = new SKPaint(font)
{
Color = isDisabled ? SymbolDisabledColor : SymbolColor,
IsAntialias = true
};
var textBounds = new SKRect();
textPaint.MeasureText(symbol, ref textBounds);
canvas.DrawText(symbol, rect.MidX - textBounds.MidX, rect.MidY - textBounds.MidY, textPaint);
}
private bool CanIncrement() => IsEnabled && Value < Maximum;
private bool CanDecrement() => IsEnabled && Value > Minimum;
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
if (e.X < ButtonWidth)
{
_isMinusPressed = true;
if (CanDecrement()) Value -= Increment;
}
else if (e.X > Bounds.Width - ButtonWidth)
{
_isPlusPressed = true;
if (CanIncrement()) Value += Increment;
}
Invalidate();
}
public override void OnPointerReleased(PointerEventArgs e)
{
_isMinusPressed = false;
_isPlusPressed = false;
Invalidate();
}
public override void OnKeyDown(KeyEventArgs e)
{
if (!IsEnabled) return;
switch (e.Key)
{
case Key.Up:
case Key.Right:
if (CanIncrement()) Value += Increment;
e.Handled = true;
break;
case Key.Down:
case Key.Left:
if (CanDecrement()) Value -= Increment;
e.Handled = true;
break;
}
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(ButtonWidth * 2 + 1, 32);
}
}

View File

@@ -1,375 +1,469 @@
using System;
using System.Collections.Generic;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A view that supports swipe gestures to reveal actions.
/// </summary>
public class SkiaSwipeView : SkiaLayoutView
{
private SkiaView? _content;
private SkiaView? _content;
private readonly List<SwipeItem> _leftItems = new();
private readonly List<SwipeItem> _rightItems = new();
private readonly List<SwipeItem> _topItems = new();
private readonly List<SwipeItem> _bottomItems = new();
private readonly List<SwipeItem> _leftItems = new List<SwipeItem>();
private float _swipeOffset = 0f;
private SwipeDirection _activeDirection = SwipeDirection.None;
private bool _isSwiping = false;
private float _swipeStartX;
private float _swipeStartY;
private float _swipeStartOffset;
private bool _isOpen = false;
private readonly List<SwipeItem> _rightItems = new List<SwipeItem>();
private const float SwipeThreshold = 60f;
private const float VelocityThreshold = 500f;
private float _velocity;
private DateTime _lastMoveTime;
private float _lastMovePosition;
private readonly List<SwipeItem> _topItems = new List<SwipeItem>();
/// <summary>
/// Gets or sets the content view.
/// </summary>
public SkiaView? Content
{
get => _content;
set
{
if (_content != value)
{
if (_content != null)
{
RemoveChild(_content);
}
private readonly List<SwipeItem> _bottomItems = new List<SwipeItem>();
_content = value;
private float _swipeOffset;
if (_content != null)
{
AddChild(_content);
}
private SwipeDirection _activeDirection;
InvalidateMeasure();
Invalidate();
}
}
}
private bool _isSwiping;
/// <summary>
/// Gets the left swipe items.
/// </summary>
public IList<SwipeItem> LeftItems => _leftItems;
private float _swipeStartX;
/// <summary>
/// Gets the right swipe items.
/// </summary>
public IList<SwipeItem> RightItems => _rightItems;
private float _swipeStartY;
/// <summary>
/// Gets the top swipe items.
/// </summary>
public IList<SwipeItem> TopItems => _topItems;
private float _swipeStartOffset;
/// <summary>
/// Gets the bottom swipe items.
/// </summary>
public IList<SwipeItem> BottomItems => _bottomItems;
private bool _isOpen;
/// <summary>
/// Gets or sets the swipe mode.
/// </summary>
public SwipeMode Mode { get; set; } = SwipeMode.Reveal;
private const float SwipeThreshold = 60f;
/// <summary>
/// Gets or sets the left swipe threshold.
/// </summary>
public float LeftSwipeThreshold { get; set; } = 100f;
private const float VelocityThreshold = 500f;
/// <summary>
/// Gets or sets the right swipe threshold.
/// </summary>
public float RightSwipeThreshold { get; set; } = 100f;
private float _velocity;
/// <summary>
/// Event raised when swipe is started.
/// </summary>
public event EventHandler<SwipeStartedEventArgs>? SwipeStarted;
private DateTime _lastMoveTime;
/// <summary>
/// Event raised when swipe ends.
/// </summary>
public event EventHandler<SwipeEndedEventArgs>? SwipeEnded;
private float _lastMovePosition;
/// <summary>
/// Opens the swipe view in the specified direction.
/// </summary>
public void Open(SwipeDirection direction)
{
_activeDirection = direction;
_isOpen = true;
public SkiaView? Content
{
get
{
return _content;
}
set
{
if (_content != value)
{
if (_content != null)
{
RemoveChild(_content);
}
_content = value;
if (_content != null)
{
AddChild(_content);
}
InvalidateMeasure();
Invalidate();
}
}
}
float targetOffset = direction switch
{
SwipeDirection.Left => -RightSwipeThreshold,
SwipeDirection.Right => LeftSwipeThreshold,
_ => 0
};
public IList<SwipeItem> LeftItems => _leftItems;
AnimateTo(targetOffset);
}
public IList<SwipeItem> RightItems => _rightItems;
/// <summary>
/// Closes the swipe view.
/// </summary>
public void Close()
{
_isOpen = false;
AnimateTo(0);
}
public IList<SwipeItem> TopItems => _topItems;
private void AnimateTo(float target)
{
// Simple animation - in production would use proper animation
_swipeOffset = target;
Invalidate();
}
public IList<SwipeItem> BottomItems => _bottomItems;
protected override SKSize MeasureOverride(SKSize availableSize)
{
if (_content != null)
{
_content.Measure(availableSize);
}
return availableSize;
}
public SwipeMode Mode { get; set; }
protected override SKRect ArrangeOverride(SKRect bounds)
{
if (_content != null)
{
var contentBounds = new SKRect(
bounds.Left + _swipeOffset,
bounds.Top,
bounds.Right + _swipeOffset,
bounds.Bottom);
_content.Arrange(contentBounds);
}
return bounds;
}
public float LeftSwipeThreshold { get; set; } = 100f;
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
canvas.Save();
canvas.ClipRect(bounds);
public float RightSwipeThreshold { get; set; } = 100f;
// Draw swipe items behind content
if (_swipeOffset > 0)
{
DrawSwipeItems(canvas, bounds, _leftItems, true);
}
else if (_swipeOffset < 0)
{
DrawSwipeItems(canvas, bounds, _rightItems, false);
}
public event EventHandler<SwipeStartedEventArgs>? SwipeStarted;
// Draw content
_content?.Draw(canvas);
public event EventHandler<SwipeEndedEventArgs>? SwipeEnded;
canvas.Restore();
}
public void Open(SwipeDirection direction)
{
_activeDirection = direction;
_isOpen = true;
AnimateTo(direction switch
{
SwipeDirection.Left => 0f - RightSwipeThreshold,
SwipeDirection.Right => LeftSwipeThreshold,
_ => 0f,
});
}
private void DrawSwipeItems(SKCanvas canvas, SKRect bounds, List<SwipeItem> items, bool isLeft)
{
if (items.Count == 0) return;
public void Close()
{
_isOpen = false;
AnimateTo(0f);
}
float revealWidth = Math.Abs(_swipeOffset);
float itemWidth = revealWidth / items.Count;
private void AnimateTo(float target)
{
_swipeOffset = target;
Invalidate();
}
for (int i = 0; i < items.Count; i++)
{
var item = items[i];
float x = isLeft ? bounds.Left + i * itemWidth : bounds.Right - (items.Count - i) * itemWidth;
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
if (_content != null)
{
_content.Measure(availableSize);
}
return availableSize;
}
var itemBounds = new SKRect(
x,
bounds.Top,
x + itemWidth,
bounds.Bottom);
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
if (_content != null)
{
SKRect bounds2 = default(SKRect);
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref bounds)).Left + _swipeOffset, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Right + _swipeOffset, ((SKRect)(ref bounds)).Bottom);
_content.Arrange(bounds2);
}
return bounds;
}
// Draw background
using var bgPaint = new SKPaint
{
Color = item.BackgroundColor,
Style = SKPaintStyle.Fill
};
canvas.DrawRect(itemBounds, bgPaint);
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
canvas.Save();
canvas.ClipRect(bounds, (SKClipOperation)1, false);
if (_swipeOffset > 0f)
{
DrawSwipeItems(canvas, bounds, _leftItems, isLeft: true);
}
else if (_swipeOffset < 0f)
{
DrawSwipeItems(canvas, bounds, _rightItems, isLeft: false);
}
_content?.Draw(canvas);
canvas.Restore();
}
// Draw icon or text
if (!string.IsNullOrEmpty(item.Text))
{
using var textPaint = new SKPaint
{
Color = item.TextColor,
TextSize = 14f,
IsAntialias = true,
TextAlign = SKTextAlign.Center
};
private void DrawSwipeItems(SKCanvas canvas, SKRect bounds, List<SwipeItem> items, bool isLeft)
{
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Expected O, but got Unknown
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Expected O, but got Unknown
if (items.Count == 0)
{
return;
}
float num = Math.Abs(_swipeOffset) / (float)items.Count;
SKRect val = default(SKRect);
for (int i = 0; i < items.Count; i++)
{
SwipeItem swipeItem = items[i];
float num2 = (isLeft ? (((SKRect)(ref bounds)).Left + (float)i * num) : (((SKRect)(ref bounds)).Right - (float)(items.Count - i) * num));
((SKRect)(ref val))._002Ector(num2, ((SKRect)(ref bounds)).Top, num2 + num, ((SKRect)(ref bounds)).Bottom);
SKPaint val2 = new SKPaint
{
Color = swipeItem.BackgroundColor,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawRect(val, val2);
if (!string.IsNullOrEmpty(swipeItem.Text))
{
SKPaint val3 = new SKPaint
{
Color = swipeItem.TextColor,
TextSize = 14f,
IsAntialias = true,
TextAlign = (SKTextAlign)1
};
try
{
float num3 = ((SKRect)(ref val)).MidY + 5f;
canvas.DrawText(swipeItem.Text, ((SKRect)(ref val)).MidX, num3, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
}
float textY = itemBounds.MidY + 5;
canvas.DrawText(item.Text, itemBounds.MidX, textY, textPaint);
}
}
}
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
if (_isOpen)
{
if (_swipeOffset > 0f)
{
bounds = base.Bounds;
if (x < ((SKRect)(ref bounds)).Left + _swipeOffset)
{
return this;
}
}
if (_swipeOffset < 0f)
{
bounds = base.Bounds;
if (x > ((SKRect)(ref bounds)).Right + _swipeOffset)
{
return this;
}
}
}
if (_content != null)
{
SkiaView skiaView = _content.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
}
return null;
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y)) return null;
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
if (!base.IsEnabled)
{
return;
}
if (_isOpen)
{
SwipeItem swipeItem = null;
SKRect bounds;
if (_swipeOffset > 0f)
{
float x = e.X;
bounds = base.Bounds;
int num = (int)((x - ((SKRect)(ref bounds)).Left) / (_swipeOffset / (float)_leftItems.Count));
if (num >= 0 && num < _leftItems.Count)
{
swipeItem = _leftItems[num];
}
}
else if (_swipeOffset < 0f)
{
float num2 = Math.Abs(_swipeOffset) / (float)_rightItems.Count;
float x2 = e.X;
bounds = base.Bounds;
int num3 = (int)((x2 - (((SKRect)(ref bounds)).Right + _swipeOffset)) / num2);
if (num3 >= 0 && num3 < _rightItems.Count)
{
swipeItem = _rightItems[num3];
}
}
if (swipeItem != null)
{
swipeItem.OnInvoked();
Close();
e.Handled = true;
return;
}
}
_isSwiping = true;
_swipeStartX = e.X;
_swipeStartY = e.Y;
_swipeStartOffset = _swipeOffset;
_lastMovePosition = e.X;
_lastMoveTime = DateTime.UtcNow;
_velocity = 0f;
base.OnPointerPressed(e);
}
// Check if hit is on swipe items
if (_isOpen)
{
if (_swipeOffset > 0 && x < Bounds.Left + _swipeOffset)
{
return this; // Hit on left items
}
else if (_swipeOffset < 0 && x > Bounds.Right + _swipeOffset)
{
return this; // Hit on right items
}
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!_isSwiping)
{
return;
}
float num = e.X - _swipeStartX;
_ = e.Y;
_ = _swipeStartY;
if (_activeDirection == SwipeDirection.None && Math.Abs(num) > 10f)
{
_activeDirection = ((!(num > 0f)) ? SwipeDirection.Left : SwipeDirection.Right);
this.SwipeStarted?.Invoke(this, new SwipeStartedEventArgs(_activeDirection));
}
if (_activeDirection == SwipeDirection.Right || _activeDirection == SwipeDirection.Left)
{
_swipeOffset = _swipeStartOffset + num;
float max = ((_leftItems.Count > 0) ? LeftSwipeThreshold : 0f);
float min = ((_rightItems.Count > 0) ? (0f - RightSwipeThreshold) : 0f);
_swipeOffset = Math.Clamp(_swipeOffset, min, max);
DateTime utcNow = DateTime.UtcNow;
float num2 = (float)(utcNow - _lastMoveTime).TotalSeconds;
if (num2 > 0f)
{
_velocity = (e.X - _lastMovePosition) / num2;
}
_lastMovePosition = e.X;
_lastMoveTime = utcNow;
Invalidate();
e.Handled = true;
}
base.OnPointerMoved(e);
}
if (_content != null)
{
var hit = _content.HitTest(x, y);
if (hit != null) return hit;
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (!_isSwiping)
{
return;
}
_isSwiping = false;
bool flag = false;
if ((!(Math.Abs(_velocity) > 500f)) ? (Math.Abs(_swipeOffset) > 60f) : ((_velocity > 0f && _leftItems.Count > 0) || (_velocity < 0f && _rightItems.Count > 0)))
{
if (_swipeOffset > 0f)
{
Open(SwipeDirection.Right);
}
else
{
Open(SwipeDirection.Left);
}
}
else
{
Close();
}
this.SwipeEnded?.Invoke(this, new SwipeEndedEventArgs(_activeDirection, _isOpen));
_activeDirection = SwipeDirection.None;
base.OnPointerReleased(e);
}
return this;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
// Check for swipe item tap when open
if (_isOpen)
{
SwipeItem? tappedItem = null;
if (_swipeOffset > 0)
{
int index = (int)((e.X - Bounds.Left) / (_swipeOffset / _leftItems.Count));
if (index >= 0 && index < _leftItems.Count)
{
tappedItem = _leftItems[index];
}
}
else if (_swipeOffset < 0)
{
float itemWidth = Math.Abs(_swipeOffset) / _rightItems.Count;
int index = (int)((e.X - (Bounds.Right + _swipeOffset)) / itemWidth);
if (index >= 0 && index < _rightItems.Count)
{
tappedItem = _rightItems[index];
}
}
if (tappedItem != null)
{
tappedItem.OnInvoked();
Close();
e.Handled = true;
return;
}
}
_isSwiping = true;
_swipeStartX = e.X;
_swipeStartY = e.Y;
_swipeStartOffset = _swipeOffset;
_lastMovePosition = e.X;
_lastMoveTime = DateTime.UtcNow;
_velocity = 0;
base.OnPointerPressed(e);
}
public override void OnPointerMoved(PointerEventArgs e)
{
if (!_isSwiping) return;
float deltaX = e.X - _swipeStartX;
float deltaY = e.Y - _swipeStartY;
// Determine swipe direction
if (_activeDirection == SwipeDirection.None)
{
if (Math.Abs(deltaX) > 10)
{
_activeDirection = deltaX > 0 ? SwipeDirection.Right : SwipeDirection.Left;
SwipeStarted?.Invoke(this, new SwipeStartedEventArgs(_activeDirection));
}
}
if (_activeDirection == SwipeDirection.Right || _activeDirection == SwipeDirection.Left)
{
_swipeOffset = _swipeStartOffset + deltaX;
// Clamp offset based on available items
float maxRight = _leftItems.Count > 0 ? LeftSwipeThreshold : 0;
float maxLeft = _rightItems.Count > 0 ? -RightSwipeThreshold : 0;
_swipeOffset = Math.Clamp(_swipeOffset, maxLeft, maxRight);
// Calculate velocity
var now = DateTime.UtcNow;
float timeDelta = (float)(now - _lastMoveTime).TotalSeconds;
if (timeDelta > 0)
{
_velocity = (e.X - _lastMovePosition) / timeDelta;
}
_lastMovePosition = e.X;
_lastMoveTime = now;
Invalidate();
e.Handled = true;
}
base.OnPointerMoved(e);
}
public override void OnPointerReleased(PointerEventArgs e)
{
if (!_isSwiping) return;
_isSwiping = false;
// Determine final state
bool shouldOpen = false;
if (Math.Abs(_velocity) > VelocityThreshold)
{
// Use velocity
shouldOpen = (_velocity > 0 && _leftItems.Count > 0) || (_velocity < 0 && _rightItems.Count > 0);
}
else
{
// Use threshold
shouldOpen = Math.Abs(_swipeOffset) > SwipeThreshold;
}
if (shouldOpen)
{
if (_swipeOffset > 0)
{
Open(SwipeDirection.Right);
}
else
{
Open(SwipeDirection.Left);
}
}
else
{
Close();
}
SwipeEnded?.Invoke(this, new SwipeEndedEventArgs(_activeDirection, _isOpen));
_activeDirection = SwipeDirection.None;
base.OnPointerReleased(e);
}
}
/// <summary>
/// Represents a swipe action item.
/// </summary>
public class SwipeItem
{
/// <summary>
/// Gets or sets the text.
/// </summary>
public string Text { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the icon source.
/// </summary>
public string? IconSource { get; set; }
/// <summary>
/// Gets or sets the background color.
/// </summary>
public SKColor BackgroundColor { get; set; } = new SKColor(33, 150, 243);
/// <summary>
/// Gets or sets the text color.
/// </summary>
public SKColor TextColor { get; set; } = SKColors.White;
/// <summary>
/// Event raised when the item is invoked.
/// </summary>
public event EventHandler? Invoked;
internal void OnInvoked()
{
Invoked?.Invoke(this, EventArgs.Empty);
}
}
/// <summary>
/// Swipe direction.
/// </summary>
public enum SwipeDirection
{
None,
Left,
Right,
Up,
Down
}
/// <summary>
/// Swipe mode.
/// </summary>
public enum SwipeMode
{
Reveal,
Execute
}
/// <summary>
/// Event args for swipe started.
/// </summary>
public class SwipeStartedEventArgs : EventArgs
{
public SwipeDirection Direction { get; }
public SwipeStartedEventArgs(SwipeDirection direction)
{
Direction = direction;
}
}
/// <summary>
/// Event args for swipe ended.
/// </summary>
public class SwipeEndedEventArgs : EventArgs
{
public SwipeDirection Direction { get; }
public bool IsOpen { get; }
public SwipeEndedEventArgs(SwipeDirection direction, bool isOpen)
{
Direction = direction;
IsOpen = isOpen;
}
}

View File

@@ -1,343 +1,339 @@
using System;
using Microsoft.Maui.Controls;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Skia-rendered toggle switch control with full XAML styling support.
/// </summary>
public class SkiaSwitch : SkiaView
{
public static readonly BindableProperty IsOnProperty = BindableProperty.Create("IsOn", typeof(bool), typeof(SkiaSwitch), (object)false, (BindingMode)1, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).OnIsOnChanged();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
#region BindableProperties
public static readonly BindableProperty OnTrackColorProperty = BindableProperty.Create("OnTrackColor", typeof(SKColor), typeof(SkiaSwitch), (object)new SKColor((byte)33, (byte)150, (byte)243), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for IsOn.
/// </summary>
public static readonly BindableProperty IsOnProperty =
BindableProperty.Create(
nameof(IsOn),
typeof(bool),
typeof(SkiaSwitch),
false,
BindingMode.TwoWay,
propertyChanged: (b, o, n) => ((SkiaSwitch)b).OnIsOnChanged());
public static readonly BindableProperty OffTrackColorProperty = BindableProperty.Create("OffTrackColor", typeof(SKColor), typeof(SkiaSwitch), (object)new SKColor((byte)158, (byte)158, (byte)158), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for OnTrackColor.
/// </summary>
public static readonly BindableProperty OnTrackColorProperty =
BindableProperty.Create(
nameof(OnTrackColor),
typeof(SKColor),
typeof(SkiaSwitch),
new SKColor(0x21, 0x96, 0xF3),
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create("ThumbColor", typeof(SKColor), typeof(SkiaSwitch), (object)SKColors.White, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for OffTrackColor.
/// </summary>
public static readonly BindableProperty OffTrackColorProperty =
BindableProperty.Create(
nameof(OffTrackColor),
typeof(SKColor),
typeof(SkiaSwitch),
new SKColor(0x9E, 0x9E, 0x9E),
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create("DisabledColor", typeof(SKColor), typeof(SkiaSwitch), (object)new SKColor((byte)189, (byte)189, (byte)189), (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for ThumbColor.
/// </summary>
public static readonly BindableProperty ThumbColorProperty =
BindableProperty.Create(
nameof(ThumbColor),
typeof(SKColor),
typeof(SkiaSwitch),
SKColors.White,
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
public static readonly BindableProperty TrackWidthProperty = BindableProperty.Create("TrackWidth", typeof(float), typeof(SkiaSwitch), (object)52f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for DisabledColor.
/// </summary>
public static readonly BindableProperty DisabledColorProperty =
BindableProperty.Create(
nameof(DisabledColor),
typeof(SKColor),
typeof(SkiaSwitch),
new SKColor(0xBD, 0xBD, 0xBD),
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
public static readonly BindableProperty TrackHeightProperty = BindableProperty.Create("TrackHeight", typeof(float), typeof(SkiaSwitch), (object)32f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).InvalidateMeasure();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for TrackWidth.
/// </summary>
public static readonly BindableProperty TrackWidthProperty =
BindableProperty.Create(
nameof(TrackWidth),
typeof(float),
typeof(SkiaSwitch),
52f,
propertyChanged: (b, o, n) => ((SkiaSwitch)b).InvalidateMeasure());
public static readonly BindableProperty ThumbRadiusProperty = BindableProperty.Create("ThumbRadius", typeof(float), typeof(SkiaSwitch), (object)12f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for TrackHeight.
/// </summary>
public static readonly BindableProperty TrackHeightProperty =
BindableProperty.Create(
nameof(TrackHeight),
typeof(float),
typeof(SkiaSwitch),
32f,
propertyChanged: (b, o, n) => ((SkiaSwitch)b).InvalidateMeasure());
public static readonly BindableProperty ThumbPaddingProperty = BindableProperty.Create("ThumbPadding", typeof(float), typeof(SkiaSwitch), (object)4f, (BindingMode)2, (ValidateValueDelegate)null, (BindingPropertyChangedDelegate)delegate(BindableObject b, object o, object n)
{
((SkiaSwitch)(object)b).Invalidate();
}, (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
/// <summary>
/// Bindable property for ThumbRadius.
/// </summary>
public static readonly BindableProperty ThumbRadiusProperty =
BindableProperty.Create(
nameof(ThumbRadius),
typeof(float),
typeof(SkiaSwitch),
12f,
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
private float _animationProgress;
/// <summary>
/// Bindable property for ThumbPadding.
/// </summary>
public static readonly BindableProperty ThumbPaddingProperty =
BindableProperty.Create(
nameof(ThumbPadding),
typeof(float),
typeof(SkiaSwitch),
4f,
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
public bool IsOn
{
get
{
return (bool)((BindableObject)this).GetValue(IsOnProperty);
}
set
{
((BindableObject)this).SetValue(IsOnProperty, (object)value);
}
}
#endregion
public SKColor OnTrackColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(OnTrackColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(OnTrackColorProperty, (object)value);
}
}
#region Properties
public SKColor OffTrackColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(OffTrackColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(OffTrackColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets whether the switch is on.
/// </summary>
public bool IsOn
{
get => (bool)GetValue(IsOnProperty);
set => SetValue(IsOnProperty, value);
}
public SKColor ThumbColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(ThumbColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(ThumbColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the on track color.
/// </summary>
public SKColor OnTrackColor
{
get => (SKColor)GetValue(OnTrackColorProperty);
set => SetValue(OnTrackColorProperty, value);
}
public SKColor DisabledColor
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
return (SKColor)((BindableObject)this).GetValue(DisabledColorProperty);
}
set
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
((BindableObject)this).SetValue(DisabledColorProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the off track color.
/// </summary>
public SKColor OffTrackColor
{
get => (SKColor)GetValue(OffTrackColorProperty);
set => SetValue(OffTrackColorProperty, value);
}
public float TrackWidth
{
get
{
return (float)((BindableObject)this).GetValue(TrackWidthProperty);
}
set
{
((BindableObject)this).SetValue(TrackWidthProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the thumb color.
/// </summary>
public SKColor ThumbColor
{
get => (SKColor)GetValue(ThumbColorProperty);
set => SetValue(ThumbColorProperty, value);
}
public float TrackHeight
{
get
{
return (float)((BindableObject)this).GetValue(TrackHeightProperty);
}
set
{
((BindableObject)this).SetValue(TrackHeightProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the disabled color.
/// </summary>
public SKColor DisabledColor
{
get => (SKColor)GetValue(DisabledColorProperty);
set => SetValue(DisabledColorProperty, value);
}
public float ThumbRadius
{
get
{
return (float)((BindableObject)this).GetValue(ThumbRadiusProperty);
}
set
{
((BindableObject)this).SetValue(ThumbRadiusProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the track width.
/// </summary>
public float TrackWidth
{
get => (float)GetValue(TrackWidthProperty);
set => SetValue(TrackWidthProperty, value);
}
public float ThumbPadding
{
get
{
return (float)((BindableObject)this).GetValue(ThumbPaddingProperty);
}
set
{
((BindableObject)this).SetValue(ThumbPaddingProperty, (object)value);
}
}
/// <summary>
/// Gets or sets the track height.
/// </summary>
public float TrackHeight
{
get => (float)GetValue(TrackHeightProperty);
set => SetValue(TrackHeightProperty, value);
}
public event EventHandler<ToggledEventArgs>? Toggled;
/// <summary>
/// Gets or sets the thumb radius.
/// </summary>
public float ThumbRadius
{
get => (float)GetValue(ThumbRadiusProperty);
set => SetValue(ThumbRadiusProperty, value);
}
public SkiaSwitch()
{
base.IsFocusable = true;
}
/// <summary>
/// Gets or sets the thumb padding.
/// </summary>
public float ThumbPadding
{
get => (float)GetValue(ThumbPaddingProperty);
set => SetValue(ThumbPaddingProperty, value);
}
private void OnIsOnChanged()
{
_animationProgress = (IsOn ? 1f : 0f);
this.Toggled?.Invoke(this, new ToggledEventArgs(IsOn));
SkiaVisualStateManager.GoToState(this, IsOn ? "On" : "Off");
Invalidate();
}
#endregion
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Expected O, but got Unknown
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Expected O, but got Unknown
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Expected O, but got Unknown
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Unknown result type (might be due to invalid IL or missing references)
//IL_017d: Expected O, but got Unknown
//IL_0196: Unknown result type (might be due to invalid IL or missing references)
//IL_019b: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
//IL_01cd: Expected O, but got Unknown
//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
//IL_01e7: Expected O, but got Unknown
float midY = ((SKRect)(ref bounds)).MidY;
float num = ((SKRect)(ref bounds)).MidX - TrackWidth / 2f;
float num2 = num + TrackWidth;
float num3 = num + ThumbPadding + ThumbRadius;
float num4 = num2 - ThumbPadding - ThumbRadius;
float num5 = num3 + _animationProgress * (num4 - num3);
SKColor color = (base.IsEnabled ? InterpolateColor(OffTrackColor, OnTrackColor, _animationProgress) : DisabledColor);
SKPaint val = new SKPaint
{
Color = color,
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
SKRoundRect val2 = new SKRoundRect(new SKRect(num, midY - TrackHeight / 2f, num2, midY + TrackHeight / 2f), TrackHeight / 2f);
canvas.DrawRoundRect(val2, val);
if (base.IsEnabled)
{
SKPaint val3 = new SKPaint
{
Color = new SKColor((byte)0, (byte)0, (byte)0, (byte)40),
IsAntialias = true,
MaskFilter = SKMaskFilter.CreateBlur((SKBlurStyle)0, 2f)
};
try
{
canvas.DrawCircle(num5 + 1f, midY + 1f, ThumbRadius, val3);
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
SKPaint val4 = new SKPaint
{
Color = (SKColor)(base.IsEnabled ? ThumbColor : new SKColor((byte)245, (byte)245, (byte)245)),
IsAntialias = true,
Style = (SKPaintStyle)0
};
try
{
canvas.DrawCircle(num5, midY, ThumbRadius, val4);
if (base.IsFocused)
{
SKPaint val5 = new SKPaint();
SKColor onTrackColor = OnTrackColor;
val5.Color = ((SKColor)(ref onTrackColor)).WithAlpha((byte)60);
val5.IsAntialias = true;
val5.Style = (SKPaintStyle)1;
val5.StrokeWidth = 3f;
SKPaint val6 = val5;
try
{
SKRoundRect val7 = new SKRoundRect(val2.Rect, TrackHeight / 2f);
val7.Inflate(3f, 3f);
canvas.DrawRoundRect(val7, val6);
return;
}
finally
{
((IDisposable)val6)?.Dispose();
}
}
}
finally
{
((IDisposable)val4)?.Dispose();
}
}
finally
{
((IDisposable)val)?.Dispose();
}
}
private float _animationProgress; // 0 = off, 1 = on
private static SKColor InterpolateColor(SKColor from, SKColor to, float t)
{
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
return new SKColor((byte)((float)(int)((SKColor)(ref from)).Red + (float)(((SKColor)(ref to)).Red - ((SKColor)(ref from)).Red) * t), (byte)((float)(int)((SKColor)(ref from)).Green + (float)(((SKColor)(ref to)).Green - ((SKColor)(ref from)).Green) * t), (byte)((float)(int)((SKColor)(ref from)).Blue + (float)(((SKColor)(ref to)).Blue - ((SKColor)(ref from)).Blue) * t), (byte)((float)(int)((SKColor)(ref from)).Alpha + (float)(((SKColor)(ref to)).Alpha - ((SKColor)(ref from)).Alpha) * t));
}
/// <summary>
/// Event raised when the switch is toggled.
/// </summary>
public event EventHandler<ToggledEventArgs>? Toggled;
public override void OnPointerPressed(PointerEventArgs e)
{
if (base.IsEnabled)
{
IsOn = !IsOn;
e.Handled = true;
}
}
public SkiaSwitch()
{
IsFocusable = true;
}
public override void OnPointerReleased(PointerEventArgs e)
{
}
private void OnIsOnChanged()
{
_animationProgress = IsOn ? 1f : 0f;
Toggled?.Invoke(this, new ToggledEventArgs(IsOn));
SkiaVisualStateManager.GoToState(this, IsOn ? SkiaVisualStateManager.CommonStates.On : SkiaVisualStateManager.CommonStates.Off);
Invalidate();
}
public override void OnKeyDown(KeyEventArgs e)
{
if (base.IsEnabled && (e.Key == Key.Space || e.Key == Key.Enter))
{
IsOn = !IsOn;
e.Handled = true;
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
var centerY = bounds.MidY;
var trackLeft = bounds.MidX - TrackWidth / 2;
var trackRight = trackLeft + TrackWidth;
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
}
// Calculate thumb position
var thumbMinX = trackLeft + ThumbPadding + ThumbRadius;
var thumbMaxX = trackRight - ThumbPadding - ThumbRadius;
var thumbX = thumbMinX + _animationProgress * (thumbMaxX - thumbMinX);
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(TrackWidth + 8f, TrackHeight + 8f);
}
// Interpolate track color
var trackColor = IsEnabled
? InterpolateColor(OffTrackColor, OnTrackColor, _animationProgress)
: DisabledColor;
// Draw track
using var trackPaint = new SKPaint
{
Color = trackColor,
IsAntialias = true,
Style = SKPaintStyle.Fill
};
var trackRect = new SKRoundRect(
new SKRect(trackLeft, centerY - TrackHeight / 2, trackRight, centerY + TrackHeight / 2),
TrackHeight / 2);
canvas.DrawRoundRect(trackRect, trackPaint);
// Draw thumb shadow
if (IsEnabled)
{
using var shadowPaint = new SKPaint
{
Color = new SKColor(0, 0, 0, 40),
IsAntialias = true,
MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Normal, 2)
};
canvas.DrawCircle(thumbX + 1, centerY + 1, ThumbRadius, shadowPaint);
}
// Draw thumb
using var thumbPaint = new SKPaint
{
Color = IsEnabled ? ThumbColor : new SKColor(0xF5, 0xF5, 0xF5),
IsAntialias = true,
Style = SKPaintStyle.Fill
};
canvas.DrawCircle(thumbX, centerY, ThumbRadius, thumbPaint);
// Draw focus ring
if (IsFocused)
{
using var focusPaint = new SKPaint
{
Color = OnTrackColor.WithAlpha(60),
IsAntialias = true,
Style = SKPaintStyle.Stroke,
StrokeWidth = 3
};
var focusRect = new SKRoundRect(trackRect.Rect, TrackHeight / 2);
focusRect.Inflate(3, 3);
canvas.DrawRoundRect(focusRect, focusPaint);
}
}
private static SKColor InterpolateColor(SKColor from, SKColor to, float t)
{
return new SKColor(
(byte)(from.Red + (to.Red - from.Red) * t),
(byte)(from.Green + (to.Green - from.Green) * t),
(byte)(from.Blue + (to.Blue - from.Blue) * t),
(byte)(from.Alpha + (to.Alpha - from.Alpha) * t));
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
IsOn = !IsOn;
e.Handled = true;
}
public override void OnPointerReleased(PointerEventArgs e)
{
// Toggle handled in OnPointerPressed
}
public override void OnKeyDown(KeyEventArgs e)
{
if (!IsEnabled) return;
if (e.Key == Key.Space || e.Key == Key.Enter)
{
IsOn = !IsOn;
e.Handled = true;
}
}
protected override void OnEnabledChanged()
{
base.OnEnabledChanged();
SkiaVisualStateManager.GoToState(this, IsEnabled ? SkiaVisualStateManager.CommonStates.Normal : SkiaVisualStateManager.CommonStates.Disabled);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
return new SKSize(TrackWidth + 8, TrackHeight + 8);
}
}
/// <summary>
/// Event args for toggled events.
/// </summary>
public class ToggledEventArgs : EventArgs
{
public bool Value { get; }
public ToggledEventArgs(bool value) => Value = value;
}

View File

@@ -1,443 +1,422 @@
using System;
using System.Collections.Generic;
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// A page that displays tabs for navigation between child pages.
/// </summary>
public class SkiaTabbedPage : SkiaLayoutView
{
private readonly List<TabItem> _tabs = new List<TabItem>();
private readonly List<TabItem> _tabs = new();
private int _selectedIndex = 0;
private float _tabBarHeight = 48f;
private bool _tabBarOnBottom = false;
private int _selectedIndex;
/// <summary>
/// Gets or sets the height of the tab bar.
/// </summary>
public float TabBarHeight
{
get => _tabBarHeight;
set
{
if (_tabBarHeight != value)
{
_tabBarHeight = value;
InvalidateMeasure();
Invalidate();
}
}
}
private float _tabBarHeight = 48f;
/// <summary>
/// Gets or sets whether the tab bar is positioned at the bottom.
/// </summary>
public bool TabBarOnBottom
{
get => _tabBarOnBottom;
set
{
if (_tabBarOnBottom != value)
{
_tabBarOnBottom = value;
Invalidate();
}
}
}
private bool _tabBarOnBottom;
/// <summary>
/// Gets or sets the selected tab index.
/// </summary>
public int SelectedIndex
{
get => _selectedIndex;
set
{
if (value >= 0 && value < _tabs.Count && _selectedIndex != value)
{
_selectedIndex = value;
SelectedIndexChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
}
}
public float TabBarHeight
{
get
{
return _tabBarHeight;
}
set
{
if (_tabBarHeight != value)
{
_tabBarHeight = value;
InvalidateMeasure();
Invalidate();
}
}
}
/// <summary>
/// Gets the currently selected tab.
/// </summary>
public TabItem? SelectedTab => _selectedIndex >= 0 && _selectedIndex < _tabs.Count
? _tabs[_selectedIndex]
: null;
public bool TabBarOnBottom
{
get
{
return _tabBarOnBottom;
}
set
{
if (_tabBarOnBottom != value)
{
_tabBarOnBottom = value;
Invalidate();
}
}
}
/// <summary>
/// Gets the tabs in this page.
/// </summary>
public IReadOnlyList<TabItem> Tabs => _tabs;
public int SelectedIndex
{
get
{
return _selectedIndex;
}
set
{
if (value >= 0 && value < _tabs.Count && _selectedIndex != value)
{
_selectedIndex = value;
this.SelectedIndexChanged?.Invoke(this, EventArgs.Empty);
Invalidate();
}
}
}
/// <summary>
/// Background color for the tab bar.
/// </summary>
public SKColor TabBarBackgroundColor { get; set; } = new SKColor(33, 150, 243); // Material Blue
public TabItem? SelectedTab
{
get
{
if (_selectedIndex < 0 || _selectedIndex >= _tabs.Count)
{
return null;
}
return _tabs[_selectedIndex];
}
}
/// <summary>
/// Color for selected tab text/icon.
/// </summary>
public SKColor SelectedTabColor { get; set; } = SKColors.White;
public IReadOnlyList<TabItem> Tabs => _tabs;
/// <summary>
/// Color for unselected tab text/icon.
/// </summary>
public SKColor UnselectedTabColor { get; set; } = new SKColor(255, 255, 255, 180);
public SKColor TabBarBackgroundColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
/// <summary>
/// Color of the selection indicator.
/// </summary>
public SKColor IndicatorColor { get; set; } = SKColors.White;
public SKColor SelectedTabColor { get; set; } = SKColors.White;
/// <summary>
/// Height of the selection indicator.
/// </summary>
public float IndicatorHeight { get; set; } = 3f;
public SKColor UnselectedTabColor { get; set; } = new SKColor(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)180);
/// <summary>
/// Event raised when the selected index changes.
/// </summary>
public event EventHandler? SelectedIndexChanged;
public SKColor IndicatorColor { get; set; } = SKColors.White;
/// <summary>
/// Adds a tab with the specified title and content.
/// </summary>
public void AddTab(string title, SkiaView content, string? iconPath = null)
{
var tab = new TabItem
{
Title = title,
Content = content,
IconPath = iconPath
};
public float IndicatorHeight { get; set; } = 3f;
_tabs.Add(tab);
AddChild(content);
public event EventHandler? SelectedIndexChanged;
if (_tabs.Count == 1)
{
_selectedIndex = 0;
}
public void AddTab(string title, SkiaView content, string? iconPath = null)
{
TabItem item = new TabItem
{
Title = title,
Content = content,
IconPath = iconPath
};
_tabs.Add(item);
AddChild(content);
if (_tabs.Count == 1)
{
_selectedIndex = 0;
}
InvalidateMeasure();
Invalidate();
}
InvalidateMeasure();
Invalidate();
}
public void RemoveTab(int index)
{
if (index >= 0 && index < _tabs.Count)
{
TabItem tabItem = _tabs[index];
_tabs.RemoveAt(index);
RemoveChild(tabItem.Content);
if (_selectedIndex >= _tabs.Count)
{
_selectedIndex = Math.Max(0, _tabs.Count - 1);
}
InvalidateMeasure();
Invalidate();
}
}
/// <summary>
/// Removes a tab at the specified index.
/// </summary>
public void RemoveTab(int index)
{
if (index >= 0 && index < _tabs.Count)
{
var tab = _tabs[index];
_tabs.RemoveAt(index);
RemoveChild(tab.Content);
public void ClearTabs()
{
foreach (TabItem tab in _tabs)
{
RemoveChild(tab.Content);
}
_tabs.Clear();
_selectedIndex = 0;
InvalidateMeasure();
Invalidate();
}
if (_selectedIndex >= _tabs.Count)
{
_selectedIndex = Math.Max(0, _tabs.Count - 1);
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
float num = ((SKSize)(ref availableSize)).Height - TabBarHeight;
SKSize availableSize2 = default(SKSize);
((SKSize)(ref availableSize2))._002Ector(((SKSize)(ref availableSize)).Width, num);
foreach (TabItem tab in _tabs)
{
tab.Content.Measure(availableSize2);
}
return availableSize;
}
InvalidateMeasure();
Invalidate();
}
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
SKRect bounds2 = default(SKRect);
if (TabBarOnBottom)
{
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom - TabBarHeight);
}
else
{
((SKRect)(ref bounds2))._002Ector(((SKRect)(ref bounds)).Left, ((SKRect)(ref bounds)).Top + TabBarHeight, ((SKRect)(ref bounds)).Right, ((SKRect)(ref bounds)).Bottom);
}
foreach (TabItem tab in _tabs)
{
tab.Content.Arrange(bounds2);
}
return bounds;
}
/// <summary>
/// Clears all tabs.
/// </summary>
public void ClearTabs()
{
foreach (var tab in _tabs)
{
RemoveChild(tab.Content);
}
_tabs.Clear();
_selectedIndex = 0;
InvalidateMeasure();
Invalidate();
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
canvas.Save();
canvas.ClipRect(bounds, (SKClipOperation)1, false);
DrawTabBar(canvas);
if (_selectedIndex >= 0 && _selectedIndex < _tabs.Count)
{
_tabs[_selectedIndex].Content.Draw(canvas);
}
canvas.Restore();
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
// Measure the content area (excluding tab bar)
var contentHeight = availableSize.Height - TabBarHeight;
var contentSize = new SKSize(availableSize.Width, contentHeight);
private void DrawTabBar(SKCanvas canvas)
{
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Expected O, but got Unknown
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Expected O, but got Unknown
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_016a: Unknown result type (might be due to invalid IL or missing references)
//IL_0186: Unknown result type (might be due to invalid IL or missing references)
//IL_020a: Unknown result type (might be due to invalid IL or missing references)
//IL_020f: Unknown result type (might be due to invalid IL or missing references)
//IL_0211: Unknown result type (might be due to invalid IL or missing references)
//IL_021b: Unknown result type (might be due to invalid IL or missing references)
//IL_0222: Unknown result type (might be due to invalid IL or missing references)
//IL_022b: Expected O, but got Unknown
//IL_0270: Unknown result type (might be due to invalid IL or missing references)
//IL_0275: Unknown result type (might be due to invalid IL or missing references)
//IL_0278: Unknown result type (might be due to invalid IL or missing references)
SKRect bounds;
SKRect val = default(SKRect);
if (TabBarOnBottom)
{
bounds = base.Bounds;
float left = ((SKRect)(ref bounds)).Left;
bounds = base.Bounds;
float num = ((SKRect)(ref bounds)).Bottom - TabBarHeight;
bounds = base.Bounds;
float right = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
((SKRect)(ref val))._002Ector(left, num, right, ((SKRect)(ref bounds)).Bottom);
}
else
{
bounds = base.Bounds;
float left2 = ((SKRect)(ref bounds)).Left;
bounds = base.Bounds;
float top = ((SKRect)(ref bounds)).Top;
bounds = base.Bounds;
float right2 = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
((SKRect)(ref val))._002Ector(left2, top, right2, ((SKRect)(ref bounds)).Top + TabBarHeight);
}
SKPaint val2 = new SKPaint
{
Color = TabBarBackgroundColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
canvas.DrawRect(val, val2);
if (_tabs.Count == 0)
{
return;
}
float num2 = ((SKRect)(ref val)).Width / (float)_tabs.Count;
SKPaint val3 = new SKPaint
{
IsAntialias = true,
TextSize = 14f,
Typeface = SKTypeface.Default
};
try
{
SKRect val4 = default(SKRect);
for (int i = 0; i < _tabs.Count; i++)
{
TabItem tabItem = _tabs[i];
((SKRect)(ref val4))._002Ector(((SKRect)(ref val)).Left + (float)i * num2, ((SKRect)(ref val)).Top, ((SKRect)(ref val)).Left + (float)(i + 1) * num2, ((SKRect)(ref val)).Bottom);
bool flag = i == _selectedIndex;
val3.Color = (flag ? SelectedTabColor : UnselectedTabColor);
val3.FakeBoldText = flag;
SKRect val5 = default(SKRect);
val3.MeasureText(tabItem.Title, ref val5);
float num3 = ((SKRect)(ref val4)).MidX - ((SKRect)(ref val5)).MidX;
float num4 = ((SKRect)(ref val4)).MidY - ((SKRect)(ref val5)).MidY;
canvas.DrawText(tabItem.Title, num3, num4, val3);
}
if (_selectedIndex >= 0 && _selectedIndex < _tabs.Count)
{
SKPaint val6 = new SKPaint
{
Color = IndicatorColor,
Style = (SKPaintStyle)0,
IsAntialias = true
};
try
{
float num5 = ((SKRect)(ref val)).Left + (float)_selectedIndex * num2;
float num6 = (TabBarOnBottom ? ((SKRect)(ref val)).Top : (((SKRect)(ref val)).Bottom - IndicatorHeight));
SKRect val7 = new SKRect(num5, num6, num5 + num2, num6 + IndicatorHeight);
canvas.DrawRect(val7, val6);
return;
}
finally
{
((IDisposable)val6)?.Dispose();
}
}
}
finally
{
((IDisposable)val3)?.Dispose();
}
}
finally
{
((IDisposable)val2)?.Dispose();
}
}
foreach (var tab in _tabs)
{
tab.Content.Measure(contentSize);
}
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
SKRect val = default(SKRect);
if (TabBarOnBottom)
{
bounds = base.Bounds;
float left = ((SKRect)(ref bounds)).Left;
bounds = base.Bounds;
float num = ((SKRect)(ref bounds)).Bottom - TabBarHeight;
bounds = base.Bounds;
float right = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
((SKRect)(ref val))._002Ector(left, num, right, ((SKRect)(ref bounds)).Bottom);
}
else
{
bounds = base.Bounds;
float left2 = ((SKRect)(ref bounds)).Left;
bounds = base.Bounds;
float top = ((SKRect)(ref bounds)).Top;
bounds = base.Bounds;
float right2 = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
((SKRect)(ref val))._002Ector(left2, top, right2, ((SKRect)(ref bounds)).Top + TabBarHeight);
}
if (((SKRect)(ref val)).Contains(x, y))
{
return this;
}
if (_selectedIndex >= 0 && _selectedIndex < _tabs.Count)
{
SkiaView skiaView = _tabs[_selectedIndex].Content.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
}
return null;
}
return availableSize;
}
public override void OnPointerPressed(PointerEventArgs e)
{
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
if (base.IsEnabled)
{
SKRect bounds;
SKRect val = default(SKRect);
if (TabBarOnBottom)
{
bounds = base.Bounds;
float left = ((SKRect)(ref bounds)).Left;
bounds = base.Bounds;
float num = ((SKRect)(ref bounds)).Bottom - TabBarHeight;
bounds = base.Bounds;
float right = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
((SKRect)(ref val))._002Ector(left, num, right, ((SKRect)(ref bounds)).Bottom);
}
else
{
bounds = base.Bounds;
float left2 = ((SKRect)(ref bounds)).Left;
bounds = base.Bounds;
float top = ((SKRect)(ref bounds)).Top;
bounds = base.Bounds;
float right2 = ((SKRect)(ref bounds)).Right;
bounds = base.Bounds;
((SKRect)(ref val))._002Ector(left2, top, right2, ((SKRect)(ref bounds)).Top + TabBarHeight);
}
if (((SKRect)(ref val)).Contains(e.X, e.Y) && _tabs.Count > 0)
{
float num2 = ((SKRect)(ref val)).Width / (float)_tabs.Count;
int value = (int)((e.X - ((SKRect)(ref val)).Left) / num2);
value = Math.Clamp(value, 0, _tabs.Count - 1);
SelectedIndex = value;
e.Handled = true;
}
base.OnPointerPressed(e);
}
}
protected override SKRect ArrangeOverride(SKRect bounds)
{
// Calculate content bounds based on tab bar position
SKRect contentBounds;
if (TabBarOnBottom)
{
contentBounds = new SKRect(
bounds.Left,
bounds.Top,
bounds.Right,
bounds.Bottom - TabBarHeight);
}
else
{
contentBounds = new SKRect(
bounds.Left,
bounds.Top + TabBarHeight,
bounds.Right,
bounds.Bottom);
}
// Arrange each tab's content to fill the content area
foreach (var tab in _tabs)
{
tab.Content.Arrange(contentBounds);
}
return bounds;
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
canvas.Save();
canvas.ClipRect(bounds);
// Draw tab bar background
DrawTabBar(canvas);
// Draw selected content
if (_selectedIndex >= 0 && _selectedIndex < _tabs.Count)
{
_tabs[_selectedIndex].Content.Draw(canvas);
}
canvas.Restore();
}
private void DrawTabBar(SKCanvas canvas)
{
// Calculate tab bar bounds
SKRect tabBarBounds;
if (TabBarOnBottom)
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Bottom - TabBarHeight,
Bounds.Right,
Bounds.Bottom);
}
else
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Top,
Bounds.Right,
Bounds.Top + TabBarHeight);
}
// Draw background
using var bgPaint = new SKPaint
{
Color = TabBarBackgroundColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
canvas.DrawRect(tabBarBounds, bgPaint);
if (_tabs.Count == 0) return;
// Calculate tab width
float tabWidth = tabBarBounds.Width / _tabs.Count;
// Draw tabs
using var textPaint = new SKPaint
{
IsAntialias = true,
TextSize = 14f,
Typeface = SKTypeface.Default
};
for (int i = 0; i < _tabs.Count; i++)
{
var tab = _tabs[i];
var tabBounds = new SKRect(
tabBarBounds.Left + i * tabWidth,
tabBarBounds.Top,
tabBarBounds.Left + (i + 1) * tabWidth,
tabBarBounds.Bottom);
bool isSelected = i == _selectedIndex;
textPaint.Color = isSelected ? SelectedTabColor : UnselectedTabColor;
textPaint.FakeBoldText = isSelected;
// Draw tab title centered
var textBounds = new SKRect();
textPaint.MeasureText(tab.Title, ref textBounds);
float textX = tabBounds.MidX - textBounds.MidX;
float textY = tabBounds.MidY - textBounds.MidY;
canvas.DrawText(tab.Title, textX, textY, textPaint);
}
// Draw selection indicator
if (_selectedIndex >= 0 && _selectedIndex < _tabs.Count)
{
using var indicatorPaint = new SKPaint
{
Color = IndicatorColor,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
float indicatorLeft = tabBarBounds.Left + _selectedIndex * tabWidth;
float indicatorTop = TabBarOnBottom
? tabBarBounds.Top
: tabBarBounds.Bottom - IndicatorHeight;
var indicatorRect = new SKRect(
indicatorLeft,
indicatorTop,
indicatorLeft + tabWidth,
indicatorTop + IndicatorHeight);
canvas.DrawRect(indicatorRect, indicatorPaint);
}
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y)) return null;
// Check if hit is in tab bar
SKRect tabBarBounds;
if (TabBarOnBottom)
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Bottom - TabBarHeight,
Bounds.Right,
Bounds.Bottom);
}
else
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Top,
Bounds.Right,
Bounds.Top + TabBarHeight);
}
if (tabBarBounds.Contains(x, y))
{
return this; // Tab bar handles its own hits
}
// Check selected content
if (_selectedIndex >= 0 && _selectedIndex < _tabs.Count)
{
var hit = _tabs[_selectedIndex].Content.HitTest(x, y);
if (hit != null) return hit;
}
return this;
}
public override void OnPointerPressed(PointerEventArgs e)
{
if (!IsEnabled) return;
// Check if click is in tab bar
SKRect tabBarBounds;
if (TabBarOnBottom)
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Bottom - TabBarHeight,
Bounds.Right,
Bounds.Bottom);
}
else
{
tabBarBounds = new SKRect(
Bounds.Left,
Bounds.Top,
Bounds.Right,
Bounds.Top + TabBarHeight);
}
if (tabBarBounds.Contains(e.X, e.Y) && _tabs.Count > 0)
{
// Calculate which tab was clicked
float tabWidth = tabBarBounds.Width / _tabs.Count;
int clickedIndex = (int)((e.X - tabBarBounds.Left) / tabWidth);
clickedIndex = Math.Clamp(clickedIndex, 0, _tabs.Count - 1);
SelectedIndex = clickedIndex;
e.Handled = true;
}
base.OnPointerPressed(e);
}
}
/// <summary>
/// Represents a tab item with title, icon, and content.
/// </summary>
public class TabItem
{
/// <summary>
/// The title displayed in the tab.
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// Optional icon path for the tab.
/// </summary>
public string? IconPath { get; set; }
/// <summary>
/// The content view displayed when this tab is selected.
/// </summary>
public SkiaView Content { get; set; } = null!;
/// <summary>
/// Optional badge text to display on the tab.
/// </summary>
public string? Badge { get; set; }
}

View File

@@ -1,413 +1,367 @@
using System;
// 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;
using Microsoft.Maui.Controls.Shapes;
using Microsoft.Maui.Graphics;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
/// <summary>
/// Base class for Skia controls that support ControlTemplates.
/// Provides infrastructure for completely redefining control appearance via XAML.
/// </summary>
public abstract class SkiaTemplatedView : SkiaView
{
private SkiaView? _templateRoot;
private SkiaView? _templateRoot;
private bool _templateApplied;
private bool _templateApplied;
#region BindableProperties
public static readonly BindableProperty ControlTemplateProperty = BindableProperty.Create("ControlTemplate", typeof(ControlTemplate), typeof(SkiaTemplatedView), (object)null, (BindingMode)2, (ValidateValueDelegate)null, new BindingPropertyChangedDelegate(OnControlTemplateChanged), (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
public static readonly BindableProperty ControlTemplateProperty =
BindableProperty.Create(nameof(ControlTemplate), typeof(ControlTemplate), typeof(SkiaTemplatedView), null,
propertyChanged: OnControlTemplateChanged);
public ControlTemplate? ControlTemplate
{
get
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
return (ControlTemplate)((BindableObject)this).GetValue(ControlTemplateProperty);
}
set
{
((BindableObject)this).SetValue(ControlTemplateProperty, (object)value);
}
}
#endregion
protected SkiaView? TemplateRoot => _templateRoot;
#region Properties
protected bool IsTemplateApplied => _templateApplied;
/// <summary>
/// Gets or sets the control template that defines the visual appearance.
/// </summary>
public ControlTemplate? ControlTemplate
{
get => (ControlTemplate?)GetValue(ControlTemplateProperty);
set => SetValue(ControlTemplateProperty, value);
}
private static void OnControlTemplateChanged(BindableObject bindable, object oldValue, object newValue)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
//IL_001c: Expected O, but got Unknown
if (bindable is SkiaTemplatedView skiaTemplatedView)
{
skiaTemplatedView.OnControlTemplateChanged((ControlTemplate)oldValue, (ControlTemplate)newValue);
}
}
/// <summary>
/// Gets the root element created from the ControlTemplate.
/// </summary>
protected SkiaView? TemplateRoot => _templateRoot;
protected virtual void OnControlTemplateChanged(ControlTemplate? oldTemplate, ControlTemplate? newTemplate)
{
_templateApplied = false;
_templateRoot = null;
if (newTemplate != null)
{
ApplyTemplate();
}
InvalidateMeasure();
}
/// <summary>
/// Gets a value indicating whether a template has been applied.
/// </summary>
protected bool IsTemplateApplied => _templateApplied;
protected virtual void ApplyTemplate()
{
if (ControlTemplate == null || _templateApplied)
{
return;
}
try
{
object obj = ((ElementTemplate)ControlTemplate).CreateContent();
Element val = (Element)((obj is Element) ? obj : null);
if (val != null)
{
_templateRoot = ConvertElementToSkiaView(val);
}
else if (obj is SkiaView templateRoot)
{
_templateRoot = templateRoot;
}
if (_templateRoot != null)
{
_templateRoot.Parent = this;
OnTemplateApplied();
}
_templateApplied = true;
}
catch (Exception)
{
}
}
#endregion
protected virtual void OnTemplateApplied()
{
SkiaContentPresenter skiaContentPresenter = FindTemplateChild<SkiaContentPresenter>("PART_ContentPresenter");
if (skiaContentPresenter != null)
{
OnContentPresenterFound(skiaContentPresenter);
}
}
private static void OnControlTemplateChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is SkiaTemplatedView view)
{
view.OnControlTemplateChanged((ControlTemplate?)oldValue, (ControlTemplate?)newValue);
}
}
protected virtual void OnContentPresenterFound(SkiaContentPresenter presenter)
{
}
/// <summary>
/// Called when the ControlTemplate changes.
/// </summary>
protected virtual void OnControlTemplateChanged(ControlTemplate? oldTemplate, ControlTemplate? newTemplate)
{
_templateApplied = false;
_templateRoot = null;
protected T? FindTemplateChild<T>(string name) where T : SkiaView
{
if (_templateRoot == null)
{
return null;
}
return FindChild<T>(_templateRoot, name);
}
if (newTemplate != null)
{
ApplyTemplate();
}
private static T? FindChild<T>(SkiaView root, string name) where T : SkiaView
{
if (root is T result && root.Name == name)
{
return result;
}
if (root is SkiaLayoutView skiaLayoutView)
{
foreach (SkiaView child in skiaLayoutView.Children)
{
T val = FindChild<T>(child, name);
if (val != null)
{
return val;
}
}
}
else if (root is SkiaContentPresenter { Content: not null } skiaContentPresenter)
{
return FindChild<T>(skiaContentPresenter.Content, name);
}
return null;
}
InvalidateMeasure();
}
protected virtual SkiaView? ConvertElementToSkiaView(Element element)
{
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
StackLayout val = (StackLayout)(object)((element is StackLayout) ? element : null);
if (val == null)
{
Grid val2 = (Grid)(object)((element is Grid) ? element : null);
if (val2 == null)
{
Border val3 = (Border)(object)((element is Border) ? element : null);
if (val3 == null)
{
Label val4 = (Label)(object)((element is Label) ? element : null);
if (val4 == null)
{
if (element is ContentPresenter)
{
return new SkiaContentPresenter();
}
return new SkiaLabel
{
Text = "[" + ((object)element).GetType().Name + "]",
TextColor = SKColors.Gray
};
}
return CreateSkiaLabel(val4);
}
return CreateSkiaBorder(val3);
}
return CreateSkiaGrid(val2);
}
return CreateSkiaStackLayout(val);
}
/// <summary>
/// Applies the current ControlTemplate if one is set.
/// </summary>
protected virtual void ApplyTemplate()
{
if (ControlTemplate == null || _templateApplied)
return;
private SkiaStackLayout CreateSkiaStackLayout(StackLayout sl)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
SkiaStackLayout skiaStackLayout = new SkiaStackLayout
{
Orientation = (((int)sl.Orientation != 0) ? StackOrientation.Horizontal : StackOrientation.Vertical),
Spacing = (float)((StackBase)sl).Spacing
};
foreach (IView child in ((Layout)sl).Children)
{
Element val = (Element)(object)((child is Element) ? child : null);
if (val != null)
{
SkiaView skiaView = ConvertElementToSkiaView(val);
if (skiaView != null)
{
skiaStackLayout.AddChild(skiaView);
}
}
}
return skiaStackLayout;
}
try
{
// Create content from template
var content = ControlTemplate.CreateContent();
private SkiaGrid CreateSkiaGrid(Grid grid)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_016b: Expected O, but got Unknown
//IL_016f: Unknown result type (might be due to invalid IL or missing references)
//IL_0179: Expected O, but got Unknown
//IL_017d: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Expected O, but got Unknown
//IL_018b: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Expected O, but got Unknown
SkiaGrid skiaGrid = new SkiaGrid();
GridLength val;
foreach (RowDefinition item3 in (DefinitionCollection<RowDefinition>)(object)grid.RowDefinitions)
{
val = item3.Height;
GridLength gridLength;
if (!((GridLength)(ref val)).IsAuto)
{
val = item3.Height;
if (!((GridLength)(ref val)).IsStar)
{
val = item3.Height;
gridLength = new GridLength((float)((GridLength)(ref val)).Value);
}
else
{
val = item3.Height;
gridLength = new GridLength((float)((GridLength)(ref val)).Value, GridUnitType.Star);
}
}
else
{
gridLength = GridLength.Auto;
}
GridLength item = gridLength;
skiaGrid.RowDefinitions.Add(item);
}
foreach (ColumnDefinition item4 in (DefinitionCollection<ColumnDefinition>)(object)grid.ColumnDefinitions)
{
val = item4.Width;
GridLength gridLength2;
if (!((GridLength)(ref val)).IsAuto)
{
val = item4.Width;
if (!((GridLength)(ref val)).IsStar)
{
val = item4.Width;
gridLength2 = new GridLength((float)((GridLength)(ref val)).Value);
}
else
{
val = item4.Width;
gridLength2 = new GridLength((float)((GridLength)(ref val)).Value, GridUnitType.Star);
}
}
else
{
gridLength2 = GridLength.Auto;
}
GridLength item2 = gridLength2;
skiaGrid.ColumnDefinitions.Add(item2);
}
foreach (IView child in ((Layout)grid).Children)
{
Element val2 = (Element)(object)((child is Element) ? child : null);
if (val2 != null)
{
SkiaView skiaView = ConvertElementToSkiaView(val2);
if (skiaView != null)
{
int row = Grid.GetRow((BindableObject)child);
int column = Grid.GetColumn((BindableObject)child);
int rowSpan = Grid.GetRowSpan((BindableObject)child);
int columnSpan = Grid.GetColumnSpan((BindableObject)child);
skiaGrid.AddChild(skiaView, row, column, rowSpan, columnSpan);
}
}
}
return skiaGrid;
}
// If the content is a MAUI Element, try to convert it to a SkiaView
if (content is Element element)
{
_templateRoot = ConvertElementToSkiaView(element);
}
else if (content is SkiaView skiaView)
{
_templateRoot = skiaView;
}
private SkiaBorder CreateSkiaBorder(Border border)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
float cornerRadius = 0f;
IShape strokeShape = border.StrokeShape;
RoundRectangle val = (RoundRectangle)(object)((strokeShape is RoundRectangle) ? strokeShape : null);
if (val != null)
{
CornerRadius cornerRadius2 = val.CornerRadius;
cornerRadius = (float)((CornerRadius)(ref cornerRadius2)).TopLeft;
}
SkiaBorder skiaBorder = new SkiaBorder
{
CornerRadius = cornerRadius,
StrokeThickness = (float)border.StrokeThickness
};
Brush stroke = border.Stroke;
SolidColorBrush val2 = (SolidColorBrush)(object)((stroke is SolidColorBrush) ? stroke : null);
if (val2 != null)
{
skiaBorder.Stroke = val2.Color.ToSKColor();
}
Brush background = ((VisualElement)border).Background;
SolidColorBrush val3 = (SolidColorBrush)(object)((background is SolidColorBrush) ? background : null);
if (val3 != null)
{
skiaBorder.BackgroundColor = val3.Color.ToSKColor();
}
Element content = (Element)(object)border.Content;
if (content != null)
{
SkiaView skiaView = ConvertElementToSkiaView(content);
if (skiaView != null)
{
skiaBorder.AddChild(skiaView);
}
}
return skiaBorder;
}
if (_templateRoot != null)
{
_templateRoot.Parent = this;
OnTemplateApplied();
}
private SkiaLabel CreateSkiaLabel(Label label)
{
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
SkiaLabel skiaLabel = new SkiaLabel
{
Text = (label.Text ?? ""),
FontSize = (float)label.FontSize
};
if (label.TextColor != null)
{
skiaLabel.TextColor = label.TextColor.ToSKColor();
}
return skiaLabel;
}
_templateApplied = true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Error applying template: {ex.Message}");
}
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
if (_templateRoot != null && _templateApplied)
{
_templateRoot.Draw(canvas);
}
else
{
DrawDefaultAppearance(canvas, bounds);
}
}
/// <summary>
/// Called after a template has been successfully applied.
/// Override to perform template-specific initialization.
/// </summary>
protected virtual void OnTemplateApplied()
{
// Find and bind ContentPresenter if present
var presenter = FindTemplateChild<SkiaContentPresenter>("PART_ContentPresenter");
if (presenter != null)
{
OnContentPresenterFound(presenter);
}
}
protected abstract void DrawDefaultAppearance(SKCanvas canvas, SKRect bounds);
/// <summary>
/// Called when a ContentPresenter is found in the template.
/// Override to set up the content binding.
/// </summary>
protected virtual void OnContentPresenterFound(SkiaContentPresenter presenter)
{
// Derived classes should override to bind their content
}
protected override SKSize MeasureOverride(SKSize availableSize)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
if (_templateRoot != null && _templateApplied)
{
return _templateRoot.Measure(availableSize);
}
return MeasureDefaultAppearance(availableSize);
}
/// <summary>
/// Finds a named element in the template tree.
/// </summary>
protected T? FindTemplateChild<T>(string name) where T : SkiaView
{
if (_templateRoot == null)
return null;
protected virtual SKSize MeasureDefaultAppearance(SKSize availableSize)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
return new SKSize(100f, 40f);
}
return FindChild<T>(_templateRoot, name);
}
public new void Arrange(SKRect bounds)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
base.Arrange(bounds);
if (_templateRoot != null && _templateApplied)
{
_templateRoot.Arrange(bounds);
}
}
private static T? FindChild<T>(SkiaView root, string name) where T : SkiaView
{
if (root is T typed && root.Name == name)
return typed;
public override SkiaView? HitTest(float x, float y)
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
if (base.IsVisible)
{
SKRect bounds = base.Bounds;
if (((SKRect)(ref bounds)).Contains(x, y))
{
if (_templateRoot != null && _templateApplied)
{
SkiaView skiaView = _templateRoot.HitTest(x, y);
if (skiaView != null)
{
return skiaView;
}
}
return this;
}
}
return null;
}
if (root is SkiaLayoutView layout)
{
foreach (var child in layout.Children)
{
var found = FindChild<T>(child, name);
if (found != null)
return found;
}
}
else if (root is SkiaContentPresenter presenter && presenter.Content != null)
{
return FindChild<T>(presenter.Content, name);
}
return null;
}
/// <summary>
/// Converts a MAUI Element to a SkiaView.
/// Override to provide custom conversion logic.
/// </summary>
protected virtual SkiaView? ConvertElementToSkiaView(Element element)
{
// This is a simplified conversion - in a full implementation,
// you would use the handler system to create proper platform views
return element switch
{
// Handle common layout types
Microsoft.Maui.Controls.StackLayout sl => CreateSkiaStackLayout(sl),
Microsoft.Maui.Controls.Grid grid => CreateSkiaGrid(grid),
Microsoft.Maui.Controls.Border border => CreateSkiaBorder(border),
Microsoft.Maui.Controls.Label label => CreateSkiaLabel(label),
Microsoft.Maui.Controls.ContentPresenter cp => new SkiaContentPresenter(),
_ => new SkiaLabel { Text = $"[{element.GetType().Name}]", TextColor = SKColors.Gray }
};
}
private SkiaStackLayout CreateSkiaStackLayout(Microsoft.Maui.Controls.StackLayout sl)
{
var layout = new SkiaStackLayout
{
Orientation = sl.Orientation == Microsoft.Maui.Controls.StackOrientation.Vertical
? StackOrientation.Vertical
: StackOrientation.Horizontal,
Spacing = (float)sl.Spacing
};
foreach (var child in sl.Children)
{
if (child is Element element)
{
var skiaChild = ConvertElementToSkiaView(element);
if (skiaChild != null)
layout.AddChild(skiaChild);
}
}
return layout;
}
private SkiaGrid CreateSkiaGrid(Microsoft.Maui.Controls.Grid grid)
{
var layout = new SkiaGrid();
// Set row definitions
foreach (var rowDef in grid.RowDefinitions)
{
var gridLength = rowDef.Height.IsAuto ? GridLength.Auto :
rowDef.Height.IsStar ? new GridLength((float)rowDef.Height.Value, GridUnitType.Star) :
new GridLength((float)rowDef.Height.Value, GridUnitType.Absolute);
layout.RowDefinitions.Add(gridLength);
}
// Set column definitions
foreach (var colDef in grid.ColumnDefinitions)
{
var gridLength = colDef.Width.IsAuto ? GridLength.Auto :
colDef.Width.IsStar ? new GridLength((float)colDef.Width.Value, GridUnitType.Star) :
new GridLength((float)colDef.Width.Value, GridUnitType.Absolute);
layout.ColumnDefinitions.Add(gridLength);
}
// Add children
foreach (var child in grid.Children)
{
if (child is Element element)
{
var skiaChild = ConvertElementToSkiaView(element);
if (skiaChild != null)
{
var row = Microsoft.Maui.Controls.Grid.GetRow((BindableObject)child);
var col = Microsoft.Maui.Controls.Grid.GetColumn((BindableObject)child);
var rowSpan = Microsoft.Maui.Controls.Grid.GetRowSpan((BindableObject)child);
var colSpan = Microsoft.Maui.Controls.Grid.GetColumnSpan((BindableObject)child);
layout.AddChild(skiaChild, row, col, rowSpan, colSpan);
}
}
}
return layout;
}
private SkiaBorder CreateSkiaBorder(Microsoft.Maui.Controls.Border border)
{
float cornerRadius = 0;
if (border.StrokeShape is Microsoft.Maui.Controls.Shapes.RoundRectangle rr)
{
cornerRadius = (float)rr.CornerRadius.TopLeft;
}
var skiaBorder = new SkiaBorder
{
CornerRadius = cornerRadius,
StrokeThickness = (float)border.StrokeThickness
};
if (border.Stroke is SolidColorBrush strokeBrush)
{
skiaBorder.Stroke = strokeBrush.Color.ToSKColor();
}
if (border.Background is SolidColorBrush bgBrush)
{
skiaBorder.BackgroundColor = bgBrush.Color.ToSKColor();
}
if (border.Content is Element content)
{
var skiaContent = ConvertElementToSkiaView(content);
if (skiaContent != null)
skiaBorder.AddChild(skiaContent);
}
return skiaBorder;
}
private SkiaLabel CreateSkiaLabel(Microsoft.Maui.Controls.Label label)
{
var skiaLabel = new SkiaLabel
{
Text = label.Text ?? "",
FontSize = (float)label.FontSize
};
if (label.TextColor != null)
{
skiaLabel.TextColor = label.TextColor.ToSKColor();
}
return skiaLabel;
}
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{
if (_templateRoot != null && _templateApplied)
{
// Render the template
_templateRoot.Draw(canvas);
}
else
{
// Render default appearance
DrawDefaultAppearance(canvas, bounds);
}
}
/// <summary>
/// Draws the default appearance when no template is applied.
/// Override in derived classes to provide default rendering.
/// </summary>
protected abstract void DrawDefaultAppearance(SKCanvas canvas, SKRect bounds);
protected override SKSize MeasureOverride(SKSize availableSize)
{
if (_templateRoot != null && _templateApplied)
{
return _templateRoot.Measure(availableSize);
}
return MeasureDefaultAppearance(availableSize);
}
/// <summary>
/// Measures the default appearance when no template is applied.
/// Override in derived classes.
/// </summary>
protected virtual SKSize MeasureDefaultAppearance(SKSize availableSize)
{
return new SKSize(100, 40);
}
public new void Arrange(SKRect bounds)
{
base.Arrange(bounds);
if (_templateRoot != null && _templateApplied)
{
_templateRoot.Arrange(bounds);
}
}
public override SkiaView? HitTest(float x, float y)
{
if (!IsVisible || !Bounds.Contains(x, y))
return null;
if (_templateRoot != null && _templateApplied)
{
var hit = _templateRoot.HitTest(x, y);
if (hit != null)
return hit;
}
return this;
}
}

View File

@@ -1,8 +0,0 @@
namespace Microsoft.Maui.Platform;
public enum SkiaTextAlignment
{
Left,
Center,
Right
}

View File

@@ -1,28 +0,0 @@
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaTextSpan
{
public string Text { get; set; } = "";
public SKColor? TextColor { get; set; }
public SKColor? BackgroundColor { get; set; }
public string? FontFamily { get; set; }
public float FontSize { get; set; }
public bool IsBold { get; set; }
public bool IsItalic { get; set; }
public bool IsUnderline { get; set; }
public bool IsStrikethrough { get; set; }
public float CharacterSpacing { get; set; }
public float LineHeight { get; set; } = 1f;
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +0,0 @@
using System.Windows.Input;
using SkiaSharp;
namespace Microsoft.Maui.Platform;
public class SkiaToolbarItem
{
public string Text { get; set; } = "";
public SKBitmap? Icon { get; set; }
public SkiaToolbarItemOrder Order { get; set; }
public ICommand? Command { get; set; }
public SKRect HitBounds { get; set; }
}

View File

@@ -1,7 +0,0 @@
namespace Microsoft.Maui.Platform;
public enum SkiaToolbarItemOrder
{
Primary,
Secondary
}

View File

@@ -1,8 +0,0 @@
namespace Microsoft.Maui.Platform;
public enum SkiaVerticalAlignment
{
Top,
Center,
Bottom
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +0,0 @@
using System.Collections.Generic;
namespace Microsoft.Maui.Platform;
public class SkiaVisualState
{
public string Name { get; set; } = "";
public List<SkiaVisualStateSetter> Setters { get; } = new List<SkiaVisualStateSetter>();
}

View File

@@ -1,12 +0,0 @@
using System.Collections.Generic;
namespace Microsoft.Maui.Platform;
public class SkiaVisualStateGroup
{
public string Name { get; set; } = "";
public List<SkiaVisualState> States { get; } = new List<SkiaVisualState>();
public SkiaVisualState? CurrentState { get; set; }
}

View File

@@ -1,7 +0,0 @@
using System.Collections.Generic;
namespace Microsoft.Maui.Platform;
public class SkiaVisualStateGroupList : List<SkiaVisualStateGroup>
{
}

View File

@@ -1,98 +1,216 @@
using Microsoft.Maui.Controls;
// 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;
/// <summary>
/// Visual State Manager for Skia-rendered controls.
/// Provides state-based styling through XAML VisualStateGroups.
/// </summary>
public static class SkiaVisualStateManager
{
public static class CommonStates
{
public const string Normal = "Normal";
/// <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 const string Disabled = "Disabled";
/// <summary>
/// Attached property for VisualStateGroups.
/// </summary>
public static readonly BindableProperty VisualStateGroupsProperty =
BindableProperty.CreateAttached(
"VisualStateGroups",
typeof(SkiaVisualStateGroupList),
typeof(SkiaVisualStateManager),
null,
propertyChanged: OnVisualStateGroupsChanged);
public const string Focused = "Focused";
/// <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 PointerOver = "PointerOver";
/// <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 Pressed = "Pressed";
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 Selected = "Selected";
/// <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 Checked = "Checked";
bool stateFound = false;
public const string Unchecked = "Unchecked";
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 On = "On";
if (targetState != null)
{
// Unapply current state if different
if (group.CurrentState != null && group.CurrentState != targetState)
{
UnapplyState(view, group.CurrentState);
}
public const string Off = "Off";
}
// Apply new state
ApplyState(view, targetState);
group.CurrentState = targetState;
stateFound = true;
}
}
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);
return stateFound;
}
public static SkiaVisualStateGroupList? GetVisualStateGroups(SkiaView view)
{
return (SkiaVisualStateGroupList)((BindableObject)view).GetValue(VisualStateGroupsProperty);
}
private static void ApplyState(SkiaView view, SkiaVisualState state)
{
foreach (var setter in state.Setters)
{
setter.Apply(view);
}
}
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);
}
}
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);
}
}

View File

@@ -1,35 +0,0 @@
using Microsoft.Maui.Controls;
namespace Microsoft.Maui.Platform;
public class SkiaVisualStateSetter
{
private object? _originalValue;
private bool _hasOriginalValue;
public BindableProperty? Property { get; set; }
public object? Value { get; set; }
public void Apply(SkiaView view)
{
if (Property != null)
{
if (!_hasOriginalValue)
{
_originalValue = ((BindableObject)view).GetValue(Property);
_hasOriginalValue = true;
}
((BindableObject)view).SetValue(Property, Value);
}
}
public void Unapply(SkiaView view)
{
if (Property != null && _hasOriginalValue)
{
((BindableObject)view).SetValue(Property, _originalValue);
}
}
}

View File

File diff suppressed because it is too large Load Diff