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-06-24 06:53:54 +0300
committerTiago Conceição <Tiago_caza@hotmail.com>2022-06-24 06:53:54 +0300
commit67fbec1fff373a6ca6ae9f512eb28fe3fc379bb7 (patch)
treec4fc746605254c7d453352bee0bcd3ea664ceb8b
parent97c78a8d8c6574212d5c330def875642e0f39a40 (diff)
v3.5.1v3.5.1
- **PCB Exposure:** - (Fix) Able to omit X or Y coordinate and use last known value in place - (Fix) Reusing macros in apertures was causing to use the last aperture values for all previous apertures that share the same macro name - (Fix) Implement the inch measurement (%MOIN*%) - (Fix) Crash when redo the operation (Ctrl + Shift + Z) - **UI - Issue list:** - (Add) Context menu when right click issues to select an action - (Add) Option to solidify suction cups when right click on the issue - (Improvement) Better confirmation text when click on remove issue(s) with detailed list of actions
-rw-r--r--CHANGELOG.md12
-rw-r--r--RELEASE_NOTES.md23
-rw-r--r--UVtools.Core/Gerber/Apertures/Aperture.cs32
-rw-r--r--UVtools.Core/Gerber/Apertures/CircleAperture.cs7
-rw-r--r--UVtools.Core/Gerber/Apertures/EllipseAperture.cs10
-rw-r--r--UVtools.Core/Gerber/Apertures/MacroAperture.cs9
-rw-r--r--UVtools.Core/Gerber/Apertures/PoygonAperture.cs6
-rw-r--r--UVtools.Core/Gerber/Apertures/RectangleAperture.cs12
-rw-r--r--UVtools.Core/Gerber/GerberDocument.cs43
-rw-r--r--UVtools.Core/Gerber/Macro.cs11
-rw-r--r--UVtools.Core/Gerber/Primitives/CenterLinePrimitive.cs7
-rw-r--r--UVtools.Core/Gerber/Primitives/CirclePrimitive.cs5
-rw-r--r--UVtools.Core/Gerber/Primitives/CommentPrimitive.cs2
-rw-r--r--UVtools.Core/Gerber/Primitives/OutlinePrimitive.cs13
-rw-r--r--UVtools.Core/Gerber/Primitives/PolygonPrimitive.cs7
-rw-r--r--UVtools.Core/Gerber/Primitives/Primitive.cs5
-rw-r--r--UVtools.Core/Gerber/Primitives/VectorLinePrimitive.cs9
-rw-r--r--UVtools.Core/Layers/MainIssue.cs9
-rw-r--r--UVtools.Core/Operations/OperationPCBExposure.cs6
-rw-r--r--UVtools.Core/Operations/OperationSolidify.cs2
-rw-r--r--UVtools.Core/UVtools.Core.csproj2
-rw-r--r--UVtools.InstallerMM/UVtools.InstallerMM.wxs2
-rw-r--r--UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs2
-rw-r--r--UVtools.WPF/MainWindow.Issues.cs124
-rw-r--r--UVtools.WPF/MainWindow.axaml73
-rw-r--r--UVtools.WPF/UVtools.WPF.csproj2
26 files changed, 325 insertions, 110 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 714d4f4..47408b9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,17 @@
# Changelog
+## 24/06/2022 - v3.5.1
+
+- **PCB Exposure:**
+ - (Fix) Able to omit X or Y coordinate and use last known value in place
+ - (Fix) Reusing macros in apertures was causing to use the last aperture values for all previous apertures that share the same macro name
+ - (Fix) Implement the inch measurement (%MOIN*%)
+ - (Fix) Crash when redo the operation (Ctrl + Shift + Z)
+- **UI - Issue list:**
+ - (Add) Context menu when right click issues to select an action
+ - (Add) Option to solidify suction cups when right click on the issue
+ - (Improvement) Better confirmation text when click on remove issue(s) with detailed list of actions
+
## 19/06/2022 - v3.5.0
- **PCB Exposure:**
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 9c7b302..0dd9480 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,17 +1,10 @@
- **PCB Exposure:**
- - (Add) Able to select multiple files and create a layer per file or merge them into one layer
- - (Add) Able to import files from a zip file
- - (Improvement) Round pixel coordinates and line thickness
- - (Improvement) Better position precision for primitives
- - (Improvement) Disable the ok button if no files were selected
- - (Change) Do not auto mirror based on printer lcd mirror type
- - (Fix) Limit line thickness to 1px minimum
- - (Fix) Allow leading zero omit from XY coordinates (#492)
- - (Fix) Mirror option was shifting the board position
-- (Add) Calibrate - Blooming effect: Generates test models with various strategies and increments to measure the blooming effect
-- (Add) Setting: Issues - Default order by, changes the default order on the issues list (#482)
-- (Improvement) CTBv4 and encrypted: Fetch `BottomWaitTimes` virtual property from first bottom layer that has at least 2 pixels (#483)
-- (Fix) Linux: Enable desktop integration for AppImages (#490)
-- (Fix) Extracting zip contents inside folders would cause a error and not extract those contents
-- (Upgrade) AvaloniaUI from 0.10.14 to 0.10.15 [Fixes auto-size problems]
+ - (Fix) Able to omit X or Y coordinate and use last known value in place
+ - (Fix) Reusing macros in apertures was causing to use the last aperture values for all previous apertures that share the same macro name
+ - (Fix) Implement the inch measurement (%MOIN*%)
+ - (Fix) Crash when redo the operation (Ctrl + Shift + Z)
+- **UI - Issue list:**
+ - (Add) Context menu when right click issues to select an action
+ - (Add) Option to solidify suction cups when right click on the issue
+ - (Improvement) Better confirmation text when click on remove issue(s) with detailed list of actions
diff --git a/UVtools.Core/Gerber/Apertures/Aperture.cs b/UVtools.Core/Gerber/Apertures/Aperture.cs
index 68cb3c6..39bff36 100644
--- a/UVtools.Core/Gerber/Apertures/Aperture.cs
+++ b/UVtools.Core/Gerber/Apertures/Aperture.cs
@@ -13,6 +13,7 @@ using System.Text.RegularExpressions;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
+using UVtools.Core.Extensions;
namespace UVtools.Core.Gerber.Apertures;
@@ -29,13 +30,24 @@ public abstract class Aperture
/// </summary>
public string Name { get; set; } = string.Empty;
+ public GerberDocument Document { get; set; } = null!;
+
#endregion
protected Aperture() { }
- protected Aperture(int index) { Index = index; }
- protected Aperture(string name) { Name = name; }
- protected Aperture(int index, string name) : this(index) { Name = name; }
+ protected Aperture(GerberDocument document, int index)
+ {
+ Document = document;
+ Index = index;
+ }
+
+ protected Aperture(GerberDocument document, string name)
+ {
+ Document = document;
+ Name = name;
+ }
+ protected Aperture(GerberDocument document, int index, string name) : this(document, index) { Name = name; }
public abstract void DrawFlashD3(Mat mat, SizeF xyPpmm, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected);
@@ -47,13 +59,12 @@ public abstract class Aperture
if (!int.TryParse(match.Groups[1].Value, out var index)) return null;
//if (!char.TryParse(match.Groups[2].Value, out var type)) return null;
-
switch (match.Groups[2].Value)
{
case "C":
{
if (!double.TryParse(match.Groups[3].Value, out var diameter)) return null;
- return new CircleAperture(index, diameter);
+ return new CircleAperture(document, index, diameter);
}
case "O":
{
@@ -62,7 +73,7 @@ public abstract class Aperture
if (!float.TryParse(split[0], out var width)) return null;
if (!float.TryParse(split[1], out var height)) return null;
- return new EllipseAperture(index, width, height);
+ return new EllipseAperture(document, index, width, height);
}
case "R":
{
@@ -71,7 +82,7 @@ public abstract class Aperture
if (!float.TryParse(split[0], out var width)) return null;
if (!float.TryParse(split[1], out var height)) return null;
- return new RectangleAperture(index, width, height);
+ return new RectangleAperture(document, index, width, height);
}
case "P":
{
@@ -80,11 +91,12 @@ public abstract class Aperture
if (!double.TryParse(split[0], out var diameter)) return null;
if (!ushort.TryParse(split[1], out var vertices)) return null;
- return new PolygonAperture(index, diameter, vertices);
+ return new PolygonAperture(document, index, diameter, vertices);
}
default: // macro
{
if (!document.Macros.TryGetValue(match.Groups[2].Value, out var macro)) return null;
+ macro = macro.Clone();
var parseLine = line.TrimEnd('%', '*');
var commaIndex = parseLine.IndexOf(',')+1;
if (commaIndex == 0) return null;
@@ -92,10 +104,10 @@ public abstract class Aperture
var args = new[] {"0"}.Concat(parseLine.Split('X', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)).ToArray();
foreach (var primitive in macro)
{
- primitive.ParseExpressions(args);
+ primitive.ParseExpressions(document, args);
}
- return new MacroAperture(index, macro);
+ return new MacroAperture(document, index, macro);
}
}
}
diff --git a/UVtools.Core/Gerber/Apertures/CircleAperture.cs b/UVtools.Core/Gerber/Apertures/CircleAperture.cs
index 2f00787..0071b0f 100644
--- a/UVtools.Core/Gerber/Apertures/CircleAperture.cs
+++ b/UVtools.Core/Gerber/Apertures/CircleAperture.cs
@@ -6,7 +6,6 @@
* of this license document, but changing it is not allowed.
*/
-using System;
using System.Drawing;
using Emgu.CV;
using Emgu.CV.CvEnum;
@@ -22,11 +21,11 @@ public class CircleAperture : Aperture
#endregion
#region Constructor
- public CircleAperture() : base("Circle") { }
+ public CircleAperture(GerberDocument document) : base(document, "Circle") { }
- public CircleAperture(int index, double diameter) : base(index, "Circle")
+ public CircleAperture(GerberDocument document, int index, double diameter) : base(document, index, "Circle")
{
- Diameter = diameter;
+ Diameter = document.GetMillimeters(diameter);
}
#endregion
diff --git a/UVtools.Core/Gerber/Apertures/EllipseAperture.cs b/UVtools.Core/Gerber/Apertures/EllipseAperture.cs
index 7ac6f2e..c2d967e 100644
--- a/UVtools.Core/Gerber/Apertures/EllipseAperture.cs
+++ b/UVtools.Core/Gerber/Apertures/EllipseAperture.cs
@@ -20,16 +20,16 @@ public class EllipseAperture : Aperture
#endregion
#region Constructor
- public EllipseAperture() : base("Ellipse") { }
+ public EllipseAperture(GerberDocument document) : base(document, "Ellipse") { }
- public EllipseAperture(int index, float width, float height) : base(index, "Ellipse")
+ public EllipseAperture(GerberDocument document, int index, float width, float height) : this(document, index, new SizeF(width, height))
{
- Axes = new SizeF(width, height);
+
}
- public EllipseAperture(int index, SizeF axes) : base(index, "Ellipse")
+ public EllipseAperture(GerberDocument document, int index, SizeF axes) : base(document, index, "Ellipse")
{
- Axes = axes;
+ Axes = document.GetMillimeters(axes);
}
#endregion
diff --git a/UVtools.Core/Gerber/Apertures/MacroAperture.cs b/UVtools.Core/Gerber/Apertures/MacroAperture.cs
index 1f4cea1..af403cb 100644
--- a/UVtools.Core/Gerber/Apertures/MacroAperture.cs
+++ b/UVtools.Core/Gerber/Apertures/MacroAperture.cs
@@ -21,9 +21,9 @@ public class MacroAperture : Aperture
#endregion
#region Constructor
- public MacroAperture() : base("Macro") { }
+ public MacroAperture(GerberDocument document) : base(document, "Macro") { }
- public MacroAperture(int index, Macro macro) : base(index, "Macro")
+ public MacroAperture(GerberDocument document, int index, Macro macro) : base(document, index, "Macro")
{
Macro = macro;
}
@@ -31,9 +31,10 @@ public class MacroAperture : Aperture
public override void DrawFlashD3(Mat mat, SizeF xyPpmm, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected)
{
- foreach (var macro in Macro)
+ foreach (var primitive in Macro)
{
- macro.DrawFlashD3(mat, xyPpmm, at, color, lineType);
+ //if(primitive.Name == "Comment") continue;
+ primitive.DrawFlashD3(mat, xyPpmm, at, color, lineType);
}
}
} \ No newline at end of file
diff --git a/UVtools.Core/Gerber/Apertures/PoygonAperture.cs b/UVtools.Core/Gerber/Apertures/PoygonAperture.cs
index e10c1c2..0b8bb9a 100644
--- a/UVtools.Core/Gerber/Apertures/PoygonAperture.cs
+++ b/UVtools.Core/Gerber/Apertures/PoygonAperture.cs
@@ -23,11 +23,11 @@ public class PolygonAperture : Aperture
#endregion
#region Constructor
- public PolygonAperture() : base("Polygon") { }
+ public PolygonAperture(GerberDocument document) : base(document, "Polygon") { }
- public PolygonAperture(int index, double diameter, ushort vertices) : base(index, "Polygon")
+ public PolygonAperture(GerberDocument document, int index, double diameter, ushort vertices) : base(document, index, "Polygon")
{
- Diameter = diameter;
+ Diameter = document.GetMillimeters(diameter);
Vertices = vertices;
}
#endregion
diff --git a/UVtools.Core/Gerber/Apertures/RectangleAperture.cs b/UVtools.Core/Gerber/Apertures/RectangleAperture.cs
index 5dbd5a2..3be7bc4 100644
--- a/UVtools.Core/Gerber/Apertures/RectangleAperture.cs
+++ b/UVtools.Core/Gerber/Apertures/RectangleAperture.cs
@@ -21,16 +21,14 @@ public class RectangleAperture : Aperture
#endregion
#region Constructor
- public RectangleAperture() : base("Rectangle") { }
+ public RectangleAperture(GerberDocument document) : base(document, "Rectangle") { }
- public RectangleAperture(int index, float width, float height) : base(index, "Rectangle")
- {
- Size = new SizeF(width, height);
- }
+ public RectangleAperture(GerberDocument document, int index, float width, float height) : this(document, index, new SizeF(width, height))
+ { }
- public RectangleAperture(int index, SizeF size) : base(index, "Rectangle")
+ public RectangleAperture(GerberDocument document, int index, SizeF size) : base(document, index, "Rectangle")
{
- Size = size;
+ Size = document.GetMillimeters(size);
}
#endregion
diff --git a/UVtools.Core/Gerber/GerberDocument.cs b/UVtools.Core/Gerber/GerberDocument.cs
index e150e24..3bd3887 100644
--- a/UVtools.Core/Gerber/GerberDocument.cs
+++ b/UVtools.Core/Gerber/GerberDocument.cs
@@ -13,6 +13,7 @@ using System.IO;
using System.Text.RegularExpressions;
using Emgu.CV;
using Emgu.CV.CvEnum;
+using Emgu.CV.Structure;
using Emgu.CV.Util;
using UVtools.Core.Extensions;
using UVtools.Core.Gerber.Apertures;
@@ -166,6 +167,8 @@ public class GerberDocument
using var vec = new VectorOfPoint(regionPoints.ToArray());
CvInvoke.FillPoly(mat, vec, document.Polarity == GerberPolarityType.Dark ? EmguExtensions.WhiteColor : EmguExtensions.BlackColor, enableAntialiasing ? LineType.AntiAlias : LineType.EightConnected);
}
+ //CvInvoke.Imshow("G37", mat);
+ //CvInvoke.WaitKey();
regionPoints.Clear();
continue;
}
@@ -228,9 +231,15 @@ public class GerberDocument
var fraction = matchX.Groups[1].Value.Substring(matchX.Groups[1].Value.Length - document.CoordinateXFractionalDigits, document.CoordinateXFractionalDigits);
double.TryParse($"{integers}.{fraction}", out nowX);
}
+
+ nowX = document.GetMillimeters(nowX);
}
}
}
+ else
+ {
+ nowX = currentX;
+ }
if (matchY.Success && matchY.Groups.Count >= 2)
{
@@ -248,9 +257,14 @@ public class GerberDocument
var fraction = matchY.Groups[1].Value.Substring(matchY.Groups[1].Value.Length - document.CoordinateYFractionalDigits, document.CoordinateYFractionalDigits);
double.TryParse($"{integers}.{fraction}", out nowY);
}
+ nowY = document.GetMillimeters(nowY);
}
}
}
+ else
+ {
+ nowY = currentY;
+ }
if (insideRegion)
{
@@ -294,7 +308,7 @@ public class GerberDocument
var fraction = matchI.Groups[1].Value.Substring(matchI.Groups[1].Value.Length - document.CoordinateXFractionalDigits, document.CoordinateXFractionalDigits);
double.TryParse($"{integers}.{fraction}", out xOffset);
}
-
+ xOffset = document.GetMillimeters(xOffset);
}
}
@@ -312,6 +326,7 @@ public class GerberDocument
var fraction = matchJ.Groups[1].Value.Substring(matchJ.Groups[1].Value.Length - document.CoordinateYFractionalDigits, document.CoordinateYFractionalDigits);
double.TryParse($"{integers}.{fraction}", out yOffset);
}
+ yOffset = document.GetMillimeters(yOffset);
}
}
@@ -354,6 +369,8 @@ public class GerberDocument
{
currentAperture.DrawFlashD3(mat, xyPpmm, new PointF((float) nowX, (float) nowY),
document.Polarity == GerberPolarityType.Dark ? EmguExtensions.WhiteColor : EmguExtensions.BlackColor, enableAntialiasing ? LineType.AntiAlias : LineType.EightConnected);
+ //CvInvoke.Imshow("G37", mat);
+ //CvInvoke.WaitKey();
}
}
@@ -366,6 +383,30 @@ public class GerberDocument
return document;
}
+ public float GetMillimeters(float size)
+ {
+ if (UnitType == GerberUnitType.Millimeter) return size;
+ return size * 25.4f;
+ }
+
+ public double GetMillimeters(double size)
+ {
+ if (UnitType == GerberUnitType.Millimeter) return size;
+ return size * 25.4;
+ }
+
+ public SizeF GetMillimeters(SizeF size)
+ {
+ if (UnitType == GerberUnitType.Millimeter) return size;
+ return new SizeF(size.Width * 25.4f, size.Height * 25.4f);
+ }
+
+ public PointF GetMillimeters(PointF point)
+ {
+ if (UnitType == GerberUnitType.Millimeter) return point;
+ return new PointF(point.X * 25.4f, point.Y * 25.4f);
+ }
+
public static Point PositionMmToPx(PointF atMm, SizeF xyPpmm)
=> new((int)Math.Round(atMm.X * xyPpmm.Width, MidpointRounding.AwayFromZero), (int)Math.Round(atMm.Y * xyPpmm.Height, MidpointRounding.AwayFromZero));
diff --git a/UVtools.Core/Gerber/Macro.cs b/UVtools.Core/Gerber/Macro.cs
index 6d9a013..6a5d3c1 100644
--- a/UVtools.Core/Gerber/Macro.cs
+++ b/UVtools.Core/Gerber/Macro.cs
@@ -89,6 +89,17 @@ public class Macro : IReadOnlyList<Primitive>
}
}
+ public Macro Clone()
+ {
+ var macro = new Macro(Name);
+ foreach (var primitive in Primitives)
+ {
+ macro.Primitives.Add(primitive.Clone());
+ }
+
+ return macro;
+ }
+
public static Macro? Parse(string line)
{
diff --git a/UVtools.Core/Gerber/Primitives/CenterLinePrimitive.cs b/UVtools.Core/Gerber/Primitives/CenterLinePrimitive.cs
index 5ac51fd..6e6d751 100644
--- a/UVtools.Core/Gerber/Primitives/CenterLinePrimitive.cs
+++ b/UVtools.Core/Gerber/Primitives/CenterLinePrimitive.cs
@@ -6,7 +6,6 @@
* of this license document, but changing it is not allowed.
*/
-using System;
using System.Data;
using System.Drawing;
using System.Text.RegularExpressions;
@@ -104,7 +103,7 @@ public class CenterLinePrimitive : Primitive
//CvInvoke.Rectangle(mat, rectangle, color, -1, lineType);
}
- public override void ParseExpressions(params string[] args)
+ public override void ParseExpressions(GerberDocument document, params string[] args)
{
string csharpExp, result;
float num;
@@ -126,6 +125,7 @@ public class CenterLinePrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out var val)) Width = val;
}
+ Width = document.GetMillimeters(Width);
if (float.TryParse(HeightExpression, out num)) Height = num;
else
@@ -135,6 +135,7 @@ public class CenterLinePrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out var val)) Height = val;
}
+ Height = document.GetMillimeters(Height);
if (float.TryParse(CenterXExpression, out num)) CenterX = num;
else
@@ -144,6 +145,7 @@ public class CenterLinePrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out num)) CenterX = num;
}
+ CenterX = document.GetMillimeters(CenterX);
if (float.TryParse(CenterYExpression, out num)) CenterY = num;
else
@@ -153,6 +155,7 @@ public class CenterLinePrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out num)) CenterY = num;
}
+ CenterY = document.GetMillimeters(CenterY);
if (float.TryParse(RotationExpression, out num)) Rotation = (short)num;
else
diff --git a/UVtools.Core/Gerber/Primitives/CirclePrimitive.cs b/UVtools.Core/Gerber/Primitives/CirclePrimitive.cs
index 601cf0f..5364e0d 100644
--- a/UVtools.Core/Gerber/Primitives/CirclePrimitive.cs
+++ b/UVtools.Core/Gerber/Primitives/CirclePrimitive.cs
@@ -92,7 +92,7 @@ public class CirclePrimitive : Primitive
GerberDocument.SizeMmToPx(Diameter / 2, xyPpmm.Max()), color, -1, lineType);
}
- public override void ParseExpressions(params string[] args)
+ public override void ParseExpressions(GerberDocument document, params string[] args)
{
string csharpExp, result;
float num;
@@ -114,6 +114,7 @@ public class CirclePrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out num)) Diameter = num;
}
+ Diameter = document.GetMillimeters(Diameter);
if (float.TryParse(CenterXExpression, out num)) CenterX = num;
else
@@ -123,6 +124,7 @@ public class CirclePrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out num)) CenterX = num;
}
+ CenterX = document.GetMillimeters(CenterX);
if (float.TryParse(CenterYExpression, out num)) CenterY = num;
else
@@ -132,6 +134,7 @@ public class CirclePrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out num)) CenterY = num;
}
+ CenterY = document.GetMillimeters(CenterY);
if (float.TryParse(RotationExpression, out num)) Rotation = (short)num;
diff --git a/UVtools.Core/Gerber/Primitives/CommentPrimitive.cs b/UVtools.Core/Gerber/Primitives/CommentPrimitive.cs
index 25a9b07..a909911 100644
--- a/UVtools.Core/Gerber/Primitives/CommentPrimitive.cs
+++ b/UVtools.Core/Gerber/Primitives/CommentPrimitive.cs
@@ -50,7 +50,7 @@ public class CommentPrimitive : Primitive
}
- public override void ParseExpressions(params string[] args)
+ public override void ParseExpressions(GerberDocument document, params string[] args)
{
}
} \ No newline at end of file
diff --git a/UVtools.Core/Gerber/Primitives/OutlinePrimitive.cs b/UVtools.Core/Gerber/Primitives/OutlinePrimitive.cs
index 93a505a..80ecfaf 100644
--- a/UVtools.Core/Gerber/Primitives/OutlinePrimitive.cs
+++ b/UVtools.Core/Gerber/Primitives/OutlinePrimitive.cs
@@ -10,6 +10,7 @@ using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
+using System.Linq;
using System.Text.RegularExpressions;
using Emgu.CV;
using Emgu.CV.CvEnum;
@@ -94,7 +95,7 @@ public class OutlinePrimitive : Primitive
CvInvoke.FillPoly(mat, vec, color, lineType);
}
- public override void ParseExpressions(params string[] args)
+ public override void ParseExpressions(GerberDocument document, params string[] args)
{
string csharpExp, result;
float num;
@@ -125,7 +126,7 @@ public class OutlinePrimitive : Primitive
}
else
{
- coordinates.Add(new PointF(x.Value, num));
+ coordinates.Add(document.GetMillimeters(new PointF(x.Value, num)));
x = null;
}
}
@@ -143,4 +144,12 @@ public class OutlinePrimitive : Primitive
IsParsed = true;
}
+
+ public override Primitive Clone()
+ {
+ var primitive = MemberwiseClone() as OutlinePrimitive;
+ primitive!.CoordinatesExpression = primitive.CoordinatesExpression.ToArray();
+ primitive.Coordinates = primitive.Coordinates.ToArray();
+ return primitive;
+ }
} \ No newline at end of file
diff --git a/UVtools.Core/Gerber/Primitives/PolygonPrimitive.cs b/UVtools.Core/Gerber/Primitives/PolygonPrimitive.cs
index 1657336..2bb7289 100644
--- a/UVtools.Core/Gerber/Primitives/PolygonPrimitive.cs
+++ b/UVtools.Core/Gerber/Primitives/PolygonPrimitive.cs
@@ -6,7 +6,6 @@
* of this license document, but changing it is not allowed.
*/
-using System;
using System.Data;
using System.Drawing;
using System.Text.RegularExpressions;
@@ -101,7 +100,7 @@ public class PolygonPrimitive : Primitive
color, 0, -1, lineType);
}
- public override void ParseExpressions(params string[] args)
+ public override void ParseExpressions(GerberDocument document, params string[] args)
{
string csharpExp, result;
float num;
@@ -132,6 +131,7 @@ public class PolygonPrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out num)) CenterX = num;
}
+ CenterX = document.GetMillimeters(CenterX);
if (float.TryParse(CenterYExpression, out num)) CenterY = num;
else
@@ -141,6 +141,7 @@ public class PolygonPrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out num)) CenterY = num;
}
+ CenterY = document.GetMillimeters(CenterY);
if (float.TryParse(DiameterExpression, out num)) Diameter = num;
else
@@ -150,7 +151,7 @@ public class PolygonPrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out num)) Diameter = num;
}
-
+ Diameter = document.GetMillimeters(Diameter);
if (float.TryParse(RotationExpression, out num)) Rotation = (short)num;
else
diff --git a/UVtools.Core/Gerber/Primitives/Primitive.cs b/UVtools.Core/Gerber/Primitives/Primitive.cs
index 9658a24..0a7740f 100644
--- a/UVtools.Core/Gerber/Primitives/Primitive.cs
+++ b/UVtools.Core/Gerber/Primitives/Primitive.cs
@@ -6,6 +6,7 @@
* of this license document, but changing it is not allowed.
*/
+using System;
using System.Drawing;
using Emgu.CV;
using Emgu.CV.CvEnum;
@@ -26,5 +27,7 @@ public abstract class Primitive
public abstract void DrawFlashD3(Mat mat, SizeF xyPpmm, PointF at, MCvScalar color, LineType lineType = LineType.EightConnected);
- public abstract void ParseExpressions(params string[] args);
+ public abstract void ParseExpressions(GerberDocument document, params string[] args);
+
+ public virtual Primitive Clone() => (Primitive)MemberwiseClone();
} \ No newline at end of file
diff --git a/UVtools.Core/Gerber/Primitives/VectorLinePrimitive.cs b/UVtools.Core/Gerber/Primitives/VectorLinePrimitive.cs
index 94f712a..9916a1d 100644
--- a/UVtools.Core/Gerber/Primitives/VectorLinePrimitive.cs
+++ b/UVtools.Core/Gerber/Primitives/VectorLinePrimitive.cs
@@ -6,7 +6,6 @@
* of this license document, but changing it is not allowed.
*/
-using System;
using System.Data;
using System.Drawing;
using System.Text.RegularExpressions;
@@ -112,7 +111,7 @@ public class VectorLinePrimitive : Primitive
//CvInvoke.Rectangle(mat, rectangle, color, -1, lineType);
}
- public override void ParseExpressions(params string[] args)
+ public override void ParseExpressions(GerberDocument document, params string[] args)
{
string csharpExp, result;
float num;
@@ -134,6 +133,7 @@ public class VectorLinePrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out var val)) LineWidth = val;
}
+ LineWidth = document.GetMillimeters(LineWidth);
if (float.TryParse(StartXExpression, out num)) StartX = num;
else
@@ -143,6 +143,7 @@ public class VectorLinePrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out num)) StartX = num;
}
+ StartX = document.GetMillimeters(StartX);
if (float.TryParse(EndXExpression, out num)) EndX = num;
else
@@ -152,6 +153,7 @@ public class VectorLinePrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out num)) EndX = num;
}
+ EndX = document.GetMillimeters(EndX);
if (float.TryParse(StartYExpression, out num)) StartY = num;
else
@@ -161,6 +163,7 @@ public class VectorLinePrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out num)) StartY = num;
}
+ StartY = document.GetMillimeters(StartY);
if (float.TryParse(EndYExpression, out num)) EndY = num;
else
@@ -170,7 +173,7 @@ public class VectorLinePrimitive : Primitive
result = exp.Compute(csharpExp, null).ToString()!;
if (float.TryParse(result, out num)) EndY = num;
}
-
+ EndY = document.GetMillimeters(EndY);
if (float.TryParse(RotationExpression, out num)) Rotation = (short)num;
else
diff --git a/UVtools.Core/Layers/MainIssue.cs b/UVtools.Core/Layers/MainIssue.cs
index fbc9ec9..8b7cf7e 100644
--- a/UVtools.Core/Layers/MainIssue.cs
+++ b/UVtools.Core/Layers/MainIssue.cs
@@ -30,6 +30,15 @@ public class MainIssue : IReadOnlyList<Issue>
//HoleSandwich,
}
+ public bool IsIsland => Type == IssueType.Island;
+ public bool IsOverhang => Type == IssueType.Overhang;
+ public bool IsResinTrap => Type == IssueType.ResinTrap;
+ public bool IsSuctionCup => Type == IssueType.SuctionCup;
+ public bool IsTouchingBound => Type == IssueType.TouchingBound;
+ public bool IsPrintHeight => Type == IssueType.PrintHeight;
+ public bool IsEmptyLayer => Type == IssueType.EmptyLayer;
+ public bool IsDebug => Type == IssueType.Debug;
+
/// <summary>
/// Gets the issue type associated
/// </summary>
diff --git a/UVtools.Core/Operations/OperationPCBExposure.cs b/UVtools.Core/Operations/OperationPCBExposure.cs
index 7df3085..96fd82d 100644
--- a/UVtools.Core/Operations/OperationPCBExposure.cs
+++ b/UVtools.Core/Operations/OperationPCBExposure.cs
@@ -313,6 +313,12 @@ public class OperationPCBExposure : Operation
if (mergeMat is not null)
{
using var croppedMat = mergeMat.CropByBounds(20);
+ /*if (_mirror)
+ {
+ var flip = SlicerFile.DisplayMirror;
+ if (flip == FlipDirection.None) flip = FlipDirection.Horizontally;
+ CvInvoke.Flip(croppedMat, croppedMat, (FlipType)flip);
+ }*/
using var bgrMat = new Mat();
CvInvoke.CvtColor(croppedMat, bgrMat, ColorConversion.Gray2Bgr);
SlicerFile.SetThumbnails(bgrMat);
diff --git a/UVtools.Core/Operations/OperationSolidify.cs b/UVtools.Core/Operations/OperationSolidify.cs
index ba2426e..c3e68e3 100644
--- a/UVtools.Core/Operations/OperationSolidify.cs
+++ b/UVtools.Core/Operations/OperationSolidify.cs
@@ -34,7 +34,7 @@ public sealed class OperationSolidify : Operation
#region Overrides
- public override string IconClass => "fa-solid fa-circle";
+ public override string IconClass => "fa-solid fa-diamond";
public override string Title => "Solidify";
public override string Description =>
diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj
index 1b93a05..eb96200 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>3.5.0</Version>
+ <Version>3.5.1</Version>
<Copyright>Copyright © 2020 PTRTECH</Copyright>
<PackageIcon>UVtools.png</PackageIcon>
<Platforms>AnyCPU;x64</Platforms>
diff --git a/UVtools.InstallerMM/UVtools.InstallerMM.wxs b/UVtools.InstallerMM/UVtools.InstallerMM.wxs
index 848eea0..03b3cc7 100644
--- a/UVtools.InstallerMM/UVtools.InstallerMM.wxs
+++ b/UVtools.InstallerMM/UVtools.InstallerMM.wxs
@@ -2,7 +2,7 @@
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define ComponentRules="OneToOne"?>
<!-- SourceDir instructs IsWiX the location of the directory that contains files for this merge module -->
- <?define SourceDir="..\publish\UVtools_win-x64_v3.5.0"?>
+ <?define SourceDir="..\publish\UVtools_win-x64_v3.5.1"?>
<Module Id="UVtools" Language="1033" Version="1.0.0.0">
<Package Id="12aaa1cf-ff06-4a02-abd5-2ac01ac4f83b" Manufacturer="PTRTECH" InstallerVersion="200" Keywords="MSLA, DLP" Description="MSLA/DLP, file analysis, repair, conversion and manipulation" InstallScope="perMachine" Platform="x64" />
<Directory Id="TARGETDIR" Name="SourceDir">
diff --git a/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs
index f729167..4bcebac 100644
--- a/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs
+++ b/UVtools.WPF/Controls/Tools/ToolPCBExposureControl.axaml.cs
@@ -77,7 +77,7 @@ namespace UVtools.WPF.Controls.Tools
};
_timer.Stop();
_timer.Start();
- ParentWindow.ButtonOkEnabled = Operation.FileCount > 0;
+ if(ParentWindow is not null) ParentWindow.ButtonOkEnabled = Operation.FileCount > 0;
Operation.Files.CollectionChanged += (sender, e) => ParentWindow.ButtonOkEnabled = Operation.FileCount > 0;
break;
}
diff --git a/UVtools.WPF/MainWindow.Issues.cs b/UVtools.WPF/MainWindow.Issues.cs
index 6141baf..08435ff 100644
--- a/UVtools.WPF/MainWindow.Issues.cs
+++ b/UVtools.WPF/MainWindow.Issues.cs
@@ -115,20 +115,65 @@ public partial class MainWindow
return retValue;
}*/
- public async void OnClickIssueRemove()
+ public async void RemoveRepairIssues(IEnumerable<MainIssue> issues, bool promptConfirmation = true, bool suctionCupDrill = true)
{
- if (IssuesGrid.SelectedItems.Count == 0) return;
+ if (!issues.Any()) return;
+
+ uint emptyLayers = 0;
+ uint islands = 0;
+ uint resinTraps = 0;
+ uint suctionCups = 0;
+ foreach (MainIssue mainIssue in issues)
+ {
+ switch (mainIssue.Type)
+ {
+ case MainIssue.IssueType.Island:
+ islands++;
+ break;
+ case MainIssue.IssueType.Overhang:
+ // No action
+ break;
+ case MainIssue.IssueType.ResinTrap:
+ resinTraps++;
+ break;
+ case MainIssue.IssueType.SuctionCup:
+ suctionCups++;
+ break;
+ case MainIssue.IssueType.TouchingBound:
+ // No action
+ break;
+ case MainIssue.IssueType.PrintHeight:
+ // No action
+ break;
+ case MainIssue.IssueType.EmptyLayer:
+ emptyLayers++;
+ break;
+ case MainIssue.IssueType.Debug:
+ // No action
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
- if (await this.MessageBoxQuestion($"Are you sure you want to remove all selected {IssuesGrid.SelectedItems.Count} issues?\n\n" +
- "Warning: Removing an island can cause other issues to appear if there is material present in the layers above it.\n" +
- "Always check previous and next layers before performing an island removal.", $"Remove {IssuesGrid.SelectedItems.Count} Issues?") != ButtonResult.Yes) return;
+ if (emptyLayers == 0 && islands == 0 && resinTraps == 0 && suctionCups == 0) return;
+
+ if (promptConfirmation && await this.MessageBoxQuestion(
+ $"Are you sure you want to remove and/or repair all selected {issues.Count()} issues?\n\n" +
+ "If any, this option will:\n" +
+ (emptyLayers > 0 ? $"- Remove {emptyLayers} empty layer(s)\n" : string.Empty) +
+ (islands > 0 ? $"- Remove {emptyLayers} island(s)\n" : string.Empty) +
+ (resinTraps > 0 ? $"- Fill/solidify {resinTraps} resin trap(s)\n" : string.Empty) +
+ (suctionCups > 0 ? $"- Drill {suctionCups} suction cup(s) at it's center\n" : string.Empty) +
+ "\nWarning: Removing an island can cause other issues to appear if there is material present in the layers above it.\n" +
+ "Always check previous and next layers before performing an island removal.", $"Remove {issues.Count()} Issues?") != ButtonResult.Yes) return;
var processParallelIssues = new Dictionary<uint, List<Issue>>();
var processSuctionCups = new List<MainIssue>();
var layersToRemove = new List<uint>();
- foreach (MainIssue mainIssue in IssuesGrid.SelectedItems)
+ foreach (MainIssue mainIssue in issues)
{
switch (mainIssue.Type)
{
@@ -148,6 +193,22 @@ public partial class MainWindow
}
continue;
case MainIssue.IssueType.SuctionCup:
+ if (!suctionCupDrill)
+ {
+ foreach (var issue in mainIssue)
+ {
+ // Islands and resin traps
+ if (!processParallelIssues.TryGetValue(issue.LayerIndex, out var issueList))
+ {
+ issueList = new List<Issue>();
+ processParallelIssues.Add(issue.LayerIndex, issueList);
+ }
+
+ issueList.Add(issue);
+
+ }
+ continue;
+ }
if(mainIssue.StartLayerIndex == 0) continue;
processSuctionCups.Add(mainIssue);
continue;
@@ -192,7 +253,7 @@ public partial class MainWindow
edited = true;
}
- else if (issue.Type == MainIssue.IssueType.ResinTrap)
+ else if (issue.Type == MainIssue.IssueType.ResinTrap || (issue.Type == MainIssue.IssueType.SuctionCup && !suctionCupDrill))
{
var issueOfContours = (IssueOfContours)issue;
using var contours = new VectorOfVectorOfPoint(issueOfContours.Contours);
@@ -219,13 +280,13 @@ public partial class MainWindow
OperationLayerRemove.RemoveLayers(SlicerFile, layersToRemove);
}
- issueRemoveList.AddRange(SlicerFile.IssueManager.DrillSuctionCupsForIssues(processSuctionCups, UserSettings.Instance.LayerRepair.SuctionCupsVentHole, Progress));
+ if(suctionCupDrill) issueRemoveList.AddRange(SlicerFile.IssueManager.DrillSuctionCupsForIssues(processSuctionCups, UserSettings.Instance.LayerRepair.SuctionCupsVentHole, Progress));
}
catch (Exception ex)
{
Dispatcher.UIThread.InvokeAsync(async () =>
- await this.MessageBoxError(ex.ToString(), "Removal failed"));
+ await this.MessageBoxError(ex.ToString(), "Removal/repair failed"));
return false;
}
@@ -245,8 +306,14 @@ public partial class MainWindow
// Update GUI
- foreach (MainIssue issue in IssuesGrid.SelectedItems)
+ foreach (MainIssue issue in issues)
{
+ if (issue.IsSuctionCup && !suctionCupDrill)
+ {
+ issueRemoveList.Add(issue);
+ continue;
+ }
+
if (issue.Type
is not MainIssue.IssueType.Island
and not MainIssue.IssueType.ResinTrap
@@ -256,7 +323,7 @@ public partial class MainWindow
issueRemoveList.Add(issue);
- if (issue.Type == MainIssue.IssueType.Island)
+ if (issue.IsIsland)
{
var nextLayer = issue.StartLayerIndex + 1;
if (nextLayer >= SlicerFile.LayerCount) continue;
@@ -289,6 +356,41 @@ public partial class MainWindow
CanSave = true;
}
+ public void OnClickIssueRemove()
+ {
+ RemoveRepairIssues(IssuesGrid.SelectedItems.OfType<MainIssue>(), true);
+ }
+
+ public void SelectedIssuesIslandRemove()
+ {
+ if (IssuesGrid.SelectedItem is null) return;
+ RemoveRepairIssues(IssuesGrid.SelectedItems.OfType<MainIssue>().Where(mainIssue => mainIssue.IsIsland), false);
+ }
+
+ public void SelectedIssuesResinTrapSolidify()
+ {
+ if (IssuesGrid.SelectedItem is null) return;
+ RemoveRepairIssues(IssuesGrid.SelectedItems.OfType<MainIssue>().Where(mainIssue => mainIssue.IsResinTrap), false);
+ }
+
+ public void SelectedIssuesSuctionCupDrill()
+ {
+ if (IssuesGrid.SelectedItem is null) return;
+ RemoveRepairIssues(IssuesGrid.SelectedItems.OfType<MainIssue>().Where(mainIssue => mainIssue.IsSuctionCup), false);
+ }
+
+ public void SelectedIssuesSuctionCupSolidify()
+ {
+ if (IssuesGrid.SelectedItem is null) return;
+ RemoveRepairIssues(IssuesGrid.SelectedItems.OfType<MainIssue>().Where(mainIssue => mainIssue.IsSuctionCup), false, false);
+ }
+
+ public void SelectedIssuesEmptyLayerRemove()
+ {
+ if (IssuesGrid.SelectedItem is null) return;
+ RemoveRepairIssues(IssuesGrid.SelectedItems.OfType<MainIssue>().Where(mainIssue => mainIssue.IsEmptyLayer), false);
+ }
+
public async void OnClickIssueIgnore()
{
if ((_globalModifiers & KeyModifiers.Alt) != 0)
diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml
index 7534f69..ed04fb6 100644
--- a/UVtools.WPF/MainWindow.axaml
+++ b/UVtools.WPF/MainWindow.axaml
@@ -236,7 +236,7 @@
<WrapPanel
Orientation="Horizontal"
VerticalAlignment="Center">
- <TextBlock Text="{Binding SlicerFile.LayerHeight, StringFormat=Layer height: \{0\}mm}"/>
+ <TextBlock Text="{Binding SlicerFile.LayerHeight, StringFormat=Layer height: {0}mm}"/>
<TextBlock IsVisible="{Binding SlicerFile.CanUseBottomLayerCount}" Text=" | "/>
<TextBlock IsVisible="{Binding SlicerFile.CanUseBottomLayerCount}"
@@ -266,28 +266,28 @@
<TextBlock IsVisible="{Binding SlicerFile.PrintTimeHours}" Text=" | "/>
<TextBlock IsVisible="{Binding SlicerFile.PrintTimeHours}"
- Text="{Binding SlicerFile.PrintTimeString, StringFormat=Print time: \{0\}}"/>
+ Text="{Binding SlicerFile.PrintTimeString, StringFormat=Print time: {0}}"/>
<TextBlock IsVisible="{Binding SlicerFile.MaterialMilliliters}" Text=" | "/>
<TextBlock IsVisible="{Binding SlicerFile.MaterialMilliliters}"
- Text="{Binding SlicerFile.MaterialMilliliters, StringFormat=Used material: \{0\}ml}"/>
+ Text="{Binding SlicerFile.MaterialMilliliters, StringFormat=Used material: {0}ml}"/>
<TextBlock IsVisible="{Binding SlicerFile.MaterialCost}" Text=" | "/>
- <TextBlock IsVisible="{Binding SlicerFile.MaterialCost}" Text="{Binding SlicerFile.MaterialCost, StringFormat=Material cost: \{0\}€}"/>
+ <TextBlock IsVisible="{Binding SlicerFile.MaterialCost}" Text="{Binding SlicerFile.MaterialCost, StringFormat=Material cost: {0}€}"/>
<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\}}"/>
+ 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\}}"/>
+ Text="{Binding SlicerFile.MachineName, StringFormat=Machine: {0}}"/>
</WrapPanel>
</Border>
@@ -385,13 +385,13 @@
<TextBlock
VerticalAlignment="Center"
- Text="{Binding SlicerProperties.Count, StringFormat=Properties: \{0\}}"/>
+ Text="{Binding SlicerProperties.Count, StringFormat=Properties: {0}}"/>
<TextBlock VerticalAlignment="Center" Text="|"/>
<TextBlock
VerticalAlignment="Center"
- Text="{Binding SlicerFile.Configs.Length, StringFormat=Groups: \{0\}}"/>
+ Text="{Binding SlicerFile.Configs.Length, StringFormat=Groups: {0}}"/>
</StackPanel>
@@ -510,12 +510,12 @@
<Grid RowDefinitions="Auto,*">
<StackPanel Grid.Row="0" Orientation="Horizontal" Spacing="5">
<TextBlock
- Text="{Binding GCodeLines, StringFormat=Lines: \{0\}}"
+ Text="{Binding GCodeLines, StringFormat=Lines: {0}}"
VerticalAlignment="Center"/>
<TextBlock Text="|" VerticalAlignment="Center"/>
- <TextBlock Text="{Binding #GCodeText.Text.Length, StringFormat=Chars: \{0\}}"
+ <TextBlock Text="{Binding #GCodeText.Text.Length, StringFormat=Chars: {0}}"
VerticalAlignment="Center"/>
</StackPanel>
@@ -640,19 +640,17 @@
</StackPanel>
- <StackPanel
- Grid.Row="0"
- Orientation="Horizontal"
- Spacing="2"
- HorizontalAlignment="Right"
- VerticalAlignment="Center">
+ <StackPanel Grid.Row="0"
+ Orientation="Horizontal"
+ Spacing="2"
+ HorizontalAlignment="Right"
+ VerticalAlignment="Center">
- <Button
- IsEnabled="{Binding IsFileLoaded}"
- ToolTip.Tip="Attempt to repair issues"
- VerticalAlignment="Stretch"
- i:Attached.Icon="fa-solid fa-toolbox"
- Command="{Binding OnClickRepairIssues}"/>
+ <Button IsEnabled="{Binding IsFileLoaded}"
+ ToolTip.Tip="Attempt to repair issues"
+ VerticalAlignment="Stretch"
+ i:Attached.Icon="fa-solid fa-toolbox"
+ Command="{Binding OnClickRepairIssues}"/>
<uc:ButtonWithIcon VerticalAlignment="Stretch"
ToolTip.Tip="Compute Issues.
@@ -736,7 +734,18 @@
IsReadOnly="True"
ClipboardCopyMode="None"
Items="{Binding IssuesGridItems}">
- <DataGrid.Columns>
+ <DataGrid.ContextMenu>
+ <ContextMenu IsVisible="{Binding #IssuesGrid.SelectedItem, Converter={x:Static ObjectConverters.IsNotNull}}">
+ <MenuItem i:MenuItem.Icon="fa-solid fa-eye-slash" Command="{Binding OnClickIssueIgnore}" Header="Ignore issue(s)"/>
+ <Separator/>
+ <MenuItem i:MenuItem.Icon="fa-solid fa-trash-can" Command="{Binding SelectedIssuesIslandRemove}" IsVisible="{Binding #IssuesGrid.SelectedItem.IsIsland}" Header="Remove island(s)"/>
+ <MenuItem i:MenuItem.Icon="fa-solid fa-diamond" Command="{Binding SelectedIssuesResinTrapSolidify}" IsVisible="{Binding #IssuesGrid.SelectedItem.IsResinTrap}" Header="Fill/solidify resin trap(s)"/>
+ <MenuItem i:MenuItem.Icon="fa-solid fa-circle-dot" Command="{Binding SelectedIssuesSuctionCupDrill}" IsVisible="{Binding #IssuesGrid.SelectedItem.IsSuctionCup}" Header="Drill suction cup(s)"/>
+ <MenuItem i:MenuItem.Icon="fa-solid fa-diamond" Command="{Binding SelectedIssuesSuctionCupSolidify}" IsVisible="{Binding #IssuesGrid.SelectedItem.IsSuctionCup}" Header="Fill/solidify suction cup(s)"/>
+ <MenuItem i:MenuItem.Icon="fa-solid fa-trash-can" Command="{Binding SelectedIssuesEmptyLayerRemove}" IsVisible="{Binding #IssuesGrid.SelectedItem.IsEmptyLayer}" Header="Remove empty layer(s)"/>
+ </ContextMenu>
+ </DataGrid.ContextMenu>
+ <DataGrid.Columns>
<DataGridTextColumn Header="Type"
Binding="{Binding Type}"
@@ -1003,7 +1012,7 @@
Grid.Row="10"
Grid.Column="4"
VerticalAlignment="Center"
- Text="{Binding DrawingPixelDrawing.RemovePixelBrightnessPercent, StringFormat=\{0:0\}%}" />
+ Text="{Binding DrawingPixelDrawing.RemovePixelBrightnessPercent, StringFormat={}{0:0}%}" />
<TextBlock
Grid.Row="12"
@@ -1022,7 +1031,7 @@
Grid.Row="12"
Grid.Column="4"
VerticalAlignment="Center"
- Text="{Binding DrawingPixelDrawing.PixelBrightnessPercent, StringFormat=\{0:0\}%}" />
+ Text="{Binding DrawingPixelDrawing.PixelBrightnessPercent, StringFormat={}{0:0}%}" />
<TextBlock
Grid.Row="14"
@@ -1187,7 +1196,7 @@
Grid.Row="16"
Grid.Column="4"
VerticalAlignment="Center"
- Text="{Binding DrawingPixelText.RemovePixelBrightnessPercent, StringFormat=\{0:0\}%}" />
+ Text="{Binding DrawingPixelText.RemovePixelBrightnessPercent, StringFormat={}{0:0}%}" />
<TextBlock
Grid.Row="18"
@@ -1205,7 +1214,7 @@
Grid.Row="18"
Grid.Column="4"
VerticalAlignment="Center"
- Text="{Binding DrawingPixelText.PixelBrightnessPercent, StringFormat=\{0:0\}%}" />
+ Text="{Binding DrawingPixelText.PixelBrightnessPercent, StringFormat={}{0:0}%}" />
<TextBlock
@@ -1269,7 +1278,7 @@
Grid.Row="0"
Grid.Column="4"
VerticalAlignment="Center"
- Text="{Binding DrawingPixelEraser.PixelBrightnessPercent, StringFormat=\{0:0\}%}" />
+ Text="{Binding DrawingPixelEraser.PixelBrightnessPercent, StringFormat={}{0:0}%}" />
<TextBlock
Grid.Row="2"
@@ -1365,7 +1374,7 @@
Grid.Row="6"
Grid.Column="4"
VerticalAlignment="Center"
- Text="{Binding DrawingPixelSupport.PixelBrightnessPercent, StringFormat=\{0:0\}%}" />
+ Text="{Binding DrawingPixelSupport.PixelBrightnessPercent, StringFormat={}{0:0}%}" />
</Grid>
</StackPanel>
@@ -1434,7 +1443,7 @@
<uc:ButtonWithIcon IsEnabled="{Binding Drawings.Count}"
Icon="fa-solid fa-check"
Spacing="5"
- Text="{Binding Drawings.Count, StringFormat=Apply \{0\} operations}"
+ Text="{Binding Drawings.Count, StringFormat=Apply {0} operations}"
Command="{Binding DrawModifications}"
CommandParameter="false"/>
</StackPanel>
@@ -2072,7 +2081,7 @@
<TextBlock
ToolTip.Tip="Layer preview computation time."
Margin="5,0,0,0"
- VerticalAlignment="Center" Text="{Binding ShowLayerRenderMs, StringFormat=\{0\}ms}"/>
+ VerticalAlignment="Center" Text="{Binding ShowLayerRenderMs, StringFormat={}{0}ms}"/>
</WrapPanel>
</Grid>
</Grid>
@@ -2095,7 +2104,7 @@
Margin="10" Text="{Binding Progress.Title}"/>
<TextBlock
Grid.Row="1"
- Margin="10,0,10,10" Text="{Binding Progress.ElapsedTimeStr, StringFormat=Elapsed Time: \{0\}}"/>
+ Margin="10,0,10,10" Text="{Binding Progress.ElapsedTimeStr, StringFormat=Elapsed Time: {0}}"/>
<TextBlock
Grid.Row="2"
Margin="10,0,10,10" Text="{Binding Progress.Description}" HorizontalAlignment="Center"/>
diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj
index 8a10c97..e962877 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>3.5.0</Version>
+ <Version>3.5.1</Version>
<Platforms>AnyCPU;x64</Platforms>
<PackageIcon>UVtools.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>