Fix gallery navigation: arrow keys, cursor stuck past ChoiceButton, scroll bounce

This commit is contained in:
Ryan Hughes
2026-05-18 01:57:26 -04:00
parent 54da1a90ab
commit 7cdf35e462
2 changed files with 20 additions and 24 deletions
@@ -20,15 +20,16 @@ import QtQuick
// } // }
// } // }
// //
// Keys.priority: Keys.AfterItem means a focused descendant (e.g. a // Keys.priority: Keys.BeforeItem means this handler gets keys first,
// TextField inside an inline password prompt) gets the event first. Only // even when a descendant has activeFocus. That's what lets Up/Down
// events the focused subtree ignores reach this handler — that's what // arrows drive the cursor instead of being consumed by an inner
// lets j/k/Esc keep working in the panel while an input field consumes // Flickable's built-in scroll handling. When a panel has an inline
// typing. // editor (wifi passphrase, gallery TextField demo) the panel must
// set `blocked: editor.activeFocus` so this handler short-circuits
// and the editor receives keys normally.
// //
// blocked: when true, ALL keys are forwarded to descendants without // blocked: when true, ALL keys are forwarded to descendants without
// triggering signals. Useful when an inline editor is open and the // triggering signals.
// caller wants the cursor model frozen.
Item { Item {
id: root id: root
@@ -41,7 +42,7 @@ Item {
signal textKey(string text) signal textKey(string text)
focus: true focus: true
Keys.priority: Keys.AfterItem Keys.priority: Keys.BeforeItem
Keys.onPressed: function(event) { Keys.onPressed: function(event) {
if (blocked) return if (blocked) return
@@ -232,22 +232,17 @@ Item {
// hasCursor change handler of every cursor target below. // hasCursor change handler of every cursor target below.
function ensureCursorVisible(item) { function ensureCursorVisible(item) {
if (!item || !scrollArea) return if (!item || !scrollArea) return
var sb = scrollArea.ScrollBar.vertical var flick = scrollArea.contentItem
if (!sb || scrollArea.contentHeight <= scrollArea.height) return if (!flick || flick.contentY === undefined) return
var contentItem = scrollArea.contentItem var pt = item.mapToItem(flick.contentItem || flick, 0, 0)
if (!contentItem) return var top = pt.y
var p = item.mapToItem(contentItem, 0, 0) var bottom = top + (item.height || 0)
var itemTop = p.y var viewTop = flick.contentY
var itemBottom = p.y + item.height var viewBottom = viewTop + flick.height
var viewTop = sb.position * scrollArea.contentHeight var margin = 12
var viewBottom = viewTop + scrollArea.height if (top < viewTop + margin) flick.contentY = Math.max(0, top - margin)
var pad = 20 else if (bottom > viewBottom - margin)
if (itemTop < viewTop + pad) { flick.contentY = bottom + margin - flick.height
sb.position = Math.max(0, (itemTop - pad) / scrollArea.contentHeight)
} else if (itemBottom > viewBottom - pad) {
var newPos = (itemBottom + pad - scrollArea.height) / scrollArea.contentHeight
sb.position = Math.max(0, Math.min(1 - sb.size, newPos))
}
} }
FloatingWindow { FloatingWindow {