123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- using Avalonia;
- using Avalonia.Controls;
- using Avalonia.Controls.Shapes;
- using Avalonia.Data;
- using Avalonia.Input;
- using Avalonia.Markup.Xaml;
- using Avalonia.Media;
- using CommunityToolkit.Mvvm.Input;
- using InABox.Avalonia.Components.ImageEditing;
- using System.Collections.ObjectModel;
- namespace InABox.Avalonia.Components;
- public enum ImageEditingMode
- {
- Polyline
- }
- // TODO: Make it so we don't re-render everything everytime 'Objects' changes.
- public partial class ImageEditor : UserControl
- {
- public static readonly StyledProperty<IImage?> SourceProperty =
- AvaloniaProperty.Register<ImageEditor, IImage?>(nameof(Source));
- public static readonly StyledProperty<IBrush?> PrimaryBrushProperty =
- AvaloniaProperty.Register<ImageEditor, IBrush?>(nameof(PrimaryBrush), new SolidColorBrush(Colors.Black));
- public IImage? Source
- {
- get => GetValue(SourceProperty);
- set => SetValue(SourceProperty, value);
- }
- #region Editing Properties
- public ImageEditingMode Mode { get; set; } = ImageEditingMode.Polyline;
- public IBrush? PrimaryBrush
- {
- get => GetValue(PrimaryBrushProperty);
- set => SetValue(PrimaryBrushProperty, value);
- }
- public double LineThickness { get; set; } = 1.0;
- #endregion
- private ObservableCollection<IImageEditorObject> Objects = new();
- private IImageEditorObject? CurrentObject;
- private Stack<IImageEditorObject> RedoStack = new();
- public ImageEditor()
- {
- InitializeComponent();
- Objects.CollectionChanged += Objects_CollectionChanged;
- SetMode(Mode);
- }
- #region Editing Commands
- private void Undo()
- {
- RedoStack.Push(Objects[^1]);
- Objects.RemoveAt(Objects.Count - 1);
- }
- private void Redo()
- {
- if (!RedoStack.TryPop(out var top)) return;
- Objects.Add(top);
- }
- private void AddObject(IImageEditorObject obj)
- {
- Objects.Add(obj);
- RedoStack.Clear();
- }
- [RelayCommand]
- private void SetMode(ImageEditingMode mode)
- {
- Mode = mode;
- switch (mode)
- {
- case ImageEditingMode.Polyline:
- var line = new Polyline
- {
- Points = [new(0, 0), new(20, 8), new(5, 16), new(25, 25)],
- Width = 25,
- Height = 25
- };
- line.Bind(Polyline.StrokeProperty, new Binding(nameof(PrimaryBrush)) { Source = this });
- ShapeButton.Content = line;
- break;
- }
- }
- #endregion
- private void Objects_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
- {
- Canvas.Children.Clear();
- foreach(var item in Objects)
- {
- item.Update();
- Canvas.Children.Add(item.GetControl());
- }
- }
- Point ConvertToImageCoordinates(Point canvasCoordinates)
- {
- return canvasCoordinates;
- }
- private void Canvas_PointerPressed(object? sender, PointerPressedEventArgs e)
- {
- var position = ConvertToImageCoordinates(e.GetPosition(Canvas));
- switch (Mode)
- {
- case ImageEditingMode.Polyline:
- CurrentObject = new PolylineObject
- {
- Points = [position],
- PrimaryBrush = PrimaryBrush,
- Thickness = LineThickness
- };
- AddObject(CurrentObject);
- break;
- }
- }
- private void Canvas_PointerMoved(object? sender, PointerEventArgs e)
- {
- var position = ConvertToImageCoordinates(e.GetPosition(Canvas));
- if(CurrentObject is PolylineObject polyline)
- {
- polyline.Points.Add(position);
- polyline.Update();
- }
- }
- private void Canvas_PointerReleased(object? sender, PointerReleasedEventArgs e)
- {
- var position = ConvertToImageCoordinates(e.GetPosition(Canvas));
- if(CurrentObject is PolylineObject polyline)
- {
- polyline.Points.Add(position);
- polyline.Update();
- CurrentObject = null;
- }
- }
- }
|