diff --git a/CHANGELOG.md b/CHANGELOG.md
index f44504cf..68d99b47 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
# Changelog
+## 21/06/2023 - v3.14.4
+
+- (Add) File - Rename: Allow to rename the current file with a new name (Ctrl + F2)
+- (Improvement) Tool - Edit print parameters: It now apply settings without close the window, allowing user to do continuous work. After all editing is done the user must manually close the window (#731)
+- (Improvement) Resin traps and suction cups: Optimization of contour grouping will now make the detection faster if it contains a large number of contours
+- (Change) Lower the default setting for binary threshold for resin traps, from 127 to 100
+- (Fix) macOS: Unable to have settings on Monterey or above due the settings folder no longer exists on recent systems. (#728)
+ Your current settings will not be automatically transferred to the new location, to do such please copy them over or use the following command before upgrade: `mv "$HOME/.local/share/UVtools" "$HOME/Library/Application Support"`
+ If you already ran UVtools and would like to transfer old settings, use: `cp -Rf "$HOME/.local/share/UVtools/" "$HOME/Library/Application Support/UVtools/"`
+- (Upgrade) .NET from 6.0.16 to 6.0.18
+
## 11/06/2023 - v3.14.3
- **Settings:**
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 091a18e9..7f671e2e 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,9 +1,9 @@
-- **Settings:**
- - (Add) After save the file replace on it name with the updated print time and material if possible
- - (Add) File 'Save as' default name with extended variables (#725)
- - (Add) File 'Save as' name cleanup regex
- - (Add) When save as a file and if the file name already exists on that directory it will append a number up to one available
- - (Remove) File 'Save as' suffix and prefix
-- (Add) About: Graphic card name
-- (Fix) CTB Encrypted: Check the checksum as last step to be compatible with new Chitubox 1.4.5 CTB files (#696, #726)
+- (Add) File - Rename: Allow to rename the current file with a new name (Ctrl + F2)
+- (Improvement) Tool - Edit print parameters: It now apply settings without close the window, allowing user to do continuous work. After all editing is done the user must manually close the window (#731)
+- (Improvement) Resin traps and suction cups: Optimization of contour grouping will now make the detection faster if it contain a large number of contours
+- (Change) Lower the default setting for binary threshold for resin traps, from 127 to 100
+- (Fix) macOS: Unable to have settings on Monterey or above due the settings folder no longer exists on recent systems. (#728)
+ Your current settings will not be automatically transferred to the new location, to do such please copy them over or use the following command before upgrade: `mv "$HOME/.local/share/UVtools" "$HOME/Library/Application Support"`
+ If you already ran UVtools and would like to transfer old settings, use: `cp -Rf "$HOME/.local/share/UVtools/" "$HOME/Library/Application Support/UVtools/"`
+- (Upgrade) .NET from 6.0.16 to 6.0.18
diff --git a/Scripts/010 Editor/FileFormats.1pj b/Scripts/010 Editor/FileFormats.1pj
index a6c26eec..d1a11aed 100644
--- a/Scripts/010 Editor/FileFormats.1pj
+++ b/Scripts/010 Editor/FileFormats.1pj
@@ -8,6 +8,7 @@
ctb_decrypted.bt
ctb_encrypted.bt
cxdlp.bt
+ cxdlpv4.bt
cxdlp_v1.bt
fdg.bt
gr1.bt
diff --git a/Scripts/010 Editor/cxdlp.bt b/Scripts/010 Editor/cxdlp.bt
index b92fae4b..8da2f509 100644
--- a/Scripts/010 Editor/cxdlp.bt
+++ b/Scripts/010 Editor/cxdlp.bt
@@ -35,8 +35,8 @@ typedef struct(int size) {
} RgbPreviewImageRawData;
struct HEADER {
- uint32 HeaderSize ;
- char Header[HeaderSize] ;
+ uint32 MagicSize ;
+ char Magic[MagicSize] ;
uint16 Version ;
diff --git a/Scripts/010 Editor/cxdlpv4.bt b/Scripts/010 Editor/cxdlpv4.bt
new file mode 100644
index 00000000..64501d9c
--- /dev/null
+++ b/Scripts/010 Editor/cxdlpv4.bt
@@ -0,0 +1,179 @@
+//------------------------------------------------
+//--- 010 Editor v8.0.1 Binary Template
+//
+// File: cxdlpv4
+// Authors: Tiago Conceição
+//------------------------------------------------
+
+LittleEndian();
+
+struct HEADER {
+ BigEndian();
+ uint32 MagicSize ;
+ char Magic[MagicSize] ;
+ ushort Version ;
+
+ uint32 PrinterModelSize ;
+ char PrinterModel[PrinterModelSize] ;
+ LittleEndian();
+
+ ushort ResolutionX ;
+ ushort ResolutionY ;
+
+ float BedSizeX ;
+ float BedSizeY ;
+ float BedSizeZ ;
+
+ float TotalHeightMilimeter ;
+ float LayerHeightMilimeter ;
+ uint BottomLayersCount ;
+
+ uint PreviewSmallOffsetAddress ;
+ uint LayersDefinitionOffsetAddress ;
+ uint LayerCount ;
+ uint PreviewLargeOffsetAddress ;
+ uint PrintTime ;
+ uint ProjectorType ;
+ uint PrintParametersOffsetAddress ;
+ uint PrintParametersSize ;
+ uint AntiAliasLevel ;
+ ushort LightPWM ;
+ ushort BottomLightPWM ;
+ uint EncryptionKey ;
+ uint SlicerOffset ;
+ uint SlicerSize ;
+} header;
+
+struct PREVIEW {
+ uint ResolutionX ;
+ uint ResolutionY ;
+ uint ImageOffset ;
+ uint ImageLength ;
+ uint Unknown1 ;
+ uint Unknown2 ;
+ uint Unknown3 ;
+ uint Unknown4 ;
+
+ ubyte Data[ImageLength] ;
+};
+
+struct PRINT_PARAMETERS {
+ float BottomLiftHeight ;
+ float BottomLiftSpeed ;
+ float LiftHeight ;
+ float LiftSpeed ;
+ float RetractSpeed ;
+ float VolumeMl ;
+ float WeightG ;
+ float CostDollars ;
+ float BottomLightOffDelay ;
+ float LightOffDelay ;
+
+ uint BottomLayerCount ;
+ float ExposureTime ;
+ float BottomExposureTime ;
+ uint Padding ;
+ uint Padding ;
+ uint Padding ;
+ uint Padding ;
+};
+
+struct SLICER_INFO {
+ float BottomLiftHeight2 ;
+ float BottomLiftSpeed2 ;
+ float LiftHeight2 ;
+ float LiftSpeed2 ;
+ float RetractHeight2 ;
+ float RetractSpeed2 ;
+ float RestTimeAfterLift ;
+
+ uint PerLayerSettings ; // 0 to not support, 1 to support
+ uint TimestampMinutes ;
+ uint AntiAliasLevel ;
+ uint SoftwareVersion ; // 0
+ float RestTimeAfterRetract ;
+ float RestTimeBeforeLift ;
+ float BottomExposureTime ;
+ float ExposureTime ;
+ float RestTimeAfterLift ;
+ uint TransitionLayerCount ;
+ uint Padding ;
+ uint Padding ;
+};
+
+if(header.PreviewSmallOffsetAddress > 0)
+{
+ FSeek(header.PreviewSmallOffsetAddress);
+ PREVIEW previewSmall ;
+}
+
+if(header.PreviewLargeOffsetAddress > 0)
+{
+ FSeek(header.PreviewLargeOffsetAddress);
+ PREVIEW previewLarge ;
+}
+
+if(header.PrintParametersOffsetAddress > 0){
+ FSeek(header.PrintParametersOffsetAddress);
+ PRINT_PARAMETERS parameters ;
+}
+
+if(header.SlicerOffset > 0){
+ FSeek(header.SlicerOffset);
+ SLICER_INFO SlicerInfo ;
+}
+
+struct LAYER_DATA {
+ float LayerPositionZ ;
+ float LayerExposure ;
+ float LightOffSeconds ;
+ uint DataAddress ;
+ uint DataSize ;
+ uint DataType ;
+ uint CentroidDistance ;
+ uint TotalArea ;
+ uint Unknown ;
+ uint Unknown ;
+};
+
+struct LAYER_DATAEX {
+ float LiftHeight ;
+ float LiftSpeed ;
+ float LiftHeight2 ;
+ float LiftSpeed2 ;
+ float RetractSpeed ;
+ float RetractHeight2 ;
+ float RetractSpeed2 ;
+ float RestTimeBeforeLift ;
+ float RestTimeAfterLift ;
+ float RestTimeAfterRetract ;
+ float LightPWM ;
+};
+
+
+typedef struct(int size) {
+ ubyte layerDataBlock[size] ;
+} LAYER_RLE;
+
+FSeek(header.LayersDefinitionOffsetAddress);
+struct LAYERS {
+ local uint i;
+ for( i = 0; i < header.LayerCount; i++ ){
+ LAYER_DATA layerData ;
+ }
+} layers;
+
+struct LAYERSEX {
+ local uint i;
+
+ for( i = 0; i < header.LayerCount; i++ ){
+ LAYER_DATAEX layerDataEx;
+ LAYER_RLE lD(layers.layerData[i].DataSize - 44);
+ }
+
+} layersEx;
+
+
+BigEndian();
+uint CheckSum ;
+LittleEndian();
\ No newline at end of file
diff --git a/UVtools.Core/CoreSettings.cs b/UVtools.Core/CoreSettings.cs
index 870a7c25..9ca28b70 100644
--- a/UVtools.Core/CoreSettings.cs
+++ b/UVtools.Core/CoreSettings.cs
@@ -108,6 +108,11 @@ public static string DefaultSettingsFolder
{
get
{
+ if (OperatingSystem.IsMacOS())
+ {
+ return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", About.Software);
+ }
+
var folder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
if (string.IsNullOrWhiteSpace(folder)) folder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
if (string.IsNullOrWhiteSpace(folder)) folder = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
diff --git a/UVtools.Core/EmguCV/EmguContours.cs b/UVtools.Core/EmguCV/EmguContours.cs
index 555b7520..101c20a2 100644
--- a/UVtools.Core/EmguCV/EmguContours.cs
+++ b/UVtools.Core/EmguCV/EmguContours.cs
@@ -258,6 +258,24 @@ public static List[] GetContoursInGroups(VectorOfVectorOf
///
public static List GetPositiveContoursInGroups(VectorOfVectorOfPoint contours, int[,] hierarchy)
{
+ var vectorSize = contours.Size;
+ var result = new List();
+ VectorOfVectorOfPoint? vec = null;
+ for (int i = 0; i < vectorSize; i++)
+ {
+ if (hierarchy[i, EmguContour.HierarchyParent] == -1)
+ {
+ vec = new VectorOfVectorOfPoint(contours[i]);
+ result.Add(vec);
+ }
+ else
+ {
+ vec.Push(contours[i]);
+ }
+ }
+
+ return result;
+ /* Old
var result = new List();
var vectorSize = contours.Size;
var processedContours = new bool[vectorSize];
@@ -275,7 +293,7 @@ public static List GetPositiveContoursInGroups(VectorOfVe
}
}
- return result;
+ return result;*/
}
///
@@ -287,6 +305,26 @@ public static List GetNegativeContoursInGroups(VectorOfVe
{
var result = new List();
var vectorSize = contours.Size;
+ for (int i = 1; i < vectorSize; i++)
+ {
+ if (hierarchy[i, EmguContour.HierarchyParent] == -1) continue;
+ var vec = new VectorOfVectorOfPoint(contours[i]);
+ result.Add(vec);
+
+ var contourId = i;
+ for (i += 1; i < vectorSize && hierarchy[i, EmguContour.HierarchyParent] >= contourId; i++)
+ {
+ vec.Push(contours[i]);
+ }
+
+ i--;
+ }
+
+ return result;
+
+ // Old code
+ /*var result = new List();
+ var vectorSize = contours.Size;
var processedContours = new bool[vectorSize];
for (int i = 0; i < vectorSize; i++)
{
@@ -303,7 +341,7 @@ public static List GetNegativeContoursInGroups(VectorOfVe
}
}
- return result;
+ return result;*/
}
///
diff --git a/UVtools.Core/Layers/LayerIssueConfiguration.cs b/UVtools.Core/Layers/LayerIssueConfiguration.cs
index 70055b81..20a3029c 100644
--- a/UVtools.Core/Layers/LayerIssueConfiguration.cs
+++ b/UVtools.Core/Layers/LayerIssueConfiguration.cs
@@ -138,7 +138,7 @@ public sealed class IslandDetectionConfiguration : DetectionConfiguration
public bool AllowDiagonalBonds { get; set; } = false;
///
- /// Gets or sets the binary threshold, all pixels below this value will turn in black, otherwise white
+ /// Gets or sets the binary threshold, all pixels equal or below this value will turn in black, otherwise white
/// Set to 0 to disable this operation
///
public byte BinaryThreshold { get; set; } = 1;
@@ -218,10 +218,10 @@ public sealed class ResinTrapDetectionConfiguration : DetectionConfiguration
public uint StartLayerIndex { get; set; }
///
- /// Gets or sets the binary threshold, all pixels below this value will turn in black, otherwise white
+ /// Gets or sets the binary threshold, all pixels equal or below this value will turn in black, otherwise white
/// Set to 0 to disable this operation
///
- public byte BinaryThreshold { get; set; } = 127;
+ public byte BinaryThreshold { get; set; } = 100;
///
/// Gets the required area size (x*y) to consider process a hollow area (0-255)
diff --git a/UVtools.Core/Managers/IssueManager.cs b/UVtools.Core/Managers/IssueManager.cs
index 183f9bc5..02cb98b0 100644
--- a/UVtools.Core/Managers/IssueManager.cs
+++ b/UVtools.Core/Managers/IssueManager.cs
@@ -237,7 +237,10 @@ void GenerateAirMap(IInputArray input, IInputOutputArray output, VectorOfVectorO
Parallel.For(0, SlicerFile.LayerCount, CoreSettings.ParallelOptions, layerIndexInt =>
{
progress.PauseIfRequested();
- if (progress.Token.IsCancellationRequested) return;
+ if (progress.Token.IsCancellationRequested)
+ {
+ return;
+ }
uint layerIndex = (uint)layerIndexInt;
var layer = SlicerFile[layerIndex];
@@ -255,7 +258,6 @@ void GenerateAirMap(IInputArray input, IInputOutputArray output, VectorOfVectorO
)
{
progress.LockAndIncrement();
-
return;
}
@@ -606,9 +608,9 @@ void GenerateAirMap(IInputArray input, IInputOutputArray output, VectorOfVectorO
}
var contourLayer = resinTrapImage.Roi(SlicerFile.BoundingRectangle);
- using var contours = contourLayer.FindContours(out var heirarchy, RetrType.Tree);
- externalContours[layerIndex] = EmguContours.GetExternalContours(contours, heirarchy);
- hollows[layerIndex] = EmguContours.GetNegativeContoursInGroups(contours, heirarchy);
+ using var contours = contourLayer.FindContours(out var hierarchy, RetrType.Tree);
+ externalContours[layerIndex] = EmguContours.GetExternalContours(contours, hierarchy);
+ hollows[layerIndex] = EmguContours.GetNegativeContoursInGroups(contours, hierarchy);
resinTrapsContoursArea[layerIndex] = EmguContours.GetContoursArea(hollows[layerIndex]);
if (needDispose)
@@ -647,6 +649,8 @@ void GenerateAirMap(IInputArray input, IInputOutputArray output, VectorOfVectorO
}); // Parallel end
}
+ if (progress.Token.IsCancellationRequested) return GetResult();
+
if (resinTrapConfig.Enabled)
{
//progress.Reset("Detecting Air Boundaries (Resin traps)", LayerCount);
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index f20eee3f..48c06786 100644
--- a/UVtools.Core/UVtools.Core.csproj
+++ b/UVtools.Core/UVtools.Core.csproj
@@ -10,7 +10,7 @@
https://github.com/sn4k3/UVtools
https://github.com/sn4k3/UVtools
MSLA/DLP, file analysis, calibration, repair, conversion and manipulation
- 3.14.3
+ 3.14.4
Copyright © 2020 PTRTECH
UVtools.png
AnyCPU;x64
@@ -91,7 +91,7 @@
-
+
diff --git a/UVtools.WPF/Controls/RenameFileControl.axaml b/UVtools.WPF/Controls/RenameFileControl.axaml
new file mode 100644
index 00000000..e848845e
--- /dev/null
+++ b/UVtools.WPF/Controls/RenameFileControl.axaml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UVtools.WPF/Controls/RenameFileControl.axaml.cs b/UVtools.WPF/Controls/RenameFileControl.axaml.cs
new file mode 100644
index 00000000..e778b9c7
--- /dev/null
+++ b/UVtools.WPF/Controls/RenameFileControl.axaml.cs
@@ -0,0 +1,111 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Markup.Xaml;
+using MessageBox.Avalonia.Enums;
+using UVtools.Core.FileFormats;
+using UVtools.WPF.Extensions;
+
+namespace UVtools.WPF.Controls
+{
+ public partial class RenameFileControl : ToolBaseControl
+ {
+ private string _newFileNameNoExt;
+ private readonly string _fileExtension;
+ private bool _overwrite;
+
+ public string OldFilePath { get; }
+ public string OldFileNameNoExt { get; }
+
+ public string FileExtension => _fileExtension;
+
+ public string NewFileNameNoExt
+ {
+ get => _newFileNameNoExt;
+ set
+ {
+ if (!RaiseAndSetIfChanged(ref _newFileNameNoExt, value)) return;
+ RaisePropertyChanged(nameof(NewFileName));
+ RaisePropertyChanged(nameof(NewFilePath));
+ ParentWindow.ButtonOkEnabled = CanRename;
+ }
+ }
+
+ public string NewFileName => $"{_newFileNameNoExt}.{_fileExtension}";
+
+ public string NewFilePath => Path.Combine(SlicerFile.DirectoryPath, NewFileName);
+
+ public bool Overwrite
+ {
+ get => _overwrite;
+ set => RaiseAndSetIfChanged(ref _overwrite, value);
+ }
+
+ public bool CanRename => !string.IsNullOrWhiteSpace(_newFileNameNoExt) && !string.Equals(OldFileNameNoExt, _newFileNameNoExt.Trim(), StringComparison.Ordinal) && _newFileNameNoExt.IndexOfAny(Path.GetInvalidFileNameChars()) == -1;
+
+ public RenameFileControl()
+ {
+ OldFilePath = SlicerFile.FileFullPath;
+ _newFileNameNoExt = OldFileNameNoExt = FileFormat.GetFileNameStripExtensions(OldFilePath, out _fileExtension);
+
+ DataContext = this;
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ protected override void OnInitialized()
+ {
+ ParentWindow.ButtonOkEnabled = false;
+ }
+
+ public override string Validate()
+ {
+ var sb = new StringBuilder();
+
+ if (string.IsNullOrWhiteSpace(_newFileNameNoExt))
+ {
+ sb.AppendLine("The filename can not be blank.");
+ }
+
+ if (string.Equals(OldFileNameNoExt, _newFileNameNoExt, StringComparison.Ordinal))
+ {
+ sb.AppendLine("The old and new filename can not be the same.");
+ }
+
+ var invalidChars = Path.GetInvalidFileNameChars();
+ if (_newFileNameNoExt.IndexOfAny(invalidChars) >= 0)
+ {
+ return $"The filename have invalid characters. The following characters are forbidden:\n{string.Join(", ", Path.GetInvalidFileNameChars())}";
+ }
+
+ return sb.ToString();
+ }
+
+ public override async Task OnBeforeProcess()
+ {
+ NewFileNameNoExt = _newFileNameNoExt.Trim();
+ if (!CanRename)
+ {
+ return false;
+ }
+
+ if (_overwrite) return true;
+
+ if (!File.Exists(NewFilePath)) return true;
+ if (await ParentWindow.MessageBoxQuestion(
+ $"The file \"{_newFileNameNoExt}\" already exists, do you want to overwrite?",
+ "File already exists") == ButtonResult.Yes)
+ {
+ Overwrite = true;
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/UVtools.WPF/Controls/ToolBaseControl.cs b/UVtools.WPF/Controls/ToolBaseControl.cs
new file mode 100644
index 00000000..a69645c9
--- /dev/null
+++ b/UVtools.WPF/Controls/ToolBaseControl.cs
@@ -0,0 +1,49 @@
+using System.Threading.Tasks;
+using UVtools.WPF.Extensions;
+using UVtools.WPF.Windows;
+
+namespace UVtools.WPF.Controls;
+
+public class ToolBaseControl : UserControlEx
+{
+ public ToolWindow ParentWindow { get; set; } = null;
+
+ public bool CanRun { get; set; } = true;
+
+ public virtual string Validate() => null;
+
+ public virtual bool ValidateSpawn() => true;
+
+ ///
+ /// Validates if is safe to continue with operation
+ ///
+ ///
+ public virtual async Task ValidateForm()
+ {
+ return await ValidateFormFromString(Validate());
+ }
+
+ ///
+ /// Validates if is safe to continue with operation, if not shows a message box with the error
+ ///
+ ///
+ ///
+ public async Task ValidateFormFromString(string text)
+ {
+ if (string.IsNullOrEmpty(text)) return true;
+ await ParentWindow.MessageBoxError(text);
+ return false;
+ }
+
+ ///
+ /// Called before process, ie click on Ok button
+ ///
+ /// True if can continue processing the operation, otherwise false
+ public virtual Task OnBeforeProcess() => Task.FromResult(true);
+
+ ///
+ /// Called after process, ie click on Ok button
+ ///
+ ///
+ public virtual Task OnAfterProcess() => Task.FromResult(true);
+}
\ No newline at end of file
diff --git a/UVtools.WPF/Controls/Tools/ToolControl.axaml b/UVtools.WPF/Controls/Tools/ToolControl.axaml
deleted file mode 100644
index 9fca8863..00000000
--- a/UVtools.WPF/Controls/Tools/ToolControl.axaml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
diff --git a/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolControl.cs
similarity index 56%
rename from UVtools.WPF/Controls/Tools/ToolControl.axaml.cs
rename to UVtools.WPF/Controls/Tools/ToolControl.cs
index 6b2f2d1e..756deee5 100644
--- a/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolControl.cs
@@ -1,14 +1,12 @@
using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
using System.Threading.Tasks;
-using UVtools.Core.Objects;
using UVtools.Core.Operations;
using UVtools.WPF.Extensions;
using UVtools.WPF.Windows;
namespace UVtools.WPF.Controls.Tools;
-public class ToolControl : UserControlEx
+public class ToolControl : ToolBaseControl
{
private Operation _baseOperation;
@@ -39,37 +37,27 @@ public Operation BaseOperation
}
}
- public ToolWindow ParentWindow { get; set; } = null;
-
- public bool CanRun { get; set; } = true;
-
public ToolControl()
{
- InitializeComponent();
}
public ToolControl(Operation operation)
{
BaseOperation = operation;
if (!ValidateSpawn()) return;
- InitializeComponent();
}
- private void InitializeComponent()
- {
- AvaloniaXamlLoader.Load(this);
- }
-
- public bool ValidateSpawn()
+ public override bool ValidateSpawn()
{
if (Design.IsDesignMode) return true;
- if(_baseOperation is null)
+ if (_baseOperation is null)
{
App.MainWindow.MessageBoxInfo("The operation does not contain a valid configuration.\n" +
"Please contact the support/developer.", BaseOperation.NotSupportedTitle).ConfigureAwait(false);
CanRun = false;
return false;
}
+
if (!_baseOperation.ValidateSpawn(out var message))
{
App.MainWindow.MessageBoxInfo(message, BaseOperation.NotSupportedTitle).ConfigureAwait(false);
@@ -80,43 +68,20 @@ public bool ValidateSpawn()
return true;
}
+
public virtual void Callback(ToolWindow.Callbacks callback) { }
public virtual bool UpdateOperation() => true;
- /*public virtual void SetOperation(Operation operation)
+ public override string Validate()
{
- BaseOperation = operation;
- ResetDataContext();
- }*/
-
- ///
- /// Validates if is safe to continue with operation
- ///
- ///
- public virtual async Task ValidateForm()
+ return BaseOperation.Validate();
+ }
+
+ public override async Task ValidateForm()
{
if (BaseOperation is null) return true;
if (!UpdateOperation()) return false;
- return await ValidateFormFromString(BaseOperation.Validate());
- }
-
- ///
- /// Validates if is safe to continue with operation, if not shows a message box with the error
- ///
- ///
- ///
- public async Task ValidateFormFromString(string text)
- {
- if (string.IsNullOrEmpty(text)) return true;
- await ParentWindow.MessageBoxError(text);
- return false;
+ return await base.ValidateForm();
}
-
- ///
- /// Validates if is safe to continue with operation, if not shows a message box with the error
- ///
- ///
- ///
- public async Task ValidateFormFromString(ValueDescription text) => await ValidateFormFromString(text?.ToString());
}
\ No newline at end of file
diff --git a/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs
index 83ee0092..ebbce927 100644
--- a/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs
@@ -6,6 +6,7 @@
using System;
using System.ComponentModel;
using System.Globalization;
+using System.Threading.Tasks;
using UVtools.Core.FileFormats;
using UVtools.Core.Operations;
using UVtools.WPF.Windows;
@@ -179,6 +180,25 @@ private void InitializeComponent()
AvaloniaXamlLoader.Load(this);
}
+ protected override void OnInitialized()
+ {
+ ParentWindow.CloseWindowAfterProcess = false;
+ }
+
+ public void RefreshModifiers()
+ {
+ if (Operation.PerLayerOverride)
+ {
+ Operation.Modifiers = SlicerFile.PrintParameterPerLayerModifiers;
+ SlicerFile.RefreshPrintParametersPerLayerModifiersValues(Operation.LayerIndexStart);
+ }
+ else
+ {
+ Operation.Modifiers = SlicerFile.PrintParameterModifiers;
+ SlicerFile.RefreshPrintParametersModifiersValues();
+ }
+ }
+
public override void Callback(ToolWindow.Callbacks callback)
{
switch (callback)
@@ -207,20 +227,18 @@ private void OperationOnPropertyChanged(object sender, PropertyChangedEventArgs
}
if (e.PropertyName == nameof(Operation.PerLayerOverride))
{
- if (Operation.PerLayerOverride)
- {
- Operation.Modifiers = SlicerFile.PrintParameterPerLayerModifiers;
- SlicerFile.RefreshPrintParametersPerLayerModifiersValues(Operation.LayerIndexStart);
- }
- else
- {
- Operation.Modifiers = SlicerFile.PrintParameterModifiers;
- SlicerFile.RefreshPrintParametersModifiersValues();
- }
-
+ RefreshModifiers();
ParentWindow.LayerRangeVisible = Operation.PerLayerOverride;
PopulateGrid();
return;
}
}
+
+ public override Task OnAfterProcess()
+ {
+ Operation.Execute();
+ RefreshModifiers();
+ PopulateGrid();
+ return Task.FromResult(true);
+ }
}
\ No newline at end of file
diff --git a/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs
index f5ad69c4..10209acc 100644
--- a/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs
@@ -20,7 +20,23 @@ private void InitializeComponent()
AvaloniaXamlLoader.Load(this);
}
- public static OperationRepairLayers GetOperationRepairLayers() => new (App.SlicerFile)
+ public static OperationRepairLayers GetOperationDisabledRepair() => new (App.SlicerFile)
+ {
+ RepairIslands = false,
+ RepairResinTraps = false,
+ RepairSuctionCups = false,
+ RemoveEmptyLayers = false,
+ RemoveIslandsBelowEqualPixelCount = 0,
+ RemoveIslandsRecursiveIterations = 0,
+ AttachIslandsBelowLayers = 0,
+ ResinTrapsOverlapBy = 0,
+ SuctionCupsVentHole = 0,
+ GapClosingIterations = 0,
+ NoiseRemovalIterations = 0,
+ IssuesDetectionConfig = App.MainWindow.GetIssuesDetectionConfiguration()
+ };
+
+ public static OperationRepairLayers GetOperationRepairLayers() => new(App.SlicerFile)
{
RepairIslands = UserSettings.Instance.LayerRepair.RepairIslands,
RepairResinTraps = UserSettings.Instance.LayerRepair.RepairResinTraps,
diff --git a/UVtools.WPF/ErrorLog.cs b/UVtools.WPF/ErrorLog.cs
index 1dd6775d..340906e9 100644
--- a/UVtools.WPF/ErrorLog.cs
+++ b/UVtools.WPF/ErrorLog.cs
@@ -9,14 +9,13 @@ public static class ErrorLog
{
private const string Filename = "errors.log";
- public static string FullPath = Path.Combine(UserSettings.SettingsFolder, Filename);
+ public static string FullPath => Path.Combine(CoreSettings.DefaultSettingsFolderAndEnsureCreation, Filename);
public static void AppendLine(string errorType, string text)
{
try
{
- File.AppendAllText(FullPath,
- $"[v{About.VersionStr}] ({errorType}) @ {DateTime.Now}: {text}{Environment.NewLine}");
+ File.AppendAllText(FullPath, $"[v{About.VersionStr}] ({errorType}) @ {DateTime.Now}: {text}{Environment.NewLine}");
}
catch (Exception exception)
{
diff --git a/UVtools.WPF/MainWindow.Progress.cs b/UVtools.WPF/MainWindow.Progress.cs
index c7fedc5d..67af78f4 100644
--- a/UVtools.WPF/MainWindow.Progress.cs
+++ b/UVtools.WPF/MainWindow.Progress.cs
@@ -46,9 +46,7 @@ public void InitProgress()
Debug.WriteLine(_lastTotalSeconds);*/
_progressLastTotalSeconds = elapsedSeconds;
-
Dispatcher.UIThread.InvokeAsync(() => Progress.TriggerRefresh(), DispatcherPriority.Render);
-
};
}
diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml
index 888442f6..f98df384 100644
--- a/UVtools.WPF/MainWindow.axaml
+++ b/UVtools.WPF/MainWindow.axaml
@@ -53,6 +53,13 @@
Command="{Binding ReloadFile}"
i:MenuItem.Icon="mdi-file-restore"/>
+
+