diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1841534..6d59303 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,10 @@
* (Improvement) GUI is now scalable
* (Fix) Some bug found and fixed during convertion
+## 01/10/2020 - v0.8.4.1
+
+* (Fix) Tool - Pattern: Unable to use an anchor
+
## 01/10/2020 - v0.8.4.0
* (Add) Tool: Arithmetic operations
diff --git a/UVtools.Core/Layer/LayerManager.cs b/UVtools.Core/Layer/LayerManager.cs
index a869141..e8a0ced 100644
--- a/UVtools.Core/Layer/LayerManager.cs
+++ b/UVtools.Core/Layer/LayerManager.cs
@@ -1753,7 +1753,7 @@ namespace UVtools.Core
progress.Token.ThrowIfCancellationRequested();
if (operation.Anchor == Enumerations.Anchor.None) return;
- var operationMove = new OperationMove(BoundingRectangle, 0, 0, operation.Anchor)
+ var operationMove = new OperationMove(BoundingRectangle, operation.ImageWidth, operation.ImageHeight, operation.Anchor)
{
LayerIndexStart = operation.LayerIndexStart, LayerIndexEnd = operation.LayerIndexEnd
};
diff --git a/UVtools.Core/Operations/OperationBlur.cs b/UVtools.Core/Operations/OperationBlur.cs
index ad73309..e3042d1 100644
--- a/UVtools.Core/Operations/OperationBlur.cs
+++ b/UVtools.Core/Operations/OperationBlur.cs
@@ -13,6 +13,9 @@ namespace UVtools.Core.Operations
{
public sealed class OperationBlur : Operation
{
+ private BlurAlgorithm _blurOperation = BlurAlgorithm.Blur;
+ private uint _size = 1;
+
#region Overrides
public override string Title => "Blur";
@@ -55,26 +58,6 @@ namespace UVtools.Core.Operations
#endregion
- #region Properties
-
-
- public static StringTag[] BlurTypes => new[]
- {
- new StringTag("Blur: Normalized box filter", BlurAlgorithm.Blur),
- new StringTag("Pyramid: Down/up-sampling step of Gaussian pyramid decomposition", BlurAlgorithm.Pyramid),
- new StringTag("Median Blur: Each pixel becomes the median of its surrounding pixels", BlurAlgorithm.MedianBlur),
- new StringTag("Gaussian Blur: Each pixel is a sum of fractions of each pixel in its neighborhood", BlurAlgorithm.GaussianBlur),
- new StringTag("Filter 2D: Applies an arbitrary linear filter to an image", BlurAlgorithm.Filter2D),
- };
-
- public BlurAlgorithm BlurOperation { get; set; } = BlurAlgorithm.Blur;
-
- public uint Size { get; set; } = 1;
-
- public Kernel Kernel { get; set; } = new Kernel();
-
- #endregion
-
#region Enums
public enum BlurAlgorithm
{
@@ -85,5 +68,34 @@ namespace UVtools.Core.Operations
Filter2D
}
#endregion
+
+ #region Properties
+
+ public static StringTag[] BlurTypes => new[]
+ {
+ new StringTag("Blur: Normalized box filter", BlurAlgorithm.Blur),
+ new StringTag("Pyramid: Down/up-sampling step of Gaussian pyramid decomposition", BlurAlgorithm.Pyramid),
+ new StringTag("Median Blur: Each pixel becomes the median of its surrounding pixels", BlurAlgorithm.MedianBlur),
+ new StringTag("Gaussian Blur: Each pixel is a sum of fractions of each pixel in its neighborhood", BlurAlgorithm.GaussianBlur),
+ new StringTag("Filter 2D: Applies an arbitrary linear filter to an image", BlurAlgorithm.Filter2D),
+ };
+
+ public BlurAlgorithm BlurOperation
+ {
+ get => _blurOperation;
+ set => RaiseAndSetIfChanged(ref _blurOperation, value);
+ }
+
+ public uint Size
+ {
+ get => _size;
+ set => RaiseAndSetIfChanged(ref _size, value);
+ }
+
+ public Kernel Kernel { get; set; } = new Kernel();
+
+ #endregion
+
+
}
}
diff --git a/UVtools.Core/Operations/OperationMove.cs b/UVtools.Core/Operations/OperationMove.cs
index 93deb5d..60c9840 100644
--- a/UVtools.Core/Operations/OperationMove.cs
+++ b/UVtools.Core/Operations/OperationMove.cs
@@ -205,7 +205,7 @@ namespace UVtools.Core.Operations
{
}
- public OperationMove(Rectangle srcRoi, uint imageWidth = 0, uint imageHeight = 0, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter)
+ public OperationMove(Rectangle srcRoi, uint imageWidth, uint imageHeight, Enumerations.Anchor anchor = Enumerations.Anchor.MiddleCenter)
{
ROI = srcRoi;
ImageWidth = imageWidth;
diff --git a/UVtools.Core/Operations/OperationPattern.cs b/UVtools.Core/Operations/OperationPattern.cs
index e5d0e69..4297f42 100644
--- a/UVtools.Core/Operations/OperationPattern.cs
+++ b/UVtools.Core/Operations/OperationPattern.cs
@@ -13,6 +13,17 @@ namespace UVtools.Core.Operations
{
public class OperationPattern : Operation
{
+ private Enumerations.Anchor _anchor = Enumerations.Anchor.None;
+ private ushort _colSpacing;
+ private ushort _rowSpacing;
+ private ushort _maxColSpacing;
+ private ushort _maxRowSpacing;
+ private ushort _cols = 1;
+ private ushort _rows = 1;
+ private ushort _maxCols;
+ private ushort _maxRows;
+ private bool _isWithinBoundary = true;
+
#region Overrides
public override string Title => "Pattern";
@@ -45,24 +56,121 @@ namespace UVtools.Core.Operations
#endregion
- public Enumerations.Anchor Anchor { get; set; }
+ public Enumerations.Anchor Anchor
+ {
+ get => _anchor;
+ set => RaiseAndSetIfChanged(ref _anchor, value);
+ }
public uint ImageWidth { get; }
public uint ImageHeight { get; }
- public ushort MarginCol { get; set; }
- public ushort MarginRow { get; set; }
+ public ushort Cols
+ {
+ get => _cols;
+ set
+ {
+ if (!RaiseAndSetIfChanged(ref _cols, value)) return;
+ RaisePropertyChanged(nameof(InfoCols));
+ RaisePropertyChanged(nameof(InfoWidthStr));
+ RaisePropertyChanged(nameof(InfoModelWithinBoundaryStr));
+ ValidateBounds();
+ }
+ }
- public ushort MaxMarginCol { get; set; }
- public ushort MaxMarginRow { get; set; }
+ public ushort Rows
+ {
+ get => _rows;
+ set
+ {
+ if (!RaiseAndSetIfChanged(ref _rows, value)) return;
+ RaisePropertyChanged(nameof(InfoRows));
+ RaisePropertyChanged(nameof(InfoHeightStr));
+ RaisePropertyChanged(nameof(InfoModelWithinBoundaryStr));
+ ValidateBounds();
+ }
+ }
- public ushort Cols { get; set; } = 1;
- public ushort Rows { get; set; } = 1;
+ public ushort MaxCols
+ {
+ get => _maxCols;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _maxCols, value)) return;
+ RaisePropertyChanged(nameof(InfoCols));
+ ValidateBounds();
+ }
+ }
- public ushort MaxCols { get; set; }
- public ushort MaxRows { get; set; }
+ public ushort MaxRows
+ {
+ get => _maxRows;
+ set
+ {
+ if (!RaiseAndSetIfChanged(ref _maxRows, value)) return;
+ RaisePropertyChanged(nameof(InfoRows));
+ ValidateBounds();
+ }
+ }
- public Size GetPatternVolume => new Size(Cols * ROI.Width + (Cols - 1) * MarginCol, Rows * ROI.Height + (Rows - 1) * MarginRow);
+ public ushort ColSpacing
+ {
+ get => _colSpacing;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _colSpacing, value)) return;
+ RaisePropertyChanged(nameof(InfoWidthStr));
+ RaisePropertyChanged(nameof(InfoModelWithinBoundaryStr));
+ ValidateBounds();
+ }
+ }
+
+ public ushort RowSpacing
+ {
+ get => _rowSpacing;
+ set
+ {
+ if (!RaiseAndSetIfChanged(ref _rowSpacing, value)) return;
+ RaisePropertyChanged(nameof(InfoHeightStr));
+ RaisePropertyChanged(nameof(InfoModelWithinBoundaryStr));
+ ValidateBounds();
+ }
+ }
+
+ public ushort MaxColSpacing
+ {
+ get => _maxColSpacing;
+ set => RaiseAndSetIfChanged(ref _maxColSpacing, value);
+ }
+
+ public ushort MaxRowSpacing
+ {
+ get => _maxRowSpacing;
+ set => RaiseAndSetIfChanged(ref _maxRowSpacing, value);
+ }
+
+ public string InfoCols => $"Columns: {Cols} / {MaxCols}";
+ public string InfoRows => $"Rows: {Rows} / {MaxRows}";
+
+ public string InfoWidthStr =>
+ $"Width: {GetPatternVolume.Width} (Min: {ROI.Width}, Max: {ImageWidth})";
+
+ public string InfoHeightStr =>
+ $"Width: {GetPatternVolume.Height} (Min: {ROI.Height}, Max: {ImageHeight})";
+
+ public bool IsWithinBoundary
+ {
+ get => _isWithinBoundary;
+ set
+ {
+ if (!RaiseAndSetIfChanged(ref _isWithinBoundary, value)) return;
+ RaisePropertyChanged(nameof(InfoModelWithinBoundaryStr));
+ }
+ }
+
+ public string InfoModelWithinBoundaryStr => "Model within boundary: " + (_isWithinBoundary ? "Yes" : "No");
+
+ public Size GetPatternVolume => new Size(Cols * ROI.Width + (Cols - 1) * ColSpacing, Rows * ROI.Height + (Rows - 1) * RowSpacing);
public OperationPattern()
{
@@ -74,6 +182,12 @@ namespace UVtools.Core.Operations
ImageHeight = (uint) resolution.Height;
SetRoi(srcRoi);
+ Fill();
+ }
+
+ public void SetAnchor(byte value)
+ {
+ Anchor = (Enumerations.Anchor)value;
}
public void SetRoi(Rectangle srcRoi)
@@ -83,73 +197,29 @@ namespace UVtools.Core.Operations
MaxCols = (ushort)(ImageWidth / srcRoi.Width);
MaxRows = (ushort)(ImageHeight / srcRoi.Height);
- MaxMarginCol = CalculateMarginCol(MaxCols);
- MaxMarginRow = CalculateMarginRow(MaxRows);
+ MaxColSpacing = CalculateAutoColSpacing(MaxCols);
+ MaxRowSpacing = CalculateAutoRowSpacing(MaxRows);
}
-
- /*public void CalculateDstRoi()
- {
- _dstRoi.Size = SrcRoi.Size;
-
- switch (Anchor)
- {
- case Anchor.TopLeft:
- _dstRoi.Location = new Point(0, 0);
- break;
- case Anchor.TopCenter:
- _dstRoi.Location = new Point((int)(ImageWidth / 2 - SrcRoi.Width / 2), 0);
- break;
- case Anchor.TopRight:
- _dstRoi.Location = new Point((int)(ImageWidth - SrcRoi.Width), 0);
- break;
- case Anchor.MiddleLeft:
- _dstRoi.Location = new Point(0, (int)(ImageHeight / 2 - SrcRoi.Height / 2));
- break;
- case Anchor.MiddleCenter:
- _dstRoi.Location = new Point((int)(ImageWidth / 2 - SrcRoi.Width / 2), (int)(ImageHeight / 2 - SrcRoi.Height / 2));
- break;
- case Anchor.MiddleRight:
- _dstRoi.Location = new Point((int)(ImageWidth - SrcRoi.Width), (int)(ImageHeight / 2 - SrcRoi.Height / 2));
- break;
- case Anchor.BottomLeft:
- _dstRoi.Location = new Point(0, (int)(ImageHeight - SrcRoi.Height));
- break;
- case Anchor.BottomCenter:
- _dstRoi.Location = new Point((int)(ImageWidth / 2 - SrcRoi.Width / 2), (int)(ImageHeight - SrcRoi.Height));
- break;
- case Anchor.BottomRight:
- _dstRoi.Location = new Point((int)(ImageWidth - SrcRoi.Width), (int)(ImageHeight - SrcRoi.Height));
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
-
- _dstRoi.X += MarginLeft;
- _dstRoi.X -= MarginRight;
- _dstRoi.Y += MarginTop;
- _dstRoi.Y -= MarginBottom;
- }*/
-
///
/// Fills the plate with maximum cols and rows
///
public void Fill()
{
Cols = MaxCols;
- MarginCol = MaxMarginCol;
+ ColSpacing = MaxColSpacing;
Rows = MaxRows;
- MarginRow = MaxMarginRow;
+ RowSpacing = MaxRowSpacing;
}
- public ushort CalculateMarginCol(ushort cols)
+ public ushort CalculateAutoColSpacing(ushort cols)
{
if (cols <= 1) return 0;
return (ushort)((ImageWidth - ROI.Width * cols) / cols);
}
- public ushort CalculateMarginRow(ushort rows)
+ public ushort CalculateAutoRowSpacing(ushort rows)
{
if (rows <= 1) return 0;
return (ushort)((ImageHeight - ROI.Height * rows) / rows);
@@ -160,15 +230,24 @@ namespace UVtools.Core.Operations
var patternVolume = GetPatternVolume;
return new Rectangle(new Point(
- (int) (col * ROI.Width + col * MarginCol + (ImageWidth - patternVolume.Width) / 2),
- (int) (row * ROI.Height + row * MarginRow + (ImageHeight - patternVolume.Height) / 2)), ROI.Size);
+ (int) (col * ROI.Width + col * ColSpacing + (ImageWidth - patternVolume.Width) / 2),
+ (int) (row * ROI.Height + row * RowSpacing + (ImageHeight - patternVolume.Height) / 2)), ROI.Size);
+ }
+
+ public void FillColumnSpacing()
+ {
+ ColSpacing = CalculateAutoColSpacing(_cols);
+ }
+
+ public void FillRowSpacing()
+ {
+ RowSpacing = CalculateAutoRowSpacing(_rows);
}
public bool ValidateBounds()
{
var volume = GetPatternVolume;
- if (volume.Width > ImageWidth || volume.Height > ImageHeight) return false;
- return true;
+ return IsWithinBoundary = volume.Width <= ImageWidth && volume.Height <= ImageHeight;
}
}
}
diff --git a/UVtools.GUI/Controls/Tools/CtrlToolPattern.cs b/UVtools.GUI/Controls/Tools/CtrlToolPattern.cs
index 3519d2b..1721a20 100644
--- a/UVtools.GUI/Controls/Tools/CtrlToolPattern.cs
+++ b/UVtools.GUI/Controls/Tools/CtrlToolPattern.cs
@@ -46,8 +46,8 @@ namespace UVtools.GUI.Controls.Tools
nmCols.Maximum = Operation.MaxCols;
nmRows.Maximum = Operation.MaxRows;
- nmMarginCol.Value = Operation.MaxMarginCol;
- nmMarginRow.Value = Operation.MaxMarginRow;
+ nmMarginCol.Value = Operation.MaxColSpacing;
+ nmMarginRow.Value = Operation.MaxRowSpacing;
nmCols.Value = Operation.MaxCols;
nmRows.Value = Operation.MaxRows;
Operation.Fill();
@@ -86,8 +86,8 @@ namespace UVtools.GUI.Controls.Tools
i++;
}
- Operation.MarginCol = (ushort)nmMarginCol.Value;
- Operation.MarginRow = (ushort)nmMarginRow.Value;
+ Operation.ColSpacing = (ushort)nmMarginCol.Value;
+ Operation.RowSpacing = (ushort)nmMarginRow.Value;
Operation.Cols = (ushort)nmCols.Value;
Operation.Rows = (ushort)nmRows.Value;
@@ -102,8 +102,8 @@ namespace UVtools.GUI.Controls.Tools
ButtonOkEnabled = insideBounds && (Operation.Cols > 1 || Operation.Rows > 1);
lbInsideBounds.Text = "Model within boundary: " + (insideBounds ? "Yes" : "No");
- lbVolumeWidth.Text = $"Width: {Operation.GetPatternVolume.Width} (Min:{Operation.ROI.Width}, Max:{Operation.ImageWidth})";
- lbVolumeHeight.Text = $"Height: {Operation.GetPatternVolume.Height} (Min:{Operation.ROI.Height}, Max:{Operation.ImageHeight})";
+ lbVolumeWidth.Text = $"Width: {Operation.GetPatternVolume.Width} (Min: {Operation.ROI.Width}, Max: {Operation.ImageWidth})";
+ lbVolumeHeight.Text = $"Height: {Operation.GetPatternVolume.Height} (Min: {Operation.ROI.Height}, Max: {Operation.ImageHeight})";
lbCols.Text = $"Columns: {nmCols.Value} / {Operation.MaxCols}";
lbRows.Text = $"Rows: {nmRows.Value} / {Operation.MaxRows}";
@@ -114,14 +114,14 @@ namespace UVtools.GUI.Controls.Tools
if (ReferenceEquals(sender, btnAutoMarginCol))
{
UpdateOperation();
- nmMarginCol.Value = Operation.CalculateMarginCol((ushort)nmCols.Value).Clamp(0, (ushort) nmMarginCol.Maximum);
+ nmMarginCol.Value = Operation.CalculateAutoColSpacing((ushort)nmCols.Value).Clamp(0, (ushort) nmMarginCol.Maximum);
return;
}
if (ReferenceEquals(sender, btnAutoMarginRow))
{
UpdateOperation();
- nmMarginRow.Value = Operation.CalculateMarginRow((ushort)nmRows.Value).Clamp(0, (ushort) nmMarginRow.Maximum);
+ nmMarginRow.Value = Operation.CalculateAutoRowSpacing((ushort)nmRows.Value).Clamp(0, (ushort) nmMarginRow.Maximum);
return;
}
}
diff --git a/UVtools.WPF/Controls/AdvancedImageBox.cs b/UVtools.WPF/Controls/AdvancedImageBox.cs
index e90492e..1a8c0c9 100644
--- a/UVtools.WPF/Controls/AdvancedImageBox.cs
+++ b/UVtools.WPF/Controls/AdvancedImageBox.cs
@@ -5,6 +5,7 @@ using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.CompilerServices;
+using System.Timers;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
@@ -13,6 +14,7 @@ using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Skia;
using Avalonia.Styling;
+using Avalonia.Threading;
using UVtools.Core.Extensions;
using UVtools.WPF.Extensions;
using Bitmap = Avalonia.Media.Imaging.Bitmap;
@@ -586,7 +588,19 @@ namespace UVtools.WPF.Controls
set => RaiseAndSetIfChanged(ref _zoomLevels, value);
}
+ private int _oldZoom = 100;
private int _zoom = 100;
+
+ ///
+ /// Gets or sets the zoom.
+ ///
+ /// The zoom.
+ public virtual int OldZoom
+ {
+ get => _oldZoom;
+ set => RaiseAndSetIfChanged(ref _oldZoom, value);
+ }
+
///
/// Gets or sets the zoom.
///
@@ -594,7 +608,24 @@ namespace UVtools.WPF.Controls
public virtual int Zoom
{
get => _zoom;
- set => SetZoom(value, value > Zoom ? ImageZoomActions.ZoomIn : ImageZoomActions.ZoomOut);
+ set
+ {
+ var previousZoom = _zoom;
+ var newZoom = value.Clamp(MinZoom, MaxZoom);
+
+ if (_zoom == newZoom) return;
+ _zoom = newZoom;
+ if (!UpdateViewPort())
+ {
+ InvalidateArrange();
+ }
+
+ OldZoom = previousZoom;
+ RaisePropertyChanged(nameof(Zoom));
+ //this.OnZoomChanged(EventArgs.Empty);
+ //this.OnZoomed(new ImageBoxZoomEventArgs(actions, source, previousZoom, this.Zoom));
+ //SetZoom(value, value > Zoom ? ImageZoomActions.ZoomIn : ImageZoomActions.ZoomOut);
+ }
}
public virtual bool IsActualSize => Zoom == 100;
@@ -751,7 +782,7 @@ namespace UVtools.WPF.Controls
int newZoom = GetZoomLevel(action);
RestoreSizeMode();
- SetZoom(newZoom, action);
+ Zoom = newZoom;
if (preservePosition && Zoom != currentZoom)
{
@@ -891,7 +922,7 @@ namespace UVtools.WPF.Controls
var y = imageLocation.Y * ZoomFactor - relativeDisplayPoint.Y;
Offset = new Vector(x, y);
- Debug.WriteLine(
+ /*Debug.WriteLine(
$"X/Y: {x},{y} | \n" +
$"Offset: {Offset} | \n" +
$"ZoomFactor: {ZoomFactor} | \n" +
@@ -899,32 +930,7 @@ namespace UVtools.WPF.Controls
$"MAX: {HorizontalScrollBarMaximum},{VerticalScrollBarMaximum} \n" +
$"ViewPort: {Viewport.Width},{Viewport.Height} \n" +
$"Container: {SizedContainer.Width},{SizedContainer.Height} \n" +
- $"Relative: {relativeDisplayPoint}");
- }
-
- ///
- /// Updates the current zoom.
- ///
- /// The new zoom value.
- /// The zoom actions that caused the value to be updated.
- /// The source of the zoom operation.
- private void SetZoom(int value, ImageZoomActions actions)
- {
- var previousZoom = _zoom;
- value = value.Clamp(MinZoom, MaxZoom);
-
- if (_zoom != value)
- {
- _zoom = value;
- if (!UpdateViewPort())
- {
- InvalidateArrange();
- }
-
- RaisePropertyChanged(nameof(Zoom));
- //this.OnZoomChanged(EventArgs.Empty);
- //this.OnZoomed(new ImageBoxZoomEventArgs(actions, source, previousZoom, this.Zoom));
- }
+ $"Relative: {relativeDisplayPoint}");*/
}
///
@@ -939,7 +945,7 @@ namespace UVtools.WPF.Controls
/// true if the current scrolling position should be preserved relative to the new zoom level, false to reset.
public virtual void ZoomIn(bool preservePosition)
{
- //this.PerformZoomIn(ImageBoxActionSources.Unknown, preservePosition);
+ PerformZoom(ImageZoomActions.ZoomIn, preservePosition);
}
///
@@ -954,7 +960,7 @@ namespace UVtools.WPF.Controls
/// true if the current scrolling position should be preserved relative to the new zoom level, false to reset.
public virtual void ZoomOut(bool preservePosition)
{
- // this.PerformZoomOut(ImageBoxActionSources.Unknown, preservePosition);
+ PerformZoom(ImageZoomActions.ZoomOut, preservePosition);
}
///
@@ -1029,16 +1035,34 @@ namespace UVtools.WPF.Controls
/// The rectangle to fit the view port to.
public virtual void ZoomToRegion(Rect rectangle)
{
- {
- var ratioX = Viewport.Width / rectangle.Width;
- var ratioY = Viewport.Height / rectangle.Height;
- var zoomFactor = Math.Min(ratioX, ratioY);
- var cx = rectangle.X + rectangle.Width / 2;
- var cy = rectangle.Y + rectangle.Height / 2;
+ var ratioX = Viewport.Width / rectangle.Width;
+ var ratioY = Viewport.Height / rectangle.Height;
+ var zoomFactor = Math.Min(ratioX, ratioY);
+ var cx = rectangle.X + rectangle.Width / 2;
+ var cy = rectangle.Y + rectangle.Height / 2;
+
+
+ Debug.WriteLine($"Before zoom: {Viewport}");
+ Zoom = (int) (zoomFactor * 100); // This function sets the zoom so viewport will change
+ Debug.WriteLine($"After zoom, viewport changed: {Viewport}");
+
+ //CenterAt(new Point(cx, cy)); // If i call this here, it will move to the wrong position due wrong viewport
+
+ Timer timer = new Timer(1)
+ {
+ AutoReset = false,
+ };
+ timer.Elapsed += (sender, args) =>
+ {
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ // This will fix centerAt position
+ Debug.WriteLine($"1ms delayed viewport: {Viewport}");
+ CenterAt(new Point(cx, cy));
+ });
+ };
+ timer.Start();
- Zoom = (int)(zoomFactor * 100);
- CenterAt(new Point(cx, cy));
- }
}
///
@@ -1110,7 +1134,8 @@ namespace UVtools.WPF.Controls
private void PerformActualSize()
{
SizeMode = SizeModes.Normal;
- SetZoom(100, ImageZoomActions.ActualSize | (Zoom < 100 ? ImageZoomActions.ZoomIn : ImageZoomActions.ZoomOut));
+ //SetZoom(100, ImageZoomActions.ActualSize | (Zoom < 100 ? ImageZoomActions.ZoomIn : ImageZoomActions.ZoomOut));
+ Zoom = 100;
}
private void EventOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
diff --git a/UVtools.WPF/Controls/KernelControl.axaml b/UVtools.WPF/Controls/KernelControl.axaml
index e93b461..53d39a6 100644
--- a/UVtools.WPF/Controls/KernelControl.axaml
+++ b/UVtools.WPF/Controls/KernelControl.axaml
@@ -12,6 +12,7 @@
VerticalAlignment="Stretch"
AcceptsReturn="True"
Watermark="Kernel matrix"
+ UseFloatingWatermark="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Text="{Binding MatrixText}"
diff --git a/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml b/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml
new file mode 100644
index 0000000..36bbe84
--- /dev/null
+++ b/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml.cs
new file mode 100644
index 0000000..4a03116
--- /dev/null
+++ b/UVtools.WPF/Controls/Tools/ToolBlurControl.axaml.cs
@@ -0,0 +1,59 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using UVtools.Core.Operations;
+
+namespace UVtools.WPF.Controls.Tools
+{
+ public class ToolBlurControl : ToolControl
+ {
+ private int _selectedAlgorithmIndex;
+ private bool _isSizeEnabled = true;
+ private bool _isKernelVisible;
+ private KernelControl _kernelCtrl;
+ public OperationBlur Operation { get; }
+
+ public int SelectedAlgorithmIndex
+ {
+ get => _selectedAlgorithmIndex;
+ set
+ {
+ if(!RaiseAndSetIfChanged(ref _selectedAlgorithmIndex, value) || value < 0) return;
+ Operation.BlurOperation = (OperationBlur.BlurAlgorithm) OperationBlur.BlurTypes[_selectedAlgorithmIndex].Tag;
+ IsKernelVisible = Operation.BlurOperation == OperationBlur.BlurAlgorithm.Filter2D;
+ IsSizeEnabled = Operation.BlurOperation != OperationBlur.BlurAlgorithm.Pyramid &&
+ Operation.BlurOperation != OperationBlur.BlurAlgorithm.Filter2D;
+ }
+ }
+
+ public bool IsSizeEnabled
+ {
+ get => _isSizeEnabled;
+ set => RaiseAndSetIfChanged(ref _isSizeEnabled, value);
+ }
+
+ public bool IsKernelVisible
+ {
+ get => _isKernelVisible;
+ set => RaiseAndSetIfChanged(ref _isKernelVisible, value);
+ }
+
+ public ToolBlurControl()
+ {
+ InitializeComponent();
+ BaseOperation = Operation = new OperationBlur();
+ _kernelCtrl = this.Find("KernelCtrl");
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override bool UpdateOperation()
+ {
+ Operation.Kernel.Matrix = _kernelCtrl.GetMatrix();
+ Operation.Kernel.Anchor = _kernelCtrl.Anchor;
+ return !(Operation.Kernel.Matrix is null);
+ }
+ }
+}
diff --git a/UVtools.WPF/Controls/Tools/ToolMoveControl.axaml b/UVtools.WPF/Controls/Tools/ToolMoveControl.axaml
index 56a87eb..e9e3953 100644
--- a/UVtools.WPF/Controls/Tools/ToolMoveControl.axaml
+++ b/UVtools.WPF/Controls/Tools/ToolMoveControl.axaml
@@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="550" d:DesignHeight="250"
x:Class="UVtools.WPF.Controls.Tools.ToolMoveControl">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UVtools.WPF/Controls/Tools/ToolPatternControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolPatternControl.axaml.cs
new file mode 100644
index 0000000..1b2bbc9
--- /dev/null
+++ b/UVtools.WPF/Controls/Tools/ToolPatternControl.axaml.cs
@@ -0,0 +1,66 @@
+using System;
+using Avalonia.Markup.Xaml;
+using UVtools.Core.Operations;
+using UVtools.WPF.Extensions;
+using UVtools.WPF.Windows;
+
+namespace UVtools.WPF.Controls.Tools
+{
+ public class ToolPatternControl : ToolControl
+ {
+ public OperationPattern Operation { get; }
+ private bool _isDefaultAnchorChecked = true;
+
+ public bool IsDefaultAnchorChecked
+ {
+ get => _isDefaultAnchorChecked;
+ set => RaiseAndSetIfChanged(ref _isDefaultAnchorChecked, value);
+ }
+
+ public ToolPatternControl()
+ {
+ InitializeComponent();
+ var roi = App.MainWindow.ROI;
+ BaseOperation = Operation = new OperationPattern(roi.IsEmpty ? App.SlicerFile.LayerManager.BoundingRectangle : roi, App.SlicerFile.Resolution);
+
+ if (Operation.MaxRows < 2 && Operation.MaxCols < 2)
+ {
+ App.MainWindow.MessageBoxInfo("The available free volume is not enough to pattern this object.\n" +
+ "To run this tool the free space must allow at least 1 copy.", "Unable to pattern");
+ CanRun = false;
+ return;
+ }
+
+
+ Operation.PropertyChanged += (sender, e) =>
+ {
+ if (e.PropertyName.Equals(nameof(Operation.IsWithinBoundary)))
+ {
+ ParentWindow.ButtonOkEnabled = Operation.IsWithinBoundary;
+ }
+ };
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void Callback(ToolWindow.Callbacks callback)
+ {
+ switch (callback)
+ {
+ case ToolWindow.Callbacks.Init:
+ ParentWindow.IsButton1Visible = true;
+ break;
+ case ToolWindow.Callbacks.ClearROI:
+ Operation.SetRoi(App.SlicerFile.LayerManager.BoundingRectangle);
+ break;
+ case ToolWindow.Callbacks.Button1:
+ Operation.Fill();
+ IsDefaultAnchorChecked = true;
+ break;
+ }
+ }
+ }
+}
diff --git a/UVtools.WPF/Controls/WindowEx.cs b/UVtools.WPF/Controls/WindowEx.cs
index f3b062d..5f870f2 100644
--- a/UVtools.WPF/Controls/WindowEx.cs
+++ b/UVtools.WPF/Controls/WindowEx.cs
@@ -71,10 +71,10 @@ namespace UVtools.WPF.Controls
Close(DialogResult);
}
- public void ResetDataContext()
+ public virtual void ResetDataContext()
{
var old = DataContext;
- DataContext = new object();
+ DataContext = null;
DataContext = old;
}
}
diff --git a/UVtools.WPF/MainWindow.axaml b/UVtools.WPF/MainWindow.axaml
index 978b17e..7f1803f 100644
--- a/UVtools.WPF/MainWindow.axaml
+++ b/UVtools.WPF/MainWindow.axaml
@@ -248,7 +248,9 @@
-
+
@@ -759,7 +762,6 @@
Maximum="{Binding SliderMaximumValue}"
Value="{Binding ActualLayer}"
TickFrequency="1"
- TickPlacement="Outside"
SmallChange="1"
LargeChange="10"
IsSnapToTickEnabled="True"
diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs
index 6c66b9d..4ddbaf8 100644
--- a/UVtools.WPF/MainWindow.axaml.cs
+++ b/UVtools.WPF/MainWindow.axaml.cs
@@ -1135,8 +1135,8 @@ namespace UVtools.WPF
public PixelPicker LayerPixelPicker { get; } = new PixelPicker();
- public string LayerZoomStr => $"{LayerImageBox.Zoom / 100}x" +
- (AppSettings.LockedZoomLevel == LayerImageBox.Zoom ? "🔒" : string.Empty);
+ public string LayerZoomStr => $"{LayerImageBox.Zoom / 100m}x" +
+ (AppSettings.LockedZoomLevel == LayerImageBox.Zoom ? " 🔒" : string.Empty);
public string LayerResolutionStr => SlicerFile?.Resolution.ToString() ?? "Unloaded";
public uint ActualLayer
@@ -1144,6 +1144,7 @@ namespace UVtools.WPF
get => _actualLayer;
set
{
+ if (DataContext is null) return;
if (!RaiseAndSetIfChanged(ref _actualLayer, value)) return;
ShowLayer();
InvalidateLayerNavigation();
@@ -1240,7 +1241,16 @@ namespace UVtools.WPF
menuTool.Click += async (sender, args) => await ShowRunOperation(operation.GetType());
}
}
-
+
+
+ LayerImageBox.PropertyChanged += (sender, e) =>
+ {
+ if (e.PropertyName == nameof(LayerImageBox.Zoom))
+ {
+ RaisePropertyChanged(nameof(LayerZoomStr));
+ return;
+ }
+ };
/*LayerSlider.PropertyChanged += (sender, args) =>
{