More fixes

This commit is contained in:
2026-01-17 05:22:37 +00:00
parent f62d4aa5f2
commit 7d2ac327a3
58 changed files with 754 additions and 666 deletions

View File

@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Platform; using Microsoft.Maui.Platform;
using SkiaSharp; using SkiaSharp;
@@ -24,12 +25,12 @@ public class GtkWebViewProxy : SkiaView
_platformView = platformView; _platformView = platformView;
} }
public override void Arrange(SKRect bounds) public override void Arrange(Rect bounds)
{ {
base.Arrange(bounds); base.Arrange(bounds);
// Bounds are already in absolute window coordinates - use them directly // Bounds are already in absolute window coordinates - use them directly
// The Skia layout system uses absolute coordinates throughout // The Skia layout system uses absolute coordinates throughout
_handler.RegisterWithHost(Bounds); _handler.RegisterWithHost(new SKRect((float)Bounds.Left, (float)Bounds.Top, (float)Bounds.Right, (float)Bounds.Bottom));
} }
public override void Draw(SKCanvas canvas) public override void Draw(SKCanvas canvas)
@@ -40,7 +41,7 @@ public class GtkWebViewProxy : SkiaView
Color = new SKColor(0, 0, 0, 0), Color = new SKColor(0, 0, 0, 0),
Style = SKPaintStyle.Fill Style = SKPaintStyle.Fill
}; };
canvas.DrawRect(Bounds, paint); canvas.DrawRect(new SKRect((float)Bounds.Left, (float)Bounds.Top, (float)Bounds.Right, (float)Bounds.Bottom), paint);
} }
public void Navigate(string url) public void Navigate(string url)

View File

@@ -177,8 +177,8 @@ public class SkiaWindow
// Draw main content // Draw main content
if (_content != null) if (_content != null)
{ {
_content.Measure(new SKSize(_width, _height)); _content.Measure(new Size(_width, _height));
_content.Arrange(new SKRect(0, 0, _width, _height)); _content.Arrange(new Rect(0, 0, _width, _height));
_content.Draw(canvas); _content.Draw(canvas);
} }

View File

@@ -156,7 +156,7 @@ public class LinuxApplication : IDisposable
_rootView = value; _rootView = value;
if (_rootView != null && _mainWindow != null) if (_rootView != null && _mainWindow != null)
{ {
_rootView.Arrange(new SkiaSharp.SKRect( _rootView.Arrange(new Microsoft.Maui.Graphics.Rect(
0, 0, 0, 0,
_mainWindow.Width, _mainWindow.Width,
_mainWindow.Height)); _mainWindow.Height));
@@ -542,8 +542,8 @@ public class LinuxApplication : IDisposable
{ {
if (_rootView != null) if (_rootView != null)
{ {
_rootView.Measure(new SKSize(width, height)); _rootView.Measure(new Size(width, height));
_rootView.Arrange(new SKRect(0, 0, width, height)); _rootView.Arrange(new Rect(0, 0, width, height));
} }
} }
@@ -569,9 +569,9 @@ public class LinuxApplication : IDisposable
if (_rootView != null) if (_rootView != null)
{ {
// Re-measure with new available size, then arrange // Re-measure with new available size, then arrange
var availableSize = new SkiaSharp.SKSize(size.Width, size.Height); var availableSize = new Size(size.Width, size.Height);
_rootView.Measure(availableSize); _rootView.Measure(availableSize);
_rootView.Arrange(new SkiaSharp.SKRect(0, 0, size.Width, size.Height)); _rootView.Arrange(new Rect(0, 0, size.Width, size.Height));
} }
_renderingEngine?.InvalidateAll(); _renderingEngine?.InvalidateAll();
} }

View File

@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp; using SkiaSharp;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Platform.Linux.Window; using Microsoft.Maui.Platform.Linux.Window;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@@ -207,9 +208,9 @@ public class GpuRenderingEngine : IDisposable
if (_canvas == null) return; if (_canvas == null) return;
// Measure and arrange // Measure and arrange
var availableSize = new SKSize(Width, Height); var availableSize = new Size(Width, Height);
rootView.Measure(availableSize); rootView.Measure(availableSize);
rootView.Arrange(new SKRect(0, 0, Width, Height)); rootView.Arrange(new Rect(0, 0, Width, Height));
// Determine regions to redraw // Determine regions to redraw
List<SKRect> regionsToRedraw; List<SKRect> regionsToRedraw;

View File

@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using SkiaSharp; using SkiaSharp;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Platform.Linux.Window; using Microsoft.Maui.Platform.Linux.Window;
using Microsoft.Maui.Platform; using Microsoft.Maui.Platform;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@@ -167,9 +168,9 @@ public class SkiaRenderingEngine : IDisposable
return; return;
// Measure and arrange // Measure and arrange
var availableSize = new SKSize(Width, Height); var availableSize = new Size(Width, Height);
rootView.Measure(availableSize); rootView.Measure(availableSize);
rootView.Arrange(new SKRect(0, 0, Width, Height)); rootView.Arrange(new Rect(0, 0, Width, Height));
// Determine what to redraw // Determine what to redraw
List<SKRect> regionsToRedraw; List<SKRect> regionsToRedraw;

View File

@@ -3,15 +3,55 @@
namespace Microsoft.Maui.Platform.Linux.Services; namespace Microsoft.Maui.Platform.Linux.Services;
public enum HotkeyKey /// <summary>
/// X11 keysym values for global hotkey registration.
/// </summary>
public enum HotkeyKey : uint
{ {
None, None = 0,
A, B, C, D, E, F, G, H, I, J, K, L, M,
N, O, P, Q, R, S, T, U, V, W, X, Y, Z, // Letters (lowercase X11 keysyms)
D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, A = 0x61, B = 0x62, C = 0x63, D = 0x64, E = 0x65,
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F = 0x66, G = 0x67, H = 0x68, I = 0x69, J = 0x6A,
Space, Enter, Escape, Tab, Backspace, Delete, Insert, K = 0x6B, L = 0x6C, M = 0x6D, N = 0x6E, O = 0x6F,
Home, End, PageUp, PageDown, P = 0x70, Q = 0x71, R = 0x72, S = 0x73, T = 0x74,
Left, Right, Up, Down, U = 0x75, V = 0x76, W = 0x77, X = 0x78, Y = 0x79,
PrintScreen, Pause, NumLock, ScrollLock, CapsLock Z = 0x7A,
// Digits
D0 = 0x30, D1 = 0x31, D2 = 0x32, D3 = 0x33, D4 = 0x34,
D5 = 0x35, D6 = 0x36, D7 = 0x37, D8 = 0x38, D9 = 0x39,
// Function keys
F1 = 0xFFBE, F2 = 0xFFBF, F3 = 0xFFC0, F4 = 0xFFC1,
F5 = 0xFFC2, F6 = 0xFFC3, F7 = 0xFFC4, F8 = 0xFFC5,
F9 = 0xFFC6, F10 = 0xFFC7, F11 = 0xFFC8, F12 = 0xFFC9,
// Special keys
Space = 0x20,
Enter = 0xFF0D,
Escape = 0xFF1B,
Tab = 0xFF09,
Backspace = 0xFF08,
Delete = 0xFFFF,
Insert = 0xFF63,
// Navigation keys
Home = 0xFF50,
End = 0xFF57,
PageUp = 0xFF55,
PageDown = 0xFF56,
// Arrow keys
Left = 0xFF51,
Right = 0xFF53,
Up = 0xFF52,
Down = 0xFF54,
// Lock keys
PrintScreen = 0xFF61,
Pause = 0xFF13,
NumLock = 0xFF7F,
ScrollLock = 0xFF14,
CapsLock = 0xFFE5
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Maui.Graphics;
using SkiaSharp; using SkiaSharp;
namespace Microsoft.Maui.Platform; namespace Microsoft.Maui.Platform;
@@ -64,8 +65,8 @@ public static class LinuxDialogService
{ {
foreach (var dialog in _activeDialogs) foreach (var dialog in _activeDialogs)
{ {
dialog.Measure(new SKSize(bounds.Width, bounds.Height)); dialog.Measure(new Size(bounds.Width, bounds.Height));
dialog.Arrange(bounds); dialog.Arrange(new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height));
dialog.Draw(canvas); dialog.Draw(canvas);
} }
} }

View File

@@ -284,11 +284,11 @@ public class SkiaActivityIndicator : SkiaView
#region Layout #region Layout
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var size = (float)Size; var size = (float)Size;
var strokeWidth = (float)StrokeWidth; var strokeWidth = (float)StrokeWidth;
return new SKSize(size + strokeWidth * 2, size + strokeWidth * 2); return new Size(size + strokeWidth * 2, size + strokeWidth * 2);
} }
#endregion #endregion

View File

@@ -311,7 +311,7 @@ public class SkiaAlertDialog : SkiaView
_tcs.TrySetResult(result); _tcs.TrySetResult(result);
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
// Dialog takes full screen for the overlay // Dialog takes full screen for the overlay
return availableSize; return availableSize;

View File

@@ -423,7 +423,7 @@ public class SkiaBorder : SkiaLayoutView
protected override SKRect GetContentBounds() protected override SKRect GetContentBounds()
{ {
return GetContentBounds(Bounds); return GetContentBounds(new SKRect((float)Bounds.Left, (float)Bounds.Top, (float)Bounds.Right, (float)Bounds.Bottom));
} }
protected new SKRect GetContentBounds(SKRect bounds) protected new SKRect GetContentBounds(SKRect bounds)
@@ -437,7 +437,7 @@ public class SkiaBorder : SkiaLayoutView
bounds.Bottom - (float)padding.Bottom - strokeThickness); bounds.Bottom - (float)padding.Bottom - strokeThickness);
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
float strokeThickness = (float)StrokeThickness; float strokeThickness = (float)StrokeThickness;
var padding = BorderPadding; var padding = BorderPadding;
@@ -445,43 +445,43 @@ public class SkiaBorder : SkiaLayoutView
float paddingHeight = (float)(padding.Top + padding.Bottom) + strokeThickness * 2f; float paddingHeight = (float)(padding.Top + padding.Bottom) + strokeThickness * 2f;
// Respect explicit size requests // Respect explicit size requests
var requestedWidth = WidthRequest >= 0.0 ? (float)WidthRequest : availableSize.Width; var requestedWidth = WidthRequest >= 0.0 ? (float)WidthRequest : (float)availableSize.Width;
var requestedHeight = HeightRequest >= 0.0 ? (float)HeightRequest : availableSize.Height; var requestedHeight = HeightRequest >= 0.0 ? (float)HeightRequest : (float)availableSize.Height;
var childAvailable = new SKSize( var childAvailable = new Size(
Math.Max(0f, requestedWidth - paddingWidth), Math.Max(0f, requestedWidth - paddingWidth),
Math.Max(0f, requestedHeight - paddingHeight)); Math.Max(0f, requestedHeight - paddingHeight));
var maxChildSize = SKSize.Empty; var maxChildSize = Size.Zero;
foreach (var child in Children) foreach (var child in Children)
{ {
var childSize = child.Measure(childAvailable); var childSize = child.Measure(childAvailable);
maxChildSize = new SKSize( maxChildSize = new Size(
Math.Max(maxChildSize.Width, childSize.Width), Math.Max(maxChildSize.Width, childSize.Width),
Math.Max(maxChildSize.Height, childSize.Height)); Math.Max(maxChildSize.Height, childSize.Height));
} }
// Use requested size if set, otherwise use child size + padding // Use requested size if set, otherwise use child size + padding
var width = WidthRequest >= 0.0 ? (float)WidthRequest : maxChildSize.Width + paddingWidth; var width = WidthRequest >= 0.0 ? (float)WidthRequest : (float)maxChildSize.Width + paddingWidth;
var height = HeightRequest >= 0.0 ? (float)HeightRequest : maxChildSize.Height + paddingHeight; var height = HeightRequest >= 0.0 ? (float)HeightRequest : (float)maxChildSize.Height + paddingHeight;
return new SKSize(width, height); return new Size(width, height);
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
var contentBounds = GetContentBounds(bounds); var contentBounds = GetContentBounds(new SKRect((float)bounds.Left, (float)bounds.Top, (float)bounds.Right, (float)bounds.Bottom));
foreach (var child in Children) foreach (var child in Children)
{ {
// Apply child's margin // Apply child's margin
var margin = child.Margin; var margin = child.Margin;
var marginedBounds = new SKRect( var marginedBounds = new Rect(
contentBounds.Left + (float)margin.Left, contentBounds.Left + margin.Left,
contentBounds.Top + (float)margin.Top, contentBounds.Top + margin.Top,
contentBounds.Right - (float)margin.Right, contentBounds.Width - margin.Left - margin.Right,
contentBounds.Bottom - (float)margin.Bottom); contentBounds.Height - margin.Top - margin.Bottom);
child.Arrange(marginedBounds); child.Arrange(marginedBounds);
} }
@@ -515,7 +515,7 @@ public class SkiaBorder : SkiaLayoutView
if (IsVisible && IsEnabled) if (IsVisible && IsEnabled)
{ {
var bounds = Bounds; var bounds = Bounds;
if (bounds.Contains(new SKPoint(x, y))) if (bounds.Contains(x, y))
{ {
if (HasTapGestureRecognizers()) if (HasTapGestureRecognizers())
{ {

View File

@@ -103,19 +103,19 @@ public class SkiaBoxView : SkiaView
#region Measurement #region Measurement
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
// BoxView uses explicit size or a default size when in unbounded context // BoxView uses explicit size or a default size when in unbounded context
var width = WidthRequest >= 0 ? (float)WidthRequest : var width = WidthRequest >= 0 ? WidthRequest :
(float.IsInfinity(availableSize.Width) ? 40f : availableSize.Width); (double.IsInfinity(availableSize.Width) ? 40.0 : availableSize.Width);
var height = HeightRequest >= 0 ? (float)HeightRequest : var height = HeightRequest >= 0 ? HeightRequest :
(float.IsInfinity(availableSize.Height) ? 40f : availableSize.Height); (double.IsInfinity(availableSize.Height) ? 40.0 : availableSize.Height);
// Ensure no NaN values // Ensure no NaN values
if (float.IsNaN(width)) width = 40f; if (double.IsNaN(width)) width = 40.0;
if (float.IsNaN(height)) height = 40f; if (double.IsNaN(height)) height = 40.0;
return new SKSize(width, height); return new Size(width, height);
} }
#endregion #endregion

View File

@@ -940,7 +940,7 @@ public class SkiaButton : SkiaView, IButtonController
#region Measurement #region Measurement
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var padding = Padding; var padding = Padding;
float paddingH = (float)(padding.Left + padding.Right); float paddingH = (float)(padding.Left + padding.Right);
@@ -1037,7 +1037,7 @@ public class SkiaButton : SkiaView, IButtonController
height = (float)HeightRequest; height = (float)HeightRequest;
} }
return new SKSize(Math.Max(width, 44f), Math.Max(height, 30f)); return new Size(Math.Max(width, 44f), Math.Max(height, 30f));
} }
#endregion #endregion

View File

@@ -204,39 +204,39 @@ public class SkiaCarouselView : SkiaLayoutView
private float GetOffsetForPosition(int position) private float GetOffsetForPosition(int position)
{ {
float itemWidth = Bounds.Width - (float)PeekAreaInsets * 2; float itemWidth = (float)Bounds.Width - (float)PeekAreaInsets * 2;
return position * (itemWidth + (float)ItemSpacing); return position * (itemWidth + (float)ItemSpacing);
} }
private int GetPositionForOffset(float offset) private int GetPositionForOffset(float offset)
{ {
float itemWidth = Bounds.Width - (float)PeekAreaInsets * 2; float itemWidth = (float)Bounds.Width - (float)PeekAreaInsets * 2;
if (itemWidth <= 0) return 0; if (itemWidth <= 0) return 0;
return Math.Clamp((int)Math.Round(offset / (itemWidth + (float)ItemSpacing)), 0, Math.Max(0, _items.Count - 1)); return Math.Clamp((int)Math.Round(offset / (itemWidth + (float)ItemSpacing)), 0, Math.Max(0, _items.Count - 1));
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
float itemWidth = availableSize.Width - (float)PeekAreaInsets * 2; float itemWidth = (float)availableSize.Width - (float)PeekAreaInsets * 2;
float itemHeight = availableSize.Height - (ShowIndicators ? 30 : 0); float itemHeight = (float)availableSize.Height - (ShowIndicators ? 30 : 0);
foreach (var item in _items) foreach (var item in _items)
{ {
item.Measure(new SKSize(itemWidth, itemHeight)); item.Measure(new Size(itemWidth, itemHeight));
} }
return availableSize; return availableSize;
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
float itemWidth = bounds.Width - (float)PeekAreaInsets * 2; float itemWidth = (float)bounds.Width - (float)PeekAreaInsets * 2;
float itemHeight = bounds.Height - (ShowIndicators ? 30 : 0); float itemHeight = (float)bounds.Height - (ShowIndicators ? 30 : 0);
for (int i = 0; i < _items.Count; i++) for (int i = 0; i < _items.Count; i++)
{ {
float x = bounds.Left + (float)PeekAreaInsets + i * (itemWidth + (float)ItemSpacing) - _scrollOffset; float x = (float)bounds.Left + (float)PeekAreaInsets + i * (itemWidth + (float)ItemSpacing) - _scrollOffset;
var itemBounds = new SKRect(x, bounds.Top, x + itemWidth, bounds.Top + itemHeight); var itemBounds = new Rect(x, bounds.Top, itemWidth, itemHeight);
_items[i].Arrange(itemBounds); _items[i].Arrange(itemBounds);
} }
@@ -389,7 +389,7 @@ public class SkiaCarouselView : SkiaLayoutView
_isDragging = false; _isDragging = false;
// Determine target position based on velocity and position // Determine target position based on velocity and position
float itemWidth = Bounds.Width - (float)PeekAreaInsets * 2; float itemWidth = (float)Bounds.Width - (float)PeekAreaInsets * 2;
int targetPosition = GetPositionForOffset(_scrollOffset); int targetPosition = GetPositionForOffset(_scrollOffset);
// Apply velocity influence // Apply velocity influence

View File

@@ -431,10 +431,10 @@ public class SkiaCheckBox : SkiaView
#region Layout #region Layout
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var boxSize = (float)BoxSize; var boxSize = BoxSize;
return new SKSize(boxSize + 8f, boxSize + 8f); return new Size(boxSize + 8.0, boxSize + 8.0);
} }
#endregion #endregion

View File

@@ -420,10 +420,10 @@ public class SkiaCollectionView : SkiaItemsView
{ {
try try
{ {
var availableSize = new SKSize(bounds.Width, float.MaxValue); var availableSize = new Size(bounds.Width, float.MaxValue);
var measuredSize = itemView.Measure(availableSize); var measuredSize = itemView.Measure(availableSize);
var rawHeight = measuredSize.Height; var rawHeight = (float)measuredSize.Height;
if (float.IsNaN(rawHeight) || float.IsInfinity(rawHeight) || rawHeight > 10000f) if (float.IsNaN(rawHeight) || float.IsInfinity(rawHeight) || rawHeight > 10000f)
{ {
rawHeight = ItemHeight; rawHeight = ItemHeight;
@@ -437,7 +437,7 @@ public class SkiaCollectionView : SkiaItemsView
} }
var actualBounds = new SKRect(bounds.Left, bounds.Top, bounds.Right, bounds.Top + measuredHeight); var actualBounds = new SKRect(bounds.Left, bounds.Top, bounds.Right, bounds.Top + measuredHeight);
itemView.Arrange(actualBounds); itemView.Arrange(new Rect(actualBounds.Left, actualBounds.Top, actualBounds.Width, actualBounds.Height));
itemView.Draw(canvas); itemView.Draw(canvas);
if (isSelected) if (isSelected)

View File

@@ -125,42 +125,42 @@ public class SkiaContentPresenter : SkiaView
Content?.Draw(canvas); Content?.Draw(canvas);
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var padding = Padding; var padding = Padding;
var paddingLeft = (float)padding.Left; var paddingLeft = padding.Left;
var paddingTop = (float)padding.Top; var paddingTop = padding.Top;
var paddingRight = (float)padding.Right; var paddingRight = padding.Right;
var paddingBottom = (float)padding.Bottom; var paddingBottom = padding.Bottom;
if (Content == null) if (Content == null)
return new SKSize(paddingLeft + paddingRight, paddingTop + paddingBottom); return new Size(paddingLeft + paddingRight, paddingTop + paddingBottom);
// When alignment is not Fill, give content unlimited size in that dimension // When alignment is not Fill, give content unlimited size in that dimension
// so it can measure its natural size without truncation // so it can measure its natural size without truncation
var measureWidth = HorizontalContentAlignment == LayoutAlignment.Fill var measureWidth = HorizontalContentAlignment == LayoutAlignment.Fill
? Math.Max(0, availableSize.Width - paddingLeft - paddingRight) ? (float)Math.Max(0, availableSize.Width - paddingLeft - paddingRight)
: float.PositiveInfinity; : float.PositiveInfinity;
var measureHeight = VerticalContentAlignment == LayoutAlignment.Fill var measureHeight = VerticalContentAlignment == LayoutAlignment.Fill
? Math.Max(0, availableSize.Height - paddingTop - paddingBottom) ? (float)Math.Max(0, availableSize.Height - paddingTop - paddingBottom)
: float.PositiveInfinity; : float.PositiveInfinity;
var contentSize = Content.Measure(new SKSize(measureWidth, measureHeight)); var contentSize = Content.Measure(new Size(measureWidth, measureHeight));
return new SKSize( return new Size(
contentSize.Width + paddingLeft + paddingRight, contentSize.Width + paddingLeft + paddingRight,
contentSize.Height + paddingTop + paddingBottom); contentSize.Height + paddingTop + paddingBottom);
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
if (Content != null) if (Content != null)
{ {
var padding = Padding; var padding = Padding;
var contentBounds = new SKRect( var contentBounds = new Rect(
bounds.Left + (float)padding.Left, bounds.Left + padding.Left,
bounds.Top + (float)padding.Top, bounds.Top + padding.Top,
bounds.Right - (float)padding.Right, bounds.Width - padding.Left - padding.Right,
bounds.Bottom - (float)padding.Bottom); bounds.Height - padding.Top - padding.Bottom);
// Apply alignment // Apply alignment
var contentSize = Content.DesiredSize; var contentSize = Content.DesiredSize;
@@ -171,12 +171,12 @@ public class SkiaContentPresenter : SkiaView
return bounds; return bounds;
} }
private static SKRect ApplyAlignment(SKRect availableBounds, SKSize contentSize, LayoutAlignment horizontal, LayoutAlignment vertical) private static Rect ApplyAlignment(Rect availableBounds, Size contentSize, LayoutAlignment horizontal, LayoutAlignment vertical)
{ {
float x = availableBounds.Left; double x = availableBounds.Left;
float y = availableBounds.Top; double y = availableBounds.Top;
float width = horizontal == LayoutAlignment.Fill ? availableBounds.Width : contentSize.Width; double width = horizontal == LayoutAlignment.Fill ? availableBounds.Width : contentSize.Width;
float height = vertical == LayoutAlignment.Fill ? availableBounds.Height : contentSize.Height; double height = vertical == LayoutAlignment.Fill ? availableBounds.Height : contentSize.Height;
// Horizontal alignment // Horizontal alignment
switch (horizontal) switch (horizontal)
@@ -200,7 +200,7 @@ public class SkiaContentPresenter : SkiaView
break; break;
} }
return new SKRect(x, y, x + width, y + height); return new Rect(x, y, width, height);
} }
public override SkiaView? HitTest(float x, float y) public override SkiaView? HitTest(float x, float y)

View File

@@ -299,7 +299,8 @@ public class SkiaDatePicker : SkiaView
{ {
if (_isOpen) if (_isOpen)
{ {
DrawCalendar(canvas, ScreenBounds); var skScreenBounds = new SKRect((float)ScreenBounds.Left, (float)ScreenBounds.Top, (float)(ScreenBounds.Left + ScreenBounds.Width), (float)(ScreenBounds.Top + ScreenBounds.Height));
DrawCalendar(canvas, skScreenBounds);
} }
} }
@@ -579,7 +580,7 @@ public class SkiaDatePicker : SkiaView
if (IsOpen) if (IsOpen)
{ {
SKRect screenBounds = ScreenBounds; SKRect screenBounds = new SKRect((float)ScreenBounds.Left, (float)ScreenBounds.Top, (float)(ScreenBounds.Left + ScreenBounds.Width), (float)(ScreenBounds.Top + ScreenBounds.Height));
SKRect calendarRect = GetCalendarRect(screenBounds); SKRect calendarRect = GetCalendarRect(screenBounds);
SKRect headerRect = new SKRect(calendarRect.Left, calendarRect.Top, calendarRect.Right, calendarRect.Top + 48f); SKRect headerRect = new SKRect(calendarRect.Left, calendarRect.Top, calendarRect.Right, calendarRect.Top + 48f);
@@ -680,14 +681,14 @@ public class SkiaDatePicker : SkiaView
} }
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
return new SKSize(availableSize.Width < float.MaxValue ? Math.Min(availableSize.Width, 200f) : 200f, 40f); return new Size(availableSize.Width < double.MaxValue ? Math.Min(availableSize.Width, 200.0) : 200.0, 40.0);
} }
protected override bool HitTestPopupArea(float x, float y) protected override bool HitTestPopupArea(float x, float y)
{ {
SKRect screenBounds = ScreenBounds; SKRect screenBounds = new SKRect((float)ScreenBounds.Left, (float)ScreenBounds.Top, (float)(ScreenBounds.Left + ScreenBounds.Width), (float)(ScreenBounds.Top + ScreenBounds.Height));
if (screenBounds.Contains(x, y)) if (screenBounds.Contains(x, y))
{ {
return true; return true;

View File

@@ -1075,9 +1075,9 @@ public class SkiaEditor : SkiaView, IInputContext
{ {
_scrollOffsetY = cursorY; _scrollOffsetY = cursorY;
} }
else if (cursorY + lineSpacing > _scrollOffsetY + viewHeight) else if (cursorY + lineSpacing > _scrollOffsetY + (float)viewHeight)
{ {
_scrollOffsetY = cursorY + lineSpacing - viewHeight; _scrollOffsetY = cursorY + lineSpacing - (float)viewHeight;
} }
} }
@@ -1377,7 +1377,7 @@ public class SkiaEditor : SkiaView, IInputContext
var lineHeight = (float)LineHeight; var lineHeight = (float)LineHeight;
var lineSpacing = fontSize * lineHeight; var lineSpacing = fontSize * lineHeight;
var totalHeight = _lines.Count * lineSpacing; var totalHeight = _lines.Count * lineSpacing;
var viewHeight = Bounds.Height - (float)(Padding.Top + Padding.Bottom); var viewHeight = (float)Bounds.Height - (float)(Padding.Top + Padding.Bottom);
var maxScroll = Math.Max(0, totalHeight - viewHeight); var maxScroll = Math.Max(0, totalHeight - viewHeight);
_scrollOffsetY = Math.Clamp(_scrollOffsetY - e.DeltaY * 3, 0, maxScroll); _scrollOffsetY = Math.Clamp(_scrollOffsetY - e.DeltaY * 3, 0, maxScroll);
@@ -1578,22 +1578,22 @@ public class SkiaEditor : SkiaView, IInputContext
_inputMethodService.SetCursorLocation(x, y, 2, height); _inputMethodService.SetCursorLocation(x, y, 2, height);
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
if (AutoSize) if (AutoSize)
{ {
var fontSize = (float)FontSize; var fontSize = (float)FontSize;
var lineHeight = (float)LineHeight; var lineHeight = (float)LineHeight;
var lineSpacing = fontSize * lineHeight; var lineSpacing = fontSize * lineHeight;
var verticalPadding = (float)(Padding.Top + Padding.Bottom); var verticalPadding = Padding.Top + Padding.Bottom;
var height = Math.Max(lineSpacing + verticalPadding, _lines.Count * lineSpacing + verticalPadding); var height = Math.Max(lineSpacing + verticalPadding, _lines.Count * lineSpacing + verticalPadding);
return new SKSize( return new Size(
availableSize.Width < float.MaxValue ? availableSize.Width : 200, availableSize.Width < double.MaxValue ? availableSize.Width : 200,
(float)Math.Min(height, availableSize.Height < float.MaxValue ? availableSize.Height : 200)); Math.Min(height, availableSize.Height < double.MaxValue ? availableSize.Height : 200));
} }
return new SKSize( return new Size(
availableSize.Width < float.MaxValue ? Math.Min(availableSize.Width, 200) : 200, availableSize.Width < double.MaxValue ? Math.Min(availableSize.Width, 200) : 200,
availableSize.Height < float.MaxValue ? Math.Min(availableSize.Height, 150) : 150); availableSize.Height < double.MaxValue ? Math.Min(availableSize.Height, 150) : 150);
} }
} }

View File

@@ -1367,8 +1367,8 @@ public class SkiaEntry : SkiaView, IInputContext
{ {
var clearButtonSize = 20f; var clearButtonSize = 20f;
var clearButtonMargin = 8f; var clearButtonMargin = 8f;
var clearCenterX = Bounds.Right - clearButtonMargin - clearButtonSize / 2; var clearCenterX = (float)(Bounds.Left + Bounds.Width) - clearButtonMargin - clearButtonSize / 2;
var clearCenterY = Bounds.MidY; var clearCenterY = (float)(Bounds.Top + Bounds.Height / 2);
var dx = e.X - clearCenterX; var dx = e.X - clearCenterX;
var dy = e.Y - clearCenterY; var dy = e.Y - clearCenterY;
@@ -1385,7 +1385,7 @@ public class SkiaEntry : SkiaView, IInputContext
// Calculate cursor position from click using screen coordinates // Calculate cursor position from click using screen coordinates
var screenBounds = ScreenBounds; var screenBounds = ScreenBounds;
var clickX = e.X - screenBounds.Left - (float)Padding.Left + _scrollOffset; var clickX = e.X - (float)screenBounds.Left - (float)Padding.Left + _scrollOffset;
_cursorPosition = GetCharacterIndexAtX(clickX); _cursorPosition = GetCharacterIndexAtX(clickX);
// Check for double-click (select word) // Check for double-click (select word)
@@ -1446,7 +1446,7 @@ public class SkiaEntry : SkiaView, IInputContext
// Extend selection to current mouse position // Extend selection to current mouse position
var screenBounds = ScreenBounds; var screenBounds = ScreenBounds;
var clickX = e.X - screenBounds.Left - (float)Padding.Left + _scrollOffset; var clickX = e.X - (float)screenBounds.Left - (float)Padding.Left + _scrollOffset;
var newPosition = GetCharacterIndexAtX(clickX); var newPosition = GetCharacterIndexAtX(clickX);
if (newPosition != _cursorPosition) if (newPosition != _cursorPosition)
@@ -1675,7 +1675,7 @@ public class SkiaEntry : SkiaView, IInputContext
_inputMethodService.SetCursorLocation(x, y, 2, height); _inputMethodService.SetCursorLocation(x, y, 2, height);
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var fontStyle = GetFontStyle(); var fontStyle = GetFontStyle();
var typeface = SkiaRenderingEngine.Current?.ResourceCache.GetTypeface(GetEffectiveFontFamily(), fontStyle) var typeface = SkiaRenderingEngine.Current?.ResourceCache.GetTypeface(GetEffectiveFontFamily(), fontStyle)
@@ -1688,9 +1688,9 @@ public class SkiaEntry : SkiaView, IInputContext
var metrics = font.Metrics; var metrics = font.Metrics;
var textHeight = metrics.Descent - metrics.Ascent + metrics.Leading; var textHeight = metrics.Descent - metrics.Ascent + metrics.Leading;
return new SKSize( return new Size(
200, // Default width, will be overridden by layout 200, // Default width, will be overridden by layout
textHeight + (float)Padding.Top + (float)Padding.Bottom + (float)BorderWidth * 2); textHeight + Padding.Top + Padding.Bottom + BorderWidth * 2);
} }
} }

View File

@@ -88,34 +88,36 @@ public class SkiaFlexLayout : SkiaLayoutView
public static FlexAlignSelf GetAlignSelf(SkiaView view) => (FlexAlignSelf)view.GetValue(AlignSelfProperty); public static FlexAlignSelf GetAlignSelf(SkiaView view) => (FlexAlignSelf)view.GetValue(AlignSelfProperty);
public static void SetAlignSelf(SkiaView view, FlexAlignSelf value) => view.SetValue(AlignSelfProperty, value); public static void SetAlignSelf(SkiaView view, FlexAlignSelf value) => view.SetValue(AlignSelfProperty, value);
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
bool isRow = Direction == FlexDirection.Row || Direction == FlexDirection.RowReverse; bool isRow = Direction == FlexDirection.Row || Direction == FlexDirection.RowReverse;
float totalMain = 0f; float totalMain = 0f;
float maxCross = 0f; float maxCross = 0f;
var sizeAvailable = new Size(availableSize.Width, availableSize.Height);
foreach (var child in Children) foreach (var child in Children)
{ {
if (!child.IsVisible) if (!child.IsVisible)
continue; continue;
var childSize = child.Measure(availableSize); var childSize = child.Measure(sizeAvailable);
if (isRow) if (isRow)
{ {
totalMain += childSize.Width; totalMain += (float)childSize.Width;
maxCross = Math.Max(maxCross, childSize.Height); maxCross = Math.Max(maxCross, (float)childSize.Height);
} }
else else
{ {
totalMain += childSize.Height; totalMain += (float)childSize.Height;
maxCross = Math.Max(maxCross, childSize.Width); maxCross = Math.Max(maxCross, (float)childSize.Width);
} }
} }
return isRow ? new SKSize(totalMain, maxCross) : new SKSize(maxCross, totalMain); return isRow ? new Size(totalMain, maxCross) : new Size(maxCross, totalMain);
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
if (Children.Count == 0) if (Children.Count == 0)
return bounds; return bounds;
@@ -127,10 +129,10 @@ public class SkiaFlexLayout : SkiaLayoutView
if (orderedChildren.Count == 0) if (orderedChildren.Count == 0)
return bounds; return bounds;
float mainSize = isRow ? bounds.Width : bounds.Height; float mainSize = isRow ? (float)bounds.Width : (float)bounds.Height;
float crossSize = isRow ? bounds.Height : bounds.Width; float crossSize = isRow ? (float)bounds.Height : (float)bounds.Width;
var childInfos = new List<(SkiaView child, SKSize size, float grow, float shrink)>(); var childInfos = new List<(SkiaView child, Size size, float grow, float shrink)>();
float totalBasis = 0f; float totalBasis = 0f;
float totalGrow = 0f; float totalGrow = 0f;
float totalShrink = 0f; float totalShrink = 0f;
@@ -141,21 +143,21 @@ public class SkiaFlexLayout : SkiaLayoutView
float grow = GetGrow(child); float grow = GetGrow(child);
float shrink = GetShrink(child); float shrink = GetShrink(child);
SKSize size; Size size;
if (basis.IsAuto) if (basis.IsAuto)
{ {
size = child.Measure(new SKSize(bounds.Width, bounds.Height)); size = child.Measure(new Size(bounds.Width, bounds.Height));
} }
else else
{ {
float length = basis.Length; float length = basis.Length;
size = isRow size = isRow
? child.Measure(new SKSize(length, bounds.Height)) ? child.Measure(new Size(length, bounds.Height))
: child.Measure(new SKSize(bounds.Width, length)); : child.Measure(new Size(bounds.Width, length));
} }
childInfos.Add((child, size, grow, shrink)); childInfos.Add((child, size, grow, shrink));
totalBasis += isRow ? size.Width : size.Height; totalBasis += isRow ? (float)size.Width : (float)size.Height;
totalGrow += grow; totalGrow += grow;
totalShrink += shrink; totalShrink += shrink;
} }
@@ -165,8 +167,8 @@ public class SkiaFlexLayout : SkiaLayoutView
var resolvedSizes = new List<(SkiaView child, float mainSize, float crossSize)>(); var resolvedSizes = new List<(SkiaView child, float mainSize, float crossSize)>();
foreach (var (child, size, grow, shrink) in childInfos) foreach (var (child, size, grow, shrink) in childInfos)
{ {
float childMainSize = isRow ? size.Width : size.Height; float childMainSize = isRow ? (float)size.Width : (float)size.Height;
float childCrossSize = isRow ? size.Height : size.Width; float childCrossSize = isRow ? (float)size.Height : (float)size.Width;
if (freeSpace > 0f && totalGrow > 0f) if (freeSpace > 0f && totalGrow > 0f)
{ {
@@ -183,7 +185,7 @@ public class SkiaFlexLayout : SkiaLayoutView
float usedSpace = resolvedSizes.Sum(s => s.mainSize); float usedSpace = resolvedSizes.Sum(s => s.mainSize);
float remainingSpace = Math.Max(0f, mainSize - usedSpace); float remainingSpace = Math.Max(0f, mainSize - usedSpace);
float position = isRow ? bounds.Left : bounds.Top; float position = isRow ? (float)bounds.Left : (float)bounds.Top;
float spacing = 0f; float spacing = 0f;
switch (JustifyContent) switch (JustifyContent)
@@ -221,13 +223,13 @@ public class SkiaFlexLayout : SkiaLayoutView
var alignSelf = GetAlignSelf(child); var alignSelf = GetAlignSelf(child);
var effectiveAlign = alignSelf == FlexAlignSelf.Auto ? AlignItems : (FlexAlignItems)alignSelf; var effectiveAlign = alignSelf == FlexAlignSelf.Auto ? AlignItems : (FlexAlignItems)alignSelf;
float crossPos = isRow ? bounds.Top : bounds.Left; float crossPos = isRow ? (float)bounds.Top : (float)bounds.Left;
float finalCrossSize = childCrossSize; float finalCrossSize = childCrossSize;
switch (effectiveAlign) switch (effectiveAlign)
{ {
case FlexAlignItems.End: case FlexAlignItems.End:
crossPos = (isRow ? bounds.Bottom : bounds.Right) - finalCrossSize; crossPos = (isRow ? (float)bounds.Bottom : (float)bounds.Right) - finalCrossSize;
break; break;
case FlexAlignItems.Center: case FlexAlignItems.Center:
crossPos += (crossSize - finalCrossSize) / 2f; crossPos += (crossSize - finalCrossSize) / 2f;
@@ -237,14 +239,14 @@ public class SkiaFlexLayout : SkiaLayoutView
break; break;
} }
SKRect childBounds; Rect childBounds;
if (isRow) if (isRow)
{ {
childBounds = new SKRect(position, crossPos, position + childMainSize, crossPos + finalCrossSize); childBounds = new Rect(position, crossPos, childMainSize, finalCrossSize);
} }
else else
{ {
childBounds = new SKRect(crossPos, position, crossPos + finalCrossSize, position + childMainSize); childBounds = new Rect(crossPos, position, finalCrossSize, childMainSize);
} }
child.Arrange(childBounds); child.Arrange(childBounds);

View File

@@ -154,40 +154,36 @@ public class SkiaFlyoutPage : SkiaLayoutView
/// </summary> /// </summary>
public event EventHandler? IsPresentedChanged; public event EventHandler? IsPresentedChanged;
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
// Measure flyout // Measure flyout
if (_flyout != null) if (_flyout != null)
{ {
_flyout.Measure(new SKSize(FlyoutWidth, availableSize.Height)); _flyout.Measure(new Size(FlyoutWidth, availableSize.Height));
} }
// Measure detail to full size // Measure detail to full size
if (_detail != null) if (_detail != null)
{ {
_detail.Measure(availableSize); _detail.Measure(new Size(availableSize.Width, availableSize.Height));
} }
return availableSize; return availableSize;
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
// Arrange detail to fill the entire area // Arrange detail to fill the entire area
if (_detail != null) if (_detail != null)
{ {
_detail.Arrange(bounds); _detail.Arrange(new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height));
} }
// Arrange flyout (positioned based on animation progress) // Arrange flyout (positioned based on animation progress)
if (_flyout != null) if (_flyout != null)
{ {
float flyoutX = bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress); float flyoutX = (float)bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress);
var flyoutBounds = new SKRect( var flyoutBounds = new Rect(flyoutX, bounds.Top, FlyoutWidth, bounds.Height);
flyoutX,
bounds.Top,
flyoutX + FlyoutWidth,
bounds.Bottom);
_flyout.Arrange(flyoutBounds); _flyout.Arrange(flyoutBounds);
} }
@@ -211,7 +207,8 @@ public class SkiaFlyoutPage : SkiaLayoutView
Color = _scrimColorSK.WithAlpha((byte)(_scrimColorSK.Alpha * _flyoutAnimationProgress)), Color = _scrimColorSK.WithAlpha((byte)(_scrimColorSK.Alpha * _flyoutAnimationProgress)),
Style = SKPaintStyle.Fill Style = SKPaintStyle.Fill
}; };
canvas.DrawRect(Bounds, scrimPaint); var skBounds = new SKRect((float)Bounds.Left, (float)Bounds.Top, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height));
canvas.DrawRect(skBounds, scrimPaint);
// Draw flyout shadow // Draw flyout shadow
if (_flyout != null && ShadowWidth > 0) if (_flyout != null && ShadowWidth > 0)
@@ -230,12 +227,12 @@ public class SkiaFlyoutPage : SkiaLayoutView
{ {
if (_flyout == null) return; if (_flyout == null) return;
float shadowRight = _flyout.Bounds.Right; float shadowRight = (float)(_flyout.Bounds.Left + _flyout.Bounds.Width);
var shadowRect = new SKRect( var shadowRect = new SKRect(
shadowRight, shadowRight,
Bounds.Top, (float)Bounds.Top,
shadowRight + ShadowWidth, shadowRight + ShadowWidth,
Bounds.Bottom); (float)(Bounds.Top + Bounds.Height));
using var shadowPaint = new SKPaint using var shadowPaint = new SKPaint
{ {

View File

@@ -49,17 +49,17 @@ public class SkiaGraphicsView : SkiaView
} }
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
// Graphics view takes all available space by default // Graphics view takes all available space by default
if (availableSize.Width < float.MaxValue && availableSize.Height < float.MaxValue) if (availableSize.Width < double.MaxValue && availableSize.Height < double.MaxValue)
{ {
return availableSize; return availableSize;
} }
// Return a reasonable default size // Return a reasonable default size
return new SKSize( return new Size(
availableSize.Width < float.MaxValue ? availableSize.Width : 100, availableSize.Width < double.MaxValue ? availableSize.Width : 100,
availableSize.Height < float.MaxValue ? availableSize.Height : 100); availableSize.Height < double.MaxValue ? availableSize.Height : 100);
} }
} }

View File

@@ -1028,7 +1028,7 @@ public class SkiaImage : SkiaView
Invalidate(); Invalidate();
} }
public override void Arrange(SKRect bounds) public override void Arrange(Rect bounds)
{ {
base.Arrange(bounds); base.Arrange(bounds);
@@ -1037,21 +1037,21 @@ public class SkiaImage : SkiaView
{ {
if (_isSvg && !string.IsNullOrEmpty(_currentFilePath) && !_isLoading) if (_isSvg && !string.IsNullOrEmpty(_currentFilePath) && !_isLoading)
{ {
float width = bounds.Width; float width = (float)bounds.Width;
float height = bounds.Height; float height = (float)bounds.Height;
if ((width > _svgLoadedWidth * 1.1 || height > _svgLoadedHeight * 1.1) && if ((width > _svgLoadedWidth * 1.1 || height > _svgLoadedHeight * 1.1) &&
width > 0f && height > 0f && width > 0f && height > 0f &&
(width != _lastArrangedBounds.Width || height != _lastArrangedBounds.Height)) (width != _lastArrangedBounds.Width || height != _lastArrangedBounds.Height))
{ {
_lastArrangedBounds = bounds; _lastArrangedBounds = new SKRect((float)bounds.Left, (float)bounds.Top, (float)bounds.Right, (float)bounds.Bottom);
_ = LoadSvgAtSizeAsync(_currentFilePath, width, height); _ = LoadSvgAtSizeAsync(_currentFilePath, width, height);
} }
} }
} }
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
var desiredWidth = DesiredSize.Width; var desiredWidth = DesiredSize.Width;
var desiredHeight = DesiredSize.Height; var desiredHeight = DesiredSize.Height;
@@ -1059,38 +1059,38 @@ public class SkiaImage : SkiaView
if (desiredWidth > 0 && desiredHeight > 0 && if (desiredWidth > 0 && desiredHeight > 0 &&
(desiredWidth < bounds.Width || desiredHeight < bounds.Height)) (desiredWidth < bounds.Width || desiredHeight < bounds.Height))
{ {
float finalWidth = Math.Min(desiredWidth, bounds.Width); double finalWidth = Math.Min(desiredWidth, bounds.Width);
float finalHeight = Math.Min(desiredHeight, bounds.Height); double finalHeight = Math.Min(desiredHeight, bounds.Height);
float x = bounds.Left; double x = bounds.Left;
var hAlignValue = (int)HorizontalOptions.Alignment; var hAlignValue = (int)HorizontalOptions.Alignment;
if (hAlignValue == 1) x = bounds.Left + (bounds.Width - finalWidth) / 2; if (hAlignValue == 1) x = bounds.Left + (bounds.Width - finalWidth) / 2;
else if (hAlignValue == 2) x = bounds.Right - finalWidth; else if (hAlignValue == 2) x = bounds.Right - finalWidth;
float y = bounds.Top; double y = bounds.Top;
var vAlignValue = (int)VerticalOptions.Alignment; var vAlignValue = (int)VerticalOptions.Alignment;
if (vAlignValue == 1) y = bounds.Top + (bounds.Height - finalHeight) / 2; if (vAlignValue == 1) y = bounds.Top + (bounds.Height - finalHeight) / 2;
else if (vAlignValue == 2) y = bounds.Bottom - finalHeight; else if (vAlignValue == 2) y = bounds.Bottom - finalHeight;
return new SKRect(x, y, x + finalWidth, y + finalHeight); return new Rect(x, y, finalWidth, finalHeight);
} }
return bounds; return bounds;
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
double widthRequest = base.WidthRequest; double widthRequest = base.WidthRequest;
double heightRequest = base.HeightRequest; double heightRequest = base.HeightRequest;
if (widthRequest > 0.0 && heightRequest > 0.0) if (widthRequest > 0.0 && heightRequest > 0.0)
return new SKSize((float)widthRequest, (float)heightRequest); return new Size(widthRequest, heightRequest);
if (_image == null) if (_image == null)
{ {
if (widthRequest > 0.0) return new SKSize((float)widthRequest, (float)widthRequest); if (widthRequest > 0.0) return new Size(widthRequest, widthRequest);
if (heightRequest > 0.0) return new SKSize((float)heightRequest, (float)heightRequest); if (heightRequest > 0.0) return new Size(heightRequest, heightRequest);
return new SKSize(100f, 100f); return new Size(100.0, 100.0);
} }
float imageWidth = _image.Width; float imageWidth = _image.Width;
@@ -1098,35 +1098,35 @@ public class SkiaImage : SkiaView
if (widthRequest > 0.0) if (widthRequest > 0.0)
{ {
float scale = (float)widthRequest / imageWidth; double scale = widthRequest / imageWidth;
return new SKSize((float)widthRequest, imageHeight * scale); return new Size(widthRequest, imageHeight * scale);
} }
if (heightRequest > 0.0) if (heightRequest > 0.0)
{ {
float scale = (float)heightRequest / imageHeight; double scale = heightRequest / imageHeight;
return new SKSize(imageWidth * scale, (float)heightRequest); return new Size(imageWidth * scale, heightRequest);
} }
if (availableSize.Width < float.MaxValue && availableSize.Height < float.MaxValue) if (availableSize.Width < double.MaxValue && availableSize.Height < double.MaxValue)
{ {
float scale = Math.Min(availableSize.Width / imageWidth, availableSize.Height / imageHeight); double scale = Math.Min(availableSize.Width / imageWidth, availableSize.Height / imageHeight);
return new SKSize(imageWidth * scale, imageHeight * scale); return new Size(imageWidth * scale, imageHeight * scale);
} }
if (availableSize.Width < float.MaxValue) if (availableSize.Width < double.MaxValue)
{ {
float scale = availableSize.Width / imageWidth; double scale = availableSize.Width / imageWidth;
return new SKSize(availableSize.Width, imageHeight * scale); return new Size(availableSize.Width, imageHeight * scale);
} }
if (availableSize.Height < float.MaxValue) if (availableSize.Height < double.MaxValue)
{ {
float scale = availableSize.Height / imageHeight; double scale = availableSize.Height / imageHeight;
return new SKSize(imageWidth * scale, availableSize.Height); return new Size(imageWidth * scale, availableSize.Height);
} }
return new SKSize(imageWidth, imageHeight); return new Size(imageWidth, imageHeight);
} }
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)

