bar tooltips: refractor tooltip bg to StyledPopup

This commit is contained in:
end-4
2025-08-11 20:33:01 +07:00
parent 291b997972
commit 6a8a9172b1
7 changed files with 284 additions and 315 deletions
@@ -97,7 +97,8 @@ MouseArea {
StyledPopup { StyledPopup {
hoverTarget: root hoverTarget: root
contentComponent: BatteryPopup {
BatteryPopup {
id: batteryPopup id: batteryPopup
anchors.centerIn: parent anchors.centerIn: parent
} }
+102 -112
View File
@@ -5,134 +5,124 @@ import qs
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
Rectangle { ColumnLayout {
id: root id: columnLayout
readonly property real margin: 10 anchors.centerIn: parent
implicitWidth: columnLayout.implicitWidth + margin * 2 spacing: 4
implicitHeight: columnLayout.implicitHeight + margin * 2
color: Appearance.colors.colSurfaceContainer
radius: Appearance.rounding.small
clip: true
ColumnLayout { // Header
id: columnLayout RowLayout {
anchors.centerIn: parent id: header
spacing: 4 spacing: 5
// Header MaterialSymbol {
RowLayout { fill: 0
id: header font.weight: Font.Medium
spacing: 5 text: "battery_android_full"
iconSize: Appearance.font.pixelSize.large
color: Appearance.colors.colOnSurfaceVariant
}
MaterialSymbol { StyledText {
fill: 0 text: "Battery"
font.weight: Font.Medium font {
text: "battery_android_full" weight: Font.Medium
iconSize: Appearance.font.pixelSize.large pixelSize: Appearance.font.pixelSize.normal
color: Appearance.colors.colOnSurfaceVariant
} }
color: Appearance.colors.colOnSurfaceVariant
}
}
StyledText { // This row is hidden when the battery is full.
text: "Battery" RowLayout {
font { spacing: 5
weight: Font.Medium Layout.fillWidth: true
pixelSize: Appearance.font.pixelSize.normal property bool rowVisible: {
} let timeValue = Battery.isCharging ? Battery.timeToFull : Battery.timeToEmpty;
color: Appearance.colors.colOnSurfaceVariant let power = Battery.energyRate;
return !(Battery.chargeState == 4 || timeValue <= 0 || power <= 0.01);
}
visible: rowVisible
opacity: rowVisible ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: 500
} }
} }
// This row is hidden when the battery is full. MaterialSymbol {
RowLayout { text: "schedule"
spacing: 5 color: Appearance.colors.colOnSurfaceVariant
iconSize: Appearance.font.pixelSize.large
}
StyledText {
text: Battery.isCharging ? Translation.tr("Time to full:") : Translation.tr("Time to empty:")
color: Appearance.colors.colOnSurfaceVariant
}
StyledText {
Layout.fillWidth: true Layout.fillWidth: true
property bool rowVisible: { horizontalAlignment: Text.AlignRight
let timeValue = Battery.isCharging ? Battery.timeToFull : Battery.timeToEmpty; color: Appearance.colors.colOnSurfaceVariant
let power = Battery.energyRate; text: {
return !(Battery.chargeState == 4 || timeValue <= 0 || power <= 0.01); function formatTime(seconds) {
} var h = Math.floor(seconds / 3600);
visible: rowVisible var m = Math.floor((seconds % 3600) / 60);
opacity: rowVisible ? 1 : 0 if (h > 0)
Behavior on opacity { return `${h}h, ${m}m`;
NumberAnimation {
duration: 500
}
}
MaterialSymbol {
text: "schedule"
color: Appearance.colors.colOnSurfaceVariant
iconSize: Appearance.font.pixelSize.large
}
StyledText {
text: Battery.isCharging ? Translation.tr("Time to full:") : Translation.tr("Time to empty:")
color: Appearance.colors.colOnSurfaceVariant
}
StyledText {
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
color: Appearance.colors.colOnSurfaceVariant
text: {
function formatTime(seconds) {
var h = Math.floor(seconds / 3600);
var m = Math.floor((seconds % 3600) / 60);
if (h > 0)
return `${h}h, ${m}m`;
else
return `${m}m`;
}
if (Battery.isCharging)
return formatTime(Battery.timeToFull);
else else
return formatTime(Battery.timeToEmpty); return `${m}m`;
} }
if (Battery.isCharging)
return formatTime(Battery.timeToFull);
else
return formatTime(Battery.timeToEmpty);
}
}
}
RowLayout {
spacing: 5
Layout.fillWidth: true
property bool rowVisible: !(Battery.chargeState != 4 && Battery.energyRate == 0)
visible: rowVisible
opacity: rowVisible ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: 500
} }
} }
RowLayout { MaterialSymbol {
spacing: 5 text: "bolt"
color: Appearance.colors.colOnSurfaceVariant
iconSize: Appearance.font.pixelSize.large
}
StyledText {
text: {
if (Battery.chargeState == 4) {
return Translation.tr("Fully charged");
} else if (Battery.chargeState == 1) {
return Translation.tr("Charging:");
} else {
return Translation.tr("Discharging:");
}
}
color: Appearance.colors.colOnSurfaceVariant
}
StyledText {
Layout.fillWidth: true Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
property bool rowVisible: !(Battery.chargeState != 4 && Battery.energyRate == 0) color: Appearance.colors.colOnSurfaceVariant
visible: rowVisible text: {
opacity: rowVisible ? 1 : 0 if (Battery.chargeState == 4) {
Behavior on opacity { return "";
NumberAnimation { } else {
duration: 500 return `${Battery.energyRate.toFixed(2)}W`;
}
}
MaterialSymbol {
text: "bolt"
color: Appearance.colors.colOnSurfaceVariant
iconSize: Appearance.font.pixelSize.large
}
StyledText {
text: {
if (Battery.chargeState == 4) {
return Translation.tr("Fully charged");
} else if (Battery.chargeState == 1) {
return Translation.tr("Charging:");
} else {
return Translation.tr("Discharging:");
}
}
color: Appearance.colors.colOnSurfaceVariant
}
StyledText {
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
color: Appearance.colors.colOnSurfaceVariant
text: {
if (Battery.chargeState == 4) {
return "";
} else {
return `${Battery.energyRate.toFixed(2)}W`;
}
} }
} }
} }
} }
} }
@@ -75,72 +75,63 @@ Item {
StyledPopup { StyledPopup {
hoverTarget: mouseArea hoverTarget: mouseArea
contentComponent: Rectangle {
id: datePopup ColumnLayout {
readonly property real margin: 12 id: columnLayout
implicitWidth: columnLayout.implicitWidth + margin * 2 anchors.centerIn: parent
implicitHeight: columnLayout.implicitHeight + margin * 2 spacing: 4
color: Appearance.colors.colSurfaceContainer
radius: Appearance.rounding.small
clip: true
// Date + Time row
RowLayout {
spacing: 5
MaterialSymbol {
fill: 0
font.weight: Font.Medium
text: "calendar_month"
iconSize: Appearance.font.pixelSize.large
color: Appearance.colors.colOnSurfaceVariant
}
StyledText {
horizontalAlignment: Text.AlignLeft
color: Appearance.colors.colOnSurfaceVariant
text: `${root.formattedDate} ${root.formattedTime}`
font.weight: Font.Medium
}
}
// Uptime row
RowLayout {
spacing: 5
Layout.fillWidth: true
MaterialSymbol { text: "timelapse"; color: Appearance.colors.colOnSurfaceVariant; font.pixelSize: Appearance.font.pixelSize.large }
StyledText { text: Translation.tr("System uptime:"); color: Appearance.colors.colOnSurfaceVariant }
StyledText {
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
color: Appearance.colors.colOnSurfaceVariant
text: root.formattedUptime
}
}
// Tasks
ColumnLayout { ColumnLayout {
id: columnLayout spacing: 0
anchors.centerIn: parent Layout.fillWidth: true
spacing: 4
// Date + Time row
RowLayout { RowLayout {
spacing: 5 spacing: 4
Layout.fillWidth: true
MaterialSymbol { MaterialSymbol { text: "checklist"; color: Appearance.colors.colOnSurfaceVariant; font.pixelSize: Appearance.font.pixelSize.large }
fill: 0 StyledText { text: Translation.tr("To Do:"); color: Appearance.colors.colOnSurfaceVariant }
font.weight: Font.Medium
text: "calendar_month"
iconSize: Appearance.font.pixelSize.large
color: Appearance.colors.colOnSurfaceVariant
}
StyledText {
horizontalAlignment: Text.AlignLeft
color: Appearance.colors.colOnSurfaceVariant
text: `${root.formattedDate} ${root.formattedTime}`
font.weight: Font.Medium
}
} }
// Uptime row StyledText {
RowLayout {
spacing: 5
Layout.fillWidth: true Layout.fillWidth: true
MaterialSymbol { text: "timelapse"; color: Appearance.colors.colOnSurfaceVariant; font.pixelSize: Appearance.font.pixelSize.large } horizontalAlignment: Text.AlignLeft
StyledText { text: Translation.tr("System uptime:"); color: Appearance.colors.colOnSurfaceVariant } wrapMode: Text.Wrap
StyledText { color: Appearance.colors.colOnSurfaceVariant
Layout.fillWidth: true text: root.todosSection
horizontalAlignment: Text.AlignRight
color: Appearance.colors.colOnSurfaceVariant
text: root.formattedUptime
}
}
// Tasks
ColumnLayout {
spacing: 0
Layout.fillWidth: true
RowLayout {
spacing: 4
Layout.fillWidth: true
MaterialSymbol { text: "checklist"; color: Appearance.colors.colOnSurfaceVariant; font.pixelSize: Appearance.font.pixelSize.large }
StyledText { text: Translation.tr("To Do:"); color: Appearance.colors.colOnSurfaceVariant }
}
StyledText {
Layout.fillWidth: true
horizontalAlignment: Text.AlignLeft
wrapMode: Text.Wrap
color: Appearance.colors.colOnSurfaceVariant
text: root.todosSection
}
} }
} }
} }
+41 -50
View File
@@ -70,70 +70,61 @@ Item {
StyledPopup { StyledPopup {
hoverTarget: mouseArea hoverTarget: mouseArea
contentComponent: Rectangle {
id: resourcePopup ColumnLayout {
readonly property real margin: 10 id: columnLayout
implicitWidth: columnLayout.implicitWidth + margin * 2 anchors.centerIn: parent
implicitHeight: columnLayout.implicitHeight + margin * 2 spacing: 4
color: Appearance.colors.colSurfaceContainer
radius: Appearance.rounding.small
clip: true
ColumnLayout { // Header
id: columnLayout RowLayout {
anchors.centerIn: parent id: header
spacing: 4 spacing: 5
// Header MaterialSymbol {
RowLayout { fill: 0
id: header font.weight: Font.Medium
text: root.tooltipHeaderIcon
iconSize: Appearance.font.pixelSize.large
color: Appearance.colors.colOnSurfaceVariant
}
StyledText {
text: root.tooltipHeaderText
font {
weight: Font.Medium
pixelSize: Appearance.font.pixelSize.normal
}
color: Appearance.colors.colOnSurfaceVariant
}
}
// Info rows
Repeater {
model: root.tooltipData
delegate: RowLayout {
spacing: 5 spacing: 5
Layout.fillWidth: true
MaterialSymbol { MaterialSymbol {
fill: 0 text: modelData.icon
font.weight: Font.Medium color: Appearance.colors.colOnSurfaceVariant
text: root.tooltipHeaderIcon
iconSize: Appearance.font.pixelSize.large iconSize: Appearance.font.pixelSize.large
color: Appearance.colors.colOnSurfaceVariant
} }
StyledText { StyledText {
text: root.tooltipHeaderText text: modelData.label
font {
weight: Font.Medium
pixelSize: Appearance.font.pixelSize.normal
}
color: Appearance.colors.colOnSurfaceVariant color: Appearance.colors.colOnSurfaceVariant
} }
} StyledText {
// Info rows
Repeater {
model: root.tooltipData
delegate: RowLayout {
spacing: 5
Layout.fillWidth: true Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
MaterialSymbol { visible: modelData.value !== ""
text: modelData.icon color: Appearance.colors.colOnSurfaceVariant
color: Appearance.colors.colOnSurfaceVariant text: modelData.value
iconSize: Appearance.font.pixelSize.large
}
StyledText {
text: modelData.label
color: Appearance.colors.colOnSurfaceVariant
}
StyledText {
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
visible: modelData.value !== ""
color: Appearance.colors.colOnSurfaceVariant
text: modelData.value
}
} }
} }
} }
} }
} }
@@ -38,7 +38,8 @@ MouseArea {
StyledPopup { StyledPopup {
hoverTarget: root hoverTarget: root
contentComponent: WeatherPopup {
WeatherPopup {
id: weatherPopup id: weatherPopup
anchors.centerIn: parent anchors.centerIn: parent
} }
@@ -6,94 +6,83 @@ import qs.modules.common.widgets
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
Rectangle { ColumnLayout {
id: root id: columnLayout
readonly property real margin: 10 spacing: 5
implicitWidth: columnLayout.implicitWidth + margin * 2 implicitWidth: Math.max(header.implicitWidth, gridLayout.implicitWidth)
implicitHeight: columnLayout.implicitHeight + margin * 2 implicitHeight: gridLayout.implicitHeight
color: Appearance.colors.colSurfaceContainer
radius: Appearance.rounding.small
clip: true
ColumnLayout { // Header
id: columnLayout RowLayout {
id: header
spacing: 5 spacing: 5
anchors.centerIn: root Layout.alignment: Qt.AlignHCenter
implicitWidth: Math.max(header.implicitWidth, gridLayout.implicitWidth)
implicitHeight: gridLayout.implicitHeight
// Header MaterialSymbol {
RowLayout { fill: 0
id: header font.weight: Font.Medium
spacing: 5 text: "location_on"
Layout.alignment: Qt.AlignHCenter iconSize: Appearance.font.pixelSize.large
color: Appearance.colors.colOnSurfaceVariant
MaterialSymbol {
fill: 0
font.weight: Font.Medium
text: "location_on"
iconSize: Appearance.font.pixelSize.large
color: Appearance.colors.colOnSurfaceVariant
}
StyledText {
text: Weather.data.city
font {
weight: Font.Medium
pixelSize: Appearance.font.pixelSize.normal
}
color: Appearance.colors.colOnSurfaceVariant
}
} }
// Metrics grid StyledText {
GridLayout { text: Weather.data.city
id: gridLayout font {
columns: 2 weight: Font.Medium
rowSpacing: 5 pixelSize: Appearance.font.pixelSize.normal
columnSpacing: 5
uniformCellWidths: true
WeatherCard {
title: Translation.tr("UV Index")
symbol: "wb_sunny"
value: Weather.data.uv
}
WeatherCard {
title: Translation.tr("Wind")
symbol: "air"
value: `(${Weather.data.windDir}) ${Weather.data.wind}`
}
WeatherCard {
title: Translation.tr("Precipitation")
symbol: "rainy_light"
value: Weather.data.precip
}
WeatherCard {
title: Translation.tr("Humidity")
symbol: "humidity_low"
value: Weather.data.humidity
}
WeatherCard {
title: Translation.tr("Visibility")
symbol: "visibility"
value: Weather.data.visib
}
WeatherCard {
title: Translation.tr("Pressure")
symbol: "readiness_score"
value: Weather.data.press
}
WeatherCard {
title: Translation.tr("Sunrise")
symbol: "wb_twilight"
value: Weather.data.sunrise
}
WeatherCard {
title: Translation.tr("Sunset")
symbol: "bedtime"
value: Weather.data.sunset
} }
color: Appearance.colors.colOnSurfaceVariant
} }
} }
}
// Metrics grid
GridLayout {
id: gridLayout
columns: 2
rowSpacing: 5
columnSpacing: 5
uniformCellWidths: true
WeatherCard {
title: Translation.tr("UV Index")
symbol: "wb_sunny"
value: Weather.data.uv
}
WeatherCard {
title: Translation.tr("Wind")
symbol: "air"
value: `(${Weather.data.windDir}) ${Weather.data.wind}`
}
WeatherCard {
title: Translation.tr("Precipitation")
symbol: "rainy_light"
value: Weather.data.precip
}
WeatherCard {
title: Translation.tr("Humidity")
symbol: "humidity_low"
value: Weather.data.humidity
}
WeatherCard {
title: Translation.tr("Visibility")
symbol: "visibility"
value: Weather.data.visib
}
WeatherCard {
title: Translation.tr("Pressure")
symbol: "readiness_score"
value: Weather.data.press
}
WeatherCard {
title: Translation.tr("Sunrise")
symbol: "wb_twilight"
value: Weather.data.sunrise
}
WeatherCard {
title: Translation.tr("Sunset")
symbol: "bedtime"
value: Weather.data.sunset
}
}
}
@@ -10,8 +10,8 @@ import Quickshell.Wayland
LazyLoader { LazyLoader {
id: root id: root
property Item hoverTarget property MouseArea hoverTarget
property Component contentComponent default property Item contentItem
active: hoverTarget && hoverTarget.containsMouse active: hoverTarget && hoverTarget.containsMouse
@@ -25,13 +25,13 @@ LazyLoader {
anchors.top: !Config.options.bar.bottom anchors.top: !Config.options.bar.bottom
anchors.bottom: Config.options.bar.bottom anchors.bottom: Config.options.bar.bottom
implicitWidth: popupContent.implicitWidth implicitWidth: popupBackground.implicitWidth
implicitHeight: popupContent.implicitHeight implicitHeight: popupBackground.implicitHeight
margins { margins {
left: root.QsWindow?.mapFromItem( left: root.QsWindow?.mapFromItem(
root.hoverTarget, root.hoverTarget,
(root.hoverTarget.width - popupContent.implicitWidth) / 2, 0 (root.hoverTarget.width - popupBackground.implicitWidth) / 2, 0
).x ).x
top: Appearance.sizes.hyprlandGapsOut top: Appearance.sizes.hyprlandGapsOut
bottom: Appearance.sizes.hyprlandGapsOut bottom: Appearance.sizes.hyprlandGapsOut
@@ -39,10 +39,16 @@ LazyLoader {
WlrLayershell.namespace: "quickshell:popup" WlrLayershell.namespace: "quickshell:popup"
WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.layer: WlrLayer.Overlay
Loader { Rectangle {
id: popupContent id: popupBackground
sourceComponent: root.contentComponent readonly property real margin: 10
anchors.centerIn: parent color: Appearance.colors.colSurfaceContainer
radius: Appearance.rounding.small
implicitWidth: root.contentItem.implicitWidth + margin * 2
implicitHeight: root.contentItem.implicitHeight + margin * 2
children: [root.contentItem]
} }
} }
} }