feat(qt): the sidebar's playlist and My QBZ filters follow the search-box contract

Both inline fields were bare TextInputs: no clear cross, no Escape.
They are QbzSearchField now — Escape empties the filter, hands the
keyboard back and folds the field into its title; the cross empties it
and keeps the caret. The control grew what a 22px header row needs: an
optional leading glyph (the toggle already shows one), a cross sized to
the field, and an `escaped` signal for hosts that fold the field away.

cc
This commit is contained in:
vicrodh committed 2026-09-14 00:49:54 -06:00
1 parent a564ed936b
commit 3d4d3bc6ed
2 files changed
+47 -67

No files matched your search

+17 -7
View File
@@ -22,6 +22,14 @@ Rectangle {
property alias text: input.text
property string placeholder: ""
/// The leading magnifier; off for hosts whose own toggle already shows one
/// (the sidebar's inline filters).
property bool showGlyph: true
/// Escape emptied the field and handed the keyboard back; a host that
/// folds the field away listens here.
signal escaped()
/// The clear cross scales with a short field (the sidebar's 22px rows).
readonly property int clearSize: Math.min(22, Math.max(16, height - 2))
property int glyphSize: 14
property int fontPx: 13
property int sidePadding: 10
@@ -80,6 +88,7 @@ Rectangle {
}
QbzIcon {
visible: root.showGlyph
name: "search"
width: root.glyphSize
height: root.glyphSize
@@ -92,7 +101,7 @@ Rectangle {
QbzTextEditMenu { }
anchors.left: parent.left
anchors.right: clearSlot.left
anchors.leftMargin: root.sidePadding + root.glyphSize + 7
anchors.leftMargin: root.sidePadding + (root.showGlyph ? root.glyphSize + 7 : 0)
anchors.rightMargin: 4
height: parent.height
color: theme.textPrimary
@@ -106,6 +115,7 @@ Rectangle {
}
Keys.onEscapePressed: function (event) {
root.clearAndBlur()
root.escaped()
event.accepted = true
}
Text {
@@ -124,19 +134,19 @@ Rectangle {
id: clearSlot
anchors.right: parent.right
anchors.rightMargin: 5
width: input.text !== "" ? 22 : 0
width: input.text !== "" ? root.clearSize : 0
height: parent.height
visible: input.text !== ""
Rectangle {
anchors.centerIn: parent
width: 22
height: 22
radius: 11
width: root.clearSize
height: root.clearSize
radius: root.clearSize / 2
color: clearArea.containsMouse ? theme.surfaceHover : "transparent"
QbzIcon {
name: "x"
width: 12
height: 12
width: Math.round(root.clearSize * 0.55)
height: Math.round(root.clearSize * 0.55)
anchors.centerIn: parent
tintName: clearArea.containsMouse ? "textPrimary" : "muted"
}
+30 -60
View File
@@ -903,12 +903,10 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onClicked: {
root.myqbzSearchOpen = !root.myqbzSearchOpen
if (!root.myqbzSearchOpen) {
myqbzSearchEdit.text = ""
root.myqbzSearch = ""
} else {
myqbzSearchEdit.forceActiveFocus()
}
if (!root.myqbzSearchOpen)
myqbzSearchEdit.clear()
else
myqbzSearchEdit.focusField()
}
}
}
@@ -999,8 +997,11 @@ Rectangle {
onClicked: QbzShell.navigateTo("collections")
}
}
// Inline search field (filters the tree client-side).
Rectangle {
// Inline search field (filters the tree client-side). The
// shared search box: Escape empties it AND folds it away,
// the cross empties it and keeps the caret.
QbzSearchField {
id: myqbzSearchEdit
visible: root.myqbzSearchOpen
anchors.left: myqbzBrandIcon.right
anchors.leftMargin: 8
@@ -1009,28 +1010,12 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
height: 22
radius: 4
color: (theme.ambientOn ? theme.surfaceElevatedA50 : theme.surfaceElevated)
border.width: 1
border.color: theme.borderSubtle
TextInput {
QbzTextEditMenu { }
id: myqbzSearchEdit
anchors.fill: parent
anchors.leftMargin: 6
color: theme.textPrimary
font.pixelSize: 12
verticalAlignment: Text.AlignVCenter
clip: true
onTextEdited: root.myqbzSearch = text
Text {
visible: myqbzSearchEdit.text === ""
anchors.fill: parent
text: QbzSession.tr("Search My QBZ", QbzSession.trRev)
color: theme.textMuted
font.pixelSize: 12
verticalAlignment: Text.AlignVCenter
}
}
showGlyph: false
sidePadding: 6
fontPx: 12
placeholder: QbzSession.tr("Search My QBZ", QbzSession.trRev)
onEdited: function (text) { root.myqbzSearch = text }
onEscaped: root.myqbzSearchOpen = false
}
}
@@ -1280,34 +1265,21 @@ Rectangle {
font.letterSpacing: 1
verticalAlignment: Text.AlignVCenter
}
// Inline search input (filters entries, recursive).
Rectangle {
// Inline search input (filters entries, recursive). The shared
// search box: Escape empties it AND folds it back into the title,
// the cross empties it and keeps the caret.
QbzSearchField {
id: searchEdit
visible: root.searchOpen
width: parent.width - 4 * 26
height: 22
radius: 4
color: (theme.ambientOn ? theme.surfaceElevatedA50 : theme.surfaceElevated)
border.width: 1
border.color: theme.borderSubtle
TextInput {
QbzTextEditMenu { }
id: searchEdit
anchors.fill: parent
anchors.leftMargin: 6
color: theme.textPrimary
font.pixelSize: 12
verticalAlignment: Text.AlignVCenter
clip: true
onTextEdited: QbzShell.sidebarSearch(text)
Text {
visible: searchEdit.text === ""
anchors.fill: parent
text: QbzSession.tr("Search playlists", QbzSession.trRev)
color: theme.textMuted
font.pixelSize: 12
verticalAlignment: Text.AlignVCenter
}
}
showGlyph: false
sidePadding: 6
fontPx: 12
placeholder: QbzSession.tr("Search playlists", QbzSession.trRev)
onEdited: function (text) { QbzShell.sidebarSearch(text) }
onEscaped: root.searchOpen = false
}
// Search toggle.
@@ -1330,12 +1302,10 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onClicked: {
root.searchOpen = !root.searchOpen
if (!root.searchOpen) {
searchEdit.text = ""
QbzShell.sidebarSearch("")
} else {
searchEdit.forceActiveFocus()
}
if (!root.searchOpen)
searchEdit.clear()
else
searchEdit.focusField()
}
}
}