瀏覽代碼

avalonia: Added TextObject to ImageEditor

Kenric Nugteren 4 天之前
父節點
當前提交
79ab5088d3

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

@@ -112,7 +112,7 @@
 														<Button Width="40" Height="40" Margin="10"
 																CommandParameter="{Binding Mode}"
 																Command="{Binding $parent[components:ImageEditor].SetModeCommand}"
-																Content="{Binding Canvas}"/>
+																Content="{Binding Content}"/>
 													</DataTemplate>
 												</ItemsControl.ItemTemplate>
 												<ItemsControl.ItemsPanel>

+ 73 - 5
InABox.Avalonia/Components/ImageEditor/ImageEditor.axaml.cs

@@ -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,7 @@ using InABox.Avalonia.Converters;
 using InABox.Core;
 using SkiaSharp;
 using System.Collections.ObjectModel;
+using System.Threading.Tasks;
 
 namespace InABox.Avalonia.Components;
 
@@ -22,14 +24,16 @@ public enum ImageEditingMode
 {
     Polyline,
     Rectangle,
-    Ellipse
+    Ellipse,
+    Text,
+    Dimension
 }
 
-public class ImageEditorModeButton(ImageEditingMode mode, Canvas? canvas)
+public class ImageEditorModeButton(ImageEditingMode mode, Control? content)
 {
     public ImageEditingMode Mode { get; set; } = mode;
 
-    public Canvas? Canvas { get; set; } = canvas;
+    public Control? Content { get; set; } = content;
 }
 
 public class ImageEditorTransparentImageBrushConverter : AbstractConverter<IBrush?, IBrush?>
@@ -309,6 +313,7 @@ public partial class ImageEditor : UserControl
         AddModeButton(ImageEditingMode.Polyline);
         AddModeButton(ImageEditingMode.Rectangle);
         AddModeButton(ImageEditingMode.Ellipse);
+        AddModeButton(ImageEditingMode.Text);
     }
 
     private void AddModeButton(ImageEditingMode mode)
@@ -316,7 +321,7 @@ public partial class ImageEditor : UserControl
         ModeButtons.Add(new(mode, CreateModeButtonContent(mode)));
     }
 
-    private Canvas? CreateModeButtonContent(ImageEditingMode mode, bool bindColour = false)
+    private Control? CreateModeButtonContent(ImageEditingMode mode, bool bindColour = false)
     {
         switch (mode)
         {
@@ -405,6 +410,14 @@ public partial class ImageEditor : UserControl
                 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;
+                return textBox;
             default:
                 return null;
         }
@@ -460,7 +473,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 +483,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);
@@ -511,6 +529,15 @@ public partial class ImageEditor : UserControl
                 };
                 AddObject(CurrentObject);
                 break;
+            case ImageEditingMode.Text:
+                CurrentObject = new SelectionObject
+                {
+                    Point1 = position,
+                    Point2 = position,
+                    PrimaryBrush = PrimaryBrush
+                };
+                AddObject(CurrentObject);
+                break;
         }
     }
 
@@ -534,6 +561,11 @@ 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;
         }
     }
 
@@ -560,9 +592,45 @@ 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;
         }
 
     }
 
+    private async Task CreateObjectFromSelection(SelectionObject selection)
+    {
+        switch (Mode)
+        {
+            case ImageEditingMode.Text:
+                var text = await Navigation.Popup<TextEditViewModel, string?>(x => { });
+                if(text is null)
+                {
+                    return;
+                }
+                CurrentObject = new TextObject
+                {
+                    Point = selection.GetTopLeft(),
+                    Size = selection.GetSize(),
+                    Text = text,
+                    PrimaryBrush = selection.PrimaryBrush
+                };
+                AddObject(CurrentObject);
+                break;
+        }
+    }
+
     #endregion
 }

+ 91 - 0
InABox.Avalonia/Components/ImageEditor/Objects/SelectionObject.cs

