using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; using Azaion.Common.DTO; using Azaion.Common.Extensions; using Label = System.Windows.Controls.Label; namespace Azaion.Common.Controls; public class DetectionControl : Border { private readonly Action _resizeStart; private const double RESIZE_RECT_SIZE = 12; private readonly Grid _grid; private readonly Label _detectionLabel; public readonly Canvas DetectionLabelContainer; public TimeSpan Time { get; set; } private readonly double _confidence; private List _resizedRectangles = new(); private DetectionClass _detectionClass = null!; public DetectionClass DetectionClass { get => _detectionClass; set { var brush = new SolidColorBrush(value.Color.ToConfidenceColor()); BorderBrush = brush; BorderThickness = new Thickness(3); foreach (var rect in _resizedRectangles) rect.Stroke = brush; _detectionLabel.Background = new SolidColorBrush(value.Color.ToConfidenceColor(_confidence)); _detectionLabel.Content = _detectionLabelText(value.UIName); _detectionClass = value; } } private readonly Rectangle _selectionFrame; private bool _isSelected; public bool IsSelected { get => _isSelected; set { _selectionFrame.Visibility = value ? Visibility.Visible : Visibility.Collapsed; _isSelected = value; } } public void UpdateAdornerScale(double scale) { if (Math.Abs(scale) < 0.0001) return; var inverseScale = 1.0 / scale; BorderThickness = new Thickness(4 * inverseScale); foreach (var rect in _resizedRectangles) { rect.Width = 2 * RESIZE_RECT_SIZE * inverseScale; rect.Height = 2 * RESIZE_RECT_SIZE * inverseScale;; rect.Margin = new Thickness(-RESIZE_RECT_SIZE * 0.7); } } public (HorizontalAlignment Horizontal, VerticalAlignment Vertical) DetectionLabelPosition { get => (DetectionLabelContainer.HorizontalAlignment, DetectionLabelContainer.VerticalAlignment); set { DetectionLabelContainer.HorizontalAlignment = value.Horizontal; DetectionLabelContainer.VerticalAlignment = value.Vertical; } } private string _detectionLabelText(string detectionClassName) => _confidence >= 0.995 ? detectionClassName : $"{detectionClassName}: {_confidence * 100:F0}%"; //double public DetectionControl(DetectionClass detectionClass, TimeSpan time, Action resizeStart, CanvasLabel canvasLabel) { Width = canvasLabel.Width; Height = canvasLabel.Height; Time = time; _resizeStart = resizeStart; _confidence = canvasLabel.Confidence; DetectionLabelContainer = new Canvas { HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Top, ClipToBounds = false, }; _detectionLabel = new Label { Content = _detectionLabelText(detectionClass.Name), FontSize = 16, Visibility = Visibility.Visible }; DetectionLabelContainer.Children.Add(_detectionLabel); _selectionFrame = new Rectangle { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch, Stroke = new SolidColorBrush(Colors.Black), StrokeThickness = 2, Visibility = Visibility.Collapsed }; _resizedRectangles = [ CreateResizeRect("rLT", HorizontalAlignment.Left, VerticalAlignment.Top, Cursors.SizeNWSE), CreateResizeRect("rCT", HorizontalAlignment.Center, VerticalAlignment.Top, Cursors.SizeNS), CreateResizeRect("rRT", HorizontalAlignment.Right, VerticalAlignment.Top, Cursors.SizeNESW), CreateResizeRect("rLC", HorizontalAlignment.Left, VerticalAlignment.Center, Cursors.SizeWE), CreateResizeRect("rRC", HorizontalAlignment.Right, VerticalAlignment.Center, Cursors.SizeWE), CreateResizeRect("rLB", HorizontalAlignment.Left, VerticalAlignment.Bottom, Cursors.SizeNESW), CreateResizeRect("rCB", HorizontalAlignment.Center, VerticalAlignment.Bottom, Cursors.SizeNS), CreateResizeRect("rRB", HorizontalAlignment.Right, VerticalAlignment.Bottom, Cursors.SizeNWSE) ]; _grid = new Grid { Background = Brushes.Transparent, HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch, Children = { _selectionFrame } }; foreach (var rect in _resizedRectangles) _grid.Children.Add(rect); _grid.Children.Add(DetectionLabelContainer); Child = _grid; Cursor = Cursors.SizeAll; DetectionClass = detectionClass; } //small corners private Rectangle CreateResizeRect(string name, HorizontalAlignment ha, VerticalAlignment va, Cursor crs) { var rect = new Rectangle() // small rectangles at the corners and sides { ClipToBounds = false, Margin = new Thickness(-RESIZE_RECT_SIZE * 0.7), HorizontalAlignment = ha, VerticalAlignment = va, Width = RESIZE_RECT_SIZE, Height = RESIZE_RECT_SIZE, Stroke = new SolidColorBrush(Color.FromArgb(230, 20, 20, 20)), // small rectangles color Fill = new SolidColorBrush(Color.FromArgb(150, 80, 80, 80)), Cursor = crs, Name = name, }; rect.MouseDown += (sender, args) => _resizeStart(sender, args); return rect; } public YoloLabel GetLabel(Size canvasSize, Size? videoSize = null) { var label = new CanvasLabel(DetectionClass.YoloId, Canvas.GetLeft(this), Canvas.GetTop(this), Width, Height); return new YoloLabel(label, canvasSize, videoSize); } }