Buttons that rest on surfaceElevated used surfaceHover for their hover fill: a 6% white wash meant for rows that rest transparent. Over an elevated button it lands DARKER than the rest fill — on a modal's dark ground the Cancel/Save/footer buttons went near-black under the pointer. QbzTheme gains surfaceElevatedHover (a lift of surfaceElevated, derived so every palette has it), its ambient half-alpha twin, and the elevatedFill / elevatedHoverFill pair an ambient-aware control paints. Every site with the old pairing (65 across modals, toolbars, selects, circle actions, chips and cards) now hovers to the lift. cc
125 lines
5.2 KiB
QML
125 lines
5.2 KiB
QML
// QbzToolButton — the MyQBZ detail toolbar's `ToolBtn`
|
||
// (myqbz/MixtapeDetailView.slint:85-151): a 30px bordered chip that is
|
||
// icon-only, icon+label, or icon+label+badge, with TWO distinct active looks.
|
||
//
|
||
// Why not controls/BrowseGenreButton.qml: that one is hard-bound to
|
||
// `QbzBridge.genreFilterJson` and builds its own label out of it, so a generic
|
||
// label/badge/active-mode contract cannot be a parameter of it.
|
||
//
|
||
// THE TWO ACTIVE MODES are the whole point, and they are not interchangeable:
|
||
// * `fillActive: true` — active paints an ACCENT FILL (the Filter button,
|
||
// which is labelled and carries the filter count).
|
||
// * `fillActive: false` — active paints an accent BORDER on the normal
|
||
// elevated fill (the icon-only Select / Reset buttons). Never a fill.
|
||
//
|
||
// Numbers: height 30, r6, width = the row's own padded width (:97-99, so the
|
||
// padding centres the content rather than an absolute x offset), 1px border;
|
||
// padding 8/side icon-only and 10/side labelled (:108-109); row spacing 6;
|
||
// glyph 15x15; label 12px; badge 16x16 r8 with 10px semibold text.
|
||
//
|
||
// Where the .slint hardcodes `#ffffff` on the accent fill (:120, :127, :137)
|
||
// this uses `theme.accentGlyphTint` / `theme.accentGlyphColor` — the measured
|
||
// on-accent selector (theme/QbzTheme.qml, "ON AN ACCENT FILL"). The badge's
|
||
// non-filled text stays `accentText` because there it sits on the accent disc,
|
||
// which is what that token is for.
|
||
|
||
import QtQuick
|
||
import com.blitzfc.qbz
|
||
import "../theme"
|
||
|
||
Rectangle {
|
||
id: root
|
||
|
||
property string name: ""
|
||
property string label: ""
|
||
/// > 0 renders the trailing count disc.
|
||
property int badge: 0
|
||
property bool active: false
|
||
/// Active = accent FILL (labelled buttons) vs accent BORDER (icon-only).
|
||
property bool fillActive: false
|
||
/// THE SECOND SCALE — the Playlist Manager toolbar's `PmToolButton` /
|
||
/// `PmIconButton` (playlist/PlaylistManagerView.slint:162-230), which is the
|
||
/// same control 4 px taller with more air. The port's established idiom for
|
||
/// a second size on one control (`QbzLineEdit.sm`, `QbzSelect.sm`,
|
||
/// `QbzToggleButton.sm`), rather than a 90 %-identical fork.
|
||
///
|
||
/// Under `large`: height 34, padH 11 (the reference's `row { x: 11 }` and
|
||
/// `width: row.preferred-width + 22`), row spacing 7, label 13, NO border
|
||
/// (except the accent-border arm, which the PM never uses), and an
|
||
/// icon-only button is a 34 × 34 square with a 16 px glyph — the 15 → 16
|
||
/// delta between the labelled and icon-only forms IS the reference
|
||
/// (`:180-184` vs `:216-222`); do not unify it.
|
||
///
|
||
/// The idle GLYPH tint also changes, and it is the largest of the deltas:
|
||
/// this control tints idle glyphs `muted` (#888888) where the reference
|
||
/// paints `Theme.text-secondary` (#cccccc) on five of its six toolbar
|
||
/// controls. Defaults are untouched, so the MyQBZ toolbars cannot regress.
|
||
property bool large: false
|
||
signal clicked()
|
||
|
||
QbzTheme { id: theme }
|
||
|
||
readonly property bool filled: root.active && root.fillActive
|
||
readonly property bool iconOnly: root.label === ""
|
||
readonly property int padH: root.large ? 11 : (root.iconOnly ? 8 : 10)
|
||
|
||
height: root.large ? 34 : 30
|
||
implicitWidth: (root.large && root.iconOnly)
|
||
? 34
|
||
: 2 * root.padH + row.implicitWidth
|
||
radius: 6
|
||
color: root.filled ? theme.accent
|
||
: (toolArea.containsMouse ? theme.surfaceElevatedHover : theme.surfaceElevated)
|
||
border.width: (root.large && !(root.active && !root.fillActive)) ? 0 : 1
|
||
border.color: (root.active && !root.fillActive) ? theme.accent : theme.borderSubtle
|
||
|
||
Row {
|
||
id: row
|
||
anchors.centerIn: parent
|
||
spacing: root.large ? 7 : 6
|
||
|
||
QbzIcon {
|
||
anchors.verticalCenter: parent.verticalCenter
|
||
name: root.name
|
||
width: (root.large && root.iconOnly) ? 16 : 15
|
||
height: (root.large && root.iconOnly) ? 16 : 15
|
||
tintName: root.filled ? theme.accentGlyphTint
|
||
: (root.active ? "textPrimary" : (root.large ? "secondary" : "muted"))
|
||
}
|
||
Text {
|
||
visible: root.label !== ""
|
||
anchors.verticalCenter: parent.verticalCenter
|
||
text: root.label
|
||
color: root.filled ? theme.accentGlyphColor
|
||
: (root.active ? theme.textPrimary : theme.textSecondary)
|
||
font.pixelSize: root.large ? 13 : 12
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
Rectangle {
|
||
visible: root.badge > 0
|
||
anchors.verticalCenter: parent.verticalCenter
|
||
width: root.badge > 0 ? 16 : 0
|
||
height: 16
|
||
radius: 8
|
||
color: root.filled ? theme.accentGlyphColor : theme.accent
|
||
Text {
|
||
anchors.centerIn: parent
|
||
text: root.badge
|
||
color: root.filled ? theme.accent : theme.accentText
|
||
font.pixelSize: 10
|
||
font.weight: theme.weightSemibold
|
||
horizontalAlignment: Text.AlignHCenter
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
}
|
||
}
|
||
|
||
MouseArea {
|
||
id: toolArea
|
||
anchors.fill: parent
|
||
hoverEnabled: true
|
||
cursorShape: Qt.PointingHandCursor
|
||
onClicked: root.clicked()
|
||
}
|
||
}
|