This commit is contained in:
Wiesław Šoltés 2022-01-18 11:43:46 +01:00
Родитель 493bce219c
Коммит 029fc5ab82
7 изменённых файлов: 155 добавлений и 53 удалений

Просмотреть файл

@ -1,65 +1,43 @@
using Avalonia;
using System.Collections.ObjectModel;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Media;
using VectorPaint.ViewModels;
using VectorPaint.ViewModels.Drawables;
using VectorPaint.ViewModels.Tools;
namespace VectorPaint.Controls;
public class VectorCanvas : Control
{
private Drawable? _drawable;
private Point _start;
public ObservableCollection<Tool> Tools { get; set; }
public override void Render(DrawingContext context)
public Tool? CurrentTool { get; set; }
public VectorCanvas()
{
if (DataContext is MainWindowViewModel mainWindowViewModel)
Tools = new ObservableCollection<Tool>()
{
context.DrawRectangle(Brushes.WhiteSmoke, null, Bounds);
new SelectionTool()
};
foreach (var drawable in mainWindowViewModel.Drawables)
{
drawable.Draw(context);
}
}
base.Render(context);
CurrentTool = Tools[0];
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
if (DataContext is MainWindowViewModel mainWindowViewModel)
if (DataContext is IDrawing drawing)
{
var point = e.GetCurrentPoint(this).Position;
_start = point;
foreach (var drawable in mainWindowViewModel.Drawables)
{
var contains = drawable.HitTest(point);
if (contains)
{
_drawable = drawable;
break;
}
}
if (_drawable is { })
{
e.Pointer.Capture(this);
}
CurrentTool?.OnPointerPressed(drawing, e);
}
base.OnPointerPressed(e);
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
if (_drawable is { })
if (DataContext is IDrawing drawing)
{
e.Pointer.Capture(null);
_drawable = null;
CurrentTool?.OnPointerReleased(drawing, e);
}
base.OnPointerReleased(e);
@ -67,17 +45,21 @@ public class VectorCanvas : Control
protected override void OnPointerMoved(PointerEventArgs e)
{
if (_drawable is { })
if (DataContext is IDrawing drawing)
{
var point = e.GetCurrentPoint(this).Position;
_drawable.Move(point - _start);
_start = point;
InvalidateVisual();
CurrentTool?.OnPointerMoved(drawing, e);
}
base.OnPointerMoved(e);
}
public override void Render(DrawingContext context)
{
if (DataContext is IDrawing drawing)
{
drawing.Draw(context, Bounds);
}
base.Render(context);
}
}

Просмотреть файл

@ -49,7 +49,7 @@ public class RectangleDrawable : GeometryDrawable
new Point(_topLeft.X, _topLeft.Y),
new Point(_bottomRight.X, _bottomRight.Y));
}
protected sealed override Geometry? CreateGeometry()
{
if (_topLeft is null || _bottomRight is null)

Просмотреть файл

@ -1,21 +1,37 @@
using System.Collections.ObjectModel;
using Avalonia;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.VisualTree;
using ReactiveUI;
using VectorPaint.ViewModels.Drawables;
namespace VectorPaint.ViewModels;
public class MainWindowViewModel : ViewModelBase
public interface IDrawing
{
public ObservableCollection<Drawable> _drawables;
ObservableCollection<Drawable> Drawables { get; set; }
Drawable? HitTest(Point point);
void Draw(DrawingContext context, Rect bounds);
void Invalidate();
IVisual? Canvas { get; set; }
IInputElement? Input { get; set; }
}
public class MainWindowViewModel : ViewModelBase, IDrawing
{
private ObservableCollection<Drawable> _drawables;
public ObservableCollection<Drawable> Drawables
{
get => _drawables;
set => this.RaiseAndSetIfChanged(ref _drawables, value);
}
public IVisual? Canvas { get; set; }
public IInputElement? Input { get; set; }
public MainWindowViewModel()
{
_drawables = new ObservableCollection<Drawable>();
@ -27,6 +43,13 @@ public class MainWindowViewModel : ViewModelBase
};
_drawables.Add(line0);
var ellipse0 = new EllipseDrawable()
{
TopLeft = new PointDrawable(30, 210),
BottomRight = new PointDrawable(90, 270)
};
_drawables.Add(ellipse0);
var rect0 = new RectangleDrawable()
{
TopLeft = new PointDrawable(210, 30),
@ -56,11 +79,32 @@ public class MainWindowViewModel : ViewModelBase
}
}
public void Draw(DrawingContext context)
public Drawable? HitTest(Point point)
{
for (var i = _drawables.Count - 1; i >= 0; i--)
{
var drawable = _drawables[i];
if (drawable.HitTest(point))
{
return drawable;
}
}
return null;
}
public void Draw(DrawingContext context, Rect bounds)
{
context.DrawRectangle(Brushes.WhiteSmoke, null, bounds);
foreach (var drawable in _drawables)
{
drawable.Draw(context);
}
}
public void Invalidate()
{
Canvas?.InvalidateVisual();
}
}

Просмотреть файл

@ -0,0 +1,46 @@
using Avalonia;
using Avalonia.Input;
using VectorPaint.ViewModels.Drawables;
namespace VectorPaint.ViewModels.Tools;
public class SelectionTool : Tool
{
private Drawable? _drawable;
private Point _start;
public override void OnPointerPressed(IDrawing drawing, PointerPressedEventArgs e)
{
var point = e.GetCurrentPoint(drawing.Input).Position;
var drawable = drawing.HitTest(point);
if (drawable is { })
{
_drawable = drawable;
_start = point;
e.Pointer.Capture(drawing.Input);
}
}
public override void OnPointerReleased(IDrawing drawing, PointerReleasedEventArgs e)
{
if (_drawable is { })
{
e.Pointer.Capture(null);
_drawable = null;
}
}
public override void OnPointerMoved(IDrawing drawing, PointerEventArgs e)
{
if (_drawable is { })
{
var point = e.GetCurrentPoint(drawing.Input).Position;
_drawable.Move(point - _start);
_start = point;
drawing.Invalidate();
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
using Avalonia.Input;
namespace VectorPaint.ViewModels.Tools;
public abstract class Tool
{
public abstract void OnPointerPressed(IDrawing drawing, PointerPressedEventArgs e);
public abstract void OnPointerReleased(IDrawing drawing, PointerReleasedEventArgs e);
public abstract void OnPointerMoved(IDrawing drawing, PointerEventArgs e);
}

Просмотреть файл

@ -11,7 +11,7 @@
<vm:MainWindowViewModel />
</Design.DataContext>
<c:VectorCanvas />
<c:VectorCanvas Name="VectorCanvas" />
</UserControl>

Просмотреть файл

@ -1,5 +1,8 @@
using Avalonia.Controls;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using VectorPaint.Controls;
using VectorPaint.ViewModels;
namespace VectorPaint.Views;
@ -14,5 +17,20 @@ public class MainView : UserControl
{
AvaloniaXamlLoader.Load(this);
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
if (DataContext is IDrawing drawing)
{
var vectorCanvas = this.FindControl<VectorCanvas>("VectorCanvas");
if (vectorCanvas is { })
{
drawing.Canvas = vectorCanvas;
drawing.Input = vectorCanvas;
}
}
base.OnAttachedToVisualTree(e);
}
}