using Lattice.Core.Geometry;
using Lattice.UI.DragDrop.Abstractions;
using Lattice.UI.DragDrop.WinUI.Controls;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
namespace Lattice.UI.DragDrop.WinUI.Services;
///
/// Хост для управления визуальными элементами перетаскивания в окне WinUI.
///
///
///
/// Этот класс отвечает за отображение и управление визуальными элементами
/// во время операций перетаскивания, включая:
/// - Drag-визуализацию (элемент, следующий за курсором)
/// - Drop-превью (подсветка областей сброса)
///
///
/// Хост создает оверлейный слой поверх всего содержимого окна для корректного
/// отображения визуальных элементов поверх других UI-компонентов.
///
///
public sealed class WinUIDragDropHost : IDragDropHost, IDisposable
{
private DragDropOverlay? _overlay;
private Window? _window;
private bool _disposed;
///
/// Инициализирует хост для работы с указанным окном.
///
/// Окно, в котором будет работать перетаскивание.
///
/// Выбрасывается, если равен null.
///
///
/// Выбрасывается, если хост уже был удален.
///
///
///
/// Этот метод создает оверлейный слой и добавляет его в визуальное дерево окна.
/// Если содержимое окна не является , создается контейнер .
///
///
/// Метод должен быть вызван один раз перед использованием других методов хоста.
///
///
public void Initialize(Window window)
{
if (_disposed) throw new ObjectDisposedException(nameof(WinUIDragDropHost));
_window = window ?? throw new ArgumentNullException(nameof(window));
// Создаем оверлей
_overlay = new DragDropOverlay();
// Добавляем оверлей в окно
if (_window.Content is Panel panel)
{
panel.Children.Add(_overlay);
}
else
{
// Если контент не Panel, создаем Grid
var grid = new Grid();
grid.Children.Add(_window.Content as UIElement ?? new Grid());
grid.Children.Add(_overlay);
_window.Content = grid;
}
}
///
/// Отображает визуальное представление перетаскиваемого элемента.
///
/// Визуальный элемент для отображения.
/// Позиция отображения в координатах экрана.
///
/// Визуальный элемент будет отображен на оверлейном слое в указанной позиции
/// и будет следовать за курсором при обновлении через .
///
public void ShowDragVisual(object dragVisual, Point position)
{
if (_overlay == null || _disposed) return;
if (dragVisual is UIElement element)
{
_overlay.ShowDragVisual(element, position.X, position.Y);
}
}
///
public void UpdateDragVisualPosition(object dragVisual, Point position)
{
if (_overlay == null || _disposed) return;
if (dragVisual is UIElement element)
{
_overlay.UpdateDragVisualPosition(element, position.X, position.Y);
}
}
///
public void HideDragVisual(object dragVisual)
{
if (_overlay == null || _disposed) return;
if (dragVisual is UIElement element)
{
_overlay.HideDragVisual(element);
}
else
{
// Скрываем все визуальные элементы
var current = _overlay.GetCurrentDragVisual();
if (current != null)
{
_overlay.HideDragVisual(current);
}
}
}
///
public void ShowDropAdorner(IDropVisualAdorner adorner)
{
if (_overlay == null || _disposed) return;
if (adorner is DropPreviewAdorner dropAdorner)
{
// Для WinUI пока просто игнорируем
}
}
///
public void HideDropAdorner(IDropVisualAdorner adorner)
{
if (_overlay == null || _disposed) return;
_overlay.HideAllDropPreviews();
}
///
public void Dispose()
{
if (_disposed) return;
if (_overlay != null && _window?.Content is Panel panel)
{
panel.Children.Remove(_overlay);
_overlay.ClearAllVisuals();
}
_overlay = null;
_window = null;
_disposed = true;
GC.SuppressFinalize(this);
}
}