Add quick toggles to the grab bar

Beside the gear: full keyboard, hold keys, and the numeric keypad,
navigation and function key sections, each behind a drawn icon and lit
while on. Section toggles hide when the layout lacks the section. The
grab pill narrows when a small window leaves it less room.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 00:29:48 +01:00
co-authored by Claude Opus 5.5
parent b94463a277
commit ac5f43ca5f
5 changed files with 197 additions and 1 deletions
+40
View File
@@ -0,0 +1,40 @@
import QtQuick
// A small on/off button in the grab bar; lit while on. The icon goes inside
// and should draw in `foreground`.
Item {
id: toggle
required property string label
property bool checked: false
readonly property color foreground: checked ? Theme.accentText : (tap.pressed ? Theme.text : Theme.handle)
default property alias icon: iconArea.data
signal toggled(bool checked)
implicitWidth: 34
implicitHeight: 22
Accessible.role: Accessible.CheckBox
Accessible.name: label
Accessible.checked: checked
Rectangle {
anchors.centerIn: parent
width: 30
height: 20
radius: 5
color: Theme.accent
visible: toggle.checked
}
Item {
id: iconArea
anchors.centerIn: parent
width: 20
height: 14
}
TapHandler {
id: tap
onTapped: toggle.toggled(!toggle.checked)
}
}
+3 -1
View File
@@ -5,13 +5,15 @@ import QtQuick
Item {
id: handle
// Narrower when the bar's buttons leave less room in the middle.
property real pillWidth: 120
signal dragStarted()
implicitHeight: 22
Rectangle {
anchors.centerIn: parent
width: 120
width: handle.pillWidth
height: 5
radius: height / 2
color: Theme.handle
+9
View File
@@ -65,16 +65,25 @@ Window {
DragHandle {
id: handle
anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
pillWidth: Math.min(120, width - 2 * (quickToggles.x + quickToggles.width + 12))
onDragStarted: root.startSystemMove()
}
SettingsButton {
id: settingsButton
anchors { left: parent.left; leftMargin: 8; bottom: parent.bottom }
checked: root.settingsOpen
alert: root.diagnostics.problems.length > 0
onClicked: root.settingsOpen = !root.settingsOpen
}
QuickToggles {
id: quickToggles
anchors { left: settingsButton.right; bottom: parent.bottom }
settings: root.settings
layoutModel: root.layoutModel
}
ResizeHandle {
anchors { right: parent.right; bottom: parent.bottom }
onDragStarted: root.startSystemResize(Qt.RightEdge | Qt.BottomEdge)
+143
View File
@@ -0,0 +1,143 @@
import QtQuick
import Sloposk
// One-tap switches for the most changed key options, beside the gear.
// Icons are drawn from boxes so they don't depend on the fonts installed.
Row {
id: toggles
required property Settings settings
required property LayoutModel layoutModel
function hasSection(id) {
return layoutModel.sections.some(s => s.id === id);
}
// Shows or hides one of the template's optional sections; absent from
// layouts without it.
component SectionToggle: BarToggle {
required property string section
visible: toggles.hasSection(section)
checked: toggles.settings.visibleSections.includes(section)
onToggled: checked => toggles.settings.setSectionVisible(section, checked)
}
// A grid of tiny keys, optionally in a keyboard outline.
component KeyGrid: Item {
id: keyGrid
required property color color
required property int columns
required property int rows
property bool framed: false
anchors.fill: parent
Rectangle {
anchors.fill: parent
visible: keyGrid.framed
radius: 2
color: "transparent"
border { width: 1.5; color: keyGrid.color }
}
Grid {
readonly property real key: keyGrid.framed ? 2 : 3
anchors.centerIn: parent
columns: keyGrid.columns
spacing: 1
Repeater {
model: keyGrid.columns * keyGrid.rows
Rectangle {
width: parent.key
height: parent.key
radius: 0.5
color: keyGrid.color
}
}
}
}
// A key outline with a label on it.
component LabelledKey: Rectangle {
property alias label: caption.text
property alias textColor: caption.color
anchors.centerIn: parent
width: 20
height: 14
radius: 3
color: "transparent"
border { width: 1.5; color: caption.color }
Text {
id: caption
anchors.centerIn: parent
font { pixelSize: 9; bold: true }
}
}
BarToggle {
id: full
label: qsTr("Full Keyboard")
checked: toggles.settings.fullKeyboard
onToggled: checked => toggles.settings.fullKeyboard = checked
KeyGrid { color: full.foreground; columns: 6; rows: 3; framed: true }
}
BarToggle {
id: hold
label: qsTr("Hold Keys")
checked: toggles.settings.holdKeys
onToggled: checked => toggles.settings.holdKeys = checked
// A fingertip resting on a key, holding it down.
Rectangle {
anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom }
width: 18
height: 8
radius: 2
color: "transparent"
border { width: 1.5; color: hold.foreground }
}
Rectangle {
anchors { horizontalCenter: parent.horizontalCenter; top: parent.top; topMargin: 1 }
width: 8
height: 11
radius: 4
color: hold.foreground
}
}
SectionToggle {
id: numpad
section: "numpad"
label: qsTr("Numeric Keypad")
KeyGrid { color: numpad.foreground; columns: 3; rows: 3 }
}
SectionToggle {
id: navigation
section: "navigation"
label: qsTr("Navigation Keys")
// The inverted T of the arrow keys.
Repeater {
model: [[1, 0], [0, 1], [1, 1], [2, 1]]
Rectangle {
required property var modelData
x: 1.5 + modelData[0] * 6
y: 1.5 + modelData[1] * 6
width: 5
height: 5
radius: 1
color: navigation.foreground
}
}
}
SectionToggle {
id: fn
section: "function"
label: qsTr("Function Keys")
LabelledKey { label: "Fn"; textColor: fn.foreground }
}
}