From fcce5f304b7edb2a7a67772dab1688190f1f4bca Mon Sep 17 00:00:00 2001 From: thomas Date: Thu, 27 Aug 2026 13:02:34 +0100 Subject: [PATCH] UI: Fixed hover colours --- .../modules/bar/BluetoothIndicator.qml | 26 ++++------ .../modules/bar/NetworkIndicator.qml | 29 +++++------ .../quickshell/modules/bar/PowerButton.qml | 49 +++++++++++++------ .../modules/bar/TailscaleIndicator.qml | 34 ++++++------- 4 files changed, 72 insertions(+), 66 deletions(-) diff --git a/dotfiles/.config/quickshell/modules/bar/BluetoothIndicator.qml b/dotfiles/.config/quickshell/modules/bar/BluetoothIndicator.qml index 2f7235f..bcfca55 100644 --- a/dotfiles/.config/quickshell/modules/bar/BluetoothIndicator.qml +++ b/dotfiles/.config/quickshell/modules/bar/BluetoothIndicator.qml @@ -213,18 +213,12 @@ Item { width: parent ? parent.width : 0 radius: 0 implicitHeight: rowContent.implicitHeight + 12 - color: devRow.dev.connected - ? Qt.rgba(Colors.primary.r, Colors.primary.g, Colors.primary.b, 0.18) - : (rowMouse.containsMouse ? Colors.primary : "transparent") - - // Colors.primaryText (used below whenever hovered) assumes a solid - // Colors.primary fill behind it — true for a hovered *disconnected* - // row, but a connected row's background stays the translucent tint - // above even while hovered, so primaryText (dark, meant for a bright - // solid fill) reads poorly against it. This hardcoded near-white - // (same one NetworkIndicator.qml/TailscaleIndicator.qml use for the - // same reason) is used instead for that one case. - readonly property color activeHoverColor: "#c9f0f0f0" + // Hover checked first (same ordering as Volume.qml's DeviceRow): + // hovering always shows a solid Colors.primary fill, even for an + // already-connected row, so the primaryText used below never has to + // sit on top of the dimmer translucent tint instead. + color: rowMouse.containsMouse ? Colors.primary + : (devRow.dev.connected ? Qt.rgba(Colors.primary.r, Colors.primary.g, Colors.primary.b, 0.18) : "transparent") // Hover-only outline, offset outside the row rather than drawn on // its own edge — same treatment as NetworkIndicator.qml's NetworkRow. @@ -257,7 +251,7 @@ Item { font.family: Appearance.iconFontFamilyRounded font.variableAxes: Appearance.iconFontAxes font.pixelSize: 14 - color: rowMouse.containsMouse ? (devRow.dev.connected ? devRow.activeHoverColor : Colors.primaryText) : Colors.foreground + color: rowMouse.containsMouse ? Colors.primaryText : Colors.foreground } ColumnLayout { @@ -271,7 +265,7 @@ Item { font.family: Appearance.fontFamily font.pixelSize: Appearance.fontSize font.bold: devRow.dev.connected - color: rowMouse.containsMouse ? (devRow.dev.connected ? devRow.activeHoverColor : Colors.primaryText) : Colors.foreground + color: rowMouse.containsMouse ? Colors.primaryText : Colors.foreground } Text { readonly property string statusText: { @@ -285,7 +279,7 @@ Item { text: statusText font.family: Appearance.fontFamily font.pixelSize: Appearance.fontSizeSmall - color: rowMouse.containsMouse ? (devRow.dev.connected ? devRow.activeHoverColor : Colors.primaryText) : Colors.muted + color: rowMouse.containsMouse ? Colors.primaryText : Colors.muted } } @@ -296,7 +290,7 @@ Item { font.family: Appearance.iconFontFamilyRounded font.variableAxes: Appearance.iconFontAxes font.pixelSize: 14 - color: rowMouse.containsMouse ? (devRow.dev.connected ? devRow.activeHoverColor : Colors.primaryText) : Colors.muted + color: rowMouse.containsMouse ? Colors.primaryText : Colors.muted } } diff --git a/dotfiles/.config/quickshell/modules/bar/NetworkIndicator.qml b/dotfiles/.config/quickshell/modules/bar/NetworkIndicator.qml index 099ba15..097805e 100644 --- a/dotfiles/.config/quickshell/modules/bar/NetworkIndicator.qml +++ b/dotfiles/.config/quickshell/modules/bar/NetworkIndicator.qml @@ -660,19 +660,12 @@ Item { width: parent ? parent.width : 0 radius: 0 implicitHeight: rowContent.implicitHeight + 12 - color: (netRow.net.connected || netRow.passwordOpen) - ? Qt.rgba(Colors.primary.r, Colors.primary.g, Colors.primary.b, 0.18) - : (rowMouse.containsMouse ? Colors.primary : "transparent") - readonly property bool active: netRow.net.connected || netRow.passwordOpen - - // Colors.primaryText (used below whenever hovered) assumes a solid - // Colors.primary fill behind it — true for a hovered *inactive* row, - // but an active row's background stays the translucent tint above - // even while hovered, so primaryText (dark, meant for a bright solid - // fill) reads poorly against it. This hardcoded near-white (same one - // TailscaleIndicator.qml uses for the same reason) is used instead - // for that one case. - readonly property color activeHoverColor: "#c9f0f0f0" + // Hover checked first (same ordering as Volume.qml's DeviceRow): + // hovering always shows a solid Colors.primary fill, even for an + // already-active row, so the primaryText used below never has to + // sit on top of the dimmer translucent tint instead. + color: rowMouse.containsMouse ? Colors.primary + : ((netRow.net.connected || netRow.passwordOpen) ? Qt.rgba(Colors.primary.r, Colors.primary.g, Colors.primary.b, 0.18) : "transparent") // Hover-only outline, offset outside the row rather than drawn on // its own edge — same treatment as ToggleSwitch's halo and the DNS @@ -708,7 +701,7 @@ Item { font.family: Appearance.iconFontFamilyRounded font.variableAxes: Appearance.iconFontAxes font.pixelSize: 16 - color: rowMouse.containsMouse ? (netRow.active ? netRow.activeHoverColor : Colors.primaryText) : Colors.foreground + color: rowMouse.containsMouse ? Colors.primaryText : Colors.foreground // The wifi-fan glyph itself is flat/wide — stretch it // vertically to read taller while keeping its width (and // the layout around it) unchanged. @@ -729,14 +722,14 @@ Item { font.family: Appearance.fontFamily font.pixelSize: Appearance.fontSize font.bold: netRow.net.connected - color: rowMouse.containsMouse ? (netRow.active ? netRow.activeHoverColor : Colors.primaryText) : Colors.foreground + color: rowMouse.containsMouse ? Colors.primaryText : Colors.foreground } Text { visible: netRow.net.connected text: "Connected" font.family: Appearance.fontFamily font.pixelSize: Appearance.fontSizeSmall - color: rowMouse.containsMouse ? (netRow.active ? netRow.activeHoverColor : Colors.primaryText) : Colors.foreground + color: rowMouse.containsMouse ? Colors.primaryText : Colors.foreground } } Text { @@ -745,7 +738,7 @@ Item { font.family: Appearance.iconFontFamilyRounded font.variableAxes: Appearance.iconFontAxes font.pixelSize: 13 - color: rowMouse.containsMouse ? (netRow.active ? netRow.activeHoverColor : Colors.primaryText) : Colors.muted + color: rowMouse.containsMouse ? Colors.primaryText : Colors.muted } Text { id: forgetIcon @@ -754,7 +747,7 @@ Item { font.family: Appearance.iconFontFamilyRounded font.variableAxes: Appearance.iconFontAxes font.pixelSize: 14 - color: rowMouse.containsMouse ? (netRow.active ? netRow.activeHoverColor : Colors.primaryText) : Colors.muted + color: rowMouse.containsMouse ? Colors.primaryText : Colors.muted } } } diff --git a/dotfiles/.config/quickshell/modules/bar/PowerButton.qml b/dotfiles/.config/quickshell/modules/bar/PowerButton.qml index 9478137..45cefa2 100644 --- a/dotfiles/.config/quickshell/modules/bar/PowerButton.qml +++ b/dotfiles/.config/quickshell/modules/bar/PowerButton.qml @@ -41,10 +41,12 @@ Item { id: menu visible: false color: "transparent" - implicitWidth: 210 - // Same padding as Volume.qml's panel. + // Same contentWidth/contentPadding split as the other panels + // (Volume.qml, NetworkIndicator.qml, etc.) rather than a single + // magic implicitWidth. + readonly property int contentWidth: 178 readonly property int contentPadding: 16 - readonly property int labelOffset: -135 + implicitWidth: contentWidth + contentPadding * 2 implicitHeight: mainColumn.implicitHeight + contentPadding * 2 anchor { @@ -122,36 +124,55 @@ Item { { label: "Shut down", icon: "power_settings_new", cmd: ["systemctl", "poweroff"] } ] + // Same shape as this project's other selectable rows + // (e.g. VpnIndicator.qml's ProviderRow, + // TailscaleIndicator.qml's ExitNodeRow): radius 0, a + // fixed-width icon column followed by a fillWidth + // label, and an offset hover halo rather than one + // drawn on the row's own edge. delegate: Rectangle { id: entry required property var modelData width: parent ? parent.width : 0 - height: 40 - radius: Appearance.radiusSmall + radius: 0 + implicitHeight: entryContent.implicitHeight + 12 color: (!entry.modelData.disabled && entryMouse.containsMouse) ? Colors.primary : "transparent" - RowLayout { + Rectangle { anchors.fill: parent - anchors.leftMargin: 8 + anchors.margins: -3 + radius: 0 + color: "transparent" + border.color: Colors.foreground + border.width: entryMouse.containsMouse ? 1 : 0 + } + + RowLayout { + id: entryContent + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.margins: 6 spacing: 8 + Text { - Layout.preferredWidth: 25 - Layout.minimumWidth: 25 - Layout.maximumWidth: 25 + Layout.preferredWidth: 20 + Layout.minimumWidth: 20 + Layout.maximumWidth: 20 horizontalAlignment: Text.AlignLeft text: entry.modelData.icon font.family: Appearance.iconFontFamilyRounded font.variableAxes: Appearance.iconFontAxes - font.pixelSize: entry.modelData.iconSize || 15 + font.pixelSize: 14 opacity: entry.modelData.disabled ? 0.4 : 1 color: entryMouse.containsMouse ? Colors.primaryText : Colors.foreground } Text { - Layout.leftMargin: menu.labelOffset + (entry.modelData.textOffset || 0) + Layout.fillWidth: true text: entry.modelData.label - horizontalAlignment: Text.AlignLeft + elide: Text.ElideRight font.family: Appearance.fontFamily - font.pixelSize: 16 + font.pixelSize: Appearance.fontSize opacity: entry.modelData.disabled ? 0.4 : 1 color: entryMouse.containsMouse ? Colors.primaryText : Colors.foreground } diff --git a/dotfiles/.config/quickshell/modules/bar/TailscaleIndicator.qml b/dotfiles/.config/quickshell/modules/bar/TailscaleIndicator.qml index ed23d33..b39cd38 100644 --- a/dotfiles/.config/quickshell/modules/bar/TailscaleIndicator.qml +++ b/dotfiles/.config/quickshell/modules/bar/TailscaleIndicator.qml @@ -547,18 +547,12 @@ Item { width: parent ? parent.width : 0 radius: 0 implicitHeight: rowContent.implicitHeight + 12 - color: exitRow.active - ? Qt.rgba(Colors.primary.r, Colors.primary.g, Colors.primary.b, 0.18) - : (rowMouse.containsMouse ? Colors.primary : "transparent") - - // Colors.primaryText (used below whenever hovered) assumes a solid - // Colors.primary fill behind it — true for a hovered *inactive* row, - // but an *active* row's background stays the translucent tint above - // even while hovered, so primaryText (dark, meant for a bright solid - // fill) reads poorly against it. This hardcoded near-white (same one - // used for TailscaleLogo's bright dots, for the same "needs to be - // reliably visible" reason) is used instead for that one case. - readonly property color activeHoverColor: "#c9f0f0f0" + // Hover checked first (same ordering as Volume.qml's DeviceRow): + // hovering always shows a solid Colors.primary fill, even for an + // already-active row, so the primaryText used below never has to + // sit on top of the dimmer translucent tint instead. + color: rowMouse.containsMouse ? Colors.primary + : (exitRow.active ? Qt.rgba(Colors.primary.r, Colors.primary.g, Colors.primary.b, 0.18) : "transparent") // Hover-only outline, offset outside the row rather than drawn on // its own edge — same treatment as NetworkIndicator.qml's NetworkRow. @@ -590,7 +584,7 @@ Item { font.family: Appearance.iconFontFamilyRounded font.variableAxes: Appearance.iconFontAxes font.pixelSize: 14 - color: rowMouse.containsMouse ? (exitRow.active ? exitRow.activeHoverColor : Colors.primaryText) : Colors.foreground + color: rowMouse.containsMouse ? Colors.primaryText : Colors.foreground } Text { Layout.fillWidth: true @@ -599,7 +593,7 @@ Item { font.family: Appearance.fontFamily font.pixelSize: Appearance.fontSize font.bold: exitRow.active - color: rowMouse.containsMouse ? (exitRow.active ? exitRow.activeHoverColor : Colors.primaryText) : Colors.foreground + color: rowMouse.containsMouse ? Colors.primaryText : Colors.foreground } Text { visible: exitRow.active @@ -607,7 +601,7 @@ Item { font.family: Appearance.iconFontFamilyRounded font.variableAxes: Appearance.iconFontAxes font.pixelSize: 14 - color: rowMouse.containsMouse ? exitRow.activeHoverColor : Colors.primary + color: rowMouse.containsMouse ? Colors.primaryText : Colors.primary } } @@ -631,9 +625,13 @@ Item { width: parent ? parent.width : 0 radius: 0 implicitHeight: accountContent.implicitHeight + 12 - color: accountRow.selected - ? Qt.rgba(Colors.primary.r, Colors.primary.g, Colors.primary.b, 0.18) - : (accountMouse.containsMouse ? Colors.primary : "transparent") + // Hover checked first (same ordering as Volume.qml's DeviceRow): + // hovering always shows a solid Colors.primary fill, even for an + // already-selected row, so the primaryText the texts below already + // assume on hover is always correct (this row had the same + // active-first ordering bug as ExitNodeRow, just never reported). + color: accountMouse.containsMouse ? Colors.primary + : (accountRow.selected ? Qt.rgba(Colors.primary.r, Colors.primary.g, Colors.primary.b, 0.18) : "transparent") // Hover-only outline, offset outside the row — same treatment as // ExitNodeRow/NetworkRow. Not inside a clipped Flickable, so no