Files
qbz/crates/qbz-qt/qml/controls/QbzIconButton.qml
T
vicrodh a1c771c39e fix(qbz-qt): row buttons, cover triggers, light-theme contrast, flyouts, genre filter
**Track-row buttons did nothing.** Declaration order is z-order in QML, and the
row-wide MouseArea added for right-click was declared last — so it covered the
heart, cloud and menu buttons and swallowed their presses.
propagateComposedEvents cannot rescue that: a press is not a composed event,
which is why only the row's own double-click still worked.

**Covers appeared only after a scroll.** Three compounding defects, not one. The
window report fired on contentY and on model change, both of which happen while
the tab body is still hidden behind its loading flag, so the report that
mattered hit the not-visible early return and was discarded with nothing to
re-fire it. The debounce reset on every change, so a burst of mount-time reports
kept pushing its trailing edge out. And a single pending slot meant that when
two surfaces are mounted at once — the artist rail and that artist's grid — the
second overwrote the first, so one pane was never requested at all. Eviction had
the same shape: each report deleted everything outside its own array, so the two
panes deleted each other's covers.

**Latest release had no cover** because the artist page's collector skipped it,
along with Appears On and the playlists strip.

**Light themes.** The mechanism is Slint's, from 2.0.2 and issue #638: the
on-surface arm on circle actions, header-light deciding the header foreground
only when a dark backdrop is actually painted, and the circular backing behind
the track-row play glyph. Ported as specified rather than approximated. Two
icons rendered in their SVG's own colour because they pointed at the raw asset
instead of a baked tint — a sweep found the rest of that class.

**Navigation flyouts** exist, one component serving both the sidebar and the
header nav modes.

**Filter by genre and the Discover sort now work**, everywhere the control is
drawn. The genre ids were already a parameter on the discover fetch that the
port always passed empty.

cc
2026-07-28 19:55:33 -06:00

67 lines
2.8 KiB
QML

// QbzIconButton — the square icon button (Slint BarControls IconButton /
// HeaderIconButton), consolidated in phase 22 from PlayerBar.BarIconBtn +
// NowPlayingBarSmall.BarIconBtn (verbatim twins), QueuePanel.PanelIconBtn
// and HeaderBar.HeaderIconBtn.
// Arms: `btnSize` (32 default; 30 compact panels, 36 header), `iconSize`,
// `active` (accent glyph), `activeBackground` (HeaderBar: elevated fill
// when active), `btnEnabled` (dims 0.3 + muted glyph, disarms).
//
// LIGHT-THEME CORRECTNESS: the glyph tints are PRE-BAKED SVG colours
// (assets/icons/<tint>/) — "primary" is literally #ffffff and "secondary"
// #cccccc, i.e. the DARK theme's text-primary / text-secondary frozen into
// the asset. On a light theme those render near-white on a light surface and
// the whole button set disappears, which is the reported bug. The bake is
// therefore chosen from the LIVE token's lightness instead of being
// hardcoded: bright token -> the light bake, dark token -> the dark bake.
// TODO(glue): the durable home for this is a QbzTheme.tintFor(token) helper
// (or real runtime tinting in QbzIcon) — see the report; it is duplicated in
// FavToggle / TransportControls / SongCard until then.
import QtQuick
import com.blitzfc.qbz
import "../theme"
Rectangle {
id: btn
property string name: ""
property int btnSize: 32
property int iconSize: 16
property bool active: false
property bool activeBackground: false
property bool btnEnabled: true
signal clicked()
QbzTheme { id: theme }
// Bake that actually matches Theme.text-primary / text-secondary in the
// ACTIVE theme (BarControls.slint IconButton: hover -> text-primary,
// idle -> text-secondary). text-muted maps to the "muted" bake in both
// polarities: #888888 is mid-grey and reads on light and dark alike.
readonly property string tintStrong: theme.textPrimary.hslLightness > 0.5 ? "primary" : "black"
readonly property string tintWeak: theme.textSecondary.hslLightness > 0.5 ? "secondary" : "muted"
width: btnSize
height: btnSize
radius: theme.radiusSm
opacity: btnEnabled ? 1.0 : 0.3
color: (biArea.containsMouse && btnEnabled) ? theme.surfaceHover
: (active && activeBackground) ? theme.surfaceElevated : "transparent"
QbzIcon {
name: parent.name
width: parent.iconSize
height: parent.iconSize
anchors.centerIn: parent
tintName: !parent.btnEnabled ? "muted"
: parent.active ? "accent"
: biArea.containsMouse ? btn.tintStrong : btn.tintWeak
}
MouseArea {
id: biArea
anchors.fill: parent
enabled: parent.btnEnabled
hoverEnabled: true
cursorShape: parent.btnEnabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: if (parent.btnEnabled) parent.clicked()
}
}