diff options
author | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-12-03 01:28:14 +0300 |
---|---|---|
committer | Tiago Conceição <Tiago_caza@hotmail.com> | 2021-12-03 01:28:14 +0300 |
commit | 40a89a71d1a920d330e25350f113eb5b1bf9f97e (patch) | |
tree | 32ead8eeb7303ba602342d70b341703abeb68030 | |
parent | 2d1f205c75062b6b2c6b6004536114e8028bda4b (diff) |
v2.25.3v2.25.3
- **File - Send to:**
- (Add) Icons to distinguish each send type
- (Add) Allow to configure processes to open the file with (#352)
- (Improvement) CXDLP: When encoding the file, only attempt to change the machine name if not starts with 'CL-' (#351)
- (Improvement) UI: Remove the "0/?" and just show the title on the progress bar
- (Change) CTBv4: Remove the following validation to be compatible with lychee and CTB SDK: "Malformed file, PrintParametersV4 found invalid validation values, expected (4, 4) got (x, y)" (#354)
-rw-r--r-- | CHANGELOG.md | 9 | ||||
-rw-r--r-- | CREDITS.md | 3 | ||||
-rw-r--r-- | Scripts/010 Editor/cxdlp_v2.bt | 12 | ||||
-rw-r--r-- | UVtools.Core/FileFormats/CXDLPFile.cs | 64 | ||||
-rw-r--r-- | UVtools.Core/FileFormats/ChituboxFile.cs | 4 | ||||
-rw-r--r-- | UVtools.Core/Objects/MappedProcess.cs | 173 | ||||
-rw-r--r-- | UVtools.Core/Operations/OperationProgress.cs | 21 | ||||
-rw-r--r-- | UVtools.Core/UVtools.Core.csproj | 4 | ||||
-rw-r--r-- | UVtools.WPF/Assets/Icons/cog-16x16.png | bin | 0 -> 190 bytes | |||
-rw-r--r-- | UVtools.WPF/Assets/Icons/folder-16x16.png | bin | 0 -> 97 bytes | |||
-rw-r--r-- | UVtools.WPF/Assets/Icons/network-wired-16x16.png | bin | 0 -> 133 bytes | |||
-rw-r--r-- | UVtools.WPF/Assets/Icons/usb-16x16.png | bin | 0 -> 164 bytes | |||
-rw-r--r-- | UVtools.WPF/MainWindow.axaml.cs | 111 | ||||
-rw-r--r-- | UVtools.WPF/UVtools.WPF.csproj | 4 | ||||
-rw-r--r-- | UVtools.WPF/UserSettings.cs | 178 | ||||
-rw-r--r-- | UVtools.WPF/Windows/SettingsWindow.axaml | 78 | ||||
-rw-r--r-- | UVtools.WPF/Windows/SettingsWindow.axaml.cs | 31 | ||||
-rw-r--r-- | build/CreateRelease.WPF.ps1 | 2 |
18 files changed, 644 insertions, 50 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 99e5d79..44e3855 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 02/12/2021 - v2.25.3 + +- **File - Send to:** + - (Add) Icons to distinguish each send type + - (Add) Allow to configure processes to open the file with (#352) +- (Improvement) CXDLP: When encoding the file, only attempt to change the machine name if not starts with 'CL-' (#351) +- (Improvement) UI: Remove the "0/?" and just show the title on the progress bar +- (Change) CTBv4: Remove the following validation to be compatible with lychee and CTB SDK: "Malformed file, PrintParametersV4 found invalid validation values, expected (4, 4) got (x, y)" (#354) + ## 25/11/2021 - v2.25.2 - **About box:** @@ -64,4 +64,5 @@ - Peter Csaki - Chris Luginbuhl - Tim Savage -- Peopoly Inc
\ No newline at end of file +- Peopoly Inc +- Riccardo Kocmann
\ No newline at end of file diff --git a/Scripts/010 Editor/cxdlp_v2.bt b/Scripts/010 Editor/cxdlp_v2.bt index 5c6171b..180d7fa 100644 --- a/Scripts/010 Editor/cxdlp_v2.bt +++ b/Scripts/010 Editor/cxdlp_v2.bt @@ -88,6 +88,18 @@ struct LAYER_DEF { ubyte rn3[2] <fgcolor=cBlack, bgcolor=cRed>; } layerDefs; +if(header.version >= 3){ + struct SLICER_INFO { + uint32 SoftwareNameSize; + char SoftwareName[SoftwareNameSize]; + uint32 MaterialNameSize; + char MaterialName[MaterialNameSize]; + ubyte offset[67-SoftwareNameSize-MaterialNameSize]; + ubyte rn0[2] <fgcolor=cBlack, bgcolor=cRed>; + } slicerInfo; +} + + struct LAYERS { local int i; for( i = 0; i < header.totalLayers; i++ ){ diff --git a/UVtools.Core/FileFormats/CXDLPFile.cs b/UVtools.Core/FileFormats/CXDLPFile.cs index ff39673..32e1768 100644 --- a/UVtools.Core/FileFormats/CXDLPFile.cs +++ b/UVtools.Core/FileFormats/CXDLPFile.cs @@ -18,7 +18,6 @@ using System.Threading.Tasks; using BinarySerialization; using Emgu.CV; using Emgu.CV.Structure; -using MoreLinq; using UVtools.Core.Extensions; using UVtools.Core.Layers; using UVtools.Core.Operations; @@ -82,7 +81,7 @@ namespace UVtools.Core.FileFormats [FieldOrder(4)] [FieldLength(nameof(PrinterModelSize))] - public byte[] PrinterModelArray { get; set; } = { 0x43, 0x4C, 0x2D, 0x38, 0x39, 0x0 }; // CL-89 + public byte[] PrinterModelArray { get; set; } = Array.Empty<byte>(); // CL-89 { 0x43, 0x4C, 0x2D, 0x38, 0x39, 0x0 } [Ignore] public string PrinterModel @@ -215,7 +214,7 @@ namespace UVtools.Core.FileFormats } #endregion - #region Layer Def + #region PreLayer public sealed class PreLayer { @@ -233,6 +232,27 @@ namespace UVtools.Core.FileFormats } } + #endregion + + #region SlicerInfoV3 + + public sealed class SlicerInfoV3 + { + [FieldOrder(0)] [FieldEndianness(Endianness.Big)] public uint SoftwareNameSize { get; set; } = (uint)About.SoftwareWithVersion.Length; + + [FieldOrder(1)] [FieldLength(nameof(SoftwareNameSize))] public string SoftwareName { get; set; } = About.SoftwareWithVersion; + + [FieldOrder(2)] [FieldEndianness(Endianness.Big)] public uint MaterialNameSize { get; set; } + + [FieldOrder(3)] [FieldLength(nameof(MaterialNameSize))] public string MaterialName { get; set; } + + //[FieldOrder(4)] [FieldOffset(67 - SoftwareNameSize - MaterialNameSize)] public PageBreak PageBreak { get; set; } = new(); + } + + #endregion + + #region Layer Def + public sealed class LayerDef { [FieldOrder(0)] [FieldEndianness(Endianness.Big)] public uint LayerArea { get; set; } @@ -355,6 +375,7 @@ namespace UVtools.Core.FileFormats public Header HeaderSettings { get; protected internal set; } = new(); public SlicerInfo SlicerInfoSettings { get; protected internal set; } = new(); + public SlicerInfoV3 SlicerInfoV3Settings { get; protected internal set; } = new(); public Footer FooterSettings { get; protected internal set; } = new(); public override FileFormatType FileType => FileFormatType.Binary; @@ -556,6 +577,12 @@ namespace UVtools.Core.FileFormats set => base.MachineName = HeaderSettings.PrinterModel = value; } + public override string MaterialName + { + get => SlicerInfoV3Settings.MaterialName; + set => base.MaterialName = SlicerInfoV3Settings.MaterialName = value; + } + public override object[] Configs => new object[] { HeaderSettings, SlicerInfoSettings, FooterSettings }; #endregion @@ -574,21 +601,24 @@ namespace UVtools.Core.FileFormats { using var outputFile = new FileStream(FileFullPath, FileMode.Create, FileAccess.ReadWrite); - if (ResolutionX == 1620 && ResolutionY == 2560) - { - MachineName = "CL-60"; - } - else if (ResolutionX == 3840 && ResolutionY == 2400) - { - MachineName = "CL-89"; - } - else if (ResolutionX == 3840 && ResolutionY == 2160) - { - MachineName = "CL-133"; - } - else if (!MachineName.StartsWith("CL-")) + if (!MachineName.StartsWith("CL-")) { - throw new Exception("Unable to detect the printer model from resolution, check if resolution is well defined on slicer for your printer model."); + if (ResolutionX == 1620 && ResolutionY == 2560) + { + MachineName = "CL-60"; // One + } + else if (ResolutionX == 3840 && ResolutionY == 2400) // Sky or lite + { + MachineName = "CL-89"; // Sky + } + else if (ResolutionX == 3840 && ResolutionY == 2160) + { + MachineName = "CL-133"; // Max + } + else + { + throw new InvalidDataException("Unable to detect the printer model from resolution, check if resolution is well defined on slicer for your printer model."); + } } SanitizeProperties(); diff --git a/UVtools.Core/FileFormats/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs index f032d6d..213b50a 100644 --- a/UVtools.Core/FileFormats/ChituboxFile.cs +++ b/UVtools.Core/FileFormats/ChituboxFile.cs @@ -2038,13 +2038,13 @@ namespace UVtools.Core.FileFormats Debug.Write("Print Parameters V4 -> "); Debug.WriteLine(PrintParametersV4Settings); - if (PrintParametersV4Settings.Four1 != 4 && PrintParametersV4Settings.Four2 != 4) + /*if (PrintParametersV4Settings.Four1 != 4 && PrintParametersV4Settings.Four2 != 4) { throw new FileLoadException( $"Malformed file, PrintParametersV4 found invalid validation values, expected (4, 4) " + $"but got ({PrintParametersV4Settings.Four1}, {PrintParametersV4Settings.Four2})", FileFullPath); - } + }*/ } LayerManager.Init(HeaderSettings.LayerCount, DecodeType == FileDecodeType.Partial); diff --git a/UVtools.Core/Objects/MappedProcess.cs b/UVtools.Core/Objects/MappedProcess.cs new file mode 100644 index 0000000..6060097 --- /dev/null +++ b/UVtools.Core/Objects/MappedProcess.cs @@ -0,0 +1,173 @@ +/* + * 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.Diagnostics; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using UVtools.Core.FileFormats; +using UVtools.Core.Objects; + +namespace UVtools.Core.Objects +{ + public class MappedProcess : BindableBase + { + #region Constants + + public const string DefaultArgument = "\"{0}\""; + #endregion + + #region Members + + private bool _isEnabled = true; + private string _applicationPath; + private string _name; + private string _arguments = DefaultArgument; + private string _compatibleExtensions; + private bool _waitForExit; + + #endregion + + #region Properties + + /// <summary> + /// Gets or sets if this device is enabled + /// </summary> + public bool IsEnabled + { + get => _isEnabled; + set => RaiseAndSetIfChanged(ref _isEnabled, value); + } + + /// <summary> + /// Gets or sets the full path for the application + /// </summary> + public string ApplicationPath + { + get => _applicationPath; + set => RaiseAndSetIfChanged(ref _applicationPath, value); + } + + /// <summary> + /// Gets or sets the path name alias + /// </summary> + public string Name + { + get => _name; + set => RaiseAndSetIfChanged(ref _name, value); + } + + /// <summary> + /// Gets or sets the arguments for the application + /// </summary> + public string Arguments + { + get => _arguments; + set => RaiseAndSetIfChanged(ref _arguments, value); + } + + /// <summary> + /// Gets or sets the compatible extensions with this device. + /// Empty or null to be compatible with everything + /// </summary> + public string CompatibleExtensions + { + get => _compatibleExtensions; + set => RaiseAndSetIfChanged(ref _compatibleExtensions, value); + } + + public bool WaitForExit + { + get => _waitForExit; + set => RaiseAndSetIfChanged(ref _waitForExit, value); + } + + #endregion + + #region Contructors + + public MappedProcess() { } + + public MappedProcess(bool isEnabled, string applicationPath, string name = null, string arguments = DefaultArgument) + { + _isEnabled = isEnabled; + _applicationPath = applicationPath; + if (string.IsNullOrWhiteSpace(name)) + { + name = Path.GetFileNameWithoutExtension(applicationPath); + } + _name = name; + + if (string.IsNullOrWhiteSpace(arguments)) + { + arguments = DefaultArgument; + } + + _arguments = arguments; + } + + public MappedProcess(string applicationPath, string name = null, string arguments = DefaultArgument) : this(true, applicationPath, name, arguments) + { } + + #endregion + + #region Methods + + public bool IsValid() + { + return File.Exists(_applicationPath); + } + + public async Task StartProcess(FileFormat slicerFile, CancellationToken cancellationToken = default) + { + await StartProcess(slicerFile.FileFullPath, cancellationToken); + } + + public async Task StartProcess(string slicerFile, CancellationToken cancellationToken = default) + { + var arguments = string.IsNullOrWhiteSpace(_arguments) ? $"\"{slicerFile}\"" : string.Format(_arguments, slicerFile); + using var process = Process.Start(_applicationPath, arguments); + if (process is null) return; + if (_waitForExit) + { + await process.WaitForExitAsync(cancellationToken); + } + } + + public override string ToString() + { + return $"{_applicationPath} {Arguments}"; + } + + protected bool Equals(MappedProcess other) + { + return _applicationPath == other._applicationPath && _name == other._name && _arguments == other._arguments && _compatibleExtensions == other._compatibleExtensions; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((MappedProcess)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(_applicationPath, _name, _arguments, _compatibleExtensions); + } + + public MappedProcess Clone() + { + return MemberwiseClone() as MappedProcess; + } + + #endregion + } +} diff --git a/UVtools.Core/Operations/OperationProgress.cs b/UVtools.Core/Operations/OperationProgress.cs index a1a418f..480b75a 100644 --- a/UVtools.Core/Operations/OperationProgress.cs +++ b/UVtools.Core/Operations/OperationProgress.cs @@ -95,7 +95,11 @@ namespace UVtools.Core.Operations public string ItemName { get => _itemName; - set => RaiseAndSetIfChanged(ref _itemName, value); + set + { + if(!RaiseAndSetIfChanged(ref _itemName, value)) return; + RaisePropertyChanged(nameof(Description)); + } } /// <summary> @@ -201,9 +205,20 @@ namespace UVtools.Core.Operations public override string ToString() { - return _itemCount == 0 ? + if (_itemCount == 0 && _processedItems == 0) + { + return $"{_itemName}"; + } + + if (_itemCount == 0 && _processedItems > 0) + { + return $"{_processedItems} {_itemName}"; + } + + return $"{_processedItems.ToString().PadLeft(_itemCount.ToString().Length, '0')}/{_itemCount} {_itemName} | {ProgressPercent:F2}%"; + /*return _itemCount == 0 ? $"{_processedItems}/? {_itemName}" : -$"{_processedItems.ToString().PadLeft(_itemCount.ToString().Length, '0')}/{_itemCount} {_itemName} | {ProgressPercent:F2}%"; +$"{_processedItems.ToString().PadLeft(_itemCount.ToString().Length, '0')}/{_itemCount} {_itemName} | {ProgressPercent:F2}%";*/ } public void TriggerRefresh() diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index 5fc06b9..949e014 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.25.2</Version> + <Version>2.25.3</Version> <Copyright>Copyright © 2020 PTRTECH</Copyright> <PackageIcon>UVtools.png</PackageIcon> <Platforms>AnyCPU;x64</Platforms> @@ -52,7 +52,7 @@ <PackageReference Include="BinarySerializer" Version="8.6.1.2" /> <PackageReference Include="Emgu.CV" Version="4.5.4.4788" /> <PackageReference Include="KdTree" Version="1.4.1" /> - <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.0.1" /> + <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.1.0-1.final" /> <PackageReference Include="Microsoft.Win32.Registry" Version="6.0.0-preview.5.21301.5" /> <PackageReference Include="morelinq" Version="3.3.2" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> diff --git a/UVtools.WPF/Assets/Icons/cog-16x16.png b/UVtools.WPF/Assets/Icons/cog-16x16.png Binary files differnew file mode 100644 index 0000000..b8a242f --- /dev/null +++ b/UVtools.WPF/Assets/Icons/cog-16x16.png diff --git a/UVtools.WPF/Assets/Icons/folder-16x16.png b/UVtools.WPF/Assets/Icons/folder-16x16.png Binary files differnew file mode 100644 index 0000000..fb7a5b4 --- /dev/null +++ b/UVtools.WPF/Assets/Icons/folder-16x16.png diff --git a/UVtools.WPF/Assets/Icons/network-wired-16x16.png b/UVtools.WPF/Assets/Icons/network-wired-16x16.png Binary files differnew file mode 100644 index 0000000..567f2cd --- /dev/null +++ b/UVtools.WPF/Assets/Icons/network-wired-16x16.png diff --git a/UVtools.WPF/Assets/Icons/usb-16x16.png b/UVtools.WPF/Assets/Icons/usb-16x16.png Binary files differnew file mode 100644 index 0000000..03e109d --- /dev/null +++ b/UVtools.WPF/Assets/Icons/usb-16x16.png diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs index d96b89d..182ee9c 100644 --- a/UVtools.WPF/MainWindow.axaml.cs +++ b/UVtools.WPF/MainWindow.axaml.cs @@ -30,6 +30,7 @@ using UVtools.Core.FileFormats; using UVtools.Core.Layers; using UVtools.Core.Managers; using UVtools.Core.Network; +using UVtools.Core.Objects; using UVtools.Core.Operations; using UVtools.Core.SystemOS; using UVtools.WPF.Controls; @@ -620,27 +621,35 @@ namespace UVtools.WPF var drives = DriveInfo.GetDrives(); - foreach (var drive in drives) + if (drives.Length > 0) { - if(drive.DriveType != DriveType.Removable || !drive.IsReady) continue; // Not our target, skip - if (SlicerFile.FileFullPath.StartsWith(drive.Name)) continue; // File already on this device, skip - - var header = drive.Name; - if (!string.IsNullOrWhiteSpace(drive.VolumeLabel)) + foreach (var drive in drives) { - header += $" {drive.VolumeLabel}"; - } + if (drive.DriveType != DriveType.Removable || !drive.IsReady) continue; // Not our target, skip + if (SlicerFile.FileFullPath.StartsWith(drive.Name)) + continue; // File already on this device, skip - header += $" ({SizeExtensions.SizeSuffix(drive.AvailableFreeSpace)}) [{drive.DriveFormat}]"; + var header = drive.Name; + if (!string.IsNullOrWhiteSpace(drive.VolumeLabel)) + { + header += $" {drive.VolumeLabel}"; + } - var menuItem = new MenuItem - { - Header = header, - Tag = drive, - }; - menuItem.Click += FileSendToItemClick; + header += $" ({SizeExtensions.SizeSuffix(drive.AvailableFreeSpace)}) [{drive.DriveFormat}]"; + + var menuItem = new MenuItem + { + Header = header, + Tag = drive, + Icon = new Image + { + Source = new Bitmap(App.GetAsset("/Assets/Icons/usb-16x16.png")) + } + }; + menuItem.Click += FileSendToItemClick; - menuItems.Add(menuItem); + menuItems.Add(menuItem); + } } if (Settings.General.SendToCustomLocations is not null && Settings.General.SendToCustomLocations.Count > 0) @@ -666,6 +675,10 @@ namespace UVtools.WPF { Header = location.ToString(), Tag = location, + Icon = new Image + { + Source = new Bitmap(App.GetAsset("/Assets/Icons/folder-16x16.png")) + } }; menuItem.Click += FileSendToItemClick; @@ -696,6 +709,44 @@ namespace UVtools.WPF { Header = remotePrinter.ToString(), Tag = remotePrinter, + Icon = new Image + { + Source = new Bitmap(App.GetAsset("/Assets/Icons/network-wired-16x16.png")) + } + }; + menuItem.Click += FileSendToItemClick; + + menuItems.Add(menuItem); + } + } + + if (Settings.General.SendToProcess is not null && Settings.General.SendToProcess.Count > 0) + { + foreach (var application in Settings.General.SendToProcess) + { + if (!application.IsEnabled ) continue; + + if (!string.IsNullOrWhiteSpace(application.CompatibleExtensions)) + { + var extensions = application.CompatibleExtensions.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + + var found = false; + foreach (var ext in extensions) + { + found = SlicerFile.FileFullPath.EndsWith($".{ext}"); + if (found) break; + } + if (!found) continue; + } + + var menuItem = new MenuItem + { + Header = application.Name, + Tag = application, + Icon = new Image + { + Source = new Bitmap(App.GetAsset("/Assets/Icons/cog-16x16.png")) + } }; menuItem.Click += FileSendToItemClick; @@ -735,6 +786,10 @@ namespace UVtools.WPF { path = preRemotePrinter.HostUrl; } + else if (menuItem.Tag is MappedProcess process) + { + path = process.Name; + } else { return; @@ -757,8 +812,8 @@ namespace UVtools.WPF } } - ShowProgressWindow($"Copying: {SlicerFile.Filename} to {path}", true); - Progress.ItemName = "Copying"; + ShowProgressWindow($"Sending: {SlicerFile.Filename} to {path}"); + Progress.ItemName = "Sending"; if (menuItem.Tag is RemotePrinter remotePrinter) @@ -839,6 +894,20 @@ namespace UVtools.WPF } } } + else if (menuItem.Tag is MappedProcess process) + { + Progress.ItemName = "Waiting for completion"; + try + { + await process.StartProcess(SlicerFile, Progress.Token); + } + catch (OperationCanceledException){} + catch (Exception ex) + { + await this.MessageBoxError(ex.Message, $"Unable to start the process {process.Name}"); + } + + } else { /*var copyResult = await Task.Factory.StartNew(() => @@ -914,7 +983,7 @@ namespace UVtools.WPF } catch (Exception exception) { - await this.MessageBoxError(exception.ToString(), "Unable to copy the file"); + await this.MessageBoxError(exception.Message, "Unable to copy the file"); } if(copyResult && menuItem.Tag is DriveInfo removableDrive && OperatingSystem.IsWindows() && Settings.General.SendToPromptForRemovableDeviceEject) @@ -934,7 +1003,7 @@ namespace UVtools.WPF catch (Exception exception) { Dispatcher.UIThread.InvokeAsync(async () => - await this.MessageBoxError(exception.ToString(), $"Unable to eject the drive {removableDrive.Name}")); + await this.MessageBoxError(exception.Message, $"Unable to eject the drive {removableDrive.Name}")); } return false; @@ -1891,7 +1960,7 @@ namespace UVtools.WPF } Dispatcher.UIThread.InvokeAsync(async () => - await this.MessageBoxError($"Convertion was not successful! Maybe not implemented...\n{extraMessage}{ex}", "Convertion unsuccessful")); + await this.MessageBoxError($"{extraMessage}{ex}", "Convertion unsuccessful")); } return false; diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index 7b76ea0..e04e08c 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.25.2</Version> + <Version>2.25.3</Version> <Platforms>AnyCPU;x64</Platforms> </PropertyGroup> @@ -40,7 +40,7 @@ <PackageReference Include="Avalonia.Desktop" Version="0.10.8" /> <PackageReference Include="Avalonia.Diagnostics" Version="0.10.8" /> <PackageReference Include="Emgu.CV.runtime.windows" Version="4.5.4.4788" /> - <PackageReference Include="MessageBox.Avalonia" Version="1.5.5" /> + <PackageReference Include="MessageBox.Avalonia" Version="1.6.0" /> <PackageReference Include="ThemeEditor.Controls.ColorPicker" Version="0.10.8" /> </ItemGroup> <ItemGroup> diff --git a/UVtools.WPF/UserSettings.cs b/UVtools.WPF/UserSettings.cs index 7332940..9532110 100644 --- a/UVtools.WPF/UserSettings.cs +++ b/UVtools.WPF/UserSettings.cs @@ -7,6 +7,7 @@ */ using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; @@ -15,6 +16,7 @@ using Avalonia.Media; using JetBrains.Annotations; using UVtools.Core; using UVtools.Core.Extensions; +using UVtools.Core.FileFormats; using UVtools.Core.Network; using UVtools.Core.Objects; using Color=UVtools.WPF.Structures.Color; @@ -56,6 +58,7 @@ namespace UVtools.WPF private string _fileSaveNameSuffix = "_copy"; private bool _sendToPromptForRemovableDeviceEject = true; private RangeObservableCollection<MappedDevice> _sendToCustomLocations = new(); + private RangeObservableCollection<MappedProcess> _sendToProcess = new(); public bool StartMaximized @@ -188,6 +191,12 @@ namespace UVtools.WPF set => RaiseAndSetIfChanged(ref _sendToCustomLocations, value); } + public RangeObservableCollection<MappedProcess> SendToProcess + { + get => _sendToProcess; + set => RaiseAndSetIfChanged(ref _sendToProcess, value); + } + public GeneralUserSettings() { } public GeneralUserSettings Clone() @@ -1717,6 +1726,175 @@ namespace UVtools.WPF }*/ }); } + + if (_instance.General.SendToProcess.Count == 0) + { + if (OperatingSystem.IsWindows()) + { + var findDirectories = new List<string> + { + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + }; + if (Environment.Is64BitOperatingSystem) + { + findDirectories.Add(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)); + } + + foreach (var path in findDirectories) + { + var directories = Directory.GetDirectories(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)); + foreach (var directory in directories) + { + /*if (directory.StartsWith($"{path}\\Prusa3D", StringComparison.InvariantCultureIgnoreCase)) + { + var executable = $"{directory}\\PrusaSlicer\\prusa-slicer.exe"; + if (File.Exists(executable)) + { + var application = new MappedApplication(executable, "Slicer: PrusaSlicer"); + foreach (var slicerFile in FileFormat.AvailableFormats) + { + if (slicerFile is not SL1File) continue; + application.CompatibleExtensions += slicerFile.GetFileExtensions(string.Empty, ";"); + } + + _instance.General.SendToApplications.Add(application); + } + + continue; + }*/ + + if (directory.StartsWith($"{path}\\Chitubox", StringComparison.InvariantCultureIgnoreCase)) + { + var executable = $"{directory}\\CHITUBOX.exe"; + //var executablePro = $"{directory}\\CHITUBOXPro.exe"; + if (File.Exists(executable)) + { + _instance.General.SendToProcess.Add(new MappedProcess(executable, "Slicer: Chitubox") + { + CompatibleExtensions = "cbddlp;ctb;phz;photon;photons;fdg" + }); + } + /*else if (File.Exists(executablePro)) + { + _instance.General.SendToApplications.Add(new MappedApplication(executablePro, "Slicer: Chitubox Pro") + { + CompatibleExtensions = "cbddlp;ctb;phz;photon;photons;fdg" + }); + }*/ + continue; + } + + if (directory.StartsWith($"{path}\\Photon_WorkShop", StringComparison.InvariantCultureIgnoreCase)) + { + var directoryName = Path.GetFileName(directory); + var executable = $"{directory}\\{directoryName}.exe"; + if (File.Exists(executable)) + { + var application = new MappedProcess(executable, $"Slicer: {directoryName.Replace('_', ' ')}") + { + CompatibleExtensions = "photon;photons;" + }; + foreach (var slicerFile in FileFormat.AvailableFormats) + { + if (slicerFile is not PhotonWorkshopFile) continue; + application.CompatibleExtensions += slicerFile.GetFileExtensions(string.Empty, ";"); + } + + + _instance.General.SendToProcess.Add(application); + } + continue; + } + + if (directory.StartsWith($"{path}\\UNIZ", StringComparison.InvariantCultureIgnoreCase)) + { + var executable = $"{directory}\\UnizMaker\\UnizMaker.exe"; + if (File.Exists(executable)) + { + _instance.General.SendToProcess.Add(new MappedProcess(executable, "Slicer: UnizMaker") + { + CompatibleExtensions = "zcode" + }); + } + continue; + } + + if (directory.StartsWith($"{path}\\Zortrax", StringComparison.InvariantCultureIgnoreCase)) + { + var executable = $"{directory}\\Z-Suite\\Z-SUITE.exe"; + if (File.Exists(executable)) + { + _instance.General.SendToProcess.Add(new MappedProcess(executable, "Slicer: Z-SUITE") + { + CompatibleExtensions = "zcodex" + }); + } + continue; + } + + if (directory.StartsWith($"{path}\\WinRAR", StringComparison.InvariantCultureIgnoreCase)) + { + var executable = $"{directory}\\WinRAR.exe"; + if (File.Exists(executable)) + { + var application = new MappedProcess(executable, "Open archive: WinRAR") + { + CompatibleExtensions = "zip;sl1;sl1s;cws;zcode;zcodex;vdt;uvt" + }; + _instance.General.SendToProcess.Add(application); + } + + continue; + } + + if (directory.StartsWith($"{path}\\7-Zip", StringComparison.InvariantCultureIgnoreCase)) + { + var executable = $"{directory}\\7zFM.exe"; + if (File.Exists(executable)) + { + var application = new MappedProcess(executable, "Open archive: 7-Zip") + { + CompatibleExtensions = "zip;sl1;sl1s;cws;zcode;zcodex;vdt;uvt" + }; + _instance.General.SendToProcess.Add(application); + } + + continue; + } + + + if (directory.StartsWith($"{path}\\010 Editor", StringComparison.InvariantCultureIgnoreCase)) + { + var executable = $"{directory}\\010Editor.exe"; + if (File.Exists(executable)) + { + var application = new MappedProcess(true, executable, "Hex editor: 010"); + _instance.General.SendToProcess.Add(application); + } + + continue; + } + + if (directory.StartsWith($"{path}\\HxD", StringComparison.InvariantCultureIgnoreCase)) + { + var executable = $"{directory}\\HxD.exe"; + if (File.Exists(executable)) + { + var application = new MappedProcess(false, executable, "Hex editor: HxD"); + _instance.General.SendToProcess.Add(application); + } + + continue; + } + } + } + + if (_instance.General.SendToProcess.Count > 0) + { + _instance.General.SendToProcess.Sort((process, mappedProcess) => string.Compare(process.Name, mappedProcess.Name, StringComparison.Ordinal)); + } + } + } } catch (Exception e) { diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml b/UVtools.WPF/Windows/SettingsWindow.axaml index ad97d67..93de17a 100644 --- a/UVtools.WPF/Windows/SettingsWindow.axaml +++ b/UVtools.WPF/Windows/SettingsWindow.axaml @@ -332,7 +332,7 @@ <Grid RowDefinitions="Auto" ColumnDefinitions="*,Auto" Background="LightBlue"> <TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" - Padding="10" FontWeight="Bold" Text="Send to - Custom locations"/> + Padding="10" FontWeight="Bold" Text="Send to - Custom location"/> <StackPanel Grid.Row="0" Grid.Column="1" HorizontalAlignment="Right" Orientation="Horizontal" Spacing="2"> @@ -363,6 +363,7 @@ CanUserSortColumns="True" GridLinesVisibility="Horizontal" IsReadOnly="False" + MinHeight="100" SelectionMode="Extended" ClipboardCopyMode="IncludeHeader" Items="{Binding Settings.General.SendToCustomLocations}"> @@ -391,6 +392,81 @@ </StackPanel> </Border> + <Border + Classes="GroupBox" + Margin="5"> + + <StackPanel Orientation="Vertical"> + <Grid RowDefinitions="Auto" ColumnDefinitions="*,Auto" Background="LightBlue"> + <TextBlock Grid.Row="0" Grid.Column="0" + ToolTip.Tip="Allow to open a new process with arguments and pass the current file.
 +
Wait exit: Interrupt the UI and wait for process completion/exit. +
Arguments: Use "{0}" to indicate the current loaded file path, when empty, it will pass "{0}" by default." + VerticalAlignment="Center" + Padding="10" FontWeight="Bold" Text="Send to - Process"/> + + <StackPanel Grid.Row="0" Grid.Column="1" + HorizontalAlignment="Right" Orientation="Horizontal" Spacing="2"> + <Button ToolTip.Tip="Add location" VerticalAlignment="Center" + Command="{Binding SendToAddProcess}"> + <Image Source="/Assets/Icons/plus-16x16.png"/> + </Button> + + <Button ToolTip.Tip="Remove selected process(es)" VerticalAlignment="Center" + IsEnabled="{Binding #SendToProcessGrid.SelectedItem, Converter={x:Static ObjectConverters.IsNotNull}}" + Command="{Binding SendToRemoveProcess}"> + <Image Source="/Assets/Icons/trash-16x16.png"/> + </Button> + </StackPanel> + + </Grid> + + <StackPanel Margin="10" Orientation="Vertical" Spacing="10"> + + <DataGrid + Name="SendToProcessGrid" + CanUserReorderColumns="True" + CanUserResizeColumns="True" + CanUserSortColumns="True" + GridLinesVisibility="Horizontal" + IsReadOnly="False" + SelectionMode="Extended" + ClipboardCopyMode="IncludeHeader" + MinHeight="100" + Items="{Binding Settings.General.SendToProcess}"> + <DataGrid.Columns> + <DataGridCheckBoxColumn Header="Enabled" + Binding="{Binding IsEnabled}" + IsReadOnly="False" + Width="Auto" /> + <DataGridCheckBoxColumn Header="Wait exit" + Binding="{Binding WaitForExit}" + IsReadOnly="False" + Width="Auto" /> + <DataGridTextColumn Header="Alias name" + Binding="{Binding Name}" + IsReadOnly="False" + Width="150" /> + <DataGridTextColumn Header="Process path" + Binding="{Binding ApplicationPath}" + IsReadOnly="True" + Width="*" /> + <DataGridTextColumn Header="Arguments" + Binding="{Binding Arguments}" + IsReadOnly="False" + Width="110" /> + <DataGridTextColumn Header="Extensions" + Binding="{Binding CompatibleExtensions}" + IsReadOnly="False" + Width="150" /> + </DataGrid.Columns> + + </DataGrid> + </StackPanel> + + </StackPanel> + </Border> + </StackPanel> </ScrollViewer> diff --git a/UVtools.WPF/Windows/SettingsWindow.axaml.cs b/UVtools.WPF/Windows/SettingsWindow.axaml.cs index 8f61d2c..e4e3675 100644 --- a/UVtools.WPF/Windows/SettingsWindow.axaml.cs +++ b/UVtools.WPF/Windows/SettingsWindow.axaml.cs @@ -10,6 +10,7 @@ using Avalonia.Threading; using MessageBox.Avalonia.Enums; using UVtools.Core.FileFormats; using UVtools.Core.Network; +using UVtools.Core.Objects; using UVtools.WPF.Controls; using UVtools.WPF.Extensions; using Color = UVtools.WPF.Structures.Color; @@ -21,6 +22,7 @@ namespace UVtools.WPF.Windows private double _scrollViewerMaxHeight; private int _selectedTabIndex; private DataGrid _sendToCustomLocationsGrid; + private DataGrid _sendToProcessGrid; private ComboBox _networkRemotePrinterComboBox; public int MaxProcessorCount => Environment.ProcessorCount; @@ -83,6 +85,7 @@ namespace UVtools.WPF.Windows InitializeComponent(); _sendToCustomLocationsGrid = this.FindControl<DataGrid>("SendToCustomLocationsGrid"); + _sendToProcessGrid = this.FindControl<DataGrid>("SendToProcessGrid"); _networkRemotePrinterComboBox = this.FindControl<ComboBox>("NetworkRemotePrinterComboBox"); } @@ -202,6 +205,34 @@ namespace UVtools.WPF.Windows Settings.General.SendToCustomLocations.RemoveRange(_sendToCustomLocationsGrid.SelectedItems.Cast<MappedDevice>()); } + public async void SendToAddProcess() + { + var openFolder = new OpenFileDialog(); + var result = await openFolder.ShowAsync(this); + + if (result is null || result.Length == 0) return; + var file = new MappedProcess(result[0]); + if (Settings.General.SendToProcess.Contains(file)) + { + await this.MessageBoxError("The selected process already exists on the list:\n" + + $"{result}"); + return; + } + + Settings.General.SendToProcess.Add(file); + } + + public async void SendToRemoveProcess() + { + if (_sendToProcessGrid.SelectedItems.Count == 0) return; + + if (await this.MessageBoxQuestion( + $"Are you sure you want to remove the {_sendToProcessGrid.SelectedItems.Count} selected entries?") != + ButtonResult.Yes) return; + + Settings.General.SendToProcess.RemoveRange(_sendToProcessGrid.SelectedItems.Cast<MappedProcess>()); + } + public async void SelectColor(string property) { foreach (var packObject in UserSettings.PackObjects) diff --git a/build/CreateRelease.WPF.ps1 b/build/CreateRelease.WPF.ps1 index 9fd1628..ed1ced5 100644 --- a/build/CreateRelease.WPF.ps1 +++ b/build/CreateRelease.WPF.ps1 @@ -36,7 +36,7 @@ $enableMSI = $true #$buildOnly = 'win-x64' #$buildOnly = 'linux-x64' #$buildOnly = 'osx-x64' -#$enableNugetPublish = $true +$enableNugetPublish = $true # Profilling $stopWatch = New-Object -TypeName System.Diagnostics.Stopwatch $deployStopWatch = New-Object -TypeName System.Diagnostics.Stopwatch |