Say what the drag payload actually is: the arming, not the cargo
`drag-payload` was documented as "called when a drag starts, so it always reflects the selection as it is at that moment". Neither half is true, and the comment is the only reason anyone would believe the drop reads it. `DragArea` tests `data.is_empty()` in its event filter — on every pointer event, the first one included, which arrives long before there is a drag. And a Slint binding that calls a callback has no dependency to be invalidated on, so it is evaluated once, when a finger first lands on that cell, and cached for the life of the cell. What it answers is therefore always an empty selection. None of the drop handlers read it; every one of them reads `dragging`, which `drag-started` fills in at the moment that matters. What this callback does is keep the `DragArea` armed, and it manages that only because `set_user_data` is called unconditionally — an empty `Vec` is still user data. Guarding that call, which reads as an obvious tidy-up, would silently stop the grid dragging at all. Comments only. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1377,15 +1377,29 @@ export component LibraryGrid inherits Rectangle {
|
||||
/// selected. The name arrives from the sheet below rather than being
|
||||
/// invented by Rust and corrected afterwards — see `naming`.
|
||||
callback collection-from-selection(string);
|
||||
/// The drag payload: the selected image ids, wrapped by Rust. Called when a
|
||||
/// drag starts, so it always reflects the selection as it is at that moment.
|
||||
/// **What arms the drag, not what it carries.**
|
||||
///
|
||||
/// `DragArea` refuses to begin a drag while its `data` is empty, and it
|
||||
/// asks on every pointer event — including the first one, long before
|
||||
/// anything is being dragged. A binding that calls a callback is evaluated
|
||||
/// once and cached, because there is nothing for Slint to invalidate it on,
|
||||
/// so whatever this answers the first time a finger touches a cell is what
|
||||
/// that cell's `DragArea` believes for the rest of its life.
|
||||
///
|
||||
/// It is therefore *not* the payload the drop reads, whatever it looks
|
||||
/// like: what travels is `dragging` in `collections_ui`, recorded by
|
||||
/// `drag-started` and read back by `dropped-on`. See the Rust side for why
|
||||
/// this has to answer something non-empty unconditionally.
|
||||
pure callback drag-payload() -> data-transfer;
|
||||
/// What travels under the cursor: the dragged thumbnail, or a fanned stack
|
||||
/// of them where several are being carried. Composited in Rust, because
|
||||
/// Slint accepts one bitmap here and cannot draw a pile of images into it.
|
||||
in property <image> drag-image;
|
||||
/// A drag began on this cell. Lets Rust promote an unselected cell to the
|
||||
/// selection before the payload is read.
|
||||
/// A drag began on this cell.
|
||||
///
|
||||
/// This, not `drag-payload`, is where what the drag carries is decided: it
|
||||
/// fires with the selection as it stands at the moment the drag starts, and
|
||||
/// lets Rust promote an unselected cell into the selection first.
|
||||
callback drag-started(int);
|
||||
/// The drag ended — dropped or cancelled. Clears the transient UI state.
|
||||
callback drag-finished();
|
||||
@@ -2901,6 +2915,7 @@ export component LibraryGrid inherits Rectangle {
|
||||
// is what a join table means, and it is why the modifier-free
|
||||
// gesture must not be `move`.
|
||||
allow-copy: true;
|
||||
// Not the payload — the arming. See `drag-payload`.
|
||||
data: root.drag-payload();
|
||||
// What travels under the cursor is the photograph itself — and
|
||||
// where several are being dragged, a stack of them. Composited
|
||||
|
||||
Reference in New Issue
Block a user