Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sn4k3/UVtools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiago Conceição <Tiago_caza@hotmail.com>2022-02-16 01:14:52 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2022-02-16 01:14:52 +0300
commit374e590574e6be0c5d5d08f49bc1f638f46d82b5 (patch)
tree930a9fe7ffbf22c45725c188e337b9b6aabb3868
parent554794d0d8408974e45d6dd730adb38acee7434a (diff)
v2.28.1v2.28.1
- (Add) File - Terminal: Inject C# code into UVtools with an interactive terminal - (Improvement) Modifiers: Better increment values for the spin up/down buttons - (Improvement) Tool - Timelapse: Better lift and feeds for virtual layer, also allow to set custom lift speed for that mode - (Fix) Tool - Edit print parameters: Disallow to change PositionZ in layers with an active alternating pattern - (Fix) GCode: When generating layers higher than the next, it will not return to the correct position z
-rw-r--r--CHANGELOG.md8
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs50
-rw-r--r--UVtools.Core/GCode/GCodeBuilder.cs6
-rw-r--r--UVtools.Core/Operations/OperationEditParameters.cs19
-rw-r--r--UVtools.Core/Operations/OperationTimelapse.cs60
-rw-r--r--UVtools.Core/UVtools.Core.csproj2
-rw-r--r--UVtools.WPF/Assets/Icons/terminal-16x16.pngbin0 -> 123 bytes
-rw-r--r--UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs4
-rw-r--r--UVtools.WPF/Controls/Tools/ToolTimelapseControl.axaml38
-rw-r--r--UVtools.WPF/Extensions/WindowExtensions.cs19
-rw-r--r--UVtools.WPF/MainWindow.axaml15
-rw-r--r--UVtools.WPF/MainWindow.axaml.cs11
-rw-r--r--UVtools.WPF/UVtools.WPF.csproj4
-rw-r--r--UVtools.WPF/Windows/TerminalWindow.axaml78
-rw-r--r--UVtools.WPF/Windows/TerminalWindow.axaml.cs200
-rw-r--r--UVtools.WPF/Windows/ToolWindow.axaml.cs9
16 files changed, 439 insertions, 84 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f0e0b26..72c96dd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## 15/02/2022 - v2.28.1
+
+- (Add) File - Terminal: Inject C# code into UVtools with an interactive terminal
+- (Improvement) Modifiers: Better increment values for the spin up/down buttons
+- (Improvement) Tool - Timelapse: Better lift and feeds for virtual layer, also allow to set custom lift speed for that mode
+- (Fix) Tool - Edit print parameters: Disallow to change PositionZ in layers with an active alternating pattern
+- (Fix) GCode: When generating layers higher than the next, it will not return to the correct position z
+
## 13/02/2022 - v2.28.0
- **Core:**
diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs
index 007dbff..ce5ad49 100644
--- a/UVtools.Core/FileFormats/FileFormat.cs
+++ b/UVtools.Core/FileFormats/FileFormat.cs
@@ -147,46 +147,46 @@ namespace UVtools.Core.FileFormats
{
#region Instances
- public static PrintParameterModifier PositionZ { get; } = new ("Position Z", "Absolute Z position", "mm",0, 100000, Layer.HeightPrecision);
- public static PrintParameterModifier BottomLayerCount { get; } = new ("Bottom layers count", "Number of bottom/burn-in layers", "layers",0, ushort.MaxValue, 0);
-
+ public static PrintParameterModifier PositionZ { get; } = new ("Position Z", "Absolute Z position", "mm",0, 100000, 0.01, Layer.HeightPrecision);
+ public static PrintParameterModifier BottomLayerCount { get; } = new ("Bottom layers count", "Number of bottom/burn-in layers", "layers",0, ushort.MaxValue, 1, 0);
+
public static PrintParameterModifier BottomLightOffDelay { get; } = new("Bottom light-off seconds", "Total motor movement time + rest time to wait before cure a new bottom layer", "s");
public static PrintParameterModifier LightOffDelay { get; } = new("Light-off seconds", "Total motor movement time + rest time to wait before cure a new layer", "s");
- public static PrintParameterModifier BottomWaitTimeBeforeCure { get; } = new ("Bottom wait before cure", "Time to wait/rest before cure a new bottom layer\nChitubox: Rest after retract\nLychee: Wait before print", "s", 0, 1000, 2);
- public static PrintParameterModifier WaitTimeBeforeCure { get; } = new ("Wait before cure", "Time to wait/rest before cure a new layer\nChitubox: Rest after retract\nLychee: Wait before print", "s", 0, 1000, 2);
+ public static PrintParameterModifier BottomWaitTimeBeforeCure { get; } = new ("Bottom wait before cure", "Time to wait/rest before cure a new bottom layer\nChitubox: Rest after retract\nLychee: Wait before print", "s");
+ public static PrintParameterModifier WaitTimeBeforeCure { get; } = new ("Wait before cure", "Time to wait/rest before cure a new layer\nChitubox: Rest after retract\nLychee: Wait before print", "s");
- public static PrintParameterModifier BottomExposureTime { get; } = new ("Bottom exposure time", "Bottom layers cure time", "s", 0.1M, 1000, 2);
- public static PrintParameterModifier ExposureTime { get; } = new ("Exposure time", "Layers cure time", "s", 0.1M, 1000, 2);
+ public static PrintParameterModifier BottomExposureTime { get; } = new ("Bottom exposure time", "Bottom layers cure time", "s", 0.1M);
+ public static PrintParameterModifier ExposureTime { get; } = new ("Exposure time", "Layers cure time", "s", 0.1M);
- public static PrintParameterModifier BottomWaitTimeAfterCure { get; } = new("Bottom wait after cure", "Time to wait/rest after cure a new bottom layer\nChitubox: Rest before lift\nLychee: Wait after print", "s", 0, 1000, 2);
- public static PrintParameterModifier WaitTimeAfterCure { get; } = new("Wait after cure", "Time to wait/rest after cure a new bottom layer\nChitubox: Rest before lift\nLychee: Wait after print", "s", 0, 1000, 2);
+ public static PrintParameterModifier BottomWaitTimeAfterCure { get; } = new("Bottom wait after cure", "Time to wait/rest after cure a new bottom layer\nChitubox: Rest before lift\nLychee: Wait after print", "s");
+ public static PrintParameterModifier WaitTimeAfterCure { get; } = new("Wait after cure", "Time to wait/rest after cure a new bottom layer\nChitubox: Rest before lift\nLychee: Wait after print", "s");
public static PrintParameterModifier BottomLiftHeight { get; } = new ("Bottom lift height", "Bottom lift/peel height between layers", "mm", 1);
public static PrintParameterModifier LiftHeight { get; } = new ("Lift height", @"Lift/peel height between layers", "mm", 1);
- public static PrintParameterModifier BottomLiftSpeed { get; } = new ("Bottom lift speed", null, "mm/min", 10, 5000, 2);
- public static PrintParameterModifier LiftSpeed { get; } = new ("Lift speed", null, "mm/min", 10, 5000, 2);
+ public static PrintParameterModifier BottomLiftSpeed { get; } = new ("Bottom lift speed", null, "mm/min", 10, 5000, 5);
+ public static PrintParameterModifier LiftSpeed { get; } = new ("Lift speed", null, "mm/min", 10, 5000, 5);
public static PrintParameterModifier BottomLiftHeight2 { get; } = new("2) Bottom lift height", "Bottom second lift/peel height between layers", "mm");
public static PrintParameterModifier LiftHeight2 { get; } = new("2) Lift height", @"Second lift/peel height between layers", "mm");
- public static PrintParameterModifier BottomLiftSpeed2 { get; } = new("2) Bottom lift speed", null, "mm/min", 10, 5000, 2);
- public static PrintParameterModifier LiftSpeed2 { get; } = new("2) Lift speed", null, "mm/min", 10, 5000, 2);
+ public static PrintParameterModifier BottomLiftSpeed2 { get; } = new("2) Bottom lift speed", null, "mm/min", 10, 5000, 5);
+ public static PrintParameterModifier LiftSpeed2 { get; } = new("2) Lift speed", null, "mm/min", 10, 5000, 5);
- public static PrintParameterModifier BottomWaitTimeAfterLift { get; } = new("Bottom wait after lift", "Time to wait/rest after a lift/peel sequence at bottom layers\nChitubox: Rest after lift\nLychee: Wait after lift", "s", 0, 1000, 2);
- public static PrintParameterModifier WaitTimeAfterLift { get; } = new("Wait after lift", "Time to wait/rest after a lift/peel sequence at layers\nChitubox: Rest after lift\nLychee: Wait after lift", "s", 0, 1000, 2);
+ public static PrintParameterModifier BottomWaitTimeAfterLift { get; } = new("Bottom wait after lift", "Time to wait/rest after a lift/peel sequence at bottom layers\nChitubox: Rest after lift\nLychee: Wait after lift", "s");
+ public static PrintParameterModifier WaitTimeAfterLift { get; } = new("Wait after lift", "Time to wait/rest after a lift/peel sequence at layers\nChitubox: Rest after lift\nLychee: Wait after lift", "s");
- public static PrintParameterModifier BottomRetractSpeed { get; } = new ("Bottom retract speed", "Bottom down speed from lift height to next layer cure position", "mm/min", 10, 5000, 2);
- public static PrintParameterModifier RetractSpeed { get; } = new ("Retract speed", "Down speed from lift height to next layer cure position", "mm/min", 10, 5000, 2);
+ public static PrintParameterModifier BottomRetractSpeed { get; } = new ("Bottom retract speed", "Bottom down speed from lift height to next layer cure position", "mm/min", 10, 5000, 5);
+ public static PrintParameterModifier RetractSpeed { get; } = new ("Retract speed", "Down speed from lift height to next layer cure position", "mm/min", 10, 5000, 5);
public static PrintParameterModifier BottomRetractHeight2 { get; } = new("2) Bottom retract height", null, "mm");
public static PrintParameterModifier RetractHeight2 { get; } = new("2) Retract height", null, "mm");
- public static PrintParameterModifier BottomRetractSpeed2 { get; } = new("2) Bottom retract speed", null, "mm/min", 10, 5000, 2);
- public static PrintParameterModifier RetractSpeed2 { get; } = new("2) Retract speed", null, "mm/min", 10, 5000, 2);
+ public static PrintParameterModifier BottomRetractSpeed2 { get; } = new("2) Bottom retract speed", null, "mm/min", 10, 5000, 5);
+ public static PrintParameterModifier RetractSpeed2 { get; } = new("2) Retract speed", null, "mm/min", 10, 5000, 5);
- public static PrintParameterModifier BottomLightPWM { get; } = new ("Bottom light PWM", "UV LED power for bottom layers", "☀", 1, byte.MaxValue, 0);
- public static PrintParameterModifier LightPWM { get; } = new ("Light PWM", "UV LED power for layers", "☀", 1, byte.MaxValue, 0);
+ public static PrintParameterModifier BottomLightPWM { get; } = new ("Bottom light PWM", "UV LED power for bottom layers", "☀", 1, byte.MaxValue, 5, 0);
+ public static PrintParameterModifier LightPWM { get; } = new ("Light PWM", "UV LED power for layers", "☀", 1, byte.MaxValue, 5, 0);
/*public static PrintParameterModifier[] Parameters = {
BottomLayerCount,
@@ -241,6 +241,11 @@ namespace UVtools.Core.FileFormats
public decimal Maximum { get; }
/// <summary>
+ /// Gets the incrementing value for the dropdown
+ /// </summary>
+ public double Increment { get; set; } = 1;
+
+ /// <summary>
/// Gets the number of decimal plates
/// </summary>
public byte DecimalPlates { get; }
@@ -268,13 +273,14 @@ namespace UVtools.Core.FileFormats
#endregion
#region Constructor
- public PrintParameterModifier(string name, string description = null, string valueUnit = null, decimal minimum = 0, decimal maximum = 1000, byte decimalPlates = 2)
+ public PrintParameterModifier(string name, string description = null, string valueUnit = null, decimal minimum = 0, decimal maximum = 1000, double increment = 0.5, byte decimalPlates = 2)
{
Name = name;
Description = description ?? $"Modify '{name}'";
ValueUnit = valueUnit ?? string.Empty;
Minimum = minimum;
Maximum = maximum;
+ Increment = decimalPlates == 0 ? Math.Max(1, increment) : increment;
DecimalPlates = decimalPlates;
}
#endregion
diff --git a/UVtools.Core/GCode/GCodeBuilder.cs b/UVtools.Core/GCode/GCodeBuilder.cs
index 6081be0..4ee83cc 100644
--- a/UVtools.Core/GCode/GCodeBuilder.cs
+++ b/UVtools.Core/GCode/GCodeBuilder.cs
@@ -673,15 +673,15 @@ namespace UVtools.Core.GCode
{
AppendLiftMoveGx(lifts, retracts, waitAfterLift, 0, layer);
}
- else if (lastZPosition < layer.PositionZ) // Ensure Z is on correct position
+ else if (lastZPosition != layer.PositionZ) // Ensure Z is on correct position
{
switch (GCodePositioningType)
{
case GCodePositioningTypes.Absolute:
- AppendMoveGx(layer.PositionZ, liftSpeed);
+ AppendMoveGx(layer.PositionZ, lastZPosition < layer.PositionZ ? Math.Max(liftSpeed, liftSpeed2) : Math.Max(retractSpeed, retractSpeed2));
break;
case GCodePositioningTypes.Partial:
- AppendMoveGx(Layer.RoundHeight(layer.PositionZ - lastZPosition), liftSpeed);
+ AppendMoveGx(Layer.RoundHeight(layer.PositionZ - lastZPosition), lastZPosition < layer.PositionZ ? Math.Max(liftSpeed, liftSpeed2) : Math.Max(retractSpeed, retractSpeed2));
break;
}
diff --git a/UVtools.Core/Operations/OperationEditParameters.cs b/UVtools.Core/Operations/OperationEditParameters.cs
index 7e6e8f3..99d1b8a 100644
--- a/UVtools.Core/Operations/OperationEditParameters.cs
+++ b/UVtools.Core/Operations/OperationEditParameters.cs
@@ -22,7 +22,7 @@ namespace UVtools.Core.Operations
private bool _propagateModificationsToLayers = true;
private bool _perLayerOverride;
private uint _setNumberOfLayer = 1;
- private uint _skipNumberOfLayer = 0;
+ private uint _skipNumberOfLayer;
#endregion
@@ -92,6 +92,15 @@ namespace UVtools.Core.Operations
sb.AppendLine("Nothing changed\nDo some changes or cancel the operation.");
}
+ if (Modifiers.Contains(FileFormat.PrintParameterModifier.PositionZ)
+ && FileFormat.PrintParameterModifier.PositionZ.HasChanged
+ && _skipNumberOfLayer > 0
+ && LayerRangeCount > 1
+ && _setNumberOfLayer + _skipNumberOfLayer < LayerRangeCount)
+ {
+ sb.AppendLine("Can not change the PositionZ in layers with an active alternating pattern.");
+ }
+
return sb.ToString();
}
@@ -156,18 +165,18 @@ namespace UVtools.Core.Operations
protected override bool ExecuteInternally(OperationProgress progress)
{
- if (PerLayerOverride)
+ if (_perLayerOverride)
{
uint setLayers = 0;
for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
{
SlicerFile[layerIndex].SetValuesFromPrintParametersModifiers(Modifiers);
- if (SkipNumberOfLayer <= 0) continue;
+ if (_skipNumberOfLayer == 0) continue;
setLayers++;
- if (setLayers >= SetNumberOfLayer)
+ if (setLayers >= _setNumberOfLayer)
{
setLayers = 0;
- layerIndex += SkipNumberOfLayer;
+ layerIndex += _skipNumberOfLayer;
}
}
diff --git a/UVtools.Core/Operations/OperationTimelapse.cs b/UVtools.Core/Operations/OperationTimelapse.cs
index 084ea57..075bee4 100644
--- a/UVtools.Core/Operations/OperationTimelapse.cs
+++ b/UVtools.Core/Operations/OperationTimelapse.cs
@@ -105,11 +105,6 @@ namespace UVtools.Core.Operations
#region Properties
- /// <summary>
- /// Gets the minimum possible
- /// </summary>
- public float MinimumPositionZ => Layer.RoundHeight(SlicerFile.PrintHeight + SlicerFile.LayerHeight);
-
public TimelapseRaiseMode RaiseMode
{
get => _raiseMode;
@@ -178,6 +173,8 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _useCustomLift, value);
}
+ public bool CanUseCustomLift => _useCustomLift && SlicerFile.CanUseLayerLiftHeight;
+
public decimal SlowLiftHeight
{
get => _slowLiftHeight;
@@ -307,7 +304,7 @@ namespace UVtools.Core.Operations
switch (_raiseMode)
{
case TimelapseRaiseMode.LiftHeight:
- if (_useCustomLift)
+ if (CanUseCustomLift)
{
layer.LiftSpeed = (float)_liftSpeed;
layer.RetractSpeed = (float)_retractSpeed;
@@ -333,7 +330,7 @@ namespace UVtools.Core.Operations
}
}
- if (SlicerFile.CanUseLayerLiftHeight2 && (layer.LiftHeight2 > 0 || _useCustomLift && _slowLiftHeight > 0)) // TSMC
+ if (SlicerFile.CanUseLayerLiftHeight2 && (layer.LiftHeight2 > 0 || CanUseCustomLift && _slowLiftHeight > 0)) // TSMC
{
layer.LiftHeight2 = Math.Max(0, (float)_raisePositionZ - layer.PositionZ - layer.LiftHeight);
}
@@ -375,37 +372,52 @@ namespace UVtools.Core.Operations
RetractHeight2 = 0
};
- layer.SetNoDelays();
-
- /*if (_useCustomLift)
+ if (CanUseCustomLift)
{
- layer.LiftSpeed = (float) _liftSpeed;
- layer.RetractSpeed = (float) _retractSpeed;
+ layer.LiftSpeed = (float)_liftSpeed;
+ layer.RetractSpeed = (float)_retractSpeed;
+
+ /*if (SlicerFile.CanUseLayerLiftHeight2)
+ {
+ layer.LiftHeight = (float)_slowLiftHeight;
+ }*/
if (SlicerFile.CanUseLayerLiftSpeed2)
{
- layer.LiftSpeed2 = (float) _liftSpeed2;
+ layer.LiftSpeed2 = (float)_liftSpeed2;
}
if (SlicerFile.CanUseLayerRetractSpeed2)
{
- layer.RetractSpeed2 = (float) _retractSpeed2;
+ layer.RetractSpeed2 = (float)_retractSpeed2;
}
- }*/
+ }
+
+ layer.SetNoDelays();
var layers = SlicerFile.ToList();
for (int i = 0; i < virtualLayers.Count; i++)
{
- /*var newLayer = layer.Clone();
- if (!_useCustomLift)
+ int insertIndex = (int)virtualLayers[i];
+ SlicerFile[insertIndex].LiftHeightTotal = SlicerFile.SupportsGCode ? 0 : 0.1f;
+
+ if (CanUseCustomLift)
{
- var intersectLayer = Math.Clamp(virtualLayers[i] + i, 0, SlicerFile.LastLayerIndex);
- SlicerFile[intersectLayer].CopyLiftTo(newLayer);
- // This layer does not require a lift procedure
- newLayer.LiftHeightTotal = SlicerFile.SupportsGCode ? 0 : 0.1f;
- newLayer.RetractHeight2 = 0;
- }*/
- layers.Insert((int)(virtualLayers[i] + i), layer.Clone());
+ SlicerFile[insertIndex].LiftSpeed = (float)_liftSpeed;
+ SlicerFile[insertIndex].RetractSpeed = (float)_retractSpeed;
+
+ if (SlicerFile.CanUseLayerLiftSpeed2)
+ {
+ SlicerFile[insertIndex].LiftSpeed2 = (float)_retractSpeed2;
+ }
+
+ if (SlicerFile.CanUseLayerRetractSpeed2)
+ {
+ SlicerFile[insertIndex].RetractSpeed2 = (float)_retractSpeed2;
+ }
+ }
+
+ layers.Insert(insertIndex + i, layer.Clone());
}
SlicerFile.SuppressRebuildPropertiesWork(() => SlicerFile.LayerManager.Layers = layers.ToArray());
}
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index b020595..b0724ec 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.28.0</Version>
+ <Version>2.28.1</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
diff --git a/UVtools.WPF/Assets/Icons/terminal-16x16.png b/UVtools.WPF/Assets/Icons/terminal-16x16.png
new file mode 100644
index 0000000..98f041d
--- /dev/null
+++ b/UVtools.WPF/Assets/Icons/terminal-16x16.png
Binary files differ
diff --git a/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs
index 475edb0..69447da 100644
--- a/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolEditParametersControl.axaml.cs
@@ -62,7 +62,7 @@ namespace UVtools.WPF.Controls.Tools
HorizontalAlignment = HorizontalAlignment.Stretch,
Minimum = (double) modifier.Minimum,
Maximum = (double) modifier.Maximum,
- Increment = modifier.DecimalPlates == 0 ? 1 : 0.5,
+ Increment = modifier.Increment,
Value = (double)modifier.NewValue,
Tag = this,
//Width = 100,
@@ -70,7 +70,7 @@ namespace UVtools.WPF.Controls.Tools
};
if (modifier.DecimalPlates > 0)
{
- NewValue.FormatString = "F02";
+ NewValue.FormatString = $"F{modifier.DecimalPlates}";
}
Unit = new TextBlock
diff --git a/UVtools.WPF/Controls/Tools/ToolTimelapseControl.axaml b/UVtools.WPF/Controls/Tools/ToolTimelapseControl.axaml
index edabb6f..57d9702 100644
--- a/UVtools.WPF/Controls/Tools/ToolTimelapseControl.axaml
+++ b/UVtools.WPF/Controls/Tools/ToolTimelapseControl.axaml
@@ -151,7 +151,6 @@
IsChecked="{Binding Operation.UseCustomLift}">
<CheckBox.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
- <Binding Path="Operation.IsLiftHeightMode"/>
<Binding Path="SlicerFile.CanUseLayerLiftHeight"/>
</MultiBinding>
</CheckBox.IsVisible>
@@ -162,7 +161,6 @@
ColumnDefinitions="Auto,10,210,5,Auto,5,210">
<Grid.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.And}">
- <Binding Path="Operation.IsLiftHeightMode"/>
<Binding Path="Operation.UseCustomLift"/>
<Binding Path="SlicerFile.CanUseLayerLiftHeight"/>
</MultiBinding>
@@ -172,6 +170,7 @@
VerticalAlignment="Center"
ToolTip.Tip="The slow first lift sequence (TSMC).
&#x0a;Use a low value or 0 to disable."
+ IsVisible="{Binding !Operation.IsVirtualLayerMode}"
Text="Slow lift height:"/>
<NumericUpDown Grid.Row="0" Grid.Column="2"
@@ -179,15 +178,26 @@
Minimum="0"
Maximum="20"
Increment="1"
- IsVisible="{Binding SlicerFile.CanUseLayerLiftHeight2}"
Value="{Binding Operation.SlowLiftHeight}">
+ <NumericUpDown.IsVisible>
+ <MultiBinding Converter="{x:Static BoolConverters.And}">
+ <Binding Path="SlicerFile.CanUseLayerLiftHeight2"/>
+ <Binding Path="!Operation.IsVirtualLayerMode"/>
+ </MultiBinding>
+ </NumericUpDown.IsVisible>
</NumericUpDown>
<TextBlock Grid.Row="0" Grid.Column="2"
VerticalAlignment="Center"
ToolTip.Tip="(Not supported by your printer / file format)"
- IsVisible="{Binding !SlicerFile.CanUseLayerLiftHeight2}"
- Text="(Not supported)"/>
+ Text="(Not supported)">
+ <TextBlock.IsVisible>
+ <MultiBinding Converter="{x:Static BoolConverters.And}">
+ <Binding Path="!SlicerFile.CanUseLayerLiftHeight2"/>
+ <Binding Path="!Operation.IsVirtualLayerMode"/>
+ </MultiBinding>
+ </TextBlock.IsVisible>
+ </TextBlock>
<TextBlock Grid.Row="2" Grid.Column="0"
VerticalAlignment="Center"
@@ -225,6 +235,7 @@
VerticalAlignment="Center"
ToolTip.Tip="The slow last retract sequence (TSMC).
&#x0a;Use a low value or 0 to disable."
+ IsVisible="{Binding !Operation.IsVirtualLayerMode}"
Text="Slow retract height:"/>
<NumericUpDown Grid.Row="4" Grid.Column="2"
@@ -232,15 +243,26 @@
Minimum="0"
Maximum="20"
Increment="1"
- IsVisible="{Binding SlicerFile.CanUseLayerRetractHeight2}"
Value="{Binding Operation.SlowRetractHeight}">
+ <NumericUpDown.IsVisible>
+ <MultiBinding Converter="{x:Static BoolConverters.And}">
+ <Binding Path="SlicerFile.CanUseLayerRetractHeight2"/>
+ <Binding Path="!Operation.IsVirtualLayerMode"/>
+ </MultiBinding>
+ </NumericUpDown.IsVisible>
</NumericUpDown>
<TextBlock Grid.Row="4" Grid.Column="2"
VerticalAlignment="Center"
ToolTip.Tip="(Not supported by your printer / file format)"
- IsVisible="{Binding !SlicerFile.CanUseLayerRetractHeight2}"
- Text="(Not supported)"/>
+ Text="(Not supported)">
+ <TextBlock.IsVisible>
+ <MultiBinding Converter="{x:Static BoolConverters.And}">
+ <Binding Path="!SlicerFile.CanUseLayerRetractHeight2"/>
+ <Binding Path="!Operation.IsVirtualLayerMode"/>
+ </MultiBinding>
+ </TextBlock.IsVisible>
+ </TextBlock>
<TextBlock Grid.Row="6" Grid.Column="0"
diff --git a/UVtools.WPF/Extensions/WindowExtensions.cs b/UVtools.WPF/Extensions/WindowExtensions.cs
index c6bb5c0..70915fd 100644
--- a/UVtools.WPF/Extensions/WindowExtensions.cs
+++ b/UVtools.WPF/Extensions/WindowExtensions.cs
@@ -20,7 +20,7 @@ namespace UVtools.WPF.Extensions
public static class WindowExtensions
{
public static async Task<ButtonResult> MessageBoxGeneric(this Window window, string message, string title = null,
- ButtonEnum buttons = ButtonEnum.Ok, Icon icon = Icon.None, bool topMost = false, WindowStartupLocation location = WindowStartupLocation.CenterOwner, Style style = Style.None)
+ ButtonEnum buttons = ButtonEnum.Ok, Icon icon = Icon.None, bool topMost = false, WindowStartupLocation location = WindowStartupLocation.CenterOwner)
{
var messageBoxStandardWindow = MessageBox.Avalonia.MessageBoxManager.GetMessageBoxStandardWindow(
new MessageBoxStandardParams
@@ -29,7 +29,6 @@ namespace UVtools.WPF.Extensions
ContentTitle = title ?? window.Title,
ContentMessage = message,
Icon = icon,
- Style = style,
WindowIcon = new WindowIcon(App.GetAsset("/Assets/Icons/UVtools.ico")),
WindowStartupLocation = location,
CanResize = UserSettings.Instance.General.WindowsCanResize,
@@ -42,17 +41,17 @@ namespace UVtools.WPF.Extensions
return await messageBoxStandardWindow.ShowDialog(window);
}
- public static async Task<ButtonResult> MessageBoxInfo(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool topMost = false, Style style = Style.None)
- => await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Information", buttons, Icon.Info, topMost, WindowStartupLocation.CenterOwner, style);
+ public static async Task<ButtonResult> MessageBoxInfo(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool topMost = false)
+ => await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Information", buttons, Icon.Info, topMost, WindowStartupLocation.CenterOwner);
- public static async Task<ButtonResult> MessageBoxError(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool topMost = false, Style style = Style.None)
- => await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Error", buttons, Icon.Error, topMost, WindowStartupLocation.CenterOwner, style);
+ public static async Task<ButtonResult> MessageBoxError(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool topMost = false)
+ => await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Error", buttons, Icon.Error, topMost, WindowStartupLocation.CenterOwner);
- public static async Task<ButtonResult> MessageBoxQuestion(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.YesNo, bool topMost = false, Style style = Style.None)
- => await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Question", buttons, Icon.Setting, topMost, WindowStartupLocation.CenterOwner, style);
+ public static async Task<ButtonResult> MessageBoxQuestion(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.YesNo, bool topMost = false)
+ => await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Question", buttons, Icon.Setting, topMost, WindowStartupLocation.CenterOwner);
- public static async Task<ButtonResult> MessageBoxWaring(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool topMost = false, Style style = Style.None)
- => await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Question", buttons, Icon.Warning, topMost, WindowStartupLocation.CenterOwner, style);
+ public static async Task<ButtonResult> MessageBoxWaring(this Window window, string message, string title = null, ButtonEnum buttons = ButtonEnum.Ok, bool topMost = false)
+ => await window.MessageBoxGeneric(message, title ?? $"{window.Title} - Question", buttons, Icon.Warning, topMost, WindowStartupLocation.CenterOwner);
public static void ShowDialogSync(this Window window, Window parent = null)
diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml
index d141d39..9fff996 100644
--- a/UVtools.WPF/MainWindow.axaml
+++ b/UVtools.WPF/MainWindow.axaml
@@ -127,8 +127,19 @@
<Image Source="\Assets\Icons\extract-object-16x16.png"/>
</MenuItem.Icon>
</MenuItem>
-
- <MenuItem
+
+ <MenuItem Name="MainMenu.File.Terminal"
+ HotKey="Ctrl+Shift+T" InputGesture="Ctrl+Shift+T"
+ Header="_Terminal"
+ Command="{Binding OpenTerminal}"
+ IsEnabled="{Binding IsFileLoaded}">
+ <MenuItem.Icon>
+ <Image Source="\Assets\Icons\terminal-16x16.png"/>
+ </MenuItem.Icon>
+ </MenuItem>
+
+
+ <MenuItem
Name="MainMenu.File.Convert"
Header="_Convert to"
IsEnabled="{Binding IsFileLoaded}"
diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs
index 92d60f3..c5e7297 100644
--- a/UVtools.WPF/MainWindow.axaml.cs
+++ b/UVtools.WPF/MainWindow.axaml.cs
@@ -617,7 +617,7 @@ namespace UVtools.WPF
AddHandler(DragDrop.DropEvent, (sender, e) =>
{
- ProcessFiles(e.Data.GetFileNames().ToArray());
+ ProcessFiles(e.Data.GetFileNames()?.ToArray());
});
_menuFileSendTo = this.FindControl<MenuItem>("MainMenu.File.SendTo");
@@ -1823,8 +1823,6 @@ namespace UVtools.WPF
VisibleThumbnailIndex = 1;
- RefreshProperties();
-
UpdateTitle();
if (mat is not null)
@@ -1904,7 +1902,7 @@ namespace UVtools.WPF
$"Ratio: {xRatio}:{yRatio}\n",
"Incorrect image ratio detected");
}
-
+ RefreshProperties();
ResetDataContext();
ForceUpdateActualLayer(actualLayer.Clamp(actualLayer, SliderMaximumValue));
@@ -2234,6 +2232,11 @@ namespace UVtools.WPF
}
+ public void OpenTerminal()
+ {
+ new TerminalWindow().Show(this);
+ }
+
#region Operations
public async Task<Operation> ShowRunOperation(Operation loadOperation) =>
diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj
index 013498f..052eca7 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.28.0</Version>
+ <Version>2.28.1</Version>
<Platforms>AnyCPU;x64</Platforms>
<PackageIcon>UVtools.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
@@ -44,7 +44,7 @@
<PackageReference Include="Avalonia.Desktop" Version="0.10.12" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.12" />
<PackageReference Include="Emgu.CV.runtime.windows" Version="4.5.5.4823" />
- <PackageReference Include="MessageBox.Avalonia" Version="1.7.1" />
+ <PackageReference Include="MessageBox.Avalonia" Version="1.8.1-night" />
<PackageReference Include="ThemeEditor.Controls.ColorPicker" Version="0.10.12" />
</ItemGroup>
<ItemGroup>
diff --git a/UVtools.WPF/Windows/TerminalWindow.axaml b/UVtools.WPF/Windows/TerminalWindow.axaml
new file mode 100644
index 0000000..fe88998
--- /dev/null
+++ b/UVtools.WPF/Windows/TerminalWindow.axaml
@@ -0,0 +1,78 @@
+<uc:WindowEx xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:uc="clr-namespace:UVtools.WPF.Controls"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="500"
+ MinWidth="500"
+ MinHeight="300"
+ Width="800"
+ Height="500"
+ Padding="10"
+ WindowStartupLocation="CenterOwner"
+ DragDrop.AllowDrop="True"
+ Icon="/Assets/Icons/UVtools.ico"
+ x:Class="UVtools.WPF.Windows.TerminalWindow"
+ Title="UVtools interactive terminal">
+ <Grid RowDefinitions="4*,5,*,5,Auto">
+ <TextBox Grid.Row="0"
+ Name="TerminalTextBox"
+ AcceptsReturn="True"
+ IsReadOnly="True"
+ Watermark="Terminal"
+ UseFloatingWatermark="True"
+ Text="{Binding TerminalText}"/>
+
+ <GridSplitter Grid.Row="1"
+ ResizeDirection="Rows"
+ ResizeBehavior="PreviousAndNext"/>
+
+ <TextBox Grid.Row="2"
+ AcceptsReturn="{Binding MultiLine}"
+ Watermark="> Type in the command or text to send
+&#x0a;Alt + enter: Shortcut to send the command"
+ Text="{Binding CommandText}"/>
+
+ <WrapPanel Grid.Row="4" Orientation="Horizontal" HorizontalAlignment="Right">
+ <!--
+ <ToggleSwitch VerticalAlignment="Center"
+ IsChecked="{Binding MultiLine}"
+ OnContent="Multi line"
+ OffContent="Single line"/>
+-->
+ <ToggleButton Margin="0,0,0,0"
+ VerticalAlignment="Center"
+ IsChecked="{Binding Verbose}"
+ ToolTip.Tip="Sent command appears on the terminal text"
+ Content="Verbose"/>
+
+ <ToggleButton Margin="2,0,0,0"
+ VerticalAlignment="Center"
+ IsChecked="{Binding ClearCommandAfterSend}"
+ ToolTip.Tip="Clears the sent command on the input box"
+ Content="Clear"/>
+
+ <ToggleButton Margin="2,0,0,0"
+ VerticalAlignment="Center"
+ IsChecked="{Binding AutoScroll}"
+ Content="Auto scroll"/>
+
+
+ <Button Margin="15,0,0,0"
+ Content="Clear"
+ VerticalAlignment="Center"
+ Command="{Binding Clear}"
+ ToolTip.Tip="Clears the terminal text (cls)
+&#x0a;Alt + delete"
+ HotKey="Alt+Delete"/>
+ <Button Margin="5,0,0,0"
+ Content="Send"
+ Padding="40,6"
+ VerticalAlignment="Center"
+ Command="{Binding SendCommand}"
+ IsDefault="True"
+ HotKey="Alt+Enter"/>
+ </WrapPanel>
+
+ </Grid>
+</uc:WindowEx>
diff --git a/UVtools.WPF/Windows/TerminalWindow.axaml.cs b/UVtools.WPF/Windows/TerminalWindow.axaml.cs
new file mode 100644
index 0000000..8e937c6
--- /dev/null
+++ b/UVtools.WPF/Windows/TerminalWindow.axaml.cs
@@ -0,0 +1,200 @@
+/*
+ * 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.IO;
+using System.Text;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Markup.Xaml;
+using Microsoft.CodeAnalysis.CSharp.Scripting;
+using Microsoft.CodeAnalysis.Scripting;
+using UVtools.Core;
+using UVtools.WPF.Controls;
+
+namespace UVtools.WPF.Windows
+{
+ public partial class TerminalWindow : WindowEx
+ {
+ private static readonly string DefaultTerminalText = $"> Welcome to {About.Software} interactive terminal.\n" +
+ "> Type in some commands in C# language to inject code.\n" +
+ "> Example 1: SlicerFile.FirstLayer\n" +
+ "> Example 2: SlicerFile.ExposureTime = 3\n\n";
+
+ private string _terminalText = DefaultTerminalText;
+ private string _commandText = string.Empty;
+
+ private bool _multiLine = true;
+ private bool _autoScroll = true;
+ private bool _verbose;
+ private bool _clearCommandAfterSend = true;
+
+ private readonly TextBox _terminalTextBox;
+ public ScriptState _scriptState;
+
+ #region Properties
+
+ public string TerminalText
+ {
+ get => _terminalText;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _terminalText, value)) return;
+ if(_autoScroll) _terminalTextBox.CaretIndex = _terminalText.Length - 1;
+ }
+ }
+
+ public string CommandText
+ {
+ get => _commandText;
+ set => RaiseAndSetIfChanged(ref _commandText, value ?? string.Empty);
+ }
+
+ public bool MultiLine
+ {
+ get => _multiLine;
+ set => RaiseAndSetIfChanged(ref _multiLine, value);
+ }
+
+ public bool AutoScroll
+ {
+ get => _autoScroll;
+ set => RaiseAndSetIfChanged(ref _autoScroll, value);
+ }
+
+ public bool Verbose
+ {
+ get => _verbose;
+ set => RaiseAndSetIfChanged(ref _verbose, value);
+ }
+
+ public bool ClearCommandAfterSend
+ {
+ get => _clearCommandAfterSend;
+ set => RaiseAndSetIfChanged(ref _clearCommandAfterSend, value);
+ }
+
+ #endregion
+
+ public TerminalWindow()
+ {
+ InitializeComponent();
+#if DEBUG
+ this.AttachDevTools();
+#endif
+
+ _terminalTextBox = this.FindControl<TextBox>("TerminalTextBox");
+ AddHandler(DragDrop.DropEvent, (sender, e) =>
+ {
+ var text = e.Data.GetText();
+ if (text is not null)
+ {
+ CommandText = text;
+ return;
+ }
+
+ var fileNames = e.Data.GetFileNames();
+ if (fileNames is not null)
+ {
+ var sb = new StringBuilder();
+ foreach (var fileName in fileNames)
+ {
+ try
+ {
+ if (!File.Exists(fileName)) continue;
+ var fi = new FileInfo(fileName);
+ if(fi.Length > 5000000) continue; // 5Mb only!
+ sb.AppendLine(File.ReadAllText(fi.FullName));
+ }
+ catch (Exception exception)
+ {
+ Console.WriteLine(exception);
+ }
+
+ }
+
+ CommandText = sb.ToString();
+ }
+ });
+
+ DataContext = this;
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public void Clear()
+ {
+ TerminalText = DefaultTerminalText;
+ }
+
+ public async void SendCommand()
+ {
+ if (string.IsNullOrWhiteSpace(_commandText))
+ {
+ TerminalText += '\n';
+ return;
+ }
+
+ var output = new StringBuilder(_terminalText);
+ if (_verbose) output.AppendLine(_commandText);
+
+ try
+ {
+ if (_scriptState is null)
+ {
+ _scriptState = CSharpScript.RunAsync(_commandText,
+ ScriptOptions.Default
+ .AddReferences(typeof(About).Assembly)
+ .AddImports(
+ "System",
+ "System.Collections.Generic",
+ "System.Math",
+ "System.IO",
+ "System.Linq",
+ "System.Threading",
+ "System.Threading.Tasks",
+ "UVtools.Core",
+ "UVtools.Core.Extensions",
+ "UVtools.Core.FileFormats",
+ "UVtools.Core.Layers",
+ "UVtools.Core.Objects",
+ "UVtools.Core.Operations")
+ .WithAllowUnsafe(true), this).Result;
+ }
+ else
+ {
+ _scriptState = await _scriptState.ContinueWithAsync(_commandText);
+ }
+
+ if (_scriptState.ReturnValue is not null)
+ {
+ output.AppendLine(_scriptState.ReturnValue.ToString());
+ }
+ else if (_scriptState.Exception is not null)
+ {
+ output.AppendLine(_scriptState.Exception.ToString());
+ }
+ else if(!_verbose)
+ {
+ output.AppendLine(_commandText);
+ }
+ }
+ catch (Exception e)
+ {
+ output.AppendLine(e.Message);
+ }
+
+ TerminalText = output.ToString();
+
+ if (_clearCommandAfterSend) CommandText = string.Empty;
+ }
+ }
+}
diff --git a/UVtools.WPF/Windows/ToolWindow.axaml.cs b/UVtools.WPF/Windows/ToolWindow.axaml.cs
index 43d13cd..a3543d6 100644
--- a/UVtools.WPF/Windows/ToolWindow.axaml.cs
+++ b/UVtools.WPF/Windows/ToolWindow.axaml.cs
@@ -1,4 +1,11 @@
-using System;
+/*
+ * 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.Collections.ObjectModel;
using System.Drawing;
using Avalonia;