using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Controls.Shapes; using Avalonia.Input; using Avalonia.Media; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; namespace InABox.Avalonia.Components.ImageEditing; internal class DimensionObject : IImageEditorStateObject { public IBrush? PrimaryBrush { get; set; } public Point Point1 { get; set; } public Point Point2 { get; set; } public double LineThickness { get; set; } public string Text { get; set; } = ""; public double Offset { get; set; } = 10; public bool Complete { get; set; } = false; private Canvas Control = new(); private Thumb? Thumb; private bool _active = true; private ImageEditorState _state = new(1.0); public Control GetControl() => Control; private Vector GetMainVec() { var p1 = new Vector(Point1.X, Point1.Y); var p2 = new Vector(Point2.X, Point2.Y); var mainVec = p2 - p1; var length = mainVec.Length; if(length == 0) { mainVec = new Vector(0, 0); } else { mainVec /= length; } return mainVec; } private Vector GetPerpVec() { var mainVec = GetMainVec(); return new Vector(mainVec.Y, -mainVec.X); } private void CreateThumb() { var p1 = new Vector(Point1.X, Point1.Y); var p2 = new Vector(Point2.X, Point2.Y); var mainVec = p2 - p1; var length = mainVec.Length; if(length == 0) { mainVec = new Vector(0, 0); } else { mainVec /= length; } var perpVec = new Vector(mainVec.Y, -mainVec.X); var offset = perpVec * Offset; var thumbSize = 30; if(Thumb is not null) { Thumb.RenderTransform = new TransformGroup { Children = [ new RotateTransform(Math.Atan2(mainVec.Y, mainVec.X) * 180 / Math.PI) ] }; Thumb.BorderThickness = new(1); Thumb.Width = length; Thumb.Height = Math.Max(20, thumbSize / _state.ScaleFactor); var thumbPos = p1 + offset + mainVec * length / 2; Canvas.SetLeft(Thumb, thumbPos.X - Thumb.Width / 2); Canvas.SetTop(Thumb, thumbPos.Y - Thumb.Height / 2); } } public void SetState(ImageEditorState state) { _state = state; CreateThumb(); } public void Update() { Control.Children.RemoveAll(Control.Children.Where(x => !(x is Thumb))); Point Point(Vector v) => new(v.X, v.Y); var p1 = new Vector(Point1.X, Point1.Y); var p2 = new Vector(Point2.X, Point2.Y); var mainVec = p2 - p1; var length = mainVec.Length; if(length == 0) { mainVec = new Vector(0, 0); } else { mainVec /= length; } var perpVec = new Vector(mainVec.Y, -mainVec.X); var arrowLength = LineThickness * 2; var offset = perpVec * Offset; var middle = p1 + offset + mainVec * length / 2; var line1 = new Line { StartPoint = Point(p1 + offset), EndPoint = Point(middle), StrokeLineCap = PenLineCap.Round }; var line2 = new Line { StartPoint = Point(middle), EndPoint = Point(p2 + offset), StrokeLineCap = PenLineCap.Round }; var mainLines = new List() { line1, line2, new() { StartPoint = Point(p1 + offset), EndPoint = Point(p1 + mainVec * arrowLength + perpVec * arrowLength + offset), StrokeLineCap = PenLineCap.Square }, new() { StartPoint = Point(p1 + offset), EndPoint = Point(p1 + mainVec * arrowLength - perpVec * arrowLength + offset), StrokeLineCap = PenLineCap.Square }, new() { StartPoint = Point(p2 + offset), EndPoint = Point(p2 - mainVec * arrowLength + perpVec * arrowLength + offset), StrokeLineCap = PenLineCap.Square }, new() { StartPoint = Point(p2 + offset), EndPoint = Point(p2 - mainVec * arrowLength - perpVec * arrowLength + offset), StrokeLineCap = PenLineCap.Square } }; var dotLines = new List() { new() { StartPoint = Point(p1), EndPoint = Point(p1 + offset) }, new() { StartPoint = Point(p2), EndPoint = Point(p2 + offset) }, }; foreach (var line in dotLines) { line.StrokeThickness = LineThickness; line.Stroke = PrimaryBrush; line.StrokeDashArray = [2, 2]; Control.Children.Add(line); } foreach (var line in mainLines) { line.StrokeThickness = LineThickness; line.Stroke = PrimaryBrush; Control.Children.Add(line); } var textHeight = 20; var text = new TextBlock { Text = Text, FontSize = textHeight, TextAlignment = TextAlignment.Center, Foreground = PrimaryBrush }; text.RenderTransform = new RotateTransform(Math.Atan2(mainVec.Y, mainVec.X) * 180 / Math.PI); var textPos = p1 + offset + mainVec * length / 2; Canvas.SetLeft(text, textPos.X); Canvas.SetTop(text, textPos.Y); text.SizeChanged += (o, e) => { line1.EndPoint = Point(middle - mainVec * (text.Bounds.Width / 2 + 5)); line2.StartPoint = Point(middle + mainVec * (text.Bounds.Width / 2 + 5)); var topCorner = textPos - mainVec * text.Bounds.Width / 2 + perpVec * text.Bounds.Height / 2; Canvas.SetLeft(text, textPos.X - text.Bounds.Width / 2); Canvas.SetTop(text, textPos.Y - text.Bounds.Height / 2); }; Control.Children.Add(text); if(Thumb is null && _active && length > 0) { Thumb = new(); Thumb.Cursor = new(StandardCursorType.SizeAll); Thumb.DragDelta += Thumb_DragDelta; Thumb.ZIndex = 1; Control.Children.Add(Thumb); } CreateThumb(); } private Vector Rotate(Vector v, double angle) { angle = Math.Atan2(v.Y, v.X) + angle; var length = v.Length; return new Vector( length * Math.Cos(angle), length * Math.Sin(angle)); } private void Thumb_DragDelta(object? sender, VectorEventArgs e) { var main = GetMainVec(); var v = Vector.Dot(Rotate(e.Vector, Math.Atan2(main.Y, main.X)), GetPerpVec()) / _state.ScaleFactor; Offset += v; Update(); } public void SetActive(bool active) { _active = active; if(Thumb is not null) { Control.Children.Remove(Thumb); Thumb = null; } } }