/
docNemo
/
clothes-graph
Обзор
Документация
Войти
/
docNemo
/
clothes-graph
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
src/ClothesGraph.App/Controls/DraftOverlay.cs
123 строки
5 KB
docNemo
Фундамент продукта: параметрическое построение выкроек, печать, установщик
08 авг 2026, 22:17
08 авг 2026, 22:17
cd47cce
Код
Авторство
О чём код?
using System; using System.Collections.Generic; using System.Globalization; using System.Numerics; using Avalonia; using Avalonia.Controls; using Avalonia.Media; using ClothesGraph.App.ViewModels; using ClothesGraph.Rendering; namespace ClothesGraph.App.Controls; /// <summary> /// Точки, их подписи и отметки ошибок поверх поверхности вывода. /// </summary> /// <remarks> /// Рисуется напрямую в контексте вывода, а не деревом элементов: маркеров и /// подписей на чертеже сотни, и отдельный элемент на каждый обошёлся бы /// заметно дороже без всякой пользы. /// </remarks> public sealed class DraftOverlay : Control { private const double MarkerRadius = 3.5; private const double LabelOffset = 8.0; private static readonly IBrush PointBrush = new SolidColorBrush(Color.FromRgb(0xD8, 0xDC, 0xE6)); private static readonly IBrush SelectedBrush = new SolidColorBrush(Color.FromRgb(0x4D, 0xA6, 0xFF)); private static readonly IBrush HoveredBrush = new SolidColorBrush(Color.FromRgb(0xFF, 0xB8, 0x40)); private static readonly IBrush FailureBrush = new SolidColorBrush(Color.FromRgb(0xFF, 0x6B, 0x6B)); private static readonly IBrush LabelBrush = new SolidColorBrush(Color.FromRgb(0x9A, 0xA2, 0xB4)); private readonly Pen _markerPen = new(new SolidColorBrush(Color.FromRgb(0x14, 0x16, 0x1B)), 1.5); public static readonly StyledProperty<IReadOnlyList<DraftPointMarker>> PointsProperty = AvaloniaProperty.Register<DraftOverlay, IReadOnlyList<DraftPointMarker>>( nameof(Points), Array.Empty<DraftPointMarker>()); public static readonly StyledProperty<ViewportCamera?> CameraProperty = AvaloniaProperty.Register<DraftOverlay, ViewportCamera?>(nameof(Camera)); public static readonly StyledProperty<bool> ShowLabelsProperty = AvaloniaProperty.Register<DraftOverlay, bool>(nameof(ShowLabels), true); static DraftOverlay() { AffectsRender<DraftOverlay>(PointsProperty, CameraProperty, ShowLabelsProperty); } public DraftOverlay() { // Оверлей только показывает: щелчки и наведение обрабатывает вьюпорт под ним. IsHitTestVisible = false; } public IReadOnlyList<DraftPointMarker> Points { get => GetValue(PointsProperty); set => SetValue(PointsProperty, value); } public ViewportCamera? Camera { get => GetValue(CameraProperty); set => SetValue(CameraProperty, value); } public bool ShowLabels { get => GetValue(ShowLabelsProperty); set => SetValue(ShowLabelsProperty, value); } public override void Render(DrawingContext context) { base.Render(context); var camera = Camera; if (camera is null) return; var surface = new Vector2((float)Bounds.Width, (float)Bounds.Height); var typeface = new Typeface(FontFamily.Default); foreach (var marker in Points) { var screen = camera.ToScreen(marker.Position, surface); // Точки за пределами кадра пропускаются: подпись всё равно // не поместилась бы, а построение текста стоит заметно дороже круга. if (screen.X < -32 || screen.Y < -32 || screen.X > surface.X + 32 || screen.Y > surface.Y + 32) continue; var centre = new Point(screen.X, screen.Y); var brush = marker switch { { IsSelected: true } => SelectedBrush, { IsHovered: true } => HoveredBrush, _ => PointBrush }; var radius = marker.IsSelected || marker.IsHovered ? MarkerRadius + 1.5 : MarkerRadius; context.DrawEllipse(brush, _markerPen, centre, radius, radius); if (!ShowLabels) continue; var label = new FormattedText( marker.Name, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, 11, marker.IsSelected ? SelectedBrush : LabelBrush); context.DrawText(label, new Point(screen.X + LabelOffset, screen.Y - LabelOffset - 4)); } } /// <summary>Кисть для отметок неразрешимых построений.</summary> internal static IBrush FailureMarkerBrush => FailureBrush; }