pragma ComponentBehavior: Bound import "root:/widgets" import "root:/services" import "root:/config" import Quickshell import Quickshell.Widgets import QtQuick import QtQuick.Controls StackView { id: root required property Item popouts required property QsMenuHandle trayItem implicitWidth: currentItem.implicitWidth implicitHeight: currentItem.implicitHeight initialItem: SubMenu { handle: root.trayItem } pushEnter: Anim {} pushExit: Anim {} popEnter: Anim {} popExit: Anim {} component Anim: Transition { NumberAnimation { duration: 0 } } component SubMenu: Column { id: menu required property QsMenuHandle handle property bool isSubMenu property bool shown padding: Appearance.padding.smaller spacing: Appearance.spacing.small opacity: shown ? 1 : 0 scale: shown ? 1 : 0.8 Component.onCompleted: shown = true StackView.onActivating: shown = true StackView.onDeactivating: shown = false StackView.onRemoved: destroy() Behavior on opacity { NumberAnimation { duration: Appearance.anim.durations.normal easing.type: Easing.BezierSpline easing.bezierCurve: Appearance.anim.curves.standard } } Behavior on scale { NumberAnimation { duration: Appearance.anim.durations.normal easing.type: Easing.BezierSpline easing.bezierCurve: Appearance.anim.curves.standard } } QsMenuOpener { id: menuOpener menu: menu.handle } Repeater { model: menuOpener.children StyledRect { id: item required property QsMenuEntry modelData implicitWidth: BarConfig.sizes.trayMenuWidth implicitHeight: modelData.isSeparator ? 1 : children.implicitHeight radius: Appearance.rounding.full color: modelData.isSeparator ? Colours.palette.m3outlineVariant : "transparent" Loader { id: children anchors.left: parent.left anchors.right: parent.right active: !item.modelData.isSeparator asynchronous: true sourceComponent: Item { implicitHeight: label.implicitHeight StateLayer { anchors.margins: -Appearance.padding.small / 2 anchors.leftMargin: -Appearance.padding.smaller anchors.rightMargin: -Appearance.padding.smaller radius: item.radius disabled: !item.modelData.enabled function onClicked(): void { const entry = item.modelData; if (entry.hasChildren) root.push(subMenuComp.createObject(null, { handle: entry, isSubMenu: true })); else { item.modelData.triggered(); root.popouts.hasCurrent = false; } } } Loader { id: icon anchors.left: parent.left active: item.modelData.icon !== "" asynchronous: true sourceComponent: IconImage { implicitSize: label.implicitHeight source: item.modelData.icon } } StyledText { id: label anchors.left: icon.right anchors.leftMargin: icon.active ? Appearance.spacing.smaller : 0 text: labelMetrics.elidedText color: item.modelData.enabled ? Colours.palette.m3onSurface : Colours.palette.m3outline } TextMetrics { id: labelMetrics text: item.modelData.text font.pointSize: label.font.pointSize font.family: label.font.family elide: Text.ElideRight elideWidth: BarConfig.sizes.trayMenuWidth - (icon.active ? icon.implicitWidth + label.anchors.leftMargin : 0) - (expand.active ? expand.implicitWidth + Appearance.spacing.normal : 0) } Loader { id: expand anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right active: item.modelData.hasChildren asynchronous: true sourceComponent: MaterialIcon { text: "chevron_right" color: item.modelData.enabled ? Colours.palette.m3onSurface : Colours.palette.m3outline } } } } } } Loader { active: menu.isSubMenu asynchronous: true sourceComponent: Item { implicitWidth: back.implicitWidth implicitHeight: back.implicitHeight + Appearance.spacing.small / 2 Item { anchors.bottom: parent.bottom implicitWidth: back.implicitWidth implicitHeight: back.implicitHeight StyledRect { anchors.fill: parent anchors.margins: -Appearance.padding.small / 2 anchors.leftMargin: -Appearance.padding.smaller anchors.rightMargin: -Appearance.padding.smaller * 2 radius: Appearance.rounding.full color: Colours.palette.m3secondaryContainer StateLayer { radius: parent.radius color: Colours.palette.m3onSecondaryContainer function onClicked(): void { root.pop(); } } } Row { id: back anchors.verticalCenter: parent.verticalCenter MaterialIcon { anchors.verticalCenter: parent.verticalCenter text: "chevron_left" color: Colours.palette.m3onSecondaryContainer } StyledText { anchors.verticalCenter: parent.verticalCenter text: qsTr("Back") color: Colours.palette.m3onSecondaryContainer } } } } } } Component { id: subMenuComp SubMenu {} } }