using System; using System.Text.Json.Nodes; using System.Threading.Tasks; using Avalonia; using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Threading; using Dock.Avalonia.Controls; using Dock.Model; using Dock.Model.Core; using Dock.Serializer; using StabilityMatrix.Avalonia.Models.Inference; using StabilityMatrix.Avalonia.ViewModels.Base; namespace StabilityMatrix.Avalonia.Controls.Dock; /// /// Base for Dock controls /// Expects a named "Dock" in the XAML /// public abstract class DockUserControlBase : DropTargetUserControlBase { private DockControl? baseDock; private readonly DockSerializer dockSerializer = new(typeof(AvaloniaList<>)); private readonly DockState dockState = new(); /// protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); baseDock = this.FindControl("Dock") ?? throw new NullReferenceException("DockControl not found"); if (baseDock.Layout is { } layout) { dockState.Save(layout); // Dispatcher.UIThread.Post(() => dockState.Save(layout), DispatcherPriority.Background); } } /// protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); // Attach handlers for view state saving and loading if (DataContext is InferenceTabViewModelBase vm) { vm.SaveViewStateRequested += DataContext_OnSaveViewStateRequested; vm.LoadViewStateRequested += DataContext_OnLoadViewStateRequested; } } /// protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { base.OnDetachedFromVisualTree(e); // Detach handlers for view state saving and loading if (DataContext is InferenceTabViewModelBase vm) { vm.SaveViewStateRequested -= DataContext_OnSaveViewStateRequested; vm.LoadViewStateRequested -= DataContext_OnLoadViewStateRequested; } } private void DataContext_OnSaveViewStateRequested(object? sender, SaveViewStateEventArgs args) { var saveTcs = new TaskCompletionSource(); Dispatcher.UIThread.Post(() => { var state = new ViewState { DockLayout = SaveDockLayout() }; saveTcs.SetResult(state); }); args.StateTask ??= saveTcs.Task; } private void DataContext_OnLoadViewStateRequested(object? sender, LoadViewStateEventArgs args) { if (args.State?.DockLayout is { } layout) { // Provided LoadDockLayout(layout); } else { // Restore default RestoreDockLayout(); } } private void LoadDockLayout(JsonObject data) { LoadDockLayout(data.ToJsonString()); } private void LoadDockLayout(string data) { if (baseDock is null) return; if (dockSerializer.Deserialize(data) is { } layout) { baseDock.Layout = layout; } } private void RestoreDockLayout() { // TODO: idk this doesn't work if (baseDock?.Layout != null) { dockState.Restore(baseDock.Layout); } } protected string? SaveDockLayout() { return baseDock is null ? null : dockSerializer.Serialize(baseDock.Layout); } }