quickshell: custom QML tray context menus
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
63bd64ec56
commit
e02e1f41c1
1 changed files with 116 additions and 3 deletions
|
|
@ -566,6 +566,7 @@ in
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Hyprland
|
import Quickshell.Hyprland
|
||||||
import Quickshell.Services.SystemTray
|
import Quickshell.Services.SystemTray
|
||||||
|
import Quickshell.Widgets
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
|
@ -655,6 +656,7 @@ in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tray icon popup
|
||||||
PopupWindow {
|
PopupWindow {
|
||||||
id: trayPopup
|
id: trayPopup
|
||||||
anchor.item: trayToggle
|
anchor.item: trayToggle
|
||||||
|
|
@ -696,13 +698,13 @@ in
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: trayMouse
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
onClicked: (event) => {
|
onClicked: (event) => {
|
||||||
if (event.button === Qt.RightButton && modelData.hasMenu) {
|
if (event.button === Qt.RightButton && modelData.hasMenu) {
|
||||||
let mapped = trayMouse.mapToItem(null, event.x, event.y);
|
contextMenu.trayItem = modelData;
|
||||||
modelData.display(trayPopup, mapped.x, mapped.y);
|
menuOpener.menu = modelData.menu;
|
||||||
|
contextMenu.visible = true;
|
||||||
} else {
|
} else {
|
||||||
modelData.activate();
|
modelData.activate();
|
||||||
}
|
}
|
||||||
|
|
@ -713,6 +715,117 @@ in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Custom-rendered context menu
|
||||||
|
PopupWindow {
|
||||||
|
id: contextMenu
|
||||||
|
property var trayItem: null
|
||||||
|
anchor.item: trayToggle
|
||||||
|
anchor.edges: Edges.Bottom | Edges.Right
|
||||||
|
anchor.gravity: Edges.Bottom | Edges.Left
|
||||||
|
anchor.adjustment: PopupAdjustment.Slide
|
||||||
|
visible: false
|
||||||
|
color: "transparent"
|
||||||
|
implicitWidth: menuColumn.width + 2
|
||||||
|
implicitHeight: menuColumn.height + 2
|
||||||
|
|
||||||
|
QsMenuOpener {
|
||||||
|
id: menuOpener
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: menuColumn
|
||||||
|
width: menuItems.width + 16
|
||||||
|
height: menuItems.height + 12
|
||||||
|
color: "#${c.base00}"
|
||||||
|
border.color: "#${c.base03}"
|
||||||
|
border.width: 1
|
||||||
|
radius: 8
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: menuItems
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: 200
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: menuOpener.children
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
required property var modelData
|
||||||
|
width: 200
|
||||||
|
sourceComponent: modelData.isSeparator ? separatorComp : menuItemComp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close when clicking outside
|
||||||
|
onVisibleChanged: {
|
||||||
|
if (!visible) {
|
||||||
|
menuOpener.menu = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Menu item delegate
|
||||||
|
component MenuItemDelegate: Rectangle {
|
||||||
|
required property var modelData
|
||||||
|
width: 200
|
||||||
|
height: modelData.isSeparator ? 1 : 28
|
||||||
|
color: itemMouse.containsMouse && modelData.enabled ? "#${c.base02}" : "transparent"
|
||||||
|
radius: 4
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
spacing: 8
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: modelData.text ?? ""
|
||||||
|
color: modelData.enabled ? "#${c.base05}" : "#${c.base03}"
|
||||||
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 12
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
visible: modelData.buttonType !== QsMenuButtonType.None
|
||||||
|
text: modelData.checkState === Qt.Checked ? "\u2713" : ""
|
||||||
|
color: "#${c.base0D}"
|
||||||
|
font.family: "FiraMono Nerd Font"
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: itemMouse
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
enabled: modelData.enabled
|
||||||
|
onClicked: {
|
||||||
|
modelData.triggered();
|
||||||
|
contextMenu.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separator delegate
|
||||||
|
component SeparatorDelegate: Rectangle {
|
||||||
|
width: 200
|
||||||
|
height: 9
|
||||||
|
color: "transparent"
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.width - 20
|
||||||
|
height: 1
|
||||||
|
color: "#${c.base03}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component { id: menuItemComp; MenuItemDelegate {} }
|
||||||
|
Component { id: separatorComp; SeparatorDelegate {} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue