Добавлен проект UI
This commit is contained in:
145
Lattice.UI/DragDrop/DockTabHandler.cs
Normal file
145
Lattice.UI/DragDrop/DockTabHandler.cs
Normal file
@@ -0,0 +1,145 @@
|
||||
using Lattice.Core.Models;
|
||||
using Lattice.Core.Models.Enums;
|
||||
using Lattice.UI.Controls;
|
||||
using Lattice.UI.Services;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Lattice.UI.DragDrop;
|
||||
|
||||
/// <summary>
|
||||
/// Обработчик перетаскивания панелей и вкладок для системы Lattice.
|
||||
/// </summary>
|
||||
public class DockTabHandler
|
||||
{
|
||||
private bool _isDragging;
|
||||
private readonly LatticeDockHost _host;
|
||||
|
||||
// Состояние текущей операции перетаскивания
|
||||
private LayoutNode? _sourceNode;
|
||||
private LayoutNode? _targetNode;
|
||||
private DockDirection _currentSide;
|
||||
|
||||
public DockTabHandler(LatticeDockHost host)
|
||||
{
|
||||
_host = host;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Привязывает логику перетаскивания к визуальному элементу (заголовку панели).
|
||||
/// </summary>
|
||||
/// <param name="header">Элемент, за который пользователь "хватает" панель.</param>
|
||||
/// <param name="node">Узел макета, связанный с этой панелью.</param>
|
||||
public void Attach(FrameworkElement header, LayoutNode node)
|
||||
{
|
||||
header.PointerPressed += (s, e) =>
|
||||
{
|
||||
_isDragging = true;
|
||||
_sourceNode = node;
|
||||
header.CapturePointer(e.Pointer);
|
||||
|
||||
if (_host.AnchorOverlay != null)
|
||||
_host.AnchorOverlay.Visibility = Visibility.Visible;
|
||||
};
|
||||
|
||||
header.PointerMoved += (s, e) =>
|
||||
{
|
||||
if (!_isDragging) return;
|
||||
|
||||
// Получаем позицию курсора относительно всего хоста
|
||||
Point pointerPos = e.GetCurrentPoint(_host).Position;
|
||||
UpdateOverlayPosition(pointerPos);
|
||||
};
|
||||
|
||||
header.PointerReleased += (s, e) =>
|
||||
{
|
||||
if (!_isDragging) return;
|
||||
|
||||
_isDragging = false;
|
||||
header.ReleasePointerCapture(e.Pointer);
|
||||
CompleteDocking();
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обновляет положение визуальных подсказок и рассчитывает зоны сброса.
|
||||
/// </summary>
|
||||
private void UpdateOverlayPosition(Point pointerPosition)
|
||||
{
|
||||
var overlay = _host.AnchorOverlay;
|
||||
if (overlay == null) return;
|
||||
|
||||
// 1. Позиционируем "ромб" с кнопками докинга
|
||||
overlay.PositionAnchors(pointerPosition);
|
||||
|
||||
// 2. Хит-тестинг: ищем LatticePane под курсором (исключая саму перетаскиваемую панель)
|
||||
var elements = VisualTreeHelper.FindElementsInHostCoordinates(pointerPosition, _host);
|
||||
var targetPane = elements.OfType<LatticePane>()
|
||||
.FirstOrDefault(p => (p.DataContext as LayoutNode)?.Id != _sourceNode?.Id);
|
||||
|
||||
if (targetPane != null && targetPane.DataContext is LayoutNode targetNode)
|
||||
{
|
||||
_targetNode = targetNode;
|
||||
|
||||
// 3. Расчет локальной позиции для определения стороны
|
||||
var transform = targetPane.TransformToVisual(_host);
|
||||
Point localPoint = transform.Inverse.TransformPoint(pointerPosition);
|
||||
|
||||
// 4. Определяем сторону через сервис
|
||||
_currentSide = VisualTreeService.GetHitZone(targetPane, localPoint);
|
||||
|
||||
// 5. Показываем синее превью зоны сброса
|
||||
Rect previewRect = CalculatePreviewRect(targetPane, _currentSide);
|
||||
Rect globalPreviewRect = transform.TransformBounds(previewRect);
|
||||
|
||||
overlay.ShowPreview(globalPreviewRect);
|
||||
}
|
||||
else
|
||||
{
|
||||
_targetNode = null;
|
||||
overlay.HidePreview();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Рассчитывает прямоугольник предпросмотра на основе выбранной стороны.
|
||||
/// </summary>
|
||||
private Rect CalculatePreviewRect(FrameworkElement pane, DockDirection side)
|
||||
{
|
||||
double w = pane.ActualWidth;
|
||||
double h = pane.ActualHeight;
|
||||
|
||||
return side switch
|
||||
{
|
||||
DockDirection.Left => new Rect(0, 0, w / 2, h),
|
||||
DockDirection.Right => new Rect(w / 2, 0, w / 2, h),
|
||||
DockDirection.Top => new Rect(0, 0, w, h / 2),
|
||||
DockDirection.Bottom => new Rect(0, h / 2, w, h / 2),
|
||||
_ => new Rect(0, 0, w, h) // Center
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Завершает операцию докинга, передавая данные в Core Engine.
|
||||
/// </summary>
|
||||
private void CompleteDocking()
|
||||
{
|
||||
if (_sourceNode != null && _targetNode != null && _host.Manager != null)
|
||||
{
|
||||
// Вызываем логику перестроения дерева в Lattice.Core
|
||||
_host.Manager.Dock(_sourceNode, _targetNode, _currentSide);
|
||||
}
|
||||
|
||||
// Очистка UI
|
||||
var overlay = _host.AnchorOverlay;
|
||||
if (overlay != null)
|
||||
{
|
||||
overlay.Visibility = Visibility.Collapsed;
|
||||
overlay.HidePreview();
|
||||
}
|
||||
|
||||
_sourceNode = null;
|
||||
_targetNode = null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user