qamp/Qrakhen.TilingFrames/Models/TilingHost.cs

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