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;
///
/// Обработчик перетаскивания панелей и вкладок для системы Lattice.
///
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;
}
///
/// Привязывает логику перетаскивания к визуальному элементу (заголовку панели).
///
/// Элемент, за который пользователь "хватает" панель.
/// Узел макета, связанный с этой панелью.
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();
};
}
///
/// Обновляет положение визуальных подсказок и рассчитывает зоны сброса.
///
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()
.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();
}
}
///
/// Рассчитывает прямоугольник предпросмотра на основе выбранной стороны.
///
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
};
}
///
/// Завершает операцию докинга, передавая данные в Core Engine.
///
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;
}
}