diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-13 09:53:35 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-13 09:53:35 +0200 |
| commit | 934fdbeb44ff96d86840e20f5d69497556539aa9 (patch) | |
| tree | 613a81952461e1c70d74f3b1745b2299066eb9fc /desktop/island | |
| parent | c382cca72c126fd9d35f11f8cb0a16e39870da2c (diff) | |
| download | quickshell-934fdbeb44ff96d86840e20f5d69497556539aa9.tar.gz quickshell-934fdbeb44ff96d86840e20f5d69497556539aa9.zip | |
feat(island): controls grid with an edit mode
Four columns, the visible list from Prefs. Edit mode puts a MouseArea
over each tile that drags it and drops it into the slot under its
centre, a × that hides it, and a strip of hidden tiles with a + each.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop/island')
| -rw-r--r-- | desktop/island/ControlsPanel.qml | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/desktop/island/ControlsPanel.qml b/desktop/island/ControlsPanel.qml new file mode 100644 index 0000000..a21b892 --- /dev/null +++ b/desktop/island/ControlsPanel.qml @@ -0,0 +1,175 @@ +// 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 Quickshell +import Quickshell.Widgets +import QtQuick +import ".." +import "Controls.js" as Controls + +// The grid of controls and its edit mode. In edit mode a tile is dragged to +// a new slot, a × hides it, and hidden tiles wait in a strip below with a +. +// Every change is written to Prefs at once. +Column { + id: panel + + required property QtObject sound + property bool editing: false + + signal openDrawer(string page) + + spacing: 12 + + Item { + width: panel.width + height: 20 + + Text { + anchors.verticalCenter: parent.verticalCenter + text: panel.editing ? "Edit controls" : "Controls" + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2; bold: true } + color: Theme.text + } + + IconImage { + anchors { right: parent.right; verticalCenter: parent.verticalCenter } + implicitSize: 16 + opacity: panel.editing ? 1 : 0.6 + source: Quickshell.iconPath("document-edit", true) + + MouseArea { + anchors.fill: parent + anchors.margins: -4 + cursorShape: Qt.PointingHandCursor + onClicked: panel.editing = !panel.editing + } + } + } + + Item { + id: grid + + readonly property int cols: 4 + readonly property real gap: 8 + readonly property real cell: (width - gap * (cols - 1)) / cols + readonly property real pitch: cell + gap + readonly property int rows: Math.ceil(Prefs.controls.length / cols) + + width: panel.width + height: Math.max(0, rows * pitch - gap) + + Repeater { + model: Prefs.controls + + delegate: Item { + id: slot + required property string modelData + required property int index + + width: grid.cell + height: grid.cell + x: (index % grid.cols) * grid.pitch + y: Math.floor(index / grid.cols) * grid.pitch + z: mover.pressed ? 1 : 0 + + ControlTile { + width: parent.width + height: parent.height + x: mover.pressed ? mover.dx : 0 + y: mover.pressed ? mover.dy : 0 + tileId: slot.modelData + sound: panel.sound + onOpenPage: page => panel.openDrawer(page) + } + + // Edit mode only, and above the tile so it takes the press + // instead of the toggle. Offsets the tile while held; on + // release the tile lands in the slot under its centre. + MouseArea { + id: mover + anchors.fill: parent + enabled: panel.editing + preventStealing: true + cursorShape: pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor + property real sx: 0 + property real sy: 0 + property real dx: 0 + property real dy: 0 + onPressed: mouse => { sx = mouse.x; sy = mouse.y; dx = 0; dy = 0; } + onPositionChanged: mouse => { dx = mouse.x - sx; dy = mouse.y - sy; } + onReleased: { + const to = Controls.slotAt(slot.x + dx + width / 2, slot.y + dy + height / 2, + grid.pitch, grid.cols, Prefs.controls.length); + if (to !== slot.index) + Prefs.setControls(Controls.move(Prefs.controls, slot.index, to)); + } + } + + IconImage { + visible: panel.editing && !mover.pressed + anchors { top: parent.top; right: parent.right; margins: 3 } + implicitSize: 14 + source: Quickshell.iconPath("window-close", true) + + MouseArea { + anchors.fill: parent + anchors.margins: -4 + cursorShape: Qt.PointingHandCursor + onClicked: Prefs.setControls(Controls.hide(Prefs.controls, slot.modelData)) + } + } + } + } + } + + Flow { + width: panel.width + spacing: 6 + visible: panel.editing && Controls.hidden(Prefs.controls).length > 0 + + Repeater { + model: Controls.hidden(Prefs.controls) + + delegate: Rectangle { + id: chip + required property string modelData + width: chipRow.implicitWidth + 16 + height: 28 + radius: 14 + color: Qt.alpha(Theme.surface, 0.5) + + Row { + id: chipRow + anchors.centerIn: parent + spacing: 4 + + IconImage { + anchors.verticalCenter: parent.verticalCenter + implicitSize: 14 + source: Quickshell.iconPath("list-add", true) + } + Text { + anchors.verticalCenter: parent.verticalCenter + text: Controls.tile(chip.modelData).label + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } + color: Theme.text + } + } + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: Prefs.setControls(Controls.show(Prefs.controls, chip.modelData)) + } + } + } + } +} |
