using Lattice.Core.Docking.Abstractions;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Lattice.Core.Docking.Models;
///
/// Представляет конечный узел (лист) дерева компоновки, который непосредственно
/// содержит коллекцию вкладок с контентом. Этот класс является контейнером для
/// отображаемого пользователю содержимого.
///
///
/// Лист является основным элементом, с которым взаимодействует пользователь
/// при работе с документами или инструментальными панелями в IDE-подобных
/// приложениях.
///
public class DockLeaf : IDockContainer, INotifyPropertyChanged
{
///
/// Происходит при изменении значения свойства.
///
public event PropertyChangedEventHandler? PropertyChanged;
private readonly ObservableCollection _items = new();
private IDockContent? _activeContent;
private string _id;
private TabPlacement _tabPlacement = TabPlacement.Bottom;
///
/// Получает или задает уникальный идентификатор листа.
///
///
/// Строковый идентификатор, уникальный в пределах дерева компоновки.
///
public string Id
{
get => _id;
internal set
{
if (_id != value)
{
_id = value;
OnPropertyChanged();
}
}
}
///
/// Получает или задает родительский элемент в иерархии дерева компоновки.
///
///
/// Родительский элемент или null, если этот лист является корневым.
///
public IDockElement? Parent { get; set; }
///
/// Получает список вкладок, содержащихся в данном контейнере.
///
///
/// Коллекция объектов, реализующих .
///
///
/// Эта коллекция является наблюдаемой (ObservableCollection), что позволяет
/// автоматически обновлять пользовательский интерфейс при добавлении или
/// удалении вкладок.
///
public IList Children => _items;
///
/// Получает или задает активную (выбранную) вкладку в контейнере.
///
///
/// Активная вкладка или null, если в контейнере нет вкладок.
///
///
/// При установке нового значения проверяется, что вкладка действительно
/// содержится в коллекции .
/// Изменение этого свойства вызывает событие .
///
public IDockContent? ActiveContent
{
get => _activeContent;
set
{
if (value != null && !_items.Contains(value)) return;
if (_activeContent != value)
{
_activeContent = value;
OnPropertyChanged();
}
}
}
///
/// Получает или задает желаемую ширину элемента.
///
///
/// Ширина в пикселях или относительных единицах.
///
public double Width { get; set; }
///
/// Получает или задает желаемую высоту элемента.
///
///
/// Высота в пикселях или относительных единицах.
///
public double Height { get; set; }
///
/// Получает или задает минимально допустимую ширину элемента.
///
///
/// Минимальная ширина в пикселях. Значение по умолчанию: 100.
///
public double MinWidth { get; set; } = 100;
///
/// Получает или задает минимально допустимую высоту элемента.
///
///
/// Минимальная высота в пикселях. Значение по умолчанию: 100.
///
public double MinHeight { get; set; } = 100;
///
/// Получает или задает положение полосы вкладок в контейнере.
///
///
/// Значение перечисления , определяющее,
/// где располагаются вкладки относительно содержимого.
///
///
/// Поддерживаются все четыре стороны: верх, низ, лево, право.
///
public TabPlacement TabPlacement
{
get => _tabPlacement;
set
{
if (_tabPlacement != value)
{
_tabPlacement = value;
OnPropertyChanged();
}
}
}
///
/// Инициализирует новый экземпляр класса .
///
///
/// Уникальный идентификатор листа. Если не указан, генерируется новый GUID.
///
///
/// Создает пустой лист с коллекцией вкладок и генерирует уникальный
/// идентификатор, если он не был предоставлен.
///
public DockLeaf(string? id = null)
{
_id = id ?? Guid.NewGuid().ToString();
}
///
/// Вызывает событие .
///
///
/// Имя изменившегося свойства. Если не указано, определяется автоматически.
///
protected void OnPropertyChanged([CallerMemberName] string? name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
///
/// Добавляет контент в контейнер и делает его активным.
///
///
/// Контент для добавления.
///
///
/// Если контент уже содержится в коллекции, он не добавляется повторно,
/// но становится активным.
/// Этот метод обновляет свойство и вызывает
/// соответствующее событие изменения свойства.
///
public void AddContent(IDockContent content)
{
if (content == null) return;
if (!_items.Contains(content))
{
_items.Add(content);
}
ActiveContent = content;
}
///
/// Удаляет контент из контейнера.
///
///
/// Контент для удаления.
///
///
/// Если удаляемый контент является активным, автоматически выбирается
/// новая активная вкладка (следующая в списке или предыдущая, если удалена
/// последняя).
/// Если после удаления контейнер становится пустым, он может быть удален
/// из дерева макета системой компоновки.
///
public void RemoveContent(IDockContent content)
{
if (content == null) return;
int index = _items.IndexOf(content);
if (index == -1) return;
_items.RemoveAt(index);
if (ActiveContent == content)
{
if (_items.Count > 0)
ActiveContent = _items[Math.Min(index, _items.Count - 1)];
else
ActiveContent = null;
}
}
}