waffles: ctrl alt del menu

This commit is contained in:
end-4
2025-12-06 23:14:08 +01:00
parent 80a7804ade
commit 13968db31c
29 changed files with 578 additions and 90 deletions
@@ -0,0 +1,189 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import qs.modules.waffle.looks
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
Item {
id: root
Component.onCompleted: {
lockButton.forceActiveFocus();
}
ColumnLayout {
anchors.centerIn: parent
spacing: 4
WSessionScreenTextButton {
id: lockButton
focus: true
text: Translation.tr("Lock")
onClicked: {
GlobalStates.sessionOpen = false;
Session.lock();
}
KeyNavigation.up: powerButton
KeyNavigation.down: signOutButton
}
WSessionScreenTextButton {
id: signOutButton
focus: true
text: Translation.tr("Sign out")
onClicked: {
GlobalStates.sessionOpen = false;
Session.logout();
}
KeyNavigation.up: lockButton
KeyNavigation.down: changePasswordButton
}
WSessionScreenTextButton {
id: changePasswordButton
focus: true
text: Translation.tr("Change password")
onClicked: {
GlobalStates.sessionOpen = false;
Session.changePassword();
}
KeyNavigation.up: signOutButton
KeyNavigation.down: taskManagerButton
}
WSessionScreenTextButton {
id: taskManagerButton
focus: true
text: Translation.tr("Task Manager")
onClicked: {
GlobalStates.sessionOpen = false;
Session.launchTaskManager();
}
KeyNavigation.up: signOutButton
KeyNavigation.down: cancelButton
}
CancelButton {
id: cancelButton
Layout.fillWidth: true
Layout.leftMargin: 5
Layout.rightMargin: 5
Layout.topMargin: 38
onClicked: GlobalStates.sessionOpen = false
KeyNavigation.up: taskManagerButton
KeyNavigation.down: powerButton
}
}
RowLayout {
anchors {
bottom: parent.bottom
right: parent.right
bottomMargin: 21
rightMargin: 31
}
PowerButton {
id: powerButton
KeyNavigation.up: cancelButton
KeyNavigation.down: lockButton
}
}
component PowerButton: WSessionScreenTextButton {
id: root
implicitWidth: 40
implicitHeight: 40
focusRingRadius: Looks.radius.large
colBackgroundHover: Looks.colors.bg2Hover
colBackgroundActive: Looks.colors.bg2Active
property color color: {
if (root.down) {
return root.colBackgroundActive;
} else if (root.hovered) {
return root.colBackgroundHover;
} else {
return root.colBackground;
}
}
background: Rectangle {
id: background
radius: Looks.radius.medium
color: root.color
}
contentItem: Item {
FluentIcon {
anchors.centerIn: parent
implicitSize: 20
icon: "power"
}
}
onClicked: {
powerMenu.visible = !powerMenu.visible;
}
WMenu {
id: powerMenu
x: -powerMenu.implicitWidth / 2 + root.implicitWidth / 2
y: -powerMenu.implicitHeight
Action {
icon.name: "power"
text: Translation.tr("Shut down")
onTriggered: Session.poweroff()
}
Action {
icon.name: "arrow-counterclockwise"
text: Translation.tr("Restart")
onTriggered: Session.reboot()
}
}
}
component CancelButton: WBorderlessButton {
id: root
implicitHeight: 32
colBackground: Looks.colors.bg1Base
colBackgroundHover: Qt.lighter(Looks.colors.bg1Base, 1.2)
colBackgroundActive: Qt.lighter(Looks.colors.bg1Base, 1.1)
property bool keyboardDown: false
Keys.onPressed: event => {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
keyboardDown = true;
event.accepted = true;
}
}
Keys.onReleased: event => {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
keyboardDown = false;
root.clicked();
event.accepted = true;
}
}
contentItem: WText {
text: Translation.tr("Cancel")
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Looks.font.pixelSize.large
}
Rectangle {
visible: cancelButton.focus
anchors {
fill: parent
margins: -3
}
radius: cancelButton.background.radius + 4
color: "transparent"
border.width: 2
border.color: "#ffffff"
}
}
}
@@ -0,0 +1,54 @@
pragma ComponentBehavior: Bound
import QtQuick
import qs
import qs.modules.waffle.looks
WTextButton {
id: root
implicitWidth: 135
implicitHeight: 40
horizontalPadding: 5
property bool keyboardDown: false
property alias focusRingRadius: focusRing.radius
Keys.onPressed: event => {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
keyboardDown = true;
event.accepted = true;
}
}
Keys.onReleased: event => {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
keyboardDown = false;
root.clicked();
event.accepted = true;
}
}
contentItem: Item {
id: contentItem
implicitWidth: buttonText.implicitWidth
WText {
id: buttonText
anchors.fill: parent
color: (root.pressed || root.keyboardDown) ? Looks.colors.fg1 : Looks.colors.fg
text: root.text
font.pixelSize: Looks.font.pixelSize.large
}
}
Rectangle {
id: focusRing
visible: root.focus
anchors {
fill: parent
margins: -4
}
color: "transparent"
border.width: 2
border.color: "#ffffff"
}
}
@@ -0,0 +1,117 @@
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
Scope {
id: root
property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name)
Loader {
id: sessionLoader
active: GlobalStates.sessionOpen
onActiveChanged: {
if (sessionLoader.active) SessionWarnings.refresh();
}
Connections {
target: GlobalStates
function onScreenLockedChanged() {
if (GlobalStates.screenLocked) {
GlobalStates.sessionOpen = false;
}
}
}
sourceComponent: PanelWindow { // Session menu
id: sessionRoot
visible: sessionLoader.active
property string subtitle
function hide() {
GlobalStates.sessionOpen = false;
}
exclusionMode: ExclusionMode.Ignore
WlrLayershell.namespace: "quickshell:session"
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
// This is a big surface so we needa carefully choose the transparency,
// or we'll get a large scary rgb blob
color: "#000000"
anchors {
top: true
left: true
right: true
bottom: true
}
Item {
anchors.fill: parent
focus: true
Keys.onPressed: (event) => {
if (event.key === Qt.Key_Escape) {
sessionRoot.hide();
}
}
SessionScreenContent {
anchors.fill: parent
}
}
}
}
IpcHandler {
target: "session"
function toggle(): void {
GlobalStates.sessionOpen = !GlobalStates.sessionOpen;
}
function close(): void {
GlobalStates.sessionOpen = false
}
function open(): void {
GlobalStates.sessionOpen = true
}
}
GlobalShortcut {
name: "sessionToggle"
description: "Toggles session screen on press"
onPressed: {
GlobalStates.sessionOpen = !GlobalStates.sessionOpen;
}
}
GlobalShortcut {
name: "sessionOpen"
description: "Opens session screen on press"
onPressed: {
GlobalStates.sessionOpen = true
}
}
GlobalShortcut {
name: "sessionClose"
description: "Closes session screen on press"
onPressed: {
GlobalStates.sessionOpen = false
}
}
}