79 lines
2.6 KiB
C#
79 lines
2.6 KiB
C#
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;
|
|
|
|
/// <summary>
|
|
/// Выполняет hit-test для определения зоны докинга в WinUI.
|
|
/// </summary>
|
|
public static class DockZoneHitTester
|
|
{
|
|
/// <summary>
|
|
/// Выполняет hit-test по экранной точке и возвращает цель докинга.
|
|
/// </summary>
|
|
/// <param name="host">WinUI-хост раскладки.</param>
|
|
/// <param name="screenPoint">Точка в координатах окна.</param>
|
|
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;
|
|
}
|
|
}
|