diff --git a/settings/hyprland.nix b/settings/hyprland.nix index cca40e8..6955d56 100644 --- a/settings/hyprland.nix +++ b/settings/hyprland.nix @@ -566,6 +566,7 @@ in import Quickshell import Quickshell.Hyprland import Quickshell.Services.SystemTray + import Quickshell.Widgets import QtQuick import QtQuick.Layouts @@ -655,6 +656,7 @@ in } } + // Tray icon popup PopupWindow { id: trayPopup anchor.item: trayToggle @@ -696,13 +698,13 @@ in } MouseArea { - id: trayMouse anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton onClicked: (event) => { if (event.button === Qt.RightButton && modelData.hasMenu) { - let mapped = trayMouse.mapToItem(null, event.x, event.y); - modelData.display(trayPopup, mapped.x, mapped.y); + contextMenu.trayItem = modelData; + menuOpener.menu = modelData.menu; + contextMenu.visible = true; } else { 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 {} } } } }