View File

@@ -641,7 +641,7 @@ public class SkiaImageButton : SkiaView
Released?.Invoke(this, EventArgs.Empty); Released?.Invoke(this, EventArgs.Empty);
if (wasPressed && Bounds.Contains(new SKPoint(e.X, e.Y))) if (wasPressed && Bounds.Contains(e.X, e.Y))
{ {
Clicked?.Invoke(this, EventArgs.Empty); Clicked?.Invoke(this, EventArgs.Empty);
ExecuteCommand(); ExecuteCommand();
@@ -687,66 +687,65 @@ public class SkiaImageButton : SkiaView
#region Layout #region Layout
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var padding = Padding; var padding = Padding;
var paddingWidth = (float)(padding.Left + padding.Right); var paddingWidth = padding.Left + padding.Right;
var paddingHeight = (float)(padding.Top + padding.Bottom); var paddingHeight = padding.Top + padding.Bottom;
// Respect explicit WidthRequest/HeightRequest first (MAUI standard behavior) // Respect explicit WidthRequest/HeightRequest first (MAUI standard behavior)
if (WidthRequest > 0 && HeightRequest > 0) if (WidthRequest > 0 && HeightRequest > 0)
{ {
return new SKSize((float)WidthRequest, (float)HeightRequest); return new Size(WidthRequest, HeightRequest);
} }
if (WidthRequest > 0) if (WidthRequest > 0)
{ {
// Fixed width, calculate height from aspect ratio or use width // Fixed width, calculate height from aspect ratio or use width
float height = HeightRequest > 0 ? (float)HeightRequest double height = HeightRequest > 0 ? HeightRequest
: _image != null ? (float)WidthRequest * _image.Height / _image.Width : _image != null ? WidthRequest * _image.Height / _image.Width
: (float)WidthRequest; : WidthRequest;
return new SKSize((float)WidthRequest, height); return new Size(WidthRequest, height);
} }
if (HeightRequest > 0) if (HeightRequest > 0)
{ {
// Fixed height, calculate width from aspect ratio or use height // Fixed height, calculate width from aspect ratio or use height
float width = WidthRequest > 0 ? (float)WidthRequest double width = WidthRequest > 0 ? WidthRequest
: _image != null ? (float)HeightRequest * _image.Width / _image.Height : _image != null ? HeightRequest * _image.Width / _image.Height
: (float)HeightRequest; : HeightRequest;
return new SKSize(width, (float)HeightRequest); return new Size(width, HeightRequest);
} }
// No explicit size - calculate from content // No explicit size - calculate from content
if (_image == null) if (_image == null)
return new SKSize(44 + paddingWidth, 44 + paddingHeight); // Default touch target size return new Size(44 + paddingWidth, 44 + paddingHeight); // Default touch target size
var imageWidth = _image.Width; var imageWidth = _image.Width;
var imageHeight = _image.Height; var imageHeight = _image.Height;
if (availableSize.Width < float.MaxValue && availableSize.Height < float.MaxValue) if (availableSize.Width < double.MaxValue && availableSize.Height < double.MaxValue)
{ {
var availableContent = new SKSize( var availableContentW = availableSize.Width - paddingWidth;
availableSize.Width - paddingWidth, var availableContentH = availableSize.Height - paddingHeight;
availableSize.Height - paddingHeight); var scale = Math.Min(availableContentW / imageWidth, availableContentH / imageHeight);
var scale = Math.Min(availableContent.Width / imageWidth, availableContent.Height / imageHeight); return new Size(imageWidth * scale + paddingWidth, imageHeight * scale + paddingHeight);
return new SKSize(imageWidth * scale + paddingWidth, imageHeight * scale + paddingHeight);
} }
else if (availableSize.Width < float.MaxValue) else if (availableSize.Width < double.MaxValue)
{ {
var availableWidth = availableSize.Width - paddingWidth; var availableWidth = availableSize.Width - paddingWidth;
var scale = availableWidth / imageWidth; var scale = availableWidth / imageWidth;
return new SKSize(availableSize.Width, imageHeight * scale + paddingHeight); return new Size(availableSize.Width, imageHeight * scale + paddingHeight);
} }
else if (availableSize.Height < float.MaxValue) else if (availableSize.Height < double.MaxValue)
{ {
var availableHeight = availableSize.Height - paddingHeight; var availableHeight = availableSize.Height - paddingHeight;
var scale = availableHeight / imageHeight; var scale = availableHeight / imageHeight;
return new SKSize(imageWidth * scale + paddingWidth, availableSize.Height); return new Size(imageWidth * scale + paddingWidth, availableSize.Height);
} }
return new SKSize(imageWidth + paddingWidth, imageHeight + paddingHeight); return new Size(imageWidth + paddingWidth, imageHeight + paddingHeight);
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
// If we have explicit size requests, constrain to desired size // If we have explicit size requests, constrain to desired size
// This follows MAUI standard behavior - controls respect WidthRequest/HeightRequest // This follows MAUI standard behavior - controls respect WidthRequest/HeightRequest
@@ -757,12 +756,12 @@ public class SkiaImageButton : SkiaView
if (desiredWidth > 0 && desiredHeight > 0 && if (desiredWidth > 0 && desiredHeight > 0 &&
(desiredWidth < bounds.Width || desiredHeight < bounds.Height)) (desiredWidth < bounds.Width || desiredHeight < bounds.Height))
{ {
float finalWidth = Math.Min(desiredWidth, bounds.Width); double finalWidth = Math.Min(desiredWidth, bounds.Width);
float finalHeight = Math.Min(desiredHeight, bounds.Height); double finalHeight = Math.Min(desiredHeight, bounds.Height);
// Calculate position based on HorizontalOptions // Calculate position based on HorizontalOptions
// LayoutAlignment: Start=0, Center=1, End=2, Fill=3 // LayoutAlignment: Start=0, Center=1, End=2, Fill=3
float x = bounds.Left; double x = bounds.Left;
var hAlignValue = (int)HorizontalOptions.Alignment; var hAlignValue = (int)HorizontalOptions.Alignment;
if (hAlignValue == 1) // Center if (hAlignValue == 1) // Center
{ {
@@ -775,7 +774,7 @@ public class SkiaImageButton : SkiaView
// Fill (3) and Start (0) both use x = bounds.Left // Fill (3) and Start (0) both use x = bounds.Left
// Calculate position based on VerticalOptions // Calculate position based on VerticalOptions
float y = bounds.Top; double y = bounds.Top;
var vAlignValue = (int)VerticalOptions.Alignment; var vAlignValue = (int)VerticalOptions.Alignment;
if (vAlignValue == 1) // Center if (vAlignValue == 1) // Center
{ {
@@ -787,7 +786,7 @@ public class SkiaImageButton : SkiaView
} }
// Fill (3) and Start (0) both use y = bounds.Top // Fill (3) and Start (0) both use y = bounds.Top
return new SKRect(x, y, x + finalWidth, y + finalHeight); return new Rect(x, y, finalWidth, finalHeight);
} }
return bounds; return bounds;

View File

@@ -145,18 +145,18 @@ public class SkiaIndicatorView : SkiaView
/// </summary> /// </summary>
public bool HideSingle { get; set; } = true; public bool HideSingle { get; set; } = true;
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
if (_count <= 0 || (HideSingle && _count <= 1)) if (_count <= 0 || (HideSingle && _count <= 1))
{ {
return SKSize.Empty; return Size.Zero;
} }
int visibleCount = Math.Min(_count, MaximumVisible); int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * (float)IndicatorSize + (visibleCount - 1) * (float)IndicatorSpacing; double totalWidth = visibleCount * IndicatorSize + (visibleCount - 1) * IndicatorSpacing;
float height = Math.Max((float)IndicatorSize, (float)SelectedIndicatorSize); double height = Math.Max(IndicatorSize, SelectedIndicatorSize);
return new SKSize(totalWidth, height); return new Size(totalWidth, height);
} }
protected override void OnDraw(SKCanvas canvas, SKRect bounds) protected override void OnDraw(SKCanvas canvas, SKRect bounds)
@@ -164,12 +164,13 @@ public class SkiaIndicatorView : SkiaView
if (_count <= 0 || (HideSingle && _count <= 1)) return; if (_count <= 0 || (HideSingle && _count <= 1)) return;
canvas.Save(); canvas.Save();
canvas.ClipRect(Bounds); var skBounds = new SKRect((float)Bounds.Left, (float)Bounds.Top, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height));
canvas.ClipRect(skBounds);
int visibleCount = Math.Min(_count, MaximumVisible); int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * (float)IndicatorSize + (visibleCount - 1) * (float)IndicatorSpacing; float totalWidth = visibleCount * (float)IndicatorSize + (visibleCount - 1) * (float)IndicatorSpacing;
float startX = Bounds.MidX - totalWidth / 2 + (float)IndicatorSize / 2; float startX = (float)(Bounds.Left + Bounds.Width / 2) - totalWidth / 2 + (float)IndicatorSize / 2;
float centerY = Bounds.MidY; float centerY = (float)(Bounds.Top + Bounds.Height / 2);
// Determine visible range if count > MaximumVisible // Determine visible range if count > MaximumVisible
int startIndex = 0; int startIndex = 0;
@@ -283,7 +284,7 @@ public class SkiaIndicatorView : SkiaView
{ {
int visibleCount = Math.Min(_count, MaximumVisible); int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * (float)IndicatorSize + (visibleCount - 1) * (float)IndicatorSpacing; float totalWidth = visibleCount * (float)IndicatorSize + (visibleCount - 1) * (float)IndicatorSpacing;
float startX = Bounds.MidX - totalWidth / 2; float startX = (float)(Bounds.Left + Bounds.Width / 2) - totalWidth / 2;
int startIndex = 0; int startIndex = 0;
if (_count > MaximumVisible) if (_count > MaximumVisible)
@@ -316,7 +317,7 @@ public class SkiaIndicatorView : SkiaView
// Calculate which indicator was clicked // Calculate which indicator was clicked
int visibleCount = Math.Min(_count, MaximumVisible); int visibleCount = Math.Min(_count, MaximumVisible);
float totalWidth = visibleCount * (float)IndicatorSize + (visibleCount - 1) * (float)IndicatorSpacing; float totalWidth = visibleCount * (float)IndicatorSize + (visibleCount - 1) * (float)IndicatorSpacing;
float startX = Bounds.MidX - totalWidth / 2; float startX = (float)(Bounds.Left + Bounds.Width / 2) - totalWidth / 2;
int startIndex = 0; int startIndex = 0;
if (_count > MaximumVisible) if (_count > MaximumVisible)

View File

@@ -176,7 +176,7 @@ public class SkiaItemsView : SkiaView
} }
// Use ScreenBounds.Height for visible viewport // Use ScreenBounds.Height for visible viewport
protected float MaxScrollOffset => Math.Max(0, TotalContentHeight - ScreenBounds.Height); protected float MaxScrollOffset => Math.Max(0, TotalContentHeight - (float)ScreenBounds.Height);
protected override void OnDraw(SKCanvas canvas, SKRect bounds) protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{ {
@@ -284,11 +284,11 @@ public class SkiaItemsView : SkiaView
if (itemView != null) if (itemView != null)
{ {
// Measure with large height to get natural size // Measure with large height to get natural size
var availableSize = new SKSize(bounds.Width, float.MaxValue); var availableSize = new Size(bounds.Width, float.MaxValue);
var measuredSize = itemView.Measure(availableSize); var measuredSize = itemView.Measure(availableSize);
// Store individual item height (with minimum of default height) // Store individual item height (with minimum of default height)
var measuredHeight = Math.Max(measuredSize.Height, _itemHeight); var measuredHeight = Math.Max((float)measuredSize.Height, _itemHeight);
if (!_itemHeights.TryGetValue(index, out var cachedHeight) || Math.Abs(cachedHeight - measuredHeight) > 1) if (!_itemHeights.TryGetValue(index, out var cachedHeight) || Math.Abs(cachedHeight - measuredHeight) > 1)
{ {
_itemHeights[index] = measuredHeight; _itemHeights[index] = measuredHeight;
@@ -300,7 +300,7 @@ public class SkiaItemsView : SkiaView
} }
// Arrange with the actual measured height // Arrange with the actual measured height
var actualBounds = new SKRect(bounds.Left, bounds.Top, bounds.Right, bounds.Top + measuredHeight); var actualBounds = new Rect(bounds.Left, bounds.Top, bounds.Width, measuredHeight);
itemView.Arrange(actualBounds); itemView.Arrange(actualBounds);
itemView.Draw(canvas); itemView.Draw(canvas);
return; return;
@@ -423,8 +423,8 @@ public class SkiaItemsView : SkiaView
_scrollbarDragStartY = e.Y; _scrollbarDragStartY = e.Y;
_scrollbarDragStartScrollOffset = _scrollOffset; _scrollbarDragStartScrollOffset = _scrollOffset;
// Cache values to prevent stutter // Cache values to prevent stutter
var thumbHeight = Math.Max(20, Bounds.Height * (Bounds.Height / TotalContentHeight)); var thumbHeight = Math.Max(20f, (float)Bounds.Height * ((float)Bounds.Height / TotalContentHeight));
_scrollbarDragAvailableTrack = Bounds.Height - thumbHeight; _scrollbarDragAvailableTrack = (float)Bounds.Height - thumbHeight;
_scrollbarDragMaxScroll = MaxScrollOffset; _scrollbarDragMaxScroll = MaxScrollOffset;
return; return;
} }
@@ -445,15 +445,15 @@ public class SkiaItemsView : SkiaView
{ {
// Use ScreenBounds for hit testing (input events use screen coordinates) // Use ScreenBounds for hit testing (input events use screen coordinates)
var screenBounds = ScreenBounds; var screenBounds = ScreenBounds;
var viewportRatio = screenBounds.Height / TotalContentHeight; var viewportRatio = (float)screenBounds.Height / TotalContentHeight;
var thumbHeight = Math.Max(20, screenBounds.Height * viewportRatio); var thumbHeight = Math.Max(20f, (float)screenBounds.Height * viewportRatio);
var scrollRatio = MaxScrollOffset > 0 ? _scrollOffset / MaxScrollOffset : 0; var scrollRatio = MaxScrollOffset > 0 ? _scrollOffset / MaxScrollOffset : 0f;
var thumbY = screenBounds.Top + (screenBounds.Height - thumbHeight) * scrollRatio; var thumbY = (float)screenBounds.Top + ((float)screenBounds.Height - thumbHeight) * scrollRatio;
return new SKRect( return new SKRect(
screenBounds.Right - _scrollBarWidth, (float)(screenBounds.Left + screenBounds.Width) - _scrollBarWidth,
thumbY, thumbY,
screenBounds.Right, (float)(screenBounds.Left + screenBounds.Width),
thumbY + thumbHeight); thumbY + thumbHeight);
} }
@@ -621,12 +621,12 @@ public class SkiaItemsView : SkiaView
break; break;
case Key.PageUp: case Key.PageUp:
SetScrollOffset(_scrollOffset - Bounds.Height); SetScrollOffset(_scrollOffset - (float)Bounds.Height);
e.Handled = true; e.Handled = true;
break; break;
case Key.PageDown: case Key.PageDown:
SetScrollOffset(_scrollOffset + Bounds.Height); SetScrollOffset(_scrollOffset + (float)Bounds.Height);
e.Handled = true; e.Handled = true;
break; break;
@@ -663,9 +663,9 @@ public class SkiaItemsView : SkiaView
{ {
SetScrollOffset(itemTop); SetScrollOffset(itemTop);
} }
else if (itemBottom > _scrollOffset + Bounds.Height) else if (itemBottom > _scrollOffset + (float)Bounds.Height)
{ {
SetScrollOffset(itemBottom - Bounds.Height); SetScrollOffset(itemBottom - (float)Bounds.Height);
} }
} }
@@ -679,14 +679,14 @@ public class SkiaItemsView : SkiaView
public override SkiaView? HitTest(float x, float y) public override SkiaView? HitTest(float x, float y)
{ {
// HitTest uses Bounds (content space) - coordinates are transformed by parent // HitTest uses Bounds (content space) - coordinates are transformed by parent
if (!IsVisible || !Bounds.Contains(new SKPoint(x, y))) if (!IsVisible || !Bounds.Contains(x, y))
return null; return null;
// Check scrollbar area FIRST before content // Check scrollbar area FIRST before content
// This ensures scrollbar clicks are handled by this view // This ensures scrollbar clicks are handled by this view
if (_showVerticalScrollBar && TotalContentHeight > Bounds.Height) if (_showVerticalScrollBar && TotalContentHeight > (float)Bounds.Height)
{ {
var trackArea = new SKRect(Bounds.Right - _scrollBarWidth, Bounds.Top, Bounds.Right, Bounds.Bottom); var trackArea = new SKRect((float)(Bounds.Left + Bounds.Width) - _scrollBarWidth, (float)Bounds.Top, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height));
if (trackArea.Contains(x, y)) if (trackArea.Contains(x, y))
return this; return this;
} }
@@ -694,21 +694,21 @@ public class SkiaItemsView : SkiaView
return this; return this;
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var width = availableSize.Width < float.MaxValue ? availableSize.Width : 200; var width = availableSize.Width < double.MaxValue ? availableSize.Width : 200;
var height = availableSize.Height < float.MaxValue ? availableSize.Height : 300; var height = availableSize.Height < double.MaxValue ? availableSize.Height : 300;
// Clear item caches when width changes significantly (items need re-measurement for text wrapping) // Clear item caches when width changes significantly (items need re-measurement for text wrapping)
if (Math.Abs(width - _lastMeasuredWidth) > 5) if (Math.Abs(width - _lastMeasuredWidth) > 5)
{ {
_itemHeights.Clear(); _itemHeights.Clear();
_itemViewCache.Clear(); _itemViewCache.Clear();
_lastMeasuredWidth = width; _lastMeasuredWidth = (float)width;
} }
// Items view takes all available space // Items view takes all available space
return new SKSize(width, height); return new Size(width, height);
} }
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)

View File

@@ -410,7 +410,7 @@ public class SkiaLabel : SkiaView
// Calculate character position from click // Calculate character position from click
var screenBounds = ScreenBounds; var screenBounds = ScreenBounds;
var clickX = e.X - screenBounds.Left - (float)Padding.Left; var clickX = e.X - (float)screenBounds.Left - (float)Padding.Left;
var charIndex = GetCharacterIndexAtX(clickX); var charIndex = GetCharacterIndexAtX(clickX);
// Check for double-click (select word) // Check for double-click (select word)
@@ -448,7 +448,7 @@ public class SkiaLabel : SkiaView
if (string.IsNullOrEmpty(text)) return; if (string.IsNullOrEmpty(text)) return;
var screenBounds = ScreenBounds; var screenBounds = ScreenBounds;
var clickX = e.X - screenBounds.Left - (float)Padding.Left; var clickX = e.X - (float)screenBounds.Left - (float)Padding.Left;
var charIndex = GetCharacterIndexAtX(clickX); var charIndex = GetCharacterIndexAtX(clickX);
_selectionLength = charIndex - _selectionStart; _selectionLength = charIndex - _selectionStart;
@@ -1192,16 +1192,16 @@ public class SkiaLabel : SkiaView
#region Measurement #region Measurement
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var padding = Padding; var padding = Padding;
float paddingH = (float)(padding.Left + padding.Right); double paddingH = padding.Left + padding.Right;
float paddingV = (float)(padding.Top + padding.Bottom); double paddingV = padding.Top + padding.Bottom;
string displayText = GetDisplayText(); string displayText = GetDisplayText();
if (string.IsNullOrEmpty(displayText) && (FormattedText == null || FormattedText.Spans.Count == 0)) if (string.IsNullOrEmpty(displayText) && (FormattedText == null || FormattedText.Spans.Count == 0))
{ {
return new SKSize(paddingH, paddingV + (float)FontSize); return new Size(paddingH, paddingV + FontSize);
} }
float fontSize = FontSize > 0 ? (float)FontSize : 14f; float fontSize = FontSize > 0 ? (float)FontSize : 14f;
@@ -1213,7 +1213,7 @@ public class SkiaLabel : SkiaView
using var paint = new SKPaint(font); using var paint = new SKPaint(font);
float width, height; double width, height;
// LineHeight -1 means platform default (use 1.0 multiplier) // LineHeight -1 means platform default (use 1.0 multiplier)
double effectiveLineHeight = LineHeight < 0 ? 1.0 : LineHeight; double effectiveLineHeight = LineHeight < 0 ? 1.0 : LineHeight;
@@ -1221,7 +1221,7 @@ public class SkiaLabel : SkiaView
{ {
// Measure formatted text // Measure formatted text
width = 0; width = 0;
height = (float)(fontSize * effectiveLineHeight); height = fontSize * effectiveLineHeight;
foreach (var span in FormattedText.Spans) foreach (var span in FormattedText.Spans)
{ {
if (!string.IsNullOrEmpty(span.Text)) if (!string.IsNullOrEmpty(span.Text))
@@ -1240,7 +1240,7 @@ public class SkiaLabel : SkiaView
// Account for character spacing // Account for character spacing
if (CharacterSpacing != 0 && displayText.Length > 1) if (CharacterSpacing != 0 && displayText.Length > 1)
{ {
width += (float)(CharacterSpacing * (displayText.Length - 1)); width += CharacterSpacing * (displayText.Length - 1);
} }
// Account for multi-line // Account for multi-line
@@ -1248,7 +1248,7 @@ public class SkiaLabel : SkiaView
{ {
var lines = displayText.Split('\n'); var lines = displayText.Split('\n');
int lineCount = MaxLines > 0 ? Math.Min(lines.Length, MaxLines) : lines.Length; int lineCount = MaxLines > 0 ? Math.Min(lines.Length, MaxLines) : lines.Length;
height = (float)(lineCount * fontSize * effectiveLineHeight); height = lineCount * fontSize * effectiveLineHeight;
} }
} }
@@ -1258,14 +1258,14 @@ public class SkiaLabel : SkiaView
// Respect explicit size requests // Respect explicit size requests
if (WidthRequest >= 0) if (WidthRequest >= 0)
{ {
width = (float)WidthRequest; width = WidthRequest;
} }
if (HeightRequest >= 0) if (HeightRequest >= 0)
{ {
height = (float)HeightRequest; height = HeightRequest;
} }
return new SKSize(Math.Max(width, 1f), Math.Max(height, 1f)); return new Size(Math.Max(width, 1.0), Math.Max(height, 1.0));
} }
#endregion #endregion

