using Lattice.Layout.UI.Docking; using Lattice.Layout.UI.WinUI.Controls; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media; using System; using System.Linq; using Windows.Foundation; namespace Lattice.Layout.UI.WinUI.Docking; /// /// Выполняет hit-test для определения зоны докинга в WinUI. /// public static class DockZoneHitTester { /// /// Выполняет hit-test по экранной точке и возвращает цель докинга. /// /// WinUI-хост раскладки. /// Точка в координатах окна. public static DockTarget? HitTest(WinUILayoutHost host, Point screenPoint) { if (host is null) throw new ArgumentNullException(nameof(host)); // Предполагаем, что LayoutLayer — основной слой, в котором живёт визуальное дерево. var layoutLayer = host.LayoutLayer; if (layoutLayer is null) return null; // Переводим координаты в систему координат layoutLayer. var elements = VisualTreeHelper.FindElementsInHostCoordinates(screenPoint, host.LayoutLayer); var firstElement = elements.FirstOrDefault(); if (firstElement is null) return null; // Ищем ближайший IWinUIVisual. var visual = FindVisual(firstElement); if (visual is null) return null; if (visual is not ILayoutVisual layoutVisual) return null; // Вычисляем зону докинга для найденного контрола. var control = visual.Control; var bounds = control.TransformToVisual(layoutLayer) .TransformBounds(new Rect(0, 0, control.ActualWidth, control.ActualHeight)); var localX = screenPoint.X - bounds.X; var localY = screenPoint.Y - bounds.Y; var zone = DockingUtils.GetZone(localX, localY, bounds.Width, bounds.Height); return new DockTarget(layoutVisual, zone); } private static IWinUIVisual? FindVisual(UIElement element) { DependencyObject? current = element; while (current is not null) { if (current is FrameworkElement fe && fe.DataContext is IWinUIVisual ctxVisual) return ctxVisual; if (current is IWinUIVisual winuiVisual) return winuiVisual; current = VisualTreeHelper.GetParent(current); } return null; } }