diff --git a/ryoku/shell/CHANGELOG.md b/ryoku/shell/CHANGELOG.md index 5f08410cf..50f2a5e0e 100644 --- a/ryoku/shell/CHANGELOG.md +++ b/ryoku/shell/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog: ryoku/shell/ ## Unreleased +- **Clicking an expanded Controls drawer no longer closes the panel.** Opening the + Brightness or Volume drawer grew the panel, but clicks on the newly grown part + still counted as clicks outside it. The whole drawer now takes clicks, and the + settings popup stays inside the panel when it is centred. - **Windows reach the Shima dock again.** Under the Shima bar style the frame and the dock both reserved the dock's band, which left a dock-tall gap between windows and the dock. The frame's reservation is now the only one there. diff --git a/ryoku/shell/quickshell/shell/modules/sidebar/ControlsBar.qml b/ryoku/shell/quickshell/shell/modules/sidebar/ControlsBar.qml index 200d4f22f..825d9737d 100644 --- a/ryoku/shell/quickshell/shell/modules/sidebar/ControlsBar.qml +++ b/ryoku/shell/quickshell/shell/modules/sidebar/ControlsBar.qml @@ -11,6 +11,8 @@ Item { required property real s required property var screen required property bool active + // the panel's window can reach past its card, so the card bounds the settings popup + property Item card: null signal session(string action) signal openExtensions() signal requestClose() @@ -169,25 +171,26 @@ Item { ControlsSettingsPopup { id: settings + readonly property Item bounds: root.card ?? host parent: root x: { - if (!host) + if (!bounds) return 0; - const origin = root.mapToItem(host, 0, 0); - return Math.max(0, Math.min(host.width - width, origin.x + root.width - width)) - origin.x; + const origin = root.mapToItem(bounds, 0, 0); + return Math.max(0, Math.min(bounds.width - width, origin.x + root.width - width)) - origin.x; } y: { - if (!host) + if (!bounds) return 0; - const origin = root.mapToItem(host, 0, 0); + const origin = root.mapToItem(bounds, 0, 0); const preferred = origin.y - height - Tokens.s2 * root.s; - return Math.max(0, Math.min(host.height - height, preferred)) - origin.y; + return Math.max(0, Math.min(bounds.height - height, preferred)) - origin.y; } s: root.s active: root.active // keep the popup wholly above the bar so it never covers the gear that closes // it, measured on every open because the bar settles after the popup exists - onAboutToShow: maxHeight = host ? Math.max(1, root.mapToItem(host, 0, 0).y - Tokens.s2 * root.s) : hostHeight + onAboutToShow: maxHeight = bounds ? Math.max(1, root.mapToItem(bounds, 0, 0).y - Tokens.s2 * root.s) : hostHeight onOpenExtensions: root.openExtensions() onRequestClose: root.requestClose() } diff --git a/ryoku/shell/quickshell/shell/modules/sidebar/ControlsBoard.qml b/ryoku/shell/quickshell/shell/modules/sidebar/ControlsBoard.qml index e96a56ee6..818263b09 100644 --- a/ryoku/shell/quickshell/shell/modules/sidebar/ControlsBoard.qml +++ b/ryoku/shell/quickshell/shell/modules/sidebar/ControlsBoard.qml @@ -14,6 +14,7 @@ Item { required property var screen required property bool active property string page: "controls" + property Item card: null signal requestClose() readonly property string currentPage: ["wifi", "bluetooth"].indexOf(page) >= 0 ? page : "controls" @@ -136,6 +137,7 @@ Item { height: implicitHeight s: root.s screen: root.screen + card: root.card active: root.overviewActive onSession: action => root.session(action) onOpenExtensions: root.showPage("plugins") diff --git a/ryoku/shell/quickshell/shell/modules/sidebar/Sidebar.qml b/ryoku/shell/quickshell/shell/modules/sidebar/Sidebar.qml index fa986009f..bc12d77b2 100644 --- a/ryoku/shell/quickshell/shell/modules/sidebar/Sidebar.qml +++ b/ryoku/shell/quickshell/shell/modules/sidebar/Sidebar.qml @@ -81,6 +81,9 @@ Scope { } // The dismiss surface never animates. Only the small corner buffer redraws. + // Since it does not redraw, a mask edited after its first frame never reaches + // the compositor, so its hole is the panel's whole column, which stays fixed + // while an inline drawer or section grows the panel inside it. PanelWindow { id: dismiss screen: root.screen @@ -99,9 +102,9 @@ Scope { Region { intersection: Intersection.Subtract x: root.panelX - y: root.panelY + y: root.roomY width: root.wantedWidth - height: root.wantedHeight + height: root.availableHeight } Region { intersection: Intersection.Subtract; width: dismiss.width; height: root.clearances.top } Region { intersection: Intersection.Subtract; y: dismiss.height - root.clearances.bottom; width: dismiss.width; height: root.clearances.bottom } @@ -125,17 +128,33 @@ Scope { exclusionMode: ExclusionMode.Ignore exclusiveZone: 0 anchors { top: true; left: true } - margins.top: root.panelY + margins.top: root.roomY margins.left: root.panelX implicitWidth: root.wantedWidth - implicitHeight: root.wantedHeight + implicitHeight: root.availableHeight WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.namespace: "ryoku-sidebar-left" WlrLayershell.keyboardFocus: root.active ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None + // The dismiss hole spans the whole column, so a press in its clear part + // above or below the panel has to dismiss here instead. + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + onPressed: mouse => { + if (mouse.y >= surface.y && mouse.y < surface.y + surface.height) { + mouse.accepted = false; + return; + } + Qt.callLater(() => SidebarState.close(root.screen)); + } + } + FocusScope { id: surface - anchors.fill: parent + y: root.panelY - root.roomY + width: parent.width + height: root.wantedHeight opacity: root.reveal scale: 0.985 + root.reveal * 0.015 transformOrigin: root.panelTransformOrigin diff --git a/ryoku/shell/quickshell/shell/modules/sidebar/SidebarChrome.qml b/ryoku/shell/quickshell/shell/modules/sidebar/SidebarChrome.qml index 9727a7992..c74ea5c38 100644 --- a/ryoku/shell/quickshell/shell/modules/sidebar/SidebarChrome.qml +++ b/ryoku/shell/quickshell/shell/modules/sidebar/SidebarChrome.qml @@ -121,6 +121,7 @@ Item { ControlsBoard { s: root.s screen: root.screen + card: root active: root.active && root.page !== "plugins" page: root.page onRequestClose: root.closeRequested()