Files
qbz/crates/qbz-slint/ui/primitives/ContextMenuItem.slint
T
vicrodh da7758b9d6 feat(slint): new now-playing bar layout
Land the "New" now-playing bar as the first of the four switchable
layouts. A dedicated SongCard component holds the cover (or an idle
sleeping cat), the elidable title, the artist·album links, and the
vertical audio stamp (compact quality badge over the backend/mode LEDs).
A full-width seek bar sits on top with a buffer-driven stream lock.

The controls row uses responsive symmetric column zones (39/30/25% by
window width); the side columns share one fraction so the transport stays
absolutely centred and PLAY lands on the window centre. The song-card /
controls divider is a hard wall: the text column stretches to push the
audio stamp to its right edge, the album elides first (and never collapses
to zero) so the stamp is always visible and never crosses the wall.

Adds QualityBadgeFull compact mode, backend/mode output LED labels from
settings, a global TooltipOverlay so clipped columns keep their tooltips,
and the supporting icons.

cc
2026-06-02 06:48:36 -06:00

67 lines
2.2 KiB
Plaintext

// One row of a context menu — an icon, a label, and a click callback.
import { Theme } from "../foundation/semantic-colors.slint";
import { Typography } from "../foundation/typography.slint";
import { QbzIcon } from "QbzIcon.slint";
export component ContextMenuItem inherits Rectangle {
in property <image> icon;
in property <string> label;
// When false the row collapses to zero height and stops rendering /
// capturing input — lets a `for` build a filtered list without an
// inner `if` (which Slint does not allow as a direct `for` child).
in property <bool> shown: true;
// When false the row is muted and ignores clicks (a feature that exists
// but is not available yet, e.g. Mini / Immersive window modes).
in property <bool> enabled: true;
// Optional trailing check, for single-choice menus (the selected row).
in property <bool> selected: false;
callback clicked();
height: root.shown ? 33px : 0px;
visible: root.shown;
clip: true;
background: (ta.has-hover && root.enabled) ? Theme.surface-hover : transparent;
opacity: root.enabled ? 1.0 : 0.4;
HorizontalLayout {
padding-left: 11px;
padding-right: 16px;
spacing: 10px;
VerticalLayout {
alignment: center;
QbzIcon {
source: root.icon;
width: 15px;
height: 15px;
tint: ta.has-hover ? Theme.text-primary : Theme.text-secondary;
}
}
Text {
text: root.label;
color: ta.has-hover ? Theme.text-primary : Theme.text-secondary;
font-size: 13px;
vertical-alignment: center;
horizontal-stretch: 1;
}
if root.selected: VerticalLayout {
alignment: center;
QbzIcon {
source: @image-url("../assets/icons/check.svg");
width: 14px;
height: 14px;
tint: Theme.accent;
}
}
}
ta := TouchArea {
mouse-cursor: root.enabled ? pointer : default;
clicked => {
if (root.enabled) {
root.clicked();
}
}
}
}