@@ -0,0 +1,91 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Shapes;
+using Avalonia.Media;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace InABox.Avalonia.Components.ImageEditing;
+
+internal class SelectionObject : IImageEditorObject
+{
+    public IBrush? PrimaryBrush { get; set; }
+
+    public Point Point1 { get; set; }
+
+    public Point Point2 { get; set; }
+
+    private Rectangle Control = new();
+
+    public Control GetControl() => Control;
+
+    public Point GetTopLeft()
+    {
+        return new(
+            Math.Min(Point1.X, Point2.X),
+            Math.Min(Point1.Y, Point2.Y));
+    }
+    public Size GetSize()
+    {
+        return new(
+            Math.Abs(Point2.X - Point1.X),
+            Math.Abs(Point2.Y - Point1.Y));
+    }
+
+    public void Update()
+    {
+        Control.Stroke = GetBrush();
+        Control.StrokeThickness = 5;
+        Control.StrokeDashArray = [2, 2];
+
+        var topLeft = GetTopLeft();
+        var size = GetSize();
+
+        Canvas.SetLeft(Control, topLeft.X);
+        Canvas.SetTop(Control, topLeft.Y);
+        Control.Width = size.Width;
+        Control.Height = size.Height;
+    }
+
+    private IBrush? GetBrush()
+    {
+        var brush = new VisualBrush
+        {
+            TileMode = TileMode.Tile,
+            DestinationRect = new(0, 0, 4, 4, RelativeUnit.Absolute)
+        };
+        var canvas = new Canvas
+        {
+            Width = 10,
+            Height = 10
+        };
+        var rect1 = new Rectangle { Width = 5, Height = 5 };
+        var rect2 = new Rectangle { Width = 5, Height = 5 };
+        var rect3 = new Rectangle { Width = 5, Height = 5 };
+        var rect4 = new Rectangle { Width = 5, Height = 5 };
+
+        Canvas.SetLeft(rect2, 5);
+        Canvas.SetTop(rect2, 0);
+
+        Canvas.SetLeft(rect3, 5);
+        Canvas.SetTop(rect3, 5);
+
+        Canvas.SetLeft(rect4, 0);
+        Canvas.SetTop(rect4, 5);
+
+        rect1.Fill = new SolidColorBrush(Colors.White);
+        rect2.Fill = new SolidColorBrush(Colors.Black);
+        rect3.Fill = new SolidColorBrush(Colors.White);
+        rect4.Fill = new SolidColorBrush(Colors.Black);
+
+        canvas.Children.Add(rect1);
+        canvas.Children.Add(rect2);
+        canvas.Children.Add(rect3);
+
+        brush.Visual = canvas;
+        return brush;
+    }
+}

+ 49 - 0
InABox.Avalonia/Components/ImageEditor/Objects/TextObject.cs

@@ -0,0 +1,49 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Platform;
+using Avalonia.Controls.Shapes;
+using Avalonia.Layout;
+using Avalonia.Media;
+using Avalonia.Media.TextFormatting;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace InABox.Avalonia.Components.ImageEditing;
+
+internal class TextObject : IImageEditorObject
+{
+    public IBrush? PrimaryBrush { get; set; }
+
+    public Point Point { get; set; }
+
+    public Size Size { get; set; }
+
+    public string Text { get; set; } = "";
+
+    private TextBlock Control = new();
+
+    public Control GetControl() => Control;
+
+    public void Update()
+    {
+        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;
+
+        var scaleFactor = Math.Min(Size.Width / width, Size.Height / height);
+
+        Control.FontSize = 12 * scaleFactor;
+        Control.Text = Text;
+        Control.Foreground = PrimaryBrush;
+    }
+}

+ 3 - 3
InABox.Client.RPC/InABox.Client.RPC.csproj

@@ -11,10 +11,10 @@
     </ItemGroup>
 
     <ItemGroup>
-      <PackageReference Include="H.Formatters" Version="2.0.59" />
-      <PackageReference Include="H.Formatters.BinaryFormatter" Version="2.0.59" />
+      <PackageReference Include="H.Formatters" Version="15.0.0" />
+      <PackageReference Include="H.Formatters.BinaryFormatter" Version="15.0.0" />
       <PackageReference Include="H.Formatters.MessagePack" Version="15.0.0" />
-      <PackageReference Include="H.Pipes" Version="2.0.59" />
+      <PackageReference Include="H.Pipes" Version="15.0.0" />
       <PackageReference Include="WebSocket4Net" Version="0.15.2" />
     </ItemGroup>
 

+ 5 - 5
InABox.Server/InABox.Server.csproj

@@ -10,11 +10,11 @@
         <PackageReference Include="Fleck" Version="1.2.0" />
         <PackageReference Include="GenHTTP.Core" Version="8.4.1" />
         <PackageReference Include="GenHTTP.Modules.Practices" Version="8.4.0" />
-        <PackageReference Include="H.Formatters.BinaryFormatter" Version="2.0.59" />
-        <PackageReference Include="H.Formatters.Ceras" Version="2.0.59" />
-        <PackageReference Include="H.Formatters.MessagePack" Version="2.0.59" />
-        <PackageReference Include="H.Pipes" Version="2.0.59" />
-        <PackageReference Include="H.Pipes.AccessControl" Version="2.0.59" />
+        <PackageReference Include="H.Formatters.BinaryFormatter" Version="15.0.0" />
+        <PackageReference Include="H.Formatters.Ceras" Version="15.0.0" />
+        <PackageReference Include="H.Formatters.MessagePack" Version="15.0.0" />
+        <PackageReference Include="H.Pipes" Version="15.0.0" />
+        <PackageReference Include="H.Pipes.AccessControl" Version="15.0.0" />
     </ItemGroup>
 
     <ItemGroup>