201 lines
8.0 KiB
QML
201 lines
8.0 KiB
QML
import QtQuick
|
|
import QtQuick.Layouts
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import Quickshell.Hyprland
|
|
import "../../config"
|
|
|
|
Item {
|
|
id: root
|
|
implicitWidth: label.implicitWidth + 2
|
|
implicitHeight: Appearance.barHeight
|
|
|
|
// The bar's own PanelWindow — passed in from Bar.qml so this popup can
|
|
// anchor to the bar itself rather than to this icon, keeping it a fixed
|
|
// distance from the bar and the screen edge regardless of where this
|
|
// icon sits in the row.
|
|
required property var barWindow
|
|
|
|
Text {
|
|
id: label
|
|
anchors.centerIn: parent
|
|
font.family: Appearance.iconFontFamilyRounded
|
|
font.variableAxes: Appearance.iconFontAxes
|
|
font.pixelSize: 16
|
|
color: Colors.foreground
|
|
text: "settings_power"
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
menu.visible = !menu.visible
|
|
grab.active = menu.visible
|
|
}
|
|
}
|
|
|
|
Process { id: proc }
|
|
|
|
PopupWindow {
|
|
id: menu
|
|
visible: false
|
|
color: "transparent"
|
|
// Same contentWidth/contentPadding split as the other panels
|
|
// (Volume.qml, NetworkIndicator.qml, etc.) rather than a single
|
|
// magic implicitWidth.
|
|
readonly property int contentWidth: 178
|
|
readonly property int contentPadding: 16
|
|
implicitWidth: contentWidth + contentPadding * 2
|
|
implicitHeight: mainColumn.implicitHeight + contentPadding * 2
|
|
|
|
anchor {
|
|
window: root.barWindow
|
|
// Unlike anchor.item, anchor.window doesn't default rect to the
|
|
// window's own bounds — set it explicitly so edges/gravity below
|
|
// resolve against the full bar (and thus the true screen edges)
|
|
// instead of a near-zero rect at the window's origin.
|
|
rect.x: 0
|
|
rect.y: 0
|
|
rect.width: root.barWindow.width
|
|
rect.height: root.barWindow.height
|
|
edges: Edges.Bottom | Edges.Right
|
|
gravity: Edges.Bottom | Edges.Left
|
|
margins.bottom: -4
|
|
margins.right: 0
|
|
}
|
|
|
|
HyprlandFocusGrab {
|
|
id: grab
|
|
windows: [menu]
|
|
onCleared: menu.visible = false
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
radius: 0
|
|
color: Colors.surface
|
|
border.color: Colors.muted
|
|
border.width: 3
|
|
|
|
Column {
|
|
id: mainColumn
|
|
anchors.fill: parent
|
|
anchors.margins: menu.contentPadding
|
|
spacing: 10
|
|
|
|
// Header — same title layout as Volume.qml's panel: the bar
|
|
// icon large, plus a bold title.
|
|
RowLayout {
|
|
id: header
|
|
width: parent.width
|
|
spacing: 8
|
|
|
|
Text {
|
|
text: label.text
|
|
font.family: Appearance.iconFontFamilyRounded
|
|
font.variableAxes: Appearance.iconFontAxes
|
|
font.pixelSize: 23
|
|
color: Colors.foreground
|
|
}
|
|
|
|
Text {
|
|
Layout.fillWidth: true
|
|
text: "Power"
|
|
font.family: Appearance.fontFamily
|
|
font.pixelSize: 18
|
|
font.bold: true
|
|
color: Colors.foreground
|
|
}
|
|
}
|
|
|
|
Column {
|
|
width: parent.width
|
|
spacing: 2
|
|
|
|
Repeater {
|
|
id: list
|
|
model: [
|
|
{ label: "Lock", icon: "lock", cmd: ["hyprlock"] },
|
|
{ label: "Suspend", icon: "bedtime", cmd: ["systemctl", "suspend"] },
|
|
{ label: "Hibernate", icon: "ac_unit", cmd: ["systemctl", "hibernate"] },
|
|
{ label: "Log out", icon: "logout", cmd: ["hyprctl", "dispatch", "exit"] },
|
|
{ label: "Reboot", icon: "restart_alt", cmd: ["systemctl", "reboot"] },
|
|
{ label: "Shut down", icon: "power_settings_new", cmd: ["systemctl", "poweroff"] }
|
|
]
|
|
|
|
// Same shape as this project's other selectable rows
|
|
// (e.g. VpnIndicator.qml's ProviderRow,
|
|
// TailscaleIndicator.qml's ExitNodeRow): radius 0, a
|
|
// fixed-width icon column followed by a fillWidth
|
|
// label, and an offset hover halo rather than one
|
|
// drawn on the row's own edge.
|
|
delegate: Rectangle {
|
|
id: entry
|
|
required property var modelData
|
|
width: parent ? parent.width : 0
|
|
radius: 0
|
|
implicitHeight: entryContent.implicitHeight + 12
|
|
color: (!entry.modelData.disabled && entryMouse.containsMouse) ? Colors.primary : "transparent"
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
anchors.margins: -3
|
|
radius: 0
|
|
color: "transparent"
|
|
border.color: Colors.foreground
|
|
border.width: entryMouse.containsMouse ? 1 : 0
|
|
}
|
|
|
|
RowLayout {
|
|
id: entryContent
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.margins: 6
|
|
spacing: 8
|
|
|
|
Text {
|
|
Layout.preferredWidth: 20
|
|
Layout.minimumWidth: 20
|
|
Layout.maximumWidth: 20
|
|
horizontalAlignment: Text.AlignLeft
|
|
text: entry.modelData.icon
|
|
font.family: Appearance.iconFontFamilyRounded
|
|
font.variableAxes: Appearance.iconFontAxes
|
|
font.pixelSize: 14
|
|
opacity: entry.modelData.disabled ? 0.4 : 1
|
|
color: entryMouse.containsMouse ? Colors.primaryText : Colors.foreground
|
|
}
|
|
Text {
|
|
Layout.fillWidth: true
|
|
text: entry.modelData.label
|
|
elide: Text.ElideRight
|
|
font.family: Appearance.fontFamily
|
|
font.pixelSize: Appearance.fontSize
|
|
opacity: entry.modelData.disabled ? 0.4 : 1
|
|
color: entryMouse.containsMouse ? Colors.primaryText : Colors.foreground
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: entryMouse
|
|
anchors.fill: parent
|
|
enabled: !entry.modelData.disabled
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: {
|
|
proc.command = entry.modelData.cmd
|
|
proc.running = true
|
|
menu.visible = false
|
|
grab.active = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|