Merge pull request #3 from Zacharias-Brohn/customtray

Customtray
This commit was merged in pull request #3.
This commit is contained in:
Zach
2025-11-02 22:26:25 +01:00
committed by GitHub
7 changed files with 297 additions and 17 deletions
+1
View File
@@ -16,6 +16,7 @@ Scope {
PanelWindow {
id: bar
required property var modelData
property bool trayMenuVisible: false
screen: modelData
anchors {
+91
View File
@@ -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"
}
}
}
}
}
}
+35 -17
View File
@@ -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;
}
}
}
+136
View File
@@ -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 {}
}
}
+4
View File
@@ -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
+29
View File
@@ -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
}
}
}
}
+1
View File
@@ -3,4 +3,5 @@ import Quickshell
Scope {
Bar {}
// Wallpaper {}
}