// 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 } } } }