Files
Panama/config/dot/quickshell/modules/bar/TrayMenu.qml
T

102 lines
3.3 KiB
QML

// A tray item's DBus menu, drawn natively so it inherits the shell's theme.
//
// Submenus drill down in place rather than flying out sideways — a popover with
// a back row, the way GNOME's menus behave, and far less fiddly than chasing a
// cascade of popup windows with the mouse.
import Quickshell
import Quickshell.Services.SystemTray
import QtQuick
import qs.config
import qs.widgets
Popover {
id: root
required property SystemTrayItem trayItem
// Popover's container is a plain Item and does not size itself from its
// children, so the window dimensions come from the column's implicit size.
// Rows take their *actual* width from the window in the other direction —
// the two chains are independent, so there is no binding loop.
implicitWidth: Math.max(body.implicitWidth + contentPadding * 2, 200)
implicitHeight: body.implicitHeight + contentPadding * 2
// Stack of submenu handles; empty means we are at the top level.
property var menuStack: []
onVisibleChanged: if (!visible)
root.menuStack = []
QsMenuOpener {
id: opener
menu: root.menuStack.length > 0 ? root.menuStack[root.menuStack.length - 1] : root.trayItem.menu
}
Column {
id: body
width: parent.width
spacing: 2
// Back row, only while inside a submenu.
TrayMenuRow {
width: parent.width
visible: root.menuStack.length > 0
label: "\u{F0141} Back" // md-chevron_left
onActivated: root.menuStack = root.menuStack.slice(0, -1)
}
Repeater {
model: opener.children
delegate: Loader {
id: entryLoader
required property var modelData
width: body.width
sourceComponent: entryLoader.modelData.isSeparator ? separator : row
Component {
id: separator
Item {
implicitHeight: 7
Rectangle {
anchors.verticalCenter: parent.verticalCenter
width: parent.width
height: 1
color: Theme.alpha(Theme.fg, 0.1)
}
}
}
Component {
id: row
TrayMenuRow {
// QsMenuEntry calls it `text`, not `label`.
label: entryLoader.modelData.text
icon: entryLoader.modelData.icon
rowEnabled: entryLoader.modelData.enabled
buttonType: entryLoader.modelData.buttonType
checkState: entryLoader.modelData.checkState
submenu: entryLoader.modelData.hasChildren
onActivated: {
if (entryLoader.modelData.hasChildren) {
root.menuStack = root.menuStack.concat([entryLoader.modelData]);
return;
}
entryLoader.modelData.triggered();
root.visible = false;
}
}
}
}
}
}
}