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>2020-09-23 01:44:35 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2020-09-23 01:44:35 +0300
commit2f848af71837bfe36b35040b8847d456b778d84a (patch)
treef1d9c39efc48964e2b6ce67644aa1228ebf6da4e
parent732d27e647b51a65c2736320d4f0ee590acb0d12 (diff)
v0.8.2.4v0.8.2.4
* (Add) Layer Importer: Option to merge images * (Improvement) Layer difference computation time, faster render
-rw-r--r--CHANGELOG.md5
-rw-r--r--UVtools.Core/FileFormats/FileFormat.cs4
-rw-r--r--UVtools.Core/FileFormats/IFileFormat.cs5
-rw-r--r--UVtools.Core/Layer/LayerManager.cs10
-rw-r--r--UVtools.Core/Operations/OperationLayerImport.cs1
-rw-r--r--UVtools.Core/UVtools.Core.csproj6
-rw-r--r--UVtools.GUI/Controls/Tools/CtrlToolLayerImport.Designer.cs18
-rw-r--r--UVtools.GUI/Controls/Tools/CtrlToolLayerImport.cs5
-rw-r--r--UVtools.GUI/FrmMain.cs101
-rw-r--r--UVtools.GUI/Properties/AssemblyInfo.cs4
-rw-r--r--UVtools.GUI/UVtools.GUI.csproj4
-rw-r--r--UVtools.WPF/MainWindow.axaml144
-rw-r--r--UVtools.WPF/MainWindow.axaml.cs83
-rw-r--r--UVtools.WPF/Structures/SlicerProperty.cs41
14 files changed, 331 insertions, 100 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a729c1f..f431d41 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog
+## 22/09/2020 - v0.8.2.4
+
+* (Add) Layer Importer: Option to merge images
+* (Improvement) Layer difference computation time, faster render
+
## 19/09/2020 - v0.8.2.3
* (Add) Tooltip for next and previous layer buttons with associated shortcut (#61)
diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs
index 7c72f15..3f245f2 100644
--- a/UVtools.Core/FileFormats/FileFormat.cs
+++ b/UVtools.Core/FileFormats/FileFormat.cs
@@ -354,7 +354,9 @@ namespace UVtools.Core.FileFormats
public abstract float PrintTime { get; }
-
+
+ public float PrintTimeHours => (float) Math.Round(PrintTime / 3600, 2);
+
public abstract float UsedMaterial { get; }
public abstract float MaterialCost { get; }
diff --git a/UVtools.Core/FileFormats/IFileFormat.cs b/UVtools.Core/FileFormats/IFileFormat.cs
index e166b55..3b77858 100644
--- a/UVtools.Core/FileFormats/IFileFormat.cs
+++ b/UVtools.Core/FileFormats/IFileFormat.cs
@@ -186,6 +186,11 @@ namespace UVtools.Core.FileFormats
float PrintTime { get; }
/// <summary>
+ /// Gets the estimate print time in hours
+ /// </summary>
+ float PrintTimeHours { get; }
+
+ /// <summary>
/// Gets the estimate used material in ml
/// </summary>
float UsedMaterial { get; }
diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs
index ad3e149..183a333 100644
--- a/UVtools.Core/Layer/LayerManager.cs
+++ b/UVtools.Core/Layer/LayerManager.cs
@@ -1343,6 +1343,16 @@ namespace UVtools.Core
{
var mat = CvInvoke.Imread(operation.Files[i], ImreadModes.Grayscale);
uint layerIndex = (uint) (startIndex + i);
+ if (operation.MergeImages)
+ {
+ if (!(this[layerIndex] is null))
+ {
+ using (var oldMat = this[layerIndex].LayerMat)
+ {
+ CvInvoke.Add(oldMat, mat, mat);
+ }
+ }
+ }
this[layerIndex] = new Layer(layerIndex, mat);
lock (progress.Mutex)
diff --git a/UVtools.Core/Operations/OperationLayerImport.cs b/UVtools.Core/Operations/OperationLayerImport.cs
index 89e3159..b7c8502 100644
--- a/UVtools.Core/Operations/OperationLayerImport.cs
+++ b/UVtools.Core/Operations/OperationLayerImport.cs
@@ -80,6 +80,7 @@ namespace UVtools.Core.Operations
public bool ReplaceStartLayer { get; set; }
public bool ReplaceSubsequentLayers { get; set; }
public bool DiscardRemainingLayers { get; set; }
+ public bool MergeImages { get; set; }
public List<string> Files { get; } = new List<string>();
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index 9d1d0f1..df16c45 100644
--- a/UVtools.Core/UVtools.Core.csproj
+++ b/UVtools.Core/UVtools.Core.csproj
@@ -10,12 +10,12 @@
<RepositoryUrl>https://github.com/sn4k3/UVtools</RepositoryUrl>
<PackageProjectUrl>https://github.com/sn4k3/UVtools</PackageProjectUrl>
<Description>MSLA/DLP, file analysis, repair, conversion and manipulation</Description>
- <Version>0.8.2.3</Version>
+ <Version>0.8.2.4</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
- <AssemblyVersion>0.8.2.3</AssemblyVersion>
- <FileVersion>0.8.2.3</FileVersion>
+ <AssemblyVersion>0.8.2.4</AssemblyVersion>
+ <FileVersion>0.8.2.4</FileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
diff --git a/UVtools.GUI/Controls/Tools/CtrlToolLayerImport.Designer.cs b/UVtools.GUI/Controls/Tools/CtrlToolLayerImport.Designer.cs
index 66a17c1..371dff4 100644
--- a/UVtools.GUI/Controls/Tools/CtrlToolLayerImport.Designer.cs
+++ b/UVtools.GUI/Controls/Tools/CtrlToolLayerImport.Designer.cs
@@ -48,6 +48,7 @@
this.pbSelectedImage = new System.Windows.Forms.PictureBox();
this.cbReplaceSubsequentLayers = new System.Windows.Forms.CheckBox();
this.cbDiscardRemainingLayers = new System.Windows.Forms.CheckBox();
+ this.cbMergeImages = new System.Windows.Forms.CheckBox();
((System.ComponentModel.ISupportInitialize)(this.nmInsertAfterLayer)).BeginInit();
this.tsBar.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
@@ -276,11 +277,25 @@
this.cbDiscardRemainingLayers.UseVisualStyleBackColor = true;
this.cbDiscardRemainingLayers.CheckedChanged += new System.EventHandler(this.EventClick);
//
+ // cbMergeImages
+ //
+ this.cbMergeImages.AutoSize = true;
+ this.cbMergeImages.Enabled = false;
+ this.cbMergeImages.Location = new System.Drawing.Point(244, 83);
+ this.cbMergeImages.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
+ this.cbMergeImages.Name = "cbMergeImages";
+ this.cbMergeImages.Size = new System.Drawing.Size(128, 24);
+ this.cbMergeImages.TabIndex = 41;
+ this.cbMergeImages.Text = "Merge images";
+ this.toolTip.SetToolTip(this.cbMergeImages, "Merge source layer with target layer\r\n(Require \"Replace subsequent layers\")");
+ this.cbMergeImages.UseVisualStyleBackColor = true;
+ this.cbMergeImages.CheckedChanged += new System.EventHandler(this.EventClick);
+ //
// CtrlToolLayerImport
//
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
+ this.Controls.Add(this.cbMergeImages);
this.Controls.Add(this.cbDiscardRemainingLayers);
this.Controls.Add(this.cbReplaceSubsequentLayers);
this.Controls.Add(this.lbResult);
@@ -330,5 +345,6 @@
private System.Windows.Forms.PictureBox pbSelectedImage;
private System.Windows.Forms.CheckBox cbReplaceSubsequentLayers;
private System.Windows.Forms.CheckBox cbDiscardRemainingLayers;
+ private System.Windows.Forms.CheckBox cbMergeImages;
}
}
diff --git a/UVtools.GUI/Controls/Tools/CtrlToolLayerImport.cs b/UVtools.GUI/Controls/Tools/CtrlToolLayerImport.cs
index 41b591a..53090af 100644
--- a/UVtools.GUI/Controls/Tools/CtrlToolLayerImport.cs
+++ b/UVtools.GUI/Controls/Tools/CtrlToolLayerImport.cs
@@ -40,6 +40,7 @@ namespace UVtools.GUI.Controls.Tools
Operation.ReplaceStartLayer = cbReplaceStartLayer.Checked;
Operation.ReplaceSubsequentLayers = cbReplaceSubsequentLayers.Checked;
Operation.DiscardRemainingLayers = cbDiscardRemainingLayers.Checked;
+ Operation.MergeImages = cbMergeImages.Checked;
return true;
}
@@ -79,10 +80,12 @@ namespace UVtools.GUI.Controls.Tools
{
if (ReferenceEquals(sender, cbReplaceSubsequentLayers))
{
- cbDiscardRemainingLayers.Enabled = cbReplaceSubsequentLayers.Checked;
+ cbDiscardRemainingLayers.Enabled = cbDiscardRemainingLayers.Enabled = cbReplaceSubsequentLayers.Checked;
+ cbMergeImages.Enabled = cbReplaceSubsequentLayers.Checked;
if (!cbReplaceSubsequentLayers.Checked)
{
cbDiscardRemainingLayers.Checked = false;
+ cbMergeImages.Checked = false;
}
}
diff --git a/UVtools.GUI/FrmMain.cs b/UVtools.GUI/FrmMain.cs
index 12867f6..ac3fe8c 100644
--- a/UVtools.GUI/FrmMain.cs
+++ b/UVtools.GUI/FrmMain.cs
@@ -2275,7 +2275,7 @@ namespace UVtools.GUI
/// Shows a layer number
/// </summary>
/// <param name="layerNum">Layer number</param>
- void ShowLayer(uint layerNum)
+ unsafe void ShowLayer(uint layerNum)
{
if (SlicerFile is null) return;
@@ -2316,8 +2316,10 @@ namespace UVtools.GUI
CvInvoke.CvtColor(ActualLayerImage, ActualLayerImageBgr, ColorConversion.Gray2Bgr);
- var imageSpan = ActualLayerImage.GetPixelSpan<byte>();
- var imageBgrSpan = ActualLayerImageBgr.GetPixelSpan<byte>();
+ //var imageSpan = ActualLayerImage.GetPixelSpan<byte>();
+ //var imageBgrSpan = ActualLayerImageBgr.GetPixelSpan<byte>();
+ var imageSpan = ActualLayerImage.GetBytePointer();
+ var imageBgrSpan = ActualLayerImageBgr.GetBytePointer();
if (btnLayerImageLayerOutlineEdgeDetection.Checked)
@@ -2332,71 +2334,30 @@ namespace UVtools.GUI
{
if (layerNum > 0 && layerNum < SlicerFile.LayerCount - 1)
{
- using (var previousImage = SlicerFile[layerNum - 1].LayerMat)
- using (var nextImage = SlicerFile[layerNum + 1].LayerMat)
+ Mat previousImage = null;
+ Mat nextImage = null;
+
+ // Can improve performance on >4K images?
+ Parallel.Invoke(
+ () => { previousImage = SlicerFile[ActualLayer - 1].LayerMat; },
+ () => { nextImage = SlicerFile[ActualLayer + 1].LayerMat; });
+
+ /*using (var previousImage = SlicerFile[_actualLayer - 1].LayerMat)
+ using (var nextImage = SlicerFile[_actualLayer + 1].LayerMat)
+ {*/
+ //var previousSpan = previousImage.GetPixelSpan<byte>();
+ //var nextSpan = nextImage.GetPixelSpan<byte>();
+
+ var previousSpan = previousImage.GetBytePointer();
+ var nextSpan = nextImage.GetBytePointer();
+
+ int width = ActualLayerImage.Width;
+ int channels = ActualLayerImageBgr.NumberOfChannels;
+ Parallel.For(0, ActualLayerImageBgr.Height, y =>
{
- var previousSpan = previousImage.GetPixelSpan<byte>();
- var nextSpan = nextImage.GetPixelSpan<byte>();
-
- /*Parallel.For(0, imageSpan.Length, i =>
- {
- var currentByte = ActualLayerImage.GetSinglePixelSpan<byte>(i);
- var previousByte = previousImage.GetSinglePixelSpan<byte>(i);
- var nextByte = nextImage.GetSinglePixelSpan<byte>(i);
-
- if (currentByte[0] != 0) return;
- Color color = Color.Empty;
- if (previousByte[0] > 0 && nextByte[0] > 0)
- {
- color = Settings.Default.PreviousNextLayerColor;
- }
- else if (previousByte[0] > 0)
- {
- color = Settings.Default.PreviousLayerColor;
- }
- else if (nextByte[0] > 0)
- {
- color = Settings.Default.NextLayerColor;
- }
-
- if (color.IsEmpty) return;
- ActualLayerImageBgr.SetByte(i * 3, new[]{ color.B , color.G, color.R });
- });*/
-
- /*Parallel.For(0, ActualLayerImage.Height, y =>
- {
- var currentSpan = ActualLayerImage.GetPixelRowSpan<byte>(y);
- var currentRGBSpan = ActualLayerImageBgr.GetPixelRowSpan<byte>(y);
- var previousSpan = previousImage.GetPixelRowSpan<byte>(y);
- var nextSpan = nextImage.GetPixelRowSpan<byte>(y);
-
- for (int x = 0; x < currentSpan.Length; x++)
- {
- if (currentSpan[x] != 0) continue;
- Color color = Color.Empty;
- if (previousSpan[x] > 0 && nextSpan[x] > 0)
- {
- color = Settings.Default.PreviousNextLayerColor;
- }
- else if (previousSpan[x] > 0)
- {
- color = Settings.Default.PreviousLayerColor;
- }
- else if (nextSpan[x] > 0)
- {
- color = Settings.Default.NextLayerColor;
- }
-
- if (color.IsEmpty) continue;
- var bgrPixel = x * 3;
- currentRGBSpan[bgrPixel] = color.B; // B
- currentRGBSpan[++bgrPixel] = color.G; // G
- currentRGBSpan[++bgrPixel] = color.R; // R
- }
- });*/
-
- for (int pixel = 0; pixel < imageSpan.Length; pixel++)
+ for (int x = 0; x < width; x++)
{
+ int pixel = y * width + x;
if (imageSpan[pixel] != 0) continue;
Color color = Color.Empty;
if (previousSpan[pixel] > 0 && nextSpan[pixel] > 0)
@@ -2413,12 +2374,16 @@ namespace UVtools.GUI
}
if (color.IsEmpty) continue;
- var bgrPixel = pixel * 3;
+ var bgrPixel = pixel * channels;
imageBgrSpan[bgrPixel] = color.B; // B
imageBgrSpan[++bgrPixel] = color.G; // G
imageBgrSpan[++bgrPixel] = color.R; // R
+ //imageBgrSpan[++bgrPixel] = color.A; // A
}
- }
+ });
+
+ previousImage.Dispose();
+ nextImage.Dispose();
}
}
diff --git a/UVtools.GUI/Properties/AssemblyInfo.cs b/UVtools.GUI/Properties/AssemblyInfo.cs
index e011fe6..dd226f7 100644
--- a/UVtools.GUI/Properties/AssemblyInfo.cs
+++ b/UVtools.GUI/Properties/AssemblyInfo.cs
@@ -35,5 +35,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("0.8.2.3")]
-[assembly: AssemblyFileVersion("0.8.2.3")]
+[assembly: AssemblyVersion("0.8.2.4")]
+[assembly: AssemblyFileVersion("0.8.2.4")]
diff --git a/UVtools.GUI/UVtools.GUI.csproj b/UVtools.GUI/UVtools.GUI.csproj
index b1269db..4b2b1c5 100644
--- a/UVtools.GUI/UVtools.GUI.csproj
+++ b/UVtools.GUI/UVtools.GUI.csproj
@@ -41,6 +41,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -51,6 +52,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>UVtools.ico</ApplicationIcon>
@@ -67,6 +69,7 @@
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
@@ -77,6 +80,7 @@
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>false</SignAssembly>
diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml
index 76f60c1..b18591d 100644
--- a/UVtools.WPF/MainWindow.axaml
+++ b/UVtools.WPF/MainWindow.axaml
@@ -108,35 +108,135 @@
</MenuItem>
</Menu>
- <Menu DockPanel.Dock="Bottom"
- IsEnabled="{Binding IsFileLoaded}"
- >
- <MenuItem Header="_File">
- <MenuItem Header="_Open..."/>
- <Separator/>
- <MenuItem Header="_Exit"/>
- </MenuItem>
- <MenuItem Header="_Edit">
- <MenuItem Header="Copy"/>
- <MenuItem Header="Paste"/>
- </MenuItem>
- </Menu>
+ <Border Padding="5" DockPanel.Dock="Bottom" Background="WhiteSmoke" IsVisible="{Binding IsFileLoaded}">
+ <StackPanel
+ VerticalAlignment="Center"
+ Orientation="Horizontal"
+ Spacing="5"
+ >
+ <TextBlock Text="{Binding SlicerFile.LayerHeight, StringFormat=Layer height: \{0\}mm}"/>
+ <TextBlock Text="|"/>
+
+ <TextBlock Text="{Binding SlicerFile.BottomLayerCount, StringFormat=Bottom layers: \{0\}}"/>
+ <TextBlock Text="|"/>
+
+ <TextBlock Text="{Binding SlicerFile.BottomExposureTime, StringFormat=Bottom exposure: \{0\}s}"/>
+ <TextBlock Text="|"/>
+
+ <TextBlock Text="{Binding SlicerFile.ExposureTime, StringFormat=Exposure: \{0\}s}"/>
+
+ <TextBlock IsVisible="{Binding SlicerFile.PrintTimeHours}"
+ Text="|"/>
+ <TextBlock IsVisible="{Binding SlicerFile.PrintTimeHours}"
+ Text="{Binding SlicerFile.PrintTimeHours, StringFormat=Print time: \{0\}h}"/>
+
+
+ <TextBlock IsVisible="{Binding SlicerFile.UsedMaterial}"
+ Text="|"/>
+ <TextBlock IsVisible="{Binding SlicerFile.UsedMaterial}"
+ Text="{Binding SlicerFile.UsedMaterial, StringFormat=Used material: \{0\}ml}"/>
+
+
+ <TextBlock IsVisible="{Binding SlicerFile.MaterialCost}"
+ Text="|"/>
+ <TextBlock IsVisible="{Binding SlicerFile.MaterialCost}"
+ Text="{Binding SlicerFile.MaterialCost, StringFormat=Material cost: \{0\}ml}"/>
+
+
+ <TextBlock IsVisible="{Binding SlicerFile.MaterialName, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
+ Text="|"/>
+ <TextBlock IsVisible="{Binding SlicerFile.MaterialName, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
+ Text="{Binding SlicerFile.MaterialName, StringFormat=Material: \{0\}}"/>
+
+
+ <TextBlock IsVisible="{Binding SlicerFile.MachineName, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
+ Text="|"/>
+ <TextBlock IsVisible="{Binding SlicerFile.MachineName, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
+ Text="{Binding SlicerFile.MachineName, StringFormat=Machine: \{0\}}"/>
+ </StackPanel>
+ </Border>
<TabControl
- IsEnabled="{Binding IsFileLoaded}"
DockPanel.Dock="Left"
Width="400"
- SelectedIndex="3">
- <TabItem>
+ SelectedIndex="{Binding TabSelectedIndex}">
+ <TabItem IsEnabled="{Binding IsFileLoaded}" >
<TabItem.Header>
<StackPanel VerticalAlignment="Center" Orientation="Horizontal">
<Image Source="/Assets/Icons/button-info-16x16.png" Width="16"/>
<TextBlock Margin="5,0,0,0">Information</TextBlock>
</StackPanel>
</TabItem.Header>
+
+ <Grid IsVisible="{Binding IsFileLoadeds}" RowDefinitions="Auto,Auto,Auto,*">
+ <StackPanel Background="WhiteSmoke"
+ Grid.Row="0"
+ Orientation="Horizontal"
+ Spacing="5"
+ VerticalAlignment="Center">
+ <Button
+ IsEnabled="{Binding ThumbnailCanGoPrevious}"
+ Command="{Binding ThumbnailGoPrevious}"
+ >
+ <Image Source="/Assets/Icons/back-16x16.png" Width="16"/>
+ </Button>
+
+ <TextBlock VerticalAlignment="Center">
+ <TextBlock.Text>
+ <MultiBinding StringFormat="\{0\}/\{1\}">
+ <Binding Path="VisibleThumbnailIndex"/>
+ <Binding Path="SlicerFile.CreatedThumbnailsCount"/>
+ </MultiBinding>
+ </TextBlock.Text>
+ </TextBlock>
+
+ <Button
+ IsEnabled="{Binding ThumbnailCanGoNext}"
+ Command="{Binding ThumbnailGoNext}"
+ >
+ <Image Source="/Assets/Icons/next-16x16.png" Width="16"/>
+ </Button>
+
+ </StackPanel>
+
+ <StackPanel
+ Grid.Row="0"
+ Orientation="Horizontal"
+ Spacing="5"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center">
+ <TextBlock VerticalAlignment="Center"
+ Text="{Binding VisibleThumbnailResolution}"/>
+ </StackPanel>
+
+ <Image Grid.Row="1" Source="{Binding VisibleThumbnailImage}"/>
+
+ <DataGrid Grid.Row="3"
+ CanUserReorderColumns="True"
+ CanUserResizeColumns="True"
+ CanUserSortColumns="True"
+ GridLinesVisibility="All"
+ IsReadOnly="True"
+ ClipboardCopyMode="IncludeHeader"
+ Items="{Binding SlicerProperties}">
+ <DataGrid.Columns>
+ <DataGridTextColumn Header="Name"
+ Binding="{Binding Name}"
+ Width="Auto" />
+ <DataGridTextColumn Header="Value"
+ Binding="{Binding Value}"
+ Width="Auto" />
+ <DataGridTextColumn Header="Group"
+ Binding="{Binding Group}"
+ Width="Auto" />
+ </DataGrid.Columns>
+
+ </DataGrid>
+ </Grid>
+
</TabItem>
- <TabItem IsVisible="{Binding SlicerFile.HaveGCode}">
+ <TabItem IsVisible="{Binding HaveGCode}">
<TabItem.Header>
<StackPanel VerticalAlignment="Center" Orientation="Horizontal">
<Image Source="/Assets/Icons/code-16x16.png" Width="16"/>
@@ -146,7 +246,7 @@
</TabItem>
- <TabItem>
+ <TabItem IsEnabled="{Binding IsFileLoaded}" >
<TabItem.Header>
<StackPanel VerticalAlignment="Center" Orientation="Horizontal">
<Image Source="/Assets/Icons/warning-16x16.png" Width="16"/>
@@ -275,7 +375,6 @@
Name="Layer.Navigation.Slider"
Minimum="0"
Maximum="{Binding SliderMaximumValue}"
- Ticks="{Binding SliderMaximumValue}"
Value="{Binding ActualLayer}"
TickFrequency="1"
TickPlacement="Outside"
@@ -357,7 +456,7 @@
<StackPanel HorizontalAlignment="Left" Grid.Row="0" Orientation="Horizontal" Spacing="1">
<ToggleButton
IsChecked="{Binding ShowLayerImageRotated}"
- HotKey="Ctrl + R"
+ HotKey="Ctrl+R"
ToolTip.Tip="Auto rotate layer preview image at 90º (This can slow down the layer preview) [CTRL+R]"
>
<StackPanel Orientation="Horizontal">
@@ -397,10 +496,11 @@
</ToggleButton>
<Button
- ToolTip.Tip="Right click to access the various outlines."
+ ToolTip.Tip="Click to access the various outlines."
+ Command="{Binding #LayerPreviewOutlineContextMenu.Open}"
>
<Button.ContextMenu>
- <ContextMenu PlacementMode="Bottom">
+ <ContextMenu Name="LayerPreviewOutlineContextMenu" PlacementMode="Bottom">
<CheckBox
IsChecked="{Binding ShowLayerOutlinePrintVolumeBoundary}"
Content="Print volume boundary"/>
diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs
index 39c9101..88a0895 100644
--- a/UVtools.WPF/MainWindow.axaml.cs
+++ b/UVtools.WPF/MainWindow.axaml.cs
@@ -19,6 +19,7 @@ using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
+using Avalonia.Media.Imaging;
using Avalonia.Threading;
using Emgu.CV;
using Emgu.CV.CvEnum;
@@ -102,6 +103,7 @@ namespace UVtools.WPF
public Border LayerNavigationTooltipBorder;
#region DataSets
+ public ObservableCollection<SlicerProperty> SlicerProperties { get; } = new ObservableCollection<SlicerProperty>();
public ObservableCollection<LogItem> Logs { get; } = new ObservableCollection<LogItem>();
public ObservableCollection<LayerIssue> Issues { get; } = new ObservableCollection<LayerIssue>();
public ObservableCollection<PixelOperation> Drawings { get; } = new ObservableCollection<PixelOperation>();
@@ -113,6 +115,9 @@ namespace UVtools.WPF
private uint _actualLayer;
private bool _isGUIEnabled = true;
private bool _canSave;
+ private int _tabSelectedIndex;
+ private uint _visibleThumbnailIndex;
+ private Bitmap _visibleThumbnailImage;
private bool _isVerbose;
private bool _showLayerImageRotated;
private bool _showLayerImageDifference;
@@ -135,7 +140,7 @@ namespace UVtools.WPF
{
if (!SetProperty(ref _isGUIEnabled, value)) return;
if (!_isGUIEnabled) return;
- if (ProgressWindow.IsActive)
+ if (!(ProgressWindow is null))
{
Dispatcher.UIThread.InvokeAsync(() =>
{
@@ -151,16 +156,73 @@ namespace UVtools.WPF
public bool IsFileLoaded
{
- get => !ReferenceEquals(SlicerFile, null);
+ get => !(SlicerFile is null);
set => OnPropertyChanged();
}
+ public bool HaveGCode => IsFileLoaded && SlicerFile.HaveGCode;
+
public bool CanSave
{
get => _canSave;
set => SetProperty(ref _canSave, value);
}
+ public int TabSelectedIndex
+ {
+ get => _tabSelectedIndex;
+ set => SetProperty(ref _tabSelectedIndex, value);
+ }
+
+ public uint VisibleThumbnailIndex
+ {
+ get => _visibleThumbnailIndex;
+ set
+ {
+ SetProperty(ref _visibleThumbnailIndex, value);
+ OnPropertyChanged(nameof(ThumbnailCanGoPrevious));
+ OnPropertyChanged(nameof(ThumbnailCanGoNext));
+ if (value == 0)
+ {
+ VisibleThumbnailImage = null;
+ return;
+ }
+
+ if (SlicerFile is null) return;
+ if (_visibleThumbnailIndex > SlicerFile.Thumbnails.Length) return;
+ VisibleThumbnailImage = SlicerFile.Thumbnails[_visibleThumbnailIndex-1].ToBitmap();
+ }
+ }
+
+ public bool ThumbnailCanGoPrevious => SlicerFile is { } && _visibleThumbnailIndex > 1;
+ public bool ThumbnailCanGoNext => SlicerFile is { } && _visibleThumbnailIndex < SlicerFile.Thumbnails.Length;
+
+ public void ThumbnailGoPrevious()
+ {
+ if (!ThumbnailCanGoPrevious) return;
+ VisibleThumbnailIndex--;
+ }
+
+ public void ThumbnailGoNext()
+ {
+ if (!ThumbnailCanGoNext) return;
+ VisibleThumbnailIndex++;
+ }
+
+ public Bitmap VisibleThumbnailImage
+ {
+ get => _visibleThumbnailImage;
+ set
+ {
+ SetProperty(ref _visibleThumbnailImage, value);
+ OnPropertyChanged(nameof(VisibleThumbnailResolution));
+ }
+ }
+
+ public string VisibleThumbnailResolution => _visibleThumbnailImage is null ? null : $"{{Width: {_visibleThumbnailImage.Size.Width}, Height: {_visibleThumbnailImage.Size.Height}}}";
+
+
+
public bool IsVerbose
{
get => _isVerbose;
@@ -433,7 +495,9 @@ namespace UVtools.WPF
SlicerFile?.Dispose();
App.SlicerFile = null;
LayerCache.Clear();
+ VisibleThumbnailIndex = 0;
LayerImageBox.Image = null;
+ SlicerProperties.Clear();
ResetDataContext();
}
@@ -512,6 +576,21 @@ namespace UVtools.WPF
LayerImageBox.Image = bitmapRgb;*/
_actualLayer = actualLayer;
+ if(SlicerFile.CreatedThumbnailsCount > 0) VisibleThumbnailIndex = 1;
+
+ if (!(SlicerFile.Configs is null))
+ {
+ foreach (var config in SlicerFile.Configs)
+ {
+ var type = config.GetType();
+ foreach (var property in type.GetProperties())
+ {
+ SlicerProperties.Add(new SlicerProperty(property.Name, property.GetValue(config, null)?.ToString(), type.Name));
+ }
+ }
+ }
+
+
ShowLayer();
ResetDataContext();
diff --git a/UVtools.WPF/Structures/SlicerProperty.cs b/UVtools.WPF/Structures/SlicerProperty.cs
new file mode 100644
index 0000000..94cdc82
--- /dev/null
+++ b/UVtools.WPF/Structures/SlicerProperty.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Text;
+using Avalonia;
+using ReactiveUI;
+
+namespace UVtools.WPF.Structures
+{
+ public class SlicerProperty : ReactiveObject
+ {
+ private string _name;
+ private string _value;
+ private string _group;
+
+ public string Name
+ {
+ get => _name;
+ set => this.RaiseAndSetIfChanged(ref _name, value);
+ }
+
+ public string Value
+ {
+ get => _value;
+ set => this.RaiseAndSetIfChanged(ref _value, value);
+ }
+
+ public string Group
+ {
+ get => _group;
+ set => this.RaiseAndSetIfChanged(ref _group, value);
+ }
+
+ public SlicerProperty(string name, string value, string group = null)
+ {
+ _name = name;
+ _value = value;
+ _group = group;
+ }
+ }
+}