Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sn4k3/UVtools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiago Conceição <Tiago_caza@hotmail.com>2020-11-05 21:27:44 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2020-11-05 21:27:44 +0300
commit5da3c7e173094666cd900b3ee09fe3dd93d97985 (patch)
tree9cefc79bf4e48c44721f09475237239a38bb005e
parent50ce7d8f12cdd3e4514b409dcc3718ce8897d1a5 (diff)
v1.1.3v1.1.3
* (Add) Auto-updater: When a new version is detected UVtools still show the same green button at top, on click, it will prompt for auto or manual update. On Linux and Mac the script will kill all UVtools instances and auto-upgrade. On Windows the user must close all instances and continue with the shown MSI installation * (Add) Tool profiles: Create and remove named presets for some tools * (Add) Event handler for handling non-UI thread exceptions * (Fix) Mac: File - Open in a new window was not working * (Fix) Tool - Rotate: Allow negative angles * (Fix) Tool - Rotate: The operation was inverting the angle * (Fix) Tools: Select normal layers can crash the program with small files with low layer count, eg: 3 layers total
-rw-r--r--CHANGELOG.md13
-rw-r--r--UVtools.Core/Layer/Layer.cs2
-rw-r--r--UVtools.Core/Objects/Kernel.cs2
-rw-r--r--UVtools.Core/Operations/Operation.cs61
-rw-r--r--UVtools.Core/Operations/OperationArithmetic.cs28
-rw-r--r--UVtools.Core/Operations/OperationBlur.cs44
-rw-r--r--UVtools.Core/Operations/OperationCalculator.cs5
-rw-r--r--UVtools.Core/Operations/OperationChangeResolution.cs34
-rw-r--r--UVtools.Core/Operations/OperationEditParameters.cs8
-rw-r--r--UVtools.Core/Operations/OperationFlip.cs50
-rw-r--r--UVtools.Core/Operations/OperationLayerClone.cs9
-rw-r--r--UVtools.Core/Operations/OperationLayerImport.cs7
-rw-r--r--UVtools.Core/Operations/OperationLayerReHeight.cs7
-rw-r--r--UVtools.Core/Operations/OperationLayerRemove.cs9
-rw-r--r--UVtools.Core/Operations/OperationMask.cs6
-rw-r--r--UVtools.Core/Operations/OperationMorph.cs50
-rw-r--r--UVtools.Core/Operations/OperationMove.cs3
-rw-r--r--UVtools.Core/Operations/OperationPattern.cs5
-rw-r--r--UVtools.Core/Operations/OperationPixelDimming.cs37
-rw-r--r--UVtools.Core/Operations/OperationRepairLayers.cs9
-rw-r--r--UVtools.Core/Operations/OperationResize.cs41
-rw-r--r--UVtools.Core/Operations/OperationRotate.cs30
-rw-r--r--UVtools.Core/Operations/OperationSolidify.cs5
-rw-r--r--UVtools.Core/Operations/OperationThreshold.cs36
-rw-r--r--UVtools.Core/UVtools.Core.csproj2
-rw-r--r--UVtools.WPF/App.axaml.cs24
-rw-r--r--UVtools.WPF/Controls/Tools/ToolArithmeticControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolBlurControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolCalculatorControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolControl.axaml.cs20
-rw-r--r--UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolFlipControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolLayerCloneControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs8
-rw-r--r--UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolLayerRemoveControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolMaskControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolMorphControl.axaml.cs5
-rw-r--r--UVtools.WPF/Controls/Tools/ToolMoveControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolPatternControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolResizeControl.axaml.cs7
-rw-r--r--UVtools.WPF/Controls/Tools/ToolRotateControl.axaml2
-rw-r--r--UVtools.WPF/Controls/Tools/ToolRotateControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolThresholdControl.axaml.cs4
-rw-r--r--UVtools.WPF/MainWindow.axaml.cs44
-rw-r--r--UVtools.WPF/Program.cs20
-rw-r--r--UVtools.WPF/Structures/AppVersionChecker.cs188
-rw-r--r--UVtools.WPF/Structures/OperationProfiles.cs270
-rw-r--r--UVtools.WPF/UVtools.WPF.csproj3
-rw-r--r--UVtools.WPF/UserSettings.cs12
-rw-r--r--UVtools.WPF/Windows/ToolWindow.axaml100
-rw-r--r--UVtools.WPF/Windows/ToolWindow.axaml.cs191
55 files changed, 1342 insertions, 119 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 21a5ea9..fa94ac5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# Changelog
+## 05/11/2020 - v1.1.3
+
+* (Add) Auto-updater: When a new version is detected UVtools still show the same green button at top,
+on click, it will prompt for auto or manual update.
+On Linux and Mac the script will kill all UVtools instances and auto-upgrade.
+On Windows the user must close all instances and continue with the shown MSI installation
+* (Add) Tool profiles: Create and remove named presets for some tools
+* (Add) Event handler for handling non-UI thread exceptions
+* (Fix) Mac: File - Open in a new window was not working
+* (Fix) Tool - Rotate: Allow negative angles
+* (Fix) Tool - Rotate: The operation was inverting the angle
+* (Fix) Tools: Select normal layers can crash the program with small files with low layer count, eg: 3 layers total
+
## 02/11/2020 - v1.1.2
* (Add) Program start elapsed seconds on Log
diff --git a/UVtools.Core/Layer/Layer.cs b/UVtools.Core/Layer/Layer.cs
index 342f119..e60d856 100644
--- a/UVtools.Core/Layer/Layer.cs
+++ b/UVtools.Core/Layer/Layer.cs
@@ -685,7 +685,7 @@ namespace UVtools.Core
var halfHeight = target.Height / 2.0f;
using (var translateTransform = new Matrix<double>(2, 3))
{
- CvInvoke.GetRotationMatrix2D(new PointF(halfWidth, halfHeight), (double) operation.AngleDegrees, 1.0, translateTransform);
+ CvInvoke.GetRotationMatrix2D(new PointF(halfWidth, halfHeight), (double) -operation.AngleDegrees, 1.0, translateTransform);
/*var rect = new RotatedRect(PointF.Empty, mat.Size, (float) angle).MinAreaRect();
translateTransform[0, 2] += rect.Width / 2.0 - mat.Cols / 2.0;
translateTransform[0, 2] += rect.Height / 2.0 - mat.Rows / 2.0;*/
diff --git a/UVtools.Core/Objects/Kernel.cs b/UVtools.Core/Objects/Kernel.cs
index f57c93c..b73a0a5 100644
--- a/UVtools.Core/Objects/Kernel.cs
+++ b/UVtools.Core/Objects/Kernel.cs
@@ -6,11 +6,13 @@
* of this license document, but changing it is not allowed.
*/
+using System;
using System.Drawing;
using Emgu.CV;
namespace UVtools.Core.Objects
{
+ [Serializable]
public sealed class Kernel
{
public Matrix<byte> Matrix { get; set; }
diff --git a/UVtools.Core/Operations/Operation.cs b/UVtools.Core/Operations/Operation.cs
index b9d374c..385b6a9 100644
--- a/UVtools.Core/Operations/Operation.cs
+++ b/UVtools.Core/Operations/Operation.cs
@@ -6,17 +6,22 @@
* of this license document, but changing it is not allowed.
*/
+using System;
using System.Drawing;
+using System.Xml.Serialization;
using Emgu.CV;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public abstract class Operation : BindableBase
{
private Rectangle _roi = Rectangle.Empty;
private uint _layerIndexEnd;
private uint _layerIndexStart;
+ private string _profileName;
+ private Enumerations.LayerRangeSelection _layerRangeSelection = Enumerations.LayerRangeSelection.All;
public const byte ClassNameLength = 9;
/// <summary>
@@ -24,7 +29,16 @@ namespace UVtools.Core.Operations
/// </summary>
public string Id => GetType().Name.Remove(0, ClassNameLength);
- public virtual Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.All;
+ public virtual Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.All;
+
+ /// <summary>
+ /// Gets the last used layer range selection, returns none if custom
+ /// </summary>
+ public Enumerations.LayerRangeSelection LayerRangeSelection
+ {
+ get => _layerRangeSelection;
+ set => RaiseAndSetIfChanged(ref _layerRangeSelection, value);
+ }
/// <summary>
/// Gets if this operation should set layer range to the actual layer index on layer preview
@@ -32,9 +46,14 @@ namespace UVtools.Core.Operations
public virtual bool PassActualLayerIndex => false;
/// <summary>
- /// Gets if this control can make use of ROI
+ /// Gets if this operation can make use of ROI
+ /// </summary>
+ public virtual bool CanROI => true;
+
+ /// <summary>
+ /// Gets if this operation can store profiles
/// </summary>
- public virtual bool CanROI { get; set; } = true;
+ public virtual bool CanHaveProfiles => true;
/// <summary>
/// Gets if this operation supports cancellation
@@ -106,8 +125,18 @@ namespace UVtools.Core.Operations
public uint LayerRangeCount => LayerIndexEnd - LayerIndexStart + 1;
/// <summary>
+ /// Gets the name for this profile
+ /// </summary>
+ public string ProfileName
+ {
+ get => _profileName;
+ set => RaiseAndSetIfChanged(ref _profileName, value);
+ }
+
+ /// <summary>
/// Gets or sets an ROI to process this operation
/// </summary>
+ [XmlIgnore]
public Rectangle ROI
{
get => _roi;
@@ -120,5 +149,31 @@ namespace UVtools.Core.Operations
{
return HaveROI ? new Mat(defaultMat, ROI) : defaultMat;
}
+
+ public virtual Operation Clone()
+ {
+ return MemberwiseClone() as Operation;
+ }
+
+ public override string ToString()
+ {
+ if (!string.IsNullOrEmpty(ProfileName)) return ProfileName;
+
+ var result = $"{Title}: {LayerRangeString}";
+ return result;
+ }
+
+ public virtual string LayerRangeString
+ {
+ get
+ {
+ if (LayerRangeSelection == Enumerations.LayerRangeSelection.None)
+ {
+ return $" [Layers: {LayerIndexStart}-{LayerIndexEnd}]";
+ }
+
+ return $" [Layers: {LayerRangeSelection}]";
+ }
+ }
}
}
diff --git a/UVtools.Core/Operations/OperationArithmetic.cs b/UVtools.Core/Operations/OperationArithmetic.cs
index bb55b8a..00f9f61 100644
--- a/UVtools.Core/Operations/OperationArithmetic.cs
+++ b/UVtools.Core/Operations/OperationArithmetic.cs
@@ -9,11 +9,13 @@
using System;
using System.Collections.Generic;
using System.Text;
+using System.Xml.Serialization;
using Emgu.CV;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public class OperationArithmetic : Operation
{
private string _sentence;
@@ -85,8 +87,10 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _sentence, value);
}
+ [XmlIgnore]
public List<ArithmeticOperation> Operations { get; } = new List<ArithmeticOperation>();
+ [XmlIgnore]
public List<uint> SetLayers { get; } = new List<uint>();
public bool IsValid => SetLayers.Count > 0 & Operations.Count > 0;
@@ -181,9 +185,29 @@ namespace UVtools.Core.Operations
return true;
}
- public OperationArithmetic()
+ public override string ToString()
{
-
+ var result = $"{_sentence}" + LayerRangeString;
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
+
+ protected bool Equals(OperationArithmetic other)
+ {
+ return _sentence == other._sentence;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is null) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != GetType()) return false;
+ return Equals((OperationArithmetic) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return (_sentence != null ? _sentence.GetHashCode() : 0);
}
}
}
diff --git a/UVtools.Core/Operations/OperationBlur.cs b/UVtools.Core/Operations/OperationBlur.cs
index e3042d1..f8c1e58 100644
--- a/UVtools.Core/Operations/OperationBlur.cs
+++ b/UVtools.Core/Operations/OperationBlur.cs
@@ -6,11 +6,14 @@
* of this license document, but changing it is not allowed.
*/
+using System;
using System.Text;
+using System.Xml.Serialization;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public sealed class OperationBlur : Operation
{
private BlurAlgorithm _blurOperation = BlurAlgorithm.Blur;
@@ -80,6 +83,19 @@ namespace UVtools.Core.Operations
new StringTag("Filter 2D: Applies an arbitrary linear filter to an image", BlurAlgorithm.Filter2D),
};
+ public byte BlurTypeIndex
+ {
+ get
+ {
+ for (byte i = 0; i < BlurTypes.Length; i++)
+ {
+ if ((BlurAlgorithm)BlurTypes[i].Tag == BlurOperation) return i;
+ }
+
+ return 0;
+ }
+ }
+
public BlurAlgorithm BlurOperation
{
get => _blurOperation;
@@ -92,10 +108,36 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _size, value);
}
+ [XmlIgnore]
public Kernel Kernel { get; set; } = new Kernel();
+ public override string ToString()
+ {
+ var result = $"[{_blurOperation}] [Size: {_size}]" + LayerRangeString;
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
+
#endregion
-
+ #region Equality
+ private bool Equals(OperationBlur other)
+ {
+ return _blurOperation == other._blurOperation && _size == other._size;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return ReferenceEquals(this, obj) || obj is OperationBlur other && Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return ((int) _blurOperation * 397) ^ (int) _size;
+ }
+ }
+ #endregion
}
}
diff --git a/UVtools.Core/Operations/OperationCalculator.cs b/UVtools.Core/Operations/OperationCalculator.cs
index 06f0687..b88274c 100644
--- a/UVtools.Core/Operations/OperationCalculator.cs
+++ b/UVtools.Core/Operations/OperationCalculator.cs
@@ -12,6 +12,7 @@ using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public class OperationCalculator : Operation
{
public override string Title => "Calculator";
@@ -23,9 +24,11 @@ namespace UVtools.Core.Operations
public override string ProgressAction => null;
- public override Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
public override bool CanROI => false;
+ public override bool CanHaveProfiles => false;
+
public MillimetersToPixels CalcMillimetersToPixels { get; set; }
public LightOffDelayC CalcLightOffDelay { get; set; }
diff --git a/UVtools.Core/Operations/OperationChangeResolution.cs b/UVtools.Core/Operations/OperationChangeResolution.cs
index 9fa8eb1..da9160c 100644
--- a/UVtools.Core/Operations/OperationChangeResolution.cs
+++ b/UVtools.Core/Operations/OperationChangeResolution.cs
@@ -13,6 +13,7 @@ using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public sealed class OperationChangeResolution : Operation
{
private uint _newResolutionX;
@@ -48,8 +49,8 @@ namespace UVtools.Core.Operations
#region Overrides
- public override Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.None;
- public override bool CanROI { get; set; } = false;
+ public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override bool CanROI => false;
public override string Title => "Change print resolution";
public override string Description =>
"Crops or resizes all layer images to fit an alternate print area\n\n" +
@@ -145,6 +146,35 @@ namespace UVtools.Core.Operations
public static Resolution[] Presets => GetResolutions();
+ public override string ToString()
+ {
+ var result = $"{_newResolutionX} x {_newResolutionY}";
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
+
+ #endregion
+
+ #region Equality
+
+ private bool Equals(OperationChangeResolution other)
+ {
+ return _newResolutionX == other._newResolutionX && _newResolutionY == other._newResolutionY;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return ReferenceEquals(this, obj) || obj is OperationChangeResolution other && Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return ((int) _newResolutionX * 397) ^ (int) _newResolutionY;
+ }
+ }
+
#endregion
}
diff --git a/UVtools.Core/Operations/OperationEditParameters.cs b/UVtools.Core/Operations/OperationEditParameters.cs
index 0c4dd3f..7f774a6 100644
--- a/UVtools.Core/Operations/OperationEditParameters.cs
+++ b/UVtools.Core/Operations/OperationEditParameters.cs
@@ -6,6 +6,7 @@
* of this license document, but changing it is not allowed.
*/
+using System;
using System.Linq;
using System.Text;
using UVtools.Core.FileFormats;
@@ -13,13 +14,14 @@ using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public class OperationEditParameters : Operation
{
private bool _perLayerOverride;
- public override Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
- public override bool CanROI { get; set; } = false;
+ public override bool CanROI => false;
public override string Title => "Edit print parameters";
@@ -58,6 +60,8 @@ namespace UVtools.Core.Operations
public override string ProgressAction => "Changing print parameters";
+ public override bool CanHaveProfiles => false;
+
public override StringTag Validate(params object[] parameters)
{
var sb = new StringBuilder();
diff --git a/UVtools.Core/Operations/OperationFlip.cs b/UVtools.Core/Operations/OperationFlip.cs
index fad6768..aeadc67 100644
--- a/UVtools.Core/Operations/OperationFlip.cs
+++ b/UVtools.Core/Operations/OperationFlip.cs
@@ -11,8 +11,12 @@ using Emgu.CV.CvEnum;
namespace UVtools.Core.Operations
{
+ [Serializable]
public class OperationFlip : Operation
{
+ private bool _makeCopy;
+ private Enumerations.FlipDirection _flipDirection = Enumerations.FlipDirection.Horizontally;
+
public override string Title => "Flip";
public override string Description =>
"Flip the layers of the model vertically and/or horizontally.";
@@ -29,9 +33,19 @@ namespace UVtools.Core.Operations
public override string ProgressAction => "Flipped layers";
- public Enumerations.FlipDirection FlipDirection { get; set; } = Enumerations.FlipDirection.Horizontally;
+ public Enumerations.FlipDirection FlipDirection
+ {
+ get => _flipDirection;
+ set => RaiseAndSetIfChanged(ref _flipDirection, value);
+ }
+
+ public bool MakeCopy
+ {
+ get => _makeCopy;
+ set => RaiseAndSetIfChanged(ref _makeCopy, value);
+ }
- public bool MakeCopy { get; set; }
+ public static Array FlipDirections => Enum.GetValues(typeof(Enumerations.FlipDirection));
public FlipType FlipTypeOpenCV
{
@@ -55,6 +69,36 @@ namespace UVtools.Core.Operations
}
}
- public static Array FlipDirections => Enum.GetValues(typeof(Enumerations.FlipDirection));
+ public override string ToString()
+ {
+ var result = $"[{_flipDirection}] [Blend: {_makeCopy}]" + LayerRangeString;
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
+
+ #region Equality
+
+ protected bool Equals(OperationFlip other)
+ {
+ return _makeCopy == other._makeCopy && _flipDirection == other._flipDirection;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is null) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != GetType()) return false;
+ return Equals((OperationFlip) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return (_makeCopy.GetHashCode() * 397) ^ (int) _flipDirection;
+ }
+ }
+
+ #endregion
}
}
diff --git a/UVtools.Core/Operations/OperationLayerClone.cs b/UVtools.Core/Operations/OperationLayerClone.cs
index e1e896c..2271135 100644
--- a/UVtools.Core/Operations/OperationLayerClone.cs
+++ b/UVtools.Core/Operations/OperationLayerClone.cs
@@ -5,19 +5,22 @@
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
+
+using System;
using System.Text;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public sealed class OperationLayerClone : Operation
{
private uint _clones = 1;
#region Overrides
- public override Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.Current;
- public override bool CanROI { get; set; } = false;
+ public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.Current;
+ public override bool CanROI => false;
public override bool PassActualLayerIndex => true;
public override string Title => "Clone layers";
@@ -34,6 +37,8 @@ namespace UVtools.Core.Operations
public override bool CanCancel => false;
+ public override bool CanHaveProfiles => false;
+
public override StringTag Validate(params object[] parameters)
{
var sb = new StringBuilder();
diff --git a/UVtools.Core/Operations/OperationLayerImport.cs b/UVtools.Core/Operations/OperationLayerImport.cs
index 07099f0..df45ad4 100644
--- a/UVtools.Core/Operations/OperationLayerImport.cs
+++ b/UVtools.Core/Operations/OperationLayerImport.cs
@@ -20,6 +20,7 @@ using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public sealed class OperationLayerImport : Operation
{
private uint _insertAfterLayerIndex;
@@ -31,8 +32,8 @@ namespace UVtools.Core.Operations
#region Overrides
- public override Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.None;
- public override bool CanROI { get; set; } = false;
+ public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override bool CanROI => false;
public override string Title => "Import Layers";
public override string Description =>
@@ -51,6 +52,8 @@ namespace UVtools.Core.Operations
public override uint LayerIndexStart => InsertAfterLayerIndex + (ReplaceStartLayer ? 0u : 1);
public override uint LayerIndexEnd => (uint)(LayerIndexStart + Count - 1);
+ public override bool CanHaveProfiles => false;
+
public override StringTag Validate(params object[] parameters)
{
var result = new ConcurrentBag<StringTag>();
diff --git a/UVtools.Core/Operations/OperationLayerReHeight.cs b/UVtools.Core/Operations/OperationLayerReHeight.cs
index f5550c1..32bf0bc 100644
--- a/UVtools.Core/Operations/OperationLayerReHeight.cs
+++ b/UVtools.Core/Operations/OperationLayerReHeight.cs
@@ -14,14 +14,15 @@ using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public sealed class OperationLayerReHeight : Operation
{
private OperationLayerReHeightItem _item;
#region Overrides
- public override Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.None;
- public override bool CanROI { get; set; } = false;
+ public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override bool CanROI => false;
public override string Title => "Adjust layer height";
public override string Description =>
"Adjust the layer height of the model\n\n" +
@@ -38,6 +39,8 @@ namespace UVtools.Core.Operations
public override bool CanCancel => false;
+ public override bool CanHaveProfiles => false;
+
public override StringTag Validate(params object[] parameters)
{
var sb = new StringBuilder();
diff --git a/UVtools.Core/Operations/OperationLayerRemove.cs b/UVtools.Core/Operations/OperationLayerRemove.cs
index b2fb9ca..25dd621 100644
--- a/UVtools.Core/Operations/OperationLayerRemove.cs
+++ b/UVtools.Core/Operations/OperationLayerRemove.cs
@@ -5,16 +5,19 @@
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
+
+using System;
using System.Text;
namespace UVtools.Core.Operations
{
+ [Serializable]
public sealed class OperationLayerRemove : Operation
{
#region Overrides
- public override Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.Current;
- public override bool CanROI { get; set; } = false;
+ public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.Current;
+ public override bool CanROI => false;
public override bool PassActualLayerIndex => true;
public override string Title => "Remove layers";
@@ -32,6 +35,8 @@ namespace UVtools.Core.Operations
public override bool CanCancel => false;
+ public override bool CanHaveProfiles => false;
+
#endregion
#region Properties
diff --git a/UVtools.Core/Operations/OperationMask.cs b/UVtools.Core/Operations/OperationMask.cs
index ed1c3c3..c702371 100644
--- a/UVtools.Core/Operations/OperationMask.cs
+++ b/UVtools.Core/Operations/OperationMask.cs
@@ -6,13 +6,16 @@
* of this license document, but changing it is not allowed.
*/
+using System;
using System.Text;
+using System.Xml.Serialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public class OperationMask : Operation
{
public override string Title => "Mask";
@@ -30,6 +33,8 @@ namespace UVtools.Core.Operations
public override string ProgressAction => "Masked layers";
+ public override bool CanHaveProfiles => false;
+
public override StringTag Validate(params object[] parameters)
{
var sb = new StringBuilder();
@@ -41,6 +46,7 @@ namespace UVtools.Core.Operations
return new StringTag(sb.ToString());
}
+ [XmlIgnore]
public Mat Mask { get; set; }
public bool HaveMask => !(Mask is null);
diff --git a/UVtools.Core/Operations/OperationMorph.cs b/UVtools.Core/Operations/OperationMorph.cs
index 9be71f7..a16d92c 100644
--- a/UVtools.Core/Operations/OperationMorph.cs
+++ b/UVtools.Core/Operations/OperationMorph.cs
@@ -6,11 +6,14 @@
* of this license document, but changing it is not allowed.
*/
+using System;
+using System.Xml.Serialization;
using Emgu.CV.CvEnum;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public sealed class OperationMorph : Operation
{
private MorphOp _morphOperation = MorphOp.Erode;
@@ -46,6 +49,19 @@ namespace UVtools.Core.Operations
new StringTag("Gradient - Removes the interior areas of objects", MorphOp.Gradient),
};
+ public byte MorphOperationIndex
+ {
+ get
+ {
+ for (byte i = 0; i < MorphOperations.Length; i++)
+ {
+ if ((MorphOp) MorphOperations[i].Tag == MorphOperation) return i;
+ }
+
+ return 0;
+ }
+ }
+
public MorphOp MorphOperation
{
get => _morphOperation;
@@ -70,8 +86,42 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _fadeInOut, value);
}
+ [XmlIgnore]
public Kernel Kernel { get; set; } = new Kernel();
+ public override string ToString()
+ {
+ var result = $"[{_morphOperation}] [Iterations: {_iterationsStart}/{_iterationsEnd}] [Fade: {_fadeInOut}]" + LayerRangeString;
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
+
+ #endregion
+
+ #region Equality
+
+ private bool Equals(OperationMorph other)
+ {
+ return _morphOperation == other._morphOperation && _iterationsStart == other._iterationsStart && _iterationsEnd == other._iterationsEnd && _fadeInOut == other._fadeInOut;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return ReferenceEquals(this, obj) || obj is OperationMorph other && Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ var hashCode = (int) _morphOperation;
+ hashCode = (hashCode * 397) ^ (int) _iterationsStart;
+ hashCode = (hashCode * 397) ^ (int) _iterationsEnd;
+ hashCode = (hashCode * 397) ^ _fadeInOut.GetHashCode();
+ return hashCode;
+ }
+ }
+
#endregion
}
}
diff --git a/UVtools.Core/Operations/OperationMove.cs b/UVtools.Core/Operations/OperationMove.cs
index 60c9840..b25b611 100644
--- a/UVtools.Core/Operations/OperationMove.cs
+++ b/UVtools.Core/Operations/OperationMove.cs
@@ -13,6 +13,7 @@ using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public class OperationMove : Operation
{
public override string Title => "Move";
@@ -29,6 +30,8 @@ namespace UVtools.Core.Operations
public override string ProgressAction => (IsCutMove ? "Moved" : "Copied")+" layers";
+ public override bool CanHaveProfiles => false;
+
public override StringTag Validate(params object[] parameters)
{
var sb = new StringBuilder();
diff --git a/UVtools.Core/Operations/OperationPattern.cs b/UVtools.Core/Operations/OperationPattern.cs
index 4297f42..7d66f7d 100644
--- a/UVtools.Core/Operations/OperationPattern.cs
+++ b/UVtools.Core/Operations/OperationPattern.cs
@@ -5,12 +5,15 @@
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
+
+using System;
using System.Drawing;
using System.Text;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public class OperationPattern : Operation
{
private Enumerations.Anchor _anchor = Enumerations.Anchor.None;
@@ -37,6 +40,8 @@ namespace UVtools.Core.Operations
public override string ProgressAction => "Patterned layers";
+ public override bool CanHaveProfiles => false;
+
public override StringTag Validate(params object[] parameters)
{
var sb = new StringBuilder();
diff --git a/UVtools.Core/Operations/OperationPixelDimming.cs b/UVtools.Core/Operations/OperationPixelDimming.cs
index 22941d6..24bbeaa 100644
--- a/UVtools.Core/Operations/OperationPixelDimming.cs
+++ b/UVtools.Core/Operations/OperationPixelDimming.cs
@@ -6,12 +6,15 @@
* of this license document, but changing it is not allowed.
*/
+using System;
using System.Text;
+using System.Xml.Serialization;
using Emgu.CV;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public class OperationPixelDimming : Operation
{
private uint _borderSize = 5;
@@ -68,12 +71,14 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _bordersOnly, value);
}
+ [XmlIgnore]
public Matrix<byte> EvenPattern
{
get => _evenPattern;
set => RaiseAndSetIfChanged(ref _evenPattern, value);
}
+ [XmlIgnore]
public Matrix<byte> OddPattern
{
get => _oddPattern;
@@ -81,5 +86,37 @@ namespace UVtools.Core.Operations
}
#endregion
+
+ public override string ToString()
+ {
+ var result = $"[Border: {_borderSize}px] [Only borders: {_bordersOnly}]" + LayerRangeString;
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
+
+ #region Equality
+
+ protected bool Equals(OperationPixelDimming other)
+ {
+ return _borderSize == other._borderSize && _bordersOnly == other._bordersOnly;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is null) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != GetType()) return false;
+ return Equals((OperationPixelDimming) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ return ((int) _borderSize * 397) ^ _bordersOnly.GetHashCode();
+ }
+ }
+
+ #endregion
}
}
diff --git a/UVtools.Core/Operations/OperationRepairLayers.cs b/UVtools.Core/Operations/OperationRepairLayers.cs
index e004682..d54054e 100644
--- a/UVtools.Core/Operations/OperationRepairLayers.cs
+++ b/UVtools.Core/Operations/OperationRepairLayers.cs
@@ -6,12 +6,15 @@
* of this license document, but changing it is not allowed.
*/
+using System;
using System.Collections.Generic;
using System.Text;
+using System.Xml.Serialization;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public class OperationRepairLayers : Operation
{
private bool _repairIslands = true;
@@ -21,7 +24,7 @@ namespace UVtools.Core.Operations
private ushort _removeIslandsRecursiveIterations = 4;
private uint _gapClosingIterations = 1;
private uint _noiseRemovalIterations = 0;
- public override bool CanROI { get; set; } = false;
+ public override bool CanROI => false;
public override string Title => "Repair layers and issues";
public override string Description => null;
@@ -32,6 +35,8 @@ namespace UVtools.Core.Operations
public override string ProgressAction => "Repaired layers";
+ public override bool CanHaveProfiles => false;
+
public override StringTag Validate(params object[] parameters)
{
var sb = new StringBuilder();
@@ -86,8 +91,10 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _noiseRemovalIterations, value);
}
+ [XmlIgnore]
public IslandDetectionConfiguration IslandDetectionConfig { get; set; }
+ [XmlIgnore]
public List<LayerIssue> Issues { get; set; }
}
diff --git a/UVtools.Core/Operations/OperationResize.cs b/UVtools.Core/Operations/OperationResize.cs
index 2225067..fa20389 100644
--- a/UVtools.Core/Operations/OperationResize.cs
+++ b/UVtools.Core/Operations/OperationResize.cs
@@ -5,11 +5,14 @@
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
+
+using System;
using System.Text;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
+ [Serializable]
public class OperationResize : Operation
{
private decimal _x = 100;
@@ -31,7 +34,7 @@ namespace UVtools.Core.Operations
public override string ProgressTitle =>
$"Resizing from layers {LayerIndexStart} to {LayerIndexEnd} at X:{X}% Y:{Y}% ";
- public override string ProgressAction => "Reiszed layers";
+ public override string ProgressAction => "Resized layers";
public override StringTag Validate(params object[] parameters)
{
@@ -86,5 +89,41 @@ namespace UVtools.Core.Operations
public OperationResize()
{
}
+
+ public override string ToString()
+ {
+ var result = $"[X: {_x}%, Y: {_y}%] [Fade: {_isFade}] [Constrain: {_constrainXy}]"+ LayerRangeString;
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
+
+ #region Equality
+
+ protected bool Equals(OperationResize other)
+ {
+ return _x == other._x && _y == other._y && _constrainXy == other._constrainXy && _isFade == other._isFade;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is null) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != GetType()) return false;
+ return Equals((OperationResize) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ var hashCode = _x.GetHashCode();
+ hashCode = (hashCode * 397) ^ _y.GetHashCode();
+ hashCode = (hashCode * 397) ^ _constrainXy.GetHashCode();
+ hashCode = (hashCode * 397) ^ _isFade.GetHashCode();
+ return hashCode;
+ }
+ }
+
+ #endregion
}
}
diff --git a/UVtools.Core/Operations/OperationRotate.cs b/UVtools.Core/Operations/OperationRotate.cs
index e95991f..4d32762 100644
--- a/UVtools.Core/Operations/OperationRotate.cs
+++ b/UVtools.Core/Operations/OperationRotate.cs
@@ -10,6 +10,7 @@ using System;
namespace UVtools.Core.Operations
{
+ [Serializable]
public class OperationRotate : Operation
{
private decimal _angleDegrees = 90;
@@ -30,5 +31,34 @@ namespace UVtools.Core.Operations
get => _angleDegrees;
set => RaiseAndSetIfChanged(ref _angleDegrees, value);
}
+
+ public override string ToString()
+ {
+ var result = $"[Angle: {Math.Abs(_angleDegrees)}º {(AngleDegrees < 0 ? "CCW" : "CW")}]" + LayerRangeString;
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
+
+ #region Equality
+
+ protected bool Equals(OperationRotate other)
+ {
+ return _angleDegrees == other._angleDegrees;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is null) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != GetType()) return false;
+ return Equals((OperationRotate) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return _angleDegrees.GetHashCode();
+ }
+
+ #endregion
}
}
diff --git a/UVtools.Core/Operations/OperationSolidify.cs b/UVtools.Core/Operations/OperationSolidify.cs
index fc6aa96..af9474c 100644
--- a/UVtools.Core/Operations/OperationSolidify.cs
+++ b/UVtools.Core/Operations/OperationSolidify.cs
@@ -6,8 +6,11 @@
* of this license document, but changing it is not allowed.
*/
+using System;
+
namespace UVtools.Core.Operations
{
+ [Serializable]
public sealed class OperationSolidify : Operation
{
#region Overrides
@@ -26,6 +29,8 @@ namespace UVtools.Core.Operations
public override string ProgressAction => "Solidified layers";
+ public override bool CanHaveProfiles => false;
+
#endregion
}
}
diff --git a/UVtools.Core/Operations/OperationThreshold.cs b/UVtools.Core/Operations/OperationThreshold.cs
index 8854ac7..143f173 100644
--- a/UVtools.Core/Operations/OperationThreshold.cs
+++ b/UVtools.Core/Operations/OperationThreshold.cs
@@ -11,6 +11,7 @@ using Emgu.CV.CvEnum;
namespace UVtools.Core.Operations
{
+ [Serializable]
public class OperationThreshold : Operation
{
private byte _threshold = 127;
@@ -51,5 +52,40 @@ namespace UVtools.Core.Operations
}
public static Array ThresholdTypes => Enum.GetValues(typeof(ThresholdType));
+
+ public override string ToString()
+ {
+ var result = $"[{_type} = {_threshold} / {_maximum}]" + LayerRangeString;
+ if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
+ return result;
+ }
+
+ #region Equality
+
+ protected bool Equals(OperationThreshold other)
+ {
+ return _threshold == other._threshold && _maximum == other._maximum && _type == other._type;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != this.GetType()) return false;
+ return Equals((OperationThreshold) obj);
+ }
+
+ public override int GetHashCode()
+ {
+ unchecked
+ {
+ var hashCode = _threshold.GetHashCode();
+ hashCode = (hashCode * 397) ^ _maximum.GetHashCode();
+ hashCode = (hashCode * 397) ^ (int) _type;
+ return hashCode;
+ }
+ }
+
+ #endregion
}
}
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index 4486203..1966dac 100644
--- a/UVtools.Core/UVtools.Core.csproj
+++ b/UVtools.Core/UVtools.Core.csproj
@@ -10,7 +10,7 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, repair, conversion and manipulation</Description>
- <Version>1.1.2</Version>
+ <Version>1.1.3</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
diff --git a/UVtools.WPF/App.axaml.cs b/UVtools.WPF/App.axaml.cs
index b946e10..8df3fa8 100644
--- a/UVtools.WPF/App.axaml.cs
+++ b/UVtools.WPF/App.axaml.cs
@@ -20,7 +20,9 @@ using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.ThemeManager;
using Emgu.CV;
+using UVtools.Core;
using UVtools.Core.FileFormats;
+using UVtools.Core.Operations;
using UVtools.WPF.Extensions;
using UVtools.WPF.Structures;
@@ -49,6 +51,8 @@ namespace UVtools.WPF
UserSettings.Load();
UserSettings.SetVersion();
+ OperationProfiles.Load();
+
ThemeSelector = Avalonia.ThemeManager.ThemeSelector.Create(Path.Combine(ApplicationPath, "Assets", "Themes"));
ThemeSelector.LoadSelectedTheme(Path.Combine(UserSettings.SettingsFolder, "selected.theme"));
if (ThemeSelector.SelectedTheme.Name == "UVtoolsDark" || ThemeSelector.SelectedTheme.Name == "Light")
@@ -87,25 +91,24 @@ namespace UVtools.WPF
}
#region Utilities
+
+ public static string AppExecutable = Path.Combine(ApplicationPath, About.Software);
+ public static string AppExecutableQuoted = $"\"{AppExecutable}\"";
public static void NewInstance(string filePath)
{
try
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
- var info = new ProcessStartInfo("UVtools.exe", $"\"{filePath}\"")
- {
- UseShellExecute = true
- };
- Process.Start(info).Dispose();
+ StartProcess($"{AppExecutable}.exe", $"\"{filePath}\"");
}
- else if(File.Exists("UVtools"))
+ else if(File.Exists(AppExecutable)) // Direct execute
{
- Process.Start("UVtools", $"\"{filePath}\"").Dispose();
+ StartProcess(AppExecutable, $"\"{filePath}\"");
}
else
{
- Process.Start("dotnet", $"UVtools.dll \"{filePath}\"").Dispose();
+ StartProcess("dotnet", $"UVtools.dll \"{filePath}\"");
}
}
catch (Exception e)
@@ -142,11 +145,11 @@ namespace UVtools.WPF
}
- public static void StartProcess(string name)
+ public static void StartProcess(string name, string arguments = null)
{
try
{
- using (Process.Start(new ProcessStartInfo(name)
+ using (Process.Start(new ProcessStartInfo(name, arguments)
{
UseShellExecute = true
})) { }
@@ -155,7 +158,6 @@ namespace UVtools.WPF
{
Debug.WriteLine(e);
}
-
}
public static Stream GetAsset(string url)
diff --git a/UVtools.WPF/Controls/Tools/ToolArithmeticControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolArithmeticControl.axaml.cs
index 73fef89..623633e 100644
--- a/UVtools.WPF/Controls/Tools/ToolArithmeticControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolArithmeticControl.axaml.cs
@@ -6,12 +6,12 @@ namespace UVtools.WPF.Controls.Tools
{
public class ToolArithmeticControl : ToolControl
{
- public OperationArithmetic Operation { get; }
+ public OperationArithmetic Operation => BaseOperation as OperationArithmetic;
public ToolArithmeticControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationArithmetic();
+ BaseOperation = new OperationArithmetic();
Operation.PropertyChanged += (sender, e) =>
{
if (e.PropertyName == nameof(Operation.Sentence))
diff --git a/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml.cs
index 4a03116..88058ec 100644
--- a/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml.cs
@@ -10,7 +10,7 @@ namespace UVtools.WPF.Controls.Tools
private bool _isSizeEnabled = true;
private bool _isKernelVisible;
private KernelControl _kernelCtrl;
- public OperationBlur Operation { get; }
+ public OperationBlur Operation => BaseOperation as OperationBlur;
public int SelectedAlgorithmIndex
{
@@ -40,7 +40,7 @@ namespace UVtools.WPF.Controls.Tools
public ToolBlurControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationBlur();
+ BaseOperation = new OperationBlur();
_kernelCtrl = this.Find<KernelControl>("KernelCtrl");
}
diff --git a/UVtools.WPF/Controls/Tools/ToolCalculatorControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolCalculatorControl.axaml.cs
index f8acf19..c342418 100644
--- a/UVtools.WPF/Controls/Tools/ToolCalculatorControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolCalculatorControl.axaml.cs
@@ -6,14 +6,14 @@ namespace UVtools.WPF.Controls.Tools
{
public class ToolCalculatorControl : ToolControl
{
- public OperationCalculator Operation { get; }
+ public OperationCalculator Operation => BaseOperation as OperationCalculator;
public FileFormat SlicerFile => App.SlicerFile;
public ToolCalculatorControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationCalculator
+ BaseOperation = new OperationCalculator
{
CalcMillimetersToPixels = new OperationCalculator.MillimetersToPixels(SlicerFile.Resolution, SlicerFile.Display),
CalcLightOffDelay = new OperationCalculator.LightOffDelayC(
diff --git a/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs
index 5f47e72..2762a3c 100644
--- a/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolChangeResolutionControl.axaml.cs
@@ -8,7 +8,7 @@ namespace UVtools.WPF.Controls.Tools
public class ToolChangeResolutionControl : ToolControl
{
private OperationChangeResolution.Resolution _selectedPresetItem;
- public OperationChangeResolution Operation { get; }
+ public OperationChangeResolution Operation => BaseOperation as OperationChangeResolution;
public OperationChangeResolution.Resolution SelectedPresetItem
{
@@ -34,7 +34,7 @@ namespace UVtools.WPF.Controls.Tools
public ToolChangeResolutionControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationChangeResolution(App.SlicerFile.Resolution, App.SlicerFile.LayerManager.BoundingRectangle);
+ BaseOperation = new OperationChangeResolution(App.SlicerFile.Resolution, App.SlicerFile.LayerManager.BoundingRectangle);
}
private void InitializeComponent()
diff --git a/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs
index e91f2fd..8ec6d5b 100644
--- a/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs
@@ -9,7 +9,19 @@ namespace UVtools.WPF.Controls.Tools
{
public class ToolControl : UserControlEx
{
- public Operation BaseOperation = null;
+ private Operation _baseOperation;
+
+ public Operation BaseOperation
+ {
+ get => _baseOperation;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _baseOperation, value)) return;
+ if (DataContext is null) return;
+ ResetDataContext();
+ }
+ }
+
public ToolWindow ParentWindow { get; set; } = null;
public bool CanRun { get; set; } = true;
@@ -33,6 +45,12 @@ namespace UVtools.WPF.Controls.Tools
public virtual bool UpdateOperation() => true;
+ /*public virtual void SetOperation(Operation operation)
+ {
+ BaseOperation = operation;
+ ResetDataContext();
+ }*/
+
/// <summary>
/// Validates if is safe to continue with operation
/// </summary>
diff --git a/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs
index d1e761b..ba83fec 100644
--- a/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs
@@ -16,7 +16,7 @@ namespace UVtools.WPF.Controls.Tools
{
public class ToolEditParametersControl : ToolControl
{
- public OperationEditParameters Operation { get; }
+ public OperationEditParameters Operation => BaseOperation as OperationEditParameters;
public bool SupportPerLayerSettings => App.SlicerFile.SupportPerLayerSettings;
public RowControl[] RowControls;
@@ -110,7 +110,7 @@ namespace UVtools.WPF.Controls.Tools
InitializeComponent();
App.SlicerFile.RefreshPrintParametersModifiersValues();
- BaseOperation = Operation = new OperationEditParameters(App.SlicerFile.PrintParameterModifiers);
+ BaseOperation = new OperationEditParameters(App.SlicerFile.PrintParameterModifiers);
if (Operation.Modifiers is null || Operation.Modifiers.Length == 0)
{
diff --git a/UVtools.WPF/Controls/Tools/ToolFlipControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolFlipControl.axaml.cs
index c2d973b..7899b4d 100644
--- a/UVtools.WPF/Controls/Tools/ToolFlipControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolFlipControl.axaml.cs
@@ -5,12 +5,12 @@ namespace UVtools.WPF.Controls.Tools
{
public class ToolFlipControl : ToolControl
{
- public OperationFlip Operation { get; }
+ public OperationFlip Operation => BaseOperation as OperationFlip;
public ToolFlipControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationFlip();
+ BaseOperation = new OperationFlip();
}
private void InitializeComponent()
diff --git a/UVtools.WPF/Controls/Tools/ToolLayerCloneControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolLayerCloneControl.axaml.cs
index a394fa5..bbc7776 100644
--- a/UVtools.WPF/Controls/Tools/ToolLayerCloneControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolLayerCloneControl.axaml.cs
@@ -6,7 +6,7 @@ namespace UVtools.WPF.Controls.Tools
{
public class ToolLayerCloneControl : ToolControl
{
- public OperationLayerClone Operation { get; }
+ public OperationLayerClone Operation => BaseOperation as OperationLayerClone;
public uint ExtraLayers => (uint)Math.Max(0, ((int)Operation.LayerIndexEnd - Operation.LayerIndexStart + 1) * Operation.Clones);
@@ -31,7 +31,7 @@ namespace UVtools.WPF.Controls.Tools
public ToolLayerCloneControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationLayerClone();
+ BaseOperation = new OperationLayerClone();
Operation.PropertyChanged += (sender, args) =>
{
RaisePropertyChanged(nameof(InfoLayersStr));
diff --git a/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs
index 7e08757..f96b5f9 100644
--- a/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs
@@ -2,7 +2,6 @@
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
-using Avalonia.Controls.Shapes;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
using Avalonia.Media.Imaging;
@@ -12,7 +11,6 @@ using UVtools.Core.Objects;
using UVtools.Core.Operations;
using UVtools.WPF.Extensions;
using UVtools.WPF.Windows;
-using Path = System.IO.Path;
namespace UVtools.WPF.Controls.Tools
{
@@ -23,8 +21,8 @@ namespace UVtools.WPF.Controls.Tools
private Bitmap _previewImage;
private ListBox FilesListBox;
-
- public OperationLayerImport Operation { get; }
+
+ public OperationLayerImport Operation => BaseOperation as OperationLayerImport;
public uint MaximumLayer => App.SlicerFile.LastLayerIndex;
@@ -83,7 +81,7 @@ namespace UVtools.WPF.Controls.Tools
public ToolLayerImportControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationLayerImport(App.SlicerFile.Resolution);
+ BaseOperation = new OperationLayerImport(App.SlicerFile.Resolution);
Operation.Files.CollectionChanged += (sender, args) => RefreshGUI();
Operation.PropertyChanged += (sender, args) => RefreshGUI();
FilesListBox = this.Find<ListBox>("FilesListBox");
diff --git a/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml.cs
index 88c0d0a..feb5e56 100644
--- a/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolLayerReHeightControl.axaml.cs
@@ -6,7 +6,7 @@ namespace UVtools.WPF.Controls.Tools
{
public class ToolLayerReHeightControl : ToolControl
{
- public OperationLayerReHeight Operation { get; }
+ public OperationLayerReHeight Operation => BaseOperation as OperationLayerReHeight;
public OperationLayerReHeight.OperationLayerReHeightItem[] Presets { get; } = OperationLayerReHeight.GetItems(
App.SlicerFile.LayerCount,
@@ -17,7 +17,7 @@ namespace UVtools.WPF.Controls.Tools
public ToolLayerReHeightControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationLayerReHeight();
+ BaseOperation = new OperationLayerReHeight();
if (Presets.Length == 0)
{
diff --git a/UVtools.WPF/Controls/Tools/ToolLayerRemoveControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolLayerRemoveControl.axaml.cs
index e025811..a2ada0e 100644
--- a/UVtools.WPF/Controls/Tools/ToolLayerRemoveControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolLayerRemoveControl.axaml.cs
@@ -6,7 +6,7 @@ namespace UVtools.WPF.Controls.Tools
{
public class ToolLayerRemoveControl : ToolControl
{
- public OperationLayerRemove Operation { get; }
+ public OperationLayerRemove Operation => BaseOperation as OperationLayerRemove;
public uint ExtraLayers => (uint)Math.Max(0, (int)Operation.LayerIndexEnd - Operation.LayerIndexStart + 1);
@@ -31,7 +31,7 @@ namespace UVtools.WPF.Controls.Tools
public ToolLayerRemoveControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationLayerRemove();
+ BaseOperation = new OperationLayerRemove();
Operation.PropertyChanged += (sender, args) =>
{
RaisePropertyChanged(nameof(InfoLayersStr));
diff --git a/UVtools.WPF/Controls/Tools/ToolMaskControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolMaskControl.axaml.cs
index 62486b7..bad26b4 100644
--- a/UVtools.WPF/Controls/Tools/ToolMaskControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolMaskControl.axaml.cs
@@ -20,7 +20,7 @@ namespace UVtools.WPF.Controls.Tools
private byte _genMaximumBrightness = byte.MaxValue;
private uint _genDiameter;
private Bitmap _maskImage;
- public OperationMask Operation { get; }
+ public OperationMask Operation => BaseOperation as OperationMask;
public bool IsMaskInverted
{
@@ -69,7 +69,7 @@ namespace UVtools.WPF.Controls.Tools
public ToolMaskControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationMask();
+ BaseOperation = new OperationMask();
}
private void InitializeComponent()
diff --git a/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml.cs
index 5384461..7dac93e 100644
--- a/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolMorphControl.axaml.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Emgu.CV.CvEnum;
@@ -10,7 +11,7 @@ namespace UVtools.WPF.Controls.Tools
public class ToolMorphControl : ToolControl
{
private byte _morphSelectedIndex;
- public OperationMorph Operation { get; }
+ public OperationMorph Operation => BaseOperation as OperationMorph;
private KernelControl _kernelCtrl;
@@ -27,7 +28,7 @@ namespace UVtools.WPF.Controls.Tools
public ToolMorphControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationMorph();
+ BaseOperation = new OperationMorph();
_kernelCtrl = this.Find<KernelControl>("KernelCtrl");
}
diff --git a/UVtools.WPF/Controls/Tools/ToolMoveControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolMoveControl.axaml.cs
index 03a604e..a18fc5f 100644
--- a/UVtools.WPF/Controls/Tools/ToolMoveControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolMoveControl.axaml.cs
@@ -7,7 +7,7 @@ namespace UVtools.WPF.Controls.Tools
public class ToolMoveControl : ToolControl
{
private bool _isMiddleCenterChecked = true;
- public OperationMove Operation { get; }
+ public OperationMove Operation => BaseOperation as OperationMove;
public bool IsMiddleCenterChecked
{
@@ -19,7 +19,7 @@ namespace UVtools.WPF.Controls.Tools
{
InitializeComponent();
var roi = App.MainWindow.ROI;
- BaseOperation = Operation = new OperationMove(roi.IsEmpty ? App.SlicerFile.LayerManager.BoundingRectangle : roi, (uint)App.MainWindow.LayerCache.Image.Width,
+ BaseOperation = new OperationMove(roi.IsEmpty ? App.SlicerFile.LayerManager.BoundingRectangle : roi, (uint)App.MainWindow.LayerCache.Image.Width,
(uint)App.MainWindow.LayerCache.Image.Height);
Operation.PropertyChanged += (sender, e) =>
diff --git a/UVtools.WPF/Controls/Tools/ToolPatternControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolPatternControl.axaml.cs
index 1b2bbc9..cb29ad4 100644
--- a/UVtools.WPF/Controls/Tools/ToolPatternControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolPatternControl.axaml.cs
@@ -8,7 +8,7 @@ namespace UVtools.WPF.Controls.Tools
{
public class ToolPatternControl : ToolControl
{
- public OperationPattern Operation { get; }
+ public OperationPattern Operation => BaseOperation as OperationPattern;
private bool _isDefaultAnchorChecked = true;
public bool IsDefaultAnchorChecked
@@ -21,7 +21,7 @@ namespace UVtools.WPF.Controls.Tools
{
InitializeComponent();
var roi = App.MainWindow.ROI;
- BaseOperation = Operation = new OperationPattern(roi.IsEmpty ? App.SlicerFile.LayerManager.BoundingRectangle : roi, App.SlicerFile.Resolution);
+ BaseOperation = new OperationPattern(roi.IsEmpty ? App.SlicerFile.LayerManager.BoundingRectangle : roi, App.SlicerFile.Resolution);
if (Operation.MaxRows < 2 && Operation.MaxCols < 2)
{
diff --git a/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs
index 24bdd26..36499a2 100644
--- a/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolPixelDimmingControl.axaml.cs
@@ -28,7 +28,7 @@ namespace UVtools.WPF.Controls.Tools
private byte _dimGenBrightness = 127;
private ushort _infillGenThickness = 10;
private ushort _infillGenSpacing = 20;
- public OperationPixelDimming Operation { get; }
+ public OperationPixelDimming Operation => BaseOperation as OperationPixelDimming;
public string PatternText
{
@@ -63,7 +63,7 @@ namespace UVtools.WPF.Controls.Tools
public ToolPixelDimmingControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationPixelDimming();
+ BaseOperation = new OperationPixelDimming();
GeneratePixelDimming("Chessboard");
}
diff --git a/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs
index 843c096..0c317d8 100644
--- a/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolRepairLayersControl.axaml.cs
@@ -6,12 +6,12 @@ namespace UVtools.WPF.Controls.Tools
{
public class ToolRepairLayersControl : ToolControl
{
- public OperationRepairLayers Operation { get; }
+ public OperationRepairLayers Operation => BaseOperation as OperationRepairLayers;
public ToolRepairLayersControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationRepairLayers
+ BaseOperation = new OperationRepairLayers
{
RepairIslands = UserSettings.Instance.LayerRepair.RepairIslands,
RepairResinTraps = UserSettings.Instance.LayerRepair.RepairResinTraps,
diff --git a/UVtools.WPF/Controls/Tools/ToolResizeControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolResizeControl.axaml.cs
index 2f66254..c88b965 100644
--- a/UVtools.WPF/Controls/Tools/ToolResizeControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolResizeControl.axaml.cs
@@ -1,17 +1,16 @@
-using Avalonia.Controls;
-using Avalonia.Markup.Xaml;
+using Avalonia.Markup.Xaml;
using UVtools.Core.Operations;
namespace UVtools.WPF.Controls.Tools
{
public class ToolResizeControl : ToolControl
{
- public OperationResize Operation { get; }
+ public OperationResize Operation => BaseOperation as OperationResize;
public ToolResizeControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationResize();
+ BaseOperation = new OperationResize();
}
private void InitializeComponent()
diff --git a/UVtools.WPF/Controls/Tools/ToolRotateControl.axaml b/UVtools.WPF/Controls/Tools/ToolRotateControl.axaml
index cf5d180..832c0e6 100644
--- a/UVtools.WPF/Controls/Tools/ToolRotateControl.axaml
+++ b/UVtools.WPF/Controls/Tools/ToolRotateControl.axaml
@@ -9,7 +9,7 @@
<NumericUpDown
MinWidth="100"
MaxWidth="150"
- Minimum="0.01"
+ Minimum="-359.99"
Maximum="359.99"
Increment="0.01"
FormatString="{}{0:#,0.00}"
diff --git a/UVtools.WPF/Controls/Tools/ToolRotateControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolRotateControl.axaml.cs
index 14bcec7..c09b075 100644
--- a/UVtools.WPF/Controls/Tools/ToolRotateControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolRotateControl.axaml.cs
@@ -5,12 +5,12 @@ namespace UVtools.WPF.Controls.Tools
{
public class ToolRotateControl : ToolControl
{
- public OperationRotate Operation { get; }
+ public OperationRotate Operation => BaseOperation as OperationRotate;
public ToolRotateControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationRotate();
+ BaseOperation = new OperationRotate();
}
private void InitializeComponent()
diff --git a/UVtools.WPF/Controls/Tools/ToolThresholdControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolThresholdControl.axaml.cs
index 5809c8b..648bbbf 100644
--- a/UVtools.WPF/Controls/Tools/ToolThresholdControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolThresholdControl.axaml.cs
@@ -10,7 +10,7 @@ namespace UVtools.WPF.Controls.Tools
private bool _isThresholdEnabled = true;
private bool _isMaximumEnabled = true;
private bool _isTypeEnabled = true;
- public OperationThreshold Operation { get; }
+ public OperationThreshold Operation => BaseOperation as OperationThreshold;
public string[] Presets => new[]
{
@@ -74,7 +74,7 @@ namespace UVtools.WPF.Controls.Tools
public ToolThresholdControl()
{
InitializeComponent();
- BaseOperation = Operation = new OperationThreshold();
+ BaseOperation = new OperationThreshold();
}
private void InitializeComponent()
diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs
index fa2de86..1cff077 100644
--- a/UVtools.WPF/MainWindow.axaml.cs
+++ b/UVtools.WPF/MainWindow.axaml.cs
@@ -688,7 +688,49 @@ namespace UVtools.WPF
await new PrusaSlicerManager().ShowDialog(this);
}
- public void MenuNewVersionClicked() => App.OpenBrowser(VersionChecker.Url);
+ public async void MenuNewVersionClicked()
+ {
+ var result =
+ await this.MessageBoxQuestion(
+ $"Do you like to auto-update {About.Software} v{AppSettings.Version} to v{VersionChecker.Version}?\n\n" +
+ "Yes: Auto update\n" +
+ "No: Manual update\n" +
+ "Cancel: No action", "Update UVtools?", ButtonEnum.YesNoCancel);
+
+ if (result == ButtonResult.Yes)
+ {
+ IsGUIEnabled = false;
+
+ var task = await Task.Factory.StartNew(async () =>
+ {
+ ShowProgressWindow($"Downloading: {VersionChecker.Filename}");
+ try
+ {
+ VersionChecker.AutoUpgrade(ProgressWindow.RestartProgress(false));
+ return true;
+ }
+ catch (OperationCanceledException)
+ {
+ }
+ catch (Exception exception)
+ {
+ Dispatcher.UIThread.InvokeAsync(async () =>
+ await this.MessageBoxError(exception.ToString(), "Error opening the file"));
+ }
+
+ return false;
+ });
+
+ IsGUIEnabled = true;
+
+ return;
+ }
+ if (result == ButtonResult.No)
+ {
+ App.OpenBrowser(VersionChecker.UrlLatestRelease);
+ return;
+ }
+ }
#endregion
diff --git a/UVtools.WPF/Program.cs b/UVtools.WPF/Program.cs
index 1d7fa50..efd7797 100644
--- a/UVtools.WPF/Program.cs
+++ b/UVtools.WPF/Program.cs
@@ -1,6 +1,8 @@
using System;
using System.Diagnostics;
using Avalonia;
+using Avalonia.Threading;
+using UVtools.WPF.Extensions;
namespace UVtools.WPF
{
@@ -18,10 +20,28 @@ namespace UVtools.WPF
ProgramStartupTime = Stopwatch.StartNew();
Args = args;
+ // Add the event handler for handling non-UI thread exceptions to the event.
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
+
BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
}
+ private static async void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ try
+ {
+ Exception ex = (Exception)e.ExceptionObject;
+ string errorMsg = "An application error occurred. Please contact the administrator with the following information:\n\n" +
+ $"{ex}";
+
+ await App.MainWindow.MessageBoxError(errorMsg, "Fatal Non-UI Error");
+ }
+ catch (Exception exc)
+ {
+ }
+ }
+
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
diff --git a/UVtools.WPF/Structures/AppVersionChecker.cs b/UVtools.WPF/Structures/AppVersionChecker.cs
index 3d843f1..0d9f333 100644
--- a/UVtools.WPF/Structures/AppVersionChecker.cs
+++ b/UVtools.WPF/Structures/AppVersionChecker.cs
@@ -6,19 +6,72 @@
* of this license document, but changing it is not allowed.
*/
using System;
+using System.Collections.Specialized;
using System.Diagnostics;
+using System.IO;
+using System.IO.Compression;
using System.Net;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using ABI.Windows.Data.Json;
using Avalonia.Threading;
+using Newtonsoft.Json;
using UVtools.Core;
using UVtools.Core.Objects;
+using UVtools.Core.Operations;
+using UVtools.WPF.Extensions;
namespace UVtools.WPF.Structures
{
public class AppVersionChecker : BindableBase
{
+ public const string GitHubReleaseApi = "https://api.github.com/repos/sn4k3/UVtools/releases/latest";
private string _version;
private string _url;
+ public string Filename
+ {
+ get
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return $"{About.Software}_win-x64_v{_version}.msi";
+ }
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return $"{About.Software}_linux-x64_v{_version}.zip";
+ }
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ return $"{About.Software}_osx-x64_v{_version}.zip";
+ }
+
+ return $"{About.Software}_universal-x86-x64_v{_version}.zip";
+ }
+ }
+
+ public string Runtime
+ {
+ get
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return "win-x64";
+ }
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return "linux-x64";
+ }
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ return "osx-x64";
+ }
+
+ return "universal-x86-x64";
+ }
+ }
+
public string Version
{
get => _version;
@@ -30,19 +83,46 @@ namespace UVtools.WPF.Structures
}
}
- public string VersionAnnouncementText => $"New version {_version} is available!";
+ public string VersionAnnouncementText => $"New version v{_version} is available!";
- public string Url => $"{About.Website}/releases/tag/{_version}";
+ public string UrlLatestRelease => $"{About.Website}/releases/latest";
+
+ public string DownloadLink => string.IsNullOrEmpty(Filename) ? null : $"{About.Website}/releases/download/v{_version}/{Filename}";
public bool HaveNewVersion => !string.IsNullOrEmpty(Version);
+ public string DownloadedFile { get; private set; }
+
public bool Check()
{
try
{
- using (WebClient client = new WebClient())
+ using (WebClient client = new WebClient
{
- string htmlCode = client.DownloadString($"{About.Website}/releases");
+ Headers = new WebHeaderCollection
+ {
+ {HttpRequestHeader.Accept, "application/json"},
+ {HttpRequestHeader.UserAgent, "Request"}
+ }
+ })
+ {
+ var response = client.DownloadString(GitHubReleaseApi);
+ dynamic json = JsonConvert.DeserializeObject(response);
+ string tag_name = json.tag_name;
+ if (string.IsNullOrEmpty(tag_name)) return false;
+ tag_name = tag_name.Trim(' ', 'v', 'V');
+ Debug.WriteLine($"Version checker: v{AppSettings.VersionStr} <=> v{tag_name}");
+
+ if (string.Compare(tag_name, AppSettings.VersionStr, StringComparison.OrdinalIgnoreCase) > 0)
+ {
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ Version = tag_name;
+ Debug.WriteLine($"New version detected: {DownloadLink}");
+ });
+ return true;
+ }
+ /*string htmlCode = client.DownloadString($"{About.Website}/releases");
const string searchFor = "/releases/tag/";
var startIndex = htmlCode.IndexOf(searchFor, StringComparison.InvariantCultureIgnoreCase) +
searchFor.Length;
@@ -55,7 +135,7 @@ namespace UVtools.WPF.Structures
Version = version;;
});
return true;
- }
+ }*/
}
}
catch (Exception e)
@@ -65,5 +145,103 @@ namespace UVtools.WPF.Structures
return false;
}
+
+ public bool AutoUpgrade(OperationProgress progress)
+ {
+ if (!HaveNewVersion) return false;
+ progress.ItemName = "Megabytes";
+ try
+ {
+ using (var client = new WebClient())
+ {
+ var path = Path.GetTempPath();
+ DownloadedFile = Path.Combine(path, Filename);
+ Debug.WriteLine($"Downloading to: {DownloadedFile}");
+
+
+ client.DownloadProgressChanged += (sender, e) =>
+ {
+ progress.Reset("Megabytes", (uint)e.TotalBytesToReceive / 1048576, (uint)e.BytesReceived / 1048576);
+ };
+ client.DownloadFileCompleted += (sender, e) =>
+ {
+ progress.Reset("Extracting");
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ App.StartProcess(DownloadedFile);
+ Environment.Exit(0);
+ }
+ else
+ {
+ string upgradeFolder = "UPDATED_VERSION";
+ var targetDir = Path.Combine(App.ApplicationPath, upgradeFolder);
+ using (var stream = File.Open(DownloadedFile, FileMode.Open))
+ {
+ using (ZipArchive zip = new ZipArchive(stream, ZipArchiveMode.Read))
+ {
+ zip.ExtractToDirectory(targetDir, true);
+ }
+ }
+
+ File.Delete(DownloadedFile);
+
+ string upgradeFileName = $"{About.Software}_upgrade.sh";
+ var upgradeFile = Path.Combine(App.ApplicationPath, upgradeFileName);
+ using (var stream = File.CreateText(upgradeFile))
+ {
+ stream.WriteLine("#!/bin/bash");
+ stream.WriteLine($"echo {About.Software} v{AppSettings.Version} updater script");
+ stream.WriteLine($"cd '{App.ApplicationPath}'");
+ stream.WriteLine($"killall {About.Software}");
+ stream.WriteLine("sleep 0.5");
+ stream.WriteLine($"cp -fR {upgradeFolder}/* .");
+ stream.WriteLine($"rm -fr {upgradeFolder}");
+ stream.WriteLine("sleep 0.5");
+ //stream.WriteLine($"[ -f {About.Software} ] && {App.AppExecutableQuoted} & || dotnet {About.Software}.dll &");
+ stream.WriteLine($"if [ -f '{About.Software}' ]; then");
+ stream.WriteLine($" ./{About.Software} &");
+ stream.WriteLine("else");
+ stream.WriteLine($" dotnet {About.Software}.dll &");
+ stream.WriteLine("fi");
+ stream.WriteLine($"rm -f {upgradeFileName}");
+ //stream.WriteLine("exit");
+ stream.Close();
+ }
+
+ App.StartProcess("bash", $"\"{upgradeFile}\"");
+
+ //App.NewInstance(App.MainWindow.SlicerFile?.FileFullPath);
+ Environment.Exit(0);
+ }
+
+ lock (e.UserState)
+ {
+ //releases blocked thread
+ Monitor.Pulse(e.UserState);
+ }
+ };
+
+
+ var syncObject = new object();
+
+ lock (syncObject)
+ {
+ client.DownloadFileAsync(new Uri(DownloadLink), DownloadedFile, syncObject);
+ //This would block the thread until download completes
+ Monitor.Wait(syncObject);
+ }
+
+ }
+ }
+ catch (Exception e)
+ {
+ Dispatcher.UIThread.InvokeAsync(async () =>
+ await App.MainWindow.MessageBoxError(e.ToString(), "Error downloading the file"));
+ return false;
+ }
+
+
+ return false;
+ }
}
}
diff --git a/UVtools.WPF/Structures/OperationProfiles.cs b/UVtools.WPF/Structures/OperationProfiles.cs
new file mode 100644
index 0000000..c351776
--- /dev/null
+++ b/UVtools.WPF/Structures/OperationProfiles.cs
@@ -0,0 +1,270 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Xml.Serialization;
+using UVtools.Core.Operations;
+
+namespace UVtools.WPF.Structures
+{
+ [Serializable]
+ public class OperationProfiles //: IList<Operation>
+ {
+ #region Properties
+ /// <summary>
+ /// Default filepath for store <see cref="UserSettings"/>
+ /// </summary>
+ private static string FilePath => Path.Combine(UserSettings.SettingsFolder, "operation_profiles.xml");
+
+ [XmlElement(typeof(OperationArithmetic))]
+ [XmlElement(typeof(OperationBlur))]
+ //[XmlElement(typeof(OperationCalculator))]
+ [XmlElement(typeof(OperationChangeResolution))]
+ //[XmlElement(typeof(OperationEditParameters))]
+ [XmlElement(typeof(OperationFlip))]
+ //[XmlElement(typeof(OperationLayerClone))]
+ //[XmlElement(typeof(OperationLayerImport))]
+ //[XmlElement(typeof(OperationLayerReHeight))]
+ //[XmlElement(typeof(OperationLayerRemove))]
+ //[XmlElement(typeof(OperationMask))]
+ [XmlElement(typeof(OperationMorph))]
+ //[XmlElement(typeof(OperationMove))]
+ //[XmlElement(typeof(OperationPattern))]
+ [XmlElement(typeof(OperationPixelDimming))]
+ //[XmlElement(typeof(OperationRepairLayers))]
+ [XmlElement(typeof(OperationResize))]
+ [XmlElement(typeof(OperationRotate))]
+ [XmlElement(typeof(OperationThreshold))]
+ public List<Operation> Operations { get; internal set; } = new List<Operation>();
+
+ [XmlIgnore]
+ public static List<Operation> Profiles
+ {
+ get => Instance.Operations;
+ internal set => Instance.Operations = value;
+ }
+
+ #endregion
+
+ #region Singleton
+ private static OperationProfiles _instance;
+ /// <summary>
+ /// Instance of <see cref="UserSettings"/> (singleton)
+ /// </summary>
+ public static OperationProfiles Instance
+ {
+ get => _instance ??= new OperationProfiles();
+ internal set => _instance = value;
+ }
+
+ //public static List<Operation> Operations => _instance.Operations;
+ #endregion
+
+ #region Constructor
+
+ private OperationProfiles()
+ { }
+
+ #endregion
+
+ #region Indexers
+
+ public Operation this[uint index]
+ {
+ get => Operations[(int) index];
+ set => Operations[(int) index] = value;
+ }
+
+ public Operation this[int index]
+ {
+ get => Operations[index];
+ set => Operations[index] = value;
+ }
+
+ #endregion
+
+ #region Enumerable
+
+ public IEnumerator<Operation> GetEnumerator()
+ {
+ return Operations.GetEnumerator();
+ }
+
+ /*IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }*/
+ #endregion
+
+ #region List Implementation
+ public void Add(Operation item)
+ {
+ Operations.Add(item);
+ }
+
+ public int IndexOf(Operation item)
+ {
+ return Operations.IndexOf(item);
+ }
+
+ public void Insert(int index, Operation item)
+ {
+ Operations.Insert(index, item);
+ }
+
+ public bool Remove(Operation item)
+ {
+ return Operations.Remove(item);
+ }
+
+ public void RemoveAt(int index)
+ {
+ Operations.RemoveAt(index);
+ }
+
+ public void Clear()
+ {
+ Operations.Clear();
+ }
+
+ public bool Contains(Operation item)
+ {
+ return Operations.Contains(item);
+ }
+
+ public void CopyTo(Operation[] array, int arrayIndex)
+ {
+ Operations.CopyTo(array, arrayIndex);
+ }
+
+ public int Count => Operations.Count;
+ public bool IsReadOnly => false;
+ #endregion
+
+ #region Static Methods
+ /// <summary>
+ /// Clear all profiles
+ /// </summary>
+ /// <param name="save">True to save settings on file, otherwise false</param>
+ public static void ClearProfiles(bool save = true)
+ {
+ Instance.Clear();
+ if (save) Save();
+ }
+
+ /// <summary>
+ /// Clear all profiles given a type
+ /// </summary>
+ /// <param name="type">Type profiles to clear</param>
+ /// <param name="save">True to save settings on file, otherwise false</param>
+ public static void ClearProfiles(Type type, bool save = true)
+ {
+ Profiles.RemoveAll(operation => operation.GetType() == type);
+ if (save) Save();
+ }
+
+ /// <summary>
+ /// Load settings from file
+ /// </summary>
+ public static void Load()
+ {
+ if (!File.Exists(FilePath))
+ {
+ return;
+ }
+
+ var serializer = new XmlSerializer(Instance.GetType());
+ try
+ {
+ using var myXmlReader = new StreamReader(FilePath);
+ _instance = (OperationProfiles)serializer.Deserialize(myXmlReader);
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine(e.ToString());
+ ClearProfiles();
+ }
+ }
+
+ /// <summary>
+ /// Save settings to file
+ /// </summary>
+ public static void Save()
+ {
+ var serializer = new XmlSerializer(Instance.GetType());
+ try
+ {
+ using var myXmlWriter = new StreamWriter(FilePath);
+ serializer.Serialize(myXmlWriter, Instance);
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine(e.ToString());
+ }
+ }
+
+ public static Operation FindByName(Operation baseOperation, string profileName)
+ {
+ return Profiles.Find(operation =>
+ operation.GetType() == baseOperation.GetType() &&
+ (
+ !string.IsNullOrWhiteSpace(profileName) && operation.ProfileName == profileName
+ || operation.Equals(baseOperation)
+ ));
+ }
+
+
+ /// <summary>
+ /// Adds a profile
+ /// </summary>
+ /// <param name="operation"></param>
+ /// <param name="save"></param>
+ public static void AddProfile(Operation operation, bool save = true)
+ {
+ Profiles.Insert(0, operation);
+ if(save) Save();
+ }
+
+ /// <summary>
+ /// Removes a profile
+ /// </summary>
+ /// <param name="operation"></param>
+ /// <param name="save"></param>
+ public static void RemoveProfile(Operation operation, bool save = true)
+ {
+ Instance.Remove(operation);
+ if (save) Save();
+ }
+
+ /// <summary>
+ /// Get all profiles within a type
+ /// </summary>
+ /// <param name="type"></param>
+ /// <returns></returns>
+ public static List<Operation> GetOperations(Type type)
+ => Profiles.Where(operation => operation.GetType() == type).ToList();
+
+ /// <summary>
+ /// Get all profiles within a type
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <returns></returns>
+ public static List<T> GetOperations<T>()
+ {
+ var result = new List<T>();
+ foreach (var operation in _instance)
+ {
+ if (operation is T operationCast)
+ {
+ result.Add(operationCast);
+ }
+ }
+
+ return result;
+ }
+
+ #endregion
+ }
+}
diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj
index b0ddb53..005df41 100644
--- a/UVtools.WPF/UVtools.WPF.csproj
+++ b/UVtools.WPF/UVtools.WPF.csproj
@@ -12,7 +12,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
- <Version>1.1.2</Version>
+ <Version>1.1.3</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -29,7 +29,6 @@
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.0-preview6" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.0-preview6" />
<PackageReference Include="Avalonia.ThemeManager" Version="0.10.0-preview6" />
- <PackageReference Include="Emgu.CV.runtime.raspbian" Version="4.4.0.4099" />
<PackageReference Include="Emgu.CV.runtime.ubuntu" Version="4.4.0.4099" />
<PackageReference Include="Emgu.CV.runtime.windows" Version="4.4.0.4099" />
<PackageReference Include="MessageBox.Avalonia" Version="0.10.0-prev2" />
diff --git a/UVtools.WPF/UserSettings.cs b/UVtools.WPF/UserSettings.cs
index c6dc4bb..28fbe6e 100644
--- a/UVtools.WPF/UserSettings.cs
+++ b/UVtools.WPF/UserSettings.cs
@@ -9,7 +9,6 @@
using System;
using System.Diagnostics;
using System.IO;
-using System.Runtime.InteropServices;
using System.Xml.Serialization;
using Avalonia.Media;
using JetBrains.Annotations;
@@ -951,7 +950,16 @@ namespace UVtools.WPF
get
{
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), About.Software);
- Directory.CreateDirectory(path);
+ try
+ {
+ if (!Directory.Exists(path))
+ Directory.CreateDirectory(path);
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine(e);
+ }
+
return path;
}
}
diff --git a/UVtools.WPF/Windows/ToolWindow.axaml b/UVtools.WPF/Windows/ToolWindow.axaml
index 0fba631..4c37dda 100644
--- a/UVtools.WPF/Windows/ToolWindow.axaml
+++ b/UVtools.WPF/Windows/ToolWindow.axaml
@@ -202,6 +202,106 @@
</StackPanel>
</Border>
+
+ <!-- Profiles -->
+ <Border
+ Background="WhiteSmoke"
+ Margin="5"
+ BorderBrush="LightBlue"
+ BorderThickness="4"
+ IsVisible="{Binding IsProfilesVisible}"
+ >
+
+ <StackPanel Orientation="Vertical">
+ <Grid
+ ColumnDefinitions="Auto,*" Background="LightBlue">
+ <TextBlock
+ Padding="10" FontWeight="Bold"
+ VerticalAlignment="Center"
+ Text="{Binding Profiles.Count, StringFormat=Profiles: \{0\}}" />
+
+ <StackPanel Orientation="Horizontal"
+ Grid.Column="1"
+ HorizontalAlignment="Right"
+ Spacing="2">
+ <Button
+ VerticalAlignment="Center"
+ ToolTip.Tip="Clear all profiles"
+ IsEnabled="{Binding Profiles.Count}"
+ Command="{Binding ClearProfiles}"
+ >
+ <Image Width="16" Height="16" Source="/Assets/Icons/delete-16x16.png" />
+ </Button>
+
+
+ </StackPanel>
+
+ </Grid>
+
+ <Grid
+ RowDefinitions="Auto,Auto"
+ ColumnDefinitions="*,5,Auto"
+ Margin="15"
+ >
+
+ <ComboBox
+ Margin="0,0,0,10"
+ IsEnabled="{Binding Profiles.Count}"
+ IsVisible="{Binding Profiles.Count}"
+ SelectedItem="{Binding SelectedProfileItem}"
+ Items="{Binding Profiles}" />
+
+ <Button
+ Grid.Row="0"
+ Grid.Column="2"
+ Margin="0,0,0,10"
+ VerticalAlignment="Center"
+ ToolTip.Tip="Remove the selected profile"
+ IsEnabled="{Binding SelectedProfileItem, Converter={x:Static ObjectConverters.IsNotNull}}"
+ IsVisible="{Binding Profiles.Count}"
+ Command="{Binding RemoveSelectedProfile}"
+ >
+ <Image Source="/Assets/Icons/trash-16x16.png" />
+ </Button>
+
+ <TextBox
+ Grid.Row="1"
+ Grid.Column="0"
+ IsEnabled="{Binding ButtonOkEnabled}"
+ Text="{Binding ProfileText}"
+ Watermark="Profile name or leave empty for auto name"
+ />
+
+ <Button
+ Grid.Row="1"
+ Grid.Column="2"
+ VerticalAlignment="Center"
+ ToolTip.Tip="Add a new profile with the current set values"
+ IsEnabled="{Binding ButtonOkEnabled}"
+ Command="{Binding AddProfile}"
+ >
+ <Image Source="/Assets/Icons/plus-16x16.png" />
+ </Button>
+
+ </Grid>
+
+
+ <!--
+ <StackPanel Spacing="20" Margin="15,0,15,15" Orientation="Horizontal">
+ <CheckBox
+ Content="Clear ROI after perform the operation"
+ IsChecked="{Binding ClearROIAfterOperation}"
+ />
+ <Button
+ Padding="5"
+ Content="Clear ROI"
+ Command="{Binding ClearROI}"/>
+ </StackPanel>
+ !-->
+
+ </StackPanel>
+
+ </Border>
<!-- Content -->
<Border
diff --git a/UVtools.WPF/Windows/ToolWindow.axaml.cs b/UVtools.WPF/Windows/ToolWindow.axaml.cs
index 4757e0d..a767cf5 100644
--- a/UVtools.WPF/Windows/ToolWindow.axaml.cs
+++ b/UVtools.WPF/Windows/ToolWindow.axaml.cs
@@ -1,14 +1,20 @@
using System;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
using System.Drawing;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Threading;
+using DynamicData;
using MessageBox.Avalonia.Enums;
using UVtools.Core;
+using UVtools.Core.Extensions;
+using UVtools.Core.Operations;
using UVtools.WPF.Controls;
using UVtools.WPF.Controls.Tools;
using UVtools.WPF.Extensions;
+using UVtools.WPF.Structures;
namespace UVtools.WPF.Windows
{
@@ -29,8 +35,14 @@ namespace UVtools.WPF.Windows
private uint _layerIndexStart;
private uint _layerIndexEnd;
private bool _isROIVisible;
+
private bool _clearRoiAfterOperation;
+ private bool _isProfilesVisible;
+ private ObservableCollection<Operation> _profiles = new ObservableCollection<Operation>();
+ private Operation _selectedProfileItem;
+ private string _profileText;
+
private IControl _contentControl;
private bool _isButton1Visible;
private string _button1Text = "Reset to defaults";
@@ -42,6 +54,8 @@ namespace UVtools.WPF.Windows
private string _buttonOkText = "Ok";
private bool _buttonOkVisible = true;
private double _scrollViewerMaxHeight=double.PositiveInfinity;
+
+
public double ScrollViewerMaxHeight
{
@@ -92,8 +106,12 @@ namespace UVtools.WPF.Windows
set
{
if (!(ToolControl?.BaseOperation is null))
+ {
+ ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.None;
ToolControl.BaseOperation.LayerIndexStart = value;
-
+ }
+
+ value = value.Clamp(0, App.SlicerFile.LastLayerIndex);
if (!RaiseAndSetIfChanged(ref _layerIndexStart, value)) return;
RaisePropertyChanged(nameof(LayerStartMM));
RaisePropertyChanged(nameof(LayerRangeCountStr));
@@ -115,8 +133,12 @@ namespace UVtools.WPF.Windows
set
{
if (!(ToolControl?.BaseOperation is null))
+ {
+ ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.None;
ToolControl.BaseOperation.LayerIndexEnd = value;
+ }
+ value = value.Clamp(0, App.SlicerFile.LastLayerIndex);
if (!RaiseAndSetIfChanged(ref _layerIndexEnd, value)) return;
RaisePropertyChanged(nameof(LayerEndMM));
RaisePropertyChanged(nameof(LayerRangeCountStr));
@@ -141,33 +163,74 @@ namespace UVtools.WPF.Windows
{
LayerIndexStart = 0;
LayerIndexEnd = MaximumLayerIndex;
+ if(!(ToolControl is null))
+ ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.All;
}
public void SelectCurrentLayer()
{
LayerIndexStart = LayerIndexEnd = App.MainWindow.ActualLayer;
+ if (!(ToolControl is null))
+ ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.Current;
}
public void SelectBottomLayers()
{
LayerIndexStart = 0;
LayerIndexEnd = App.SlicerFile.BottomLayerCount-1u;
+ if (!(ToolControl is null))
+ ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.Bottom;
}
public void SelectNormalLayers()
{
LayerIndexStart = App.SlicerFile.BottomLayerCount;
LayerIndexEnd = MaximumLayerIndex;
+ if (!(ToolControl is null))
+ ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.Normal;
}
public void SelectFirstLayer()
{
LayerIndexStart = LayerIndexEnd = 0;
+ if (!(ToolControl is null))
+ ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.First;
}
public void SelectLastLayer()
{
LayerIndexStart = LayerIndexEnd = MaximumLayerIndex;
+ if (!(ToolControl is null))
+ ToolControl.BaseOperation.LayerRangeSelection = Enumerations.LayerRangeSelection.Last;
+ }
+
+ public void SelectLayers(Enumerations.LayerRangeSelection range)
+ {
+ switch (range)
+ {
+ case Enumerations.LayerRangeSelection.None:
+ break;
+ case Enumerations.LayerRangeSelection.All:
+ SelectAllLayers();
+ break;
+ case Enumerations.LayerRangeSelection.Current:
+ SelectCurrentLayer();
+ break;
+ case Enumerations.LayerRangeSelection.Bottom:
+ SelectBottomLayers();
+ break;
+ case Enumerations.LayerRangeSelection.Normal:
+ SelectNormalLayers();
+ break;
+ case Enumerations.LayerRangeSelection.First:
+ SelectFirstLayer();
+ break;
+ case Enumerations.LayerRangeSelection.Last:
+ SelectLastLayer();
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
}
#endregion
@@ -203,6 +266,98 @@ namespace UVtools.WPF.Windows
#endregion
+ #region Profiles
+ public bool IsProfilesVisible
+ {
+ get => _isProfilesVisible;
+ set => RaiseAndSetIfChanged(ref _isProfilesVisible, value);
+ }
+
+ public ObservableCollection<Operation> Profiles
+ {
+ get => _profiles;
+ set => RaiseAndSetIfChanged(ref _profiles, value);
+ }
+
+ public Operation SelectedProfileItem
+ {
+ get => _selectedProfileItem;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _selectedProfileItem, value) || value is null) return;
+ var operation = _selectedProfileItem.Clone();
+ operation.ProfileName = null;
+ ToolControl.BaseOperation = operation;
+ SelectLayers(operation.LayerRangeSelection);
+
+ if (operation is OperationMorph operationMorph && ToolControl is ToolMorphControl toolMorphControl)
+ {
+ toolMorphControl.MorphSelectedIndex = operationMorph.MorphOperationIndex;
+ }
+ else if (operation is OperationBlur operationBlur && ToolControl is ToolBlurControl toolBlurControl)
+ {
+ toolBlurControl.SelectedAlgorithmIndex = operationBlur.BlurTypeIndex;
+ }
+ }
+ }
+
+ public string ProfileText
+ {
+ get => _profileText;
+ set => RaiseAndSetIfChanged(ref _profileText, value);
+ }
+
+ public async void AddProfile()
+ {
+ var name = string.IsNullOrWhiteSpace(_profileText) ? null : _profileText.Trim();
+ var operation = OperationProfiles.FindByName(ToolControl.BaseOperation, name);
+ if (!(operation is null))
+ {
+ if (await this.MessageBoxQuestion(
+ $"A profile with same name or settings already exists.\nDo you want to overwrite:\n{operation}",
+ "Overwrite profile?") != ButtonResult.Yes) return;
+ /*var index = OperationProfiles.Instance.IndexOf(operation);
+ OperationProfiles.Profiles[index] = ToolControl.BaseOperation;
+ index = Profiles.IndexOf(operation);
+ Profiles[index] = ToolControl.BaseOperation;*/
+
+ OperationProfiles.RemoveProfile(operation, false);
+ Profiles.Remove(operation);
+ }
+
+ var toAdd = ToolControl.BaseOperation.Clone();
+ toAdd.ProfileName = string.IsNullOrWhiteSpace(_profileText) ? null : _profileText.Trim();
+ OperationProfiles.AddProfile(toAdd);
+ Profiles.Insert(0, toAdd);
+
+ ProfileText = null;
+ }
+
+ public async void RemoveSelectedProfile()
+ {
+ if (_selectedProfileItem is null) return;
+ if (await this.MessageBoxQuestion(
+ $"Are you sure you want to remove the selected profile?\n{_selectedProfileItem}",
+ "Remove selected profile?") != ButtonResult.Yes) return;
+
+ OperationProfiles.RemoveProfile(_selectedProfileItem);
+ Profiles.Remove(_selectedProfileItem);
+ SelectedProfileItem = null;
+ }
+
+ public async void ClearProfiles()
+ {
+ if (Profiles.Count == 0) return;
+ if (await this.MessageBoxQuestion(
+ $"Are you sure you want to clear all the {Profiles.Count} profiles?",
+ "Clear all profiles?") != ButtonResult.Yes) return;
+
+ OperationProfiles.ClearProfiles(Profiles[0].GetType());
+ Profiles.Clear();
+ }
+
+ #endregion
+
#region Content
public bool IsContentVisible => ContentControl is null || ContentControl.IsVisible;
@@ -300,41 +455,23 @@ namespace UVtools.WPF.Windows
toolControl.Margin = new Thickness(15);
Title = toolControl.BaseOperation.Title;
- LayerRangeVisible = toolControl.BaseOperation.LayerRangeSelection != Enumerations.LayerRangeSelection.None;
+ LayerRangeVisible = toolControl.BaseOperation.StartLayerRangeSelection != Enumerations.LayerRangeSelection.None;
//IsROIVisible = toolControl.BaseOperation.CanROI;
ContentControl = toolControl;
ButtonOkText = toolControl.BaseOperation.ButtonOkText;
ButtonOkVisible = ButtonOkEnabled = toolControl.BaseOperation.HaveAction;
- switch (toolControl.BaseOperation.LayerRangeSelection)
- {
- case Enumerations.LayerRangeSelection.None:
- break;
- case Enumerations.LayerRangeSelection.All:
- SelectAllLayers();
- break;
- case Enumerations.LayerRangeSelection.Current:
- SelectCurrentLayer();
- break;
- case Enumerations.LayerRangeSelection.Bottom:
- SelectBottomLayers();
- break;
- case Enumerations.LayerRangeSelection.Normal:
- SelectNormalLayers();
- break;
- case Enumerations.LayerRangeSelection.First:
- SelectFirstLayer();
- break;
- case Enumerations.LayerRangeSelection.Last:
- SelectLastLayer();
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
+ SelectLayers(toolControl.BaseOperation.StartLayerRangeSelection);
//RaisePropertyChanged(nameof(IsContentVisible));
//RaisePropertyChanged(nameof(IsROIVisible));
+ if (ToolControl.BaseOperation.CanHaveProfiles)
+ {
+ var profiles = OperationProfiles.GetOperations(ToolControl.BaseOperation.GetType());
+ Profiles.AddRange(profiles);
+ IsProfilesVisible = true;
+ }
// Ensure the description don't stretch window
DispatcherTimer.Run(() =>