diff --git a/UVtools.Core/Enumerations.cs b/UVtools.Core/Enumerations.cs
index 052e28a..45f7ad6 100644
--- a/UVtools.Core/Enumerations.cs
+++ b/UVtools.Core/Enumerations.cs
@@ -6,6 +6,17 @@ namespace UVtools.Core
{
public class Enumerations
{
+ public enum LayerRangeSelection : byte
+ {
+ None,
+ All,
+ Current,
+ Bottom,
+ Normal,
+ First,
+ Last
+ }
+
public enum FlipDirection : byte
{
Horizontally,
diff --git a/UVtools.Core/Operations/Operation.cs b/UVtools.Core/Operations/Operation.cs
index 7bc3b79..648d540 100644
--- a/UVtools.Core/Operations/Operation.cs
+++ b/UVtools.Core/Operations/Operation.cs
@@ -21,11 +21,18 @@ namespace UVtools.Core.Operations
///
public string Id => GetType().Name.Remove(0, ClassNameLength);
+ public virtual Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.All;
+
///
/// Gets if this operation should set layer range to the actual layer index on layer preview
///
public virtual bool PassActualLayerIndex => false;
+ ///
+ /// Gets if this control can make use of ROI
+ ///
+ public virtual bool CanROI { get; set; } = true;
+
///
/// Gets if this operation supports cancellation
///
diff --git a/UVtools.Core/Operations/OperationChangeResolution.cs b/UVtools.Core/Operations/OperationChangeResolution.cs
index 9c7e161..b1af86f 100644
--- a/UVtools.Core/Operations/OperationChangeResolution.cs
+++ b/UVtools.Core/Operations/OperationChangeResolution.cs
@@ -41,6 +41,8 @@ namespace UVtools.Core.Operations
#region Overrides
+ public override Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override bool CanROI { get; set; } = false;
public override string Title => "Change print resolution";
public override string Description =>
"Crops or resizes all layer images to fit an alternate print area\n\n" +
diff --git a/UVtools.Core/Operations/OperationEditParameters.cs b/UVtools.Core/Operations/OperationEditParameters.cs
index 7d55dca..77e08c0 100644
--- a/UVtools.Core/Operations/OperationEditParameters.cs
+++ b/UVtools.Core/Operations/OperationEditParameters.cs
@@ -12,6 +12,10 @@ namespace UVtools.Core.Operations
{
public class OperationEditParameters : Operation
{
+ public override Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.None;
+
+ public override bool CanROI { get; set; } = false;
+
public override string Title => "Edit print parameters";
public override string Description =>
diff --git a/UVtools.Core/Operations/OperationFlip.cs b/UVtools.Core/Operations/OperationFlip.cs
index fe24205..fa1a508 100644
--- a/UVtools.Core/Operations/OperationFlip.cs
+++ b/UVtools.Core/Operations/OperationFlip.cs
@@ -6,6 +6,7 @@
* of this license document, but changing it is not allowed.
*/
+using System;
using Emgu.CV.CvEnum;
namespace UVtools.Core.Operations
@@ -27,8 +28,8 @@ namespace UVtools.Core.Operations
: $"Flipping {(MakeCopy == true ? "and blending " : "")}layers {LayerIndexStart} through {LayerIndexEnd} {FlipDirection}";
public override string ProgressAction => "Flipped layers";
-
- public Enumerations.FlipDirection FlipDirection { get; set; }
+
+ public Enumerations.FlipDirection FlipDirection { get; set; } = Enumerations.FlipDirection.Horizontally;
public bool MakeCopy { get; set; }
@@ -54,6 +55,8 @@ namespace UVtools.Core.Operations
}
}
+ public static Array FlipDirections => Enum.GetValues(typeof(Enumerations.FlipDirection));
+
}
diff --git a/UVtools.Core/Operations/OperationLayerClone.cs b/UVtools.Core/Operations/OperationLayerClone.cs
index db078cb..1d6214e 100644
--- a/UVtools.Core/Operations/OperationLayerClone.cs
+++ b/UVtools.Core/Operations/OperationLayerClone.cs
@@ -14,6 +14,8 @@ namespace UVtools.Core.Operations
{
#region Overrides
+ public override Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.Current;
+ public override bool CanROI { get; set; } = false;
public override bool PassActualLayerIndex => true;
public override string Title => "Clone layer(s)";
diff --git a/UVtools.Core/Operations/OperationLayerImport.cs b/UVtools.Core/Operations/OperationLayerImport.cs
index b7c8502..7756a6a 100644
--- a/UVtools.Core/Operations/OperationLayerImport.cs
+++ b/UVtools.Core/Operations/OperationLayerImport.cs
@@ -21,6 +21,9 @@ namespace UVtools.Core.Operations
public sealed class OperationLayerImport : Operation
{
#region Overrides
+
+ public override Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override bool CanROI { get; set; } = false;
public override string Title => "Import Layers";
public override string Description =>
diff --git a/UVtools.Core/Operations/OperationLayerReHeight.cs b/UVtools.Core/Operations/OperationLayerReHeight.cs
index 60da0dd..a7f4f8b 100644
--- a/UVtools.Core/Operations/OperationLayerReHeight.cs
+++ b/UVtools.Core/Operations/OperationLayerReHeight.cs
@@ -18,6 +18,8 @@ namespace UVtools.Core.Operations
{
#region Overrides
+ public override Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.None;
+ public override bool CanROI { get; set; } = false;
public override string Title => "Adjust layer height";
public override string Description =>
"Adjust the layer height of the model\n\n" +
diff --git a/UVtools.Core/Operations/OperationLayerRemove.cs b/UVtools.Core/Operations/OperationLayerRemove.cs
index cc71e62..b2fb9ca 100644
--- a/UVtools.Core/Operations/OperationLayerRemove.cs
+++ b/UVtools.Core/Operations/OperationLayerRemove.cs
@@ -13,6 +13,8 @@ namespace UVtools.Core.Operations
{
#region Overrides
+ public override Enumerations.LayerRangeSelection LayerRangeSelection => Enumerations.LayerRangeSelection.Current;
+ public override bool CanROI { get; set; } = false;
public override bool PassActualLayerIndex => true;
public override string Title => "Remove layers";
diff --git a/UVtools.Core/Operations/OperationRepairLayers.cs b/UVtools.Core/Operations/OperationRepairLayers.cs
index 0b90180..4291576 100644
--- a/UVtools.Core/Operations/OperationRepairLayers.cs
+++ b/UVtools.Core/Operations/OperationRepairLayers.cs
@@ -14,6 +14,7 @@ namespace UVtools.Core.Operations
{
public class OperationRepairLayers : Operation
{
+ public override bool CanROI { get; set; } = false;
public override string Title => "Repair layers and issues";
public override string Description => null;
diff --git a/UVtools.GUI/Forms/FrmToolWindow.Designer.cs b/UVtools.GUI/Forms/FrmToolWindow.Designer.cs
index fe732e0..65cd767 100644
--- a/UVtools.GUI/Forms/FrmToolWindow.Designer.cs
+++ b/UVtools.GUI/Forms/FrmToolWindow.Designer.cs
@@ -41,6 +41,7 @@ namespace UVtools.GUI.Forms
this.lbLayerRangeFromMM = new System.Windows.Forms.Label();
this.lbLayerRangeToMM = new System.Windows.Forms.Label();
this.nmLayerRangeEnd = new System.Windows.Forms.NumericUpDown();
+ this.btnLayerRangeSelect = new UVtools.GUI.Controls.SplitButton();
this.cmLayerRange = new System.Windows.Forms.ContextMenuStrip(this.components);
this.btnLayerRangeAllLayers = new System.Windows.Forms.ToolStripMenuItem();
this.btnLayerRangeCurrentLayer = new System.Windows.Forms.ToolStripMenuItem();
@@ -61,11 +62,10 @@ namespace UVtools.GUI.Forms
this.btnOk = new System.Windows.Forms.Button();
this.pnROI = new System.Windows.Forms.Panel();
this.gbROI = new System.Windows.Forms.GroupBox();
+ this.cbClearRoiAfterOperation = new System.Windows.Forms.CheckBox();
this.lbRoi = new System.Windows.Forms.Label();
this.btnClearRoi = new System.Windows.Forms.Button();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
- this.cbClearRoiAfterOperation = new System.Windows.Forms.CheckBox();
- this.btnLayerRangeSelect = new UVtools.GUI.Controls.SplitButton();
this.pnDescription.SuspendLayout();
this.pnLayerRange.SuspendLayout();
this.gbLayerRange.SuspendLayout();
@@ -193,6 +193,16 @@ namespace UVtools.GUI.Forms
this.nmLayerRangeEnd.TabIndex = 14;
this.nmLayerRangeEnd.ValueChanged += new System.EventHandler(this.EventValueChanged);
//
+ // btnLayerRangeSelect
+ //
+ this.btnLayerRangeSelect.Location = new System.Drawing.Point(359, 31);
+ this.btnLayerRangeSelect.Menu = this.cmLayerRange;
+ this.btnLayerRangeSelect.Name = "btnLayerRangeSelect";
+ this.btnLayerRangeSelect.Size = new System.Drawing.Size(180, 26);
+ this.btnLayerRangeSelect.TabIndex = 18;
+ this.btnLayerRangeSelect.Text = "Select";
+ this.btnLayerRangeSelect.UseVisualStyleBackColor = true;
+ //
// cmLayerRange
//
this.cmLayerRange.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
@@ -434,6 +444,16 @@ namespace UVtools.GUI.Forms
this.gbROI.Text = "ROI - Region of interest";
this.toolTip.SetToolTip(this.gbROI, "The impact of the operation will be limited to the ROI, which can be set directly" +
" from the layer preview window.");
+ //
+ // cbClearRoiAfterOperation
+ //
+ this.cbClearRoiAfterOperation.AutoSize = true;
+ this.cbClearRoiAfterOperation.Location = new System.Drawing.Point(11, 61);
+ this.cbClearRoiAfterOperation.Name = "cbClearRoiAfterOperation";
+ this.cbClearRoiAfterOperation.Size = new System.Drawing.Size(292, 24);
+ this.cbClearRoiAfterOperation.TabIndex = 3;
+ this.cbClearRoiAfterOperation.Text = "Clear ROI after perform the operation";
+ this.cbClearRoiAfterOperation.UseVisualStyleBackColor = true;
//
// lbRoi
//
@@ -464,26 +484,6 @@ namespace UVtools.GUI.Forms
this.toolTip.ToolTipIcon = System.Windows.Forms.ToolTipIcon.Info;
this.toolTip.ToolTipTitle = "Information";
//
- // cbClearRoiAfterOperation
- //
- this.cbClearRoiAfterOperation.AutoSize = true;
- this.cbClearRoiAfterOperation.Location = new System.Drawing.Point(11, 61);
- this.cbClearRoiAfterOperation.Name = "cbClearRoiAfterOperation";
- this.cbClearRoiAfterOperation.Size = new System.Drawing.Size(292, 24);
- this.cbClearRoiAfterOperation.TabIndex = 3;
- this.cbClearRoiAfterOperation.Text = "Clear ROI after perform the operation";
- this.cbClearRoiAfterOperation.UseVisualStyleBackColor = true;
- //
- // btnLayerRangeSelect
- //
- this.btnLayerRangeSelect.Location = new System.Drawing.Point(359, 31);
- this.btnLayerRangeSelect.Menu = this.cmLayerRange;
- this.btnLayerRangeSelect.Name = "btnLayerRangeSelect";
- this.btnLayerRangeSelect.Size = new System.Drawing.Size(180, 26);
- this.btnLayerRangeSelect.TabIndex = 18;
- this.btnLayerRangeSelect.Text = "Select";
- this.btnLayerRangeSelect.UseVisualStyleBackColor = true;
- //
// FrmToolWindow
//
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
diff --git a/UVtools.WPF/Controls/AdvancedImageBox.cs b/UVtools.WPF/Controls/AdvancedImageBox.cs
index 04f3033..5b785da 100644
--- a/UVtools.WPF/Controls/AdvancedImageBox.cs
+++ b/UVtools.WPF/Controls/AdvancedImageBox.cs
@@ -636,7 +636,7 @@ namespace UVtools.WPF.Controls
set => SetProperty(ref _pixelGridThreshold, value);
}
- public RectangleF SelectionRegion
+ public Rect SelectionRegion
{
get => _selectionRegion;
set => SetProperty(ref _selectionRegion, value);
@@ -660,7 +660,7 @@ namespace UVtools.WPF.Controls
private bool _invertMouse = false;
private bool _autoCenter = true;
private SizeModes _sizeMode = SizeModes.Normal;
- private RectangleF _selectionRegion;
+ private Rect _selectionRegion;
public ContentControl FillContainer { get; } = new ContentControl
{
@@ -1313,7 +1313,7 @@ namespace UVtools.WPF.Controls
public virtual void SelectAll()
{
if (Image is null) return;
- SelectionRegion = new RectangleF(0, 0, (float) Image.Size.Width, (float) Image.Size.Height);
+ SelectionRegion = new Rect(0, 0, Image.Size.Width, Image.Size.Height);
}
///
@@ -1321,7 +1321,7 @@ namespace UVtools.WPF.Controls
///
public virtual void SelectNone()
{
- SelectionRegion = RectangleF.Empty;
+ SelectionRegion = Rect.Empty;
}
#endregion
diff --git a/UVtools.WPF/Controls/Tools/ToolControl.axaml b/UVtools.WPF/Controls/Tools/ToolControl.axaml
new file mode 100644
index 0000000..dafec5a
--- /dev/null
+++ b/UVtools.WPF/Controls/Tools/ToolControl.axaml
@@ -0,0 +1,8 @@
+
+
diff --git a/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs
new file mode 100644
index 0000000..f5ae257
--- /dev/null
+++ b/UVtools.WPF/Controls/Tools/ToolControl.axaml.cs
@@ -0,0 +1,78 @@
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using UVtools.Core.Operations;
+using UVtools.WPF.Windows;
+
+namespace UVtools.WPF.Controls.Tools
+{
+ public abstract class ToolControl : UserControl, INotifyPropertyChanged
+ {
+ #region BindableBase
+ ///
+ /// Multicast event for property change notifications.
+ ///
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ ///
+ /// Checks if a property already matches a desired value. Sets the property and
+ /// notifies listeners only when necessary.
+ ///
+ /// Type of the property.
+ /// Reference to a property with both getter and setter.
+ /// Desired value for the property.
+ ///
+ /// Name of the property used to notify listeners. This
+ /// value is optional and can be provided automatically when invoked from compilers that
+ /// support CallerMemberName.
+ ///
+ ///
+ /// True if the value was changed, false if the existing value matched the
+ /// desired value.
+ ///
+ protected bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null)
+ {
+ if (Equals(storage, value))
+ {
+ return false;
+ }
+
+ storage = value;
+ OnPropertyChanged(propertyName);
+ return true;
+ }
+
+ ///
+ /// Notifies listeners that a property value has changed.
+ ///
+ ///
+ /// Name of the property used to notify listeners. This
+ /// value is optional and can be provided automatically when invoked from compilers
+ /// that support .
+ ///
+ protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
+ {
+ var eventHandler = PropertyChanged;
+ eventHandler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+ #endregion
+
+ public Operation BaseOperation = null;
+ public ToolWindow ParentWindow = null;
+
+ public ToolControl()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public virtual void Callback(ToolWindow.Callbacks callback) { }
+
+ public virtual bool ValidateForm() => true;
+ }
+}
diff --git a/UVtools.WPF/Controls/Tools/ToolFlipControl.axaml b/UVtools.WPF/Controls/Tools/ToolFlipControl.axaml
new file mode 100644
index 0000000..dc56f52
--- /dev/null
+++ b/UVtools.WPF/Controls/Tools/ToolFlipControl.axaml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/UVtools.WPF/Controls/Tools/ToolFlipControl.axaml.cs b/UVtools.WPF/Controls/Tools/ToolFlipControl.axaml.cs
new file mode 100644
index 0000000..eda1fca
--- /dev/null
+++ b/UVtools.WPF/Controls/Tools/ToolFlipControl.axaml.cs
@@ -0,0 +1,22 @@
+using Avalonia.Markup.Xaml;
+using UVtools.Core.Operations;
+
+namespace UVtools.WPF.Controls.Tools
+{
+ public class ToolFlipControl : ToolControl
+ {
+ public OperationFlip Operation { get; }
+
+ public ToolFlipControl()
+ {
+ InitializeComponent();
+ BaseOperation = Operation = new OperationFlip();
+ DataContext = this;
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs
index 3320117..7cdbc93 100644
--- a/UVtools.WPF/MainWindow.axaml.cs
+++ b/UVtools.WPF/MainWindow.axaml.cs
@@ -32,8 +32,10 @@ using ReactiveUI;
using UVtools.Core;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
+using UVtools.Core.Operations;
using UVtools.Core.PixelEditor;
using UVtools.WPF.Controls;
+using UVtools.WPF.Controls.Tools;
using UVtools.WPF.Extensions;
using UVtools.WPF.Structures;
using UVtools.WPF.Windows;
@@ -640,7 +642,7 @@ namespace UVtools.WPF
private void IssuesGridOnSelectionChanged(PointerPressedEventArgs pointer = null)
{
- if (IssuesGrid.SelectedItems.Count > 1) return;
+ if (IssuesGrid.SelectedItems.Count != 1) return;
if (!(IssuesGrid.SelectedItem is LayerIssue issue)) return;
if (issue.Type == LayerIssue.IssueType.TouchingBound || issue.Type == LayerIssue.IssueType.EmptyLayer ||
@@ -674,26 +676,26 @@ namespace UVtools.WPF
private void IssuesGridOnCellPointerPressed(object? sender, DataGridCellPointerPressedEventArgs e)
{
- if(!(IssuesGrid.SelectedItem is LayerIssue issue)) return;
+ if (IssuesGrid.SelectedItems.Count != 1 || e.PointerPressedEventArgs.ClickCount == 2) return;
+ if (!(IssuesGrid.SelectedItem is LayerIssue issue)) return;
// Double clicking an issue will center and zoom into the
// selected issue. Left click on an issue will zoom to fit.
var pointer = e.PointerPressedEventArgs.GetCurrentPoint(IssuesGrid);
- if (e.PointerPressedEventArgs.ClickCount == 2)
+ if (pointer.Properties.IsLeftButtonPressed)
{
- if (pointer.Properties.IsLeftButtonPressed)
- {
- ZoomToIssue(issue, e.PointerPressedEventArgs);
- return;
- }
-
- if (pointer.Properties.IsRightButtonPressed)
- {
- ZoomToFit(e.PointerPressedEventArgs);
- return;
- }
+ ZoomToIssue(issue, e.PointerPressedEventArgs);
+ return;
}
+ if (pointer.Properties.IsRightButtonPressed)
+ {
+ ZoomToFit(e.PointerPressedEventArgs);
+ return;
+ }
+
+ ForceUpdateActualLayer(issue.LayerIndex);
+
}
public void OnClickDetectIssues()
@@ -1156,6 +1158,7 @@ namespace UVtools.WPF
public async void MenuHelpAboutClicked()
{
+ new ToolWindow(new ToolFlipControl()).Show(this);
await new AboutWindow().ShowDialog(this);
}
diff --git a/UVtools.WPF/Windows/ToolWindow.axaml b/UVtools.WPF/Windows/ToolWindow.axaml
new file mode 100644
index 0000000..858e101
--- /dev/null
+++ b/UVtools.WPF/Windows/ToolWindow.axaml
@@ -0,0 +1,243 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UVtools.WPF/Windows/ToolWindow.axaml.cs b/UVtools.WPF/Windows/ToolWindow.axaml.cs
new file mode 100644
index 0000000..f967baf
--- /dev/null
+++ b/UVtools.WPF/Windows/ToolWindow.axaml.cs
@@ -0,0 +1,275 @@
+using System;
+using System.Timers;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using MessageBox.Avalonia.Enums;
+using UVtools.Core;
+using UVtools.WPF.Controls;
+using UVtools.WPF.Controls.Tools;
+using UVtools.WPF.Extensions;
+
+namespace UVtools.WPF.Windows
+{
+ public class ToolWindow : WindowEx
+ {
+ public enum Callbacks : byte
+ {
+ ClearROI,
+ Button1, // Reset to defaults
+ Checkbox1, // Show Advanced
+ }
+ public ToolControl ToolControl;
+ private string _description;
+ private double _descriptionMaxWidth;
+ private bool _layerRangeVisible = true;
+ private uint _layerIndexStart;
+ private uint _layerIndexEnd;
+ private bool _buttonOkEnabled = true;
+ private string _buttonOkText = "Ok";
+ private bool _isROIVisible;
+ private Rect _roi = Rect.Empty;
+ private bool _clearRoiAfterOperation;
+
+ private IControl _contentControl;
+
+ #region Description
+
+ public string Description
+ {
+ get => _description;
+ set => SetProperty(ref _description, value);
+ }
+
+ public double DescriptionMaxWidth
+ {
+ get => _descriptionMaxWidth;
+ set => SetProperty(ref _descriptionMaxWidth, value);
+ }
+
+ #endregion
+
+ #region Layer Selector
+
+ public bool LayerRangeVisible
+ {
+ get => _layerRangeVisible;
+ set => SetProperty(ref _layerRangeVisible, value);
+ }
+
+ public uint LayerIndexStart
+ {
+ get => _layerIndexStart;
+ set
+ {
+ SetProperty(ref _layerIndexStart, value);
+ if(!(ToolControl?.BaseOperation is null))
+ ToolControl.BaseOperation.LayerIndexStart = _layerIndexStart;
+ }
+ }
+
+ public uint LayerIndexEnd
+ {
+ get => _layerIndexEnd;
+ set
+ {
+ SetProperty(ref _layerIndexEnd, value);
+ if (!(ToolControl?.BaseOperation is null))
+ ToolControl.BaseOperation.LayerIndexEnd = _layerIndexEnd;
+ }
+ }
+
+ public uint MaximumLayerIndex => App.MainWindow?.SliderMaximumValue ?? 0;
+
+ public void SelectAllLayers()
+ {
+ LayerIndexStart = 0;
+ LayerIndexEnd = MaximumLayerIndex;
+ }
+
+ public void SelectCurrentLayer()
+ {
+ LayerIndexStart = LayerIndexEnd = App.MainWindow.ActualLayer;
+ }
+
+ public void SelectBottomLayers()
+ {
+ LayerIndexStart = 0;
+ LayerIndexEnd = App.SlicerFile.BottomLayerCount-1u;
+ }
+
+ public void SelectNormalLayers()
+ {
+ LayerIndexStart = App.SlicerFile.BottomLayerCount;
+ LayerIndexEnd = MaximumLayerIndex;
+ }
+
+ public void SelectFirstLayer()
+ {
+ LayerIndexStart = LayerIndexEnd = 0;
+ }
+
+ public void SelectLastLayer()
+ {
+ LayerIndexStart = LayerIndexEnd = MaximumLayerIndex;
+ }
+ #endregion
+
+ #region ROI
+
+ public bool IsROIVisible
+ {
+ get => ToolControl?.BaseOperation.HaveROI ?? _isROIVisible;
+ set => SetProperty(ref _isROIVisible, value);
+ }
+
+ public Rect ROI
+ {
+ get => _roi;
+ set => SetProperty(ref _roi, value);
+ }
+
+ public bool ClearROIAfterOperation
+ {
+ get => _clearRoiAfterOperation;
+ set => SetProperty(ref _clearRoiAfterOperation, value);
+ }
+
+ public async void ClearROI()
+ {
+ if (await this.MessageBoxQuestion("Are you sure you want to clear the current ROI?\n" +
+ "This action can not be reverted, to select another ROI you must quit this window and select it on layer preview.",
+ "Clear the current ROI?") != ButtonResult.Yes) return;
+ IsROIVisible = false;
+ App.MainWindow.LayerImageBox.SelectNone();
+ ToolControl?.Callback(Callbacks.ClearROI);
+ }
+
+ #endregion
+
+ #region Content
+
+ public IControl ContentControl
+ {
+ get => _contentControl;
+ set => SetProperty(ref _contentControl, value);
+ }
+
+ #endregion
+
+ #region Actions
+
+ public bool ButtonOkEnabled
+ {
+ get => _buttonOkEnabled;
+ set => SetProperty(ref _buttonOkEnabled, value);
+ }
+
+ public string ButtonOkText
+ {
+ get => _buttonOkText;
+ set => SetProperty(ref _buttonOkText, value);
+ }
+
+ #endregion
+
+ public ToolWindow()
+ {
+ InitializeComponent();
+ DataContext = this;
+ SelectAllLayers();
+ }
+
+ public ToolWindow(string description = null, bool layerRangeVisible = true) : this()
+ {
+ Description = description;
+ LayerRangeVisible = layerRangeVisible;
+ }
+
+ public ToolWindow(ToolControl toolControl) : this( )
+ {
+ ToolControl = toolControl;
+ toolControl.ParentWindow = this;
+
+ Title = toolControl.BaseOperation.Title;
+ LayerRangeVisible = toolControl.BaseOperation.LayerRangeSelection != Enumerations.LayerRangeSelection.None;
+ IsROIVisible = toolControl.BaseOperation.CanROI;
+ ContentControl = toolControl;
+ ButtonOkText = toolControl.BaseOperation.ButtonOkText;
+
+ switch (toolControl.BaseOperation.LayerRangeSelection)
+ {
+ case Enumerations.LayerRangeSelection.None:
+ break;
+ case Enumerations.LayerRangeSelection.All:
+ SelectAllLayers();
+ break;
+ case Enumerations.LayerRangeSelection.Current:
+ SelectCurrentLayer();
+ break;
+ case Enumerations.LayerRangeSelection.Bottom:
+ SelectBottomLayers();
+ break;
+ case Enumerations.LayerRangeSelection.Normal:
+ SelectNormalLayers();
+ break;
+ case Enumerations.LayerRangeSelection.First:
+ SelectFirstLayer();
+ break;
+ case Enumerations.LayerRangeSelection.Last:
+ SelectLastLayer();
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ // Ensure the description don't stretch window
+ var timer = new Timer(10)
+ {
+ AutoReset = true
+ };
+ timer.Elapsed += (sender, args) =>
+ {
+ if (Bounds.Width == 0) return;
+ DescriptionMaxWidth = Math.Max(Bounds.Width, ToolControl?.Bounds.Width ?? 0);
+ Description = toolControl.BaseOperation.Description;
+ timer.Stop();
+ timer.Dispose();
+ };
+ timer.Start();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public async void Process()
+ {
+ if (LayerIndexStart > LayerIndexEnd)
+ {
+ await this.MessageBoxError("Layer range start can't be higher than layer end.\nPlease fix and try again.");
+ return;
+ }
+
+ if (!ReferenceEquals(ToolControl, null))
+ {
+ if(!ToolControl.ValidateForm()) return;
+ if (!string.IsNullOrEmpty(ToolControl.BaseOperation.ConfirmationText))
+ {
+ if (await this.MessageBoxQuestion(
+ $"Are you sure you want to {ToolControl.BaseOperation.ConfirmationText}") !=
+ ButtonResult.Yes) return;
+ }
+ }
+
+ if (ClearROIAfterOperation)
+ {
+ App.MainWindow.LayerImageBox.SelectNone();
+ }
+
+ DialogResult = DialogResults.OK;
+ Close(DialogResult);
+ }
+ }
+}