using Lattice.Core.Docking.Abstractions;
using Lattice.Core.Docking.Engine;
using Lattice.Core.Docking.Models;
using Lattice.UI.Docking.Abstractions;
using Lattice.UI.Docking.Services;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Lattice.UI;
///
/// Визуальный контрол для отображения группы разделения (сплиттера).
/// Реализует интерфейс для интеграции с системой докинга.
///
public sealed class LatticeDockGroup : Control, IDockGroupControl, IDisposable
{
private readonly PropertyChangedEventHandler _modelPropertyChangedHandler;
private bool _disposed;
private DockGroup? _model;
private Grid? _rootGrid;
private ContentControl? _firstChildControl;
private ContentControl? _secondChildControl;
private LayoutManager? _layoutManager;
private DockDragDropService? _dragDropService;
private IDockContextManager? _contextManager;
private bool _isSelected;
private bool _isActive;
private bool _canDrag = true;
private bool _canDrop = true;
private double _splitRatio = 0.5;
private double _splitterSize = 4.0;
///
/// Инициализирует новый экземпляр класса .
///
public LatticeDockGroup()
{
this.DefaultStyleKey = typeof(LatticeDockGroup);
_modelPropertyChangedHandler = OnModelPropertyChanged;
this.DataContextChanged += OnDataContextChanged;
}
///
public IDockElement? Model
{
get => _model;
set
{
if (_model == value) return;
DetachModel();
_model = value as DockGroup;
AttachModel();
OnPropertyChanged(nameof(Model));
}
}
///
public LayoutManager? LayoutManager
{
get => _layoutManager;
set
{
if (_layoutManager == value) return;
_layoutManager = value;
OnPropertyChanged(nameof(LayoutManager));
}
}
///
public IDockDragDropService? DragDropService
{
get => _dragDropService;
set
{
if (_dragDropService == value) return;
_dragDropService = value;
OnPropertyChanged(nameof(DragDropService));
}
}
///
public IDockContextManager? ContextManager
{
get => _contextManager;
set
{
if (_contextManager == value) return;
_contextManager = value;
OnPropertyChanged(nameof(ContextManager));
}
}
///
public bool IsSelected
{
get => _isSelected;
set
{
if (_isSelected == value) return;
_isSelected = value;
OnPropertyChanged(nameof(IsSelected));
}
}
///
public bool IsActive
{
get => _isActive;
set
{
if (_isActive == value) return;
_isActive = value;
OnPropertyChanged(nameof(IsActive));
}
}
///
public bool CanDrag
{
get => _canDrag;
set
{
if (_canDrag == value) return;
_canDrag = value;
OnPropertyChanged(nameof(CanDrag));
}
}
///
public bool CanDrop
{
get => _canDrop;
set
{
if (_canDrop == value) return;
_canDrop = value;
OnPropertyChanged(nameof(CanDrop));
}
}
///
public SplitDirection Orientation
{
get => _model?.Orientation ?? SplitDirection.Horizontal;
set
{
if (_model != null && _model.Orientation != value)
{
_model.Orientation = value;
UpdateLayoutDefinitions();
}
}
}
///
public double SplitRatio
{
get => _splitRatio;
set
{
if (Math.Abs(_splitRatio - value) > 0.001)
{
_splitRatio = value;
UpdateLayoutDefinitions();
OnPropertyChanged(nameof(SplitRatio));
SplitRatioChanged?.Invoke(this,
new SplitRatioChangedEventArgs(value, SplitRatioChangeSource.Programmatic));
}
}
}
///
public double SplitterSize
{
get => _splitterSize;
set
{
if (Math.Abs(_splitterSize - value) > 0.001)
{
_splitterSize = value;
OnPropertyChanged(nameof(SplitterSize));
}
}
}
///
public IDockControl? FirstChild => _firstChildControl?.Content as IDockControl;
///
public IDockControl? SecondChild => _secondChildControl?.Content as IDockControl;
///
public event EventHandler? SplitRatioChanged;
///
public event PropertyChangedEventHandler? PropertyChanged;
///
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
_rootGrid = GetTemplateChild("PART_Grid") as Grid;
_firstChildControl = GetTemplateChild("PART_First") as ContentControl;
_secondChildControl = GetTemplateChild("PART_Second") as ContentControl;
UpdateLayoutDefinitions();
}
private void OnDataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
{
Model = args.NewValue as DockGroup;
}
private void AttachModel()
{
if (_model != null)
{
_model.PropertyChanged += _modelPropertyChangedHandler;
this.DataContext = _model;
// Инициализируем свойства из модели
_splitRatio = _model.SplitRatio;
UpdateLayoutDefinitions();
}
}
private void DetachModel()
{
if (_model != null)
{
_model.PropertyChanged -= _modelPropertyChangedHandler;
this.DataContext = null;
}
}
private void OnModelPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(DockGroup.Orientation):
OnPropertyChanged(nameof(Orientation));
UpdateLayoutDefinitions();
break;
case nameof(DockGroup.SplitRatio):
if (_model != null)
{
_splitRatio = _model.SplitRatio;
OnPropertyChanged(nameof(SplitRatio));
UpdateLayoutDefinitions();
}
break;
}
}
private void UpdateLayoutDefinitions()
{
if (_rootGrid == null || _model == null) return;
_rootGrid.ColumnDefinitions.Clear();
_rootGrid.RowDefinitions.Clear();
if (_model.Orientation == SplitDirection.Horizontal)
{
// Горизонтальное разделение
_rootGrid.ColumnDefinitions.Add(new ColumnDefinition
{ Width = new GridLength(_model.SplitRatio, GridUnitType.Star) });
_rootGrid.ColumnDefinitions.Add(new ColumnDefinition
{ Width = GridLength.Auto });
_rootGrid.ColumnDefinitions.Add(new ColumnDefinition
{ Width = new GridLength(1 - _model.SplitRatio, GridUnitType.Star) });
// Устанавливаем позиции элементов
if (_firstChildControl != null)
{
Grid.SetColumn(_firstChildControl, 0);
Grid.SetRow(_firstChildControl, 0);
}
if (_secondChildControl != null)
{
Grid.SetColumn(_secondChildControl, 2);
Grid.SetRow(_secondChildControl, 0);
}
}
else
{
// Вертикальное разделение
_rootGrid.RowDefinitions.Add(new RowDefinition
{ Height = new GridLength(_model.SplitRatio, GridUnitType.Star) });
_rootGrid.RowDefinitions.Add(new RowDefinition
{ Height = GridLength.Auto });
_rootGrid.RowDefinitions.Add(new RowDefinition
{ Height = new GridLength(1 - _model.SplitRatio, GridUnitType.Star) });
// Устанавливаем позиции элементов
if (_firstChildControl != null)
{
Grid.SetRow(_firstChildControl, 0);
Grid.SetColumn(_firstChildControl, 0);
}
if (_secondChildControl != null)
{
Grid.SetRow(_secondChildControl, 2);
Grid.SetColumn(_secondChildControl, 0);
}
}
}
///
public void SetChildren(IDockControl? firstChild, IDockControl? secondChild)
{
if (_firstChildControl != null)
_firstChildControl.Content = firstChild;
if (_secondChildControl != null)
_secondChildControl.Content = secondChild;
UpdateLayoutDefinitions();
}
///
public void Refresh()
{
UpdateLayoutDefinitions();
}
///
public void ApplyTheme(IDockTheme theme)
{
// Применение темы к контролу
if (theme != null)
{
// TODO: Реализовать применение темы к стилям контрола
}
}
///
public void OnModelPropertyChanged(string propertyName)
{
if (_model != null)
{
OnModelPropertyChanged(_model, new PropertyChangedEventArgs(propertyName));
}
}
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
///
public void Dispose()
{
if (!_disposed)
{
DetachModel();
_disposed = true;
GC.SuppressFinalize(this);
}
}
}