diff --git a/CHANGELOG.md b/CHANGELOG.md index c097926..6bdf59b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## /09/2020 - v0.8.2.3 + + ## 16/09/2020 - v0.8.2.2 * (Add) Support for PHZ zip files when renamed to .zip diff --git a/CreateRelease.ps1 b/CreateRelease.ps1 index 03f5a5a..45dc54b 100644 --- a/CreateRelease.ps1 +++ b/CreateRelease.ps1 @@ -1,7 +1,7 @@ cd $PSScriptRoot $version = (Get-Command UVtools.GUI\bin\Release\UVtools.Core.dll).FileVersionInfo.FileVersion -Remove-Item "$PSScriptRoot\UVtools.GUI\bin\Release\Logs" -Recurse +Remove-Item "$PSScriptRoot\UVtools.GUI\bin\Release\Logs" -Recurse -ErrorAction Ignore Add-Type -A System.IO.Compression.FileSystem [IO.Compression.ZipFile]::CreateFromDirectory("$PSScriptRoot\UVtools.GUI\bin\Release", "$PSScriptRoot\UVtools.GUI\bin\UVtools_v$version.zip") diff --git a/UVtools.Core/FileFormats/UVJFile.cs b/UVtools.Core/FileFormats/UVJFile.cs index 4b56d0c..79d232b 100644 --- a/UVtools.Core/FileFormats/UVJFile.cs +++ b/UVtools.Core/FileFormats/UVJFile.cs @@ -350,6 +350,8 @@ namespace UVtools.Core.FileFormats public override void Decode(string fileFullPath, OperationProgress progress = null) { base.Decode(fileFullPath, progress); + if(progress is null) progress = new OperationProgress(); + progress.Reset(OperationProgress.StatusGatherLayers, LayerCount); FileFullPath = fileFullPath; using (var inputFile = ZipFile.Open(FileFullPath, ZipArchiveMode.Read)) diff --git a/UVtools.Core/Objects/BindableBase.cs b/UVtools.Core/Objects/BindableBase.cs index 5f9447b..946b5ca 100644 --- a/UVtools.Core/Objects/BindableBase.cs +++ b/UVtools.Core/Objects/BindableBase.cs @@ -49,6 +49,12 @@ namespace UVtools.Core.Objects return true; } + protected bool SetProperty([CallerMemberName] string propertyName = null) + { + OnPropertyChanged(propertyName); + return true; + } + /// /// Notifies listeners that a property value has changed. /// diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index f39e99f..9d1d0f1 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -10,12 +10,12 @@ https://github.com/sn4k3/UVtools https://github.com/sn4k3/UVtools MSLA/DLP, file analysis, repair, conversion and manipulation - 0.8.2.2 + 0.8.2.3 Copyright © 2020 PTRTECH UVtools.png AnyCPU;x64 - 0.8.2.2 - 0.8.2.2 + 0.8.2.3 + 0.8.2.3 diff --git a/UVtools.GUI/Properties/AssemblyInfo.cs b/UVtools.GUI/Properties/AssemblyInfo.cs index 442aef9..e011fe6 100644 --- a/UVtools.GUI/Properties/AssemblyInfo.cs +++ b/UVtools.GUI/Properties/AssemblyInfo.cs @@ -35,5 +35,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.8.2.2")] -[assembly: AssemblyFileVersion("0.8.2.2")] +[assembly: AssemblyVersion("0.8.2.3")] +[assembly: AssemblyFileVersion("0.8.2.3")] diff --git a/UVtools.WPF/App.axaml.cs b/UVtools.WPF/App.axaml.cs index d4730d7..85895f8 100644 --- a/UVtools.WPF/App.axaml.cs +++ b/UVtools.WPF/App.axaml.cs @@ -1,11 +1,15 @@ -using System.Diagnostics; +/* + * 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 Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using Avalonia.ThemeManager; -using MessageBox.Avalonia.DTO; -using MessageBox.Avalonia.Enums; -using MessageBox.Avalonia.Models; using UVtools.Core.FileFormats; namespace UVtools.WPF @@ -25,16 +29,16 @@ namespace UVtools.WPF { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - Selector = ThemeSelector.Create("Themes"); - Selector.LoadSelectedTheme("UVtools.theme"); + UserSettings.Load(); + + Selector = ThemeSelector.Create("Assets/Themes"); + Selector.LoadSelectedTheme("Assets/selected.theme"); desktop.MainWindow = new MainWindow { //DataContext = Selector }; desktop.Exit += (sender, e) - => Selector.SaveSelectedTheme("UVtools.theme"); - - Debug.WriteLine(Selector.Themes[1].Name); + => Selector.SaveSelectedTheme("Assets/selected.theme"); } base.OnFrameworkInitializationCompleted(); diff --git a/UVtools.WPF/Assets/Icons/UVtools.ico b/UVtools.WPF/Assets/Icons/UVtools.ico new file mode 100644 index 0000000..2a642ec Binary files /dev/null and b/UVtools.WPF/Assets/Icons/UVtools.ico differ diff --git a/UVtools.WPF/Themes/UVtools.themes b/UVtools.WPF/Assets/Themes/UVtools.themes similarity index 100% rename from UVtools.WPF/Themes/UVtools.themes rename to UVtools.WPF/Assets/Themes/UVtools.themes diff --git a/UVtools.WPF/Themes/UVtoolsDark.xaml b/UVtools.WPF/Assets/Themes/UVtoolsDark.xaml similarity index 100% rename from UVtools.WPF/Themes/UVtoolsDark.xaml rename to UVtools.WPF/Assets/Themes/UVtoolsDark.xaml diff --git a/UVtools.WPF/Themes/UVtoolsLight.xaml b/UVtools.WPF/Assets/Themes/UVtoolsLight.xaml similarity index 100% rename from UVtools.WPF/Themes/UVtoolsLight.xaml rename to UVtools.WPF/Assets/Themes/UVtoolsLight.xaml diff --git a/UVtools.WPF/Extensions/BitmapExtension.cs b/UVtools.WPF/Extensions/BitmapExtension.cs index deee547..d82b89c 100644 --- a/UVtools.WPF/Extensions/BitmapExtension.cs +++ b/UVtools.WPF/Extensions/BitmapExtension.cs @@ -1,4 +1,11 @@ -using System; +/* + * 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 System.Diagnostics; using System.Runtime.InteropServices; using Avalonia; @@ -16,6 +23,55 @@ namespace UVtools.WPF.Extensions /// public static class BitmapExtension { + public static int GetStep(this WriteableBitmap bitmap) + => (int)(bitmap.Size.Width * 4); + + /// + /// Gets the total length of this + /// + /// + /// The total length of this + public static int GetLength(this WriteableBitmap bitmap) + => (int) (bitmap.Size.Width * 4 * bitmap.Size.Height); + + public static int GetPixelPos(this WriteableBitmap bitmap, int x, int y) + => (int)(bitmap.Size.Width * 4 * y + x); + + /// + /// Gets a single pixel span to manipulate or read pixels + /// + /// Pixel type + /// Input + /// A containing all pixels in data memory + public static unsafe Span GetPixelSpan(this WriteableBitmap bitmap) + { + using var l = bitmap.Lock(); + return new Span(l.Address.ToPointer(), bitmap.GetLength()); + } + + + public static unsafe Span GetPixelSpan(this WriteableBitmap bitmap, int length, int offset = 0) + { + using var l = bitmap.Lock(); + return new Span(IntPtr.Add(l.Address, offset).ToPointer(), length); + } + + public static Span GetSinglePixelSpan(this WriteableBitmap bitmap, int x, int y, int length = 3) + { + using var l = bitmap.Lock(); + return bitmap.GetPixelSpan(length, bitmap.GetPixelPos(x, y)); + } + + public static Span GetSinglePixelPosSpan(this WriteableBitmap bitmap, int pos, int length = 3) + => bitmap.GetPixelSpan(length, pos); + + + public static unsafe Span GetPixelRowSpan(this WriteableBitmap bitmap, int y, int length = 0, int offset = 0) + { + using var l = bitmap.Lock(); + return new Span(IntPtr.Add(l.Address, (int) (bitmap.Size.Width * 4 * y + offset)).ToPointer(), (int) (length == 0 ? bitmap.Size.Width * 4 : length)); + } + public static SKBitmap ToSkBitmap(this Mat mat) { SKBitmap bitmap; @@ -52,65 +108,77 @@ namespace UVtools.WPF.Extensions return SKImage.FromBitmap(bitmap); } - public static Bitmap ToBitmap(this Mat mat) + public static WriteableBitmap ToBitmap(this Mat mat) { - if (mat.NumberOfChannels == 1) - { - var writeableBitmap = new WriteableBitmap(new PixelSize(mat.Width, mat.Height), new Vector(72, 72), - PixelFormat.Rgba8888, AlphaFormat.Unpremul); - var span = mat.GetPixelSpan(); - var bytes = new[] {0, 0, 0, 255}; - using (var lockBuffer = writeableBitmap.Lock()) - { - for (var i = 1; i < span.Length; i++) - { - bytes[0] = bytes[1] = bytes[2] = span[i]; - Marshal.Copy(bytes, 0, - new IntPtr(lockBuffer.Address.ToInt64() + i * 4), bytes.Length); - } - } + var dataCount = mat.Width * mat.Height; - return writeableBitmap; + 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) + { + //Stopwatch sw = Stopwatch.StartNew(); + // Method 1 (Span copy) + case 1: + var srcPixels1 = (byte*) (void*) mat.DataPointer; + for (var i = 0; i < dataCount; i++) + { + var color = srcPixels1[i]; + targetPixels[i] = (uint) (color | color << 8 | color << 16 | 0xff << 24); + } + + break; + case 3: + var srcPixels2 = (byte*) (void*) mat.DataPointer; + uint pixel = 0; + for (uint i = 0; i < dataCount; i++) + { + targetPixels[i] = (uint)(srcPixels2[pixel++] | srcPixels2[pixel++] << 8 | srcPixels2[pixel++] << 16 | 0xff << 24); + } + + break; + case 4: + var srcPixels4 = (uint*) (void*) mat.DataPointer; + for (uint i = 0; i < dataCount; i++) + { + targetPixels[i] = srcPixels4[i]; + } + + break; + } } - return null; - } - /*PixelFormat targetPixelFormat = PixelFormat.Bgra8888; - - switch (mat.NumberOfChannels) - { - case 3: - targetPixelFormat = PixelFormat.Rgb565; - break; - case 4: - targetPixelFormat = PixelFormat.Bgra8888; - break; - default: - throw new Exception("Unknown color type"); - } + return writableBitmap; + /*Debug.WriteLine($"Method 1 (Span copy): {sw.ElapsedMilliseconds}ms"); + + // Method 2 (OpenCV Convertion + Copy Marshal) + sw.Restart(); + CvInvoke.CvtColor(mat, target, ColorConversion.Bgr2Bgra); + var buffer = target.GetBytes(); + Marshal.Copy(buffer, 0, lockBuffer.Address, buffer.Length); + Debug.WriteLine($"Method 2 (OpenCV Convertion + Copy Marshal): {sw.ElapsedMilliseconds}ms"); - - var writeableBitmap = new WriteableBitmap(new PixelSize(mat.Width, mat.Height), new Vector(72, 72), targetPixelFormat, AlphaFormat.Unpremul); - using var lockBuffer = writeableBitmap.Lock(); - var buffer = mat.GetBytes(); - for (var y = 0; y < mat.Height; y++) - { - Marshal.Copy(buffer, y * lockBuffer.RowBytes, new IntPtr(lockBuffer.Address.ToInt64() + y * lockBuffer.RowBytes), lockBuffer.RowBytes); + + //sw.Restart(); + CvInvoke.CvtColor(mat, target, ColorConversion.Bgr2Bgra); + unsafe + { + var srcAddress = (uint*)(void*)target.DataPointer; + var targetAddress = (uint*)(void*)lockBuffer.Address; + *targetAddress = *srcAddress; + } + //Debug.WriteLine($"Method 3 (OpenCV Convertion + Set Address): {sw.ElapsedMilliseconds}ms"); + + return writableBitmap; + */ + /* for (var y = 0; y < mat.Height; y++) + { + Marshal.Copy(buffer, y * lockBuffer.RowBytes, new IntPtr(lockBuffer.Address.ToInt64() + y * lockBuffer.RowBytes), lockBuffer.RowBytes); + }*/ } - //Marshal.Copy(buffer, 0, lockBuffer.Address, buffer.Length); - - SKBitmap bitmap = new SKBitmap(new SKImageInfo(mat.Width, mat.Height, SKColorType.Gray8)); - bitmap.SetPixels(mat.DataPointer); - Debug.WriteLine(bitmap.Info.ColorType); - - bitmap = SKBitmap.Decode(buffer.AsSpan(), new SKImageInfo - { - Width = mat.Width, - Height = mat.Height, - ColorType = SKColorType.Gray8, - });*/ - - /*return writeableBitmap; - }*/ } } \ No newline at end of file diff --git a/UVtools.WPF/Extensions/MatrixHelper.cs b/UVtools.WPF/Extensions/MatrixHelper.cs deleted file mode 100644 index f8b1e78..0000000 --- a/UVtools.WPF/Extensions/MatrixHelper.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using Avalonia; - -namespace UVtools.WPF.Extensions -{ - /// - /// Avalonia Matrix helper methods. - /// - public static class MatrixHelper - { - /// - /// Creates a translation matrix using the specified offsets. - /// - /// X-coordinate offset. - /// Y-coordinate offset. - /// The created translation matrix. - public static Matrix Translate(double offsetX, double offsetY) - { - return new Matrix(1.0, 0.0, 0.0, 1.0, offsetX, offsetY); - } - - /// - /// Prepends a translation around the center of provided matrix. - /// - /// The matrix to prepend translation. - /// X-coordinate offset. - /// Y-coordinate offset. - /// The created translation matrix. - public static Matrix TranslatePrepend(Matrix matrix, double offsetX, double offsetY) - { - return Translate(offsetX, offsetY) * matrix; - } - - /// - /// Creates a matrix that scales along the x-axis and y-axis. - /// - /// Scaling factor that is applied along the x-axis. - /// Scaling factor that is applied along the y-axis. - /// The created scaling matrix. - public static Matrix Scale(double scaleX, double scaleY) - { - return new Matrix(scaleX, 0, 0, scaleY, 0.0, 0.0); - } - - /// - /// Creates a matrix that is scaling from a specified center. - /// - /// Scaling factor that is applied along the x-axis. - /// Scaling factor that is applied along the y-axis. - /// The center X-coordinate of the scaling. - /// The center Y-coordinate of the scaling. - /// The created scaling matrix. - public static Matrix ScaleAt(double scaleX, double scaleY, double centerX, double centerY) - { - return new Matrix(scaleX, 0, 0, scaleY, centerX - (scaleX * centerX), centerY - (scaleY * centerY)); - } - - /// - /// Prepends a scale around the center of provided matrix. - /// - /// The matrix to prepend scale. - /// Scaling factor that is applied along the x-axis. - /// Scaling factor that is applied along the y-axis. - /// The center X-coordinate of the scaling. - /// The center Y-coordinate of the scaling. - /// The created scaling matrix. - public static Matrix ScaleAtPrepend(Matrix matrix, double scaleX, double scaleY, double centerX, double centerY) - { - return ScaleAt(scaleX, scaleY, centerX, centerY) * matrix; - } - - /// - /// Creates a skew matrix. - /// - /// Angle of skew along the X-axis in radians. - /// Angle of skew along the Y-axis in radians. - /// When the method completes, contains the created skew matrix. - public static Matrix Skew(float angleX, float angleY) - { - return new Matrix(1.0, Math.Tan(angleX), Math.Tan(angleY), 1.0, 0.0, 0.0); - } - - /// - /// Creates a matrix that rotates. - /// - /// Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis. - /// The created rotation matrix. - public static Matrix Rotation(double radians) - { - double cos = Math.Cos(radians); - double sin = Math.Sin(radians); - return new Matrix(cos, sin, -sin, cos, 0, 0); - } - - /// - /// Creates a matrix that rotates about a specified center. - /// - /// Angle of rotation in radians. - /// The center X-coordinate of the rotation. - /// The center Y-coordinate of the rotation. - /// The created rotation matrix. - public static Matrix Rotation(double angle, double centerX, double centerY) - { - return Translate(-centerX, -centerY) * Rotation(angle) * Translate(centerX, centerY); - } - - /// - /// Creates a matrix that rotates about a specified center. - /// - /// Angle of rotation in radians. - /// The center of the rotation. - /// The created rotation matrix. - public static Matrix Rotation(double angle, Vector center) - { - return Translate(-center.X, -center.Y) * Rotation(angle) * Translate(center.X, center.Y); - } - - /// - /// Transforms a point by this matrix. - /// - /// The matrix to use as a transformation matrix. - /// >The original point to apply the transformation. - /// The result of the transformation for the input point. - public static Point TransformPoint(Matrix matrix, Point point) - { - return new Point( - (point.X * matrix.M11) + (point.Y * matrix.M21) + matrix.M31, - (point.X * matrix.M12) + (point.Y * matrix.M22) + matrix.M32); - } - } -} diff --git a/UVtools.WPF/Extensions/PrimitivesExtensions.cs b/UVtools.WPF/Extensions/PrimitivesExtensions.cs index d4ff66c..7c99cf4 100644 --- a/UVtools.WPF/Extensions/PrimitivesExtensions.cs +++ b/UVtools.WPF/Extensions/PrimitivesExtensions.cs @@ -1,4 +1,12 @@ -using Avalonia; +/* + * 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 Avalonia; namespace UVtools.WPF.Extensions { diff --git a/UVtools.WPF/Extensions/WindowExtensions.cs b/UVtools.WPF/Extensions/WindowExtensions.cs index 191ae84..84d5ad3 100644 --- a/UVtools.WPF/Extensions/WindowExtensions.cs +++ b/UVtools.WPF/Extensions/WindowExtensions.cs @@ -1,11 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Text; +/* + * 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.Threading.Tasks; using Avalonia.Controls; using MessageBox.Avalonia.DTO; using MessageBox.Avalonia.Enums; -using MessageBox.Avalonia.Models; namespace UVtools.WPF.Extensions { diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml index 6a55a48..a89a854 100644 --- a/UVtools.WPF/MainWindow.axaml +++ b/UVtools.WPF/MainWindow.axaml @@ -7,9 +7,11 @@ xmlns:idc="clr-namespace:Dock.Avalonia.Controls;assembly=Dock.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="UVtools.WPF.MainWindow" - Title="UVtools"> + Title="UVtools" + Icon="/Assets/Icons/UVtools.ico" + > - + @@ -57,6 +59,14 @@ + + + + + + + + diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs index 01cc19c..2de8811 100644 --- a/UVtools.WPF/MainWindow.axaml.cs +++ b/UVtools.WPF/MainWindow.axaml.cs @@ -1,18 +1,23 @@ -using System; +/* + * 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 System.ComponentModel; +using System.Diagnostics; using System.IO; using System.Runtime.CompilerServices; using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Markup.Xaml; -using MessageBox.Avalonia.DTO; -using MessageBox.Avalonia.Enums; -using MessageBox.Avalonia.Models; -using SkiaSharp; using UVtools.Core.FileFormats; using UVtools.WPF.Controls; using UVtools.WPF.Extensions; using UVtools.WPF.ViewModels; +using UVtools.WPF.Windows; namespace UVtools.WPF { @@ -71,9 +76,6 @@ namespace UVtools.WPF - - - public AdvancedImageBox LayerImage; public Button ZoomToFitButton; public Button CenterButton; @@ -133,6 +135,8 @@ namespace UVtools.WPF App.SlicerFile = FileFormat.FindByExtension(fileName, true, true); if (App.SlicerFile is null) return; + ViewModel.IsGUIEnabled = false; + var task = Task.Factory.StartNew(() => { try @@ -153,37 +157,23 @@ namespace UVtools.WPF } }); + //ProgressWindow progressWindow = new ProgressWindow(); + //progressWindow.ShowDialog(this); + + + task.Wait(); var mat = App.SlicerFile[0].LayerMat; var matRgb = App.SlicerFile[0].BrgMat; - var skbitmapGray = mat.ToSkBitmap(); - using (var image = SKImage.FromBitmap(skbitmapGray)) - using (var data = image.Encode(SKEncodedImageFormat.Png, 80)) - { - // save the data to a stream - using (var stream = File.OpenWrite("D:\\gray.png")) - { - data.SaveTo(stream); - } - } - + Debug.WriteLine("4K grayscale - BGRA convertion:"); + var bitmap = mat.ToBitmap(); + Debug.WriteLine("4K BGR - BGRA convertion:"); + var bitmapRgb = matRgb.ToBitmap(); + LayerImage.Image = bitmapRgb; - - var skbitmapRBG = matRgb.ToSkBitmap(); - using (var image = SKImage.FromBitmap(skbitmapRBG)) - using (var data = image.Encode(SKEncodedImageFormat.Png, 80)) - { - // save the data to a stream - using (var stream = File.OpenWrite("D:\\rgb.png")) - { - data.SaveTo(stream); - } - } - - //Avalonia.Skia.SkiaSharpExtensions. - //LayerImage.Image = bitmap; + ViewModel.IsGUIEnabled = true; } } } diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index 31d7731..9ae0c0d 100644 --- a/UVtools.WPF/UVtools.WPF.csproj +++ b/UVtools.WPF/UVtools.WPF.csproj @@ -4,6 +4,20 @@ netcoreapp3.1 UVtools UVtools.ico + Tiago Conceição + PTRTECH + MSLA/DLP, file analysis, repair, conversion and manipulation + Copyright © 2020 PTRTECH + https://github.com/sn4k3/UVtools + LICENSE + https://github.com/sn4k3/UVtools + Git + + + true + + + true @@ -13,6 +27,7 @@ + @@ -20,6 +35,9 @@ + + + MSBuild:Compile @@ -27,14 +45,18 @@ MSBuild:Compile - + PreserveNewest - + PreserveNewest - + PreserveNewest + + True + + diff --git a/UVtools.WPF/UserSettings.cs b/UVtools.WPF/UserSettings.cs new file mode 100644 index 0000000..e0e5f6d --- /dev/null +++ b/UVtools.WPF/UserSettings.cs @@ -0,0 +1,231 @@ +/* + * 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 System.Diagnostics; +using System.IO; +using System.Xml.Serialization; +using Avalonia.Media; + +namespace UVtools.WPF +{ + [Serializable] + public sealed class UserSettings + { + #region Sub classes + [Serializable] + public sealed class GeneralUserSettings + { + public bool StartMaximized { get; set; } = true; + public bool CheckForUpdatesOnStartup { get; set; } = true; + public byte DefaultOpenFileExtensionIndex { get; set; } + public string DefaultDirectoryOpenFile { get; set; } + public string DefaultDirectorySaveFile { get; set; } + public string DefaultDirectoryExtractFile { get; set; } + public string DefaultDirectoryConvertFile { get; set; } + public bool PromptOverwriteFileSave { get; set; } = true; + public string FileSaveNamePrefix { get; set; } + public string FileSaveNameSuffix { get; set; } = "_copy"; + } + + [Serializable] + public sealed class LayerPreviewUserSettings + { + public Color TooltipOverlayBackgroundColor { get; set; } = new Color(210, 255, 255, 192); + + public bool TooltipOverlay { get; set; } = true; + + public Color VolumeBoundsOutlineColor { get; set; } = new Color(210, 0, 255, 0); + public byte VolumeBoundsOutlineThickness { get; set; } = 3; + public bool VolumeBoundsOutline { get; set; } = true; + + public Color LayerBoundsOutlineColor { get; set; } = new Color(210, 0, 255, 0); + public byte LayerBoundsOutlineThickness { get; set; } = 3; + public bool LayerBoundsOutline { get; set; } = true; + + public Color HollowOutlineColor { get; set; } = new Color(210, 255, 165, 0); + public byte HollowOutlineLineThickness { get; set; } = 3; + public bool HollowOutline { get; set; } = true; + + public Color PreviousLayerDifferenceColor { get; set; } = new Color(255, 255, 0, 255); + public Color NextLayerDifferenceColor { get; set; } = new Color(255, 0, 255, 255); + public Color BothLayerDifferenceColor { get; set; } = new Color(255, 255, 0, 0); + public bool ShowLayerDifference { get; set; } = true; + + public Color IslandColor { get; set; } = new Color(255, 255,215, 0); + public Color IslandHighlightColor { get; set; } = new Color(255, 255,255, 0); + public Color ResinTrapColor { get; set; } = new Color(255, 244, 164, 96); + public Color ResinTrapHighlightColor { get; set; } = new Color(255, 255, 165, 0); + public Color TouchingBoundsColor { get; set; } = new Color(255, 255, 0, 0); + public Color CrosshairColor { get; set; } = new Color(255, 255, 0, 0); + + public bool ZoomToFitPrintVolumeBounds { get; set; } = true; + public byte ZoomLockLevelIndex { get; set; } = 7; + public bool ZoomIssues { get; set; } = true; + + public bool CrosshairShowOnlyOnSelectedIssues { get; set; } = false; + public byte CrosshairFadeLevelIndex { get; set; } = 5; + public uint CrosshairLength { get; set; } = 20; + public byte CrosshairMargin { get; set; } = 5; + + public bool AutoRotateLayerBestView { get; set; } = true; + public bool LayerZoomToFitOnLoad { get; set; } = true; + + } + + [Serializable] + public sealed class IssuesUserSettings + { + public bool ComputeIssuesOnLoad { get; set; } = false; + public bool ComputeIssuesOnClickTab { get; set; } = true; + public bool ComputeIslands { get; set; } = true; + public bool ComputeResinTraps { get; set; } = true; + public bool ComputeTouchingBounds { get; set; } = true; + public bool ComputeEmptyLayers { get; set; } = true; + + public bool IslandAllowDiagonalBonds { get; set; } = false; + public byte IslandBinaryThreshold { get; set; } = 0; + public byte IslandRequiredAreaToProcessCheck { get; set; } = 1; + public byte IslandRequiredPixelsToSupport { get; set; } = 10; + public byte IslandRequiredPixelBrightnessToSupport { get; set; } = 150; + + + public byte ResinTrapBinaryThreshold { get; set; } = 127; + public byte ResinTrapRequiredAreaToProcessCheck { get; set; } = 17; + public byte ResinTrapRequiredBlackPixelsToDrain { get; set; } = 10; + public byte ResinTrapMaximumPixelBrightnessToDrain { get; set; } = 30; + + } + + [Serializable] + public sealed class PixelEditorUserSettings + { + public Color AddPixelColor { get; set; } = new Color(255, 144, 238, 144); + public Color AddPixelHighlightColor { get; set; } = new Color(255, 0, 255, 0); + + public Color RemovePixelColor { get; set; } = new Color(255, 219, 112, 147); + public Color RemovePixelHighlightColor { get; set; } = new Color(255, 139, 0, 0); + + public Color SupportsColor { get; set; } = new Color(255, 0, 255, 255); + public Color SupportsHighlightColor { get; set; } = new Color(255, 0, 139, 139); + + public Color DrainHolesColor { get; set; } = new Color(255, 142, 69, 133); + public Color DrainHolesHighlightColor { get; set; } = new Color(255, 159, 0, 197); + + public bool PartialUpdateIslandsOnEditing { get; set; } = true; + public bool CloseEditorOnApply { get; set; } = false; + } + + [Serializable] + public sealed class LayerRepairUserSettings + { + + public byte ClosingIterations { get; set; } = 2; + public byte OpeningIterations { get; set; } = 0; + public byte RemoveIslandsBelowEqualPixels { get; set; } = 10; + + public bool RepairIslands { get; set; } = true; + public bool RepairResinTraps { get; set; } = true; + public bool RemoveEmptyLayers { get; set; } = true; + } + + #endregion + + #region Singleton + /// + /// Default filepath for store + /// + private const string FilePath = "Assets/usersettings.xml"; + + + private static UserSettings _instance; + /// + /// Instance of (singleton) + /// + public static UserSettings Instance => _instance ??= new UserSettings(); + #endregion + + #region Properties + + public GeneralUserSettings General { get; set; } = new GeneralUserSettings(); + public LayerPreviewUserSettings LayerPreview { get; set; } = new LayerPreviewUserSettings(); + public IssuesUserSettings Issues { get; set; } = new IssuesUserSettings(); + public PixelEditorUserSettings PixelEditor { get; set; } = new PixelEditorUserSettings(); + public LayerRepairUserSettings LayerRepair { get; set; } = new LayerRepairUserSettings(); + + /// + /// Gets or sets the number of times this file has been saved + /// + public uint SavesCount { get; set; } + + /// + /// Gets or sets the last time this file has been modified + /// + public DateTime ModifiedDateTime { get; set; } + #endregion + + #region Constructor + private UserSettings() + { } + #endregion + + #region Static Methods + /// + /// Reset settings to defaults + /// + /// True to save settings on file, otherwise false + public static void Reset(bool save = false) + { + _instance = new UserSettings(); + if(save) Save(); + } + + /// + /// Load settings from file + /// + public static void Load() + { + if (!File.Exists(FilePath)) + { + return; + } + + var serializer = new XmlSerializer(typeof(UserSettings)); + using StreamReader myXmlReader = new StreamReader(FilePath); + try + { + _instance = (UserSettings)serializer.Deserialize(myXmlReader); + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + } + + + /// + /// Save settings to file + /// + public static void Save() + { + Instance.SavesCount++; + _instance.ModifiedDateTime = DateTime.Now; + var serializer = new XmlSerializer(_instance.GetType()); + using StreamWriter myXmlWriter = new StreamWriter(FilePath); + try + { + serializer.Serialize(myXmlWriter, _instance); + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + } + } + #endregion + } +} diff --git a/UVtools.WPF/ViewModels/MainWindowViewModel.cs b/UVtools.WPF/ViewModels/MainWindowViewModel.cs index c69bf7f..2583d5f 100644 --- a/UVtools.WPF/ViewModels/MainWindowViewModel.cs +++ b/UVtools.WPF/ViewModels/MainWindowViewModel.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Reflection; using Avalonia.Controls; using JetBrains.Annotations; using MessageBox.Avalonia.DTO; @@ -6,13 +7,26 @@ using MessageBox.Avalonia.Enums; using MessageBox.Avalonia.Models; using UVtools.Core.Objects; using UVtools.WPF.Extensions; +using UVtools.WPF.Windows; namespace UVtools.WPF.ViewModels { public class MainWindowViewModel : BindableBase { private MainWindow Parent; - public bool IsFileLoaded => !ReferenceEquals(App.SlicerFile, null); + + private bool _isGUIEnabled = true; + public bool IsGUIEnabled + { + get => _isGUIEnabled; + set => SetProperty(ref _isGUIEnabled, value); + } + + public bool IsFileLoaded + { + get => !ReferenceEquals(App.SlicerFile, null); + set => SetProperty(); + } public MainWindowViewModel(MainWindow parent) { @@ -28,5 +42,12 @@ namespace UVtools.WPF.ViewModels var files = await dialog.ShowAsync(Parent); Parent.ProcessFiles(files); } + + public async void MenuFileSettingsClicked() + { + SettingsWindow settingsWindow = new SettingsWindow(); + settingsWindow.Title += $" [v{Assembly.GetEntryAssembly().GetName().Version}]"; + await settingsWindow.ShowDialog(Parent); + } } } diff --git a/UVtools.WPF/Windows/ProgressWindow.axaml b/UVtools.WPF/Windows/ProgressWindow.axaml new file mode 100644 index 0000000..fbcc4a2 --- /dev/null +++ b/UVtools.WPF/Windows/ProgressWindow.axaml @@ -0,0 +1,25 @@ + + + + + + + + + + + diff --git a/UVtools.WPF/Windows/ProgressWindow.axaml.cs b/UVtools.WPF/Windows/ProgressWindow.axaml.cs new file mode 100644 index 0000000..b9744e6 --- /dev/null +++ b/UVtools.WPF/Windows/ProgressWindow.axaml.cs @@ -0,0 +1,26 @@ +/* + * 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 Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace UVtools.WPF.Windows +{ + public class ProgressWindow : Window + { + public ProgressWindow() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + + } + } +} diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml b/UVtools.WPF/Windows/SettingsWindow.axaml new file mode 100644 index 0000000..6ff2278 --- /dev/null +++ b/UVtools.WPF/Windows/SettingsWindow.axaml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml.cs b/UVtools.WPF/Windows/SettingsWindow.axaml.cs new file mode 100644 index 0000000..dee093d --- /dev/null +++ b/UVtools.WPF/Windows/SettingsWindow.axaml.cs @@ -0,0 +1,19 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace UVtools.WPF.Windows +{ + public class SettingsWindow : Window + { + public SettingsWindow() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +}