From 8a17c047c9c78323be897370409d98bd12432134 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Mon, 15 Sep 2025 19:01:18 +0200 Subject: [PATCH 01/36] README: add missing icon info --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 0429709..c5943af 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,23 @@ Start the Shell with: `qs -c noctalia-shell` Access settings through the side panel (top right button) to configure weather, wallpapers, screen recording, audio, network, and theme options. Configuration is usually stored in ~/.config/noctalia. +### Some of my app icons are missing! + +The issue is most likely that you did not set up your environment variables properly. +Example environment variables that you can use one of the following: + +If you already have an icon theme set for GTK then you can use this one: +- `QT_QPA_PLATFORMTHEME=gtk3` + +You can also use Qt6ct to set your icon theme, for that you can use: +- `QT_QPA_PLATFORMTHEME=qt6ct` + +If you don't have either of those set then you can just use: +- `QS_ICON_THEME="youricontheme"` + +**Any of these environment variables should go into `/etc/environment` (you need to reboot afterwards). For NixOS you can use `environment.variables` or `home.sessionVariables`.** + + ### Application Launcher The launcher supports special commands for enhanced functionality: From 4edeedd5ad89dcef5dcdc2ce4b26c02776fd95cd Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Mon, 15 Sep 2025 13:19:12 -0400 Subject: [PATCH 02/36] v2.9.2-dev --- Services/UpdateService.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Services/UpdateService.qml b/Services/UpdateService.qml index c56a489..5c3606b 100644 --- a/Services/UpdateService.qml +++ b/Services/UpdateService.qml @@ -9,7 +9,7 @@ Singleton { // Public properties property string baseVersion: "2.9.2" - property bool isDevelopment: false + property bool isDevelopment: true property string currentVersion: `v${!isDevelopment ? baseVersion : baseVersion + "-dev"}` From 2a62a13b16a5cbdc115999ce4f866dea37e705d6 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Mon, 15 Sep 2025 19:40:00 +0200 Subject: [PATCH 03/36] README: remove useless layer-rule --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index c5943af..d839edc 100644 --- a/README.md +++ b/README.md @@ -295,10 +295,6 @@ window-rule { clip-to-geometry true } -layer-rule { - match namespace="^quickshell-wallpaper$" -} - layer-rule { match namespace="^quickshell-overview$" place-within-backdrop true From 33a75d042db916633772a301f84c8b823f996f46 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Mon, 15 Sep 2025 21:07:42 -0400 Subject: [PATCH 04/36] IconImage: They have to be asynchronous or the may crash QS on startup. TaskBar was crashing very often during development. --- Modules/Bar/Widgets/SidePanelToggle.qml | 1 + Modules/Bar/Widgets/Taskbar.qml | 1 + 2 files changed, 2 insertions(+) diff --git a/Modules/Bar/Widgets/SidePanelToggle.qml b/Modules/Bar/Widgets/SidePanelToggle.qml index c3347a8..293a2ca 100644 --- a/Modules/Bar/Widgets/SidePanelToggle.qml +++ b/Modules/Bar/Widgets/SidePanelToggle.qml @@ -51,5 +51,6 @@ NIconButton { source: useDistroLogo ? DistroLogoService.osLogo : "" visible: useDistroLogo && source !== "" smooth: true + asynchronous: true } } diff --git a/Modules/Bar/Widgets/Taskbar.qml b/Modules/Bar/Widgets/Taskbar.qml index 3c570ec..14fbc55 100644 --- a/Modules/Bar/Widgets/Taskbar.qml +++ b/Modules/Bar/Widgets/Taskbar.qml @@ -58,6 +58,7 @@ Rectangle { height: Style.marginL * root.scaling source: AppIcons.iconForAppId(taskbarItem.modelData.appId) smooth: true + asynchronous: true } } From abe51f49286035d23fa88032f911833ec0ffa11d Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Mon, 15 Sep 2025 21:21:42 -0400 Subject: [PATCH 05/36] NSpinBox: use fixed font for number --- Widgets/NSpinBox.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/Widgets/NSpinBox.qml b/Widgets/NSpinBox.qml index cbc1561..0f5feb0 100644 --- a/Widgets/NSpinBox.qml +++ b/Widgets/NSpinBox.qml @@ -173,6 +173,7 @@ RowLayout { NText { anchors.centerIn: parent text: root.prefix + spinBox.value + root.suffix + font.family: Settings.data.ui.fontFixed font.pointSize: Style.fontSizeM * scaling font.weight: Style.fontWeightMedium color: Color.mOnSurface From 593a0bfc2cfef9a4f0337e4c6bc4ce7660f81478 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Mon, 15 Sep 2025 21:36:09 -0400 Subject: [PATCH 06/36] NColorPicker: sizing improvements --- Widgets/NColorPicker.qml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Widgets/NColorPicker.qml b/Widgets/NColorPicker.qml index 92525dd..c638e44 100644 --- a/Widgets/NColorPicker.qml +++ b/Widgets/NColorPicker.qml @@ -13,7 +13,7 @@ Rectangle { signal colorSelected(color color) implicitWidth: 150 * scaling - implicitHeight: 40 * scaling + implicitHeight: Math.round(Style.baseWidgetSize * 1.1 * scaling) radius: Style.radiusM * scaling color: Color.mSurface @@ -40,12 +40,16 @@ Rectangle { RowLayout { anchors.fill: parent - anchors.margins: Style.marginS * scaling + anchors { + leftMargin: Style.marginL * scaling + rightMargin: Style.marginL * scaling + } spacing: Style.marginS * scaling + // Color preview circle Rectangle { - Layout.preferredWidth: 24 * scaling - Layout.preferredHeight: 24 * scaling + Layout.preferredWidth: root.height * 0.6 * scaling + Layout.preferredHeight: root.height * 0.6 * scaling radius: Layout.preferredWidth * 0.5 color: root.selectedColor border.color: Color.mOutline @@ -56,11 +60,14 @@ Rectangle { text: root.selectedColor.toString().toUpperCase() font.family: Settings.data.ui.fontFixed Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter } NIcon { icon: "color-picker" color: Color.mOnSurfaceVariant + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter } } } From 47ef62beb36a2416f0260f81bf8aa05d61df4a00 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Mon, 15 Sep 2025 22:33:09 -0400 Subject: [PATCH 07/36] Widgets Sizing: reworked our sizing approach to prepare for different bar densities. --- Commons/Style.qml | 14 +++++----- Modules/Bar/Bar.qml | 17 +++--------- Modules/Bar/Widgets/ActiveWindow.qml | 21 ++++++++------- Modules/Bar/Widgets/Bluetooth.qml | 2 +- Modules/Bar/Widgets/Clock.qml | 2 +- Modules/Bar/Widgets/DarkModeToggle.qml | 4 +-- Modules/Bar/Widgets/KeepAwake.qml | 7 ++--- Modules/Bar/Widgets/NightLight.qml | 2 +- Modules/Bar/Widgets/NotificationHistory.qml | 2 +- Modules/Bar/Widgets/PowerProfile.qml | 2 +- Modules/Bar/Widgets/PowerToggle.qml | 2 +- .../Bar/Widgets/ScreenRecorderIndicator.qml | 2 +- Modules/Bar/Widgets/SidePanelToggle.qml | 2 +- Modules/Bar/Widgets/Taskbar.qml | 2 +- Modules/Bar/Widgets/WiFi.qml | 3 +-- Modules/BluetoothPanel/BluetoothPanel.qml | 4 +-- Modules/Notification/Notification.qml | 2 +- .../Notification/NotificationHistoryPanel.qml | 12 ++++----- .../SettingsPanel/Bar/BarSectionEditor.qml | 7 +++-- Modules/SettingsPanel/Tabs/AudioTab.qml | 2 +- Modules/SettingsPanel/Tabs/BarTab.qml | 4 +-- Modules/SettingsPanel/Tabs/DisplayTab.qml | 20 ++++---------- Modules/SettingsPanel/Tabs/DockTab.qml | 4 +-- .../SettingsPanel/Tabs/NotificationTab.qml | 4 +-- Modules/Toast/SimpleToast.qml | 2 +- Modules/WiFiPanel/WiFiPanel.qml | 12 ++++----- Widgets/NIconButton.qml | 9 +++---- Widgets/NPill.qml | 3 --- Widgets/NPillHorizontal.qml | 27 +++++++++---------- Widgets/NPillVertical.qml | 3 +-- Widgets/NWidgetLoader.qml | 2 +- 31 files changed, 88 insertions(+), 113 deletions(-) diff --git a/Commons/Style.qml b/Commons/Style.qml index 97f6258..109400f 100644 --- a/Commons/Style.qml +++ b/Commons/Style.qml @@ -65,14 +65,16 @@ Singleton { property int animationSlow: Math.round(450 / Settings.data.general.animationSpeed) property int animationSlowest: Math.round(750 / Settings.data.general.animationSpeed) - // Dimensions - property int barHeight: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 39 : 37 - property int capsuleHeight: (barHeight * 0.73) - property int baseWidgetSize: (barHeight * 0.9) - property int sliderWidth: 200 - // Delays property int tooltipDelay: 300 property int tooltipDelayLong: 1200 property int pillDelay: 500 + + // Settings widgets base size + property real baseWidgetSize: 33 + property real sliderWidth: 200 + + // Bar Dimensions + property real barHeight: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 39 : 37 + property real capsuleHeight: Math.round(barHeight * 0.73) } diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index 11a618d..fb2257a 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -68,23 +68,13 @@ Variants { radius: Settings.data.bar.floating ? Style.radiusL : 0 } - // For vertical bars, use a single column layout Loader { - id: verticalBarLayout anchors.fill: parent - visible: Settings.data.bar.position === "left" || Settings.data.bar.position === "right" - sourceComponent: verticalBarComponent + active: true + sourceComponent: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? verticalBarComponent : horizontalBarComponent } - // For horizontal bars, use the original three-section layout - Loader { - id: horizontalBarLayout - anchors.fill: parent - visible: Settings.data.bar.position === "top" || Settings.data.bar.position === "bottom" - sourceComponent: horizontalBarComponent - } - - // Main layout components + // For vertical bars Component { id: verticalBarComponent Item { @@ -163,6 +153,7 @@ Variants { } } + // For horizontal bars Component { id: horizontalBarComponent Item { diff --git a/Modules/Bar/Widgets/ActiveWindow.qml b/Modules/Bar/Widgets/ActiveWindow.qml index e9bb66d..4aa8fc4 100644 --- a/Modules/Bar/Widgets/ActiveWindow.qml +++ b/Modules/Bar/Widgets/ActiveWindow.qml @@ -38,7 +38,7 @@ Item { readonly property string barPosition: Settings.data.bar.position implicitHeight: (barPosition === "left" || barPosition === "right") ? calculatedVerticalHeight() : Math.round(Style.barHeight * scaling) - implicitWidth: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : (horizontalLayout.implicitWidth + Style.marginM * 2 * scaling) + implicitWidth: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * 0.8 * scaling) : (horizontalLayout.implicitWidth + Style.marginM * 2 * scaling) function getTitle() { try { @@ -60,7 +60,7 @@ Item { let total = Style.marginM * 2 * scaling // internal padding if (showIcon) { - total += Style.baseWidgetSize * 0.5 * scaling + 2 * scaling // icon + spacing + total += Style.capsuleHeight * 0.5 * scaling + 2 * scaling // icon + spacing } // Calculate actual text width more accurately @@ -129,11 +129,13 @@ Item { Rectangle { id: windowTitleRect visible: root.visible - anchors.left: parent.left + anchors.left: (barPosition === "top" || barPosition === "bottom") ? parent.left : undefined + anchors.top: (barPosition === "left" || barPosition === "right") ? parent.top : undefined anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * scaling) : (horizontalLayout.implicitWidth + Style.marginM * 2 * scaling) height: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * scaling) : Math.round(Style.capsuleHeight * scaling) - radius: Math.round(Style.radiusM * scaling) + radius: width / 2 color: Color.mSurfaceVariant Item { @@ -152,8 +154,8 @@ Item { // Window icon Item { - Layout.preferredWidth: Style.baseWidgetSize * 0.5 * scaling - Layout.preferredHeight: Style.baseWidgetSize * 0.5 * scaling + Layout.preferredWidth: Style.capsuleHeight * 0.75 * scaling + Layout.preferredHeight: Style.capsuleHeight * 0.75 * scaling Layout.alignment: Qt.AlignVCenter visible: getTitle() !== "" && showIcon @@ -217,11 +219,10 @@ Item { // Window icon Item { - width: Style.baseWidgetSize * 0.5 * scaling - height: Style.baseWidgetSize * 0.5 * scaling + width: Style.capsuleHeight * 0.75 * scaling + height: Style.capsuleHeight * 0.75 * scaling anchors.centerIn: parent - visible: getTitle() !== "" && showIcon - + IconImage { id: windowIconVertical anchors.fill: parent diff --git a/Modules/Bar/Widgets/Bluetooth.qml b/Modules/Bar/Widgets/Bluetooth.qml index 41588bf..da69b27 100644 --- a/Modules/Bar/Widgets/Bluetooth.qml +++ b/Modules/Bar/Widgets/Bluetooth.qml @@ -13,7 +13,7 @@ NIconButton { property ShellScreen screen property real scaling: 1.0 - sizeRatio: 0.8 + baseSize: Style.capsuleHeight colorBg: Color.mSurfaceVariant colorFg: Color.mOnSurface colorBorder: Color.transparent diff --git a/Modules/Bar/Widgets/Clock.qml b/Modules/Bar/Widgets/Clock.qml index 45ebece..14fb8cc 100644 --- a/Modules/Bar/Widgets/Clock.qml +++ b/Modules/Bar/Widgets/Clock.qml @@ -39,7 +39,7 @@ Rectangle { readonly property bool verticalMode: barPosition === "left" || barPosition === "right" implicitWidth: verticalMode ? Math.round(Style.capsuleHeight * scaling) : Math.round(layout.implicitWidth + Style.marginM * 2 * scaling) - implicitHeight: verticalMode ? Math.round(Style.capsuleHeight * 2.5 * scaling) : Math.round(Style.baseWidgetSize * 0.8 * scaling) // Match NPill + implicitHeight: verticalMode ? Math.round(Style.capsuleHeight * 2.5 * scaling) : Math.round(Style.capsuleHeight * scaling) // Match NPill radius: Math.round(Style.radiusS * scaling) color: Color.mSurfaceVariant diff --git a/Modules/Bar/Widgets/DarkModeToggle.qml b/Modules/Bar/Widgets/DarkModeToggle.qml index cf68958..92bcf8f 100644 --- a/Modules/Bar/Widgets/DarkModeToggle.qml +++ b/Modules/Bar/Widgets/DarkModeToggle.qml @@ -10,9 +10,9 @@ NIconButton { property real scaling: 1.0 icon: "dark-mode" - tooltipText: "Toggle light/dark mode" - sizeRatio: 0.8 + tooltipText: "Toggle light/dark mode." + baseSize: Style.capsuleHeight colorBg: Settings.data.colorSchemes.darkMode ? Color.mSurfaceVariant : Color.mPrimary colorFg: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mOnPrimary colorBorder: Color.transparent diff --git a/Modules/Bar/Widgets/KeepAwake.qml b/Modules/Bar/Widgets/KeepAwake.qml index 10a55f2..1345295 100644 --- a/Modules/Bar/Widgets/KeepAwake.qml +++ b/Modules/Bar/Widgets/KeepAwake.qml @@ -11,14 +11,11 @@ NIconButton { property ShellScreen screen property real scaling: 1.0 - sizeRatio: 0.8 - + baseSize: Style.capsuleHeight icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off" tooltipText: IdleInhibitorService.isInhibited ? "Disable keep awake" : "Enable keep awake" colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mOnSurface colorBorder: Color.transparent - onClicked: { - IdleInhibitorService.manualToggle() - } + onClicked: IdleInhibitorService.manualToggle() } diff --git a/Modules/Bar/Widgets/NightLight.qml b/Modules/Bar/Widgets/NightLight.qml index 43028a1..ee109fa 100644 --- a/Modules/Bar/Widgets/NightLight.qml +++ b/Modules/Bar/Widgets/NightLight.qml @@ -14,7 +14,7 @@ NIconButton { property ShellScreen screen property real scaling: 1.0 - sizeRatio: 0.8 + baseSize: Style.capsuleHeight colorBg: Settings.data.nightLight.forced ? Color.mPrimary : Color.mSurfaceVariant colorFg: Settings.data.nightLight.forced ? Color.mOnPrimary : Color.mOnSurface colorBorder: Color.transparent diff --git a/Modules/Bar/Widgets/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml index 3021b47..2967b71 100644 --- a/Modules/Bar/Widgets/NotificationHistory.qml +++ b/Modules/Bar/Widgets/NotificationHistory.qml @@ -49,7 +49,7 @@ NIconButton { return count } - sizeRatio: 0.8 + baseSize: Style.capsuleHeight icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell" tooltipText: Settings.data.notifications.doNotDisturb ? "Notification history.\nRight-click to disable 'Do Not Disturb'." : "Notification history.\nRight-click to enable 'Do Not Disturb'." colorBg: Color.mSurfaceVariant diff --git a/Modules/Bar/Widgets/PowerProfile.qml b/Modules/Bar/Widgets/PowerProfile.qml index 219e907..fafa462 100644 --- a/Modules/Bar/Widgets/PowerProfile.qml +++ b/Modules/Bar/Widgets/PowerProfile.qml @@ -13,7 +13,7 @@ NIconButton { property real scaling: 1.0 readonly property bool hasPP: PowerProfileService.available - sizeRatio: 0.8 + baseSize: Style.capsuleHeight visible: hasPP function profileIcon() { diff --git a/Modules/Bar/Widgets/PowerToggle.qml b/Modules/Bar/Widgets/PowerToggle.qml index eccecf3..799d648 100644 --- a/Modules/Bar/Widgets/PowerToggle.qml +++ b/Modules/Bar/Widgets/PowerToggle.qml @@ -11,7 +11,7 @@ NIconButton { property ShellScreen screen property real scaling: 1.0 - sizeRatio: 0.8 + baseSize: Style.capsuleHeight icon: "power" tooltipText: "Power Settings" diff --git a/Modules/Bar/Widgets/ScreenRecorderIndicator.qml b/Modules/Bar/Widgets/ScreenRecorderIndicator.qml index efa8299..eb0246a 100644 --- a/Modules/Bar/Widgets/ScreenRecorderIndicator.qml +++ b/Modules/Bar/Widgets/ScreenRecorderIndicator.qml @@ -13,7 +13,7 @@ NIconButton { visible: ScreenRecorderService.isRecording icon: "camera-video" tooltipText: "Screen recording is active\nClick to stop recording" - sizeRatio: 0.8 + baseSize: Style.capsuleHeight colorBg: Color.mPrimary colorFg: Color.mOnPrimary onClicked: ScreenRecorderService.toggleRecording() diff --git a/Modules/Bar/Widgets/SidePanelToggle.qml b/Modules/Bar/Widgets/SidePanelToggle.qml index 293a2ca..3f647ab 100644 --- a/Modules/Bar/Widgets/SidePanelToggle.qml +++ b/Modules/Bar/Widgets/SidePanelToggle.qml @@ -33,7 +33,7 @@ NIconButton { icon: useDistroLogo ? "" : "noctalia" tooltipText: "Open side panel." - sizeRatio: 0.85 + baseSize: Style.capsuleHeight colorBg: Color.mSurfaceVariant colorFg: Color.mOnSurface diff --git a/Modules/Bar/Widgets/Taskbar.qml b/Modules/Bar/Widgets/Taskbar.qml index 14fbc55..e6b5435 100644 --- a/Modules/Bar/Widgets/Taskbar.qml +++ b/Modules/Bar/Widgets/Taskbar.qml @@ -15,7 +15,7 @@ Rectangle { property ShellScreen screen property real scaling: 1.0 - readonly property real itemSize: Style.baseWidgetSize * 0.8 * scaling + readonly property real itemSize: Style.capsuleHeight * 0.8 * scaling // Always visible when there are toplevels implicitWidth: taskbarLayout.implicitWidth + Style.marginM * scaling * 2 diff --git a/Modules/Bar/Widgets/WiFi.qml b/Modules/Bar/Widgets/WiFi.qml index 74b3e73..b93dbaa 100644 --- a/Modules/Bar/Widgets/WiFi.qml +++ b/Modules/Bar/Widgets/WiFi.qml @@ -13,8 +13,7 @@ NIconButton { property ShellScreen screen property real scaling: 1.0 - sizeRatio: 0.8 - + baseSize: Style.capsuleHeight colorBg: Color.mSurfaceVariant colorFg: Color.mOnSurface colorBorder: Color.transparent diff --git a/Modules/BluetoothPanel/BluetoothPanel.qml b/Modules/BluetoothPanel/BluetoothPanel.qml index 12a5ce0..aa743f0 100644 --- a/Modules/BluetoothPanel/BluetoothPanel.qml +++ b/Modules/BluetoothPanel/BluetoothPanel.qml @@ -53,7 +53,7 @@ NPanel { enabled: Settings.data.network.bluetoothEnabled icon: BluetoothService.adapter && BluetoothService.adapter.discovering ? "stop" : "refresh" tooltipText: "Refresh Devices" - sizeRatio: 0.8 + baseSize: Style.baseWidgetSize * 0.8 onClicked: { if (BluetoothService.adapter) { BluetoothService.adapter.discovering = !BluetoothService.adapter.discovering @@ -64,7 +64,7 @@ NPanel { NIconButton { icon: "close" tooltipText: "Close." - sizeRatio: 0.8 + baseSize: Style.baseWidgetSize * 0.8 onClicked: { root.close() } diff --git a/Modules/Notification/Notification.qml b/Modules/Notification/Notification.qml index 940c6d6..68d0906 100644 --- a/Modules/Notification/Notification.qml +++ b/Modules/Notification/Notification.qml @@ -326,7 +326,7 @@ Variants { NIconButton { icon: "close" tooltipText: "Close." - sizeRatio: 0.6 + baseSize: Style.baseWidgetSize * 0.6 anchors.top: parent.top anchors.topMargin: Style.marginM * scaling anchors.right: parent.right diff --git a/Modules/Notification/NotificationHistoryPanel.qml b/Modules/Notification/NotificationHistoryPanel.qml index 0a9e852..3d4b8a6 100644 --- a/Modules/Notification/NotificationHistoryPanel.qml +++ b/Modules/Notification/NotificationHistoryPanel.qml @@ -48,15 +48,15 @@ NPanel { NIconButton { icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell" tooltipText: Settings.data.notifications.doNotDisturb ? "'Do Not Disturb' is enabled." : "'Do Not Disturb' is disabled." - sizeRatio: 0.8 + baseSize: Style.baseWidgetSize * 0.8 onClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb onRightClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb } NIconButton { icon: "trash" - tooltipText: "Clear history" - sizeRatio: 0.8 + tooltipText: "Clear history." + baseSize: Style.baseWidgetSize * 0.8 onClicked: { NotificationService.clearHistory() root.close() @@ -66,7 +66,7 @@ NPanel { NIconButton { icon: "close" tooltipText: "Close." - sizeRatio: 0.8 + baseSize: Style.baseWidgetSize * 0.8 onClicked: { root.close() } @@ -198,8 +198,8 @@ NPanel { // Delete button NIconButton { icon: "trash" - tooltipText: "Delete notification" - sizeRatio: 0.7 + tooltipText: "Delete notification." + baseSize: Style.baseWidgetSize * 0.7 Layout.alignment: Qt.AlignTop onClicked: { diff --git a/Modules/SettingsPanel/Bar/BarSectionEditor.qml b/Modules/SettingsPanel/Bar/BarSectionEditor.qml index 0c1919b..7c9de5e 100644 --- a/Modules/SettingsPanel/Bar/BarSectionEditor.qml +++ b/Modules/SettingsPanel/Bar/BarSectionEditor.qml @@ -14,6 +14,9 @@ NBox { property var widgetModel: [] property var availableWidgets: [] + + readonly property real miniButtonSize: Style.baseWidgetSize * 0.65 + signal addWidget(string widgetId, string section) signal removeWidget(string section, int index) signal reorderWidget(string section, int fromIndex, int toIndex) @@ -178,7 +181,7 @@ NBox { active: BarWidgetRegistry.widgetHasUserSettings(modelData.id) sourceComponent: NIconButton { icon: "settings" - sizeRatio: 0.6 + baseSize: miniButtonSize colorBorder: Qt.alpha(Color.mOutline, Style.opacityLight) colorBg: Color.mOnSurface colorFg: Color.mOnPrimary @@ -218,7 +221,7 @@ NBox { NIconButton { icon: "close" - sizeRatio: 0.6 + baseSize: miniButtonSize colorBorder: Qt.alpha(Color.mOutline, Style.opacityLight) colorBg: Color.mOnSurface colorFg: Color.mOnPrimary diff --git a/Modules/SettingsPanel/Tabs/AudioTab.qml b/Modules/SettingsPanel/Tabs/AudioTab.qml index b0d42ac..463185c 100644 --- a/Modules/SettingsPanel/Tabs/AudioTab.qml +++ b/Modules/SettingsPanel/Tabs/AudioTab.qml @@ -298,7 +298,7 @@ ColumnLayout { NIconButton { icon: "close" - sizeRatio: 0.8 + baseSize: Style.baseWidgetSize * 0.8 Layout.alignment: Qt.AlignVCenter Layout.rightMargin: Style.marginXS * scaling onClicked: { diff --git a/Modules/SettingsPanel/Tabs/BarTab.qml b/Modules/SettingsPanel/Tabs/BarTab.qml index 1b4353c..fb038f1 100644 --- a/Modules/SettingsPanel/Tabs/BarTab.qml +++ b/Modules/SettingsPanel/Tabs/BarTab.qml @@ -177,8 +177,8 @@ ColumnLayout { model: Quickshell.screens || [] delegate: NCheckbox { Layout.fillWidth: true - label: `${modelData.name || "Unknown"}${modelData.model ? `: ${modelData.model}` : ""}` - description: `${modelData.width}x${modelData.height} at (${modelData.x}, ${modelData.y})` + label: modelData.name || "Unknown" + description: `${modelData.model} - ${modelData.width}x${modelData.height} [x:${modelData.x} y:${modelData.y}]` checked: (Settings.data.bar.monitors || []).indexOf(modelData.name) !== -1 onToggled: checked => { if (checked) { diff --git a/Modules/SettingsPanel/Tabs/DisplayTab.qml b/Modules/SettingsPanel/Tabs/DisplayTab.qml index b5e41f8..2d496b6 100644 --- a/Modules/SettingsPanel/Tabs/DisplayTab.qml +++ b/Modules/SettingsPanel/Tabs/DisplayTab.qml @@ -87,19 +87,9 @@ ColumnLayout { anchors.margins: Style.marginL * scaling spacing: Style.marginXXS * scaling - NText { - text: (`${modelData.name}: ${modelData.model}` || "Unknown") - font.pointSize: Style.fontSizeL * scaling - font.weight: Style.fontWeightBold - color: Color.mPrimary - } - - NText { - text: `Resolution: ${modelData.width}x${modelData.height} at (${modelData.x}, ${modelData.y})` - font.pointSize: Style.fontSizeXS * scaling - color: Color.mOnSurfaceVariant - wrapMode: Text.WordWrap - Layout.fillWidth: true + NLabel { + label: modelData.name|| "Unknown" + description: `${modelData.model} - ${modelData.width}x${modelData.height} [x:${modelData.x} y:${modelData.y}]` } // Scale @@ -134,8 +124,8 @@ ColumnLayout { NIconButton { icon: "refresh" - sizeRatio: 0.8 - tooltipText: "Reset scaling" + baseSize: Style.baseWidgetSize * 0.9 + tooltipText: "Reset scaling." onClicked: ScalingService.setScreenScale(modelData, 1.0) anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter diff --git a/Modules/SettingsPanel/Tabs/DockTab.qml b/Modules/SettingsPanel/Tabs/DockTab.qml index 293378c..efc077b 100644 --- a/Modules/SettingsPanel/Tabs/DockTab.qml +++ b/Modules/SettingsPanel/Tabs/DockTab.qml @@ -100,8 +100,8 @@ ColumnLayout { model: Quickshell.screens || [] delegate: NCheckbox { Layout.fillWidth: true - label: `${modelData.name || "Unknown"}${modelData.model ? `: ${modelData.model}` : ""}` - description: `${modelData.width}x${modelData.height} at (${modelData.x}, ${modelData.y})` + label: modelData.name || "Unknown" + description: `${modelData.model} - ${modelData.width}x${modelData.height} [x:${modelData.x} y:${modelData.y}]` checked: (Settings.data.dock.monitors || []).indexOf(modelData.name) !== -1 onToggled: checked => { if (checked) { diff --git a/Modules/SettingsPanel/Tabs/NotificationTab.qml b/Modules/SettingsPanel/Tabs/NotificationTab.qml index fa6d268..1f05bad 100644 --- a/Modules/SettingsPanel/Tabs/NotificationTab.qml +++ b/Modules/SettingsPanel/Tabs/NotificationTab.qml @@ -60,8 +60,8 @@ ColumnLayout { model: Quickshell.screens || [] delegate: NCheckbox { Layout.fillWidth: true - label: `${modelData.name || "Unknown"}${modelData.model ? `: ${modelData.model}` : ""}` - description: `${modelData.width}x${modelData.height} at (${modelData.x}, ${modelData.y})` + label: modelData.name || "Unknown" + description: `${modelData.model} - ${modelData.width}x${modelData.height} [x:${modelData.x} y:${modelData.y}]` checked: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1 onToggled: checked => { if (checked) { diff --git a/Modules/Toast/SimpleToast.qml b/Modules/Toast/SimpleToast.qml index bc51858..90a8416 100644 --- a/Modules/Toast/SimpleToast.qml +++ b/Modules/Toast/SimpleToast.qml @@ -136,7 +136,7 @@ Rectangle { colorBorder: Color.transparent colorBorderHover: Color.mOutline - sizeRatio: 0.8 + baseSize: Style.baseWidgetSize * 0.8 Layout.alignment: Qt.AlignTop onClicked: root.hide() diff --git a/Modules/WiFiPanel/WiFiPanel.qml b/Modules/WiFiPanel/WiFiPanel.qml index bfda627..190110c 100644 --- a/Modules/WiFiPanel/WiFiPanel.qml +++ b/Modules/WiFiPanel/WiFiPanel.qml @@ -57,7 +57,7 @@ NPanel { NIconButton { icon: "refresh" tooltipText: "Refresh" - sizeRatio: 0.8 + baseSize: Style.baseWidgetSize * 0.8 enabled: Settings.data.network.wifiEnabled && !NetworkService.scanning onClicked: NetworkService.scan() } @@ -65,7 +65,7 @@ NPanel { NIconButton { icon: "close" tooltipText: "Close." - sizeRatio: 0.8 + baseSize: Style.baseWidgetSize * 0.8 onClicked: root.close() } } @@ -106,7 +106,7 @@ NPanel { NIconButton { icon: "close" - sizeRatio: 0.6 + baseSize: Style.baseWidgetSize * 0.6 onClicked: NetworkService.lastError = "" } } @@ -368,7 +368,7 @@ NPanel { visible: (modelData.existing || modelData.cached) && !modelData.connected && NetworkService.connectingTo !== modelData.ssid && NetworkService.forgettingNetwork !== modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid icon: "trash" tooltipText: "Forget network" - sizeRatio: 0.7 + baseSize: Style.baseWidgetSize * 0.8 onClicked: expandedSsid = expandedSsid === modelData.ssid ? "" : modelData.ssid } @@ -478,7 +478,7 @@ NPanel { NIconButton { icon: "close" - sizeRatio: 0.8 + baseSize: Style.baseWidgetSize * 0.8 onClicked: { passwordSsid = "" passwordInput = "" @@ -532,7 +532,7 @@ NPanel { NIconButton { icon: "close" - sizeRatio: 0.8 + baseSize: Style.baseWidgetSize * 0.8 onClicked: expandedSsid = "" } } diff --git a/Widgets/NIconButton.qml b/Widgets/NIconButton.qml index 07f2798..291cde3 100644 --- a/Widgets/NIconButton.qml +++ b/Widgets/NIconButton.qml @@ -7,8 +7,7 @@ import qs.Services Rectangle { id: root - // Multiplier to control how large the button container is relative to Style.baseWidgetSize - property real sizeRatio: 1.0 + property real baseSize: Style.baseWidgetSize property string icon property string tooltipText @@ -29,8 +28,8 @@ Rectangle { signal rightClicked signal middleClicked - implicitWidth: Math.round(Style.baseWidgetSize * scaling * sizeRatio) - implicitHeight: Math.round(Style.baseWidgetSize * scaling * sizeRatio) + implicitWidth: Math.round(baseSize * scaling) + implicitHeight: Math.round(baseSize * scaling) opacity: root.enabled ? Style.opacityFull : Style.opacityMedium color: root.enabled && root.hovering ? colorBgHover : colorBg @@ -47,7 +46,7 @@ Rectangle { NIcon { icon: root.icon - font.pointSize: Math.max(1, root.width * 0.47) + font.pointSize: Math.max(1, root.width * 0.48) color: root.enabled && root.hovering ? colorFgHover : colorFg // Center horizontally x: (root.width - width) / 2 diff --git a/Widgets/NPill.qml b/Widgets/NPill.qml index d6f0fac..b69fdc1 100644 --- a/Widgets/NPill.qml +++ b/Widgets/NPill.qml @@ -10,7 +10,6 @@ Item { property string text: "" property string suffix: "" property string tooltipText: "" - property real sizeRatio: 0.8 property bool autoHide: false property bool forceOpen: false property bool forceClose: false @@ -46,7 +45,6 @@ Item { text: root.text suffix: root.suffix tooltipText: root.tooltipText - sizeRatio: root.sizeRatio autoHide: root.autoHide forceOpen: root.forceOpen forceClose: root.forceClose @@ -71,7 +69,6 @@ Item { text: root.text suffix: root.suffix tooltipText: root.tooltipText - sizeRatio: root.sizeRatio autoHide: root.autoHide forceOpen: root.forceOpen forceClose: root.forceClose diff --git a/Widgets/NPillHorizontal.qml b/Widgets/NPillHorizontal.qml index 89888ba..842714a 100644 --- a/Widgets/NPillHorizontal.qml +++ b/Widgets/NPillHorizontal.qml @@ -10,7 +10,6 @@ Item { property string text: "" property string suffix: "" property string tooltipText: "" - property real sizeRatio: 0.8 property bool autoHide: false property bool forceOpen: false property bool forceClose: false @@ -34,19 +33,17 @@ Item { property bool showPill: false property bool shouldAnimateHide: false - // Exposed width logic - readonly property int iconSize: Math.round(Style.baseWidgetSize * sizeRatio * scaling) - readonly property int pillHeight: iconSize - readonly property int pillPaddingHorizontal: 3 * 2 * scaling // Very precise adjustment don't replace by Style.margin - readonly property int pillOverlap: iconSize * 0.5 - readonly property int maxPillWidth: Math.max(1, textItem.implicitWidth + pillPaddingHorizontal * 2 + pillOverlap) + readonly property int pillHeight: Math.round(Style.capsuleHeight * scaling) + readonly property int pillPaddingHorizontal: Math.round(Style.capsuleHeight * 0.2 * scaling) + readonly property int pillOverlap: Math.round(Style.capsuleHeight * 0.5 * scaling) + readonly property int pillMaxWidth: Math.max(1, textItem.implicitWidth + pillPaddingHorizontal * 2 + pillOverlap) - width: iconSize + Math.max(0, pill.width - pillOverlap) + width: pillHeight + Math.max(0, pill.width - pillOverlap) height: pillHeight Rectangle { id: pill - width: revealed ? maxPillWidth : 1 + width: revealed ? pillMaxWidth : 1 height: pillHeight x: rightOpen ? (iconCircle.x + iconCircle.width / 2) : // Opens right @@ -76,7 +73,7 @@ Item { } text: root.text + root.suffix font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXS * scaling + font.pointSize: Math.max(1, root.pillHeight * 0.33) font.weight: Style.fontWeightBold color: forceOpen ? Color.mOnSurface : Color.mPrimary visible: revealed @@ -100,8 +97,8 @@ Item { Rectangle { id: iconCircle - width: iconSize - height: iconSize + width: pillHeight + height: pillHeight radius: width * 0.5 color: hovered ? Color.mTertiary : Color.mSurfaceVariant anchors.verticalCenter: parent.verticalCenter @@ -117,7 +114,7 @@ Item { NIcon { icon: root.icon - font.pointSize: Style.fontSizeM * scaling + font.pointSize: Math.max(1, pillHeight * 0.5) color: hovered ? Color.mOnTertiary : Color.mOnSurface // Center horizontally x: (iconCircle.width - width) / 2 @@ -133,7 +130,7 @@ Item { target: pill property: "width" from: 1 - to: maxPillWidth + to: pillMaxWidth duration: Style.animationNormal easing.type: Easing.OutCubic } @@ -173,7 +170,7 @@ Item { NumberAnimation { target: pill property: "width" - from: maxPillWidth + from: pillMaxWidth to: 1 duration: Style.animationNormal easing.type: Easing.InCubic diff --git a/Widgets/NPillVertical.qml b/Widgets/NPillVertical.qml index fb5037a..a02031a 100644 --- a/Widgets/NPillVertical.qml +++ b/Widgets/NPillVertical.qml @@ -10,7 +10,6 @@ Item { property string text: "" property string suffix: "" property string tooltipText: "" - property real sizeRatio: 0.8 property bool autoHide: false property bool forceOpen: false property bool forceClose: false @@ -43,7 +42,7 @@ Item { property bool shouldAnimateHide: false // Sizing logic for vertical bars - readonly property int iconSize: Math.round(Style.baseWidgetSize * sizeRatio * scaling) + readonly property int iconSize: Math.round(Style.capsuleHeight * scaling) readonly property int pillHeight: iconSize readonly property int pillPaddingVertical: 3 * 2 * scaling // Very precise adjustment don't replace by Style.margin readonly property int pillOverlap: iconSize * 0.5 diff --git a/Widgets/NWidgetLoader.qml b/Widgets/NWidgetLoader.qml index 17bf887..ac4c542 100644 --- a/Widgets/NWidgetLoader.qml +++ b/Widgets/NWidgetLoader.qml @@ -49,7 +49,7 @@ Item { item.onLoaded() } - //Logger.log("NWidgetLoader", "Loaded", widgetId, "on screen", item.screen.name) + Logger.log("NWidgetLoader", "Loaded", widgetId, "on screen", item.screen.name) } } From 937675ebb383bab8d11c9deb75dc1103d3417e01 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Mon, 15 Sep 2025 22:56:05 -0400 Subject: [PATCH 08/36] TaskBar: implemented vertical mode --- Modules/Bar/Widgets/Taskbar.qml | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/Modules/Bar/Widgets/Taskbar.qml b/Modules/Bar/Widgets/Taskbar.qml index e6b5435..906459f 100644 --- a/Modules/Bar/Widgets/Taskbar.qml +++ b/Modules/Bar/Widgets/Taskbar.qml @@ -1,5 +1,3 @@ -pragma ComponentBehavior - import QtQuick import QtQuick.Controls import QtQuick.Layouts @@ -16,17 +14,30 @@ Rectangle { property real scaling: 1.0 readonly property real itemSize: Style.capsuleHeight * 0.8 * scaling + readonly property bool isVerticalBar: Settings.data.bar.position === "left" || Settings.data.bar.position === "right" // Always visible when there are toplevels - implicitWidth: taskbarLayout.implicitWidth + Style.marginM * scaling * 2 - implicitHeight: Math.round(Style.capsuleHeight * scaling) + implicitWidth: isVerticalBar ? Math.round(Style.capsuleHeight * scaling) : taskbarLayout.implicitWidth + Style.marginM * scaling * 2 + implicitHeight: isVerticalBar ? taskbarLayout.implicitHeight + Style.marginM * scaling * 2 : Math.round(Style.capsuleHeight * scaling) radius: Math.round(Style.radiusM * scaling) color: Color.mSurfaceVariant - RowLayout { + GridLayout { id: taskbarLayout - anchors.centerIn: parent - spacing: Style.marginXXS * root.scaling + anchors.fill: parent + anchors { + leftMargin: isVerticalBar ? undefined : Style.marginM * scaling + rightMargin: isVerticalBar ? undefined : Style.marginM * scaling + topMargin: isVerticalBar ? Style.marginM * scaling : undefined + bottomMargin: isVerticalBar ? Style.marginM * scaling : undefined + } + + // Configure GridLayout to behave like RowLayout or ColumnLayout + rows: isVerticalBar ? -1 : 1 // -1 means unlimited + columns: isVerticalBar ? 1 : -1 // -1 means unlimited + + rowSpacing: isVerticalBar ? Style.marginXXS * root.scaling : 0 + columnSpacing: isVerticalBar ? 0 : Style.marginXXS * root.scaling Repeater { model: ToplevelManager && ToplevelManager.toplevels ? ToplevelManager.toplevels : [] From 5f3add5d99cc93679b4544d4cc897e08e8ed4c92 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Mon, 15 Sep 2025 22:56:22 -0400 Subject: [PATCH 09/36] autoformatting --- Modules/Bar/Bar.qml | 1 - Modules/Bar/Widgets/ActiveWindow.qml | 2 +- Modules/SettingsPanel/Bar/BarSectionEditor.qml | 1 - Modules/SettingsPanel/Tabs/DisplayTab.qml | 2 +- Widgets/NColorPicker.qml | 2 +- 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index fb2257a..c98798f 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -70,7 +70,6 @@ Variants { Loader { anchors.fill: parent - active: true sourceComponent: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? verticalBarComponent : horizontalBarComponent } diff --git a/Modules/Bar/Widgets/ActiveWindow.qml b/Modules/Bar/Widgets/ActiveWindow.qml index 4aa8fc4..75fefc6 100644 --- a/Modules/Bar/Widgets/ActiveWindow.qml +++ b/Modules/Bar/Widgets/ActiveWindow.qml @@ -222,7 +222,7 @@ Item { width: Style.capsuleHeight * 0.75 * scaling height: Style.capsuleHeight * 0.75 * scaling anchors.centerIn: parent - + IconImage { id: windowIconVertical anchors.fill: parent diff --git a/Modules/SettingsPanel/Bar/BarSectionEditor.qml b/Modules/SettingsPanel/Bar/BarSectionEditor.qml index 7c9de5e..79ee7c1 100644 --- a/Modules/SettingsPanel/Bar/BarSectionEditor.qml +++ b/Modules/SettingsPanel/Bar/BarSectionEditor.qml @@ -14,7 +14,6 @@ NBox { property var widgetModel: [] property var availableWidgets: [] - readonly property real miniButtonSize: Style.baseWidgetSize * 0.65 signal addWidget(string widgetId, string section) diff --git a/Modules/SettingsPanel/Tabs/DisplayTab.qml b/Modules/SettingsPanel/Tabs/DisplayTab.qml index 2d496b6..65c14ef 100644 --- a/Modules/SettingsPanel/Tabs/DisplayTab.qml +++ b/Modules/SettingsPanel/Tabs/DisplayTab.qml @@ -88,7 +88,7 @@ ColumnLayout { spacing: Style.marginXXS * scaling NLabel { - label: modelData.name|| "Unknown" + label: modelData.name || "Unknown" description: `${modelData.model} - ${modelData.width}x${modelData.height} [x:${modelData.x} y:${modelData.y}]` } diff --git a/Widgets/NColorPicker.qml b/Widgets/NColorPicker.qml index c638e44..8eee16b 100644 --- a/Widgets/NColorPicker.qml +++ b/Widgets/NColorPicker.qml @@ -42,7 +42,7 @@ Rectangle { anchors.fill: parent anchors { leftMargin: Style.marginL * scaling - rightMargin: Style.marginL * scaling + rightMargin: Style.marginL * scaling } spacing: Style.marginS * scaling From 93c674f3564f848c55212bc87a18755726254487 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Mon, 15 Sep 2025 23:06:06 -0400 Subject: [PATCH 10/36] SysMonitor: converted dual layout for vertical/horiz bar to a single grid layout --- Modules/Bar/Widgets/SystemMonitor.qml | 463 ++++++++++---------------- 1 file changed, 167 insertions(+), 296 deletions(-) diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml index 37cdc42..7f07938 100644 --- a/Modules/Bar/Widgets/SystemMonitor.qml +++ b/Modules/Bar/Widgets/SystemMonitor.qml @@ -29,6 +29,7 @@ Rectangle { } readonly property string barPosition: Settings.data.bar.position + readonly property bool isVertical: barPosition === "left" || barPosition === "right" readonly property bool showCpuUsage: (widgetSettings.showCpuUsage !== undefined) ? widgetSettings.showCpuUsage : widgetMetadata.showCpuUsage readonly property bool showCpuTemp: (widgetSettings.showCpuTemp !== undefined) ? widgetSettings.showCpuTemp : widgetMetadata.showCpuTemp @@ -38,8 +39,8 @@ Rectangle { readonly property bool showDiskUsage: (widgetSettings.showDiskUsage !== undefined) ? widgetSettings.showDiskUsage : widgetMetadata.showDiskUsage anchors.centerIn: parent - implicitWidth: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * scaling) : Math.round(horizontalLayout.implicitWidth + Style.marginM * 2 * scaling) - implicitHeight: (barPosition === "left" || barPosition === "right") ? Math.round(verticalLayout.implicitHeight + Style.marginM * 2 * scaling) : Math.round(Style.capsuleHeight * scaling) + implicitWidth: isVertical ? Math.round(Style.capsuleHeight * scaling) : Math.round(mainGrid.implicitWidth + Style.marginM * 2 * scaling) + implicitHeight: isVertical ? Math.round(mainGrid.implicitHeight + Style.marginM * 2 * scaling) : Math.round(Style.capsuleHeight * scaling) radius: Math.round(Style.radiusM * scaling) color: Color.mSurfaceVariant @@ -63,384 +64,254 @@ Rectangle { return display + units[unitIndex] } - // Horizontal layout for top/bottom bars - RowLayout { - id: horizontalLayout + GridLayout { + id: mainGrid anchors.centerIn: parent - anchors.leftMargin: Style.marginM * scaling - anchors.rightMargin: Style.marginM * scaling - spacing: Style.marginXS * scaling - visible: barPosition === "top" || barPosition === "bottom" + + // Dynamic layout based on bar orientation + flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight + rows: isVertical ? -1 : 1 + columns: isVertical ? 1 : -1 + + rowSpacing: isVertical ? (Style.marginS * scaling) : (Style.marginXS * scaling) + columnSpacing: isVertical ? (Style.marginXS * scaling) : (Style.marginXS * scaling) // CPU Usage Component Item { - Layout.preferredWidth: cpuUsageRow.implicitWidth + Layout.preferredWidth: cpuUsageContent.implicitWidth Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) - Layout.alignment: Qt.AlignVCenter + Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showCpuUsage - RowLayout { - id: cpuUsageRow + GridLayout { + id: cpuUsageContent anchors.centerIn: parent - spacing: Style.marginXXS * scaling + flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight + rows: isVertical ? 2 : 1 + columns: isVertical ? 1 : 2 + rowSpacing: Style.marginXXS * scaling + columnSpacing: Style.marginXXS * scaling + + NText { + text: isVertical ? `${Math.round(SystemStatService.cpuUsage)}%` : `${SystemStatService.cpuUsage}%` + font.family: Settings.data.ui.fontFixed + font.pointSize: isVertical ? (Style.fontSizeXXS * scaling) : (Style.fontSizeXS * scaling) + font.weight: Style.fontWeightMedium + Layout.alignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: Color.mPrimary + Layout.row: isVertical ? 0 : 0 + Layout.column: isVertical ? 0 : 1 + } NIcon { icon: "cpu-usage" - font.pointSize: Style.fontSizeM * scaling - Layout.alignment: Qt.AlignVCenter - } - - NText { - text: `${SystemStatService.cpuUsage}%` - font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXS * scaling - font.weight: Style.fontWeightMedium - Layout.alignment: Qt.AlignVCenter - verticalAlignment: Text.AlignVCenter - color: Color.mPrimary + font.pointSize: isVertical ? (Style.fontSizeS * scaling) : (Style.fontSizeM * scaling) + Layout.alignment: Qt.AlignCenter + Layout.row: isVertical ? 1 : 0 + Layout.column: 0 } } } // CPU Temperature Component Item { - Layout.preferredWidth: cpuTempRow.implicitWidth + Layout.preferredWidth: cpuTempContent.implicitWidth Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) - Layout.alignment: Qt.AlignVCenter + Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showCpuTemp - RowLayout { - id: cpuTempRow + GridLayout { + id: cpuTempContent anchors.centerIn: parent - spacing: Style.marginXXS * scaling + flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight + rows: isVertical ? 2 : 1 + columns: isVertical ? 1 : 2 + rowSpacing: Style.marginXXS * scaling + columnSpacing: Style.marginXXS * scaling + + NText { + text: isVertical ? `${SystemStatService.cpuTemp}°` : `${SystemStatService.cpuTemp}°C` + font.family: Settings.data.ui.fontFixed + font.pointSize: isVertical ? (Style.fontSizeXXS * scaling) : (Style.fontSizeXS * scaling) + font.weight: Style.fontWeightMedium + Layout.alignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: Color.mPrimary + Layout.row: isVertical ? 0 : 0 + Layout.column: isVertical ? 0 : 1 + } NIcon { icon: "cpu-temperature" - // Fire is so tall, we need to make it smaller - font.pointSize: Style.fontSizeS * scaling - Layout.alignment: Qt.AlignVCenter - } - - NText { - text: `${SystemStatService.cpuTemp}°C` - font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXS * scaling - font.weight: Style.fontWeightMedium - Layout.alignment: Qt.AlignVCenter - verticalAlignment: Text.AlignVCenter - color: Color.mPrimary + font.pointSize: isVertical ? (Style.fontSizeXS * scaling) : (Style.fontSizeS * scaling) + Layout.alignment: Qt.AlignCenter + Layout.row: isVertical ? 1 : 0 + Layout.column: 0 } } } // Memory Usage Component Item { - Layout.preferredWidth: memoryUsageRow.implicitWidth + Layout.preferredWidth: memoryContent.implicitWidth Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) - Layout.alignment: Qt.AlignVCenter + Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showMemoryUsage - RowLayout { - id: memoryUsageRow + GridLayout { + id: memoryContent anchors.centerIn: parent - spacing: Style.marginXXS * scaling + flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight + rows: isVertical ? 2 : 1 + columns: isVertical ? 1 : 2 + rowSpacing: Style.marginXXS * scaling + columnSpacing: Style.marginXXS * scaling + + NText { + text: { + if (showMemoryAsPercent) { + return `${SystemStatService.memPercent}%` + } else { + return isVertical ? `${Math.round(SystemStatService.memGb)}G` : `${SystemStatService.memGb}G` + } + } + font.family: Settings.data.ui.fontFixed + font.pointSize: isVertical ? (Style.fontSizeXXS * scaling) : (Style.fontSizeXS * scaling) + font.weight: Style.fontWeightMedium + Layout.alignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: Color.mPrimary + Layout.row: isVertical ? 0 : 0 + Layout.column: isVertical ? 0 : 1 + } NIcon { icon: "memory" - font.pointSize: Style.fontSizeM * scaling - Layout.alignment: Qt.AlignVCenter - } - - NText { - text: showMemoryAsPercent ? `${SystemStatService.memPercent}%` : `${SystemStatService.memGb}G` - font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXS * scaling - font.weight: Style.fontWeightMedium - Layout.alignment: Qt.AlignVCenter - verticalAlignment: Text.AlignVCenter - color: Color.mPrimary + font.pointSize: isVertical ? (Style.fontSizeS * scaling) : (Style.fontSizeM * scaling) + Layout.alignment: Qt.AlignCenter + Layout.row: isVertical ? 1 : 0 + Layout.column: 0 } } } // Network Download Speed Component Item { - Layout.preferredWidth: networkDownloadRow.implicitWidth + Layout.preferredWidth: downloadContent.implicitWidth Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) - Layout.alignment: Qt.AlignVCenter + Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showNetworkStats - RowLayout { - id: networkDownloadRow + GridLayout { + id: downloadContent anchors.centerIn: parent - spacing: Style.marginXS * scaling + flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight + rows: isVertical ? 2 : 1 + columns: isVertical ? 1 : 2 + rowSpacing: Style.marginXXS * scaling + columnSpacing: isVertical ? (Style.marginXXS * scaling) : (Style.marginXS * scaling) + + NText { + text: isVertical ? formatCompactSpeed(SystemStatService.rxSpeed) : SystemStatService.formatSpeed(SystemStatService.rxSpeed) + font.family: Settings.data.ui.fontFixed + font.pointSize: isVertical ? (Style.fontSizeXXS * scaling) : (Style.fontSizeXS * scaling) + font.weight: Style.fontWeightMedium + Layout.alignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: Color.mPrimary + Layout.row: isVertical ? 0 : 0 + Layout.column: isVertical ? 0 : 1 + } NIcon { icon: "download-speed" - font.pointSize: Style.fontSizeM * scaling - Layout.alignment: Qt.AlignVCenter - } - - NText { - text: SystemStatService.formatSpeed(SystemStatService.rxSpeed) - font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXS * scaling - font.weight: Style.fontWeightMedium - Layout.alignment: Qt.AlignVCenter - verticalAlignment: Text.AlignVCenter - color: Color.mPrimary + font.pointSize: isVertical ? (Style.fontSizeS * scaling) : (Style.fontSizeM * scaling) + Layout.alignment: Qt.AlignCenter + Layout.row: isVertical ? 1 : 0 + Layout.column: 0 } } } // Network Upload Speed Component Item { - Layout.preferredWidth: networkUploadRow.implicitWidth + Layout.preferredWidth: uploadContent.implicitWidth Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) - Layout.alignment: Qt.AlignVCenter + Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showNetworkStats - RowLayout { - id: networkUploadRow + GridLayout { + id: uploadContent anchors.centerIn: parent - spacing: Style.marginXS * scaling + flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight + rows: isVertical ? 2 : 1 + columns: isVertical ? 1 : 2 + rowSpacing: Style.marginXXS * scaling + columnSpacing: isVertical ? (Style.marginXXS * scaling) : (Style.marginXS * scaling) + + NText { + text: isVertical ? formatCompactSpeed(SystemStatService.txSpeed) : SystemStatService.formatSpeed(SystemStatService.txSpeed) + font.family: Settings.data.ui.fontFixed + font.pointSize: isVertical ? (Style.fontSizeXXS * scaling) : (Style.fontSizeXS * scaling) + font.weight: Style.fontWeightMedium + Layout.alignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: Color.mPrimary + Layout.row: isVertical ? 0 : 0 + Layout.column: isVertical ? 0 : 1 + } NIcon { icon: "upload-speed" - font.pointSize: Style.fontSizeM * scaling - Layout.alignment: Qt.AlignVCenter - } - - NText { - text: SystemStatService.formatSpeed(SystemStatService.txSpeed) - font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXS * scaling - font.weight: Style.fontWeightMedium - Layout.alignment: Qt.AlignVCenter - verticalAlignment: Text.AlignVCenter - color: Color.mPrimary + font.pointSize: isVertical ? (Style.fontSizeS * scaling) : (Style.fontSizeM * scaling) + Layout.alignment: Qt.AlignCenter + Layout.row: isVertical ? 1 : 0 + Layout.column: 0 } } } // Disk Usage Component (primary drive) Item { - Layout.preferredWidth: diskUsageRow.implicitWidth + Layout.preferredWidth: diskContent.implicitWidth Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) - Layout.alignment: Qt.AlignVCenter + Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showDiskUsage - RowLayout { - id: diskUsageRow + GridLayout { + id: diskContent anchors.centerIn: parent - spacing: Style.marginXS * scaling - - NIcon { - icon: "storage" - font.pointSize: Style.fontSizeM * scaling - Layout.alignment: Qt.AlignVCenter - } + flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight + rows: isVertical ? 2 : 1 + columns: isVertical ? 1 : 2 + rowSpacing: Style.marginXXS * scaling + columnSpacing: isVertical ? (Style.marginXXS * scaling) : (Style.marginXS * scaling) NText { text: `${SystemStatService.diskPercent}%` font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXS * scaling + font.pointSize: isVertical ? (Style.fontSizeXXS * scaling) : (Style.fontSizeXS * scaling) font.weight: Style.fontWeightMedium - Layout.alignment: Qt.AlignVCenter + Layout.alignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter color: Color.mPrimary - } - } - } - } - - // Vertical layout for left/right bars - ColumnLayout { - id: verticalLayout - anchors.centerIn: parent - anchors.topMargin: Style.marginS * scaling - anchors.bottomMargin: Style.marginS * scaling - width: Math.round(28 * scaling) - spacing: Style.marginS * scaling - visible: barPosition === "left" || barPosition === "right" - - // CPU Usage Component - Item { - Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) - Layout.preferredWidth: Math.round(28 * scaling) - Layout.alignment: Qt.AlignHCenter - visible: showCpuUsage - - Column { - id: cpuUsageRowVertical - anchors.centerIn: parent - spacing: Style.marginXXS * scaling - - NText { - text: `${Math.round(SystemStatService.cpuUsage)}%` - font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXXS * scaling - font.weight: Style.fontWeightMedium - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - color: Color.mPrimary - } - - NIcon { - icon: "cpu-usage" - font.pointSize: Style.fontSizeS * scaling - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - // CPU Temperature Component - Item { - Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) - Layout.preferredWidth: Math.round(28 * scaling) - Layout.alignment: Qt.AlignHCenter - visible: showCpuTemp - - Column { - id: cpuTempRowVertical - anchors.centerIn: parent - spacing: Style.marginXXS * scaling - - NText { - text: `${SystemStatService.cpuTemp}°` - font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXXS * scaling - font.weight: Style.fontWeightMedium - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - color: Color.mPrimary - } - - NIcon { - icon: "cpu-temperature" - // Fire is so tall, we need to make it smaller - font.pointSize: Style.fontSizeXS * scaling - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - // Memory Usage Component - Item { - Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) - Layout.preferredWidth: Math.round(28 * scaling) - Layout.alignment: Qt.AlignHCenter - visible: showMemoryUsage - - Column { - id: memoryUsageRowVertical - anchors.centerIn: parent - spacing: Style.marginXXS * scaling - - NText { - text: showMemoryAsPercent ? `${SystemStatService.memPercent}%` : `${Math.round(SystemStatService.memGb)}G` - font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXXS * scaling - font.weight: Style.fontWeightMedium - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - color: Color.mPrimary - } - - NIcon { - icon: "memory" - font.pointSize: Style.fontSizeS * scaling - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - // Network Download Speed Component - Item { - Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) - Layout.preferredWidth: Math.round(28 * scaling) - Layout.alignment: Qt.AlignHCenter - visible: showNetworkStats - - Column { - id: networkDownloadRowVertical - anchors.centerIn: parent - spacing: Style.marginXXS * scaling - - NText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - text: formatCompactSpeed(SystemStatService.rxSpeed) - font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXXS * scaling - font.weight: Style.fontWeightMedium - color: Color.mPrimary - } - - NIcon { - icon: "download-speed" - font.pointSize: Style.fontSizeS * scaling - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - // Network Upload Speed Component - Item { - Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) - Layout.preferredWidth: Math.round(28 * scaling) - Layout.alignment: Qt.AlignHCenter - visible: showNetworkStats - - Column { - id: networkUploadRowVertical - anchors.centerIn: parent - spacing: Style.marginXXS * scaling - - NText { - anchors.horizontalCenter: parent.horizontalCenter - horizontalAlignment: Text.AlignHCenter - text: formatCompactSpeed(SystemStatService.txSpeed) - font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXXS * scaling - font.weight: Style.fontWeightMedium - color: Color.mPrimary - } - - NIcon { - icon: "upload-speed" - font.pointSize: Style.fontSizeS * scaling - anchors.horizontalCenter: parent.horizontalCenter - } - } - } - - // Disk Usage Component (primary drive) - Item { - Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) - Layout.preferredWidth: Math.round(28 * scaling) - Layout.alignment: Qt.AlignHCenter - visible: showDiskUsage - - ColumnLayout { - id: diskUsageRowVertical - anchors.centerIn: parent - spacing: Style.marginXXS * scaling - - NText { - text: `${SystemStatService.diskPercent}%` - font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXXS * scaling - font.weight: Style.fontWeightMedium - Layout.alignment: Qt.AlignHCenter - horizontalAlignment: Text.AlignHCenter - color: Color.mPrimary + Layout.row: isVertical ? 0 : 0 + Layout.column: isVertical ? 0 : 1 } NIcon { icon: "storage" - font.pointSize: Style.fontSizeS * scaling - Layout.alignment: Qt.AlignHCenter + font.pointSize: isVertical ? (Style.fontSizeS * scaling) : (Style.fontSizeM * scaling) + Layout.alignment: Qt.AlignCenter + Layout.row: isVertical ? 1 : 0 + Layout.column: 0 } } } From ac1902c76a41801f3bb41d349b671ef6c29a781f Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 00:39:30 -0400 Subject: [PATCH 11/36] Bar: compact mode works pretty well but need some more testing. --- Commons/Settings.qml | 9 ++- Commons/Style.qml | 24 ++++++- Modules/Bar/Widgets/ActiveWindow.qml | 16 ++++- Modules/Bar/Widgets/Battery.qml | 1 + Modules/Bar/Widgets/Bluetooth.qml | 1 + Modules/Bar/Widgets/Brightness.qml | 1 + Modules/Bar/Widgets/Clock.qml | 5 +- Modules/Bar/Widgets/CustomButton.qml | 1 + Modules/Bar/Widgets/DarkModeToggle.qml | 2 +- Modules/Bar/Widgets/KeepAwake.qml | 1 + Modules/Bar/Widgets/KeyboardLayout.qml | 1 + Modules/Bar/Widgets/MediaMini.qml | 3 +- Modules/Bar/Widgets/Microphone.qml | 1 + Modules/Bar/Widgets/NightLight.qml | 1 + Modules/Bar/Widgets/NotificationHistory.qml | 1 + Modules/Bar/Widgets/PowerProfile.qml | 1 + Modules/Bar/Widgets/PowerToggle.qml | 2 +- .../Bar/Widgets/ScreenRecorderIndicator.qml | 1 + Modules/Bar/Widgets/SidePanelToggle.qml | 2 +- Modules/Bar/Widgets/SystemMonitor.qml | 58 +++++++--------- Modules/Bar/Widgets/Taskbar.qml | 17 ++--- Modules/Bar/Widgets/Tray.qml | 5 +- Modules/Bar/Widgets/Volume.qml | 1 + Modules/Bar/Widgets/WiFi.qml | 1 + Modules/Bar/Widgets/Workspace.qml | 13 ++-- Modules/SettingsPanel/Tabs/BarTab.qml | 68 ++++++++++++------- Services/SystemStatService.qml | 20 ++++++ 27 files changed, 169 insertions(+), 88 deletions(-) diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 7d3d885..992ed8c 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -121,6 +121,12 @@ Singleton { } } } + + // Upgrade the density of the bar so the look stay the same for people who upgrade. + if (adapter.settingsVersion == 2) { + adapter.bar.density = "comfortable" + adapter.settingsVersion++ + } } // ----------------------------------------------------- @@ -259,13 +265,14 @@ Singleton { JsonAdapter { id: adapter - property int settingsVersion: 2 + property int settingsVersion: 3 // bar property JsonObject bar: JsonObject { property string position: "top" // "top", "bottom", "left", or "right" property real backgroundOpacity: 1.0 property list monitors: [] + property string density: "default" // "compact", "default", "comfortable" // Floating bar settings property bool floating: false diff --git a/Commons/Style.qml b/Commons/Style.qml index 109400f..769dbc0 100644 --- a/Commons/Style.qml +++ b/Commons/Style.qml @@ -75,6 +75,26 @@ Singleton { property real sliderWidth: 200 // Bar Dimensions - property real barHeight: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 39 : 37 - property real capsuleHeight: Math.round(barHeight * 0.73) + property real barHeight: { + if (Settings.data.bar.density === "compact") { + return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 25 : 23 + } + if (Settings.data.bar.density === "default") { + return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 29 : 27 + } + if (Settings.data.bar.density === "comfortable") { + return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 39 : 37 + } + } + property real capsuleHeight: { + if (Settings.data.bar.density === "compact") { + return barHeight + } + if (Settings.data.bar.density === "default") { + return barHeight + } + if (Settings.data.bar.density === "comfortable") { + return Math.round(barHeight * 0.73) + } + } } diff --git a/Modules/Bar/Widgets/ActiveWindow.qml b/Modules/Bar/Widgets/ActiveWindow.qml index 75fefc6..3b32b1e 100644 --- a/Modules/Bar/Widgets/ActiveWindow.qml +++ b/Modules/Bar/Widgets/ActiveWindow.qml @@ -37,9 +37,19 @@ Item { readonly property real maxWidth: minWidth * 2 readonly property string barPosition: Settings.data.bar.position + readonly property bool isVertical: barPosition === "left" || barPosition === "right" + readonly property bool compact: (Settings.data.bar.density === "compact") + implicitHeight: (barPosition === "left" || barPosition === "right") ? calculatedVerticalHeight() : Math.round(Style.barHeight * scaling) implicitWidth: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * 0.8 * scaling) : (horizontalLayout.implicitWidth + Style.marginM * 2 * scaling) + readonly property real textSize: { + var base = isVertical ? width : height + return Math.max(1, compact ? base * 0.43 : base * 0.33) + } + + readonly property real iconSize: textSize * 1.25 + function getTitle() { try { return CompositorService.focusedWindowTitle !== "(No active window)" ? CompositorService.focusedWindowTitle : "" @@ -122,7 +132,7 @@ Item { id: fullTitleMetrics visible: false text: getTitle() - font.pointSize: Style.fontSizeS * scaling + font.pointSize: textSize font.weight: Style.fontWeightMedium } @@ -136,7 +146,7 @@ Item { width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * scaling) : (horizontalLayout.implicitWidth + Style.marginM * 2 * scaling) height: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * scaling) : Math.round(Style.capsuleHeight * scaling) radius: width / 2 - color: Color.mSurfaceVariant + color: compact ? Color.transparent : Color.mSurfaceVariant Item { id: mainContainer @@ -193,7 +203,7 @@ Item { Layout.alignment: Qt.AlignVCenter horizontalAlignment: Text.AlignLeft text: getTitle() - font.pointSize: Style.fontSizeS * scaling + font.pointSize: textSize font.weight: Style.fontWeightMedium elide: mouseArea.containsMouse ? Text.ElideNone : Text.ElideRight verticalAlignment: Text.AlignVCenter diff --git a/Modules/Bar/Widgets/Battery.qml b/Modules/Bar/Widgets/Battery.qml index fa2705b..f91599a 100644 --- a/Modules/Bar/Widgets/Battery.qml +++ b/Modules/Bar/Widgets/Battery.qml @@ -84,6 +84,7 @@ Item { NPill { id: pill + compact: (Settings.data.bar.density === "compact") rightOpen: BarWidgetRegistry.getNPillDirection(root) icon: testMode ? BatteryService.getIcon(testPercent, testCharging, true) : BatteryService.getIcon(percent, charging, isReady) text: (isReady || testMode) ? Math.round(percent) : "-" diff --git a/Modules/Bar/Widgets/Bluetooth.qml b/Modules/Bar/Widgets/Bluetooth.qml index da69b27..40ed96a 100644 --- a/Modules/Bar/Widgets/Bluetooth.qml +++ b/Modules/Bar/Widgets/Bluetooth.qml @@ -14,6 +14,7 @@ NIconButton { property real scaling: 1.0 baseSize: Style.capsuleHeight + compact: (Settings.data.bar.density === "compact") colorBg: Color.mSurfaceVariant colorFg: Color.mOnSurface colorBorder: Color.transparent diff --git a/Modules/Bar/Widgets/Brightness.qml b/Modules/Bar/Widgets/Brightness.qml index 0ca072e..e01c157 100644 --- a/Modules/Bar/Widgets/Brightness.qml +++ b/Modules/Bar/Widgets/Brightness.qml @@ -76,6 +76,7 @@ Item { NPill { id: pill + compact: (Settings.data.bar.density === "compact") rightOpen: BarWidgetRegistry.getNPillDirection(root) icon: getIcon() autoHide: false // Important to be false so we can hover as long as we want diff --git a/Modules/Bar/Widgets/Clock.qml b/Modules/Bar/Widgets/Clock.qml index 14fb8cc..e4a95bf 100644 --- a/Modules/Bar/Widgets/Clock.qml +++ b/Modules/Bar/Widgets/Clock.qml @@ -29,6 +29,7 @@ Rectangle { } readonly property string barPosition: Settings.data.bar.position + readonly property bool compact: (Settings.data.bar.density === "compact") // Resolve settings: try user settings or defaults from BarWidgetRegistry readonly property bool use12h: widgetSettings.use12HourClock !== undefined ? widgetSettings.use12HourClock : widgetMetadata.use12HourClock @@ -42,12 +43,12 @@ Rectangle { implicitHeight: verticalMode ? Math.round(Style.capsuleHeight * 2.5 * scaling) : Math.round(Style.capsuleHeight * scaling) // Match NPill radius: Math.round(Style.radiusS * scaling) - color: Color.mSurfaceVariant + color: compact ? Color.transparent : Color.mSurfaceVariant Item { id: clockContainer anchors.fill: parent - anchors.margins: Style.marginXS * scaling + anchors.margins: compact ? 0 : Style.marginXS * scaling ColumnLayout { id: layout diff --git a/Modules/Bar/Widgets/CustomButton.qml b/Modules/Bar/Widgets/CustomButton.qml index 9ab1b11..d32c8a8 100644 --- a/Modules/Bar/Widgets/CustomButton.qml +++ b/Modules/Bar/Widgets/CustomButton.qml @@ -49,6 +49,7 @@ Item { rightOpen: BarWidgetRegistry.getNPillDirection(root) icon: customIcon text: _dynamicText + compact: (Settings.data.bar.density === "compact") autoHide: false forceOpen: _dynamicText !== "" forceClose: false diff --git a/Modules/Bar/Widgets/DarkModeToggle.qml b/Modules/Bar/Widgets/DarkModeToggle.qml index 92bcf8f..8e39204 100644 --- a/Modules/Bar/Widgets/DarkModeToggle.qml +++ b/Modules/Bar/Widgets/DarkModeToggle.qml @@ -11,7 +11,7 @@ NIconButton { icon: "dark-mode" tooltipText: "Toggle light/dark mode." - + compact: (Settings.data.bar.density === "compact") baseSize: Style.capsuleHeight colorBg: Settings.data.colorSchemes.darkMode ? Color.mSurfaceVariant : Color.mPrimary colorFg: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mOnPrimary diff --git a/Modules/Bar/Widgets/KeepAwake.qml b/Modules/Bar/Widgets/KeepAwake.qml index 1345295..eb0cf13 100644 --- a/Modules/Bar/Widgets/KeepAwake.qml +++ b/Modules/Bar/Widgets/KeepAwake.qml @@ -12,6 +12,7 @@ NIconButton { property real scaling: 1.0 baseSize: Style.capsuleHeight + compact: (Settings.data.bar.density === "compact") icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off" tooltipText: IdleInhibitorService.isInhibited ? "Disable keep awake" : "Enable keep awake" colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant diff --git a/Modules/Bar/Widgets/KeyboardLayout.qml b/Modules/Bar/Widgets/KeyboardLayout.qml index 87aef27..e1f4095 100644 --- a/Modules/Bar/Widgets/KeyboardLayout.qml +++ b/Modules/Bar/Widgets/KeyboardLayout.qml @@ -42,6 +42,7 @@ Item { id: pill anchors.verticalCenter: parent.verticalCenter + compact: (Settings.data.bar.density === "compact") rightOpen: BarWidgetRegistry.getNPillDirection(root) icon: "keyboard" autoHide: false // Important to be false so we can hover as long as we want diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml index 5cdf228..9ec433e 100644 --- a/Modules/Bar/Widgets/MediaMini.qml +++ b/Modules/Bar/Widgets/MediaMini.qml @@ -31,6 +31,7 @@ Item { } readonly property string barPosition: Settings.data.bar.position + readonly property bool compact: (Settings.data.bar.density === "compact") readonly property bool showAlbumArt: (widgetSettings.showAlbumArt !== undefined) ? widgetSettings.showAlbumArt : widgetMetadata.showAlbumArt readonly property bool showVisualizer: (widgetSettings.showVisualizer !== undefined) ? widgetSettings.showVisualizer : widgetMetadata.showVisualizer @@ -81,7 +82,7 @@ Item { width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : (rowLayout.implicitWidth + Style.marginM * 2 * scaling) height: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : Math.round(Style.capsuleHeight * scaling) radius: (barPosition === "left" || barPosition === "right") ? width / 2 : Math.round(Style.radiusM * scaling) - color: Color.mSurfaceVariant + color: compact ? Color.transparent : Color.mSurfaceVariant // Used to anchor the tooltip, so the tooltip does not move when the content expands Item { diff --git a/Modules/Bar/Widgets/Microphone.qml b/Modules/Bar/Widgets/Microphone.qml index 3844260..98f0011 100644 --- a/Modules/Bar/Widgets/Microphone.qml +++ b/Modules/Bar/Widgets/Microphone.qml @@ -90,6 +90,7 @@ Item { id: pill rightOpen: BarWidgetRegistry.getNPillDirection(root) icon: getIcon() + compact: (Settings.data.bar.density === "compact") autoHide: false // Important to be false so we can hover as long as we want text: Math.floor(AudioService.inputVolume * 100) suffix: "%" diff --git a/Modules/Bar/Widgets/NightLight.qml b/Modules/Bar/Widgets/NightLight.qml index ee109fa..9d40eb0 100644 --- a/Modules/Bar/Widgets/NightLight.qml +++ b/Modules/Bar/Widgets/NightLight.qml @@ -14,6 +14,7 @@ NIconButton { property ShellScreen screen property real scaling: 1.0 + compact: (Settings.data.bar.density === "compact") baseSize: Style.capsuleHeight colorBg: Settings.data.nightLight.forced ? Color.mPrimary : Color.mSurfaceVariant colorFg: Settings.data.nightLight.forced ? Color.mOnPrimary : Color.mOnSurface diff --git a/Modules/Bar/Widgets/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml index 2967b71..edbe211 100644 --- a/Modules/Bar/Widgets/NotificationHistory.qml +++ b/Modules/Bar/Widgets/NotificationHistory.qml @@ -50,6 +50,7 @@ NIconButton { } baseSize: Style.capsuleHeight + compact: (Settings.data.bar.density === "compact") icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell" tooltipText: Settings.data.notifications.doNotDisturb ? "Notification history.\nRight-click to disable 'Do Not Disturb'." : "Notification history.\nRight-click to enable 'Do Not Disturb'." colorBg: Color.mSurfaceVariant diff --git a/Modules/Bar/Widgets/PowerProfile.qml b/Modules/Bar/Widgets/PowerProfile.qml index fafa462..1aba22a 100644 --- a/Modules/Bar/Widgets/PowerProfile.qml +++ b/Modules/Bar/Widgets/PowerProfile.qml @@ -46,6 +46,7 @@ NIconButton { icon: root.profileIcon() tooltipText: root.profileName() + compact: (Settings.data.bar.density === "compact") colorBg: (PowerProfileService.profile === PowerProfile.Balanced) ? Color.mSurfaceVariant : Color.mPrimary colorFg: (PowerProfileService.profile === PowerProfile.Balanced) ? Color.mOnSurface : Color.mOnPrimary colorBorder: Color.transparent diff --git a/Modules/Bar/Widgets/PowerToggle.qml b/Modules/Bar/Widgets/PowerToggle.qml index 799d648..bd6eceb 100644 --- a/Modules/Bar/Widgets/PowerToggle.qml +++ b/Modules/Bar/Widgets/PowerToggle.qml @@ -11,8 +11,8 @@ NIconButton { property ShellScreen screen property real scaling: 1.0 + compact: (Settings.data.bar.density === "compact") baseSize: Style.capsuleHeight - icon: "power" tooltipText: "Power Settings" colorBg: Color.mSurfaceVariant diff --git a/Modules/Bar/Widgets/ScreenRecorderIndicator.qml b/Modules/Bar/Widgets/ScreenRecorderIndicator.qml index eb0246a..7ddb867 100644 --- a/Modules/Bar/Widgets/ScreenRecorderIndicator.qml +++ b/Modules/Bar/Widgets/ScreenRecorderIndicator.qml @@ -13,6 +13,7 @@ NIconButton { visible: ScreenRecorderService.isRecording icon: "camera-video" tooltipText: "Screen recording is active\nClick to stop recording" + compact: (Settings.data.bar.density === "compact") baseSize: Style.capsuleHeight colorBg: Color.mPrimary colorFg: Color.mOnPrimary diff --git a/Modules/Bar/Widgets/SidePanelToggle.qml b/Modules/Bar/Widgets/SidePanelToggle.qml index 3f647ab..d0eae9f 100644 --- a/Modules/Bar/Widgets/SidePanelToggle.qml +++ b/Modules/Bar/Widgets/SidePanelToggle.qml @@ -34,7 +34,7 @@ NIconButton { icon: useDistroLogo ? "" : "noctalia" tooltipText: "Open side panel." baseSize: Style.capsuleHeight - + compact: (Settings.data.bar.density === "compact") colorBg: Color.mSurfaceVariant colorFg: Color.mOnSurface colorBgHover: useDistroLogo ? Color.mSurfaceVariant : Color.mTertiary diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml index 7f07938..a2bbe16 100644 --- a/Modules/Bar/Widgets/SystemMonitor.qml +++ b/Modules/Bar/Widgets/SystemMonitor.qml @@ -30,6 +30,7 @@ Rectangle { readonly property string barPosition: Settings.data.bar.position readonly property bool isVertical: barPosition === "left" || barPosition === "right" + readonly property bool compact: (Settings.data.bar.density === "compact") readonly property bool showCpuUsage: (widgetSettings.showCpuUsage !== undefined) ? widgetSettings.showCpuUsage : widgetMetadata.showCpuUsage readonly property bool showCpuTemp: (widgetSettings.showCpuTemp !== undefined) ? widgetSettings.showCpuTemp : widgetMetadata.showCpuTemp @@ -38,31 +39,18 @@ Rectangle { readonly property bool showNetworkStats: (widgetSettings.showNetworkStats !== undefined) ? widgetSettings.showNetworkStats : widgetMetadata.showNetworkStats readonly property bool showDiskUsage: (widgetSettings.showDiskUsage !== undefined) ? widgetSettings.showDiskUsage : widgetMetadata.showDiskUsage + readonly property real textSize: { + var base = isVertical ? width * 0.82 : height + return Math.max(1, compact ? base * 0.43 : base * 0.33) + } + + readonly property real iconSize: textSize * 1.25 + anchors.centerIn: parent implicitWidth: isVertical ? Math.round(Style.capsuleHeight * scaling) : Math.round(mainGrid.implicitWidth + Style.marginM * 2 * scaling) implicitHeight: isVertical ? Math.round(mainGrid.implicitHeight + Style.marginM * 2 * scaling) : Math.round(Style.capsuleHeight * scaling) radius: Math.round(Style.radiusM * scaling) - color: Color.mSurfaceVariant - - // Compact speed formatter for vertical bar display - function formatCompactSpeed(bytesPerSecond) { - if (!bytesPerSecond || bytesPerSecond <= 0) - return "0" - const units = ["", "k", "M", "G"] - let value = bytesPerSecond - let unitIndex = 0 - while (value >= 1024 && unitIndex < units.length - 1) { - value = value / 1024.0 - unitIndex++ - } - // Promote at ~100 of current unit (e.g., 100k -> ~0.1M shown as 0.1M or 0M if rounded) - if (unitIndex < units.length - 1 && value >= 100) { - value = value / 1024.0 - unitIndex++ - } - const display = (value >= 10) ? Math.round(value).toString() : value.toFixed(1) - return display + units[unitIndex] - } + color: compact ? Color.transparent : Color.mSurfaceVariant GridLayout { id: mainGrid @@ -95,7 +83,7 @@ Rectangle { NText { text: isVertical ? `${Math.round(SystemStatService.cpuUsage)}%` : `${SystemStatService.cpuUsage}%` font.family: Settings.data.ui.fontFixed - font.pointSize: isVertical ? (Style.fontSizeXXS * scaling) : (Style.fontSizeXS * scaling) + font.pointSize: textSize font.weight: Style.fontWeightMedium Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter @@ -107,7 +95,7 @@ Rectangle { NIcon { icon: "cpu-usage" - font.pointSize: isVertical ? (Style.fontSizeS * scaling) : (Style.fontSizeM * scaling) + font.pointSize: iconSize Layout.alignment: Qt.AlignCenter Layout.row: isVertical ? 1 : 0 Layout.column: 0 @@ -134,7 +122,7 @@ Rectangle { NText { text: isVertical ? `${SystemStatService.cpuTemp}°` : `${SystemStatService.cpuTemp}°C` font.family: Settings.data.ui.fontFixed - font.pointSize: isVertical ? (Style.fontSizeXXS * scaling) : (Style.fontSizeXS * scaling) + font.pointSize: textSize font.weight: Style.fontWeightMedium Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter @@ -146,7 +134,7 @@ Rectangle { NIcon { icon: "cpu-temperature" - font.pointSize: isVertical ? (Style.fontSizeXS * scaling) : (Style.fontSizeS * scaling) + font.pointSize: iconSize Layout.alignment: Qt.AlignCenter Layout.row: isVertical ? 1 : 0 Layout.column: 0 @@ -179,7 +167,7 @@ Rectangle { } } font.family: Settings.data.ui.fontFixed - font.pointSize: isVertical ? (Style.fontSizeXXS * scaling) : (Style.fontSizeXS * scaling) + font.pointSize: textSize font.weight: Style.fontWeightMedium Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter @@ -191,7 +179,7 @@ Rectangle { NIcon { icon: "memory" - font.pointSize: isVertical ? (Style.fontSizeS * scaling) : (Style.fontSizeM * scaling) + font.pointSize: iconSize Layout.alignment: Qt.AlignCenter Layout.row: isVertical ? 1 : 0 Layout.column: 0 @@ -216,9 +204,9 @@ Rectangle { columnSpacing: isVertical ? (Style.marginXXS * scaling) : (Style.marginXS * scaling) NText { - text: isVertical ? formatCompactSpeed(SystemStatService.rxSpeed) : SystemStatService.formatSpeed(SystemStatService.rxSpeed) + text: isVertical ? SystemStatService.formatCompactSpeed(SystemStatService.rxSpeed) : SystemStatService.formatSpeed(SystemStatService.rxSpeed) font.family: Settings.data.ui.fontFixed - font.pointSize: isVertical ? (Style.fontSizeXXS * scaling) : (Style.fontSizeXS * scaling) + font.pointSize: textSize font.weight: Style.fontWeightMedium Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter @@ -230,7 +218,7 @@ Rectangle { NIcon { icon: "download-speed" - font.pointSize: isVertical ? (Style.fontSizeS * scaling) : (Style.fontSizeM * scaling) + font.pointSize: iconSize Layout.alignment: Qt.AlignCenter Layout.row: isVertical ? 1 : 0 Layout.column: 0 @@ -255,9 +243,9 @@ Rectangle { columnSpacing: isVertical ? (Style.marginXXS * scaling) : (Style.marginXS * scaling) NText { - text: isVertical ? formatCompactSpeed(SystemStatService.txSpeed) : SystemStatService.formatSpeed(SystemStatService.txSpeed) + text: isVertical ? SystemStatService.formatCompactSpeed(SystemStatService.txSpeed) : SystemStatService.formatSpeed(SystemStatService.txSpeed) font.family: Settings.data.ui.fontFixed - font.pointSize: isVertical ? (Style.fontSizeXXS * scaling) : (Style.fontSizeXS * scaling) + font.pointSize: textSize font.weight: Style.fontWeightMedium Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter @@ -269,7 +257,7 @@ Rectangle { NIcon { icon: "upload-speed" - font.pointSize: isVertical ? (Style.fontSizeS * scaling) : (Style.fontSizeM * scaling) + font.pointSize: iconSize Layout.alignment: Qt.AlignCenter Layout.row: isVertical ? 1 : 0 Layout.column: 0 @@ -296,7 +284,7 @@ Rectangle { NText { text: `${SystemStatService.diskPercent}%` font.family: Settings.data.ui.fontFixed - font.pointSize: isVertical ? (Style.fontSizeXXS * scaling) : (Style.fontSizeXS * scaling) + font.pointSize: textSize font.weight: Style.fontWeightMedium Layout.alignment: Qt.AlignCenter horizontalAlignment: Text.AlignHCenter @@ -308,7 +296,7 @@ Rectangle { NIcon { icon: "storage" - font.pointSize: isVertical ? (Style.fontSizeS * scaling) : (Style.fontSizeM * scaling) + font.pointSize: iconSize Layout.alignment: Qt.AlignCenter Layout.row: isVertical ? 1 : 0 Layout.column: 0 diff --git a/Modules/Bar/Widgets/Taskbar.qml b/Modules/Bar/Widgets/Taskbar.qml index 906459f..f846704 100644 --- a/Modules/Bar/Widgets/Taskbar.qml +++ b/Modules/Bar/Widgets/Taskbar.qml @@ -13,14 +13,15 @@ Rectangle { property ShellScreen screen property real scaling: 1.0 - readonly property real itemSize: Style.capsuleHeight * 0.8 * scaling readonly property bool isVerticalBar: Settings.data.bar.position === "left" || Settings.data.bar.position === "right" + readonly property bool compact: (Settings.data.bar.density === "compact") + readonly property real itemSize: compact ? Style.capsuleHeight * 0.9 * scaling : Style.capsuleHeight * 0.8 * scaling // Always visible when there are toplevels implicitWidth: isVerticalBar ? Math.round(Style.capsuleHeight * scaling) : taskbarLayout.implicitWidth + Style.marginM * scaling * 2 implicitHeight: isVerticalBar ? taskbarLayout.implicitHeight + Style.marginM * scaling * 2 : Math.round(Style.capsuleHeight * scaling) radius: Math.round(Style.radiusM * scaling) - color: Color.mSurfaceVariant + color: compact ? Color.transparent : Color.mSurfaceVariant GridLayout { id: taskbarLayout @@ -28,8 +29,8 @@ Rectangle { anchors { leftMargin: isVerticalBar ? undefined : Style.marginM * scaling rightMargin: isVerticalBar ? undefined : Style.marginM * scaling - topMargin: isVerticalBar ? Style.marginM * scaling : undefined - bottomMargin: isVerticalBar ? Style.marginM * scaling : undefined + topMargin: compact ? 0 : isVerticalBar ? Style.marginM * scaling : undefined + bottomMargin: compact ? 0 : isVerticalBar ? Style.marginM * scaling : undefined } // Configure GridLayout to behave like RowLayout or ColumnLayout @@ -54,8 +55,8 @@ Rectangle { Rectangle { id: iconBackground anchors.centerIn: parent - width: root.itemSize * 0.75 - height: root.itemSize * 0.75 + width: parent.width + height: parent.height color: taskbarItem.isActive ? Color.mPrimary : root.color border.width: 0 radius: Math.round(Style.radiusXS * root.scaling) @@ -65,8 +66,8 @@ Rectangle { IconImage { id: appIcon anchors.centerIn: parent - width: Style.marginL * root.scaling - height: Style.marginL * root.scaling + width: parent.width + height: parent.height source: AppIcons.iconForAppId(taskbarItem.modelData.appId) smooth: true asynchronous: true diff --git a/Modules/Bar/Widgets/Tray.qml b/Modules/Bar/Widgets/Tray.qml index daa4c80..7a43e82 100644 --- a/Modules/Bar/Widgets/Tray.qml +++ b/Modules/Bar/Widgets/Tray.qml @@ -16,9 +16,10 @@ Rectangle { property ShellScreen screen property real scaling: 1.0 - readonly property real itemSize: 24 * scaling readonly property string barPosition: Settings.data.bar.position readonly property bool isVertical: barPosition === "left" || barPosition === "right" + readonly property bool compact: (Settings.data.bar.density === "compact") + readonly property real itemSize: isVertical ? width * 0.75 : height * 0.85 function onLoaded() { // When the widget is fully initialized with its props set the screen for the trayMenu @@ -31,7 +32,7 @@ Rectangle { implicitWidth: isVertical ? Math.round(Style.capsuleHeight * scaling) : (trayFlow.implicitWidth + Style.marginS * scaling * 2) implicitHeight: isVertical ? (trayFlow.implicitHeight + Style.marginS * scaling * 2) : Math.round(Style.capsuleHeight * scaling) radius: Math.round(Style.radiusM * scaling) - color: Color.mSurfaceVariant + color: compact ? Color.transparent : Color.mSurfaceVariant Layout.alignment: Qt.AlignVCenter diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml index 15e1ddc..bebc532 100644 --- a/Modules/Bar/Widgets/Volume.qml +++ b/Modules/Bar/Widgets/Volume.qml @@ -74,6 +74,7 @@ Item { NPill { id: pill + compact: (Settings.data.bar.density === "compact") rightOpen: BarWidgetRegistry.getNPillDirection(root) icon: getIcon() autoHide: false // Important to be false so we can hover as long as we want diff --git a/Modules/Bar/Widgets/WiFi.qml b/Modules/Bar/Widgets/WiFi.qml index b93dbaa..fb64f68 100644 --- a/Modules/Bar/Widgets/WiFi.qml +++ b/Modules/Bar/Widgets/WiFi.qml @@ -13,6 +13,7 @@ NIconButton { property ShellScreen screen property real scaling: 1.0 + compact: (Settings.data.bar.density === "compact") baseSize: Style.capsuleHeight colorBg: Color.mSurfaceVariant colorFg: Color.mOnSurface diff --git a/Modules/Bar/Widgets/Workspace.qml b/Modules/Bar/Widgets/Workspace.qml index 8d668a9..a623582 100644 --- a/Modules/Bar/Widgets/Workspace.qml +++ b/Modules/Bar/Widgets/Workspace.qml @@ -32,6 +32,7 @@ Item { } readonly property string barPosition: Settings.data.bar.position + readonly property bool compact: (Settings.data.bar.density === "compact") readonly property string labelMode: (widgetSettings.labelMode !== undefined) ? widgetSettings.labelMode : widgetMetadata.labelMode readonly property bool hideUnoccupied: (widgetSettings.hideUnoccupied !== undefined) ? widgetSettings.hideUnoccupied : widgetMetadata.hideUnoccupied @@ -176,7 +177,7 @@ Item { width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * scaling) : parent.width height: (barPosition === "left" || barPosition === "right") ? parent.height : Math.round(Style.capsuleHeight * scaling) radius: Math.round(Style.radiusM * scaling) - color: Color.mSurfaceVariant + color: compact ? Color.transparent : Color.mSurfaceVariant anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter @@ -187,7 +188,6 @@ Item { id: pillRow spacing: spacingBetweenPills anchors.verticalCenter: workspaceBackground.verticalCenter - width: root.width - horizontalPadding * 2 x: horizontalPadding visible: barPosition === "top" || barPosition === "bottom" @@ -196,7 +196,7 @@ Item { model: localWorkspaces Item { id: workspacePillContainer - height: (labelMode !== "none") ? Math.round(18 * scaling) : Math.round(14 * scaling) + height: compact ? root.height : workspaceBackground.height * 0.75 width: root.calculatedWsWidth(model) Rectangle { @@ -216,7 +216,7 @@ Item { return model.idx.toString() } } - font.pointSize: model.isFocused ? Style.fontSizeXS * scaling : Style.fontSizeXXS * scaling + font.pointSize: model.isFocused ? workspacePillContainer.height * 0.5 : workspacePillContainer.height * 0.42 font.capitalization: Font.AllUppercase font.family: Settings.data.ui.fontFixed font.weight: Style.fontWeightBold @@ -332,7 +332,6 @@ Item { id: pillColumn spacing: spacingBetweenPills anchors.horizontalCenter: workspaceBackground.horizontalCenter - height: root.height - horizontalPadding * 2 y: horizontalPadding visible: barPosition === "left" || barPosition === "right" @@ -341,7 +340,7 @@ Item { model: localWorkspaces Item { id: workspacePillContainerVertical - width: (labelMode !== "none") ? Math.round(18 * scaling) : Math.round(14 * scaling) + width: compact ? root.width : workspaceBackground.width * 0.75 height: root.calculatedWsHeight(model) Rectangle { @@ -361,7 +360,7 @@ Item { return model.idx.toString() } } - font.pointSize: model.isFocused ? Style.fontSizeXS * scaling : Style.fontSizeXXS * scaling + font.pointSize: model.isFocused ? workspacePillContainerVertical.width * 0.45 : workspacePillContainerVertical.width * 0.42 font.capitalization: Font.AllUppercase font.family: Settings.data.ui.fontFixed font.weight: Style.fontWeightBold diff --git a/Modules/SettingsPanel/Tabs/BarTab.qml b/Modules/SettingsPanel/Tabs/BarTab.qml index fb038f1..fe83373 100644 --- a/Modules/SettingsPanel/Tabs/BarTab.qml +++ b/Modules/SettingsPanel/Tabs/BarTab.qml @@ -45,32 +45,52 @@ ColumnLayout { description: "Configure bar appearance and positioning." } - RowLayout { - NComboBox { - Layout.fillWidth: true - label: "Bar Position" - description: "Choose where to place the bar on the screen." - model: ListModel { - ListElement { - key: "top" - name: "Top" - } - ListElement { - key: "bottom" - name: "Bottom" - } - ListElement { - key: "left" - name: "Left" - } - ListElement { - key: "right" - name: "Right" - } + NComboBox { + Layout.fillWidth: true + label: "Bar Position" + description: "Choose where to place the bar on the screen." + model: ListModel { + ListElement { + key: "top" + name: "Top" + } + ListElement { + key: "bottom" + name: "Bottom" + } + ListElement { + key: "left" + name: "Left" + } + ListElement { + key: "right" + name: "Right" } - currentKey: Settings.data.bar.position - onSelected: key => Settings.data.bar.position = key } + currentKey: Settings.data.bar.position + onSelected: key => Settings.data.bar.position = key + } + + NComboBox { + Layout.fillWidth: true + label: "Bar Density" + description: "Choose the density of the bar." + model: ListModel { + ListElement { + key: "compact" + name: "Compact" + } + ListElement { + key: "default" + name: "Default" + } + ListElement { + key: "comfortable" + name: "Comfortable" + } + } + currentKey: Settings.data.bar.density + onSelected: key => Settings.data.bar.density = key } ColumnLayout { diff --git a/Services/SystemStatService.qml b/Services/SystemStatService.qml index a8d37d1..7a87e5c 100644 --- a/Services/SystemStatService.qml +++ b/Services/SystemStatService.qml @@ -333,6 +333,26 @@ Singleton { } } + // Compact speed formatter for vertical bar display + function formatCompactSpeed(bytesPerSecond) { + if (!bytesPerSecond || bytesPerSecond <= 0) + return "0" + const units = ["", "K", "M", "G"] + let value = bytesPerSecond + let unitIndex = 0 + while (value >= 1024 && unitIndex < units.length - 1) { + value = value / 1024.0 + unitIndex++ + } + // Promote at ~100 of current unit (e.g., 100k -> ~0.1M shown as 0.1M or 0M if rounded) + if (unitIndex < units.length - 1 && value >= 100) { + value = value / 1024.0 + unitIndex++ + } + const display = Math.round(value).toString() + return display + units[unitIndex] + } + // ------------------------------------------------------- // Function to start fetching and computing the cpu temperature function updateCpuTemperature() { From b52451fde5f8b8bd3d8c836e5253130f09f6af23 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 00:40:02 -0400 Subject: [PATCH 12/36] Bar density: leftover files from previous commit --- Widgets/NIconButton.qml | 5 +++-- Widgets/NPill.qml | 3 +++ Widgets/NPillHorizontal.qml | 12 ++++++++---- Widgets/NPillVertical.qml | 36 ++++++++++++++++++++---------------- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/Widgets/NIconButton.qml b/Widgets/NIconButton.qml index 291cde3..c9358cd 100644 --- a/Widgets/NIconButton.qml +++ b/Widgets/NIconButton.qml @@ -14,6 +14,7 @@ Rectangle { property bool enabled: true property bool allowClickWhenDisabled: false property bool hovering: false + property bool compact: false property color colorBg: Color.mSurfaceVariant property color colorFg: Color.mPrimary @@ -32,7 +33,7 @@ Rectangle { implicitHeight: Math.round(baseSize * scaling) opacity: root.enabled ? Style.opacityFull : Style.opacityMedium - color: root.enabled && root.hovering ? colorBgHover : colorBg + color: root.enabled && root.hovering ? colorBgHover : root.compact ? Color.transparent : colorBg radius: width * 0.5 border.color: root.enabled && root.hovering ? colorBorderHover : colorBorder border.width: Math.max(1, Style.borderS * scaling) @@ -46,7 +47,7 @@ Rectangle { NIcon { icon: root.icon - font.pointSize: Math.max(1, root.width * 0.48) + font.pointSize: Math.max(1, root.compact ? root.width * 0.65 : root.width * 0.48) color: root.enabled && root.hovering ? colorFgHover : colorFg // Center horizontally x: (root.width - width) / 2 diff --git a/Widgets/NPill.qml b/Widgets/NPill.qml index b69fdc1..28d2578 100644 --- a/Widgets/NPill.qml +++ b/Widgets/NPill.qml @@ -16,6 +16,7 @@ Item { property bool disableOpen: false property bool rightOpen: false property bool hovered: false + property bool compact: false readonly property string barPosition: Settings.data.bar.position readonly property bool isVerticalBar: barPosition === "left" || barPosition === "right" @@ -51,6 +52,7 @@ Item { disableOpen: root.disableOpen rightOpen: root.rightOpen hovered: root.hovered + compact: root.compact onShown: root.shown() onHidden: root.hidden() onEntered: root.entered() @@ -75,6 +77,7 @@ Item { disableOpen: root.disableOpen rightOpen: root.rightOpen hovered: root.hovered + compact: root.compact onShown: root.shown() onHidden: root.hidden() onEntered: root.entered() diff --git a/Widgets/NPillHorizontal.qml b/Widgets/NPillHorizontal.qml index 842714a..dcc7230 100644 --- a/Widgets/NPillHorizontal.qml +++ b/Widgets/NPillHorizontal.qml @@ -16,6 +16,7 @@ Item { property bool disableOpen: false property bool rightOpen: false property bool hovered: false + property bool compact: false // Effective shown state (true if hovered/animated open or forced) readonly property bool revealed: forceOpen || showPill @@ -38,6 +39,9 @@ Item { readonly property int pillOverlap: Math.round(Style.capsuleHeight * 0.5 * scaling) readonly property int pillMaxWidth: Math.max(1, textItem.implicitWidth + pillPaddingHorizontal * 2 + pillOverlap) + readonly property real iconSize: Math.max(1, compact ? pillHeight * 0.65 : pillHeight * 0.48) + readonly property real textSize: Math.max(1, compact ? pillHeight * 0.45 : pillHeight * 0.33) + width: pillHeight + Math.max(0, pill.width - pillOverlap) height: pillHeight @@ -50,7 +54,7 @@ Item { (iconCircle.x + iconCircle.width / 2) - width // Opens left opacity: revealed ? Style.opacityFull : Style.opacityNone - color: Color.mSurfaceVariant + color: compact ? Color.transparent : Color.mSurfaceVariant topLeftRadius: rightOpen ? 0 : pillHeight * 0.5 bottomLeftRadius: rightOpen ? 0 : pillHeight * 0.5 @@ -73,7 +77,7 @@ Item { } text: root.text + root.suffix font.family: Settings.data.ui.fontFixed - font.pointSize: Math.max(1, root.pillHeight * 0.33) + font.pointSize: textSize font.weight: Style.fontWeightBold color: forceOpen ? Color.mOnSurface : Color.mPrimary visible: revealed @@ -100,7 +104,7 @@ Item { width: pillHeight height: pillHeight radius: width * 0.5 - color: hovered ? Color.mTertiary : Color.mSurfaceVariant + color: hovered ? Color.mTertiary : compact ? Color.transparent : Color.mSurfaceVariant anchors.verticalCenter: parent.verticalCenter x: rightOpen ? 0 : (parent.width - width) @@ -114,7 +118,7 @@ Item { NIcon { icon: root.icon - font.pointSize: Math.max(1, pillHeight * 0.5) + font.pointSize: iconSize color: hovered ? Color.mOnTertiary : Color.mOnSurface // Center horizontally x: (iconCircle.width - width) / 2 diff --git a/Widgets/NPillVertical.qml b/Widgets/NPillVertical.qml index a02031a..6f186da 100644 --- a/Widgets/NPillVertical.qml +++ b/Widgets/NPillVertical.qml @@ -16,6 +16,7 @@ Item { property bool disableOpen: false property bool rightOpen: false property bool hovered: false + property bool compact: false // Bar position detection for pill direction readonly property string barPosition: Settings.data.bar.position @@ -42,16 +43,19 @@ Item { property bool shouldAnimateHide: false // Sizing logic for vertical bars - readonly property int iconSize: Math.round(Style.capsuleHeight * scaling) - readonly property int pillHeight: iconSize + readonly property int buttonSize: Math.round(Style.capsuleHeight * scaling) + readonly property int pillHeight: buttonSize readonly property int pillPaddingVertical: 3 * 2 * scaling // Very precise adjustment don't replace by Style.margin - readonly property int pillOverlap: iconSize * 0.5 - readonly property int maxPillWidth: iconSize + readonly property int pillOverlap: buttonSize * 0.5 + readonly property int maxPillWidth: buttonSize readonly property int maxPillHeight: Math.max(1, textItem.implicitHeight + pillPaddingVertical * 4) + readonly property real iconSize: Math.max(1, compact ? pillHeight * 0.65 : pillHeight * 0.48) + readonly property real textSize: Math.max(1, compact ? pillHeight * 0.38 : pillHeight * 0.33) + // For vertical bars: width is just icon size, height includes pill space - width: iconSize - height: revealed ? (iconSize + maxPillHeight - pillOverlap) : iconSize + width: buttonSize + height: revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize Rectangle { id: pill @@ -63,13 +67,13 @@ Item { y: openUpward ? (iconCircle.y + iconCircle.height / 2 - height) : (iconCircle.y + iconCircle.height / 2) opacity: revealed ? Style.opacityFull : Style.opacityNone - color: Color.mSurfaceVariant + color: compact ? Color.transparent : Color.mSurfaceVariant // Radius logic for vertical expansion - rounded on the side that connects to icon - topLeftRadius: openUpward ? iconSize * 0.5 : 0 - bottomLeftRadius: openDownward ? iconSize * 0.5 : 0 - topRightRadius: openUpward ? iconSize * 0.5 : 0 - bottomRightRadius: openDownward ? iconSize * 0.5 : 0 + topLeftRadius: openUpward ? buttonSize * 0.5 : 0 + bottomLeftRadius: openDownward ? buttonSize * 0.5 : 0 + topRightRadius: openUpward ? buttonSize * 0.5 : 0 + bottomRightRadius: openDownward ? buttonSize * 0.5 : 0 anchors.horizontalCenter: parent.horizontalCenter @@ -87,7 +91,7 @@ Item { } text: root.text + root.suffix font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeXXS * scaling + font.pointSize: textSize font.weight: Style.fontWeightMedium horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter @@ -120,10 +124,10 @@ Item { Rectangle { id: iconCircle - width: iconSize - height: iconSize + width: buttonSize + height: buttonSize radius: width * 0.5 - color: hovered ? Color.mTertiary : Color.mSurfaceVariant + color: hovered ? Color.mTertiary : compact ? Color.transparent : Color.mSurfaceVariant // Icon positioning based on direction x: 0 @@ -139,7 +143,7 @@ Item { NIcon { icon: root.icon - font.pointSize: Style.fontSizeM * scaling + font.pointSize: iconSize color: hovered ? Color.mOnTertiary : Color.mOnSurface // Center horizontally x: (iconCircle.width - width) / 2 From 339505abe3c3eed34dca9cb096724c2a2222f6fb Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 00:42:44 -0400 Subject: [PATCH 13/36] Workspace: better font sizing for active workspace --- Modules/Bar/Widgets/Workspace.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Bar/Widgets/Workspace.qml b/Modules/Bar/Widgets/Workspace.qml index a623582..dce8908 100644 --- a/Modules/Bar/Widgets/Workspace.qml +++ b/Modules/Bar/Widgets/Workspace.qml @@ -216,7 +216,7 @@ Item { return model.idx.toString() } } - font.pointSize: model.isFocused ? workspacePillContainer.height * 0.5 : workspacePillContainer.height * 0.42 + font.pointSize: model.isFocused ? workspacePillContainer.height * 0.45 : workspacePillContainer.height * 0.42 font.capitalization: Font.AllUppercase font.family: Settings.data.ui.fontFixed font.weight: Style.fontWeightBold From d8db0861277f3eca048d38b51c13617e122cb2f7 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Tue, 16 Sep 2025 09:05:17 +0200 Subject: [PATCH 14/36] NotificationHistoryPanel: remove hover of notifications --- Modules/Notification/NotificationHistoryPanel.qml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/Notification/NotificationHistoryPanel.qml b/Modules/Notification/NotificationHistoryPanel.qml index 3d4b8a6..c6cddd6 100644 --- a/Modules/Notification/NotificationHistoryPanel.qml +++ b/Modules/Notification/NotificationHistoryPanel.qml @@ -136,7 +136,7 @@ NPanel { width: notificationList.width height: notificationLayout.implicitHeight + (Style.marginM * scaling * 2) radius: Style.radiusM * scaling - color: notificationMouseArea.containsMouse ? Color.mTertiary : Color.mSurfaceVariant + color: Color.mSurfaceVariant border.color: Qt.alpha(Color.mOutline, Style.opacityMedium) border.width: Math.max(1, Style.borderS * scaling) @@ -169,7 +169,7 @@ NPanel { text: (summary || "No summary").substring(0, 100) font.pointSize: Style.fontSizeM * scaling font.weight: Font.Medium - color: notificationMouseArea.containsMouse ? Color.mOnTertiary : Color.mPrimary + color: Color.mPrimary wrapMode: Text.Wrap Layout.fillWidth: true maximumLineCount: 2 @@ -179,7 +179,7 @@ NPanel { NText { text: (body || "").substring(0, 150) font.pointSize: Style.fontSizeXS * scaling - color: notificationMouseArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface + color: Color.mOnSurface wrapMode: Text.Wrap Layout.fillWidth: true maximumLineCount: 3 @@ -190,7 +190,7 @@ NPanel { NText { text: NotificationService.formatTimestamp(timestamp) font.pointSize: Style.fontSizeXS * scaling - color: notificationMouseArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface + color: Color.mOnSurface Layout.fillWidth: true } } From 03698e7bb9ea89b12fdceebad0c36259a41dfa5f Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Tue, 16 Sep 2025 13:08:30 +0200 Subject: [PATCH 15/36] ActiveWindow: use same font height as MediaMini --- Commons/Style.qml | 2 +- Modules/Bar/Widgets/ActiveWindow.qml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Commons/Style.qml b/Commons/Style.qml index 769dbc0..4c8692d 100644 --- a/Commons/Style.qml +++ b/Commons/Style.qml @@ -91,7 +91,7 @@ Singleton { return barHeight } if (Settings.data.bar.density === "default") { - return barHeight + return barHeight * 0.9 } if (Settings.data.bar.density === "comfortable") { return Math.round(barHeight * 0.73) diff --git a/Modules/Bar/Widgets/ActiveWindow.qml b/Modules/Bar/Widgets/ActiveWindow.qml index 3b32b1e..f1e2121 100644 --- a/Modules/Bar/Widgets/ActiveWindow.qml +++ b/Modules/Bar/Widgets/ActiveWindow.qml @@ -132,7 +132,7 @@ Item { id: fullTitleMetrics visible: false text: getTitle() - font.pointSize: textSize + font.pointSize: Style.fontSizeS * scaling font.weight: Style.fontWeightMedium } @@ -203,7 +203,7 @@ Item { Layout.alignment: Qt.AlignVCenter horizontalAlignment: Text.AlignLeft text: getTitle() - font.pointSize: textSize + font.pointSize: Style.fontSizeS * scaling font.weight: Style.fontWeightMedium elide: mouseArea.containsMouse ? Text.ElideNone : Text.ElideRight verticalAlignment: Text.AlignVCenter From a2caebb8e5838f82c01c8cec2874ee90c0e7d520 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 08:10:10 -0400 Subject: [PATCH 16/36] Bar Density: improved workspace widget + slight density adjustments --- Commons/Style.qml | 10 +++--- Modules/Bar/Widgets/Workspace.qml | 55 ++++++++++++++++--------------- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/Commons/Style.qml b/Commons/Style.qml index 4c8692d..9e58ba7 100644 --- a/Commons/Style.qml +++ b/Commons/Style.qml @@ -77,10 +77,10 @@ Singleton { // Bar Dimensions property real barHeight: { if (Settings.data.bar.density === "compact") { - return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 25 : 23 + return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 27 : 25 } if (Settings.data.bar.density === "default") { - return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 29 : 27 + return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 33 : 31 } if (Settings.data.bar.density === "comfortable") { return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 39 : 37 @@ -88,13 +88,13 @@ Singleton { } property real capsuleHeight: { if (Settings.data.bar.density === "compact") { - return barHeight + return barHeight * 0.95 } if (Settings.data.bar.density === "default") { - return barHeight * 0.9 + return barHeight * 0.85 } if (Settings.data.bar.density === "comfortable") { - return Math.round(barHeight * 0.73) + return barHeight * 0.73 } } } diff --git a/Modules/Bar/Widgets/Workspace.qml b/Modules/Bar/Widgets/Workspace.qml index dce8908..5ce0462 100644 --- a/Modules/Bar/Widgets/Workspace.qml +++ b/Modules/Bar/Widgets/Workspace.qml @@ -32,7 +32,9 @@ Item { } readonly property string barPosition: Settings.data.bar.position + readonly property bool isVertical: barPosition === "left" || barPosition === "right" readonly property bool compact: (Settings.data.bar.density === "compact") + readonly property real baseDimensionRatio: compact ? 0.85 : 0.73 readonly property string labelMode: (widgetSettings.labelMode !== undefined) ? widgetSettings.labelMode : widgetMetadata.labelMode readonly property bool hideUnoccupied: (widgetSettings.hideUnoccupied !== undefined) ? widgetSettings.hideUnoccupied : widgetMetadata.hideUnoccupied @@ -50,43 +52,42 @@ Item { signal workspaceChanged(int workspaceId, color accentColor) - implicitHeight: (barPosition === "left" || barPosition === "right") ? calculatedVerticalHeight() : Math.round(Style.barHeight * scaling) - implicitWidth: (barPosition === "left" || barPosition === "right") ? Math.round(Style.barHeight * scaling) : calculatedHorizontalWidth() + implicitWidth: isVertical ? Math.round(Style.barHeight * scaling) : computeWidth() + implicitHeight: isVertical ? computeHeight() : Math.round(Style.barHeight * scaling) - function calculatedWsWidth(ws) { + + function getWorkspaceWidth(ws) { + const d = Style.capsuleHeight * root.baseDimensionRatio if (ws.isFocused) - return Math.round(44 * scaling) - else if (ws.isActive) - return Math.round(28 * scaling) - else - return Math.round(20 * scaling) + return d * 2.5 + else + return d } - function calculatedWsHeight(ws) { + function getWorkspaceHeight(ws) { + const d = Style.capsuleHeight * root.baseDimensionRatio if (ws.isFocused) - return Math.round(44 * scaling) - else if (ws.isActive) - return Math.round(28 * scaling) - else - return Math.round(20 * scaling) + return d * 3 + else + return d } - function calculatedVerticalHeight() { + function computeWidth() { let total = 0 for (var i = 0; i < localWorkspaces.count; i++) { const ws = localWorkspaces.get(i) - total += calculatedWsHeight(ws) + total += getWorkspaceWidth(ws) } total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills total += horizontalPadding * 2 return total } - function calculatedHorizontalWidth() { + function computeHeight() { let total = 0 for (var i = 0; i < localWorkspaces.count; i++) { const ws = localWorkspaces.get(i) - total += calculatedWsWidth(ws) + total += getWorkspaceHeight(ws) } total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills total += horizontalPadding * 2 @@ -174,8 +175,8 @@ Item { Rectangle { id: workspaceBackground - width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * scaling) : parent.width - height: (barPosition === "left" || barPosition === "right") ? parent.height : Math.round(Style.capsuleHeight * scaling) + width: isVertical ? Math.round(Style.capsuleHeight * scaling) : parent.width + height: isVertical ? parent.height : Math.round(Style.capsuleHeight * scaling) radius: Math.round(Style.radiusM * scaling) color: compact ? Color.transparent : Color.mSurfaceVariant @@ -189,16 +190,16 @@ Item { spacing: spacingBetweenPills anchors.verticalCenter: workspaceBackground.verticalCenter x: horizontalPadding - visible: barPosition === "top" || barPosition === "bottom" + visible: !isVertical Repeater { id: workspaceRepeaterHorizontal model: localWorkspaces Item { id: workspacePillContainer - height: compact ? root.height : workspaceBackground.height * 0.75 - width: root.calculatedWsWidth(model) - + width: root.getWorkspaceWidth(model) + height: Style.capsuleHeight * root.baseDimensionRatio + Rectangle { id: pill anchors.fill: parent @@ -333,15 +334,15 @@ Item { spacing: spacingBetweenPills anchors.horizontalCenter: workspaceBackground.horizontalCenter y: horizontalPadding - visible: barPosition === "left" || barPosition === "right" + visible: isVertical Repeater { id: workspaceRepeaterVertical model: localWorkspaces Item { id: workspacePillContainerVertical - width: compact ? root.width : workspaceBackground.width * 0.75 - height: root.calculatedWsHeight(model) + width: Style.capsuleHeight * root.baseDimensionRatio + height: root.getWorkspaceHeight(model) Rectangle { id: pillVertical From ed6562475d565ab6d898e1c89bb97ac10fdcd955 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 08:16:29 -0400 Subject: [PATCH 17/36] Monitors configuration: improved description. Fix #292 --- Modules/SettingsPanel/Tabs/BarTab.qml | 2 +- Modules/SettingsPanel/Tabs/DockTab.qml | 2 +- Modules/SettingsPanel/Tabs/NotificationTab.qml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/SettingsPanel/Tabs/BarTab.qml b/Modules/SettingsPanel/Tabs/BarTab.qml index fe83373..deeda9d 100644 --- a/Modules/SettingsPanel/Tabs/BarTab.qml +++ b/Modules/SettingsPanel/Tabs/BarTab.qml @@ -190,7 +190,7 @@ ColumnLayout { NHeader { label: "Monitors Configuration" - description: "Choose which monitors should display the bar." + description: "Show bar on specific monitors. Defaults to all if none are chosen." } Repeater { diff --git a/Modules/SettingsPanel/Tabs/DockTab.qml b/Modules/SettingsPanel/Tabs/DockTab.qml index efc077b..b8a22ec 100644 --- a/Modules/SettingsPanel/Tabs/DockTab.qml +++ b/Modules/SettingsPanel/Tabs/DockTab.qml @@ -93,7 +93,7 @@ ColumnLayout { NHeader { label: "Monitors Configuration" - description: "Choose which monitors should display the dock." + description: "Show dock on specific monitors." } Repeater { diff --git a/Modules/SettingsPanel/Tabs/NotificationTab.qml b/Modules/SettingsPanel/Tabs/NotificationTab.qml index 1f05bad..a996b1e 100644 --- a/Modules/SettingsPanel/Tabs/NotificationTab.qml +++ b/Modules/SettingsPanel/Tabs/NotificationTab.qml @@ -53,7 +53,7 @@ ColumnLayout { NHeader { label: "Monitors Configuration" - description: "Choose which monitors should display notifications." + description: "Show bar on specific monitors. Defaults to all if none are chosen." } Repeater { From c6ee99375df13f92e80c085440eb6c53650e2ec1 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 08:35:43 -0400 Subject: [PATCH 18/36] Screen recorder: typo fix --- Modules/SettingsPanel/Tabs/ScreenRecorderTab.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/SettingsPanel/Tabs/ScreenRecorderTab.qml b/Modules/SettingsPanel/Tabs/ScreenRecorderTab.qml index 05cb66a..63f9f70 100644 --- a/Modules/SettingsPanel/Tabs/ScreenRecorderTab.qml +++ b/Modules/SettingsPanel/Tabs/ScreenRecorderTab.qml @@ -64,7 +64,7 @@ ColumnLayout { // Source NComboBox { label: "Video Source" - description: "Portal is recommend, if you get artifacts try Screen." + description: "Portal is recommended, if you get artifacts try Screen." model: ListModel { ListElement { key: "portal" From 2e63f93d419c73354093e9bf8b1165c57958a6f8 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 08:48:19 -0400 Subject: [PATCH 19/36] Workspace: less chunky --- Modules/Bar/Widgets/Workspace.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Bar/Widgets/Workspace.qml b/Modules/Bar/Widgets/Workspace.qml index 5ce0462..d16d374 100644 --- a/Modules/Bar/Widgets/Workspace.qml +++ b/Modules/Bar/Widgets/Workspace.qml @@ -34,7 +34,7 @@ Item { readonly property string barPosition: Settings.data.bar.position readonly property bool isVertical: barPosition === "left" || barPosition === "right" readonly property bool compact: (Settings.data.bar.density === "compact") - readonly property real baseDimensionRatio: compact ? 0.85 : 0.73 + readonly property real baseDimensionRatio: compact ? 0.85 : 0.65 readonly property string labelMode: (widgetSettings.labelMode !== undefined) ? widgetSettings.labelMode : widgetMetadata.labelMode readonly property bool hideUnoccupied: (widgetSettings.hideUnoccupied !== undefined) ? widgetSettings.hideUnoccupied : widgetMetadata.hideUnoccupied From 0da59954cd3241a9e5e8222a7941d910bbb002e0 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 08:55:36 -0400 Subject: [PATCH 20/36] Workspace: less chunky when no numbers --- Commons/Style.qml | 2 +- Modules/Bar/Widgets/Workspace.qml | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Commons/Style.qml b/Commons/Style.qml index 9e58ba7..fe8a919 100644 --- a/Commons/Style.qml +++ b/Commons/Style.qml @@ -91,7 +91,7 @@ Singleton { return barHeight * 0.95 } if (Settings.data.bar.density === "default") { - return barHeight * 0.85 + return barHeight * 0.82 } if (Settings.data.bar.density === "comfortable") { return barHeight * 0.73 diff --git a/Modules/Bar/Widgets/Workspace.qml b/Modules/Bar/Widgets/Workspace.qml index d16d374..1aff33d 100644 --- a/Modules/Bar/Widgets/Workspace.qml +++ b/Modules/Bar/Widgets/Workspace.qml @@ -34,7 +34,13 @@ Item { readonly property string barPosition: Settings.data.bar.position readonly property bool isVertical: barPosition === "left" || barPosition === "right" readonly property bool compact: (Settings.data.bar.density === "compact") - readonly property real baseDimensionRatio: compact ? 0.85 : 0.65 + readonly property real baseDimensionRatio: { + const b = compact ? 0.85 : 0.65 + if (widgetSettings.labelMode === "none") { + return b * 0.75 + } + return b + } readonly property string labelMode: (widgetSettings.labelMode !== undefined) ? widgetSettings.labelMode : widgetMetadata.labelMode readonly property bool hideUnoccupied: (widgetSettings.hideUnoccupied !== undefined) ? widgetSettings.hideUnoccupied : widgetMetadata.hideUnoccupied From 071100459f7387eafc249913b0592bbe08a8fff9 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 09:06:40 -0400 Subject: [PATCH 21/36] Better compact mode --- Commons/Style.qml | 2 +- Modules/Bar/Widgets/Workspace.qml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Commons/Style.qml b/Commons/Style.qml index fe8a919..c8607f7 100644 --- a/Commons/Style.qml +++ b/Commons/Style.qml @@ -88,7 +88,7 @@ Singleton { } property real capsuleHeight: { if (Settings.data.bar.density === "compact") { - return barHeight * 0.95 + return barHeight * 0.85 } if (Settings.data.bar.density === "default") { return barHeight * 0.82 diff --git a/Modules/Bar/Widgets/Workspace.qml b/Modules/Bar/Widgets/Workspace.qml index 1aff33d..973aa8c 100644 --- a/Modules/Bar/Widgets/Workspace.qml +++ b/Modules/Bar/Widgets/Workspace.qml @@ -86,7 +86,7 @@ Item { } total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills total += horizontalPadding * 2 - return total + return Math.round(total) } function computeHeight() { @@ -97,7 +97,7 @@ Item { } total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills total += horizontalPadding * 2 - return total + return Math.round(total) } Component.onCompleted: { From 95d2dbe3fcf0ddd4f33705fdd4205d57d5d5edf1 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 09:23:37 -0400 Subject: [PATCH 22/36] Optional capsule bg --- Commons/Settings.qml | 1 + Modules/Bar/Widgets/ActiveWindow.qml | 2 +- Modules/Bar/Widgets/Clock.qml | 2 +- Modules/Bar/Widgets/MediaMini.qml | 2 +- Modules/Bar/Widgets/SidePanelToggle.qml | 2 +- Modules/Bar/Widgets/SystemMonitor.qml | 2 +- Modules/Bar/Widgets/Taskbar.qml | 2 +- Modules/Bar/Widgets/Tray.qml | 2 +- Modules/Bar/Widgets/Workspace.qml | 9 ++++----- Modules/SettingsPanel/Tabs/BarTab.qml | 9 +++++++++ Widgets/NIconButton.qml | 2 +- Widgets/NPillHorizontal.qml | 4 ++-- Widgets/NPillVertical.qml | 4 ++-- 13 files changed, 26 insertions(+), 17 deletions(-) diff --git a/Commons/Settings.qml b/Commons/Settings.qml index 992ed8c..dc0ee1d 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -273,6 +273,7 @@ Singleton { property real backgroundOpacity: 1.0 property list monitors: [] property string density: "default" // "compact", "default", "comfortable" + property bool showCapsule: true // Floating bar settings property bool floating: false diff --git a/Modules/Bar/Widgets/ActiveWindow.qml b/Modules/Bar/Widgets/ActiveWindow.qml index f1e2121..c190445 100644 --- a/Modules/Bar/Widgets/ActiveWindow.qml +++ b/Modules/Bar/Widgets/ActiveWindow.qml @@ -146,7 +146,7 @@ Item { width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * scaling) : (horizontalLayout.implicitWidth + Style.marginM * 2 * scaling) height: (barPosition === "left" || barPosition === "right") ? Math.round(Style.capsuleHeight * scaling) : Math.round(Style.capsuleHeight * scaling) radius: width / 2 - color: compact ? Color.transparent : Color.mSurfaceVariant + color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent Item { id: mainContainer diff --git a/Modules/Bar/Widgets/Clock.qml b/Modules/Bar/Widgets/Clock.qml index e4a95bf..0cf3ff9 100644 --- a/Modules/Bar/Widgets/Clock.qml +++ b/Modules/Bar/Widgets/Clock.qml @@ -43,7 +43,7 @@ Rectangle { implicitHeight: verticalMode ? Math.round(Style.capsuleHeight * 2.5 * scaling) : Math.round(Style.capsuleHeight * scaling) // Match NPill radius: Math.round(Style.radiusS * scaling) - color: compact ? Color.transparent : Color.mSurfaceVariant + color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent Item { id: clockContainer diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml index 9ec433e..6d55d48 100644 --- a/Modules/Bar/Widgets/MediaMini.qml +++ b/Modules/Bar/Widgets/MediaMini.qml @@ -82,7 +82,7 @@ Item { width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : (rowLayout.implicitWidth + Style.marginM * 2 * scaling) height: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : Math.round(Style.capsuleHeight * scaling) radius: (barPosition === "left" || barPosition === "right") ? width / 2 : Math.round(Style.radiusM * scaling) - color: compact ? Color.transparent : Color.mSurfaceVariant + color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent // Used to anchor the tooltip, so the tooltip does not move when the content expands Item { diff --git a/Modules/Bar/Widgets/SidePanelToggle.qml b/Modules/Bar/Widgets/SidePanelToggle.qml index d0eae9f..4c122d1 100644 --- a/Modules/Bar/Widgets/SidePanelToggle.qml +++ b/Modules/Bar/Widgets/SidePanelToggle.qml @@ -46,7 +46,7 @@ NIconButton { IconImage { id: logo anchors.centerIn: parent - width: root.width * 0.85 + width: root.width * 0.8 height: width source: useDistroLogo ? DistroLogoService.osLogo : "" visible: useDistroLogo && source !== "" diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml index a2bbe16..5bc5f86 100644 --- a/Modules/Bar/Widgets/SystemMonitor.qml +++ b/Modules/Bar/Widgets/SystemMonitor.qml @@ -50,7 +50,7 @@ Rectangle { implicitWidth: isVertical ? Math.round(Style.capsuleHeight * scaling) : Math.round(mainGrid.implicitWidth + Style.marginM * 2 * scaling) implicitHeight: isVertical ? Math.round(mainGrid.implicitHeight + Style.marginM * 2 * scaling) : Math.round(Style.capsuleHeight * scaling) radius: Math.round(Style.radiusM * scaling) - color: compact ? Color.transparent : Color.mSurfaceVariant + color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent GridLayout { id: mainGrid diff --git a/Modules/Bar/Widgets/Taskbar.qml b/Modules/Bar/Widgets/Taskbar.qml index f846704..d69007c 100644 --- a/Modules/Bar/Widgets/Taskbar.qml +++ b/Modules/Bar/Widgets/Taskbar.qml @@ -21,7 +21,7 @@ Rectangle { implicitWidth: isVerticalBar ? Math.round(Style.capsuleHeight * scaling) : taskbarLayout.implicitWidth + Style.marginM * scaling * 2 implicitHeight: isVerticalBar ? taskbarLayout.implicitHeight + Style.marginM * scaling * 2 : Math.round(Style.capsuleHeight * scaling) radius: Math.round(Style.radiusM * scaling) - color: compact ? Color.transparent : Color.mSurfaceVariant + color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent GridLayout { id: taskbarLayout diff --git a/Modules/Bar/Widgets/Tray.qml b/Modules/Bar/Widgets/Tray.qml index 7a43e82..3904a9c 100644 --- a/Modules/Bar/Widgets/Tray.qml +++ b/Modules/Bar/Widgets/Tray.qml @@ -32,7 +32,7 @@ Rectangle { implicitWidth: isVertical ? Math.round(Style.capsuleHeight * scaling) : (trayFlow.implicitWidth + Style.marginS * scaling * 2) implicitHeight: isVertical ? (trayFlow.implicitHeight + Style.marginS * scaling * 2) : Math.round(Style.capsuleHeight * scaling) radius: Math.round(Style.radiusM * scaling) - color: compact ? Color.transparent : Color.mSurfaceVariant + color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent Layout.alignment: Qt.AlignVCenter diff --git a/Modules/Bar/Widgets/Workspace.qml b/Modules/Bar/Widgets/Workspace.qml index 973aa8c..1a4f30e 100644 --- a/Modules/Bar/Widgets/Workspace.qml +++ b/Modules/Bar/Widgets/Workspace.qml @@ -61,12 +61,11 @@ Item { implicitWidth: isVertical ? Math.round(Style.barHeight * scaling) : computeWidth() implicitHeight: isVertical ? computeHeight() : Math.round(Style.barHeight * scaling) - function getWorkspaceWidth(ws) { const d = Style.capsuleHeight * root.baseDimensionRatio if (ws.isFocused) return d * 2.5 - else + else return d } @@ -74,7 +73,7 @@ Item { const d = Style.capsuleHeight * root.baseDimensionRatio if (ws.isFocused) return d * 3 - else + else return d } @@ -184,7 +183,7 @@ Item { width: isVertical ? Math.round(Style.capsuleHeight * scaling) : parent.width height: isVertical ? parent.height : Math.round(Style.capsuleHeight * scaling) radius: Math.round(Style.radiusM * scaling) - color: compact ? Color.transparent : Color.mSurfaceVariant + color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter @@ -205,7 +204,7 @@ Item { id: workspacePillContainer width: root.getWorkspaceWidth(model) height: Style.capsuleHeight * root.baseDimensionRatio - + Rectangle { id: pill anchors.fill: parent diff --git a/Modules/SettingsPanel/Tabs/BarTab.qml b/Modules/SettingsPanel/Tabs/BarTab.qml index deeda9d..c7c2d6b 100644 --- a/Modules/SettingsPanel/Tabs/BarTab.qml +++ b/Modules/SettingsPanel/Tabs/BarTab.qml @@ -112,6 +112,15 @@ ColumnLayout { text: Math.floor(Settings.data.bar.backgroundOpacity * 100) + "%" } } + + NToggle { + Layout.fillWidth: true + label: "Show Capsule" + description: "Adds a capsule behind each widget to improve readability on transparent bars." + checked: Settings.data.bar.showCapsule + onToggled: checked => Settings.data.bar.showCapsule = checked + } + NToggle { Layout.fillWidth: true label: "Floating Bar" diff --git a/Widgets/NIconButton.qml b/Widgets/NIconButton.qml index c9358cd..ce5cc26 100644 --- a/Widgets/NIconButton.qml +++ b/Widgets/NIconButton.qml @@ -33,7 +33,7 @@ Rectangle { implicitHeight: Math.round(baseSize * scaling) opacity: root.enabled ? Style.opacityFull : Style.opacityMedium - color: root.enabled && root.hovering ? colorBgHover : root.compact ? Color.transparent : colorBg + color: root.enabled && root.hovering ? colorBgHover : Settings.data.bar.showCapsule ? colorBg : Color.transparent radius: width * 0.5 border.color: root.enabled && root.hovering ? colorBorderHover : colorBorder border.width: Math.max(1, Style.borderS * scaling) diff --git a/Widgets/NPillHorizontal.qml b/Widgets/NPillHorizontal.qml index dcc7230..45cc95b 100644 --- a/Widgets/NPillHorizontal.qml +++ b/Widgets/NPillHorizontal.qml @@ -54,7 +54,7 @@ Item { (iconCircle.x + iconCircle.width / 2) - width // Opens left opacity: revealed ? Style.opacityFull : Style.opacityNone - color: compact ? Color.transparent : Color.mSurfaceVariant + color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent topLeftRadius: rightOpen ? 0 : pillHeight * 0.5 bottomLeftRadius: rightOpen ? 0 : pillHeight * 0.5 @@ -104,7 +104,7 @@ Item { width: pillHeight height: pillHeight radius: width * 0.5 - color: hovered ? Color.mTertiary : compact ? Color.transparent : Color.mSurfaceVariant + color: hovered ? Color.mTertiary : Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent anchors.verticalCenter: parent.verticalCenter x: rightOpen ? 0 : (parent.width - width) diff --git a/Widgets/NPillVertical.qml b/Widgets/NPillVertical.qml index 6f186da..1c5991a 100644 --- a/Widgets/NPillVertical.qml +++ b/Widgets/NPillVertical.qml @@ -67,7 +67,7 @@ Item { y: openUpward ? (iconCircle.y + iconCircle.height / 2 - height) : (iconCircle.y + iconCircle.height / 2) opacity: revealed ? Style.opacityFull : Style.opacityNone - color: compact ? Color.transparent : Color.mSurfaceVariant + color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent // Radius logic for vertical expansion - rounded on the side that connects to icon topLeftRadius: openUpward ? buttonSize * 0.5 : 0 @@ -127,7 +127,7 @@ Item { width: buttonSize height: buttonSize radius: width * 0.5 - color: hovered ? Color.mTertiary : compact ? Color.transparent : Color.mSurfaceVariant + color: hovered ? Color.mTertiary : Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent // Icon positioning based on direction x: 0 From 03bdfdb340772cb764159d09ff77b0977d52a066 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Tue, 16 Sep 2025 15:25:46 +0200 Subject: [PATCH 23/36] Notification: replace unread badge with small circle --- Modules/Bar/Widgets/NotificationHistory.qml | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/Modules/Bar/Widgets/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml index edbe211..2446312 100644 --- a/Modules/Bar/Widgets/NotificationHistory.qml +++ b/Modules/Bar/Widgets/NotificationHistory.qml @@ -69,29 +69,20 @@ NIconButton { Loader { anchors.right: parent.right anchors.top: parent.top - anchors.rightMargin: -4 * scaling - anchors.topMargin: -4 * scaling + anchors.rightMargin: 2 * scaling + anchors.topMargin: 1 * scaling z: 2 active: showUnreadBadge && (!hideWhenZero || computeUnreadCount() > 0) sourceComponent: Rectangle { id: badge readonly property int count: computeUnreadCount() - readonly property string label: count <= 99 ? String(count) : "99+" - readonly property real pad: 8 * scaling - height: 16 * scaling - width: Math.max(height, textNode.implicitWidth + pad) + height: 8 * scaling + width: height radius: height / 2 color: Color.mError border.color: Color.mSurface border.width: 1 visible: count > 0 || !hideWhenZero - NText { - id: textNode - anchors.centerIn: parent - text: badge.label - font.pointSize: Style.fontSizeXXS * scaling - color: Color.mOnError - } } } } From 2c3eb6efdab4c75ab70eb914b24150cc4b456a8a Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 12:09:12 -0400 Subject: [PATCH 24/36] Launcher: AppPlugin, close panel immediately to avoid focusing issues. --- Modules/Launcher/Plugins/ApplicationsPlugin.qml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Modules/Launcher/Plugins/ApplicationsPlugin.qml b/Modules/Launcher/Plugins/ApplicationsPlugin.qml index e6eced4..2d21a5f 100644 --- a/Modules/Launcher/Plugins/ApplicationsPlugin.qml +++ b/Modules/Launcher/Plugins/ApplicationsPlugin.qml @@ -79,8 +79,11 @@ Item { "icon": app.icon || "application-x-executable", "isImage": false, "onActivate": function () { - Logger.log("ApplicationsPlugin", `Launching: ${app.name}`) + // Close the launcher/NPanel immediately without any animations. + // Ensures we are not preventing the future focusing of the app + launcher.closeCompleted() + Logger.log("ApplicationsPlugin", `Launching: ${app.name}`) if (Settings.data.appLauncher.useApp2Unit && app.id) { Logger.log("ApplicationsPlugin", `Using app2unit for: ${app.id}`) if (app.runInTerminal) @@ -89,11 +92,9 @@ Item { Quickshell.execDetached(["app2unit", "--"].concat(app.command)) } else if (app.execute) { app.execute() - } else if (app.exec) { - // Fallback to manual execution - Process.execute(app.exec) + } else { + Logger.log("ApplicationsPlugin", `Could not launch: ${app.name}`) } - launcher.close() } } } From b625df6484e536eb6f04bcf84b907342db1942d7 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 12:22:51 -0400 Subject: [PATCH 25/36] Icons: slightly smaller noctalia logo to better match the others. --- Assets/Fonts/tabler/tabler-icons.ttf | Bin 2408924 -> 2408964 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Assets/Fonts/tabler/tabler-icons.ttf b/Assets/Fonts/tabler/tabler-icons.ttf index 8626fa17aceaa180bf790639d4fc7ef254227b9a..2d936ba138865b3e7ba4c384c56eb54a17527b5b 100644 GIT binary patch delta 20902 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 Kn7{gW!?Yg~)XGo* delta 20876 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 From eb26aa10f713b712d2447a8f98cd3b01e037ca5e Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 20:28:07 -0400 Subject: [PATCH 26/36] NPanel: Reworked all margins and X,Y computation to make things simpler. Fix #298 - Temporarily removed Dimming as it was a pain to manage on each panel, this will be reimplemented in a better way soon. --- Modules/Calendar/Calendar.qml | 1 - .../Notification/NotificationHistoryPanel.qml | 1 - Widgets/NPanel.qml | 218 ++++++++---------- 3 files changed, 99 insertions(+), 121 deletions(-) diff --git a/Modules/Calendar/Calendar.qml b/Modules/Calendar/Calendar.qml index 80c6fd3..80b994a 100644 --- a/Modules/Calendar/Calendar.qml +++ b/Modules/Calendar/Calendar.qml @@ -12,7 +12,6 @@ NPanel { preferredWidth: 340 preferredHeight: 320 - panelAnchorRight: Settings.data.bar.position === "right" // Main Column panelContent: ColumnLayout { diff --git a/Modules/Notification/NotificationHistoryPanel.qml b/Modules/Notification/NotificationHistoryPanel.qml index c6cddd6..fd5be5f 100644 --- a/Modules/Notification/NotificationHistoryPanel.qml +++ b/Modules/Notification/NotificationHistoryPanel.qml @@ -14,7 +14,6 @@ NPanel { preferredWidth: 380 preferredHeight: 500 - panelAnchorRight: Settings.data.bar.position === "right" panelKeyboardFocus: true panelContent: Rectangle { diff --git a/Widgets/NPanel.qml b/Widgets/NPanel.qml index ef286f1..3575801 100644 --- a/Widgets/NPanel.qml +++ b/Widgets/NPanel.qml @@ -40,7 +40,6 @@ Loader { property real opacityValue: originalOpacity property alias isClosing: hideTimer.running - readonly property string barPosition: Settings.data.bar.position signal opened signal closed @@ -141,10 +140,11 @@ Loader { // PanelWindow has its own screen property inherited of QsWindow property real scaling: ScalingService.getScreenScale(screen) - readonly property real barHeight: Math.round(Style.barHeight * scaling) - readonly property real barWidth: Math.round(Style.barHeight * scaling) - readonly property bool barAtBottom: Settings.data.bar.position === "bottom" + + readonly property string barPosition: Settings.data.bar.position + readonly property bool isVertical: barPosition === "left" || barPosition === "right" readonly property bool barIsVisible: (screen !== null) && (Settings.data.bar.monitors.includes(screen.name) || (Settings.data.bar.monitors.length === 0)) + readonly property real verticalBarWidth: Math.round(Style.barHeight * scaling) Connections { target: ScalingService @@ -169,8 +169,8 @@ Loader { visible: true - // Dim desktop if required - color: (root.active && !root.isClosing && Settings.data.general.dimDesktop) ? Qt.alpha(Color.mShadow, Style.opacityHeavy) : Color.transparent + // No dimming here + color: Color.transparent WlrLayershell.exclusionMode: ExclusionMode.Ignore WlrLayershell.namespace: "noctalia-panel" @@ -186,28 +186,53 @@ Loader { anchors.left: true anchors.right: true anchors.bottom: true + margins.top: { - if (!barIsVisible || barAtBottom) { + if (!barIsVisible) { return 0 } - switch (Settings.data.bar.position) { + switch (barPosition || panelAnchorVerticalCenter) { case "top": - return (Style.barHeight + Style.marginM) * scaling + (Settings.data.bar.floating && !panelAnchorVerticalCenter ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0) + return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * 2 * Style.marginXL * scaling : 0) default: - return Style.marginM * scaling + return Style.marginS * scaling } } margins.bottom: { - if (!barIsVisible || !barAtBottom) { + if (!barIsVisible || panelAnchorVerticalCenter) { return 0 } - switch (Settings.data.bar.position) { + switch (barPosition) { case "bottom": - return (Style.barHeight + Style.marginM) * scaling + (Settings.data.bar.floating && !panelAnchorVerticalCenter ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0) + return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * 2 * Style.marginXL * scaling : 0) default: + return Style.marginS * scaling + } + } + + margins.left: { + if (!barIsVisible || panelAnchorHorizontalCenter) { return 0 } + switch (barPosition) { + case "left": + return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * 2 * Style.marginXL * scaling : 0) + default: + return Style.marginS * scaling + } + } + + margins.right: { + if (!barIsVisible || panelAnchorHorizontalCenter) { + return 0 + } + switch (barPosition) { + case "right": + return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * 2 * Style.marginXL * scaling : 0) + default: + return Style.marginS * scaling + } } // Close any panel with Esc without requiring focus @@ -259,126 +284,81 @@ Loader { x: calculatedX y: calculatedY + // --------------------------------------------- + // --------------------------------------------- + // All Style.marginXXX are handled above in the PanelWindow itself. + // Does not account for corners are they are negligible and helps keep the code clean. + // --------------------------------------------- property int calculatedX: { - var barPosition = Settings.data.bar.position + // Priority to fixed anchoring + if (panelAnchorHorizontalCenter) { + return Math.round((panelWindow.width - panelBackground.width) / 2) + } else if (panelAnchorLeft) { + return 0 + } else if (panelAnchorRight) { + return Math.round(panelWindow.width - panelBackground.width) + } - // Check anchor properties first, even when using button positioning - if (!panelAnchorHorizontalCenter && panelAnchorLeft) { - return Math.round(Style.marginS * scaling) - } else if (!panelAnchorHorizontalCenter && panelAnchorRight) { - // For right anchor, consider bar position + // No fixed anchoring + if (isVertical) { + // Vertical bar if (barPosition === "right") { - // If bar is on right, position panel to the left of the bar - var maxX = panelWindow.width - barWidth - panelBackground.width - (Style.marginS * scaling) - - // If we have button position, position close to the button like working panels - if (root.useButtonPosition) { - // Use the same logic as working panels - position at edge of bar with spacing - var maxXWithSpacing = panelWindow.width - barWidth - panelBackground.width - // Add spacing - more if screen corners are disabled, less if enabled - if (!Settings.data.general.showScreenCorners || Settings.data.bar.floating) { - maxXWithSpacing -= Style.marginL * scaling - } else { - maxXWithSpacing -= Style.marginM * scaling - } - return Math.round(maxXWithSpacing) - } else { - return Math.round(maxX) - } + // To the left of the right bar + return Math.round(panelWindow.width - panelBackground.width) } else { - // Default right positioning - var rightX = panelWindow.width - panelBackground.width - (Style.marginS * scaling) - return Math.round(rightX) + // To the right of the left bar + return 0 } - } else if (root.useButtonPosition) { - // Position panel relative to button (only if no explicit anchoring) - var targetX - - // For vertical bars, position panel close to the button - if (barPosition === "left") { - // Position panel to the right of the left bar, close to the button - var minX = barWidth - // Add spacing - more if screen corners are disabled, less if enabled - if (!Settings.data.general.showScreenCorners || Settings.data.bar.floating) { - minX += Style.marginL * scaling - } else { - minX += Style.marginM * scaling - } - targetX = minX - } else if (barPosition === "right") { - // Position panel to the left of the right bar, close to the button - var maxX = panelWindow.width - barWidth - panelBackground.width - // Add spacing - more if screen corners are disabled, less if enabled - if (!Settings.data.general.showScreenCorners || Settings.data.bar.floating) { - maxX -= Style.marginL * scaling - } else { - maxX -= Style.marginM * scaling - } - targetX = maxX - } else { - // For horizontal bars, center panel on button - targetX = root.buttonPosition.x + (root.buttonWidth / 2) - (panelBackground.width / 2) - } - - // Keep panel within screen bounds - var maxScreenX = panelWindow.width - panelBackground.width - (Style.marginS * scaling) - var minScreenX = Style.marginS * scaling - - return Math.round(Math.max(minScreenX, Math.min(targetX, maxScreenX))) } else { - // For vertical bars, center but avoid bar overlap - var centerX = (panelWindow.width - panelBackground.width) / 2 - if (barPosition === "left") { - var minX = barWidth - // Add spacing - more if screen corners are disabled, less if enabled - if (!Settings.data.general.showScreenCorners || Settings.data.bar.floating) { - minX += Style.marginL * scaling - } else { - minX += Style.marginM * scaling - } - centerX = Math.max(centerX, minX) - } else if (barPosition === "right") { - // For right bar, center but ensure it doesn't overlap with the bar - var maxX = panelWindow.width - barWidth - panelBackground.width - // Add spacing - more if screen corners are disabled, less if enabled - if (!Settings.data.general.showScreenCorners || Settings.data.bar.floating) { - maxX -= Style.marginL * scaling - } else { - maxX -= Style.marginM * scaling - } - centerX = Math.min(centerX, maxX) + // Horizontal bar + if (root.useButtonPosition) { + // Position panel relative to button + var targetX = buttonPosition.x + (buttonWidth / 2) - (panelBackground.width / 2) + // Keep panel within screen bounds + var maxX = panelWindow.width - panelBackground.width + var minX = Style.marginS * scaling + return Math.round(Math.max(minX, Math.min(targetX, maxX))) + } else { + // Fallback to center horizontally + return Math.round((panelWindow.width - panelBackground.width) / 2) } - return Math.round(centerX) } } + // --------------------------------------------- property int calculatedY: { - var barPosition = Settings.data.bar.position - - if (root.useButtonPosition) { - // Position panel relative to button - var targetY = root.buttonPosition.y + (root.buttonHeight / 2) - (panelBackground.height / 2) - - // Keep panel within screen bounds - var maxY = panelWindow.height - panelBackground.height - (Style.marginS * scaling) - var minY = Style.marginS * scaling - - return Math.round(Math.max(minY, Math.min(targetY, maxY))) - } else if (panelAnchorVerticalCenter) { + // Priority to fixed anchoring + if (panelAnchorVerticalCenter) { return Math.round((panelWindow.height - panelBackground.height) / 2) - } else if (panelAnchorBottom) { - return Math.round(panelWindow.height - panelBackground.height - (Style.marginS * scaling)) } else if (panelAnchorTop) { - return Math.round(Style.marginS * scaling) - } else if (barPosition === "left" || barPosition === "right") { - // For vertical bars, center vertically - return Math.round((panelWindow.height - panelBackground.height) / 2) - } else if (!barAtBottom) { - // Below the top bar - return Math.round(Style.marginS * scaling) + return 0 + } else if (panelAnchorBottom) { + return Math.round(panelWindow.height - panelBackground.height) + } + + // No fixed anchoring + if (isVertical) { + // Vertical bar + if (useButtonPosition) { + // Position panel relative to button + var targetY = buttonPosition.y + (buttonHeight / 2) - (panelBackground.height / 2) + // Keep panel within screen bounds + var maxY = panelWindow.height - panelBackground.height + var minY = Style.marginS * scaling + return Math.round(Math.max(minY, Math.min(targetY, maxY))) + } else { + // Fallback to center vertically + return Math.round((panelWindow.height - panelBackground.height) / 2) + } } else { - // Above the bottom bar - return Math.round(panelWindow.height - panelBackground.height - (Style.marginS * scaling)) + // Horizontal bar + if (barPosition === "bottom") { + // Above the bottom bar + return Math.round(panelWindow.height - panelBackground.height) + } else { + // Below the top bar + return 0 + } } } From 6f1ae43d62f25dea4804982a1c38ff861892db6e Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 21:35:27 -0400 Subject: [PATCH 27/36] Dimmer: new implementation of the screen diming in a separate component. --- Modules/Background/Dimmer.qml | 76 +++++++++++++++++++++++++++++++++++ Services/PanelService.qml | 11 +++++ Widgets/NPanel.qml | 10 ++++- shell.qml | 1 + 4 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 Modules/Background/Dimmer.qml diff --git a/Modules/Background/Dimmer.qml b/Modules/Background/Dimmer.qml new file mode 100644 index 0000000..6185ad8 --- /dev/null +++ b/Modules/Background/Dimmer.qml @@ -0,0 +1,76 @@ +import QtQuick +import QtQuick.Effects +import Quickshell +import Quickshell.Wayland +import qs.Commons +import qs.Services +import qs.Widgets + +Variants { + model: Quickshell.screens + + delegate: Loader { + required property ShellScreen modelData + + // Dimmer is only active on the screen where the panel is currently open. + active: { + if (Settings.isLoaded && Settings.data.general.dimDesktop && modelData !== undefined && PanelService.openedPanel !== null && PanelService.openedPanel.item !== null) { + return (PanelService.openedPanel.item.screen === modelData) + } + + return false + } + + sourceComponent: PanelWindow { + id: panel + + property real customOpacity: 0 + + Component.onCompleted: { + if (modelData) { + Logger.log("Dimmer", "component loaded on", modelData.name) + } + + // When a NPanel opens it seems it is initialized with the primary screen for a very brief moment + // before the screen actually updates to the proper value. We use a timer to delay the fade in to avoid + // a single frame flicker on the main screen when opening a panel on another screen. + fadeInTimer.start() + } + + Connections { + target: PanelService + function onWillClose() { + customOpacity = Style.opacityNone + } + } + + Timer { + id: fadeInTimer + interval: 100 + onTriggered: customOpacity = Style.opacityHeavy + } + + screen: modelData + + WlrLayershell.layer: WlrLayer.Top + WlrLayershell.exclusionMode: ExclusionMode.Ignore + WlrLayershell.keyboardFocus: WlrKeyboardFocus.None + WlrLayershell.namespace: "quickshell-dimmer" + + // mask: Region {} + anchors { + top: true + bottom: true + right: true + left: true + } + + color: Qt.alpha(Color.mShadow, customOpacity) + Behavior on color { + ColorAnimation { + duration: Style.animationSlow + } + } + } + } +} diff --git a/Services/PanelService.qml b/Services/PanelService.qml index 8922034..f1df973 100644 --- a/Services/PanelService.qml +++ b/Services/PanelService.qml @@ -16,6 +16,9 @@ Singleton { property var registeredPanels: ({}) + signal willOpen + signal willClose + // Register this panel function registerPanel(panel) { registeredPanels[panel.objectName] = panel @@ -38,6 +41,14 @@ Singleton { openedPanel.close() } openedPanel = panel + + // emit signal + willOpen() + } + + function willClosePanel(panel) { + // emit signal + willClose() } function closedPanel(panel) { diff --git a/Widgets/NPanel.qml b/Widgets/NPanel.qml index 3575801..88d3bb9 100644 --- a/Widgets/NPanel.qml +++ b/Widgets/NPanel.qml @@ -111,6 +111,7 @@ Loader { scaleValue = originalScale opacityValue = originalOpacity hideTimer.start() + PanelService.willClosePanel(root) } // ----------------------------------------- @@ -146,6 +147,10 @@ Loader { readonly property bool barIsVisible: (screen !== null) && (Settings.data.bar.monitors.includes(screen.name) || (Settings.data.bar.monitors.length === 0)) readonly property real verticalBarWidth: Math.round(Style.barHeight * scaling) + Component.onCompleted: { + Logger.log("NPanel", "Opened", root.objectName) + } + Connections { target: ScalingService function onScaleChanged(screenName, scale) { @@ -172,6 +177,7 @@ Loader { // No dimming here color: Color.transparent + WlrLayershell.layer: Settings.data.general.dimDesktop ? WlrLayer.Overlay : WlrLayer.Top WlrLayershell.exclusionMode: ExclusionMode.Ignore WlrLayershell.namespace: "noctalia-panel" WlrLayershell.keyboardFocus: root.panelKeyboardFocus ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None @@ -280,14 +286,14 @@ Loader { scale: root.scaleValue opacity: root.opacityValue - x: calculatedX y: calculatedY - // --------------------------------------------- // --------------------------------------------- // All Style.marginXXX are handled above in the PanelWindow itself. // Does not account for corners are they are negligible and helps keep the code clean. + // --------------------------------------------- + // --------------------------------------------- property int calculatedX: { // Priority to fixed anchoring diff --git a/shell.qml b/shell.qml index 24544f5..6f0e8ea 100644 --- a/shell.qml +++ b/shell.qml @@ -37,6 +37,7 @@ ShellRoot { Background {} Overview {} ScreenCorners {} + Dimmer {} Bar {} Dock {} From cdca7c1d83b287f50eda8769b5b721ab8d14d093 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 21:53:11 -0400 Subject: [PATCH 28/36] NPanel dimensions & Dimmer: Panels have no margin they are full screen and prevent clicking on the bar until dismissed. Margins are now included in the rectangle X,Y coordinates calculation Might sound weird at first but it fixes a lot of inconsistencies/issues we have had for a long time when a panel was open: - can't close panel when clicking in a dead zone of the bar. - hovering an icon on the bar used to make it look like you could interact with it, but the click would just close the panel and not actuall y do anything with bar . I recommend turning back on dimming, as it is now way cooler. Changed the default to true. --- Commons/Settings.qml | 2 +- Widgets/NPanel.qml | 120 +++++++++++++++++++++---------------------- 2 files changed, 60 insertions(+), 62 deletions(-) diff --git a/Commons/Settings.qml b/Commons/Settings.qml index dc0ee1d..a6ecf64 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -328,7 +328,7 @@ Singleton { // general property JsonObject general: JsonObject { property string avatarImage: defaultAvatar - property bool dimDesktop: false + property bool dimDesktop: true property bool showScreenCorners: false property bool forceBlackScreenCorners: false property real radiusRatio: 1.0 diff --git a/Widgets/NPanel.qml b/Widgets/NPanel.qml index 88d3bb9..a232b84 100644 --- a/Widgets/NPanel.qml +++ b/Widgets/NPanel.qml @@ -193,54 +193,6 @@ Loader { anchors.right: true anchors.bottom: true - margins.top: { - if (!barIsVisible) { - return 0 - } - switch (barPosition || panelAnchorVerticalCenter) { - case "top": - return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * 2 * Style.marginXL * scaling : 0) - default: - return Style.marginS * scaling - } - } - - margins.bottom: { - if (!barIsVisible || panelAnchorVerticalCenter) { - return 0 - } - switch (barPosition) { - case "bottom": - return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * 2 * Style.marginXL * scaling : 0) - default: - return Style.marginS * scaling - } - } - - margins.left: { - if (!barIsVisible || panelAnchorHorizontalCenter) { - return 0 - } - switch (barPosition) { - case "left": - return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * 2 * Style.marginXL * scaling : 0) - default: - return Style.marginS * scaling - } - } - - margins.right: { - if (!barIsVisible || panelAnchorHorizontalCenter) { - return 0 - } - switch (barPosition) { - case "right": - return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * 2 * Style.marginXL * scaling : 0) - default: - return Style.marginS * scaling - } - } - // Close any panel with Esc without requiring focus Shortcut { sequences: ["Escape"] @@ -290,9 +242,55 @@ Loader { y: calculatedY // --------------------------------------------- - // All Style.marginXXX are handled above in the PanelWindow itself. // Does not account for corners are they are negligible and helps keep the code clean. // --------------------------------------------- + property real marginTop: { + if (!barIsVisible) { + return 0 + } + switch (barPosition || panelAnchorVerticalCenter) { + case "top": + return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * 2 * Style.marginXL * scaling : 0) + default: + return Style.marginS * scaling + } + } + + property real marginBottom: { + if (!barIsVisible || panelAnchorVerticalCenter) { + return 0 + } + switch (barPosition) { + case "bottom": + return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * 2 * Style.marginXL * scaling : 0) + default: + return Style.marginS * scaling + } + } + + property real marginLeft: { + if (!barIsVisible || panelAnchorHorizontalCenter) { + return 0 + } + switch (barPosition) { + case "left": + return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * 2 * Style.marginXL * scaling : 0) + default: + return Style.marginS * scaling + } + } + + property real marginRight: { + if (!barIsVisible || panelAnchorHorizontalCenter) { + return 0 + } + switch (barPosition) { + case "right": + return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * 2 * Style.marginXL * scaling : 0) + default: + return Style.marginS * scaling + } + } // --------------------------------------------- property int calculatedX: { @@ -300,9 +298,9 @@ Loader { if (panelAnchorHorizontalCenter) { return Math.round((panelWindow.width - panelBackground.width) / 2) } else if (panelAnchorLeft) { - return 0 + return marginLeft } else if (panelAnchorRight) { - return Math.round(panelWindow.width - panelBackground.width) + return Math.round(panelWindow.width - panelBackground.width - marginRight) } // No fixed anchoring @@ -310,10 +308,10 @@ Loader { // Vertical bar if (barPosition === "right") { // To the left of the right bar - return Math.round(panelWindow.width - panelBackground.width) + return Math.round(panelWindow.width - panelBackground.width - marginRight) } else { // To the right of the left bar - return 0 + return marginLeft } } else { // Horizontal bar @@ -321,8 +319,8 @@ Loader { // Position panel relative to button var targetX = buttonPosition.x + (buttonWidth / 2) - (panelBackground.width / 2) // Keep panel within screen bounds - var maxX = panelWindow.width - panelBackground.width - var minX = Style.marginS * scaling + var maxX = panelWindow.width - panelBackground.width - marginRight + var minX = marginLeft return Math.round(Math.max(minX, Math.min(targetX, maxX))) } else { // Fallback to center horizontally @@ -337,9 +335,9 @@ Loader { if (panelAnchorVerticalCenter) { return Math.round((panelWindow.height - panelBackground.height) / 2) } else if (panelAnchorTop) { - return 0 + return marginTop } else if (panelAnchorBottom) { - return Math.round(panelWindow.height - panelBackground.height) + return Math.round(panelWindow.height - panelBackground.height - marginBottom) } // No fixed anchoring @@ -349,8 +347,8 @@ Loader { // Position panel relative to button var targetY = buttonPosition.y + (buttonHeight / 2) - (panelBackground.height / 2) // Keep panel within screen bounds - var maxY = panelWindow.height - panelBackground.height - var minY = Style.marginS * scaling + var maxY = panelWindow.height - panelBackground.height - marginBottom + var minY = marginTop return Math.round(Math.max(minY, Math.min(targetY, maxY))) } else { // Fallback to center vertically @@ -360,10 +358,10 @@ Loader { // Horizontal bar if (barPosition === "bottom") { // Above the bottom bar - return Math.round(panelWindow.height - panelBackground.height) + return Math.round(panelWindow.height - panelBackground.height - marginBottom) } else { // Below the top bar - return 0 + return marginTop } } } From 3a6bf8d299420d7c0a20c011d00d427e2f22e6b6 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 22:20:42 -0400 Subject: [PATCH 29/36] Bar widgets: fixed bg colors when used with showCapsule=false --- Modules/Bar/Widgets/Bluetooth.qml | 2 +- Modules/Bar/Widgets/DarkModeToggle.qml | 4 +++- Modules/Bar/Widgets/KeepAwake.qml | 2 +- Modules/Bar/Widgets/NightLight.qml | 2 +- Modules/Bar/Widgets/NotificationHistory.qml | 2 +- Modules/Bar/Widgets/PowerProfile.qml | 2 +- Modules/Bar/Widgets/PowerToggle.qml | 2 +- Modules/Bar/Widgets/SidePanelToggle.qml | 2 +- Modules/Bar/Widgets/WiFi.qml | 2 +- Widgets/NIconButton.qml | 2 +- 10 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Modules/Bar/Widgets/Bluetooth.qml b/Modules/Bar/Widgets/Bluetooth.qml index 40ed96a..656794b 100644 --- a/Modules/Bar/Widgets/Bluetooth.qml +++ b/Modules/Bar/Widgets/Bluetooth.qml @@ -15,7 +15,7 @@ NIconButton { baseSize: Style.capsuleHeight compact: (Settings.data.bar.density === "compact") - colorBg: Color.mSurfaceVariant + colorBg: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent colorFg: Color.mOnSurface colorBorder: Color.transparent colorBorderHover: Color.transparent diff --git a/Modules/Bar/Widgets/DarkModeToggle.qml b/Modules/Bar/Widgets/DarkModeToggle.qml index 8e39204..0e45bd2 100644 --- a/Modules/Bar/Widgets/DarkModeToggle.qml +++ b/Modules/Bar/Widgets/DarkModeToggle.qml @@ -13,9 +13,11 @@ NIconButton { tooltipText: "Toggle light/dark mode." compact: (Settings.data.bar.density === "compact") baseSize: Style.capsuleHeight - colorBg: Settings.data.colorSchemes.darkMode ? Color.mSurfaceVariant : Color.mPrimary + colorBg: Settings.data.colorSchemes.darkMode ? (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) : Color.mPrimary colorFg: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mOnPrimary colorBorder: Color.transparent colorBorderHover: Color.transparent onClicked: Settings.data.colorSchemes.darkMode = !Settings.data.colorSchemes.darkMode } + + diff --git a/Modules/Bar/Widgets/KeepAwake.qml b/Modules/Bar/Widgets/KeepAwake.qml index eb0cf13..9c4626f 100644 --- a/Modules/Bar/Widgets/KeepAwake.qml +++ b/Modules/Bar/Widgets/KeepAwake.qml @@ -15,7 +15,7 @@ NIconButton { compact: (Settings.data.bar.density === "compact") icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off" tooltipText: IdleInhibitorService.isInhibited ? "Disable keep awake" : "Enable keep awake" - colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant + colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mOnSurface colorBorder: Color.transparent onClicked: IdleInhibitorService.manualToggle() diff --git a/Modules/Bar/Widgets/NightLight.qml b/Modules/Bar/Widgets/NightLight.qml index 9d40eb0..d48097c 100644 --- a/Modules/Bar/Widgets/NightLight.qml +++ b/Modules/Bar/Widgets/NightLight.qml @@ -16,7 +16,7 @@ NIconButton { compact: (Settings.data.bar.density === "compact") baseSize: Style.capsuleHeight - colorBg: Settings.data.nightLight.forced ? Color.mPrimary : Color.mSurfaceVariant + colorBg: Settings.data.nightLight.forced ? Color.mPrimary : (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) colorFg: Settings.data.nightLight.forced ? Color.mOnPrimary : Color.mOnSurface colorBorder: Color.transparent colorBorderHover: Color.transparent diff --git a/Modules/Bar/Widgets/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml index 2446312..91faa68 100644 --- a/Modules/Bar/Widgets/NotificationHistory.qml +++ b/Modules/Bar/Widgets/NotificationHistory.qml @@ -53,7 +53,7 @@ NIconButton { compact: (Settings.data.bar.density === "compact") icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell" tooltipText: Settings.data.notifications.doNotDisturb ? "Notification history.\nRight-click to disable 'Do Not Disturb'." : "Notification history.\nRight-click to enable 'Do Not Disturb'." - colorBg: Color.mSurfaceVariant + colorBg: (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) colorFg: Color.mOnSurface colorBorder: Color.transparent colorBorderHover: Color.transparent diff --git a/Modules/Bar/Widgets/PowerProfile.qml b/Modules/Bar/Widgets/PowerProfile.qml index 1aba22a..2ddda3f 100644 --- a/Modules/Bar/Widgets/PowerProfile.qml +++ b/Modules/Bar/Widgets/PowerProfile.qml @@ -47,7 +47,7 @@ NIconButton { icon: root.profileIcon() tooltipText: root.profileName() compact: (Settings.data.bar.density === "compact") - colorBg: (PowerProfileService.profile === PowerProfile.Balanced) ? Color.mSurfaceVariant : Color.mPrimary + colorBg: (PowerProfileService.profile === PowerProfile.Balanced) ? (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) : Color.mPrimary colorFg: (PowerProfileService.profile === PowerProfile.Balanced) ? Color.mOnSurface : Color.mOnPrimary colorBorder: Color.transparent colorBorderHover: Color.transparent diff --git a/Modules/Bar/Widgets/PowerToggle.qml b/Modules/Bar/Widgets/PowerToggle.qml index bd6eceb..9f33274 100644 --- a/Modules/Bar/Widgets/PowerToggle.qml +++ b/Modules/Bar/Widgets/PowerToggle.qml @@ -15,7 +15,7 @@ NIconButton { baseSize: Style.capsuleHeight icon: "power" tooltipText: "Power Settings" - colorBg: Color.mSurfaceVariant + colorBg: (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) colorFg: Color.mError colorBorder: Color.transparent colorBorderHover: Color.transparent diff --git a/Modules/Bar/Widgets/SidePanelToggle.qml b/Modules/Bar/Widgets/SidePanelToggle.qml index 4c122d1..b52e41f 100644 --- a/Modules/Bar/Widgets/SidePanelToggle.qml +++ b/Modules/Bar/Widgets/SidePanelToggle.qml @@ -35,7 +35,7 @@ NIconButton { tooltipText: "Open side panel." baseSize: Style.capsuleHeight compact: (Settings.data.bar.density === "compact") - colorBg: Color.mSurfaceVariant + colorBg: (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) colorFg: Color.mOnSurface colorBgHover: useDistroLogo ? Color.mSurfaceVariant : Color.mTertiary colorBorder: Color.transparent diff --git a/Modules/Bar/Widgets/WiFi.qml b/Modules/Bar/Widgets/WiFi.qml index fb64f68..9bc6058 100644 --- a/Modules/Bar/Widgets/WiFi.qml +++ b/Modules/Bar/Widgets/WiFi.qml @@ -15,7 +15,7 @@ NIconButton { compact: (Settings.data.bar.density === "compact") baseSize: Style.capsuleHeight - colorBg: Color.mSurfaceVariant + colorBg: (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) colorFg: Color.mOnSurface colorBorder: Color.transparent colorBorderHover: Color.transparent diff --git a/Widgets/NIconButton.qml b/Widgets/NIconButton.qml index ce5cc26..5989190 100644 --- a/Widgets/NIconButton.qml +++ b/Widgets/NIconButton.qml @@ -33,7 +33,7 @@ Rectangle { implicitHeight: Math.round(baseSize * scaling) opacity: root.enabled ? Style.opacityFull : Style.opacityMedium - color: root.enabled && root.hovering ? colorBgHover : Settings.data.bar.showCapsule ? colorBg : Color.transparent + color: root.enabled && root.hovering ? colorBgHover : colorBg radius: width * 0.5 border.color: root.enabled && root.hovering ? colorBorderHover : colorBorder border.width: Math.max(1, Style.borderS * scaling) From a92b4b311af1f931efad554b2dc64fbbf241f682 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 22:26:56 -0400 Subject: [PATCH 30/36] Renamed and moved NPill to BarPill. Pill should not be used outside of the Bar as they rely on bar settings. --- Widgets/NPill.qml => Modules/Bar/Extras/BarPill.qml | 5 +++-- .../Bar/Extras/BarPillHorizontal.qml | 1 + .../Bar/Extras/BarPillVertical.qml | 2 ++ Modules/Bar/Widgets/Battery.qml | 5 +++-- Modules/Bar/Widgets/Brightness.qml | 5 +++-- Modules/Bar/Widgets/Clock.qml | 2 +- Modules/Bar/Widgets/CustomButton.qml | 5 +++-- Modules/Bar/Widgets/KeyboardLayout.qml | 5 +++-- Modules/Bar/Widgets/Microphone.qml | 5 +++-- Modules/Bar/Widgets/Volume.qml | 5 +++-- Services/BarWidgetRegistry.qml | 2 +- 11 files changed, 26 insertions(+), 16 deletions(-) rename Widgets/NPill.qml => Modules/Bar/Extras/BarPill.qml (97%) rename Widgets/NPillHorizontal.qml => Modules/Bar/Extras/BarPillHorizontal.qml (99%) rename Widgets/NPillVertical.qml => Modules/Bar/Extras/BarPillVertical.qml (99%) diff --git a/Widgets/NPill.qml b/Modules/Bar/Extras/BarPill.qml similarity index 97% rename from Widgets/NPill.qml rename to Modules/Bar/Extras/BarPill.qml index 28d2578..6714d17 100644 --- a/Widgets/NPill.qml +++ b/Modules/Bar/Extras/BarPill.qml @@ -2,6 +2,7 @@ import QtQuick import QtQuick.Controls import qs.Commons import qs.Services +import qs.Widgets Item { id: root @@ -41,7 +42,7 @@ Item { Component { id: verticalPillComponent - NPillVertical { + BarPillVertical { icon: root.icon text: root.text suffix: root.suffix @@ -66,7 +67,7 @@ Item { Component { id: horizontalPillComponent - NPillHorizontal { + BarPillHorizontal { icon: root.icon text: root.text suffix: root.suffix diff --git a/Widgets/NPillHorizontal.qml b/Modules/Bar/Extras/BarPillHorizontal.qml similarity index 99% rename from Widgets/NPillHorizontal.qml rename to Modules/Bar/Extras/BarPillHorizontal.qml index 45cc95b..0e4b548 100644 --- a/Widgets/NPillHorizontal.qml +++ b/Modules/Bar/Extras/BarPillHorizontal.qml @@ -2,6 +2,7 @@ import QtQuick import QtQuick.Controls import qs.Commons import qs.Services +import qs.Widgets Item { id: root diff --git a/Widgets/NPillVertical.qml b/Modules/Bar/Extras/BarPillVertical.qml similarity index 99% rename from Widgets/NPillVertical.qml rename to Modules/Bar/Extras/BarPillVertical.qml index 1c5991a..9b97527 100644 --- a/Widgets/NPillVertical.qml +++ b/Modules/Bar/Extras/BarPillVertical.qml @@ -2,6 +2,8 @@ import QtQuick import QtQuick.Controls import qs.Commons import qs.Services +import qs.Widgets + Item { id: root diff --git a/Modules/Bar/Widgets/Battery.qml b/Modules/Bar/Widgets/Battery.qml index f91599a..2b5ec67 100644 --- a/Modules/Bar/Widgets/Battery.qml +++ b/Modules/Bar/Widgets/Battery.qml @@ -5,6 +5,7 @@ import QtQuick.Layouts import qs.Commons import qs.Services import qs.Widgets +import qs.Modules.Bar.Extras Item { id: root @@ -81,11 +82,11 @@ Item { } } - NPill { + BarPill { id: pill compact: (Settings.data.bar.density === "compact") - rightOpen: BarWidgetRegistry.getNPillDirection(root) + rightOpen: BarWidgetRegistry.getPillDirection(root) icon: testMode ? BatteryService.getIcon(testPercent, testCharging, true) : BatteryService.getIcon(percent, charging, isReady) text: (isReady || testMode) ? Math.round(percent) : "-" suffix: "%" diff --git a/Modules/Bar/Widgets/Brightness.qml b/Modules/Bar/Widgets/Brightness.qml index e01c157..c588b1d 100644 --- a/Modules/Bar/Widgets/Brightness.qml +++ b/Modules/Bar/Widgets/Brightness.qml @@ -4,6 +4,7 @@ import qs.Commons import qs.Modules.SettingsPanel import qs.Services import qs.Widgets +import qs.Modules.Bar.Extras Item { id: root @@ -73,11 +74,11 @@ Item { onTriggered: pill.hide() } - NPill { + BarPill { id: pill compact: (Settings.data.bar.density === "compact") - rightOpen: BarWidgetRegistry.getNPillDirection(root) + rightOpen: BarWidgetRegistry.getPillDirection(root) icon: getIcon() autoHide: false // Important to be false so we can hover as long as we want text: { diff --git a/Modules/Bar/Widgets/Clock.qml b/Modules/Bar/Widgets/Clock.qml index 0cf3ff9..3b2e4f7 100644 --- a/Modules/Bar/Widgets/Clock.qml +++ b/Modules/Bar/Widgets/Clock.qml @@ -40,7 +40,7 @@ Rectangle { readonly property bool verticalMode: barPosition === "left" || barPosition === "right" implicitWidth: verticalMode ? Math.round(Style.capsuleHeight * scaling) : Math.round(layout.implicitWidth + Style.marginM * 2 * scaling) - implicitHeight: verticalMode ? Math.round(Style.capsuleHeight * 2.5 * scaling) : Math.round(Style.capsuleHeight * scaling) // Match NPill + implicitHeight: verticalMode ? Math.round(Style.capsuleHeight * 2.5 * scaling) : Math.round(Style.capsuleHeight * scaling) // Match BarPill radius: Math.round(Style.radiusS * scaling) color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent diff --git a/Modules/Bar/Widgets/CustomButton.qml b/Modules/Bar/Widgets/CustomButton.qml index d32c8a8..496c670 100644 --- a/Modules/Bar/Widgets/CustomButton.qml +++ b/Modules/Bar/Widgets/CustomButton.qml @@ -6,6 +6,7 @@ import qs.Commons import qs.Services import qs.Widgets import qs.Modules.SettingsPanel +import qs.Modules.Bar.Extras Item { id: root @@ -43,10 +44,10 @@ Item { implicitWidth: pill.width implicitHeight: pill.height - NPill { + BarPill { id: pill - rightOpen: BarWidgetRegistry.getNPillDirection(root) + rightOpen: BarWidgetRegistry.getPillDirection(root) icon: customIcon text: _dynamicText compact: (Settings.data.bar.density === "compact") diff --git a/Modules/Bar/Widgets/KeyboardLayout.qml b/Modules/Bar/Widgets/KeyboardLayout.qml index e1f4095..13b4dac 100644 --- a/Modules/Bar/Widgets/KeyboardLayout.qml +++ b/Modules/Bar/Widgets/KeyboardLayout.qml @@ -6,6 +6,7 @@ import Quickshell.Io import qs.Commons import qs.Services import qs.Widgets +import qs.Modules.Bar.Extras Item { id: root @@ -38,12 +39,12 @@ Item { implicitWidth: pill.width implicitHeight: pill.height - NPill { + BarPill { id: pill anchors.verticalCenter: parent.verticalCenter compact: (Settings.data.bar.density === "compact") - rightOpen: BarWidgetRegistry.getNPillDirection(root) + rightOpen: BarWidgetRegistry.getPillDirection(root) icon: "keyboard" autoHide: false // Important to be false so we can hover as long as we want text: currentLayout.toUpperCase() diff --git a/Modules/Bar/Widgets/Microphone.qml b/Modules/Bar/Widgets/Microphone.qml index 98f0011..7504414 100644 --- a/Modules/Bar/Widgets/Microphone.qml +++ b/Modules/Bar/Widgets/Microphone.qml @@ -6,6 +6,7 @@ import qs.Commons import qs.Modules.SettingsPanel import qs.Services import qs.Widgets +import qs.Modules.Bar.Extras Item { id: root @@ -86,9 +87,9 @@ Item { } } - NPill { + BarPill { id: pill - rightOpen: BarWidgetRegistry.getNPillDirection(root) + rightOpen: BarWidgetRegistry.getPillDirection(root) icon: getIcon() compact: (Settings.data.bar.density === "compact") autoHide: false // Important to be false so we can hover as long as we want diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml index bebc532..bcacd7f 100644 --- a/Modules/Bar/Widgets/Volume.qml +++ b/Modules/Bar/Widgets/Volume.qml @@ -6,6 +6,7 @@ import qs.Commons import qs.Modules.SettingsPanel import qs.Services import qs.Widgets +import qs.Modules.Bar.Extras Item { id: root @@ -71,11 +72,11 @@ Item { } } - NPill { + BarPill { id: pill compact: (Settings.data.bar.density === "compact") - rightOpen: BarWidgetRegistry.getNPillDirection(root) + rightOpen: BarWidgetRegistry.getPillDirection(root) icon: getIcon() autoHide: false // Important to be false so we can hover as long as we want text: Math.floor(AudioService.volume * 100) diff --git a/Services/BarWidgetRegistry.qml b/Services/BarWidgetRegistry.qml index 392b570..f12a94c 100644 --- a/Services/BarWidgetRegistry.qml +++ b/Services/BarWidgetRegistry.qml @@ -207,7 +207,7 @@ Singleton { return (widgetMetadata[id] !== undefined) && (widgetMetadata[id].allowUserSettings === true) } - function getNPillDirection(widget) { + function getPillDirection(widget) { try { if (widget.section === "left") { return true From de6b7c64705afd442565cfe8fc3982ab9bd0aaf3 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 22:47:43 -0400 Subject: [PATCH 31/36] Dimmer: bulletproffed test on screen --- Modules/Background/Dimmer.qml | 4 ++-- Modules/Bar/Extras/BarPillVertical.qml | 1 - Modules/Bar/Widgets/DarkModeToggle.qml | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Modules/Background/Dimmer.qml b/Modules/Background/Dimmer.qml index 6185ad8..9456d97 100644 --- a/Modules/Background/Dimmer.qml +++ b/Modules/Background/Dimmer.qml @@ -14,7 +14,7 @@ Variants { // Dimmer is only active on the screen where the panel is currently open. active: { - if (Settings.isLoaded && Settings.data.general.dimDesktop && modelData !== undefined && PanelService.openedPanel !== null && PanelService.openedPanel.item !== null) { + if (Settings.isLoaded && Settings.data.general.dimDesktop && modelData !== undefined && PanelService.openedPanel !== null && PanelService.openedPanel.item !== undefined && PanelService.openedPanel.item !== null) { return (PanelService.openedPanel.item.screen === modelData) } @@ -28,7 +28,7 @@ Variants { Component.onCompleted: { if (modelData) { - Logger.log("Dimmer", "component loaded on", modelData.name) + Logger.log("Dimmer", "Loaded on", modelData.name) } // When a NPanel opens it seems it is initialized with the primary screen for a very brief moment diff --git a/Modules/Bar/Extras/BarPillVertical.qml b/Modules/Bar/Extras/BarPillVertical.qml index 9b97527..494083e 100644 --- a/Modules/Bar/Extras/BarPillVertical.qml +++ b/Modules/Bar/Extras/BarPillVertical.qml @@ -4,7 +4,6 @@ import qs.Commons import qs.Services import qs.Widgets - Item { id: root diff --git a/Modules/Bar/Widgets/DarkModeToggle.qml b/Modules/Bar/Widgets/DarkModeToggle.qml index 0e45bd2..a5ada46 100644 --- a/Modules/Bar/Widgets/DarkModeToggle.qml +++ b/Modules/Bar/Widgets/DarkModeToggle.qml @@ -19,5 +19,3 @@ NIconButton { colorBorderHover: Color.transparent onClicked: Settings.data.colorSchemes.darkMode = !Settings.data.colorSchemes.darkMode } - - From 166da9191ef9e493c0efc9e3acedd7e2be02db5d Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 22:48:57 -0400 Subject: [PATCH 32/36] v2.10.0 --- Services/UpdateService.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Services/UpdateService.qml b/Services/UpdateService.qml index 5c3606b..f65fc89 100644 --- a/Services/UpdateService.qml +++ b/Services/UpdateService.qml @@ -8,8 +8,8 @@ Singleton { id: root // Public properties - property string baseVersion: "2.9.2" - property bool isDevelopment: true + property string baseVersion: "2.10.0" + property bool isDevelopment: false property string currentVersion: `v${!isDevelopment ? baseVersion : baseVersion + "-dev"}` From 7acca17b832b085da12b500bcd886c6df52951bb Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 23:10:12 -0400 Subject: [PATCH 33/36] 2.10.0-dev --- Modules/Bar/Widgets/ScreenRecorderIndicator.qml | 2 +- Services/UpdateService.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/Bar/Widgets/ScreenRecorderIndicator.qml b/Modules/Bar/Widgets/ScreenRecorderIndicator.qml index 7ddb867..e8a36cb 100644 --- a/Modules/Bar/Widgets/ScreenRecorderIndicator.qml +++ b/Modules/Bar/Widgets/ScreenRecorderIndicator.qml @@ -12,7 +12,7 @@ NIconButton { visible: ScreenRecorderService.isRecording icon: "camera-video" - tooltipText: "Screen recording is active\nClick to stop recording" + tooltipText: "Screen recording is active.\nClick to stop recording." compact: (Settings.data.bar.density === "compact") baseSize: Style.capsuleHeight colorBg: Color.mPrimary diff --git a/Services/UpdateService.qml b/Services/UpdateService.qml index f65fc89..da5a6db 100644 --- a/Services/UpdateService.qml +++ b/Services/UpdateService.qml @@ -9,7 +9,7 @@ Singleton { // Public properties property string baseVersion: "2.10.0" - property bool isDevelopment: false + property bool isDevelopment: true property string currentVersion: `v${!isDevelopment ? baseVersion : baseVersion + "-dev"}` From 0b790c219df381f25b70d197df83d05197b73a88 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 23:23:16 -0400 Subject: [PATCH 34/36] Dimming: replaced dimmer by panel dimming, now that we have no margins it works fine. --- Modules/Background/Dimmer.qml | 76 ----------------------------------- Widgets/NPanel.qml | 11 ++--- shell.qml | 1 - 3 files changed, 6 insertions(+), 82 deletions(-) delete mode 100644 Modules/Background/Dimmer.qml diff --git a/Modules/Background/Dimmer.qml b/Modules/Background/Dimmer.qml deleted file mode 100644 index 9456d97..0000000 --- a/Modules/Background/Dimmer.qml +++ /dev/null @@ -1,76 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Wayland -import qs.Commons -import qs.Services -import qs.Widgets - -Variants { - model: Quickshell.screens - - delegate: Loader { - required property ShellScreen modelData - - // Dimmer is only active on the screen where the panel is currently open. - active: { - if (Settings.isLoaded && Settings.data.general.dimDesktop && modelData !== undefined && PanelService.openedPanel !== null && PanelService.openedPanel.item !== undefined && PanelService.openedPanel.item !== null) { - return (PanelService.openedPanel.item.screen === modelData) - } - - return false - } - - sourceComponent: PanelWindow { - id: panel - - property real customOpacity: 0 - - Component.onCompleted: { - if (modelData) { - Logger.log("Dimmer", "Loaded on", modelData.name) - } - - // When a NPanel opens it seems it is initialized with the primary screen for a very brief moment - // before the screen actually updates to the proper value. We use a timer to delay the fade in to avoid - // a single frame flicker on the main screen when opening a panel on another screen. - fadeInTimer.start() - } - - Connections { - target: PanelService - function onWillClose() { - customOpacity = Style.opacityNone - } - } - - Timer { - id: fadeInTimer - interval: 100 - onTriggered: customOpacity = Style.opacityHeavy - } - - screen: modelData - - WlrLayershell.layer: WlrLayer.Top - WlrLayershell.exclusionMode: ExclusionMode.Ignore - WlrLayershell.keyboardFocus: WlrKeyboardFocus.None - WlrLayershell.namespace: "quickshell-dimmer" - - // mask: Region {} - anchors { - top: true - bottom: true - right: true - left: true - } - - color: Qt.alpha(Color.mShadow, customOpacity) - Behavior on color { - ColorAnimation { - duration: Style.animationSlow - } - } - } - } -} diff --git a/Widgets/NPanel.qml b/Widgets/NPanel.qml index a232b84..5b4b898 100644 --- a/Widgets/NPanel.qml +++ b/Widgets/NPanel.qml @@ -38,6 +38,7 @@ Loader { readonly property real originalOpacity: 0.0 property real scaleValue: originalScale property real opacityValue: originalOpacity + property real dimmingOpacity: 0 property alias isClosing: hideTimer.running @@ -108,6 +109,7 @@ Loader { // ----------------------------------------- function close() { + dimmingOpacity = 0 scaleValue = originalScale opacityValue = originalOpacity hideTimer.start() @@ -149,6 +151,7 @@ Loader { Component.onCompleted: { Logger.log("NPanel", "Opened", root.objectName) + dimmingOpacity = Style.opacityHeavy } Connections { @@ -174,17 +177,14 @@ Loader { visible: true - // No dimming here - color: Color.transparent - - WlrLayershell.layer: Settings.data.general.dimDesktop ? WlrLayer.Overlay : WlrLayer.Top + color: Settings.data.general.dimDesktop ? Qt.alpha(Color.mShadow, dimmingOpacity) : Color.transparent WlrLayershell.exclusionMode: ExclusionMode.Ignore WlrLayershell.namespace: "noctalia-panel" WlrLayershell.keyboardFocus: root.panelKeyboardFocus ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None Behavior on color { ColorAnimation { - duration: Style.animationNormal + duration: Style.animationSlow } } @@ -208,6 +208,7 @@ Loader { onClicked: root.close() } + // The actual panel's content Rectangle { id: panelBackground color: panelBackgroundColor diff --git a/shell.qml b/shell.qml index 6f0e8ea..24544f5 100644 --- a/shell.qml +++ b/shell.qml @@ -37,7 +37,6 @@ ShellRoot { Background {} Overview {} ScreenCorners {} - Dimmer {} Bar {} Dock {} From 292337dc00031c6878ee36f502236197946fdba1 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 23:26:35 -0400 Subject: [PATCH 35/36] Settings: Put monitor configs below other settings on Bar and Notif. tabs --- Modules/SettingsPanel/Tabs/BarTab.qml | 68 +++++++++---------- .../SettingsPanel/Tabs/NotificationTab.qml | 68 +++++++++---------- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/Modules/SettingsPanel/Tabs/BarTab.qml b/Modules/SettingsPanel/Tabs/BarTab.qml index c7c2d6b..8a005bc 100644 --- a/Modules/SettingsPanel/Tabs/BarTab.qml +++ b/Modules/SettingsPanel/Tabs/BarTab.qml @@ -192,40 +192,6 @@ ColumnLayout { Layout.bottomMargin: Style.marginXL * scaling } - // Monitor Configuration - ColumnLayout { - spacing: Style.marginM * scaling - Layout.fillWidth: true - - NHeader { - label: "Monitors Configuration" - description: "Show bar on specific monitors. Defaults to all if none are chosen." - } - - Repeater { - model: Quickshell.screens || [] - delegate: NCheckbox { - Layout.fillWidth: true - label: modelData.name || "Unknown" - description: `${modelData.model} - ${modelData.width}x${modelData.height} [x:${modelData.x} y:${modelData.y}]` - checked: (Settings.data.bar.monitors || []).indexOf(modelData.name) !== -1 - onToggled: checked => { - if (checked) { - Settings.data.bar.monitors = addMonitor(Settings.data.bar.monitors, modelData.name) - } else { - Settings.data.bar.monitors = removeMonitor(Settings.data.bar.monitors, modelData.name) - } - } - } - } - } - - NDivider { - Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling - } - // Widgets Management Section ColumnLayout { spacing: Style.marginXXS * scaling @@ -293,6 +259,40 @@ ColumnLayout { Layout.bottomMargin: Style.marginXL * scaling } + // Monitor Configuration + ColumnLayout { + spacing: Style.marginM * scaling + Layout.fillWidth: true + + NHeader { + label: "Monitors Configuration" + description: "Show bar on specific monitors. Defaults to all if none are chosen." + } + + Repeater { + model: Quickshell.screens || [] + delegate: NCheckbox { + Layout.fillWidth: true + label: modelData.name || "Unknown" + description: `${modelData.model} - ${modelData.width}x${modelData.height} [x:${modelData.x} y:${modelData.y}]` + checked: (Settings.data.bar.monitors || []).indexOf(modelData.name) !== -1 + onToggled: checked => { + if (checked) { + Settings.data.bar.monitors = addMonitor(Settings.data.bar.monitors, modelData.name) + } else { + Settings.data.bar.monitors = removeMonitor(Settings.data.bar.monitors, modelData.name) + } + } + } + } + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: Style.marginXL * scaling + Layout.bottomMargin: Style.marginXL * scaling + } + // --------------------------------- // Signal functions // --------------------------------- diff --git a/Modules/SettingsPanel/Tabs/NotificationTab.qml b/Modules/SettingsPanel/Tabs/NotificationTab.qml index a996b1e..7d7a7f2 100644 --- a/Modules/SettingsPanel/Tabs/NotificationTab.qml +++ b/Modules/SettingsPanel/Tabs/NotificationTab.qml @@ -46,40 +46,6 @@ ColumnLayout { Layout.bottomMargin: Style.marginXL * scaling } - // Monitor Configuration - ColumnLayout { - spacing: Style.marginM * scaling - Layout.fillWidth: true - - NHeader { - label: "Monitors Configuration" - description: "Show bar on specific monitors. Defaults to all if none are chosen." - } - - Repeater { - model: Quickshell.screens || [] - delegate: NCheckbox { - Layout.fillWidth: true - label: modelData.name || "Unknown" - description: `${modelData.model} - ${modelData.width}x${modelData.height} [x:${modelData.x} y:${modelData.y}]` - checked: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1 - onToggled: checked => { - if (checked) { - Settings.data.notifications.monitors = addMonitor(Settings.data.notifications.monitors, modelData.name) - } else { - Settings.data.notifications.monitors = removeMonitor(Settings.data.notifications.monitors, modelData.name) - } - } - } - } - } - - NDivider { - Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling - } - // Notification Duration Settings ColumnLayout { spacing: Style.marginL * scaling @@ -159,4 +125,38 @@ ColumnLayout { Layout.topMargin: Style.marginXL * scaling Layout.bottomMargin: Style.marginXL * scaling } + + // Monitor Configuration + ColumnLayout { + spacing: Style.marginM * scaling + Layout.fillWidth: true + + NHeader { + label: "Monitors Configuration" + description: "Show bar on specific monitors. Defaults to all if none are chosen." + } + + Repeater { + model: Quickshell.screens || [] + delegate: NCheckbox { + Layout.fillWidth: true + label: modelData.name || "Unknown" + description: `${modelData.model} - ${modelData.width}x${modelData.height} [x:${modelData.x} y:${modelData.y}]` + checked: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1 + onToggled: checked => { + if (checked) { + Settings.data.notifications.monitors = addMonitor(Settings.data.notifications.monitors, modelData.name) + } else { + Settings.data.notifications.monitors = removeMonitor(Settings.data.notifications.monitors, modelData.name) + } + } + } + } + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: Style.marginXL * scaling + Layout.bottomMargin: Style.marginXL * scaling + } } From 82044601122252c6b229b577a7a53d0d10cd04d3 Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Tue, 16 Sep 2025 23:29:02 -0400 Subject: [PATCH 36/36] v2.11.0 --- Services/UpdateService.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Services/UpdateService.qml b/Services/UpdateService.qml index da5a6db..92bd577 100644 --- a/Services/UpdateService.qml +++ b/Services/UpdateService.qml @@ -8,8 +8,8 @@ Singleton { id: root // Public properties - property string baseVersion: "2.10.0" - property bool isDevelopment: true + property string baseVersion: "2.11.0" + property bool isDevelopment: false property string currentVersion: `v${!isDevelopment ? baseVersion : baseVersion + "-dev"}`