using Lattice.Core.Docking.Abstractions; using System.ComponentModel; using System.Runtime.CompilerServices; namespace Lattice.Core.Docking.Models; /// /// Представляет узел дерева компоновки, который разделяет доступную область /// между двумя дочерними элементами. Этот класс является основным структурным /// элементом для создания сложных макетов с разделителями. /// /// /// Каждая группа содержит два дочерних элемента ( и ), /// которые могут быть либо другими группами (для создания вложенной структуры), /// либо листами () с контентом. /// Направление разделения определяется свойством . /// public class DockGroup : IDockElement, INotifyPropertyChanged { /// /// Происходит при изменении значения свойства. /// public event PropertyChangedEventHandler? PropertyChanged; private double _splitRatio = 0.5; private string _id; private IDockElement _first; private IDockElement _second; /// /// Получает или задает уникальный идентификатор группы. /// /// /// Строковый идентификатор, уникальный в пределах дерева компоновки. /// /// /// Идентификатор используется для сериализации/десериализации макета, /// поиска элементов и отслеживания изменений в дереве. /// public string Id { get => _id; internal set { if (_id != value) { _id = value; OnPropertyChanged(); } } } /// /// Получает или задает родительский элемент в иерархии дерева компоновки. /// /// /// Родительский элемент или null, если эта группа является корневой. /// /// /// Это свойство управляется системой компоновки при добавлении или /// удалении элементов из дерева. /// public IDockElement? Parent { get; set; } /// /// Получает или задает первый дочерний элемент (левую или верхнюю область). /// /// /// Элемент, занимающий первую часть разделенной области. /// /// /// Выбрасывается при попытке установить значение null. /// /// /// При установке нового значения автоматически обновляется свойство /// у дочернего элемента. /// public IDockElement First { get => _first; set { if (_first != value) { _first = value ?? throw new ArgumentNullException(nameof(value)); _first.Parent = this; OnPropertyChanged(); } } } /// /// Получает или задает второй дочерний элемент (правую или нижнюю область). /// /// /// Элемент, занимающий вторую часть разделенной области. /// /// /// Выбрасывается при попытке установить значение null. /// /// /// При установке нового значения автоматически обновляется свойство /// у дочернего элемента. /// public IDockElement Second { get => _second; set { if (_second != value) { _second = value ?? throw new ArgumentNullException(nameof(value)); _second.Parent = this; OnPropertyChanged(); } } } /// /// Получает или задает направление разделения данной группы. /// /// /// Значение перечисления , указывающее, /// как разделена область: горизонтально или вертикально. /// /// /// /// создает левую и правую области /// создает верхнюю и нижнюю области /// /// public SplitDirection Orientation { get; set; } /// /// Получает или задает соотношение разделения между первым и вторым элементами. /// /// /// Значение от 0.0 до 1.0, где: /// /// 0.0 - вся область принадлежит второму элементу /// 0.5 - область разделена поровну /// 1.0 - вся область принадлежит первому элементу /// /// /// /// Изменение этого свойства вызывает событие /// и может привести к перерисовке пользовательского интерфейса. /// public double SplitRatio { get => _splitRatio; set { if (Math.Abs(_splitRatio - value) > double.Epsilon) { _splitRatio = value; OnPropertyChanged(); } } } /// /// Получает или задает желаемую ширину элемента. /// /// /// Ширина в пикселях или относительных единицах. /// public double Width { get; set; } /// /// Получает или задает желаемую высоту элемента. /// /// /// Высота в пикселях или относительных единицах. /// public double Height { get; set; } /// /// Получает минимально допустимую ширину элемента. /// /// /// Минимальная ширина в пикселях, при которой элемент сохраняет функциональность. /// /// /// Для группы минимальная ширина вычисляется как сумма минимальных ширин /// дочерних элементов при горизонтальной ориентации или максимум минимальных /// ширин при вертикальной ориентации. /// public double MinWidth => Orientation == SplitDirection.Horizontal ? First.MinWidth + Second.MinWidth : Math.Max(First.MinWidth, Second.MinWidth); /// /// Получает минимально допустимую высоту элемента. /// /// /// Минимальная высота в пикселях, при которой элемент сохраняет функциональность. /// /// /// Для группы минимальная высота вычисляется как сумма минимальных высот /// дочерних элементов при вертикальной ориентации или максимум минимальных /// высот при горизонтальной ориентации. /// public double MinHeight => Orientation == SplitDirection.Vertical ? First.MinHeight + Second.MinHeight : Math.Max(First.MinHeight, Second.MinHeight); /// /// Инициализирует новый экземпляр класса . /// /// /// Первый дочерний элемент (левая или верхняя область). /// /// /// Второй дочерний элемент (правая или нижняя область). /// /// /// Направление разделения между дочерними элементами. /// /// /// Уникальный идентификатор группы. Если не указан, генерируется новый GUID. /// /// /// Выбрасывается, когда или /// равны null. /// /// /// Конструктор автоматически устанавливает свойство /// у дочерних элементов на текущую группу и генерирует уникальный идентификатор, /// если он не был предоставлен. /// public DockGroup(IDockElement first, IDockElement second, SplitDirection orientation, string? id = null) { First = first ?? throw new ArgumentNullException(nameof(first)); Second = second ?? throw new ArgumentNullException(nameof(second)); Orientation = orientation; Id = id ?? Guid.NewGuid().ToString(); First.Parent = this; Second.Parent = this; } /// /// Вызывает событие . /// /// /// Имя изменившегося свойства. Если не указано, определяется автоматически. /// protected void OnPropertyChanged([CallerMemberName] string? name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } }