Files
Panama/config/dot/quickshell/modules/settings/ChoiceGrid.qml
Gabriel Brown 5671324eb2 Make displays configurable, with a revert countdown
Resolution, refresh rate, scale, and rotation, applied through
hl.monitor{} and stored per output.

This is the only setting in Panama where a wrong value can leave the
user unable to SEE the screen well enough to undo it: a mode the panel
cannot show, or a scale that makes everything unreadable, is not
recoverable through the UI that caused it. So a change is never applied
irreversibly. It is applied, then reverted automatically after fifteen
seconds unless confirmed, and confirming is what writes it to the
settings store -- letting the countdown run leaves nothing behind.

The contract tests that property specifically: it applies a scale, waits
out the countdown, and asserts the display came back and that nothing
was stored. A regression there is not a broken feature, it is a user
staring at a blank monitor.

Modes are grouped by resolution with refresh rates beside them. The
panel reports 35, many differing only in refresh-rate rounding -- 60.00
and 59.94 -- which as a flat list of buttons is noise rather than
choice; equal rounded pairs collapse, leaving 21.

Only mode, scale, and transform are configurable. Colour management and
bit depth stay in monitors.lua because they carry a documented screencopy
tradeoff that a settings page cannot explain at the moment you would be
changing it.

Also replaces the display policy rows with the schema-bound ones, so the
page no longer restates labels that PreferenceSchema already holds.

Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L
2026-08-18 02:55:43 -04:00

119 lines
3.7 KiB
QML

// A row of choices that wraps, for options that do not fit a segmented control.
//
// ChoiceRow puts two or three options on one line. Scales and rotations are
// more numerous and their labels are wider, so they wrap into a grid rather
// than shrinking to illegibility on a narrow, tiled window.
//
// Unlike ChoiceRow this is not schema-bound: it reports a value and lets the
// caller decide what to do with it, because a display change has to go through
// an apply-then-confirm cycle rather than straight into the store.
import QtQuick
import qs.config
Column {
id: root
property string label: ""
property string detail: ""
property var options: []
property var current: null
property bool enabled: true
property bool divider: true
signal picked(var value)
spacing: 9
bottomPadding: 12
Column {
width: parent.width
spacing: 3
Text {
width: parent.width
text: root.label
color: Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
font.weight: Font.Medium
}
Text {
width: parent.width
visible: root.detail !== ""
text: root.detail
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
wrapMode: Text.WordWrap
}
}
Flow {
width: parent.width
spacing: 7
Repeater {
model: root.options
Rectangle {
id: option
required property var modelData
readonly property bool selected: root.current === option.modelData.value
implicitWidth: Math.max(78, caption.implicitWidth + 26)
implicitHeight: 32
radius: 9
opacity: root.enabled ? 1 : 0.45
color: option.selected ? "transparent" : Theme.alpha(Theme.fg, hover.hovered && root.enabled ? 0.11 : 0.06)
border.width: option.selected ? 1 : 0
border.color: Theme.alpha(Theme.accent, 0.5)
// The prism marks the selection here as everywhere else.
Rectangle {
anchors.fill: parent
radius: parent.radius
visible: option.selected
border.width: 0
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop { position: 0.0; color: Theme.alpha(Theme.accent, 0.28) }
GradientStop { position: 1.0; color: Theme.alpha(Theme.accentSecondary, 0.28) }
}
}
Text {
id: caption
anchors.centerIn: parent
text: option.modelData.label
color: option.selected ? Theme.fg : Theme.fgDim
font.family: Theme.fontFamily
font.features: Theme.tabularFigures
font.pixelSize: Theme.fontSize
font.weight: option.selected ? Font.DemiBold : Font.Normal
}
HoverHandler {
id: hover
enabled: root.enabled
cursorShape: Qt.PointingHandCursor
}
TapHandler {
enabled: root.enabled && !option.selected
onTapped: root.picked(option.modelData.value)
}
}
}
}
Rectangle {
width: parent.width
height: 1
visible: root.divider
color: Theme.alpha(Theme.fg, 0.065)
}
}