ImageEditor.axaml.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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 line = new Polyline
  70. {
  71. Points = [new(0, 0), new(20, 8), new(5, 16), new(25, 25)],
  72. Width = 25,
  73. Height = 25
  74. };
  75. line.Bind(Polyline.StrokeProperty, new Binding(nameof(PrimaryBrush)) { Source = this });
  76. ShapeButton.Content = line;
  77. break;
  78. }
  79. }
  80. #endregion
  81. private void Objects_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
  82. {
  83. Canvas.Children.Clear();
  84. foreach(var item in Objects)
  85. {
  86. item.Update();
  87. Canvas.Children.Add(item.GetControl());
  88. }
  89. }
  90. Point ConvertToImageCoordinates(Point canvasCoordinates)
  91. {
  92. return canvasCoordinates;
  93. }
  94. private void Canvas_PointerPressed(object? sender, PointerPressedEventArgs e)
  95. {
  96. var position = ConvertToImageCoordinates(e.GetPosition(Canvas));
  97. switch (Mode)
  98. {
  99. case ImageEditingMode.Polyline:
  100. CurrentObject = new PolylineObject
  101. {
  102. Points = [position],
  103. PrimaryBrush = PrimaryBrush,
  104. Thickness = LineThickness
  105. };
  106. AddObject(CurrentObject);
  107. break;
  108. }
  109. }
  110. private void Canvas_PointerMoved(object? sender, PointerEventArgs e)
  111. {
  112. var position = ConvertToImageCoordinates(e.GetPosition(Canvas));
  113. if(CurrentObject is PolylineObject polyline)
  114. {
  115. polyline.Points.Add(position);
  116. polyline.Update();
  117. }
  118. }
  119. private void Canvas_PointerReleased(object? sender, PointerReleasedEventArgs e)
  120. {
  121. var position = ConvertToImageCoordinates(e.GetPosition(Canvas));
  122. if(CurrentObject is PolylineObject polyline)
  123. {
  124. polyline.Points.Add(position);
  125. polyline.Update();
  126. CurrentObject = null;
  127. }
  128. }
  129. }