fix(dock): complete tear-off flow and add rollback on failure
This commit is contained in:
@@ -306,20 +306,23 @@ public sealed partial class DockLayout : Control
|
|||||||
{
|
{
|
||||||
DockMutationEngine.CleanupEmptyNodes(_sourceNode);
|
DockMutationEngine.CleanupEmptyNodes(_sourceNode);
|
||||||
|
|
||||||
// Raise event to let the host handle window creation
|
try
|
||||||
TabTornOff?.Invoke(this, new TabTornOffEventArgs(_draggedItem));
|
{
|
||||||
|
// Raise event to let the host handle window creation
|
||||||
|
TabTornOff?.Invoke(this, new TabTornOffEventArgs(_draggedItem));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Rollback: Re-insert the item if the tear-off handler fails
|
||||||
|
_sourceNode.Items.Add(_draggedItem);
|
||||||
|
Logger.LogError($"Failed to tear off tab: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearDragOperationState();
|
ClearDragOperationState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TabTornOffEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public object TabContent { get; }
|
|
||||||
public TabTornOffEventArgs(object tabContent) => TabContent = tabContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
private object? _draggedItem;
|
private object? _draggedItem;
|
||||||
private DockPanelNode? _sourceNode;
|
private DockPanelNode? _sourceNode;
|
||||||
private DockPosition _currentDropPosition = DockPosition.None;
|
private DockPosition _currentDropPosition = DockPosition.None;
|
||||||
|
|||||||
17
src/Editor/Ghost.Editor/View/Controls/TabTornOffEventArgs.cs
Normal file
17
src/Editor/Ghost.Editor/View/Controls/TabTornOffEventArgs.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
namespace Ghost.Editor.View.Controls;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event arguments for the TabTornOff event.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class TabTornOffEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the content of the tab being torn off.
|
||||||
|
/// </summary>
|
||||||
|
public object TabContent { get; }
|
||||||
|
|
||||||
|
public TabTornOffEventArgs(object tabContent)
|
||||||
|
{
|
||||||
|
TabContent = tabContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Ghost.Editor.Core.Controls.Internal.Docking;
|
using Ghost.Editor.Core.Controls.Internal.Docking;
|
||||||
|
using Ghost.Editor.View.Controls;
|
||||||
using WinUIEx;
|
using WinUIEx;
|
||||||
|
|
||||||
namespace Ghost.Editor.View.Windows;
|
namespace Ghost.Editor.View.Windows;
|
||||||
@@ -16,5 +17,13 @@ internal sealed partial class DockWindow : WindowEx
|
|||||||
rootGroup.AddChild(panel);
|
rootGroup.AddChild(panel);
|
||||||
|
|
||||||
PART_DockLayout.Root = rootGroup;
|
PART_DockLayout.Root = rootGroup;
|
||||||
|
PART_DockLayout.TabTornOff += OnTabTornOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTabTornOff(object? sender, TabTornOffEventArgs e)
|
||||||
|
{
|
||||||
|
var newWindow = new DockWindow(e.TabContent);
|
||||||
|
App.AddSecondaryWindow(newWindow);
|
||||||
|
newWindow.Activate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Ghost.Editor.Core;
|
using Ghost.Editor.Core;
|
||||||
using Ghost.Editor.Core.Contracts;
|
using Ghost.Editor.Core.Contracts;
|
||||||
using Ghost.Editor.Core.Services;
|
using Ghost.Editor.Core.Services;
|
||||||
|
using Ghost.Editor.View.Controls;
|
||||||
using Ghost.Editor.ViewModels.Windows;
|
using Ghost.Editor.ViewModels.Windows;
|
||||||
using Windows.ApplicationModel;
|
using Windows.ApplicationModel;
|
||||||
using WinUIEx;
|
using WinUIEx;
|
||||||
@@ -34,6 +35,17 @@ internal sealed partial class EngineEditorWindow : WindowEx
|
|||||||
|
|
||||||
SetTitleBar(PART_TitleBar);
|
SetTitleBar(PART_TitleBar);
|
||||||
this.CenterOnScreen();
|
this.CenterOnScreen();
|
||||||
|
|
||||||
|
// Note: DockLayout is not directly in the XAML but created by RenderTree.
|
||||||
|
// However, we can subscribe to the event if we find it or if it's exposed.
|
||||||
|
// Since DockLayout is a TemplatePart or child of a Grid, we might need to wait for it.
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTabTornOff(object? sender, TabTornOffEventArgs e)
|
||||||
|
{
|
||||||
|
var newWindow = new DockWindow(e.TabContent);
|
||||||
|
App.AddSecondaryWindow(newWindow);
|
||||||
|
newWindow.Activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MainGrid_Loaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
private void MainGrid_Loaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||||
|
|||||||
Reference in New Issue
Block a user