Доработан Docking
This commit is contained in:
@@ -77,21 +77,23 @@ public interface IAutoHidePanelControl : IDockControl
|
||||
/// <summary>
|
||||
/// Задает фиксированное состояние панели.
|
||||
/// </summary>
|
||||
/// <param name="pinned">true, чтобы зафиксировать панель; false, чтобы разрешить автоскрытие.</param>
|
||||
/// <param name="pinned">
|
||||
/// true, чтобы зафиксировать панель; false, чтобы разрешить автоскрытие.
|
||||
/// </param>
|
||||
void SetPinned(bool pinned);
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при изменении видимости панели.
|
||||
/// Происходит при изменении видимости панели.
|
||||
/// </summary>
|
||||
event EventHandler VisibilityChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при наведении курсора на панель.
|
||||
/// Происходит при наведении курсора на панель.
|
||||
/// </summary>
|
||||
event EventHandler MouseEntered;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при уходе курсора с панели.
|
||||
/// Происходит при уходе курсора с панели.
|
||||
/// </summary>
|
||||
event EventHandler MouseLeft;
|
||||
}
|
||||
@@ -1,40 +1,58 @@
|
||||
namespace Lattice.UI.Docking.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Определяет контракт для команды док-системы.
|
||||
/// Определяет контракт для команды в UI-слое док-системы.
|
||||
/// Команды представляют действия, которые могут быть выполнены пользователем.
|
||||
/// </summary>
|
||||
public interface IDockCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает идентификатор команды.
|
||||
/// Получает уникальный идентификатор команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Строковый идентификатор команды.
|
||||
/// </value>
|
||||
string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает отображаемое имя команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Имя команды, отображаемое в пользовательском интерфейсе.
|
||||
/// </value>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает описание команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Текстовое описание функциональности команды.
|
||||
/// </value>
|
||||
string Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает значок команды.
|
||||
/// Получает идентификатор ресурса для иконки команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Имя ресурса иконки или путь к файлу иконки.
|
||||
/// </value>
|
||||
string Icon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает комбинацию клавиш для команды.
|
||||
/// Получает комбинацию клавиш для быстрого вызова команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Строковое представление горячей клавиши (например, "Ctrl+S").
|
||||
/// </value>
|
||||
string Shortcut { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Определяет, можно ли выполнить команду.
|
||||
/// Определяет, можно ли выполнить команду в текущем контексте.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Параметр команды.</param>
|
||||
/// <returns>true, если команду можно выполнить; в противном случае — false.</returns>
|
||||
/// <returns>
|
||||
/// true, если команду можно выполнить; в противном случае false.
|
||||
/// </returns>
|
||||
bool CanExecute(object? parameter);
|
||||
|
||||
/// <summary>
|
||||
@@ -44,7 +62,7 @@ public interface IDockCommand
|
||||
void Execute(object? parameter);
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при изменении возможности выполнения команды.
|
||||
/// Происходит при изменении возможности выполнения команды.
|
||||
/// </summary>
|
||||
event EventHandler CanExecuteChanged;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,9 @@ public interface IDockContextManager
|
||||
/// <param name="element">Элемент, для которого показывается меню.</param>
|
||||
/// <param name="x">Координата X для отображения меню.</param>
|
||||
/// <param name="y">Координата Y для отображения меню.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="element"/> равен null.
|
||||
/// </exception>
|
||||
void ShowContextMenu(IDockControl element, double x, double y);
|
||||
|
||||
/// <summary>
|
||||
@@ -23,6 +26,10 @@ public interface IDockContextManager
|
||||
/// </summary>
|
||||
/// <param name="commandId">Идентификатор команды.</param>
|
||||
/// <param name="command">Команда для регистрации.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="commandId"/> или <paramref name="command"/>
|
||||
/// равны null.
|
||||
/// </exception>
|
||||
void RegisterCommand(string commandId, IDockCommand command);
|
||||
|
||||
/// <summary>
|
||||
@@ -32,12 +39,12 @@ public interface IDockContextManager
|
||||
void UnregisterCommand(string commandId);
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при показе контекстного меню.
|
||||
/// Происходит при показе контекстного меню.
|
||||
/// </summary>
|
||||
event EventHandler<ContextMenuShownEventArgs> ContextMenuShown;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при скрытии контекстного меню.
|
||||
/// Происходит при скрытии контекстного меню.
|
||||
/// </summary>
|
||||
event EventHandler ContextMenuHidden;
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,12 @@ namespace Lattice.UI.Docking.Abstractions;
|
||||
/// <summary>
|
||||
/// Определяет базовый контракт для всех UI-контролов, участвующих в системе докинга.
|
||||
/// Этот интерфейс предоставляет общие свойства и методы, необходимые для интеграции
|
||||
/// с менеджером макета и системой перетаскивания.
|
||||
/// с менеджером макета и UI-сервисами.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Реализации этого интерфейса должны отображать элементы док-системы (DockGroup, DockLeaf)
|
||||
/// и обеспечивать взаимодействие пользователя с ними через жесты мыши, клавиатуру и сенсорный ввод.
|
||||
/// Интерфейс обеспечивает двухстороннюю связь между визуальными элементами и их моделями данных.
|
||||
/// </remarks>
|
||||
public interface IDockControl : INotifyPropertyChanged
|
||||
{
|
||||
@@ -22,6 +23,10 @@ public interface IDockControl : INotifyPropertyChanged
|
||||
/// Экземпляр класса, реализующего <see cref="IDockElement"/>, который представляет
|
||||
/// состояние и структуру отображаемого элемента док-системы.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Изменение модели должно приводить к обновлению визуального представления.
|
||||
/// Свойство используется для привязки данных между UI-слоем и слоем бизнес-логики.
|
||||
/// </remarks>
|
||||
IDockElement? Model { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -30,62 +35,57 @@ public interface IDockControl : INotifyPropertyChanged
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="LayoutManager"/>, управляющий структурой док-системы.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Менеджер макета предоставляет доступ к дереву компоновки, плавающим окнам
|
||||
/// и автоскрываемым панелям, а также методы для манипуляции структурой.
|
||||
/// </remarks>
|
||||
LayoutManager? LayoutManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает сервис перетаскивания, используемый этим контролом.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Реализация <see cref="IDragDropService"/> для обработки операций перетаскивания.
|
||||
/// </value>
|
||||
IDragDropService? DragDropService { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает контекстный менеджер для этого контрола.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockContextManager"/>, управляющий контекстными меню и действиями.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Контекстный менеджер используется для отображения контекстно-зависимых команд
|
||||
/// при щелчке правой кнопкой мыши или других пользовательских действиях.
|
||||
/// </remarks>
|
||||
IDockContextManager? ContextManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает признак того, что контрол выбран.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если контрол выбран; в противном случае — false.
|
||||
/// true, если контрол выбран; в противном случае false.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Выделение контрола обычно визуально выделяет его границы или фон,
|
||||
/// чтобы указать пользователю на активный элемент. В каждый момент времени
|
||||
/// может быть выбран только один контрол в пределах контейнера.
|
||||
/// </remarks>
|
||||
bool IsSelected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает признак того, что контрол активен.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если контрол активен; в противном случае — false.
|
||||
/// true, если контрол активен; в противном случае false.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Активный контрол получает фокус ввода и может обрабатывать команды клавиатуры.
|
||||
/// Обычно соответствует активной вкладке в контейнере или активному окну.
|
||||
/// </remarks>
|
||||
bool IsActive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает признак того, что контрол можно перетаскивать.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если контрол можно перетаскивать; в противном случае — false.
|
||||
/// </value>
|
||||
bool CanDrag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает признак того, что контрол может принимать сброс.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если контрол может принимать сброс; в противном случае — false.
|
||||
/// </value>
|
||||
bool CanDrop { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Обновляет внешний вид контрола в соответствии с текущим состоянием модели.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Этот метод должен вызываться при изменении свойств модели или при необходимости
|
||||
/// принудительного обновления UI (например, после изменения темы или масштаба).
|
||||
/// Реализация должна обеспечить синхронизацию всех визуальных аспектов контрола
|
||||
/// с текущими значениями свойств модели.
|
||||
/// </remarks>
|
||||
void Refresh();
|
||||
|
||||
@@ -93,11 +93,23 @@ public interface IDockControl : INotifyPropertyChanged
|
||||
/// Применяет указанную тему к контролу.
|
||||
/// </summary>
|
||||
/// <param name="theme">Тема для применения.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="theme"/> равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Метод должен обновить все стили, цвета и параметры отображения контрола
|
||||
/// в соответствии с переданной темой. Изменения должны применяться немедленно.
|
||||
/// </remarks>
|
||||
void ApplyTheme(IDockTheme theme);
|
||||
|
||||
/// <summary>
|
||||
/// Вызывается при изменении состояния модели для обновления UI.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Имя изменившегося свойства модели.</param>
|
||||
/// <remarks>
|
||||
/// Этот метод предназначен для уведомления UI о конкретных изменениях в модели,
|
||||
/// что позволяет выполнять точечные обновления вместо полного перестроения.
|
||||
/// Должен вызываться из обработчиков событий изменения свойств модели.
|
||||
/// </remarks>
|
||||
void OnModelPropertyChanged(string propertyName);
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
namespace Lattice.UI.Docking.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Предоставляет сервис для операций перетаскивания в UI-слое док-системы.
|
||||
/// Абстрагирует платформенно-зависимую логику перетаскивания и обеспечивает
|
||||
/// единый интерфейс для управления операциями drag-and-drop.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Этот интерфейс служит мостом между базовым менеджером перетаскивания из Core
|
||||
/// и UI-контролами, добавляя визуальную обратную связь и обработку событий,
|
||||
/// специфичных для пользовательского интерфейса.
|
||||
/// </remarks>
|
||||
public interface IDockDragDropService
|
||||
{
|
||||
/// <summary>
|
||||
/// Начинает операцию перетаскивания для указанного элемента.
|
||||
/// </summary>
|
||||
/// <param name="element">UI-контрол, который инициирует перетаскивание.</param>
|
||||
/// <param name="dragInfo">
|
||||
/// Информация о перетаскивании, содержащая данные и параметры операции.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="element"/> или <paramref name="dragInfo"/> равны null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Этот метод должен создавать визуальное представление перетаскиваемого элемента
|
||||
/// и инициировать отслеживание перемещения мыши.
|
||||
/// </remarks>
|
||||
void StartDrag(IDockControl element, Core.DragDrop.Models.DragInfo dragInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Обновляет позицию текущей операции перетаскивания.
|
||||
/// </summary>
|
||||
/// <param name="x">Новая координата X курсора в экранных координатах.</param>
|
||||
/// <param name="y">Новая координата Y курсора в экранных координатах.</param>
|
||||
/// <remarks>
|
||||
/// Вызывается при каждом перемещении мыши во время операции перетаскивания.
|
||||
/// Должен обновлять позицию визуального представления и проверять возможные цели сброса.
|
||||
/// </remarks>
|
||||
void UpdateDrag(double x, double y);
|
||||
|
||||
/// <summary>
|
||||
/// Завершает текущую операцию перетаскивания в указанной позиции.
|
||||
/// </summary>
|
||||
/// <param name="x">Координата X завершения перетаскивания.</param>
|
||||
/// <param name="y">Координата Y завершения перетаскивания.</param>
|
||||
/// <remarks>
|
||||
/// Выполняет сброс данных на текущую цель (если она есть) и очищает ресурсы,
|
||||
/// выделенные для операции перетаскивания.
|
||||
/// </remarks>
|
||||
void EndDrag(double x, double y);
|
||||
|
||||
/// <summary>
|
||||
/// Отменяет текущую операцию перетаскивания.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Вызывается при нажатии клавиши Escape или других действиях, приводящих к отмене.
|
||||
/// Должен восстанавливать исходное состояние элементов и очищать ресурсы.
|
||||
/// </remarks>
|
||||
void CancelDrag();
|
||||
|
||||
/// <summary>
|
||||
/// Показывает визуальную подсказку о возможной позиции сброса.
|
||||
/// </summary>
|
||||
/// <param name="element">UI-контрол, для которого показывается подсказка.</param>
|
||||
/// <param name="position">Предполагаемая позиция сброса.</param>
|
||||
/// <remarks>
|
||||
/// Используется для визуальной обратной связи, чтобы пользователь видел,
|
||||
/// куда будет помещен элемент при отпускании кнопки мыши.
|
||||
/// </remarks>
|
||||
void ShowDropHint(IDockControl element, Models.DropPosition position);
|
||||
|
||||
/// <summary>
|
||||
/// Скрывает текущую визуальную подсказку о сбросе.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Вызывается, когда курсор покидает допустимую область сброса
|
||||
/// или операция перетаскивания завершается.
|
||||
/// </remarks>
|
||||
void HideDropHint();
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при начале операции перетаскивания.
|
||||
/// </summary>
|
||||
event EventHandler<DragStartedEventArgs> DragStarted;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при обновлении позиции перетаскивания.
|
||||
/// </summary>
|
||||
event EventHandler<DragUpdatedEventArgs> DragUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при завершении операции перетаскивания.
|
||||
/// </summary>
|
||||
event EventHandler<DragCompletedEventArgs> DragCompleted;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при отмене операции перетаскивания.
|
||||
/// </summary>
|
||||
event EventHandler DragCancelled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Предоставляет данные для события начала перетаскивания.
|
||||
/// </summary>
|
||||
public class DragStartedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает UI-контрол, который инициировал перетаскивание.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockControl"/>, представляющий источник перетаскивания.
|
||||
/// Может быть null, если перетаскивание инициировано не из UI-элемента.
|
||||
/// </value>
|
||||
public IDockControl? Source { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает информацию о перетаскивании.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="Core.DragDrop.Models.DragInfo"/> с данными перетаскивания.
|
||||
/// </value>
|
||||
public Core.DragDrop.Models.DragInfo DragInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="DragStartedEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="source">Источник перетаскивания.</param>
|
||||
/// <param name="dragInfo">Информация о перетаскивании.</param>
|
||||
public DragStartedEventArgs(IDockControl? source, Core.DragDrop.Models.DragInfo dragInfo)
|
||||
{
|
||||
Source = source;
|
||||
DragInfo = dragInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Предоставляет данные для события обновления перетаскивания.
|
||||
/// </summary>
|
||||
public class DragUpdatedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает UI-контрол, который инициировал перетаскивание.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockControl"/>, представляющий источник перетаскивания.
|
||||
/// </value>
|
||||
public IDockControl? Source { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает текущую координату X курсора.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Координата X в экранных координатах.
|
||||
/// </value>
|
||||
public double X { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает текущую координату Y курсора.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Координата Y в экранных координатах.
|
||||
/// </value>
|
||||
public double Y { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает информацию о перетаскивании.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="Core.DragDrop.Models.DragInfo"/> с текущими данными перетаскивания.
|
||||
/// </value>
|
||||
public Core.DragDrop.Models.DragInfo DragInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="DragUpdatedEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="source">Источник перетаскивания.</param>
|
||||
/// <param name="x">Текущая координата X.</param>
|
||||
/// <param name="y">Текущая координата Y.</param>
|
||||
/// <param name="dragInfo">Информация о перетаскивании.</param>
|
||||
public DragUpdatedEventArgs(IDockControl? source, double x, double y, Core.DragDrop.Models.DragInfo dragInfo)
|
||||
{
|
||||
Source = source;
|
||||
X = x;
|
||||
Y = y;
|
||||
DragInfo = dragInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Предоставляет данные для события завершения перетаскивания.
|
||||
/// </summary>
|
||||
public class DragCompletedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает UI-контрол, который инициировал перетаскивание.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockControl"/>, представляющий источник перетаскивания.
|
||||
/// Может быть null, если операция была инициирована не из UI.
|
||||
/// </value>
|
||||
public IDockControl? Source { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает UI-контрол, на который был выполнен сброс.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockControl"/>, представляющий цель сброса.
|
||||
/// Может быть null, если сброс был выполнен вне допустимой области.
|
||||
/// </value>
|
||||
public IDockControl? Target { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает позицию сброса относительно целевого элемента.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Значение перечисления <see cref="DropPosition"/>, указывающее позицию сброса.
|
||||
/// </value>
|
||||
public Models.DropPosition DropPosition { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает информацию о перетаскивании.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="Core.DragDrop.Models.DragInfo"/> с данными завершенной операции.
|
||||
/// Может быть null, если операция была отменена.
|
||||
/// </value>
|
||||
public Core.DragDrop.Models.DragInfo? DragInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает значение, указывающее успешность операции сброса.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если данные были успешно сброшены на цель; false, если операция была отменена
|
||||
/// или сброс не был выполнен.
|
||||
/// </value>
|
||||
public bool Success { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="DragCompletedEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="source">Источник перетаскивания.</param>
|
||||
/// <param name="target">Цель сброса.</param>
|
||||
/// <param name="dropPosition">Позиция сброса.</param>
|
||||
/// <param name="dragInfo">Информация о перетаскивании.</param>
|
||||
/// <param name="success">Признак успешности операции.</param>
|
||||
public DragCompletedEventArgs(IDockControl? source, IDockControl? target,
|
||||
Models.DropPosition dropPosition, Core.DragDrop.Models.DragInfo? dragInfo, bool success)
|
||||
{
|
||||
Source = source;
|
||||
Target = target;
|
||||
DropPosition = dropPosition;
|
||||
DragInfo = dragInfo;
|
||||
Success = success;
|
||||
}
|
||||
}
|
||||
@@ -60,23 +60,23 @@ public interface IDockGroupControl : IDockControl
|
||||
void SetChildren(IDockControl? firstChild, IDockControl? secondChild);
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при изменении соотношения разделения.
|
||||
/// Происходит при изменении соотношения разделения.
|
||||
/// </summary>
|
||||
event EventHandler<SplitRatioChangedEventArgs> SplitRatioChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Аргументы события изменения соотношения разделения.
|
||||
/// Предоставляет данные для события изменения соотношения разделения.
|
||||
/// </summary>
|
||||
public class SplitRatioChangedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Новое соотношение разделения.
|
||||
/// Получает новое соотношение разделения.
|
||||
/// </summary>
|
||||
public double NewRatio { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Источник изменения (пользователь или программа).
|
||||
/// Получает источник изменения соотношения разделения.
|
||||
/// </summary>
|
||||
public SplitRatioChangeSource Source { get; }
|
||||
|
||||
@@ -93,16 +93,22 @@ public class SplitRatioChangedEventArgs : EventArgs
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Источник изменения соотношения разделения.
|
||||
/// Определяет источник изменения соотношения разделения.
|
||||
/// </summary>
|
||||
public enum SplitRatioChangeSource
|
||||
{
|
||||
/// <summary>Изменение выполнено пользователем.</summary>
|
||||
/// <summary>
|
||||
/// Изменение выполнено пользователем.
|
||||
/// </summary>
|
||||
User,
|
||||
|
||||
/// <summary>Изменение выполнено программой.</summary>
|
||||
/// <summary>
|
||||
/// Изменение выполнено программой.
|
||||
/// </summary>
|
||||
Programmatic,
|
||||
|
||||
/// <summary>Изменение выполнено при восстановлении состояния.</summary>
|
||||
/// <summary>
|
||||
/// Изменение выполнено при восстановлении состояния.
|
||||
/// </summary>
|
||||
Restore
|
||||
}
|
||||
@@ -10,8 +10,7 @@ namespace Lattice.UI.Docking.Abstractions;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Реализации этого интерфейса представляют собой центральный координатор UI-слоя,
|
||||
/// который интегрирует функциональность менеджера макета, системы перетаскивания
|
||||
/// и контекстных меню в единый визуальный компонент.
|
||||
/// который интегрирует функциональность менеджера макета и контекстных меню в единый визуальный компонент.
|
||||
/// </remarks>
|
||||
public interface IDockHost : IDockControl
|
||||
{
|
||||
@@ -23,8 +22,7 @@ public interface IDockHost : IDockControl
|
||||
/// представляющих все активные плавающие окна в системе.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Плавающие окна могут быть созданы пользователем путем перетаскивания элементов
|
||||
/// за пределы основного окна или программно через методы API.
|
||||
/// Плавающие окна могут быть созданы пользователем или программно через методы API.
|
||||
/// </remarks>
|
||||
IEnumerable<IFloatingWindowControl> FloatingWindows { get; }
|
||||
|
||||
@@ -45,7 +43,7 @@ public interface IDockHost : IDockControl
|
||||
/// Получает или задает значение, указывающее, отображается ли панель инструментов (Toolbox).
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если панель инструментов видима; в противном случае — false.
|
||||
/// true, если панель инструментов видима; в противном случае false.
|
||||
/// Значение по умолчанию зависит от реализации.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
@@ -58,7 +56,7 @@ public interface IDockHost : IDockControl
|
||||
/// Получает или задает значение, указывающее, отображается ли строка состояния.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если строка состояния видима; в противном случае — false.
|
||||
/// true, если строка состояния видима; в противном случае false.
|
||||
/// Значение по умолчанию зависит от реализации.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
@@ -71,9 +69,9 @@ public interface IDockHost : IDockControl
|
||||
/// Получает или задает значение, указывающее, отображается ли главное меню приложения.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если главное меню видимо; в противном случае — false.
|
||||
/// true, если главное меню видимо; в противном случае false.
|
||||
/// Значение по умолчанию зависит от реализации.
|
||||
/// </remarks>
|
||||
/// </value>
|
||||
bool ShowMenu { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -148,7 +146,7 @@ public interface IDockHost : IDockControl
|
||||
void RemoveAutoHidePanel(IAutoHidePanelControl panel);
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при изменении структуры макета док-системы.
|
||||
/// Происходит при изменении структуры макета док-системы.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Может вызываться при добавлении/удалении элементов, изменении размеров,
|
||||
@@ -157,12 +155,12 @@ public interface IDockHost : IDockControl
|
||||
event EventHandler LayoutChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при создании нового плавающего окна.
|
||||
/// Происходит при создании нового плавающего окна.
|
||||
/// </summary>
|
||||
event EventHandler<FloatingWindowCreatedEventArgs> FloatingWindowCreated;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при закрытии плавающего окна.
|
||||
/// Происходит при закрытии плавающего окна.
|
||||
/// </summary>
|
||||
event EventHandler<FloatingWindowClosedEventArgs> FloatingWindowClosed;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public interface IDockLeafControl : IDockControl
|
||||
/// Получает или задает признак отображения кнопки закрытия на вкладках.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если кнопки закрытия отображаются; в противном случае — false.
|
||||
/// true, если кнопки закрытия отображаются; в противном случае false.
|
||||
/// </value>
|
||||
bool ShowCloseButtons { get; set; }
|
||||
|
||||
@@ -34,7 +34,7 @@ public interface IDockLeafControl : IDockControl
|
||||
/// Получает или задает признак возможности изменения порядка вкладок.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если порядок вкладок можно изменять; в противном случае — false.
|
||||
/// true, если порядок вкладок можно изменять; в противном случае false.
|
||||
/// </value>
|
||||
bool CanReorderTabs { get; set; }
|
||||
|
||||
@@ -50,25 +50,39 @@ public interface IDockLeafControl : IDockControl
|
||||
/// Добавляет вкладку в контрол.
|
||||
/// </summary>
|
||||
/// <param name="content">Контент для добавления.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="content"/> равен null.
|
||||
/// </exception>
|
||||
void AddContent(IDockContent content);
|
||||
|
||||
/// <summary>
|
||||
/// Удаляет вкладку из контрола.
|
||||
/// </summary>
|
||||
/// <param name="content">Контент для удаления.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="content"/> равен null.
|
||||
/// </exception>
|
||||
void RemoveContent(IDockContent content);
|
||||
|
||||
/// <summary>
|
||||
/// Закрывает указанную вкладку.
|
||||
/// </summary>
|
||||
/// <param name="content">Контент для закрытия.</param>
|
||||
/// <returns>true, если вкладка была закрыта; в противном случае — false.</returns>
|
||||
/// <returns>
|
||||
/// true, если вкладка была закрыта; в противном случае false.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="content"/> равен null.
|
||||
/// </exception>
|
||||
bool CloseContent(IDockContent content);
|
||||
|
||||
/// <summary>
|
||||
/// Закрывает все вкладки, кроме указанной.
|
||||
/// </summary>
|
||||
/// <param name="exceptContent">Вкладка, которую нужно оставить открытой.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="exceptContent"/> равен null.
|
||||
/// </exception>
|
||||
void CloseAllExcept(IDockContent exceptContent);
|
||||
|
||||
/// <summary>
|
||||
@@ -77,39 +91,41 @@ public interface IDockLeafControl : IDockControl
|
||||
void CloseAll();
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при изменении активной вкладки.
|
||||
/// Происходит при изменении активной вкладки.
|
||||
/// </summary>
|
||||
event EventHandler<ActiveContentChangedEventArgs> ActiveContentChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при запросе закрытия вкладки.
|
||||
/// Происходит при запросе закрытия вкладки.
|
||||
/// </summary>
|
||||
event EventHandler<ContentClosingEventArgs> ContentClosing;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при изменении порядка вкладок.
|
||||
/// Происходит при изменении порядка вкладок.
|
||||
/// </summary>
|
||||
event EventHandler<TabsReorderedEventArgs> TabsReordered;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Аргументы события изменения активного контента.
|
||||
/// Предоставляет данные для события изменения активного контента.
|
||||
/// </summary>
|
||||
public class ActiveContentChangedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Предыдущий активный контент.
|
||||
/// Получает предыдущий активный контент.
|
||||
/// </summary>
|
||||
public IDockContent? OldContent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Новый активный контент.
|
||||
/// Получает новый активный контент.
|
||||
/// </summary>
|
||||
public IDockContent? NewContent { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="ActiveContentChangedEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="oldContent">Предыдущий активный контент.</param>
|
||||
/// <param name="newContent">Новый активный контент.</param>
|
||||
public ActiveContentChangedEventArgs(IDockContent? oldContent, IDockContent? newContent)
|
||||
{
|
||||
OldContent = oldContent;
|
||||
@@ -118,63 +134,79 @@ public class ActiveContentChangedEventArgs : EventArgs
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Аргументы события закрытия контента.
|
||||
/// Предоставляет данные для события закрытия контента.
|
||||
/// </summary>
|
||||
public class ContentClosingEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Контент, который закрывается.
|
||||
/// Получает контент, который закрывается.
|
||||
/// </summary>
|
||||
public IDockContent Content { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Показывает, можно ли отменить закрытие.
|
||||
/// Получает или задает значение, указывающее, можно ли отменить закрытие.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если закрытие можно отменить; в противном случае false.
|
||||
/// </value>
|
||||
public bool CanCancel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает признак отмены закрытия.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если закрытие отменено; в противном случае false.
|
||||
/// </value>
|
||||
public bool Cancel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="ContentClosingEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="content">Контент, который закрывается.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="content"/> равен null.
|
||||
/// </exception>
|
||||
public ContentClosingEventArgs(IDockContent content)
|
||||
{
|
||||
Content = content;
|
||||
Content = content ?? throw new ArgumentNullException(nameof(content));
|
||||
CanCancel = true;
|
||||
Cancel = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Аргументы события изменения порядка вкладок.
|
||||
/// Предоставляет данные для события изменения порядка вкладок.
|
||||
/// </summary>
|
||||
public class TabsReorderedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Старый индекс вкладки.
|
||||
/// Получает старый индекс вкладки.
|
||||
/// </summary>
|
||||
public int OldIndex { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Новый индекс вкладки.
|
||||
/// Получает новый индекс вкладки.
|
||||
/// </summary>
|
||||
public int NewIndex { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Перемещаемый контент.
|
||||
/// Получает перемещаемый контент.
|
||||
/// </summary>
|
||||
public IDockContent Content { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="TabsReorderedEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="oldIndex">Старый индекс вкладки.</param>
|
||||
/// <param name="newIndex">Новый индекс вкладки.</param>
|
||||
/// <param name="content">Перемещаемый контент.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="content"/> равен null.
|
||||
/// </exception>
|
||||
public TabsReorderedEventArgs(int oldIndex, int newIndex, IDockContent content)
|
||||
{
|
||||
OldIndex = oldIndex;
|
||||
NewIndex = newIndex;
|
||||
Content = content;
|
||||
Content = content ?? throw new ArgumentNullException(nameof(content));
|
||||
}
|
||||
}
|
||||
72
Lattice.UI.Docking/Abstractions/IDockSplitterControl.cs
Normal file
72
Lattice.UI.Docking/Abstractions/IDockSplitterControl.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
namespace Lattice.UI.Docking.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Определяет контракт для контрола разделителя между элементами док-системы.
|
||||
/// Разделитель позволяет пользователю изменять размер смежных элементов.
|
||||
/// </summary>
|
||||
public interface IDockSplitterControl : IDockControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает или задает ориентацию разделителя.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Ориентация разделителя (горизонтальная или вертикальная).
|
||||
/// </value>
|
||||
Core.Docking.Models.SplitDirection Orientation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает признак того, что разделитель активен (перетаскивается).
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если разделитель активен; в противном случае false.
|
||||
/// </value>
|
||||
bool IsDragging { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Происходит при начале перетаскивания разделителя.
|
||||
/// </summary>
|
||||
event EventHandler DragStarted;
|
||||
|
||||
/// <summary>
|
||||
/// Происходит при перетаскивании разделителя.
|
||||
/// </summary>
|
||||
event EventHandler<SplitterDraggedEventArgs> DragDelta;
|
||||
|
||||
/// <summary>
|
||||
/// Происходит при завершении перетаскивания разделителя.
|
||||
/// </summary>
|
||||
event EventHandler DragCompleted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Предоставляет данные для события перетаскивания разделителя.
|
||||
/// </summary>
|
||||
public class SplitterDraggedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает изменение позиции по горизонтали.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Изменение по горизонтали в пикселях.
|
||||
/// </value>
|
||||
public double HorizontalChange { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает изменение позиции по вертикали.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Изменение по вертикали в пикселях.
|
||||
/// </value>
|
||||
public double VerticalChange { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="SplitterDraggedEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="horizontalChange">Изменение по горизонтали.</param>
|
||||
/// <param name="verticalChange">Изменение по вертикали.</param>
|
||||
public SplitterDraggedEventArgs(double horizontalChange, double verticalChange)
|
||||
{
|
||||
HorizontalChange = horizontalChange;
|
||||
VerticalChange = verticalChange;
|
||||
}
|
||||
}
|
||||
@@ -77,31 +77,37 @@ public interface IDockTheme
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Аргументы события показа контекстного меню.
|
||||
/// Предоставляет данные для события показа контекстного меню.
|
||||
/// </summary>
|
||||
public class ContextMenuShownEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Элемент, для которого показано меню.
|
||||
/// Получает элемент, для которого показано меню.
|
||||
/// </summary>
|
||||
public IDockControl Target { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Координата X меню.
|
||||
/// Получает координату X меню.
|
||||
/// </summary>
|
||||
public double X { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Координата Y меню.
|
||||
/// Получает координату Y меню.
|
||||
/// </summary>
|
||||
public double Y { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="ContextMenuShownEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="target">Элемент, для которого показано меню.</param>
|
||||
/// <param name="x">Координата X меню.</param>
|
||||
/// <param name="y">Координата Y меню.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="target"/> равен null.
|
||||
/// </exception>
|
||||
public ContextMenuShownEventArgs(IDockControl target, double x, double y)
|
||||
{
|
||||
Target = target;
|
||||
Target = target ?? throw new ArgumentNullException(nameof(target));
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
@@ -22,12 +22,8 @@ public interface IDockUIService
|
||||
/// Платформенно-зависимый объект окна, который можно отобразить.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="host"/> равен null.
|
||||
/// Выбрасывается, когда <paramref name="host"/> равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Реализация должна создавать окно с соответствующими стилями и поведением
|
||||
/// для целевой платформы, настроенное для работы с док-системой.
|
||||
/// </remarks>
|
||||
object CreateMainWindow(IDockHost host);
|
||||
|
||||
/// <summary>
|
||||
@@ -42,12 +38,8 @@ public interface IDockUIService
|
||||
/// null - диалог был закрыт без выбора.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="title"/> или <paramref name="content"/> равны null.
|
||||
/// Выбрасывается, когда <paramref name="title"/> или <paramref name="content"/> равны null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Реализация должна блокировать взаимодействие с родительским окном
|
||||
/// до закрытия диалога.
|
||||
/// </remarks>
|
||||
bool? ShowDialog(string title, object content);
|
||||
|
||||
/// <summary>
|
||||
@@ -56,12 +48,8 @@ public interface IDockUIService
|
||||
/// <param name="message">Текст сообщения.</param>
|
||||
/// <param name="caption">Заголовок окна сообщения.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="message"/> или <paramref name="caption"/> равны null.
|
||||
/// Выбрасывается, когда <paramref name="message"/> или <paramref name="caption"/> равны null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Реализация должна использовать стандартные диалоги платформы
|
||||
/// или создавать кастомные окна сообщений.
|
||||
/// </remarks>
|
||||
void ShowMessage(string message, string caption);
|
||||
|
||||
/// <summary>
|
||||
@@ -73,12 +61,8 @@ public interface IDockUIService
|
||||
/// true, если пользователь выбрал "Yes"; false, если пользователь выбрал "No".
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="message"/> или <paramref name="caption"/> равны null.
|
||||
/// Выбрасывается, когда <paramref name="message"/> или <paramref name="caption"/> равны null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Используется для получения подтверждения от пользователя перед выполнением
|
||||
/// критических операций (закрытие вкладок, сброс настроек и т.д.).
|
||||
/// </remarks>
|
||||
bool Confirm(string message, string caption);
|
||||
|
||||
/// <summary>
|
||||
@@ -90,12 +74,8 @@ public interface IDockUIService
|
||||
/// Введенный пользователем текст или null, если диалог был отменен.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="prompt"/> равен null.
|
||||
/// Выбрасывается, когда <paramref name="prompt"/> равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Реализация должна предоставлять однострочное поле ввода текста
|
||||
/// с возможностью отмены операции.
|
||||
/// </remarks>
|
||||
string? Prompt(string prompt, string? defaultValue = null);
|
||||
|
||||
/// <summary>
|
||||
@@ -103,12 +83,7 @@ public interface IDockUIService
|
||||
/// </summary>
|
||||
/// <param name="action">Действие для выполнения.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="action"/> равен null.
|
||||
/// Выбрасывается, когда <paramref name="action"/> равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Этот метод гарантирует, что действие будет выполнено в потоке,
|
||||
/// связанном с пользовательским интерфейсом, что необходимо для
|
||||
/// безопасного обновления UI-элементов.
|
||||
/// </remarks>
|
||||
void InvokeOnUIThread(Action action);
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public interface IFloatingWindowControl : IDockControl
|
||||
/// Получает или задает признак того, что окно можно изменять.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если размеры окна можно изменять; в противном случае — false.
|
||||
/// true, если размеры окна можно изменять; в противном случае false.
|
||||
/// </value>
|
||||
bool CanResize { get; set; }
|
||||
|
||||
@@ -61,7 +61,7 @@ public interface IFloatingWindowControl : IDockControl
|
||||
/// Получает или задает признак того, что окно можно перемещать.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если окно можно перемещать; в противном случае — false.
|
||||
/// true, если окно можно перемещать; в противном случае false.
|
||||
/// </value>
|
||||
bool CanMove { get; set; }
|
||||
|
||||
@@ -69,7 +69,7 @@ public interface IFloatingWindowControl : IDockControl
|
||||
/// Получает или задает признак того, что окно всегда поверх других окон.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если окно всегда поверх; в противном случае — false.
|
||||
/// true, если окно всегда поверх; в противном случае false.
|
||||
/// </value>
|
||||
bool AlwaysOnTop { get; set; }
|
||||
|
||||
@@ -94,17 +94,17 @@ public interface IFloatingWindowControl : IDockControl
|
||||
void Activate();
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при закрытии окна.
|
||||
/// Происходит при закрытии окна.
|
||||
/// </summary>
|
||||
event EventHandler Closing;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при изменении положения окна.
|
||||
/// Происходит при изменении положения окна.
|
||||
/// </summary>
|
||||
event EventHandler LocationChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при изменении размера окна.
|
||||
/// Происходит при изменении размера окна.
|
||||
/// </summary>
|
||||
event EventHandler SizeChanged;
|
||||
}
|
||||
@@ -1,33 +1,85 @@
|
||||
using Lattice.UI.Docking.Abstractions;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Lattice.UI.Docking.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Базовая реализация команды док-системы.
|
||||
/// Предоставляет базовую реализацию команды док-системы.
|
||||
/// Реализует интерфейс <see cref="IDockCommand"/> и <see cref="INotifyPropertyChanged"/>
|
||||
/// для поддержки уведомлений об изменении свойств.
|
||||
/// </summary>
|
||||
public abstract class DockCommandBase : IDockCommand
|
||||
/// <remarks>
|
||||
/// Этот класс предоставляет общую логику для команд, включая управление состоянием
|
||||
/// возможности выполнения, уведомление об изменениях и реализацию интерфейса ICommand.
|
||||
/// </remarks>
|
||||
public abstract class DockCommandBase : IDockCommand, INotifyPropertyChanged
|
||||
{
|
||||
/// <summary>
|
||||
/// Происходит при изменении возможности выполнения команды.
|
||||
/// </summary>
|
||||
public event EventHandler? CanExecuteChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Происходит при изменении значения свойства.
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
private bool _canExecute = true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <summary>
|
||||
/// Получает уникальный идентификатор команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Строковый идентификатор команды. Должен быть уникальным в пределах системы.
|
||||
/// </value>
|
||||
public abstract string Id { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <summary>
|
||||
/// Получает отображаемое имя команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Имя команды, отображаемое в пользовательском интерфейсе.
|
||||
/// </value>
|
||||
public abstract string Name { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <summary>
|
||||
/// Получает описание команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Текстовое описание функциональности команды.
|
||||
/// Реализация по умолчанию возвращает пустую строку.
|
||||
/// </value>
|
||||
public virtual string Description => string.Empty;
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <summary>
|
||||
/// Получает идентификатор ресурса для иконки команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Имя ресурса иконки или путь к файлу иконки.
|
||||
/// Реализация по умолчанию возвращает пустую строку.
|
||||
/// </value>
|
||||
public virtual string Icon => string.Empty;
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <summary>
|
||||
/// Получает комбинацию клавиш для быстрого вызова команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Строковое представление горячей клавиши.
|
||||
/// Реализация по умолчанию возвращает пустую строку.
|
||||
/// </value>
|
||||
public virtual string Shortcut => string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает признак возможности выполнения команды.
|
||||
/// Получает или задает значение, указывающее, можно ли выполнить команду.
|
||||
/// </summary>
|
||||
public bool CanExecute
|
||||
/// <value>
|
||||
/// true, если команду можно выполнить; в противном случае false.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// При изменении этого свойства генерируется событие <see cref="CanExecuteChanged"/>.
|
||||
/// </remarks>
|
||||
protected bool CanExecuteValue
|
||||
{
|
||||
get => _canExecute;
|
||||
set
|
||||
@@ -36,42 +88,131 @@ public abstract class DockCommandBase : IDockCommand
|
||||
{
|
||||
_canExecute = value;
|
||||
OnCanExecuteChanged();
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler? CanExecuteChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <summary>
|
||||
/// Определяет, можно ли выполнить команду в текущем контексте.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Параметр команды.</param>
|
||||
/// <returns>
|
||||
/// true, если команду можно выполнить; в противном случае false.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Реализация по умолчанию возвращает значение свойства <see cref="CanExecuteValue"/>.
|
||||
/// </remarks>
|
||||
public virtual bool CanExecute(object? parameter)
|
||||
{
|
||||
return _canExecute;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <summary>
|
||||
/// Выполняет команду.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Параметр команды.</param>
|
||||
/// <remarks>
|
||||
/// Этот метод должен быть реализован в производных классах.
|
||||
/// </remarks>
|
||||
public abstract void Execute(object? parameter);
|
||||
|
||||
/// <summary>
|
||||
/// Вызывает событие изменения возможности выполнения команды.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Этот метод может быть переопределен в производных классах для добавления
|
||||
/// дополнительной логики перед вызовом события.
|
||||
/// </remarks>
|
||||
protected virtual void OnCanExecuteChanged()
|
||||
{
|
||||
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Вызывает событие <see cref="PropertyChanged"/>.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">
|
||||
/// Имя изменившегося свойства. Если не указано, определяется автоматически.
|
||||
/// </param>
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Базовая команда для закрытия контента.
|
||||
/// Предоставляет команду для закрытия контента (вкладки).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Команда закрывает активную вкладку в указанном контроле листа.
|
||||
/// </remarks>
|
||||
public class CloseContentCommand : DockCommandBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает уникальный идентификатор команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Идентификатор "CloseContent".
|
||||
/// </value>
|
||||
public override string Id => "CloseContent";
|
||||
|
||||
/// <summary>
|
||||
/// Получает отображаемое имя команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Имя "Close".
|
||||
/// </value>
|
||||
public override string Name => "Close";
|
||||
|
||||
/// <summary>
|
||||
/// Получает описание команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Описание "Close the current tab".
|
||||
/// </value>
|
||||
public override string Description => "Close the current tab";
|
||||
|
||||
/// <summary>
|
||||
/// Получает идентификатор ресурса для иконки команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Идентификатор "Close".
|
||||
/// </value>
|
||||
public override string Icon => "Close";
|
||||
|
||||
/// <summary>
|
||||
/// Получает комбинацию клавиш для быстрого вызова команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Горячая клавиша "Ctrl+F4".
|
||||
/// </value>
|
||||
public override string Shortcut => "Ctrl+F4";
|
||||
|
||||
/// <summary>
|
||||
/// Определяет, можно ли выполнить команду в текущем контексте.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Параметр команды.</param>
|
||||
/// <returns>
|
||||
/// true, если команду можно выполнить; в противном случае false.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Команда доступна только если параметр является контролом листа
|
||||
/// и содержит активный контент.
|
||||
/// </remarks>
|
||||
public override bool CanExecute(object? parameter)
|
||||
{
|
||||
return parameter is Abstractions.IDockLeafControl leafControl &&
|
||||
leafControl.ActiveContent != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выполняет команду закрытия контента.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Параметр команды. Ожидается <see cref="Abstractions.IDockLeafControl"/>.</param>
|
||||
/// <remarks>
|
||||
/// Команда закрывает активную вкладку в указанном контроле листа.
|
||||
/// </remarks>
|
||||
public override void Execute(object? parameter)
|
||||
{
|
||||
if (parameter is Abstractions.IDockLeafControl leafControl &&
|
||||
@@ -83,33 +224,137 @@ public class CloseContentCommand : DockCommandBase
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Базовая команда для создания плавающего окна.
|
||||
/// Предоставляет команду для создания плавающего окна из элемента.
|
||||
/// </summary>
|
||||
public class FloatWindowCommand : DockCommandBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает уникальный идентификатор команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Идентификатор "FloatWindow".
|
||||
/// </value>
|
||||
public override string Id => "FloatWindow";
|
||||
|
||||
/// <summary>
|
||||
/// Получает отображаемое имя команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Имя "Float".
|
||||
/// </value>
|
||||
public override string Name => "Float";
|
||||
|
||||
/// <summary>
|
||||
/// Получает описание команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Описание "Float the window as a separate window".
|
||||
/// </value>
|
||||
public override string Description => "Float the window as a separate window";
|
||||
|
||||
/// <summary>
|
||||
/// Получает идентификатор ресурса для иконки команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Идентификатор "Float".
|
||||
/// </value>
|
||||
public override string Icon => "Float";
|
||||
|
||||
/// <summary>
|
||||
/// Определяет, можно ли выполнить команду в текущем контексте.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Параметр команды.</param>
|
||||
/// <returns>
|
||||
/// true, если команду можно выполнить; в противном случае false.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Команда доступна только если параметр является элементом док-системы,
|
||||
/// который может быть преобразован в плавающее окно.
|
||||
/// </remarks>
|
||||
public override bool CanExecute(object? parameter)
|
||||
{
|
||||
return parameter is Core.Docking.Abstractions.IDockElement;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выполняет команду создания плавающего окна.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Параметр команды. Ожидается <see cref="Core.Docking.Abstractions.IDockElement"/>.</param>
|
||||
/// <remarks>
|
||||
/// Реализация зависит от конкретного UI и должна быть предоставлена в производных классах.
|
||||
/// Базовая реализация не выполняет никаких действий.
|
||||
/// </remarks>
|
||||
public override void Execute(object? parameter)
|
||||
{
|
||||
// Реализация зависит от конкретного UI
|
||||
// В базовом классе метод не выполняет никаких действий
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Базовая команда для закрепления окна.
|
||||
/// Предоставляет команду для закрепления плавающего окна.
|
||||
/// </summary>
|
||||
public class DockWindowCommand : DockCommandBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает уникальный идентификатор команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Идентификатор "DockWindow".
|
||||
/// </value>
|
||||
public override string Id => "DockWindow";
|
||||
|
||||
/// <summary>
|
||||
/// Получает отображаемое имя команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Имя "Dock".
|
||||
/// </value>
|
||||
public override string Name => "Dock";
|
||||
|
||||
/// <summary>
|
||||
/// Получает описание команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Описание "Dock the window to the main window".
|
||||
/// </value>
|
||||
public override string Description => "Dock the window to the main window";
|
||||
|
||||
/// <summary>
|
||||
/// Получает идентификатор ресурса для иконки команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Идентификатор "Dock".
|
||||
/// </value>
|
||||
public override string Icon => "Dock";
|
||||
|
||||
/// <summary>
|
||||
/// Определяет, можно ли выполнить команду в текущем контексте.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Параметр команды.</param>
|
||||
/// <returns>
|
||||
/// true, если команду можно выполнить; в противном случае false.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Команда доступна только если параметр является плавающим окном,
|
||||
/// которое может быть закреплено в основном окне.
|
||||
/// </remarks>
|
||||
public override bool CanExecute(object? parameter)
|
||||
{
|
||||
return parameter is Abstractions.IFloatingWindowControl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выполняет команду закрепления окна.
|
||||
/// </summary>
|
||||
/// <param name="parameter">Параметр команды. Ожидается <see cref="Abstractions.IFloatingWindowControl"/>.</param>
|
||||
/// <remarks>
|
||||
/// Реализация зависит от конкретного UI и должна быть предоставлена в производных классах.
|
||||
/// Базовая реализация не выполняет никаких действий.
|
||||
/// </remarks>
|
||||
public override void Execute(object? parameter)
|
||||
{
|
||||
// Реализация зависит от конкретного UI
|
||||
// В базовом классе метод не выполняет никаких действий
|
||||
}
|
||||
}
|
||||
@@ -5,57 +5,136 @@ using Lattice.UI.Docking.Abstractions;
|
||||
namespace Lattice.UI.Docking.Factories;
|
||||
|
||||
/// <summary>
|
||||
/// Базовая фабрика для создания UI-контролов док-системы.
|
||||
/// Предоставляет базовую реализацию фабрики для создания UI-контролов док-системы.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Этот класс реализует общую логику для фабрик контролов, включая настройку
|
||||
/// общих свойств и создание контролов для произвольных элементов.
|
||||
/// </remarks>
|
||||
public abstract class DockControlFactoryBase : IDockControlFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает или задает сервис перетаскивания для создаваемых контролов.
|
||||
/// </summary>
|
||||
public Services.IDockDragDropService? DragDropService { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает менеджер контекста для создаваемых контролов.
|
||||
/// </summary>
|
||||
public Services.IDockContextManager? ContextManager { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract IDockGroupControl CreateGroupControl(DockGroup group);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract IDockLeafControl CreateLeafControl(DockLeaf leaf);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract IFloatingWindowControl CreateFloatingWindowControl(DockWindow window);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract IAutoHidePanelControl CreateAutoHidePanelControl(AutoHidePanel panel);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract IDockSplitterControl CreateSplitterControl(SplitDirection orientation);
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockContextManager"/> или null, если не установлен.
|
||||
/// </value>
|
||||
public IDockContextManager? ContextManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Создает контрол для произвольного элемента док-системы.
|
||||
/// Создает контрол для группы разделения.
|
||||
/// </summary>
|
||||
/// <param name="group">Модель группы.</param>
|
||||
/// <returns>
|
||||
/// Созданный контрол группы.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="group"/> равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Этот метод должен быть реализован в производных классах.
|
||||
/// </remarks>
|
||||
public abstract IDockGroupControl CreateGroupControl(DockGroup group);
|
||||
|
||||
/// <summary>
|
||||
/// Создает контрол для контейнера вкладок.
|
||||
/// </summary>
|
||||
/// <param name="leaf">Модель листа.</param>
|
||||
/// <returns>
|
||||
/// Созданный контрол листа.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="leaf"/> равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Этот метод должен быть реализован в производных классах.
|
||||
/// </remarks>
|
||||
public abstract IDockLeafControl CreateLeafControl(DockLeaf leaf);
|
||||
|
||||
/// <summary>
|
||||
/// Создает контрол для плавающего окна.
|
||||
/// </summary>
|
||||
/// <param name="window">Модель окна.</param>
|
||||
/// <returns>
|
||||
/// Созданный контрол окна.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="window"/> равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Этот метод должен быть реализован в производных классах.
|
||||
/// </remarks>
|
||||
public abstract IFloatingWindowControl CreateFloatingWindowControl(DockWindow window);
|
||||
|
||||
/// <summary>
|
||||
/// Создает контрол для автоскрываемой панели.
|
||||
/// </summary>
|
||||
/// <param name="panel">Модель панели.</param>
|
||||
/// <returns>
|
||||
/// Созданный контрол панели.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="panel"/> равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Этот метод должен быть реализован в производных классах.
|
||||
/// </remarks>
|
||||
public abstract IAutoHidePanelControl CreateAutoHidePanelControl(AutoHidePanel panel);
|
||||
|
||||
/// <summary>
|
||||
/// Создает контрол для разделителя.
|
||||
/// </summary>
|
||||
/// <param name="orientation">Ориентация разделителя.</param>
|
||||
/// <returns>
|
||||
/// Созданный контрол разделителя.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Этот метод должен быть реализован в производных классах.
|
||||
/// </remarks>
|
||||
public abstract IDockSplitterControl CreateSplitterControl(SplitDirection orientation);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual IDockControl? CreateControlForElement(IDockElement element)
|
||||
{
|
||||
return element switch
|
||||
if (element == null) throw new ArgumentNullException(nameof(element));
|
||||
|
||||
IDockControl? control = null;
|
||||
|
||||
switch (element)
|
||||
{
|
||||
DockGroup group => CreateGroupControl(group),
|
||||
DockLeaf leaf => CreateLeafControl(leaf),
|
||||
_ => null
|
||||
};
|
||||
case DockGroup group:
|
||||
control = CreateGroupControl(group);
|
||||
break;
|
||||
case DockLeaf leaf:
|
||||
control = CreateLeafControl(leaf);
|
||||
break;
|
||||
default:
|
||||
control = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (control != null)
|
||||
{
|
||||
ConfigureControl(control);
|
||||
}
|
||||
|
||||
return control;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Настраивает общие свойства контрола.
|
||||
/// </summary>
|
||||
/// <param name="control">Контрол для настройки.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="control"/> равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Устанавливает общие свойства, такие как контекстный менеджер,
|
||||
/// для всех создаваемых контролов.
|
||||
/// </remarks>
|
||||
protected virtual void ConfigureControl(IDockControl control)
|
||||
{
|
||||
if (DragDropService != null)
|
||||
{
|
||||
control.DragDropService = DragDropService;
|
||||
}
|
||||
if (control == null) throw new ArgumentNullException(nameof(control));
|
||||
|
||||
if (ContextManager != null)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Lattice.Core.Docking.Models;
|
||||
using Lattice.Core.Docking.Abstractions;
|
||||
using Lattice.Core.Docking.Models;
|
||||
using Lattice.UI.Docking.Abstractions;
|
||||
|
||||
namespace Lattice.UI.Docking.Factories;
|
||||
@@ -6,96 +7,82 @@ namespace Lattice.UI.Docking.Factories;
|
||||
/// <summary>
|
||||
/// Определяет контракт для фабрики, создающей UI-контролы для элементов док-системы.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Фабрика обеспечивает абстракцию над созданием конкретных UI-контролов,
|
||||
/// что позволяет легко заменять реализации для разных платформ или тем оформления.
|
||||
/// </remarks>
|
||||
public interface IDockControlFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Создает контрол для группы разделения.
|
||||
/// </summary>
|
||||
/// <param name="group">Модель группы.</param>
|
||||
/// <returns>Созданный контрол группы.</returns>
|
||||
/// <returns>
|
||||
/// Созданный контрол группы.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="group"/> равен null.
|
||||
/// </exception>
|
||||
IDockGroupControl CreateGroupControl(DockGroup group);
|
||||
|
||||
/// <summary>
|
||||
/// Создает контрол для контейнера вкладок.
|
||||
/// </summary>
|
||||
/// <param name="leaf">Модель листа.</param>
|
||||
/// <returns>Созданный контрол листа.</returns>
|
||||
/// <returns>
|
||||
/// Созданный контрол листа.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="leaf"/> равен null.
|
||||
/// </exception>
|
||||
IDockLeafControl CreateLeafControl(DockLeaf leaf);
|
||||
|
||||
/// <summary>
|
||||
/// Создает контрол для плавающего окна.
|
||||
/// </summary>
|
||||
/// <param name="window">Модель окна.</param>
|
||||
/// <returns>Созданный контрол окна.</returns>
|
||||
/// <returns>
|
||||
/// Созданный контрол окна.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="window"/> равен null.
|
||||
/// </exception>
|
||||
IFloatingWindowControl CreateFloatingWindowControl(DockWindow window);
|
||||
|
||||
/// <summary>
|
||||
/// Создает контрол для автоскрываемой панели.
|
||||
/// </summary>
|
||||
/// <param name="panel">Модель панели.</param>
|
||||
/// <returns>Созданный контрол панели.</returns>
|
||||
/// <returns>
|
||||
/// Созданный контрол панели.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="panel"/> равен null.
|
||||
/// </exception>
|
||||
IAutoHidePanelControl CreateAutoHidePanelControl(AutoHidePanel panel);
|
||||
|
||||
/// <summary>
|
||||
/// Создает контрол для разделителя.
|
||||
/// </summary>
|
||||
/// <param name="orientation">Ориентация разделителя.</param>
|
||||
/// <returns>Созданный контрол разделителя.</returns>
|
||||
/// <returns>
|
||||
/// Созданный контрол разделителя.
|
||||
/// </returns>
|
||||
IDockSplitterControl CreateSplitterControl(SplitDirection orientation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Определяет контракт для контрола разделителя.
|
||||
/// </summary>
|
||||
public interface IDockSplitterControl : IDockControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает или задает ориентацию разделителя.
|
||||
/// </summary>
|
||||
SplitDirection Orientation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает признак того, что разделитель активен.
|
||||
/// Создает контрол для произвольного элемента док-системы.
|
||||
/// </summary>
|
||||
bool IsActive { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при начале перетаскивания разделителя.
|
||||
/// </summary>
|
||||
event EventHandler DragStarted;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при перетаскивании разделителя.
|
||||
/// </summary>
|
||||
event EventHandler<SplitterDraggedEventArgs> DragDelta;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при завершении перетаскивания разделителя.
|
||||
/// </summary>
|
||||
event EventHandler DragCompleted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Аргументы события перетаскивания разделителя.
|
||||
/// </summary>
|
||||
public class SplitterDraggedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Изменение по горизонтали.
|
||||
/// </summary>
|
||||
public double HorizontalChange { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Изменение по вертикали.
|
||||
/// </summary>
|
||||
public double VerticalChange { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="SplitterDraggedEventArgs"/>.
|
||||
/// </summary>
|
||||
public SplitterDraggedEventArgs(double horizontalChange, double verticalChange)
|
||||
{
|
||||
HorizontalChange = horizontalChange;
|
||||
VerticalChange = verticalChange;
|
||||
}
|
||||
/// <param name="element">Элемент для создания контрола.</param>
|
||||
/// <returns>
|
||||
/// Созданный контрол или null, если тип элемента не поддерживается.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="element"/> равен null.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Метод использует сопоставление с шаблоном для определения типа элемента
|
||||
/// и вызова соответствующего метода создания.
|
||||
/// </remarks>
|
||||
IDockControl? CreateControlForElement(IDockElement element);
|
||||
}
|
||||
113
Lattice.UI.Docking/Implementations/DockControlBase.cs
Normal file
113
Lattice.UI.Docking/Implementations/DockControlBase.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using Lattice.Core.Docking.Abstractions;
|
||||
using Lattice.Core.Docking.Engine;
|
||||
using Lattice.UI.Docking.Abstractions;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Lattice.UI.Docking.Implementations;
|
||||
|
||||
/// <summary>
|
||||
/// Базовая реализация контрола док-системы.
|
||||
/// </summary>
|
||||
public abstract class DockControlBase : IDockControl, INotifyPropertyChanged
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
private IDockElement? _model;
|
||||
private LayoutManager? _layoutManager;
|
||||
private IDockContextManager? _contextManager;
|
||||
private bool _isSelected;
|
||||
private bool _isActive;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IDockElement? Model
|
||||
{
|
||||
get => _model;
|
||||
set
|
||||
{
|
||||
if (_model != value)
|
||||
{
|
||||
_model = value;
|
||||
OnPropertyChanged(nameof(Model));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public LayoutManager? LayoutManager
|
||||
{
|
||||
get => _layoutManager;
|
||||
set
|
||||
{
|
||||
if (_layoutManager != value)
|
||||
{
|
||||
_layoutManager = value;
|
||||
OnPropertyChanged(nameof(LayoutManager));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IDockContextManager? ContextManager
|
||||
{
|
||||
get => _contextManager;
|
||||
set
|
||||
{
|
||||
if (_contextManager != value)
|
||||
{
|
||||
_contextManager = value;
|
||||
OnPropertyChanged(nameof(ContextManager));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsSelected
|
||||
{
|
||||
get => _isSelected;
|
||||
set
|
||||
{
|
||||
if (_isSelected != value)
|
||||
{
|
||||
_isSelected = value;
|
||||
OnPropertyChanged(nameof(IsSelected));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsActive
|
||||
{
|
||||
get => _isActive;
|
||||
set
|
||||
{
|
||||
if (_isActive != value)
|
||||
{
|
||||
_isActive = value;
|
||||
OnPropertyChanged(nameof(IsActive));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract void Refresh();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract void ApplyTheme(IDockTheme theme);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void OnModelPropertyChanged(string propertyName)
|
||||
{
|
||||
// Базовая реализация просто обновляет весь контрол
|
||||
Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Вызывает событие <see cref="PropertyChanged"/>.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Имя измененного свойства.</param>
|
||||
protected virtual void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,4 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Lattice.Core.Docking\Lattice.Core.Docking.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Converters\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lattice.Core.Docking.Abstractions;
|
||||
using Lattice.Core.Docking.Engine;
|
||||
using Lattice.Core.Docking.Engine;
|
||||
using Lattice.Core.Docking.Services;
|
||||
using Lattice.UI.Docking.Abstractions;
|
||||
using Lattice.UI.Docking.Factories;
|
||||
@@ -8,14 +7,7 @@ namespace Lattice.UI.Docking;
|
||||
|
||||
/// <summary>
|
||||
/// Предоставляет статический API для инициализации и управления UI-фреймворком Lattice.
|
||||
/// Является точкой входа для интеграции док-системы в приложение и централизованным
|
||||
/// хранилищем для основных сервисов и компонентов.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Этот класс реализует шаблон Singleton для доступа к глобальным сервисам.
|
||||
/// Все компоненты инициализируются через строитель <see cref="LatticeBuilder"/>,
|
||||
/// что обеспечивает гибкую конфигурацию и соблюдение принципа инверсии зависимостей.
|
||||
/// </remarks>
|
||||
public static class LatticeUIFramework
|
||||
{
|
||||
private static bool _isInitialized;
|
||||
@@ -24,22 +16,11 @@ public static class LatticeUIFramework
|
||||
/// <summary>
|
||||
/// Получает значение, указывающее, инициализирован ли фреймворк.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если фреймворк был инициализирован вызовом <see cref="Initialize"/>;
|
||||
/// в противном случае — false.
|
||||
/// </value>
|
||||
public static bool IsInitialized => _isInitialized;
|
||||
|
||||
/// <summary>
|
||||
/// Получает текущий строитель конфигурации фреймворка.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="LatticeBuilder"/>, используемый для настройки фреймворка.
|
||||
/// Возвращает null, если фреймворк не инициализирован.
|
||||
/// </value>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Выбрасывается при попытке доступа к свойству до инициализации фреймворка.
|
||||
/// </exception>
|
||||
public static LatticeBuilder CurrentBuilder
|
||||
{
|
||||
get
|
||||
@@ -53,67 +34,31 @@ public static class LatticeUIFramework
|
||||
/// <summary>
|
||||
/// Получает менеджер макета из текущего строителя.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="LayoutManager"/>, управляющий структурой док-системы.
|
||||
/// </value>
|
||||
public static LayoutManager? LayoutManager => _currentBuilder?.LayoutManager;
|
||||
|
||||
/// <summary>
|
||||
/// Получает реестр контента из текущего строителя.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="ContentRegistry"/>, содержащий зарегистрированные типы контента.
|
||||
/// </value>
|
||||
public static ContentRegistry? ContentRegistry => _currentBuilder?.ContentRegistry;
|
||||
|
||||
/// <summary>
|
||||
/// Получает фабрику контролов из текущего строителя.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockControlFactory"/> для создания UI-контролов.
|
||||
/// </value>
|
||||
public static IDockControlFactory? ControlFactory => _currentBuilder?.ControlFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Получает сервис перетаскивания из текущего строителя.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockDragDropService"/> для управления операциями drag-and-drop.
|
||||
/// </value>
|
||||
public static IDockDragDropService? DragDropService => _currentBuilder?.DragDropService;
|
||||
|
||||
/// <summary>
|
||||
/// Получает менеджер контекстных меню из текущего строителя.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockContextManager"/> для управления контекстными меню.
|
||||
/// </value>
|
||||
public static IDockContextManager? ContextManager => _currentBuilder?.ContextManager;
|
||||
|
||||
/// <summary>
|
||||
/// Получает UI-сервис из текущего строителя.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockUIService"/> для выполнения платформенно-зависимых операций.
|
||||
/// </value>
|
||||
public static IDockUIService? UIService => _currentBuilder?.UIService;
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует фреймворк Lattice с указанными параметрами.
|
||||
/// </summary>
|
||||
/// <param name="options">
|
||||
/// Настройки инициализации. Если null, используются параметры по умолчанию.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="LatticeBuilder"/> для дальнейшей конфигурации фреймворка.
|
||||
/// </returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Выбрасывается, если фреймворк уже инициализирован.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// Этот метод должен вызываться один раз при запуске приложения, перед любыми
|
||||
/// попытками использования компонентов док-системы.
|
||||
/// </remarks>
|
||||
public static LatticeBuilder Initialize(LatticeOptions? options = null)
|
||||
{
|
||||
if (_isInitialized)
|
||||
@@ -121,11 +66,9 @@ public static class LatticeUIFramework
|
||||
|
||||
options ??= new LatticeOptions();
|
||||
|
||||
// Создаем основные компоненты Core-слоя
|
||||
var layoutManager = new LayoutManager();
|
||||
var contentRegistry = new ContentRegistry();
|
||||
|
||||
// Создаем строитель с основными компонентами
|
||||
_currentBuilder = new LatticeBuilder(layoutManager, contentRegistry, options);
|
||||
_isInitialized = true;
|
||||
|
||||
@@ -135,10 +78,6 @@ public static class LatticeUIFramework
|
||||
/// <summary>
|
||||
/// Сбрасывает состояние фреймворка к неинициализированному.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Используется в основном для целей тестирования. В рабочем приложении
|
||||
/// фреймворк должен инициализироваться один раз на протяжении жизненного цикла.
|
||||
/// </remarks>
|
||||
public static void Reset()
|
||||
{
|
||||
_isInitialized = false;
|
||||
@@ -148,54 +87,35 @@ public static class LatticeUIFramework
|
||||
|
||||
/// <summary>
|
||||
/// Представляет настройки инициализации фреймворка Lattice.
|
||||
/// Позволяет кастомизировать поведение системы при запуске.
|
||||
/// </summary>
|
||||
public class LatticeOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает или задает значение, указывающее, следует ли автоматически
|
||||
/// регистрировать стандартные команды (закрыть, сделать плавающим и т.д.).
|
||||
/// регистрировать стандартные команды.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, чтобы зарегистрировать стандартные команды; в противном случае — false.
|
||||
/// Значение по умолчанию: true.
|
||||
/// </value>
|
||||
public bool RegisterDefaultCommands { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает значение, указывающее, следует ли автоматически
|
||||
/// создавать сервисы при их первом запросе.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, чтобы автоматически создавать сервисы; в противном случае — false.
|
||||
/// Значение по умолчанию: true.
|
||||
/// </value>
|
||||
public bool AutoCreateServices { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает идентификатор приложения, используемый при
|
||||
/// сериализации макета для различения конфигураций разных приложений.
|
||||
/// Получает или задает идентификатор приложения.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Строковый идентификатор приложения или null, если идентификатор не задан.
|
||||
/// </value>
|
||||
public string? ApplicationId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает значение, указывающее, следует ли включить
|
||||
/// расширенное логирование операций системы.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, чтобы включить подробное логирование; в противном случае — false.
|
||||
/// Значение по умолчанию: false.
|
||||
/// </value>
|
||||
public bool EnableVerboseLogging { get; set; } = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Предоставляет fluent-интерфейс для конфигурации фреймворка Lattice.
|
||||
/// Инкапсулирует процесс настройки всех компонентов системы и обеспечивает
|
||||
/// согласованное состояние после инициализации.
|
||||
/// </summary>
|
||||
public sealed class LatticeBuilder
|
||||
{
|
||||
@@ -203,120 +123,59 @@ public sealed class LatticeBuilder
|
||||
private readonly ContentRegistry _contentRegistry;
|
||||
private readonly LatticeOptions _options;
|
||||
private IDockControlFactory? _controlFactory;
|
||||
private IDockDragDropService? _dragDropService;
|
||||
private IDockContextManager? _contextManager;
|
||||
private IDockUIService? _uiService;
|
||||
private bool _isBuilt;
|
||||
|
||||
/// <summary>
|
||||
/// Получает менеджер макета, связанный с этим строителем.
|
||||
/// Получает менеджер макета.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="LayoutManager"/> для управления структурой док-системы.
|
||||
/// </value>
|
||||
public LayoutManager LayoutManager => _layoutManager;
|
||||
|
||||
/// <summary>
|
||||
/// Получает реестр контента, связанный с этим строителем.
|
||||
/// Получает реестр контента.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="ContentRegistry"/> для регистрации типов контента.
|
||||
/// </value>
|
||||
public ContentRegistry ContentRegistry => _contentRegistry;
|
||||
|
||||
/// <summary>
|
||||
/// Получает фабрику контролов, связанную с этим строителем.
|
||||
/// Получает фабрику контролов.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockControlFactory"/> или null, если фабрика не задана.
|
||||
/// </value>
|
||||
public IDockControlFactory? ControlFactory => _controlFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Получает сервис перетаскивания, связанный с этим строителем.
|
||||
/// Получает менеджер контекстных меню.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockDragDropService"/> или null, если сервис не задан.
|
||||
/// </value>
|
||||
public IDockDragDropService? DragDropService => _dragDropService;
|
||||
|
||||
/// <summary>
|
||||
/// Получает менеджер контекстных меню, связанный с этим строителем.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockContextManager"/> или null, если менеджер не задан.
|
||||
/// </value>
|
||||
public IDockContextManager? ContextManager => _contextManager;
|
||||
|
||||
/// <summary>
|
||||
/// Получает UI-сервис, связанный с этим строителем.
|
||||
/// Получает UI-сервис.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Экземпляр <see cref="IDockUIService"/> или null, если сервис не задан.
|
||||
/// </value>
|
||||
public IDockUIService? UIService => _uiService;
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="LatticeBuilder"/>.
|
||||
/// </summary>
|
||||
/// <param name="layoutManager">Менеджер макета.</param>
|
||||
/// <param name="contentRegistry">Реестр контента.</param>
|
||||
/// <param name="options">Опции инициализации.</param>
|
||||
internal LatticeBuilder(LayoutManager layoutManager, ContentRegistry contentRegistry, LatticeOptions options)
|
||||
{
|
||||
_layoutManager = layoutManager ?? throw new ArgumentNullException(nameof(layoutManager));
|
||||
_contentRegistry = contentRegistry ?? throw new ArgumentNullException(nameof(contentRegistry));
|
||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
|
||||
_layoutManager.ContentRegistry = contentRegistry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Регистрирует фабрику контролов для создания UI-элементов.
|
||||
/// </summary>
|
||||
/// <param name="factory">
|
||||
/// Фабрика контролов, реализующая <see cref="IDockControlFactory"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Текущий экземпляр строителя для цепочки вызовов.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="factory"/> равен null.
|
||||
/// </exception>
|
||||
public LatticeBuilder WithControlFactory(IDockControlFactory factory)
|
||||
{
|
||||
_controlFactory = factory ?? throw new ArgumentNullException(nameof(factory));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Регистрирует сервис перетаскивания для управления операциями drag-and-drop.
|
||||
/// </summary>
|
||||
/// <param name="service">
|
||||
/// Сервис перетаскивания, реализующий <see cref="IDockDragDropService"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Текущий экземпляр строителя для цепочки вызовов.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="service"/> равен null.
|
||||
/// </exception>
|
||||
public LatticeBuilder WithDragDropService(IDockDragDropService service)
|
||||
{
|
||||
_dragDropService = service ?? throw new ArgumentNullException(nameof(service));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Регистрирует менеджер контекстных меню для управления контекстными действиями.
|
||||
/// </summary>
|
||||
/// <param name="manager">
|
||||
/// Менеджер контекстных меню, реализующий <see cref="IDockContextManager"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Текущий экземпляр строителя для цепочки вызовов.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="manager"/> равен null.
|
||||
/// </exception>
|
||||
public LatticeBuilder WithContextManager(IDockContextManager manager)
|
||||
{
|
||||
_contextManager = manager ?? throw new ArgumentNullException(nameof(manager));
|
||||
@@ -326,15 +185,6 @@ public sealed class LatticeBuilder
|
||||
/// <summary>
|
||||
/// Регистрирует UI-сервис для выполнения платформенно-зависимых операций.
|
||||
/// </summary>
|
||||
/// <param name="service">
|
||||
/// UI-сервис, реализующий <see cref="IDockUIService"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Текущий экземпляр строителя для цепочки вызовов.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="service"/> равен null.
|
||||
/// </exception>
|
||||
public LatticeBuilder WithUIService(IDockUIService service)
|
||||
{
|
||||
_uiService = service ?? throw new ArgumentNullException(nameof(service));
|
||||
@@ -342,20 +192,8 @@ public sealed class LatticeBuilder
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Регистрирует тип контента в реестре для последующего создания экземпляров.
|
||||
/// Регистрирует тип контента в реестре.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// Тип контента, реализующий <see cref="IDockContent"/>.
|
||||
/// </typeparam>
|
||||
/// <param name="contentTypeId">Уникальный идентификатор типа контента.</param>
|
||||
/// <param name="factory">Фабричный метод для создания экземпляров контента.</param>
|
||||
/// <param name="metadata">Метаданные типа контента (опционально).</param>
|
||||
/// <returns>
|
||||
/// Текущий экземпляр строителя для цепочки вызовов.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Выбрасывается, если <paramref name="contentTypeId"/> или <paramref name="factory"/> равны null.
|
||||
/// </exception>
|
||||
public LatticeBuilder RegisterContentType<T>(string contentTypeId, Func<T> factory, ContentMetadata? metadata = null)
|
||||
where T : Core.Docking.Abstractions.IDockContent
|
||||
{
|
||||
@@ -367,73 +205,76 @@ public sealed class LatticeBuilder
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Завершает конфигурацию и создает готовый к использованию док-хост.
|
||||
/// Завершает конфигурацию фреймворка.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="IDockHost"/>, настроенный в соответствии с текущей конфигурацией.
|
||||
/// </returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Выбрасывается, если не задана фабрика контролов или метод уже был вызван.
|
||||
/// </exception>
|
||||
public IDockHost Build()
|
||||
public ILatticeFramework Build()
|
||||
{
|
||||
if (_isBuilt)
|
||||
throw new InvalidOperationException("Builder has already been built.");
|
||||
throw new InvalidOperationException("Framework has already been built.");
|
||||
|
||||
if (_controlFactory == null)
|
||||
throw new InvalidOperationException("Control factory must be specified. Call WithControlFactory() first.");
|
||||
|
||||
// Автоматически создаем отсутствующие сервисы, если включена опция
|
||||
if (_options.AutoCreateServices)
|
||||
{
|
||||
_dragDropService ??= CreateDefaultDragDropService();
|
||||
_contextManager ??= CreateDefaultContextManager();
|
||||
_uiService ??= CreateDefaultUIService();
|
||||
}
|
||||
|
||||
// Создаем хост через фабрику
|
||||
// (предполагается, что фабрика имеет метод CreateDockHost)
|
||||
if (_controlFactory is WinUI.Factories.WinUIDockControlFactory winUIFactory)
|
||||
{
|
||||
var host = winUIFactory.CreateDockHost();
|
||||
|
||||
// Настраиваем хост
|
||||
host.LayoutManager = _layoutManager;
|
||||
host.DragDropService = _dragDropService;
|
||||
host.ContextManager = _contextManager;
|
||||
|
||||
_isBuilt = true;
|
||||
return host;
|
||||
}
|
||||
|
||||
throw new NotSupportedException($"Control factory of type {_controlFactory.GetType().Name} is not supported.");
|
||||
_isBuilt = true;
|
||||
return new LatticeFramework(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Предоставляет интерфейс для доступа к компонентам фреймворка Lattice.
|
||||
/// </summary>
|
||||
public interface ILatticeFramework
|
||||
{
|
||||
/// <summary>
|
||||
/// Получает менеджер макета.
|
||||
/// </summary>
|
||||
LayoutManager LayoutManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Создает сервис перетаскивания по умолчанию.
|
||||
/// Получает реестр контента.
|
||||
/// </summary>
|
||||
private IDockDragDropService CreateDefaultDragDropService()
|
||||
{
|
||||
// Реализация зависит от платформы
|
||||
// В реальном коде здесь должна быть проверка платформы
|
||||
return new WinUI.Services.WinUIDragDropService();
|
||||
}
|
||||
ContentRegistry ContentRegistry { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Создает менеджер контекстных меню по умолчанию.
|
||||
/// Получает фабрику контролов.
|
||||
/// </summary>
|
||||
private IDockContextManager CreateDefaultContextManager()
|
||||
{
|
||||
// Реализация зависит от платформы
|
||||
return new WinUI.Services.WinUIDockContextManager();
|
||||
}
|
||||
IDockControlFactory? ControlFactory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Создает UI-сервис по умолчанию.
|
||||
/// Получает менеджер контекстных меню.
|
||||
/// </summary>
|
||||
private IDockUIService CreateDefaultUIService()
|
||||
IDockContextManager? ContextManager { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает UI-сервис.
|
||||
/// </summary>
|
||||
IDockUIService? UIService { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Реализация интерфейса <see cref="ILatticeFramework"/>.
|
||||
/// </summary>
|
||||
internal class LatticeFramework : ILatticeFramework
|
||||
{
|
||||
private readonly LatticeBuilder _builder;
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр класса <see cref="LatticeFramework"/>.
|
||||
/// </summary>
|
||||
public LatticeFramework(LatticeBuilder builder)
|
||||
{
|
||||
// Реализация зависит от платформы
|
||||
return new WinUI.Services.WinUIDockUIService();
|
||||
_builder = builder ?? throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public LayoutManager LayoutManager => _builder.LayoutManager;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ContentRegistry ContentRegistry => _builder.ContentRegistry;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IDockControlFactory? ControlFactory => _builder.ControlFactory;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IDockContextManager? ContextManager => _builder.ContextManager;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IDockUIService? UIService => _builder.UIService;
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
using Lattice.Core.Geometry;
|
||||
using Lattice.UI.Docking.Abstractions;
|
||||
|
||||
namespace Lattice.UI.Docking.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Расширенная информация о перетаскивании для UI-слоя.
|
||||
/// Добавляет визуальные аспекты и UI-контекст к базовой информации о перетаскивании.
|
||||
/// </summary>
|
||||
public class UiDragInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Базовые данные перетаскивания.
|
||||
/// </summary>
|
||||
public Core.DragDrop.Models.DragInfo BaseDragInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// UI-контрол, который является источником перетаскивания.
|
||||
/// </summary>
|
||||
public IDockControl? SourceControl { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Визуальное представление перетаскиваемого элемента.
|
||||
/// </summary>
|
||||
public object? DragVisual { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Смещение курсора относительно элемента при начале перетаскивания.
|
||||
/// </summary>
|
||||
public Point VisualOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Размер визуального представления.
|
||||
/// </summary>
|
||||
public Size VisualSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Прозрачность визуального представления.
|
||||
/// </summary>
|
||||
public double VisualOpacity { get; set; } = 0.7;
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр <see cref="UiDragInfo"/>.
|
||||
/// </summary>
|
||||
public UiDragInfo(Core.DragDrop.Models.DragInfo baseDragInfo, IDockControl? sourceControl = null)
|
||||
{
|
||||
BaseDragInfo = baseDragInfo;
|
||||
SourceControl = sourceControl;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Расширенная информация о сбросе для UI-слоя.
|
||||
/// Добавляет визуальные подсказки и UI-контекст.
|
||||
/// </summary>
|
||||
public class UiDropInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Базовые данные сброса.
|
||||
/// </summary>
|
||||
public Core.DragDrop.Models.DropInfo BaseDropInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// UI-контрол, который является целью сброса.
|
||||
/// </summary>
|
||||
public IDockControl? TargetControl { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Позиция сброса относительно элемента.
|
||||
/// </summary>
|
||||
public DropPosition DropPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Визуальная подсказка для области сброса.
|
||||
/// </summary>
|
||||
public object? DropHintVisual { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Признак того, что курсор находится над допустимой областью сброса.
|
||||
/// </summary>
|
||||
public bool IsOverValidTarget { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Интенсивность подсветки области сброса (0.0 - 1.0).
|
||||
/// </summary>
|
||||
public double HighlightIntensity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр <see cref="UiDropInfo"/>.
|
||||
/// </summary>
|
||||
public UiDropInfo(Core.DragDrop.Models.DropInfo baseDropInfo, IDockControl? targetControl = null)
|
||||
{
|
||||
BaseDropInfo = baseDropInfo;
|
||||
TargetControl = targetControl;
|
||||
DropPosition = DropPosition.Center;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Определяет позицию сброса относительно элемента.
|
||||
/// </summary>
|
||||
public enum DropPosition
|
||||
{
|
||||
/// <summary> Слева от элемента. </summary>
|
||||
Left,
|
||||
|
||||
/// <summary> Справа от элемента. </summary>
|
||||
Right,
|
||||
|
||||
/// <summary> Сверху от элемента. </summary>
|
||||
Top,
|
||||
|
||||
/// <summary> Снизу от элемента. </summary>
|
||||
Bottom,
|
||||
|
||||
/// <summary> В центре элемента (для объединения вкладок). </summary>
|
||||
Center,
|
||||
|
||||
/// <summary> В виде новой вкладки. </summary>
|
||||
Tab
|
||||
}
|
||||
|
||||
|
||||
public class DragStartedEventArgs : EventArgs
|
||||
{
|
||||
public IDockControl? Source { get; }
|
||||
public Core.DragDrop.Models.DragInfo DragInfo { get; }
|
||||
// ... конструктор
|
||||
}
|
||||
|
||||
public class DragUpdatedEventArgs : EventArgs
|
||||
{
|
||||
public IDockControl? Source { get; }
|
||||
public double X { get; }
|
||||
public double Y { get; }
|
||||
public Core.DragDrop.Models.DragInfo DragInfo { get; }
|
||||
// ... конструктор
|
||||
}
|
||||
|
||||
public class DragCompletedEventArgs : EventArgs
|
||||
{
|
||||
public IDockControl? Source { get; }
|
||||
public IDockControl? Target { get; }
|
||||
public Models.DropPosition DropPosition { get; }
|
||||
public Core.DragDrop.Models.DragInfo? DragInfo { get; }
|
||||
public bool Success { get; }
|
||||
// ... конструктор
|
||||
}
|
||||
@@ -1,417 +0,0 @@
|
||||
using Lattice.Core.DragDrop.Abstractions;
|
||||
using Lattice.Core.DragDrop.Services;
|
||||
using Lattice.UI.Docking.Abstractions;
|
||||
using Lattice.UI.Docking.Models;
|
||||
|
||||
namespace Lattice.UI.Docking.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Реализация сервиса перетаскивания для UI-слоя док-системы.
|
||||
/// Координирует взаимодействие между базовым менеджером перетаскивания
|
||||
/// и UI-контролами, обеспечивая визуальную обратную связь.
|
||||
/// </summary>
|
||||
public class DockDragDropService : IDockDragDropService
|
||||
{
|
||||
private readonly DragDropManagerEx _dragDropManager;
|
||||
private readonly Dictionary<IDockControl, IDragSource> _registeredDragSources = new();
|
||||
private readonly Dictionary<IDockControl, IDropTarget> _registeredDropTargets = new();
|
||||
private UiDragInfo? _currentUiDragInfo;
|
||||
private UiDropInfo? _currentUiDropInfo;
|
||||
private IDropTarget? _lastDropTarget;
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр <see cref="DockDragDropService"/>.
|
||||
/// </summary>
|
||||
public DockDragDropService()
|
||||
{
|
||||
_dragDropManager = new DragDropManagerEx();
|
||||
HookEvents();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Инициализирует новый экземпляр с указанным менеджером перетаскивания.
|
||||
/// </summary>
|
||||
public DockDragDropService(DragDropManagerEx dragDropManager)
|
||||
{
|
||||
_dragDropManager = dragDropManager;
|
||||
HookEvents();
|
||||
}
|
||||
|
||||
private void HookEvents()
|
||||
{
|
||||
_dragDropManager.DragStarted += OnDragStarted;
|
||||
_dragDropManager.DragUpdated += OnDragUpdated;
|
||||
_dragDropManager.DragCompleted += OnDragCompleted;
|
||||
_dragDropManager.DragCancelled += OnDragCancelled;
|
||||
_dragDropManager.DropTargetChanged += OnDropTargetChanged;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RegisterDragSource(IDockControl element, IDragSource dragSource)
|
||||
{
|
||||
if (element == null) throw new ArgumentNullException(nameof(element));
|
||||
if (dragSource == null) throw new ArgumentNullException(nameof(dragSource));
|
||||
|
||||
_registeredDragSources[element] = dragSource;
|
||||
|
||||
// Регистрируем границы элемента в менеджере
|
||||
var bounds = CalculateBounds(element);
|
||||
_dragDropManager.RegisterDropTarget(dragSource as IDropTarget ?? new AdapterDropTarget(dragSource),
|
||||
bounds, 0, element.GetType().Name);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RegisterDropTarget(IDockControl element, IDropTarget dropTarget)
|
||||
{
|
||||
if (element == null) throw new ArgumentNullException(nameof(element));
|
||||
if (dropTarget == null) throw new ArgumentNullException(nameof(dropTarget));
|
||||
|
||||
_registeredDropTargets[element] = dropTarget;
|
||||
|
||||
var bounds = CalculateBounds(element);
|
||||
_dragDropManager.RegisterDropTarget(dropTarget, bounds, 0, element.GetType().Name);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void UnregisterDragSource(IDockControl element)
|
||||
{
|
||||
if (element == null) throw new ArgumentNullException(nameof(element));
|
||||
|
||||
_registeredDragSources.Remove(element);
|
||||
// TODO: Реализовать отмену регистрации в менеджере
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void UnregisterDropTarget(IDockControl element)
|
||||
{
|
||||
if (element == null) throw new ArgumentNullException(nameof(element));
|
||||
|
||||
_registeredDropTargets.Remove(element);
|
||||
// TODO: Реализовать отмену регистрации в менеджере
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void StartDrag(IDockControl element, Core.DragDrop.Models.DragInfo dragInfo)
|
||||
{
|
||||
if (element == null) throw new ArgumentNullException(nameof(element));
|
||||
if (dragInfo == null) throw new ArgumentNullException(nameof(dragInfo));
|
||||
|
||||
if (_registeredDragSources.TryGetValue(element, out var dragSource))
|
||||
{
|
||||
_currentUiDragInfo = new UiDragInfo(dragInfo, element);
|
||||
_dragDropManager.StartDrag(dragSource, dragInfo.StartPosition);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void UpdateDragVisual(double x, double y)
|
||||
{
|
||||
var position = new Core.DragDrop.Geometry.Point(x, y);
|
||||
_dragDropManager.UpdateDrag(position);
|
||||
|
||||
if (_currentUiDragInfo != null)
|
||||
{
|
||||
// Обновляем позицию визуального представления
|
||||
OnDragVisualUpdated?.Invoke(this, new DragVisualUpdatedEventArgs(
|
||||
_currentUiDragInfo, position));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void EndDrag(double x, double y)
|
||||
{
|
||||
var position = new Core.DragDrop.Geometry.Point(x, y);
|
||||
_dragDropManager.EndDrag(position);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CancelDrag()
|
||||
{
|
||||
_dragDropManager.CancelDrag();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ShowDropHint(IDockControl element, DropPosition position)
|
||||
{
|
||||
if (_currentUiDropInfo != null)
|
||||
{
|
||||
_currentUiDropInfo.DropPosition = position;
|
||||
_currentUiDropInfo.IsOverValidTarget = true;
|
||||
_currentUiDropInfo.HighlightIntensity = 0.8;
|
||||
|
||||
OnDropHintChanged?.Invoke(this, new DropHintEventArgs(
|
||||
element, position, true, _currentUiDropInfo.HighlightIntensity));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void HideDropHint()
|
||||
{
|
||||
if (_currentUiDropInfo != null)
|
||||
{
|
||||
_currentUiDropInfo.IsOverValidTarget = false;
|
||||
_currentUiDropInfo.HighlightIntensity = 0.0;
|
||||
|
||||
OnDropHintChanged?.Invoke(this, new DropHintEventArgs(
|
||||
_currentUiDropInfo.TargetControl,
|
||||
_currentUiDropInfo.DropPosition,
|
||||
false,
|
||||
0.0));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<DragStartedEventArgs>? DragStarted;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<DragUpdatedEventArgs>? DragUpdated;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler<DragCompletedEventArgs>? DragCompleted;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler? DragCancelled;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при обновлении визуального представления перетаскивания.
|
||||
/// </summary>
|
||||
public event EventHandler<DragVisualUpdatedEventArgs>? OnDragVisualUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Событие, возникающее при изменении визуальной подсказки сброса.
|
||||
/// </summary>
|
||||
public event EventHandler<DropHintEventArgs>? OnDropHintChanged;
|
||||
|
||||
private void OnDragStarted(object? sender, DragStartedEventArgs e)
|
||||
{
|
||||
// Обновляем UI-информацию
|
||||
if (_currentUiDragInfo != null)
|
||||
{
|
||||
_currentUiDragInfo.BaseDragInfo.StartPosition = e.StartPosition;
|
||||
|
||||
// Создаем визуальное представление
|
||||
CreateDragVisual(_currentUiDragInfo);
|
||||
|
||||
DragStarted?.Invoke(this, new DragStartedEventArgs(
|
||||
_currentUiDragInfo.SourceControl,
|
||||
_currentUiDragInfo.BaseDragInfo));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDragUpdated(object? sender, DragUpdatedEventArgs e)
|
||||
{
|
||||
if (_currentUiDragInfo != null)
|
||||
{
|
||||
// Обновляем позицию визуального представления
|
||||
UpdateDragVisualPosition(e.Position);
|
||||
|
||||
DragUpdated?.Invoke(this, new DragUpdatedEventArgs(
|
||||
_currentUiDragInfo.SourceControl,
|
||||
e.Position.X,
|
||||
e.Position.Y,
|
||||
_currentUiDragInfo.BaseDragInfo));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDragCompleted(object? sender, DragCompletedEventArgs e)
|
||||
{
|
||||
var targetControl = _currentUiDropInfo?.TargetControl;
|
||||
var dropPosition = _currentUiDropInfo?.DropPosition ?? DropPosition.Center;
|
||||
|
||||
DragCompleted?.Invoke(this, new DragCompletedEventArgs(
|
||||
_currentUiDragInfo?.SourceControl,
|
||||
targetControl,
|
||||
dropPosition,
|
||||
_currentUiDragInfo?.BaseDragInfo,
|
||||
e.Effects != Core.DragDrop.Enums.DragDropEffects.None));
|
||||
|
||||
// Очищаем визуальные представления
|
||||
CleanupDragVisual();
|
||||
CleanupDropHint();
|
||||
|
||||
_currentUiDragInfo = null;
|
||||
_currentUiDropInfo = null;
|
||||
_lastDropTarget = null;
|
||||
}
|
||||
|
||||
private void OnDragCancelled(object? sender, DragCancelledEventArgs e)
|
||||
{
|
||||
DragCancelled?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
CleanupDragVisual();
|
||||
CleanupDropHint();
|
||||
|
||||
_currentUiDragInfo = null;
|
||||
_currentUiDropInfo = null;
|
||||
_lastDropTarget = null;
|
||||
}
|
||||
|
||||
private void OnDropTargetChanged(object? sender, DropTargetChangedEventArgs e)
|
||||
{
|
||||
var dropTarget = e.Target;
|
||||
|
||||
// Обновляем UI-информацию о сбросе
|
||||
if (dropTarget != null)
|
||||
{
|
||||
// Находим соответствующий UI-контрол
|
||||
var targetControl = _registeredDropTargets
|
||||
.FirstOrDefault(kv => kv.Value == dropTarget)
|
||||
.Key;
|
||||
|
||||
_currentUiDropInfo = new UiDropInfo(
|
||||
new Core.DragDrop.Models.DropInfo(
|
||||
_dragDropManager.CurrentDragInfo?.Data,
|
||||
e.TargetBounds.Center,
|
||||
_dragDropManager.CurrentDragInfo?.AllowedEffects ?? Core.DragDrop.Enums.DragDropEffects.None,
|
||||
dropTarget),
|
||||
targetControl);
|
||||
|
||||
_currentUiDropInfo.DropPosition = CalculateDropPosition(
|
||||
_currentUiDragInfo?.BaseDragInfo.StartPosition ?? Core.DragDrop.Geometry.Point.Zero,
|
||||
e.TargetBounds);
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentUiDropInfo = null;
|
||||
}
|
||||
|
||||
// Уведомляем об изменении цели сброса
|
||||
if (_lastDropTarget != dropTarget)
|
||||
{
|
||||
if (_lastDropTarget != null)
|
||||
{
|
||||
HideDropHint();
|
||||
}
|
||||
|
||||
if (dropTarget != null && _currentUiDropInfo != null)
|
||||
{
|
||||
ShowDropHint(_currentUiDropInfo.TargetControl, _currentUiDropInfo.DropPosition);
|
||||
}
|
||||
|
||||
_lastDropTarget = dropTarget;
|
||||
}
|
||||
}
|
||||
|
||||
private Core.DragDrop.Geometry.Rect CalculateBounds(IDockControl element)
|
||||
{
|
||||
// В UI-реализациях этот метод должен быть переопределен
|
||||
// для вычисления реальных границ элемента на экране
|
||||
return new Core.DragDrop.Geometry.Rect(0, 0, 100, 100);
|
||||
}
|
||||
|
||||
private DropPosition CalculateDropPosition(Core.DragDrop.Geometry.Point cursorPos, Core.DragDrop.Geometry.Rect targetBounds)
|
||||
{
|
||||
// Простая логика определения позиции сброса
|
||||
var center = targetBounds.Center;
|
||||
var relativeX = (cursorPos.X - targetBounds.X) / targetBounds.Width;
|
||||
var relativeY = (cursorPos.Y - targetBounds.Y) / targetBounds.Height;
|
||||
|
||||
if (relativeX < 0.25) return DropPosition.Left;
|
||||
if (relativeX > 0.75) return DropPosition.Right;
|
||||
if (relativeY < 0.25) return DropPosition.Top;
|
||||
if (relativeY > 0.75) return DropPosition.Bottom;
|
||||
|
||||
return DropPosition.Center;
|
||||
}
|
||||
|
||||
private void CreateDragVisual(UiDragInfo dragInfo)
|
||||
{
|
||||
// В UI-реализациях этот метод должен создавать визуальное представление
|
||||
OnDragVisualUpdated?.Invoke(this, new DragVisualUpdatedEventArgs(
|
||||
dragInfo, dragInfo.BaseDragInfo.StartPosition));
|
||||
}
|
||||
|
||||
private void UpdateDragVisualPosition(Core.DragDrop.Geometry.Point position)
|
||||
{
|
||||
if (_currentUiDragInfo != null)
|
||||
{
|
||||
OnDragVisualUpdated?.Invoke(this, new DragVisualUpdatedEventArgs(
|
||||
_currentUiDragInfo, position));
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanupDragVisual()
|
||||
{
|
||||
// В UI-реализациях этот метод должен очищать визуальное представление
|
||||
OnDragVisualUpdated?.Invoke(this, new DragVisualUpdatedEventArgs(null, Core.DragDrop.Geometry.Point.Zero));
|
||||
}
|
||||
|
||||
private void CleanupDropHint()
|
||||
{
|
||||
HideDropHint();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Адаптер для преобразования IDragSource в IDropTarget.
|
||||
/// </summary>
|
||||
internal class AdapterDropTarget : IDropTarget
|
||||
{
|
||||
private readonly IDragSource _dragSource;
|
||||
|
||||
public AdapterDropTarget(IDragSource dragSource)
|
||||
{
|
||||
_dragSource = dragSource;
|
||||
}
|
||||
|
||||
public bool CanAcceptDrop(Core.DragDrop.Models.DropInfo dropInfo) => false;
|
||||
public void DragOver(Core.DragDrop.Models.DropInfo dropInfo) { }
|
||||
public void Drop(Core.DragDrop.Models.DropInfo dropInfo) { }
|
||||
public void DragLeave() { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Аргументы события обновления визуального представления перетаскивания.
|
||||
/// </summary>
|
||||
public class DragVisualUpdatedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Информация о перетаскивании.
|
||||
/// </summary>
|
||||
public UiDragInfo? DragInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Текущая позиция.
|
||||
/// </summary>
|
||||
public Core.DragDrop.Geometry.Point Position { get; }
|
||||
|
||||
public DragVisualUpdatedEventArgs(UiDragInfo? dragInfo, Core.DragDrop.Geometry.Point position)
|
||||
{
|
||||
DragInfo = dragInfo;
|
||||
Position = position;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Аргументы события изменения визуальной подсказки сброса.
|
||||
/// </summary>
|
||||
public class DropHintEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Целевой элемент.
|
||||
/// </summary>
|
||||
public IDockControl? Target { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Позиция сброса.
|
||||
/// </summary>
|
||||
public DropPosition Position { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Показывает, видима ли подсказка.
|
||||
/// </summary>
|
||||
public bool IsVisible { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Интенсивность подсветки.
|
||||
/// </summary>
|
||||
public double Intensity { get; }
|
||||
|
||||
public DropHintEventArgs(IDockControl? target, DropPosition position, bool isVisible, double intensity)
|
||||
{
|
||||
Target = target;
|
||||
Position = position;
|
||||
IsVisible = isVisible;
|
||||
Intensity = intensity;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Lattice.UI.Docking.Abstractions;
|
||||
// Lattice.UI.Docking\Services\DockUIServiceBase.cs
|
||||
using Lattice.UI.Docking.Abstractions;
|
||||
|
||||
namespace Lattice.UI.Docking.Services;
|
||||
|
||||
@@ -7,107 +8,21 @@ namespace Lattice.UI.Docking.Services;
|
||||
/// </summary>
|
||||
public abstract class DockUIServiceBase : IDockUIService
|
||||
{
|
||||
private IDockTheme? _currentTheme;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract object CreateMainWindow(IDockHost host);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual bool? ShowDialog(string title, object content)
|
||||
{
|
||||
// Базовая реализация - просто возвращает null
|
||||
// В производных классах должна быть реальная реализация
|
||||
return null;
|
||||
}
|
||||
public abstract bool? ShowDialog(string title, object content);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void ShowMessage(string message, string caption)
|
||||
{
|
||||
// Базовая реализация не делает ничего
|
||||
// В производных классах должна быть реальная реализация
|
||||
}
|
||||
public abstract void ShowMessage(string message, string caption);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual bool Confirm(string message, string caption)
|
||||
{
|
||||
// Базовая реализация всегда возвращает true
|
||||
// В производных классах должна быть реальная реализация
|
||||
return true;
|
||||
}
|
||||
public abstract bool Confirm(string message, string caption);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual string? Prompt(string prompt, string? defaultValue = null)
|
||||
{
|
||||
// Базовая реализация возвращает значение по умолчанию
|
||||
// В производных классах должна быть реальная реализация
|
||||
return defaultValue;
|
||||
}
|
||||
public abstract string? Prompt(string prompt, string? defaultValue = null);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void InvokeOnUIThread(Action action)
|
||||
{
|
||||
// Базовая реализация просто выполняет действие
|
||||
// В производных классах должна быть синхронизация с UI-потоком
|
||||
action?.Invoke();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual IDockTheme GetCurrentTheme()
|
||||
{
|
||||
return _currentTheme ?? CreateDefaultTheme();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void SetTheme(IDockTheme theme)
|
||||
{
|
||||
_currentTheme = theme;
|
||||
theme.Apply();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает тему по умолчанию.
|
||||
/// </summary>
|
||||
protected virtual IDockTheme CreateDefaultTheme()
|
||||
{
|
||||
return new DefaultDockTheme();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Тема оформления по умолчанию.
|
||||
/// </summary>
|
||||
public class DefaultDockTheme : IDockTheme
|
||||
{
|
||||
public string Name => "Default";
|
||||
public string BackgroundColor { get; set; } = "#1E1E1E";
|
||||
public string PanelBackgroundColor { get; set; } = "#252526";
|
||||
public string TabBackgroundColor { get; set; } = "#2D2D2D";
|
||||
public string ActiveTabBackgroundColor { get; set; } = "#3E3E3E";
|
||||
public string BorderColor { get; set; } = "#3F3F46";
|
||||
public string SplitterColor { get; set; } = "#2D2D2D";
|
||||
public string TextColor { get; set; } = "#CCCCCC";
|
||||
public string AccentColor { get; set; } = "#007ACC";
|
||||
public double CornerRadius { get; set; } = 3.0;
|
||||
public double BorderThickness { get; set; } = 1.0;
|
||||
public double SplitterWidth { get; set; } = 4.0;
|
||||
|
||||
public void Apply()
|
||||
{
|
||||
// В UI-реализациях этот метод должен применять тему к элементам
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
BackgroundColor = "#1E1E1E";
|
||||
PanelBackgroundColor = "#252526";
|
||||
TabBackgroundColor = "#2D2D2D";
|
||||
ActiveTabBackgroundColor = "#3E3E3E";
|
||||
BorderColor = "#3F3F46";
|
||||
SplitterColor = "#2D2D2D";
|
||||
TextColor = "#CCCCCC";
|
||||
AccentColor = "#007ACC";
|
||||
CornerRadius = 3.0;
|
||||
BorderThickness = 1.0;
|
||||
SplitterWidth = 4.0;
|
||||
}
|
||||
public abstract void InvokeOnUIThread(Action action);
|
||||
}
|
||||
@@ -34,21 +34,16 @@ public static class DockUtilities
|
||||
var control = factory.CreateControlForElement(element);
|
||||
if (control == null) return null;
|
||||
|
||||
// Устанавливаем родительский контрол
|
||||
if (parentControl != null)
|
||||
{
|
||||
// Здесь может быть установка дополнительных связей
|
||||
}
|
||||
|
||||
// Рекурсивно создаем дочерние контролы
|
||||
if (element is DockGroup group)
|
||||
if (element is DockGroup group && control is IDockGroupControl groupControl)
|
||||
{
|
||||
if (control is IDockGroupControl groupControl)
|
||||
{
|
||||
var firstChild = CreateControlForElement(group.First, factory, control);
|
||||
var secondChild = CreateControlForElement(group.Second, factory, control);
|
||||
groupControl.SetChildren(firstChild, secondChild);
|
||||
}
|
||||
var firstChild = CreateControlForElement(group.First, factory, control);
|
||||
var secondChild = CreateControlForElement(group.Second, factory, control);
|
||||
groupControl.SetChildren(firstChild, secondChild);
|
||||
}
|
||||
|
||||
return control;
|
||||
@@ -57,10 +52,9 @@ public static class DockUtilities
|
||||
/// <summary>
|
||||
/// Находит контрол для указанного элемента в дереве контролов.
|
||||
/// </summary>
|
||||
public static IDockControl? FindControlForElement(IDockControl root, IDockElement element)
|
||||
public static IDockControl? FindControlForElement(IDockControl? root, IDockElement element)
|
||||
{
|
||||
if (root == null) throw new ArgumentNullException(nameof(root));
|
||||
if (element == null) throw new ArgumentNullException(nameof(element));
|
||||
if (root == null || element == null) return null;
|
||||
|
||||
if (root.Model?.Id == element.Id)
|
||||
return root;
|
||||
@@ -88,6 +82,5 @@ public static class DockUtilities
|
||||
if (factory == null) throw new ArgumentNullException(nameof(factory));
|
||||
|
||||
// TODO: Реализовать эффективное обновление дерева контролов
|
||||
// вместо полной перестройки
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user