diff --git a/Modules/Bar/Widgets/ArchUpdater.qml b/Modules/Bar/Widgets/ArchUpdater.qml index b86eb50..e405ecf 100644 --- a/Modules/Bar/Widgets/ArchUpdater.qml +++ b/Modules/Bar/Widgets/ArchUpdater.qml @@ -48,10 +48,10 @@ NIconButton { let tooltip = header if (pacmanTooltip !== "") { - tooltip += "
" + pacmanTooltip + tooltip += "\n" + pacmanTooltip } if (aurTooltip !== "") { - tooltip += "
" + aurTooltip + tooltip += "\n" + aurTooltip } return tooltip } diff --git a/Modules/Bar/Widgets/Battery.qml b/Modules/Bar/Widgets/Battery.qml index e76a0a3..f149b9b 100644 --- a/Modules/Bar/Widgets/Battery.qml +++ b/Modules/Bar/Widgets/Battery.qml @@ -103,7 +103,7 @@ Item { let lines = [] if (testMode) { lines.push("Time left: " + Time.formatVagueHumanReadableDuration(12345)) - return lines.join("
") + return lines.join("\n") } if (!isReady || !battery.isLaptopBattery) { return "No battery detected" @@ -130,7 +130,7 @@ Item { if (battery.healthPercentage !== undefined && battery.healthPercentage > 0) { lines.push("Health: " + Math.round(battery.healthPercentage) + "%") } - return lines.join("
") + return lines.join("\n") } } } diff --git a/Modules/Bar/Widgets/Bluetooth.qml b/Modules/Bar/Widgets/Bluetooth.qml index 0b8b4f9..7cb4186 100644 --- a/Modules/Bar/Widgets/Bluetooth.qml +++ b/Modules/Bar/Widgets/Bluetooth.qml @@ -21,6 +21,6 @@ NIconButton { colorBorderHover: Color.transparent icon: "bluetooth" - tooltipText: "Bluetooth Devices" + tooltipText: "Bluetooth devices" onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(screen, this) } diff --git a/Modules/Bar/Widgets/Brightness.qml b/Modules/Bar/Widgets/Brightness.qml index 63a8c20..bc09dca 100644 --- a/Modules/Bar/Widgets/Brightness.qml +++ b/Modules/Bar/Widgets/Brightness.qml @@ -70,8 +70,8 @@ Item { var monitor = getMonitor() if (!monitor) return "" - return "Brightness: " + Math.round(monitor.brightness * 100) + "%
Method: " + monitor.method - + "
Left click for advanced settings.
Scroll up/down to change brightness." + return "Brightness: " + Math.round(monitor.brightness * 100) + "%\nMethod: " + monitor.method + + "\nLeft click for advanced settings.\nScroll up/down to change brightness." } onWheel: function (angle) { diff --git a/Modules/Bar/Widgets/KeyboardLayout.qml b/Modules/Bar/Widgets/KeyboardLayout.qml index 0ee56e5..d655055 100644 --- a/Modules/Bar/Widgets/KeyboardLayout.qml +++ b/Modules/Bar/Widgets/KeyboardLayout.qml @@ -25,7 +25,7 @@ Row { collapsedIconColor: Color.mOnSurface autoHide: false // Important to be false so we can hover as long as we want text: currentLayout - tooltipText: "Keyboard Layout: " + currentLayout + tooltipText: "Keyboard layout: " + currentLayout onClicked: { diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml index dbfe5cf..5607fe2 100644 --- a/Modules/Bar/Widgets/MediaMini.qml +++ b/Modules/Bar/Widgets/MediaMini.qml @@ -26,9 +26,8 @@ Row { NText { id: fullTitleMetrics visible: false - text: getTitle() - font.pointSize: Style.fontSizeS * scaling - font.weight: Style.fontWeightMedium + text: titleText.text + font: titleText.font } Rectangle { @@ -50,37 +49,6 @@ Row { 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 { id: mainContainer anchors.fill: parent @@ -172,18 +140,18 @@ Row { NText { id: titleText - // If hovered, show up to 400 pixels, otherwise show up to 120 pixels - width: (mouseArea.containsMouse) ? Math.min(fullTitleMetrics.contentWidth + (Style.marginS * scaling), - 400 * scaling) : Math.min( - fullTitleMetrics.contentWidth + (Style.marginS * scaling), 120 * scaling) + // If hovered or just switched window, show up to 400 pixels + // If not hovered show up to 120 pixels + width: (mouseArea.containsMouse) ? Math.min(fullTitleMetrics.contentWidth, + 400 * scaling) : Math.min(fullTitleMetrics.contentWidth, + 120 * scaling) text: getTitle() font.pointSize: Style.fontSizeS * scaling font.weight: Style.fontWeightMedium - elide: mouseArea.containsMouse ? Text.ElideNone : Text.ElideRight + elide: Text.ElideRight anchors.verticalCenter: parent.verticalCenter verticalAlignment: Text.AlignVCenter color: Color.mTertiary - clip: true Behavior on width { 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,14 +200,14 @@ Row { text: { var str = "" if (MediaService.canGoNext) { - str += "Right click for next
" + str += "Right click for next\n" } if (MediaService.canGoPrevious) { - str += "Middle click for previous
" + str += "Middle click for previous\n" } return str } target: anchor positionAbove: Settings.data.bar.position === "bottom" } -} +} \ No newline at end of file diff --git a/Modules/Bar/Widgets/NightLight.qml b/Modules/Bar/Widgets/NightLight.qml index 43e330e..f6eda83 100644 --- a/Modules/Bar/Widgets/NightLight.qml +++ b/Modules/Bar/Widgets/NightLight.qml @@ -21,7 +21,7 @@ NIconButton { colorBorderHover: Color.transparent icon: Settings.data.nightLight.enabled ? "bedtime" : "bedtime_off" - tooltipText: `Night Light: ${Settings.data.nightLight.enabled ? "enabled" : "disabled"}
Left click to toggle.
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 onRightClicked: { diff --git a/Modules/Bar/Widgets/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml index 8a1e8c3..ff0db05 100644 --- a/Modules/Bar/Widgets/NotificationHistory.qml +++ b/Modules/Bar/Widgets/NotificationHistory.qml @@ -15,7 +15,7 @@ NIconButton { sizeRatio: 0.8 icon: "notifications" - tooltipText: "Notification History" + tooltipText: "Notification history" colorBg: Color.mSurfaceVariant colorFg: Color.mOnSurface colorBorder: Color.transparent diff --git a/Modules/Bar/Widgets/ScreenRecorderIndicator.qml b/Modules/Bar/Widgets/ScreenRecorderIndicator.qml index 38ed2c7..ce68391 100644 --- a/Modules/Bar/Widgets/ScreenRecorderIndicator.qml +++ b/Modules/Bar/Widgets/ScreenRecorderIndicator.qml @@ -12,7 +12,7 @@ NIconButton { visible: ScreenRecorderService.isRecording icon: "videocam" - tooltipText: "Screen Recording Active\nClick To Stop Recording" + tooltipText: "Screen recording is active\nClick to stop recording" sizeRatio: 0.8 colorBg: Color.mPrimary colorFg: Color.mOnPrimary diff --git a/Modules/Bar/Widgets/SidePanelToggle.qml b/Modules/Bar/Widgets/SidePanelToggle.qml index 0a6e6b3..7020209 100644 --- a/Modules/Bar/Widgets/SidePanelToggle.qml +++ b/Modules/Bar/Widgets/SidePanelToggle.qml @@ -10,7 +10,7 @@ NIconButton { property real scaling: ScalingService.scale(screen) icon: "widgets" - tooltipText: "Open Side Panel" + tooltipText: "Open side panel" sizeRatio: 0.8 colorBg: Color.mSurfaceVariant diff --git a/Modules/Bar/Widgets/Taskbar.qml b/Modules/Bar/Widgets/Taskbar.qml new file mode 100644 index 0000000..04da2e0 --- /dev/null +++ b/Modules/Bar/Widgets/Taskbar.qml @@ -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" + } + } + } + } +} diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml index 24a8492..8819cc9 100644 --- a/Modules/Bar/Widgets/Volume.qml +++ b/Modules/Bar/Widgets/Volume.qml @@ -59,7 +59,7 @@ Item { autoHide: false // Important to be false so we can hover as long as we want text: Math.floor(AudioService.volume * 100) + "%" tooltipText: "Volume: " + Math.round( - AudioService.volume * 100) + "%
Left click for advanced settings.
Scroll up/down to change volume." + AudioService.volume * 100) + "%\nLeft click for advanced settings.\nScroll up/down to change volume." onWheel: function (delta) { wheelAccumulator += delta diff --git a/Modules/Bar/Widgets/WiFi.qml b/Modules/Bar/Widgets/WiFi.qml index f4ec9dd..2362a82 100644 --- a/Modules/Bar/Widgets/WiFi.qml +++ b/Modules/Bar/Widgets/WiFi.qml @@ -50,6 +50,6 @@ NIconButton { return "signal_wifi_bad" } } - tooltipText: "Network / WiFi" + tooltipText: "Network / Wi-Fi" onClicked: PanelService.getPanel("wifiPanel")?.toggle(screen, this) } diff --git a/Modules/Calendar/Calendar.qml b/Modules/Calendar/Calendar.qml index ea5b260..891a866 100644 --- a/Modules/Calendar/Calendar.qml +++ b/Modules/Calendar/Calendar.qml @@ -29,7 +29,7 @@ NPanel { NIconButton { icon: "chevron_left" - tooltipText: "Previous Month" + tooltipText: "Previous month" onClicked: { let newDate = new Date(grid.year, grid.month - 1, 1) grid.year = newDate.getFullYear() @@ -48,7 +48,7 @@ NPanel { NIconButton { icon: "chevron_right" - tooltipText: "Next Month" + tooltipText: "Next month" onClicked: { let newDate = new Date(grid.year, grid.month + 1, 1) grid.year = newDate.getFullYear() diff --git a/Modules/Notification/NotificationHistoryPanel.qml b/Modules/Notification/NotificationHistoryPanel.qml index 8001d39..3b10aec 100644 --- a/Modules/Notification/NotificationHistoryPanel.qml +++ b/Modules/Notification/NotificationHistoryPanel.qml @@ -45,7 +45,7 @@ NPanel { NIconButton { icon: "delete" - tooltipText: "Clear History" + tooltipText: "Clear history" sizeRatio: 0.8 onClicked: NotificationService.clearHistory() } @@ -158,7 +158,7 @@ NPanel { // Trash icon button NIconButton { icon: "delete" - tooltipText: "Delete Notification" + tooltipText: "Delete notification" sizeRatio: 0.7 onClicked: { diff --git a/Modules/SettingsPanel/Tabs/DisplayTab.qml b/Modules/SettingsPanel/Tabs/DisplayTab.qml index 67905aa..b2bda25 100644 --- a/Modules/SettingsPanel/Tabs/DisplayTab.qml +++ b/Modules/SettingsPanel/Tabs/DisplayTab.qml @@ -212,7 +212,7 @@ ColumnLayout { NIconButton { icon: "refresh" - tooltipText: "Reset Scaling" + tooltipText: "Reset scaling" onClicked: ScalingService.setMonitorScale(modelData.name, 1.0) } } diff --git a/Modules/SidePanel/Cards/MediaCard.qml b/Modules/SidePanel/Cards/MediaCard.qml index eaac9a5..65f7211 100644 --- a/Modules/SidePanel/Cards/MediaCard.qml +++ b/Modules/SidePanel/Cards/MediaCard.qml @@ -324,7 +324,7 @@ NBox { // Next button NIconButton { icon: "skip_next" - tooltipText: "Next Media" + tooltipText: "Next media" visible: MediaService.canGoNext onClicked: MediaService.canGoNext ? MediaService.next() : {} } diff --git a/Modules/SidePanel/Cards/PowerProfilesCard.qml b/Modules/SidePanel/Cards/PowerProfilesCard.qml index 2c36642..2bdd88a 100644 --- a/Modules/SidePanel/Cards/PowerProfilesCard.qml +++ b/Modules/SidePanel/Cards/PowerProfilesCard.qml @@ -29,7 +29,7 @@ NBox { // Performance NIconButton { icon: "speed" - tooltipText: "Set Performance Power Profile" + tooltipText: "Set performance power profile" enabled: hasPP opacity: enabled ? Style.opacityFull : Style.opacityMedium colorBg: (enabled && powerProfiles.profile === PowerProfile.Performance) ? Color.mPrimary : Color.mSurfaceVariant @@ -43,7 +43,7 @@ NBox { // Balanced NIconButton { icon: "balance" - tooltipText: "Set Balanced Power Profile" + tooltipText: "Set balanced power profile" enabled: hasPP opacity: enabled ? Style.opacityFull : Style.opacityMedium colorBg: (enabled && powerProfiles.profile === PowerProfile.Balanced) ? Color.mPrimary : Color.mSurfaceVariant @@ -57,7 +57,7 @@ NBox { // Eco NIconButton { icon: "eco" - tooltipText: "Set Eco Power Profile" + tooltipText: "Set eco power profile" enabled: hasPP opacity: enabled ? Style.opacityFull : Style.opacityMedium colorBg: (enabled && powerProfiles.profile === PowerProfile.PowerSaver) ? Color.mPrimary : Color.mSurfaceVariant diff --git a/Modules/SidePanel/Cards/ProfileCard.qml b/Modules/SidePanel/Cards/ProfileCard.qml index 7374159..d58abe8 100644 --- a/Modules/SidePanel/Cards/ProfileCard.qml +++ b/Modules/SidePanel/Cards/ProfileCard.qml @@ -58,7 +58,7 @@ NBox { } NIconButton { icon: "settings" - tooltipText: "Open Settings" + tooltipText: "Open settings" onClicked: { settingsPanel.requestedTab = SettingsPanel.Tab.General settingsPanel.open(screen) @@ -68,7 +68,7 @@ NBox { NIconButton { id: powerButton icon: "power_settings_new" - tooltipText: "Power Menu" + tooltipText: "Power menu" onClicked: { powerPanel.open(screen) sidePanel.close() @@ -78,7 +78,7 @@ NBox { NIconButton { id: closeButton icon: "close" - tooltipText: "Close Side Panel" + tooltipText: "Close side panel" onClicked: { sidePanel.close() } diff --git a/Modules/SidePanel/Cards/UtilitiesCard.qml b/Modules/SidePanel/Cards/UtilitiesCard.qml index 26f3b4e..5bb6a05 100644 --- a/Modules/SidePanel/Cards/UtilitiesCard.qml +++ b/Modules/SidePanel/Cards/UtilitiesCard.qml @@ -26,7 +26,7 @@ NBox { // Screen Recorder NIconButton { 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 colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mPrimary onClicked: { @@ -37,7 +37,7 @@ NBox { // Idle Inhibitor NIconButton { 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 colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mPrimary onClicked: { @@ -48,7 +48,7 @@ NBox { // Wallpaper NIconButton { icon: "image" - tooltipText: "Open Wallpaper Selector" + tooltipText: "Open wallpaper selector" onClicked: { var settingsPanel = PanelService.getPanel("settingsPanel") settingsPanel.requestedTab = SettingsPanel.Tab.WallpaperSelector diff --git a/Modules/WiFiPanel/WiFiPanel.qml b/Modules/WiFiPanel/WiFiPanel.qml index 3780b6f..4349cc4 100644 --- a/Modules/WiFiPanel/WiFiPanel.qml +++ b/Modules/WiFiPanel/WiFiPanel.qml @@ -51,7 +51,7 @@ NPanel { NIconButton { icon: "refresh" - tooltipText: "Refresh Networks" + tooltipText: "Refresh networks" sizeRatio: 0.8 enabled: Settings.data.network.wifiEnabled && !NetworkService.isLoading onClicked: { diff --git a/Services/ArchUpdaterService.qml b/Services/ArchUpdaterService.qml index 02d2f06..7f5444d 100644 --- a/Services/ArchUpdaterService.qml +++ b/Services/ArchUpdaterService.qml @@ -141,7 +141,7 @@ Singleton { onExited: function (exitCode) { if (exitCode === 0 && updateInProgress) { // Success indicators found - console.log("ArchUpdater: Update completed successfully") + Logger.log("ArchUpdater", "Update completed successfully") updateInProgress = false updateFailed = false updateCompleteTimer.stop() diff --git a/Services/BarWidgetRegistry.qml b/Services/BarWidgetRegistry.qml index 5ff44fd..4ea47bd 100644 --- a/Services/BarWidgetRegistry.qml +++ b/Services/BarWidgetRegistry.qml @@ -23,6 +23,7 @@ Singleton { "ScreenRecorderIndicator": screenRecorderIndicatorComponent, "SidePanelToggle": sidePanelToggleComponent, "SystemMonitor": systemMonitorComponent, + "Taskbar": taskbarComponent, "Tray": trayComponent, "Volume": volumeComponent, "WiFi": wiFiComponent, @@ -84,6 +85,9 @@ Singleton { property Component workspaceComponent: Component { Workspace {} } + property Component taskbarComponent: Component { + Taskbar {} + } // ------------------------------ // Helper function to get widget component by name diff --git a/Widgets/NText.qml b/Widgets/NText.qml index 1d54c89..00f5561 100644 --- a/Widgets/NText.qml +++ b/Widgets/NText.qml @@ -13,5 +13,4 @@ Text { font.kerning: true color: Color.mOnSurface renderType: Text.QtRendering - textFormat: Text.RichText }