Return the action the drag offered, not the one this row prefers

Slint negotiates a drag action between source and target, and the
runtime clamps whatever `can-drop` returns against the set the source
allowed: an action outside it becomes `none`. Both drop targets here
named a constant instead of echoing what was on offer, and each named
the wrong one for half its traffic.

A collection row takes two kinds of payload. Photographs come from a
DragArea allowing `copy`; a collection being nested comes from one
allowing `move`. The row asked for `copy` unconditionally, so images
filed correctly and every collection dropped on a collection was
refused — nesting by drag has never worked. The trash had the same
fault mirrored: it insisted on `move` while the grid's cells allow only
`copy`, so it refused every photograph dragged to it.

Neither failure had anything to see. A clamped action is delivered as a
refusal, which looks exactly like a target that declined on purpose, so
the drag simply did nothing and left no error to search for.

`decide_drop`'s Reparent branch was tested and passing throughout. It
tests the decision, not the negotiation, and nothing was reaching it.
This commit is contained in:
2026-09-07 19:59:44 +02:00
parent bac5801618
commit 577bbd82b0
2 changed files with 28 additions and 11 deletions
+24 -7
View File
@@ -127,12 +127,23 @@ component TreeRow inherits Rectangle {
if (!root.drop-allowed) {
return DragAction.none;
}
return DragAction.copy;
// The action the *source* offered, echoed back, rather than a
// constant. Two different things are dropped on this row — a
// selection of photographs, whose DragArea allows only `copy`, and
// a collection being nested, whose DragArea allows only `move` —
// and the runtime clamps whatever is returned here against the
// source's allowed set, treating anything outside it as `none`.
//
// So a hard-coded `copy` accepted images and *silently refused
// every collection*: nesting by drag could not work at all, and it
// failed with nothing to see, because an action clamped to `none`
// is indistinguishable from a target that simply said no.
return ev.proposed-action;
}
dropped(ev) => {
root.dropped();
return DragAction.copy;
return ev.proposed-action;
}
// Dwelling over a collapsed parent springs it open. Reported rather
@@ -642,13 +653,19 @@ export component CollectionsPanel inherits Rectangle {
trash-drop := DropArea {
width: 100%;
height: 100%;
// Deliberately `move`, where a collection drop is `copy`: this
// one really does take the photograph out of the library, and
// the cursor should say so.
can-drop(ev) => { return DragAction.move; }
// Echoed from the source, like the row above: the grid's
// cells allow `copy` alone, so the `move` this used to insist
// on was clamped to `none` and the trash refused every
// photograph dragged onto it.
//
// What this row does is destructive whatever the negotiated
// action is called — `dropped-on-trash` moves the file — so
// the name was never what made it so, and naming it cost the
// feature.
can-drop(ev) => { return ev.proposed-action; }
dropped(ev) => {
root.dropped-on-trash();
return DragAction.move;
return ev.proposed-action;
}
}