110 lines
3.7 KiB
QML
110 lines
3.7 KiB
QML
// Popup.qml - a reusable popup component for Quickshell.
|
|
import Quickshell
|
|
import Quickshell.Wayland
|
|
import QtQuick
|
|
|
|
PanelWindow {
|
|
id: root
|
|
|
|
required property var screen
|
|
required property string popupName
|
|
|
|
property int rightMargin: 10
|
|
property int topMargin: 1
|
|
property int autoHideDelay: Theme.popupAutoHideDelay
|
|
|
|
default property alias content: contentItem.data
|
|
|
|
// ── Visibility ────────────────────────────────────────────
|
|
property bool logicalOpen: GlobalStates.popups.active === popupName
|
|
property bool _keepVisible: false
|
|
|
|
visible: logicalOpen || _keepVisible
|
|
|
|
onLogicalOpenChanged: {
|
|
if (logicalOpen) {
|
|
closeTimer.stop()
|
|
_keepVisible = false
|
|
openY.start()
|
|
openOpacity.start()
|
|
} else {
|
|
hideTimer.stop()
|
|
_keepVisible = true
|
|
closeY.start()
|
|
closeOpacity.start()
|
|
closeTimer.restart()
|
|
}
|
|
}
|
|
|
|
// Keeps the Overlay window alive for the duration of the close animation
|
|
Timer {
|
|
id: closeTimer
|
|
interval: 280
|
|
onTriggered: root._keepVisible = false
|
|
}
|
|
|
|
WlrLayershell.layer: WlrLayer.Overlay
|
|
WlrLayershell.namespace: "quickshell-popup-" + popupName
|
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
|
|
|
anchors { top: true; left: true; right: true; bottom: true }
|
|
color: Qt.rgba(0, 0, 0, 0)
|
|
|
|
Timer {
|
|
id: hideTimer
|
|
interval: root.autoHideDelay
|
|
repeat: false
|
|
onTriggered: GlobalStates.popups.close()
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
onClicked: GlobalStates.popups.close()
|
|
}
|
|
|
|
// ── Slide animations ──────────────────────────────────────
|
|
NumberAnimation { id: openY; target: box; property: "y"; to: root.topMargin; duration: 250; easing.type: Easing.OutCubic }
|
|
NumberAnimation { id: closeY; target: box; property: "y"; to: root.topMargin - 200; duration: 200; easing.type: Easing.InCubic }
|
|
NumberAnimation { id: openOpacity; target: box; property: "opacity"; to: Theme.popupOpacity; duration: 200 }
|
|
NumberAnimation { id: closeOpacity;target: box; property: "opacity"; to: 0.0; duration: 200 }
|
|
|
|
// ── Popup box ─────────────────────────────────────────────
|
|
Rectangle {
|
|
id: box
|
|
|
|
x: {
|
|
var ax = GlobalStates.popups.anchorX
|
|
var centered = ax > 0 ? ax - width / 2 : parent.width - width - root.rightMargin
|
|
return Math.max(4, Math.min(parent.width - width - 4, centered))
|
|
}
|
|
|
|
// Initial state: closed (above the bar, transparent)
|
|
y: root.topMargin - 40
|
|
opacity: 0.0
|
|
|
|
width: contentItem.implicitWidth + 10
|
|
height: contentItem.implicitHeight + 10
|
|
|
|
color: Theme.popupBackground
|
|
radius: Theme.radius * 2
|
|
border.color: Theme.popupBorderColor
|
|
border.width: Theme.popupBorderWidth
|
|
|
|
// Absorb clicks so the outer close-on-click doesn't fire inside the box
|
|
MouseArea { anchors.fill: parent }
|
|
|
|
// HoverHandler doesn't lose hover when a child MouseArea grabs a press,
|
|
// so clicking buttons won't accidentally start the hide timer.
|
|
HoverHandler {
|
|
onHoveredChanged: hovered ? hideTimer.stop() : hideTimer.start()
|
|
}
|
|
|
|
Item {
|
|
id: contentItem
|
|
x: 5; y: 5
|
|
implicitWidth: childrenRect.width
|
|
implicitHeight: childrenRect.height
|
|
}
|
|
}
|
|
}
|