quickshell: session menu card backing, keyboard nav with default selection
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
a14ccd8c09
commit
516b8b6d5b
1 changed files with 75 additions and 44 deletions
|
|
@ -475,6 +475,8 @@ in
|
||||||
required property var shellRoot
|
required property var shellRoot
|
||||||
screen: modelData
|
screen: modelData
|
||||||
WlrLayershell.namespace: "quickshell-bar"
|
WlrLayershell.namespace: "quickshell-bar"
|
||||||
|
// Keyboard only while the session menu is open (arrow/Enter nav)
|
||||||
|
WlrLayershell.keyboardFocus: sessionMenu.open ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: true
|
top: true
|
||||||
|
|
@ -528,25 +530,54 @@ in
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Session menu: icon-only power controls morphing out of
|
// ── Session menu: icon-only power controls morphing out of
|
||||||
// the right frame column at screen centre (Super+L).
|
// the right frame column at screen centre (Super+L). Keyboard:
|
||||||
|
// arrows/Tab move the selection, Enter activates, Esc closes.
|
||||||
Item {
|
Item {
|
||||||
id: sessionMenu
|
id: sessionMenu
|
||||||
property bool open: false
|
property bool open: false
|
||||||
property real openW: open ? 56 : 0
|
property int selIdx: 0
|
||||||
|
property real openW: open ? 64 : 0
|
||||||
Behavior on openW {
|
Behavior on openW {
|
||||||
NumberAnimation { duration: 280; easing.type: Easing.OutExpo }
|
NumberAnimation { duration: 280; easing.type: Easing.OutExpo }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readonly property var actions: [
|
||||||
|
{ icon: "lock", danger: false, act: "lock" },
|
||||||
|
{ icon: "logout", danger: false, act: "logout" },
|
||||||
|
{ icon: "restart_alt", danger: true, act: "reboot" },
|
||||||
|
{ icon: "power_settings_new", danger: true, act: "poweroff" }
|
||||||
|
]
|
||||||
|
|
||||||
|
function activate(act) {
|
||||||
|
open = false;
|
||||||
|
if (act === "lock") Quickshell.execDetached([Commands.hyprlock]);
|
||||||
|
else if (act === "logout") Hyprland.dispatch("hl.dsp.exit()");
|
||||||
|
else if (act === "reboot") Quickshell.execDetached([Commands.systemctl, "reboot"]);
|
||||||
|
else Quickshell.execDetached([Commands.systemctl, "poweroff"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
open = !open;
|
||||||
|
if (open) {
|
||||||
|
selIdx = 0;
|
||||||
|
forceActiveFocus();
|
||||||
|
_sessionAutoClose.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
x: bar.width - Theme.frameWidth - openW
|
x: bar.width - Theme.frameWidth - openW
|
||||||
y: Math.round((bar.height - height) / 2)
|
y: Math.round((bar.height - height) / 2)
|
||||||
width: openW
|
width: openW
|
||||||
height: sessionCol.height + 24
|
height: sessionCard.height + 24
|
||||||
visible: openW > 0.5
|
visible: openW > 0.5
|
||||||
|
|
||||||
function toggle() {
|
focus: open
|
||||||
open = !open;
|
Keys.onEscapePressed: open = false
|
||||||
if (open) _sessionAutoClose.restart();
|
Keys.onUpPressed: { selIdx = (selIdx + actions.length - 1) % actions.length; _sessionAutoClose.restart(); }
|
||||||
}
|
Keys.onDownPressed: { selIdx = (selIdx + 1) % actions.length; _sessionAutoClose.restart(); }
|
||||||
|
Keys.onTabPressed: { selIdx = (selIdx + 1) % actions.length; _sessionAutoClose.restart(); }
|
||||||
|
Keys.onReturnPressed: activate(actions[selIdx].act)
|
||||||
|
Keys.onEnterPressed: activate(actions[selIdx].act)
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: _sessionAutoClose
|
id: _sessionAutoClose
|
||||||
|
|
@ -570,51 +601,51 @@ in
|
||||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
// Card backing, matching the other dropdowns
|
||||||
id: sessionCol
|
Rectangle {
|
||||||
|
id: sessionCard
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 8
|
anchors.rightMargin: 8
|
||||||
spacing: 4
|
width: 48
|
||||||
|
height: sessionCol.height + 8
|
||||||
|
radius: 8
|
||||||
|
color: Theme.base01
|
||||||
|
|
||||||
Repeater {
|
Column {
|
||||||
model: [
|
id: sessionCol
|
||||||
{ icon: "lock", danger: false, act: "lock" },
|
anchors.centerIn: parent
|
||||||
{ icon: "logout", danger: false, act: "logout" },
|
spacing: 4
|
||||||
{ icon: "restart_alt", danger: true, act: "reboot" },
|
|
||||||
{ icon: "power_settings_new", danger: true, act: "poweroff" }
|
|
||||||
]
|
|
||||||
|
|
||||||
Rectangle {
|
Repeater {
|
||||||
id: sessBtn
|
model: sessionMenu.actions
|
||||||
required property var modelData
|
|
||||||
width: 40
|
|
||||||
height: 40
|
|
||||||
radius: 8
|
|
||||||
color: sessBtnMa.containsMouse ? Theme.base02 : "transparent"
|
|
||||||
Behavior on color { ColorAnimation { duration: 120 } }
|
|
||||||
|
|
||||||
Text {
|
Rectangle {
|
||||||
anchors.centerIn: parent
|
id: sessBtn
|
||||||
text: sessBtn.modelData.icon
|
required property var modelData
|
||||||
color: sessBtn.modelData.danger && sessBtnMa.containsMouse
|
required property int index
|
||||||
? Theme.base08 : Theme.base05
|
width: 40
|
||||||
|
height: 40
|
||||||
|
radius: 8
|
||||||
|
color: sessionMenu.selIdx === index ? Theme.base02 : "transparent"
|
||||||
Behavior on color { ColorAnimation { duration: 120 } }
|
Behavior on color { ColorAnimation { duration: 120 } }
|
||||||
font.family: Theme.iconFont
|
|
||||||
font.pixelSize: 20
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
Text {
|
||||||
id: sessBtnMa
|
anchors.centerIn: parent
|
||||||
anchors.fill: parent
|
text: sessBtn.modelData.icon
|
||||||
hoverEnabled: true
|
color: sessBtn.modelData.danger && sessionMenu.selIdx === sessBtn.index
|
||||||
cursorShape: Qt.PointingHandCursor
|
? Theme.base08 : Theme.base05
|
||||||
onClicked: {
|
Behavior on color { ColorAnimation { duration: 120 } }
|
||||||
sessionMenu.open = false;
|
font.family: Theme.iconFont
|
||||||
if (sessBtn.modelData.act === "lock") Quickshell.execDetached([Commands.hyprlock]);
|
font.pixelSize: 20
|
||||||
else if (sessBtn.modelData.act === "logout") Hyprland.dispatch("hl.dsp.exit()");
|
}
|
||||||
else if (sessBtn.modelData.act === "reboot") Quickshell.execDetached([Commands.systemctl, "reboot"]);
|
|
||||||
else Quickshell.execDetached([Commands.systemctl, "poweroff"]);
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onEntered: sessionMenu.selIdx = sessBtn.index
|
||||||
|
onClicked: sessionMenu.activate(sessBtn.modelData.act)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue