feat(qt): header tab labels grow to the sidebar's 13 px when the room allows

The full text tabs kept an 11 px label at every width. The size now comes
from measuring the labels: 11 px stays the floor (the tabs beside the search
box at the 1140 px breakpoint), 12 or 13 px when every label plus its chrome
fits in the room left of the centred search box — 13 px being what the
sidebar rows and the flyout entries use, so with space the two hosts read
the same. Measured rather than a width breakpoint because the labels are
translated and their count changes (offline hides the Qobuz sections,
Purchases is opt-in).

cc
This commit is contained in:
vicrodh committed 2026-09-13 11:31:28 -06:00
1 parent db7ddc5edd
commit ae644dc163
1 file changed
+52 -4
+52 -4
View File
@@ -189,6 +189,53 @@ Rectangle {
// HeaderMenuState.open-index).
readonly property string activeNav: navFlyout.activeSection
// ---- Full-tab label size (2026-09-13) --------------------------------
// 11 px is the floor: the tabs beside the search box at the 1140 px
// breakpoint. 12 / 13 px when every label, MEASURED, fits in the room
// left of the search box — 13 px is what the sidebar rows and the flyout
// entries use, so with space the two hosts read the same. Measured, not
// a window-width breakpoint: the labels are translated and their count
// changes (offline hides the Qobuz sections, Purchases is opt-in), so no
// fixed width would hold for every locale.
readonly property string navLabelsJoined: {
var parts = []
var s = root.navSections || []
for (var i = 0; i < s.length; i++)
if (!(s[i].qobuz && QbzSession.offline)) parts.push(s[i].label)
if (root.purchasesInHeader) parts.push(QbzSession.tr("Purchases", QbzSession.trRev))
return parts.join("")
}
readonly property int navTabCount: {
var n = 0
var s = root.navSections || []
for (var i = 0; i < s.length; i++)
if (!(s[i].qobuz && QbzSession.offline)) n++
return n + (root.purchasesInHeader ? 1 : 0)
}
TextMetrics {
id: navMetrics13
font.pixelSize: 13
font.weight: theme.weightSemibold
text: root.navLabelsJoined
}
TextMetrics {
id: navMetrics12
font.pixelSize: 12
font.weight: theme.weightSemibold
text: root.navLabelsJoined
}
// Per-tab chrome around the label: paddings, the 14 px glyph and its
// 6 px gap above the 1140 px breakpoint, and the Row's 2 px spacing.
readonly property real navTabsChrome:
root.navTabCount * ((root.width >= 1140 ? 9 + 14 + 6 : 11) + 11 + 2)
// Room between the tabs' left edge and the (centred) search box.
readonly property real navTabsRoom: searchBox.x - (leftControls.x + fullTabs.x) - 16
readonly property int navLabelPx:
!root.headerTabsOn ? 11
: navMetrics13.advanceWidth + root.navTabsChrome <= root.navTabsRoom ? 13
: navMetrics12.advanceWidth + root.navTabsChrome <= root.navTabsRoom ? 12
: 11
// Which of the two header forms is mounted (mutually exclusive, and both
// off while the nav lives in the sidebar and the sidebar is not closed).
readonly property bool headerTabsOn: !QbzShell.navInSidebar
@@ -218,8 +265,8 @@ Rectangle {
}
// Full text tab (HeaderBar.slint NavTab): 30px tall, radius sm, icon 14
// (dropped under 1140px), label 11px — semibold + elevated fill when the
// section is the current view.
// (dropped under 1140px), label 11-13 px (`navLabelPx`) — semibold +
// elevated fill when the section is the current view.
/// The title-bar Purchases entry. Deliberately NOT a `NavTab`: that
/// component is built around a section object and its click opens the
/// flyout, while Purchases navigates straight to its route.
@@ -256,7 +303,7 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
text: QbzSession.tr("Purchases", QbzSession.trRev)
color: theme.textPrimary
font.pixelSize: 11
font.pixelSize: root.navLabelPx
font.weight: purchaseTab.isActive ? theme.weightSemibold : theme.weightRegular
}
}
@@ -314,7 +361,7 @@ Rectangle {
height: parent.height
text: navTab.section ? navTab.section.label : ""
color: theme.textPrimary
font.pixelSize: 11
font.pixelSize: root.navLabelPx
font.weight: navTab.isActive ? theme.weightSemibold : theme.weightRegular
verticalAlignment: Text.AlignVCenter
}
@@ -423,6 +470,7 @@ Rectangle {
// closed, compact form OFF. Sits AFTER the three sacred buttons so it
// can never overlap them (HeaderBar.slint:853).
Row {
id: fullTabs
visible: root.headerTabsOn
height: parent.height
spacing: 2