304 lines
8.4 KiB
C#
304 lines
8.4 KiB
C#
using Lattice.Core.Docking.Abstractions;
|
||
using Lattice.Core.Docking.Engine;
|
||
using Lattice.Core.Docking.Models;
|
||
using Lattice.UI.Docking.Abstractions;
|
||
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 IDockContextManager? _contextManager;
|
||
private bool _isSelected;
|
||
private bool _isActive;
|
||
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 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 => true;
|
||
public bool CanDrop => true;
|
||
|
||
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<SplitRatioChangedEventArgs>? 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 object? PrepareDragData()
|
||
{
|
||
return Model;
|
||
}
|
||
|
||
public bool HandleDrop(object data, DockPosition position)
|
||
{
|
||
// TODO: Реализовать обработку сброса
|
||
return false;
|
||
}
|
||
|
||
public void Refresh()
|
||
{
|
||
UpdateLayoutDefinitions();
|
||
}
|
||
|
||
public void ApplyTheme(IDockTheme theme)
|
||
{
|
||
// 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);
|
||
}
|
||
}
|
||
} |