Browse Source

avalonia: changed ImageEditor text font size functionality. Added zoom and pan

Kenric Nugteren 1 week ago
parent
commit
f612021aae

+ 34 - 1
InABox.Avalonia/Components/ImageEditor/ImageEditor.axaml

@@ -69,7 +69,7 @@
 				<RowDefinition Height="*"/>
 				<RowDefinition Height="Auto"/>
 			</Grid.RowDefinitions>
-			<Canvas Name="OuterCanvas" Grid.Row="1" Background="White">
+			<Canvas Name="OuterCanvas" Grid.Row="1" Background="White" PointerWheelChanged="OuterCanvas_PointerWheelChanged">
 				<Canvas.GestureRecognizers>
 					<image:PanAndZoomGestureRecognizer/>
 				</Canvas.GestureRecognizers>
@@ -140,6 +140,39 @@
 						</Grid.ColumnDefinitions>
 						<StackPanel Grid.Column="1" Margin="-10"
 									Orientation="Horizontal">
+							<Button Name="FontSizeButton" Width="40" Height="40"
+									Margin="10">
+								<Canvas Width="25" Height="25"
+										HorizontalAlignment="Center" VerticalAlignment="Center">
+									<TextBlock Text="A" FontSize="20"
+											   Canvas.Left="2"
+											   Canvas.Bottom="1"/>
+									<TextBlock Text="A" FontSize="10"
+											   Canvas.Left="15"
+											   Canvas.Bottom="3"/>
+								</Canvas>
+								<Button.Flyout>
+									<Flyout Placement="Top" VerticalOffset="0">
+										<Border>
+											<Grid>
+												<Grid.RowDefinitions>
+													<RowDefinition Height="40"/>
+													<RowDefinition Height="Auto"/>
+												</Grid.RowDefinitions>
+												<TextBlock FontSize="{Binding $parent[components:ImageEditor].FontSize}"
+														   Text="Aa"
+														   VerticalAlignment="Center"
+														   TextAlignment="Center"/>
+												<Slider Value="{Binding $parent[components:ImageEditor].FontSize}"
+														Grid.Row="1"
+														Minimum="5.0"
+														Maximum="40.0"
+														Width="150"/>
+											</Grid>
+										</Border>
+									</Flyout>
+								</Button.Flyout>
+							</Button>
 							<Button Name="LineThicknessButton" Width="40" Height="40"
 									Margin="10">
 								<Canvas Width="25" Height="21"

+ 62 - 45
InABox.Avalonia/Components/ImageEditor/ImageEditor.axaml.cs

@@ -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;
         }
     }

+ 2 - 20
InABox.Avalonia/Components/ImageEditor/Objects/TextObject.cs

@@ -20,7 +20,7 @@ internal class TextObject : IImageEditorObject
 
     public Point Point { get; set; }
 
-    public Size Size { get; set; }
+    public double FontSize { get; set; }
 
     public string Text { get; set; } = "";
 
@@ -33,25 +33,7 @@ internal class TextObject : IImageEditorObject
         Canvas.SetLeft(Control, Point.X);
         Canvas.SetTop(Control, Point.Y);
 
-        var font = new Typeface(Control.FontFamily);
-
-        var formatted = new FormattedText(Text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, font, 12, PrimaryBrush);
-
-        var width = formatted.WidthIncludingTrailingWhitespace;
-        var height = formatted.Height;
-
-        if(Size.Width == 0)
-        {
-            Size = Size.WithWidth(width);
-        }
-        if(Size.Height == 0)
-        {
-            Size = Size.WithHeight(height);
-        }
-
-        var scaleFactor = Math.Min(Size.Width / width, Size.Height / height);
-
-        Control.FontSize = 12 * scaleFactor;
+        Control.FontSize = FontSize;
         Control.Text = Text;
         Control.Foreground = PrimaryBrush;
     }