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) => {