diff --git a/README.md b/README.md
index 7344ad53..33b13100 100644
--- a/README.md
+++ b/README.md
@@ -94,8 +94,9 @@ ___Please star ⭐ if you like it, helps very much!___
## What's New
-### Nuget 1.2.9.6
+### Nuget 1.2.9.7
for SkiaSharp 2.88.9-preview.2.2
+* Added gestures delegate `OnGestures` to SkiaLayout.
* HotFix for SkiaCarousel always setting index at 0 upon initialization.
* HotFix for random crash accessing disposed LoadedImageSource.
* [HotFix](https://github.com/taublast/DrawnUi.Maui/issues/136) for loading images from StreamImageSource
@@ -127,6 +128,7 @@ V3 preview: subclassed `SkiaShaderEffect`, implementing `ISkiaGestureProcessor`,
## Development Notes
+* To compile the v3 version that supports NEW SHADERS you must set `true` inside `Directory.Build.props` file.
* All files to be consumed (images etc) must be placed inside the MAUI app Resources/Raw folder, subfolders allowed. If you need to load from the native app folder use prefix "file://".
* Accessibility support is compatible and is on the roadmap.
@@ -720,12 +722,6 @@ It will render a mask over its children when hovered, think of it as an inverted
## Published Apps powered by DrawnUI For .Net MAUI
-### Bug ID: Insect Identifier AI
-
-_Totally drawn with just one root view `Canvas` and `SkiaShell` for navigation. First ever drawn MAUI app!_
-
-GooglePlay: https://play.google.com/store/apps/details?id=com.niroapps.insects
-
### Racebox
_MAUI pages with canvases, custom navigation. All scrolls, cells collections, maps, buttons, labels and custom controls are drawn._
@@ -733,6 +729,13 @@ _MAUI pages with canvases, custom navigation. All scrolls, cells collections, ma
iOS: https://apps.apple.com/us/app/racebox-vehicle-dynamics/id6444165250
GooglePlay: https://play.google.com/store/apps/details?id=com.raceboxcompanion.app
+### Bug ID: Insect Identifier AI
+
+_Totally drawn with just one root view `Canvas` and `SkiaShell` for navigation. First ever drawn MAUI app!_
+
+__Ooops looks like the app API went dead, client maybe abandoned the project due to AI detecting stuff better than dedicated neural networks!__
+
+GooglePlay: https://play.google.com/store/apps/details?id=com.niroapps.insects
+
-
diff --git a/dev/github_uploadnugets.bat b/dev/github_uploadnugets.bat
index 11226b74..2252670b 100644
--- a/dev/github_uploadnugets.bat
+++ b/dev/github_uploadnugets.bat
@@ -13,8 +13,8 @@ REM Define the source directory for the packages
set "source_dir=E:\Nugets"
REM Define the list of file masks for the packages
-set "mask[1]=DrawnUi.Maui*.1.2.9.6*.nupkg"
-set "mask[2]=AppoMobi.Maui.DrawnUi.1.2.9.6*.*nupkg"
+set "mask[1]=DrawnUi.Maui*.1.2.9.7*.nupkg"
+set "mask[2]=AppoMobi.Maui.DrawnUi.1.2.9.7*.*nupkg"
set "mask_count=2"
REM Loop through each file mask
diff --git a/dev/nuget_uploadnugets.bat b/dev/nuget_uploadnugets.bat
index ba35ed1a..d1d37227 100644
--- a/dev/nuget_uploadnugets.bat
+++ b/dev/nuget_uploadnugets.bat
@@ -13,8 +13,8 @@ REM Define the source directory for the packages
set "source_dir=E:\Nugets"
REM Define the list of file masks for the packages
-set "mask[1]=DrawnUi.Maui*.1.2.9.6*.nupkg"
-set "mask[2]=AppoMobi.Maui.DrawnUi.1.2.9.6*.*nupkg"
+set "mask[1]=DrawnUi.Maui*.1.2.9.7*.nupkg"
+set "mask[2]=AppoMobi.Maui.DrawnUi.1.2.9.7*.*nupkg"
set "mask_count=2"
REM Loop through each file mask
@@ -24,7 +24,7 @@ for /L %%i in (1,1,%mask_count%) do (
REM Loop through each package file matching the mask in the source directory
for %%f in ("!source_dir!\!file_mask!") do (
echo Uploading "%%f" to NUGET.ORG with API key.
- nuget push "%%f" -Source https://api.nuget.org/v3/index.json -ApiKey %APIKEY%
+ nuget push "%%f" -Source https://api.nuget.org/v3/index.json -ApiKey %APIKEY% -SkipDuplicate
if errorlevel 1 (
echo An error occurred while uploading "%%f".
) else (
diff --git a/src/Addons/DrawnUi.Maui.Camera/DrawnUi.Maui.Camera.csproj b/src/Addons/DrawnUi.Maui.Camera/DrawnUi.Maui.Camera.csproj
index bd332139..6dbbf4a2 100644
--- a/src/Addons/DrawnUi.Maui.Camera/DrawnUi.Maui.Camera.csproj
+++ b/src/Addons/DrawnUi.Maui.Camera/DrawnUi.Maui.Camera.csproj
@@ -44,7 +44,7 @@
-
+
\ No newline at end of file
diff --git a/src/Addons/DrawnUi.Maui.Game/DrawnUi.Maui.Game.csproj b/src/Addons/DrawnUi.Maui.Game/DrawnUi.Maui.Game.csproj
index 6dcf808b..8232e474 100644
--- a/src/Addons/DrawnUi.Maui.Game/DrawnUi.Maui.Game.csproj
+++ b/src/Addons/DrawnUi.Maui.Game/DrawnUi.Maui.Game.csproj
@@ -42,7 +42,7 @@
-
+
diff --git a/src/Addons/DrawnUi.Maui.MapsUi/src/DrawnUi.Maui.MapsUi.csproj b/src/Addons/DrawnUi.Maui.MapsUi/src/DrawnUi.Maui.MapsUi.csproj
index b9b06758..d06c087e 100644
--- a/src/Addons/DrawnUi.Maui.MapsUi/src/DrawnUi.Maui.MapsUi.csproj
+++ b/src/Addons/DrawnUi.Maui.MapsUi/src/DrawnUi.Maui.MapsUi.csproj
@@ -54,7 +54,7 @@
-
+
diff --git a/src/Addons/DrawnUi.Maui.Rive/DrawnUi.Maui.Rive.csproj b/src/Addons/DrawnUi.Maui.Rive/DrawnUi.Maui.Rive.csproj
index 57b26e5a..694847f8 100644
--- a/src/Addons/DrawnUi.Maui.Rive/DrawnUi.Maui.Rive.csproj
+++ b/src/Addons/DrawnUi.Maui.Rive/DrawnUi.Maui.Rive.csproj
@@ -47,7 +47,7 @@
-
+
diff --git a/src/Addons/DrawnUi.MauiGraphics/DrawnUi.MauiGraphics.csproj b/src/Addons/DrawnUi.MauiGraphics/DrawnUi.MauiGraphics.csproj
index 58c28344..9d1c496c 100644
--- a/src/Addons/DrawnUi.MauiGraphics/DrawnUi.MauiGraphics.csproj
+++ b/src/Addons/DrawnUi.MauiGraphics/DrawnUi.MauiGraphics.csproj
@@ -41,7 +41,7 @@
-
+
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 109d7734..ba4d863c 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -5,13 +5,13 @@
Using SkiaSharp 2.xx. Checkout the DrawnUi Sandbox project for usage example.
- 1.2.9.6
+ 1.2.9.7
$(DefineConstants);SKIA3
Using SkiaSharp 3-preview. New handlers, SKSL, WinUI hardware acceleration etc..
- 1.3.55.1-pre
+ 1.3.56.1-pre
\ No newline at end of file
diff --git a/src/Engine/Draw/Base/SkiaControl.Shared.cs b/src/Engine/Draw/Base/SkiaControl.Shared.cs
index 34242037..66a268c1 100644
--- a/src/Engine/Draw/Base/SkiaControl.Shared.cs
+++ b/src/Engine/Draw/Base/SkiaControl.Shared.cs
@@ -5858,19 +5858,14 @@ public bool SetupShadow(SKPaint paint, SkiaShadow shadow, float scale)
{
if (shadow != null && paint != null)
{
-
- if (LastShadow == null || LastShadow.Shadow != shadow ||
- LastShadow.Scale != scale)
+ var kill = LastShadow;
+ LastShadow = new()
{
- var kill = LastShadow;
- LastShadow = new()
- {
- Filter = CreateShadow(shadow, scale),
- Scale = scale,
- Shadow = shadow
- };
- DisposeObject(kill);
- }
+ Filter = CreateShadow(shadow, scale),
+ Scale = scale,
+ Shadow = shadow
+ };
+ DisposeObject(kill);
var old = paint.ImageFilter;
paint.ImageFilter = LastShadow.Filter;
diff --git a/src/Engine/Draw/Layout/SkiaLayout.Grid.Structure.cs b/src/Engine/Draw/Layout/SkiaLayout.Grid.Structure.cs
index df99eaec..610558e7 100644
--- a/src/Engine/Draw/Layout/SkiaLayout.Grid.Structure.cs
+++ b/src/Engine/Draw/Layout/SkiaLayout.Grid.Structure.cs
@@ -5,92 +5,6 @@
namespace DrawnUi.Maui.Draw;
-public static class FluentExtensions
-{
- public static T With(this T view, Action action) where T : SkiaControl
- {
- action?.Invoke(view);
- return view;
- }
-
- public static T WithParent(this T view, IDrawnBase parent) where T : SkiaControl
- {
- parent.AddSubView(view);
- return view;
- }
-
- public static T CenterX(this T view) where T : SkiaControl
- {
- view.HorizontalOptions = LayoutOptions.Center;
- return view;
- }
-
- public static T CenterY(this T view) where T : SkiaControl
- {
- view.VerticalOptions = LayoutOptions.Center;
- return view;
- }
-
-}
-
-public static class GridExtensions
-{
- public static T WithRow(this T view, int row) where T : SkiaControl
- {
- Grid.SetRow(view, row);
- return view;
- }
-
- public static T WithColumn(this T view, int column) where T : SkiaControl
- {
- Grid.SetColumn(view, column);
- return view;
- }
-
- public static T WithRowSpan(this T view, int rowSpan) where T : SkiaControl
- {
- Grid.SetRowSpan(view, rowSpan);
- return view;
- }
-
- public static T WithColumnSpan(this T view, int columnSpan) where T : SkiaControl
- {
- Grid.SetColumnSpan(view, columnSpan);
- return view;
- }
-
- public static SkiaLayout WithColumnDefinitions(this SkiaLayout grid, string columnDefinitions)
- {
- var converter = new ColumnDefinitionCollectionTypeConverter();
-
- if (converter.CanConvertFrom(typeof(string)))
- {
- var columns = (ColumnDefinitionCollection)converter.ConvertFromInvariantString(columnDefinitions);
- grid.ColumnDefinitions = columns;
- }
- else
- {
- throw new InvalidOperationException("ColumnDefinitionCollectionTypeConverter cannot convert from string.");
- }
- return grid;
- }
- public static SkiaLayout WithRowDefinitions(this SkiaLayout grid, string definitions)
- {
- var converter = new ColumnDefinitionCollectionTypeConverter();
-
- if (converter.CanConvertFrom(typeof(string)))
- {
- var defs = (RowDefinitionCollection)converter.ConvertFromInvariantString(definitions);
- grid.RowDefinitions = defs;
- }
- else
- {
- throw new InvalidOperationException("RowDefinitionCollectionTypeConverter cannot convert from string.");
- }
- return grid;
- }
-}
-
public partial class SkiaLayout
{
public class SkiaGridStructure
diff --git a/src/Engine/Draw/Layout/SkiaLayout.cs b/src/Engine/Draw/Layout/SkiaLayout.cs
index ec35b81a..6e78b40e 100644
--- a/src/Engine/Draw/Layout/SkiaLayout.cs
+++ b/src/Engine/Draw/Layout/SkiaLayout.cs
@@ -8,6 +8,30 @@ namespace DrawnUi.Maui.Draw
public partial class SkiaLayout : SkiaControl, ISkiaGestureListener, ISkiaGridLayout
{
+ ///
+ /// For easier code-behind use
+ ///
+ ///
+ ///
+ ///
+ public override ISkiaGestureListener OnSkiaGestureEvent(SkiaGesturesParameters args, GestureEventProcessingInfo apply)
+ {
+ if (!CanDraw)
+ return null;
+
+ if (OnGestures != null)
+ {
+ return OnGestures(args, apply);
+ }
+
+ return base.OnSkiaGestureEvent(args, apply);
+ }
+
+ ///
+ /// Delegate for use instead of calling base.OnSkiaGestureEvent
+ ///
+ public Func OnGestures;
+
public override bool IsGestureForChild(SkiaControlWithRect child, SKPoint point)
{
if (this.IsStack)
@@ -978,6 +1002,8 @@ public override void OnDisposing()
StackStructure?.Clear();
StackStructureMeasured?.Clear();
+ OnGestures = null;
+
base.OnDisposing();
}
diff --git a/src/Engine/Internals/Extensions/FluentExtensions.cs b/src/Engine/Internals/Extensions/FluentExtensions.cs
new file mode 100644
index 00000000..a6787010
--- /dev/null
+++ b/src/Engine/Internals/Extensions/FluentExtensions.cs
@@ -0,0 +1,89 @@
+namespace DrawnUi.Maui.Draw
+{
+ public static class FluentExtensions
+ {
+ public static T With(this T view, Action action) where T : SkiaControl
+ {
+ action?.Invoke(view);
+ return view;
+ }
+
+ public static T WithParent(this T view, IDrawnBase parent) where T : SkiaControl
+ {
+ parent.AddSubView(view);
+ return view;
+ }
+
+ public static T CenterX(this T view) where T : SkiaControl
+ {
+ view.HorizontalOptions = LayoutOptions.Center;
+ return view;
+ }
+
+ public static T CenterY(this T view) where T : SkiaControl
+ {
+ view.VerticalOptions = LayoutOptions.Center;
+ return view;
+ }
+
+
+ #region GRID
+
+ public static T WithRow(this T view, int row) where T : SkiaControl
+ {
+ Grid.SetRow(view, row);
+ return view;
+ }
+
+ public static T WithColumn(this T view, int column) where T : SkiaControl
+ {
+ Grid.SetColumn(view, column);
+ return view;
+ }
+
+ public static T WithRowSpan(this T view, int rowSpan) where T : SkiaControl
+ {
+ Grid.SetRowSpan(view, rowSpan);
+ return view;
+ }
+
+ public static T WithColumnSpan(this T view, int columnSpan) where T : SkiaControl
+ {
+ Grid.SetColumnSpan(view, columnSpan);
+ return view;
+ }
+
+ public static SkiaLayout WithColumnDefinitions(this SkiaLayout grid, string columnDefinitions)
+ {
+ var converter = new ColumnDefinitionCollectionTypeConverter();
+
+ if (converter.CanConvertFrom(typeof(string)))
+ {
+ var columns = (ColumnDefinitionCollection)converter.ConvertFromInvariantString(columnDefinitions);
+ grid.ColumnDefinitions = columns;
+ }
+ else
+ {
+ throw new InvalidOperationException("ColumnDefinitionCollectionTypeConverter cannot convert from string.");
+ }
+ return grid;
+ }
+ public static SkiaLayout WithRowDefinitions(this SkiaLayout grid, string definitions)
+ {
+ var converter = new ColumnDefinitionCollectionTypeConverter();
+
+ if (converter.CanConvertFrom(typeof(string)))
+ {
+ var defs = (RowDefinitionCollection)converter.ConvertFromInvariantString(definitions);
+ grid.RowDefinitions = defs;
+ }
+ else
+ {
+ throw new InvalidOperationException("RowDefinitionCollectionTypeConverter cannot convert from string.");
+ }
+ return grid;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/samples/Sandbox/App.xaml b/src/samples/Sandbox/App.xaml
index 3638ba9f..e31c9cc4 100644
--- a/src/samples/Sandbox/App.xaml
+++ b/src/samples/Sandbox/App.xaml
@@ -3,8 +3,8 @@
x:Class="Sandbox.App"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
- xmlns:xaml="clr-namespace:DrawnUi.Maui.Infrastructure.Xaml;assembly=DrawnUi.Maui"
- xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit">
+ xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
+ xmlns:xaml="clr-namespace:DrawnUi.Maui.Infrastructure.Xaml;assembly=DrawnUi.Maui">
diff --git a/src/samples/Sandbox/MainPageCodeBehindEmpty.cs b/src/samples/Sandbox/MainPageCodeBehindEmpty.cs
new file mode 100644
index 00000000..4d63374c
--- /dev/null
+++ b/src/samples/Sandbox/MainPageCodeBehindEmpty.cs
@@ -0,0 +1,51 @@
+using Sandbox.Views;
+using Canvas = DrawnUi.Maui.Views.Canvas;
+
+namespace Sandbox
+{
+ public class MainPageCodeBehindEmpty : BasePage, IDisposable
+ {
+ Canvas Canvas;
+
+ public void Dispose()
+ {
+ this.Content = null;
+ Canvas?.Dispose();
+ }
+
+ public MainPageCodeBehindEmpty()
+ {
+#if DEBUG
+ HotReloadService.UpdateApplicationEvent += ReloadUI;
+#endif
+ Build();
+ }
+
+ private int _reloads;
+
+ void Build()
+ {
+ Canvas?.Dispose();
+
+ Canvas = new Canvas()
+ {
+ VerticalOptions = LayoutOptions.Fill,
+ HorizontalOptions = LayoutOptions.Fill,
+ BackgroundColor = Colors.LightGray
+ };
+
+ _reloads++;
+
+ this.Content = Canvas;
+ }
+
+ private void ReloadUI(Type[] obj)
+ {
+ MainThread.BeginInvokeOnMainThread(() =>
+ {
+ Build();
+ });
+ }
+
+ }
+}
diff --git a/src/samples/Sandbox/MainPageCodeForVideo.cs b/src/samples/Sandbox/MainPageCodeForVideo.cs
new file mode 100644
index 00000000..affa8bf5
--- /dev/null
+++ b/src/samples/Sandbox/MainPageCodeForVideo.cs
@@ -0,0 +1,143 @@
+using AppoMobi.Maui.Gestures;
+using Sandbox.Views;
+using Canvas = DrawnUi.Maui.Views.Canvas;
+
+namespace Sandbox
+{
+ public class MainPageCodeForVideo : BasePage, IDisposable
+ {
+ Canvas Canvas;
+
+ public void Dispose()
+ {
+ this.Content = null;
+ Canvas?.Dispose();
+ }
+
+ public MainPageCodeForVideo()
+ {
+#if DEBUG
+ HotReloadService.UpdateApplicationEvent += ReloadUI;
+#endif
+ Build();
+ }
+
+ private int _reloads;
+
+ private int _counter;
+ private SkiaLabel _label;
+
+ void Build()
+ {
+ Canvas?.Dispose();
+
+ Canvas = new Canvas()
+ {
+ Gestures = GesturesMode.Enabled,
+ BackgroundColor = Colors.LightGray,
+ Content = new SkiaLayout()
+ {
+ UseCache = SkiaCacheType.Image,
+ Children = new List()
+ {
+ new SkiaShape()
+ {
+ MinimumWidthRequest = 200,
+ Margin = 10,
+ StrokeColor = Colors.Black,
+ StrokeWidth = 1,
+ CornerRadius = 16,
+ BackgroundColor = Colors.CadetBlue,
+ Padding = new Thickness(16,8),
+ Content = new SkiaLayout()
+ {
+ Spacing = 12,
+ HorizontalOptions = LayoutOptions.Center,
+ Type = LayoutType.Row,
+ Children = new List()
+ {
+ new SkiaSvg()
+ {
+ WidthRequest = 18,
+ LockRatio = 1,
+ SvgString = "",
+ TintColor = Colors.White
+ },
+ new SkiaLabel()
+ {
+ TranslationY = -1,
+ TextColor = Colors.White,
+ VerticalOptions = LayoutOptions.Center,
+ Text="Placeholder"
+ }.With((c) =>
+ {
+ _label = c;
+ })
+ }
+ }
+ }.With((c) =>
+ {
+ c.Shadows.Add(new ()
+ {
+ Color = Colors.Black,
+ Blur = 2,
+ X = 2, Y=2
+ });
+ c.OnGestures = (args, info) =>
+ {
+ if (args.Type == TouchActionResult.Down)
+ {
+ c.TranslationX = 1;
+ c.TranslationY = 1;
+
+ var shadow = c.Shadows[0];
+ shadow.X = 0;
+ shadow.X = 0;
+
+ c.BackgroundColor = Colors.Blue;
+
+ return c;
+ }
+
+ if (args.Type == TouchActionResult.Up)
+ {
+ c.BackgroundColor = Colors.CadetBlue;
+
+
+ c.TranslationX = 0;
+ c.TranslationY = 0;
+
+ var shadow = c.Shadows[0];
+ shadow.X = 2;
+ shadow.X = 2;
+ }
+
+ if (args.Type == TouchActionResult.Tapped)
+ {
+ _label.Text = $"Was tapped {_counter++} time(s)";
+
+ return c;
+ }
+
+ return null;
+ };
+ })
+ }
+ }
+ };
+
+ _reloads++;
+
+ this.Content = Canvas;
+ }
+
+ private void ReloadUI(Type[] obj)
+ {
+ MainThread.BeginInvokeOnMainThread(() =>
+ {
+ Build();
+ });
+ }
+
+ }
+}
diff --git a/src/samples/Sandbox/Views/MainPageShader.xaml b/src/samples/Sandbox/Views/MainPageShader.xaml
index 8b97feec..aa0a1879 100644
--- a/src/samples/Sandbox/Views/MainPageShader.xaml
+++ b/src/samples/Sandbox/Views/MainPageShader.xaml
@@ -102,7 +102,7 @@
SecondarySource="Images/leather.jpg"
VerticalMargin="{Binding Source={x:Reference Texture}, Path=Margins.Top}">
-
+
-
+