feat(qt): search boxes clear on Escape, drop focus, and offer a clear cross
Every search field follows one contract: Escape empties the text AND hands the keyboard back to the shell root, and a clickable cross clears the text while keeping the caret in the field. The header search shows the cross left of the Enter glyph while the cortinilla is open; QbzLineEdit's search mode and the new QbzSearchField (the album track filter and the playlist filter) float it at the right edge. Each field also keeps its focus after an edit unless another text input took it, and logs when it had to reclaim it. cc
This commit is contained in:
1 parent
e546e6614e
commit
b868319233
6 files changed
+245
-73
No files matched your search
@@ -942,6 +942,24 @@ Rectangle {
|
||||
function focusSearch() {
|
||||
searchInput.forceActiveFocus()
|
||||
}
|
||||
// FOCUS RETENTION (2026-09-13, every search box): after an edit, once the
|
||||
// event loop settles, reclaim the keyboard unless another text input took
|
||||
// it — the dropdown opening or closing must never steal it mid-word.
|
||||
property bool _searchReclaim: false
|
||||
function _reclaimSearchFocus() {
|
||||
if (!root._searchReclaim)
|
||||
return
|
||||
root._searchReclaim = false
|
||||
if (searchInput.activeFocus)
|
||||
return
|
||||
var win = root.Window.window
|
||||
var current = win ? win.activeFocusItem : null
|
||||
if (current instanceof TextInput || current instanceof TextEdit)
|
||||
return
|
||||
console.log("[HeaderBar] search lost focus after an edit; reclaimed (holder was "
|
||||
+ (current ? current.toString() : "none") + ")")
|
||||
searchInput.forceActiveFocus()
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: searchBox
|
||||
@@ -1001,7 +1019,11 @@ Rectangle {
|
||||
QbzSearch.searchLive(text)
|
||||
}
|
||||
}
|
||||
onTextEdited: applyLiveQuery()
|
||||
onTextEdited: {
|
||||
applyLiveQuery()
|
||||
root._searchReclaim = true
|
||||
Qt.callLater(root._reclaimSearchFocus)
|
||||
}
|
||||
|
||||
// The Enter rule (HeaderBar.slint on-enter): cortinilla open +
|
||||
// a keyboard selection -> activate the row; open + none -> full
|
||||
@@ -1045,8 +1067,9 @@ Rectangle {
|
||||
// the modals use, not merely cleared: a null
|
||||
// activeFocusItem passes the gate but leaves AppShell's
|
||||
// Keys handler receiving nothing at all.
|
||||
if (QbzSearch.cortinillaOpen)
|
||||
QbzSearch.cortinillaDismiss()
|
||||
// …and it empties the box too (2026-09-13, every search
|
||||
// box): clearSearch() drops the text and the dropdown.
|
||||
root.clearSearch()
|
||||
event.accepted = true
|
||||
var p = searchInput
|
||||
while (p.parent) {
|
||||
@@ -1078,6 +1101,7 @@ Rectangle {
|
||||
// open (Slint: it lives in the box, opposite the magnifier), else
|
||||
// the × clear.
|
||||
Text {
|
||||
id: enterHint
|
||||
visible: QbzSearch.cortinillaOpen
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 10
|
||||
@@ -1087,10 +1111,13 @@ Rectangle {
|
||||
font.pixelSize: 12
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
// The clear cross: always there while there is text (2026-09-13); it
|
||||
// sits to the LEFT of the ↵ hint while the dropdown is open, at the
|
||||
// right edge otherwise.
|
||||
Rectangle {
|
||||
visible: !QbzSearch.cortinillaOpen && searchInput.text !== ""
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 5
|
||||
visible: searchInput.text !== ""
|
||||
anchors.right: QbzSearch.cortinillaOpen ? enterHint.left : parent.right
|
||||
anchors.rightMargin: QbzSearch.cortinillaOpen ? 4 : 5
|
||||
width: 22
|
||||
height: 22
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Reference in new issue
Block a user