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>2021-01-03 03:47:20 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2021-01-03 03:47:20 +0300
commita7d15a24d0179b06b64daf1be5f4e08c488cb930 (patch)
treeb3823c82f6031da7a6c10571945973a88390778a
parent92588fd1592236d5fef67391e55cf05b6111ed9b (diff)
v2.1.1v2.1.1
* (Add) About box: Primary screen identifier and open on screen identifier * (Add) Calibrator - External tests * (Change) Rewrite 'Action - Import Layer(s)' to support file formats and add the followig importation types: * **Insert:** Insert layers. (Requires images with bounds equal or less than file resolution) * **Replace:** Replace layers. (Requires images with bounds equal or less than file resolution) * **Stack:** Stack layers content. (Requires images with bounds equal or less than file resolution) * **Merge:** Merge/Sum layers content. (Requires images with same resolution) * **Subtract:** Subtract layers content. (Requires images with same resolution) * **BitwiseAnd:** Perform a 'bitwise and' operation over layer pixels. (Requires images with same resolution) * **BitwiseOr:** Perform a 'bitwise or' operation over layer pixels. (Requires images with same resolution) * **BitwiseXOr:** Perform a 'bitwise xor' operation over layer pixels. (Requires images with same resolution) * (Change) Icon for Tool - Raft Relief * (Change) Windows and dialogs max size are now calculated to where window is opened instead of use the primary or first screen all the time
-rw-r--r--CHANGELOG.md16
-rw-r--r--README.md13
-rw-r--r--UVtools.Core/Extensions/EmguExtensions.cs11
-rw-r--r--UVtools.Core/FileFormats/SL1File.cs10
-rw-r--r--UVtools.Core/Layer/Layer.cs27
-rw-r--r--UVtools.Core/Layer/LayerManager.cs76
-rw-r--r--UVtools.Core/Managers/ClipboardManager.cs2
-rw-r--r--UVtools.Core/Operations/OperationCalibrateExternalTests.cs47
-rw-r--r--UVtools.Core/Operations/OperationLayerImport.cs393
-rw-r--r--UVtools.Core/Operations/OperationMove.cs8
-rw-r--r--UVtools.Core/UVtools.Core.csproj2
-rw-r--r--UVtools.WPF/App.axaml.cs10
-rw-r--r--UVtools.WPF/Assets/Icons/bookmark-16x16.pngbin0 -> 114 bytes
-rw-r--r--UVtools.WPF/Assets/Icons/cookie-16x16.pngbin0 -> 183 bytes
-rw-r--r--UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml35
-rw-r--r--UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml.cs30
-rw-r--r--UVtools.WPF/Controls/Helpers.cs2
-rw-r--r--UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml103
-rw-r--r--UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs40
-rw-r--r--UVtools.WPF/Extensions/WindowExtensions.cs16
-rw-r--r--UVtools.WPF/MainWindow.axaml.cs45
-rw-r--r--UVtools.WPF/UVtools.WPF.csproj5
-rw-r--r--UVtools.WPF/Windows/AboutWindow.axaml.cs12
-rw-r--r--UVtools.WPF/Windows/SettingsWindow.axaml.cs2
-rw-r--r--UVtools.WPF/Windows/ToolWindow.axaml.cs2
25 files changed, 713 insertions, 194 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 00c9fb8..853079a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
# Changelog
+## 03/12/2020 - v2.1.1
+
+* (Add) About box: Primary screen identifier and open on screen identifier
+* (Add) Calibrator - External tests
+* (Change) Rewrite 'Action - Import Layer(s)' to support file formats and add the followig importation types:
+ * **Insert:** Insert layers. (Requires images with bounds equal or less than file resolution)
+ * **Replace:** Replace layers. (Requires images with bounds equal or less than file resolution)
+ * **Stack:** Stack layers content. (Requires images with bounds equal or less than file resolution)
+ * **Merge:** Merge/Sum layers content. (Requires images with same resolution)
+ * **Subtract:** Subtract layers content. (Requires images with same resolution)
+ * **BitwiseAnd:** Perform a 'bitwise and' operation over layer pixels. (Requires images with same resolution)
+ * **BitwiseOr:** Perform a 'bitwise or' operation over layer pixels. (Requires images with same resolution)
+ * **BitwiseXOr:** Perform a 'bitwise xor' operation over layer pixels. (Requires images with same resolution)
+* (Change) Icon for Tool - Raft Relief
+* (Change) Windows and dialogs max size are now calculated to where window is opened instead of use the primary or first screen all the time
+
## 29/12/2020 - v2.1.0
* (Add) Tool - Redraw model/supports: Redraw the model or supports with a set brightness. This requires an extra sliced file from same object but without any supports and raft, straight to the build plate.
diff --git a/README.md b/README.md
index 0ee0652..bb9af0b 100644
--- a/README.md
+++ b/README.md
@@ -193,15 +193,15 @@ sudo apt-get install -y libjpeg-dev libpng-dev libgeotiff-dev libdc1394-22 libav
**Arch/Manjaro/Similars**
```bash
-sudo pacman -S openjpeg2 libjpeg-turbo libpng libgeotiff libdc1394 libdc1394 ffmpeg openexr tbb dotnet-runtime
+sudo pacman -S openjpeg2 libjpeg-turbo libpng libgeotiff libdc1394 libdc1394 ffmpeg openexr tbb
```
To run UVtools open it folder on a terminal and call one of:
* Double-click UVtools file
* `./UVtools`
-* `dotnet UVtools.dll` [For universal package only]
-* `sh UVtools.sh` [For universal package only]
+* `sh UVtools.sh`
+* `dotnet UVtools.dll` [For universal package only, requires dotnet-runtime]
* As a pratical alternative you can create a shortcut on Desktop
### Mac
@@ -213,20 +213,19 @@ To run UVtools open it folder on a terminal and call one of:
<!---
* Donwload and install: https://dotnet.microsoft.com/download/dotnet/thank-you/sdk-5.0.101-macos-x64-installer
brew install libjpeg libpng libgeotiff libdc1394 ffmpeg openexr tbb
--->
-
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
brew analytics off
brew cask install dotnet
```
+-->
To run UVtools open it folder on a terminal and call one of:
* Double-click UVtools file
* `./UVtools`
-* `dotnet UVtools.dll` [For universal package only]
-* `sh UVtools.sh` [For universal package only]
+* `sh UVtools.sh`
+* `dotnet UVtools.dll` [For universal package only, requires dotnet-runtime]
* As a pratical alternative you can create a shortcut on Desktop
## How to use
diff --git a/UVtools.Core/Extensions/EmguExtensions.cs b/UVtools.Core/Extensions/EmguExtensions.cs
index a48a5c7..42db640 100644
--- a/UVtools.Core/Extensions/EmguExtensions.cs
+++ b/UVtools.Core/Extensions/EmguExtensions.cs
@@ -255,5 +255,16 @@ namespace UVtools.Core.Extensions
return mat;
}
+ public static Mat RoiFromCenter(this Mat mat, Size size)
+ {
+ if (size == mat.Size) return mat;
+ return new Mat(mat, new Rectangle(
+ mat.Size.Width / 2 - size.Width / 2,
+ mat.Size.Height / 2 - size.Height / 2,
+ size.Width,
+ size.Height
+ ));
+ }
+
}
}
diff --git a/UVtools.Core/FileFormats/SL1File.cs b/UVtools.Core/FileFormats/SL1File.cs
index 0db56ef..68229b9 100644
--- a/UVtools.Core/FileFormats/SL1File.cs
+++ b/UVtools.Core/FileFormats/SL1File.cs
@@ -275,15 +275,15 @@ namespace UVtools.Core.FileFormats
#endregion
#region Properties
- public Printer PrinterSettings { get; private set; }
+ public Printer PrinterSettings { get; private set; } = new();
- public Material MaterialSettings { get; private set; }
+ public Material MaterialSettings { get; private set; } = new();
- public Print PrintSettings { get; private set; }
+ public Print PrintSettings { get; private set; } = new();
- public OutputConfig OutputConfigSettings { get; private set; }
+ public OutputConfig OutputConfigSettings { get; private set; } = new();
- public Statistics Statistics { get; } = new Statistics();
+ public Statistics Statistics { get; } = new ();
public override FileFormatType FileType => FileFormatType.Archive;
diff --git a/UVtools.Core/Layer/Layer.cs b/UVtools.Core/Layer/Layer.cs
index 875ca1b..568692b 100644
--- a/UVtools.Core/Layer/Layer.cs
+++ b/UVtools.Core/Layer/Layer.cs
@@ -204,7 +204,7 @@ namespace UVtools.Core
{
get
{
- Mat mat = new Mat();
+ Mat mat = new();
CvInvoke.Imdecode(CompressedBytes, ImreadModes.Grayscale, mat);
return mat;
}
@@ -246,26 +246,28 @@ namespace UVtools.Core
GetBoundingRectangle();
}*/
- if (!(parentLayerManager is null))
- {
- _positionZ = SlicerFile.GetHeightFromLayer(index);
- _exposureTime = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomExposureTime, SlicerFile.ExposureTime);
- _liftHeight = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftHeight, SlicerFile.LiftHeight);
- _liftSpeed = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed);
- _retractSpeed = SlicerFile.RetractSpeed;
- _lightPwm = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
- }
+ if (parentLayerManager is null) return;
+ _positionZ = SlicerFile.GetHeightFromLayer(index);
+ _exposureTime = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomExposureTime, SlicerFile.ExposureTime);
+ _liftHeight = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftHeight, SlicerFile.LiftHeight);
+ _liftSpeed = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLiftSpeed, SlicerFile.LiftSpeed);
+ _retractSpeed = SlicerFile.RetractSpeed;
+ _lightPwm = SlicerFile.GetInitialLayerValueOrNormal(index, SlicerFile.BottomLightPWM, SlicerFile.LightPWM);
}
+ public Layer(uint index, byte[] compressedBytes, FileFormat slicerFile) : this(index, compressedBytes, slicerFile.LayerManager)
+ {}
+
public Layer(uint index, Mat layerMat, LayerManager parentLayerManager) : this(index, new byte[0], parentLayerManager)
{
LayerMat = layerMat;
IsModified = false;
}
+ public Layer(uint index, Mat layerMat, FileFormat slicerFile) : this(index, layerMat, slicerFile.LayerManager) { }
- public Layer(uint index, Stream stream, LayerManager parentLayerManager) : this(index, stream.ToArray(), parentLayerManager)
- { }
+ public Layer(uint index, Stream stream, LayerManager parentLayerManager) : this(index, stream.ToArray(), parentLayerManager) { }
+ public Layer(uint index, Stream stream, FileFormat slicerFile) : this(index, stream.ToArray(), slicerFile.LayerManager) { }
#endregion
#region Equatables
@@ -366,6 +368,7 @@ namespace UVtools.Core
bool needDispose = false;
if (mat is null)
{
+ if (_compressedBytes is null || _compressedBytes.Length == 0) return Rectangle.Empty;
mat = LayerMat;
needDispose = true;
}
diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs
index f354ea2..5a2924c 100644
--- a/UVtools.Core/Layer/LayerManager.cs
+++ b/UVtools.Core/Layer/LayerManager.cs
@@ -203,17 +203,15 @@ namespace UVtools.Core
public Rectangle GetBoundingRectangle(OperationProgress progress = null)
{
+ progress ??= new OperationProgress(OperationProgress.StatusOptimizingBounds, Count-1);
if (!_boundingRectangle.IsEmpty || Count == 0 || this[0] is null) return _boundingRectangle;
_boundingRectangle = this[0].BoundingRectangle;
if (_boundingRectangle.IsEmpty) // Safe checking
{
- progress?.Reset(OperationProgress.StatusOptimizingBounds, Count);
+ progress.Reset(OperationProgress.StatusOptimizingBounds, Count-1);
Parallel.For(0, Count, layerIndex =>
{
- if (!ReferenceEquals(progress, null) && progress.Token.IsCancellationRequested)
- {
- return;
- }
+ if (progress.Token.IsCancellationRequested) return;
this[layerIndex].GetBoundingRectangle();
@@ -233,12 +231,11 @@ namespace UVtools.Core
}
- progress?.Reset(OperationProgress.StatusCalculatingBounds, Count);
+ progress.Reset(OperationProgress.StatusCalculatingBounds, Count-1);
for (int i = 1; i < Count; i++)
{
if(this[i].BoundingRectangle.IsEmpty) continue;
_boundingRectangle = Rectangle.Union(_boundingRectangle, this[i].BoundingRectangle);
- if (ReferenceEquals(progress, null)) continue;
progress++;
}
@@ -1149,7 +1146,7 @@ namespace UVtools.Core
/// Reallocate with new size
/// </summary>
/// <returns></returns>
- public LayerManager Reallocate(uint newLayerCount, bool makeClone = false)
+ public LayerManager ReallocateNew(uint newLayerCount, bool makeClone = false)
{
LayerManager layerManager = new LayerManager(newLayerCount, SlicerFile);
foreach (var layer in this)
@@ -1164,6 +1161,69 @@ namespace UVtools.Core
}
/// <summary>
+ /// Reallocate with add size
+ /// </summary>
+ /// <returns></returns>
+ public void Reallocate(uint insertAtLayerIndex, uint layerCount, bool initBlack = false)
+ {
+ var layers = Layers;
+ Layers = new Layer[Count + layerCount];
+
+ // Rearrange
+ for (uint layerIndex = 0; layerIndex < insertAtLayerIndex; layerIndex++)
+ {
+ Layers[layerIndex] = layers[layerIndex];
+ }
+
+ // Rearrange
+ for (uint layerIndex = insertAtLayerIndex; layerIndex < layers.Length; layerIndex++)
+ {
+ Layers[layerCount + layerIndex] = layers[layerIndex];
+ Layers[layerCount + layerIndex].Index = layerCount + layerIndex;
+ }
+
+ // Allocate new layers
+ if (initBlack)
+ {
+ Parallel.For(insertAtLayerIndex, insertAtLayerIndex + layerCount, layerIndex =>
+ {
+ Layers[layerIndex] = new Layer((uint) layerIndex, EmguExtensions.InitMat(SlicerFile.Resolution), this);
+ });
+ }
+ /*for (uint layerIndex = insertAtLayerIndex; layerIndex < insertAtLayerIndex + layerCount; layerIndex++)
+ {
+ Layers[layerIndex] = initBlack ? new Layer(layerIndex, EmguExtensions.InitMat(SlicerFile.Resolution), this) : null;
+ }*/
+ }
+
+ public void ReallocateRange(uint startLayerIndex, uint endLayerIndex)
+ {
+ var layers = Layers;
+ if ((int)(endLayerIndex - startLayerIndex) < 0) return;
+ Layers = new Layer[1 + endLayerIndex - startLayerIndex];
+
+ uint currentLayerIndex = 0;
+ for (uint layerIndex = startLayerIndex; layerIndex <= endLayerIndex; layerIndex++)
+ {
+ Layers[currentLayerIndex++] = layers[layerIndex];
+ }
+
+ BoundingRectangle = Rectangle.Empty;
+ }
+
+ /// <summary>
+ /// Reallocate at start
+ /// </summary>
+ /// <returns></returns>
+ public void ReallocateStart(uint layerCount, bool initBlack = false) => Reallocate(0, layerCount, initBlack);
+
+ /// <summary>
+ /// Reallocate at end
+ /// </summary>
+ /// <returns></returns>
+ public void ReallocateEnd(uint layerCount, bool initBlack = false) => Reallocate(Count, layerCount, initBlack);
+
+ /// <summary>
/// Clone this object
/// </summary>
/// <returns></returns>
diff --git a/UVtools.Core/Managers/ClipboardManager.cs b/UVtools.Core/Managers/ClipboardManager.cs
index abb1a68..f87085f 100644
--- a/UVtools.Core/Managers/ClipboardManager.cs
+++ b/UVtools.Core/Managers/ClipboardManager.cs
@@ -122,7 +122,7 @@ namespace UVtools.Core.Managers
var clip = this[i];
if (layerManager.Count != clip.LayerCount) // Need resize layer manager
{
- layerManager = layerManager.Reallocate(clip.LayerCount);
+ layerManager = layerManager.ReallocateNew(clip.LayerCount);
ReallocatedLayerCount = true;
}
diff --git a/UVtools.Core/Operations/OperationCalibrateExternalTests.cs b/UVtools.Core/Operations/OperationCalibrateExternalTests.cs
new file mode 100644
index 0000000..64a5bb6
--- /dev/null
+++ b/UVtools.Core/Operations/OperationCalibrateExternalTests.cs
@@ -0,0 +1,47 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+
+
+namespace UVtools.Core.Operations
+{
+ public class OperationCalibrateExternalTests : Operation
+ {
+ #region Members
+ #endregion
+
+ #region Overrides
+
+ public override Enumerations.LayerRangeSelection StartLayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override bool CanROI => false;
+ public override bool CanHaveProfiles => false;
+ public override string ButtonOkText => null;
+ public override string Title => "External tests";
+ public override string Description =>
+ "A set of useful external tests to run within your slicer.\nClick on a button to open website and instructions.";
+
+ public override string ConfirmationText => null;
+
+ public override string ProgressTitle => null;
+
+ public override string ProgressAction => null;
+
+ #endregion
+
+ #region Properties
+
+ #endregion
+
+ #region Equality
+
+ #endregion
+
+ #region Methods
+
+ #endregion
+ }
+}
diff --git a/UVtools.Core/Operations/OperationLayerImport.cs b/UVtools.Core/Operations/OperationLayerImport.cs
index 17c4dba..7e5b822 100644
--- a/UVtools.Core/Operations/OperationLayerImport.cs
+++ b/UVtools.Core/Operations/OperationLayerImport.cs
@@ -6,15 +6,17 @@
* of this license document, but changing it is not allowed.
*/
using System;
-using System.Collections.Concurrent;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using System.Xml.Serialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
+using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
@@ -23,12 +25,26 @@ namespace UVtools.Core.Operations
[Serializable]
public sealed class OperationLayerImport : Operation
{
- private uint _insertAfterLayerIndex;
- private bool _replaceStartLayer;
- private bool _replaceSubsequentLayers;
- private bool _discardRemainingLayers;
- private bool _mergeImages;
- private ObservableCollection<StringTag> _files = new ObservableCollection<StringTag>();
+ #region Enums
+ public enum ImportTypes : byte
+ {
+ Insert,
+ Replace,
+ Stack,
+ Merge,
+ Subtract,
+ BitwiseAnd,
+ BitwiseOr,
+ BitwiseXOr,
+ }
+ #endregion
+
+ private ImportTypes _importType = ImportTypes.Stack;
+ private uint _startLayerIndex;
+ private bool _extendBeyondLayerCount = true;
+ private bool _discardUnmodifiedLayers;
+ private ushort _stackMargin = 50;
+ private ObservableCollection<StringTag> _files = new();
#region Overrides
@@ -37,26 +53,25 @@ namespace UVtools.Core.Operations
public override string Title => "Import Layers";
public override string Description =>
- "Import layers from local files into the model at a selected layer height.\n\n" +
+ "Import layers from local files into the model at a selected layer height.\n" +
"NOTE: Imported images must be greyscale and have the same resolution as the model.";
- public override string ConfirmationText => $"import {Count} layer{(Count!=1?"s":"")}?";
+ public override string ConfirmationText => $"{_importType} import {Count} file{(Count>=1?"s":"")}?";
public override string ProgressTitle =>
- $"Importing {Count} layer{(Count!=1 ? "s" : "")}";
+ $"{_importType} importing {Count} file{(Count>=1 ? "s" : "")}";
public override string ProgressAction => "Imported layers";
public override bool CanCancel => true;
- public override uint LayerIndexStart => InsertAfterLayerIndex + (ReplaceStartLayer ? 0u : 1);
- public override uint LayerIndexEnd => (uint)(LayerIndexStart + Count - 1);
+ public override uint LayerIndexEnd => _startLayerIndex + Count - 1;
public override bool CanHaveProfiles => false;
public override StringTag Validate(params object[] parameters)
{
- var result = new ConcurrentBag<StringTag>();
+ /*var result = new ConcurrentBag<StringTag>();
Parallel.ForEach(Files, file =>
{
using (Mat mat = CvInvoke.Imread(file.TagString, ImreadModes.AnyColor))
@@ -83,52 +98,76 @@ namespace UVtools.Core.Operations
}
message.AppendLine(file.Content);
}
+
+
+ return new StringTag(message.ToString(), result);*/
+
+ StringBuilder sb = new();
+
+ if (Files.Count == 0)
+ {
+ sb.AppendLine("No files to import.");
+ }
- return new StringTag(message.ToString(), result);
+ return new StringTag(sb.ToString());
}
#endregion
#region Properties
+ [XmlIgnore]
public Size FileResolution { get; }
- public uint InsertAfterLayerIndex
+ public ImportTypes ImportType
{
- get => _insertAfterLayerIndex;
- set => RaiseAndSetIfChanged(ref _insertAfterLayerIndex, value);
+ get => _importType;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _importType, value)) return;
+ RaisePropertyChanged(nameof(IsImportStackType));
+ RaisePropertyChanged(nameof(IsExtendBeyondLayerCountVisible));
+ }
}
- public bool ReplaceStartLayer
+
+ public static Array ImportTypesItems => Enum.GetValues(typeof(ImportTypes));
+
+ public bool IsImportStackType => _importType == ImportTypes.Stack;
+
+ public uint StartLayerIndex
{
- get => _replaceStartLayer;
- set => RaiseAndSetIfChanged(ref _replaceStartLayer, value);
+ get => _startLayerIndex;
+ set => RaiseAndSetIfChanged(ref _startLayerIndex, value);
}
- public bool ReplaceSubsequentLayers
+ public bool ExtendBeyondLayerCount
{
- get => _replaceSubsequentLayers;
- set => RaiseAndSetIfChanged(ref _replaceSubsequentLayers, value);
+ get => _extendBeyondLayerCount;
+ set => RaiseAndSetIfChanged(ref _extendBeyondLayerCount, value);
}
- public bool DiscardRemainingLayers
+ public bool IsExtendBeyondLayerCountVisible => _importType == ImportTypes.Replace || _importType == ImportTypes.Stack || _importType == ImportTypes.Merge;
+
+ public bool DiscardUnmodifiedLayers
{
- get => _discardRemainingLayers;
- set => RaiseAndSetIfChanged(ref _discardRemainingLayers, value);
+ get => _discardUnmodifiedLayers;
+ set => RaiseAndSetIfChanged(ref _discardUnmodifiedLayers, value);
}
- public bool MergeImages
+ public ushort StackMargin
{
- get => _mergeImages;
- set => RaiseAndSetIfChanged(ref _mergeImages, value);
+ get => _stackMargin;
+ set => RaiseAndSetIfChanged(ref _stackMargin, value);
}
+ [XmlIgnore]
public ObservableCollection<StringTag> Files
{
get => _files;
set => RaiseAndSetIfChanged(ref _files, value);
}
- public int Count => Files.Count;
+ public uint Count => (uint) Files.Count;
#endregion
#region Constructor
@@ -163,7 +202,7 @@ namespace UVtools.Core.Operations
}
- public uint CalculateTotalLayers(uint totalLayers)
+ /*public uint CalculateTotalLayers(uint totalLayers)
{
if (DiscardRemainingLayers)
{
@@ -176,7 +215,7 @@ namespace UVtools.Core.Operations
}
return (uint)(totalLayers + Files.Count - (ReplaceStartLayer ? 1 : 0));
- }
+ }*/
public override string ToString()
{
@@ -188,67 +227,275 @@ namespace UVtools.Core.Operations
public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
{
progress ??= new OperationProgress();
- progress.Reset(ProgressAction, (uint)Count);
-
- var oldLayers = slicerFile.LayerManager.Layers;
- uint newLayerCount = CalculateTotalLayers((uint)oldLayers.Length);
- uint startIndex = LayerIndexStart;
- var layers = new Layer[newLayerCount];
-
- // Keep same layers up to InsertAfterLayerIndex
- for (uint i = 0; i <= InsertAfterLayerIndex; i++)
+ slicerFile.SuppressRebuildProperties = true;
+
+ List<FileFormat> fileFormats = new();
+ List<KeyValuePair<uint, string>> keyImage = new();
+ int lastProcessedLayerIndex = -1;
+
+ // Order raw images
+ for (int i = 0; i < Count; i++)
{
- layers[i] = oldLayers[i];
+ if (!Files[i].TagString.EndsWith(".png", StringComparison.OrdinalIgnoreCase) &&
+ !Files[i].TagString.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) &&
+ !Files[i].TagString.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) &&
+ !Files[i].TagString.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) &&
+ !Files[i].TagString.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)) continue;
+ keyImage.Add(new KeyValuePair<uint, string>((uint) keyImage.Count, Files[i].TagString));
}
- // Keep all old layers if not discarding them
- if (ReplaceSubsequentLayers)
+ // Create virtual file format with images
+ if (keyImage.Count > 0)
{
- if (!DiscardRemainingLayers)
+ progress.Reset("Packing images", (uint) keyImage.Count);
+ SL1File format = new SL1File();
+ format.LayerManager = new LayerManager((uint) keyImage.Count, format);
+
+ Parallel.ForEach(keyImage, pair =>
{
- for (uint i = InsertAfterLayerIndex + 1; i < oldLayers.Length; i++)
+ if (progress.Token.IsCancellationRequested) return;
+ using var mat = CvInvoke.Imread(pair.Value, ImreadModes.Grayscale);
+ if (pair.Key == 0) format.Resolution = mat.Size;
+ format[pair.Key] = new Layer(pair.Key, mat, format);
+
+ lock (progress.Mutex)
{
- layers[i] = oldLayers[i];
+ progress++;
}
- }
+ });
+
+ progress.Token.ThrowIfCancellationRequested();
+ fileFormats.Add(format);
}
- else // Push remaining layers to the end of imported layers
+
+ // Order remaining possible file formats
+ for (int i = 0; i < Count; i++)
+ {
+ if (Files[i].TagString.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ||
+ Files[i].TagString.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) ||
+ Files[i].TagString.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) ||
+ Files[i].TagString.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) ||
+ Files[i].TagString.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)) continue;
+
+ var fileFormat = FileFormat.FindByExtension(Files[i].TagString, true, true);
+ if(fileFormat is null) continue;
+ fileFormat.FileFullPath = Files[i].TagString;
+ fileFormats.Add(fileFormat);
+ }
+
+ progress.Token.ThrowIfCancellationRequested();
+
+ if (fileFormats.Count == 0) return false;
+
+ if (_importType == ImportTypes.Stack)
+ {
+ new OperationMove(slicerFile, Enumerations.Anchor.TopLeft){LayerIndexEnd = slicerFile.LastLayerIndex}.Execute(slicerFile, progress);
+ }
+
+ foreach (var fileFormat in fileFormats)
{
- uint oldLayerIndex = InsertAfterLayerIndex;
- for (uint i = LayerIndexEnd + 1; i < newLayerCount; i++)
+ if (!string.IsNullOrEmpty(fileFormat.FileFullPath))
{
- oldLayerIndex++;
- layers[i] = oldLayers[oldLayerIndex];
+ fileFormat.Decode(fileFormat.FileFullPath, progress);
}
- }
+ var boundingRectangle = slicerFile.LayerManager.GetBoundingRectangle(progress);
+ var fileFormatBoundingRectangle = fileFormat.LayerManager.GetBoundingRectangle(progress);
+ var roiRectangle = Rectangle.Empty;
- Parallel.For(0, Count,
- //new ParallelOptions{MaxDegreeOfParallelism = 1},
- i =>
+ // Check if is possible to process this file
+ switch (_importType)
{
- var mat = CvInvoke.Imread(Files[i].TagString, ImreadModes.Grayscale);
- uint layerIndex = (uint)(startIndex + i);
- if (MergeImages)
- {
- if (layers[layerIndex] is not null)
+ case ImportTypes.Insert:
+ if (slicerFile.Resolution != fileFormat.Resolution &&
+ (slicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width ||
+ slicerFile.Resolution.Height < fileFormat.LayerManager.BoundingRectangle.Height)) continue;
+ slicerFile.LayerManager.Reallocate(_startLayerIndex, fileFormat.LayerCount);
+ break;
+ case ImportTypes.Replace:
+ case ImportTypes.Stack:
+ if (slicerFile.Resolution != fileFormat.Resolution &&
+ (slicerFile.Resolution.Width < fileFormat.LayerManager.BoundingRectangle.Width ||
+ slicerFile.Resolution.Height < fileFormat.LayerManager.BoundingRectangle.Height)) continue;
+
+
+ if(fileFormatBoundingRectangle.Width >= slicerFile.ResolutionX || fileFormatBoundingRectangle.Height >= slicerFile.ResolutionY)
+ continue;
+
+ int x = 0;
+ int y = 0;
+
+ if (boundingRectangle.Right + _stackMargin + fileFormatBoundingRectangle.Width <
+ slicerFile.ResolutionX)
{
- using var oldMat = layers[layerIndex].LayerMat;
- CvInvoke.Add(oldMat, mat, mat);
+ x = boundingRectangle.Right + _stackMargin;
+ }
+ else
+ {
+ y = boundingRectangle.Bottom + _stackMargin;
}
- }
- layers[layerIndex] = new Layer(layerIndex, mat, slicerFile.LayerManager);
- lock (progress.Mutex)
+ if (y >= slicerFile.ResolutionY)
+ continue;
+
+ roiRectangle = new Rectangle(x, y, fileFormatBoundingRectangle.Width, fileFormatBoundingRectangle.Height);
+
+ if (_extendBeyondLayerCount)
+ {
+ int layerCountDifference = (int) (_startLayerIndex + fileFormat.LayerCount - slicerFile.LayerCount);
+ if (layerCountDifference > 0)
+ {
+ slicerFile.LayerManager.ReallocateEnd((uint) layerCountDifference, _importType == ImportTypes.Stack);
+ }
+ }
+
+ break;
+ case ImportTypes.Merge:
+ if (slicerFile.Resolution != fileFormat.Resolution) continue;
+ if (_extendBeyondLayerCount)
+ {
+ int layerCountDifference = (int)(_startLayerIndex + fileFormat.LayerCount - slicerFile.LayerCount);
+ if (layerCountDifference > 0)
+ {
+ slicerFile.LayerManager.ReallocateEnd((uint)layerCountDifference, true);
+ }
+ }
+ break;
+ case ImportTypes.Subtract:
+ case ImportTypes.BitwiseAnd:
+ case ImportTypes.BitwiseOr:
+ case ImportTypes.BitwiseXOr:
+ if (slicerFile.Resolution != fileFormat.Resolution) continue;
+ break;
+ }
+
+ progress.Reset(ProgressAction, fileFormat.LayerCount);
+ Parallel.For(0, fileFormat.LayerCount,
+ //new ParallelOptions{MaxDegreeOfParallelism = 1},
+ i =>
{
- progress++;
- }
- });
+ if (progress.Token.IsCancellationRequested) return;
+ uint layerIndex = (uint)(_startLayerIndex + i);
+
+ switch (_importType)
+ {
+ case ImportTypes.Insert:
+ {
+ if (layerIndex >= slicerFile.LayerCount) return;
+ if (slicerFile.Resolution == fileFormat.Resolution)
+ {
+ slicerFile[layerIndex] = fileFormat[i];
+ break;
+ }
+
+ using var layer = fileFormat[i].LayerMat;
+ using var layerRoi = layer.RoiFromCenter(slicerFile.Resolution);
+ slicerFile[layerIndex] = new Layer(layerIndex, layerRoi, slicerFile);
+
+ break;
+ }
+ case ImportTypes.Replace:
+ {
+ if (layerIndex >= slicerFile.LayerCount) return;
+ if (slicerFile.Resolution == fileFormat.Resolution)
+ {
+ slicerFile[layerIndex] = fileFormat[i];
+ break;
+ }
+
+ using var layer = fileFormat[i].LayerMat;
+ using var layerRoi = layer.RoiFromCenter(slicerFile.Resolution);
+ slicerFile[layerIndex] = new Layer(layerIndex, layerRoi, slicerFile);
+ break;
+ }
+ case ImportTypes.Stack:
+ {
+ if (layerIndex >= slicerFile.LayerCount) return;
+ using var mat = slicerFile[layerIndex].LayerMat;
+ using var importMat = fileFormat[i].LayerMat;
+ var matRoi = new Mat(mat, roiRectangle);
+ var importMatRoi = new Mat(importMat, fileFormatBoundingRectangle);
+ importMatRoi.CopyTo(matRoi);
+ slicerFile[layerIndex].LayerMat = mat;
+
+ break;
+ }
+ case ImportTypes.Merge:
+ {
+ if (layerIndex >= slicerFile.LayerCount) return;
+ using var originalMat = slicerFile[layerIndex].LayerMat;
+ using var newMat = fileFormat[i].LayerMat;
+ CvInvoke.Add(originalMat, newMat, newMat);
+ slicerFile[layerIndex].LayerMat = newMat;
+ break;
+ }
+ case ImportTypes.Subtract:
+ {
+ if (layerIndex >= slicerFile.LayerCount) return;
+ using var originalMat = slicerFile[layerIndex].LayerMat;
+ using var newMat = fileFormat[i].LayerMat;
+ CvInvoke.Subtract(originalMat, newMat, newMat);
+ slicerFile[layerIndex].LayerMat = newMat;
+ break;
+ }
+ case ImportTypes.BitwiseAnd:
+ {
+ if (layerIndex >= slicerFile.LayerCount) return;
+ using var originalMat = slicerFile[layerIndex].LayerMat;
+ using var newMat = fileFormat[i].LayerMat;
+ CvInvoke.BitwiseAnd(originalMat, newMat, newMat);
+ slicerFile[layerIndex].LayerMat = newMat;
+ break;
+ }
+ case ImportTypes.BitwiseOr:
+ {
+ if (layerIndex >= slicerFile.LayerCount) return;
+ using var originalMat = slicerFile[layerIndex].LayerMat;
+ using var newMat = fileFormat[i].LayerMat;
+ CvInvoke.BitwiseOr(originalMat, newMat, newMat);
+ slicerFile[layerIndex].LayerMat = newMat;
+ break;
+ }
+ case ImportTypes.BitwiseXOr:
+ {
+ if (layerIndex >= slicerFile.LayerCount) return;
+ using var originalMat = slicerFile[layerIndex].LayerMat;
+ using var newMat = fileFormat[i].LayerMat;
+ CvInvoke.BitwiseXor(originalMat, newMat, newMat);
+ slicerFile[layerIndex].LayerMat = newMat;
+ break;
+ }
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
- slicerFile.LayerManager.Layers = layers;
- slicerFile.RequireFullEncode = true;
- progress.Token.ThrowIfCancellationRequested();
+ lock (progress.Mutex)
+ {
+ lastProcessedLayerIndex = Math.Max(lastProcessedLayerIndex, (int)layerIndex);
+ progress++;
+ }
+ });
+
+ fileFormat.Dispose();
+ progress.Token.ThrowIfCancellationRequested();
+ }
+
+ if (_importType == ImportTypes.Stack)
+ {
+ new OperationMove(slicerFile) { LayerIndexEnd = slicerFile.LastLayerIndex }.Execute(slicerFile, progress);
+ }
+
+ if (lastProcessedLayerIndex <= -1) return false;
+
+ if (lastProcessedLayerIndex + 1 < slicerFile.LayerCount && _discardUnmodifiedLayers)
+ {
+ slicerFile.LayerManager.ReallocateRange(0, (uint) lastProcessedLayerIndex);
+ }
+
+ slicerFile.LayerManager.RebuildLayersProperties();
+ slicerFile.SuppressRebuildProperties = false;
+ slicerFile.RequireFullEncode = true;
return true;
}
diff --git a/UVtools.Core/Operations/OperationMove.cs b/UVtools.Core/Operations/OperationMove.cs
index 09f046d..12bcae0 100644
--- a/UVtools.Core/Operations/OperationMove.cs
+++ b/UVtools.Core/Operations/OperationMove.cs
@@ -227,6 +227,14 @@ namespace UVtools.Core.Operations
{
}
+ public OperationMove(FileFormat slicerFile, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter)
+ {
+ ROI = slicerFile.LayerManager.BoundingRectangle;
+ ImageWidth = slicerFile.ResolutionX;
+ ImageHeight = slicerFile.ResolutionY;
+ Anchor = anchor;
+ }
+
public OperationMove(Rectangle srcRoi, uint imageWidth, uint imageHeight, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter)
{
ROI = srcRoi;
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index 73ec8e0..28f66fc 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>2.1.0</Version>
+ <Version>2.1.1</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 4d14ccc..c4b717a 100644
--- a/UVtools.WPF/App.axaml.cs
+++ b/UVtools.WPF/App.axaml.cs
@@ -13,9 +13,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
-using System.Threading;
using Avalonia;
-using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Media.Imaging;
@@ -38,8 +36,6 @@ namespace UVtools.WPF
public static AppVersionChecker VersionChecker { get; } = new AppVersionChecker();
- public static Size MaxWindowSize = Size.Empty;
-
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
@@ -124,15 +120,15 @@ namespace UVtools.WPF
{
try
{
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ if (OperatingSystem.IsWindows())
{
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }).Dispose();
}
- else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ else if (OperatingSystem.IsLinux())
{
Process.Start("xdg-open", url).Dispose();
}
- else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ else if (OperatingSystem.IsMacOS())
{
Process.Start("open", url).Dispose();
}
diff --git a/UVtools.WPF/Assets/Icons/bookmark-16x16.png b/UVtools.WPF/Assets/Icons/bookmark-16x16.png
new file mode 100644
index 0000000..b6e8b3e
--- /dev/null
+++ b/UVtools.WPF/Assets/Icons/bookmark-16x16.png
Binary files differ
diff --git a/UVtools.WPF/Assets/Icons/cookie-16x16.png b/UVtools.WPF/Assets/Icons/cookie-16x16.png
new file mode 100644
index 0000000..2c90a8b
--- /dev/null
+++ b/UVtools.WPF/Assets/Icons/cookie-16x16.png
Binary files differ
diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml b/UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml
new file mode 100644
index 0000000..0b8421f
--- /dev/null
+++ b/UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml
@@ -0,0 +1,35 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ x:Class="UVtools.WPF.Controls.Calibrators.CalibrateExternalTestsControl">
+ <Grid
+ RowDefinitions="Auto,Auto,Auto"
+ ColumnDefinitions="400">
+
+ <Button Grid.Row="0"
+ Padding="5"
+ Content="Photonsters Validation Matrix / Exposure finder"
+ Command="{Binding ButtonClicked}"
+ VerticalAlignment="Center"
+ CommandParameter="https://www.thingiverse.com/thing:4707289"/>
+
+ <Button Grid.Row="1"
+ Margin="0,5,0,0"
+ Padding="5"
+ Content="Support pull test"
+ Command="{Binding ButtonClicked}"
+ VerticalAlignment="Center"
+ CommandParameter="https://www.thingiverse.com/thing:4308175"/>
+
+ <Button Grid.Row="2"
+ Margin="0,5,0,0"
+ Padding="5"
+ Content="AmeraLabs town calibration part"
+ Command="{Binding ButtonClicked}"
+ VerticalAlignment="Center"
+ CommandParameter="https://www.thingiverse.com/thing:2810666"/>
+
+ </Grid>
+</UserControl>
diff --git a/UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml.cs b/UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml.cs
new file mode 100644
index 0000000..c2ed96a
--- /dev/null
+++ b/UVtools.WPF/Controls/Calibrators/CalibrateExternalTestsControl.axaml.cs
@@ -0,0 +1,30 @@
+using System.Diagnostics;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using UVtools.Core.Operations;
+using UVtools.WPF.Controls.Tools;
+
+namespace UVtools.WPF.Controls.Calibrators
+{
+ public class CalibrateExternalTestsControl : ToolControl
+ {
+ public OperationCalibrateExternalTests Operation => BaseOperation as OperationCalibrateExternalTests;
+ public CalibrateExternalTestsControl()
+ {
+ this.InitializeComponent();
+ BaseOperation = new OperationCalibrateExternalTests();
+ Debug.WriteLine("asdasdasdasd");
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public void ButtonClicked(string url)
+ {
+ App.OpenBrowser(url);
+ }
+ }
+}
diff --git a/UVtools.WPF/Controls/Helpers.cs b/UVtools.WPF/Controls/Helpers.cs
index 9530e78..28ec99f 100644
--- a/UVtools.WPF/Controls/Helpers.cs
+++ b/UVtools.WPF/Controls/Helpers.cs
@@ -13,7 +13,7 @@ namespace UVtools.WPF.Controls
{
public static class Helpers
{
- public static readonly List<FileDialogFilter> ImagesFileFilter = new List<FileDialogFilter>
+ public static readonly List<FileDialogFilter> ImagesFileFilter = new()
{
new FileDialogFilter
{
diff --git a/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml b/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml
index ce0164f..fa74937 100644
--- a/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml
+++ b/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml
@@ -6,42 +6,75 @@
x:Class="UVtools.WPF.Controls.Tools.ToolLayerImportControl">
<StackPanel Spacing="10">
- <StackPanel Spacing="10" Orientation="Horizontal">
- <TextBlock
- VerticalAlignment="Center"
- Text="Insert after layer:"/>
- <NumericUpDown
- Width="70"
- Minimum="0"
- Maximum="{Binding MaximumLayer}"
- Value="{Binding Operation.InsertAfterLayerIndex}"
- />
- <TextBlock
- VerticalAlignment="Center"
- Text="{Binding InfoLayerHeightStr}"/>
- </StackPanel>
-
- <StackPanel Spacing="10" Orientation="Horizontal">
- <CheckBox
- IsChecked="{Binding Operation.ReplaceStartLayer}"
- Content="Replace this layer"/>
-
- <CheckBox
- IsChecked="{Binding Operation.ReplaceSubsequentLayers}"
- Content="Replace subsequent layers"/>
-
- <CheckBox
- IsChecked="{Binding Operation.DiscardRemainingLayers}"
- Content="Discard remaining layers"/>
-
- <CheckBox
- IsChecked="{Binding Operation.MergeImages}"
- Content="Merge images"/>
- </StackPanel>
-
+ <Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto"
+ ColumnDefinitions="Auto,10,100,5,Auto,20,Auto">
+
+ <TextBlock Grid.Row="0" Grid.Column="0"
+ VerticalAlignment="Center"
+ ToolTip.Tip="Insert: Insert layers. (Requires images with bounds equal or less than file resolution)
+&#x0a;Replace: Replace layers. (Requires images with bounds equal or less than file resolution)
+&#x0a;Stack: Stack layers content. (Requires images with bounds equal or less than file resolution)
+&#x0a;Merge: Merge/Sum layers content. (Requires images with same resolution)
+&#x0a;Subtract: Subtract layers content. (Requires images with same resolution)
+&#x0a;BitwiseAnd: Perform a 'bitwise and' operation over layer pixels. (Requires images with same resolution)
+&#x0a;BitwiseOr: Perform a 'bitwise or' operation over layer pixels. (Requires images with same resolution)
+&#x0a;BitwiseXOr: Perform a 'bitwise xor' operation over layer pixels. (Requires images with same resolution)"
+ Text="Import type:"/>
+
+ <ComboBox Grid.Row="0" Grid.Column="2"
+ VerticalAlignment="Center"
+ SelectedItem="{Binding Operation.ImportType}"
+ Items="{Binding Operation.ImportTypesItems}"/>
+
+ <TextBlock Grid.Row="0" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="layers"/>
+
+ <CheckBox Grid.Row="0" Grid.Column="6"
+ IsChecked="{Binding Operation.ExtendBeyondLayerCount}"
+ IsVisible="{Binding Operation.IsExtendBeyondLayerCountVisible}"
+ ToolTip.Tip="If enabled, imported images that go beyond last layer are appended. The file will grow in layer count if necessary to fit all imported layers.
+&#x0a;If disabled, all imported images that go beyond last layer are discarded. The file will maintain same layer count."
+ Content="Extend beyond layer count"/>
+
+ <TextBlock Grid.Row="2" Grid.Column="0"
+ VerticalAlignment="Center"
+ Text="Start at layer:"/>
+ <NumericUpDown Grid.Row="2" Grid.Column="2"
+ ClipValueToMinMax="True"
+ Minimum="0"
+ Maximum="{Binding MaximumLayer}"
+ Value="{Binding Operation.StartLayerIndex}"/>
+ <TextBlock Grid.Row="2" Grid.Column="4"
+ VerticalAlignment="Center"
+ Text="{Binding InfoLayerHeightStr}"/>
+
+ <CheckBox Grid.Row="4" Grid.Column="2" Grid.ColumnSpan="5"
+ IsChecked="{Binding Operation.DiscardUnmodifiedLayers}"
+ ToolTip.Tip="If enabled, all unmodified layers forward the last inserted layer are discarded.
+&#x0a;If disabled, the unmodified layers are kept."
+ Content="Discard unmodified layers"/>
+
+ <TextBlock Grid.Row="6" Grid.Column="0"
+ VerticalAlignment="Center"
+ IsVisible="{Binding Operation.IsImportStackType}"
+ Text="Stack margin:"/>
+ <NumericUpDown Grid.Row="6" Grid.Column="2"
+ ClipValueToMinMax="True"
+ IsVisible="{Binding Operation.IsImportStackType}"
+ Minimum="0"
+ Maximum="65535"
+ Value="{Binding Operation.StackMargin}"/>
+ <TextBlock Grid.Row="6" Grid.Column="4"
+ VerticalAlignment="Center"
+ IsVisible="{Binding Operation.IsImportStackType}"
+ Text="px"/>
+ </Grid>
+
+
<CheckBox
IsChecked="{Binding IsAutoSortLayersByFileNameChecked}"
- Content="Auto sort layers by file name"/>
+ Content="Auto sort files by filename"/>
<TextBlock Text="{Binding InfoImportResult}" />
@@ -90,7 +123,7 @@
<TextBlock
VerticalAlignment="Center"
- Text="{Binding Operation.Files.Count, StringFormat=Layers: \{0\}}"/>
+ Text="{Binding Operation.Files.Count, StringFormat=Files: \{0\}}"/>
</StackPanel>
</Grid>
</Border>
diff --git a/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs
index f96b5f9..db58958 100644
--- a/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolLayerImportControl.axaml.cs
@@ -1,4 +1,6 @@
-using System.Collections.Concurrent;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
@@ -7,6 +9,7 @@ using Avalonia.Markup.Xaml;
using Avalonia.Media.Imaging;
using DynamicData;
using MessageBox.Avalonia.Enums;
+using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
using UVtools.Core.Operations;
using UVtools.WPF.Extensions;
@@ -26,7 +29,7 @@ namespace UVtools.WPF.Controls.Tools
public uint MaximumLayer => App.SlicerFile.LastLayerIndex;
- public string InfoLayerHeightStr => $"({App.SlicerFile.GetHeightFromLayer(Operation.InsertAfterLayerIndex)}mm)";
+ public string InfoLayerHeightStr => $"({App.SlicerFile.GetHeightFromLayer(Operation.StartLayerIndex)}mm)";
public bool IsAutoSortLayersByFileNameChecked
{
@@ -39,7 +42,7 @@ namespace UVtools.WPF.Controls.Tools
get
{
if (Operation.Files.Count <= 0) return null;
- uint modelTotalLayers = Operation.CalculateTotalLayers(App.SlicerFile.LayerCount);
+ /*uint modelTotalLayers = (uint) Operation.Files.Count;//Operation.CalculateTotalLayers(App.SlicerFile.LayerCount);
string textFactor = "grow";
if (modelTotalLayers < App.SlicerFile.LayerCount)
{
@@ -48,10 +51,11 @@ namespace UVtools.WPF.Controls.Tools
else if (modelTotalLayers == App.SlicerFile.LayerCount)
{
textFactor = "keep";
- }
- return
- $"{Operation.Files.Count} layers will be imported into model starting from layer {Operation.InsertAfterLayerIndex} {InfoLayerHeightStr}.\n" +
- $"Model will {textFactor} from layers {App.SlicerFile.LayerCount} ({App.SlicerFile.TotalHeight}mm) to {modelTotalLayers} ({App.SlicerFile.GetHeightFromLayer(modelTotalLayers, false)}mm)";
+ }*/
+
+ return
+ $"{Operation.Files.Count} files will be imported into model starting from layer {Operation.StartLayerIndex} {InfoLayerHeightStr}.";
+ //$"Model will {textFactor} from layers {App.SlicerFile.LayerCount} ({App.SlicerFile.TotalHeight}mm) to {modelTotalLayers} ({App.SlicerFile.GetHeightFromLayer(modelTotalLayers, false)}mm)";
}
}
@@ -67,6 +71,11 @@ namespace UVtools.WPF.Controls.Tools
PreviewImage = null;
return;
}
+ if (!_selectedFile.TagString.EndsWith(".png", StringComparison.OrdinalIgnoreCase) &&
+ !_selectedFile.TagString.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) &&
+ !_selectedFile.TagString.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) &&
+ !_selectedFile.TagString.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) &&
+ !_selectedFile.TagString.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)) return;
PreviewImage = new Bitmap(_selectedFile.TagString);
}
}
@@ -118,7 +127,7 @@ namespace UVtools.WPF.Controls.Tools
AvaloniaXamlLoader.Load(this);
}
- public override async Task<bool> ValidateForm()
+ /*public override async Task<bool> ValidateForm()
{
UpdateOperation();
var message = Operation.Validate();
@@ -136,14 +145,14 @@ namespace UVtools.WPF.Controls.Tools
}
return false;
- }
+ }*/
public override void Callback(ToolWindow.Callbacks callback)
{
switch (callback)
{
case ToolWindow.Callbacks.Init:
- ParentWindow.ButtonOkEnabled = false;
+ RefreshGUI();
break;
}
}
@@ -157,10 +166,19 @@ namespace UVtools.WPF.Controls.Tools
public async void AddFiles()
{
+ var filters = Helpers.ToAvaloniaFileFilter(FileFormat.AllFileFiltersAvalonia);
+ var orderedFilters = new List<FileDialogFilter> { filters[UserSettings.Instance.General.DefaultOpenFileExtensionIndex] };
+ for (int i = 0; i < filters.Count; i++)
+ {
+ if (i == UserSettings.Instance.General.DefaultOpenFileExtensionIndex) continue;
+ orderedFilters.Add(filters[i]);
+ }
+
var dialog = new OpenFileDialog
{
AllowMultiple = true,
- Filters = Helpers.ImagesFileFilter
+ Filters = orderedFilters,
+ Directory = UserSettings.Instance.General.DefaultDirectoryOpenFile
};
var files = await dialog.ShowAsync(ParentWindow);
diff --git a/UVtools.WPF/Extensions/WindowExtensions.cs b/UVtools.WPF/Extensions/WindowExtensions.cs
index 8ad4405..22a871f 100644
--- a/UVtools.WPF/Extensions/WindowExtensions.cs
+++ b/UVtools.WPF/Extensions/WindowExtensions.cs
@@ -8,8 +8,10 @@
using System.Threading;
using System.Threading.Tasks;
+using Avalonia;
using Avalonia.Controls;
using Avalonia.Threading;
+using Avalonia.VisualTree;
using MessageBox.Avalonia.DTO;
using MessageBox.Avalonia.Enums;
@@ -31,7 +33,7 @@ namespace UVtools.WPF.Extensions
WindowIcon = new WindowIcon(App.GetAsset("/Assets/Icons/UVtools.ico")),
WindowStartupLocation = location,
CanResize = false,
- MaxWidth = App.MaxWindowSize.Width - UserSettings.Instance.General.WindowsHorizontalMargin,
+ MaxWidth = window.GetScreenWorkingArea().Width - UserSettings.Instance.General.WindowsHorizontalMargin,
ShowInCenter = true
});
@@ -76,6 +78,18 @@ namespace UVtools.WPF.Extensions
window.DataContext = new object();
window.DataContext = old;
}
+
+ public static System.Drawing.Size GetScreenWorkingArea(this Window window)
+ {
+ var screen = window.Screens.ScreenFromVisual(window) ??
+ window.Screens.ScreenFromVisual(App.MainWindow) ??
+ window.Screens.Primary ??
+ window.Screens.All[0];
+
+ return new System.Drawing.Size(
+ UserSettings.Instance.General.WindowsTakeIntoAccountScreenScaling ? (int)(screen.WorkingArea.Width / screen.PixelDensity) : screen.WorkingArea.Width,
+ UserSettings.Instance.General.WindowsTakeIntoAccountScreenScaling ? (int)(screen.WorkingArea.Height / screen.PixelDensity) : screen.WorkingArea.Height);
+ }
}
}
diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs
index 78de0d8..a704012 100644
--- a/UVtools.WPF/MainWindow.axaml.cs
+++ b/UVtools.WPF/MainWindow.axaml.cs
@@ -127,7 +127,7 @@ namespace UVtools.WPF
Tag = new OperationRaftRelief(),
Icon = new Avalonia.Controls.Image
{
- Source = new Bitmap(App.GetAsset("/Assets/Icons/dot-circle-16x16.png"))
+ Source = new Bitmap(App.GetAsset("/Assets/Icons/cookie-16x16.png"))
}
},
new MenuItem
@@ -254,6 +254,14 @@ namespace UVtools.WPF
Source = new Bitmap(App.GetAsset("/Assets/Icons/chart-pie-16x16.png"))
}
},
+ new()
+ {
+ Tag = new OperationCalibrateExternalTests(),
+ Icon = new Avalonia.Controls.Image
+ {
+ Source = new Bitmap(App.GetAsset("/Assets/Icons/bookmark-16x16.png"))
+ }
+ },
};
public static MenuItem[] LayerActionsMenu { get; } =
@@ -448,14 +456,6 @@ namespace UVtools.WPF
//PropertyChanged += OnPropertyChanged;
UpdateTitle();
- UpdateMaxWindowsSize();
-
- if (Settings.General.StartMaximized
- || ClientSize.Width > App.MaxWindowSize.Width
- || ClientSize.Height > App.MaxWindowSize.Height)
- {
- WindowState = WindowState.Maximized;
- }
var clientSizeObs = this.GetObservable(ClientSizeProperty);
clientSizeObs.Subscribe(size => UpdateLayerTrackerHighlightIssues());
@@ -471,24 +471,20 @@ namespace UVtools.WPF
});
}
- public void UpdateMaxWindowsSize()
- {
- /*Console.WriteLine($"Settings is null?: {Settings is null}");
- Console.WriteLine($"Settings.General is null?: {Settings.General is null}");
- Console.WriteLine($"Screens is null?: {Screens is null}");
- Console.WriteLine($"ScreenCount: {Screens.ScreenCount}");
- Console.WriteLine($"Screens.Primary is null?: {Screens.Primary is null}");*/
- var screen = Screens.Primary ?? Screens.All[0];
- App.MaxWindowSize = new System.Drawing.Size(
- Settings.General.WindowsTakeIntoAccountScreenScaling ? (int)(screen.WorkingArea.Width / screen.PixelDensity) : screen.WorkingArea.Width,
- Settings.General.WindowsTakeIntoAccountScreenScaling ? (int)(screen.WorkingArea.Height / screen.PixelDensity) : screen.WorkingArea.Height);
- }
-
protected override void OnOpened(EventArgs e)
{
base.OnOpened(e);
-
-
+
+ var windowSize = this.GetScreenWorkingArea();
+
+ if (Settings.General.StartMaximized
+ || ClientSize.Width > windowSize.Width
+ || ClientSize.Height > windowSize.Height)
+ {
+ WindowState = WindowState.Maximized;
+ }
+
+
AddLog($"{About.Software} start", Program.ProgramStartupTime.Elapsed.TotalSeconds);
if (Settings.General.CheckForUpdatesOnStartup)
@@ -768,7 +764,6 @@ namespace UVtools.WPF
{
SettingsWindow settingsWindow = new SettingsWindow();
await settingsWindow.ShowDialog(this);
- UpdateMaxWindowsSize();
}
public void OpenWebsite()
diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj
index 3c153db..c3ab44a 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>2.1.0</Version>
+ <Version>2.1.1</Version>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -82,6 +82,9 @@
<Compile Update="Controls\AdvancedImageBox.axaml.cs">
<DependentUpon>AdvancedImageBox.axaml</DependentUpon>
</Compile>
+ <Compile Update="Controls\Calibrators\CalibrateExternalTestsControl.axaml.cs">
+ <DependentUpon>CalibrateExternalTestsControl.axaml</DependentUpon>
+ </Compile>
<Compile Update="Controls\Tools\ToolLayerRemoveControl.axaml.cs">
<DependentUpon>ToolLayerRemoveControl.axaml</DependentUpon>
</Compile>
diff --git a/UVtools.WPF/Windows/AboutWindow.axaml.cs b/UVtools.WPF/Windows/AboutWindow.axaml.cs
index 6926d67..b94becd 100644
--- a/UVtools.WPF/Windows/AboutWindow.axaml.cs
+++ b/UVtools.WPF/Windows/AboutWindow.axaml.cs
@@ -20,9 +20,9 @@ namespace UVtools.WPF.Windows
public string FrameworkDescription => RuntimeInformation.FrameworkDescription;
public int ProcessorCount => Environment.ProcessorCount;
public int ScreenCount => Screens.ScreenCount;
- public string ScreenResolution => $"{Screens.Primary.Bounds.Width} x {Screens.Primary.Bounds.Height} @ {Screens.Primary.PixelDensity*100}%";
- public string WorkingArea => $"{Screens.Primary.WorkingArea.Width} x {Screens.Primary.WorkingArea.Height}";
- public string RealWorkingArea => $"{App.MaxWindowSize.Width} x {App.MaxWindowSize.Height}";
+ //public string ScreenResolution => $"{Screens.Primary.Bounds.Width} x {Screens.Primary.Bounds.Height} @ {Screens.Primary.PixelDensity*100}%";
+ //public string WorkingArea => $"{Screens.Primary.WorkingArea.Width} x {Screens.Primary.WorkingArea.Height}";
+ //public string RealWorkingArea => $"{App.MaxWindowSize.Width} x {App.MaxWindowSize.Height}";
public string ScreensDescription
{
@@ -31,8 +31,12 @@ namespace UVtools.WPF.Windows
var result = new StringBuilder();
for (int i = 0; i < Screens.All.Count; i++)
{
+ var onScreen = Screens.ScreenFromVisual(App.MainWindow);
var screen = Screens.All[i];
- result.AppendLine($"{i+1}: {screen.Bounds.Width} x {screen.Bounds.Height} @ {screen.PixelDensity * 100}%");
+ result.AppendLine($"{i+1}: {screen.Bounds.Width} x {screen.Bounds.Height} @ {screen.PixelDensity * 100}%" +
+ (screen.Primary ? " (Primary)" : string.Empty) +
+ (onScreen == screen ? " (On this)" : string.Empty)
+ );
result.AppendLine($" WA: {screen.WorkingArea.Width} x {screen.WorkingArea.Height} UA: {Math.Round(screen.WorkingArea.Width / screen.PixelDensity)} x {Math.Round(screen.WorkingArea.Height / screen.PixelDensity)}");
}
return result.ToString().TrimEnd();
diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml.cs b/UVtools.WPF/Windows/SettingsWindow.axaml.cs
index 3eac5ea..de4a1b5 100644
--- a/UVtools.WPF/Windows/SettingsWindow.axaml.cs
+++ b/UVtools.WPF/Windows/SettingsWindow.axaml.cs
@@ -60,7 +60,7 @@ namespace UVtools.WPF.Windows
s => Convert.ToString(s / 100, CultureInfo.InvariantCulture) + "x").ToArray();
- ScrollViewerMaxHeight = App.MaxWindowSize.Height - Settings.General.WindowsVerticalMargin;
+ ScrollViewerMaxHeight = this.GetScreenWorkingArea().Height - Settings.General.WindowsVerticalMargin;
DataContext = this;
diff --git a/UVtools.WPF/Windows/ToolWindow.axaml.cs b/UVtools.WPF/Windows/ToolWindow.axaml.cs
index fafd25b..8f34b67 100644
--- a/UVtools.WPF/Windows/ToolWindow.axaml.cs
+++ b/UVtools.WPF/Windows/ToolWindow.axaml.cs
@@ -524,7 +524,7 @@ namespace UVtools.WPF.Windows
DispatcherTimer.Run(() =>
{
if (Bounds.Width == 0) return true;
- ScrollViewerMaxHeight = App.MaxWindowSize.Height - Bounds.Height + ToolControl.Bounds.Height - UserSettings.Instance.General.WindowsVerticalMargin;
+ ScrollViewerMaxHeight = this.GetScreenWorkingArea().Height - Bounds.Height + ToolControl.Bounds.Height - UserSettings.Instance.General.WindowsVerticalMargin;
DescriptionMaxWidth = Math.Max(Bounds.Width, ToolControl.Bounds.Width) - 40;
Description = toolControl.BaseOperation.Description;
return false;