ImageEditor.axaml.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. using Avalonia;
  2. using Avalonia.Controls;
  3. using Avalonia.Controls.Shapes;
  4. using Avalonia.Data;
  5. using Avalonia.Input;
  6. using Avalonia.Markup.Xaml;
  7. using Avalonia.Media;
  8. using CommunityToolkit.Mvvm.Input;
  9. using InABox.Avalonia.Components.ImageEditing;
  10. using System.Collections.ObjectModel;
  11. namespace InABox.Avalonia.Components;
  12. public enum ImageEditingMode
  13. {
  14. Polyline
  15. }
  16. // TODO: Make it so we don't re-render everything everytime 'Objects' changes.
  17. public partial class ImageEditor : UserControl
  18. {
  19. public static readonly StyledProperty<IImage?> SourceProperty =
  20. AvaloniaProperty.Register<ImageEditor, IImage?>(nameof(Source));
  21. public static readonly StyledProperty<IBrush?> PrimaryBrushProperty =
  22. AvaloniaProperty.Register<ImageEditor, IBrush?>(nameof(PrimaryBrush), new SolidColorBrush(Colors.Black));
  23. public IImage? Source
  24. {
  25. get => GetValue(SourceProperty);
  26. set => SetValue(SourceProperty, value);
  27. }
  28. #region Editing Properties
  29. public ImageEditingMode Mode { get; set; } = ImageEditingMode.Polyline;
  30. public IBrush? PrimaryBrush
  31. {
  32. get => GetValue(PrimaryBrushProperty);
  33. set => SetValue(PrimaryBrushProperty, value);
  34. }
  35. public double LineThickness { get; set; } = 1.0;
  36. #endregion
  37. private ObservableCollection<IImageEditorObject> Objects = new();
  38. private IImageEditorObject? CurrentObject;
  39. private Stack<IImageEditorObject> RedoStack = new();
  40. public ImageEditor()
  41. {
  42. InitializeComponent();
  43. Objects.CollectionChanged += Objects_CollectionChanged;
  44. SetMode(Mode);
  45. }
  46. #region Editing Commands
  47. private void Undo()
  48. {
  49. RedoStack.Push(Objects[^1]);
  50. Objects.RemoveAt(Objects.Count - 1);
  51. }
  52. private void Redo()
  53. {
  54. if (!RedoStack.TryPop(out var top)) return;
  55. Objects.Add(top);
  56. }
  57. private void AddObject(IImageEditorObject obj)
  58. {
  59. Objects.Add(obj);
  60. RedoStack.Clear();
  61. }
  62. [RelayCommand]
  63. private void SetMode(ImageEditingMode mode)
  64. {
  65. Mode = mode;
  66. switch (mode)
  67. {
  68. case ImageEditingMode.Polyline:
  69. var canvas = new Canvas();
  70. var points = new Point[] { new(0, 0), new(20, 8), new(5, 16), new(25, 25) };
  71. var line1 = new Polyline { Points = points, Width = 25, Height = 25 };
  72. var line2 = new Polyline { Points = points, Width = 25, Height = 25 };
  73. line1.StrokeThickness = 4;
  74. line1.StrokeLineCap = PenLineCap.Round;
  75. line2.StrokeThickness = 1.5;
  76. line1.Stroke = new SolidColorBrush(Colors.Black);
  77. line2.Bind(Polyline.StrokeProperty, new Binding(nameof(PrimaryBrush)) { Source = this });
  78. canvas.Children.Add(line1);
  79. canvas.Children.Add(line2);
  80. ShapeButton.Content = canvas;
  81. break;
  82. }
  83. }
  84. #endregion
  85. private void Objects_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
  86. {
  87. Canvas.Children.Clear();
  88. foreach(var item in Objects)
  89. {
  90. item.Update();
  91. Canvas.Children.Add(item.GetControl());
  92. }
  93. }
  94. Point ConvertToImageCoordinates(Point canvasCoordinates)
  95. {
  96. return canvasCoordinates;
  97. }
  98. private void Canvas_PointerPressed(object? sender, PointerPressedEventArgs e)
  99. {
  100. var position = ConvertToImageCoordinates(e.GetPosition(Canvas));
  101. switch (Mode)
  102. {
  103. case ImageEditingMode.Polyline:
  104. CurrentObject = new PolylineObject
  105. {
  106. Points = [position],
  107. PrimaryBrush = PrimaryBrush,
  108. Thickness = LineThickness
  109. };
  110. AddObject(CurrentObject);
  111. break;
  112. }
  113. }
  114. private void Canvas_PointerMoved(object? sender, PointerEventArgs e)
  115. {
  116. var position = ConvertToImageCoordinates(e.GetPosition(Canvas));
  117. if(CurrentObject is PolylineObject polyline)
  118. {
  119. polyline.Points.Add(position);
  120. polyline.Update();
  121. }
  122. }
  123. private void Canvas_PointerReleased(object? sender, PointerReleasedEventArgs e)
  124. {
  125. var position = ConvertToImageCoordinates(e.GetPosition(Canvas));
  126. if(CurrentObject is PolylineObject polyline)
  127. {
  128. polyline.Points.Add(position);
  129. polyline.Update();
  130. CurrentObject = null;
  131. }
  132. }
  133. }