aboutsummaryrefslogtreecommitdiffstats
path: root/keybinds/PadPanel.qml
diff options
context:
space:
mode:
Diffstat (limited to 'keybinds/PadPanel.qml')
-rw-r--r--keybinds/PadPanel.qml162
1 files changed, 162 insertions, 0 deletions
diff --git a/keybinds/PadPanel.qml b/keybinds/PadPanel.qml
new file mode 100644
index 0000000..04c95a5
--- /dev/null
+++ b/keybinds/PadPanel.qml
@@ -0,0 +1,162 @@
+// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+import QtQuick
+
+// The macropad as it sits on the desk: twelve keys in three rows of four,
+// the two encoders to their right. Each key carries its plain action;
+// hovering a key or an encoder lists everything it does underneath. The
+// last one hovered stays listed, so moving the pointer off does not blank it.
+Item {
+ id: panel
+
+ // Binds.padActions(): "k1".."k12", "top", "bottom" to [{ how, label }].
+ property var actions: ({})
+ property string hovered: ""
+
+ // Keys are unit wide; the pad is four of them, three gaps, a gap and an
+ // encoder: 5.56 units, fitted to most of the panel's width.
+ readonly property int unit: Math.floor(width * 0.85 / 5.56)
+ readonly property int padWidth: Math.round(unit * 5.56)
+
+ function plain(id) {
+ const a = (actions[id] ?? []).find(x => x.how === "Press");
+ return a ? a.label : "";
+ }
+
+ function title(id) {
+ if (id === "top") return "Top encoder";
+ if (id === "bottom") return "Bottom encoder";
+ return "Key " + id.slice(1);
+ }
+
+ // Pinned at a fixed height rather than centred: centred, the pad moved
+ // every time the list under it changed length.
+ Column {
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: parent.height * 0.3
+ spacing: panel.unit * 0.5
+
+ Row {
+ spacing: panel.unit * 0.3
+
+ Grid {
+ id: keys
+ columns: 4
+ spacing: panel.unit * 0.12
+
+ Repeater {
+ model: 12
+
+ Rectangle {
+ required property int index
+ readonly property string padId: "k" + (index + 1)
+
+ width: panel.unit
+ height: panel.unit
+ radius: panel.unit * 0.12
+ color: panel.hovered === padId ? Theme.surfaceAlt : Theme.surface
+ border.color: panel.hovered === padId ? Theme.accent : "transparent"
+ border.width: 2
+
+ Text {
+ anchors.fill: parent
+ anchors.margins: 4
+ text: panel.plain(parent.padId)
+ wrapMode: Text.Wrap
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: Theme.text
+ font.family: Theme.fontFamily
+ font.pixelSize: Math.max(10, panel.unit * 0.16)
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ onEntered: panel.hovered = parent.padId
+ }
+ }
+ }
+ }
+
+ // One encoder level with the top row, one with the bottom.
+ Item {
+ width: panel.unit * 0.9
+ height: keys.height
+
+ Repeater {
+ model: ["top", "bottom"]
+
+ Rectangle {
+ required property string modelData
+
+ y: modelData === "top" ? 0 : parent.height - height
+ width: parent.width
+ height: width
+ radius: width / 2
+ color: panel.hovered === modelData ? Theme.surfaceAlt : Theme.surface
+ border.color: panel.hovered === modelData ? Theme.accent : Theme.overlay
+ border.width: 2
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ onEntered: panel.hovered = parent.modelData
+ }
+ }
+ }
+ }
+ }
+
+ Column {
+ width: panel.padWidth
+ spacing: 6
+
+ Text {
+ text: panel.hovered ? panel.title(panel.hovered) : "Hover a key or an encoder"
+ color: Theme.accent
+ font.family: Theme.fontFamily
+ font.pixelSize: 18
+ font.bold: true
+ bottomPadding: 4
+ }
+
+ Repeater {
+ model: panel.actions[panel.hovered] ?? []
+
+ // Fixed widths summing to the column's: a Row sizes to its
+ // children.
+ Row {
+ required property var modelData
+ spacing: 12
+
+ Text {
+ width: panel.padWidth * 0.4
+ text: modelData.how
+ color: Theme.subtext
+ font.family: Theme.fontFamily
+ font.pixelSize: 15
+ }
+ Text {
+ width: panel.padWidth * 0.6 - 12
+ text: modelData.label
+ wrapMode: Text.Wrap
+ color: Theme.text
+ font.family: Theme.fontFamily
+ font.pixelSize: 15
+ }
+ }
+ }
+ }
+ }
+}