mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-08-01 21:32:18 +02:00
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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;*/
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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 { get; set; } = true;
|
||||
public virtual bool CanROI => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets if this operation can store profiles
|
||||
/// </summary>
|
||||
public virtual bool CanHaveProfiles => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets if this operation supports cancellation
|
||||
@@ -105,9 +124,19 @@ 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}]";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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; set; }
|
||||
public bool MakeCopy
|
||||
{
|
||||
get => _makeCopy;
|
||||
set => RaiseAndSetIfChanged(ref _makeCopy, value);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
+13
-11
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
{
|
||||
@@ -24,7 +22,7 @@ namespace UVtools.WPF.Controls.Tools
|
||||
|
||||
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");
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>()
|
||||
|
||||
@@ -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)
|
||||
@@ -63,6 +143,104 @@ namespace UVtools.WPF.Structures
|
||||
Debug.WriteLine(e.ToString());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
|
||||
@@ -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);
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +203,106 @@
|
||||
|
||||
</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
|
||||
IsVisible="{Binding IsContentVisible}"
|
||||
|
||||
@@ -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";
|
||||
@@ -43,6 +55,8 @@ namespace UVtools.WPF.Windows
|
||||
private bool _buttonOkVisible = true;
|
||||
private double _scrollViewerMaxHeight=double.PositiveInfinity;
|
||||
|
||||
|
||||
|
||||
public double ScrollViewerMaxHeight
|
||||
{
|
||||
get => _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(() =>
|
||||
|
||||
Reference in New Issue
Block a user