110 lines
3.5 KiB
QML
110 lines
3.5 KiB
QML
// A key chord, drawn as keys.
|
|
//
|
|
// KeycapChord { chord: "Super + Shift + Q" }
|
|
//
|
|
// The chord arrives as the display string Keybinds already produces and is
|
|
// split on "+" alone, so nothing here has to know what a keysym is. Modifiers
|
|
// are tinted and spelled in title case, which is what makes a wall of chords
|
|
// scannable: the eye finds the modifier pattern before it reads the key.
|
|
//
|
|
// Presentation only. The prettified names are never handed back -- a rebind is
|
|
// keyed by the Lua chord the service holds, and this must not become a second,
|
|
// lossy spelling of a binding.
|
|
|
|
import QtQuick
|
|
import qs.config
|
|
|
|
Row {
|
|
id: root
|
|
|
|
property string chord: ""
|
|
property int capHeight: 24
|
|
|
|
readonly property var keys: String(root.chord)
|
|
.split("+")
|
|
.map(part => part.trim())
|
|
.filter(part => part !== "")
|
|
|
|
// Case-insensitive: Keybinds renders "Super", an override is stored as
|
|
// "SUPER", and both have to tint.
|
|
readonly property var modifierNames: ({
|
|
"super": "Super",
|
|
"meta": "Super",
|
|
"win": "Super",
|
|
"shift": "Shift",
|
|
"ctrl": "Ctrl",
|
|
"control": "Ctrl",
|
|
"alt": "Alt"
|
|
})
|
|
|
|
function isModifier(key: string): bool {
|
|
return root.modifierNames[String(key).toLowerCase()] !== undefined;
|
|
}
|
|
|
|
function pretty(key: string): string {
|
|
return root.modifierNames[String(key).toLowerCase()] ?? key;
|
|
}
|
|
|
|
spacing: 4
|
|
|
|
Repeater {
|
|
model: root.keys
|
|
|
|
Row {
|
|
id: segment
|
|
|
|
required property var modelData
|
|
required property int index
|
|
|
|
readonly property bool modifier: root.isModifier(String(segment.modelData))
|
|
|
|
spacing: 4
|
|
|
|
Text {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
visible: segment.index > 0
|
|
text: "+"
|
|
color: Theme.fgMuted
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: Math.max(26, cap.implicitWidth + 14)
|
|
height: root.capHeight
|
|
radius: 6
|
|
color: Theme.alpha(Theme.fg, 0.09)
|
|
border.width: 1
|
|
border.color: Theme.alpha(Theme.fg, 0.16)
|
|
|
|
// A keycap reads as a key because it has a lip. Rectangle
|
|
// borders are uniform, so the thicker bottom edge is its own
|
|
// sliver rather than a border width.
|
|
Rectangle {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: parent.bottom
|
|
anchors.margins: 1
|
|
height: 1
|
|
color: Theme.alpha(Theme.fg, 0.16)
|
|
}
|
|
|
|
Text {
|
|
id: cap
|
|
|
|
anchors.centerIn: parent
|
|
text: root.pretty(String(segment.modelData))
|
|
color: segment.modifier ? Theme.accent : Theme.fg
|
|
font.family: Theme.fontMono
|
|
// Digits in a chord ("Super + 1") sit in a column of other
|
|
// chords; tabular figures keep that column from wobbling.
|
|
font.features: Theme.tabularFigures
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
font.weight: Font.DemiBold
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|