From 7a27d4126f06bc92041bd909929ebcdebb4a6cee Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Wed, 25 Jun 2025 17:45:26 +1000 Subject: lock: add session buttons --- config/LockConfig.qml | 2 + modules/lock/Backgrounds.qml | 69 +++++++++++++++++++++++++++ modules/lock/Buttons.qml | 111 +++++++++++++++++++++++++++++++++++++++++++ modules/lock/LockSurface.qml | 9 ++++ 4 files changed, 191 insertions(+) create mode 100644 modules/lock/Buttons.qml diff --git a/config/LockConfig.qml b/config/LockConfig.qml index 8bbf284..dcb7d70 100644 --- a/config/LockConfig.qml +++ b/config/LockConfig.qml @@ -19,5 +19,7 @@ JsonObject { property int mediaCoverBorder: 3 property int largeScreenWidth: 2560 property int smallScreenWidth: 1080 + property int buttonsWidth: 500 + property int buttonsWidthSmall: 300 } } diff --git a/modules/lock/Backgrounds.qml b/modules/lock/Backgrounds.qml index 3ac4999..e561c66 100644 --- a/modules/lock/Backgrounds.qml +++ b/modules/lock/Backgrounds.qml @@ -10,6 +10,8 @@ Item { required property bool locked required property real weatherWidth + required property real buttonsWidth + required property real buttonsHeight required property bool isNormal required property bool isLarge @@ -17,6 +19,8 @@ Item { readonly property real inputTop: innerMask.anchors.margins + inputPath.height readonly property real weatherTop: innerMask.anchors.margins + weatherPath.height readonly property real weatherRight: innerMask.anchors.margins + weatherPath.width + readonly property real buttonsTop: innerMask.anchors.margins + buttonsPath.height + readonly property real buttonsLeft: innerMask.anchors.margins + buttonsPath.width readonly property real mediaX: innerMask.anchors.margins + mediaPath.width readonly property real mediaY: innerMask.anchors.margins + mediaPath.height @@ -331,6 +335,71 @@ Item { } } } + + ShapePath { + id: buttonsPath + + property int width: root.locked ? root.buttonsWidth - Config.lock.sizes.border / 4 : 0 + property real height: root.locked ? root.buttonsHeight - Config.lock.sizes.border / 4 : 0 + + readonly property real rounding: Appearance.rounding.large * 2 + readonly property real roundingX: width < rounding * 2 ? width / 2 : rounding + readonly property real roundingY: height < rounding * 2 ? height / 2 : rounding + + strokeWidth: -1 + fillColor: root.isLarge ? Config.border.colour : "transparent" + + startX: Math.ceil(innerMask.width) + startY: Math.ceil(innerMask.height) - height - roundingY + + PathArc { + relativeX: -buttonsPath.roundingX + relativeY: buttonsPath.roundingY + radiusX: Math.min(buttonsPath.rounding, buttonsPath.width) + radiusY: Math.min(buttonsPath.rounding, buttonsPath.height) + } + PathLine { + relativeX: -(buttonsPath.width - buttonsPath.roundingX * 2) + relativeY: 0 + } + PathArc { + relativeX: -buttonsPath.roundingX + relativeY: buttonsPath.roundingY + radiusX: Math.min(buttonsPath.rounding, buttonsPath.width) + radiusY: Math.min(buttonsPath.rounding, buttonsPath.height) + direction: PathArc.Counterclockwise + } + PathLine { + relativeX: 0 + relativeY: buttonsPath.height - buttonsPath.roundingY * 2 + } + PathArc { + relativeX: -buttonsPath.roundingX + relativeY: buttonsPath.roundingY + radiusX: Math.min(buttonsPath.rounding, buttonsPath.width) + radiusY: Math.min(buttonsPath.rounding, buttonsPath.height) + } + PathLine { + relativeX: buttonsPath.width + buttonsPath.roundingX + relativeY: 0 + } + + Behavior on width { + Anim {} + } + + Behavior on height { + Anim {} + } + + Behavior on fillColor { + ColorAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } + } } component Anim: NumberAnimation { diff --git a/modules/lock/Buttons.qml b/modules/lock/Buttons.qml new file mode 100644 index 0000000..ef7af37 --- /dev/null +++ b/modules/lock/Buttons.qml @@ -0,0 +1,111 @@ +import "root:/widgets" +import "root:/services" +import "root:/config" +import Quickshell.Widgets +import QtQuick +import QtQuick.Layouts + +WrapperItem { + readonly property real nonAnimMargin: handler.hovered ? Appearance.padding.large * 2 : Appearance.padding.large * 1.2 + readonly property real nonAnimWidth: handler.hovered ? Config.lock.sizes.buttonsWidth : Config.lock.sizes.buttonsWidthSmall + readonly property real nonAnimHeight: (nonAnimWidth + nonAnimMargin * 2) / 4 + + margin: nonAnimMargin + rightMargin: 0 + bottomMargin: 0 + implicitWidth: nonAnimWidth + implicitHeight: nonAnimHeight + + Behavior on margin { + NumberAnimation { + duration: Appearance.anim.durations.large + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + Behavior on implicitWidth { + NumberAnimation { + duration: Appearance.anim.durations.large + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + Behavior on implicitHeight { + NumberAnimation { + duration: Appearance.anim.durations.large + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.emphasized + } + } + + HoverHandler { + id: handler + + target: parent + } + + RowLayout { + id: layout + + spacing: Appearance.spacing.normal + + SessionButton { + icon: "logout" + command: ["loginctl", "terminate-user", ""] + } + + SessionButton { + icon: "power_settings_new" + command: ["systemctl", "poweroff"] + } + + SessionButton { + icon: "downloading" + command: ["systemctl", "hibernate"] + } + + SessionButton { + icon: "cached" + command: ["systemctl", "reboot"] + } + } + + component SessionButton: StyledRect { + required property string icon + required property list command + + Layout.fillWidth: true + Layout.preferredHeight: width + + radius: stateLayer.containsMouse ? Appearance.rounding.large * 2 : Appearance.rounding.large * 1.2 + color: Colours.palette.m3secondaryContainer + + StateLayer { + id: stateLayer + + color: Colours.palette.m3onSecondaryContainer + + function onClicked(): void { + Quickshell.execDetached(parent.command); + } + } + + MaterialIcon { + anchors.centerIn: parent + + text: parent.icon + color: Colours.palette.m3onSecondaryContainer + font.pointSize: (parent.width * 0.4) || 1 + } + + Behavior on radius { + NumberAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } + } +} diff --git a/modules/lock/LockSurface.qml b/modules/lock/LockSurface.qml index 6c2ffa7..047116f 100644 --- a/modules/lock/LockSurface.qml +++ b/modules/lock/LockSurface.qml @@ -73,6 +73,8 @@ WlSessionLockSurface { locked: root.locked weatherWidth: weather.implicitWidth + buttonsWidth: buttons.item?.nonAnimWidth ?? 0 + buttonsHeight: buttons.item?.nonAnimHeight ?? 0 isNormal: root.screen.width > Config.lock.sizes.smallScreenWidth isLarge: root.screen.width > Config.lock.sizes.largeScreenWidth visible: false @@ -153,9 +155,16 @@ WlSessionLockSurface { } Loader { + id: buttons + active: root.screen.width > Config.lock.sizes.largeScreenWidth asynchronous: true + anchors.top: parent.bottom + anchors.left: parent.right + anchors.topMargin: -backgrounds.buttonsTop + anchors.leftMargin: -backgrounds.buttonsLeft + sourceComponent: Buttons {} } -- cgit v1.2.3-freya