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; } } }