Files
Marlon Kranzandpurian23 6d331b8fde fix(settings): show what frame mode controls (#3654)
* fix(settings): show what frame mode controls

With frame mode on, many settings did nothing or were hidden while
still applying, and nothing said so. The frame takes its color and
opacity from the first non-island bar, but that bar's Surface card is
hidden while the frame styles it, so neither had a visible control.

Add Background and Override/Opacity rows to the Appearance Frame card,
bound to the same frame bar the renderer reads. Settings the frame
provides in connected mode get a "Managed by Frame in Connected Mode"
note (Interface style border, corner style, background blur and dock
opacity, shadow targets, launcher border); settings with no effect get
"Disabled by Frame Mode" (maximize detection, bar shadow, the bar's
overlay layer in separate mode). Bar size, the bar's overlay layer in
connected mode, dock Over fullscreen and the controls of overlay-layer
docks and launchers are shown again, since they still apply.
Notification Over fullscreen shows as forced on when the frame covers
every display, and launcher rows the Spotlight style ignores are
disabled.

Also relabel the frame Width row as Thickness, raise the inset padding
maximum to its automatic range, and drop a FrameWindow handler for the
removed frameOpacity signal. No new strings.

* settings: show what frame mode controls, fix review findings

---------

Co-authored-by: purian23 <[email protected]>
2026-10-10 00:37:54 -04:00

217 lines
7.1 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import qs.Common
import qs.Services
import qs.DCommon.Widgets
import qs.Widgets
import qs.Modules.Settings.Widgets
Column {
id: root
readonly property bool isSettingsRow: true
property string text: ""
property string description: ""
property string settingKey: ""
property string tab: ""
property var tags: []
property var options: []
property string currentMode: "default"
property color customColor: "#6750A4"
property string pickerTitle: text
property int dropdownWidth: 230
property color defaultColor: Theme.primary
readonly property var optionColorMap: {
var map = {};
for (var i = 0; i < options.length; i++) {
const option = options[i];
map[option.label] = option.previewColor ?? root.colorForValue(option.value);
}
return map;
}
function colorForValue(value) {
switch (value) {
case "custom":
return root.customColor;
case "none":
return "transparent";
case "default":
return root.defaultColor;
default:
return Theme.roleColor(value);
}
}
property alias resetStore: modeRow.resetStore
property alias resetKeys: modeRow.resetKeys
property alias modified: modeRow.modified
property alias resetByKeys: modeRow.resetByKeys
signal resetRequested
signal modeSelected(string mode)
signal customColorSelected(color selectedColor)
width: parent?.width ?? 0
spacing: 0
function optionLabels() {
return options.map(option => option.label);
}
function optionLabel(value) {
for (var i = 0; i < options.length; i++) {
if (options[i].value === value)
return options[i].label;
}
return options.length > 0 ? options[0].label : "";
}
function optionValue(label) {
for (var i = 0; i < options.length; i++) {
if (options[i].label === label)
return options[i].value;
}
return options.length > 0 ? options[0].value : "default";
}
function openCustomColorPicker() {
PopoutService.colorPickerModal.selectedColor = root.customColor;
PopoutService.colorPickerModal.pickerTitle = root.pickerTitle;
PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) {
root.customColorSelected(selectedColor);
root.modeSelected("custom");
};
PopoutService.colorPickerModal.show();
}
SettingsDropdownRow {
id: modeRow
groupItem: root
onResetRequested: root.resetRequested()
text: root.text
description: root.description
tab: root.tab
settingKey: root.settingKey
tags: root.tags
options: root.optionLabels()
optionColorMap: root.optionColorMap
currentValue: root.optionLabel(root.currentMode)
dropdownWidth: root.dropdownWidth
paintBackground: !(root.parent?.isSettingsGroupHost ?? false)
onValueChanged: value => root.modeSelected(root.optionValue(value))
}
Item {
width: parent.width
height: root.currentMode === "custom" ? customChip.y + customChip.height + Theme.spacingM : 0
opacity: root.currentMode === "custom" ? 1 : 0
clip: true
Behavior on height {
NumberAnimation {
duration: SettingsMetrics.transitionDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: Theme.expressiveCurves.expressiveDefaultSpatial
}
}
Behavior on opacity {
NumberAnimation {
duration: SettingsMetrics.fadeDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: Theme.expressiveCurves.expressiveEffects
}
}
Rectangle {
id: customChip
x: SettingsMetrics.rowPaddingH
y: Theme.focusRingOffset
width: parent.width - SettingsMetrics.rowPaddingH * 2
height: Theme.listItemHeight
radius: Theme.cornerRadiusM
color: SettingsMetrics.controlColor
activeFocusOnTab: root.currentMode === "custom"
Accessible.role: Accessible.Button
Accessible.name: I18n.tr("Custom color")
Accessible.onPressAction: root.openCustomColorPicker()
Keys.onSpacePressed: root.openCustomColorPicker()
Keys.onReturnPressed: root.openCustomColorPicker()
Keys.onEnterPressed: root.openCustomColorPicker()
FocusRing {
id: chipRing
}
Row {
anchors.fill: parent
anchors.leftMargin: SettingsMetrics.rowPaddingH
anchors.rightMargin: SettingsMetrics.rowPaddingH
spacing: Theme.spacingM
DColorSwatch {
width: Theme.avatarSize
height: Theme.avatarSize
swatchColor: root.customColor
anchors.verticalCenter: parent.verticalCenter
DIcon {
anchors.centerIn: parent
name: "colorize"
size: Theme.iconSizeSmall
color: Theme.isLightColor(root.customColor) ? Theme.contrastDark : Theme.contrastLight
}
}
Column {
width: parent.width - Theme.avatarSize - editIcon.width - Theme.spacingM * 2
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Custom color")
font.pixelSize: Theme.fontSizeMedium
font.weight: Theme.fontWeightMedium
color: Theme.surfaceText
width: parent.width
horizontalAlignment: Text.AlignLeft
}
StyledText {
text: root.customColor.toString()
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
elide: Text.ElideRight
horizontalAlignment: Text.AlignLeft
}
}
DIcon {
id: editIcon
name: "edit"
size: Theme.iconSizeSmall
color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
}
StateLayer {
stateColor: Theme.surfaceText
cornerRadius: customChip.radius
focused: chipRing.visible
onClicked: {
chipRing.pointerFocused = true;
customChip.forceActiveFocus(Qt.MouseFocusReason);
root.openCustomColorPicker();
}
}
}
}
}