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;