extract shared PopupPanel for animated tray/power menus

This commit is contained in:
Damocles 2026-04-12 16:24:33 +02:00
parent 77ce83462d
commit b8ec39f2c9
6 changed files with 249 additions and 302 deletions

92
modules/PopupPanel.qml Normal file
View file

@ -0,0 +1,92 @@
import QtQuick
import Quickshell
import Quickshell.Wayland
import "." as M
// Shared flyout popup window slides down from the bar, dismisses on
// click outside. Created on demand via Loader; animates in on creation,
// animates out then emits dismissed() for the Loader to deactivate.
PanelWindow {
id: root
default property alias content: contentCol.children
required property var screen
required property real anchorX
property real panelWidth: 220
signal dismissed()
visible: true
color: "transparent"
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.exclusiveZone: 0
WlrLayershell.namespace: "nova-popup"
anchors.top: true
anchors.left: true
anchors.right: true
anchors.bottom: true
Component.onCompleted: showAnim.start()
function dismiss() {
showAnim.stop();
hideAnim.start();
}
// Click outside dismiss
MouseArea {
anchors.fill: parent
onClicked: root.dismiss()
}
Item {
id: panel
x: Math.max(0, Math.min(
Math.round(root.anchorX - contentCol.width / 2),
root.width - contentCol.width
))
y: 0
width: contentCol.width
height: contentCol.height
opacity: 0
// Eat clicks inside the panel
MouseArea {
anchors.fill: parent
}
Rectangle {
anchors.fill: parent
color: M.Theme.base01
opacity: Math.max(M.Theme.barOpacity, 0.85)
topLeftRadius: 0
topRightRadius: 0
bottomLeftRadius: M.Theme.radius
bottomRightRadius: M.Theme.radius
}
Column {
id: contentCol
width: root.panelWidth
topPadding: 4
bottomPadding: 4
spacing: 2
}
}
ParallelAnimation {
id: showAnim
NumberAnimation { target: panel; property: "opacity"; from: 0; to: 1; duration: 150; easing.type: Easing.OutCubic }
NumberAnimation { target: panel; property: "y"; from: -panel.height; to: 0; duration: 200; easing.type: Easing.OutCubic }
}
ParallelAnimation {
id: hideAnim
NumberAnimation { target: panel; property: "opacity"; to: 0; duration: 150; easing.type: Easing.InCubic }
NumberAnimation { target: panel; property: "y"; to: -panel.height; duration: 150; easing.type: Easing.InCubic }
onFinished: root.dismissed()
}
}