Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 44 additions & 28 deletions src/Dock.Avalonia/Internal/DockControlState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ private DockOperationResolution ResolveDockOperation(
isValid);
}

private void Drop(
private bool Drop(
Point point,
DragAction dragAction,
Control dropControl,
Expand All @@ -231,21 +231,21 @@ private void Drop(
{
if (selectedOperation == DockOperation.None)
{
return;
return false;
}

RemoveAdorners();

if (_context.DragControl is null || DropControl is null)
{
return;
return false;
}

if (useGlobalOperation)
{
if (DropControl is not { } dropCtrl)
{
return;
return false;
}

if (_context.DragControl.DataContext is IDockable sourceDockable
Expand All @@ -267,10 +267,11 @@ private void Drop(
var screenPixel = new PixelPoint((int)Math.Round(screenPoint.X), (int)Math.Round(screenPoint.Y));
var activePoint = active.PointToClient(screenPixel);
Float(activePoint, active, sourceDockable, factory, _context.DragOffset);
return true;
}
}
return;
}
}
return false;
}

// TODO: The validation fails in floating window as ActiveDockable is a tool dock.
// if (!ValidateGlobalTarget(sourceDockable, targetDock))
Expand All @@ -285,17 +286,18 @@ private void Drop(
sourceRoot,
targetRoot,
DockSettings.GlobalDockingProportion);
}
}
else
{
if (_context.DragControl.DataContext is IDockable sourceDockable)
{
var target = DropControl.DataContext as IDockable;
if (target is null)
{
return;
}
return true;
}
}
else
{
if (_context.DragControl.DataContext is IDockable sourceDockable)
{
var target = DropControl.DataContext as IDockable;
if (target is null)
{
return false;
}

if (!ValidateLocalTarget(sourceDockable, target))
{
Expand All @@ -304,21 +306,30 @@ private void Drop(
{
var activeDockControl = _context.DragControl.FindAncestorOfType<DockControl>();
var factory = activeDockControl?.Layout?.Factory ?? DropControl.FindAncestorOfType<DockControl>()?.Layout?.Factory;
if (activeDockControl is { } active && factory is { })
if (activeDockControl is { } active && factory is { })
{
var screenPoint = DockHelpers.GetScreenPoint(relativeTo, point);
var screenPixel = new PixelPoint((int)Math.Round(screenPoint.X), (int)Math.Round(screenPoint.Y));
var activePoint = active.PointToClient(screenPixel);
Float(activePoint, active, sourceDockable, factory, _context.DragOffset);
return true;
}
}
return;
}
}
return false;
}

Execute(point, selectedOperation, dragAction, relativeTo, sourceDockable, target);
}
}
}
if (selectedOperation == DockOperation.Window)
{
return false;
}

Execute(point, selectedOperation, dragAction, relativeTo, sourceDockable, target);
return true;
}
}

return false;
}

private void Leave()
{
Expand Down Expand Up @@ -547,8 +558,13 @@ public void Process(Point point, Vector delta, EventType eventType, DragAction d
selectedOperation = resolution.SelectedOperation;
}

Drop(_context.TargetPoint, dragAction, dropControl, _context.TargetDockControl, useGlobalOperation, selectedOperation);
executed = true;
executed = Drop(
_context.TargetPoint,
dragAction,
dropControl,
_context.TargetDockControl,
useGlobalOperation,
selectedOperation);
LogDragState($"Drop executed on '{dropControl.GetType().Name}' with action '{dragAction}'.");
}
else
Expand Down
30 changes: 24 additions & 6 deletions src/Dock.Avalonia/Internal/HostWindowState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ private void Over(Point point, DragAction dragAction, Control dropControl, Visua
LocalAdornerHelper.SetGlobalDockActive(globalOperation != DockOperation.None);
}

