nova-shell/modules/HoverPanel.qml

135 lines
3.4 KiB
QML

import QtQuick
import Quickshell
import Quickshell.Wayland
import "." as M
// Shared hover/OSD panel PanelWindow — slides down from the bar on hover or
// external trigger. Parent module computes showPanel and reads panelHovered.
PanelWindow {
id: root
required property bool showPanel
required property Item anchorItem
required property color accentColor
property string panelNamespace: "nova-panel"
property real contentWidth: 220
property bool animateHeight: false
property bool panelHovered: false
default property alias content: panelContent.children
visible: _winVisible
color: "transparent"
property bool _winVisible: false
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.exclusiveZone: 0
WlrLayershell.namespace: root.panelNamespace
anchors.top: true
anchors.left: true
margins.top: 0
implicitWidth: panelContent.width
implicitHeight: panelContent.height
Behavior on implicitHeight {
enabled: root.animateHeight
NumberAnimation {
duration: 100
easing.type: Easing.OutCubic
}
}
function _updatePosition() {
const pt = anchorItem.mapToGlobal(anchorItem.width / 2, 0);
const scr = screen;
const sw = scr?.width ?? 1920;
margins.left = Math.max(0, Math.min(Math.round(pt.x - (scr?.x ?? 0) - contentWidth / 2), sw - contentWidth));
}
onShowPanelChanged: {
if (showPanel) {
_updatePosition();
_winVisible = true;
hideAnim.stop();
showAnim.start();
} else {
showAnim.stop();
hideAnim.start();
}
}
ParallelAnimation {
id: showAnim
NumberAnimation {
target: panelContent
property: "opacity"
to: 1
duration: 120
easing.type: Easing.OutCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: 0
duration: 150
easing.type: Easing.OutCubic
}
}
ParallelAnimation {
id: hideAnim
NumberAnimation {
target: panelContent
property: "opacity"
to: 0
duration: 150
easing.type: Easing.InCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: -panelContent.height
duration: 150
easing.type: Easing.InCubic
}
onFinished: root._winVisible = false
}
HoverHandler {
onHoveredChanged: root.panelHovered = hovered
}
M.PopupBackground {
x: panelContent.x
y: panelContent.y
width: panelContent.width
height: panelContent.height
opacity: panelContent.opacity * Math.max(M.Theme.barOpacity, 0.85)
accentColor: root.accentColor
}
Column {
id: panelContent
width: root.contentWidth
opacity: 0
y: -height
}
// Border overlay — drawn on top of content so full-bleed items (e.g. album art) don't cover it
Rectangle {
x: panelContent.x
y: panelContent.y
width: panelContent.width
height: panelContent.height
color: "transparent"
border.color: root.accentColor
border.width: 1
bottomLeftRadius: M.Theme.radius
bottomRightRadius: M.Theme.radius
opacity: panelContent.opacity
}
}