mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 22:06:30 +00:00
I like it move it move it
This commit is contained in:
@@ -0,0 +1,334 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using Azaion.Annotator.DTO;
|
||||
using MediatR;
|
||||
using Color = System.Windows.Media.Color;
|
||||
using Rectangle = System.Windows.Shapes.Rectangle;
|
||||
|
||||
namespace Azaion.Annotator.Controls;
|
||||
|
||||
public class CanvasEditor : Canvas
|
||||
{
|
||||
private Point _lastPos;
|
||||
|
||||
private readonly Rectangle _newAnnotationRect;
|
||||
private Point _newAnnotationStartPos;
|
||||
|
||||
private readonly Line _horizontalLine;
|
||||
private readonly Line _verticalLine;
|
||||
private readonly TextBlock _classNameHint;
|
||||
|
||||
private Rectangle _curRec;
|
||||
private AnnotationControl _curAnn;
|
||||
|
||||
private const int MIN_SIZE = 20;
|
||||
|
||||
public FormState FormState { get; set; }
|
||||
public IMediator Mediator { get; set; }
|
||||
|
||||
private AnnotationClass _currentAnnClass;
|
||||
public AnnotationClass CurrentAnnClass
|
||||
{
|
||||
get => _currentAnnClass;
|
||||
set
|
||||
{
|
||||
_verticalLine.Stroke = value.ColorBrush;
|
||||
_verticalLine.Fill = value.ColorBrush;
|
||||
_horizontalLine.Stroke = value.ColorBrush;
|
||||
_horizontalLine.Fill = value.ColorBrush;
|
||||
_classNameHint.Text = value.Name;
|
||||
|
||||
_newAnnotationRect.Stroke = value.ColorBrush;
|
||||
_newAnnotationRect.Fill = value.ColorBrush;
|
||||
_currentAnnClass = value;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly List<AnnotationControl> CurrentAnns = new();
|
||||
|
||||
public CanvasEditor()
|
||||
{
|
||||
_horizontalLine = new Line
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
Stroke = new SolidColorBrush(Colors.Blue),
|
||||
Fill = new SolidColorBrush(Colors.Blue),
|
||||
StrokeDashArray = [5],
|
||||
StrokeThickness = 2
|
||||
};
|
||||
_verticalLine = new Line
|
||||
{
|
||||
VerticalAlignment = VerticalAlignment.Stretch,
|
||||
Stroke = new SolidColorBrush(Colors.Blue),
|
||||
Fill = new SolidColorBrush(Colors.Blue),
|
||||
StrokeDashArray = [5],
|
||||
StrokeThickness = 2
|
||||
};
|
||||
_classNameHint = new TextBlock
|
||||
{
|
||||
Text = CurrentAnnClass?.Name ?? "asd",
|
||||
Foreground = new SolidColorBrush(Colors.Black),
|
||||
Cursor = Cursors.Arrow,
|
||||
FontSize = 16,
|
||||
FontWeight = FontWeights.Bold
|
||||
};
|
||||
_newAnnotationRect = new Rectangle
|
||||
{
|
||||
Name = "selector",
|
||||
Height = 0,
|
||||
Width = 0,
|
||||
Stroke = new SolidColorBrush(Colors.Gray),
|
||||
Fill = new SolidColorBrush(Color.FromArgb(128, 128, 128, 128)),
|
||||
};
|
||||
Loaded += Init;
|
||||
}
|
||||
|
||||
private void Init(object sender, RoutedEventArgs e)
|
||||
{
|
||||
KeyDown += (_, args) =>
|
||||
{
|
||||
Console.WriteLine($"pressed {args.Key}");
|
||||
};
|
||||
MouseDown += CanvasMouseDown;
|
||||
MouseMove += CanvasMouseMove;
|
||||
MouseUp += CanvasMouseUp;
|
||||
SizeChanged += CanvasResized;
|
||||
Cursor = Cursors.Cross;
|
||||
_horizontalLine.X1 = 0;
|
||||
_horizontalLine.X2 = ActualWidth;
|
||||
_verticalLine.Y1 = 0;
|
||||
_verticalLine.Y2 = ActualHeight;
|
||||
|
||||
Children.Add(_newAnnotationRect);
|
||||
Children.Add(_horizontalLine);
|
||||
Children.Add(_verticalLine);
|
||||
Children.Add(_classNameHint);
|
||||
}
|
||||
|
||||
private void CanvasMouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
ClearSelections();
|
||||
NewAnnotationStart(sender, e);
|
||||
}
|
||||
|
||||
private void CanvasMouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
var pos = e.GetPosition(this);
|
||||
_horizontalLine.Y1 = _horizontalLine.Y2 = pos.Y;
|
||||
_verticalLine.X1 = _verticalLine.X2 = pos.X;
|
||||
SetLeft(_classNameHint, pos.X + 10);
|
||||
SetTop(_classNameHint, pos.Y - 30);
|
||||
|
||||
if (e.LeftButton != MouseButtonState.Pressed)
|
||||
return;
|
||||
if (FormState.SelectionState == SelectionState.NewAnnCreating)
|
||||
NewAnnotationCreatingMove(sender, e);
|
||||
|
||||
if (FormState.SelectionState == SelectionState.AnnResizing)
|
||||
AnnotationResizeMove(sender, e);
|
||||
|
||||
if (FormState.SelectionState == SelectionState.AnnMoving)
|
||||
AnnotationPositionMove(sender, e);
|
||||
}
|
||||
|
||||
private void CanvasMouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (FormState.SelectionState == SelectionState.NewAnnCreating)
|
||||
CreateAnnotation(e.GetPosition(this));
|
||||
|
||||
FormState.SelectionState = SelectionState.None;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void CanvasResized(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
_horizontalLine.X2 = e.NewSize.Width;
|
||||
_verticalLine.Y2 = e.NewSize.Height;
|
||||
}
|
||||
|
||||
#region Annotation Resizing & Moving
|
||||
|
||||
private void AnnotationResizeStart(object sender, MouseEventArgs e)
|
||||
{
|
||||
FormState.SelectionState = SelectionState.AnnResizing;
|
||||
_lastPos = e.GetPosition(this);
|
||||
_curRec = (Rectangle)sender;
|
||||
_curAnn = (AnnotationControl)((Grid)_curRec.Parent).Parent;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void AnnotationResizeMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (FormState.SelectionState != SelectionState.AnnResizing)
|
||||
return;
|
||||
|
||||
var currentPos = e.GetPosition(this);
|
||||
|
||||
var x = GetLeft(_curAnn);
|
||||
var y = GetTop(_curAnn);
|
||||
var offsetX = currentPos.X - _lastPos.X;
|
||||
var offsetY = currentPos.Y - _lastPos.Y;
|
||||
switch (_curRec.HorizontalAlignment, _curRec.VerticalAlignment)
|
||||
{
|
||||
case (HorizontalAlignment.Left, VerticalAlignment.Top):
|
||||
_curAnn.Width = Math.Max(MIN_SIZE, _curAnn.Width - offsetX);
|
||||
_curAnn.Height = Math.Max(MIN_SIZE, _curAnn.Height - offsetY);
|
||||
SetLeft(_curAnn, x + offsetX);
|
||||
SetTop(_curAnn, y + offsetY);
|
||||
break;
|
||||
case (HorizontalAlignment.Center, VerticalAlignment.Top):
|
||||
_curAnn.Height = Math.Max(MIN_SIZE, _curAnn.Height - offsetY);
|
||||
SetTop(_curAnn, y + offsetY);
|
||||
break;
|
||||
case (HorizontalAlignment.Right, VerticalAlignment.Top):
|
||||
_curAnn.Width = Math.Max(MIN_SIZE, _curAnn.Width + offsetX);
|
||||
_curAnn.Height = Math.Max(MIN_SIZE, _curAnn.Height - offsetY);
|
||||
SetTop(_curAnn, y + offsetY);
|
||||
break;
|
||||
|
||||
case (HorizontalAlignment.Left, VerticalAlignment.Center):
|
||||
_curAnn.Width = Math.Max(MIN_SIZE, _curAnn.Width - offsetX);
|
||||
SetLeft(_curAnn, x + offsetX);
|
||||
break;
|
||||
case (HorizontalAlignment.Right, VerticalAlignment.Center):
|
||||
_curAnn.Width = Math.Max(MIN_SIZE, _curAnn.Width + offsetX);
|
||||
break;
|
||||
|
||||
case (HorizontalAlignment.Left, VerticalAlignment.Bottom):
|
||||
_curAnn.Width = Math.Max(MIN_SIZE, _curAnn.Width - offsetX);
|
||||
_curAnn.Height = Math.Max(MIN_SIZE, _curAnn.Height + offsetY);
|
||||
SetLeft(_curAnn, x + offsetX);
|
||||
break;
|
||||
case (HorizontalAlignment.Center, VerticalAlignment.Bottom):
|
||||
_curAnn.Height = Math.Max(MIN_SIZE, _curAnn.Height + offsetY);
|
||||
break;
|
||||
case (HorizontalAlignment.Right, VerticalAlignment.Bottom):
|
||||
_curAnn.Width = Math.Max(MIN_SIZE, _curAnn.Width + offsetX);
|
||||
_curAnn.Height = Math.Max(MIN_SIZE, _curAnn.Height + offsetY);
|
||||
break;
|
||||
}
|
||||
_lastPos = currentPos;
|
||||
}
|
||||
|
||||
private void AnnotationPositionStart(object sender, MouseEventArgs e)
|
||||
{
|
||||
_lastPos = e.GetPosition(this);
|
||||
_curAnn = (AnnotationControl)sender;
|
||||
|
||||
if (!Keyboard.IsKeyDown(Key.LeftCtrl) && !Keyboard.IsKeyDown(Key.RightCtrl))
|
||||
ClearSelections();
|
||||
|
||||
_curAnn.IsSelected = true;
|
||||
|
||||
FormState.SelectionState = SelectionState.AnnMoving;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void AnnotationPositionMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (FormState.SelectionState != SelectionState.AnnMoving)
|
||||
return;
|
||||
|
||||
var currentPos = e.GetPosition(this);
|
||||
var offsetX = currentPos.X - _lastPos.X;
|
||||
var offsetY = currentPos.Y - _lastPos.Y;
|
||||
|
||||
SetLeft(_curAnn, GetLeft(_curAnn) + offsetX);
|
||||
SetTop(_curAnn, GetTop(_curAnn) + offsetY);
|
||||
_lastPos = currentPos;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region NewAnnotation
|
||||
|
||||
private void NewAnnotationStart(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
_newAnnotationStartPos = e.GetPosition(this);
|
||||
|
||||
SetLeft(_newAnnotationRect, _newAnnotationStartPos.X);
|
||||
SetTop(_newAnnotationRect, _newAnnotationStartPos.Y);
|
||||
_newAnnotationRect.MouseMove += NewAnnotationCreatingMove;
|
||||
|
||||
FormState.SelectionState = SelectionState.NewAnnCreating;
|
||||
}
|
||||
|
||||
private void NewAnnotationCreatingMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (FormState.SelectionState != SelectionState.NewAnnCreating)
|
||||
return;
|
||||
|
||||
var currentPos = e.GetPosition(this);
|
||||
var diff = currentPos - _newAnnotationStartPos;
|
||||
|
||||
_newAnnotationRect.Height = Math.Abs(diff.Y);
|
||||
_newAnnotationRect.Width = Math.Abs(diff.X);
|
||||
|
||||
if (diff.X < 0)
|
||||
SetLeft(_newAnnotationRect, currentPos.X);
|
||||
if (diff.Y < 0)
|
||||
SetTop(_newAnnotationRect, currentPos.Y);
|
||||
}
|
||||
|
||||
private void CreateAnnotation(Point endPos)
|
||||
{
|
||||
_newAnnotationRect.Width = 0;
|
||||
_newAnnotationRect.Height = 0;
|
||||
var width = Math.Abs(endPos.X - _newAnnotationStartPos.X);
|
||||
var height = Math.Abs(endPos.Y - _newAnnotationStartPos.Y);
|
||||
if (width < MIN_SIZE || height < MIN_SIZE)
|
||||
return;
|
||||
|
||||
var annotationControl = new AnnotationControl(CurrentAnnClass, AnnotationResizeStart)
|
||||
{
|
||||
Width = width,
|
||||
Height = height
|
||||
};
|
||||
annotationControl.MouseDown += AnnotationPositionStart;
|
||||
SetLeft(annotationControl, Math.Min(endPos.X, _newAnnotationStartPos.X));
|
||||
SetTop(annotationControl, Math.Min(endPos.Y, _newAnnotationStartPos.Y));
|
||||
Children.Add(annotationControl);
|
||||
CurrentAnns.Add(annotationControl);
|
||||
_newAnnotationRect.Fill = new SolidColorBrush(CurrentAnnClass.Color);
|
||||
}
|
||||
|
||||
public AnnotationControl CreateAnnotation(AnnotationClass annClass, AnnotationInfo info)
|
||||
{
|
||||
var annotationControl = new AnnotationControl(annClass, AnnotationResizeStart)
|
||||
{
|
||||
Width = info.Width,
|
||||
Height = info.Height
|
||||
};
|
||||
annotationControl.MouseDown += AnnotationPositionStart;
|
||||
SetLeft(annotationControl, info.X );
|
||||
SetTop(annotationControl, info.Y);
|
||||
Children.Add(annotationControl);
|
||||
CurrentAnns.Add(annotationControl);
|
||||
_newAnnotationRect.Fill = new SolidColorBrush(annClass.Color);
|
||||
return annotationControl;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void RemoveAnnotations(IEnumerable<AnnotationControl> listToRemove)
|
||||
{
|
||||
foreach (var ann in listToRemove)
|
||||
{
|
||||
Children.Remove(ann);
|
||||
CurrentAnns.Remove(ann);
|
||||
}
|
||||
}
|
||||
public void RemoveAllAnns() => RemoveAnnotations(CurrentAnns.ToList());
|
||||
public void RemoveSelectedAnns() => RemoveAnnotations(CurrentAnns.Where(x => x.IsSelected).ToList());
|
||||
|
||||
private void ClearSelections()
|
||||
{
|
||||
foreach (var ann in CurrentAnns)
|
||||
ann.IsSelected = false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user