diff --git a/Bar.qml b/Bar.qml index ce0cd79..bbdb1ae 100644 --- a/Bar.qml +++ b/Bar.qml @@ -16,6 +16,7 @@ Scope { PanelWindow { id: bar required property var modelData + property bool trayMenuVisible: false screen: modelData anchors { diff --git a/Modules/SubMenu.qml b/Modules/SubMenu.qml new file mode 100644 index 0000000..3f3d014 --- /dev/null +++ b/Modules/SubMenu.qml @@ -0,0 +1,91 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import QtQuick.Layouts +import Quickshell.Hyprland + +PopupWindow { + id: root + required property QsMenuHandle menu + property int height: entryCount * ( entryHeight + 3 ) + property int entryHeight: 30 + property int entryCount: 0 + implicitWidth: 300 + implicitHeight: height + color: "transparent" + + QsMenuOpener { + id: menuOpener + menu: root.menu + } + + HyprlandFocusGrab { + id: grab + windows: [ root ] + onCleared: { + root.visible = false; + } + } + + onVisibleChanged: { + grab.active = root.visible; + } + Rectangle { + id: menuRect + anchors.fill: parent + color: "#90000000" + radius: 8 + border.color: "#10FFFFFF" + ColumnLayout { + id: columnLayout + anchors.fill: parent + anchors.margins: 5 + spacing: 2 + Repeater { + id: repeater + model: menuOpener.children + Rectangle { + id: menuItem + width: root.implicitWidth + Layout.maximumWidth: parent.width + Layout.fillHeight: true + height: root.entryHeight + color: mouseArea.containsMouse && !modelData.isSeparator ? "#15FFFFFF" : "transparent" + radius: 4 + visible: modelData.isSeparator ? false : true + required property QsMenuEntry modelData + + Component.onCompleted: { + if ( !modelData.isSeparator ) { + root.entryCount += 1; + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + preventStealing: true + propagateComposedEvents: true + acceptedButtons: Qt.LeftButton + onClicked: { + if ( !menuItem.modelData.hasChildren ) { + menuItem.modelData.triggered(); + root.visible = false; + } + } + } + + Text { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 10 + text: menuItem.modelData.text + color: "white" + } + } + } + } + } +} diff --git a/Modules/TrayItem.qml b/Modules/TrayItem.qml index 406bd06..c6350da 100644 --- a/Modules/TrayItem.qml +++ b/Modules/TrayItem.qml @@ -6,27 +6,22 @@ import QtQuick.Effects import Caelestia import Quickshell import Quickshell.Widgets +import Quickshell.Hyprland import Quickshell.Services.SystemTray +import qs.Modules MouseArea { id: root required property SystemTrayItem item + property var menuHandle implicitWidth: 22 implicitHeight: 22 + hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton - onClicked: event => { - switch (event.button) { - case Qt.LeftButton: root.item.activate(); break; - case Qt.RightButton: - if (root.item.hasMenu) { - menuAnchor.open(); - } - break; - } - } + IconImage { id: icon @@ -47,17 +42,40 @@ MouseArea { mipmap: false asynchronous: true + ImageAnalyser { id: analyser sourceItem: icon + rescaleSize: 20 + } + + TrayMenu { + id: trayMenu + menu: root.item.menu + anchor.item: root + anchor.edges: Edges.Bottom + onVisibleChanged: { + if ( grab.active && !visible ) { + grab.active = false; + } + } + + HyprlandFocusGrab { + id: grab + windows: [ trayMenu ] + onCleared: { + trayMenu.visible = false; + } + } } } - QsMenuAnchor { - id: menuAnchor - menu: root.item.menu - anchor.item: root - anchor.edges: Edges.Bottom | Edges.Left - anchor.margins.top: 23 - anchor.adjustment: PopupAdjustment.SlideX + + onClicked: { + if ( mouse.button === Qt.LeftButton ) { + root.item.activate(); + } else if ( mouse.button === Qt.RightButton ) { + trayMenu.visible = !trayMenu.visible; + grab.active = true; + } } } diff --git a/Modules/TrayMenu.qml b/Modules/TrayMenu.qml new file mode 100644 index 0000000..207f979 --- /dev/null +++ b/Modules/TrayMenu.qml @@ -0,0 +1,136 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import QtQuick +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import Quickshell.Hyprland + +PopupWindow { + id: root + + signal menuActionTriggered() + required property QsMenuHandle menu + property int height: { + let count = 0; + for (let i = 0; i < repeater.count; i++) { + if (!repeater.itemAt(i).modelData.isSeparator) count++; + } + return count * (entryHeight + 3); + } + property int entryHeight: 30 + property int maxWidth: 100 + implicitWidth: Math.max(100, maxWidth + 20) + implicitHeight: height + color: "transparent" + anchor.margins { + left: -implicitWidth + } + + QsMenuOpener { + id: menuOpener + menu: root.menu + } + + Rectangle { + id: menuRect + anchors.fill: parent + color: "#90000000" + radius: 8 + border.color: "#10FFFFFF" + ColumnLayout { + id: columnLayout + anchors.fill: parent + anchors.margins: 5 + spacing: 2 + Repeater { + id: repeater + model: menuOpener.children + Rectangle { + id: menuItem + property bool containsMouseAndEnabled: mouseArea.containsMouse && menuItem.modelData.enabled + property bool containsMouseAndNotEnabled: mouseArea.containsMouse && !menuItem.modelData.enabled + width: root.implicitWidth + Layout.maximumWidth: parent.width + Layout.fillHeight: true + height: root.entryHeight + color: modelData.isSeparator ? "transparent" : containsMouseAndEnabled ? "#15FFFFFF" : containsMouseAndNotEnabled ? "#08FFFFFF" : "transparent" + radius: 4 + visible: modelData.isSeparator ? false : true + required property QsMenuEntry modelData + + TextMetrics { + id: textMetrics + font: menuText.font + text: menuItem.modelData.text + } + + Component.onCompleted: { + // Measure text width to determine maximumWidth + var textWidth = textMetrics.width + 20 + (iconImage.source ? iconImage.width + 10 : 0); + if ( textWidth > 0 && textWidth > root.maxWidth ) { + root.maxWidth = textWidth + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + preventStealing: true +propagateComposedEvents: true + acceptedButtons: Qt.LeftButton + onClicked: { + if ( !menuItem.modelData.hasChildren ) { + if ( menuItem.modelData.enabled ) { + menuItem.modelData.triggered(); + root.menuActionTriggered(); + root.visible = false; + } + } else { + subMenuComponent.createObject( null, { + menu: menuItem.modelData, + anchor: { + item: menuItem, + edges: Edges.Right + }, + visible: true + }) + } + } + } + + RowLayout { + anchors.fill: parent + Text { + id: menuText + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + Layout.leftMargin: 10 + text: menuItem.modelData.text + color: menuItem.modelData.enabled ? "white" : "gray" + } + Image { + id: iconImage + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + Layout.rightMargin: 10 + Layout.maximumWidth: 20 + Layout.maximumHeight: 20 + source: menuItem.modelData.icon + sourceSize.width: width + sourceSize.height: height + fillMode: Image.PreserveAspectFit + layer.enabled: true + layer.effect: ColorOverlay { + color: menuItem.modelData.enabled ? "white" : "gray" + } + } + } + } + } + } + } + Component { + id: subMenuComponent + SubMenu {} + } +} diff --git a/Modules/TrayWidget.qml b/Modules/TrayWidget.qml index 23122aa..13f4a52 100644 --- a/Modules/TrayWidget.qml +++ b/Modules/TrayWidget.qml @@ -1,9 +1,12 @@ +pragma ComponentBehavior: Bound + import QtQuick import QtQuick.Layouts import Quickshell import Quickshell.Services.SystemTray Rectangle { + id: root required property PanelWindow bar implicitHeight: parent.height implicitWidth: rowL.implicitWidth + 20 @@ -14,6 +17,7 @@ Rectangle { id: rowL anchors.centerIn: parent Repeater { + id: repeater model: SystemTray.items TrayItem { required property SystemTrayItem modelData diff --git a/Wallpaper.qml b/Wallpaper.qml new file mode 100644 index 0000000..7968e41 --- /dev/null +++ b/Wallpaper.qml @@ -0,0 +1,29 @@ +import Quickshell +import QtQuick +import Quickshell.Wayland + +Scope { + Variants { + model: Quickshell.screens + PanelWindow { + id: root + required property var modelData + screen: modelData + WlrLayershell.exclusionMode: ExclusionMode.Ignore + WlrLayershell.layer: WlrLayer.Bottom + + anchors { + top: true + left: true + right: true + bottom: true + } + Image { + id: wallpaperImage + anchors.fill: parent + source: "/mnt/IronWolf/SDImages/SWWW_Wals/ComfyUI_00037_.png" + fillMode: Image.PreserveAspectFit + } + } + } +} diff --git a/shell.qml b/shell.qml index 9c9d2f2..6e48a28 100644 --- a/shell.qml +++ b/shell.qml @@ -3,4 +3,5 @@ import Quickshell Scope { Bar {} + // Wallpaper {} }