diff options
author | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-02-19 07:21:53 +0300 |
---|---|---|
committer | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-02-19 07:21:53 +0300 |
commit | 9dffbd77b957c95c475ea35ad20d4410fa0f2378 (patch) | |
tree | ebc481a9b7c0e128f259bd2dad682723ce649e47 | |
parent | 9c9540646c2ed8e3eac17cfddfc05aba209084a6 (diff) |
v2.4.9v2.4.9
* **(Fix) PhotonWorkshop files: (#149)**
* CurrencySymbol to show the correct symbol and don't convert unknown values to prevent hacking
* Set PerLayerOverride to 1 only if any layer contains modified parameters that are not shared with the globals
* **(Fix) Clipboard:**
* Initing the clipboard for the first time was calling Undo and reseting parameters from layers with base settings
* Undo and redo make layer parameters to reset and recalculate position z, making invalid files when using with advanced tools
* (Fix) Tool - Edit print parameters: When editing per a layer range and reopen the tool it will show the previous set values
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | CHANGELOG.md | 10 | ||||
-rw-r--r-- | UVtools.Core/FileFormats/FileFormat.cs | 45 | ||||
-rw-r--r-- | UVtools.Core/FileFormats/IFileFormat.cs | 510 | ||||
-rw-r--r-- | UVtools.Core/FileFormats/PhotonWorkshopFile.cs | 136 | ||||
-rw-r--r-- | UVtools.Core/Layer/Layer.cs | 37 | ||||
-rw-r--r-- | UVtools.Core/Layer/LayerManager.cs | 23 | ||||
-rw-r--r-- | UVtools.Core/Managers/ClipboardManager.cs | 2 | ||||
-rw-r--r-- | UVtools.Core/Objects/Material.cs | 220 | ||||
-rw-r--r-- | UVtools.Core/Operations/OperationEditParameters.cs | 4 | ||||
-rw-r--r-- | UVtools.Core/UVtools.Core.csproj | 2 | ||||
-rw-r--r-- | UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml | 2 | ||||
-rw-r--r-- | UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs | 15 | ||||
-rw-r--r-- | UVtools.WPF/Structures/OperationProfiles.cs | 2 | ||||
-rw-r--r-- | UVtools.WPF/UVtools.WPF.csproj | 2 |
15 files changed, 958 insertions, 54 deletions
@@ -353,3 +353,5 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ +UVtools.Platforms/linux-x64/libcvextern.so +UVtools.Platforms/rhel-x64/libcvextern.so diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a6b0ae..f9999cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 19/02/2021 - v2.4.9 + +* **(Fix) PhotonWorkshop files: (#149)** + * CurrencySymbol to show the correct symbol and don't convert unknown values to prevent hacking + * Set PerLayerOverride to 1 only if any layer contains modified parameters that are not shared with the globals +* **(Fix) Clipboard:** + * Initing the clipboard for the first time was calling Undo and reseting parameters from layers with base settings + * Undo and redo make layer parameters to reset and recalculate position z, making invalid files when using with advanced tools +* (Fix) Tool - Edit print parameters: When editing per a layer range and reopen the tool it will show the previous set values + ## 18/02/2021 - v2.4.8 * (Improvement) Cache per layer and global used material for faster calculations diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs index 4e8d3f8..66ff0f4 100644 --- a/UVtools.Core/FileFormats/FileFormat.cs +++ b/UVtools.Core/FileFormats/FileFormat.cs @@ -469,12 +469,10 @@ namespace UVtools.Core.FileFormats if (oldLayerManager.Count != LayerCount) { LayerCount = _layerManager.Count; + if (SuppressRebuildProperties) return; + if (LayerCount == 0 || this[LayerCount - 1] is null) return; // Not initialized + LayerManager.RebuildLayersProperties(); } - - if (SuppressRebuildProperties) return; - if (LayerCount == 0 || this[LayerCount - 1] is null) return; // Not initialized - LayerManager.RebuildLayersProperties(); - RebuildGCode(); } } @@ -939,7 +937,6 @@ namespace UVtools.Core.FileFormats ) { LayerManager.RebuildLayersProperties(false, e.PropertyName); - RebuildGCode(); if(e.PropertyName != nameof(BottomLightPWM) && e.PropertyName != nameof(LightPWM)) PrintTime = PrintTimeComputed; return; @@ -1398,62 +1395,62 @@ namespace UVtools.Core.FileFormats if (PrintParameterModifiers is null) return; if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomLayerCount)) { - PrintParameterModifier.BottomLayerCount.OldValue = BottomLayerCount; + PrintParameterModifier.BottomLayerCount.Value = BottomLayerCount; } if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomExposureSeconds)) { - PrintParameterModifier.BottomExposureSeconds.OldValue = (decimal) BottomExposureTime; + PrintParameterModifier.BottomExposureSeconds.Value = (decimal) BottomExposureTime; } if (PrintParameterModifiers.Contains(PrintParameterModifier.ExposureSeconds)) { - PrintParameterModifier.ExposureSeconds.OldValue = (decimal)ExposureTime; + PrintParameterModifier.ExposureSeconds.Value = (decimal)ExposureTime; } if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomLightOffDelay)) { - PrintParameterModifier.BottomLightOffDelay.OldValue = (decimal)BottomLightOffDelay; + PrintParameterModifier.BottomLightOffDelay.Value = (decimal)BottomLightOffDelay; } if (PrintParameterModifiers.Contains(PrintParameterModifier.LightOffDelay)) { - PrintParameterModifier.LightOffDelay.OldValue = (decimal)LightOffDelay; + PrintParameterModifier.LightOffDelay.Value = (decimal)LightOffDelay; } if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomLiftHeight)) { - PrintParameterModifier.BottomLiftHeight.OldValue = (decimal)BottomLiftHeight; + PrintParameterModifier.BottomLiftHeight.Value = (decimal)BottomLiftHeight; } if (PrintParameterModifiers.Contains(PrintParameterModifier.LiftHeight)) { - PrintParameterModifier.LiftHeight.OldValue = (decimal)LiftHeight; + PrintParameterModifier.LiftHeight.Value = (decimal)LiftHeight; } if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomLiftSpeed)) { - PrintParameterModifier.BottomLiftSpeed.OldValue = (decimal)BottomLiftSpeed; + PrintParameterModifier.BottomLiftSpeed.Value = (decimal)BottomLiftSpeed; } if (PrintParameterModifiers.Contains(PrintParameterModifier.LiftSpeed)) { - PrintParameterModifier.LiftSpeed.OldValue = (decimal)LiftSpeed; + PrintParameterModifier.LiftSpeed.Value = (decimal)LiftSpeed; } if (PrintParameterModifiers.Contains(PrintParameterModifier.RetractSpeed)) { - PrintParameterModifier.RetractSpeed.OldValue = (decimal)RetractSpeed; + PrintParameterModifier.RetractSpeed.Value = (decimal)RetractSpeed; } if (PrintParameterModifiers.Contains(PrintParameterModifier.BottomLightPWM)) { - PrintParameterModifier.BottomLightPWM.OldValue = BottomLightPWM; + PrintParameterModifier.BottomLightPWM.Value = BottomLightPWM; } if (PrintParameterModifiers.Contains(PrintParameterModifier.LightPWM)) { - PrintParameterModifier.LightPWM.OldValue = LightPWM; + PrintParameterModifier.LightPWM.Value = LightPWM; } } @@ -1467,32 +1464,32 @@ namespace UVtools.Core.FileFormats if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.ExposureSeconds)) { - PrintParameterModifier.ExposureSeconds.OldValue = (decimal)layer.ExposureTime; + PrintParameterModifier.ExposureSeconds.Value = (decimal)layer.ExposureTime; } if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.LightOffDelay)) { - PrintParameterModifier.LightOffDelay.OldValue = (decimal)layer.LightOffDelay; + PrintParameterModifier.LightOffDelay.Value = (decimal)layer.LightOffDelay; } if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.LiftHeight)) { - PrintParameterModifier.LiftHeight.OldValue = (decimal)layer.LiftHeight; + PrintParameterModifier.LiftHeight.Value = (decimal)layer.LiftHeight; } if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.LiftSpeed)) { - PrintParameterModifier.LiftSpeed.OldValue = (decimal)layer.LiftSpeed; + PrintParameterModifier.LiftSpeed.Value = (decimal)layer.LiftSpeed; } if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.RetractSpeed)) { - PrintParameterModifier.RetractSpeed.OldValue = (decimal)layer.RetractSpeed; + PrintParameterModifier.RetractSpeed.Value = (decimal)layer.RetractSpeed; } if (PrintParameterPerLayerModifiers.Contains(PrintParameterModifier.LightPWM)) { - PrintParameterModifier.LightPWM.OldValue = layer.LightPWM; + PrintParameterModifier.LightPWM.Value = layer.LightPWM; } } diff --git a/UVtools.Core/FileFormats/IFileFormat.cs b/UVtools.Core/FileFormats/IFileFormat.cs new file mode 100644 index 0000000..e96bb0a --- /dev/null +++ b/UVtools.Core/FileFormats/IFileFormat.cs @@ -0,0 +1,510 @@ +/* + * 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. + */ + +using System; +using System.Drawing; +using System.Text; +using Emgu.CV; +using UVtools.Core.Operations; + +namespace UVtools.Core.FileFormats +{ + /// <summary> + /// Slicer file format representation interface + /// </summary> + public interface IFileFormat + { + #region Properties + /// <summary> + /// Gets the file format type + /// </summary> + FileFormat.FileFormatType FileType { get; } + + /// <summary> + /// Gets the valid file extensions for this <see cref="FileFormat"/> + /// </summary> + FileExtension[] FileExtensions { get; } + + /// <summary> + /// Gets the available <see cref="FileFormat.PrintParameterModifier"/> + /// </summary> + FileFormat.PrintParameterModifier[] PrintParameterModifiers { get; } + + /// <summary> + /// Gets the available <see cref="FileFormat.PrintParameterModifier"/> per layer + /// </summary> + FileFormat.PrintParameterModifier[] PrintParameterPerLayerModifiers { get; } + + /// <summary> + /// Gets the file filter for open and save dialogs + /// </summary> + string FileFilter { get; } + + /// <summary> + /// Gets all valid file extensions in "*.extension1;*.extension2" format + /// </summary> + + string FileFilterExtensionsOnly { get; } + + /// <summary> + /// Gets or sets if change a global property should rebuild every layer data based on them + /// </summary> + bool SuppressRebuildProperties { get; set; } + + /// <summary> + /// Gets the input file path loaded into this <see cref="FileFormat"/> + /// </summary> + string FileFullPath { get; set; } + + /// <summary> + /// Gets the thumbnails count present in this file format + /// </summary> + byte ThumbnailsCount { get; } + + /// <summary> + /// Gets the number of created thumbnails + /// </summary> + byte CreatedThumbnailsCount { get; } + + /// <summary> + /// Gets the original thumbnail sizes + /// </summary> + System.Drawing.Size[] ThumbnailsOriginalSize { get; } + + /// <summary> + /// Gets the thumbnails for this <see cref="FileFormat"/> + /// </summary> + Mat[] Thumbnails { get; set; } + + /// <summary> + /// Gets the cached layers into compressed bytes + /// </summary> + LayerManager LayerManager { get; set; } + + Size Resolution { get; set; } + + /// <summary> + /// Gets the image width resolution + /// </summary> + uint ResolutionX { get; set; } + + /// <summary> + /// Gets the image height resolution + /// </summary> + uint ResolutionY { get; set; } + + /// <summary> + /// Gets the size of display in millimeters + /// </summary> + SizeF Display { get; set; } + + /// <summary> + /// Gets or sets the display width in millimeters + /// </summary> + float DisplayWidth { get; set; } + + /// <summary> + /// Gets or sets the display height in millimeters + /// </summary> + float DisplayHeight { get; set; } + + /// <summary> + /// Gets or sets if images need to be mirrored on lcd to print on the correct orientation + /// </summary> + bool MirrorDisplay { get; set; } + + /// <summary> + /// Gets or sets the maximum printer build Z volume + /// </summary> + float MaxPrintHeight { get; set; } + + /// <summary> + /// Gets or sets the pixels per mm on X direction + /// </summary> + float Xppmm { get; set; } + + /// <summary> + /// Gets or sets the pixels per mm on Y direction + /// </summary> + float Yppmm { get; set; } + + /// <summary> + /// Gets or sets the pixels per mm + /// </summary> + SizeF Ppmm { get; set; } + + /// <summary> + /// Gets the printer XY pixel resolution + /// </summary> + decimal XYResolution { get; } + + /// <summary> + /// Gets the printer XY pixel resolution in microns + /// </summary> + decimal XYResolutionUm { get; } + + bool HaveAntiAliasing { get; } + + /// <summary> + /// Gets or sets the AntiAliasing level + /// </summary> + byte AntiAliasing { get; set; } + + /// <summary> + /// Gets Layer Height in mm + /// </summary> + float LayerHeight { get; set; } + + /// <summary> + /// Gets or sets the print height in mm + /// </summary> + float PrintHeight { get; set; } + + /// <summary> + /// Gets the last layer index + /// </summary> + uint LastLayerIndex { get; } + + #region Universal Properties + + /// <summary> + /// Gets if this format support per layer override settings + /// </summary> + bool SupportPerLayerSettings { get; } + + /// <summary> + /// Gets the number of layers present in this file + /// </summary> + uint LayerCount { get; set; } + + /// <summary> + /// Gets or sets the number of initial layer count + /// </summary> + ushort BottomLayerCount { get; set; } + + /// <summary> + /// Gets the number of normal layer count + /// </summary> + uint NormalLayerCount { get; } + + /// <summary> + /// Gets or sets the initial exposure time for <see cref="BottomLayerCount"/> in seconds + /// </summary> + float BottomExposureTime { get; set; } + + /// <summary> + /// Gets or sets the normal layer exposure time in seconds + /// </summary> + float ExposureTime { get; set; } + + /// <summary> + /// Gets or sets the bottom layer off time in seconds + /// </summary> + float BottomLightOffDelay { get; set; } + + /// <summary> + /// Gets or sets the layer off time in seconds + /// </summary> + float LightOffDelay { get; set; } + + /// <summary> + /// Gets or sets the bottom lift height in mm + /// </summary> + float BottomLiftHeight { get; set; } + + /// <summary> + /// Gets or sets the lift height in mm + /// </summary> + float LiftHeight { get; set; } + + /// <summary> + /// Gets or sets the bottom lift speed in mm/min + /// </summary> + float BottomLiftSpeed { get; set; } + + /// <summary> + /// Gets or sets the speed in mm/min + /// </summary> + float LiftSpeed { get; set; } + + /// <summary> + /// Gets the speed in mm/min for the retracts + /// </summary> + float RetractSpeed { get; set; } + + /// <summary> + /// Gets or sets the bottom pwm value from 0 to 255 + /// </summary> + byte BottomLightPWM { get; set; } + + /// <summary> + /// Gets or sets the pwm value from 0 to 255 + /// </summary> + byte LightPWM { get; set; } + #endregion + + /// <summary> + /// Gets the estimate print time in seconds + /// </summary> + float PrintTime { get; set; } + + /// <summary> + /// Gets the estimate print time in seconds, if print doesn't support it it will be calculated + /// </summary> + float PrintTimeOrComputed { get; } + + /// <summary> + /// Gets the calculated estimate print time in seconds + /// </summary> + float PrintTimeComputed { get; } + + /// <summary> + /// Gets the estimate print time in hours + /// </summary> + float PrintTimeHours { get; } + + /// <summary> + /// Gets the estimate print time in hours and minutes formatted + /// </summary> + string PrintTimeString { get; } + + /// <summary> + /// Gets the estimate used material in ml + /// </summary> + float MaterialMilliliters { get; set; } + + /// <summary> + /// Gets the estimate material in grams + /// </summary> + float MaterialGrams { get; set; } + + /// <summary> + /// Gets the estimate material cost + /// </summary> + float MaterialCost { get; set; } + + /// <summary> + /// Gets the material name + /// </summary> + string MaterialName { get; set; } + + /// <summary> + /// Gets the machine name + /// </summary> + string MachineName { get; set; } + + /// <summary> + /// Gets the GCode, returns null if not supported + /// </summary> + StringBuilder GCode { get; set; } + string GCodeStr { get; } + + /// <summary> + /// Gets if this file have available gcode + /// </summary> + bool HaveGCode { get; } + + /// <summary> + /// Get all configuration objects with properties and values + /// </summary> + object[] Configs { get; } + + /// <summary> + /// Gets if this file is valid to read + /// </summary> + bool IsValid { get; } + + #endregion + + #region Methods + /// <summary> + /// Clears all definitions and properties, it also dispose valid candidates + /// </summary> + void Clear(); + + /// <summary> + /// Validate if a file is a valid <see cref="FileFormat"/> + /// </summary> + /// <param name="fileFullPath">Full file path</param> + void FileValidation(string fileFullPath); + + /// <summary> + /// Checks if a extension is valid under the <see cref="FileFormat"/> + /// </summary> + /// <param name="extension">Extension to check</param> + /// <param name="isFilePath">True if <see cref="extension"/> is a full file path, otherwise false for extension only</param> + /// <returns>True if valid, otherwise false</returns> + bool IsExtensionValid(string extension, bool isFilePath = false); + + /// <summary> + /// Gets all valid file extensions in a specified format + /// </summary> + + string GetFileExtensions(string prepend = ".", string separator = ", "); + + /// <summary> + /// Gets a thumbnail by it height or lower + /// </summary> + /// <param name="maxHeight">Max height allowed</param> + /// <returns></returns> + Mat GetThumbnail(uint maxHeight = 400); + + /// <summary> + /// Gets a thumbnail by the largest or smallest + /// </summary> + /// <param name="largest">True to get the largest, otherwise false</param> + /// <returns></returns> + Mat GetThumbnail(bool largest); + + /// <summary> + /// Sets thumbnails from a list of thumbnails and clone them + /// </summary> + /// <param name="images"></param> + void SetThumbnails(Mat[] images); + + /// <summary> + /// Sets all thumbnails the same image + /// </summary> + /// <param name="images">Image to set</param> + void SetThumbnails(Mat images); + + /// <summary> + /// Sets a thumbnail from a disk file + /// </summary> + /// <param name="index">Thumbnail index</param> + /// <param name="filePath"></param> + void SetThumbnail(int index, string filePath); + + /// <summary> + /// Encode to an output file + /// </summary> + /// <param name="fileFullPath">Output file</param> + /// <param name="progress"></param> + void Encode(string fileFullPath, OperationProgress progress = null); + void AfterEncode(); + + /* + /// <summary> + /// Begin encode to an output file + /// </summary> + /// <param name="fileFullPath">Output file</param> + //void BeginEncode(string fileFullPath); + + /// <summary> + /// Insert a layer image to be encoded + /// </summary> + /// <param name="image"></param> + /// <param name="layerIndex"></param> + //void InsertLayerImageEncode(Image<L8> image, uint layerIndex); + + /// <summary> + /// Finish the encoding procedure + /// </summary> + //void EndEncode();*/ + + /// <summary> + /// Decode a slicer file + /// </summary> + /// <param name="fileFullPath"></param> + /// <param name="progress"></param> + void Decode(string fileFullPath, OperationProgress progress = null); + + /// <summary> + /// Extract contents to a folder + /// </summary> + /// <param name="path">Path to folder where content will be extracted</param> + /// <param name="genericConfigExtract"></param> + /// <param name="genericLayersExtract"></param> + /// <param name="progress"></param> + void Extract(string path, bool genericConfigExtract = true, bool genericLayersExtract = true, + OperationProgress progress = null); + + /// <summary> + /// Get height in mm from layer height + /// </summary> + /// <param name="layerIndex"></param> + /// <param name="realHeight"></param> + /// <returns>The height in mm</returns> + float GetHeightFromLayer(uint layerIndex, bool realHeight = true); + + /// <summary> + /// Gets the value for initial layer or normal layers based on layer index + /// </summary> + /// <typeparam name="T">Type of value</typeparam> + /// <param name="layerIndex">Layer index</param> + /// <param name="initialLayerValue">Initial value</param> + /// <param name="normalLayerValue">Normal value</param> + /// <returns></returns> + T GetInitialLayerValueOrNormal<T>(uint layerIndex, T initialLayerValue, T normalLayerValue); + + void RefreshPrintParametersModifiersValues(); + void RefreshPrintParametersPerLayerModifiersValues(uint layerIndex); + + /// <summary> + /// Gets the value attributed to <see cref="FileFormat.PrintParameterModifier"/> + /// </summary> + /// <param name="modifier">Modifier to use</param> + /// <returns>A value</returns> + object GetValueFromPrintParameterModifier(FileFormat.PrintParameterModifier modifier); + + /// <summary> + /// Sets a property value attributed to <see cref="modifier"/> + /// </summary> + /// <param name="modifier">Modifier to use</param> + /// <param name="value">Value to set</param> + /// <returns>True if set, otherwise false = <see cref="modifier"/> not found</returns> + bool SetValueFromPrintParameterModifier(FileFormat.PrintParameterModifier modifier, decimal value); + + byte SetValuesFromPrintParametersModifiers(); + + void EditPrintParameters(OperationEditParameters operation); + + /// <summary> + /// Rebuilds GCode based on current settings + /// </summary> + void RebuildGCode(); + + /// <summary> + /// Saves current configuration on input file + /// </summary> + /// <param name="progress"></param> + void Save(OperationProgress progress = null); + + /// <summary> + /// Saves current configuration on a copy + /// </summary> + /// <param name="filePath">File path to save copy as, use null to overwrite active file (Same as <see cref="Save"/>)</param> + /// <param name="progress"></param> + void SaveAs(string filePath = null, OperationProgress progress = null); + + /// <summary> + /// Converts this file type to another file type + /// </summary> + /// <param name="to">Target file format</param> + /// <param name="fileFullPath">Output path file</param> + /// <param name="progress"></param> + /// <returns>The converted file if successful, otherwise null</returns> + FileFormat Convert(Type to, string fileFullPath, OperationProgress progress = null); + + /// <summary> + /// Converts this file type to another file type + /// </summary> + /// <param name="to">Target file format</param> + /// <param name="fileFullPath">Output path file</param> + /// <param name="progress"></param> + /// <returns>TThe converted file if successful, otherwise null</returns> + FileFormat Convert(FileFormat to, string fileFullPath, OperationProgress progress = null); + + /// <summary> + /// Validate AntiAlias Level + /// </summary> + byte ValidateAntiAliasingLevel(); + + #endregion + } +} diff --git a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs index 1bada24..7f5efd2 100644 --- a/UVtools.Core/FileFormats/PhotonWorkshopFile.cs +++ b/UVtools.Core/FileFormats/PhotonWorkshopFile.cs @@ -93,6 +93,7 @@ namespace UVtools.Core.FileFormats /// <summary> /// Gets the file mark placeholder /// Fixed to "ANYCUBIC" + /// 00 /// </summary> [FieldOrder(0)] [FieldLength(MarkSize)] @@ -101,37 +102,52 @@ namespace UVtools.Core.FileFormats /// <summary> /// Gets the file format version + /// 0C /// </summary> [FieldOrder(1)] public uint Version { get; set; } = 1; /// <summary> /// Gets the area num + /// 10 /// </summary> [FieldOrder(2)] public uint AreaNum { get; set; } = 4; /// <summary> /// Gets the header start address + /// 14 /// </summary> [FieldOrder(3)] public uint HeaderAddress { get; set; } + /// <summary> + /// 18 + /// </summary> [FieldOrder(4)] public uint Offset1 { get; set; } /// <summary> /// Gets the preview start offset + /// 1C /// </summary> [FieldOrder(5)] public uint PreviewAddress { get; set; } + /// <summary> + /// 20 + /// </summary> [FieldOrder(6)] public uint Offset2 { get; set; } /// <summary> /// Gets the layer definition start address + /// 24 /// </summary> [FieldOrder(7)] public uint LayerDefinitionAddress { get; set; } + /// <summary> + /// 28 + /// </summary> [FieldOrder(8)] public uint Offset3 { get; set; } /// <summary> /// Gets layer image start address + /// 2C /// </summary> [FieldOrder(9)] public uint LayerImageAddress { get; set; } @@ -207,34 +223,129 @@ namespace UVtools.Core.FileFormats { public const string SectionMark = "HEADER"; + /// <summary> + /// 30 + /// </summary> [FieldOrder(0)] public SectionHeader Section { get; set; } + + /// <summary> + /// 40 + /// </summary> [FieldOrder(1)] public float PixelSizeUm { get; set; } = 47.25f; + + /// <summary> + /// Layer height in mm + /// 44 + /// </summary> [FieldOrder(2)] public float LayerHeight { get; set; } + + /// <summary> + /// 48 + /// </summary> [FieldOrder(3)] public float LayerExposureTime { get; set; } + + /// <summary> + /// 4C + /// </summary> [FieldOrder(4)] public float LightOffDelay { get; set; } = 1; + + /// <summary> + /// 50 + /// </summary> [FieldOrder(5)] public float BottomExposureSeconds { get; set; } + + /// <summary> + /// 54 + /// </summary> [FieldOrder(6)] public float BottomLayersCount { get; set; } + + /// <summary> + /// 58 + /// </summary> [FieldOrder(7)] public float LiftHeight { get; set; } = 6; /// <summary> /// Gets the lift speed in mm/s + /// 5C /// </summary> [FieldOrder(8)] public float LiftSpeed { get; set; } = 3; // mm/s /// <summary> /// Gets the retract speed in mm/s + /// 60 /// </summary> [FieldOrder(9)] public float RetractSpeed { get; set; } = 3; // mm/s + + /// <summary> + /// 64 + /// </summary> [FieldOrder(10)] public float VolumeMl { get; set; } + + /// <summary> + /// 68 + /// </summary> [FieldOrder(11)] public uint AntiAliasing { get; set; } = 1; + + /// <summary> + /// 6C + /// </summary> [FieldOrder(12)] public uint ResolutionX { get; set; } + + /// <summary> + /// 70 + /// </summary> [FieldOrder(13)] public uint ResolutionY { get; set; } + + /// <summary> + /// 74 + /// </summary> [FieldOrder(14)] public float WeightG { get; set; } + + /// <summary> + /// 78 + /// </summary> [FieldOrder(15)] public float Price { get; set; } - [FieldOrder(16)] public uint PriceCurrencyDec { get; set; } // 0x24 $ or ¥ 0xC2A5 - [Ignore] public string PriceCurrencySymbol => char.ConvertFromUtf32((int) PriceCurrencyDec); - [FieldOrder(17)] public uint PerLayerOverride { get; set; } = 1; // bool + + /// <summary> + /// 24 00 00 00 $ or ¥ C2 A5 00 or € = E2 82 AC 00 + /// 7C + /// </summary> + [FieldOrder(16)] public uint PriceCurrencyDec { get; set; } = 0x24; + [Ignore] public char PriceCurrencySymbol + { + get + { + switch (PriceCurrencyDec) + { + case 0x24: + return '$'; + case 0xA5C2: + return '¥'; + case 0x000020AC: + return '€'; + default: + return '$'; + } + } + } + + /// <summary> + /// 80 + /// </summary> + [FieldOrder(17)] public uint PerLayerOverride { get; set; } // bool + + /// <summary> + /// 84 + /// </summary> [FieldOrder(18)] public uint PrintTime { get; set; } + + /// <summary> + /// 88 + /// </summary> [FieldOrder(19)] public uint Offset1 { get; set; } + + /// <summary> + /// 8C + /// </summary> [FieldOrder(20)] public uint Offset2 { get; set; } public Header() @@ -262,20 +373,26 @@ namespace UVtools.Core.FileFormats { public const string SectionMark = "PREVIEW"; + /// <summary> + /// 90 + /// </summary> [FieldOrder(0)] public SectionHeader Section { get; set; } /// <summary> - /// Gets the image width, in pixels. + /// Gets the image width, in pixels. + /// A0 /// </summary> [FieldOrder(1)] public uint Width { get; set; } = 224; /// <summary> - /// Gets the resolution of the image, in dpi. + /// Gets the resolution of the image, in dpi. + /// A4 /// </summary> [FieldOrder(2)] public uint Resolution { get; set; } = 42; /// <summary> - /// Gets the image height, in pixels. + /// Gets the image height, in pixels. + /// A8 /// </summary> [FieldOrder(3)] public uint Height { get; set; } = 168; @@ -732,6 +849,9 @@ namespace UVtools.Core.FileFormats { public const string SectionMark = "LAYERDEF"; + /// <summary> + /// 1269C + /// </summary> [FieldOrder(0)] public SectionHeader Section { get; set; } [FieldOrder(1)] public uint LayerCount { get; set; } @@ -1198,7 +1318,7 @@ namespace UVtools.Core.FileFormats break; } - HeaderSettings.PerLayerOverride = 1; + HeaderSettings.PerLayerOverride = LayerManager.AllLayersHaveGlobalParameters ? 0 : 1; uint currentOffset = FileMarkSettings.HeaderAddress = (uint) Helpers.Serializer.SizeOf(FileMarkSettings); @@ -1402,7 +1522,7 @@ namespace UVtools.Core.FileFormats FileFullPath = filePath; } - HeaderSettings.PerLayerOverride = 1; + HeaderSettings.PerLayerOverride = LayerManager.AllLayersHaveGlobalParameters ? 0 : 1; using var outputFile = new FileStream(FileFullPath, FileMode.Open, FileAccess.Write); outputFile.Seek(FileMarkSettings.HeaderAddress, SeekOrigin.Begin); diff --git a/UVtools.Core/Layer/Layer.cs b/UVtools.Core/Layer/Layer.cs index 5640096..9ea9b9b 100644 --- a/UVtools.Core/Layer/Layer.cs +++ b/UVtools.Core/Layer/Layer.cs @@ -315,7 +315,7 @@ namespace UVtools.Core public string Filename => FormatFileName("layer"); /// <summary> - /// Gets if layer has been modified + /// Gets if layer image has been modified /// </summary> public bool IsModified { @@ -323,6 +323,39 @@ namespace UVtools.Core set => RaiseAndSetIfChanged(ref _isModified, value); } + /// <summary> + /// Gets if this layer have same value parameters as global settings + /// </summary> + public bool HaveGlobalParameters + { + get + { + if (SlicerFile is null) return false; // Cant verify + if (IsBottomLayer) + { + if (ExposureTime != SlicerFile.BottomExposureTime || + LiftHeight != SlicerFile.BottomLiftHeight || + LiftSpeed != SlicerFile.BottomLiftSpeed || + LightOffDelay != SlicerFile.BottomLightOffDelay || + LightPWM != SlicerFile.BottomLightPWM + ) return false; + } + else + { + if (ExposureTime != SlicerFile.ExposureTime || + LiftHeight != SlicerFile.LiftHeight || + LiftSpeed != SlicerFile.LiftSpeed || + LightOffDelay != SlicerFile.LightOffDelay || + LightPWM != SlicerFile.LightPWM + ) return false; + } + + if (RetractSpeed != SlicerFile.RetractSpeed) return false; + + return true; + } + } + #endregion #region Constructor @@ -444,7 +477,7 @@ namespace UVtools.Core public override string ToString() { - return $"{nameof(Index)}: {Index}, {nameof(Filename)}: {Filename}, {nameof(NonZeroPixelCount)}: {NonZeroPixelCount}, {nameof(BoundingRectangle)}: {BoundingRectangle}, {nameof(IsBottomLayer)}: {IsBottomLayer}, {nameof(IsNormalLayer)}: {IsNormalLayer}, {nameof(LayerHeight)}: {LayerHeight}, {nameof(PositionZ)}: {PositionZ}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(RetractSpeed)}: {RetractSpeed}, {nameof(LightPWM)}: {LightPWM}, {nameof(IsModified)}: {IsModified}"; + return $"{nameof(Index)}: {Index}, {nameof(Filename)}: {Filename}, {nameof(NonZeroPixelCount)}: {NonZeroPixelCount}, {nameof(BoundingRectangle)}: {BoundingRectangle}, {nameof(IsBottomLayer)}: {IsBottomLayer}, {nameof(IsNormalLayer)}: {IsNormalLayer}, {nameof(LayerHeight)}: {LayerHeight}, {nameof(PositionZ)}: {PositionZ}, {nameof(ExposureTime)}: {ExposureTime}, {nameof(LightOffDelay)}: {LightOffDelay}, {nameof(LiftHeight)}: {LiftHeight}, {nameof(LiftSpeed)}: {LiftSpeed}, {nameof(RetractSpeed)}: {RetractSpeed}, {nameof(LightPWM)}: {LightPWM}, {nameof(IsModified)}: {IsModified}, {nameof(HaveGlobalParameters)}: {HaveGlobalParameters}"; } #endregion diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs index c2180c6..ae9a023 100644 --- a/UVtools.Core/Layer/LayerManager.cs +++ b/UVtools.Core/Layer/LayerManager.cs @@ -108,6 +108,11 @@ namespace UVtools.Core } } + /// <summary> + /// Gets if all layers have same value parameters as global settings + /// </summary> + public bool AllLayersHaveGlobalParameters => Layers.Where(layer => layer is not null).All(layer => layer.HaveGlobalParameters); + //public float LayerHeight => Layers[0].PositionZ; #endregion @@ -280,6 +285,8 @@ namespace UVtools.Core layer.PositionZ = SlicerFile.GetHeightFromLayer(layerIndex); } } + + SlicerFile?.RebuildGCode(); } public Rectangle GetBoundingRectangle(OperationProgress progress = null) @@ -296,7 +303,7 @@ namespace UVtools.Core this[layerIndex].GetBoundingRectangle(); - if (ReferenceEquals(progress, null)) return; + if (progress is null) return; lock (progress.Mutex) { progress++; @@ -456,8 +463,8 @@ namespace UVtools.Core !overhangConfig.Enabled && (layer.Index == 0 || ( - (!ReferenceEquals(overhangConfig.WhiteListLayers, null) && !overhangConfig.WhiteListLayers.Contains(layer.Index)) && - (!ReferenceEquals(islandConfig.WhiteListLayers, null) && !islandConfig.WhiteListLayers.Contains(layer.Index)) + (overhangConfig.WhiteListLayers is not null && !overhangConfig.WhiteListLayers.Contains(layer.Index)) && + (islandConfig.WhiteListLayers is not null && !islandConfig.WhiteListLayers.Contains(layer.Index)) ) ) ) @@ -565,7 +572,7 @@ namespace UVtools.Core if (islandConfig.Enabled) { - if (!ReferenceEquals(islandConfig.WhiteListLayers, null)) // Check white list + if (islandConfig.WhiteListLayers is not null) // Check white list { if (!islandConfig.WhiteListLayers.Contains(layer.Index)) { @@ -669,7 +676,7 @@ namespace UVtools.Core // Check for overhangs if (overhangConfig.Enabled && !overhangConfig.IndependentFromIslands && island is null - || !ReferenceEquals(island, null) && islandConfig.EnhancedDetection && pixelsSupportingIsland >= 10 + || island is not null && islandConfig.EnhancedDetection && pixelsSupportingIsland >= 10 ) { points.Clear(); @@ -713,7 +720,7 @@ namespace UVtools.Core } } - if(!ReferenceEquals(island, null)) + if(island is not null) AddIssue(island); } @@ -724,7 +731,7 @@ namespace UVtools.Core if (!islandConfig.Enabled && overhangConfig.Enabled || (islandConfig.Enabled && overhangConfig.Enabled && overhangConfig.IndependentFromIslands)) { - if (!ReferenceEquals(overhangConfig.WhiteListLayers, null)) // Check white list + if (overhangConfig.WhiteListLayers is not null) // Check white list { if (!overhangConfig.WhiteListLayers.Contains(layer.Index)) { @@ -1089,7 +1096,7 @@ namespace UVtools.Core { var mat = modifiedLayers.GetOrAdd(operation.LayerIndex, u => this[operation.LayerIndex].LayerMat); - if (ReferenceEquals(layerContours, null)) + if (layerContours is null) { layerContours = new VectorOfVectorOfPoint(); layerHierarchy = new Mat(); diff --git a/UVtools.Core/Managers/ClipboardManager.cs b/UVtools.Core/Managers/ClipboardManager.cs index 4815521..364d5be 100644 --- a/UVtools.Core/Managers/ClipboardManager.cs +++ b/UVtools.Core/Managers/ClipboardManager.cs @@ -255,7 +255,9 @@ namespace UVtools.Core.Managers } Add(clip); + slicerFile.SuppressRebuildProperties = true; CurrentIndex = 0; + slicerFile.SuppressRebuildProperties = false; } /// <summary> diff --git a/UVtools.Core/Objects/Material.cs b/UVtools.Core/Objects/Material.cs new file mode 100644 index 0000000..fed7392 --- /dev/null +++ b/UVtools.Core/Objects/Material.cs @@ -0,0 +1,220 @@ +/* + * 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. + */ + +using System; + +namespace UVtools.Core.Objects +{ + /// <summary> + /// Represents a material to feed in the printer + /// </summary> + public class Material : BindableBase + { + #region Members + private string _name; + private decimal _bottleVolume = 1000; + private decimal _density = 1; + private decimal _bottleCost = 30; + private int _bottlesInStock = 1; + private decimal _bottleRemainingVolume = 1000; + private decimal _totalConsumedVolume; + private double _totalPrintTime; + + #endregion + + #region Properties + public string Name + { + get => _name; + set => RaiseAndSetIfChanged(ref _name, value); + } + + /// <summary> + /// Gets or sets the bottle volume in milliliters + /// </summary> + public decimal BottleVolume + { + get => _bottleVolume; + set + { + if(!RaiseAndSetIfChanged(ref _bottleVolume, value)) return; + RaisePropertyChanged(nameof(BottleWeight)); + RaisePropertyChanged(nameof(TotalConsumedBottles)); + } + } + + /// <summary> + /// Gets or sets the bottle weight in grams + /// </summary> + public decimal BottleWeight => _bottleVolume * _density; + + /// <summary> + /// Gets or sets the material density in g/ml + /// </summary> + public decimal Density + { + get => _density; + set + { + if(!RaiseAndSetIfChanged(ref _density, value)) return; + RaisePropertyChanged(nameof(BottleWeight)); + } + } + + /// <summary> + /// Gets or sets the bottle cost + /// </summary> + public decimal BottleCost + { + get => _bottleCost; + set => RaiseAndSetIfChanged(ref _bottleCost, value); + } + + /// <summary> + /// Gets or sets the number of bottles in stock + /// </summary> + public int BottlesInStock + { + get => _bottlesInStock; + set => RaiseAndSetIfChanged(ref _bottlesInStock, value); + } + + /// <summary> + /// Gets or sets the current bottle remaining material in milliliters + /// </summary> + public decimal BottleRemainingVolume + { + get => _bottleRemainingVolume; + set => RaiseAndSetIfChanged(ref _bottleRemainingVolume, value); + } + + /// <summary> + /// Gets the number of consumed bottles + /// </summary> + public uint TotalConsumedBottles => (uint) Math.Floor(_totalConsumedVolume / _bottleVolume); + + /// <summary> + /// Gets or sets the total number of consumed volume in milliliters + /// </summary> + public decimal TotalConsumedVolume + { + get => _totalConsumedVolume; + set => RaiseAndSetIfChanged(ref _totalConsumedVolume, value); + } + + /// <summary> + /// Gets or sets the total print time using with material in hours + /// </summary> + public double TotalPrintTime + { + get => _totalPrintTime; + set => RaiseAndSetIfChanged(ref _totalPrintTime, value); + } + + public TimeSpan TotalPrintTimeSpan => TimeSpan.FromHours(_totalPrintTime); + + #endregion + + #region Constructors + public Material() { } + + public Material(string name, decimal bottleVolume = 1000, decimal density = 1, decimal bottleCost = 30, int bottlesInStock = 1) + { + _name = name; + _bottleVolume = bottleVolume; + _density = density; + _bottleCost = bottleCost; + _bottlesInStock = bottlesInStock; + } + #endregion + + #region Overrides + + protected bool Equals(Material other) + { + return _name == other._name; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((Material) obj); + } + + public override int GetHashCode() + { + return (_name != null ? _name.GetHashCode() : 0); + } + + public override string ToString() + { + return $"{nameof(Name)}: {Name}, {nameof(BottleVolume)}: {BottleVolume}ml, {nameof(BottleWeight)}: {BottleWeight}g, {nameof(Density)}: {Density}g/ml, {nameof(BottleCost)}: {BottleCost}, {nameof(BottlesInStock)}: {BottlesInStock}, {nameof(BottleRemainingVolume)}: {BottleRemainingVolume}ml, {nameof(TotalConsumedBottles)}: {TotalConsumedBottles}, {nameof(TotalConsumedVolume)}: {TotalConsumedVolume}ml, {nameof(TotalPrintTime)}: {TotalPrintTime:F4}h"; + } + + #endregion + + #region Methods + /// <summary> + /// Gets the cost for a given volume + /// </summary> + /// <param name="volume">Volume in ml</param> + /// <returns></returns> + public decimal GetVolumeCost(decimal volume) => _bottleVolume > 0 ? volume * _bottleCost / _bottleVolume : 0; + + /// <summary> + /// Gets the grams for a given volume + /// </summary> + /// <param name="volume">Volume in ml</param> + /// <returns></returns> + public decimal GetVolumeGrams(decimal volume) => volume * _density; + + /// <summary> + /// Consume material from current bottle and manage stock + /// </summary> + /// <param name="volume">Volume to consume in milliliters</param> + /// <param name="printSeconds">Time in seconds it took to print</param> + /// <returns>True if still have bottles in stock, otherwise false</returns> + public bool Consume(decimal volume, double printSeconds = 0) + { + if (volume <= 0 || _bottleVolume == 0) return true; // Safe check + int consumedBottles = (int) Math.Floor(volume / _bottleVolume); + decimal remainder = volume % _bottleVolume; + + if (remainder > 0) + { + decimal remainingVolume = _bottleRemainingVolume - remainder; + if (remainingVolume < 0) + { + consumedBottles++; + remainingVolume += _bottleVolume; + } + + BottleRemainingVolume = remainingVolume; + } + + BottlesInStock -= consumedBottles; + + AddPrintTime(printSeconds); + + return _bottlesInStock > 0; + } + + /// <summary> + /// Add print time with this material + /// </summary> + /// <param name="seconds">Seconds to add</param> + public void AddPrintTime(double seconds) + { + if (seconds <= 0) return; + TotalPrintTime += seconds / 60 / 60; + } + #endregion + } +} diff --git a/UVtools.Core/Operations/OperationEditParameters.cs b/UVtools.Core/Operations/OperationEditParameters.cs index b59de70..16c61be 100644 --- a/UVtools.Core/Operations/OperationEditParameters.cs +++ b/UVtools.Core/Operations/OperationEditParameters.cs @@ -9,6 +9,7 @@ using System; using System.Linq; using System.Text; +using System.Xml.Serialization; using UVtools.Core.FileFormats; using UVtools.Core.Objects; @@ -85,6 +86,7 @@ namespace UVtools.Core.Operations #region Propertiers + [XmlIgnore] public FileFormat.PrintParameterModifier[] Modifiers { get; set; } /// <summary> @@ -161,6 +163,8 @@ namespace UVtools.Core.Operations SlicerFile.SetValuesFromPrintParametersModifiers(); } + SlicerFile.RefreshPrintParametersModifiersValues(); + return !progress.Token.IsCancellationRequested; } diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index d6ef422..37302e0 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, calibration, repair, conversion and manipulation</Description> - <Version>2.4.8</Version> + <Version>2.4.9</Version> <Copyright>Copyright © 2020 PTRTECH</Copyright> <PackageIcon>UVtools.png</PackageIcon> <Platforms>AnyCPU;x64</Platforms> diff --git a/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml b/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml index cc7cbe5..d7327a1 100644 --- a/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml +++ b/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml @@ -9,7 +9,7 @@ <CheckBox IsChecked="{Binding Operation.PerLayerOverride}" - IsVisible="{Binding SupportPerLayerSettings}" + IsVisible="{Binding SlicerFile.SupportPerLayerSettings}" Content="Change settings per a layer range"/> <StackPanel Orientation="Horizontal" Spacing="5" IsVisible="{Binding Operation.PerLayerOverride}"> diff --git a/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs index d51bca0..0b88b49 100644 --- a/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs +++ b/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs @@ -18,7 +18,6 @@ namespace UVtools.WPF.Controls.Tools public class ToolEditParametersControl : ToolControl { public OperationEditParameters Operation => BaseOperation as OperationEditParameters; - public bool SupportPerLayerSettings => App.SlicerFile.SupportPerLayerSettings; public RowControl[] RowControls; private Grid grid; @@ -122,9 +121,6 @@ namespace UVtools.WPF.Controls.Tools } grid = this.FindControl<Grid>("grid"); - PopulateGrid(); - - Operation.PropertyChanged += OperationOnPropertyChanged; } public void PopulateGrid() @@ -189,9 +185,12 @@ namespace UVtools.WPF.Controls.Tools switch (callback) { case ToolWindow.Callbacks.Init: + case ToolWindow.Callbacks.ProfileLoaded: ParentWindow.IsButton1Visible = true; ParentWindow.SelectCurrentLayer(); ParentWindow.LayerRangeSync = true; + PopulateGrid(); + Operation.PropertyChanged += OperationOnPropertyChanged; break; case ToolWindow.Callbacks.Button1: foreach (var rowControl in RowControls) @@ -204,9 +203,9 @@ namespace UVtools.WPF.Controls.Tools private void OperationOnPropertyChanged(object sender, PropertyChangedEventArgs e) { - if (e.PropertyName == nameof(Operation.LayerIndexStart)) + if (e.PropertyName == nameof(Operation.LayerIndexStart) && Operation.PerLayerOverride) { - App.SlicerFile.RefreshPrintParametersPerLayerModifiersValues(Operation.LayerIndexStart); + SlicerFile.RefreshPrintParametersPerLayerModifiersValues(Operation.LayerIndexStart); PopulateGrid(); return; } @@ -215,12 +214,12 @@ namespace UVtools.WPF.Controls.Tools if (Operation.PerLayerOverride) { Operation.Modifiers = App.SlicerFile.PrintParameterPerLayerModifiers; - App.SlicerFile.RefreshPrintParametersPerLayerModifiersValues(Operation.LayerIndexStart); + SlicerFile.RefreshPrintParametersPerLayerModifiersValues(Operation.LayerIndexStart); } else { Operation.Modifiers = App.SlicerFile.PrintParameterModifiers; - App.SlicerFile.RefreshPrintParametersModifiersValues(); + SlicerFile.RefreshPrintParametersModifiersValues(); } ParentWindow.LayerRangeVisible = Operation.PerLayerOverride; diff --git a/UVtools.WPF/Structures/OperationProfiles.cs b/UVtools.WPF/Structures/OperationProfiles.cs index 6300e69..b92fd97 100644 --- a/UVtools.WPF/Structures/OperationProfiles.cs +++ b/UVtools.WPF/Structures/OperationProfiles.cs @@ -67,7 +67,7 @@ namespace UVtools.WPF.Structures #region Singleton private static Lazy<OperationProfiles> _instanceHolder = - new Lazy<OperationProfiles>(() => new OperationProfiles()); + new(() => new OperationProfiles()); /// <summary> /// Instance of <see cref="UserSettings"/> (singleton) diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index fbf4dea..65e1c9a 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.4.8</Version> + <Version>2.4.9</Version> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |