119 lines
3.4 KiB
QML
119 lines
3.4 KiB
QML
// One tile in the power menu: big glyph, label underneath.
|
|
//
|
|
// Anything that ends the session arms on the first press and only fires on the
|
|
// second — an accidental Ctrl+Alt+Delete should never be one click away from
|
|
// losing everything that is open.
|
|
//
|
|
// Armed, the tile turns red and names the thing it is about to do ("Power off")
|
|
// rather than saying "Confirm". Six tiles could all say "Confirm"; only one of
|
|
// them is about to take the machine down, and the press that does it should say
|
|
// which one it is.
|
|
|
|
import QtQuick
|
|
import qs.config
|
|
|
|
Rectangle {
|
|
id: root
|
|
|
|
property string glyph: ""
|
|
property string label: ""
|
|
// Tint red on hover and require the two-step confirm.
|
|
property bool destructive: false
|
|
// Highlighted by keyboard navigation.
|
|
property bool selected: false
|
|
|
|
signal activated
|
|
|
|
readonly property bool armed: confirmTimer.running
|
|
|
|
// The tile's own label, said as a sentence rather than as a title: "Power
|
|
// Off" is the name of a menu entry, "Power off" is the thing the next press
|
|
// does. Derived, so an entry added to the menu cannot forget to name itself.
|
|
readonly property string armedLabel: root.label === ""
|
|
? "Confirm"
|
|
: root.label.charAt(0) + root.label.slice(1).toLowerCase()
|
|
|
|
implicitWidth: 136
|
|
implicitHeight: 136
|
|
radius: Theme.cardRadius + 6
|
|
border.width: 0
|
|
|
|
readonly property color accentFor: root.destructive ? Theme.danger : Theme.accent
|
|
|
|
color: {
|
|
if (root.armed)
|
|
return Theme.alpha(Theme.danger, 0.32);
|
|
if (mouse.pressed)
|
|
return Theme.alpha(root.accentFor, 0.3);
|
|
if (mouse.containsMouse || root.selected)
|
|
return Theme.alpha(root.accentFor, 0.18);
|
|
return Theme.alpha(Theme.fg, 0.07);
|
|
}
|
|
|
|
Behavior on color {
|
|
ColorAnimation {
|
|
duration: Theme.durFast
|
|
}
|
|
}
|
|
|
|
// Keyboard focus ring.
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
radius: parent.radius
|
|
color: "transparent"
|
|
border.width: root.selected ? 2 : 0
|
|
border.color: root.accentFor
|
|
visible: root.selected
|
|
}
|
|
|
|
Column {
|
|
anchors.centerIn: parent
|
|
spacing: 10
|
|
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: root.glyph
|
|
color: root.armed ? Theme.danger : Theme.fg
|
|
font.family: Theme.fontMono
|
|
font.pixelSize: 40
|
|
}
|
|
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: root.armed ? root.armedLabel : root.label
|
|
color: root.armed ? Theme.danger : Theme.fg
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSize
|
|
font.weight: Font.Medium
|
|
}
|
|
}
|
|
|
|
// Trigger from a click or from Enter while keyboard-selected.
|
|
function trigger(): void {
|
|
if (root.destructive && !root.armed) {
|
|
confirmTimer.restart();
|
|
return;
|
|
}
|
|
confirmTimer.stop();
|
|
root.activated();
|
|
}
|
|
|
|
function disarm(): void {
|
|
confirmTimer.stop();
|
|
}
|
|
|
|
// Arming is not sticky: walk away and the button forgets.
|
|
Timer {
|
|
id: confirmTimer
|
|
interval: 4000
|
|
}
|
|
|
|
MouseArea {
|
|
id: mouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: root.trigger()
|
|
}
|
|
}
|