private void Drop(Point point, DragAction dragAction, Control dropControl, Visual relativeTo)
private bool Drop(Point point, DragAction dragAction, Control dropControl, Visual relativeTo)
{
var localOperation = DockOperation.Window;
var globalOperation = DockOperation.None;
Expand All @@ -120,7 +120,7 @@ private void Drop(Point point, DragAction dragAction, Control dropControl, Visua

if (DropControl is null)
{
return;
return false;
}

var layout = _hostWindow.Window?.Layout;
Expand All @@ -129,18 +129,19 @@ private void Drop(Point point, DragAction dragAction, Control dropControl, Visua
{
if (DropControl is not { } dropCtrl)
{
return;
return false;
}

if (layout?.ActiveDockable is { } sourceDockable
&& ResolveGlobalTargetDock(dropCtrl) is { } targetDock)
{
if (!ValidateGlobalTarget(sourceDockable, targetDock))
{
return;
return false;
}

Execute(point, globalOperation, dragAction, relativeTo, sourceDockable, targetDock);
return true;
}
}
else
Expand All @@ -151,9 +152,12 @@ private void Drop(Point point, DragAction dragAction, Control dropControl, Visua
if (localOperation != DockOperation.Window)
{
Execute(point, localOperation, dragAction, relativeTo, sourceDockable, targetDockable);
return true;
}
}
}

return false;
}

private void Leave()
Expand Down Expand Up @@ -327,6 +331,8 @@ public void Process(PixelPoint point, EventType eventType)
{
if (_context.DoDragDrop)
{
var executed = false;

if (_context.TargetDockControl is { } && DropControl is { })
{
var isDropEnabled = true;
Expand All @@ -338,9 +344,21 @@ public void Process(PixelPoint point, EventType eventType)

if (isDropEnabled)
{
Drop(_context.TargetPoint, _context.DragAction, DropControl, _context.TargetDockControl);
executed = Drop(_context.TargetPoint, _context.DragAction, DropControl, _context.TargetDockControl);
}
}
}

if (!executed
&& _hostWindow.DataContext is IDockable dockable
&& DockCapabilityResolver.IsEnabled(
dockable,
DockCapability.Float,
DockCapabilityResolver.ResolveOperationDock(dockable))
&& _hostWindow.Window?.Factory is { } factory)
{
dockable.SetPointerScreenPosition(point.X, point.Y);
factory.FloatDockable(dockable);
}
}

Leave();
Expand Down
29 changes: 24 additions & 5 deletions src/Dock.Avalonia/Internal/ManagedHostWindowState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ public void Process(PixelPoint screenPoint, EventType eventType)
{
if (_context.DoDragDrop)
{
var executed = false;

if (_context.TargetDockControl is { } && DropControl is { })
{
var isDropEnabled = true;
Expand All @@ -101,9 +103,22 @@ public void Process(PixelPoint screenPoint, EventType eventType)

if (isDropEnabled)
{
Drop(_context.TargetPoint, _context.DragAction, DropControl, _context.TargetDockControl);
executed = Drop(_context.TargetPoint, _context.DragAction, DropControl, _context.TargetDockControl);
}
}

if (!executed
&& _context.DragDockable is { } dockable
&& dockable is not ManagedDockWindowDocument
&& DockCapabilityResolver.IsEnabled(
dockable,
DockCapability.Float,
DockCapabilityResolver.ResolveOperationDock(dockable))
&& _hostWindow.Window?.Factory is { } factory)
{
dockable.SetPointerScreenPosition(screenPoint.X, screenPoint.Y);
factory.FloatDockable(dockable);
Comment on lines +110 to +120
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid floating managed docs on failed drag drops

When a managed host-window drag ends without a valid dock target (executed remains false), this new fallback calls factory.FloatDockable(dockable) on _context.DragDockable, which is resolved as a ManagedDockWindowDocument. In this codebase, FactoryBase.FloatDockable removes the dockable and depends on CreateWindowFrom to recreate it, but CreateWindowFrom has no ManagedDockWindowDocument case (see src/Dock.Model/FactoryBase.cs switch around lines 632-748), so the dockable can be removed from ManagedWindowDock and disappear after an invalid drop instead of simply staying where it was dragged.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
}

_dragPreviewHelper.Hide();
Expand Down Expand Up @@ -318,7 +333,7 @@ private void Over(Point point, DragAction dragAction, Control dropControl, Visua
LocalAdornerHelper.SetGlobalDockActive(globalOperation != DockOperation.None);
}

private void Drop(Point point, DragAction dragAction, Control dropControl, Visual relativeTo)
private bool Drop(Point point, DragAction dragAction, Control dropControl, Visual relativeTo)
{
var localOperation = DockOperation.Window;
var globalOperation = DockOperation.None;
Expand All @@ -337,7 +352,7 @@ private void Drop(Point point, DragAction dragAction, Control dropControl, Visua

if (DropControl is null)
{
return;
return false;
}

var layout = _hostWindow.Window?.Layout;
Expand All @@ -346,18 +361,19 @@ private void Drop(Point point, DragAction dragAction, Control dropControl, Visua
{
if (DropControl is not { } dropCtrl)
{
return;
return false;
}

if (layout?.ActiveDockable is { } sourceDockable
&& ResolveGlobalTargetDock(dropCtrl) is { } targetDock)
{
if (!ValidateGlobalTarget(sourceDockable, targetDock))
{
return;
return false;
}

Execute(point, globalOperation, dragAction, relativeTo, sourceDockable, targetDock);
return true;
}
}
else
Expand All @@ -368,9 +384,12 @@ private void Drop(Point point, DragAction dragAction, Control dropControl, Visua
if (localOperation != DockOperation.Window)
{
Execute(point, localOperation, dragAction, relativeTo, sourceDockable, targetDockable);
return true;
}
}
}

return false;
}

private void Leave()
Expand Down
Loading
Loading