diff --git a/UVtools.Core/FileFormats/SL1File.cs b/UVtools.Core/FileFormats/SL1File.cs
index c9a0da7..1e11ef1 100644
--- a/UVtools.Core/FileFormats/SL1File.cs
+++ b/UVtools.Core/FileFormats/SL1File.cs
@@ -336,7 +336,11 @@ namespace UVtools.Core.FileFormats
public override uint LayerCount
{
- set => OutputConfigSettings.NumFast = (ushort) (LayerCount - OutputConfigSettings.NumSlow);
+ set
+ {
+ OutputConfigSettings.NumSlow = 0;
+ OutputConfigSettings.NumFast = (ushort) LayerCount;
+ }
}
public override ushort InitialLayerCount => OutputConfigSettings.NumFade;
diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs
index 414cab8..85c5138 100644
--- a/UVtools.Core/Layer/LayerManager.cs
+++ b/UVtools.Core/Layer/LayerManager.cs
@@ -23,7 +23,6 @@ using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
using UVtools.Core.Operations;
using UVtools.Core.PixelEditor;
-using System.Runtime.InteropServices;
namespace UVtools.Core
{
@@ -1361,6 +1360,67 @@ namespace UVtools.Core
progress.Token.ThrowIfCancellationRequested();
}
+ public void Import(OperationLayerImport operation, OperationProgress progress = null)
+ {
+ if (progress is null) progress = new OperationProgress();
+ progress.Reset("Imported layers", (uint)operation.Count);
+
+ var oldLayers = Layers;
+ uint newLayerCount = operation.CalculateTotalLayers((uint) Layers.Length);
+ uint startIndex = operation.StartLayerIndex;
+ Layers = new Layer[newLayerCount];
+
+ // Keep same layers up to InsertAfterLayerIndex
+ for (uint i = 0; i <= operation.InsertAfterLayerIndex; i++)
+ {
+ Layers[i] = oldLayers[i];
+ }
+
+ // Keep all old layers if not discarding them
+ if (operation.ReplaceSubsequentLayers)
+ {
+ if (!operation.DiscardRemainingLayers)
+ {
+ for (uint i = operation.InsertAfterLayerIndex + 1; i < oldLayers.Length; i++)
+ {
+ Layers[i] = oldLayers[i];
+ }
+ }
+ }
+ else // Push remaining layers to the end of imported layers
+ {
+ uint oldLayerIndex = operation.InsertAfterLayerIndex;
+ for (uint i = operation.EndLayerIndex + 1; i < newLayerCount; i++)
+ {
+ oldLayerIndex++;
+ Layers[i] = oldLayers[oldLayerIndex];
+ }
+ }
+
+
+ Parallel.For(0, operation.Count,
+ //new ParallelOptions{MaxDegreeOfParallelism = 1},
+ i =>
+ {
+ var mat = CvInvoke.Imread(operation.Files[i], ImreadModes.Grayscale);
+ uint layerIndex = (uint) (startIndex + i);
+ this[layerIndex] = new Layer(layerIndex, mat);
+
+ lock (progress.Mutex)
+ {
+ progress++;
+ }
+ });
+
+ SlicerFile.LayerCount = Count;
+ BoundingRectangle = Rectangle.Empty;
+ SlicerFile.RequireFullEncode = true;
+
+ RebuildLayersProperties();
+
+ progress.Token.ThrowIfCancellationRequested();
+ }
+
public void CloneLayer(uint layerIndexStart, uint layerIndexEnd, uint clones = 1, OperationProgress progress = null)
{
@@ -1732,6 +1792,8 @@ namespace UVtools.Core
//pixelHistory.Clear();
}
+
+
///
/// Desmodify all layers
///
diff --git a/UVtools.Core/Operations/Operation.cs b/UVtools.Core/Operations/Operation.cs
new file mode 100644
index 0000000..c61ce64
--- /dev/null
+++ b/UVtools.Core/Operations/Operation.cs
@@ -0,0 +1,19 @@
+/*
+ * GNU AFFERO GENERAL PUBLIC LICENSE
+ * Version 3, 19 November 2007
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * Everyone is permitted to copy and distribute verbatim copies
+ * of this license document, but changing it is not allowed.
+ */
+namespace UVtools.Core.Operations
+{
+ public class Operation
+ {
+ const byte ClassNameLength = 9;
+
+ ///
+ /// Gets the ID name of this operation, this comes from class name with "Operation" removed
+ ///
+ public string Id => GetType().Name.Remove(0, ClassNameLength);
+ }
+}
diff --git a/UVtools.Core/Operations/OperationLayerImport.cs b/UVtools.Core/Operations/OperationLayerImport.cs
index b4dacd0..25563b9 100644
--- a/UVtools.Core/Operations/OperationLayerImport.cs
+++ b/UVtools.Core/Operations/OperationLayerImport.cs
@@ -10,7 +10,7 @@ using Emgu.CV.CvEnum;
namespace UVtools.Core.Operations
{
- public sealed class OperationLayerImport
+ public sealed class OperationLayerImport : Operation
{
public uint InsertAfterLayerIndex { get; set; }
public bool ReplaceStartLayer { get; set; }
@@ -19,6 +19,8 @@ namespace UVtools.Core.Operations
public List Files { get; } = new List();
+ public int Count => Files.Count;
+
public void Sort()
{
Files.Sort((file1, file2) => string.Compare(Path.GetFileNameWithoutExtension(file1), Path.GetFileNameWithoutExtension(file2), StringComparison.Ordinal));
@@ -53,7 +55,9 @@ namespace UVtools.Core.Operations
}
return (uint)(totalLayers + Files.Count - (ReplaceStartLayer ? 1 : 0));
-
}
+
+ public uint StartLayerIndex => InsertAfterLayerIndex + (ReplaceStartLayer ? 0u : 1);
+ public uint EndLayerIndex => (uint) (StartLayerIndex + Count - 1);
}
}
diff --git a/UVtools.GUI/Controls/Tools/CtrlToolLayerImport.cs b/UVtools.GUI/Controls/Tools/CtrlToolLayerImport.cs
index 1662019..f6d6b53 100644
--- a/UVtools.GUI/Controls/Tools/CtrlToolLayerImport.cs
+++ b/UVtools.GUI/Controls/Tools/CtrlToolLayerImport.cs
@@ -26,12 +26,14 @@ namespace UVtools.GUI.Controls.Tools
InitializeComponent();
Text = "Import Layer(s)";
- nmInsertAfterLayer.Maximum = Program.SlicerFile.LayerCount;
+ nmInsertAfterLayer.Maximum = Program.SlicerFile.LayerCount-1;
nmInsertAfterLayer.Value = currentLayer;
nmInsertAfterLayer_ValueChanged(nmInsertAfterLayer, EventArgs.Empty);
}
+ public override string ConfirmationText => $"import {Operation.Count} layer(s)?";
+
public void UpdateOperation()
{
Operation.InsertAfterLayerIndex = (uint)nmInsertAfterLayer.Value;
diff --git a/UVtools.GUI/Forms/FrmToolWindow.cs b/UVtools.GUI/Forms/FrmToolWindow.cs
index 8be891e..863df42 100644
--- a/UVtools.GUI/Forms/FrmToolWindow.cs
+++ b/UVtools.GUI/Forms/FrmToolWindow.cs
@@ -308,6 +308,22 @@ namespace UVtools.GUI.Forms
public DialogResult MessageErrorBox(string message) => GUIExtensions.MessageErrorBox($"{Text} Error", message);
public DialogResult MessageQuestionBox(string message, string title = null) => GUIExtensions.MessageQuestionBox($"{title ?? Text}", message);
+ public T GetContentCtrl()
+ {
+ if (Content is T content)
+ {
+ return content;
+ }
+ try
+ {
+ return (T)Convert.ChangeType(Content, typeof(T));
+ }
+ catch (InvalidCastException)
+ {
+ return default(T);
+ }
+ }
+
#endregion
}
diff --git a/UVtools.GUI/FrmMain.cs b/UVtools.GUI/FrmMain.cs
index a5a6fa6..f025413 100644
--- a/UVtools.GUI/FrmMain.cs
+++ b/UVtools.GUI/FrmMain.cs
@@ -1162,7 +1162,47 @@ namespace UVtools.GUI
{
using (var frm = new FrmToolWindow(new CtrlToolLayerImport(ActualLayer)))
{
- frm.ShowDialog();
+ if(frm.ShowDialog() != DialogResult.OK) return;
+
+ var control = frm.GetContentCtrl();
+ var operation = control.Operation;
+
+ DisableGUI();
+ FrmLoading.SetDescription($"Importing {operation.Count} layer(s)");
+
+ var task = Task.Factory.StartNew(() =>
+ {
+ try
+ {
+ SlicerFile.LayerManager.Import(operation, FrmLoading.RestartProgress());
+ }
+ catch (OperationCanceledException)
+ {
+
+ }
+ catch (Exception ex)
+ {
+ GUIExtensions.MessageErrorBox("Error", ex.Message);
+ }
+ finally
+ {
+ Invoke((MethodInvoker)delegate
+ {
+ // Running on the UI thread
+ EnableGUI(true);
+ });
+ }
+ });
+
+ var loadingResult = FrmLoading.ShowDialog();
+
+ UpdateLayerLimits();
+ RefreshInfo();
+ ShowLayer();
+
+ menuFileSave.Enabled =
+ menuFileSaveAs.Enabled = true;
+
}
return;