95 lines
2.9 KiB
C#
95 lines
2.9 KiB
C#
using CopaData.FileInspector.GUI.Models;
|
|
using System.Collections.ObjectModel;
|
|
using System.Collections.Specialized;
|
|
|
|
namespace CopaData.FileInspector.GUI.TilingPanels.Models;
|
|
|
|
/// <summary>
|
|
/// Host node that by paradigm is located only at the very end of the tree's branches.<br/>
|
|
/// Hosts may contain at least one central control, or multiple tabs of controls.<br/>
|
|
/// Note that tab contents must _not_ be any tiling controls, as that would break hierarchy and branching logic.<br/>
|
|
/// Everything above a <see cref="TilingHost"/> will be a <see cref="TilingPanel"/> by definition.
|
|
/// </summary>
|
|
public class TilingHost : TilingNode
|
|
{
|
|
public ObservableCollection<TilingFrame> Frames { get; } = [];
|
|
|
|
private TilingFrame? _activeFrame;
|
|
public TilingFrame? ActiveFrame
|
|
{
|
|
get => _activeFrame;
|
|
set => SetField(ref _activeFrame, value);
|
|
}
|
|
|
|
public bool ShowTabs => Frames.Count > 1;
|
|
|
|
public bool IsEmpty => Frames.Count == 0;
|
|
|
|
public TilingHost(params TilingFrame[] frames)
|
|
{
|
|
if (frames != null && frames.Length > 0)
|
|
{
|
|
Frames = new ObservableCollection<TilingFrame>(frames);
|
|
ActiveFrame = Frames[^1];
|
|
foreach (var frame in Frames)
|
|
{
|
|
frame.Parent = this;
|
|
}
|
|
}
|
|
|
|
Frames.CollectionChanged += OnFramesItemsChanged;
|
|
}
|
|
|
|
private void OnFramesItemsChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
|
{
|
|
if (e.NewItems != null && e.NewItems.Count > 0)
|
|
{
|
|
// Make the last item active
|
|
ActiveFrame = e.NewItems[^1] as TilingFrame;
|
|
foreach (var item in e.NewItems)
|
|
{
|
|
if (item is TilingFrame frame)
|
|
{
|
|
// We're using a reference here as this is the only place that always listens to updates.
|
|
frame.Parent = this;
|
|
}
|
|
}
|
|
}
|
|
else if (e.OldItems != null && e.OldItems.Count > 0)
|
|
{
|
|
if (ActiveFrame != null && !Frames.Contains(ActiveFrame))
|
|
{
|
|
// Previous active tab got removed, revert back to the most recent tab or set ActiveTab to null if tabs are empty.
|
|
if (Frames.Count > 0)
|
|
{
|
|
ActiveFrame = Frames[^1];
|
|
}
|
|
else
|
|
{
|
|
ActiveFrame = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Inserts <paramref name="newHost"/> into <paramref name="targetHost"/> as a new tab
|
|
/// after being dropped in the center region by the user.<br/>
|
|
/// If the previous host only had one frame inside it, it will be detached from its parent.
|
|
/// Otherwise, only the frame will be removed and inserted into <paramref name="targetHost"/>'s frames.
|
|
/// </summary>
|
|
public static void Insert(TilingPanel rootPanel, TilingHost targetHost, TilingFrame frame)
|
|
{
|
|
if (frame.Parent?.Frames.Count < 2)
|
|
{
|
|
TilingPanel.Detach(rootPanel, frame.Parent);
|
|
}
|
|
else
|
|
{
|
|
frame.Parent?.Frames.Remove(frame);
|
|
}
|
|
|
|
targetHost.Frames.Add(frame);
|
|
}
|
|
}
|