View File

@@ -193,7 +193,7 @@ public abstract class SkiaLayoutView : SkiaView
/// </summary> /// </summary>
protected virtual SKRect GetContentBounds() protected virtual SKRect GetContentBounds()
{ {
return GetContentBounds(Bounds); return GetContentBounds(new SKRect((float)Bounds.Left, (float)Bounds.Top, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height)));
} }
/// <summary> /// <summary>
@@ -247,7 +247,7 @@ public abstract class SkiaLayoutView : SkiaView
public override SkiaView? HitTest(float x, float y) public override SkiaView? HitTest(float x, float y)
{ {
if (!IsVisible || !IsEnabled || !Bounds.Contains(new SKPoint(x, y))) if (!IsVisible || !IsEnabled || !Bounds.Contains(x, y))
{ {
if (this is SkiaBorder) if (this is SkiaBorder)
{ {
@@ -357,7 +357,7 @@ public class SkiaStackLayout : SkiaLayoutView
set => SetValue(OrientationProperty, value); set => SetValue(OrientationProperty, value);
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
// Handle NaN/Infinity in padding // Handle NaN/Infinity in padding
var paddingLeft = (float)(double.IsNaN(Padding.Left) ? 0 : Padding.Left); var paddingLeft = (float)(double.IsNaN(Padding.Left) ? 0 : Padding.Left);
@@ -365,8 +365,8 @@ public class SkiaStackLayout : SkiaLayoutView
var paddingTop = (float)(double.IsNaN(Padding.Top) ? 0 : Padding.Top); var paddingTop = (float)(double.IsNaN(Padding.Top) ? 0 : Padding.Top);
var paddingBottom = (float)(double.IsNaN(Padding.Bottom) ? 0 : Padding.Bottom); var paddingBottom = (float)(double.IsNaN(Padding.Bottom) ? 0 : Padding.Bottom);
var contentWidth = availableSize.Width - paddingLeft - paddingRight; var contentWidth = (float)availableSize.Width - paddingLeft - paddingRight;
var contentHeight = availableSize.Height - paddingTop - paddingBottom; var contentHeight = (float)availableSize.Height - paddingTop - paddingBottom;
// Clamp negative sizes to 0 // Clamp negative sizes to 0
if (contentWidth < 0 || float.IsNaN(contentWidth)) contentWidth = 0; if (contentWidth < 0 || float.IsNaN(contentWidth)) contentWidth = 0;
@@ -377,7 +377,7 @@ public class SkiaStackLayout : SkiaLayoutView
float maxWidth = 0; float maxWidth = 0;
float maxHeight = 0; float maxHeight = 0;
var childAvailable = new SKSize(contentWidth, contentHeight); var childAvailable = new Size(contentWidth, contentHeight);
foreach (var child in Children) foreach (var child in Children)
{ {
@@ -386,8 +386,8 @@ public class SkiaStackLayout : SkiaLayoutView
var childSize = child.Measure(childAvailable); var childSize = child.Measure(childAvailable);
// Skip NaN sizes from child measurements // Skip NaN sizes from child measurements
var childWidth = float.IsNaN(childSize.Width) ? 0 : childSize.Width; var childWidth = double.IsNaN(childSize.Width) ? 0f : (float)childSize.Width;
var childHeight = float.IsNaN(childSize.Height) ? 0 : childSize.Height; var childHeight = double.IsNaN(childSize.Height) ? 0f : (float)childSize.Height;
if (Orientation == StackOrientation.Vertical) if (Orientation == StackOrientation.Vertical)
{ {
@@ -408,22 +408,22 @@ public class SkiaStackLayout : SkiaLayoutView
if (Orientation == StackOrientation.Vertical) if (Orientation == StackOrientation.Vertical)
{ {
totalHeight += totalSpacing; totalHeight += totalSpacing;
return new SKSize( return new Size(
maxWidth + paddingLeft + paddingRight, maxWidth + paddingLeft + paddingRight,
totalHeight + paddingTop + paddingBottom); totalHeight + paddingTop + paddingBottom);
} }
else else
{ {
totalWidth += totalSpacing; totalWidth += totalSpacing;
return new SKSize( return new Size(
totalWidth + paddingLeft + paddingRight, totalWidth + paddingLeft + paddingRight,
maxHeight + paddingTop + paddingBottom); maxHeight + paddingTop + paddingBottom);
} }
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
var content = GetContentBounds(bounds); var content = GetContentBounds(new SKRect((float)bounds.Left, (float)bounds.Top, (float)bounds.Right, (float)bounds.Bottom));
// Clamp content dimensions if infinite - use reasonable defaults // Clamp content dimensions if infinite - use reasonable defaults
var contentWidth = float.IsInfinity(content.Width) || float.IsNaN(content.Width) ? 800f : content.Width; var contentWidth = float.IsInfinity(content.Width) || float.IsNaN(content.Width) ? 800f : content.Width;
@@ -438,14 +438,14 @@ public class SkiaStackLayout : SkiaLayoutView
var childDesired = child.DesiredSize; var childDesired = child.DesiredSize;
// Handle NaN and Infinity in desired size // Handle NaN and Infinity in desired size
var childWidth = float.IsNaN(childDesired.Width) || float.IsInfinity(childDesired.Width) var childWidth = double.IsNaN(childDesired.Width) || double.IsInfinity(childDesired.Width)
? contentWidth ? contentWidth
: childDesired.Width; : (float)childDesired.Width;
var childHeight = float.IsNaN(childDesired.Height) || float.IsInfinity(childDesired.Height) var childHeight = double.IsNaN(childDesired.Height) || double.IsInfinity(childDesired.Height)
? contentHeight ? contentHeight
: childDesired.Height; : (float)childDesired.Height;
SKRect childBounds; float childBoundsLeft, childBoundsTop, childBoundsWidth, childBoundsHeight;
if (Orientation == StackOrientation.Vertical) if (Orientation == StackOrientation.Vertical)
{ {
// For ScrollView children, give them the remaining viewport height // For ScrollView children, give them the remaining viewport height
@@ -455,11 +455,10 @@ public class SkiaStackLayout : SkiaLayoutView
? remainingHeight ? remainingHeight
: Math.Min(childHeight, remainingHeight > 0 ? remainingHeight : childHeight); : Math.Min(childHeight, remainingHeight > 0 ? remainingHeight : childHeight);
childBounds = new SKRect( childBoundsLeft = content.Left;
content.Left, childBoundsTop = content.Top + offset;
content.Top + offset, childBoundsWidth = contentWidth;
content.Left + contentWidth, childBoundsHeight = useHeight;
content.Top + offset + useHeight);
offset += useHeight + (float)Spacing; offset += useHeight + (float)Spacing;
} }
else else
@@ -473,7 +472,7 @@ public class SkiaStackLayout : SkiaLayoutView
// Respect child's VerticalOptions for horizontal layouts // Respect child's VerticalOptions for horizontal layouts
var useHeight = Math.Min(childHeight, contentHeight); var useHeight = Math.Min(childHeight, contentHeight);
float childTop = content.Top; float childTop = content.Top;
float childBottom = content.Top + useHeight; float childBottomCalc = content.Top + useHeight;
var verticalOptions = child.VerticalOptions; var verticalOptions = child.VerticalOptions;
var alignmentValue = (int)verticalOptions.Alignment; var alignmentValue = (int)verticalOptions.Alignment;
@@ -482,34 +481,33 @@ public class SkiaStackLayout : SkiaLayoutView
if (alignmentValue == 1) // Center if (alignmentValue == 1) // Center
{ {
childTop = content.Top + (contentHeight - useHeight) / 2; childTop = content.Top + (contentHeight - useHeight) / 2;
childBottom = childTop + useHeight; childBottomCalc = childTop + useHeight;
} }
else if (alignmentValue == 2) // End else if (alignmentValue == 2) // End
{ {
childTop = content.Top + contentHeight - useHeight; childTop = content.Top + contentHeight - useHeight;
childBottom = content.Top + contentHeight; childBottomCalc = content.Top + contentHeight;
} }
else if (alignmentValue == 3) // Fill else if (alignmentValue == 3) // Fill
{ {
childTop = content.Top; childTop = content.Top;
childBottom = content.Top + contentHeight; childBottomCalc = content.Top + contentHeight;
} }
childBounds = new SKRect( childBoundsLeft = content.Left + offset;
content.Left + offset, childBoundsTop = childTop;
childTop, childBoundsWidth = useWidth;
content.Left + offset + useWidth, childBoundsHeight = childBottomCalc - childTop;
childBottom);
offset += useWidth + (float)Spacing; offset += useWidth + (float)Spacing;
} }
// Apply child's margin // Apply child's margin
var margin = child.Margin; var margin = child.Margin;
var marginedBounds = new SKRect( var marginedBounds = new Rect(
childBounds.Left + (float)margin.Left, childBoundsLeft + (float)margin.Left,
childBounds.Top + (float)margin.Top, childBoundsTop + (float)margin.Top,
childBounds.Right - (float)margin.Right, childBoundsWidth - (float)margin.Left - (float)margin.Right,
childBounds.Bottom - (float)margin.Bottom); childBoundsHeight - (float)margin.Top - (float)margin.Bottom);
child.Arrange(marginedBounds); child.Arrange(marginedBounds);
} }
return bounds; return bounds;
@@ -626,10 +624,10 @@ public class SkiaGrid : SkiaLayoutView
Invalidate(); Invalidate();
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var contentWidth = availableSize.Width - (float)Padding.Left - (float)Padding.Right; var contentWidth = (float)(availableSize.Width - Padding.Left - Padding.Right);
var contentHeight = availableSize.Height - (float)Padding.Top - (float)Padding.Bottom; var contentHeight = (float)(availableSize.Height - Padding.Top - Padding.Bottom);
// Handle NaN/Infinity // Handle NaN/Infinity
if (float.IsNaN(contentWidth) || float.IsInfinity(contentWidth)) contentWidth = 800; if (float.IsNaN(contentWidth) || float.IsInfinity(contentWidth)) contentWidth = 800;
@@ -652,8 +650,8 @@ public class SkiaGrid : SkiaLayoutView
var def = pos.Column < _columnDefinitions.Count ? _columnDefinitions[pos.Column] : GridLength.Star; var def = pos.Column < _columnDefinitions.Count ? _columnDefinitions[pos.Column] : GridLength.Star;
if (def.IsAuto && pos.ColumnSpan == 1) if (def.IsAuto && pos.ColumnSpan == 1)
{ {
var childSize = child.Measure(new SKSize(float.PositiveInfinity, float.PositiveInfinity)); var childSize = child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
var childWidth = float.IsNaN(childSize.Width) ? 0 : childSize.Width; var childWidth = double.IsNaN(childSize.Width) ? 0f : (float)childSize.Width;
columnNaturalWidths[pos.Column] = Math.Max(columnNaturalWidths[pos.Column], childWidth); columnNaturalWidths[pos.Column] = Math.Max(columnNaturalWidths[pos.Column], childWidth);
} }
} }
@@ -670,11 +668,11 @@ public class SkiaGrid : SkiaLayoutView
var cellWidth = GetCellWidth(pos.Column, pos.ColumnSpan); var cellWidth = GetCellWidth(pos.Column, pos.ColumnSpan);
// Give infinite height for initial measure // Give infinite height for initial measure
var childSize = child.Measure(new SKSize(cellWidth, float.PositiveInfinity)); var childSize = child.Measure(new Size(cellWidth, double.PositiveInfinity));
// Track max height for each row // Track max height for each row
// Cap infinite/very large heights - child returning infinity means it doesn't have a natural height // Cap infinite/very large heights - child returning infinity means it doesn't have a natural height
var childHeight = childSize.Height; var childHeight = (float)childSize.Height;
if (float.IsNaN(childHeight) || float.IsInfinity(childHeight) || childHeight > 100000) if (float.IsNaN(childHeight) || float.IsInfinity(childHeight) || childHeight > 100000)
{ {
// Use a default minimum - will be expanded by Star sizing if finite height is available // Use a default minimum - will be expanded by Star sizing if finite height is available
@@ -706,16 +704,16 @@ public class SkiaGrid : SkiaLayoutView
var cellWidth = GetCellWidth(pos.Column, pos.ColumnSpan); var cellWidth = GetCellWidth(pos.Column, pos.ColumnSpan);
var cellHeight = GetCellHeight(pos.Row, pos.RowSpan); var cellHeight = GetCellHeight(pos.Row, pos.RowSpan);
child.Measure(new SKSize(cellWidth, cellHeight)); child.Measure(new Size(cellWidth, cellHeight));
} }
// Calculate total size // Calculate total size
var totalWidth = _columnWidths.Sum() + Math.Max(0, columnCount - 1) * ColumnSpacing; var totalWidth = _columnWidths.Sum() + Math.Max(0, columnCount - 1) * ColumnSpacing;
var totalHeight = _rowHeights.Sum() + Math.Max(0, rowCount - 1) * RowSpacing; var totalHeight = _rowHeights.Sum() + Math.Max(0, rowCount - 1) * RowSpacing;
return new SKSize( return new Size(
totalWidth + (float)Padding.Left + (float)Padding.Right, totalWidth + Padding.Left + Padding.Right,
totalHeight + (float)Padding.Top + (float)Padding.Bottom); totalHeight + Padding.Top + Padding.Bottom);
} }
private int GetMaxRow() private int GetMaxRow()
@@ -827,11 +825,11 @@ public class SkiaGrid : SkiaLayoutView
return offset; return offset;
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
try try
{ {
var content = GetContentBounds(bounds); var content = GetContentBounds(new SKRect((float)bounds.Left, (float)bounds.Top, (float)bounds.Right, (float)bounds.Bottom));
// Recalculate row heights for arrange bounds if they differ from measurement // Recalculate row heights for arrange bounds if they differ from measurement
// This ensures Star rows expand to fill available space // This ensures Star rows expand to fill available space
@@ -909,11 +907,11 @@ public class SkiaGrid : SkiaLayoutView
// Apply child's margin // Apply child's margin
var margin = child.Margin; var margin = child.Margin;
var marginedBounds = new SKRect( var marginedBounds = new Rect(
x + (float)margin.Left, x + (float)margin.Left,
y + (float)margin.Top, y + (float)margin.Top,
x + width - (float)margin.Right, width - (float)margin.Left - (float)margin.Right,
y + height - (float)margin.Bottom); height - (float)margin.Top - (float)margin.Bottom);
child.Arrange(marginedBounds); child.Arrange(marginedBounds);
} }
return bounds; return bounds;
@@ -1024,7 +1022,7 @@ public class SkiaAbsoluteLayout : SkiaLayoutView
Invalidate(); Invalidate();
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
float maxRight = 0; float maxRight = 0;
float maxBottom = 0; float maxBottom = 0;
@@ -1036,20 +1034,20 @@ public class SkiaAbsoluteLayout : SkiaLayoutView
var layout = GetLayoutBounds(child); var layout = GetLayoutBounds(child);
var bounds = layout.Bounds; var bounds = layout.Bounds;
child.Measure(new SKSize(bounds.Width, bounds.Height)); child.Measure(new Size(bounds.Width, bounds.Height));
maxRight = Math.Max(maxRight, bounds.Right); maxRight = Math.Max(maxRight, bounds.Right);
maxBottom = Math.Max(maxBottom, bounds.Bottom); maxBottom = Math.Max(maxBottom, bounds.Bottom);
} }
return new SKSize( return new Size(
maxRight + (float)Padding.Left + (float)Padding.Right, maxRight + Padding.Left + Padding.Right,
maxBottom + (float)Padding.Top + (float)Padding.Bottom); maxBottom + Padding.Top + Padding.Bottom);
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
var content = GetContentBounds(bounds); var content = GetContentBounds(new SKRect((float)bounds.Left, (float)bounds.Top, (float)bounds.Right, (float)bounds.Bottom));
foreach (var child in Children) foreach (var child in Children)
{ {
@@ -1077,7 +1075,7 @@ public class SkiaAbsoluteLayout : SkiaLayoutView
if (flags.HasFlag(AbsoluteLayoutFlags.WidthProportional)) if (flags.HasFlag(AbsoluteLayoutFlags.WidthProportional))
width = childBounds.Width * content.Width; width = childBounds.Width * content.Width;
else if (childBounds.Width < 0) else if (childBounds.Width < 0)
width = child.DesiredSize.Width; width = (float)child.DesiredSize.Width;
else else
width = childBounds.Width; width = childBounds.Width;
@@ -1085,17 +1083,17 @@ public class SkiaAbsoluteLayout : SkiaLayoutView
if (flags.HasFlag(AbsoluteLayoutFlags.HeightProportional)) if (flags.HasFlag(AbsoluteLayoutFlags.HeightProportional))
height = childBounds.Height * content.Height; height = childBounds.Height * content.Height;
else if (childBounds.Height < 0) else if (childBounds.Height < 0)
height = child.DesiredSize.Height; height = (float)child.DesiredSize.Height;
else else
height = childBounds.Height; height = childBounds.Height;
// Apply child's margin // Apply child's margin
var margin = child.Margin; var margin = child.Margin;
var marginedBounds = new SKRect( var marginedBounds = new Rect(
x + (float)margin.Left, x + (float)margin.Left,
y + (float)margin.Top, y + (float)margin.Top,
x + width - (float)margin.Right, width - (float)margin.Left - (float)margin.Right,
y + height - (float)margin.Bottom); height - (float)margin.Top - (float)margin.Bottom);
child.Arrange(marginedBounds); child.Arrange(marginedBounds);
} }
return bounds; return bounds;

View File

@@ -104,9 +104,9 @@ public class SkiaMenuBar : SkiaView
/// </summary> /// </summary>
public float ItemPadding { get; set; } = 12f; public float ItemPadding { get; set; } = 12f;
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
return new SKSize(availableSize.Width, BarHeight); return new Size(availableSize.Width, BarHeight);
} }
protected override void OnDraw(SKCanvas canvas, SKRect bounds) protected override void OnDraw(SKCanvas canvas, SKRect bounds)
@@ -119,7 +119,8 @@ public class SkiaMenuBar : SkiaView
Color = _menuBackgroundColorSK, Color = _menuBackgroundColorSK,
Style = SKPaintStyle.Fill Style = SKPaintStyle.Fill
}; };
canvas.DrawRect(Bounds, bgPaint); var skBounds = new SKRect((float)Bounds.Left, (float)Bounds.Top, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height));
canvas.DrawRect(skBounds, bgPaint);
// Draw bottom border // Draw bottom border
using var borderPaint = new SKPaint using var borderPaint = new SKPaint
@@ -128,7 +129,7 @@ public class SkiaMenuBar : SkiaView
Style = SKPaintStyle.Stroke, Style = SKPaintStyle.Stroke,
StrokeWidth = 1 StrokeWidth = 1
}; };
canvas.DrawLine(Bounds.Left, Bounds.Bottom, Bounds.Right, Bounds.Bottom, borderPaint); canvas.DrawLine((float)Bounds.Left, (float)(Bounds.Top + Bounds.Height), (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height), borderPaint);
// Draw menu items // Draw menu items
using var textPaint = new SKPaint using var textPaint = new SKPaint
@@ -138,7 +139,7 @@ public class SkiaMenuBar : SkiaView
IsAntialias = true IsAntialias = true
}; };
float x = Bounds.Left; float x = (float)Bounds.Left;
for (int i = 0; i < _items.Count; i++) for (int i = 0; i < _items.Count; i++)
{ {
@@ -147,7 +148,7 @@ public class SkiaMenuBar : SkiaView
textPaint.MeasureText(item.Text, ref textBounds); textPaint.MeasureText(item.Text, ref textBounds);
float itemWidth = textBounds.Width + ItemPadding * 2; float itemWidth = textBounds.Width + ItemPadding * 2;
var itemBounds = new SKRect(x, Bounds.Top, x + itemWidth, Bounds.Bottom); var itemBounds = new SKRect(x, (float)Bounds.Top, x + itemWidth, (float)(Bounds.Top + Bounds.Height));
// Draw item background // Draw item background
if (i == _openIndex) if (i == _openIndex)
@@ -161,9 +162,9 @@ public class SkiaMenuBar : SkiaView
canvas.DrawRect(itemBounds, hoverPaint); canvas.DrawRect(itemBounds, hoverPaint);
} }
// Draw text // Draw text (MidY = Top + Height/2)
float textX = x + ItemPadding; float textX = x + ItemPadding;
float textY = Bounds.MidY - textBounds.MidY; float textY = (float)(Bounds.Top + Bounds.Height / 2) - textBounds.MidY;
canvas.DrawText(item.Text, textX, textY, textPaint); canvas.DrawText(item.Text, textX, textY, textPaint);
item.Bounds = itemBounds; item.Bounds = itemBounds;

View File

@@ -287,7 +287,7 @@ public class SkiaNavigationPage : SkiaView
{ {
canvas.Save(); canvas.Save();
canvas.Translate(currentOffset, 0); canvas.Translate(currentOffset, 0);
_currentPage.Bounds = bounds; _currentPage.Bounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
_currentPage.Draw(canvas); _currentPage.Draw(canvas);
canvas.Restore(); canvas.Restore();
} }
@@ -295,7 +295,7 @@ public class SkiaNavigationPage : SkiaView
// Draw incoming page // Draw incoming page
canvas.Save(); canvas.Save();
canvas.Translate(incomingOffset, 0); canvas.Translate(incomingOffset, 0);
_incomingPage.Bounds = bounds; _incomingPage.Bounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
_incomingPage.Draw(canvas); _incomingPage.Draw(canvas);
canvas.Restore(); canvas.Restore();
} }
@@ -308,7 +308,7 @@ public class SkiaNavigationPage : SkiaView
// Draw incoming page (sliding in) // Draw incoming page (sliding in)
canvas.Save(); canvas.Save();
canvas.Translate(incomingOffset, 0); canvas.Translate(incomingOffset, 0);
_incomingPage.Bounds = bounds; _incomingPage.Bounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
_incomingPage.Draw(canvas); _incomingPage.Draw(canvas);
canvas.Restore(); canvas.Restore();
@@ -317,7 +317,7 @@ public class SkiaNavigationPage : SkiaView
{ {
canvas.Save(); canvas.Save();
canvas.Translate(currentOffset, 0); canvas.Translate(currentOffset, 0);
_currentPage.Bounds = bounds; _currentPage.Bounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
_currentPage.Draw(canvas); _currentPage.Draw(canvas);
canvas.Restore(); canvas.Restore();
} }
@@ -327,7 +327,7 @@ public class SkiaNavigationPage : SkiaView
{ {
// Draw current page normally // Draw current page normally
Console.WriteLine("[SkiaNavigationPage] OnDraw: drawing _currentPage=" + _currentPage.Title); Console.WriteLine("[SkiaNavigationPage] OnDraw: drawing _currentPage=" + _currentPage.Title);
_currentPage.Bounds = bounds; _currentPage.Bounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
_currentPage.Draw(canvas); _currentPage.Draw(canvas);
// Draw back button if applicable // Draw back button if applicable
@@ -368,7 +368,7 @@ public class SkiaNavigationPage : SkiaView
return 1 - (float)Math.Pow(1 - t, 3); return 1 - (float)Math.Pow(1 - t, 3);
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
return availableSize; return availableSize;
} }

View File

@@ -187,9 +187,9 @@ public class SkiaPage : SkiaView
contentBounds.Bottom - (float)margin.Bottom); contentBounds.Bottom - (float)margin.Bottom);
// Measure and arrange the content before drawing // Measure and arrange the content before drawing
var availableSize = new SKSize(adjustedBounds.Width, adjustedBounds.Height); var availableSize = new Size(adjustedBounds.Width, adjustedBounds.Height);
_content.Measure(availableSize); _content.Measure(availableSize);
_content.Arrange(adjustedBounds); _content.Arrange(new Rect(adjustedBounds.Left, adjustedBounds.Top, adjustedBounds.Width, adjustedBounds.Height));
Console.WriteLine($"[SkiaPage] Drawing content: {_content.GetType().Name}, Bounds={_content.Bounds}, IsVisible={_content.IsVisible}"); Console.WriteLine($"[SkiaPage] Drawing content: {_content.GetType().Name}, Bounds={_content.Bounds}, IsVisible={_content.IsVisible}");
_content.Draw(canvas); _content.Draw(canvas);
} }
@@ -294,7 +294,7 @@ public class SkiaPage : SkiaView
NavigatingFrom?.Invoke(this, EventArgs.Empty); NavigatingFrom?.Invoke(this, EventArgs.Empty);
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
// Page takes all available space // Page takes all available space
return availableSize; return availableSize;

View File

@@ -419,7 +419,8 @@ public class SkiaPicker : SkiaView
private void DrawDropdownOverlay(SKCanvas canvas) private void DrawDropdownOverlay(SKCanvas canvas)
{ {
if (_items.Count == 0 || !_isOpen) return; if (_items.Count == 0 || !_isOpen) return;
DrawDropdown(canvas, ScreenBounds); var skScreenBounds = new SKRect((float)ScreenBounds.Left, (float)ScreenBounds.Top, (float)(ScreenBounds.Left + ScreenBounds.Width), (float)(ScreenBounds.Top + ScreenBounds.Height));
DrawDropdown(canvas, skScreenBounds);
} }
protected override void OnDraw(SKCanvas canvas, SKRect bounds) protected override void OnDraw(SKCanvas canvas, SKRect bounds)
@@ -808,10 +809,10 @@ public class SkiaPicker : SkiaView
#region Layout #region Layout
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
return new SKSize( return new Size(
availableSize.Width < float.MaxValue ? Math.Min(availableSize.Width, 200) : 200, availableSize.Width < double.MaxValue ? Math.Min(availableSize.Width, 200) : 200,
40); 40);
} }
@@ -837,10 +838,10 @@ public class SkiaPicker : SkiaView
var dropdownMaxHeight = (float)_dropdownMaxHeight; var dropdownMaxHeight = (float)_dropdownMaxHeight;
var dropdownHeight = Math.Min(_items.Count * itemHeight, dropdownMaxHeight); var dropdownHeight = Math.Min(_items.Count * itemHeight, dropdownMaxHeight);
var dropdownRect = new SKRect( var dropdownRect = new SKRect(
screenBounds.Left, (float)screenBounds.Left,
screenBounds.Bottom + 4, (float)(screenBounds.Top + screenBounds.Height) + 4,
screenBounds.Right, (float)(screenBounds.Left + screenBounds.Width),
screenBounds.Bottom + 4 + dropdownHeight); (float)(screenBounds.Top + screenBounds.Height) + 4 + dropdownHeight);
return dropdownRect.Contains(x, y); return dropdownRect.Contains(x, y);
} }

View File

@@ -244,10 +244,10 @@ public class SkiaProgressBar : SkiaView
#region Layout #region Layout
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var barHeight = (float)BarHeight; var barHeight = BarHeight;
return new SKSize(200f, barHeight + 8f); return new Size(200, barHeight + 8);
} }
#endregion #endregion

View File

@@ -507,7 +507,7 @@ public class SkiaRadioButton : SkiaView
#region Layout #region Layout
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var radioSize = (float)RadioSize; var radioSize = (float)RadioSize;
var fontSize = (float)FontSize; var fontSize = (float)FontSize;
@@ -520,7 +520,7 @@ public class SkiaRadioButton : SkiaView
using var paint = new SKPaint(font); using var paint = new SKPaint(font);
textWidth = paint.MeasureText(Content) + spacing; textWidth = paint.MeasureText(Content) + spacing;
} }
return new SKSize(radioSize + textWidth, Math.Max(radioSize, fontSize * 1.5f)); return new Size(radioSize + textWidth, Math.Max(radioSize, fontSize * 1.5f));
} }
#endregion #endregion

View File

@@ -130,25 +130,21 @@ public class SkiaRefreshView : SkiaLayoutView
/// </summary> /// </summary>
public event EventHandler? Refreshing; public event EventHandler? Refreshing;
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
if (_content != null) if (_content != null)
{ {
_content.Measure(availableSize); _content.Measure(new Size(availableSize.Width, availableSize.Height));
} }
return availableSize; return availableSize;
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
if (_content != null) if (_content != null)
{ {
float offset = _isRefreshing ? _refreshThreshold : _pullDistance; float offset = _isRefreshing ? _refreshThreshold : _pullDistance;
var contentBounds = new SKRect( var contentBounds = new Rect(bounds.Left, bounds.Top + offset, bounds.Width, bounds.Height);
bounds.Left,
bounds.Top + offset,
bounds.Right,
bounds.Bottom + offset);
_content.Arrange(contentBounds); _content.Arrange(contentBounds);
} }
return bounds; return bounds;

View File

