|
@@ -19,6 +19,7 @@ using System.Collections.ObjectModel;
|
|
|
using System.Threading.Tasks;
|
|
|
using Avalonia.LogicalTree;
|
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
|
+using Microsoft.Maui.Devices;
|
|
|
|
|
|
namespace InABox.Avalonia.Components;
|
|
|
|
|
@@ -122,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);
|
|
@@ -172,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
|
|
@@ -243,23 +253,55 @@ public partial class ImageEditor : UserControl
|
|
|
}
|
|
|
|
|
|
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 = (e.ScaleOrigin - e.Pan) - ImageCenter;
|
|
|
+ var pos = originalOrigin - ImageCenter;
|
|
|
var contentMPos = pos / ScaleFactor;
|
|
|
|
|
|
- ScaleFactor = _originalScaleFactor * e.Scale;
|
|
|
+ ScaleFactor = newScaleFactor;
|
|
|
|
|
|
var scaledPos = ImageCenter + contentMPos * ScaleFactor;
|
|
|
- var offset = scaledPos - e.ScaleOrigin;
|
|
|
+ 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)
|
|
@@ -355,6 +397,7 @@ public partial class ImageEditor : UserControl
|
|
|
// ShapeButton.Content = CreateModeButtonContent(mode);
|
|
|
SecondaryColour.IsVisible = HasSecondaryColour();
|
|
|
LineThicknessButton.IsVisible = HasLineThickness();
|
|
|
+ FontSizeButton.IsVisible = Mode == ImageEditingMode.Text;
|
|
|
}
|
|
|
|
|
|
private bool HasSecondaryColour()
|
|
@@ -748,15 +791,6 @@ public partial class ImageEditor : UserControl
|
|
|
};
|
|
|
AddObject(CurrentObject);
|
|
|
break;
|
|
|
- case ImageEditingMode.Text:
|
|
|
- CurrentObject = new SelectionObject
|
|
|
- {
|
|
|
- Point1 = position,
|
|
|
- Point2 = position,
|
|
|
- PrimaryBrush = PrimaryBrush
|
|
|
- };
|
|
|
- AddObject(CurrentObject);
|
|
|
- break;
|
|
|
case ImageEditingMode.Dimension:
|
|
|
CurrentObject = new DimensionObject
|
|
|
{
|
|
@@ -831,20 +865,6 @@ public partial class ImageEditor : UserControl
|
|
|
CurrentObject = null;
|
|
|
Changed?.Invoke(this, new EventArgs());
|
|
|
break;
|
|
|
- case SelectionObject selection:
|
|
|
- selection.Point2 = position;
|
|
|
-
|
|
|
- Objects.Remove(selection);
|
|
|
- CurrentObject = null;
|
|
|
-
|
|
|
- CreateObjectFromSelection(selection).ContinueWith(task =>
|
|
|
- {
|
|
|
- if(task.Exception != null)
|
|
|
- {
|
|
|
- MobileLogging.LogExceptionMessage(task.Exception);
|
|
|
- }
|
|
|
- });
|
|
|
- break;
|
|
|
case DimensionObject dimension:
|
|
|
dimension.Point2 = position;
|
|
|
if(dimension.Point1 == dimension.Point2)
|
|
@@ -862,27 +882,24 @@ public partial class ImageEditor : UserControl
|
|
|
}, TaskScheduler.FromCurrentSynchronizationContext());
|
|
|
Changed?.Invoke(this, new EventArgs());
|
|
|
break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private async Task CreateObjectFromSelection(SelectionObject selection)
|
|
|
- {
|
|
|
- switch (Mode)
|
|
|
- {
|
|
|
- case ImageEditingMode.Text:
|
|
|
- var text = await Navigation.Popup<TextEditViewModel, string?>(x => { });
|
|
|
- if(text is null)
|
|
|
+ default:
|
|
|
+ switch (Mode)
|
|
|
{
|
|
|
- return;
|
|
|
+ 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;
|
|
|
}
|
|
|
- CurrentObject = new TextObject
|
|
|
- {
|
|
|
- Point = selection.GetTopLeft(),
|
|
|
- Size = selection.GetSize(),
|
|
|
- Text = text,
|
|
|
- PrimaryBrush = selection.PrimaryBrush
|
|
|
- };
|
|
|
- AddObject(CurrentObject);
|
|
|
break;
|
|
|
}
|
|
|
}
|