diff --git a/shell/modules/PowerMenu.qml b/shell/modules/PowerMenu.qml index 4f71f5a..4a36105 100644 --- a/shell/modules/PowerMenu.qml +++ b/shell/modules/PowerMenu.qml @@ -13,89 +13,219 @@ M.HoverPanel { readonly property bool _isNiri: Quickshell.env("NIRI_SOCKET") !== "" + // Confirmation state: null = normal menu, object = pending confirm + property var _confirmItem: null + function _run(cmd) { runCommand(cmd); dismiss(); } - Repeater { - model: [ - { - label: "Lock", - icon: "\uF023", - cmd: ["loginctl", "lock-session"], - color: S.Theme.base0D - }, - { - label: "Suspend", - icon: "\uF186", - cmd: ["systemctl", "suspend"], - color: S.Theme.base0E - }, - { - label: "Logout", - icon: "\uF2F5", - cmd: menuWindow._isNiri ? ["niri", "msg", "action", "quit"] : ["loginctl", "terminate-user", ""], - color: S.Theme.base0A - }, - { - label: "Reboot", - icon: "\uF021", - cmd: ["systemctl", "reboot"], - color: S.Theme.base09 - }, - { - label: "Shutdown", - icon: "\uF011", - cmd: ["systemctl", "poweroff"], - color: S.Theme.base08 - } - ] + function _requestAction(item) { + if (item.confirm) { + _confirmItem = item; + } else { + _run(item.cmd); + } + } - delegate: Item { - id: entry + function _cancelConfirm() { + _confirmItem = null; + } - required property var modelData - required property int index + // Normal menu entries + Column { + visible: !menuWindow._confirmItem + width: menuWindow.contentWidth - width: menuWindow.contentWidth - height: 32 + Repeater { + model: [ + { + label: "Lock", + icon: "\uF023", + cmd: ["loginctl", "lock-session"], + color: S.Theme.base0D, + confirm: false + }, + { + label: "Suspend", + icon: "\uF186", + cmd: ["systemctl", "suspend"], + color: S.Theme.base0E, + confirm: false + }, + { + label: "Logout", + icon: "\uF2F5", + cmd: menuWindow._isNiri ? ["niri", "msg", "action", "quit"] : ["loginctl", "terminate-user", ""], + color: S.Theme.base0A, + confirm: false + }, + { + label: "Reboot", + icon: "\uF021", + cmd: ["systemctl", "reboot"], + color: S.Theme.base09, + confirm: true + }, + { + label: "Shutdown", + icon: "\uF011", + cmd: ["systemctl", "poweroff"], + color: S.Theme.base08, + confirm: true + } + ] - Rectangle { - anchors.fill: parent - anchors.leftMargin: 4 - anchors.rightMargin: 4 - color: entryArea.containsMouse ? S.Theme.base02 : "transparent" - radius: S.Theme.radius - } + delegate: Item { + id: entry - Text { - id: entryIcon - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: 12 - text: entry.modelData.icon - color: entry.modelData.color - font.pixelSize: S.Theme.fontSize + 1 - font.family: S.Theme.iconFontFamily - } + required property var modelData + required property int index - Text { - anchors.verticalCenter: parent.verticalCenter - anchors.left: entryIcon.right - anchors.leftMargin: 10 - text: entry.modelData.label - color: S.Theme.base05 - font.pixelSize: S.Theme.fontSize - font.family: S.Theme.fontFamily - } + width: menuWindow.contentWidth + height: 32 - MouseArea { - id: entryArea - anchors.fill: parent - hoverEnabled: true - onClicked: menuWindow._run(entry.modelData.cmd) + Rectangle { + anchors.fill: parent + anchors.leftMargin: 4 + anchors.rightMargin: 4 + color: entryHover.hovered ? S.Theme.base02 : "transparent" + radius: S.Theme.radius + } + + Text { + id: entryIcon + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 12 + text: entry.modelData.icon + color: entry.modelData.color + font.pixelSize: S.Theme.fontSize + 1 + font.family: S.Theme.iconFontFamily + } + + Text { + anchors.verticalCenter: parent.verticalCenter + anchors.left: entryIcon.right + anchors.leftMargin: 10 + text: entry.modelData.label + color: S.Theme.base05 + font.pixelSize: S.Theme.fontSize + font.family: S.Theme.fontFamily + } + + HoverHandler { + id: entryHover + cursorShape: Qt.PointingHandCursor + } + + TapHandler { + onTapped: menuWindow._requestAction(entry.modelData) + } } } } + + // Confirmation view + Column { + visible: !!menuWindow._confirmItem + width: menuWindow.contentWidth + spacing: 4 + + Item { + width: parent.width + height: 28 + + Text { + anchors.centerIn: parent + text: menuWindow._confirmItem ? menuWindow._confirmItem.label + "?" : "" + color: menuWindow._confirmItem ? menuWindow._confirmItem.color : S.Theme.base05 + font.pixelSize: S.Theme.fontSize + font.family: S.Theme.fontFamily + font.bold: true + } + } + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: 8 + + // Cancel + Item { + width: 72 + height: 28 + + Rectangle { + anchors.fill: parent + color: cancelHover.hovered ? S.Theme.base02 : S.Theme.base01 + radius: S.Theme.radius + border.width: 1 + border.color: S.Theme.base03 + } + + Text { + anchors.centerIn: parent + text: "Cancel" + color: S.Theme.base05 + font.pixelSize: S.Theme.fontSize + font.family: S.Theme.fontFamily + } + + HoverHandler { + id: cancelHover + cursorShape: Qt.PointingHandCursor + } + + TapHandler { + onTapped: menuWindow._cancelConfirm() + } + } + + // Confirm + Item { + width: 72 + height: 28 + + Rectangle { + anchors.fill: parent + color: { + if (!menuWindow._confirmItem) + return S.Theme.base02; + const c = menuWindow._confirmItem.color; + return confirmHover.hovered ? Qt.rgba(c.r, c.g, c.b, 0.3) : Qt.rgba(c.r, c.g, c.b, 0.15); + } + radius: S.Theme.radius + border.width: 1 + border.color: menuWindow._confirmItem ? menuWindow._confirmItem.color : S.Theme.base03 + } + + Text { + anchors.centerIn: parent + text: "Confirm" + color: menuWindow._confirmItem ? menuWindow._confirmItem.color : S.Theme.base05 + font.pixelSize: S.Theme.fontSize + font.family: S.Theme.fontFamily + font.bold: true + } + + HoverHandler { + id: confirmHover + cursorShape: Qt.PointingHandCursor + } + + TapHandler { + onTapped: { + if (menuWindow._confirmItem) + menuWindow._run(menuWindow._confirmItem.cmd); + } + } + } + } + + Item { + width: 1 + height: 4 + } + } }