From d05082eaeedba8f5262fc7569f2e1e4588158929 Mon Sep 17 00:00:00 2001 From: vicrodh <103399283+vicrodh@users.noreply.github.com> Date: Sun, 13 Sep 2026 15:38:25 -0600 Subject: [PATCH] fix(qt): the player bar is one chrome band like the header, with its layout inset The bottom band is now NowPlayingBar.qml's root: full width, flush on the window's bottom edge, surface-card @ 0.5 over the ambient field like the HeaderBar, opaque surface-card otherwise. The bar layout (PlayerBar / NowPlayingBarSmall) paints no background of its own and mounts inset by the gutter on its left, right and bottom, so the bar's ends still line up with the content pane's while nothing around it shows the raw field. Both rejected shapes are documented in place: an inset plate over the raw field (three sides of raw background, the only zone of the shell without chrome) and a frame slab behind an inset plate (a bar glued onto a slab). A future layout inherits the band and the gutter from the seam instead of carrying either. cc --- crates/qbz-qt/qml/shell/AppShell.qml | 31 ++++++---------- crates/qbz-qt/qml/shell/NowPlayingBar.qml | 36 +++++++++++++++++-- .../qbz-qt/qml/shell/NowPlayingBarSmall.qml | 9 ++--- crates/qbz-qt/qml/shell/PlayerBar.qml | 7 ++-- 4 files changed, 54 insertions(+), 29 deletions(-) diff --git a/crates/qbz-qt/qml/shell/AppShell.qml b/crates/qbz-qt/qml/shell/AppShell.qml index 5ee7048cc..a59d3c32d 100644 --- a/crates/qbz-qt/qml/shell/AppShell.qml +++ b/crates/qbz-qt/qml/shell/AppShell.qml @@ -252,12 +252,14 @@ Rectangle { hostName: QbzOrbit.hostName } - // The gutter the player bar keeps to the window edges (below). Nothing - // is painted behind it: the bar floats over the shell's own ground — - // the ambient field or the root colour — exactly like the content pane's - // margins show what is under them (a backdrop was tried and rejected). - readonly property int npbGutter: Qt.platform.os === "osx" ? theme.npbGutterMac : theme.npbGutter - + // The bottom chrome band (NowPlayingBar.qml's root): full width, flush + // on the window's bottom edge, the same tier and paint as the HeaderBar + // above. The bar layout inside it keeps the content pane's gutter to the + // window's left, right and bottom edges — wider on macOS, where the + // Liquid Glass corner curve ate the cover's corner (QbzTheme.npbGutterMac) + // — and the band sizes itself: the mode-aware layout height (Small + // collapses to one header-tall row; New/Classic/Large keep the full + // 112px, AppShell.slint:396) plus that gutter. NowPlayingBar { id: npb // The small seek thumb/hit area extends above the bar by a few pixels. @@ -267,17 +269,6 @@ Rectangle { anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom - // Inset by the content pane's gutter on the three window edges - // (2026-09-13, every mode): the bar's ends line up with the pane's - // and nothing in it touches the window edge — wider on macOS, where - // the Liquid Glass corner curve ate the cover's corner - // (QbzTheme.npbGutterMac). - anchors.leftMargin: root.npbGutter - anchors.rightMargin: root.npbGutter - anchors.bottomMargin: root.npbGutter - // Mode-aware height (AppShell.slint:396): Small collapses to one - // header-tall row; New/Classic/Large keep the full 112px. - height: QbzShell.npbMode === 2 ? theme.npbSmallHeight : theme.npbLargeHeight // The shared hover-tooltip overlay (declared further down — id // references resolve at completion). All four modes consume it for // Shuffle/Repeat state; the full bar also uses it for Qobuz Connect. @@ -666,9 +657,9 @@ Rectangle { // so this width also sets the art size. x: 16 width: 208 - // Flush with the bar's bottom edge, which now sits a gutter above - // the window's (npbGutter) — the dock lifts with it. - y: npb.y + npb.height - QbzShell.largeDockHeight + // Flush with the bar LAYOUT's bottom edge, which sits a gutter above + // the window's (the band's inset) — the dock lifts with it. + y: npb.y + npb.height - npb.gutter - QbzShell.largeDockHeight ambientOn: root.ambientOn } diff --git a/crates/qbz-qt/qml/shell/NowPlayingBar.qml b/crates/qbz-qt/qml/shell/NowPlayingBar.qml index 69fc685ec..9b2781db4 100644 --- a/crates/qbz-qt/qml/shell/NowPlayingBar.qml +++ b/crates/qbz-qt/qml/shell/NowPlayingBar.qml @@ -1,13 +1,39 @@ // NowPlayingBar SHELL — the mode seam (NowPlayingBar.slint, phase 18): // mounts NowPlayingBarSmall for mode 2 (Small) and the full PlayerBar for -// modes 0 (New) / 1 (Classic) / 3 (Large). AppShell pins the height -// mode-aware (42px Small / 112px otherwise). +// modes 0 (New) / 1 (Classic) / 3 (Large), and sizes itself mode-aware +// (42px Small / 112px otherwise, plus the gutter below). +// +// THE BAND (2026-09-13). This root is the bottom chrome band, the exact +// counterpart of HeaderBar at the top: one full-width piece of chrome, flush +// on the window's bottom edge, painted surface-card @ 0.5 over the field +// while the ambient background is active and opaque surface-card otherwise. +// The bar LAYOUT mounted below is inset by `gutter` on its left, right and +// bottom, so the bar's ends line up with the content pane's and nothing in +// it touches the window edge — while the band stays continuous around it. +// Both alternatives were tried and rejected the same day: insetting the +// whole bar left the raw field showing on three sides (the only zone of the +// shell without chrome), and a frame slab behind an inset plate read as a +// bar glued onto a slab. A layout knows nothing about the band or the +// gutter: it paints no background of its own and fills the rect it is given, +// which is what keeps a future layout from needing either. import QtQuick import com.blitzfc.qbz +import "../theme" -Item { +Rectangle { id: root + color: ambientOn ? theme.surfaceCardA50 : theme.surfaceCard + readonly property bool ambientOn: theme.ambientOn + + QbzTheme { id: theme } + + /// The gutter the bar layout keeps to the window's left, right and + /// bottom edges: the pane's 8px, wider on macOS (QbzTheme.npbGutterMac). + readonly property int gutter: Qt.platform.os === "osx" ? theme.npbGutterMac : theme.npbGutter + /// The layout's own height (PlayerBar.slint / PlayerBarSmall.slint). + readonly property int layoutHeight: QbzShell.npbMode === 2 ? theme.npbSmallHeight : theme.npbLargeHeight + implicitHeight: layoutHeight + gutter // The shell's shared hover-tooltip overlay (controls/QbzTooltip.qml), // fed in by AppShell (same pattern as Sidebar.tooltip). Forwarded into @@ -18,6 +44,10 @@ Item { Loader { id: barLoader anchors.fill: parent + // The inset. Top stays flush: the band's top edge IS the layout's. + anchors.leftMargin: root.gutter + anchors.rightMargin: root.gutter + anchors.bottomMargin: root.gutter source: QbzShell.npbMode === 2 ? "NowPlayingBarSmall.qml" : "PlayerBar.qml" } diff --git a/crates/qbz-qt/qml/shell/NowPlayingBarSmall.qml b/crates/qbz-qt/qml/shell/NowPlayingBarSmall.qml index 5f0f64f50..3ee433505 100644 --- a/crates/qbz-qt/qml/shell/NowPlayingBarSmall.qml +++ b/crates/qbz-qt/qml/shell/NowPlayingBarSmall.qml @@ -40,9 +40,10 @@ import "../theme" Rectangle { id: root - // surface-card @ 0.5 while the ambient background is active (phase 14, - // PlayerBarSmall.slint). - color: ambientOn ? theme.surfaceCardA50 : theme.surfaceCard + // No background of its own: the chrome band is NowPlayingBar.qml's root + // (surface-card @ 0.5 under the ambient background, opaque surface-card + // otherwise), full width behind this inset layout — see THE BAND there. + color: "transparent" readonly property bool ambientOn: theme.ambientOn /// AppShell's one shared hover-tooltip overlay. property Item tooltip: null @@ -65,7 +66,7 @@ Rectangle { // 1366 / 1920) are the SHARED theme token, so this bar and PlayerBar can // never drift apart — see QbzTheme.npbSideFrac. // `root.width` is the window width minus the two side gutters - // (AppShell `npbGutter`): the bar is anchored left-to-right on the shell + // (NowPlayingBar.qml `gutter`): the bar is anchored left-to-right on the shell // root, exactly like PlayerBarSmall.slint reads its own root. property real sideFrac: theme.npbSideFrac(root.width) property real colCentre: 1.0 - 2.0 * root.sideFrac diff --git a/crates/qbz-qt/qml/shell/PlayerBar.qml b/crates/qbz-qt/qml/shell/PlayerBar.qml index 6a1618c37..105bd5afa 100644 --- a/crates/qbz-qt/qml/shell/PlayerBar.qml +++ b/crates/qbz-qt/qml/shell/PlayerBar.qml @@ -69,7 +69,10 @@ import "../theme" Rectangle { id: root - color: ambientOn ? theme.surfaceCardA50 : theme.surfaceCard + // No background of its own: the chrome band is NowPlayingBar.qml's root + // (surface-card @ 0.5 under the ambient background, opaque surface-card + // otherwise), full width behind this inset layout — see THE BAND there. + color: "transparent" readonly property bool ambientOn: theme.ambientOn readonly property bool largeActive: QbzShell.npbMode === 3 && QbzShell.sidebarState === 0 readonly property bool isClassic: QbzShell.npbMode === 1 @@ -103,7 +106,7 @@ Rectangle { // are the SHARED theme token (QbzTheme.npbSideFrac) — the Small bar reads // the same one, so the two bars cannot drift apart. // `root.width` is the window width minus the two side gutters - // (AppShell `npbGutter`): the bar is anchored left-to-right on the shell + // (NowPlayingBar.qml `gutter`): the bar is anchored left-to-right on the shell // root, exactly like PlayerBar.slint reads its own root. property real sideFrac: theme.npbSideFrac(root.width) property real colSide: isClassic ? 0.324 : sideFrac