89 lines
3.6 KiB
C#
89 lines
3.6 KiB
C#
using Lattice.Core.Docking.Abstractions;
|
||
using Lattice.Core.Docking.Models;
|
||
|
||
namespace Lattice.Core.Docking.Engine;
|
||
|
||
/// <summary>
|
||
/// Статический движок для манипуляции иерархией дерева компоновки.
|
||
/// Содержит чистые алгоритмы трансформации графа.
|
||
/// </summary>
|
||
public static class DockOperations
|
||
{
|
||
/// <summary>
|
||
/// Извлекает элемент из дерева. Если родительская группа остается с одним ребенком,
|
||
/// она удаляется, а ребенок занимает её место.
|
||
/// </summary>
|
||
/// <param name="element">Элемент для удаления.</param>
|
||
/// <param name="root">Текущий корень дерева.</param>
|
||
/// <returns>Новый корень дерева после оптимизации.</returns>
|
||
public static IDockElement? Remove(IDockElement element, IDockElement root)
|
||
{
|
||
if (element == root) return null;
|
||
|
||
var parent = element.Parent as DockGroup;
|
||
if (parent == null) return root;
|
||
|
||
// Определяем "выжившего" соседа
|
||
var sibling = (parent.First == element) ? parent.Second : parent.First;
|
||
var grandParent = parent.Parent as DockGroup;
|
||
|
||
if (grandParent != null)
|
||
{
|
||
// Переподключаем соседа напрямую к дедушке
|
||
if (grandParent.First == parent) grandParent.First = sibling;
|
||
else grandParent.Second = sibling;
|
||
|
||
sibling.Parent = grandParent;
|
||
return root;
|
||
}
|
||
|
||
// Если дедушки нет, сосед становится новым корнем
|
||
sibling.Parent = null;
|
||
return sibling;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Вставляет элемент в дерево, создавая новую группу разделения или объединяя контент.
|
||
/// </summary>
|
||
public static IDockElement Insert(IDockElement target, IDockElement source, DockPosition pos, IDockElement root)
|
||
{
|
||
// Случай 1: Объединение вкладок в центре
|
||
if (pos == DockPosition.Center)
|
||
{
|
||
if (target is IDockContainer targetContainer && source is IDockContainer sourceContainer)
|
||
{
|
||
var items = new List<IDockContent>(sourceContainer.Children);
|
||
foreach (var item in items)
|
||
{
|
||
sourceContainer.RemoveContent(item);
|
||
targetContainer.AddContent(item);
|
||
}
|
||
}
|
||
return root;
|
||
}
|
||
|
||
// Случай 2: Разделение (Split)
|
||
var direction = (pos == DockPosition.Left || pos == DockPosition.Right)
|
||
? SplitDirection.Horizontal : SplitDirection.Vertical;
|
||
|
||
bool sourceIsFirst = (pos == DockPosition.Left || pos == DockPosition.Top);
|
||
|
||
var oldParent = target.Parent;
|
||
|
||
// Создаем новую группу. Источник и цель делят пространство 50/50
|
||
var newGroup = sourceIsFirst
|
||
? new DockGroup(source, target, direction) { SplitRatio = 0.5 }
|
||
: new DockGroup(target, source, direction) { SplitRatio = 0.5 };
|
||
|
||
if (oldParent is DockGroup gp)
|
||
{
|
||
if (gp.First == target) gp.First = newGroup;
|
||
else gp.Second = newGroup;
|
||
newGroup.Parent = gp;
|
||
return root;
|
||
}
|
||
|
||
newGroup.Parent = null;
|
||
return newGroup; // Новая группа стала корнем
|
||
}
|
||
} |