@@ -240,9 +240,9 @@ public class SkiaScrollView : SkiaView
get get
{ {
// Handle infinite or NaN bounds - use a reasonable default viewport // Handle infinite or NaN bounds - use a reasonable default viewport
var viewportWidth = float.IsInfinity(Bounds.Width) || float.IsNaN(Bounds.Width) || Bounds.Width <= 0 var viewportWidth = double.IsInfinity(Bounds.Width) || double.IsNaN(Bounds.Width) || Bounds.Width <= 0
? 800f ? 800f
: Bounds.Width; : (float)Bounds.Width;
return Math.Max(0, ContentSize.Width - viewportWidth); return Math.Max(0, ContentSize.Width - viewportWidth);
} }
} }
@@ -256,9 +256,9 @@ public class SkiaScrollView : SkiaView
{ {
// Handle infinite, NaN, or unreasonably large bounds - use a reasonable default viewport // Handle infinite, NaN, or unreasonably large bounds - use a reasonable default viewport
var boundsHeight = Bounds.Height; var boundsHeight = Bounds.Height;
var viewportHeight = (float.IsInfinity(boundsHeight) || float.IsNaN(boundsHeight) || boundsHeight <= 0 || boundsHeight > 10000) var viewportHeight = (double.IsInfinity(boundsHeight) || double.IsNaN(boundsHeight) || boundsHeight <= 0 || boundsHeight > 10000)
? 544f // Default viewport height (600 - 56 for shell header) ? 544f // Default viewport height (600 - 56 for shell header)
: boundsHeight; : (float)boundsHeight;
return Math.Max(0, ContentSize.Height - viewportHeight); return Math.Max(0, ContentSize.Height - viewportHeight);
} }
} }
@@ -290,17 +290,18 @@ public class SkiaScrollView : SkiaView
// Reserve space for vertical scrollbar if content might be taller than viewport // Reserve space for vertical scrollbar if content might be taller than viewport
effectiveWidth -= ScrollBarWidth; effectiveWidth -= ScrollBarWidth;
} }
var availableSize = new SKSize(effectiveWidth, float.PositiveInfinity); var availableSize = new Size(effectiveWidth, double.PositiveInfinity);
// Update ContentSize with the properly constrained measurement // Update ContentSize with the properly constrained measurement
ContentSize = _content.Measure(availableSize); var contentDesired = _content.Measure(availableSize);
ContentSize = new SKSize((float)contentDesired.Width, (float)contentDesired.Height);
// Apply content's margin // Apply content's margin
var margin = _content.Margin; var margin = _content.Margin;
var contentBounds = new SKRect( var contentLeft = bounds.Left + (float)margin.Left;
bounds.Left + (float)margin.Left, var contentTop = bounds.Top + (float)margin.Top;
bounds.Top + (float)margin.Top, var contentWidth = Math.Max(bounds.Width, (float)_content.DesiredSize.Width) - (float)margin.Left - (float)margin.Right;
bounds.Left + Math.Max(bounds.Width, _content.DesiredSize.Width) - (float)margin.Right, var contentHeight = Math.Max(bounds.Height, (float)_content.DesiredSize.Height) - (float)margin.Top - (float)margin.Bottom;
bounds.Top + Math.Max(bounds.Height, _content.DesiredSize.Height) - (float)margin.Bottom); var contentBounds = new Rect(contentLeft, contentTop, contentWidth, contentHeight);
_content.Arrange(contentBounds); _content.Arrange(contentBounds);
canvas.Save(); canvas.Save();
@@ -358,8 +359,8 @@ public class SkiaScrollView : SkiaView
private void DrawVerticalScrollbar(SKCanvas canvas, SKRect bounds, bool hasHorizontal) private void DrawVerticalScrollbar(SKCanvas canvas, SKRect bounds, bool hasHorizontal)
{ {
var trackHeight = bounds.Height - (hasHorizontal ? ScrollBarWidth : 0); var trackHeight = bounds.Height - (hasHorizontal ? ScrollBarWidth : 0);
var thumbHeight = Math.Max(20, (bounds.Height / ContentSize.Height) * trackHeight); var thumbHeight = Math.Max(20f, (bounds.Height / ContentSize.Height) * trackHeight);
var thumbY = (ScrollY / ScrollableHeight) * (trackHeight - thumbHeight); var thumbY = ScrollableHeight > 0 ? (ScrollY / ScrollableHeight) * (trackHeight - thumbHeight) : 0f;
using var paint = new SKPaint using var paint = new SKPaint
{ {
@@ -381,8 +382,8 @@ public class SkiaScrollView : SkiaView
private void DrawHorizontalScrollbar(SKCanvas canvas, SKRect bounds, bool hasVertical) private void DrawHorizontalScrollbar(SKCanvas canvas, SKRect bounds, bool hasVertical)
{ {
var trackWidth = bounds.Width - (hasVertical ? ScrollBarWidth : 0); var trackWidth = bounds.Width - (hasVertical ? ScrollBarWidth : 0);
var thumbWidth = Math.Max(20, (bounds.Width / ContentSize.Width) * trackWidth); var thumbWidth = Math.Max(20f, (bounds.Width / ContentSize.Width) * trackWidth);
var thumbX = (ScrollX / ScrollableWidth) * (trackWidth - thumbWidth); var thumbX = ScrollableWidth > 0 ? (ScrollX / ScrollableWidth) * (trackWidth - thumbWidth) : 0f;
using var paint = new SKPaint using var paint = new SKPaint
{ {
@@ -444,8 +445,8 @@ public class SkiaScrollView : SkiaView
_scrollbarDragStartScrollY = _scrollY; _scrollbarDragStartScrollY = _scrollY;
// Cache values to prevent stutter from floating-point recalculations // Cache values to prevent stutter from floating-point recalculations
var hasHorizontal = ShouldShowHorizontalScrollbar(); var hasHorizontal = ShouldShowHorizontalScrollbar();
var trackHeight = Bounds.Height - (hasHorizontal ? ScrollBarWidth : 0); var trackHeight = (float)Bounds.Height - (hasHorizontal ? ScrollBarWidth : 0);
var thumbHeight = Math.Max(20, (Bounds.Height / ContentSize.Height) * trackHeight); var thumbHeight = Math.Max(20f, ((float)Bounds.Height / ContentSize.Height) * trackHeight);
_scrollbarDragAvailableTrack = trackHeight - thumbHeight; _scrollbarDragAvailableTrack = trackHeight - thumbHeight;
_scrollbarDragScrollableExtent = ScrollableHeight; _scrollbarDragScrollableExtent = ScrollableHeight;
return; return;
@@ -463,8 +464,8 @@ public class SkiaScrollView : SkiaView
_scrollbarDragStartScrollX = _scrollX; _scrollbarDragStartScrollX = _scrollX;
// Cache values to prevent stutter from floating-point recalculations // Cache values to prevent stutter from floating-point recalculations
var hasVertical = ShouldShowVerticalScrollbar(); var hasVertical = ShouldShowVerticalScrollbar();
var trackWidth = Bounds.Width - (hasVertical ? ScrollBarWidth : 0); var trackWidth = (float)Bounds.Width - (hasVertical ? ScrollBarWidth : 0);
var thumbWidth = Math.Max(20, (Bounds.Width / ContentSize.Width) * trackWidth); var thumbWidth = Math.Max(20f, ((float)Bounds.Width / ContentSize.Width) * trackWidth);
_scrollbarDragAvailableTrack = trackWidth - thumbWidth; _scrollbarDragAvailableTrack = trackWidth - thumbWidth;
_scrollbarDragScrollableExtent = ScrollableWidth; _scrollbarDragScrollableExtent = ScrollableWidth;
return; return;
@@ -549,34 +550,34 @@ public class SkiaScrollView : SkiaView
private SKRect GetVerticalScrollbarThumbBounds() private SKRect GetVerticalScrollbarThumbBounds()
{ {
var hasHorizontal = ShouldShowHorizontalScrollbar(); var hasHorizontal = ShouldShowHorizontalScrollbar();
var trackHeight = Bounds.Height - (hasHorizontal ? ScrollBarWidth : 0); var trackHeight = (float)Bounds.Height - (hasHorizontal ? ScrollBarWidth : 0);
var thumbHeight = Math.Max(20, (Bounds.Height / ContentSize.Height) * trackHeight); var thumbHeight = Math.Max(20f, ((float)Bounds.Height / ContentSize.Height) * trackHeight);
var thumbY = ScrollableHeight > 0 ? (ScrollY / ScrollableHeight) * (trackHeight - thumbHeight) : 0; var thumbY = ScrollableHeight > 0 ? (ScrollY / ScrollableHeight) * (trackHeight - thumbHeight) : 0f;
return new SKRect( return new SKRect(
Bounds.Right - ScrollBarWidth, (float)(Bounds.Left + Bounds.Width) - ScrollBarWidth,
Bounds.Top + thumbY, (float)Bounds.Top + thumbY,
Bounds.Right, (float)(Bounds.Left + Bounds.Width),
Bounds.Top + thumbY + thumbHeight); (float)Bounds.Top + thumbY + thumbHeight);
} }
private SKRect GetHorizontalScrollbarThumbBounds() private SKRect GetHorizontalScrollbarThumbBounds()
{ {
var hasVertical = ShouldShowVerticalScrollbar(); var hasVertical = ShouldShowVerticalScrollbar();
var trackWidth = Bounds.Width - (hasVertical ? ScrollBarWidth : 0); var trackWidth = (float)Bounds.Width - (hasVertical ? ScrollBarWidth : 0);
var thumbWidth = Math.Max(20, (Bounds.Width / ContentSize.Width) * trackWidth); var thumbWidth = Math.Max(20f, ((float)Bounds.Width / ContentSize.Width) * trackWidth);
var thumbX = ScrollableWidth > 0 ? (ScrollX / ScrollableWidth) * (trackWidth - thumbWidth) : 0; var thumbX = ScrollableWidth > 0 ? (ScrollX / ScrollableWidth) * (trackWidth - thumbWidth) : 0f;
return new SKRect( return new SKRect(
Bounds.Left + thumbX, (float)Bounds.Left + thumbX,
Bounds.Bottom - ScrollBarWidth, (float)(Bounds.Top + Bounds.Height) - ScrollBarWidth,
Bounds.Left + thumbX + thumbWidth, (float)Bounds.Left + thumbX + thumbWidth,
Bounds.Bottom); (float)(Bounds.Top + Bounds.Height));
} }
public override SkiaView? HitTest(float x, float y) public override SkiaView? HitTest(float x, float y)
{ {
if (!IsVisible || !IsEnabled || !Bounds.Contains(new SKPoint(x, y))) if (!IsVisible || !IsEnabled || !Bounds.Contains(x, y))
return null; return null;
// Check scrollbar areas FIRST before content // Check scrollbar areas FIRST before content
@@ -585,14 +586,14 @@ public class SkiaScrollView : SkiaView
{ {
var thumbBounds = GetVerticalScrollbarThumbBounds(); var thumbBounds = GetVerticalScrollbarThumbBounds();
// Check if click is in the scrollbar track area (not just thumb) // Check if click is in the scrollbar track area (not just thumb)
var trackArea = new SKRect(Bounds.Right - ScrollBarWidth, Bounds.Top, Bounds.Right, Bounds.Bottom); var trackArea = new SKRect((float)(Bounds.Left + Bounds.Width) - ScrollBarWidth, (float)Bounds.Top, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height));
if (trackArea.Contains(x, y)) if (trackArea.Contains(x, y))
return this; return this;
} }
if (ShouldShowHorizontalScrollbar() && ScrollableWidth > 0) if (ShouldShowHorizontalScrollbar() && ScrollableWidth > 0)
{ {
var trackArea = new SKRect(Bounds.Left, Bounds.Bottom - ScrollBarWidth, Bounds.Right, Bounds.Bottom); var trackArea = new SKRect((float)Bounds.Left, (float)(Bounds.Top + Bounds.Height) - ScrollBarWidth, (float)(Bounds.Left + Bounds.Width), (float)(Bounds.Top + Bounds.Height));
if (trackArea.Contains(x, y)) if (trackArea.Contains(x, y))
return this; return this;
} }
@@ -680,38 +681,40 @@ public class SkiaScrollView : SkiaView
float targetY = _scrollY; float targetY = _scrollY;
// Calculate viewport dimensions // Calculate viewport dimensions
float viewportWidth = Bounds.Width; float viewportWidth = (float)Bounds.Width;
float viewportHeight = Bounds.Height; float viewportHeight = (float)Bounds.Height;
float elementRight = (float)(elementBounds.Left + elementBounds.Width);
float elementBottom = (float)(elementBounds.Top + elementBounds.Height);
switch (position) switch (position)
{ {
case ScrollToPosition.Start: case ScrollToPosition.Start:
targetX = elementBounds.Left; targetX = (float)elementBounds.Left;
targetY = elementBounds.Top; targetY = (float)elementBounds.Top;
break; break;
case ScrollToPosition.Center: case ScrollToPosition.Center:
targetX = elementBounds.Left - (viewportWidth - elementBounds.Width) / 2; targetX = (float)elementBounds.Left - (viewportWidth - (float)elementBounds.Width) / 2;
targetY = elementBounds.Top - (viewportHeight - elementBounds.Height) / 2; targetY = (float)elementBounds.Top - (viewportHeight - (float)elementBounds.Height) / 2;
break; break;
case ScrollToPosition.End: case ScrollToPosition.End:
targetX = elementBounds.Right - viewportWidth; targetX = elementRight - viewportWidth;
targetY = elementBounds.Bottom - viewportHeight; targetY = elementBottom - viewportHeight;
break; break;
case ScrollToPosition.MakeVisible: case ScrollToPosition.MakeVisible:
default: default:
// Only scroll if element is not fully visible // Only scroll if element is not fully visible
if (elementBounds.Left < _scrollX) if (elementBounds.Left < _scrollX)
targetX = elementBounds.Left; targetX = (float)elementBounds.Left;
else if (elementBounds.Right > _scrollX + viewportWidth) else if (elementRight > _scrollX + viewportWidth)
targetX = elementBounds.Right - viewportWidth; targetX = elementRight - viewportWidth;
if (elementBounds.Top < _scrollY) if (elementBounds.Top < _scrollY)
targetY = elementBounds.Top; targetY = (float)elementBounds.Top;
else if (elementBounds.Bottom > _scrollY + viewportHeight) else if (elementBottom > _scrollY + viewportHeight)
targetY = elementBounds.Bottom - viewportHeight; targetY = elementBottom - viewportHeight;
break; break;
} }
@@ -730,15 +733,18 @@ public class SkiaScrollView : SkiaView
if (_content == null) return; if (_content == null) return;
var viewBounds = view.Bounds; var viewBounds = view.Bounds;
float viewRight = (float)(viewBounds.Left + viewBounds.Width);
float viewBottom = (float)(viewBounds.Top + viewBounds.Height);
// Check if view is fully visible // Check if view is fully visible
var visibleRect = new SKRect( var visibleRect = new SKRect(
ScrollX, ScrollX,
ScrollY, ScrollY,
ScrollX + Bounds.Width, ScrollX + (float)Bounds.Width,
ScrollY + Bounds.Height); ScrollY + (float)Bounds.Height);
if (visibleRect.Contains(viewBounds)) var viewSKRect = new SKRect((float)viewBounds.Left, (float)viewBounds.Top, viewRight, viewBottom);
if (visibleRect.Contains(viewSKRect))
return; return;
// Calculate scroll position to bring view into view // Calculate scroll position to bring view into view
@@ -746,14 +752,14 @@ public class SkiaScrollView : SkiaView
float targetY = ScrollY; float targetY = ScrollY;
if (viewBounds.Left < visibleRect.Left) if (viewBounds.Left < visibleRect.Left)
targetX = viewBounds.Left; targetX = (float)viewBounds.Left;
else if (viewBounds.Right > visibleRect.Right) else if (viewRight > visibleRect.Right)
targetX = viewBounds.Right - Bounds.Width; targetX = viewRight - (float)Bounds.Width;
if (viewBounds.Top < visibleRect.Top) if (viewBounds.Top < visibleRect.Top)
targetY = viewBounds.Top; targetY = (float)viewBounds.Top;
else if (viewBounds.Bottom > visibleRect.Bottom) else if (viewBottom > visibleRect.Bottom)
targetY = viewBounds.Bottom - Bounds.Height; targetY = viewBottom - (float)Bounds.Height;
ScrollTo(targetX, targetY, animated); ScrollTo(targetX, targetY, animated);
} }
@@ -770,7 +776,7 @@ public class SkiaScrollView : SkiaView
return Math.Clamp(value, 0, ScrollableHeight); return Math.Clamp(value, 0, ScrollableHeight);
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
if (_content != null) if (_content != null)
{ {
@@ -787,17 +793,17 @@ public class SkiaScrollView : SkiaView
{ {
case ScrollOrientation.Horizontal: case ScrollOrientation.Horizontal:
contentWidth = float.PositiveInfinity; contentWidth = float.PositiveInfinity;
contentHeight = float.IsInfinity(availableSize.Height) ? 400f : availableSize.Height; contentHeight = double.IsInfinity(availableSize.Height) ? 400f : (float)availableSize.Height;
break; break;
case ScrollOrientation.Neither: case ScrollOrientation.Neither:
contentWidth = float.IsInfinity(availableSize.Width) ? 400f : availableSize.Width; contentWidth = double.IsInfinity(availableSize.Width) ? 400f : (float)availableSize.Width;
contentHeight = float.IsInfinity(availableSize.Height) ? 400f : availableSize.Height; contentHeight = double.IsInfinity(availableSize.Height) ? 400f : (float)availableSize.Height;
break; break;
case ScrollOrientation.Both: case ScrollOrientation.Both:
// For Both: first measure with viewport width to get responsive layout // For Both: first measure with viewport width to get responsive layout
// Content can still exceed viewport if it has minimum width constraints // Content can still exceed viewport if it has minimum width constraints
// Reserve space for vertical scrollbar to prevent horizontal scrollbar // Reserve space for vertical scrollbar to prevent horizontal scrollbar
contentWidth = float.IsInfinity(availableSize.Width) ? 800f : availableSize.Width; contentWidth = double.IsInfinity(availableSize.Width) ? 800f : (float)availableSize.Width;
if (VerticalScrollBarVisibility != ScrollBarVisibility.Never) if (VerticalScrollBarVisibility != ScrollBarVisibility.Never)
contentWidth -= ScrollBarWidth; contentWidth -= ScrollBarWidth;
contentHeight = float.PositiveInfinity; contentHeight = float.PositiveInfinity;
@@ -805,14 +811,15 @@ public class SkiaScrollView : SkiaView
case ScrollOrientation.Vertical: case ScrollOrientation.Vertical:
default: default:
// Reserve space for vertical scrollbar to prevent horizontal scrollbar // Reserve space for vertical scrollbar to prevent horizontal scrollbar
contentWidth = float.IsInfinity(availableSize.Width) ? 800f : availableSize.Width; contentWidth = double.IsInfinity(availableSize.Width) ? 800f : (float)availableSize.Width;
if (VerticalScrollBarVisibility != ScrollBarVisibility.Never) if (VerticalScrollBarVisibility != ScrollBarVisibility.Never)
contentWidth -= ScrollBarWidth; contentWidth -= ScrollBarWidth;
contentHeight = float.PositiveInfinity; contentHeight = float.PositiveInfinity;
break; break;
} }
ContentSize = _content.Measure(new SKSize(contentWidth, contentHeight)); var contentDesiredMeasure = _content.Measure(new Size(contentWidth, contentHeight));
ContentSize = new SKSize((float)contentDesiredMeasure.Width, (float)contentDesiredMeasure.Height);
} }
else else
{ {
@@ -823,41 +830,41 @@ public class SkiaScrollView : SkiaView
// IMPORTANT: When available is infinite, return a reasonable viewport size, NOT content size // IMPORTANT: When available is infinite, return a reasonable viewport size, NOT content size
// A ScrollView should NOT expand to fit its content - it should stay at a fixed viewport // A ScrollView should NOT expand to fit its content - it should stay at a fixed viewport
// and scroll the content. Use a default viewport size when parent gives infinity. // and scroll the content. Use a default viewport size when parent gives infinity.
const float DefaultViewportWidth = 400f; const double DefaultViewportWidth = 400.0;
const float DefaultViewportHeight = 400f; const double DefaultViewportHeight = 400.0;
var width = float.IsInfinity(availableSize.Width) || float.IsNaN(availableSize.Width) var width = double.IsInfinity(availableSize.Width) || double.IsNaN(availableSize.Width)
? Math.Min(ContentSize.Width, DefaultViewportWidth) ? Math.Min(ContentSize.Width, DefaultViewportWidth)
: availableSize.Width; : availableSize.Width;
var height = float.IsInfinity(availableSize.Height) || float.IsNaN(availableSize.Height) var height = double.IsInfinity(availableSize.Height) || double.IsNaN(availableSize.Height)
? Math.Min(ContentSize.Height, DefaultViewportHeight) ? Math.Min(ContentSize.Height, DefaultViewportHeight)
: availableSize.Height; : availableSize.Height;
return new SKSize(width, height); return new Size(width, height);
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
// CRITICAL: If bounds has infinite height, use a fixed viewport size // CRITICAL: If bounds has infinite height, use a fixed viewport size
// NOT ContentSize.Height - that would make ScrollableHeight = 0 // NOT ContentSize.Height - that would make ScrollableHeight = 0
const float DefaultViewportHeight = 544f; // 600 - 56 for shell header const float DefaultViewportHeight = 544f; // 600 - 56 for shell header
var actualBounds = bounds; var actualBounds = bounds;
if (float.IsInfinity(bounds.Height) || float.IsNaN(bounds.Height)) if (double.IsInfinity(bounds.Height) || double.IsNaN(bounds.Height))
{ {
Console.WriteLine($"[SkiaScrollView] WARNING: Infinite/NaN height, using default viewport={DefaultViewportHeight}"); Console.WriteLine($"[SkiaScrollView] WARNING: Infinite/NaN height, using default viewport={DefaultViewportHeight}");
actualBounds = new SKRect(bounds.Left, bounds.Top, bounds.Right, bounds.Top + DefaultViewportHeight); actualBounds = new Rect(bounds.Left, bounds.Top, bounds.Width, DefaultViewportHeight);
} }
if (_content != null) if (_content != null)
{ {
// Apply content's margin and arrange content at its full size // Apply content's margin and arrange content at its full size
var margin = _content.Margin; var margin = _content.Margin;
var contentBounds = new SKRect( var contentLeft = (float)actualBounds.Left + (float)margin.Left;
actualBounds.Left + (float)margin.Left, var contentTop = (float)actualBounds.Top + (float)margin.Top;
actualBounds.Top + (float)margin.Top, var contentWidth = Math.Max((float)actualBounds.Width, ContentSize.Width) - (float)margin.Left - (float)margin.Right;
actualBounds.Left + Math.Max(actualBounds.Width, ContentSize.Width) - (float)margin.Right, var contentHeight = Math.Max((float)actualBounds.Height, ContentSize.Height) - (float)margin.Top - (float)margin.Bottom;
actualBounds.Top + Math.Max(actualBounds.Height, ContentSize.Height) - (float)margin.Bottom); var contentBounds = new Rect(contentLeft, contentTop, contentWidth, contentHeight);
_content.Arrange(contentBounds); _content.Arrange(contentBounds);
} }

View File

@@ -177,7 +177,7 @@ public class SkiaSearchBar : SkiaView
? bounds.Right - clearButtonSize - iconPadding * 2 ? bounds.Right - clearButtonSize - iconPadding * 2
: bounds.Right - iconPadding; : bounds.Right - iconPadding;
var entryBounds = new SKRect(entryLeft, bounds.Top, entryRight, bounds.Bottom); var entryBounds = new Rect(entryLeft, bounds.Top, entryRight - entryLeft, bounds.Height);
_entry.Arrange(entryBounds); _entry.Arrange(entryBounds);
_entry.Draw(canvas); _entry.Draw(canvas);
@@ -306,9 +306,9 @@ public class SkiaSearchBar : SkiaView
#region Measurement #region Measurement
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
return new SKSize(250, 40); return new Size(250, 40);
} }
#endregion #endregion

View File

@@ -750,36 +750,36 @@ public class SkiaShell : SkiaLayoutView
} }
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
// Measure current content with padding accounted for (consistent with ArrangeOverride) // Measure current content with padding accounted for (consistent with ArrangeOverride)
if (_currentContent != null) if (_currentContent != null)
{ {
float contentTop = NavBarIsVisible ? NavBarHeight : 0; float contentTop = NavBarIsVisible ? NavBarHeight : 0;
float contentBottom = TabBarIsVisible ? TabBarHeight : 0; float contentBottom = TabBarIsVisible ? TabBarHeight : 0;
var contentSize = new SKSize( var contentSize = new Size(
availableSize.Width - (float)Padding.Left - (float)Padding.Right, availableSize.Width - Padding.Left - Padding.Right,
availableSize.Height - contentTop - contentBottom - (float)Padding.Top - (float)Padding.Bottom); availableSize.Height - contentTop - contentBottom - Padding.Top - Padding.Bottom);
_currentContent.Measure(contentSize); _currentContent.Measure(contentSize);
} }
return availableSize; return availableSize;
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
Console.WriteLine($"[SkiaShell] ArrangeOverride - bounds={bounds}"); Console.WriteLine($"[SkiaShell] ArrangeOverride - bounds={bounds}");
// Arrange current content with padding // Arrange current content with padding
if (_currentContent != null) if (_currentContent != null)
{ {
float contentTop = bounds.Top + (NavBarIsVisible ? NavBarHeight : 0) + ContentPadding; float contentTop = (float)bounds.Top + (NavBarIsVisible ? NavBarHeight : 0) + ContentPadding;
float contentBottom = bounds.Bottom - (TabBarIsVisible ? TabBarHeight : 0) - ContentPadding; float contentBottom = (float)bounds.Bottom - (TabBarIsVisible ? TabBarHeight : 0) - ContentPadding;
var contentBounds = new SKRect( var contentBounds = new Rect(
bounds.Left + ContentPadding, bounds.Left + ContentPadding,
contentTop, contentTop,
bounds.Right - ContentPadding, bounds.Width - ContentPadding * 2,
contentBottom); contentBottom - contentTop);
Console.WriteLine($"[SkiaShell] Arranging content with bounds={contentBounds}, padding={ContentPadding}"); Console.WriteLine($"[SkiaShell] Arranging content with bounds={contentBounds}, padding={ContentPadding}");
_currentContent.Arrange(contentBounds); _currentContent.Arrange(contentBounds);
} }
@@ -1011,8 +1011,8 @@ public class SkiaShell : SkiaLayoutView
// Check flyout area // Check flyout area
if (_flyoutAnimationProgress > 0) if (_flyoutAnimationProgress > 0)
{ {
float flyoutX = Bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress); float flyoutX = (float)Bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress);
var flyoutBounds = new SKRect(flyoutX, Bounds.Top, flyoutX + FlyoutWidth, Bounds.Bottom); var flyoutBounds = new SKRect(flyoutX, (float)Bounds.Top, flyoutX + FlyoutWidth, (float)Bounds.Bottom);
if (flyoutBounds.Contains(x, y)) if (flyoutBounds.Contains(x, y))
{ {
@@ -1027,13 +1027,13 @@ public class SkiaShell : SkiaLayoutView
} }
// Check nav bar // Check nav bar
if (NavBarIsVisible && y < Bounds.Top + NavBarHeight) if (NavBarIsVisible && y < (float)Bounds.Top + NavBarHeight)
{ {
return this; return this;
} }
// Check tab bar // Check tab bar
if (TabBarIsVisible && y > Bounds.Bottom - TabBarHeight) if (TabBarIsVisible && y > (float)Bounds.Bottom - TabBarHeight)
{ {
return this; return this;
} }
@@ -1055,8 +1055,8 @@ public class SkiaShell : SkiaLayoutView
// Check flyout tap // Check flyout tap
if (_flyoutAnimationProgress > 0) if (_flyoutAnimationProgress > 0)
{ {
float flyoutX = Bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress); float flyoutX = (float)Bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress);
var flyoutBounds = new SKRect(flyoutX, Bounds.Top, flyoutX + FlyoutWidth, Bounds.Bottom); var flyoutBounds = new SKRect(flyoutX, (float)Bounds.Top, flyoutX + FlyoutWidth, (float)Bounds.Bottom);
if (flyoutBounds.Contains(e.X, e.Y)) if (flyoutBounds.Contains(e.X, e.Y))
{ {
@@ -1105,13 +1105,13 @@ public class SkiaShell : SkiaLayoutView
} }
// Check tab bar tap // Check tab bar tap
if (TabBarIsVisible && e.Y > Bounds.Bottom - TabBarHeight) if (TabBarIsVisible && e.Y > (float)Bounds.Bottom - TabBarHeight)
{ {
if (_selectedSectionIndex >= 0 && _selectedSectionIndex < _sections.Count) if (_selectedSectionIndex >= 0 && _selectedSectionIndex < _sections.Count)
{ {
var section = _sections[_selectedSectionIndex]; var section = _sections[_selectedSectionIndex];
float tabWidth = Bounds.Width / section.Items.Count; float tabWidth = (float)Bounds.Width / section.Items.Count;
int tappedIndex = (int)((e.X - Bounds.Left) / tabWidth); int tappedIndex = (int)((e.X - (float)Bounds.Left) / tabWidth);
tappedIndex = Math.Clamp(tappedIndex, 0, section.Items.Count - 1); tappedIndex = Math.Clamp(tappedIndex, 0, section.Items.Count - 1);
if (tappedIndex != _selectedItemIndex) if (tappedIndex != _selectedItemIndex)
@@ -1130,8 +1130,8 @@ public class SkiaShell : SkiaLayoutView
{ {
if (FlyoutIsPresented && _flyoutAnimationProgress > 0) if (FlyoutIsPresented && _flyoutAnimationProgress > 0)
{ {
float flyoutX = Bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress); float flyoutX = (float)Bounds.Left - FlyoutWidth + (FlyoutWidth * _flyoutAnimationProgress);
var flyoutBounds = new SKRect(flyoutX, Bounds.Top, flyoutX + FlyoutWidth, Bounds.Bottom); var flyoutBounds = new SKRect(flyoutX, (float)Bounds.Top, flyoutX + FlyoutWidth, (float)Bounds.Bottom);
if (flyoutBounds.Contains(e.X, e.Y)) if (flyoutBounds.Contains(e.X, e.Y))
{ {

View File

@@ -476,10 +476,10 @@ public class SkiaSlider : SkiaView
#region Layout #region Layout
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var thumbRadius = (float)ThumbRadius; var thumbRadius = ThumbRadius;
return new SKSize(200, thumbRadius * 2 + 16); return new Size(200, thumbRadius * 2 + 16);
} }
#endregion #endregion

View File

@@ -520,10 +520,10 @@ public class SkiaStepper : SkiaView
#region Layout #region Layout
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var buttonWidth = (float)ButtonWidth; var buttonWidth = ButtonWidth;
return new SKSize(buttonWidth * 2 + 1, 32); return new Size(buttonWidth * 2 + 1, 32);
} }
#endregion #endregion

View File

@@ -137,24 +137,24 @@ public class SkiaSwipeView : SkiaLayoutView
Invalidate(); Invalidate();
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
if (_content != null) if (_content != null)
{ {
_content.Measure(availableSize); _content.Measure(new Size(availableSize.Width, availableSize.Height));
} }
return availableSize; return availableSize;
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
if (_content != null) if (_content != null)
{ {
var contentBounds = new SKRect( var contentBounds = new Rect(
bounds.Left + _swipeOffset, bounds.Left + _swipeOffset,
bounds.Top, bounds.Top,
bounds.Right + _swipeOffset, bounds.Width,
bounds.Bottom); bounds.Height);
_content.Arrange(contentBounds); _content.Arrange(contentBounds);
} }
return bounds; return bounds;

View File

@@ -439,11 +439,11 @@ public class SkiaSwitch : SkiaView
#region Layout #region Layout
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var trackWidth = (float)TrackWidth; var trackWidth = TrackWidth;
var trackHeight = (float)TrackHeight; var trackHeight = TrackHeight;
return new SKSize(trackWidth + 8f, trackHeight + 8f); return new Size(trackWidth + 8, trackHeight + 8);
} }
#endregion #endregion

View File

@@ -216,11 +216,11 @@ public class SkiaTabbedPage : SkiaLayoutView
Invalidate(); Invalidate();
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
// Measure the content area (excluding tab bar) // Measure the content area (excluding tab bar)
var contentHeight = availableSize.Height - TabBarHeight; var contentHeight = availableSize.Height - TabBarHeight;
var contentSize = new SKSize(availableSize.Width, contentHeight); var contentSize = new Size(availableSize.Width, contentHeight);
foreach (var tab in _tabs) foreach (var tab in _tabs)
{ {
@@ -230,25 +230,25 @@ public class SkiaTabbedPage : SkiaLayoutView
return availableSize; return availableSize;
} }
protected override SKRect ArrangeOverride(SKRect bounds) protected override Rect ArrangeOverride(Rect bounds)
{ {
// Calculate content bounds based on tab bar position // Calculate content bounds based on tab bar position
SKRect contentBounds; Rect contentBounds;
if (TabBarOnBottom) if (TabBarOnBottom)
{ {
contentBounds = new SKRect( contentBounds = new Rect(
bounds.Left, bounds.Left,
bounds.Top, bounds.Top,
bounds.Right, bounds.Width,
bounds.Bottom - TabBarHeight); bounds.Height - TabBarHeight);
} }
else else
{ {
contentBounds = new SKRect( contentBounds = new Rect(
bounds.Left, bounds.Left,
bounds.Top + TabBarHeight, bounds.Top + TabBarHeight,
bounds.Right, bounds.Width,
bounds.Bottom); bounds.Height - TabBarHeight);
} }
// Arrange each tab's content to fill the content area // Arrange each tab's content to fill the content area
@@ -284,18 +284,18 @@ public class SkiaTabbedPage : SkiaLayoutView
if (TabBarOnBottom) if (TabBarOnBottom)
{ {
tabBarBounds = new SKRect( tabBarBounds = new SKRect(
Bounds.Left, (float)Bounds.Left,
Bounds.Bottom - TabBarHeight, (float)Bounds.Bottom - TabBarHeight,
Bounds.Right, (float)Bounds.Right,
Bounds.Bottom); (float)Bounds.Bottom);
} }
else else
{ {
tabBarBounds = new SKRect( tabBarBounds = new SKRect(
Bounds.Left, (float)Bounds.Left,
Bounds.Top, (float)Bounds.Top,
Bounds.Right, (float)Bounds.Right,
Bounds.Top + TabBarHeight); (float)Bounds.Top + TabBarHeight);
} }
// Draw background // Draw background
@@ -377,18 +377,18 @@ public class SkiaTabbedPage : SkiaLayoutView
if (TabBarOnBottom) if (TabBarOnBottom)
{ {
tabBarBounds = new SKRect( tabBarBounds = new SKRect(
Bounds.Left, (float)Bounds.Left,
Bounds.Bottom - TabBarHeight, (float)(Bounds.Top + Bounds.Height) - TabBarHeight,
Bounds.Right, (float)(Bounds.Left + Bounds.Width),
Bounds.Bottom); (float)(Bounds.Top + Bounds.Height));
} }
else else
{ {
tabBarBounds = new SKRect( tabBarBounds = new SKRect(
Bounds.Left, (float)Bounds.Left,
Bounds.Top, (float)Bounds.Top,
Bounds.Right, (float)(Bounds.Left + Bounds.Width),
Bounds.Top + TabBarHeight); (float)Bounds.Top + TabBarHeight);
} }
if (tabBarBounds.Contains(x, y)) if (tabBarBounds.Contains(x, y))
@@ -415,18 +415,18 @@ public class SkiaTabbedPage : SkiaLayoutView
if (TabBarOnBottom) if (TabBarOnBottom)
{ {
tabBarBounds = new SKRect( tabBarBounds = new SKRect(
Bounds.Left, (float)Bounds.Left,
Bounds.Bottom - TabBarHeight, (float)(Bounds.Top + Bounds.Height) - TabBarHeight,
Bounds.Right, (float)(Bounds.Left + Bounds.Width),
Bounds.Bottom); (float)(Bounds.Top + Bounds.Height));
} }
else else
{ {
tabBarBounds = new SKRect( tabBarBounds = new SKRect(
Bounds.Left, (float)Bounds.Left,
Bounds.Top, (float)Bounds.Top,
Bounds.Right, (float)(Bounds.Left + Bounds.Width),
Bounds.Top + TabBarHeight); (float)Bounds.Top + TabBarHeight);
} }
if (tabBarBounds.Contains(e.X, e.Y) && _tabs.Count > 0) if (tabBarBounds.Contains(e.X, e.Y) && _tabs.Count > 0)

View File

@@ -323,11 +323,12 @@ public abstract class SkiaTemplatedView : SkiaView
/// </summary> /// </summary>
protected abstract void DrawDefaultAppearance(SKCanvas canvas, SKRect bounds); protected abstract void DrawDefaultAppearance(SKCanvas canvas, SKRect bounds);
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
if (_templateRoot != null && _templateApplied) if (_templateRoot != null && _templateApplied)
{ {
return _templateRoot.Measure(availableSize); var measured = _templateRoot.Measure(new Size(availableSize.Width, availableSize.Height));
return new Size(measured.Width, measured.Height);
} }
return MeasureDefaultAppearance(availableSize); return MeasureDefaultAppearance(availableSize);
@@ -337,12 +338,12 @@ public abstract class SkiaTemplatedView : SkiaView
/// Measures the default appearance when no template is applied. /// Measures the default appearance when no template is applied.
/// Override in derived classes. /// Override in derived classes.
/// </summary> /// </summary>
protected virtual SKSize MeasureDefaultAppearance(SKSize availableSize) protected virtual Size MeasureDefaultAppearance(Size availableSize)
{ {
return new SKSize(100, 40); return new Size(100, 40);
} }
public new void Arrange(SKRect bounds) public new void Arrange(Rect bounds)
{ {
base.Arrange(bounds); base.Arrange(bounds);

View File

@@ -278,7 +278,8 @@ public class SkiaTimePicker : SkiaView
private void DrawClockOverlay(SKCanvas canvas) private void DrawClockOverlay(SKCanvas canvas)
{ {
if (!_isOpen) return; if (!_isOpen) return;
DrawClockPopup(canvas, ScreenBounds); var sb = ScreenBounds;
DrawClockPopup(canvas, new SKRect((float)sb.Left, (float)sb.Top, (float)sb.Right, (float)sb.Bottom));
} }
private void DrawPickerButton(SKCanvas canvas, SKRect bounds) private void DrawPickerButton(SKCanvas canvas, SKRect bounds)
@@ -499,7 +500,7 @@ public class SkiaTimePicker : SkiaView
if (IsOpen) if (IsOpen)
{ {
var screenBounds = ScreenBounds; var screenBounds = ScreenBounds;
var popupRect = GetPopupRect(screenBounds); var popupRect = GetPopupRect(new SKRect((float)screenBounds.Left, (float)screenBounds.Top, (float)screenBounds.Right, (float)screenBounds.Bottom));
var headerRect = new SKRect(popupRect.Left, popupRect.Top, popupRect.Right, popupRect.Top + HeaderHeight); var headerRect = new SKRect(popupRect.Left, popupRect.Top, popupRect.Right, popupRect.Top + HeaderHeight);
if (headerRect.Contains(e.X, e.Y)) if (headerRect.Contains(e.X, e.Y))
@@ -598,9 +599,9 @@ public class SkiaTimePicker : SkiaView
Invalidate(); Invalidate();
} }
protected override SKSize MeasureOverride(SKSize availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
return new SKSize(availableSize.Width < float.MaxValue ? Math.Min(availableSize.Width, 200) : 200, 40); return new Size(availableSize.Width < double.MaxValue ? Math.Min(availableSize.Width, 200) : 200, 40);
} }
protected override bool HitTestPopupArea(float x, float y) protected override bool HitTestPopupArea(float x, float y)
@@ -611,7 +612,7 @@ public class SkiaTimePicker : SkiaView
if (_isOpen) if (_isOpen)
{ {
var popupRect = GetPopupRect(screenBounds); var popupRect = GetPopupRect(new SKRect((float)screenBounds.Left, (float)screenBounds.Top, (float)screenBounds.Right, (float)screenBounds.Bottom));
return popupRect.Contains(x, y); return popupRect.Contains(x, y);
} }

View File

@@ -3,6 +3,7 @@
using Microsoft.Maui.Controls; using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Shapes; using Microsoft.Maui.Controls.Shapes;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Platform.Linux; using Microsoft.Maui.Platform.Linux;
using Microsoft.Maui.Platform.Linux.Handlers; using Microsoft.Maui.Platform.Linux.Handlers;
using Microsoft.Maui.Platform.Linux.Rendering; using Microsoft.Maui.Platform.Linux.Rendering;
@@ -701,14 +702,14 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
#endregion #endregion
private bool _disposed; private bool _disposed;
private SKRect _bounds; private Rect _bounds;
private SkiaView? _parent; private SkiaView? _parent;
private readonly List<SkiaView> _children = new(); private readonly List<SkiaView> _children = new();
/// <summary> /// <summary>
/// Gets the absolute bounds of this view in screen coordinates. /// Gets the absolute bounds of this view in screen coordinates.
/// </summary> /// </summary>
public SKRect GetAbsoluteBounds() public Rect GetAbsoluteBounds()
{ {
var bounds = Bounds; var bounds = Bounds;
var current = Parent; var current = Parent;
@@ -717,11 +718,11 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
// Adjust for scroll offset if parent is a ScrollView // Adjust for scroll offset if parent is a ScrollView
if (current is SkiaScrollView scrollView) if (current is SkiaScrollView scrollView)
{ {
bounds = new SKRect( bounds = new Rect(
bounds.Left - scrollView.ScrollX, bounds.Left - scrollView.ScrollX,
bounds.Top - scrollView.ScrollY, bounds.Top - scrollView.ScrollY,
bounds.Right - scrollView.ScrollX, bounds.Width,
bounds.Bottom - scrollView.ScrollY); bounds.Height);
} }
current = current.Parent; current = current.Parent;
} }
@@ -730,8 +731,9 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
/// <summary> /// <summary>
/// Gets or sets the bounds of this view in parent coordinates. /// Gets or sets the bounds of this view in parent coordinates.
/// Uses MAUI Rect for public API compliance.
/// </summary> /// </summary>
public SKRect Bounds public Rect Bounds
{ {
get => _bounds; get => _bounds;
set set
@@ -744,6 +746,15 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
} }
} }
/// <summary>
/// Gets the bounds as SKRect for internal SkiaSharp rendering.
/// </summary>
internal SKRect BoundsSK => new SKRect(
(float)_bounds.Left,
(float)_bounds.Top,
(float)_bounds.Right,
(float)_bounds.Bottom);
/// <summary> /// <summary>
/// Gets or sets whether this view is visible. /// Gets or sets whether this view is visible.
/// </summary> /// </summary>
@@ -1115,7 +1126,7 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
/// <summary> /// <summary>
/// Gets the bounds of this view in screen coordinates (accounting for scroll offsets). /// Gets the bounds of this view in screen coordinates (accounting for scroll offsets).
/// </summary> /// </summary>
public SKRect ScreenBounds public Rect ScreenBounds
{ {
get get
{ {
@@ -1127,11 +1138,11 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
{ {
if (parent is SkiaScrollView scrollView) if (parent is SkiaScrollView scrollView)
{ {
bounds = new SKRect( bounds = new Rect(
bounds.Left - scrollView.ScrollX, bounds.Left - scrollView.ScrollX,
bounds.Top - scrollView.ScrollY, bounds.Top - scrollView.ScrollY,
bounds.Right - scrollView.ScrollX, bounds.Width,
bounds.Bottom - scrollView.ScrollY); bounds.Height);
} }
parent = parent.Parent; parent = parent.Parent;
} }
@@ -1142,8 +1153,14 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
/// <summary> /// <summary>
/// Gets the desired size calculated during measure. /// Gets the desired size calculated during measure.
/// Uses MAUI Size for public API compliance.
/// </summary> /// </summary>
public SKSize DesiredSize { get; protected set; } public Size DesiredSize { get; protected set; }
/// <summary>
/// Gets the desired size as SKSize for internal SkiaSharp rendering.
/// </summary>
internal SKSize DesiredSizeSK => new SKSize((float)DesiredSize.Width, (float)DesiredSize.Height);
/// <summary> /// <summary>
/// Gets the child views. /// Gets the child views.
@@ -1262,7 +1279,9 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
// Notify rendering engine of dirty region // Notify rendering engine of dirty region
if (Bounds.Width > 0 && Bounds.Height > 0) if (Bounds.Width > 0 && Bounds.Height > 0)
{ {
SkiaRenderingEngine.Current?.InvalidateRegion(Bounds); SkiaRenderingEngine.Current?.InvalidateRegion(new SKRect(
(float)Bounds.Left, (float)Bounds.Top,
(float)Bounds.Right, (float)Bounds.Bottom));
} }
if (_parent != null) if (_parent != null)
@@ -1280,7 +1299,7 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
/// </summary> /// </summary>
public void InvalidateMeasure() public void InvalidateMeasure()
{ {
DesiredSize = SKSize.Empty; DesiredSize = Size.Zero;
_parent?.InvalidateMeasure(); _parent?.InvalidateMeasure();
Invalidate(); Invalidate();
} }
@@ -1297,14 +1316,17 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
canvas.Save(); canvas.Save();
// Get SKRect for internal rendering
var skBounds = BoundsSK;
// Apply transforms if any are set // Apply transforms if any are set
if (Scale != 1.0 || ScaleX != 1.0 || ScaleY != 1.0 || if (Scale != 1.0 || ScaleX != 1.0 || ScaleY != 1.0 ||
Rotation != 0.0 || RotationX != 0.0 || RotationY != 0.0 || Rotation != 0.0 || RotationX != 0.0 || RotationY != 0.0 ||
TranslationX != 0.0 || TranslationY != 0.0) TranslationX != 0.0 || TranslationY != 0.0)
{ {
// Calculate anchor point in absolute coordinates // Calculate anchor point in absolute coordinates
float anchorAbsX = Bounds.Left + (float)(Bounds.Width * AnchorX); float anchorAbsX = skBounds.Left + (float)(Bounds.Width * AnchorX);
float anchorAbsY = Bounds.Top + (float)(Bounds.Height * AnchorY); float anchorAbsY = skBounds.Top + (float)(Bounds.Height * AnchorY);
// Move origin to anchor point // Move origin to anchor point
canvas.Translate(anchorAbsX, anchorAbsY); canvas.Translate(anchorAbsX, anchorAbsY);
@@ -1342,20 +1364,20 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
// Draw shadow if set // Draw shadow if set
if (Shadow != null) if (Shadow != null)
{ {
DrawShadow(canvas, Bounds); DrawShadow(canvas, skBounds);
} }
// Apply clip geometry if set // Apply clip geometry if set
if (Clip != null) if (Clip != null)
{ {
ApplyClip(canvas, Bounds); ApplyClip(canvas, skBounds);
} }
// Draw background at absolute bounds // Draw background at absolute bounds
DrawBackground(canvas, Bounds); DrawBackground(canvas, skBounds);
// Draw content at absolute bounds // Draw content at absolute bounds
OnDraw(canvas, Bounds); OnDraw(canvas, skBounds);
// Draw children - they draw at their own absolute bounds // Draw children - they draw at their own absolute bounds
foreach (var child in _children) foreach (var child in _children)
@@ -1530,8 +1552,9 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
/// <summary> /// <summary>
/// Measures the desired size of this view. /// Measures the desired size of this view.
/// Uses MAUI Size for public API compliance.
/// </summary> /// </summary>
public SKSize Measure(SKSize availableSize) public Size Measure(Size availableSize)
{ {
DesiredSize = MeasureOverride(availableSize); DesiredSize = MeasureOverride(availableSize);
return DesiredSize; return DesiredSize;
@@ -1539,36 +1562,40 @@ public abstract class SkiaView : BindableObject, IDisposable, IAccessible
/// <summary> /// <summary>
/// Override to provide custom measurement. /// Override to provide custom measurement.
/// Uses MAUI Size for public API compliance.
/// </summary> /// </summary>
protected virtual SKSize MeasureOverride(SKSize availableSize) protected virtual Size MeasureOverride(Size availableSize)
{ {
var width = WidthRequest >= 0 ? (float)WidthRequest : 0; var width = WidthRequest >= 0 ? WidthRequest : 0;
var height = HeightRequest >= 0 ? (float)HeightRequest : 0; var height = HeightRequest >= 0 ? HeightRequest : 0;
return new SKSize(width, height); return new Size(width, height);
} }
/// <summary> /// <summary>
/// Arranges this view within the given bounds. /// Arranges this view within the given bounds.
/// Uses MAUI Rect for public API compliance.
/// </summary> /// </summary>
public virtual void Arrange(SKRect bounds) public virtual void Arrange(Rect bounds)
{ {
Bounds = ArrangeOverride(bounds); Bounds = ArrangeOverride(bounds);
} }
/// <summary> /// <summary>
/// Override to customize arrangement within the given bounds. /// Override to customize arrangement within the given bounds.
/// Uses MAUI Rect for public API compliance.
/// </summary> /// </summary>
protected virtual SKRect ArrangeOverride(SKRect bounds) protected virtual Rect ArrangeOverride(Rect bounds)
{ {
return bounds; return bounds;
} }
/// <summary> /// <summary>
/// Performs hit testing to find the view at the given point. /// Performs hit testing to find the view at the given point.
/// Uses MAUI Point for public API compliance.
/// </summary> /// </summary>
public virtual SkiaView? HitTest(SKPoint point) public virtual SkiaView? HitTest(Point point)
{ {
return HitTest(point.X, point.Y); return HitTest((float)point.X, (float)point.Y);
} }
/// <summary> /// <summary>

View File

@@ -137,7 +137,7 @@ public class SkiaWebView : SkiaView
private string? _userAgent; private string? _userAgent;
private CookieContainer _cookies = new(); private CookieContainer _cookies = new();
private double _loadProgress; private double _loadProgress;
private SKRect _lastBounds; private Rect _lastBounds;
private int _lastMainX; private int _lastMainX;
private int _lastMainY; private int _lastMainY;
private int _lastPosX; private int _lastPosX;
@@ -1340,7 +1340,7 @@ public class SkiaWebView : SkiaView
protected override void OnDraw(SKCanvas canvas, SKRect bounds) protected override void OnDraw(SKCanvas canvas, SKRect bounds)
{ {
base.OnDraw(canvas, bounds); base.OnDraw(canvas, bounds);
Bounds = bounds; Bounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
if (_isInitialized) if (_isInitialized)
{ {
@@ -1364,7 +1364,7 @@ public class SkiaWebView : SkiaView
if (needsUpdate && bounds.Width > 50f && bounds.Height > 50f) if (needsUpdate && bounds.Width > 50f && bounds.Height > 50f)
{ {
PositionUsingGtk(); PositionUsingGtk();
_lastBounds = bounds; _lastBounds = new Rect(bounds.Left, bounds.Top, bounds.Width, bounds.Height);
} }
} }
} }

View File

@@ -21,7 +21,9 @@
</PackageReference> </PackageReference>
<PackageReference Include="Moq" Version="4.20.70" /> <PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="FluentAssertions" Version="6.12.0" /> <PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="SkiaSharp" Version="3.116.1" /> <!-- Match main project SkiaSharp version for native library compatibility -->
<PackageReference Include="SkiaSharp" Version="2.88.9" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using FluentAssertions; using FluentAssertions;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Platform; using Microsoft.Maui.Platform;
using SkiaSharp; using SkiaSharp;
using Xunit; using Xunit;
@@ -42,7 +43,7 @@ public class SkiaButtonTests
var button = new SkiaButton { Text = "Test" }; var button = new SkiaButton { Text = "Test" };
// Act // Act
var size = button.Measure(new SKSize(1000, 1000)); var size = button.Measure(new Size(1000, 1000));
// Assert // Assert
size.Width.Should().BeGreaterThan(0); size.Width.Should().BeGreaterThan(0);
@@ -61,7 +62,7 @@ public class SkiaButtonTests
}; };
// Act // Act
var size = button.Measure(new SKSize(1000, 1000)); var size = button.Measure(new Size(1000, 1000));
// Assert - Measure returns content-based size // Assert - Measure returns content-based size
size.Width.Should().BeGreaterThan(0); size.Width.Should().BeGreaterThan(0);
@@ -100,7 +101,7 @@ public class SkiaButtonTests
{ {
// Arrange // Arrange
var button = new SkiaButton { Text = "Test" }; var button = new SkiaButton { Text = "Test" };
button.Bounds = new SKRect(0, 0, 100, 40); button.Bounds = new Rect(0, 0, 100, 40);
using var surface = SKSurface.Create(new SKImageInfo(200, 100)); using var surface = SKSurface.Create(new SKImageInfo(200, 100));
var canvas = surface.Canvas; var canvas = surface.Canvas;
@@ -129,7 +130,7 @@ public class SkiaButtonTests
{ {
// Arrange // Arrange
var button = new SkiaButton(); var button = new SkiaButton();
var color = new SKColor(0, 255, 0); var color = Microsoft.Maui.Graphics.Color.FromRgb(0, 255, 0);
// Act // Act
button.BackgroundColor = color; button.BackgroundColor = color;

View File

@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.Maui.Graphics;
using SkiaSharp; using SkiaSharp;
using Xunit; using Xunit;
@@ -15,7 +16,7 @@ public class SkiaCarouselViewTests
Assert.Equal(0, carousel.Position); Assert.Equal(0, carousel.Position);
Assert.False(carousel.Loop); Assert.False(carousel.Loop);
Assert.Equal(0f, carousel.PeekAreaInsets); Assert.Equal(0.0, carousel.PeekAreaInsets);
Assert.Equal(0, carousel.ItemCount); Assert.Equal(0, carousel.ItemCount);
} }
@@ -71,9 +72,9 @@ public class SkiaCarouselViewTests
{ {
var carousel = new SkiaCarouselView(); var carousel = new SkiaCarouselView();
carousel.PeekAreaInsets = 20f; carousel.PeekAreaInsets = 20.0;
Assert.Equal(20f, carousel.PeekAreaInsets); Assert.Equal(20.0, carousel.PeekAreaInsets);
} }
[Fact] [Fact]
@@ -180,9 +181,9 @@ public class SkiaCarouselViewTests
{ {
var carousel = new SkiaCarouselView(); var carousel = new SkiaCarouselView();
carousel.IndicatorColor = SKColors.Gray; carousel.IndicatorColor = Colors.Grey;
Assert.Equal(SKColors.Gray, carousel.IndicatorColor); Assert.Equal(Colors.Grey, carousel.IndicatorColor);
} }
[Fact] [Fact]
@@ -190,9 +191,9 @@ public class SkiaCarouselViewTests
{ {
var carousel = new SkiaCarouselView(); var carousel = new SkiaCarouselView();
carousel.SelectedIndicatorColor = SKColors.Blue; carousel.SelectedIndicatorColor = Colors.Blue;
Assert.Equal(SKColors.Blue, carousel.SelectedIndicatorColor); Assert.Equal(Colors.Blue, carousel.SelectedIndicatorColor);
} }
[Fact] [Fact]
@@ -213,7 +214,7 @@ public class SkiaCarouselViewTests
{ {
var carousel = new SkiaCarouselView(); var carousel = new SkiaCarouselView();
Assert.Equal(0f, carousel.ItemSpacing); Assert.Equal(0.0, carousel.ItemSpacing);
} }
[Fact] [Fact]
@@ -221,9 +222,9 @@ public class SkiaCarouselViewTests
{ {
var carousel = new SkiaCarouselView(); var carousel = new SkiaCarouselView();
carousel.ItemSpacing = 16f; carousel.ItemSpacing = 16.0;
Assert.Equal(16f, carousel.ItemSpacing); Assert.Equal(16.0, carousel.ItemSpacing);
} }
[Fact] [Fact]
@@ -245,7 +246,7 @@ public class SkiaCarouselViewTests
{ {
var carousel = new SkiaCarouselView(); var carousel = new SkiaCarouselView();
carousel.AddItem(new SkiaLabel { Text = "Item" }); carousel.AddItem(new SkiaLabel { Text = "Item" });
carousel.Arrange(new SKRect(0, 0, 300, 200)); carousel.Arrange(new Rect(0, 0, 300, 200));
var hit = carousel.HitTest(150, 100); var hit = carousel.HitTest(150, 100);

View File

@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using FluentAssertions; using FluentAssertions;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Platform; using Microsoft.Maui.Platform;
using SkiaSharp; using SkiaSharp;
using Xunit; using Xunit;
@@ -104,7 +105,7 @@ public class SkiaEntryTests
{ {
// Arrange // Arrange
var entry = new SkiaEntry { Text = "Hello" }; var entry = new SkiaEntry { Text = "Hello" };
entry.Bounds = new SKRect(0, 0, 200, 40); entry.Bounds = new Rect(0, 0, 200, 40);
entry.OnFocusGained(); entry.OnFocusGained();
var originalLength = entry.Text.Length; var originalLength = entry.Text.Length;
@@ -120,7 +121,7 @@ public class SkiaEntryTests
{ {
// Arrange // Arrange
var entry = new SkiaEntry { Text = "Hello" }; var entry = new SkiaEntry { Text = "Hello" };
entry.Bounds = new SKRect(0, 0, 200, 40); entry.Bounds = new Rect(0, 0, 200, 40);
entry.OnFocusGained(); entry.OnFocusGained();
// Act - Verify OnKeyDown doesn't throw // Act - Verify OnKeyDown doesn't throw
@@ -136,7 +137,7 @@ public class SkiaEntryTests
// Arrange // Arrange
var entry = new SkiaEntry { Text = "Hello", IsReadOnly = true }; var entry = new SkiaEntry { Text = "Hello", IsReadOnly = true };
var originalText = entry.Text; var originalText = entry.Text;
entry.Bounds = new SKRect(0, 0, 200, 40); entry.Bounds = new Rect(0, 0, 200, 40);
entry.OnFocusGained(); entry.OnFocusGained();
// Act // Act
@@ -164,7 +165,7 @@ public class SkiaEntryTests
{ {
// Arrange // Arrange
var entry = new SkiaEntry { Text = "Test", Placeholder = "Enter..." }; var entry = new SkiaEntry { Text = "Test", Placeholder = "Enter..." };
entry.Bounds = new SKRect(0, 0, 200, 40); entry.Bounds = new Rect(0, 0, 200, 40);
using var surface = SKSurface.Create(new SKImageInfo(300, 100)); using var surface = SKSurface.Create(new SKImageInfo(300, 100));
var canvas = surface.Canvas; var canvas = surface.Canvas;

View File

@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.Maui.Graphics;
using SkiaSharp; using SkiaSharp;
using Xunit; using Xunit;
@@ -66,9 +67,9 @@ public class SkiaIndicatorViewTests
{ {
var indicator = new SkiaIndicatorView(); var indicator = new SkiaIndicatorView();
indicator.IndicatorColor = SKColors.Gray; indicator.IndicatorColor = Colors.Grey;
Assert.Equal(SKColors.Gray, indicator.IndicatorColor); Assert.Equal(Colors.Grey, indicator.IndicatorColor);
} }
[Fact] [Fact]
@@ -76,9 +77,9 @@ public class SkiaIndicatorViewTests
{ {
var indicator = new SkiaIndicatorView(); var indicator = new SkiaIndicatorView();
indicator.SelectedIndicatorColor = SKColors.Blue; indicator.SelectedIndicatorColor = Colors.Blue;
Assert.Equal(SKColors.Blue, indicator.SelectedIndicatorColor); Assert.Equal(Colors.Blue, indicator.SelectedIndicatorColor);
} }
[Fact] [Fact]
@@ -86,9 +87,9 @@ public class SkiaIndicatorViewTests
{ {
var indicator = new SkiaIndicatorView(); var indicator = new SkiaIndicatorView();
indicator.IndicatorSize = 12f; indicator.IndicatorSize = 12.0;
Assert.Equal(12f, indicator.IndicatorSize); Assert.Equal(12.0, indicator.IndicatorSize);
} }
[Fact] [Fact]
@@ -96,9 +97,9 @@ public class SkiaIndicatorViewTests
{ {
var indicator = new SkiaIndicatorView(); var indicator = new SkiaIndicatorView();
indicator.SelectedIndicatorSize = 16f; indicator.SelectedIndicatorSize = 16.0;
Assert.Equal(16f, indicator.SelectedIndicatorSize); Assert.Equal(16.0, indicator.SelectedIndicatorSize);
} }
[Fact] [Fact]
@@ -106,9 +107,9 @@ public class SkiaIndicatorViewTests
{ {
var indicator = new SkiaIndicatorView(); var indicator = new SkiaIndicatorView();
indicator.IndicatorSpacing = 10f; indicator.IndicatorSpacing = 10.0;
Assert.Equal(10f, indicator.IndicatorSpacing); Assert.Equal(10.0, indicator.IndicatorSpacing);
} }
[Fact] [Fact]
@@ -164,9 +165,9 @@ public class SkiaIndicatorViewTests
{ {
var indicator = new SkiaIndicatorView(); var indicator = new SkiaIndicatorView();
indicator.BorderColor = SKColors.Black; indicator.BorderColor = Colors.Black;
Assert.Equal(SKColors.Black, indicator.BorderColor); Assert.Equal(Colors.Black, indicator.BorderColor);
} }
[Fact] [Fact]
@@ -174,9 +175,9 @@ public class SkiaIndicatorViewTests
{ {
var indicator = new SkiaIndicatorView(); var indicator = new SkiaIndicatorView();
indicator.BorderWidth = 2f; indicator.BorderWidth = 2.0;
Assert.Equal(2f, indicator.BorderWidth); Assert.Equal(2.0, indicator.BorderWidth);
} }
[Fact] [Fact]
@@ -232,9 +233,9 @@ public class SkiaIndicatorViewTests
{ {
var indicator = new SkiaIndicatorView(); var indicator = new SkiaIndicatorView();
indicator.Count = 5; indicator.Count = 5;
indicator.IndicatorSize = 10f; indicator.IndicatorSize = 10.0;
indicator.IndicatorSpacing = 8f; indicator.IndicatorSpacing = 8.0;
indicator.Arrange(new SKRect(0, 0, 200, 20)); indicator.Arrange(new Rect(0, 0, 200, 20));
var hit = indicator.HitTest(100, 10); var hit = indicator.HitTest(100, 10);

View File

@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.Maui.Graphics;
using SkiaSharp; using SkiaSharp;
using Xunit; using Xunit;
@@ -145,9 +146,9 @@ public class SkiaMenuBarTests
{ {
var menuBar = new SkiaMenuBar(); var menuBar = new SkiaMenuBar();
menuBar.BackgroundColor = SKColors.White; menuBar.BackgroundColor = Colors.White;
Assert.Equal(SKColors.White, menuBar.BackgroundColor); Assert.Equal(Colors.White, menuBar.BackgroundColor);
} }
[Fact] [Fact]
@@ -155,9 +156,9 @@ public class SkiaMenuBarTests
{ {
var menuBar = new SkiaMenuBar(); var menuBar = new SkiaMenuBar();
menuBar.TextColor = SKColors.Black; menuBar.TextColor = Colors.Black;
Assert.Equal(SKColors.Black, menuBar.TextColor); Assert.Equal(Colors.Black, menuBar.TextColor);
} }
[Fact] [Fact]
@@ -165,9 +166,9 @@ public class SkiaMenuBarTests
{ {
var menuBar = new SkiaMenuBar(); var menuBar = new SkiaMenuBar();
menuBar.HoverBackgroundColor = SKColors.LightGray; menuBar.HoverBackgroundColor = Colors.LightGrey;
Assert.Equal(SKColors.LightGray, menuBar.HoverBackgroundColor); Assert.Equal(Colors.LightGrey, menuBar.HoverBackgroundColor);
} }
[Fact] [Fact]
@@ -175,9 +176,9 @@ public class SkiaMenuBarTests
{ {
var menuBar = new SkiaMenuBar(); var menuBar = new SkiaMenuBar();
menuBar.ActiveBackgroundColor = SKColors.DarkGray; menuBar.ActiveBackgroundColor = Colors.DarkGrey;
Assert.Equal(SKColors.DarkGray, menuBar.ActiveBackgroundColor); Assert.Equal(Colors.DarkGrey, menuBar.ActiveBackgroundColor);
} }
[Fact] [Fact]
@@ -186,7 +187,7 @@ public class SkiaMenuBarTests
var menuBar = new SkiaMenuBar(); var menuBar = new SkiaMenuBar();
menuBar.BarHeight = 30f; menuBar.BarHeight = 30f;
var size = menuBar.Measure(new SKSize(800, 600)); var size = menuBar.Measure(new Size(800, 600));
Assert.Equal(30f, size.Height); Assert.Equal(30f, size.Height);
} }
@@ -196,7 +197,7 @@ public class SkiaMenuBarTests
{ {
var menuBar = new SkiaMenuBar(); var menuBar = new SkiaMenuBar();
var size = menuBar.Measure(new SKSize(800, 600)); var size = menuBar.Measure(new Size(800, 600));
Assert.Equal(800f, size.Width); Assert.Equal(800f, size.Width);
} }
@@ -205,7 +206,7 @@ public class SkiaMenuBarTests
public void HitTest_WithinBounds_ReturnsMenuBar() public void HitTest_WithinBounds_ReturnsMenuBar()
{ {
var menuBar = new SkiaMenuBar(); var menuBar = new SkiaMenuBar();
menuBar.Arrange(new SKRect(0, 0, 800, 28)); menuBar.Arrange(new Rect(0, 0, 800, 28));
var hit = menuBar.HitTest(400, 14); var hit = menuBar.HitTest(400, 14);
@@ -216,7 +217,7 @@ public class SkiaMenuBarTests
public void HitTest_OutsideBounds_ReturnsNull() public void HitTest_OutsideBounds_ReturnsNull()
{ {
var menuBar = new SkiaMenuBar(); var menuBar = new SkiaMenuBar();
menuBar.Arrange(new SKRect(0, 0, 800, 28)); menuBar.Arrange(new Rect(0, 0, 800, 28));
var hit = menuBar.HitTest(400, 50); var hit = menuBar.HitTest(400, 50);
@@ -266,9 +267,9 @@ public class SkiaMenuFlyoutTests
{ {
var flyout = new SkiaMenuFlyout(); var flyout = new SkiaMenuFlyout();
flyout.BackgroundColor = SKColors.White; flyout.BackgroundColor = Colors.White;
Assert.Equal(SKColors.White, flyout.BackgroundColor); Assert.Equal(Colors.White, flyout.BackgroundColor);
} }
[Fact] [Fact]
@@ -276,9 +277,9 @@ public class SkiaMenuFlyoutTests
{ {
var flyout = new SkiaMenuFlyout(); var flyout = new SkiaMenuFlyout();
flyout.TextColor = SKColors.Black; flyout.TextColor = Colors.Black;
Assert.Equal(SKColors.Black, flyout.TextColor); Assert.Equal(Colors.Black, flyout.TextColor);
} }
[Fact] [Fact]
@@ -286,9 +287,9 @@ public class SkiaMenuFlyoutTests
{ {
var flyout = new SkiaMenuFlyout(); var flyout = new SkiaMenuFlyout();
flyout.DisabledTextColor = new SKColor(160, 160, 160); flyout.DisabledTextColor = Color.FromRgb(160, 160, 160);
Assert.Equal(new SKColor(160, 160, 160), flyout.DisabledTextColor); Assert.Equal(Color.FromRgb(160, 160, 160), flyout.DisabledTextColor);
} }
[Fact] [Fact]
@@ -296,9 +297,9 @@ public class SkiaMenuFlyoutTests
{ {
var flyout = new SkiaMenuFlyout(); var flyout = new SkiaMenuFlyout();
flyout.HoverBackgroundColor = SKColors.LightBlue; flyout.HoverBackgroundColor = Colors.LightBlue;
Assert.Equal(SKColors.LightBlue, flyout.HoverBackgroundColor); Assert.Equal(Colors.LightBlue, flyout.HoverBackgroundColor);
} }
[Fact] [Fact]
@@ -306,9 +307,9 @@ public class SkiaMenuFlyoutTests
{ {
var flyout = new SkiaMenuFlyout(); var flyout = new SkiaMenuFlyout();
flyout.SeparatorColor = SKColors.Gray; flyout.SeparatorColor = Colors.Grey;
Assert.Equal(SKColors.Gray, flyout.SeparatorColor); Assert.Equal(Colors.Grey, flyout.SeparatorColor);
} }
[Fact] [Fact]

View File

@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.Maui.Graphics;
using SkiaSharp; using SkiaSharp;
using Xunit; using Xunit;
@@ -87,7 +88,7 @@ public class SkiaRefreshViewTests
{ {
var refreshView = new SkiaRefreshView(); var refreshView = new SkiaRefreshView();
Assert.Equal(new SKColor(33, 150, 243), refreshView.RefreshColor); Assert.Equal(Color.FromRgb(33, 150, 243), refreshView.RefreshColor);
} }
[Fact] [Fact]
@@ -95,9 +96,9 @@ public class SkiaRefreshViewTests
{ {
var refreshView = new SkiaRefreshView(); var refreshView = new SkiaRefreshView();
refreshView.RefreshColor = SKColors.Red; refreshView.RefreshColor = Colors.Red;
Assert.Equal(SKColors.Red, refreshView.RefreshColor); Assert.Equal(Colors.Red, refreshView.RefreshColor);
} }
[Fact] [Fact]
@@ -105,7 +106,7 @@ public class SkiaRefreshViewTests
{ {
var refreshView = new SkiaRefreshView(); var refreshView = new SkiaRefreshView();
Assert.Equal(SKColors.White, refreshView.RefreshBackgroundColor); Assert.Equal(Colors.White, refreshView.RefreshBackgroundColor);
} }
[Fact] [Fact]
@@ -113,9 +114,9 @@ public class SkiaRefreshViewTests
{ {
var refreshView = new SkiaRefreshView(); var refreshView = new SkiaRefreshView();
refreshView.RefreshBackgroundColor = SKColors.LightGray; refreshView.RefreshBackgroundColor = Colors.LightGrey;
Assert.Equal(SKColors.LightGray, refreshView.RefreshBackgroundColor); Assert.Equal(Colors.LightGrey, refreshView.RefreshBackgroundColor);
} }
[Fact] [Fact]
@@ -135,7 +136,7 @@ public class SkiaRefreshViewTests
var refreshView = new SkiaRefreshView(); var refreshView = new SkiaRefreshView();
var content = new SkiaLabel { Text = "Test" }; var content = new SkiaLabel { Text = "Test" };
refreshView.Content = content; refreshView.Content = content;
refreshView.Arrange(new SKRect(0, 0, 200, 400)); refreshView.Arrange(new Rect(0, 0, 200, 400));
var hit = refreshView.HitTest(100, 200); var hit = refreshView.HitTest(100, 200);

View File

@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using FluentAssertions; using FluentAssertions;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Platform; using Microsoft.Maui.Platform;
using SkiaSharp; using SkiaSharp;
using Xunit; using Xunit;
@@ -46,8 +47,8 @@ public class SkiaScrollViewTests
content.AddChild(new SkiaButton { Text = "1", RequestedHeight = 100 }); content.AddChild(new SkiaButton { Text = "1", RequestedHeight = 100 });
content.AddChild(new SkiaButton { Text = "2", RequestedHeight = 100 }); content.AddChild(new SkiaButton { Text = "2", RequestedHeight = 100 });
scrollView.Content = content; scrollView.Content = content;
scrollView.Measure(new SKSize(200, 100)); // Viewport smaller than content scrollView.Measure(new Size(200, 100)); // Viewport smaller than content
scrollView.Arrange(new SKRect(0, 0, 200, 100)); scrollView.Arrange(new Rect(0, 0, 200, 100));
// Act - Try to scroll below 0 // Act - Try to scroll below 0
scrollView.ScrollY = -50; scrollView.ScrollY = -50;
@@ -67,8 +68,8 @@ public class SkiaScrollViewTests
content.AddChild(new SkiaButton { Text = $"Button {i}", RequestedHeight = 50 }); content.AddChild(new SkiaButton { Text = $"Button {i}", RequestedHeight = 50 });
} }
scrollView.Content = content; scrollView.Content = content;
scrollView.Measure(new SKSize(200, 300)); scrollView.Measure(new Size(200, 300));
scrollView.Arrange(new SKRect(0, 0, 200, 300)); scrollView.Arrange(new Rect(0, 0, 200, 300));
var initialScrollY = scrollView.ScrollY; var initialScrollY = scrollView.ScrollY;
@@ -89,8 +90,8 @@ public class SkiaScrollViewTests
content.AddChild(button); content.AddChild(button);
scrollView.Content = content; scrollView.Content = content;
scrollView.Measure(new SKSize(200, 200)); scrollView.Measure(new Size(200, 200));
scrollView.Arrange(new SKRect(0, 0, 200, 200)); scrollView.Arrange(new Rect(0, 0, 200, 200));
// Act // Act
var hit = scrollView.HitTest(100, 25); var hit = scrollView.HitTest(100, 25);
@@ -111,8 +112,8 @@ public class SkiaScrollViewTests
} }
scrollView.Content = content; scrollView.Content = content;
scrollView.Measure(new SKSize(200, 100)); scrollView.Measure(new Size(200, 100));
scrollView.Arrange(new SKRect(0, 0, 200, 100)); scrollView.Arrange(new Rect(0, 0, 200, 100));
// Act // Act
scrollView.ScrollY = 50; scrollView.ScrollY = 50;
@@ -129,7 +130,7 @@ public class SkiaScrollViewTests
var content = new SkiaStackLayout(); var content = new SkiaStackLayout();
content.AddChild(new SkiaButton { Text = "Test" }); content.AddChild(new SkiaButton { Text = "Test" });
scrollView.Content = content; scrollView.Content = content;
scrollView.Bounds = new SKRect(0, 0, 200, 200); scrollView.Bounds = new Rect(0, 0, 200, 200);
using var surface = SKSurface.Create(new SKImageInfo(300, 300)); using var surface = SKSurface.Create(new SKImageInfo(300, 300));
var canvas = surface.Canvas; var canvas = surface.Canvas;
@@ -150,8 +151,8 @@ public class SkiaScrollViewTests
content.AddChild(new SkiaButton { Text = $"Button {i}", RequestedHeight = 50 }); content.AddChild(new SkiaButton { Text = $"Button {i}", RequestedHeight = 50 });
} }
scrollView.Content = content; scrollView.Content = content;
scrollView.Measure(new SKSize(200, 200)); scrollView.Measure(new Size(200, 200));
scrollView.Arrange(new SKRect(0, 0, 200, 200)); scrollView.Arrange(new Rect(0, 0, 200, 200));
// Act - Scroll to maximum // Act - Scroll to maximum
scrollView.ScrollY = 10000; // Very large value scrollView.ScrollY = 10000; // Very large value

View File

@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using FluentAssertions; using FluentAssertions;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Platform; using Microsoft.Maui.Platform;
using SkiaSharp; using SkiaSharp;
using Xunit; using Xunit;
@@ -19,7 +20,7 @@ public class SkiaSliderTests
// Assert // Assert
slider.Value.Should().Be(0); slider.Value.Should().Be(0);
slider.Minimum.Should().Be(0); slider.Minimum.Should().Be(0);
slider.Maximum.Should().Be(100); // Default maximum is 100 slider.Maximum.Should().Be(1.0); // MAUI Slider.Maximum default is 1.0
slider.IsEnabled.Should().BeTrue(); slider.IsEnabled.Should().BeTrue();
} }
@@ -120,7 +121,7 @@ public class SkiaSliderTests
{ {
// Arrange // Arrange
var slider = new SkiaSlider { Value = 50, Minimum = 0, Maximum = 100 }; var slider = new SkiaSlider { Value = 50, Minimum = 0, Maximum = 100 };
slider.Bounds = new SKRect(0, 0, 200, 40); slider.Bounds = new Rect(0, 0, 200, 40);
using var surface = SKSurface.Create(new SKImageInfo(300, 100)); using var surface = SKSurface.Create(new SKImageInfo(300, 100));
var canvas = surface.Canvas; var canvas = surface.Canvas;

View File

@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using FluentAssertions; using FluentAssertions;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Platform; using Microsoft.Maui.Platform;
using SkiaSharp; using SkiaSharp;
using Xunit; using Xunit;
@@ -68,7 +69,7 @@ public class SkiaStackLayoutTests
layout.AddChild(new SkiaButton { Text = "3" }); layout.AddChild(new SkiaButton { Text = "3" });
// Act // Act
var size = layout.Measure(new SKSize(200, 1000)); var size = layout.Measure(new Size(200, 1000));
// Assert - Size should account for 3 children with spacing // Assert - Size should account for 3 children with spacing
size.Height.Should().BeGreaterThan(0); size.Height.Should().BeGreaterThan(0);
@@ -89,7 +90,7 @@ public class SkiaStackLayoutTests
layout.AddChild(new SkiaButton { Text = "3" }); layout.AddChild(new SkiaButton { Text = "3" });
// Act // Act
var size = layout.Measure(new SKSize(1000, 200)); var size = layout.Measure(new Size(1000, 200));
// Assert - Size should account for 3 children with spacing // Assert - Size should account for 3 children with spacing
size.Width.Should().BeGreaterThan(0); size.Width.Should().BeGreaterThan(0);
@@ -111,8 +112,8 @@ public class SkiaStackLayoutTests
layout.AddChild(button2); layout.AddChild(button2);
// Act // Act
layout.Measure(new SKSize(200, 500)); layout.Measure(new Size(200, 500));
layout.Arrange(new SKRect(0, 0, 200, 500)); layout.Arrange(new Rect(0, 0, 200, 500));
// Assert - Button2 should be below Button1 // Assert - Button2 should be below Button1
button2.Bounds.Top.Should().BeGreaterThan(button1.Bounds.Top); button2.Bounds.Top.Should().BeGreaterThan(button1.Bounds.Top);
@@ -133,8 +134,8 @@ public class SkiaStackLayoutTests
layout.AddChild(button2); layout.AddChild(button2);
// Act // Act
layout.Measure(new SKSize(500, 200)); layout.Measure(new Size(500, 200));
layout.Arrange(new SKRect(0, 0, 500, 200)); layout.Arrange(new Rect(0, 0, 500, 200));
// Assert - Button2 should be to the right of Button1 // Assert - Button2 should be to the right of Button1
button2.Bounds.Left.Should().BeGreaterThan(button1.Bounds.Left); button2.Bounds.Left.Should().BeGreaterThan(button1.Bounds.Left);
@@ -147,14 +148,14 @@ public class SkiaStackLayoutTests
var layout = new SkiaStackLayout var layout = new SkiaStackLayout
{ {
Orientation = PlatformStackOrientation.Vertical, Orientation = PlatformStackOrientation.Vertical,
Padding = new SKRect(20, 20, 20, 20) Padding = new Microsoft.Maui.Thickness(20, 20, 20, 20)
}; };
var button = new SkiaButton { Text = "Test" }; var button = new SkiaButton { Text = "Test" };
layout.AddChild(button); layout.AddChild(button);
// Act // Act
layout.Measure(new SKSize(300, 300)); layout.Measure(new Size(300, 300));
layout.Arrange(new SKRect(0, 0, 300, 300)); layout.Arrange(new Rect(0, 0, 300, 300));
// Assert - Padding property is set // Assert - Padding property is set
layout.Padding.Left.Should().Be(20); layout.Padding.Left.Should().Be(20);
@@ -168,7 +169,7 @@ public class SkiaStackLayoutTests
var layout = new SkiaStackLayout(); var layout = new SkiaStackLayout();
layout.AddChild(new SkiaButton { Text = "1" }); layout.AddChild(new SkiaButton { Text = "1" });
layout.AddChild(new SkiaButton { Text = "2" }); layout.AddChild(new SkiaButton { Text = "2" });
layout.Bounds = new SKRect(0, 0, 200, 200); layout.Bounds = new Rect(0, 0, 200, 200);
using var surface = SKSurface.Create(new SKImageInfo(300, 300)); using var surface = SKSurface.Create(new SKImageInfo(300, 300));
var canvas = surface.Canvas; var canvas = surface.Canvas;
@@ -188,8 +189,8 @@ public class SkiaStackLayoutTests
layout.AddChild(button1); layout.AddChild(button1);
layout.AddChild(button2); layout.AddChild(button2);
layout.Measure(new SKSize(200, 200)); layout.Measure(new Size(200, 200));
layout.Arrange(new SKRect(0, 0, 200, 200)); layout.Arrange(new Rect(0, 0, 200, 200));
// Act - Hit test within layout bounds // Act - Hit test within layout bounds
var hit = layout.HitTest(100, 10); var hit = layout.HitTest(100, 10);

View File

@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements. // Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.Maui.Graphics;
using SkiaSharp; using SkiaSharp;
using Xunit; using Xunit;
@@ -36,7 +37,7 @@ public class SkiaSwipeViewTests
public void LeftItems_CanAddItems() public void LeftItems_CanAddItems()
{ {
var swipeView = new SkiaSwipeView(); var swipeView = new SkiaSwipeView();
var item = new SwipeItem { Text = "Delete", BackgroundColor = SKColors.Red }; var item = new SwipeItem { Text = "Delete", BackgroundColor = Colors.Red };
swipeView.LeftItems.Add(item); swipeView.LeftItems.Add(item);
@@ -48,7 +49,7 @@ public class SkiaSwipeViewTests
public void RightItems_CanAddItems() public void RightItems_CanAddItems()
{ {
var swipeView = new SkiaSwipeView(); var swipeView = new SkiaSwipeView();
var item = new SwipeItem { Text = "Archive", BackgroundColor = SKColors.Blue }; var item = new SwipeItem { Text = "Archive", BackgroundColor = Colors.Blue };
swipeView.RightItems.Add(item); swipeView.RightItems.Add(item);
@@ -146,17 +147,17 @@ public class SkiaSwipeViewTests
[Fact] [Fact]
public void SwipeItem_TextColor_CanBeSet() public void SwipeItem_TextColor_CanBeSet()
{ {
var item = new SwipeItem { TextColor = SKColors.Yellow }; var item = new SwipeItem { TextColor = Colors.Yellow };
Assert.Equal(SKColors.Yellow, item.TextColor); Assert.Equal(Colors.Yellow, item.TextColor);
} }
[Fact] [Fact]
public void SwipeItem_BackgroundColor_CanBeSet() public void SwipeItem_BackgroundColor_CanBeSet()
{ {
var item = new SwipeItem { BackgroundColor = SKColors.Green }; var item = new SwipeItem { BackgroundColor = Colors.Green };
Assert.Equal(SKColors.Green, item.BackgroundColor); Assert.Equal(Colors.Green, item.BackgroundColor);
} }
[Fact] [Fact]
@@ -190,7 +191,7 @@ public class SkiaSwipeViewTests
{ {
var swipeView = new SkiaSwipeView(); var swipeView = new SkiaSwipeView();
swipeView.Content = new SkiaLabel { Text = "Content" }; swipeView.Content = new SkiaLabel { Text = "Content" };
swipeView.Arrange(new SKRect(0, 0, 300, 50)); swipeView.Arrange(new Rect(0, 0, 300, 50));
var hit = swipeView.HitTest(150, 25); var hit = swipeView.HitTest(150, 25);
@@ -203,7 +204,7 @@ public class SkiaSwipeViewTests
var swipeView = new SkiaSwipeView(); var swipeView = new SkiaSwipeView();
swipeView.Content = new SkiaLabel { Text = "Test" }; swipeView.Content = new SkiaLabel { Text = "Test" };
var size = swipeView.Measure(new SKSize(300, 100)); var size = swipeView.Measure(new Size(300, 100));
Assert.True(size.Width <= 300); Assert.True(size.Width <= 300);
Assert.True(size.Height <= 100); Assert.True(size.Height <= 100);