|
@@ -7,6 +7,7 @@ using Avalonia.Interactivity;
|
|
|
using Avalonia.Markup.Xaml;
|
|
|
using Avalonia.Media;
|
|
|
using Avalonia.Media.Imaging;
|
|
|
+using Avalonia.Layout;
|
|
|
using Avalonia.Skia.Helpers;
|
|
|
using CommunityToolkit.Mvvm.Input;
|
|
|
using FluentResults;
|
|
@@ -15,6 +16,10 @@ using InABox.Avalonia.Converters;
|
|
|
using InABox.Core;
|
|
|
using SkiaSharp;
|
|
|
using System.Collections.ObjectModel;
|
|
|
+using System.Threading.Tasks;
|
|
|
+using Avalonia.LogicalTree;
|
|
|
+using CommunityToolkit.Mvvm.ComponentModel;
|
|
|
+using Microsoft.Maui.Devices;
|
|
|
|
|
|
namespace InABox.Avalonia.Components;
|
|
|
|
|
@@ -22,14 +27,19 @@ public enum ImageEditingMode
|
|
|
{
|
|
|
Polyline,
|
|
|
Rectangle,
|
|
|
- Ellipse
|
|
|
+ Ellipse,
|
|
|
+ Text,
|
|
|
+ Dimension
|
|
|
}
|
|
|
|
|
|
-public class ImageEditorModeButton(ImageEditingMode mode, Canvas? canvas)
|
|
|
+public partial class ImageEditorModeButton(ImageEditingMode mode, Control? content, bool active) : ObservableObject
|
|
|
{
|
|
|
public ImageEditingMode Mode { get; set; } = mode;
|
|
|
|
|
|
- public Canvas? Canvas { get; set; } = canvas;
|
|
|
+ public Control? Content { get; set; } = content;
|
|
|
+
|
|
|
+ [ObservableProperty]
|
|
|
+ private bool _active = active;
|
|
|
}
|
|
|
|
|
|
public class ImageEditorTransparentImageBrushConverter : AbstractConverter<IBrush?, IBrush?>
|
|
@@ -113,6 +123,9 @@ public partial class ImageEditor : UserControl
|
|
|
public static readonly StyledProperty<bool> ShowButtonsProperty =
|
|
|
AvaloniaProperty.Register<ImageEditor, bool>(nameof(ShowButtons), true);
|
|
|
|
|
|
+ public static readonly StyledProperty<double> FontSizeValueProperty =
|
|
|
+ AvaloniaProperty.Register<ImageEditor, double>(nameof(FontSizeValue), 12);
|
|
|
+
|
|
|
public IImage? Source
|
|
|
{
|
|
|
get => GetValue(SourceProperty);
|
|
@@ -163,6 +176,12 @@ public partial class ImageEditor : UserControl
|
|
|
set => SetValue(LineThicknessProperty, value);
|
|
|
}
|
|
|
|
|
|
+ public double FontSizeValue
|
|
|
+ {
|
|
|
+ get => GetValue(FontSizeValueProperty);
|
|
|
+ set => SetValue(FontSizeValueProperty, value);
|
|
|
+ }
|
|
|
+
|
|
|
#endregion
|
|
|
|
|
|
#region Events
|
|
@@ -177,11 +196,24 @@ public partial class ImageEditor : UserControl
|
|
|
|
|
|
private ObservableCollection<IImageEditorObject> Objects = new();
|
|
|
|
|
|
- private IImageEditorObject? CurrentObject;
|
|
|
+ private IImageEditorObject? _currentObject;
|
|
|
+ private IImageEditorObject? CurrentObject
|
|
|
+ {
|
|
|
+ get => _currentObject;
|
|
|
+ set
|
|
|
+ {
|
|
|
+ _currentObject?.SetActive(false);
|
|
|
+ _currentObject = value;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
private Stack<IImageEditorObject> RedoStack = new();
|
|
|
|
|
|
private double ScaleFactor = 1.0;
|
|
|
+ private double _originalScaleFactor = 1.0;
|
|
|
+
|
|
|
+ // Center of the image.
|
|
|
+ private Point ImageCenter = new();
|
|
|
|
|
|
#endregion
|
|
|
|
|
@@ -211,13 +243,70 @@ public partial class ImageEditor : UserControl
|
|
|
SetMode(Mode);
|
|
|
|
|
|
OuterCanvas.LayoutUpdated += OuterCanvas_LayoutUpdated;
|
|
|
+ OuterCanvas.AddHandler(PanAndZoomGestureRecognizer.PanAndZoomEndedEvent, OuterCanvas_PinchEnded);
|
|
|
+ OuterCanvas.AddHandler(PanAndZoomGestureRecognizer.PanAndZoomEvent, OuterCanvas_Pinch);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OuterCanvas_PinchEnded(object? sender, PanAndZoomEndedEventArgs e)
|
|
|
+ {
|
|
|
+ _originalScaleFactor = ScaleFactor;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OuterCanvas_Pinch(object? sender, PanAndZoomEventArgs e)
|
|
|
+ {
|
|
|
+ Zoom(e.ScaleOrigin - e.Pan, e.ScaleOrigin, _originalScaleFactor * e.Scale);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void Zoom(Point originalOrigin, Point newOrigin, double newScaleFactor)
|
|
|
+ {
|
|
|
+ // Convert Scale Origin to image coordinates (relative to center).
|
|
|
+ // Work out where this position will move to under the new scaling.
|
|
|
+ // Adjust so that these are the same.
|
|
|
+
|
|
|
+ var pos = originalOrigin - ImageCenter;
|
|
|
+ var contentMPos = pos / ScaleFactor;
|
|
|
+
|
|
|
+ ScaleFactor = newScaleFactor;
|
|
|
+
|
|
|
+ var scaledPos = ImageCenter + contentMPos * ScaleFactor;
|
|
|
+ var offset = scaledPos - newOrigin;
|
|
|
+
|
|
|
+ ImageCenter -= offset;
|
|
|
+ UpdateCanvasPosition();
|
|
|
+ }
|
|
|
+
|
|
|
+ private const double _wheelSpeed = 0.1;
|
|
|
+ private const double _panSpeed = 30;
|
|
|
+
|
|
|
+ private void Pan(double x, double y)
|
|
|
+ {
|
|
|
+ ImageCenter += new Vector(x, y);
|
|
|
+ UpdateCanvasPosition();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OuterCanvas_PointerWheelChanged(object? sender, PointerWheelEventArgs e)
|
|
|
+ {
|
|
|
+ if (e.KeyModifiers.HasFlag(KeyModifiers.Control))
|
|
|
+ {
|
|
|
+ var pos = e.GetPosition(OuterCanvas);
|
|
|
+ var wheelSpeed = _wheelSpeed;
|
|
|
+ Zoom(pos, pos, e.Delta.Y > 0 ? ScaleFactor * (1 + e.Delta.Y * wheelSpeed) : ScaleFactor / (1 + (-e.Delta.Y) * wheelSpeed));
|
|
|
+ }
|
|
|
+ else if(e.KeyModifiers.HasFlag(KeyModifiers.Shift))
|
|
|
+ {
|
|
|
+ Pan(e.Delta.Y * _panSpeed, e.Delta.X * _panSpeed);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Pan(e.Delta.X * _panSpeed, e.Delta.Y * _panSpeed);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
#region Layout
|
|
|
|
|
|
private void OuterCanvas_LayoutUpdated(object? sender, EventArgs e)
|
|
|
{
|
|
|
- PositionImage();
|
|
|
+ // PositionImage();
|
|
|
}
|
|
|
|
|
|
protected override void OnLoaded(RoutedEventArgs e)
|
|
@@ -233,15 +322,25 @@ public partial class ImageEditor : UserControl
|
|
|
|
|
|
var scaleFactor = Math.Min(canvasWidth / ImageWidth, canvasHeight / ImageHeight);
|
|
|
ScaleFactor = scaleFactor;
|
|
|
+ _originalScaleFactor = ScaleFactor;
|
|
|
|
|
|
- var imageWidth = ImageWidth * scaleFactor;
|
|
|
- var imageHeight = ImageHeight * scaleFactor;
|
|
|
+ ImageCenter = new Point(
|
|
|
+ OuterCanvas.Bounds.Width / 2,
|
|
|
+ OuterCanvas.Bounds.Height / 2);
|
|
|
+
|
|
|
+ UpdateCanvasPosition();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void UpdateCanvasPosition()
|
|
|
+ {
|
|
|
+ var imageWidth = ImageWidth * ScaleFactor;
|
|
|
+ var imageHeight = ImageHeight * ScaleFactor;
|
|
|
|
|
|
ImageBorder.Width = imageWidth;
|
|
|
ImageBorder.Height = imageHeight;
|
|
|
|
|
|
- Canvas.SetLeft(ImageBorder, OuterCanvas.Bounds.Width / 2 - imageWidth / 2);
|
|
|
- Canvas.SetTop(ImageBorder, OuterCanvas.Bounds.Height / 2 - imageHeight / 2);
|
|
|
+ Canvas.SetLeft(ImageBorder, ImageCenter.X - imageWidth / 2);
|
|
|
+ Canvas.SetTop(ImageBorder, ImageCenter.Y - imageHeight / 2);
|
|
|
|
|
|
Canvas.RenderTransform = new ScaleTransform(ScaleFactor, ScaleFactor);
|
|
|
Canvas.Width = ImageWidth;
|
|
@@ -290,9 +389,15 @@ public partial class ImageEditor : UserControl
|
|
|
[RelayCommand]
|
|
|
private void SetMode(ImageEditingMode mode)
|
|
|
{
|
|
|
+ foreach(var button in ModeButtons)
|
|
|
+ {
|
|
|
+ button.Active = button.Mode == mode;
|
|
|
+ }
|
|
|
Mode = mode;
|
|
|
- ShapeButton.Content = CreateModeButtonContent(mode);
|
|
|
+ // ShapeButton.Content = CreateModeButtonContent(mode);
|
|
|
SecondaryColour.IsVisible = HasSecondaryColour();
|
|
|
+ LineThicknessButton.IsVisible = HasLineThickness();
|
|
|
+ FontSizeButton.IsVisible = Mode == ImageEditingMode.Text;
|
|
|
}
|
|
|
|
|
|
private bool HasSecondaryColour()
|
|
@@ -300,6 +405,14 @@ public partial class ImageEditor : UserControl
|
|
|
return Mode == ImageEditingMode.Rectangle || Mode == ImageEditingMode.Ellipse;
|
|
|
}
|
|
|
|
|
|
+ private bool HasLineThickness()
|
|
|
+ {
|
|
|
+ return Mode == ImageEditingMode.Rectangle
|
|
|
+ || Mode == ImageEditingMode.Ellipse
|
|
|
+ || Mode == ImageEditingMode.Polyline
|
|
|
+ || Mode == ImageEditingMode.Dimension;
|
|
|
+ }
|
|
|
+
|
|
|
#endregion
|
|
|
|
|
|
#region Mode Buttons
|
|
@@ -309,40 +422,44 @@ public partial class ImageEditor : UserControl
|
|
|
AddModeButton(ImageEditingMode.Polyline);
|
|
|
AddModeButton(ImageEditingMode.Rectangle);
|
|
|
AddModeButton(ImageEditingMode.Ellipse);
|
|
|
+ AddModeButton(ImageEditingMode.Text);
|
|
|
+ AddModeButton(ImageEditingMode.Dimension);
|
|
|
}
|
|
|
|
|
|
private void AddModeButton(ImageEditingMode mode)
|
|
|
{
|
|
|
- ModeButtons.Add(new(mode, CreateModeButtonContent(mode)));
|
|
|
+ ModeButtons.Add(new(mode, CreateModeButtonContent(mode), mode == Mode));
|
|
|
}
|
|
|
|
|
|
- private Canvas? CreateModeButtonContent(ImageEditingMode mode, bool bindColour = false)
|
|
|
+ private Control? CreateModeButtonContent(ImageEditingMode mode, bool bindColour = false)
|
|
|
{
|
|
|
switch (mode)
|
|
|
{
|
|
|
case ImageEditingMode.Polyline:
|
|
|
var canvas = new Canvas();
|
|
|
- var points = new Point[] { new(0, 0), new(20, 8), new(5, 16), new(25, 25) };
|
|
|
- var line1 = new Polyline { Points = points, Width = 25, Height = 25 };
|
|
|
- var line2 = new Polyline { Points = points, Width = 25, Height = 25 };
|
|
|
- line1.StrokeThickness = 4;
|
|
|
- line1.StrokeLineCap = PenLineCap.Round;
|
|
|
- line1.StrokeJoin = PenLineJoin.Round;
|
|
|
- line1.Stroke = new SolidColorBrush(Colors.Black);
|
|
|
- canvas.Children.Add(line1);
|
|
|
-
|
|
|
- if (bindColour)
|
|
|
{
|
|
|
- line1.StrokeThickness = 5;
|
|
|
- line2.StrokeThickness = 4;
|
|
|
- line2.StrokeLineCap = PenLineCap.Round;
|
|
|
- line2.StrokeJoin = PenLineJoin.Round;
|
|
|
- line2.Bind(Polyline.StrokeProperty, new Binding(nameof(PrimaryBrush))
|
|
|
+ var points = new Point[] { new(0, 0), new(20, 8), new(5, 16), new(25, 25) };
|
|
|
+ var line1 = new Polyline { Points = points, Width = 25, Height = 25 };
|
|
|
+ var line2 = new Polyline { Points = points, Width = 25, Height = 25 };
|
|
|
+ line1.StrokeThickness = 4;
|
|
|
+ line1.StrokeLineCap = PenLineCap.Round;
|
|
|
+ line1.StrokeJoin = PenLineJoin.Round;
|
|
|
+ line1.Stroke = new SolidColorBrush(Colors.Black);
|
|
|
+ canvas.Children.Add(line1);
|
|
|
+
|
|
|
+ if (bindColour)
|
|
|
{
|
|
|
- Source = this,
|
|
|
- Converter = ImageEditorRemoveOpacityConverter.Instance
|
|
|
- });
|
|
|
- canvas.Children.Add(line2);
|
|
|
+ line1.StrokeThickness = 5;
|
|
|
+ line2.StrokeThickness = 4;
|
|
|
+ line2.StrokeLineCap = PenLineCap.Round;
|
|
|
+ line2.StrokeJoin = PenLineJoin.Round;
|
|
|
+ line2.Bind(Polyline.StrokeProperty, new Binding(nameof(PrimaryBrush))
|
|
|
+ {
|
|
|
+ Source = this,
|
|
|
+ Converter = ImageEditorRemoveOpacityConverter.Instance
|
|
|
+ });
|
|
|
+ canvas.Children.Add(line2);
|
|
|
+ }
|
|
|
}
|
|
|
return canvas;
|
|
|
case ImageEditingMode.Rectangle:
|
|
@@ -404,6 +521,129 @@ public partial class ImageEditor : UserControl
|
|
|
ellipse.Height = 25;
|
|
|
canvas.Children.Add(ellipse);
|
|
|
|
|
|
+ return canvas;
|
|
|
+ case ImageEditingMode.Text:
|
|
|
+ var textBox = new TextBlock();
|
|
|
+ textBox.Text = "T";
|
|
|
+ textBox.FontSize = 25;
|
|
|
+ textBox.TextAlignment = TextAlignment.Center;
|
|
|
+ textBox.HorizontalAlignment = HorizontalAlignment.Center;
|
|
|
+ textBox.VerticalAlignment = VerticalAlignment.Center;
|
|
|
+ if (bindColour)
|
|
|
+ {
|
|
|
+ textBox.Bind(TextBlock.ForegroundProperty, new Binding(nameof(PrimaryBrush))
|
|
|
+ {
|
|
|
+ Source = this,
|
|
|
+ Converter = ImageEditorRemoveOpacityConverter.Instance
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return textBox;
|
|
|
+ case ImageEditingMode.Dimension:
|
|
|
+ canvas = new Canvas();
|
|
|
+ canvas.Width = 25;
|
|
|
+ canvas.Height = 25;
|
|
|
+
|
|
|
+ {
|
|
|
+ var dimLines = new List<Line>();
|
|
|
+
|
|
|
+ dimLines.Add(new Line
|
|
|
+ {
|
|
|
+ StartPoint = new(2, 10),
|
|
|
+ EndPoint = new(23, 10),
|
|
|
+ StrokeLineCap = PenLineCap.Round
|
|
|
+ });
|
|
|
+ dimLines.Add(new Line
|
|
|
+ {
|
|
|
+ StartPoint = new(2, 10),
|
|
|
+ EndPoint = new(5, 7),
|
|
|
+ StrokeLineCap = PenLineCap.Square
|
|
|
+ });
|
|
|
+ dimLines.Add(new Line
|
|
|
+ {
|
|
|
+ StartPoint = new(2, 10),
|
|
|
+ EndPoint = new(5, 13),
|
|
|
+ StrokeLineCap = PenLineCap.Square
|
|
|
+ });
|
|
|
+ dimLines.Add(new Line
|
|
|
+ {
|
|
|
+ StartPoint = new(23, 10),
|
|
|
+ EndPoint = new(20, 7),
|
|
|
+ StrokeLineCap = PenLineCap.Square
|
|
|
+ });
|
|
|
+ dimLines.Add(new Line
|
|
|
+ {
|
|
|
+ StartPoint = new(23, 10),
|
|
|
+ EndPoint = new(20, 13),
|
|
|
+ StrokeLineCap = PenLineCap.Square
|
|
|
+ });
|
|
|
+
|
|
|
+ var dotLines = new List<Line>();
|
|
|
+ dotLines.Add(new Line
|
|
|
+ {
|
|
|
+ StartPoint = new(2, 10),
|
|
|
+ EndPoint = new(2, 24),
|
|
|
+ StrokeDashArray = [2, 2]
|
|
|
+ });
|
|
|
+ dotLines.Add(new Line
|
|
|
+ {
|
|
|
+ StartPoint = new(23, 10),
|
|
|
+ EndPoint = new(23, 24),
|
|
|
+ StrokeDashArray = [2, 2]
|
|
|
+ });
|
|
|
+
|
|
|
+ var number = new TextBlock
|
|
|
+ {
|
|
|
+ Text = "10",
|
|
|
+ FontSize = 9,
|
|
|
+ TextAlignment = TextAlignment.Center,
|
|
|
+ Width = 25
|
|
|
+ };
|
|
|
+ Canvas.SetLeft(number, 0);
|
|
|
+ Canvas.SetTop(number, -1);
|
|
|
+
|
|
|
+ foreach (var line in dimLines)
|
|
|
+ {
|
|
|
+ line.StrokeThickness = 2;
|
|
|
+ line.Stroke = new SolidColorBrush(Colors.Black);
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach (var line in dotLines)
|
|
|
+ {
|
|
|
+ line.StrokeThickness = 1;
|
|
|
+ line.Stroke = new SolidColorBrush(Colors.Black);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bindColour)
|
|
|
+ {
|
|
|
+ foreach (var line in dimLines)
|
|
|
+ {
|
|
|
+ line.Bind(Polyline.StrokeProperty, new Binding(nameof(PrimaryBrush))
|
|
|
+ {
|
|
|
+ Source = this,
|
|
|
+ Converter = ImageEditorRemoveOpacityConverter.Instance
|
|
|
+ });
|
|
|
+ }
|
|
|
+ foreach (var line in dotLines)
|
|
|
+ {
|
|
|
+ line.Bind(Polyline.StrokeProperty, new Binding(nameof(PrimaryBrush))
|
|
|
+ {
|
|
|
+ Source = this,
|
|
|
+ Converter = ImageEditorRemoveOpacityConverter.Instance
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach (var line in dimLines)
|
|
|
+ {
|
|
|
+ canvas.Children.Add(line);
|
|
|
+ }
|
|
|
+ foreach (var line in dotLines)
|
|
|
+ {
|
|
|
+ canvas.Children.Add(line);
|
|
|
+ }
|
|
|
+ canvas.Children.Add(number);
|
|
|
+ }
|
|
|
+
|
|
|
return canvas;
|
|
|
default:
|
|
|
return null;
|
|
@@ -432,19 +672,53 @@ public partial class ImageEditor : UserControl
|
|
|
context.DrawImage(Source, new(0, 0, ImageWidth, ImageHeight));
|
|
|
}
|
|
|
|
|
|
+ CurrentObject = null;
|
|
|
+
|
|
|
foreach (var obj in Objects)
|
|
|
{
|
|
|
var control = obj.GetControl();
|
|
|
- var left = Canvas.GetLeft(control);
|
|
|
- var top = Canvas.GetTop(control);
|
|
|
- if (double.IsNaN(left)) left = 0;
|
|
|
- if (double.IsNaN(top)) top = 0;
|
|
|
- using (context.PushTransform(Matrix.CreateTranslation(new(left, top))))
|
|
|
+ Render(context, control);
|
|
|
+ }
|
|
|
+ return renderBitmap;
|
|
|
+ }
|
|
|
+ private void Render(DrawingContext context, Control control)
|
|
|
+ {
|
|
|
+ var left = Canvas.GetLeft(control);
|
|
|
+ var top = Canvas.GetTop(control);
|
|
|
+ if (double.IsNaN(left)) left = 0;
|
|
|
+ if (double.IsNaN(top)) top = 0;
|
|
|
+
|
|
|
+ var matrix = Matrix.CreateTranslation(new(left, top));
|
|
|
+
|
|
|
+ if(control.RenderTransform is not null)
|
|
|
+ {
|
|
|
+ Vector offset;
|
|
|
+ if(control.RenderTransformOrigin.Unit == RelativeUnit.Relative)
|
|
|
+ {
|
|
|
+ offset = new Vector(
|
|
|
+ control.Bounds.Width * control.RenderTransformOrigin.Point.X,
|
|
|
+ control.Bounds.Height * control.RenderTransformOrigin.Point.Y);
|
|
|
+ }
|
|
|
+ else
|
|
|
{
|
|
|
- control.Render(context);
|
|
|
+ offset = new Vector(control.RenderTransformOrigin.Point.X, control.RenderTransformOrigin.Point.Y);
|
|
|
}
|
|
|
+
|
|
|
+ matrix = (Matrix.CreateTranslation(-offset) * control.RenderTransform.Value * Matrix.CreateTranslation(offset)) * matrix;
|
|
|
}
|
|
|
- return renderBitmap;
|
|
|
+
|
|
|
+ using (context.PushTransform(matrix))
|
|
|
+ {
|
|
|
+ control.Render(context);
|
|
|
+ if(control is Panel panel)
|
|
|
+ {
|
|
|
+ foreach(var child in panel.Children)
|
|
|
+ {
|
|
|
+ Render(context, child);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
public byte[] SaveImage()
|
|
@@ -460,7 +734,7 @@ public partial class ImageEditor : UserControl
|
|
|
|
|
|
#region Editing
|
|
|
|
|
|
- private void Objects_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
|
|
+ private void RefreshObjects()
|
|
|
{
|
|
|
Canvas.Children.Clear();
|
|
|
foreach(var item in Objects)
|
|
@@ -470,6 +744,11 @@ public partial class ImageEditor : UserControl
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private void Objects_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
|
|
+ {
|
|
|
+ RefreshObjects();
|
|
|
+ }
|
|
|
+
|
|
|
Point ConvertToImageCoordinates(Point canvasCoordinates)
|
|
|
{
|
|
|
return canvasCoordinates;// new(canvasCoordinates.X / ScaleFactor, canvasCoordinates.Y / ScaleFactor);
|
|
@@ -477,6 +756,7 @@ public partial class ImageEditor : UserControl
|
|
|
|
|
|
private void Canvas_PointerPressed(object? sender, PointerPressedEventArgs e)
|
|
|
{
|
|
|
+ CurrentObject = null;
|
|
|
var position = ConvertToImageCoordinates(e.GetPosition(Canvas));
|
|
|
switch (Mode)
|
|
|
{
|
|
@@ -511,6 +791,18 @@ public partial class ImageEditor : UserControl
|
|
|
};
|
|
|
AddObject(CurrentObject);
|
|
|
break;
|
|
|
+ case ImageEditingMode.Dimension:
|
|
|
+ CurrentObject = new DimensionObject
|
|
|
+ {
|
|
|
+ Point1 = position,
|
|
|
+ Point2 = position,
|
|
|
+ PrimaryBrush = PrimaryBrush,
|
|
|
+ Text = "",
|
|
|
+ Offset = 30,
|
|
|
+ LineThickness = LineThickness
|
|
|
+ };
|
|
|
+ AddObject(CurrentObject);
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -534,6 +826,19 @@ public partial class ImageEditor : UserControl
|
|
|
ellipse.Update();
|
|
|
Changed?.Invoke(this, new EventArgs());
|
|
|
break;
|
|
|
+ case SelectionObject textSelection:
|
|
|
+ textSelection.Point2 = position;
|
|
|
+ textSelection.Update();
|
|
|
+ Changed?.Invoke(this, new EventArgs());
|
|
|
+ break;
|
|
|
+ case DimensionObject dimension:
|
|
|
+ if (!dimension.Complete)
|
|
|
+ {
|
|
|
+ dimension.Point2 = position;
|
|
|
+ dimension.Update();
|
|
|
+ Changed?.Invoke(this, new EventArgs());
|
|
|
+ }
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -560,8 +865,43 @@ public partial class ImageEditor : UserControl
|
|
|
CurrentObject = null;
|
|
|
Changed?.Invoke(this, new EventArgs());
|
|
|
break;
|
|
|
- }
|
|
|
+ case DimensionObject dimension:
|
|
|
+ dimension.Point2 = position;
|
|
|
+ if(dimension.Point1 == dimension.Point2)
|
|
|
+ {
|
|
|
+ Objects.Remove(dimension);
|
|
|
+ CurrentObject = null;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ dimension.Complete = true;
|
|
|
|
|
|
+ Navigation.Popup<TextEditViewModel, string?>(x => { }).ContinueWith(task =>
|
|
|
+ {
|
|
|
+ dimension.Text = task.Result ?? "";
|
|
|
+ dimension.Update();
|
|
|
+ }, TaskScheduler.FromCurrentSynchronizationContext());
|
|
|
+ Changed?.Invoke(this, new EventArgs());
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ switch (Mode)
|
|
|
+ {
|
|
|
+ case ImageEditingMode.Text:
|
|
|
+ Navigation.Popup<TextEditViewModel, string?>(x => { }).ContinueWith(task =>
|
|
|
+ {
|
|
|
+ var text = new TextObject
|
|
|
+ {
|
|
|
+ Text = task.Result ?? "",
|
|
|
+ FontSize = FontSize,
|
|
|
+ PrimaryBrush = PrimaryBrush,
|
|
|
+ Point = position
|
|
|
+ };
|
|
|
+ Objects.Add(text);
|
|
|
+ }, TaskScheduler.FromCurrentSynchronizationContext());
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
#endregion
|