diff --git a/UVtools.GUI/App.config b/UVtools.GUI/App.config
index ba44a8f..919979b 100644
--- a/UVtools.GUI/App.config
+++ b/UVtools.GUI/App.config
@@ -216,8 +216,7 @@
True
-
+
10
diff --git a/UVtools.GUI/UVtools.GUI.csproj b/UVtools.GUI/UVtools.GUI.csproj
index ce2e5d3..b1269db 100644
--- a/UVtools.GUI/UVtools.GUI.csproj
+++ b/UVtools.GUI/UVtools.GUI.csproj
@@ -133,7 +133,7 @@
True
- ..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0-preview.8.20407.11\lib\net45\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0-rc.1.20451.14\lib\net45\System.Runtime.CompilerServices.Unsafe.dll
..\packages\System.Runtime.Extensions.4.3.1\lib\net462\System.Runtime.Extensions.dll
diff --git a/UVtools.GUI/packages.config b/UVtools.GUI/packages.config
index da264e0..fa04d2d 100644
--- a/UVtools.GUI/packages.config
+++ b/UVtools.GUI/packages.config
@@ -12,7 +12,7 @@
-
+
diff --git a/UVtools.WPF/App.axaml b/UVtools.WPF/App.axaml
index 922d3b3..9b64e5d 100644
--- a/UVtools.WPF/App.axaml
+++ b/UVtools.WPF/App.axaml
@@ -4,5 +4,6 @@
+
diff --git a/UVtools.WPF/App.axaml.cs b/UVtools.WPF/App.axaml.cs
index f553192..7e288f9 100644
--- a/UVtools.WPF/App.axaml.cs
+++ b/UVtools.WPF/App.axaml.cs
@@ -17,7 +17,7 @@ namespace UVtools.WPF
public class App : Application
{
public static IThemeSelector? ThemeSelector { get; set; }
-
+ public static MainWindow MainWindow;
public static FileFormat SlicerFile = null;
public override void Initialize()
@@ -30,10 +30,11 @@ namespace UVtools.WPF
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
UserSettings.Load();
+ UserSettings.SetVersion();
ThemeSelector = Avalonia.ThemeManager.ThemeSelector.Create("Assets/Themes");
ThemeSelector.LoadSelectedTheme("Assets/selected.theme");
- desktop.MainWindow = new MainWindow
+ desktop.MainWindow = MainWindow = new MainWindow
{
//DataContext = Selector
};
diff --git a/UVtools.WPF/AppSettings.cs b/UVtools.WPF/AppSettings.cs
new file mode 100644
index 0000000..9b35e1f
--- /dev/null
+++ b/UVtools.WPF/AppSettings.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+namespace UVtools.WPF
+{
+ public static class AppSettings
+ {
+ public static Version Version => Assembly.GetEntryAssembly().GetName().Version;
+ // Supported ZoomLevels for Layer Preview.
+ // These settings eliminate very small zoom factors from the ImageBox default values,
+ // while ensuring that 4K/5K build plates can still easily fit on screen.
+ public static readonly int[] ZoomLevels =
+ {20, 25, 30, 50, 75, 100, 150, 200, 300, 400, 500, 600, 700, 800, 1200, 1600};
+
+ // Count of the bottom portion of the full zoom range which will be skipped for
+ // assignable actions such as auto-zoom level, and crosshair fade level. If values
+ // are added/removed from ZoomLevels above, this value may also need to be adjusted.
+ public const byte ZoomLevelSkipCount = 7; // Start at 2x which is index 7.
+
+ ///
+ /// Returns the zoom level at which the crosshairs will fade and no longer be displayed
+ ///
+ public static int CrosshairFadeLevel => ZoomLevels[UserSettings.Instance.LayerPreview.CrosshairFadeLevelIndex + ZoomLevelSkipCount];
+
+ ///
+ /// Returns the zoom level that will be used for autozoom actions
+ ///
+ public const ushort LockedZoomLevel = 1200;
+
+
+ ///
+ /// Minimum Zoom level to which autozoom can be locked.
+ ///
+ public const byte MinLockedZoomLevel = 200;
+ }
+}
diff --git a/UVtools.WPF/Controls/AdvancedImageBox.cs b/UVtools.WPF/Controls/AdvancedImageBox.cs
index 98c6ba2..513e11d 100644
--- a/UVtools.WPF/Controls/AdvancedImageBox.cs
+++ b/UVtools.WPF/Controls/AdvancedImageBox.cs
@@ -605,6 +605,7 @@ namespace UVtools.WPF.Controls
private void FillContainerOnPointerWheelChanged(object? sender, PointerWheelEventArgs e)
{
+ if (Image is null) return;
e.Handled = true;
if (AllowZoom && SizeMode == SizeModes.Normal)
{
diff --git a/UVtools.WPF/Controls/WindowEx.cs b/UVtools.WPF/Controls/WindowEx.cs
new file mode 100644
index 0000000..9d7a09e
--- /dev/null
+++ b/UVtools.WPF/Controls/WindowEx.cs
@@ -0,0 +1,27 @@
+using Avalonia.Controls;
+
+namespace UVtools.WPF.Controls
+{
+ public class WindowEx : Window
+ {
+ public DialogResults DialogResult { get; set; } = DialogResults.Unknown;
+ public enum DialogResults
+ {
+ Unknown,
+ OK,
+ Cancel
+ }
+
+ public void CloseWithResult()
+ {
+ Close(DialogResult);
+ }
+
+ public void ResetDataContext()
+ {
+ var old = DataContext;
+ DataContext = new object();
+ DataContext = old;
+ }
+ }
+}
diff --git a/UVtools.WPF/Extensions/BitmapExtension.cs b/UVtools.WPF/Extensions/BitmapExtension.cs
index d82b89c..c050bb8 100644
--- a/UVtools.WPF/Extensions/BitmapExtension.cs
+++ b/UVtools.WPF/Extensions/BitmapExtension.cs
@@ -114,10 +114,16 @@ namespace UVtools.WPF.Extensions
var writableBitmap = new WriteableBitmap(new PixelSize(mat.Width, mat.Height), new Vector(96, 96),
PixelFormat.Bgra8888, AlphaFormat.Unpremul);
+
+
+
using var lockBuffer = writableBitmap.Lock();
+
+
unsafe
{
+
var targetPixels = (uint*) (void*) lockBuffer.Address;
switch (mat.NumberOfChannels)
{
diff --git a/UVtools.WPF/Extensions/DrawingExtensions.cs b/UVtools.WPF/Extensions/DrawingExtensions.cs
new file mode 100644
index 0000000..179d97a
--- /dev/null
+++ b/UVtools.WPF/Extensions/DrawingExtensions.cs
@@ -0,0 +1,23 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+
+namespace UVtools.WPF.Extensions
+{
+ public static class DrawingExtensions
+ {
+ public static Avalonia.Media.Color ToAvalonia(this System.Drawing.Color color)
+ {
+ return new Avalonia.Media.Color(color.A, color.R, color.G, color.B);
+ }
+
+ public static System.Drawing.Color ToDotNet(this Avalonia.Media.Color color)
+ {
+ return System.Drawing.Color.FromArgb(color.A, color.R, color.G, color.B);
+ }
+ }
+}
diff --git a/UVtools.WPF/Extensions/WindowExtensions.cs b/UVtools.WPF/Extensions/WindowExtensions.cs
index 84d5ad3..55ecdf8 100644
--- a/UVtools.WPF/Extensions/WindowExtensions.cs
+++ b/UVtools.WPF/Extensions/WindowExtensions.cs
@@ -39,7 +39,14 @@ namespace UVtools.WPF.Extensions
=> await window.MessageBoxGeneric(message, title ?? $"{window.Title} Error", buttons, Icon.Error, WindowStartupLocation.CenterOwner, style);
public static async Task MessageBoxQuestion(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.YesNo, Style style = Style.None)
- => await window.MessageBoxGeneric(message, title ?? $"{window.Title} Question", buttons, Icon.Info, WindowStartupLocation.CenterOwner, style);
+ => await window.MessageBoxGeneric(message, title ?? $"{window.Title} Question", buttons, Icon.Setting, WindowStartupLocation.CenterOwner, style);
+
+ public static void ResetDataContext(this Window window)
+ {
+ var old = window.DataContext;
+ window.DataContext = new object();
+ window.DataContext = old;
+ }
}
}
diff --git a/UVtools.WPF/LayerCache.cs b/UVtools.WPF/LayerCache.cs
new file mode 100644
index 0000000..53660fc
--- /dev/null
+++ b/UVtools.WPF/LayerCache.cs
@@ -0,0 +1,93 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+
+using System;
+using Emgu.CV;
+using Emgu.CV.CvEnum;
+using Emgu.CV.Util;
+
+namespace UVtools.WPF
+{
+ public sealed class LayerCache
+ {
+ private Mat _image;
+ private Array _layerHierarchyJagged;
+ private VectorOfVectorOfPoint _layerContours;
+ private Mat _layerHierarchy;
+
+ public Mat Image
+ {
+ get => _image;
+ set
+ {
+ Clear();
+ _image = value;
+ ImageBgr = new Mat();
+ CvInvoke.CvtColor(value, ImageBgr, ColorConversion.Gray2Bgr);
+ }
+ }
+
+ public Mat ImageBgr { get; set; }
+
+ public VectorOfVectorOfPoint LayerContours
+ {
+ get
+ {
+ if (_layerContours is null) CacheContours();
+ return _layerContours;
+ }
+ private set => _layerContours = value;
+ }
+
+ public Mat LayerHierarchy
+ {
+ get
+ {
+ if (_layerHierarchy is null) CacheContours();
+ return _layerHierarchy;
+ }
+ private set => _layerHierarchy = value;
+ }
+
+ public Array LayerHierarchyJagged
+ {
+ get
+ {
+ if(_layerHierarchyJagged is null) CacheContours();
+ return _layerHierarchyJagged;
+ }
+ private set => _layerHierarchyJagged = value;
+ }
+
+ public void CacheContours(bool refresh = false)
+ {
+ if(refresh) Clear();
+ if (!ReferenceEquals(_layerContours, null)) return;
+ _layerContours = new VectorOfVectorOfPoint();
+ _layerHierarchy = new Mat();
+ CvInvoke.FindContours(Image, _layerContours, _layerHierarchy, RetrType.Ccomp,
+ ChainApproxMethod.ChainApproxSimple);
+ _layerHierarchyJagged = _layerHierarchy.GetData();
+ }
+
+
+ ///
+ /// Clears the cache
+ ///
+ public void Clear()
+ {
+ _image?.Dispose();
+ ImageBgr?.Dispose();
+ _layerContours?.Dispose();
+ _layerContours = null;
+ _layerHierarchy?.Dispose();
+ _layerHierarchy = null;
+ _layerHierarchyJagged = null;
+ }
+ }
+}
diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml
index 1b5c877..c918c45 100644
--- a/UVtools.WPF/MainWindow.axaml
+++ b/UVtools.WPF/MainWindow.axaml
@@ -11,35 +11,35 @@
Icon="/Assets/Icons/UVtools.ico"
>
-
+
-