Files
z-bar-qt/Modules/TrayMenu.qml
T

206 lines
7.2 KiB
QML

pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell.Hyprland
PopupWindow {
id: root
signal menuActionTriggered()
required property QsMenuOpener menu
property var menuStack: []
function calcHeight() {
let count = 0;
let separatorCount = 0;
for (let i = 0; i < listLayout.count; i++) {
if (!listLayout.model.values[i].isSeparator) {
count++;
} else {
separatorCount++;
}
}
if ( root.menuStack.length > 0 ) {
count++;
}
return (count * entryHeight) + ((count - 1) * 2) + (separatorCount * 3) + 10;
}
function calcWidth() {
let menuWidth = 0;
for ( let i = 0; i < listLayout.count; i++ ) {
if ( !listLayout.model.values[i].isSeparator ) {
let entry = listLayout.model.values[i];
tempMetrics.text = entry.text;
let textWidth = tempMetrics.width + 20 + (entry.icon ?? "" ? 30 : 0) + (entry.hasChildren ? 30 : 0);
if ( textWidth > menuWidth ) {
menuWidth = textWidth;
}
}
}
return menuWidth;
}
function goBack() {
if ( root.menuStack.length > 0 ) {
root.menu = root.menuStack.pop();
}
}
onVisibleChanged: {
if ( visible ) {
root.menuStack = [];
}
}
TextMetrics {
id: tempMetrics
text: ""
}
property int height: calcHeight()
property int entryHeight: 30
property int maxWidth: calcWidth()
implicitWidth: maxWidth + 20
implicitHeight: height
color: "transparent"
anchor.gravity: Edges.Bottom
Behavior on implicitHeight {
NumberAnimation {
duration: MaterialEasing.standardTime
easing.bezierCurve: MaterialEasing.standard
}
}
Behavior on implicitWidth {
NumberAnimation {
duration: MaterialEasing.standardTime
easing.bezierCurve: MaterialEasing.standard
}
}
Rectangle {
id: menuRect
anchors.fill: parent
color: "#80151515"
radius: 8
border.color: "#40FFFFFF"
ColumnLayout {
anchors.fill: parent
anchors.margins: 5
spacing: 0
ListView {
id: listLayout
Layout.fillWidth: true
Layout.preferredHeight: root.calcHeight() - ( root.menuStack.length > 0 ? root.entryHeight + 10 : 0 )
spacing: 2
model: ScriptModel {
values: [...root.menu?.children.values]
}
delegate: Rectangle {
id: menuItem
required property QsMenuEntry modelData
property var child: QsMenuOpener {
menu: menuItem.modelData
}
property bool containsMouseAndEnabled: mouseArea.containsMouse && menuItem.modelData.enabled
property bool containsMouseAndNotEnabled: mouseArea.containsMouse && !menuItem.modelData.enabled
width: root.implicitWidth
anchors.left: parent.left
anchors.right: parent.right
height: menuItem.modelData.isSeparator ? 1 : root.entryHeight
color: menuItem.modelData.isSeparator ? "#20FFFFFF" : containsMouseAndEnabled ? "#15FFFFFF" : containsMouseAndNotEnabled ? "#08FFFFFF" : "transparent"
radius: 4
visible: true
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 {
root.menuStack.push(root.menu);
root.menu = menuItem.child;
}
}
}
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"
}
}
Text {
id: textArrow
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.rightMargin: 10
Layout.bottomMargin: 5
Layout.maximumWidth: 20
Layout.maximumHeight: 20
text: ""
color: menuItem.modelData.enabled ? "white" : "gray"
visible: menuItem.modelData.hasChildren ?? false
}
}
}
}
Rectangle {
visible: true
Layout.fillWidth: true
Layout.preferredHeight: root.entryHeight
color: mouseAreaBack.containsMouse ? "#15FFFFFF" : "transparent"
radius: 4
MouseArea {
id: mouseAreaBack
anchors.fill: parent
hoverEnabled: true
onClicked: {
root.goBack();
}
}
Text {
anchors.fill: parent
anchors.leftMargin: 10
verticalAlignment: Text.AlignVCenter
text: "Back "
color: "white"
}
}
}
}
}