123 lines
4.9 KiB
QML
123 lines
4.9 KiB
QML
// Choosing the desktop accent.
|
|
//
|
|
// Each swatch is drawn as the GRADIENT it will actually produce, not a flat
|
|
// dot, because the gradient is the thing being chosen -- the focused window
|
|
// border, the bar hairline and every active state are the two colors meeting.
|
|
// A row of flat circles would misrepresent all of them.
|
|
//
|
|
// Named accents rather than a color wheel: each name carries a curated pair
|
|
// per scheme, so every choice stays legible in both light and dark. See
|
|
// config/Theme.qml for the palette and the reasoning.
|
|
|
|
import QtQuick
|
|
import qs.config
|
|
import qs.services
|
|
|
|
Flow {
|
|
id: root
|
|
|
|
spacing: 10
|
|
|
|
readonly property string current: ThemeProfiles.activeAccentName
|
|
|
|
// The schema's own option list, not Theme.accents directly -- two lists
|
|
// hand-kept in sync is how they drift. This is the same pattern
|
|
// ChoiceRow.qml uses for every other enum row.
|
|
readonly property var spec: PreferenceSchema.spec("accentName")
|
|
readonly property var options: root.spec && root.spec.options ? root.spec.options : []
|
|
|
|
Repeater {
|
|
// The schema's option order is the palette's order, so blue is first
|
|
// because it is what Panama ships.
|
|
model: root.options
|
|
|
|
Column {
|
|
id: entry
|
|
|
|
required property var modelData
|
|
|
|
readonly property string name: entry.modelData.value
|
|
readonly property var pair: Theme.accents[entry.name]
|
|
readonly property bool selected: entry.name === root.current
|
|
readonly property color start: Theme.dark ? entry.pair.dark : entry.pair.light
|
|
readonly property color end: Theme.dark ? entry.pair.darkSecondary : entry.pair.lightSecondary
|
|
|
|
spacing: 5
|
|
|
|
// The hit target is the whole swatch+label unit, not just the
|
|
// 46px circle: the label exists specifically so someone with a
|
|
// color vision deficiency can identify an accent without it, and
|
|
// a label that cannot itself be tapped defeats that.
|
|
HoverHandler {
|
|
cursorShape: Qt.PointingHandCursor
|
|
}
|
|
|
|
TapHandler {
|
|
onTapped: {
|
|
if (!SystemSettings.commitPreference("accentName", entry.name))
|
|
console.warn("AccentPicker: commitPreference rejected accent", entry.name);
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: swatch
|
|
|
|
width: 46
|
|
height: 46
|
|
radius: 23
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
color: "transparent"
|
|
// The ring sits outside the gradient rather than over it, so a
|
|
// selected swatch still shows its true colors.
|
|
border.width: swatch.activeFocus || entry.selected ? 2 : 1
|
|
border.color: swatch.activeFocus
|
|
? Theme.accentSecondary
|
|
: (entry.selected ? Theme.fg : Theme.alpha(Theme.fg, 0.14))
|
|
activeFocusOnTab: true
|
|
|
|
Accessible.role: Accessible.Button
|
|
Accessible.name: entry.pair.label + " accent"
|
|
Accessible.description: String(entry.start) + " to " + String(entry.end)
|
|
Accessible.focusable: true
|
|
Accessible.focused: activeFocus
|
|
|
|
function choose(): void {
|
|
if (!ThemeProfiles.useCuratedAccent(entry.modelData))
|
|
console.warn("AccentPicker: accent was rejected", entry.modelData);
|
|
}
|
|
|
|
Keys.onReturnPressed: swatch.choose()
|
|
Keys.onSpacePressed: swatch.choose()
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
anchors.margins: entry.selected ? 4 : 3
|
|
radius: width / 2
|
|
border.width: 0
|
|
gradient: Gradient {
|
|
orientation: Gradient.Horizontal
|
|
GradientStop { position: 0.0; color: entry.start }
|
|
GradientStop { position: 1.0; color: entry.end }
|
|
}
|
|
}
|
|
|
|
HoverHandler { cursorShape: Qt.PointingHandCursor }
|
|
TapHandler { onTapped: swatch.choose() }
|
|
}
|
|
|
|
// Always shown, not a tooltip. Telling swatches apart by color is
|
|
// exactly what someone with a color vision deficiency cannot do,
|
|
// and it is the reason the palette is named rather than freeform --
|
|
// hiding the names behind a hover would waste that.
|
|
Text {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: entry.modelData.label
|
|
color: entry.selected ? Theme.fg : Theme.fgMuted
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
font.weight: entry.selected ? Font.DemiBold : Font.Normal
|
|
}
|
|
}
|
|
}
|
|
}
|