Update with recovered code from VM binaries (Jan 1)
Recovered from decompiled OpenMaui.Controls.Linux.dll: - SkiaShell.cs: FlyoutHeader, FlyoutFooter, scroll support (918 -> 1325 lines) - X11Window.cs: Cursor support (XCreateFontCursor, XDefineCursor) - All handlers with dark mode support - All services with latest implementations - LinuxApplication with theme change handling
This commit is contained in:
143
Views/SkiaAbsoluteLayout.cs
Normal file
143
Views/SkiaAbsoluteLayout.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,238 +1,222 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using Microsoft.Maui.Controls;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
/// <summary>
|
||||
/// Skia-rendered activity indicator (spinner) control with full XAML styling support.
|
||||
/// </summary>
|
||||
public class SkiaActivityIndicator : SkiaView
|
||||
{
|
||||
#region BindableProperties
|
||||
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);
|
||||
|
||||
/// <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 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 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 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 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 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 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 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 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 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 RotationSpeed.
|
||||
/// </summary>
|
||||
public static readonly BindableProperty RotationSpeedProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(RotationSpeed),
|
||||
typeof(float),
|
||||
typeof(SkiaActivityIndicator),
|
||||
360f);
|
||||
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 ArcCount.
|
||||
/// </summary>
|
||||
public static readonly BindableProperty ArcCountProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(ArcCount),
|
||||
typeof(int),
|
||||
typeof(SkiaActivityIndicator),
|
||||
12,
|
||||
propertyChanged: (b, o, n) => ((SkiaActivityIndicator)b).Invalidate());
|
||||
private float _rotationAngle;
|
||||
|
||||
#endregion
|
||||
private DateTime _lastUpdateTime = DateTime.UtcNow;
|
||||
|
||||
#region Properties
|
||||
public bool IsRunning
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)((BindableObject)this).GetValue(IsRunningProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(IsRunningProperty, (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 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 the indicator color.
|
||||
/// </summary>
|
||||
public SKColor Color
|
||||
{
|
||||
get => (SKColor)GetValue(ColorProperty);
|
||||
set => SetValue(ColorProperty, 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 disabled color.
|
||||
/// </summary>
|
||||
public SKColor DisabledColor
|
||||
{
|
||||
get => (SKColor)GetValue(DisabledColorProperty);
|
||||
set => SetValue(DisabledColorProperty, value);
|
||||
}
|
||||
public float Size
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(SizeProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(SizeProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the indicator size.
|
||||
/// </summary>
|
||||
public float Size
|
||||
{
|
||||
get => (float)GetValue(SizeProperty);
|
||||
set => SetValue(SizeProperty, value);
|
||||
}
|
||||
public float StrokeWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(StrokeWidthProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(StrokeWidthProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the stroke width.
|
||||
/// </summary>
|
||||
public float StrokeWidth
|
||||
{
|
||||
get => (float)GetValue(StrokeWidthProperty);
|
||||
set => SetValue(StrokeWidthProperty, value);
|
||||
}
|
||||
public float RotationSpeed
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(RotationSpeedProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(RotationSpeedProperty, (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);
|
||||
}
|
||||
public int ArcCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)((BindableObject)this).GetValue(ArcCountProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(ArcCountProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of arcs.
|
||||
/// </summary>
|
||||
public int ArcCount
|
||||
{
|
||||
get => (int)GetValue(ArcCountProperty);
|
||||
set => SetValue(ArcCountProperty, value);
|
||||
}
|
||||
private void OnIsRunningChanged()
|
||||
{
|
||||
if (IsRunning)
|
||||
{
|
||||
_lastUpdateTime = DateTime.UtcNow;
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,385 +1,440 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
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 _message;
|
||||
private readonly string? _cancel;
|
||||
private readonly string? _accept;
|
||||
private readonly TaskCompletionSource<bool> _tcs;
|
||||
private readonly string _title;
|
||||
|
||||
private SKRect _cancelButtonBounds;
|
||||
private SKRect _acceptButtonBounds;
|
||||
private bool _cancelHovered;
|
||||
private bool _acceptHovered;
|
||||
private readonly string _message;
|
||||
|
||||
// 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? _cancel;
|
||||
|
||||
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 string? _accept;
|
||||
|
||||
/// <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 readonly TaskCompletionSource<bool> _tcs;
|
||||
|
||||
/// <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 _cancelButtonBounds;
|
||||
|
||||
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 SKRect _acceptButtonBounds;
|
||||
|
||||
// Calculate dialog dimensions
|
||||
var messageLines = WrapText(_message, DialogWidth - DialogPadding * 2, 16);
|
||||
var dialogHeight = CalculateDialogHeight(messageLines.Count);
|
||||
private bool _cancelHovered;
|
||||
|
||||
var dialogLeft = bounds.MidX - DialogWidth / 2;
|
||||
var dialogTop = bounds.MidY - dialogHeight / 2;
|
||||
var dialogBounds = new SKRect(dialogLeft, dialogTop, dialogLeft + DialogWidth, dialogTop + dialogHeight);
|
||||
private bool _acceptHovered;
|
||||
|
||||
// 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 OverlayColor = new SKColor((byte)0, (byte)0, (byte)0, (byte)128);
|
||||
|
||||
// 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 DialogBackground = SKColors.White;
|
||||
|
||||
// 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 TitleColor = new SKColor((byte)33, (byte)33, (byte)33);
|
||||
|
||||
// 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 MessageColor = new SKColor((byte)97, (byte)97, (byte)97);
|
||||
|
||||
foreach (var line in messageLines)
|
||||
{
|
||||
canvas.DrawText(line, dialogBounds.Left + DialogPadding, yOffset + 16, messagePaint);
|
||||
yOffset += 22;
|
||||
}
|
||||
yOffset += 8;
|
||||
}
|
||||
private static readonly SKColor ButtonColor = new SKColor((byte)33, (byte)150, (byte)243);
|
||||
|
||||
// Draw buttons
|
||||
yOffset = dialogBounds.Bottom - DialogPadding - ButtonHeight;
|
||||
var buttonY = yOffset;
|
||||
private static readonly SKColor ButtonHoverColor = new SKColor((byte)25, (byte)118, (byte)210);
|
||||
|
||||
var buttonCount = (_accept != null ? 1 : 0) + (_cancel != null ? 1 : 0);
|
||||
var totalButtonWidth = DialogWidth - DialogPadding * 2;
|
||||
private static readonly SKColor ButtonTextColor = SKColors.White;
|
||||
|
||||
if (buttonCount == 2)
|
||||
{
|
||||
var singleButtonWidth = (totalButtonWidth - ButtonSpacing) / 2;
|
||||
private static readonly SKColor CancelButtonColor = new SKColor((byte)158, (byte)158, (byte)158);
|
||||
|
||||
// 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 CancelButtonHoverColor = new SKColor((byte)117, (byte)117, (byte)117);
|
||||
|
||||
// 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 static readonly SKColor BorderColor = new SKColor((byte)224, (byte)224, (byte)224);
|
||||
|
||||
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 DialogWidth = 400f;
|
||||
|
||||
// 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 DialogPadding = 24f;
|
||||
|
||||
var textBounds = new SKRect();
|
||||
textPaint.MeasureText(text, ref textBounds);
|
||||
private const float ButtonHeight = 44f;
|
||||
|
||||
var x = bounds.MidX - textBounds.MidX;
|
||||
var y = bounds.MidY - textBounds.MidY;
|
||||
canvas.DrawText(text, x, y, textPaint);
|
||||
}
|
||||
private const float ButtonSpacing = 12f;
|
||||
|
||||
private float CalculateDialogHeight(int messageLineCount)
|
||||
{
|
||||
var height = DialogPadding * 2; // Top and bottom padding
|
||||
private const float CornerRadius = 12f;
|
||||
|
||||
if (!string.IsNullOrEmpty(_title))
|
||||
height += 36; // Title height
|
||||
public Task<bool> Result => _tcs.Task;
|
||||
|
||||
if (!string.IsNullOrEmpty(_message))
|
||||
height += messageLineCount * 22 + 8; // Message lines + spacing
|
||||
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;
|
||||
}
|
||||
|
||||
height += ButtonHeight; // Buttons
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
return Math.Max(height, 180); // Minimum height
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> WrapText(string text, float maxWidth, float fontSize)
|
||||
{
|
||||
var lines = new List<string>();
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return lines;
|
||||
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);
|
||||
}
|
||||
|
||||
using var font = new SKFont(SKTypeface.Default, fontSize);
|
||||
using var paint = new SKPaint(font);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
var words = text.Split(' ');
|
||||
var currentLine = "";
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var word in words)
|
||||
{
|
||||
var testLine = string.IsNullOrEmpty(currentLine) ? word : currentLine + " " + word;
|
||||
var width = paint.MeasureText(testLine);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (width > maxWidth && !string.IsNullOrEmpty(currentLine))
|
||||
{
|
||||
lines.Add(currentLine);
|
||||
currentLine = word;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentLine = 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 (!string.IsNullOrEmpty(currentLine))
|
||||
lines.Add(currentLine);
|
||||
private void Dismiss(bool result)
|
||||
{
|
||||
LinuxDialogService.HideDialog(this);
|
||||
_tcs.TrySetResult(result);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
protected override SKSize MeasureOverride(SKSize availableSize)
|
||||
{
|
||||
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
|
||||
return availableSize;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
public override SkiaView? HitTest(float x, float y)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,310 +1,483 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui.Platform.Linux.Handlers;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
/// <summary>
|
||||
/// Skia-rendered border/frame container control with full XAML styling support.
|
||||
/// </summary>
|
||||
public class SkiaBorder : SkiaLayoutView
|
||||
{
|
||||
#region BindableProperties
|
||||
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);
|
||||
|
||||
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 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 CornerRadiusProperty =
|
||||
BindableProperty.Create(nameof(CornerRadius), typeof(float), typeof(SkiaBorder), 0f,
|
||||
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 StrokeProperty =
|
||||
BindableProperty.Create(nameof(Stroke), typeof(SKColor), typeof(SkiaBorder), SKColors.Black,
|
||||
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 PaddingLeftProperty =
|
||||
BindableProperty.Create(nameof(PaddingLeft), typeof(float), typeof(SkiaBorder), 0f,
|
||||
propertyChanged: (b, o, n) => ((SkiaBorder)b).InvalidateMeasure());
|
||||
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 PaddingTopProperty =
|
||||
BindableProperty.Create(nameof(PaddingTop), 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 PaddingRightProperty =
|
||||
BindableProperty.Create(nameof(PaddingRight), 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 PaddingBottomProperty =
|
||||
BindableProperty.Create(nameof(PaddingBottom), 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 HasShadowProperty =
|
||||
BindableProperty.Create(nameof(HasShadow), typeof(bool), typeof(SkiaBorder), false,
|
||||
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
|
||||
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 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 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 ShadowBlurRadiusProperty =
|
||||
BindableProperty.Create(nameof(ShadowBlurRadius), typeof(float), typeof(SkiaBorder), 4f,
|
||||
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 ShadowOffsetXProperty =
|
||||
BindableProperty.Create(nameof(ShadowOffsetX), typeof(float), typeof(SkiaBorder), 2f,
|
||||
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 ShadowOffsetYProperty =
|
||||
BindableProperty.Create(nameof(ShadowOffsetY), typeof(float), typeof(SkiaBorder), 2f,
|
||||
propertyChanged: (b, o, n) => ((SkiaBorder)b).Invalidate());
|
||||
private bool _isPressed;
|
||||
|
||||
#endregion
|
||||
public float StrokeThickness
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(StrokeThicknessProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(StrokeThicknessProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
#region Properties
|
||||
public float CornerRadius
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(CornerRadiusProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(CornerRadiusProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public float StrokeThickness
|
||||
{
|
||||
get => (float)GetValue(StrokeThicknessProperty);
|
||||
set => SetValue(StrokeThicknessProperty, value);
|
||||
}
|
||||
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 CornerRadius
|
||||
{
|
||||
get => (float)GetValue(CornerRadiusProperty);
|
||||
set => SetValue(CornerRadiusProperty, value);
|
||||
}
|
||||
public float PaddingLeft
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(PaddingLeftProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(PaddingLeftProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public SKColor Stroke
|
||||
{
|
||||
get => (SKColor)GetValue(StrokeProperty);
|
||||
set => SetValue(StrokeProperty, value);
|
||||
}
|
||||
public float PaddingTop
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(PaddingTopProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(PaddingTopProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public float PaddingLeft
|
||||
{
|
||||
get => (float)GetValue(PaddingLeftProperty);
|
||||
set => SetValue(PaddingLeftProperty, value);
|
||||
}
|
||||
public float PaddingRight
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(PaddingRightProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(PaddingRightProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public float PaddingTop
|
||||
{
|
||||
get => (float)GetValue(PaddingTopProperty);
|
||||
set => SetValue(PaddingTopProperty, value);
|
||||
}
|
||||
public float PaddingBottom
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(PaddingBottomProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(PaddingBottomProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public float PaddingRight
|
||||
{
|
||||
get => (float)GetValue(PaddingRightProperty);
|
||||
set => SetValue(PaddingRightProperty, value);
|
||||
}
|
||||
public bool HasShadow
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)((BindableObject)this).GetValue(HasShadowProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(HasShadowProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public float PaddingBottom
|
||||
{
|
||||
get => (float)GetValue(PaddingBottomProperty);
|
||||
set => SetValue(PaddingBottomProperty, 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 bool HasShadow
|
||||
{
|
||||
get => (bool)GetValue(HasShadowProperty);
|
||||
set => SetValue(HasShadowProperty, value);
|
||||
}
|
||||
public float ShadowBlurRadius
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(ShadowBlurRadiusProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(ShadowBlurRadiusProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public SKColor ShadowColor
|
||||
{
|
||||
get => (SKColor)GetValue(ShadowColorProperty);
|
||||
set => SetValue(ShadowColorProperty, value);
|
||||
}
|
||||
public float ShadowOffsetX
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(ShadowOffsetXProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(ShadowOffsetXProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public float ShadowBlurRadius
|
||||
{
|
||||
get => (float)GetValue(ShadowBlurRadiusProperty);
|
||||
set => SetValue(ShadowBlurRadiusProperty, value);
|
||||
}
|
||||
public float ShadowOffsetY
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(ShadowOffsetYProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(ShadowOffsetYProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public float ShadowOffsetX
|
||||
{
|
||||
get => (float)GetValue(ShadowOffsetXProperty);
|
||||
set => SetValue(ShadowOffsetXProperty, value);
|
||||
}
|
||||
public event EventHandler? Tapped;
|
||||
|
||||
public float ShadowOffsetY
|
||||
{
|
||||
get => (float)GetValue(ShadowOffsetYProperty);
|
||||
set => SetValue(ShadowOffsetYProperty, value);
|
||||
}
|
||||
public void SetPadding(float all)
|
||||
{
|
||||
float num = (PaddingBottom = all);
|
||||
float num3 = (PaddingRight = num);
|
||||
float paddingLeft = (PaddingTop = num3);
|
||||
PaddingLeft = paddingLeft;
|
||||
}
|
||||
|
||||
#endregion
|
||||
public void SetPadding(float horizontal, float vertical)
|
||||
{
|
||||
float paddingLeft = (PaddingRight = horizontal);
|
||||
PaddingLeft = paddingLeft;
|
||||
paddingLeft = (PaddingBottom = vertical);
|
||||
PaddingTop = paddingLeft;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets uniform padding on all sides.
|
||||
/// </summary>
|
||||
public void SetPadding(float all)
|
||||
{
|
||||
PaddingLeft = PaddingTop = PaddingRight = PaddingBottom = all;
|
||||
}
|
||||
public void SetPadding(float left, float top, float right, float bottom)
|
||||
{
|
||||
PaddingLeft = left;
|
||||
PaddingTop = top;
|
||||
PaddingRight = right;
|
||||
PaddingBottom = bottom;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets padding with horizontal and vertical values.
|
||||
/// </summary>
|
||||
public void SetPadding(float horizontal, float vertical)
|
||||
{
|
||||
PaddingLeft = PaddingRight = horizontal;
|
||||
PaddingTop = PaddingBottom = vertical;
|
||||
}
|
||||
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 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 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);
|
||||
}
|
||||
|
||||
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
var strokeThickness = StrokeThickness;
|
||||
var cornerRadius = CornerRadius;
|
||||
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);
|
||||
}
|
||||
|
||||
var borderRect = new SKRect(
|
||||
bounds.Left + strokeThickness / 2,
|
||||
bounds.Top + strokeThickness / 2,
|
||||
bounds.Right - strokeThickness / 2,
|
||||
bounds.Bottom - strokeThickness / 2);
|
||||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
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 background
|
||||
using var bgPaint = new SKPaint
|
||||
{
|
||||
Color = BackgroundColor,
|
||||
Style = SKPaintStyle.Fill,
|
||||
IsAntialias = true
|
||||
};
|
||||
canvas.DrawRoundRect(new SKRoundRect(borderRect, cornerRadius), bgPaint);
|
||||
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 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 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 children
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (child.IsVisible)
|
||||
{
|
||||
child.Draw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
protected override SKRect GetContentBounds()
|
||||
{
|
||||
return GetContentBounds(Bounds);
|
||||
}
|
||||
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 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;
|
||||
}
|
||||
public override void OnPointerExited(PointerEventArgs e)
|
||||
{
|
||||
base.OnPointerExited(e);
|
||||
_isPressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,66 +1,93 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using Microsoft.Maui.Controls;
|
||||
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(nameof(Color), typeof(SKColor), typeof(SkiaBoxView), SKColors.Transparent,
|
||||
propertyChanged: (b, o, n) => ((SkiaBoxView)b).Invalidate());
|
||||
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 CornerRadiusProperty =
|
||||
BindableProperty.Create(nameof(CornerRadius), typeof(float), typeof(SkiaBoxView), 0f,
|
||||
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 SKColor Color
|
||||
{
|
||||
get => (SKColor)GetValue(ColorProperty);
|
||||
set => SetValue(ColorProperty, value);
|
||||
}
|
||||
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 float CornerRadius
|
||||
{
|
||||
get => (float)GetValue(CornerRadiusProperty);
|
||||
set => SetValue(CornerRadiusProperty, value);
|
||||
}
|
||||
public float CornerRadius
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(CornerRadiusProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(CornerRadiusProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
using var paint = new SKPaint
|
||||
{
|
||||
Color = Color,
|
||||
Style = SKPaintStyle.Fill,
|
||||
IsAntialias = true
|
||||
};
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
1650
Views/SkiaButton.cs
1650
Views/SkiaButton.cs
File diff suppressed because it is too large
Load Diff
@@ -1,403 +1,381 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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();
|
||||
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 readonly List<SkiaView> _items = new List<SkiaView>();
|
||||
|
||||
// Animation
|
||||
private bool _isAnimating = false;
|
||||
private float _animationStartOffset;
|
||||
private float _animationTargetOffset;
|
||||
private DateTime _animationStartTime;
|
||||
private const float AnimationDurationMs = 300f;
|
||||
private int _currentPosition;
|
||||
|
||||
/// <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 _scrollOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item count.
|
||||
/// </summary>
|
||||
public int ItemCount => _items.Count;
|
||||
private float _targetScrollOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether looping is enabled.
|
||||
/// </summary>
|
||||
public bool Loop { get; set; } = false;
|
||||
private bool _isDragging;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the peek amount (how much of adjacent items to show).
|
||||
/// </summary>
|
||||
public float PeekAreaInsets { get; set; } = 0f;
|
||||
private float _dragStartX;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the spacing between items.
|
||||
/// </summary>
|
||||
public float ItemSpacing { get; set; } = 0f;
|
||||
private float _dragStartOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether swipe gestures are enabled.
|
||||
/// </summary>
|
||||
public bool IsSwipeEnabled { get; set; } = true;
|
||||
private float _velocity;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the indicator visibility.
|
||||
/// </summary>
|
||||
public bool ShowIndicators { get; set; } = true;
|
||||
private DateTime _lastDragTime;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the indicator color.
|
||||
/// </summary>
|
||||
public SKColor IndicatorColor { get; set; } = new SKColor(180, 180, 180);
|
||||
private float _lastDragX;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected indicator color.
|
||||
/// </summary>
|
||||
public SKColor SelectedIndicatorColor { get; set; } = new SKColor(33, 150, 243);
|
||||
private bool _isAnimating;
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when position changes.
|
||||
/// </summary>
|
||||
public event EventHandler<PositionChangedEventArgs>? PositionChanged;
|
||||
private float _animationStartOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when scrolling.
|
||||
/// </summary>
|
||||
public event EventHandler? Scrolled;
|
||||
private float _animationTargetOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item to the carousel.
|
||||
/// </summary>
|
||||
public void AddItem(SkiaView item)
|
||||
{
|
||||
_items.Add(item);
|
||||
AddChild(item);
|
||||
InvalidateMeasure();
|
||||
Invalidate();
|
||||
}
|
||||
private DateTime _animationStartTime;
|
||||
|
||||
/// <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();
|
||||
}
|
||||
}
|
||||
private const float AnimationDurationMs = 300f;
|
||||
|
||||
/// <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 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>
|
||||
/// Scrolls to the specified position.
|
||||
/// </summary>
|
||||
public void ScrollTo(int position, bool animate = true)
|
||||
{
|
||||
if (position < 0 || position >= _items.Count) return;
|
||||
public int ItemCount => _items.Count;
|
||||
|
||||
int oldPosition = _currentPosition;
|
||||
_currentPosition = position;
|
||||
public bool Loop { get; set; }
|
||||
|
||||
if (animate)
|
||||
{
|
||||
AnimateToPosition(position);
|
||||
}
|
||||
else
|
||||
{
|
||||
_scrollOffset = GetOffsetForPosition(position);
|
||||
_targetScrollOffset = _scrollOffset;
|
||||
Invalidate();
|
||||
}
|
||||
public float PeekAreaInsets { get; set; }
|
||||
|
||||
if (oldPosition != position)
|
||||
{
|
||||
PositionChanged?.Invoke(this, new PositionChangedEventArgs(oldPosition, position));
|
||||
}
|
||||
}
|
||||
public float ItemSpacing { get; set; }
|
||||
|
||||
private void AnimateToPosition(int position)
|
||||
{
|
||||
_animationStartOffset = _scrollOffset;
|
||||
_animationTargetOffset = GetOffsetForPosition(position);
|
||||
_animationStartTime = DateTime.UtcNow;
|
||||
_isAnimating = true;
|
||||
Invalidate();
|
||||
}
|
||||
public bool IsSwipeEnabled { get; set; } = true;
|
||||
|
||||
private float GetOffsetForPosition(int position)
|
||||
{
|
||||
float itemWidth = Bounds.Width - PeekAreaInsets * 2;
|
||||
return position * (itemWidth + ItemSpacing);
|
||||
}
|
||||
public bool ShowIndicators { get; set; } = true;
|
||||
|
||||
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 IndicatorColor { get; set; } = new SKColor((byte)180, (byte)180, (byte)180);
|
||||
|
||||
protected override SKSize MeasureOverride(SKSize availableSize)
|
||||
{
|
||||
float itemWidth = availableSize.Width - PeekAreaInsets * 2;
|
||||
float itemHeight = availableSize.Height - (ShowIndicators ? 30 : 0);
|
||||
public SKColor SelectedIndicatorColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
|
||||
|
||||
foreach (var item in _items)
|
||||
{
|
||||
item.Measure(new SKSize(itemWidth, itemHeight));
|
||||
}
|
||||
public event EventHandler<PositionChangedEventArgs>? PositionChanged;
|
||||
|
||||
return availableSize;
|
||||
}
|
||||
public event EventHandler? Scrolled;
|
||||
|
||||
protected override SKRect ArrangeOverride(SKRect bounds)
|
||||
{
|
||||
float itemWidth = bounds.Width - PeekAreaInsets * 2;
|
||||
float itemHeight = bounds.Height - (ShowIndicators ? 30 : 0);
|
||||
public void AddItem(SkiaView item)
|
||||
{
|
||||
_items.Add(item);
|
||||
AddChild(item);
|
||||
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 RemoveItem(SkiaView item)
|
||||
{
|
||||
if (_items.Remove(item))
|
||||
{
|
||||
RemoveChild(item);
|
||||
if (_currentPosition >= _items.Count)
|
||||
{
|
||||
_currentPosition = Math.Max(0, _items.Count - 1);
|
||||
}
|
||||
InvalidateMeasure();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
public void ClearItems()
|
||||
{
|
||||
foreach (SkiaView item in _items)
|
||||
{
|
||||
RemoveChild(item);
|
||||
}
|
||||
_items.Clear();
|
||||
_currentPosition = 0;
|
||||
_scrollOffset = 0f;
|
||||
_targetScrollOffset = 0f;
|
||||
InvalidateMeasure();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
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);
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ease out cubic
|
||||
float t = 1f - (1f - progress) * (1f - progress) * (1f - progress);
|
||||
private void AnimateToPosition(int position)
|
||||
{
|
||||
_animationStartOffset = _scrollOffset;
|
||||
_animationTargetOffset = GetOffsetForPosition(position);
|
||||
_animationStartTime = DateTime.UtcNow;
|
||||
_isAnimating = true;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
_scrollOffset = _animationStartOffset + (_animationTargetOffset - _animationStartOffset) * t;
|
||||
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);
|
||||
}
|
||||
|
||||
if (progress >= 1f)
|
||||
{
|
||||
_isAnimating = false;
|
||||
_scrollOffset = _animationTargetOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
Invalidate(); // Continue animation
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
canvas.Save();
|
||||
canvas.ClipRect(bounds);
|
||||
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;
|
||||
}
|
||||
|
||||
// Draw visible items
|
||||
float itemWidth = bounds.Width - PeekAreaInsets * 2;
|
||||
float contentHeight = bounds.Height - (ShowIndicators ? 30 : 0);
|
||||
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;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _items.Count; i++)
|
||||
{
|
||||
float x = bounds.Left + PeekAreaInsets + i * (itemWidth + ItemSpacing) - _scrollOffset;
|
||||
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();
|
||||
}
|
||||
|
||||
// Only draw visible items
|
||||
if (x + itemWidth > bounds.Left && x < bounds.Right)
|
||||
{
|
||||
_items[i].Draw(canvas);
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// Draw indicators
|
||||
if (ShowIndicators && _items.Count > 1)
|
||||
{
|
||||
DrawIndicators(canvas, bounds);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
canvas.Restore();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,413 +1,454 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.Maui.Controls;
|
||||
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
|
||||
{
|
||||
#region BindableProperties
|
||||
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);
|
||||
|
||||
/// <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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 BorderWidth.
|
||||
/// </summary>
|
||||
public static readonly BindableProperty BorderWidthProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(BorderWidth),
|
||||
typeof(float),
|
||||
typeof(SkiaCheckBox),
|
||||
2f,
|
||||
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 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 bool IsChecked
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)((BindableObject)this).GetValue(IsCheckedProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(IsCheckedProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#region Properties
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the checkbox is checked.
|
||||
/// </summary>
|
||||
public bool IsChecked
|
||||
{
|
||||
get => (bool)GetValue(IsCheckedProperty);
|
||||
set => SetValue(IsCheckedProperty, value);
|
||||
}
|
||||
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 the check color.
|
||||
/// </summary>
|
||||
public SKColor CheckColor
|
||||
{
|
||||
get => (SKColor)GetValue(CheckColorProperty);
|
||||
set => SetValue(CheckColorProperty, 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 box color when checked.
|
||||
/// </summary>
|
||||
public SKColor BoxColor
|
||||
{
|
||||
get => (SKColor)GetValue(BoxColorProperty);
|
||||
set => SetValue(BoxColorProperty, 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 unchecked.
|
||||
/// </summary>
|
||||
public SKColor UncheckedBoxColor
|
||||
{
|
||||
get => (SKColor)GetValue(UncheckedBoxColorProperty);
|
||||
set => SetValue(UncheckedBoxColorProperty, 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 border color.
|
||||
/// </summary>
|
||||
public SKColor BorderColor
|
||||
{
|
||||
get => (SKColor)GetValue(BorderColorProperty);
|
||||
set => SetValue(BorderColorProperty, value);
|
||||
}
|
||||
public float BoxSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(BoxSizeProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(BoxSizeProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the disabled color.
|
||||
/// </summary>
|
||||
public SKColor DisabledColor
|
||||
{
|
||||
get => (SKColor)GetValue(DisabledColorProperty);
|
||||
set => SetValue(DisabledColorProperty, value);
|
||||
}
|
||||
public float CornerRadius
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(CornerRadiusProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(CornerRadiusProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the hovered border color.
|
||||
/// </summary>
|
||||
public SKColor HoveredBorderColor
|
||||
{
|
||||
get => (SKColor)GetValue(HoveredBorderColorProperty);
|
||||
set => SetValue(HoveredBorderColorProperty, value);
|
||||
}
|
||||
public float BorderWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(BorderWidthProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(BorderWidthProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the box size.
|
||||
/// </summary>
|
||||
public float BoxSize
|
||||
{
|
||||
get => (float)GetValue(BoxSizeProperty);
|
||||
set => SetValue(BoxSizeProperty, value);
|
||||
}
|
||||
public float CheckStrokeWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(CheckStrokeWidthProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(CheckStrokeWidthProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the corner radius.
|
||||
/// </summary>
|
||||
public float CornerRadius
|
||||
{
|
||||
get => (float)GetValue(CornerRadiusProperty);
|
||||
set => SetValue(CornerRadiusProperty, value);
|
||||
}
|
||||
public bool IsHovered { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the border width.
|
||||
/// </summary>
|
||||
public float BorderWidth
|
||||
{
|
||||
get => (float)GetValue(BorderWidthProperty);
|
||||
set => SetValue(BorderWidthProperty, value);
|
||||
}
|
||||
public event EventHandler<CheckedChangedEventArgs>? CheckedChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the check stroke width.
|
||||
/// </summary>
|
||||
public float CheckStrokeWidth
|
||||
{
|
||||
get => (float)GetValue(CheckStrokeWidthProperty);
|
||||
set => SetValue(CheckStrokeWidthProperty, value);
|
||||
}
|
||||
public SkiaCheckBox()
|
||||
{
|
||||
base.IsFocusable = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the pointer is over the checkbox.
|
||||
/// </summary>
|
||||
public bool IsHovered { get; private set; }
|
||||
private void OnIsCheckedChanged()
|
||||
{
|
||||
this.CheckedChanged?.Invoke(this, new CheckedChangedEventArgs(IsChecked));
|
||||
SkiaVisualStateManager.GoToState(this, IsChecked ? "Checked" : "Unchecked");
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when checked state changes.
|
||||
/// </summary>
|
||||
public event EventHandler<CheckedChangedEventArgs>? CheckedChanged;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
public SkiaCheckBox()
|
||||
{
|
||||
IsFocusable = true;
|
||||
}
|
||||
public override void OnPointerEntered(PointerEventArgs e)
|
||||
{
|
||||
if (base.IsEnabled)
|
||||
{
|
||||
IsHovered = true;
|
||||
SkiaVisualStateManager.GoToState(this, "PointerOver");
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIsCheckedChanged()
|
||||
{
|
||||
CheckedChanged?.Invoke(this, new CheckedChangedEventArgs(IsChecked));
|
||||
SkiaVisualStateManager.GoToState(this, IsChecked ? SkiaVisualStateManager.CommonStates.Checked : SkiaVisualStateManager.CommonStates.Unchecked);
|
||||
Invalidate();
|
||||
}
|
||||
public override void OnPointerExited(PointerEventArgs e)
|
||||
{
|
||||
IsHovered = false;
|
||||
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
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 OnPointerPressed(PointerEventArgs e)
|
||||
{
|
||||
if (base.IsEnabled)
|
||||
{
|
||||
IsChecked = !IsChecked;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
var roundRect = new SKRoundRect(boxRect, CornerRadius);
|
||||
public override void OnPointerReleased(PointerEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
// Draw background
|
||||
using var bgPaint = new SKPaint
|
||||
{
|
||||
Color = !IsEnabled ? DisabledColor
|
||||
: IsChecked ? BoxColor
|
||||
: UncheckedBoxColor,
|
||||
IsAntialias = true,
|
||||
Style = SKPaintStyle.Fill
|
||||
};
|
||||
canvas.DrawRoundRect(roundRect, bgPaint);
|
||||
public override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
if (base.IsEnabled && e.Key == Key.Space)
|
||||
{
|
||||
IsChecked = !IsChecked;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 void OnEnabledChanged()
|
||||
{
|
||||
base.OnEnabledChanged();
|
||||
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
207
Views/SkiaContentPage.cs
Normal file
207
Views/SkiaContentPage.cs
Normal file
@@ -0,0 +1,207 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,257 +1,242 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using Microsoft.Maui.Controls;
|
||||
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
|
||||
{
|
||||
#region BindableProperties
|
||||
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);
|
||||
|
||||
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 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 HorizontalContentAlignmentProperty =
|
||||
BindableProperty.Create(nameof(HorizontalContentAlignment), typeof(LayoutAlignment), typeof(SkiaContentPresenter), LayoutAlignment.Fill,
|
||||
propertyChanged: (b, o, n) => ((SkiaContentPresenter)b).InvalidateMeasure());
|
||||
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 VerticalContentAlignmentProperty =
|
||||
BindableProperty.Create(nameof(VerticalContentAlignment), 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 PaddingProperty =
|
||||
BindableProperty.Create(nameof(Padding), typeof(SKRect), typeof(SkiaContentPresenter), SKRect.Empty,
|
||||
propertyChanged: (b, o, n) => ((SkiaContentPresenter)b).InvalidateMeasure());
|
||||
public SkiaView? Content
|
||||
{
|
||||
get
|
||||
{
|
||||
return (SkiaView)((BindableObject)this).GetValue(ContentProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(ContentProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
public LayoutAlignment HorizontalContentAlignment
|
||||
{
|
||||
get
|
||||
{
|
||||
return (LayoutAlignment)((BindableObject)this).GetValue(HorizontalContentAlignmentProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(HorizontalContentAlignmentProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
#region Properties
|
||||
public LayoutAlignment VerticalContentAlignment
|
||||
{
|
||||
get
|
||||
{
|
||||
return (LayoutAlignment)((BindableObject)this).GetValue(VerticalContentAlignmentProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(VerticalContentAlignmentProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content to present.
|
||||
/// </summary>
|
||||
public SkiaView? Content
|
||||
{
|
||||
get => (SkiaView?)GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
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 horizontal alignment of the content.
|
||||
/// </summary>
|
||||
public LayoutAlignment HorizontalContentAlignment
|
||||
{
|
||||
get => (LayoutAlignment)GetValue(HorizontalContentAlignmentProperty);
|
||||
set => SetValue(HorizontalContentAlignmentProperty, 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 vertical alignment of the content.
|
||||
/// </summary>
|
||||
public LayoutAlignment VerticalContentAlignment
|
||||
{
|
||||
get => (LayoutAlignment)GetValue(VerticalContentAlignmentProperty);
|
||||
set => SetValue(VerticalContentAlignmentProperty, value);
|
||||
}
|
||||
protected override void OnBindingContextChanged()
|
||||
{
|
||||
base.OnBindingContextChanged();
|
||||
if (Content != null)
|
||||
{
|
||||
BindableObject.SetInheritedBindingContext((BindableObject)(object)Content, ((BindableObject)this).BindingContext);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the padding around the content.
|
||||
/// </summary>
|
||||
public SKRect Padding
|
||||
{
|
||||
get => (SKRect)GetValue(PaddingProperty);
|
||||
set => SetValue(PaddingProperty, 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);
|
||||
}
|
||||
|
||||
#endregion
|
||||
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);
|
||||
}
|
||||
|
||||
private void OnContentChanged(SkiaView? oldContent, SkiaView? newContent)
|
||||
{
|
||||
if (oldContent != null)
|
||||
{
|
||||
oldContent.Parent = null;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
if (newContent != null)
|
||||
{
|
||||
newContent.Parent = this;
|
||||
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);
|
||||
}
|
||||
|
||||
// Propagate binding context to new content
|
||||
if (BindingContext != null)
|
||||
{
|
||||
SetInheritedBindingContext(newContent, BindingContext);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
InvalidateMeasure();
|
||||
}
|
||||
public override void OnPointerPressed(PointerEventArgs e)
|
||||
{
|
||||
Content?.OnPointerPressed(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when binding context changes. Propagates to content.
|
||||
/// </summary>
|
||||
protected override void OnBindingContextChanged()
|
||||
{
|
||||
base.OnBindingContextChanged();
|
||||
public override void OnPointerMoved(PointerEventArgs e)
|
||||
{
|
||||
Content?.OnPointerMoved(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
|
||||
public override void OnPointerReleased(PointerEventArgs e)
|
||||
{
|
||||
Content?.OnPointerReleased(e);
|
||||
}
|
||||
}
|
||||
|
||||
312
Views/SkiaContextMenu.cs
Normal file
312
Views/SkiaContextMenu.cs
Normal file
@@ -0,0 +1,312 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
2163
Views/SkiaEditor.cs
2163
Views/SkiaEditor.cs
File diff suppressed because it is too large
Load Diff
2563
Views/SkiaEntry.cs
2563
Views/SkiaEntry.cs
File diff suppressed because it is too large
Load Diff
346
Views/SkiaFlexLayout.cs
Normal file
346
Views/SkiaFlexLayout.cs
Normal file
@@ -0,0 +1,346 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,381 +1,360 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
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? _detail;
|
||||
private bool _isPresented = false;
|
||||
private float _flyoutWidth = 300f;
|
||||
private float _flyoutAnimationProgress = 0f;
|
||||
private bool _gestureEnabled = true;
|
||||
private SkiaView? _flyout;
|
||||
|
||||
// Gesture tracking
|
||||
private bool _isDragging = false;
|
||||
private float _dragStartX;
|
||||
private float _dragCurrentX;
|
||||
private SkiaView? _detail;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the flyout content (menu).
|
||||
/// </summary>
|
||||
public SkiaView? Flyout
|
||||
{
|
||||
get => _flyout;
|
||||
set
|
||||
{
|
||||
if (_flyout != value)
|
||||
{
|
||||
if (_flyout != null)
|
||||
{
|
||||
RemoveChild(_flyout);
|
||||
}
|
||||
private bool _isPresented;
|
||||
|
||||
_flyout = value;
|
||||
private float _flyoutWidth = 300f;
|
||||
|
||||
if (_flyout != null)
|
||||
{
|
||||
AddChild(_flyout);
|
||||
}
|
||||
private float _flyoutAnimationProgress;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
private bool _gestureEnabled = true;
|
||||
|
||||
/// <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 bool _isDragging;
|
||||
|
||||
_detail = value;
|
||||
private float _dragStartX;
|
||||
|
||||
if (_detail != null)
|
||||
{
|
||||
AddChild(_detail);
|
||||
}
|
||||
private float _dragCurrentX;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
public SkiaView? Flyout
|
||||
{
|
||||
get
|
||||
{
|
||||
return _flyout;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_flyout != value)
|
||||
{
|
||||
if (_flyout != null)
|
||||
{
|
||||
RemoveChild(_flyout);
|
||||
}
|
||||
_flyout = value;
|
||||
if (_flyout != null)
|
||||
{
|
||||
AddChild(_flyout);
|
||||
}
|
||||
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 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 the width of the flyout panel.
|
||||
/// </summary>
|
||||
public float FlyoutWidth
|
||||
{
|
||||
get => _flyoutWidth;
|
||||
set
|
||||
{
|
||||
if (_flyoutWidth != value)
|
||||
{
|
||||
_flyoutWidth = Math.Max(100, value);
|
||||
InvalidateMeasure();
|
||||
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 whether swipe gestures are enabled.
|
||||
/// </summary>
|
||||
public bool GestureEnabled
|
||||
{
|
||||
get => _gestureEnabled;
|
||||
set => _gestureEnabled = value;
|
||||
}
|
||||
public float FlyoutWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return _flyoutWidth;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_flyoutWidth != value)
|
||||
{
|
||||
_flyoutWidth = Math.Max(100f, value);
|
||||
InvalidateMeasure();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The flyout layout behavior.
|
||||
/// </summary>
|
||||
public FlyoutLayoutBehavior FlyoutLayoutBehavior { get; set; } = FlyoutLayoutBehavior.Default;
|
||||
public bool GestureEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _gestureEnabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
_gestureEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Background color of the scrim when flyout is open.
|
||||
/// </summary>
|
||||
public SKColor ScrimColor { get; set; } = new SKColor(0, 0, 0, 100);
|
||||
public FlyoutLayoutBehavior FlyoutLayoutBehavior { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Shadow width for the flyout.
|
||||
/// </summary>
|
||||
public float ShadowWidth { get; set; } = 8f;
|
||||
public SKColor ScrimColor { get; set; } = new SKColor((byte)0, (byte)0, (byte)0, (byte)100);
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when IsPresented changes.
|
||||
/// </summary>
|
||||
public event EventHandler? IsPresentedChanged;
|
||||
public float ShadowWidth { get; set; } = 8f;
|
||||
|
||||
protected override SKSize MeasureOverride(SKSize availableSize)
|
||||
{
|
||||
// Measure flyout
|
||||
if (_flyout != null)
|
||||
{
|
||||
_flyout.Measure(new SKSize(FlyoutWidth, availableSize.Height));
|
||||
}
|
||||
public event EventHandler? IsPresentedChanged;
|
||||
|
||||
// Measure detail to full size
|
||||
if (_detail != null)
|
||||
{
|
||||
_detail.Measure(availableSize);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
return 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;
|
||||
}
|
||||
|
||||
protected override SKRect ArrangeOverride(SKRect bounds)
|
||||
{
|
||||
// Arrange detail to fill the entire area
|
||||
if (_detail != null)
|
||||
{
|
||||
_detail.Arrange(bounds);
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
canvas.Save();
|
||||
canvas.ClipRect(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);
|
||||
}
|
||||
|
||||
// Draw detail content first
|
||||
_detail?.Draw(canvas);
|
||||
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);
|
||||
}
|
||||
|
||||
// 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 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);
|
||||
}
|
||||
|
||||
// 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
|
||||
public void ToggleFlyout()
|
||||
{
|
||||
IsPresented = !IsPresented;
|
||||
}
|
||||
}
|
||||
|
||||
18
Views/SkiaFrame.cs
Normal file
18
Views/SkiaFrame.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +1,81 @@
|
||||
// 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 System;
|
||||
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 => _drawable;
|
||||
set
|
||||
{
|
||||
_drawable = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
public IDrawable? Drawable
|
||||
{
|
||||
get
|
||||
{
|
||||
return _drawable;
|
||||
}
|
||||
set
|
||||
{
|
||||
_drawable = 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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
406
Views/SkiaGrid.cs
Normal file
406
Views/SkiaGrid.cs
Normal file
@@ -0,0 +1,406 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,263 +1,553 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SkiaSharp;
|
||||
using Microsoft.Maui.Graphics;
|
||||
using Svg.Skia;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
/// <summary>
|
||||
/// Skia-rendered image control.
|
||||
/// </summary>
|
||||
public class SkiaImage : SkiaView
|
||||
{
|
||||
private SKBitmap? _bitmap;
|
||||
private SKImage? _image;
|
||||
private bool _isLoading;
|
||||
private SKBitmap? _bitmap;
|
||||
|
||||
public SKBitmap? Bitmap
|
||||
{
|
||||
get => _bitmap;
|
||||
set
|
||||
{
|
||||
_bitmap?.Dispose();
|
||||
_bitmap = value;
|
||||
_image?.Dispose();
|
||||
_image = value != null ? SKImage.FromBitmap(value) : null;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
private SKImage? _image;
|
||||
|
||||
public Aspect Aspect { get; set; } = Aspect.AspectFit;
|
||||
public bool IsOpaque { get; set; }
|
||||
public bool IsLoading => _isLoading;
|
||||
public bool IsAnimationPlaying { get; set; }
|
||||
private bool _isLoading;
|
||||
|
||||
public event EventHandler? ImageLoaded;
|
||||
public event EventHandler<ImageLoadingErrorEventArgs>? ImageLoadingError;
|
||||
private string? _currentFilePath;
|
||||
|
||||
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 bool _isSvg;
|
||||
|
||||
if (_image == null) return;
|
||||
private CancellationTokenSource? _loadCts;
|
||||
|
||||
var imageWidth = _image.Width;
|
||||
var imageHeight = _image.Height;
|
||||
private readonly object _loadLock = new object();
|
||||
|
||||
if (imageWidth <= 0 || imageHeight <= 0) return;
|
||||
private double _svgLoadedWidth;
|
||||
|
||||
var destRect = CalculateDestRect(bounds, imageWidth, imageHeight);
|
||||
private double _svgLoadedHeight;
|
||||
|
||||
using var paint = new SKPaint
|
||||
{
|
||||
IsAntialias = true,
|
||||
FilterQuality = SKFilterQuality.High
|
||||
};
|
||||
private bool _pendingSvgReload;
|
||||
|
||||
canvas.DrawImage(_image, destRect, paint);
|
||||
}
|
||||
private SKRect _lastArrangedBounds;
|
||||
|
||||
private SKRect CalculateDestRect(SKRect bounds, float imageWidth, float imageHeight)
|
||||
{
|
||||
float destX, destY, destWidth, destHeight;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
switch (Aspect)
|
||||
{
|
||||
case Aspect.Fill:
|
||||
// Stretch to fill entire bounds
|
||||
return bounds;
|
||||
public Aspect Aspect { 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 IsOpaque { get; set; }
|
||||
|
||||
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 IsLoading => _isLoading;
|
||||
|
||||
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 bool IsAnimationPlaying { get; set; }
|
||||
|
||||
default:
|
||||
return bounds;
|
||||
}
|
||||
}
|
||||
public new double WidthRequest
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.WidthRequest;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.WidthRequest = value;
|
||||
ScheduleSvgReloadIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task LoadFromFileAsync(string filePath)
|
||||
{
|
||||
_isLoading = true;
|
||||
Invalidate();
|
||||
public new double HeightRequest
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.HeightRequest;
|
||||
}
|
||||
set
|
||||
{
|
||||
base.HeightRequest = value;
|
||||
ScheduleSvgReloadIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
using var stream = File.OpenRead(filePath);
|
||||
var bitmap = SKBitmap.Decode(stream);
|
||||
if (bitmap != null)
|
||||
{
|
||||
Bitmap = bitmap;
|
||||
}
|
||||
});
|
||||
public event EventHandler? ImageLoaded;
|
||||
|
||||
_isLoading = false;
|
||||
ImageLoaded?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_isLoading = false;
|
||||
ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(ex));
|
||||
}
|
||||
public event EventHandler<ImageLoadingErrorEventArgs>? ImageLoadingError;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task LoadFromStreamAsync(Stream stream)
|
||||
{
|
||||
_isLoading = true;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var bitmap = SKBitmap.Decode(stream);
|
||||
if (bitmap != null)
|
||||
{
|
||||
Bitmap = bitmap;
|
||||
}
|
||||
});
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
_isLoading = false;
|
||||
ImageLoaded?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_isLoading = false;
|
||||
ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(ex));
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
public async Task LoadFromUriAsync(Uri uri)
|
||||
{
|
||||
_isLoading = true;
|
||||
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using var httpClient = new HttpClient();
|
||||
var data = await httpClient.GetByteArrayAsync(uri);
|
||||
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();
|
||||
}
|
||||
|
||||
using var stream = new MemoryStream(data);
|
||||
var bitmap = SKBitmap.Decode(stream);
|
||||
if (bitmap != null)
|
||||
{
|
||||
Bitmap = bitmap;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
_isLoading = false;
|
||||
ImageLoaded?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_isLoading = false;
|
||||
ImageLoadingError?.Invoke(this, new ImageLoadingErrorEventArgs(ex));
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override SKSize MeasureOverride(SKSize availableSize)
|
||||
{
|
||||
if (_image == null)
|
||||
return new SKSize(100, 100); // Default size
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,316 +1,325 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
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 = 0;
|
||||
private int _position = 0;
|
||||
private int _count;
|
||||
|
||||
/// <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();
|
||||
}
|
||||
}
|
||||
}
|
||||
private int _position;
|
||||
|
||||
/// <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 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 indicator color.
|
||||
/// </summary>
|
||||
public SKColor IndicatorColor { get; set; } = new SKColor(180, 180, 180);
|
||||
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 selected indicator color.
|
||||
/// </summary>
|
||||
public SKColor SelectedIndicatorColor { get; set; } = new SKColor(33, 150, 243);
|
||||
public SKColor IndicatorColor { get; set; } = new SKColor((byte)180, (byte)180, (byte)180);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the indicator size.
|
||||
/// </summary>
|
||||
public float IndicatorSize { get; set; } = 10f;
|
||||
public SKColor SelectedIndicatorColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected indicator size.
|
||||
/// </summary>
|
||||
public float SelectedIndicatorSize { get; set; } = 10f;
|
||||
public float IndicatorSize { get; set; } = 10f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the spacing between indicators.
|
||||
/// </summary>
|
||||
public float IndicatorSpacing { get; set; } = 8f;
|
||||
public float SelectedIndicatorSize { get; set; } = 10f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the indicator shape.
|
||||
/// </summary>
|
||||
public IndicatorShape IndicatorShape { get; set; } = IndicatorShape.Circle;
|
||||
public float IndicatorSpacing { get; set; } = 8f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether indicators should have a border.
|
||||
/// </summary>
|
||||
public bool ShowBorder { get; set; } = false;
|
||||
public IndicatorShape IndicatorShape { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the border color.
|
||||
/// </summary>
|
||||
public SKColor BorderColor { get; set; } = new SKColor(100, 100, 100);
|
||||
public bool ShowBorder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the border width.
|
||||
/// </summary>
|
||||
public float BorderWidth { get; set; } = 1f;
|
||||
public SKColor BorderColor { get; set; } = new SKColor((byte)100, (byte)100, (byte)100);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum visible indicators.
|
||||
/// </summary>
|
||||
public int MaximumVisible { get; set; } = 10;
|
||||
public float BorderWidth { get; set; } = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to hide indicators when count is 1 or less.
|
||||
/// </summary>
|
||||
public bool HideSingle { get; set; } = true;
|
||||
public int MaximumVisible { get; set; } = 10;
|
||||
|
||||
protected override SKSize MeasureOverride(SKSize availableSize)
|
||||
{
|
||||
if (_count <= 0 || (HideSingle && _count <= 1))
|
||||
{
|
||||
return SKSize.Empty;
|
||||
}
|
||||
public bool HideSingle { get; set; } = true;
|
||||
|
||||
int visibleCount = Math.Min(_count, MaximumVisible);
|
||||
float totalWidth = visibleCount * IndicatorSize + (visibleCount - 1) * IndicatorSpacing;
|
||||
float height = Math.Max(IndicatorSize, SelectedIndicatorSize);
|
||||
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);
|
||||
}
|
||||
|
||||
return new SKSize(totalWidth, height);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
if (_count <= 0 || (HideSingle && _count <= 1)) return;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
canvas.Save();
|
||||
canvas.ClipRect(Bounds);
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1928
Views/SkiaLabel.cs
1928
Views/SkiaLabel.cs
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,598 +1,335 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
/// <summary>
|
||||
/// A horizontal menu bar control.
|
||||
/// </summary>
|
||||
public class SkiaMenuBar : SkiaView
|
||||
{
|
||||
private readonly List<MenuBarItem> _items = new();
|
||||
private int _hoveredIndex = -1;
|
||||
private int _openIndex = -1;
|
||||
private SkiaMenuFlyout? _openFlyout;
|
||||
private readonly List<MenuBarItem> _items = new List<MenuBarItem>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the menu bar items.
|
||||
/// </summary>
|
||||
public IList<MenuBarItem> Items => _items;
|
||||
private int _hoveredIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the background color.
|
||||
/// </summary>
|
||||
public SKColor BackgroundColor { get; set; } = new SKColor(240, 240, 240);
|
||||
private int _openIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text color.
|
||||
/// </summary>
|
||||
public SKColor TextColor { get; set; } = new SKColor(33, 33, 33);
|
||||
private SkiaMenuFlyout? _openFlyout;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the hover background color.
|
||||
/// </summary>
|
||||
public SKColor HoverBackgroundColor { get; set; } = new SKColor(220, 220, 220);
|
||||
public IList<MenuBarItem> Items => _items;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the active background color.
|
||||
/// </summary>
|
||||
public SKColor ActiveBackgroundColor { get; set; } = new SKColor(200, 200, 200);
|
||||
public new SKColor BackgroundColor { get; set; } = new SKColor((byte)240, (byte)240, (byte)240);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the bar height.
|
||||
/// </summary>
|
||||
public float BarHeight { get; set; } = 28f;
|
||||
public SKColor TextColor { get; set; } = new SKColor((byte)33, (byte)33, (byte)33);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the font size.
|
||||
/// </summary>
|
||||
public float FontSize { get; set; } = 13f;
|
||||
public SKColor HoverBackgroundColor { get; set; } = new SKColor((byte)220, (byte)220, (byte)220);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item padding.
|
||||
/// </summary>
|
||||
public float ItemPadding { get; set; } = 12f;
|
||||
public SKColor ActiveBackgroundColor { get; set; } = new SKColor((byte)200, (byte)200, (byte)200);
|
||||
|
||||
protected override SKSize MeasureOverride(SKSize availableSize)
|
||||
{
|
||||
return new SKSize(availableSize.Width, BarHeight);
|
||||
}
|
||||
public float BarHeight { get; set; } = 28f;
|
||||
|
||||
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
canvas.Save();
|
||||
public float FontSize { get; set; } = 13f;
|
||||
|
||||
// Draw background
|
||||
using var bgPaint = new SKPaint
|
||||
{
|
||||
Color = BackgroundColor,
|
||||
Style = SKPaintStyle.Fill
|
||||
};
|
||||
canvas.DrawRect(Bounds, bgPaint);
|
||||
public float ItemPadding { get; set; } = 12f;
|
||||
|
||||
// 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 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 menu items
|
||||
using var textPaint = new SKPaint
|
||||
{
|
||||
Color = TextColor,
|
||||
TextSize = FontSize,
|
||||
IsAntialias = true
|
||||
};
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
float x = Bounds.Left;
|
||||
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;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
float itemWidth = textBounds.Width + ItemPadding * 2;
|
||||
var itemBounds = new SKRect(x, Bounds.Top, x + itemWidth, Bounds.Bottom);
|
||||
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);
|
||||
}
|
||||
|
||||
// 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 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 text
|
||||
float textX = x + ItemPadding;
|
||||
float textY = Bounds.MidY - textBounds.MidY;
|
||||
canvas.DrawText(item.Text, textX, textY, textPaint);
|
||||
private void CloseFlyout()
|
||||
{
|
||||
if (_openFlyout != null)
|
||||
{
|
||||
_openFlyout.ItemClicked -= OnFlyoutItemClicked;
|
||||
_openFlyout = null;
|
||||
}
|
||||
_openIndex = -1;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
private void OnFlyoutItemClicked(object? sender, MenuItemClickedEventArgs e)
|
||||
{
|
||||
CloseFlyout();
|
||||
}
|
||||
}
|
||||
|
||||
304
Views/SkiaMenuFlyout.cs
Normal file
304
Views/SkiaMenuFlyout.cs
Normal file
@@ -0,0 +1,304 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,451 +1,513 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Maui.Platform.Linux;
|
||||
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();
|
||||
private SkiaPage? _currentPage;
|
||||
private bool _isAnimating;
|
||||
private float _animationProgress;
|
||||
private SkiaPage? _incomingPage;
|
||||
private bool _isPushAnimation;
|
||||
private readonly Stack<SkiaPage> _navigationStack = new Stack<SkiaPage>();
|
||||
|
||||
// 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 SkiaPage? _currentPage;
|
||||
|
||||
public SKColor BarBackgroundColor
|
||||
{
|
||||
get => _barBackgroundColor;
|
||||
set
|
||||
{
|
||||
_barBackgroundColor = value;
|
||||
UpdatePageNavigationBar();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
private bool _isAnimating;
|
||||
|
||||
public SKColor BarTextColor
|
||||
{
|
||||
get => _barTextColor;
|
||||
set
|
||||
{
|
||||
_barTextColor = value;
|
||||
UpdatePageNavigationBar();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
private float _animationProgress;
|
||||
|
||||
public float NavigationBarHeight
|
||||
{
|
||||
get => _navigationBarHeight;
|
||||
set
|
||||
{
|
||||
_navigationBarHeight = value;
|
||||
UpdatePageNavigationBar();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
private SkiaPage? _incomingPage;
|
||||
|
||||
public SkiaPage? CurrentPage => _currentPage;
|
||||
public SkiaPage? RootPage => _navigationStack.Count > 0 ? _navigationStack.Last() : _currentPage;
|
||||
public int StackDepth => _navigationStack.Count + (_currentPage != null ? 1 : 0);
|
||||
private bool _isPushAnimation;
|
||||
|
||||
public event EventHandler<NavigationEventArgs>? Pushed;
|
||||
public event EventHandler<NavigationEventArgs>? Popped;
|
||||
public event EventHandler<NavigationEventArgs>? PoppedToRoot;
|
||||
private SKColor _barBackgroundColor = new SKColor((byte)33, (byte)150, (byte)243);
|
||||
|
||||
public SkiaNavigationPage()
|
||||
{
|
||||
}
|
||||
private SKColor _barTextColor = SKColors.White;
|
||||
|
||||
public SkiaNavigationPage(SkiaPage rootPage)
|
||||
{
|
||||
SetRootPage(rootPage);
|
||||
}
|
||||
private float _navigationBarHeight = 56f;
|
||||
|
||||
public void SetRootPage(SkiaPage page)
|
||||
{
|
||||
_navigationStack.Clear();
|
||||
_currentPage?.OnDisappearing();
|
||||
_currentPage = page;
|
||||
_currentPage.Parent = this;
|
||||
ConfigurePage(_currentPage, false);
|
||||
_currentPage.OnAppearing();
|
||||
Invalidate();
|
||||
}
|
||||
private bool _showBackButton = true;
|
||||
|
||||
public void Push(SkiaPage page, bool animated = true)
|
||||
{
|
||||
if (_isAnimating) return;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
if (_currentPage != null)
|
||||
{
|
||||
_currentPage.OnDisappearing();
|
||||
_navigationStack.Push(_currentPage);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
ConfigurePage(page, true);
|
||||
page.Parent = this;
|
||||
public float NavigationBarHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
return _navigationBarHeight;
|
||||
}
|
||||
set
|
||||
{
|
||||
_navigationBarHeight = value;
|
||||
UpdatePageNavigationBar();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
if (animated)
|
||||
{
|
||||
_incomingPage = page;
|
||||
_isPushAnimation = true;
|
||||
_animationProgress = 0;
|
||||
_isAnimating = true;
|
||||
AnimatePush();
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentPage = page;
|
||||
_currentPage.OnAppearing();
|
||||
Invalidate();
|
||||
}
|
||||
public SkiaPage? CurrentPage => _currentPage;
|
||||
|
||||
Pushed?.Invoke(this, new NavigationEventArgs(page));
|
||||
}
|
||||
public SkiaPage? RootPage
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_navigationStack.Count <= 0)
|
||||
{
|
||||
return _currentPage;
|
||||
}
|
||||
return _navigationStack.Last();
|
||||
}
|
||||
}
|
||||
|
||||
public SkiaPage? Pop(bool animated = true)
|
||||
{
|
||||
if (_isAnimating || _navigationStack.Count == 0) return null;
|
||||
public int StackDepth => _navigationStack.Count + ((_currentPage != null) ? 1 : 0);
|
||||
|
||||
var poppedPage = _currentPage;
|
||||
poppedPage?.OnDisappearing();
|
||||
public event EventHandler<NavigationEventArgs>? Pushed;
|
||||
|
||||
var previousPage = _navigationStack.Pop();
|
||||
public event EventHandler<NavigationEventArgs>? Popped;
|
||||
|
||||
if (animated && poppedPage != null)
|
||||
{
|
||||
_incomingPage = previousPage;
|
||||
_isPushAnimation = false;
|
||||
_animationProgress = 0;
|
||||
_isAnimating = true;
|
||||
AnimatePop(poppedPage);
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentPage = previousPage;
|
||||
_currentPage?.OnAppearing();
|
||||
Invalidate();
|
||||
}
|
||||
public event EventHandler<NavigationEventArgs>? PoppedToRoot;
|
||||
|
||||
if (poppedPage != null)
|
||||
{
|
||||
Popped?.Invoke(this, new NavigationEventArgs(poppedPage));
|
||||
}
|
||||
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)
|
||||
|
||||
return poppedPage;
|
||||
}
|
||||
|
||||
public void PopToRoot(bool animated = true)
|
||||
{
|
||||
if (_isAnimating || _navigationStack.Count == 0) return;
|
||||
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);
|
||||
}
|
||||
|
||||
_currentPage?.OnDisappearing();
|
||||
public void SetRootPage(SkiaPage page)
|
||||
{
|
||||
_navigationStack.Clear();
|
||||
_currentPage?.OnDisappearing();
|
||||
_currentPage = page;
|
||||
_currentPage.Parent = this;
|
||||
ConfigurePage(_currentPage, showBackButton: false);
|
||||
_currentPage.OnAppearing();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
// Get root page
|
||||
SkiaPage? rootPage = null;
|
||||
while (_navigationStack.Count > 0)
|
||||
{
|
||||
rootPage = _navigationStack.Pop();
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
if (rootPage != null)
|
||||
{
|
||||
_currentPage = rootPage;
|
||||
ConfigurePage(_currentPage, false);
|
||||
_currentPage.OnAppearing();
|
||||
Invalidate();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
PoppedToRoot?.Invoke(this, new NavigationEventArgs(_currentPage!));
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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 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 UpdatePageNavigationBar()
|
||||
{
|
||||
if (_currentPage != null)
|
||||
{
|
||||
_currentPage.TitleBarColor = _barBackgroundColor;
|
||||
_currentPage.TitleTextColor = _barTextColor;
|
||||
_currentPage.NavigationBarHeight = _navigationBarHeight;
|
||||
}
|
||||
}
|
||||
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 async void AnimatePush()
|
||||
{
|
||||
const int durationMs = 250;
|
||||
const int frameMs = 16;
|
||||
var startTime = DateTime.Now;
|
||||
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();
|
||||
}
|
||||
|
||||
while (_animationProgress < 1)
|
||||
{
|
||||
await Task.Delay(frameMs);
|
||||
var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
|
||||
_animationProgress = Math.Min(1, (float)(elapsed / durationMs));
|
||||
Invalidate();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
_currentPage = _incomingPage;
|
||||
_incomingPage = null;
|
||||
_isAnimating = false;
|
||||
_currentPage?.OnAppearing();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void AnimatePop(SkiaPage outgoingPage)
|
||||
{
|
||||
const int durationMs = 250;
|
||||
const int frameMs = 16;
|
||||
var startTime = DateTime.Now;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
while (_animationProgress < 1)
|
||||
{
|
||||
await Task.Delay(frameMs);
|
||||
var elapsed = (DateTime.Now - startTime).TotalMilliseconds;
|
||||
_animationProgress = Math.Min(1, (float)(elapsed / durationMs));
|
||||
Invalidate();
|
||||
}
|
||||
private static float EaseOutCubic(float t)
|
||||
{
|
||||
return 1f - (float)Math.Pow(1f - t, 3.0);
|
||||
}
|
||||
|
||||
_currentPage = _incomingPage;
|
||||
_incomingPage = null;
|
||||
_isAnimating = false;
|
||||
_currentPage?.OnAppearing();
|
||||
outgoingPage.Parent = null;
|
||||
Invalidate();
|
||||
}
|
||||
protected override SKSize MeasureOverride(SKSize availableSize)
|
||||
{
|
||||
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
|
||||
return availableSize;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_isAnimating && _incomingPage != null)
|
||||
{
|
||||
// Draw animation
|
||||
var eased = EaseOutCubic(_animationProgress);
|
||||
public override void OnPointerMoved(PointerEventArgs e)
|
||||
{
|
||||
if (!_isAnimating)
|
||||
{
|
||||
_currentPage?.OnPointerMoved(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 OnPointerReleased(PointerEventArgs e)
|
||||
{
|
||||
if (!_isAnimating)
|
||||
{
|
||||
_currentPage?.OnPointerReleased(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 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 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 OnKeyUp(KeyEventArgs e)
|
||||
{
|
||||
if (!_isAnimating)
|
||||
{
|
||||
_currentPage?.OnKeyUp(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw incoming page (sliding in)
|
||||
canvas.Save();
|
||||
canvas.Translate(incomingOffset, 0);
|
||||
_incomingPage.Bounds = bounds;
|
||||
_incomingPage.Draw(canvas);
|
||||
canvas.Restore();
|
||||
public override void OnScroll(ScrollEventArgs e)
|
||||
{
|
||||
if (!_isAnimating)
|
||||
{
|
||||
_currentPage?.OnScroll(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,464 +1,458 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
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 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 SkiaView? _content;
|
||||
|
||||
// Padding
|
||||
private float _paddingLeft;
|
||||
private float _paddingTop;
|
||||
private float _paddingRight;
|
||||
private float _paddingBottom;
|
||||
private string _title = "";
|
||||
|
||||
public SkiaView? Content
|
||||
{
|
||||
get => _content;
|
||||
set
|
||||
{
|
||||
if (_content != null)
|
||||
{
|
||||
_content.Parent = null;
|
||||
}
|
||||
_content = value;
|
||||
if (_content != null)
|
||||
{
|
||||
_content.Parent = this;
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
private SKColor _titleBarColor = new SKColor((byte)33, (byte)150, (byte)243);
|
||||
|
||||
public string Title
|
||||
{
|
||||
get => _title;
|
||||
set
|
||||
{
|
||||
_title = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
private SKColor _titleTextColor = SKColors.White;
|
||||
|
||||
public SKColor TitleBarColor
|
||||
{
|
||||
get => _titleBarColor;
|
||||
set
|
||||
{
|
||||
_titleBarColor = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
private bool _showNavigationBar;
|
||||
|
||||
public SKColor TitleTextColor
|
||||
{
|
||||
get => _titleTextColor;
|
||||
set
|
||||
{
|
||||
_titleTextColor = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
private float _navigationBarHeight = 56f;
|
||||
|
||||
public bool ShowNavigationBar
|
||||
{
|
||||
get => _showNavigationBar;
|
||||
set
|
||||
{
|
||||
_showNavigationBar = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
private float _paddingLeft;
|
||||
|
||||
public float NavigationBarHeight
|
||||
{
|
||||
get => _navigationBarHeight;
|
||||
set
|
||||
{
|
||||
_navigationBarHeight = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
private float _paddingTop;
|
||||
|
||||
public float PaddingLeft
|
||||
{
|
||||
get => _paddingLeft;
|
||||
set { _paddingLeft = value; Invalidate(); }
|
||||
}
|
||||
private float _paddingRight;
|
||||
|
||||
public float PaddingTop
|
||||
{
|
||||
get => _paddingTop;
|
||||
set { _paddingTop = value; Invalidate(); }
|
||||
}
|
||||
private float _paddingBottom;
|
||||
|
||||
public float PaddingRight
|
||||
{
|
||||
get => _paddingRight;
|
||||
set { _paddingRight = 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 PaddingBottom
|
||||
{
|
||||
get => _paddingBottom;
|
||||
set { _paddingBottom = value; Invalidate(); }
|
||||
}
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return _title;
|
||||
}
|
||||
set
|
||||
{
|
||||
_title = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsBusy { get; set; }
|
||||
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 event EventHandler? Appearing;
|
||||
public event EventHandler? Disappearing;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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 bool ShowNavigationBar
|
||||
{
|
||||
get
|
||||
{
|
||||
return _showNavigationBar;
|
||||
}
|
||||
set
|
||||
{
|
||||
_showNavigationBar = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
var contentTop = bounds.Top;
|
||||
public float NavigationBarHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
return _navigationBarHeight;
|
||||
}
|
||||
set
|
||||
{
|
||||
_navigationBarHeight = 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 PaddingLeft
|
||||
{
|
||||
get
|
||||
{
|
||||
return _paddingLeft;
|
||||
}
|
||||
set
|
||||
{
|
||||
_paddingLeft = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate content bounds with padding
|
||||
var contentBounds = new SKRect(
|
||||
bounds.Left + _paddingLeft,
|
||||
contentTop + _paddingTop,
|
||||
bounds.Right - _paddingRight,
|
||||
bounds.Bottom - _paddingBottom);
|
||||
public float PaddingTop
|
||||
{
|
||||
get
|
||||
{
|
||||
return _paddingTop;
|
||||
}
|
||||
set
|
||||
{
|
||||
_paddingTop = 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 PaddingRight
|
||||
{
|
||||
get
|
||||
{
|
||||
return _paddingRight;
|
||||
}
|
||||
set
|
||||
{
|
||||
_paddingRight = 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 float PaddingBottom
|
||||
{
|
||||
get
|
||||
{
|
||||
return _paddingBottom;
|
||||
}
|
||||
set
|
||||
{
|
||||
_paddingBottom = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// Draw busy indicator overlay
|
||||
if (IsBusy)
|
||||
{
|
||||
DrawBusyIndicator(canvas, bounds);
|
||||
}
|
||||
}
|
||||
public bool IsBusy { get; set; }
|
||||
|
||||
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? Appearing;
|
||||
|
||||
// Draw title
|
||||
if (!string.IsNullOrEmpty(_title))
|
||||
{
|
||||
using var font = new SKFont(SKTypeface.Default, 20);
|
||||
using var textPaint = new SKPaint(font)
|
||||
{
|
||||
Color = _titleTextColor,
|
||||
IsAntialias = true
|
||||
};
|
||||
public event EventHandler? Disappearing;
|
||||
|
||||
var textBounds = new SKRect();
|
||||
textPaint.MeasureText(_title, ref textBounds);
|
||||
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 x = bounds.Left + 16;
|
||||
var y = bounds.MidY - textBounds.MidY;
|
||||
canvas.DrawText(_title, x, y, textPaint);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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();
|
||||
}
|
||||
}
|
||||
|
||||
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 OnAppearing()
|
||||
{
|
||||
Console.WriteLine($"[SkiaPage] OnAppearing called for: {Title}, HasListeners={this.Appearing != null}");
|
||||
this.Appearing?.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
|
||||
};
|
||||
public void OnDisappearing()
|
||||
{
|
||||
this.Disappearing?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
var centerX = bounds.MidX;
|
||||
var centerY = bounds.MidY;
|
||||
var radius = 20f;
|
||||
protected override SKSize MeasureOverride(SKSize availableSize)
|
||||
{
|
||||
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
|
||||
return availableSize;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnAppearing()
|
||||
{
|
||||
Console.WriteLine($"[SkiaPage] OnAppearing called for: {Title}, HasListeners={Appearing != null}");
|
||||
Appearing?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
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 OnDisappearing()
|
||||
{
|
||||
Disappearing?.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);
|
||||
}
|
||||
}
|
||||
|
||||
protected override SKSize MeasureOverride(SKSize availableSize)
|
||||
{
|
||||
// Page takes all available space
|
||||
return availableSize;
|
||||
}
|
||||
public override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
_content?.OnKeyDown(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 OnKeyUp(KeyEventArgs e)
|
||||
{
|
||||
_content?.OnKeyUp(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 void OnScroll(ScrollEventArgs e)
|
||||
{
|
||||
_content?.OnScroll(e);
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
1444
Views/SkiaPicker.cs
1444
Views/SkiaPicker.cs
File diff suppressed because it is too large
Load Diff
@@ -1,205 +1,192 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using Microsoft.Maui.Controls;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
/// <summary>
|
||||
/// Skia-rendered progress bar control with full XAML styling support.
|
||||
/// </summary>
|
||||
public class SkiaProgressBar : SkiaView
|
||||
{
|
||||
#region BindableProperties
|
||||
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);
|
||||
|
||||
/// <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 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 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 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 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 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 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 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 BarHeight.
|
||||
/// </summary>
|
||||
public static readonly BindableProperty BarHeightProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(BarHeight),
|
||||
typeof(float),
|
||||
typeof(SkiaProgressBar),
|
||||
4f,
|
||||
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).InvalidateMeasure());
|
||||
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 CornerRadius.
|
||||
/// </summary>
|
||||
public static readonly BindableProperty CornerRadiusProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(CornerRadius),
|
||||
typeof(float),
|
||||
typeof(SkiaProgressBar),
|
||||
2f,
|
||||
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate());
|
||||
public double Progress
|
||||
{
|
||||
get
|
||||
{
|
||||
return (double)((BindableObject)this).GetValue(ProgressProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(ProgressProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#region Properties
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 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 track color.
|
||||
/// </summary>
|
||||
public SKColor TrackColor
|
||||
{
|
||||
get => (SKColor)GetValue(TrackColorProperty);
|
||||
set => SetValue(TrackColorProperty, value);
|
||||
}
|
||||
public float BarHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(BarHeightProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(BarHeightProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the progress color.
|
||||
/// </summary>
|
||||
public SKColor ProgressColor
|
||||
{
|
||||
get => (SKColor)GetValue(ProgressColorProperty);
|
||||
set => SetValue(ProgressColorProperty, 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 event EventHandler<ProgressChangedEventArgs>? ProgressChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the bar height.
|
||||
/// </summary>
|
||||
public float BarHeight
|
||||
{
|
||||
get => (float)GetValue(BarHeightProperty);
|
||||
set => SetValue(BarHeightProperty, value);
|
||||
}
|
||||
private void OnProgressChanged()
|
||||
{
|
||||
this.ProgressChanged?.Invoke(this, new ProgressChangedEventArgs(Progress));
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the corner radius.
|
||||
/// </summary>
|
||||
public float CornerRadius
|
||||
{
|
||||
get => (float)GetValue(CornerRadiusProperty);
|
||||
set => SetValue(CornerRadiusProperty, 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();
|
||||
}
|
||||
}
|
||||
|
||||
#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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,284 +1,442 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Maui.Controls;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
/// <summary>
|
||||
/// Skia-rendered radio button control with full XAML styling support.
|
||||
/// </summary>
|
||||
public class SkiaRadioButton : SkiaView
|
||||
{
|
||||
#region BindableProperties
|
||||
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);
|
||||
|
||||
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 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 ContentProperty =
|
||||
BindableProperty.Create(nameof(Content), typeof(string), typeof(SkiaRadioButton), "",
|
||||
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).InvalidateMeasure());
|
||||
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 ValueProperty =
|
||||
BindableProperty.Create(nameof(Value), typeof(object), typeof(SkiaRadioButton), null);
|
||||
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 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 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 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 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 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 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 TextColorProperty =
|
||||
BindableProperty.Create(nameof(TextColor), typeof(SKColor), typeof(SkiaRadioButton), SKColors.Black,
|
||||
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 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 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 FontSizeProperty =
|
||||
BindableProperty.Create(nameof(FontSize), typeof(float), typeof(SkiaRadioButton), 14f,
|
||||
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).InvalidateMeasure());
|
||||
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 RadioSizeProperty =
|
||||
BindableProperty.Create(nameof(RadioSize), typeof(float), typeof(SkiaRadioButton), 20f,
|
||||
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 SpacingProperty =
|
||||
BindableProperty.Create(nameof(Spacing), typeof(float), typeof(SkiaRadioButton), 8f,
|
||||
propertyChanged: (b, o, n) => ((SkiaRadioButton)b).InvalidateMeasure());
|
||||
private static readonly Dictionary<string, List<WeakReference<SkiaRadioButton>>> _groups = new Dictionary<string, List<WeakReference<SkiaRadioButton>>>();
|
||||
|
||||
#endregion
|
||||
public bool IsChecked
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)((BindableObject)this).GetValue(IsCheckedProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(IsCheckedProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
#region Properties
|
||||
public string Content
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)((BindableObject)this).GetValue(ContentProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(ContentProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsChecked
|
||||
{
|
||||
get => (bool)GetValue(IsCheckedProperty);
|
||||
set => SetValue(IsCheckedProperty, value);
|
||||
}
|
||||
public object? Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return ((BindableObject)this).GetValue(ValueProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(ValueProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
public string Content
|
||||
{
|
||||
get => (string)GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
public string? GroupName
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)((BindableObject)this).GetValue(GroupNameProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(GroupNameProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public object? Value
|
||||
{
|
||||
get => GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, 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 string? GroupName
|
||||
{
|
||||
get => (string?)GetValue(GroupNameProperty);
|
||||
set => SetValue(GroupNameProperty, 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 SKColor RadioColor
|
||||
{
|
||||
get => (SKColor)GetValue(RadioColorProperty);
|
||||
set => SetValue(RadioColorProperty, 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 UncheckedColor
|
||||
{
|
||||
get => (SKColor)GetValue(UncheckedColorProperty);
|
||||
set => SetValue(UncheckedColorProperty, 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 TextColor
|
||||
{
|
||||
get => (SKColor)GetValue(TextColorProperty);
|
||||
set => SetValue(TextColorProperty, value);
|
||||
}
|
||||
public float FontSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(FontSizeProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(FontSizeProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public SKColor DisabledColor
|
||||
{
|
||||
get => (SKColor)GetValue(DisabledColorProperty);
|
||||
set => SetValue(DisabledColorProperty, value);
|
||||
}
|
||||
public float RadioSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(RadioSizeProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(RadioSizeProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public float FontSize
|
||||
{
|
||||
get => (float)GetValue(FontSizeProperty);
|
||||
set => SetValue(FontSizeProperty, value);
|
||||
}
|
||||
public float Spacing
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(SpacingProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(SpacingProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public float RadioSize
|
||||
{
|
||||
get => (float)GetValue(RadioSizeProperty);
|
||||
set => SetValue(RadioSizeProperty, value);
|
||||
}
|
||||
public event EventHandler? CheckedChanged;
|
||||
|
||||
public float Spacing
|
||||
{
|
||||
get => (float)GetValue(SpacingProperty);
|
||||
set => SetValue(SpacingProperty, value);
|
||||
}
|
||||
public SkiaRadioButton()
|
||||
{
|
||||
base.IsFocusable = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
private void OnIsCheckedChanged()
|
||||
{
|
||||
if (IsChecked && !string.IsNullOrEmpty(GroupName))
|
||||
{
|
||||
UncheckOthersInGroup();
|
||||
}
|
||||
this.CheckedChanged?.Invoke(this, EventArgs.Empty);
|
||||
SkiaVisualStateManager.GoToState(this, IsChecked ? "Checked" : "Unchecked");
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, List<WeakReference<SkiaRadioButton>>> _groups = new();
|
||||
private void OnGroupNameChanged(string? oldValue, string? newValue)
|
||||
{
|
||||
RemoveFromGroup(oldValue);
|
||||
AddToGroup(newValue);
|
||||
}
|
||||
|
||||
public event EventHandler? CheckedChanged;
|
||||
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 SkiaRadioButton()
|
||||
{
|
||||
IsFocusable = true;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
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 OnGroupNameChanged(string? oldValue, string? newValue)
|
||||
{
|
||||
RemoveFromGroup(oldValue);
|
||||
AddToGroup(newValue);
|
||||
}
|
||||
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 AddToGroup(string? groupName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(groupName)) return;
|
||||
public override void OnPointerPressed(PointerEventArgs e)
|
||||
{
|
||||
if (base.IsEnabled && !IsChecked)
|
||||
{
|
||||
IsChecked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_groups.TryGetValue(groupName, out var group))
|
||||
{
|
||||
group = new List<WeakReference<SkiaRadioButton>>();
|
||||
_groups[groupName] = group;
|
||||
}
|
||||
public override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
if (base.IsEnabled && (e.Key == Key.Space || e.Key == Key.Enter))
|
||||
{
|
||||
if (!IsChecked)
|
||||
{
|
||||
IsChecked = true;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
group.RemoveAll(wr => !wr.TryGetTarget(out _));
|
||||
group.Add(new WeakReference<SkiaRadioButton>(this));
|
||||
}
|
||||
protected override void OnEnabledChanged()
|
||||
{
|
||||
base.OnEnabledChanged();
|
||||
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,278 +1,315 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
/// <summary>
|
||||
/// A pull-to-refresh container view.
|
||||
/// </summary>
|
||||
public class SkiaRefreshView : SkiaLayoutView
|
||||
{
|
||||
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 SkiaView? _content;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content view.
|
||||
/// </summary>
|
||||
public SkiaView? Content
|
||||
{
|
||||
get => _content;
|
||||
set
|
||||
{
|
||||
if (_content != value)
|
||||
{
|
||||
if (_content != null)
|
||||
{
|
||||
RemoveChild(_content);
|
||||
}
|
||||
private bool _isRefreshing;
|
||||
|
||||
_content = value;
|
||||
private float _pullDistance;
|
||||
|
||||
if (_content != null)
|
||||
{
|
||||
AddChild(_content);
|
||||
}
|
||||
private float _refreshThreshold = 80f;
|
||||
|
||||
InvalidateMeasure();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
private bool _isPulling;
|
||||
|
||||
/// <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 _pullStartY;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pull distance required to trigger refresh.
|
||||
/// </summary>
|
||||
public float RefreshThreshold
|
||||
{
|
||||
get => _refreshThreshold;
|
||||
set => _refreshThreshold = Math.Max(40, value);
|
||||
}
|
||||
private float _spinnerRotation;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the refresh indicator color.
|
||||
/// </summary>
|
||||
public SKColor RefreshColor { get; set; } = new SKColor(33, 150, 243);
|
||||
private DateTime _lastSpinnerUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the background color of the refresh indicator.
|
||||
/// </summary>
|
||||
public SKColor RefreshBackgroundColor { get; set; } = SKColors.White;
|
||||
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>
|
||||
/// Event raised when refresh is triggered.
|
||||
/// </summary>
|
||||
public event EventHandler? Refreshing;
|
||||
public bool IsRefreshing
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isRefreshing;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_isRefreshing != value)
|
||||
{
|
||||
_isRefreshing = value;
|
||||
if (!value)
|
||||
{
|
||||
_pullDistance = 0f;
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override SKSize MeasureOverride(SKSize availableSize)
|
||||
{
|
||||
if (_content != null)
|
||||
{
|
||||
_content.Measure(availableSize);
|
||||
}
|
||||
return availableSize;
|
||||
}
|
||||
public float RefreshThreshold
|
||||
{
|
||||
get
|
||||
{
|
||||
return _refreshThreshold;
|
||||
}
|
||||
set
|
||||
{
|
||||
_refreshThreshold = Math.Max(40f, value);
|
||||
}
|
||||
}
|
||||
|
||||
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 RefreshColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
|
||||
|
||||
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
canvas.Save();
|
||||
canvas.ClipRect(bounds);
|
||||
public SKColor RefreshBackgroundColor { get; set; } = SKColors.White;
|
||||
|
||||
// Draw refresh indicator
|
||||
float indicatorY = bounds.Top + (_isRefreshing ? _refreshThreshold : _pullDistance) / 2;
|
||||
public ICommand? Command { get; set; }
|
||||
|
||||
if (_pullDistance > 0 || _isRefreshing)
|
||||
{
|
||||
DrawRefreshIndicator(canvas, bounds.MidX, indicatorY);
|
||||
}
|
||||
public object? CommandParameter { get; set; }
|
||||
|
||||
// Draw content
|
||||
_content?.Draw(canvas);
|
||||
public event EventHandler? Refreshing;
|
||||
|
||||
canvas.Restore();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
private void DrawRefreshIndicator(SKCanvas canvas, float x, float y)
|
||||
{
|
||||
float size = 36f;
|
||||
float progress = Math.Clamp(_pullDistance / _refreshThreshold, 0f, 1f);
|
||||
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;
|
||||
}
|
||||
|
||||
// Draw background circle
|
||||
using var bgPaint = new SKPaint
|
||||
{
|
||||
Color = RefreshBackgroundColor,
|
||||
Style = SKPaintStyle.Fill,
|
||||
IsAntialias = true
|
||||
};
|
||||
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();
|
||||
}
|
||||
|
||||
// Add shadow
|
||||
bgPaint.ImageFilter = SKImageFilter.CreateDropShadow(0, 2, 4, 4, new SKColor(0, 0, 0, 40));
|
||||
canvas.DrawCircle(x, y, size / 2, bgPaint);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// Draw spinner
|
||||
using var spinnerPaint = new SKPaint
|
||||
{
|
||||
Color = RefreshColor,
|
||||
Style = SKPaintStyle.Stroke,
|
||||
StrokeWidth = 3,
|
||||
IsAntialias = true,
|
||||
StrokeCap = SKStrokeCap.Round
|
||||
};
|
||||
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;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
canvas.Save();
|
||||
canvas.Translate(x, y);
|
||||
canvas.RotateDegrees(_spinnerRotation);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,242 +1,356 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
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 bool _showClearButton;
|
||||
private readonly SkiaEntry _entry;
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => _entry.Text;
|
||||
set => _entry.Text = value;
|
||||
}
|
||||
private bool _showClearButton;
|
||||
|
||||
public string Placeholder
|
||||
{
|
||||
get => _entry.Placeholder;
|
||||
set => _entry.Placeholder = value;
|
||||
}
|
||||
public string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
return _entry.Text;
|
||||
}
|
||||
set
|
||||
{
|
||||
_entry.Text = value;
|
||||
}
|
||||
}
|
||||
|
||||
public SKColor TextColor
|
||||
{
|
||||
get => _entry.TextColor;
|
||||
set => _entry.TextColor = value;
|
||||
}
|
||||
public string Placeholder
|
||||
{
|
||||
get
|
||||
{
|
||||
return _entry.Placeholder;
|
||||
}
|
||||
set
|
||||
{
|
||||
_entry.Placeholder = value;
|
||||
}
|
||||
}
|
||||
|
||||
public SKColor PlaceholderColor
|
||||
{
|
||||
get => _entry.PlaceholderColor;
|
||||
set => _entry.PlaceholderColor = 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 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 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 event EventHandler<TextChangedEventArgs>? TextChanged;
|
||||
public event EventHandler? SearchButtonPressed;
|
||||
public new SKColor BackgroundColor { get; set; } = new SKColor((byte)245, (byte)245, (byte)245);
|
||||
|
||||
public SkiaSearchBar()
|
||||
{
|
||||
_entry = new SkiaEntry
|
||||
{
|
||||
Placeholder = "Search...",
|
||||
EntryBackgroundColor = SKColors.Transparent,
|
||||
BackgroundColor = SKColors.Transparent,
|
||||
BorderColor = SKColors.Transparent,
|
||||
FocusedBorderColor = SKColors.Transparent,
|
||||
BorderWidth = 0
|
||||
};
|
||||
public SKColor IconColor { get; set; } = new SKColor((byte)117, (byte)117, (byte)117);
|
||||
|
||||
_entry.TextChanged += (s, e) =>
|
||||
{
|
||||
_showClearButton = !string.IsNullOrEmpty(e.NewTextValue);
|
||||
TextChanged?.Invoke(this, e);
|
||||
Invalidate();
|
||||
};
|
||||
public SKColor ClearButtonColor { get; set; } = new SKColor((byte)158, (byte)158, (byte)158);
|
||||
|
||||
_entry.Completed += (s, e) => SearchButtonPressed?.Invoke(this, EventArgs.Empty);
|
||||
public SKColor FocusedBorderColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
|
||||
|
||||
IsFocusable = true;
|
||||
}
|
||||
public string FontFamily { get; set; } = "Sans";
|
||||
|
||||
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
var iconPadding = 12f;
|
||||
var clearButtonSize = 20f;
|
||||
public float FontSize { get; set; } = 14f;
|
||||
|
||||
// Draw background
|
||||
using var bgPaint = new SKPaint
|
||||
{
|
||||
Color = BackgroundColor,
|
||||
IsAntialias = true,
|
||||
Style = SKPaintStyle.Fill
|
||||
};
|
||||
public float CornerRadius { get; set; } = 8f;
|
||||
|
||||
var bgRect = new SKRoundRect(bounds, CornerRadius);
|
||||
canvas.DrawRoundRect(bgRect, bgPaint);
|
||||
public float IconSize { get; set; } = 20f;
|
||||
|
||||
// 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<TextChangedEventArgs>? TextChanged;
|
||||
|
||||
// Draw search icon
|
||||
var iconX = bounds.Left + iconPadding;
|
||||
var iconY = bounds.MidY;
|
||||
DrawSearchIcon(canvas, iconX, iconY, IconSize);
|
||||
public event EventHandler? SearchButtonPressed;
|
||||
|
||||
// Calculate entry bounds - leave space for clear button
|
||||
var entryLeft = iconX + IconSize + iconPadding;
|
||||
var entryRight = _showClearButton
|
||||
? bounds.Right - clearButtonSize - iconPadding * 2
|
||||
: bounds.Right - iconPadding;
|
||||
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;
|
||||
}
|
||||
|
||||
var entryBounds = new SKRect(entryLeft, bounds.Top, entryRight, bounds.Bottom);
|
||||
_entry.Arrange(entryBounds);
|
||||
_entry.Draw(canvas);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// Draw clear button
|
||||
if (_showClearButton)
|
||||
{
|
||||
var clearX = bounds.Right - iconPadding - clearButtonSize / 2;
|
||||
var clearY = bounds.MidY;
|
||||
DrawClearButton(canvas, clearX, clearY, clearButtonSize / 2);
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
var circleRadius = size * 0.35f;
|
||||
var circleCenter = new SKPoint(x + circleRadius, y - circleRadius * 0.3f);
|
||||
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();
|
||||
}
|
||||
|
||||
// Draw magnifying glass circle
|
||||
canvas.DrawCircle(circleCenter, circleRadius, paint);
|
||||
public override void OnPointerMoved(PointerEventArgs e)
|
||||
{
|
||||
if (base.IsEnabled)
|
||||
{
|
||||
_entry.OnPointerMoved(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 OnPointerReleased(PointerEventArgs e)
|
||||
{
|
||||
_entry.OnPointerReleased(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 OnTextInput(TextInputEventArgs e)
|
||||
{
|
||||
_entry.OnTextInput(e);
|
||||
}
|
||||
|
||||
// Draw X
|
||||
using var paint = new SKPaint
|
||||
{
|
||||
Color = ClearButtonColor,
|
||||
IsAntialias = true,
|
||||
Style = SKPaintStyle.Stroke,
|
||||
StrokeWidth = 2,
|
||||
StrokeCap = SKStrokeCap.Round
|
||||
};
|
||||
public override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Escape && _showClearButton)
|
||||
{
|
||||
Text = "";
|
||||
e.Handled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_entry.OnKeyDown(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);
|
||||
}
|
||||
public override void OnKeyUp(KeyEventArgs e)
|
||||
{
|
||||
_entry.OnKeyUp(e);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
8
Views/SkiaSelectionMode.cs
Normal file
8
Views/SkiaSelectionMode.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
public enum SkiaSelectionMode
|
||||
{
|
||||
None,
|
||||
Single,
|
||||
Multiple
|
||||
}
|
||||
2229
Views/SkiaShell.cs
2229
Views/SkiaShell.cs
File diff suppressed because it is too large
Load Diff
@@ -1,398 +1,415 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using Microsoft.Maui.Controls;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
/// <summary>
|
||||
/// Skia-rendered slider control with full XAML styling support.
|
||||
/// </summary>
|
||||
public class SkiaSlider : SkiaView
|
||||
{
|
||||
#region BindableProperties
|
||||
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);
|
||||
|
||||
/// <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 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 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 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 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 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 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 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 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 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 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 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 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 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 TrackHeight.
|
||||
/// </summary>
|
||||
public static readonly BindableProperty TrackHeightProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(TrackHeight),
|
||||
typeof(float),
|
||||
typeof(SkiaSlider),
|
||||
4f,
|
||||
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 ThumbRadius.
|
||||
/// </summary>
|
||||
public static readonly BindableProperty ThumbRadiusProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(ThumbRadius),
|
||||
typeof(float),
|
||||
typeof(SkiaSlider),
|
||||
10f,
|
||||
propertyChanged: (b, o, n) => ((SkiaSlider)b).InvalidateMeasure());
|
||||
private bool _isDragging;
|
||||
|
||||
#endregion
|
||||
public double Minimum
|
||||
{
|
||||
get
|
||||
{
|
||||
return (double)((BindableObject)this).GetValue(MinimumProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(MinimumProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
#region Properties
|
||||
public double Maximum
|
||||
{
|
||||
get
|
||||
{
|
||||
return (double)((BindableObject)this).GetValue(MaximumProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(MaximumProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum value.
|
||||
/// </summary>
|
||||
public double Minimum
|
||||
{
|
||||
get => (double)GetValue(MinimumProperty);
|
||||
set => SetValue(MinimumProperty, value);
|
||||
}
|
||||
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 maximum value.
|
||||
/// </summary>
|
||||
public double Maximum
|
||||
{
|
||||
get => (double)GetValue(MaximumProperty);
|
||||
set => SetValue(MaximumProperty, 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 current value.
|
||||
/// </summary>
|
||||
public double Value
|
||||
{
|
||||
get => (double)GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, Math.Clamp(value, Minimum, Maximum));
|
||||
}
|
||||
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 track color.
|
||||
/// </summary>
|
||||
public SKColor TrackColor
|
||||
{
|
||||
get => (SKColor)GetValue(TrackColorProperty);
|
||||
set => SetValue(TrackColorProperty, 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 active track color.
|
||||
/// </summary>
|
||||
public SKColor ActiveTrackColor
|
||||
{
|
||||
get => (SKColor)GetValue(ActiveTrackColorProperty);
|
||||
set => SetValue(ActiveTrackColorProperty, 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 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 height.
|
||||
/// </summary>
|
||||
public float TrackHeight
|
||||
{
|
||||
get => (float)GetValue(TrackHeightProperty);
|
||||
set => SetValue(TrackHeightProperty, value);
|
||||
}
|
||||
public event EventHandler<SliderValueChangedEventArgs>? ValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the thumb radius.
|
||||
/// </summary>
|
||||
public float ThumbRadius
|
||||
{
|
||||
get => (float)GetValue(ThumbRadiusProperty);
|
||||
set => SetValue(ThumbRadiusProperty, value);
|
||||
}
|
||||
public event EventHandler? DragStarted;
|
||||
|
||||
#endregion
|
||||
public event EventHandler? DragCompleted;
|
||||
|
||||
private bool _isDragging;
|
||||
public SkiaSlider()
|
||||
{
|
||||
base.IsFocusable = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when the value changes.
|
||||
/// </summary>
|
||||
public event EventHandler<SliderValueChangedEventArgs>? ValueChanged;
|
||||
private void OnRangeChanged()
|
||||
{
|
||||
double num = Math.Clamp(Value, Minimum, Maximum);
|
||||
if (Value != num)
|
||||
{
|
||||
Value = num;
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when drag starts.
|
||||
/// </summary>
|
||||
public event EventHandler? DragStarted;
|
||||
private void OnValuePropertyChanged(double oldValue, double newValue)
|
||||
{
|
||||
this.ValueChanged?.Invoke(this, new SliderValueChangedEventArgs(newValue));
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when drag completes.
|
||||
/// </summary>
|
||||
public event EventHandler? DragCompleted;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
public SkiaSlider()
|
||||
{
|
||||
IsFocusable = true;
|
||||
}
|
||||
public override void OnPointerPressed(PointerEventArgs e)
|
||||
{
|
||||
if (base.IsEnabled)
|
||||
{
|
||||
_isDragging = true;
|
||||
UpdateValueFromPosition(e.X);
|
||||
this.DragStarted?.Invoke(this, EventArgs.Empty);
|
||||
SkiaVisualStateManager.GoToState(this, "Pressed");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRangeChanged()
|
||||
{
|
||||
// Clamp value to new range
|
||||
var clamped = Math.Clamp(Value, Minimum, Maximum);
|
||||
if (Value != clamped)
|
||||
{
|
||||
Value = clamped;
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
public override void OnPointerMoved(PointerEventArgs e)
|
||||
{
|
||||
if (base.IsEnabled && _isDragging)
|
||||
{
|
||||
UpdateValueFromPosition(e.X);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnValuePropertyChanged(double oldValue, double newValue)
|
||||
{
|
||||
ValueChanged?.Invoke(this, new SliderValueChangedEventArgs(newValue));
|
||||
Invalidate();
|
||||
}
|
||||
public override void OnPointerReleased(PointerEventArgs e)
|
||||
{
|
||||
if (_isDragging)
|
||||
{
|
||||
_isDragging = false;
|
||||
this.DragCompleted?.Invoke(this, EventArgs.Empty);
|
||||
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
var percentage = Maximum > Minimum ? (Value - Minimum) / (Maximum - Minimum) : 0;
|
||||
var thumbX = trackLeft + (float)(percentage * trackWidth);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw inactive track
|
||||
using var inactiveTrackPaint = new SKPaint
|
||||
{
|
||||
Color = IsEnabled ? TrackColor : DisabledColor,
|
||||
IsAntialias = true,
|
||||
Style = SKPaintStyle.Fill
|
||||
};
|
||||
protected override void OnEnabledChanged()
|
||||
{
|
||||
base.OnEnabledChanged();
|
||||
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
213
Views/SkiaStackLayout.cs
Normal file
213
Views/SkiaStackLayout.cs
Normal file
@@ -0,0 +1,213 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,261 +1,439 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using Microsoft.Maui.Controls;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
/// <summary>
|
||||
/// Skia-rendered stepper control with increment/decrement buttons.
|
||||
/// </summary>
|
||||
public class SkiaStepper : SkiaView
|
||||
{
|
||||
#region BindableProperties
|
||||
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);
|
||||
|
||||
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 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 MinimumProperty =
|
||||
BindableProperty.Create(nameof(Minimum), typeof(double), typeof(SkiaStepper), 0.0,
|
||||
propertyChanged: (b, o, n) => ((SkiaStepper)b).OnRangeChanged());
|
||||
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 MaximumProperty =
|
||||
BindableProperty.Create(nameof(Maximum), typeof(double), typeof(SkiaStepper), 100.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 IncrementProperty =
|
||||
BindableProperty.Create(nameof(Increment), typeof(double), typeof(SkiaStepper), 1.0);
|
||||
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 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 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 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 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 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 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 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 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 SymbolColorProperty =
|
||||
BindableProperty.Create(nameof(SymbolColor), typeof(SKColor), typeof(SkiaStepper), SKColors.Black,
|
||||
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 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 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 CornerRadiusProperty =
|
||||
BindableProperty.Create(nameof(CornerRadius), typeof(float), typeof(SkiaStepper), 4f,
|
||||
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 ButtonWidthProperty =
|
||||
BindableProperty.Create(nameof(ButtonWidth), typeof(float), typeof(SkiaStepper), 40f,
|
||||
propertyChanged: (b, o, n) => ((SkiaStepper)b).InvalidateMeasure());
|
||||
private bool _isMinusPressed;
|
||||
|
||||
#endregion
|
||||
private bool _isPlusPressed;
|
||||
|
||||
#region Properties
|
||||
public double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return (double)((BindableObject)this).GetValue(ValueProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(ValueProperty, (object)Math.Clamp(value, Minimum, Maximum));
|
||||
}
|
||||
}
|
||||
|
||||
public double Value
|
||||
{
|
||||
get => (double)GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, Math.Clamp(value, Minimum, Maximum));
|
||||
}
|
||||
public double Minimum
|
||||
{
|
||||
get
|
||||
{
|
||||
return (double)((BindableObject)this).GetValue(MinimumProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(MinimumProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public double Minimum
|
||||
{
|
||||
get => (double)GetValue(MinimumProperty);
|
||||
set => SetValue(MinimumProperty, value);
|
||||
}
|
||||
public double Maximum
|
||||
{
|
||||
get
|
||||
{
|
||||
return (double)((BindableObject)this).GetValue(MaximumProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(MaximumProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public double Maximum
|
||||
{
|
||||
get => (double)GetValue(MaximumProperty);
|
||||
set => SetValue(MaximumProperty, value);
|
||||
}
|
||||
public double Increment
|
||||
{
|
||||
get
|
||||
{
|
||||
return (double)((BindableObject)this).GetValue(IncrementProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(IncrementProperty, (object)Math.Max(0.001, value));
|
||||
}
|
||||
}
|
||||
|
||||
public double Increment
|
||||
{
|
||||
get => (double)GetValue(IncrementProperty);
|
||||
set => SetValue(IncrementProperty, Math.Max(0.001, 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 SKColor ButtonBackgroundColor
|
||||
{
|
||||
get => (SKColor)GetValue(ButtonBackgroundColorProperty);
|
||||
set => SetValue(ButtonBackgroundColorProperty, 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 ButtonPressedColor
|
||||
{
|
||||
get => (SKColor)GetValue(ButtonPressedColorProperty);
|
||||
set => SetValue(ButtonPressedColorProperty, 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 ButtonDisabledColor
|
||||
{
|
||||
get => (SKColor)GetValue(ButtonDisabledColorProperty);
|
||||
set => SetValue(ButtonDisabledColorProperty, 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 BorderColor
|
||||
{
|
||||
get => (SKColor)GetValue(BorderColorProperty);
|
||||
set => SetValue(BorderColorProperty, 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 SymbolColor
|
||||
{
|
||||
get => (SKColor)GetValue(SymbolColorProperty);
|
||||
set => SetValue(SymbolColorProperty, 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 SymbolDisabledColor
|
||||
{
|
||||
get => (SKColor)GetValue(SymbolDisabledColorProperty);
|
||||
set => SetValue(SymbolDisabledColorProperty, 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);
|
||||
}
|
||||
public float ButtonWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(ButtonWidthProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(ButtonWidthProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
public float ButtonWidth
|
||||
{
|
||||
get => (float)GetValue(ButtonWidthProperty);
|
||||
set => SetValue(ButtonWidthProperty, value);
|
||||
}
|
||||
public event EventHandler? ValueChanged;
|
||||
|
||||
#endregion
|
||||
public SkiaStepper()
|
||||
{
|
||||
base.IsFocusable = true;
|
||||
}
|
||||
|
||||
private bool _isMinusPressed;
|
||||
private bool _isPlusPressed;
|
||||
private void OnValuePropertyChanged(double oldValue, double newValue)
|
||||
{
|
||||
this.ValueChanged?.Invoke(this, EventArgs.Empty);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
public event EventHandler? ValueChanged;
|
||||
private void OnRangeChanged()
|
||||
{
|
||||
double num = Math.Clamp(Value, Minimum, Maximum);
|
||||
if (Value != num)
|
||||
{
|
||||
Value = num;
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
public SkiaStepper()
|
||||
{
|
||||
IsFocusable = true;
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnValuePropertyChanged(double oldValue, double newValue)
|
||||
{
|
||||
ValueChanged?.Invoke(this, EventArgs.Empty);
|
||||
Invalidate();
|
||||
}
|
||||
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 OnRangeChanged()
|
||||
{
|
||||
var clamped = Math.Clamp(Value, Minimum, Maximum);
|
||||
if (Value != clamped)
|
||||
{
|
||||
Value = clamped;
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
private bool CanIncrement()
|
||||
{
|
||||
if (base.IsEnabled)
|
||||
{
|
||||
return Value < Maximum;
|
||||
}
|
||||
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);
|
||||
private bool CanDecrement()
|
||||
{
|
||||
if (base.IsEnabled)
|
||||
{
|
||||
return Value > Minimum;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DrawButton(canvas, minusRect, "-", _isMinusPressed, !CanDecrement());
|
||||
DrawButton(canvas, plusRect, "+", _isPlusPressed, !CanIncrement());
|
||||
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();
|
||||
}
|
||||
|
||||
using var borderPaint = new SKPaint
|
||||
{
|
||||
Color = BorderColor,
|
||||
Style = SKPaintStyle.Stroke,
|
||||
StrokeWidth = 1,
|
||||
IsAntialias = true
|
||||
};
|
||||
public override void OnPointerReleased(PointerEventArgs e)
|
||||
{
|
||||
_isMinusPressed = false;
|
||||
_isPlusPressed = false;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
var totalRect = new SKRect(bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
|
||||
canvas.DrawRoundRect(new SKRoundRect(totalRect, CornerRadius), borderPaint);
|
||||
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 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,469 +1,375 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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 readonly List<SwipeItem> _leftItems = new();
|
||||
private readonly List<SwipeItem> _rightItems = new();
|
||||
private readonly List<SwipeItem> _topItems = new();
|
||||
private readonly List<SwipeItem> _bottomItems = new();
|
||||
private SkiaView? _content;
|
||||
|
||||
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> _leftItems = 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> _rightItems = 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> _topItems = new List<SwipeItem>();
|
||||
|
||||
_content = value;
|
||||
private readonly List<SwipeItem> _bottomItems = new List<SwipeItem>();
|
||||
|
||||
if (_content != null)
|
||||
{
|
||||
AddChild(_content);
|
||||
}
|
||||
private float _swipeOffset;
|
||||
|
||||
InvalidateMeasure();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
private SwipeDirection _activeDirection;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the left swipe items.
|
||||
/// </summary>
|
||||
public IList<SwipeItem> LeftItems => _leftItems;
|
||||
private bool _isSwiping;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the right swipe items.
|
||||
/// </summary>
|
||||
public IList<SwipeItem> RightItems => _rightItems;
|
||||
private float _swipeStartX;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the top swipe items.
|
||||
/// </summary>
|
||||
public IList<SwipeItem> TopItems => _topItems;
|
||||
private float _swipeStartY;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bottom swipe items.
|
||||
/// </summary>
|
||||
public IList<SwipeItem> BottomItems => _bottomItems;
|
||||
private float _swipeStartOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the swipe mode.
|
||||
/// </summary>
|
||||
public SwipeMode Mode { get; set; } = SwipeMode.Reveal;
|
||||
private bool _isOpen;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the left swipe threshold.
|
||||
/// </summary>
|
||||
public float LeftSwipeThreshold { get; set; } = 100f;
|
||||
private const float SwipeThreshold = 60f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the right swipe threshold.
|
||||
/// </summary>
|
||||
public float RightSwipeThreshold { get; set; } = 100f;
|
||||
private const float VelocityThreshold = 500f;
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when swipe is started.
|
||||
/// </summary>
|
||||
public event EventHandler<SwipeStartedEventArgs>? SwipeStarted;
|
||||
private float _velocity;
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when swipe ends.
|
||||
/// </summary>
|
||||
public event EventHandler<SwipeEndedEventArgs>? SwipeEnded;
|
||||
private DateTime _lastMoveTime;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the swipe view in the specified direction.
|
||||
/// </summary>
|
||||
public void Open(SwipeDirection direction)
|
||||
{
|
||||
_activeDirection = direction;
|
||||
_isOpen = true;
|
||||
private float _lastMovePosition;
|
||||
|
||||
float targetOffset = direction switch
|
||||
{
|
||||
SwipeDirection.Left => -RightSwipeThreshold,
|
||||
SwipeDirection.Right => LeftSwipeThreshold,
|
||||
_ => 0
|
||||
};
|
||||
public SkiaView? Content
|
||||
{
|
||||
get
|
||||
{
|
||||
return _content;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_content != value)
|
||||
{
|
||||
if (_content != null)
|
||||
{
|
||||
RemoveChild(_content);
|
||||
}
|
||||
_content = value;
|
||||
if (_content != null)
|
||||
{
|
||||
AddChild(_content);
|
||||
}
|
||||
InvalidateMeasure();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AnimateTo(targetOffset);
|
||||
}
|
||||
public IList<SwipeItem> LeftItems => _leftItems;
|
||||
|
||||
/// <summary>
|
||||
/// Closes the swipe view.
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
_isOpen = false;
|
||||
AnimateTo(0);
|
||||
}
|
||||
public IList<SwipeItem> RightItems => _rightItems;
|
||||
|
||||
private void AnimateTo(float target)
|
||||
{
|
||||
// Simple animation - in production would use proper animation
|
||||
_swipeOffset = target;
|
||||
Invalidate();
|
||||
}
|
||||
public IList<SwipeItem> TopItems => _topItems;
|
||||
|
||||
protected override SKSize MeasureOverride(SKSize availableSize)
|
||||
{
|
||||
if (_content != null)
|
||||
{
|
||||
_content.Measure(availableSize);
|
||||
}
|
||||
return availableSize;
|
||||
}
|
||||
public IList<SwipeItem> BottomItems => _bottomItems;
|
||||
|
||||
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 SwipeMode Mode { get; set; }
|
||||
|
||||
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
canvas.Save();
|
||||
canvas.ClipRect(bounds);
|
||||
public float LeftSwipeThreshold { 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 float RightSwipeThreshold { get; set; } = 100f;
|
||||
|
||||
// Draw content
|
||||
_content?.Draw(canvas);
|
||||
public event EventHandler<SwipeStartedEventArgs>? SwipeStarted;
|
||||
|
||||
canvas.Restore();
|
||||
}
|
||||
public event EventHandler<SwipeEndedEventArgs>? SwipeEnded;
|
||||
|
||||
private void DrawSwipeItems(SKCanvas canvas, SKRect bounds, List<SwipeItem> items, bool isLeft)
|
||||
{
|
||||
if (items.Count == 0) return;
|
||||
public void Open(SwipeDirection direction)
|
||||
{
|
||||
_activeDirection = direction;
|
||||
_isOpen = true;
|
||||
AnimateTo(direction switch
|
||||
{
|
||||
SwipeDirection.Left => 0f - RightSwipeThreshold,
|
||||
SwipeDirection.Right => LeftSwipeThreshold,
|
||||
_ => 0f,
|
||||
});
|
||||
}
|
||||
|
||||
float revealWidth = Math.Abs(_swipeOffset);
|
||||
float itemWidth = revealWidth / items.Count;
|
||||
public void Close()
|
||||
{
|
||||
_isOpen = false;
|
||||
AnimateTo(0f);
|
||||
}
|
||||
|
||||
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;
|
||||
private void AnimateTo(float target)
|
||||
{
|
||||
_swipeOffset = target;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
var itemBounds = new SKRect(
|
||||
x,
|
||||
bounds.Top,
|
||||
x + itemWidth,
|
||||
bounds.Bottom);
|
||||
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;
|
||||
}
|
||||
|
||||
// Draw background
|
||||
using var bgPaint = new SKPaint
|
||||
{
|
||||
Color = item.BackgroundColor,
|
||||
Style = SKPaintStyle.Fill
|
||||
};
|
||||
canvas.DrawRect(itemBounds, bgPaint);
|
||||
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 icon or text
|
||||
if (!string.IsNullOrEmpty(item.Text))
|
||||
{
|
||||
using var textPaint = new SKPaint
|
||||
{
|
||||
Color = item.TextColor,
|
||||
TextSize = 14f,
|
||||
IsAntialias = true,
|
||||
TextAlign = SKTextAlign.Center
|
||||
};
|
||||
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();
|
||||
}
|
||||
|
||||
float textY = itemBounds.MidY + 5;
|
||||
canvas.DrawText(item.Text, itemBounds.MidX, textY, textPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override SkiaView? HitTest(float x, float y)
|
||||
{
|
||||
if (!IsVisible || !Bounds.Contains(x, y)) return null;
|
||||
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;
|
||||
}
|
||||
|
||||
// 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 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);
|
||||
}
|
||||
|
||||
if (_content != null)
|
||||
{
|
||||
var hit = _content.HitTest(x, y);
|
||||
if (hit != null) return hit;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,339 +1,343 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using Microsoft.Maui.Controls;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
/// <summary>
|
||||
/// Skia-rendered toggle switch control with full XAML styling support.
|
||||
/// </summary>
|
||||
public class SkiaSwitch : SkiaView
|
||||
{
|
||||
#region BindableProperties
|
||||
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);
|
||||
|
||||
/// <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 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 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 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 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 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 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 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 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 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 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 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 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 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 ThumbRadius.
|
||||
/// </summary>
|
||||
public static readonly BindableProperty ThumbRadiusProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(ThumbRadius),
|
||||
typeof(float),
|
||||
typeof(SkiaSwitch),
|
||||
12f,
|
||||
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
|
||||
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 ThumbPadding.
|
||||
/// </summary>
|
||||
public static readonly BindableProperty ThumbPaddingProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(ThumbPadding),
|
||||
typeof(float),
|
||||
typeof(SkiaSwitch),
|
||||
4f,
|
||||
propertyChanged: (b, o, n) => ((SkiaSwitch)b).Invalidate());
|
||||
private float _animationProgress;
|
||||
|
||||
#endregion
|
||||
public bool IsOn
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)((BindableObject)this).GetValue(IsOnProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(IsOnProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
#region Properties
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the switch is on.
|
||||
/// </summary>
|
||||
public bool IsOn
|
||||
{
|
||||
get => (bool)GetValue(IsOnProperty);
|
||||
set => SetValue(IsOnProperty, value);
|
||||
}
|
||||
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 the on track color.
|
||||
/// </summary>
|
||||
public SKColor OnTrackColor
|
||||
{
|
||||
get => (SKColor)GetValue(OnTrackColorProperty);
|
||||
set => SetValue(OnTrackColorProperty, 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 off track color.
|
||||
/// </summary>
|
||||
public SKColor OffTrackColor
|
||||
{
|
||||
get => (SKColor)GetValue(OffTrackColorProperty);
|
||||
set => SetValue(OffTrackColorProperty, 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 thumb color.
|
||||
/// </summary>
|
||||
public SKColor ThumbColor
|
||||
{
|
||||
get => (SKColor)GetValue(ThumbColorProperty);
|
||||
set => SetValue(ThumbColorProperty, value);
|
||||
}
|
||||
public float TrackWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(TrackWidthProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(TrackWidthProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the disabled color.
|
||||
/// </summary>
|
||||
public SKColor DisabledColor
|
||||
{
|
||||
get => (SKColor)GetValue(DisabledColorProperty);
|
||||
set => SetValue(DisabledColorProperty, value);
|
||||
}
|
||||
public float TrackHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(TrackHeightProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(TrackHeightProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the track width.
|
||||
/// </summary>
|
||||
public float TrackWidth
|
||||
{
|
||||
get => (float)GetValue(TrackWidthProperty);
|
||||
set => SetValue(TrackWidthProperty, value);
|
||||
}
|
||||
public float ThumbRadius
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(ThumbRadiusProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(ThumbRadiusProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the track height.
|
||||
/// </summary>
|
||||
public float TrackHeight
|
||||
{
|
||||
get => (float)GetValue(TrackHeightProperty);
|
||||
set => SetValue(TrackHeightProperty, value);
|
||||
}
|
||||
public float ThumbPadding
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)((BindableObject)this).GetValue(ThumbPaddingProperty);
|
||||
}
|
||||
set
|
||||
{
|
||||
((BindableObject)this).SetValue(ThumbPaddingProperty, (object)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the thumb radius.
|
||||
/// </summary>
|
||||
public float ThumbRadius
|
||||
{
|
||||
get => (float)GetValue(ThumbRadiusProperty);
|
||||
set => SetValue(ThumbRadiusProperty, value);
|
||||
}
|
||||
public event EventHandler<ToggledEventArgs>? Toggled;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the thumb padding.
|
||||
/// </summary>
|
||||
public float ThumbPadding
|
||||
{
|
||||
get => (float)GetValue(ThumbPaddingProperty);
|
||||
set => SetValue(ThumbPaddingProperty, value);
|
||||
}
|
||||
public SkiaSwitch()
|
||||
{
|
||||
base.IsFocusable = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
private void OnIsOnChanged()
|
||||
{
|
||||
_animationProgress = (IsOn ? 1f : 0f);
|
||||
this.Toggled?.Invoke(this, new ToggledEventArgs(IsOn));
|
||||
SkiaVisualStateManager.GoToState(this, IsOn ? "On" : "Off");
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
private float _animationProgress; // 0 = off, 1 = on
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when the switch is toggled.
|
||||
/// </summary>
|
||||
public event EventHandler<ToggledEventArgs>? Toggled;
|
||||
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));
|
||||
}
|
||||
|
||||
public SkiaSwitch()
|
||||
{
|
||||
IsFocusable = true;
|
||||
}
|
||||
public override void OnPointerPressed(PointerEventArgs e)
|
||||
{
|
||||
if (base.IsEnabled)
|
||||
{
|
||||
IsOn = !IsOn;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
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 OnPointerReleased(PointerEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnDraw(SKCanvas canvas, SKRect bounds)
|
||||
{
|
||||
var centerY = bounds.MidY;
|
||||
var trackLeft = bounds.MidX - TrackWidth / 2;
|
||||
var trackRight = trackLeft + TrackWidth;
|
||||
public override void OnKeyDown(KeyEventArgs e)
|
||||
{
|
||||
if (base.IsEnabled && (e.Key == Key.Space || e.Key == Key.Enter))
|
||||
{
|
||||
IsOn = !IsOn;
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate thumb position
|
||||
var thumbMinX = trackLeft + ThumbPadding + ThumbRadius;
|
||||
var thumbMaxX = trackRight - ThumbPadding - ThumbRadius;
|
||||
var thumbX = thumbMinX + _animationProgress * (thumbMaxX - thumbMinX);
|
||||
protected override void OnEnabledChanged()
|
||||
{
|
||||
base.OnEnabledChanged();
|
||||
SkiaVisualStateManager.GoToState(this, base.IsEnabled ? "Normal" : "Disabled");
|
||||
}
|
||||
|
||||
// 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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,422 +1,443 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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();
|
||||
private int _selectedIndex = 0;
|
||||
private float _tabBarHeight = 48f;
|
||||
private bool _tabBarOnBottom = false;
|
||||
private readonly List<TabItem> _tabs = new List<TabItem>();
|
||||
|
||||
/// <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 int _selectedIndex;
|
||||
|
||||
/// <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 float _tabBarHeight = 48f;
|
||||
|
||||
/// <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();
|
||||
}
|
||||
}
|
||||
}
|
||||
private bool _tabBarOnBottom;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the currently selected tab.
|
||||
/// </summary>
|
||||
public TabItem? SelectedTab => _selectedIndex >= 0 && _selectedIndex < _tabs.Count
|
||||
? _tabs[_selectedIndex]
|
||||
: null;
|
||||
public float TabBarHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
return _tabBarHeight;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_tabBarHeight != value)
|
||||
{
|
||||
_tabBarHeight = value;
|
||||
InvalidateMeasure();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tabs in this page.
|
||||
/// </summary>
|
||||
public IReadOnlyList<TabItem> Tabs => _tabs;
|
||||
public bool TabBarOnBottom
|
||||
{
|
||||
get
|
||||
{
|
||||
return _tabBarOnBottom;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_tabBarOnBottom != value)
|
||||
{
|
||||
_tabBarOnBottom = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Background color for the tab bar.
|
||||
/// </summary>
|
||||
public SKColor TabBarBackgroundColor { get; set; } = new SKColor(33, 150, 243); // Material Blue
|
||||
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>
|
||||
/// Color for selected tab text/icon.
|
||||
/// </summary>
|
||||
public SKColor SelectedTabColor { get; set; } = SKColors.White;
|
||||
public TabItem? SelectedTab
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_selectedIndex < 0 || _selectedIndex >= _tabs.Count)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return _tabs[_selectedIndex];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Color for unselected tab text/icon.
|
||||
/// </summary>
|
||||
public SKColor UnselectedTabColor { get; set; } = new SKColor(255, 255, 255, 180);
|
||||
public IReadOnlyList<TabItem> Tabs => _tabs;
|
||||
|
||||
/// <summary>
|
||||
/// Color of the selection indicator.
|
||||
/// </summary>
|
||||
public SKColor IndicatorColor { get; set; } = SKColors.White;
|
||||
public SKColor TabBarBackgroundColor { get; set; } = new SKColor((byte)33, (byte)150, (byte)243);
|
||||
|
||||
/// <summary>
|
||||
/// Height of the selection indicator.
|
||||
/// </summary>
|
||||
public float IndicatorHeight { get; set; } = 3f;
|
||||
public SKColor SelectedTabColor { get; set; } = SKColors.White;
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when the selected index changes.
|
||||
/// </summary>
|
||||
public event EventHandler? SelectedIndexChanged;
|
||||
public SKColor UnselectedTabColor { get; set; } = new SKColor(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)180);
|
||||
|
||||
/// <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 SKColor IndicatorColor { get; set; } = SKColors.White;
|
||||
|
||||
_tabs.Add(tab);
|
||||
AddChild(content);
|
||||
public float IndicatorHeight { get; set; } = 3f;
|
||||
|
||||
if (_tabs.Count == 1)
|
||||
{
|
||||
_selectedIndex = 0;
|
||||
}
|
||||
public event EventHandler? SelectedIndexChanged;
|
||||
|
||||
InvalidateMeasure();
|
||||
Invalidate();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
/// <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 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();
|
||||
}
|
||||
}
|
||||
|
||||
if (_selectedIndex >= _tabs.Count)
|
||||
{
|
||||
_selectedIndex = Math.Max(0, _tabs.Count - 1);
|
||||
}
|
||||
public void ClearTabs()
|
||||
{
|
||||
foreach (TabItem tab in _tabs)
|
||||
{
|
||||
RemoveChild(tab.Content);
|
||||
}
|
||||
_tabs.Clear();
|
||||
_selectedIndex = 0;
|
||||
InvalidateMeasure();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
InvalidateMeasure();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all tabs.
|
||||
/// </summary>
|
||||
public void ClearTabs()
|
||||
{
|
||||
foreach (var tab in _tabs)
|
||||
{
|
||||
RemoveChild(tab.Content);
|
||||
}
|
||||
_tabs.Clear();
|
||||
_selectedIndex = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
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();
|
||||
}
|
||||
|
||||
foreach (var tab in _tabs)
|
||||
{
|
||||
tab.Content.Measure(contentSize);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
return availableSize;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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; }
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,367 +1,413 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
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 bool _templateApplied;
|
||||
private SkiaView? _templateRoot;
|
||||
|
||||
#region BindableProperties
|
||||
private bool _templateApplied;
|
||||
|
||||
public static readonly BindableProperty ControlTemplateProperty =
|
||||
BindableProperty.Create(nameof(ControlTemplate), typeof(ControlTemplate), typeof(SkiaTemplatedView), null,
|
||||
propertyChanged: OnControlTemplateChanged);
|
||||
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);
|
||||
|
||||
#endregion
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#region Properties
|
||||
protected SkiaView? TemplateRoot => _templateRoot;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the control template that defines the visual appearance.
|
||||
/// </summary>
|
||||
public ControlTemplate? ControlTemplate
|
||||
{
|
||||
get => (ControlTemplate?)GetValue(ControlTemplateProperty);
|
||||
set => SetValue(ControlTemplateProperty, value);
|
||||
}
|
||||
protected bool IsTemplateApplied => _templateApplied;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the root element created from the ControlTemplate.
|
||||
/// </summary>
|
||||
protected SkiaView? TemplateRoot => _templateRoot;
|
||||
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 a value indicating whether a template has been applied.
|
||||
/// </summary>
|
||||
protected bool IsTemplateApplied => _templateApplied;
|
||||
protected virtual void OnControlTemplateChanged(ControlTemplate? oldTemplate, ControlTemplate? newTemplate)
|
||||
{
|
||||
_templateApplied = false;
|
||||
_templateRoot = null;
|
||||
if (newTemplate != null)
|
||||
{
|
||||
ApplyTemplate();
|
||||
}
|
||||
InvalidateMeasure();
|
||||
}
|
||||
|
||||
#endregion
|
||||
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnControlTemplateChanged(BindableObject bindable, object oldValue, object newValue)
|
||||
{
|
||||
if (bindable is SkiaTemplatedView view)
|
||||
{
|
||||
view.OnControlTemplateChanged((ControlTemplate?)oldValue, (ControlTemplate?)newValue);
|
||||
}
|
||||
}
|
||||
protected virtual void OnTemplateApplied()
|
||||
{
|
||||
SkiaContentPresenter skiaContentPresenter = FindTemplateChild<SkiaContentPresenter>("PART_ContentPresenter");
|
||||
if (skiaContentPresenter != null)
|
||||
{
|
||||
OnContentPresenterFound(skiaContentPresenter);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the ControlTemplate changes.
|
||||
/// </summary>
|
||||
protected virtual void OnControlTemplateChanged(ControlTemplate? oldTemplate, ControlTemplate? newTemplate)
|
||||
{
|
||||
_templateApplied = false;
|
||||
_templateRoot = null;
|
||||
protected virtual void OnContentPresenterFound(SkiaContentPresenter presenter)
|
||||
{
|
||||
}
|
||||
|
||||
if (newTemplate != null)
|
||||
{
|
||||
ApplyTemplate();
|
||||
}
|
||||
protected T? FindTemplateChild<T>(string name) where T : SkiaView
|
||||
{
|
||||
if (_templateRoot == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return FindChild<T>(_templateRoot, name);
|
||||
}
|
||||
|
||||
InvalidateMeasure();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the current ControlTemplate if one is set.
|
||||
/// </summary>
|
||||
protected virtual void ApplyTemplate()
|
||||
{
|
||||
if (ControlTemplate == null || _templateApplied)
|
||||
return;
|
||||
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);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Create content from template
|
||||
var content = ControlTemplate.CreateContent();
|
||||
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;
|
||||
}
|
||||
|
||||
// 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 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 (_templateRoot != null)
|
||||
{
|
||||
_templateRoot.Parent = this;
|
||||
OnTemplateApplied();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
_templateApplied = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error applying template: {ex.Message}");
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/// <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 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 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 abstract void DrawDefaultAppearance(SKCanvas canvas, SKRect bounds);
|
||||
|
||||
/// <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 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);
|
||||
}
|
||||
|
||||
return FindChild<T>(_templateRoot, name);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
private static T? FindChild<T>(SkiaView root, string name) where T : SkiaView
|
||||
{
|
||||
if (root is T typed && root.Name == name)
|
||||
return typed;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
8
Views/SkiaTextAlignment.cs
Normal file
8
Views/SkiaTextAlignment.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
public enum SkiaTextAlignment
|
||||
{
|
||||
Left,
|
||||
Center,
|
||||
Right
|
||||
}
|
||||
28
Views/SkiaTextSpan.cs
Normal file
28
Views/SkiaTextSpan.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
17
Views/SkiaToolbarItem.cs
Normal file
17
Views/SkiaToolbarItem.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
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; }
|
||||
}
|
||||
7
Views/SkiaToolbarItemOrder.cs
Normal file
7
Views/SkiaToolbarItemOrder.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
public enum SkiaToolbarItemOrder
|
||||
{
|
||||
Primary,
|
||||
Secondary
|
||||
}
|
||||
8
Views/SkiaVerticalAlignment.cs
Normal file
8
Views/SkiaVerticalAlignment.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
public enum SkiaVerticalAlignment
|
||||
{
|
||||
Top,
|
||||
Center,
|
||||
Bottom
|
||||
}
|
||||
1774
Views/SkiaView.cs
1774
Views/SkiaView.cs
File diff suppressed because it is too large
Load Diff
10
Views/SkiaVisualState.cs
Normal file
10
Views/SkiaVisualState.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
public class SkiaVisualState
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
public List<SkiaVisualStateSetter> Setters { get; } = new List<SkiaVisualStateSetter>();
|
||||
}
|
||||
12
Views/SkiaVisualStateGroup.cs
Normal file
12
Views/SkiaVisualStateGroup.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
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; }
|
||||
}
|
||||
7
Views/SkiaVisualStateGroupList.cs
Normal file
7
Views/SkiaVisualStateGroupList.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
public class SkiaVisualStateGroupList : List<SkiaVisualStateGroup>
|
||||
{
|
||||
}
|
||||
@@ -1,216 +1,98 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
using Microsoft.Maui.Controls;
|
||||
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
/// <summary>
|
||||
/// Visual State Manager for Skia-rendered controls.
|
||||
/// Provides state-based styling through XAML VisualStateGroups.
|
||||
/// </summary>
|
||||
public static class SkiaVisualStateManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Common visual state names.
|
||||
/// </summary>
|
||||
public static class CommonStates
|
||||
{
|
||||
public const string Normal = "Normal";
|
||||
public const string Disabled = "Disabled";
|
||||
public const string Focused = "Focused";
|
||||
public const string PointerOver = "PointerOver";
|
||||
public const string Pressed = "Pressed";
|
||||
public const string Selected = "Selected";
|
||||
public const string Checked = "Checked";
|
||||
public const string Unchecked = "Unchecked";
|
||||
public const string On = "On";
|
||||
public const string Off = "Off";
|
||||
}
|
||||
public static class CommonStates
|
||||
{
|
||||
public const string Normal = "Normal";
|
||||
|
||||
/// <summary>
|
||||
/// Attached property for VisualStateGroups.
|
||||
/// </summary>
|
||||
public static readonly BindableProperty VisualStateGroupsProperty =
|
||||
BindableProperty.CreateAttached(
|
||||
"VisualStateGroups",
|
||||
typeof(SkiaVisualStateGroupList),
|
||||
typeof(SkiaVisualStateManager),
|
||||
null,
|
||||
propertyChanged: OnVisualStateGroupsChanged);
|
||||
public const string Disabled = "Disabled";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the visual state groups for the specified view.
|
||||
/// </summary>
|
||||
public static SkiaVisualStateGroupList? GetVisualStateGroups(SkiaView view)
|
||||
{
|
||||
return (SkiaVisualStateGroupList?)view.GetValue(VisualStateGroupsProperty);
|
||||
}
|
||||
public const string Focused = "Focused";
|
||||
|
||||
/// <summary>
|
||||
/// Sets the visual state groups for the specified view.
|
||||
/// </summary>
|
||||
public static void SetVisualStateGroups(SkiaView view, SkiaVisualStateGroupList? value)
|
||||
{
|
||||
view.SetValue(VisualStateGroupsProperty, value);
|
||||
}
|
||||
public const string PointerOver = "PointerOver";
|
||||
|
||||
private static void OnVisualStateGroupsChanged(BindableObject bindable, object? oldValue, object? newValue)
|
||||
{
|
||||
if (bindable is SkiaView view && newValue is SkiaVisualStateGroupList groups)
|
||||
{
|
||||
// Initialize to default state
|
||||
GoToState(view, CommonStates.Normal);
|
||||
}
|
||||
}
|
||||
public const string Pressed = "Pressed";
|
||||
|
||||
/// <summary>
|
||||
/// Transitions the view to the specified visual state.
|
||||
/// </summary>
|
||||
/// <param name="view">The view to transition.</param>
|
||||
/// <param name="stateName">The name of the state to transition to.</param>
|
||||
/// <returns>True if the state was found and applied, false otherwise.</returns>
|
||||
public static bool GoToState(SkiaView view, string stateName)
|
||||
{
|
||||
var groups = GetVisualStateGroups(view);
|
||||
if (groups == null || groups.Count == 0)
|
||||
return false;
|
||||
public const string Selected = "Selected";
|
||||
|
||||
bool stateFound = false;
|
||||
public const string Checked = "Checked";
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
// Find the state in this group
|
||||
SkiaVisualState? targetState = null;
|
||||
foreach (var state in group.States)
|
||||
{
|
||||
if (state.Name == stateName)
|
||||
{
|
||||
targetState = state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
public const string Unchecked = "Unchecked";
|
||||
|
||||
if (targetState != null)
|
||||
{
|
||||
// Unapply current state if different
|
||||
if (group.CurrentState != null && group.CurrentState != targetState)
|
||||
{
|
||||
UnapplyState(view, group.CurrentState);
|
||||
}
|
||||
public const string On = "On";
|
||||
|
||||
// Apply new state
|
||||
ApplyState(view, targetState);
|
||||
group.CurrentState = targetState;
|
||||
stateFound = true;
|
||||
}
|
||||
}
|
||||
public const string Off = "Off";
|
||||
}
|
||||
|
||||
return stateFound;
|
||||
}
|
||||
public static readonly BindableProperty VisualStateGroupsProperty = BindableProperty.CreateAttached("VisualStateGroups", typeof(SkiaVisualStateGroupList), typeof(SkiaVisualStateManager), (object)null, (BindingMode)2, (ValidateValueDelegate)null, new BindingPropertyChangedDelegate(OnVisualStateGroupsChanged), (BindingPropertyChangingDelegate)null, (CoerceValueDelegate)null, (CreateDefaultValueDelegate)null);
|
||||
|
||||
private static void ApplyState(SkiaView view, SkiaVisualState state)
|
||||
{
|
||||
foreach (var setter in state.Setters)
|
||||
{
|
||||
setter.Apply(view);
|
||||
}
|
||||
}
|
||||
public static SkiaVisualStateGroupList? GetVisualStateGroups(SkiaView view)
|
||||
{
|
||||
return (SkiaVisualStateGroupList)((BindableObject)view).GetValue(VisualStateGroupsProperty);
|
||||
}
|
||||
|
||||
private static void UnapplyState(SkiaView view, SkiaVisualState state)
|
||||
{
|
||||
foreach (var setter in state.Setters)
|
||||
{
|
||||
setter.Unapply(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A list of visual state groups.
|
||||
/// </summary>
|
||||
public class SkiaVisualStateGroupList : List<SkiaVisualStateGroup>
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A group of mutually exclusive visual states.
|
||||
/// </summary>
|
||||
public class SkiaVisualStateGroup
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of this group.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of states in this group.
|
||||
/// </summary>
|
||||
public List<SkiaVisualState> States { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the currently active state.
|
||||
/// </summary>
|
||||
public SkiaVisualState? CurrentState { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single visual state with its setters.
|
||||
/// </summary>
|
||||
public class SkiaVisualState
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of this state.
|
||||
/// </summary>
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of setters for this state.
|
||||
/// </summary>
|
||||
public List<SkiaVisualStateSetter> Setters { get; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a property value when a visual state is active.
|
||||
/// </summary>
|
||||
public class SkiaVisualStateSetter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the property to set.
|
||||
/// </summary>
|
||||
public BindableProperty? Property { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value to set.
|
||||
/// </summary>
|
||||
public object? Value { get; set; }
|
||||
|
||||
// Store original value for unapply
|
||||
private object? _originalValue;
|
||||
private bool _hasOriginalValue;
|
||||
|
||||
/// <summary>
|
||||
/// Applies this setter to the target view.
|
||||
/// </summary>
|
||||
public void Apply(SkiaView view)
|
||||
{
|
||||
if (Property == null) return;
|
||||
|
||||
// Store original value if not already stored
|
||||
if (!_hasOriginalValue)
|
||||
{
|
||||
_originalValue = view.GetValue(Property);
|
||||
_hasOriginalValue = true;
|
||||
}
|
||||
|
||||
view.SetValue(Property, Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unapplies this setter, restoring the original value.
|
||||
/// </summary>
|
||||
public void Unapply(SkiaView view)
|
||||
{
|
||||
if (Property == null || !_hasOriginalValue) return;
|
||||
|
||||
view.SetValue(Property, _originalValue);
|
||||
}
|
||||
public static void SetVisualStateGroups(SkiaView view, SkiaVisualStateGroupList? value)
|
||||
{
|
||||
((BindableObject)view).SetValue(VisualStateGroupsProperty, (object)value);
|
||||
}
|
||||
|
||||
private static void OnVisualStateGroupsChanged(BindableObject bindable, object? oldValue, object? newValue)
|
||||
{
|
||||
if (bindable is SkiaView view && newValue is SkiaVisualStateGroupList)
|
||||
{
|
||||
GoToState(view, "Normal");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GoToState(SkiaView view, string stateName)
|
||||
{
|
||||
SkiaVisualStateGroupList visualStateGroups = GetVisualStateGroups(view);
|
||||
if (visualStateGroups == null || visualStateGroups.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool result = false;
|
||||
foreach (SkiaVisualStateGroup item in visualStateGroups)
|
||||
{
|
||||
SkiaVisualState skiaVisualState = null;
|
||||
foreach (SkiaVisualState state in item.States)
|
||||
{
|
||||
if (state.Name == stateName)
|
||||
{
|
||||
skiaVisualState = state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skiaVisualState != null)
|
||||
{
|
||||
if (item.CurrentState != null && item.CurrentState != skiaVisualState)
|
||||
{
|
||||
UnapplyState(view, item.CurrentState);
|
||||
}
|
||||
ApplyState(view, skiaVisualState);
|
||||
item.CurrentState = skiaVisualState;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void ApplyState(SkiaView view, SkiaVisualState state)
|
||||
{
|
||||
foreach (SkiaVisualStateSetter setter in state.Setters)
|
||||
{
|
||||
setter.Apply(view);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UnapplyState(SkiaView view, SkiaVisualState state)
|
||||
{
|
||||
foreach (SkiaVisualStateSetter setter in state.Setters)
|
||||
{
|
||||
setter.Unapply(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
35
Views/SkiaVisualStateSetter.cs
Normal file
35
Views/SkiaVisualStateSetter.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
2455
Views/SkiaWebView.cs
2455
Views/SkiaWebView.cs
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user