DragAndDrop core
This commit is contained in:
83
Lattice.Layout.UI.WinUI/Docking/DockOverlay.cs
Normal file
83
Lattice.Layout.UI.WinUI/Docking/DockOverlay.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using Lattice.Layout.Abstractions;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Lattice.Layout.UI.WinUI.Docking;
|
||||
|
||||
/// <summary>
|
||||
/// Полупрозрачная подсветка зоны докинга.
|
||||
/// </summary>
|
||||
public sealed class DockOverlay : Control
|
||||
{
|
||||
public static readonly DependencyProperty ZoneProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(Zone),
|
||||
typeof(DockZone),
|
||||
typeof(DockOverlay),
|
||||
new PropertyMetadata(DockZone.Center, OnVisualPropertyChanged));
|
||||
|
||||
public static readonly DependencyProperty BoundsProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(Bounds),
|
||||
typeof(Rect),
|
||||
typeof(DockOverlay),
|
||||
new PropertyMetadata(Rect.Empty, OnVisualPropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Зона докинга, которую нужно подсветить.
|
||||
/// </summary>
|
||||
public DockZone Zone
|
||||
{
|
||||
get => (DockZone)GetValue(ZoneProperty);
|
||||
set => SetValue(ZoneProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Прямоугольник зоны в координатах родительского контейнера.
|
||||
/// </summary>
|
||||
public Rect Bounds
|
||||
{
|
||||
get => (Rect)GetValue(BoundsProperty);
|
||||
set => SetValue(BoundsProperty, value);
|
||||
}
|
||||
|
||||
private Border? _border;
|
||||
|
||||
public DockOverlay()
|
||||
{
|
||||
IsHitTestVisible = false;
|
||||
DefaultStyleKey = typeof(DockOverlay);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
_border = GetTemplateChild("PART_Border") as Border;
|
||||
UpdateVisual();
|
||||
}
|
||||
|
||||
private static void OnVisualPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is DockOverlay overlay)
|
||||
{
|
||||
overlay.UpdateVisual();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateVisual()
|
||||
{
|
||||
if (_border is null)
|
||||
return;
|
||||
|
||||
Canvas.SetLeft(this, Bounds.X);
|
||||
Canvas.SetTop(this, Bounds.Y);
|
||||
Width = Bounds.Width;
|
||||
Height = Bounds.Height;
|
||||
|
||||
_border.BorderBrush = new SolidColorBrush(Microsoft.UI.Colors.DeepSkyBlue);
|
||||
_border.BorderThickness = new Thickness(2);
|
||||
_border.Background = new SolidColorBrush(Microsoft.UI.Colors.LightSkyBlue) { Opacity = 0.25 };
|
||||
}
|
||||
}
|
||||
47
Lattice.Layout.UI.WinUI/Docking/DockOverlayHost.cs
Normal file
47
Lattice.Layout.UI.WinUI/Docking/DockOverlayHost.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Lattice.Layout.UI.Docking;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Lattice.Layout.UI.WinUI.Docking;
|
||||
|
||||
/// <summary>
|
||||
/// Контейнер для отображения подсветки зон докинга.
|
||||
/// Обычно используется как Overlay-слой внутри WinUILayoutHost.
|
||||
/// </summary>
|
||||
public sealed class DockOverlayHost : Canvas
|
||||
{
|
||||
private DockOverlay? _currentOverlay;
|
||||
|
||||
public DockOverlayHost()
|
||||
{
|
||||
IsHitTestVisible = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Отображает подсветку для указанной цели докинга.
|
||||
/// </summary>
|
||||
public void ShowOverlay(DockTarget target, Rect bounds)
|
||||
{
|
||||
if (_currentOverlay is null)
|
||||
{
|
||||
_currentOverlay = new DockOverlay();
|
||||
Children.Add(_currentOverlay);
|
||||
}
|
||||
|
||||
_currentOverlay.Zone = target.Zone;
|
||||
_currentOverlay.Bounds = bounds;
|
||||
_currentOverlay.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Скрывает подсветку зоны докинга.
|
||||
/// </summary>
|
||||
public void HideOverlay()
|
||||
{
|
||||
if (_currentOverlay is not null)
|
||||
{
|
||||
_currentOverlay.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
78
Lattice.Layout.UI.WinUI/Docking/DockZoneHitTester.cs
Normal file
78
Lattice.Layout.UI.WinUI/Docking/DockZoneHitTester.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
15
Lattice.Layout.UI.WinUI/Docking/IWinUIVisual.cs
Normal file
15
Lattice.Layout.UI.WinUI/Docking/IWinUIVisual.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace Lattice.Layout.UI.WinUI.Docking;
|
||||
|
||||
/// <summary>
|
||||
/// Интерфейс для визуальных элементов WinUI, соответствующих элементам раскладки.
|
||||
/// Нужен для hit-test и расчёта зон докинга.
|
||||
/// </summary>
|
||||
public interface IWinUIVisual
|
||||
{
|
||||
/// <summary>
|
||||
/// Реальный WinUI-элемент, отображающий данный визуальный элемент раскладки.
|
||||
/// </summary>
|
||||
FrameworkElement Control { get; }
|
||||
}
|
||||
Reference in New Issue
Block a user