From cb4de305fe89b3ffef8f72f77d250a6b78d4076b Mon Sep 17 00:00:00 2001 From: loner <2788892716@qq.com> Date: Tue, 4 Nov 2025 10:59:55 +0800 Subject: [PATCH 01/10] feat(battery): support adaptive layout for battery panel --- Modules/Bar/Battery/BatteryPanel.qml | 118 +++++++++++++-------------- 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/Modules/Bar/Battery/BatteryPanel.qml b/Modules/Bar/Battery/BatteryPanel.qml index 4d359dce..a93a73dd 100644 --- a/Modules/Bar/Battery/BatteryPanel.qml +++ b/Modules/Bar/Battery/BatteryPanel.qml @@ -10,22 +10,21 @@ import qs.Widgets NPanel { id: root - preferredWidth: 350 * Style.uiScaleRatio - preferredHeight: 210 * Style.uiScaleRatio + panelKeyboardFocus: true property var optionsModel: [] function updateOptionsModel() { let newOptions = [{ - "id": BatteryService.ChargingMode.Full, - "label": "battery.panel.full" - }, { - "id": BatteryService.ChargingMode.Balanced, - "label": "battery.panel.balanced" - }, { - "id": BatteryService.ChargingMode.Lifespan, - "label": "battery.panel.lifespan" - }] + "id": BatteryService.ChargingMode.Full, + "label": "battery.panel.full" + }, { + "id": BatteryService.ChargingMode.Balanced, + "label": "battery.panel.balanced" + }, { + "id": BatteryService.ChargingMode.Lifespan, + "label": "battery.panel.lifespan" + }] root.optionsModel = newOptions } @@ -33,11 +32,52 @@ NPanel { updateOptionsModel() } + ButtonGroup { + id: batteryGroup + } + + Component { + id: optionsComponent + ColumnLayout { + spacing: Style.marginM + Repeater { + model: root.optionsModel + delegate: NRadioButton { + ButtonGroup.group: batteryGroup + required property var modelData + text: I18n.tr(modelData.label, { + "percent": BatteryService.getThresholdValue(modelData.id) + }) + checked: BatteryService.chargingMode === modelData.id + onClicked: { + BatteryService.setChargingMode(modelData.id) + } + Layout.fillWidth: true + } + } + } + } + + Component { + id: disabledComponent + NText { + text: I18n.tr("battery.panel.disabled") + pointSize: Style.fontSizeL + color: Color.mOnSurfaceVariant + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + } + } + panelContent: Item { anchors.fill: parent + property real contentPreferredHeight: mainLayout.implicitHeight + Style.marginM * 2 + property real contentPreferredWidth: 350 * Style.uiScaleRatio ColumnLayout { - anchors.fill: parent + id: mainLayout + anchors.centerIn: parent + width: parent.contentPreferredWidth - Style.marginM * 2 anchors.margins: Style.marginM spacing: Style.marginM @@ -78,57 +118,15 @@ NPanel { } } - ButtonGroup { - id: batteryGroup - } - NBox { Layout.fillWidth: true - Layout.fillHeight: true + Layout.preferredHeight: loader.implicitHeight + Style.marginM * 2 - ColumnLayout { - anchors.fill: parent - anchors.margins: Style.marginM - spacing: Style.marginM - - Repeater { - model: optionsModel - - NRadioButton { - visible: BatteryService.chargingMode !== BatteryService.ChargingMode.Disabled - ButtonGroup.group: batteryGroup - required property var modelData - text: I18n.tr(modelData.label, { - "percent": BatteryService.getThresholdValue(modelData.id) - }) - checked: BatteryService.chargingMode === modelData.id - onClicked: { - BatteryService.setChargingMode(modelData.id) - } - Layout.fillWidth: true - } - } - } - - ColumnLayout { - visible: BatteryService.chargingMode === BatteryService.ChargingMode.Disabled - anchors.fill: parent - spacing: Style.marginM - - Item { - Layout.fillHeight: true - } - - NText { - text: I18n.tr("battery.panel.disabled") - pointSize: Style.fontSizeL - color: Color.mOnSurfaceVariant - Layout.alignment: Qt.AlignHCenter - } - - Item { - Layout.fillHeight: true - } + Loader { + id: loader + anchors.centerIn: parent + width: parent.width - Style.marginM * 2 + sourceComponent: BatteryService.chargingMode === BatteryService.ChargingMode.Disabled ? disabledComponent : optionsComponent } } } From 4ed3744cfb071d2eb8d2d2c954ac5a091cc63c98 Mon Sep 17 00:00:00 2001 From: loner <2788892716@qq.com> Date: Tue, 4 Nov 2025 11:29:17 +0800 Subject: [PATCH 02/10] fix(battery): remove panelKeyboardFocus --- Modules/Bar/Battery/BatteryPanel.qml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Modules/Bar/Battery/BatteryPanel.qml b/Modules/Bar/Battery/BatteryPanel.qml index a93a73dd..5ca255b5 100644 --- a/Modules/Bar/Battery/BatteryPanel.qml +++ b/Modules/Bar/Battery/BatteryPanel.qml @@ -10,8 +10,6 @@ import qs.Widgets NPanel { id: root - panelKeyboardFocus: true - property var optionsModel: [] function updateOptionsModel() { From 4b67e773b920b59f539a57cc07f5f1832109c8f1 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 4 Nov 2025 09:12:15 -0500 Subject: [PATCH 03/10] Calendar: disable clicking on dates unless you have gnome-calendar installed. --- Modules/Bar/Calendar/CalendarPanel.qml | 6 ++++-- Services/ProgramCheckerService.qml | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Modules/Bar/Calendar/CalendarPanel.qml b/Modules/Bar/Calendar/CalendarPanel.qml index ba0bbf8e..dddfd8be 100644 --- a/Modules/Bar/Calendar/CalendarPanel.qml +++ b/Modules/Bar/Calendar/CalendarPanel.qml @@ -611,8 +611,10 @@ NPanel { onClicked: { const dateWithSlashes = `${(modelData.month + 1).toString().padStart(2, '0')}/${modelData.day.toString().padStart(2, '0')}/${modelData.year.toString().substring(2)}` - Quickshell.execDetached(["gnome-calendar", "--date", dateWithSlashes]) - root.close() + if (ProgramCheckerService.gnomeCalendarAvailable) { + Quickshell.execDetached(["gnome-calendar", "--date", dateWithSlashes]) + root.close() + } } onExited: { diff --git a/Services/ProgramCheckerService.qml b/Services/ProgramCheckerService.qml index 93189f09..b18ef1ea 100644 --- a/Services/ProgramCheckerService.qml +++ b/Services/ProgramCheckerService.qml @@ -24,6 +24,7 @@ Singleton { property bool wlsunsetAvailable: false property bool app2unitAvailable: false property bool codeAvailable: false + property bool gnomeCalendarAvailable: false // Discord client auto-detection property var availableDiscordClients: [] @@ -109,7 +110,8 @@ Singleton { "app2unitAvailable": ["which", "app2unit"], "gpuScreenRecorderAvailable": ["sh", "-c", "command -v gpu-screen-recorder >/dev/null 2>&1 || (command -v flatpak >/dev/null 2>&1 && flatpak list --app | grep -q 'com.dec05eba.gpu_screen_recorder')"], "wlsunsetAvailable": ["which", "wlsunset"], - "codeAvailable": ["which", "code"] + "codeAvailable": ["which", "code"], + "gnomeCalendarAvailable": ["which", "gnome-calendar"] }) // Internal tracking From dc69d1f1e66e81812cce6bcc4a9fae241328b385 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 4 Nov 2025 09:49:11 -0500 Subject: [PATCH 04/10] Bar: fix 1px gap between bar an panel on right and bottom orientation --- Modules/Bar/Bar.qml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index fcd8669a..a8d6cd2f 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -47,7 +47,17 @@ Item { Loader { id: barContentLoader anchors.fill: parent - active: root.screen !== null && root.screen !== undefined + active: { + if (root.screen === null || root.screen === undefined) { + return false + } + + var monitors = Settings.data.bar.monitors || [] + var result = monitors.length === 0 || monitors.includes(root.screen.name) + + Logger.d("Shell", "NFullScreenWindow Loader for", root.screen?.name, "- shouldBeActive:", result, "- monitors:", JSON.stringify(monitors)) + return result + } sourceComponent: Item { anchors.fill: parent @@ -61,13 +71,13 @@ Item { x: { var baseX = (root.barPosition === "right") ? (parent.width - Style.barHeight - root.barMarginH) : root.barMarginH if (root.barPosition === "right") - return baseX + root.attachmentOverlap + return baseX - root.attachmentOverlap // Extend left towards panels return baseX } y: { var baseY = (root.barPosition === "bottom") ? (parent.height - Style.barHeight - root.barMarginV) : root.barMarginV if (root.barPosition === "bottom") - return baseY + root.attachmentOverlap + return baseY - root.attachmentOverlap // Extend up towards panels return baseY } width: { From fd79f75fd5fdad05a2047e551efa8c99bf1d5d37 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 4 Nov 2025 09:59:26 -0500 Subject: [PATCH 05/10] Shell/Bar: create full screen window everywhere so there is no limitations. --- Modules/Bar/Bar.qml | 1 - Modules/ControlCenter/ControlCenterPanel.qml | 22 ++++++++++++++------ Services/IPCService.qml | 15 ------------- Widgets/NPanel.qml | 11 +++++++++- shell.qml | 18 +++++++++------- 5 files changed, 37 insertions(+), 30 deletions(-) diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index a8d6cd2f..f8564ccb 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -55,7 +55,6 @@ Item { var monitors = Settings.data.bar.monitors || [] var result = monitors.length === 0 || monitors.includes(root.screen.name) - Logger.d("Shell", "NFullScreenWindow Loader for", root.screen?.name, "- shouldBeActive:", result, "- monitors:", JSON.stringify(monitors)) return result } diff --git a/Modules/ControlCenter/ControlCenterPanel.qml b/Modules/ControlCenter/ControlCenterPanel.qml index 10cccf70..9f570d91 100644 --- a/Modules/ControlCenter/ControlCenterPanel.qml +++ b/Modules/ControlCenter/ControlCenterPanel.qml @@ -49,12 +49,22 @@ NPanel { // Positioning readonly property string controlCenterPosition: Settings.data.controlCenter.position - panelAnchorHorizontalCenter: controlCenterPosition !== "close_to_bar_button" && (controlCenterPosition.endsWith("_center") || controlCenterPosition === "center") - panelAnchorVerticalCenter: controlCenterPosition === "center" - panelAnchorLeft: controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.endsWith("_left") - panelAnchorRight: controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.endsWith("_right") - panelAnchorBottom: controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.startsWith("bottom_") - panelAnchorTop: controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.startsWith("top_") + + // Check if there's a bar on this screen + readonly property bool hasBarOnScreen: { + var monitors = Settings.data.bar.monitors || [] + return monitors.length === 0 || monitors.includes(screen?.name) + } + + // When position is "close_to_bar_button" but there's no bar, fall back to center + readonly property bool shouldCenter: controlCenterPosition === "close_to_bar_button" && !hasBarOnScreen + + panelAnchorHorizontalCenter: shouldCenter || (controlCenterPosition !== "close_to_bar_button" && (controlCenterPosition.endsWith("_center") || controlCenterPosition === "center")) + panelAnchorVerticalCenter: shouldCenter || controlCenterPosition === "center" + panelAnchorLeft: !shouldCenter && controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.endsWith("_left") + panelAnchorRight: !shouldCenter && controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.endsWith("_right") + panelAnchorBottom: !shouldCenter && controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.startsWith("bottom_") + panelAnchorTop: !shouldCenter && controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.startsWith("top_") readonly property int profileHeight: Math.round(64 * Style.uiScaleRatio) readonly property int shortcutsHeight: Math.round(52 * Style.uiScaleRatio) diff --git a/Services/IPCService.qml b/Services/IPCService.qml index b3117105..aec9fa91 100644 --- a/Services/IPCService.qml +++ b/Services/IPCService.qml @@ -355,21 +355,6 @@ Item { // Execute pending callback if any if (pendingCallback) { - // Verify we have a NFullScreenWindow for this screen - var monitors = Settings.data.bar.monitors || [] - if (!(monitors.length === 0 || monitors.includes(detectedScreen.name))) { - // Fall back to first enabled screen as we can NOT show a panel on a screen without a Bar/NFullScreenWindow - if (monitors.length === 0 && Quickshell.screens.length > 0) { - detectedScreen = Quickshell.screens[0] - } else { - for (var i = 0; i < Quickshell.screens.length; i++) { - if (monitors.includes(Quickshell.screens[i].name)) { - detectedScreen = Quickshell.screens[i] - break - } - } - } - } Logger.d("IPC", "Executing pending IPC callback on screen:", detectedScreen.name) pendingCallback(detectedScreen) pendingCallback = null diff --git a/Widgets/NPanel.qml b/Widgets/NPanel.qml index b01abce5..defd7dd9 100644 --- a/Widgets/NPanel.qml +++ b/Widgets/NPanel.qml @@ -15,7 +15,16 @@ Item { // A panel can only be a attached to the bar of screen edges if property bool couldAttach: Settings.data.ui.panelsAttachedToBar - property bool couldAttachToBar: (Settings.data.ui.panelsAttachedToBar && Settings.data.bar.backgroundOpacity >= 1.0) + property bool couldAttachToBar: { + if (!Settings.data.ui.panelsAttachedToBar || Settings.data.bar.backgroundOpacity < 1.0) { + return false + } + + // A panel can only be attached to a bar if there is a bar on that screen + var monitors = Settings.data.bar.monitors || [] + var result = monitors.length === 0 || monitors.includes(screen.name) + return result + } // Edge snapping: if panel is within this distance (in pixels) from a screen edge, snap property real edgeSnapDistance: 50 diff --git a/shell.qml b/shell.qml index 8e207f67..b75e5085 100644 --- a/shell.qml +++ b/shell.qml @@ -209,11 +209,8 @@ ShellRoot { if (!modelData || !modelData.name) return false - var monitors = Settings.data.bar.monitors || [] - var result = monitors.length === 0 || monitors.includes(modelData.name) - - Logger.d("Shell", "NFullScreenWindow Loader for", modelData?.name, "- shouldBeActive:", result, "- monitors:", JSON.stringify(monitors)) - return result + Logger.d("Shell", "NFullScreenWindow activated for", modelData?.name) + return true } property bool windowLoaded: false @@ -281,9 +278,16 @@ ShellRoot { } // BarExclusionZone - created after NFullScreenWindow has fully loaded - // Must also be disabled when bar is hidden + // Disabled when bar is hidden or not configured for this screen Loader { - active: parent.windowLoaded && parent.shouldBeActive && BarService.isVisible + active: { + if (!parent.windowLoaded || !parent.shouldBeActive || !BarService.isVisible) + return false + + // Check if bar is configured for this screen + var monitors = Settings.data.bar.monitors || [] + return monitors.length === 0 || monitors.includes(modelData?.name) + } asynchronous: false sourceComponent: BarExclusionZone { From d3b4d2427a444c74c7d41d1fb2caaf1893f96035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Atoch?= Date: Tue, 4 Nov 2025 10:56:44 -0500 Subject: [PATCH 06/10] Bar: fix potential gap to the right of a right positioned bar with fractional scaling. --- Modules/Bar/Bar.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index f8564ccb..3215f0ab 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -83,7 +83,7 @@ Item { var baseWidth = root.barIsVertical ? Style.barHeight : (parent.width - root.barMarginH * 2) if (!root.barIsVertical) return baseWidth // Horizontal bars extend via height, not width - return baseWidth + root.attachmentOverlap + return baseWidth + root.attachmentOverlap + 1 } height: { var baseHeight = root.barIsVertical ? (parent.height - root.barMarginV * 2) : Style.barHeight From fa95835a1321d6f1da733ff53e5d95445b3d67ed Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 4 Nov 2025 11:28:26 -0500 Subject: [PATCH 07/10] NPanel: moving most properties inside the loader so we are sure the screen is already set. --- Widgets/NPanel.qml | 139 +++++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 69 deletions(-) diff --git a/Widgets/NPanel.qml b/Widgets/NPanel.qml index defd7dd9..848cac17 100644 --- a/Widgets/NPanel.qml +++ b/Widgets/NPanel.qml @@ -13,19 +13,6 @@ Item { // Screen property provided by NFullScreenWindow property ShellScreen screen: null - // A panel can only be a attached to the bar of screen edges if - property bool couldAttach: Settings.data.ui.panelsAttachedToBar - property bool couldAttachToBar: { - if (!Settings.data.ui.panelsAttachedToBar || Settings.data.bar.backgroundOpacity < 1.0) { - return false - } - - // A panel can only be attached to a bar if there is a bar on that screen - var monitors = Settings.data.bar.monitors || [] - var result = monitors.length === 0 || monitors.includes(screen.name) - return result - } - // Edge snapping: if panel is within this distance (in pixels) from a screen edge, snap property real edgeSnapDistance: 50 @@ -107,16 +94,6 @@ Item { readonly property bool hasExplicitHorizontalAnchor: panelAnchorHorizontalCenter || panelAnchorLeft || panelAnchorRight readonly property bool hasExplicitVerticalAnchor: panelAnchorVerticalCenter || panelAnchorTop || panelAnchorBottom - // Effective anchor properties - // These are true when: - // 1. Explicitly anchored, OR - // 2. Using button position and bar is on that edge, OR - // 3. Attached to bar with no explicit anchors (default centering behavior) - readonly property bool effectivePanelAnchorTop: panelAnchorTop || (useButtonPosition && barPosition === "top") || (couldAttach && !hasExplicitVerticalAnchor && barPosition === "top" && !barIsVertical) - readonly property bool effectivePanelAnchorBottom: panelAnchorBottom || (useButtonPosition && barPosition === "bottom") || (couldAttach && !hasExplicitVerticalAnchor && barPosition === "bottom" && !barIsVertical) - readonly property bool effectivePanelAnchorLeft: panelAnchorLeft || (useButtonPosition && barPosition === "left") || (couldAttach && !hasExplicitHorizontalAnchor && barPosition === "left" && barIsVertical) - readonly property bool effectivePanelAnchorRight: panelAnchorRight || (useButtonPosition && barPosition === "right") || (couldAttach && !hasExplicitHorizontalAnchor && barPosition === "right" && barIsVertical) - signal opened signal closed @@ -201,6 +178,30 @@ Item { sourceComponent: Item { anchors.fill: parent + // Screen-dependent attachment properties (moved from root to avoid race condition) + // By the time this Loader is active, screen has been assigned by NFullScreenWindow + readonly property bool couldAttach: Settings.data.ui.panelsAttachedToBar + readonly property bool couldAttachToBar: { + if (!Settings.data.ui.panelsAttachedToBar || Settings.data.bar.backgroundOpacity < 1.0) { + return false + } + + // A panel can only be attached to a bar if there is a bar on that screen + var monitors = Settings.data.bar.monitors || [] + var result = monitors.length === 0 || monitors.includes(root.screen?.name || "") + return result + } + + // Effective anchor properties (moved from root, depend on couldAttach) + // These are true when: + // 1. Explicitly anchored, OR + // 2. Using button position and bar is on that edge, OR + // 3. Attached to bar with no explicit anchors (default centering behavior) + readonly property bool effectivePanelAnchorTop: root.panelAnchorTop || (root.useButtonPosition && root.barPosition === "top") || (couldAttach && !root.hasExplicitVerticalAnchor && root.barPosition === "top" && !root.barIsVertical) + readonly property bool effectivePanelAnchorBottom: root.panelAnchorBottom || (root.useButtonPosition && root.barPosition === "bottom") || (couldAttach && !root.hasExplicitVerticalAnchor && root.barPosition === "bottom" && !root.barIsVertical) + readonly property bool effectivePanelAnchorLeft: root.panelAnchorLeft || (root.useButtonPosition && root.barPosition === "left") || (couldAttach && !root.hasExplicitHorizontalAnchor && root.barPosition === "left" && root.barIsVertical) + readonly property bool effectivePanelAnchorRight: root.panelAnchorRight || (root.useButtonPosition && root.barPosition === "right") || (couldAttach && !root.hasExplicitHorizontalAnchor && root.barPosition === "right" && root.barIsVertical) + // Expose panelBackground for mask region property alias maskRegion: panelBackground @@ -237,8 +238,8 @@ Item { readonly property bool hasInvertedCorners: topLeftInverted || topRightInverted || bottomLeftInverted || bottomRightInverted // Determine panel attachment type for animation - readonly property bool isAttachedToFloatingBar: hasInvertedCorners && root.barFloating && root.couldAttach - readonly property bool isAttachedToNonFloating: hasInvertedCorners && (!root.barFloating || !root.couldAttach) + readonly property bool isAttachedToFloatingBar: hasInvertedCorners && root.barFloating && couldAttach + readonly property bool isAttachedToNonFloating: hasInvertedCorners && (!root.barFloating || !couldAttach) readonly property bool isDetached: !hasInvertedCorners // Determine closest screen edge to slide from (for full slide animation) @@ -364,36 +365,36 @@ Item { // Also invert corners when touching screen edges (non-floating bar only) topLeftInverted: { // Bar attachment: only attach to bar if bar opacity >= 1.0 (no color clash) - var barInverted = root.couldAttachToBar && ((root.barPosition === "top" && !root.barIsVertical && root.effectivePanelAnchorTop) || (root.barPosition === "left" && root.barIsVertical && root.effectivePanelAnchorLeft)) + var barInverted = couldAttachToBar && ((root.barPosition === "top" && !root.barIsVertical && effectivePanelAnchorTop) || (root.barPosition === "left" && root.barIsVertical && effectivePanelAnchorLeft)) // Also detect when panel touches bar edge (e.g., centered panel that's too tall) var barTouchInverted = touchingTopBar || touchingLeftBar // Screen edge contact: can attach to screen edges even if bar opacity < 1.0 // For horizontal bars: invert when touching left/right edges // For vertical bars: invert when touching top/bottom edges - var edgeInverted = root.couldAttach && ((touchingLeftEdge && !root.barIsVertical) || (touchingTopEdge && root.barIsVertical)) + var edgeInverted = couldAttach && ((touchingLeftEdge && !root.barIsVertical) || (touchingTopEdge && root.barIsVertical)) // Also invert when touching screen edge opposite to bar (e.g., bottom edge when bar is at top) - var oppositeEdgeInverted = root.couldAttach && (touchingTopEdge && !root.barIsVertical && root.barPosition !== "top") + var oppositeEdgeInverted = couldAttach && (touchingTopEdge && !root.barIsVertical && root.barPosition !== "top") return barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted } topRightInverted: { - var barInverted = root.couldAttachToBar && ((root.barPosition === "top" && !root.barIsVertical && root.effectivePanelAnchorTop) || (root.barPosition === "right" && root.barIsVertical && root.effectivePanelAnchorRight)) + var barInverted = couldAttachToBar && ((root.barPosition === "top" && !root.barIsVertical && effectivePanelAnchorTop) || (root.barPosition === "right" && root.barIsVertical && effectivePanelAnchorRight)) var barTouchInverted = touchingTopBar || touchingRightBar - var edgeInverted = root.couldAttach && ((touchingRightEdge && !root.barIsVertical) || (touchingTopEdge && root.barIsVertical)) - var oppositeEdgeInverted = root.couldAttach && (touchingTopEdge && !root.barIsVertical && root.barPosition !== "top") + var edgeInverted = couldAttach && ((touchingRightEdge && !root.barIsVertical) || (touchingTopEdge && root.barIsVertical)) + var oppositeEdgeInverted = couldAttach && (touchingTopEdge && !root.barIsVertical && root.barPosition !== "top") return barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted } bottomLeftInverted: { - var barInverted = root.couldAttachToBar && ((root.barPosition === "bottom" && !root.barIsVertical && root.effectivePanelAnchorBottom) || (root.barPosition === "left" && root.barIsVertical && root.effectivePanelAnchorLeft)) + var barInverted = couldAttachToBar && ((root.barPosition === "bottom" && !root.barIsVertical && effectivePanelAnchorBottom) || (root.barPosition === "left" && root.barIsVertical && effectivePanelAnchorLeft)) var barTouchInverted = touchingBottomBar || touchingLeftBar - var edgeInverted = root.couldAttach && ((touchingLeftEdge && !root.barIsVertical) || (touchingBottomEdge && root.barIsVertical)) - var oppositeEdgeInverted = root.couldAttach && (touchingBottomEdge && !root.barIsVertical && root.barPosition !== "bottom") + var edgeInverted = couldAttach && ((touchingLeftEdge && !root.barIsVertical) || (touchingBottomEdge && root.barIsVertical)) + var oppositeEdgeInverted = couldAttach && (touchingBottomEdge && !root.barIsVertical && root.barPosition !== "bottom") return barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted } bottomRightInverted: { - var barInverted = root.couldAttachToBar && ((root.barPosition === "bottom" && !root.barIsVertical && root.effectivePanelAnchorBottom) || (root.barPosition === "right" && root.barIsVertical && root.effectivePanelAnchorRight)) + var barInverted = couldAttachToBar && ((root.barPosition === "bottom" && !root.barIsVertical && effectivePanelAnchorBottom) || (root.barPosition === "right" && root.barIsVertical && effectivePanelAnchorRight)) var barTouchInverted = touchingBottomBar || touchingRightBar - var edgeInverted = root.couldAttach && ((touchingRightEdge && !root.barIsVertical) || (touchingBottomEdge && root.barIsVertical)) - var oppositeEdgeInverted = root.couldAttach && (touchingBottomEdge && !root.barIsVertical && root.barPosition !== "bottom") + var edgeInverted = couldAttach && ((touchingRightEdge && !root.barIsVertical) || (touchingBottomEdge && root.barIsVertical)) + var oppositeEdgeInverted = couldAttach && (touchingBottomEdge && !root.barIsVertical && root.barPosition !== "bottom") return barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted } @@ -459,16 +460,16 @@ Item { } // Detect if panel is touching screen edges - readonly property bool touchingLeftEdge: root.couldAttach && x <= 1 - readonly property bool touchingRightEdge: root.couldAttach && (x + width) >= (parent.width - 1) - readonly property bool touchingTopEdge: root.couldAttach && y <= 1 - readonly property bool touchingBottomEdge: root.couldAttach && (y + height) >= (parent.height - 1) + readonly property bool touchingLeftEdge: couldAttach && x <= 1 + readonly property bool touchingRightEdge: couldAttach && (x + width) >= (parent.width - 1) + readonly property bool touchingTopEdge: couldAttach && y <= 1 + readonly property bool touchingBottomEdge: couldAttach && (y + height) >= (parent.height - 1) // Detect if panel is touching bar edges (for cases where centered panels snap to bar due to height constraints) - readonly property bool touchingTopBar: root.couldAttachToBar && root.barPosition === "top" && !root.barIsVertical && Math.abs(y - (root.barMarginV + Style.barHeight)) <= 1 - readonly property bool touchingBottomBar: root.couldAttachToBar && root.barPosition === "bottom" && !root.barIsVertical && Math.abs((y + height) - (parent.height - root.barMarginV - Style.barHeight)) <= 1 - readonly property bool touchingLeftBar: root.couldAttachToBar && root.barPosition === "left" && root.barIsVertical && Math.abs(x - (root.barMarginH + Style.barHeight)) <= 1 - readonly property bool touchingRightBar: root.couldAttachToBar && root.barPosition === "right" && root.barIsVertical && Math.abs((x + width) - (parent.width - root.barMarginH - Style.barHeight)) <= 1 + readonly property bool touchingTopBar: couldAttachToBar && root.barPosition === "top" && !root.barIsVertical && Math.abs(y - (root.barMarginV + Style.barHeight)) <= 1 + readonly property bool touchingBottomBar: couldAttachToBar && root.barPosition === "bottom" && !root.barIsVertical && Math.abs((y + height) - (parent.height - root.barMarginV - Style.barHeight)) <= 1 + readonly property bool touchingLeftBar: couldAttachToBar && root.barPosition === "left" && root.barIsVertical && Math.abs(x - (root.barMarginH + Style.barHeight)) <= 1 + readonly property bool touchingRightBar: couldAttachToBar && root.barPosition === "right" && root.barIsVertical && Math.abs((x + width) - (parent.width - root.barMarginH - Style.barHeight)) <= 1 // Position the panel using explicit x/y coordinates (no anchors) // This makes coordinates clearer for the click-through mask system @@ -481,7 +482,7 @@ Item { if (root.useButtonPosition && parent.width > 0 && width > 0) { if (root.barIsVertical) { // For vertical bars - if (root.couldAttach) { + if (couldAttach) { // Attached panels: align with bar edge (left or right side) if (root.barPosition === "left") { // Panel to the right of left bar @@ -517,7 +518,7 @@ Item { var panelX = root.buttonPosition.x + root.buttonWidth / 2 - width / 2 // Clamp to bar bounds (account for floating bar margins) // When attached, panel should not extend beyond bar edges - if (root.couldAttach) { + if (couldAttach) { // Inverted corners with horizontal direction extend left/right by radiusL // When bar is floating, it also has rounded corners, so we need extra insets var cornerInset = root.barFloating ? Style.radiusL * 2 : 0 @@ -554,26 +555,26 @@ Item { // For horizontal bars or no bar, center normally calculatedX = (parent.width - width) / 2 } - } else if (root.effectivePanelAnchorRight) { + } else if (effectivePanelAnchorRight) { Logger.d("NPanel", " -> Right anchor") // When attached to right vertical bar, position next to bar (like useButtonPosition does) - if (root.couldAttach && root.barIsVertical && root.barPosition === "right") { + if (couldAttach && root.barIsVertical && root.barPosition === "right") { var rightBarEdge = parent.width - root.barMarginH - Style.barHeight calculatedX = rightBarEdge - width - } else if (root.couldAttach) { + } else if (couldAttach) { // Attach to right screen edge calculatedX = parent.width - width } else { // Detached: use margin calculatedX = parent.width - width - Style.marginL } - } else if (root.effectivePanelAnchorLeft) { + } else if (effectivePanelAnchorLeft) { Logger.d("NPanel", " -> Left anchor") // When attached to left vertical bar, position next to bar (like useButtonPosition does) - if (root.couldAttach && root.barIsVertical && root.barPosition === "left") { + if (couldAttach && root.barIsVertical && root.barPosition === "left") { var leftBarEdge = root.barMarginH + Style.barHeight calculatedX = leftBarEdge - } else if (root.couldAttach) { + } else if (couldAttach) { // Attach to left screen edge calculatedX = 0 } else { @@ -599,7 +600,7 @@ Item { } } else { // For horizontal bars: center horizontally, respect bar margins if attached - if (root.couldAttach) { + if (couldAttach) { // When attached, respect bar bounds (like button position does) var cornerInset = Style.radiusL + (root.barFloating ? Style.radiusL : 0) var barLeftEdge = root.barMarginH + cornerInset @@ -614,7 +615,7 @@ Item { } // Edge snapping: snap to screen edges if close (only when attached and bar is not floating) - if (root.couldAttach && !root.barFloating && parent.width > 0 && width > 0) { + if (couldAttach && !root.barFloating && parent.width > 0 && width > 0) { // Calculate edge positions accounting for bar position // For vertical bars (left/right), we need to position panels AFTER the bar, not behind it var leftEdgePos = root.barMarginH @@ -651,7 +652,7 @@ Item { if (root.barPosition === "top") { // Panel below top bar var topBarEdge = root.barMarginV + Style.barHeight - if (root.couldAttach) { + if (couldAttach) { // Panel sits right at bar edge (inverted corners align perfectly) calculatedY = topBarEdge } else { @@ -660,7 +661,7 @@ Item { } else if (root.barPosition === "bottom") { // Panel above bottom bar var bottomBarEdge = parent.height - root.barMarginV - Style.barHeight - if (root.couldAttach) { + if (couldAttach) { // Panel sits right at bar edge (inverted corners align perfectly) calculatedY = bottomBarEdge - height } else { @@ -670,8 +671,8 @@ Item { // For vertical bars, center panel on button Y position var panelY = root.buttonPosition.y + root.buttonHeight / 2 - height / 2 // Clamp to bar bounds (account for floating bar margins and inverted corners) - var extraPadding = (root.couldAttach && root.barFloating) ? Style.radiusL : 0 - if (root.couldAttach) { + var extraPadding = (couldAttach && root.barFloating) ? Style.radiusL : 0 + if (couldAttach) { // When attached, panel should not extend beyond bar edges (accounting for floating margins) // Inverted corners with vertical direction extend up/down by radiusL // When bar is floating, it also has rounded corners, so we need extra inset @@ -689,7 +690,7 @@ Item { // Standard anchor positioning // Calculate bar offset for detached panels - they should never overlap the bar var barOffset = 0 - if (!root.couldAttach) { + if (!couldAttach) { // For detached panels, always account for bar position if (root.barPosition === "top") { barOffset = root.barMarginV + Style.barHeight + Style.marginM @@ -698,10 +699,10 @@ Item { } } else { // For attached panels with explicit anchors - if (root.effectivePanelAnchorTop && root.barPosition === "top") { + if (effectivePanelAnchorTop && root.barPosition === "top") { // When attached to top bar: position right at bar edge (inverted corners align perfectly) calculatedY = root.barMarginV + Style.barHeight - } else if (root.effectivePanelAnchorBottom && root.barPosition === "bottom") { + } else if (effectivePanelAnchorBottom && root.barPosition === "bottom") { // When attached to bottom bar: position right at bar edge (inverted corners align perfectly) calculatedY = parent.height - root.barMarginV - Style.barHeight - height } else if (!root.hasExplicitVerticalAnchor) { @@ -738,18 +739,18 @@ Item { // For vertical bars or no bar, center normally calculatedY = (parent.height - height) / 2 } - } else if (root.effectivePanelAnchorTop) { + } else if (effectivePanelAnchorTop) { // When couldAttach=true, attach to top screen edge; otherwise use margin - if (root.couldAttach) { + if (couldAttach) { calculatedY = 0 } else { // Only apply barOffset if bar is also at top (to avoid overlapping) var topBarOffset = (root.barPosition === "top") ? barOffset : 0 calculatedY = topBarOffset + Style.marginL } - } else if (root.effectivePanelAnchorBottom) { + } else if (effectivePanelAnchorBottom) { // When couldAttach=true, attach to bottom screen edge; otherwise use margin - if (root.couldAttach) { + if (couldAttach) { calculatedY = parent.height - height } else { // Only apply barOffset if bar is also at bottom (to avoid overlapping) @@ -760,7 +761,7 @@ Item { // No explicit vertical anchor if (root.barIsVertical) { // For vertical bars: center vertically on bar - if (root.couldAttach) { + if (couldAttach) { // When attached, respect bar bounds var cornerInset = root.barFloating ? Style.radiusL * 2 : 0 var barTopEdge = root.barMarginV + cornerInset @@ -772,7 +773,7 @@ Item { } } else { // For horizontal bars: attach to bar edge by default - if (root.couldAttach && !root.barIsVertical) { + if (couldAttach && !root.barIsVertical) { if (root.barPosition === "top") { calculatedY = root.barMarginV + Style.barHeight } else if (root.barPosition === "bottom") { @@ -794,7 +795,7 @@ Item { } // Edge snapping: snap to screen edges if close (only when attached and bar is not floating) - if (root.couldAttach && !root.barFloating && parent.height > 0 && height > 0) { + if (couldAttach && !root.barFloating && parent.height > 0 && height > 0) { // Calculate edge positions accounting for bar position // For horizontal bars (top/bottom), we need to position panels AFTER the bar, not behind it var topEdgePos = root.barMarginV From fd93bd20dbe7ff1b8667cffe1539146d038ed822 Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 4 Nov 2025 11:35:37 -0500 Subject: [PATCH 08/10] Settings: fix typo in "follow_bar" --- Commons/Settings.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Commons/Settings.qml b/Commons/Settings.qml index c4fa4757..c7f6b46c 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -259,7 +259,7 @@ Singleton { property string transitionType: "random" property real transitionEdgeSmoothness: 0.05 property list monitors: [] - property string panelPosition: "folow_bar" + property string panelPosition: "follow_bar" } // applauncher From d9a802fe21c8531d4b98565db4405ad00dc5e9ad Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 4 Nov 2025 11:40:31 -0500 Subject: [PATCH 09/10] Autofmt --- Modules/Bar/Battery/BatteryPanel.qml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Modules/Bar/Battery/BatteryPanel.qml b/Modules/Bar/Battery/BatteryPanel.qml index 5ca255b5..cf2d5c1e 100644 --- a/Modules/Bar/Battery/BatteryPanel.qml +++ b/Modules/Bar/Battery/BatteryPanel.qml @@ -14,15 +14,15 @@ NPanel { function updateOptionsModel() { let newOptions = [{ - "id": BatteryService.ChargingMode.Full, - "label": "battery.panel.full" - }, { - "id": BatteryService.ChargingMode.Balanced, - "label": "battery.panel.balanced" - }, { - "id": BatteryService.ChargingMode.Lifespan, - "label": "battery.panel.lifespan" - }] + "id": BatteryService.ChargingMode.Full, + "label": "battery.panel.full" + }, { + "id": BatteryService.ChargingMode.Balanced, + "label": "battery.panel.balanced" + }, { + "id": BatteryService.ChargingMode.Lifespan, + "label": "battery.panel.lifespan" + }] root.optionsModel = newOptions } @@ -44,8 +44,8 @@ NPanel { ButtonGroup.group: batteryGroup required property var modelData text: I18n.tr(modelData.label, { - "percent": BatteryService.getThresholdValue(modelData.id) - }) + "percent": BatteryService.getThresholdValue(modelData.id) + }) checked: BatteryService.chargingMode === modelData.id onClicked: { BatteryService.setChargingMode(modelData.id) From 0cdae521640203b763e921b48f921fa116141cce Mon Sep 17 00:00:00 2001 From: ItsLemmy Date: Tue, 4 Nov 2025 14:56:35 -0500 Subject: [PATCH 10/10] i18n: english tweaks --- Assets/Translations/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index 5a77e12e..94969f31 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -1494,11 +1494,11 @@ }, "panels-attached-to-bar": { "description": "Panels lock to the bar and screen edges, creating a seamless look with stylish inverted corners.", - "label": "Snap Panels to Edges" + "label": "Snap panels to edges" }, "panels-overlay": { "description": "Ensures panels and the bar remain visible, even over fullscreen applications.", - "label": "Keep Panels & Bar on Top" + "label": "Keep panels & bar on top" }, "scaling": { "description": "Changes the size of the general user interface, excluding the bar.",