From 892da2662ab4bf1d361d7d335811f02a1fd732e7 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Fri, 21 Aug 2026 20:29:10 +0200 Subject: [PATCH] Keep the stars on screen long enough to click one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rating strip was a sibling of the cell's TouchArea, declared after it so that hit-testing reached the stars first. That half worked: a star click set a rating without also opening the image. The other half did not. Hover is tracked per TouchArea, and Slint sends `Exit` to any item that drops out of the hit path. The strip taking the pointer is exactly that — `cell-touch` left the path, `has-hover` went false, and `show-empty` went with it. On an unrated cell the stars are drawn *only* on hover, so they vanished as the pointer arrived at them; the click then landed on the cell behind and opened the image. Reported as "the star menu disappears when I click on an image", which is precisely what it does. Nesting the strip inside `cell-touch` keeps both halves. Children are hit-tested before the element containing them, so a star still wins the click and still ends the walk before `cell-clicked` runs. And an ancestor stays on the item stack: it gets no `Exit`, and while a child holds the grab it is handed the event filter and never the event. Hover therefore holds for as long as the pointer is anywhere in the cell. --- ui/dr-ui/ui/library.slint | 81 ++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 30 deletions(-) diff --git a/ui/dr-ui/ui/library.slint b/ui/dr-ui/ui/library.slint index cb29e7e..0f970f3 100644 --- a/ui/dr-ui/ui/library.slint +++ b/ui/dr-ui/ui/library.slint @@ -1907,37 +1907,58 @@ export component LibraryGrid inherits Rectangle { // is why the toggling is idempotent-by-union in Rust // rather than this file trying to swallow one of them. double-clicked => { root.cell-double-clicked(i); } - } - // --- the rating strip, ABOVE the cell's own hit area --- - // - // **Declared after `cell-touch` on purpose.** Slint hit-tests - // later siblings first, so a strip nested inside the layout - // above was underneath the cell-wide TouchArea: the click set - // a rating *and* fell through to `cell-clicked`, which threw - // the user into develop on every star press. Z-order is the - // whole fix — there is no "handled" flag to set, and adding a - // travel threshold or a timer would be faking arbitration - // Slint already does correctly once the order is right. - // - // It sits over the foot of the thumbnail rather than below it: - // the caption row is spoken for by the filename, and a third - // row would cost thumbnail height on every cell to show - // something that is usually empty. - StarStrip { - x: (parent.width - self.width) / 2; - // Clear of the caption, which is the cell's last row. - y: parent.height - self.height - 26px; - rating: cell.rating; - // Empty stars appear once the pointer is over the cell, - // so there is something to aim at without filling the - // grid with chrome. On touch there is no hover, so the - // strip is always present where a rating exists — and a - // long-press is not needed to discover it. - show-empty: cell-touch.has-hover; - can-trash: !root.viewing-trash; - rate(n) => { root.cell-rated(i, n); } - trash() => { root.cell-trashed(i); } + // --- the rating strip, INSIDE the cell's hit area --- + // + // **A child of `cell-touch`, not a sibling of it.** Two + // things have to be true at once here, and only this + // nesting gets both. + // + // A star must take the click without it also reaching + // `cell-clicked`, or every rating throws the user into + // develop. Children are hit-tested before the element + // they sit in, and a child that accepts ends the walk + // before the TouchArea's own handler runs — so the star + // wins, and it wins for the same reason a later sibling + // used to. + // + // And the strip must not vanish as the pointer arrives + // at it. As a *sibling* it did: hover is tracked per + // TouchArea, Slint sends `Exit` to whatever drops out of + // the hit path, and the strip taking the pointer dropped + // `cell-touch` out of it. `has-hover` went false, which + // took `show-empty` with it, which hid the very stars + // the pointer was travelling towards — on an unrated + // cell they disappeared, the click landed on the cell + // behind them, and the image opened. That is the whole + // of the "stars vanish when I click one" report. + // + // An *ancestor* stays in the path: it keeps its place on + // the item stack, gets no `Exit`, and during a grab it is + // handed only the filter and never the event. So hover + // holds for as long as the pointer is anywhere in the + // cell, stars included. + // + // It sits over the foot of the thumbnail rather than + // below it: the caption row is spoken for by the + // filename, and a third row would cost thumbnail height + // on every cell to show something that is usually empty. + StarStrip { + x: (parent.width - self.width) / 2; + // Clear of the caption, which is the cell's last row. + y: parent.height - self.height - 26px; + rating: cell.rating; + // Empty stars appear once the pointer is over the + // cell, so there is something to aim at without + // filling the grid with chrome. On touch there is no + // hover, so the strip is always present where a + // rating exists — and a long-press is not needed to + // discover it. + show-empty: cell-touch.has-hover; + can-trash: !root.viewing-trash; + rate(n) => { root.cell-rated(i, n); } + trash() => { root.cell-trashed(i); } + } } } }