This commit is contained in:
Ly-sec 2025-08-31 15:00:56 +02:00
commit ab5b877dc3
24 changed files with 175 additions and 75 deletions

View file

@ -48,10 +48,10 @@ NIconButton {
let tooltip = header let tooltip = header
if (pacmanTooltip !== "") { if (pacmanTooltip !== "") {
tooltip += "<br/>" + pacmanTooltip tooltip += "\n" + pacmanTooltip
} }
if (aurTooltip !== "") { if (aurTooltip !== "") {
tooltip += "<br/>" + aurTooltip tooltip += "\n" + aurTooltip
} }
return tooltip return tooltip
} }

View file

@ -103,7 +103,7 @@ Item {
let lines = [] let lines = []
if (testMode) { if (testMode) {
lines.push("Time left: " + Time.formatVagueHumanReadableDuration(12345)) lines.push("Time left: " + Time.formatVagueHumanReadableDuration(12345))
return lines.join("<br/>") return lines.join("\n")
} }
if (!isReady || !battery.isLaptopBattery) { if (!isReady || !battery.isLaptopBattery) {
return "No battery detected" return "No battery detected"
@ -130,7 +130,7 @@ Item {
if (battery.healthPercentage !== undefined && battery.healthPercentage > 0) { if (battery.healthPercentage !== undefined && battery.healthPercentage > 0) {
lines.push("Health: " + Math.round(battery.healthPercentage) + "%") lines.push("Health: " + Math.round(battery.healthPercentage) + "%")
} }
return lines.join("<br/>") return lines.join("\n")
} }
} }
} }

View file

@ -21,6 +21,6 @@ NIconButton {
colorBorderHover: Color.transparent colorBorderHover: Color.transparent
icon: "bluetooth" icon: "bluetooth"
tooltipText: "Bluetooth Devices" tooltipText: "Bluetooth devices"
onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(screen, this) onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(screen, this)
} }

View file

@ -70,8 +70,8 @@ Item {
var monitor = getMonitor() var monitor = getMonitor()
if (!monitor) if (!monitor)
return "" return ""
return "Brightness: " + Math.round(monitor.brightness * 100) + "%<br/>Method: " + monitor.method return "Brightness: " + Math.round(monitor.brightness * 100) + "%\nMethod: " + monitor.method
+ "<br/>Left click for advanced settings.<br/>Scroll up/down to change brightness." + "\nLeft click for advanced settings.\nScroll up/down to change brightness."
} }
onWheel: function (angle) { onWheel: function (angle) {

View file

@ -25,7 +25,7 @@ Row {
collapsedIconColor: Color.mOnSurface collapsedIconColor: Color.mOnSurface
autoHide: false // Important to be false so we can hover as long as we want autoHide: false // Important to be false so we can hover as long as we want
text: currentLayout text: currentLayout
tooltipText: "Keyboard Layout: " + currentLayout tooltipText: "Keyboard layout: " + currentLayout
onClicked: { onClicked: {

View file

@ -26,9 +26,8 @@ Row {
NText { NText {
id: fullTitleMetrics id: fullTitleMetrics
visible: false visible: false
text: getTitle() text: titleText.text
font.pointSize: Style.fontSizeS * scaling font: titleText.font
font.weight: Style.fontWeightMedium
} }
Rectangle { Rectangle {
@ -50,37 +49,6 @@ Row {
width: 200 * scaling width: 200 * scaling
} }
// Mouse area for hover detection - direct child of Rectangle
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
onClicked: mouse => {
if (mouse.button === Qt.LeftButton) {
MediaService.playPause()
} else if (mouse.button == Qt.RightButton) {
MediaService.next()
// Need to hide the tooltip instantly
tooltip.visible = false
} else if (mouse.button == Qt.MiddleButton) {
MediaService.previous()
// Need to hide the tooltip instantly
tooltip.visible = false
}
}
onEntered: {
if (tooltip.text !== "") {
tooltip.show()
}
}
onExited: {
tooltip.hide()
}
}
Item { Item {
id: mainContainer id: mainContainer
anchors.fill: parent anchors.fill: parent
@ -172,18 +140,18 @@ Row {
NText { NText {
id: titleText id: titleText
// If hovered, show up to 400 pixels, otherwise show up to 120 pixels // If hovered or just switched window, show up to 400 pixels
width: (mouseArea.containsMouse) ? Math.min(fullTitleMetrics.contentWidth + (Style.marginS * scaling), // If not hovered show up to 120 pixels
400 * scaling) : Math.min( width: (mouseArea.containsMouse) ? Math.min(fullTitleMetrics.contentWidth,
fullTitleMetrics.contentWidth + (Style.marginS * scaling), 120 * scaling) 400 * scaling) : Math.min(fullTitleMetrics.contentWidth,
120 * scaling)
text: getTitle() text: getTitle()
font.pointSize: Style.fontSizeS * scaling font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightMedium font.weight: Style.fontWeightMedium
elide: mouseArea.containsMouse ? Text.ElideNone : Text.ElideRight elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
color: Color.mTertiary color: Color.mTertiary
clip: true
Behavior on width { Behavior on width {
NumberAnimation { NumberAnimation {
@ -193,6 +161,37 @@ Row {
} }
} }
} }
// Mouse area for hover detection
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
onClicked: mouse => {
if (mouse.button === Qt.LeftButton) {
MediaService.playPause()
} else if (mouse.button == Qt.RightButton) {
MediaService.next()
// Need to hide the tooltip instantly
tooltip.visible = false
} else if (mouse.button == Qt.MiddleButton) {
MediaService.previous()
// Need to hide the tooltip instantly
tooltip.visible = false
}
}
onEntered: {
if (tooltip.text !== "") {
tooltip.show()
}
}
onExited: {
tooltip.hide()
}
}
} }
} }
@ -201,10 +200,10 @@ Row {
text: { text: {
var str = "" var str = ""
if (MediaService.canGoNext) { if (MediaService.canGoNext) {
str += "Right click for next<br/>" str += "Right click for next\n"
} }
if (MediaService.canGoPrevious) { if (MediaService.canGoPrevious) {
str += "Middle click for previous<br/>" str += "Middle click for previous\n"
} }
return str return str
} }

View file

@ -21,7 +21,7 @@ NIconButton {
colorBorderHover: Color.transparent colorBorderHover: Color.transparent
icon: Settings.data.nightLight.enabled ? "bedtime" : "bedtime_off" icon: Settings.data.nightLight.enabled ? "bedtime" : "bedtime_off"
tooltipText: `Night Light: ${Settings.data.nightLight.enabled ? "enabled" : "disabled"}<br/>Left click to toggle.<br/>Right click to access settings.` tooltipText: `Night light: ${Settings.data.nightLight.enabled ? "enabled" : "disabled"}\nLeft click to toggle.\nRight click to access settings.`
onClicked: Settings.data.nightLight.enabled = !Settings.data.nightLight.enabled onClicked: Settings.data.nightLight.enabled = !Settings.data.nightLight.enabled
onRightClicked: { onRightClicked: {

View file

@ -15,7 +15,7 @@ NIconButton {
sizeRatio: 0.8 sizeRatio: 0.8
icon: "notifications" icon: "notifications"
tooltipText: "Notification History" tooltipText: "Notification history"
colorBg: Color.mSurfaceVariant colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface colorFg: Color.mOnSurface
colorBorder: Color.transparent colorBorder: Color.transparent

View file

@ -12,7 +12,7 @@ NIconButton {
visible: ScreenRecorderService.isRecording visible: ScreenRecorderService.isRecording
icon: "videocam" icon: "videocam"
tooltipText: "Screen Recording Active\nClick To Stop Recording" tooltipText: "Screen recording is active\nClick to stop recording"
sizeRatio: 0.8 sizeRatio: 0.8
colorBg: Color.mPrimary colorBg: Color.mPrimary
colorFg: Color.mOnPrimary colorFg: Color.mOnPrimary

View file

@ -10,7 +10,7 @@ NIconButton {
property real scaling: ScalingService.scale(screen) property real scaling: ScalingService.scale(screen)
icon: "widgets" icon: "widgets"
tooltipText: "Open Side Panel" tooltipText: "Open side panel"
sizeRatio: 0.8 sizeRatio: 0.8
colorBg: Color.mSurfaceVariant colorBg: Color.mSurfaceVariant

View file

@ -0,0 +1,98 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Widgets
import Quickshell.Wayland
import qs.Commons
import qs.Services
import qs.Widgets
Rectangle {
id: root
property ShellScreen screen
property real scaling: ScalingService.scale(screen)
readonly property real itemSize: Style.baseWidgetSize * 0.8 * scaling
// Always visible when there are toplevels
implicitWidth: taskbarRow.width + Style.marginM * scaling * 2
implicitHeight: Math.round(Style.capsuleHeight * scaling)
radius: Math.round(Style.radiusM * scaling)
color: Color.mSurfaceVariant
Row {
id: taskbarRow
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
spacing: Style.marginXXS * root.scaling
Repeater {
model: ToplevelManager && ToplevelManager.toplevels ? ToplevelManager.toplevels : []
delegate: Item {
id: taskbarItem
required property Toplevel modelData
property Toplevel toplevel: modelData
property bool isActive: ToplevelManager.activeToplevel === modelData
width: root.itemSize
height: root.itemSize
Rectangle {
id: iconBackground
anchors.centerIn: parent
width: root.itemSize * 0.75
height: root.itemSize * 0.75
color: taskbarItem.isActive ? Color.mPrimary : root.color
border.width: 0
radius: Math.round(Style.radiusXS * root.scaling)
border.color: "transparent"
z: -1
IconImage {
id: appIcon
anchors.centerIn: parent
width: Style.marginL * root.scaling
height: Style.marginL * root.scaling
source: Icons.iconForAppId(taskbarItem.modelData.appId)
smooth: true
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: function(mouse) {
if (!taskbarItem.modelData) return
if (mouse.button === Qt.LeftButton) {
try {
taskbarItem.modelData.activate()
} catch (error) {
Logger.error("Taskbar", "Failed to activate toplevel: " + error)
}
} else if (mouse.button === Qt.RightButton) {
try {
taskbarItem.modelData.close()
} catch (error) {
Logger.error("Taskbar", "Failed to close toplevel: " + error)
}
}
}
onEntered: taskbarTooltip.show()
onExited: taskbarTooltip.hide()
}
NTooltip {
id: taskbarTooltip
text: taskbarItem.modelData.title || taskbarItem.modelData.appId || "Unknown App"
target: taskbarItem
positionAbove: Settings.data.bar.position === "bottom"
}
}
}
}
}

View file

@ -59,7 +59,7 @@ Item {
autoHide: false // Important to be false so we can hover as long as we want autoHide: false // Important to be false so we can hover as long as we want
text: Math.floor(AudioService.volume * 100) + "%" text: Math.floor(AudioService.volume * 100) + "%"
tooltipText: "Volume: " + Math.round( tooltipText: "Volume: " + Math.round(
AudioService.volume * 100) + "%<br/>Left click for advanced settings.<br/>Scroll up/down to change volume." AudioService.volume * 100) + "%\nLeft click for advanced settings.\nScroll up/down to change volume."
onWheel: function (delta) { onWheel: function (delta) {
wheelAccumulator += delta wheelAccumulator += delta

View file

@ -50,6 +50,6 @@ NIconButton {
return "signal_wifi_bad" return "signal_wifi_bad"
} }
} }
tooltipText: "Network / WiFi" tooltipText: "Network / Wi-Fi"
onClicked: PanelService.getPanel("wifiPanel")?.toggle(screen, this) onClicked: PanelService.getPanel("wifiPanel")?.toggle(screen, this)
} }

View file

@ -29,7 +29,7 @@ NPanel {
NIconButton { NIconButton {
icon: "chevron_left" icon: "chevron_left"
tooltipText: "Previous Month" tooltipText: "Previous month"
onClicked: { onClicked: {
let newDate = new Date(grid.year, grid.month - 1, 1) let newDate = new Date(grid.year, grid.month - 1, 1)
grid.year = newDate.getFullYear() grid.year = newDate.getFullYear()
@ -48,7 +48,7 @@ NPanel {
NIconButton { NIconButton {
icon: "chevron_right" icon: "chevron_right"
tooltipText: "Next Month" tooltipText: "Next month"
onClicked: { onClicked: {
let newDate = new Date(grid.year, grid.month + 1, 1) let newDate = new Date(grid.year, grid.month + 1, 1)
grid.year = newDate.getFullYear() grid.year = newDate.getFullYear()

View file

@ -45,7 +45,7 @@ NPanel {
NIconButton { NIconButton {
icon: "delete" icon: "delete"
tooltipText: "Clear History" tooltipText: "Clear history"
sizeRatio: 0.8 sizeRatio: 0.8
onClicked: NotificationService.clearHistory() onClicked: NotificationService.clearHistory()
} }
@ -158,7 +158,7 @@ NPanel {
// Trash icon button // Trash icon button
NIconButton { NIconButton {
icon: "delete" icon: "delete"
tooltipText: "Delete Notification" tooltipText: "Delete notification"
sizeRatio: 0.7 sizeRatio: 0.7
onClicked: { onClicked: {

View file

@ -212,7 +212,7 @@ ColumnLayout {
NIconButton { NIconButton {
icon: "refresh" icon: "refresh"
tooltipText: "Reset Scaling" tooltipText: "Reset scaling"
onClicked: ScalingService.setMonitorScale(modelData.name, 1.0) onClicked: ScalingService.setMonitorScale(modelData.name, 1.0)
} }
} }

View file

@ -324,7 +324,7 @@ NBox {
// Next button // Next button
NIconButton { NIconButton {
icon: "skip_next" icon: "skip_next"
tooltipText: "Next Media" tooltipText: "Next media"
visible: MediaService.canGoNext visible: MediaService.canGoNext
onClicked: MediaService.canGoNext ? MediaService.next() : {} onClicked: MediaService.canGoNext ? MediaService.next() : {}
} }

View file

@ -29,7 +29,7 @@ NBox {
// Performance // Performance
NIconButton { NIconButton {
icon: "speed" icon: "speed"
tooltipText: "Set Performance Power Profile" tooltipText: "Set performance power profile"
enabled: hasPP enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium opacity: enabled ? Style.opacityFull : Style.opacityMedium
colorBg: (enabled && powerProfiles.profile === PowerProfile.Performance) ? Color.mPrimary : Color.mSurfaceVariant colorBg: (enabled && powerProfiles.profile === PowerProfile.Performance) ? Color.mPrimary : Color.mSurfaceVariant
@ -43,7 +43,7 @@ NBox {
// Balanced // Balanced
NIconButton { NIconButton {
icon: "balance" icon: "balance"
tooltipText: "Set Balanced Power Profile" tooltipText: "Set balanced power profile"
enabled: hasPP enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium opacity: enabled ? Style.opacityFull : Style.opacityMedium
colorBg: (enabled && powerProfiles.profile === PowerProfile.Balanced) ? Color.mPrimary : Color.mSurfaceVariant colorBg: (enabled && powerProfiles.profile === PowerProfile.Balanced) ? Color.mPrimary : Color.mSurfaceVariant
@ -57,7 +57,7 @@ NBox {
// Eco // Eco
NIconButton { NIconButton {
icon: "eco" icon: "eco"
tooltipText: "Set Eco Power Profile" tooltipText: "Set eco power profile"
enabled: hasPP enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium opacity: enabled ? Style.opacityFull : Style.opacityMedium
colorBg: (enabled && powerProfiles.profile === PowerProfile.PowerSaver) ? Color.mPrimary : Color.mSurfaceVariant colorBg: (enabled && powerProfiles.profile === PowerProfile.PowerSaver) ? Color.mPrimary : Color.mSurfaceVariant

View file

@ -58,7 +58,7 @@ NBox {
} }
NIconButton { NIconButton {
icon: "settings" icon: "settings"
tooltipText: "Open Settings" tooltipText: "Open settings"
onClicked: { onClicked: {
settingsPanel.requestedTab = SettingsPanel.Tab.General settingsPanel.requestedTab = SettingsPanel.Tab.General
settingsPanel.open(screen) settingsPanel.open(screen)
@ -68,7 +68,7 @@ NBox {
NIconButton { NIconButton {
id: powerButton id: powerButton
icon: "power_settings_new" icon: "power_settings_new"
tooltipText: "Power Menu" tooltipText: "Power menu"
onClicked: { onClicked: {
powerPanel.open(screen) powerPanel.open(screen)
sidePanel.close() sidePanel.close()
@ -78,7 +78,7 @@ NBox {
NIconButton { NIconButton {
id: closeButton id: closeButton
icon: "close" icon: "close"
tooltipText: "Close Side Panel" tooltipText: "Close side panel"
onClicked: { onClicked: {
sidePanel.close() sidePanel.close()
} }

View file

@ -26,7 +26,7 @@ NBox {
// Screen Recorder // Screen Recorder
NIconButton { NIconButton {
icon: "videocam" icon: "videocam"
tooltipText: ScreenRecorderService.isRecording ? "Stop Screen Recording" : "Start Screen Recording" tooltipText: ScreenRecorderService.isRecording ? "Stop screen recording" : "Start screen recording"
colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : Color.mSurfaceVariant colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : Color.mSurfaceVariant
colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mPrimary colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mPrimary
onClicked: { onClicked: {
@ -37,7 +37,7 @@ NBox {
// Idle Inhibitor // Idle Inhibitor
NIconButton { NIconButton {
icon: "coffee" icon: "coffee"
tooltipText: IdleInhibitorService.isInhibited ? "Disable Keep Awake" : "Enable Keep Awake" tooltipText: IdleInhibitorService.isInhibited ? "Disable keep awake" : "Enable keep awake"
colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant
colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mPrimary colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mPrimary
onClicked: { onClicked: {
@ -48,7 +48,7 @@ NBox {
// Wallpaper // Wallpaper
NIconButton { NIconButton {
icon: "image" icon: "image"
tooltipText: "Open Wallpaper Selector" tooltipText: "Open wallpaper selector"
onClicked: { onClicked: {
var settingsPanel = PanelService.getPanel("settingsPanel") var settingsPanel = PanelService.getPanel("settingsPanel")
settingsPanel.requestedTab = SettingsPanel.Tab.WallpaperSelector settingsPanel.requestedTab = SettingsPanel.Tab.WallpaperSelector

View file

@ -51,7 +51,7 @@ NPanel {
NIconButton { NIconButton {
icon: "refresh" icon: "refresh"
tooltipText: "Refresh Networks" tooltipText: "Refresh networks"
sizeRatio: 0.8 sizeRatio: 0.8
enabled: Settings.data.network.wifiEnabled && !NetworkService.isLoading enabled: Settings.data.network.wifiEnabled && !NetworkService.isLoading
onClicked: { onClicked: {

View file

@ -141,7 +141,7 @@ Singleton {
onExited: function (exitCode) { onExited: function (exitCode) {
if (exitCode === 0 && updateInProgress) { if (exitCode === 0 && updateInProgress) {
// Success indicators found // Success indicators found
console.log("ArchUpdater: Update completed successfully") Logger.log("ArchUpdater", "Update completed successfully")
updateInProgress = false updateInProgress = false
updateFailed = false updateFailed = false
updateCompleteTimer.stop() updateCompleteTimer.stop()

View file

@ -23,6 +23,7 @@ Singleton {
"ScreenRecorderIndicator": screenRecorderIndicatorComponent, "ScreenRecorderIndicator": screenRecorderIndicatorComponent,
"SidePanelToggle": sidePanelToggleComponent, "SidePanelToggle": sidePanelToggleComponent,
"SystemMonitor": systemMonitorComponent, "SystemMonitor": systemMonitorComponent,
"Taskbar": taskbarComponent,
"Tray": trayComponent, "Tray": trayComponent,
"Volume": volumeComponent, "Volume": volumeComponent,
"WiFi": wiFiComponent, "WiFi": wiFiComponent,
@ -84,6 +85,9 @@ Singleton {
property Component workspaceComponent: Component { property Component workspaceComponent: Component {
Workspace {} Workspace {}
} }
property Component taskbarComponent: Component {
Taskbar {}
}
// ------------------------------ // ------------------------------
// Helper function to get widget component by name // Helper function to get widget component by name

View file

@ -13,5 +13,4 @@ Text {
font.kerning: true font.kerning: true
color: Color.mOnSurface color: Color.mOnSurface
renderType: Text.QtRendering renderType: Text.QtRendering
textFormat: Text.RichText
} }