From 60858f6f02fb7dc04e727db89090e7b83399803a Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Sun, 11 May 2025 23:55:05 +1000 Subject: feat: session menu --- modules/session/Background.qml | 70 ++++++++++++++++++++++++ modules/session/Content.qml | 118 +++++++++++++++++++++++++++++++++++++++++ modules/session/Session.qml | 87 ++++++++++++++++++++++++++++++ modules/session/Wrapper.qml | 62 ++++++++++++++++++++++ 4 files changed, 337 insertions(+) create mode 100644 modules/session/Background.qml create mode 100644 modules/session/Content.qml create mode 100644 modules/session/Session.qml create mode 100644 modules/session/Wrapper.qml (limited to 'modules/session') diff --git a/modules/session/Background.qml b/modules/session/Background.qml new file mode 100644 index 0000000..4b4b92e --- /dev/null +++ b/modules/session/Background.qml @@ -0,0 +1,70 @@ +import "root:/services" +import "root:/config" +import QtQuick +import QtQuick.Shapes + +Shape { + id: root + + required property real wrapperWidth + required property real wrapperHeight + readonly property real rounding: BorderConfig.rounding + readonly property bool flatten: wrapperWidth < rounding * 2 + readonly property real roundingX: flatten ? wrapperWidth / 2 : rounding + + preferredRendererType: Shape.CurveRenderer + opacity: Colours.transparency.enabled ? Colours.transparency.base : 1 + + ShapePath { + strokeWidth: -1 + fillColor: BorderConfig.colour + + startX: root.wrapperWidth - 1 + + PathArc { + relativeX: -root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapperWidth) + radiusY: root.rounding + } + PathLine { + x: root.roundingX + relativeY: 0 + } + PathArc { + relativeX: -root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapperWidth) + radiusY: root.rounding + direction: PathArc.Counterclockwise + } + PathLine { + y: root.wrapperHeight - root.rounding * 2 + } + PathArc { + relativeX: root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapperWidth) + radiusY: root.rounding + direction: PathArc.Counterclockwise + } + PathLine { + x: (root.flatten ? root.roundingX : root.wrapperWidth - root.rounding) - 1 + relativeY: 0 + } + PathArc { + relativeX: root.roundingX + relativeY: root.rounding + radiusX: Math.min(root.rounding, root.wrapperWidth) + radiusY: root.rounding + } + + Behavior on fillColor { + ColorAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } + } +} diff --git a/modules/session/Content.qml b/modules/session/Content.qml new file mode 100644 index 0000000..d1a2c38 --- /dev/null +++ b/modules/session/Content.qml @@ -0,0 +1,118 @@ +pragma ComponentBehavior: Bound + +import "root:/widgets" +import "root:/services" +import "root:/config" +import Quickshell +import Quickshell.Io +import QtQuick + +Column { + id: root + + required property Scope session + + padding: Appearance.padding.large + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + + spacing: Appearance.spacing.large + + SessionButton { + id: logout + + icon: "logout" + command: ["uwsm", "stop"] + + KeyNavigation.down: shutdown + + Connections { + target: session + + function onSessionVisibleChanged(): void { + if (session.sessionVisible) + logout.focus = true; + } + } + } + + SessionButton { + id: shutdown + + icon: "power_settings_new" + command: ["systemctl", "poweroff"] + + KeyNavigation.up: logout + KeyNavigation.down: hibernate + } + + AnimatedImage { + width: SessionConfig.sizes.button + height: SessionConfig.sizes.button + sourceSize.width: width + sourceSize.height: height + + playing: session.sessionVisible + asynchronous: true + speed: 0.7 + source: "root:/assets/kurukuru.gif" + } + + SessionButton { + id: hibernate + + icon: "downloading" + command: ["systemctl", "hibernate"] + + KeyNavigation.up: shutdown + KeyNavigation.down: reboot + } + + SessionButton { + id: reboot + + icon: "cached" + command: ["systemctl", "reboot"] + + KeyNavigation.up: hibernate + } + + component SessionButton: StyledRect { + id: button + + required property string icon + required property list command + + implicitWidth: SessionConfig.sizes.button + implicitHeight: SessionConfig.sizes.button + + radius: Appearance.rounding.large + color: button.activeFocus ? Colours.palette.m3secondaryContainer : Colours.palette.m3surfaceContainer + + Keys.onEnterPressed: proc.startDetached() + Keys.onEscapePressed: root.session.sessionVisible = false + + Process { + id: proc + + command: button.command + } + + StateLayer { + radius: parent.radius + + function onClicked(): void { + proc.startDetached(); + } + } + + MaterialIcon { + anchors.centerIn: parent + + text: button.icon + color: button.activeFocus ? Colours.palette.m3onSecondaryContainer : Colours.palette.m3onSurface + font.pointSize: Appearance.font.size.extraLarge + } + } +} diff --git a/modules/session/Session.qml b/modules/session/Session.qml new file mode 100644 index 0000000..0f8a0d5 --- /dev/null +++ b/modules/session/Session.qml @@ -0,0 +1,87 @@ +import "root:/widgets" +import "root:/services" +import "root:/config" +import Quickshell +import Quickshell.Wayland +import QtQuick + +Scope { + id: root + + property int winHeight + property bool sessionVisible + + Connections { + target: Drawers + + function onPosChanged(screen: ShellScreen, x: int, y: int): void { + if (x > screen.width - BorderConfig.thickness && y > (screen.height - root.winHeight) / 2 && y < (screen.height + root.winHeight) / 2) + root.sessionVisible = true; + } + } + + LazyLoader { + loading: true + + StyledWindow { + id: win + + name: "osd" + keyboardFocus: root.sessionVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None + visible: wrapper.shouldBeVisible + + mask: Region { + item: wrapper + } + + anchors.left: true + anchors.right: true + height: wrapper.height + + Component.onCompleted: { + root.winHeight = height; + Drawers.rightExclusion = Qt.binding(() => bg.width); + } + + Background { + id: bg + + visible: false + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + + wrapperWidth: Math.min(wrapper.width, content.width) + wrapperHeight: wrapper.height + } + + LayerShadow { + source: bg + } + + Wrapper { + id: wrapper + + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + + implicitHeight: content.height + bg.rounding * 2 + + sessionVisible: root.sessionVisible + contentWidth: content.width + + Content { + id: content + + session: root + } + } + } + } + + CustomShortcut { + name: "session" + description: "Toggle session menu" + onPressed: root.sessionVisible = !root.sessionVisible + } +} diff --git a/modules/session/Wrapper.qml b/modules/session/Wrapper.qml new file mode 100644 index 0000000..5806972 --- /dev/null +++ b/modules/session/Wrapper.qml @@ -0,0 +1,62 @@ +import "root:/config" +import QtQuick + +Item { + id: root + + required property bool sessionVisible + required property real contentWidth + property bool shouldBeVisible + + visible: width > 0 + width: 0 + + states: State { + name: "visible" + when: root.sessionVisible + + PropertyChanges { + root.width: contentWidth + root.shouldBeVisible: true + } + } + + transitions: [ + Transition { + from: "" + to: "visible" + + SequentialAnimation { + PropertyAction { + target: root + property: "shouldBeVisible" + } + NumberAnimation { + target: root + property: "width" + duration: Appearance.anim.durations.large + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.emphasizedDecel + } + } + }, + Transition { + from: "visible" + to: "" + + SequentialAnimation { + NumberAnimation { + target: root + property: "width" + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.emphasizedAccel + } + PropertyAction { + target: root + property: "shouldBeVisible" + } + } + } + ] +} -- cgit v1.2.3-freya