settings: re-org & unify bar sections into updated sub-sections

This commit is contained in:
purian23
2026-09-22 20:41:24 -04:00
parent 7ba4bccf6c
commit a96dea2019
29 changed files with 2303 additions and 2264 deletions
+10
View File
@@ -21,6 +21,16 @@ const DMS_ACTIONS = [
{ id: "spawn dms ipc call island open notificationcenter", label: "DankIsland: Open Notification Center" },
{ id: "spawn dms ipc call island cycle", label: "DankIsland: Cycle Activity" },
{ id: "spawn dms ipc call island close", label: "DankIsland: Close" },
{ id: "spawn dms ipc call dot toggle home", label: "DankDot: Toggle" },
{ id: "spawn dms ipc call dot open home", label: "DankDot: Open Clock" },
{ id: "spawn dms ipc call dot open media", label: "DankDot: Open Media" },
{ id: "spawn dms ipc call dot open launcher", label: "DankDot: Open Launcher" },
{ id: "spawn dms ipc call dot open controlcenter", label: "DankDot: Open Control Center" },
{ id: "spawn dms ipc call dot open wallpaper", label: "DankDot: Open Wallpapers" },
{ id: "spawn dms ipc call dot open weather", label: "DankDot: Open Weather" },
{ id: "spawn dms ipc call dot open notificationcenter", label: "DankDot: Open Notification Center" },
{ id: "spawn dms ipc call dot cycle", label: "DankDot: Cycle Activity" },
{ id: "spawn dms ipc call dot close", label: "DankDot: Close" },
{ id: "spawn dms ipc call defaultApp browser", label: "Default Web Browser: Open" },
{ id: "spawn dms ipc call defaultApp fileManager", label: "Default File Manager: Open" },
{ id: "spawn dms ipc call defaultApp mail", label: "Default Mail: Open" },
+9 -1
View File
@@ -77,9 +77,13 @@ function resolveScreen(inputs, screen, options) {
// Free islands and dots float anywhere on the screen, so they never join an edge band.
const isFree = input => input.config.dot === true || (isIsland(input.config) && (input.islandPlacement ?? input.config.islandPlacement) === "free");
for (const input of enabled.filter(isFree)) {
const dot = input.config.dot === true;
// A free island keeps its satellites in a bar window on its configured edge; that band never reserves or shadows.
const satellites = !dot && (input.islandSatellites ?? input.config.islandSatellitesEnabled ?? true);
instances.push({
key: JSON.stringify([screen.name, input.config.id]), screenName: screen.name,
barId: input.config.id, configOrder: inputs.indexOf(input), edge: "", kind: "island", free: true, dot: input.config.dot === true,
barId: input.config.id, configOrder: inputs.indexOf(input), edge: "", kind: "island", free: true, dot,
satelliteEdge: satellites ? edgeName(input.config.position ?? 0) || "top" : "",
row: 0, rowThickness: 0, rowOffset: 0, reservation: 0, exclusiveZone: -1, exclusionSize: 0,
paintedBounds: { x: 0, y: 0, width: 0, height: 0 }, margins: { top: 0, bottom: 0, left: 0, right: 0 }
});
@@ -185,6 +189,10 @@ function resolveScreen(inputs, screen, options) {
};
}
function hostsBarWindow(instance) {
return instance.free ? !!instance.satelliteEdge : instance.kind === "bar" || instance.kind === "island";
}
function adjacentBar(layout, edge, config) {
if (!layout || config?.autoHide)
return null;
+33
View File
@@ -834,6 +834,7 @@ Singleton {
property var lastUsedBarByScreen: ({})
// One slot per edge; a dot floats, so it never takes one.
readonly property int edgeBarConfigCount: (barConfigs || []).filter(cfg => cfg && !isDotBarConfig(cfg)).length
readonly property var dotBarConfig: (barConfigs || []).find(cfg => isDotBarConfig(cfg)) ?? null
readonly property var islandDefaults: ({
"islandFloating": false,
"islandPlacement": "edge",
@@ -2470,6 +2471,38 @@ Singleton {
return !!bc && bc.dot === true;
}
// The dot is a companion, not a layout: the first enable clones the base bar so it inherits its look.
function setDotEnabled(enabled, baseId) {
const existing = dotBarConfig;
if (existing) {
if ((existing.enabled ?? false) !== enabled)
updateBarConfig(existing.id, {
enabled
});
return;
}
if (!enabled)
return;
const base = getBarConfig(baseId);
const source = base && !isDotBarConfig(base) ? base : getBarConfig("default");
if (!source)
return;
const config = Object.assign(JSON.parse(JSON.stringify(source)), {
id: "dot" + Date.now(),
name: I18n.tr("Dot", "bar layout: free-floating dot that opens island activities"),
enabled: true,
island: false,
dot: true,
screenPreferences: ["all"],
showOnLastDisplay: true,
followInterfaceStyle: false,
transparency: barTransparency(source)
});
// An inherited "always here" would make the base island and the dot fight by config order.
delete config.islandSharedRouting;
addBarConfig(config);
}
function islandFreePlacement(bc) {
return isDotBarConfig(bc) || (islandSetting(bc, "islandFloating") && islandSetting(bc, "islandPlacement") === "free");
}
+10 -21
View File
@@ -86,11 +86,13 @@ Singleton {
"id": "dankbar",
"text": I18n.tr("Bar"),
"icon": "toolbar",
"hint": I18n.tr("Position, appearance, island"),
"aliases": ["dot", "dankdot"],
"hint": I18n.tr("Layout, position, appearance", "settings hub hint for the bar pages"),
"hubHeader": "BarHubHeader",
"children": [
{
"id": "dankbar_settings",
"aliases": ["dank_island", "island"],
"text": I18n.tr("General", "adjective, settings page and section title for general options"),
"icon": "tune",
"tabIndex": 3,
@@ -98,28 +100,19 @@ Singleton {
},
{
"id": "dankbar_appearance",
"aliases": ["frame"],
"text": I18n.tr("Appearance", "settings page and section title for visual options"),
"icon": "palette",
"tabIndex": 6,
"hint": I18n.tr("Background, corners, spacing, widget style")
},
{
"id": "dank_island",
"text": I18n.tr("Island", "noun, dank island feature, settings page and layout option"),
"icon": "view_in_ar",
"tabIndex": 46,
"islandOnly": true,
"titleFrom": "selectedIslandTitle",
"hintFrom": "selectedIslandHint",
"hint": I18n.tr("Home layout, notifications, satellites")
},
{
"id": "frame",
"text": I18n.tr("Frame", "noun, screen frame feature, settings page and layout option"),
"icon": "frame_source",
"tabIndex": 33,
"frameOnly": true,
"hint": I18n.tr("Border, connected mode, arcs")
"id": "dankbar_advanced",
"advanced": true,
"text": I18n.tr("Advanced"),
"icon": "settings",
"tabIndex": 64,
"hint": I18n.tr("Layers, fullscreen, exclusive zone")
}
]
},
@@ -754,10 +747,6 @@ Singleton {
return false;
if (entry.autostartOnly && !DesktopService.autostartAvailable)
return false;
if (entry.frameOnly && !SettingsData.frameEnabled)
return false;
if (entry.islandOnly && !SettingsData.isIslandBarConfig(SettingsData.getBarConfig(SettingsUiState.selectedBarId)))
return false;
if (entry.cellularOnly && (NetworkService.cellularDevices?.length ?? 0) === 0)
return false;
if (entry.kind === "hub" && !entry.hubHeader && visibleLeaves(entry.id).length === 0)
-3
View File
@@ -20,9 +20,6 @@ Singleton {
property string selectedWidgetTitle: ""
property string selectedWidgetDescription: ""
property string selectedWidgetIcon: ""
readonly property bool selectedBarIsDot: SettingsData.isDotBarConfig(SettingsData.getBarConfig(selectedBarId))
readonly property string selectedIslandTitle: selectedBarIsDot ? I18n.tr("Dot", "bar layout: free-floating dot that opens island activities") : I18n.tr("Island", "noun, dank island feature, settings page and layout option")
readonly property string selectedIslandHint: selectedBarIsDot ? I18n.tr("Popups, expand, badge", "settings hub hint for the dot island page") : I18n.tr("Home layout, notifications, satellites")
function normalizeSelectedBar() {
if (SettingsData.getBarConfig(selectedBarId))
+3 -2
View File
@@ -26,7 +26,8 @@ Singleton {
popupThickness: Theme.barThickness(Resolver.option(config, "innerPadding", root.primaryBar, 4), screen.scale),
islandThickness: Resolver.islandThickness(config, SettingsData.islandDefaults),
islandFloating: SettingsData.islandSetting(config, "islandFloating"),
islandPlacement: SettingsData.islandFreePlacement(config) ? "free" : "edge"
islandPlacement: SettingsData.islandFreePlacement(config) ? "free" : "edge",
islandSatellites: SettingsData.islandSetting(config, "islandSatellitesEnabled")
})), screen, {
screens: root.screens,
displayNameMode: SettingsData.displayNameMode,
@@ -78,7 +79,7 @@ Singleton {
}
function hostedScreens(barId) {
return Quickshell.screens.filter(screen => forScreen(screen)?.instances.some(instance => instance.barId === barId && !instance.free && (instance.kind === "bar" || instance.kind === "island")));
return Quickshell.screens.filter(screen => forScreen(screen)?.instances.some(instance => instance.barId === barId && Resolver.hostsBarWindow(instance)));
}
function frameKeys(screen) {
@@ -186,6 +186,7 @@ FocusScope {
"window_rules": "WindowRulesTab.qml",
"dankbar_settings": "DankBarTab.qml",
"dankbar_appearance": "DankBarAppearanceTab.qml",
"dankbar_advanced": "DankBarAdvancedTab.qml",
"bar_widget": "BarWidgetTab.qml",
"compositor_layout": "CompositorLayoutTab.qml",
"dock_general": "DockGeneralTab.qml",
@@ -222,8 +223,6 @@ FocusScope {
"audio": "AudioTab.qml",
"locale": "LocaleTab.qml",
"multiplexers": "MuxTab.qml",
"frame": "FrameTab.qml",
"dank_island": "DankIslandTab.qml",
"users": "UsersTab.qml",
"user_create": "CreateUserTab.qml",
"greeter_auth": "GreeterAuthTab.qml",
@@ -235,7 +234,7 @@ FocusScope {
"plugins_manage": "PluginsManageTab.qml"
})
readonly property var pagesWithParentModal: ["dankbar_widgets", "window_rules", "display_config", "users", "time_weather", "weather", "lock_screen", "greeter", "dank_dash", "wallpaper_cycling", "theme_schedule", "surface_shadows", "keybinds", "dankbar_settings", "dankbar_appearance", "bar_widget", "dock_general", "dock_widgets", "dock_appearance", "dock_advanced", "launcher", "theme", "theme_apps", "media_player", "desktop_widgets", "dank_island", "autostart", "compositor_layout"]
readonly property var pagesWithParentModal: ["dankbar_widgets", "window_rules", "display_config", "users", "time_weather", "weather", "lock_screen", "greeter", "dank_dash", "wallpaper_cycling", "theme_schedule", "surface_shadows", "keybinds", "dankbar_settings", "dankbar_appearance", "bar_widget", "dock_general", "dock_widgets", "dock_appearance", "dock_advanced", "launcher", "theme", "theme_apps", "media_player", "desktop_widgets", "autostart", "compositor_layout"]
Column {
anchors.fill: parent
@@ -181,35 +181,6 @@ DankFloatingWindow {
}
}
Connections {
target: SettingsData
function onFrameEnabledChanged() {
if (!SettingsData.frameEnabled && settingsModal.currentPage === "frame")
settingsModal.setPage("dankbar");
}
function onIslandBarConfigsChanged() {
settingsModal.leaveIslandPageIfHidden();
}
}
function leaveIslandPageIfHidden() {
if (settingsModal.currentPage !== "dank_island")
return;
if (SettingsData.isIslandBarConfig(SettingsData.getBarConfig(SettingsUiState.selectedBarId)))
return;
settingsModal.setPage("dankbar");
}
Connections {
target: SettingsUiState
function onSelectedBarIdChanged() {
settingsModal.leaveIslandPageIfHidden();
}
}
Connections {
target: PluginService
+20 -6
View File
@@ -22,6 +22,8 @@ Item {
readonly property bool barRevealed: inputMask.showing
readonly property bool isIsland: barConfig?.island === true
// A free island's pill lives in IslandFreeHostWindow; this window only carries its satellites.
readonly property bool islandFree: isIsland && SettingsData.islandFreePlacement(barConfig)
readonly property var islandHost: islandLoader.item
readonly property real islandStripThickness: isIsland ? SettingsData.islandStripThickness(barConfig) : 0
readonly property string islandSatellitePosition: isIsland ? SettingsData.islandSetting(barConfig, "islandSatellitePosition") : "edges"
@@ -29,6 +31,16 @@ Item {
readonly property bool islandSatellitesHugIsland: isIsland && islandSatellitePosition === "island"
readonly property real islandSatelliteGap: isIsland ? SettingsData.islandSetting(barConfig, "islandSatelliteGap") : 0
readonly property bool islandSatelliteBackground: isIsland && SettingsData.islandSetting(barConfig, "islandSatelliteBackground")
readonly property color islandSurfaceColor: {
if (islandHost)
return islandHost.surfaceColor;
if (!isIsland)
return Theme.hostSurface;
if (SettingsData.islandSetting(barConfig, "islandHighContrast"))
return Theme.surfaceContainerHighest;
const palette = SettingsData.islandSetting(barConfig, "islandPalette");
return palette === "bright" ? Theme.surfaceBright : palette === "dim" ? Theme.surfaceDim : _hostSurface;
}
readonly property real islandChromePad: isIsland ? Theme.snap((barConfig?.innerPadding ?? 4) + Theme.spacingXS, _dpr) : 0
readonly property real islandChromeInset: islandSatelliteBackground ? islandChromePad : 0
readonly property bool islandMotionRunning: islandHost?.motionRunning ?? false
@@ -49,8 +61,10 @@ Item {
readonly property real contentAlongEnd: (isVertical ? barUnitInset.y + barUnitInset.height - topBarContent.anchors.bottomMargin : barUnitInset.x + barUnitInset.width - topBarContent.anchors.rightMargin)
readonly property real leadingSectionSize: _leftSection ? (isVertical ? _leftSection.implicitHeight : _leftSection.implicitWidth) : 0
readonly property real trailingSectionSize: _rightSection ? (isVertical ? _rightSection.implicitHeight : _rightSection.implicitWidth) : 0
readonly property real islandLeadingOffset: !islandSatellitesHugIsland ? 0 : Math.max(0, islandAlongStart - islandSatelliteGap - islandChromeInset - leadingSectionSize - contentAlongStart)
readonly property real islandTrailingOffset: !islandSatellitesHugIsland ? 0 : Math.max(0, contentAlongEnd - (islandAlongEnd + islandSatelliteGap + islandChromeInset + trailingSectionSize))
readonly property real freeSatelliteSeparation: leadingSectionSize > 0 && trailingSectionSize > 0 ? islandSatelliteGap + islandChromeInset * 2 : 0
readonly property real freeSatelliteStart: ((isVertical ? height : width) - leadingSectionSize - freeSatelliteSeparation - trailingSectionSize) / 2
readonly property real islandLeadingOffset: !islandSatellitesHugIsland ? 0 : Math.max(0, islandFree ? freeSatelliteStart - contentAlongStart : islandAlongStart - islandSatelliteGap - islandChromeInset - leadingSectionSize - contentAlongStart)
readonly property real islandTrailingOffset: !islandSatellitesHugIsland ? 0 : Math.max(0, contentAlongEnd - (islandFree ? freeSatelliteStart + leadingSectionSize + freeSatelliteSeparation + trailingSectionSize : islandAlongEnd + islandSatelliteGap + islandChromeInset + trailingSectionSize))
readonly property var leadingSectionRect: sectionRect(_leftSection, false, _revealProgress + islandLeadingOffset + islandTrailingOffset)
readonly property var trailingSectionRect: sectionRect(_rightSection, false, _revealProgress + islandLeadingOffset + islandTrailingOffset)
@@ -582,7 +596,7 @@ Item {
readonly property bool reserveExclusiveWhenAutoHidden: FrameTransitionState.effectiveFrameEnabled && usesFrameBarChrome && !!barWindow.screen && SettingsData.isScreenInPreferences(barWindow.screen, SettingsData.frameScreenPreferences)
readonly property real surfaceExclusiveZone: isIsland ? ((islandHost?.floating ?? false) ? 0 : islandStripThickness) : (!(barConfig?.visible ?? true) || (topBarCore.autoHide && !barWindow.reserveExclusiveWhenAutoHidden)) ? -1 : (barWindow.effectiveBarThickness + effectiveSpacing + (usesFrameBarChrome ? 0 : (barConfig?.bottomGap ?? 0)))
readonly property real surfaceExclusiveZone: isIsland ? ((islandFree || (islandHost?.floating ?? false)) ? 0 : islandStripThickness) : (!(barConfig?.visible ?? true) || (topBarCore.autoHide && !barWindow.reserveExclusiveWhenAutoHidden)) ? -1 : (barWindow.effectiveBarThickness + effectiveSpacing + (usesFrameBarChrome ? 0 : (barConfig?.bottomGap ?? 0)))
readonly property alias inputMaskItem: inputMask
@@ -926,7 +940,7 @@ Item {
pad: barWindow.islandChromePad
sweep: barWindow.isIsland ? SettingsData.islandSetting(barConfig, "islandSatelliteSwoopRadius") : 0
gothEnabled: barWindow.isIsland && SettingsData.islandSetting(barConfig, "islandSatelliteGothCorners")
fillColor: Theme.withAlpha(barWindow.islandHost?.surfaceColor ?? Theme.hostSurface, barWindow.isIsland ? SettingsData.islandSetting(barConfig, "islandSatelliteTransparency") : 1)
fillColor: Theme.withAlpha(barWindow.islandSurfaceColor, barWindow.isIsland ? SettingsData.islandSetting(barConfig, "islandSatelliteTransparency") : 1)
}
SectionSurface {
@@ -942,7 +956,7 @@ Item {
pad: barWindow.islandChromePad
sweep: barWindow.isIsland ? SettingsData.islandSetting(barConfig, "islandSatelliteSwoopRadius") : 0
gothEnabled: barWindow.isIsland && SettingsData.islandSetting(barConfig, "islandSatelliteGothCorners")
fillColor: Theme.withAlpha(barWindow.islandHost?.surfaceColor ?? Theme.hostSurface, barWindow.isIsland ? SettingsData.islandSetting(barConfig, "islandSatelliteTransparency") : 1)
fillColor: Theme.withAlpha(barWindow.islandSurfaceColor, barWindow.isIsland ? SettingsData.islandSetting(barConfig, "islandSatelliteTransparency") : 1)
}
MouseArea {
@@ -1002,7 +1016,7 @@ Item {
Loader {
id: islandLoader
anchors.fill: parent
active: barWindow.isIsland
active: barWindow.isIsland && !barWindow.islandFree
sourceComponent: IslandBarHost {
barConfig: barWindow.barConfig
screen: barWindow.screen
@@ -62,7 +62,7 @@ Item {
readonly property real freeMargin: Math.max(0, Math.min(64, root.setting("islandFreeEdgeMargin")))
readonly property int compactThickness: root.dotMode ? Math.max(24, Math.min(72, root.dotSize)) : root.islandMetrics.compact
readonly property bool floating: root.setting("islandFloating")
readonly property bool usesOverlayLayer: CompositorService.framePeerSurfacesUseOverlayForScreen(root.screen) || LayerShell.envUsesOverlay("DMS_DANKISLAND_LAYER", root.setting("islandUseOverlayLayer"))
readonly property bool usesOverlayLayer: root.dotMode || CompositorService.framePeerSurfacesUseOverlayForScreen(root.screen) || LayerShell.envUsesOverlay("DMS_DANKISLAND_LAYER", root.setting("islandUseOverlayLayer"))
// A free island's position only picks the orientation; a dot is always a circle.
readonly property bool isVertical: !root.dotMode && SettingsData.islandVertical(root.barConfig)
readonly property string edge: root.freeMode ? (root.isVertical ? "left" : "top") : SettingsData.islandEdge(root.barConfig)
+40 -13
View File
@@ -13,6 +13,8 @@ Column {
property string confirmingRemoveId: ""
property string editingBarId: ""
property string renameDraft: ""
readonly property bool dotSelected: SettingsData.isDotBarConfig(bar.selectedBarConfig)
readonly property bool dotEnabled: SettingsData.dotBarConfig?.enabled ?? false
BarSelectionState {
id: bar
@@ -54,7 +56,7 @@ Column {
delete newBar.island;
delete newBar.dot;
SettingsData.addBarConfig(newBar);
bar.selectedBarId = newId;
bar.select(newId);
}
function canDeleteBar(config) {
@@ -68,7 +70,7 @@ Column {
}
confirmingRemoveId = "";
SettingsData.deleteBarConfig(barId);
bar.selectedBarId = "default";
bar.select("default");
}
function canToggleBar(config) {
@@ -81,16 +83,28 @@ Column {
});
}
function setDotEnabled(enabled) {
SettingsData.setDotEnabled(enabled, bar.selectedBarId);
if (enabled) {
bar.select(SettingsData.dotBarConfig?.id ?? bar.selectedBarId);
return;
}
if (dotSelected)
bar.select(SettingsData.barConfigs.find(config => config.enabled && !SettingsData.isDotBarConfig(config))?.id ?? "default");
}
function barTitle(config) {
return config.name || I18n.tr("Bar %1", "numbered name for an unnamed bar, %1 is its position").arg(SettingsData.barConfigs.indexOf(config) + 1);
}
function barSummary(config) {
const parts = SettingsData.islandFreePlacement(config) ? [I18n.tr("Free", "bar summary: island floats anywhere on the display")] : [bar.positionLabel(config.position ?? SettingsData.Position.Top)];
const parts = SettingsData.islandFreePlacement(config) ? [I18n.tr("Floating", "bar summary: island can be dragged anywhere on the display")] : [bar.positionLabel(config.position ?? SettingsData.Position.Top)];
const prefs = config.screenPreferences || ["all"];
if (prefs.includes("all"))
parts.push(I18n.tr("All displays"));
else
parts.push(prefs.length === 1 ? I18n.tr("%1 display", "singular, bar summary of assigned monitors, %1 is 1").arg(prefs.length) : I18n.tr("%1 displays", "plural, bar summary of assigned monitors, %1 is a count").arg(prefs.length));
if (SettingsData.isDotBarConfig(config))
parts.push(I18n.tr("Dot", "bar summary: free-floating dot layout"));
else if (SettingsData.isIslandBarConfig(config))
if (SettingsData.isIslandBarConfig(config))
parts.push(I18n.tr("Island"));
return parts.join(" • ");
}
@@ -112,22 +126,21 @@ Column {
}
Repeater {
model: SettingsData.barConfigs
model: SettingsData.barConfigs.filter(config => !SettingsData.isDotBarConfig(config))
delegate: SettingsInstanceRow {
required property var modelData
required property int index
title: modelData.name || I18n.tr("Bar %1", "numbered name for an unnamed bar, %1 is its position").arg(index + 1)
title: root.barTitle(modelData)
summary: root.barSummary(modelData)
selected: bar.selectedBarId === modelData.id
checked: modelData.enabled ?? false
toggleVisible: root.canToggleBar(modelData)
deletable: root.canDeleteBar(modelData)
confirmingDelete: root.confirmingRemoveId === modelData.id
onClicked: bar.selectedBarId = modelData.id
onClicked: bar.select(modelData.id)
onToggled: checked => {
bar.selectedBarId = modelData.id;
bar.select(modelData.id);
root.setBarEnabled(modelData.id, checked);
}
onDeleteRequested: root.deleteBar(modelData.id)
@@ -137,7 +150,7 @@ Column {
SettingsRow {
title: I18n.tr("Name")
subtitle: root.editingBarId ? "" : bar.selectedBarName
visible: !!bar.selectedBarConfig
visible: !!bar.selectedBarConfig && !root.dotSelected
DankActionButton {
iconName: root.editingBarId ? "check" : "edit"
@@ -180,11 +193,25 @@ Column {
}
}
SettingsInstanceRow {
title: I18n.tr("Dot", "bar layout: free-floating dot that opens island activities")
summary: I18n.tr("A floating companion that works alongside any bar layout", "bar settings: what the dot is")
settingKey: "dotEnabled"
tags: ["dot", "dankdot", "companion", "floating", "island", "enable"]
clickable: root.dotEnabled
selected: root.dotSelected
checked: root.dotEnabled
deletable: false
onClicked: bar.select(SettingsData.dotBarConfig.id)
onToggled: checked => root.setDotEnabled(checked)
}
SettingsCard {
iconName: "toolbar"
title: I18n.tr("Layout", "noun, settings section title for arrangement options")
settingKey: "barLayout"
tags: ["layout", "standard", "frame", "island", "dot", "mode", "bar"]
visible: !root.dotSelected
tags: ["layout", "standard", "frame", "island", "mode", "bar"]
SettingsLayoutPicker {}
}
@@ -1,5 +1,6 @@
import QtQuick
import qs.Common
import qs.Services
import qs.Modules.Settings.Widgets
Column {
@@ -8,6 +9,14 @@ Column {
property var page: null
readonly property var styleValues: ["icon", "solid", "outline", "ring"]
readonly property var barConfig: {
SettingsData.barConfigs;
return SettingsData.getBarConfig(page?.barId ?? "");
}
readonly property var barStore: ({
"isDefault": keys => keys.every(key => (root.barConfig?.[key] ?? SettingsData.barConfigDefault(key)) === SettingsData.barConfigDefault(key)),
"resetToDefault": keys => SettingsData.updateBarConfig(root.page.barId, Object.fromEntries(keys.map(key => [key, SettingsData.barConfigDefault(key)])))
})
width: parent?.width ?? 0
spacing: Theme.spacingL
@@ -76,5 +85,23 @@ Column {
root.page.set("batteryStyle", root.styleValues[index]);
}
}
SettingsButtonGroupRow {
settingKey: "batteryColorMode"
tags: ["battery", "color", "level", "theme", "icon", "meter", "indicator", "accent", "green", "red"]
text: I18n.tr("Battery")
visible: BatteryService.batteryAvailable && !(root.page?.dockHosted ?? false)
resetStore: root.barStore
resetKeys: ["batteryColorMode"]
model: [I18n.tr("Theme", "battery settings: theme accent indicator colors"), I18n.tr("Level", "battery settings: charge level indicator colors")]
currentIndex: (root.barConfig?.batteryColorMode ?? "theme") === "level" ? 1 : 0
onSelectionChanged: (index, selected) => {
if (!selected)
return;
SettingsData.updateBarConfig(root.page.barId, {
batteryColorMode: index === 1 ? "level" : "theme"
});
}
}
}
}
@@ -9,6 +9,7 @@ Column {
readonly property bool inlineExpansion: page.value("trayUseInlineExpansion")
readonly property bool autoOverflow: page.value("trayAutoOverflow")
readonly property bool trayTinted: ["primary", "secondary"].includes(SettingsData.systemTrayIconTintMode || "none")
width: parent?.width ?? 0
spacing: Theme.spacingL
@@ -64,5 +65,43 @@ Column {
unit: "px"
onSliderValueChanged: newValue => root.page.set("trayIconSpacing", newValue)
}
SettingsButtonGroupRow {
readonly property var modes: ["none", "monochrome", "primary", "secondary"]
settingKey: "trayIconTint"
tags: ["tray", "icon", "tint", "monochrome", "system tray", "color"]
text: I18n.tr("Tray icon tint")
resetKeys: ["systemTrayIconTintMode"]
model: [I18n.tr("None"), I18n.tr("Monochrome"), I18n.tr("Primary"), I18n.tr("Secondary")]
currentIndex: Math.max(0, modes.indexOf(SettingsData.systemTrayIconTintMode || "none"))
onSelectionChanged: (index, selected) => {
if (!selected)
return;
SettingsData.set("systemTrayIconTintMode", modes[index]);
}
}
SettingsSliderRow {
text: I18n.tr("Tint saturation")
tags: ["tray", "tint", "saturation"]
visible: root.trayTinted
resetKeys: ["systemTrayIconTintSaturation"]
value: SettingsData.systemTrayIconTintSaturation ?? 50
minimum: 0
maximum: 100
onSliderDragFinished: finalValue => SettingsData.set("systemTrayIconTintSaturation", finalValue)
}
SettingsSliderRow {
text: I18n.tr("Tint strength")
tags: ["tray", "tint", "strength"]
visible: root.trayTinted
resetKeys: ["systemTrayIconTintStrength"]
value: SettingsData.systemTrayIconTintStrength ?? 135
minimum: 0
maximum: 200
onSliderDragFinished: finalValue => SettingsData.set("systemTrayIconTintStrength", finalValue)
}
}
}
@@ -0,0 +1,192 @@
import QtQuick
import qs.Common
import qs.Services
import qs.Modules.Settings.Widgets
Item {
id: root
LayoutMirroring.enabled: I18n.isRtl
LayoutMirroring.childrenInherit: true
readonly property bool isDot: SettingsData.isDotBarConfig(bar.selectedBarConfig)
BarSelectionState {
id: bar
}
SettingsPage {
id: mainColumn
SettingsCard {
iconName: "tune"
title: I18n.tr("Behavior")
settingKey: "barAdvanced"
tags: ["bar", "advanced", "overlay", "layer", "click", "through", "maximize", "island", "spring", "motion"]
visible: bar.selectedBarConfig?.enabled ?? false
SettingsToggleRow {
settingKey: "barClickThrough"
resetStore: bar
resetKeys: ["clickThrough"]
tags: ["clickthrough", "click", "through", "mouse", "input", "mask", "passthrough"]
visible: !bar.islandOwnsSelectedBarTop
text: I18n.tr("Click through")
checked: bar.selectedBarConfig?.clickThrough ?? false
onToggled: toggled => SettingsData.updateBarConfig(bar.selectedBarId, {
clickThrough: toggled
})
}
SettingsToggleRow {
settingKey: "barUseOverlayLayer"
resetStore: bar
resetKeys: ["useOverlayLayer"]
tags: ["bar", "fullscreen", "overlay", "layer"]
visible: !bar.islandOwnsSelectedBarTop
text: I18n.tr("Use overlay layer")
checked: bar.selectedBarConfig?.useOverlayLayer ?? false
onToggled: toggled => {
SettingsData.updateBarConfig(bar.selectedBarId, {
useOverlayLayer: toggled
});
bar.notifyHorizontalBarChange();
}
}
SettingsToggleRow {
settingKey: "islandUseOverlayLayer"
tags: ["island", "fullscreen", "overlay", "layer"]
visible: bar.selectedBarIsIsland && !root.isDot
resetStore: bar
resetKeys: ["islandUseOverlayLayer"]
text: I18n.tr("Use overlay layer")
checked: bar.islandSetting("islandUseOverlayLayer")
onToggled: checked => bar.apply("islandUseOverlayLayer", checked)
}
SettingsToggleRow {
settingKey: "islandReducedMotion"
tags: ["island", "motion", "animation", "reduce", "accessibility", "spring"]
visible: bar.selectedBarIsIsland
resetStore: bar
resetKeys: ["islandReducedMotion"]
text: I18n.tr("Reduce motion")
checked: bar.islandSetting("islandReducedMotion")
onToggled: checked => bar.apply("islandReducedMotion", checked)
}
SettingsSliderRow {
settingKey: "islandSpringStiffness"
tags: ["island", "motion", "spring", "stiffness", "animation"]
visible: bar.selectedBarIsIsland
resetStore: bar
resetKeys: ["islandSpringStiffness"]
text: I18n.tr("Spring stiffness", "island settings: spring stiffness slider")
unit: ""
minimum: 100
maximum: 1200
step: 10
value: Math.round(bar.islandSetting("islandSpringStiffness"))
enabled: !bar.islandSetting("islandReducedMotion")
onSliderValueChanged: value => bar.apply("islandSpringStiffness", value)
}
SettingsSliderRow {
settingKey: "islandSpringDamping"
tags: ["island", "motion", "spring", "damping", "bounce", "animation"]
visible: bar.selectedBarIsIsland
resetStore: bar
resetKeys: ["islandSpringDamping"]
text: I18n.tr("Spring damping", "island settings: spring damping slider")
unit: ""
minimum: 10
maximum: 100
step: 1
value: Math.round(bar.islandSetting("islandSpringDamping"))
enabled: !bar.islandSetting("islandReducedMotion")
onSliderValueChanged: value => bar.apply("islandSpringDamping", value)
}
SettingsSliderRow {
settingKey: "islandSpringMass"
tags: ["island", "motion", "spring", "mass", "inertia", "animation"]
visible: bar.selectedBarIsIsland
resetStore: bar
resetKeys: ["islandSpringMass"]
text: I18n.tr("Spring mass", "island settings: spring mass slider")
minimum: 25
maximum: 300
step: 5
unit: ""
decimals: 2
value: Math.round(bar.islandSetting("islandSpringMass") * 100)
enabled: !bar.islandSetting("islandReducedMotion")
onSliderValueChanged: value => bar.apply("islandSpringMass", value / 100)
}
SettingsToggleRow {
settingKey: "barMaximizeDetection"
resetStore: bar
resetKeys: ["maximizeDetection"]
tags: ["maximize", "gaps", "border", "fullscreen"]
visible: CompositorService.supportsBarAutoHideReveal && !root.isDot
text: I18n.tr("Maximize detection")
checked: bar.selectedBarConfig?.maximizeDetection ?? true
onToggled: toggled => SettingsData.updateBarConfig(bar.selectedBarId, {
maximizeDetection: toggled
})
}
}
SettingsCard {
iconName: "space_bar"
title: I18n.tr("Gaps")
settingKey: "barAppearanceAdvanced"
tags: ["bar", "advanced", "exclusive", "zone", "popup", "gaps"]
visible: (bar.selectedBarConfig?.enabled ?? false) && !bar.selectedBarFrameStyled && !root.isDot
SettingsSliderRow {
settingKey: "barExclusiveZone"
tags: ["exclusive", "zone", "reserved", "offset"]
visible: !bar.islandOwnsSelectedBarTop
text: I18n.tr("Exclusive zone offset")
resetStore: bar
resetKeys: ["bottomGap"]
value: bar.selectedBarConfig?.bottomGap ?? 0
minimum: -50
maximum: 50
unit: "px"
onSliderDragFinished: finalValue => SettingsData.updateBarConfig(bar.selectedBarId, {
bottomGap: finalValue
})
}
SettingsToggleRow {
text: I18n.tr("Auto popup gaps")
tags: ["popup", "gaps", "auto"]
resetStore: bar
resetKeys: ["popupGapsAuto"]
checked: bar.selectedBarConfig?.popupGapsAuto ?? true
onToggled: checked => SettingsData.updateBarConfig(bar.selectedBarId, {
popupGapsAuto: checked
})
}
SettingsSliderRow {
visible: !(bar.selectedBarConfig?.popupGapsAuto ?? true)
text: I18n.tr("Gap size")
tags: ["popup", "gaps", "size"]
resetStore: bar
resetKeys: ["popupGapsManual"]
unit: "px"
value: bar.selectedBarConfig?.popupGapsManual ?? 4
minimum: 0
maximum: 50
onSliderDragFinished: finalValue => SettingsData.updateBarConfig(bar.selectedBarId, {
popupGapsManual: finalValue
})
}
}
}
}
@@ -14,11 +14,15 @@ Item {
property var parentModal: null
readonly property bool widgetBackgroundEnabled: !(bar.selectedBarConfig?.noBackground ?? false)
readonly property bool trayTinted: ["primary", "secondary"].includes(SettingsData.systemTrayIconTintMode || "none")
readonly property var outlineColors: ["surfaceText", "secondary", "primary"]
readonly property var outlineColorLabels: [I18n.tr("Surface"), I18n.tr("Secondary"), I18n.tr("Primary")]
readonly property var paletteValues: ["default", "bright", "dim"]
readonly property var batteryStyleValues: ["solid", "outline", "ring"]
readonly property var satellitePositionValues: ["island", "edges"]
readonly property bool isDot: SettingsData.isDotBarConfig(bar.selectedBarConfig)
readonly property bool selectedIslandEnabled: bar.selectedBarIsIsland && (bar.selectedBarConfig?.enabled ?? false)
readonly property bool selectedIslandFree: bar.selectedBarIsIsland && SettingsData.islandFreePlacement(bar.selectedBarConfig)
readonly property int frameInsetPaddingDisplay: Math.round(SettingsData.frameBarContentGap)
function valueIndex(values, value, fallback) {
const index = values.indexOf(value);
@@ -32,12 +36,112 @@ Item {
SettingsPage {
id: mainColumn
SettingsCard {
iconName: "border_outer"
title: I18n.tr("Frame")
settingKey: "frameBorder"
collapsible: true
visible: !root.isDot && SettingsData.frameEnabled
SettingsSliderRow {
settingKey: "frameRounding"
tags: ["frame", "border", "rounding", "radius", "corner"]
text: I18n.tr("Radius", "corner radius slider label")
unit: "px"
minimum: 0
maximum: 100
step: 1
value: SettingsData.frameRounding
onSliderDragFinished: v => SettingsData.set("frameRounding", v)
}
SettingsSliderRow {
settingKey: "frameThickness"
tags: ["frame", "border", "thickness", "size", "width"]
text: I18n.tr("Width")
unit: "px"
minimum: 2
maximum: 100
step: 1
value: SettingsData.frameThickness
onSliderDragFinished: v => SettingsData.set("frameThickness", v)
}
SettingsSliderRow {
settingKey: "frameBarSize"
tags: ["frame", "bar", "thickness", "size", "height", "width"]
text: I18n.tr("Bar size")
unit: "px"
minimum: 24
maximum: 100
step: 1
value: SettingsData.frameBarSize
onSliderDragFinished: v => SettingsData.set("frameBarSize", v)
}
SettingsSliderRow {
settingKey: "frameBarInsetPadding"
tags: ["frame", "bar", "edge", "inset", "padding", "corner", "end"]
text: I18n.tr("Bar inset padding")
minimumLabel: I18n.tr("Edge to edge", "slider minimum label, bar touches the screen edges")
unit: "px"
minimum: 0
maximum: 48
step: 1
value: root.frameInsetPaddingDisplay
onSliderDragFinished: v => SettingsData.set("frameBarInsetPadding", v)
}
SettingsToggleRow {
id: frameBlurToggle
settingKey: "frameBlurEnabled"
tags: ["frame", "blur", "background", "glass", "transparency", "frosted"]
text: I18n.tr("Blur")
checked: SettingsData.frameBlurEnabled
onToggled: checked => SettingsData.set("frameBlurEnabled", checked)
enabled: BlurService.available && SettingsData.blurEnabled
visible: BlurService.available
}
SettingsRow {
visible: BlurService.available && !SettingsData.blurEnabled
body: Item {
width: parent.width
height: blurToggleNote.height + Theme.spacingM * 2
Row {
id: blurToggleNote
x: Theme.spacingM
width: parent.width - Theme.spacingM * 2
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: "blur_on"
size: Theme.fontSizeMedium
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Frame Blur follows Background Blur in Theme & Colors")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width - Theme.fontSizeMedium - Theme.spacingS
}
}
}
}
}
SettingsCard {
iconName: "rounded_corner"
title: I18n.tr("Bar")
title: !root.isDot ? I18n.tr("Bar") : I18n.tr("Dot", "bar layout: free-floating dot that opens island activities")
settingKey: "barCorners"
tags: ["background", "opacity", "corners", "rounded", "goth", "shadow"]
visible: (bar.selectedBarConfig?.enabled ?? false) && !bar.selectedBarFrameStyled
// Frame styling never reaches the dot's surface, which always paints its own palette and background.
visible: (bar.selectedBarConfig?.enabled ?? false) && (root.isDot || !bar.selectedBarFrameStyled)
SettingsButtonGroupRow {
settingKey: "islandPalette"
@@ -71,7 +175,7 @@ Item {
resetStore: bar
resetKeys: ["islandBatteryStyle"]
text: I18n.tr("Battery style", "island settings: battery meter style row")
visible: bar.selectedBarIsIsland && !SettingsData.isDotBarConfig(bar.selectedBarConfig) && SettingsData.islandHomeGroupEnabled(bar.selectedBarConfig, "status") && BatteryService.batteryAvailable && SettingsData.islandHomeStatusContent(bar.selectedBarConfig) === "battery"
visible: bar.selectedBarIsIsland && !root.isDot && SettingsData.islandHomeGroupEnabled(bar.selectedBarConfig, "status") && BatteryService.batteryAvailable && SettingsData.islandHomeStatusContent(bar.selectedBarConfig) === "battery"
model: [I18n.tr("Solid", "island settings: filled battery meter style"), I18n.tr("Outline", "island settings: outlined battery meter style"), I18n.tr("Circle", "island settings: circular battery meter style")]
currentIndex: root.valueIndex(root.batteryStyleValues, bar.islandSetting("islandBatteryStyle"), "solid")
onSelectionChanged: (index, selected) => {
@@ -80,10 +184,25 @@ Item {
}
}
SettingsButtonGroupRow {
settingKey: "islandBatteryColorMode"
tags: ["island", "battery", "color", "level", "theme", "meter", "accent", "green", "red"]
resetStore: bar
resetKeys: ["batteryColorMode"]
text: I18n.tr("Battery")
visible: bar.selectedBarIsIsland && !root.isDot && SettingsData.islandHomeGroupEnabled(bar.selectedBarConfig, "status") && BatteryService.batteryAvailable && SettingsData.islandHomeStatusContent(bar.selectedBarConfig) === "battery"
model: [I18n.tr("Theme", "battery settings: theme accent indicator colors"), I18n.tr("Level", "battery settings: charge level indicator colors")]
currentIndex: (bar.selectedBarConfig?.batteryColorMode ?? "theme") === "level" ? 1 : 0
onSelectionChanged: (index, selected) => {
if (selected)
bar.apply("batteryColorMode", index === 1 ? "level" : "theme");
}
}
SurfaceColorRow {
settingKey: "barSurfaceColor"
tags: ["background", "color", "surface", "bar", "material"]
visible: !bar.selectedBarFrameStyled
visible: root.isDot || !bar.selectedBarFrameStyled
resetStore: bar
resetKeys: ["surfaceColor", "surfaceCustomColor"]
text: I18n.tr("Background")
@@ -96,13 +215,46 @@ Item {
}
SettingsControlledBy {
visible: !bar.selectedBarFrameStyled && !bar.islandOwnsSelectedBarTop
visible: !root.isDot && !bar.selectedBarFrameStyled && !bar.islandOwnsSelectedBarTop
target: "surfaces"
parentModal: root.parentModal
section: "surfaceOpacity_bar_" + bar.selectedBarId
settingLabel: I18n.tr("Opacity")
}
SettingsSliderRow {
settingKey: "dotOpacity"
tags: ["dot", "opacity", "transparency", "background"]
visible: root.isDot
resetStore: bar
resetKeys: ["transparency"]
text: I18n.tr("Opacity")
minimum: 0
maximum: 100
step: 1
value: Math.round(SettingsData.barTransparency(bar.selectedBarConfig) * 100)
onSliderDragFinished: finalValue => SettingsData.updateBarConfig(bar.selectedBarId, {
followInterfaceStyle: false,
transparency: finalValue / 100
})
}
SettingsSliderRow {
settingKey: "islandFreeIdleOpacity"
tags: ["island", "free", "dot", "idle", "opacity", "fade"]
visible: root.isDot
resetStore: bar
resetKeys: ["islandFreeIdleOpacity"]
text: I18n.tr("Idle opacity", "island settings: dot opacity while idle")
unit: "%"
minimum: 5
maximum: 100
step: 1
value: Math.round(bar.islandSetting("islandFreeIdleOpacity") * 100)
enabled: bar.islandSetting("islandFreeIdleDelay") > 0
onSliderValueChanged: value => bar.apply("islandFreeIdleOpacity", value / 100)
}
SettingsButtonGroupRow {
settingKey: "barCornerStyle"
tags: ["rounded", "attached", "square", "corners", "edge", "screen", "flush"]
@@ -229,20 +381,73 @@ Item {
}
}
SettingsControlledBy {
visible: (bar.selectedBarConfig?.enabled ?? false) && bar.selectedBarFrameSanitized && !bar.islandOwnsSelectedBarTop
parentModal: root.parentModal
section: "frameBorder"
settingLabel: I18n.tr("Bar surface and spacing")
reason: SettingsData.connectedFrameModeActive ? I18n.tr("Managed by Frame in Connected Mode") : I18n.tr("Managed by Frame")
}
SettingsCard {
iconName: "space_bar"
title: I18n.tr("Size & spacing")
settingKey: "barSpacing"
tags: ["size", "scale", "font", "icon", "spacing", "padding", "inset", "length"]
visible: bar.selectedBarConfig?.enabled ?? false
visible: (bar.selectedBarConfig?.enabled ?? false) && !root.isDot
SettingsSliderRow {
settingKey: "islandReserveThickness"
tags: ["island", "placement", "reservation", "exclusive", "height", "width", "thickness"]
visible: bar.selectedBarIsIsland && !root.selectedIslandFree
resetStore: bar
resetKeys: ["islandReserveThickness"]
text: bar.selectedBarIsVertical ? I18n.tr("Reserved width", "island settings: reserved strip width slider") : I18n.tr("Reserved height", "island settings: reserved strip height slider")
unit: "px"
minimum: 24
maximum: 128
step: 1
value: bar.islandSetting("islandReserveThickness")
enabled: !bar.islandSetting("islandFloating")
onSliderValueChanged: value => bar.apply("islandReserveThickness", value)
}
SettingsSliderRow {
settingKey: "islandCompactThickness"
tags: ["island", "placement", "compact", "height", "width", "thickness", "size", "satellite"]
visible: bar.selectedBarIsIsland && !root.selectedIslandFree
resetStore: bar
resetKeys: ["islandCompactThickness"]
text: bar.selectedBarIsVertical ? I18n.tr("Compact width", "island settings: compact pill width slider") : I18n.tr("Compact height", "island settings: compact pill height slider")
unit: "px"
minimum: 24
maximum: 72
step: 1
value: bar.islandSetting("islandCompactThickness")
onSliderValueChanged: value => bar.apply("islandCompactThickness", value)
}
SettingsSliderRow {
settingKey: "islandOuterGap"
tags: ["island", "placement", "gap", "top", "margin"]
visible: bar.selectedBarIsIsland && !root.selectedIslandFree
resetStore: bar
resetKeys: ["islandOuterGap"]
text: I18n.tr("Outer gap", "island settings: gap between screen edge and island")
unit: "px"
minimum: 0
maximum: 48
step: 1
value: bar.islandSetting("islandOuterGap")
onSliderValueChanged: value => bar.apply("islandOuterGap", value)
}
SettingsSliderRow {
settingKey: "islandAlongOffset"
tags: ["island", "placement", "horizontal", "vertical", "offset", "center"]
visible: bar.selectedBarIsIsland && !root.selectedIslandFree
resetStore: bar
resetKeys: ["islandAlongOffset"]
text: bar.selectedBarIsVertical ? I18n.tr("Vertical offset", "island settings: vertical offset slider") : I18n.tr("Horizontal offset", "island settings: horizontal offset slider")
unit: "px"
minimum: -600
maximum: 600
step: 1
value: bar.islandSetting("islandAlongOffset")
onSliderValueChanged: value => bar.apply("islandAlongOffset", value)
}
SettingsSliderRow {
settingKey: "barSize"
@@ -385,12 +590,116 @@ Item {
}
}
SettingsCard {
iconName: "widgets"
title: I18n.tr("Satellites", "island settings: satellite widgets card title")
settingKey: "islandSatellites"
collapsible: true
expanded: true
visible: root.selectedIslandEnabled && !root.isDot
SettingsToggleRow {
settingKey: "islandSatellitesEnabled"
tags: ["island", "satellite", "widgets", "left", "right"]
resetStore: bar
resetKeys: ["islandSatellitesEnabled"]
text: I18n.tr("Show", "island settings: satellite widgets toggle")
checked: bar.islandSetting("islandSatellitesEnabled")
onToggled: checked => bar.apply("islandSatellitesEnabled", checked)
}
SettingsButtonGroupRow {
settingKey: "islandSatellitePosition"
tags: ["island", "satellite", "widgets", "position", "edges", "center"]
resetStore: bar
resetKeys: ["islandSatellitePosition"]
text: I18n.tr("Position", "island settings: position card title")
model: [I18n.tr("Near island", "island settings: satellites hug the island"), I18n.tr("Display edges", "island settings: satellites sit at screen edges")]
currentIndex: root.valueIndex(root.satellitePositionValues, bar.islandSetting("islandSatellitePosition"), "island")
enabled: bar.islandSetting("islandSatellitesEnabled")
onSelectionChanged: (index, selected) => {
if (selected)
bar.apply("islandSatellitePosition", root.satellitePositionValues[index] ?? "island");
}
}
SettingsToggleRow {
settingKey: "islandSatelliteBackground"
tags: ["island", "satellite", "widgets", "background", "chrome"]
resetStore: bar
resetKeys: ["islandSatelliteBackground"]
text: I18n.tr("Background", "island settings: satellite background toggle")
checked: bar.islandSetting("islandSatelliteBackground")
visible: bar.islandSetting("islandSatellitesEnabled")
onToggled: checked => bar.apply("islandSatelliteBackground", checked)
}
SettingsToggleRow {
settingKey: "islandSatelliteGothCorners"
tags: ["island", "satellite", "goth", "corners", "wing", "sweep"]
resetStore: bar
resetKeys: ["islandSatelliteGothCorners"]
text: I18n.tr("Goth corners", "island settings: satellite goth corners toggle")
checked: bar.islandSetting("islandSatelliteGothCorners")
visible: bar.islandSetting("islandSatellitesEnabled")
enabled: bar.islandSetting("islandSatelliteBackground")
onToggled: checked => bar.apply("islandSatelliteGothCorners", checked)
}
SettingsSliderRow {
settingKey: "islandSatelliteSwoopRadius"
tags: ["island", "satellite", "goth", "corners", "radius", "sweep", "size"]
resetStore: bar
resetKeys: ["islandSatelliteSwoopRadius"]
text: I18n.tr("Goth corner radius", "island settings: satellite goth corner radius slider")
unit: "px"
minimum: 4
maximum: 64
step: 1
value: bar.islandSetting("islandSatelliteSwoopRadius")
visible: bar.islandSetting("islandSatellitesEnabled")
enabled: bar.islandSetting("islandSatelliteBackground") && bar.islandSetting("islandSatelliteGothCorners")
onSliderValueChanged: value => bar.apply("islandSatelliteSwoopRadius", value)
}
SettingsSliderRow {
settingKey: "islandSatelliteTransparency"
tags: ["island", "satellite", "background", "opacity", "transparency", "blur"]
resetStore: bar
resetKeys: ["islandSatelliteTransparency"]
text: I18n.tr("Opacity", "island settings: satellite background opacity slider")
minimum: 0
maximum: 100
step: 1
value: Math.round(bar.islandSetting("islandSatelliteTransparency") * 100)
visible: bar.islandSetting("islandSatellitesEnabled")
enabled: bar.islandSetting("islandSatelliteBackground")
onSliderValueChanged: value => bar.apply("islandSatelliteTransparency", value / 100)
}
SettingsSliderRow {
settingKey: "islandSatelliteGap"
tags: ["island", "satellite", "widgets", "gap", "spacing"]
resetStore: bar
resetKeys: ["islandSatelliteGap"]
text: I18n.tr("Gap", "island settings: satellite to island gap slider")
unit: "px"
minimum: 4
maximum: 48
step: 1
value: bar.islandSetting("islandSatelliteGap")
visible: bar.islandSetting("islandSatellitesEnabled")
enabled: bar.islandSetting("islandSatellitePosition") !== "edges"
onSliderValueChanged: value => bar.apply("islandSatelliteGap", value)
}
}
SettingsCard {
iconName: "widgets"
title: I18n.tr("Widgets")
settingKey: "barWidgets"
tags: ["widget", "style", "pills", "segments", "opacity", "padding", "maximize"]
visible: bar.selectedBarConfig?.enabled ?? false
visible: (bar.selectedBarConfig?.enabled ?? false) && !root.isDot
SettingsRow {
settingKey: "barWidgetStyle"
@@ -492,7 +801,7 @@ Item {
settingKey: "barWidgetOutline"
iconName: "highlight"
title: I18n.tr("Widget outline")
visible: bar.selectedBarConfig?.enabled ?? false
visible: (bar.selectedBarConfig?.enabled ?? false) && !root.isDot
enabled: root.widgetBackgroundEnabled
resetStore: bar
resetKeys: ["widgetOutlineEnabled"]
@@ -550,6 +859,7 @@ Item {
title: I18n.tr("Widget colors")
settingKey: "widgetStyling"
tags: ["widget", "background", "color", "colorful", "text", "all", "bars"]
visible: !root.isDot
WidgetTextStyleRow {}
@@ -561,119 +871,5 @@ Item {
enabled: root.widgetBackgroundEnabled
}
}
SettingsCard {
iconName: "palette"
title: I18n.tr("Icons")
settingKey: "trayIconTint"
tags: ["icon", "tray", "tint", "battery", "color"]
visible: bar.selectedBarConfig?.enabled ?? false
SettingsButtonGroupRow {
settingKey: "batteryColorMode"
tags: ["battery", "color", "level", "theme", "icon", "meter", "indicator", "accent", "green", "red"]
text: I18n.tr("Battery")
visible: BatteryService.batteryAvailable
resetStore: bar
resetKeys: ["batteryColorMode"]
model: [I18n.tr("Theme", "battery settings: theme accent indicator colors"), I18n.tr("Level", "battery settings: charge level indicator colors")]
currentIndex: (bar.selectedBarConfig?.batteryColorMode ?? "theme") === "level" ? 1 : 0
onSelectionChanged: (index, selected) => {
if (!selected)
return;
SettingsData.updateBarConfig(bar.selectedBarId, {
batteryColorMode: index === 1 ? "level" : "theme"
});
}
}
SettingsButtonGroupRow {
readonly property var modes: ["none", "monochrome", "primary", "secondary"]
tags: ["tray", "icon", "tint", "monochrome", "system tray"]
text: I18n.tr("Tray icon tint")
resetKeys: ["systemTrayIconTintMode"]
model: [I18n.tr("None"), I18n.tr("Monochrome"), I18n.tr("Primary"), I18n.tr("Secondary")]
currentIndex: Math.max(0, modes.indexOf(SettingsData.systemTrayIconTintMode || "none"))
onSelectionChanged: (index, selected) => {
if (!selected)
return;
SettingsData.set("systemTrayIconTintMode", modes[index]);
}
}
SettingsSliderRow {
text: I18n.tr("Tint saturation")
tags: ["tray", "tint", "saturation"]
visible: root.trayTinted
resetKeys: ["systemTrayIconTintSaturation"]
value: SettingsData.systemTrayIconTintSaturation ?? 50
minimum: 0
maximum: 100
onSliderDragFinished: finalValue => SettingsData.set("systemTrayIconTintSaturation", finalValue)
}
SettingsSliderRow {
text: I18n.tr("Tint strength")
tags: ["tray", "tint", "strength"]
visible: root.trayTinted
resetKeys: ["systemTrayIconTintStrength"]
value: SettingsData.systemTrayIconTintStrength ?? 135
minimum: 0
maximum: 200
onSliderDragFinished: finalValue => SettingsData.set("systemTrayIconTintStrength", finalValue)
}
}
SettingsCard {
title: I18n.tr("Advanced")
settingKey: "barAppearanceAdvanced"
tags: ["bar", "advanced", "exclusive", "zone", "popup", "gaps"]
collapsible: true
expanded: false
visible: (bar.selectedBarConfig?.enabled ?? false) && !bar.selectedBarFrameStyled
SettingsSliderRow {
settingKey: "barExclusiveZone"
tags: ["exclusive", "zone", "reserved", "offset"]
visible: !bar.islandOwnsSelectedBarTop
text: I18n.tr("Exclusive zone offset")
resetStore: bar
resetKeys: ["bottomGap"]
value: bar.selectedBarConfig?.bottomGap ?? 0
minimum: -50
maximum: 50
unit: "px"
onSliderDragFinished: finalValue => SettingsData.updateBarConfig(bar.selectedBarId, {
bottomGap: finalValue
})
}
SettingsToggleRow {
text: I18n.tr("Auto popup gaps")
tags: ["popup", "gaps", "auto"]
resetStore: bar
resetKeys: ["popupGapsAuto"]
checked: bar.selectedBarConfig?.popupGapsAuto ?? true
onToggled: checked => SettingsData.updateBarConfig(bar.selectedBarId, {
popupGapsAuto: checked
})
}
SettingsSliderRow {
visible: !(bar.selectedBarConfig?.popupGapsAuto ?? true)
text: I18n.tr("Gap size")
tags: ["popup", "gaps", "size"]
resetStore: bar
resetKeys: ["popupGapsManual"]
unit: "px"
value: bar.selectedBarConfig?.popupGapsManual ?? 4
minimum: 0
maximum: 50
onSliderDragFinished: finalValue => SettingsData.updateBarConfig(bar.selectedBarId, {
popupGapsManual: finalValue
})
}
}
}
}
+281 -241
View File
@@ -12,18 +12,20 @@ Item {
LayoutMirroring.childrenInherit: true
property var parentModal: null
BarSelectionState {
id: bar
}
readonly property var interactionModeValues: ["click", "hybrid"]
readonly property var routingValues: ["normal", "always", "last-used"]
readonly property var placementValues: ["edge", "free"]
readonly property bool selectedBarIsDot: SettingsData.isDotBarConfig(bar.selectedBarConfig)
readonly property var clockDisplayValues: ["time", "date", "both"]
readonly property var systemLevelDisplayValues: ["icon", "percentage", "both"]
readonly property var statusContentValues: ["battery", "connectivity"]
readonly property bool isDot: SettingsData.isDotBarConfig(bar.selectedBarConfig)
readonly property bool selectedIslandEnabled: bar.selectedBarIsIsland && (bar.selectedBarConfig?.enabled ?? false)
readonly property bool selectedIslandFree: bar.selectedBarIsIsland && SettingsData.islandFreePlacement(bar.selectedBarConfig)
readonly property bool selectedIslandEdgeOrFree: bar.selectedBarIsIsland && !selectedBarIsDot
readonly property bool selectedIslandAnywhere: selectedIslandFree && !selectedBarIsDot
readonly property bool selectedIslandFloating: selectedIslandFree && !isDot
readonly property int placementIndex: !bar.islandSetting("islandFloating") ? 0 : (bar.islandSetting("islandPlacement") === "free" ? 2 : 1)
function valueIndex(values, value, fallback) {
const index = values.indexOf(value);
@@ -62,25 +64,10 @@ Item {
subtitle: I18n.tr("The Island holds this edge on a display this bar covers, so the bar stays hidden there")
}
SettingsDropdownRow {
id: sharedRouting
settingKey: "islandSharedRouting"
tags: ["dot", "island", "routing", "launcher", "dash", "control center", "ipc", "last used"]
visible: bar.selectedBarIsIsland
resetStore: bar
resetKeys: ["islandSharedRouting"]
text: I18n.tr("Shared shortcuts")
description: I18n.tr("Routes launcher, dash, control center and notification shortcuts")
options: [I18n.tr("Normal routing"), I18n.tr("Always here"), I18n.tr("Last used on this screen")]
dropdownWidth: Theme.smallBreakpoint / 2
currentValue: options[dankBarTab.valueIndex(dankBarTab.routingValues, SettingsData.islandSharedRoutingMode(bar.selectedBarConfig), "normal")]
onValueChanged: value => SettingsData.setIslandSharedRouting(bar.selectedBarId, dankBarTab.routingValues[options.indexOf(value)] ?? "normal")
}
SettingsButtonGroupRow {
settingKey: "islandFreeOrientation"
tags: ["island", "free", "orientation", "horizontal", "vertical"]
visible: dankBarTab.selectedIslandAnywhere
visible: dankBarTab.selectedIslandFloating
text: I18n.tr("Orientation", "island settings: horizontal or vertical row for a free island")
model: [I18n.tr("Horizontal", "island settings: free island orientation"), I18n.tr("Vertical", "island settings: free island orientation")]
currentIndex: SettingsData.islandVertical(bar.selectedBarConfig) ? 1 : 0
@@ -110,37 +97,30 @@ Item {
}
}
SettingsToggleRow {
settingKey: "islandFloating"
tags: ["island", "placement", "float", "overlay", "exclusive", "reserve"]
visible: dankBarTab.selectedIslandEdgeOrFree
resetStore: bar
resetKeys: ["islandFloating"]
text: I18n.tr("Float", "island settings: float toggle")
description: I18n.tr("Set floating overlay or enable drag anywhere mode")
checked: bar.islandSetting("islandFloating")
onToggled: checked => bar.apply("islandFloating", checked)
}
SettingsButtonGroupRow {
settingKey: "islandPlacement"
tags: ["island", "placement", "free", "floating", "dot", "edge", "drag"]
visible: dankBarTab.selectedIslandEdgeOrFree && bar.islandSetting("islandFloating")
tags: ["island", "placement", "docked", "overlay", "floating", "float", "free", "anywhere", "edge", "drag", "exclusive", "reserve"]
visible: bar.selectedBarIsIsland && !dankBarTab.isDot
resetStore: bar
resetKeys: ["islandPlacement"]
text: I18n.tr("Placement", "island settings: edge or free placement row")
model: [I18n.tr("Edge", "island settings: floats along a screen edge"), I18n.tr("Anywhere", "island settings: floats anywhere on the display")]
currentIndex: dankBarTab.valueIndex(dankBarTab.placementValues, bar.islandSetting("islandPlacement"), "edge")
resetKeys: ["islandFloating", "islandPlacement"]
text: I18n.tr("Placement", "island settings: docked, overlay or floating placement row")
model: [I18n.tr("Docked", "island settings: island reserves its edge strip"), I18n.tr("Overlay", "island settings: island floats over windows along its edge without reserving space"), I18n.tr("Floating", "island settings: island can be dragged anywhere on the display")]
currentIndex: dankBarTab.placementIndex
onSelectionChanged: (index, selected) => {
if (!selected)
return;
bar.apply("islandPlacement", dankBarTab.placementValues[index] ?? "edge");
const patch = {
islandFloating: index > 0
};
if (index > 0)
patch.islandPlacement = index === 2 ? "free" : "edge";
SettingsData.updateBarConfig(bar.selectedBarId, patch);
bar.notifyHorizontalBarChange();
}
}
SettingsRow {
visible: dankBarTab.selectedIslandAnywhere
visible: dankBarTab.selectedIslandFloating
body: StyledText {
width: parent.width
text: I18n.tr("Drag to move, click to open activities", "island settings: free placement hint")
@@ -150,71 +130,25 @@ Item {
}
}
SettingsSliderRow {
settingKey: "islandReserveThickness"
tags: ["island", "placement", "reservation", "exclusive", "height", "width", "thickness"]
visible: bar.selectedBarIsIsland && !dankBarTab.selectedIslandFree
SettingsDropdownRow {
id: sharedRouting
settingKey: "islandSharedRouting"
tags: ["dot", "island", "routing", "launcher", "dash", "control center", "ipc", "last used"]
visible: bar.selectedBarIsIsland
resetStore: bar
resetKeys: ["islandReserveThickness"]
text: bar.selectedBarIsVertical ? I18n.tr("Reserved width", "island settings: reserved strip width slider") : I18n.tr("Reserved height", "island settings: reserved strip height slider")
unit: "px"
minimum: 24
maximum: 128
step: 1
value: bar.islandSetting("islandReserveThickness")
enabled: !bar.islandSetting("islandFloating")
onSliderValueChanged: value => bar.apply("islandReserveThickness", value)
}
SettingsSliderRow {
settingKey: "islandCompactThickness"
tags: ["island", "placement", "compact", "height", "width", "thickness", "size", "satellite"]
visible: bar.selectedBarIsIsland && !dankBarTab.selectedIslandFree
resetStore: bar
resetKeys: ["islandCompactThickness"]
text: bar.selectedBarIsVertical ? I18n.tr("Compact width", "island settings: compact pill width slider") : I18n.tr("Compact height", "island settings: compact pill height slider")
unit: "px"
minimum: 24
maximum: 72
step: 1
value: bar.islandSetting("islandCompactThickness")
onSliderValueChanged: value => bar.apply("islandCompactThickness", value)
}
SettingsSliderRow {
settingKey: "islandOuterGap"
tags: ["island", "placement", "gap", "top", "margin"]
visible: bar.selectedBarIsIsland && !dankBarTab.selectedIslandFree
resetStore: bar
resetKeys: ["islandOuterGap"]
text: I18n.tr("Outer gap", "island settings: gap between screen edge and island")
unit: "px"
minimum: 0
maximum: 48
step: 1
value: bar.islandSetting("islandOuterGap")
onSliderValueChanged: value => bar.apply("islandOuterGap", value)
}
SettingsSliderRow {
settingKey: "islandAlongOffset"
tags: ["island", "placement", "horizontal", "vertical", "offset", "center"]
visible: bar.selectedBarIsIsland && !dankBarTab.selectedIslandFree
resetStore: bar
resetKeys: ["islandAlongOffset"]
text: bar.selectedBarIsVertical ? I18n.tr("Vertical offset", "island settings: vertical offset slider") : I18n.tr("Horizontal offset", "island settings: horizontal offset slider")
unit: "px"
minimum: -600
maximum: 600
step: 1
value: bar.islandSetting("islandAlongOffset")
onSliderValueChanged: value => bar.apply("islandAlongOffset", value)
resetKeys: ["islandSharedRouting"]
text: I18n.tr("Shared shortcuts")
description: I18n.tr("Routes launcher, dash, control center and notification shortcuts")
options: [I18n.tr("Normal routing"), I18n.tr("Always here"), I18n.tr("Last used on this screen")]
dropdownWidth: Theme.smallBreakpoint / 2
currentValue: options[dankBarTab.valueIndex(dankBarTab.routingValues, SettingsData.islandSharedRoutingMode(bar.selectedBarConfig), "normal")]
onValueChanged: value => SettingsData.setIslandSharedRouting(bar.selectedBarId, dankBarTab.routingValues[options.indexOf(value)] ?? "normal")
}
SettingsSliderRow {
settingKey: "islandFreeSize"
tags: ["island", "free", "dot", "size", "diameter"]
visible: dankBarTab.selectedBarIsDot
visible: dankBarTab.isDot
resetStore: bar
resetKeys: ["islandFreeSize"]
text: I18n.tr("Dot size", "island settings: free dot diameter slider")
@@ -244,7 +178,7 @@ Item {
SettingsSliderRow {
settingKey: "islandFreeIdleDelay"
tags: ["island", "free", "dot", "idle", "delay", "fade", "timeout"]
visible: dankBarTab.selectedBarIsDot
visible: dankBarTab.isDot
resetStore: bar
resetKeys: ["islandFreeIdleDelay"]
text: I18n.tr("Idle delay", "island settings: time before the dot fades, 0 disables idling")
@@ -256,26 +190,10 @@ Item {
onSliderValueChanged: value => bar.apply("islandFreeIdleDelay", value)
}
SettingsSliderRow {
settingKey: "islandFreeIdleOpacity"
tags: ["island", "free", "dot", "idle", "opacity", "fade"]
visible: dankBarTab.selectedBarIsDot
resetStore: bar
resetKeys: ["islandFreeIdleOpacity"]
text: I18n.tr("Idle opacity", "island settings: dot opacity while idle")
unit: "%"
minimum: 5
maximum: 100
step: 1
value: Math.round(bar.islandSetting("islandFreeIdleOpacity") * 100)
enabled: bar.islandSetting("islandFreeIdleDelay") > 0
onSliderValueChanged: value => bar.apply("islandFreeIdleOpacity", value / 100)
}
SettingsSliderRow {
settingKey: "islandFreeIdleScale"
tags: ["island", "free", "dot", "idle", "shrink", "scale"]
visible: dankBarTab.selectedBarIsDot
visible: dankBarTab.isDot
resetStore: bar
resetKeys: ["islandFreeIdleScale"]
text: I18n.tr("Idle size", "island settings: how far the dot shrinks while idle")
@@ -308,6 +226,104 @@ Item {
}
}
SettingsCard {
iconName: "tune"
title: I18n.tr("Frame")
settingKey: "frameEnabled"
tags: ["frame", "mode", "bar", "overview"]
visible: !dankBarTab.isDot && SettingsData.frameEnabled
SettingsButtonGroupRow {
settingKey: "frameModeSelector"
tags: ["frame", "mode", "connected", "separate", "popout", "flush", "float"]
resetKeys: ["frameMode"]
text: I18n.tr("Surfaces")
model: [I18n.tr("Separate", "adjective, frame surfaces mode option, opposite of connected"), I18n.tr("Connected")]
currentIndex: SettingsData.frameMode === "connected" ? 1 : 0
onSelectionChanged: (index, selected) => {
if (!selected)
return;
switch (index) {
case 1:
SettingsData.set("frameMode", "connected");
break;
default:
SettingsData.set("frameMode", "separate");
break;
}
}
}
SettingsToggleRow {
settingKey: "frameShowOnOverview"
tags: ["frame", "overview", "show", "hide", "niri"]
text: I18n.tr("Show on overview")
visible: CompositorService.supportsNativeOverview
checked: SettingsData.frameShowOnOverview
onToggled: checked => SettingsData.set("frameShowOnOverview", checked)
}
}
SettingsCard {
iconName: "blur_linear"
title: I18n.tr("Connected")
settingKey: "frameConnectedOptions"
collapsible: true
expanded: true
visible: !dankBarTab.isDot && SettingsData.frameEnabled && SettingsData.frameMode === "connected"
SettingsToggleRow {
settingKey: "frameCloseGaps"
tags: ["frame", "connected", "gap", "edge", "curves", "arcs", "expose", "popout", "notification"]
text: I18n.tr("Expose the arcs")
checked: !SettingsData.frameCloseGaps
onToggled: checked => SettingsData.set("frameCloseGaps", !checked)
}
SettingsButtonGroupRow {
settingKey: "frameLauncherEmergeSide"
tags: ["frame", "connected", "launcher", "modal", "emerge", "direction", "bottom", "top"]
text: I18n.tr("Launcher emerge side")
model: [I18n.tr("Bottom"), I18n.tr("Top")]
currentIndex: SettingsData.frameLauncherEmergeSide === "top" ? 1 : 0
onSelectionChanged: (index, selected) => {
if (!selected)
return;
SettingsData.set("frameLauncherEmergeSide", index === 1 ? "top" : "bottom");
}
}
SettingsToggleRow {
settingKey: "frameLauncherArcExtender"
tags: ["frame", "connected", "launcher", "arc", "extender", "center"]
text: I18n.tr("Arc extender")
checked: SettingsData.frameLauncherArcExtender
onToggled: checked => SettingsData.set("frameLauncherArcExtender", checked)
}
SettingsToggleRow {
settingKey: "frameLauncherEdgeHover"
tags: ["frame", "connected", "launcher", "hover", "edge", "reveal"]
text: I18n.tr("Edge hover reveal")
checked: SettingsData.frameLauncherEdgeHover
onToggled: checked => SettingsData.set("frameLauncherEdgeHover", checked)
}
}
SettingsCard {
iconName: "monitor"
title: I18n.tr("Frame displays", "settings card title: displays that draw the frame")
settingKey: "frameDisplays"
collapsible: true
expanded: false
visible: !dankBarTab.isDot && SettingsData.frameEnabled
SettingsDisplayPicker {
displayPreferences: SettingsData.frameScreenPreferences
onPreferencesChanged: prefs => SettingsData.set("frameScreenPreferences", prefs)
}
}
SettingsCard {
iconName: "visibility"
title: I18n.tr("Visibility", "settings card title for bar or dock show and hide behavior")
@@ -493,6 +509,152 @@ Item {
}
}
SettingsCard {
iconName: "home"
title: I18n.tr("Home compact", "island settings: home face card title")
settingKey: "islandActivities"
visible: dankBarTab.selectedIslandEnabled && !dankBarTab.isDot
IslandHomeLayoutEditor {
width: parent.width
barId: bar.selectedBarIsIsland ? bar.selectedBarId : ""
}
SettingsButtonGroupRow {
settingKey: "islandHomeClockDisplay"
tags: ["island", "home", "compact", "clock", "time", "date"]
resetStore: bar
resetKeys: ["islandHomeClockDisplay"]
text: I18n.tr("Clock style", "island settings: clock display mode row")
model: [I18n.tr("Time", "island settings: clock shows time only"), I18n.tr("Date", "island settings: clock shows date only"), I18n.tr("Both", "island settings: clock shows time and date")]
currentIndex: dankBarTab.valueIndex(dankBarTab.clockDisplayValues, bar.islandSetting("islandHomeClockDisplay"), "both")
onSelectionChanged: (index, selected) => {
if (selected)
bar.apply("islandHomeClockDisplay", dankBarTab.clockDisplayValues[index] ?? "both");
}
}
SettingsButtonGroupRow {
settingKey: "islandHomeVolumeDisplay"
tags: ["island", "home", "compact", "volume", "icon", "percentage"]
resetStore: bar
resetKeys: ["islandHomeVolumeDisplay"]
text: I18n.tr("Volume style", "island settings: volume display mode row")
visible: SettingsData.islandHomeGroupEnabled(bar.selectedBarConfig, "volume")
model: [I18n.tr("Icon", "island settings: level shown as icon only"), I18n.tr("Percentage", "island settings: level shown as percentage only"), I18n.tr("Both", "island settings: level shown as icon and percentage")]
currentIndex: dankBarTab.valueIndex(dankBarTab.systemLevelDisplayValues, bar.islandSetting("islandHomeVolumeDisplay"), "both")
onSelectionChanged: (index, selected) => {
if (selected)
bar.apply("islandHomeVolumeDisplay", dankBarTab.systemLevelDisplayValues[index] ?? "both");
}
}
SettingsButtonGroupRow {
settingKey: "islandHomeBrightnessDisplay"
tags: ["island", "home", "compact", "brightness", "icon", "percentage"]
resetStore: bar
resetKeys: ["islandHomeBrightnessDisplay"]
text: I18n.tr("Brightness style", "island settings: brightness display mode row")
visible: SettingsData.islandHomeGroupEnabled(bar.selectedBarConfig, "brightness")
model: [I18n.tr("Icon", "island settings: level shown as icon only"), I18n.tr("Percentage", "island settings: level shown as percentage only"), I18n.tr("Both", "island settings: level shown as icon and percentage")]
currentIndex: dankBarTab.valueIndex(dankBarTab.systemLevelDisplayValues, bar.islandSetting("islandHomeBrightnessDisplay"), "both")
onSelectionChanged: (index, selected) => {
if (selected)
bar.apply("islandHomeBrightnessDisplay", dankBarTab.systemLevelDisplayValues[index] ?? "both");
}
}
SettingsButtonGroupRow {
settingKey: "islandHomeStatusContent"
tags: ["island", "home", "compact", "status", "battery", "wifi", "bluetooth", "connectivity"]
text: I18n.tr("Control Center", "island settings: status group content row")
visible: SettingsData.islandHomeGroupEnabled(bar.selectedBarConfig, "status")
model: [I18n.tr("Battery", "island settings: status group battery content"), I18n.tr("Wi-Fi & Bluetooth", "island settings: status group connectivity content")]
currentIndex: dankBarTab.valueIndex(dankBarTab.statusContentValues, SettingsData.islandHomeStatusContent(bar.selectedBarConfig), "battery")
onSelectionChanged: (index, selected) => {
if (selected)
bar.apply("islandHomeStatusContent", dankBarTab.statusContentValues[index] ?? "battery");
}
}
SettingsToggleRow {
settingKey: "islandHomeCompactTight"
tags: ["island", "home", "compact", "narrow", "width", "height", "clock"]
resetStore: bar
resetKeys: ["islandHomeCompactTight"]
text: I18n.tr("Compact pill", "island settings: tighter home pill toggle")
checked: bar.islandSetting("islandHomeCompactTight")
onToggled: checked => bar.apply("islandHomeCompactTight", checked)
}
SettingsRow {
body: Flow {
width: parent.width
spacing: Theme.spacingS
DankButton {
text: I18n.tr("Launcher", "island settings: button to launcher tab")
iconName: "grid_view"
onClicked: {
if (!dankBarTab.parentModal)
return;
SettingsSearchService.navigateToSection("launcherStyle");
dankBarTab.parentModal.navigateTo("launcher");
}
}
DankButton {
text: I18n.tr("Time & weather", "island settings: button to weather tab")
iconName: "cloud"
onClicked: {
if (!dankBarTab.parentModal)
return;
SettingsSearchService.navigateToSection("weatherEnabled");
dankBarTab.parentModal.navigateTo("time_weather");
}
}
}
}
}
SettingsCard {
iconName: "notifications"
title: I18n.tr("Notifications", "island settings: notifications card title")
settingKey: "islandNotifications"
visible: dankBarTab.selectedIslandEnabled
SettingsToggleRow {
settingKey: "islandNotificationPopups"
tags: ["island", "notifications", "popup", "standard", "bar", "stack", "arrival"]
resetStore: bar
resetKeys: ["islandNotificationPopups"]
text: I18n.tr("Use standard popups", "island settings: show arriving notifications as stacked popups instead of in the island")
checked: bar.islandSetting("islandNotificationPopups")
onToggled: checked => bar.apply("islandNotificationPopups", checked)
}
SettingsToggleRow {
settingKey: "islandNotificationExpand"
tags: ["island", "notifications", "expand", "arrival", "size"]
resetStore: bar
resetKeys: ["islandNotificationExpand"]
text: I18n.tr("Expand by default", "island settings: expanded notification toggle")
checked: bar.islandSetting("islandNotificationExpand")
onToggled: checked => bar.apply("islandNotificationExpand", checked)
}
SettingsToggleRow {
settingKey: "islandNotificationBadgeClearOnOpen"
tags: ["island", "home", "notifications", "badge", "unread", "clear", "dismiss", "open"]
resetStore: bar
resetKeys: ["islandNotificationBadgeClearOnOpen"]
text: I18n.tr("Clear badge on open", "island settings: clear the notification badge when the center opens")
checked: bar.islandSetting("islandNotificationBadgeClearOnOpen")
enabled: dankBarTab.isDot || SettingsData.islandHomeGroupEnabled(bar.selectedBarConfig, "notifications")
onToggled: checked => bar.apply("islandNotificationBadgeClearOnOpen", checked)
}
}
SettingsToggleCard {
settingKey: "hoverPopouts"
resetStore: bar
@@ -500,7 +662,7 @@ Item {
tags: ["bar", "hover", "popout", "reveal", "widget", "delay"]
iconName: "touch_app"
title: I18n.tr("Hover popouts")
visible: bar.selectedBarConfig?.enabled ?? false
visible: (bar.selectedBarConfig?.enabled ?? false) && !dankBarTab.isDot
enabled: !(bar.selectedBarConfig?.clickThrough ?? false)
opacity: (bar.selectedBarConfig?.clickThrough ?? false) ? 0.5 : 1.0
checked: bar.selectedBarConfig?.hoverPopouts ?? false
@@ -621,127 +783,5 @@ Item {
}
}
}
SettingsCard {
title: I18n.tr("Advanced")
settingKey: "barAdvanced"
tags: ["bar", "advanced", "overlay", "layer", "click", "through", "maximize", "island", "spring", "motion"]
collapsible: true
expanded: false
visible: bar.selectedBarConfig?.enabled ?? false
SettingsToggleRow {
settingKey: "barClickThrough"
resetStore: bar
resetKeys: ["clickThrough"]
tags: ["clickthrough", "click", "through", "mouse", "input", "mask", "passthrough"]
visible: !bar.islandOwnsSelectedBarTop
text: I18n.tr("Click through")
checked: bar.selectedBarConfig?.clickThrough ?? false
onToggled: toggled => SettingsData.updateBarConfig(bar.selectedBarId, {
clickThrough: toggled
})
}
SettingsToggleRow {
settingKey: "barUseOverlayLayer"
resetStore: bar
resetKeys: ["useOverlayLayer"]
tags: ["bar", "fullscreen", "overlay", "layer"]
visible: !bar.islandOwnsSelectedBarTop
text: I18n.tr("Use overlay layer")
checked: bar.selectedBarConfig?.useOverlayLayer ?? false
onToggled: toggled => {
SettingsData.updateBarConfig(bar.selectedBarId, {
useOverlayLayer: toggled
});
bar.notifyHorizontalBarChange();
}
}
SettingsToggleRow {
settingKey: "islandUseOverlayLayer"
tags: ["island", "fullscreen", "overlay", "layer"]
visible: bar.selectedBarIsIsland
resetStore: bar
resetKeys: ["islandUseOverlayLayer"]
text: I18n.tr("Use overlay layer")
checked: bar.islandSetting("islandUseOverlayLayer")
onToggled: checked => bar.apply("islandUseOverlayLayer", checked)
}
SettingsToggleRow {
settingKey: "islandReducedMotion"
tags: ["island", "motion", "animation", "reduce", "accessibility", "spring"]
visible: bar.selectedBarIsIsland
resetStore: bar
resetKeys: ["islandReducedMotion"]
text: I18n.tr("Reduce motion")
checked: bar.islandSetting("islandReducedMotion")
onToggled: checked => bar.apply("islandReducedMotion", checked)
}
SettingsSliderRow {
settingKey: "islandSpringStiffness"
tags: ["island", "motion", "spring", "stiffness", "animation"]
visible: bar.selectedBarIsIsland
resetStore: bar
resetKeys: ["islandSpringStiffness"]
text: I18n.tr("Spring stiffness", "island settings: spring stiffness slider")
unit: ""
minimum: 100
maximum: 1200
step: 10
value: Math.round(bar.islandSetting("islandSpringStiffness"))
enabled: !bar.islandSetting("islandReducedMotion")
onSliderValueChanged: value => bar.apply("islandSpringStiffness", value)
}
SettingsSliderRow {
settingKey: "islandSpringDamping"
tags: ["island", "motion", "spring", "damping", "bounce", "animation"]
visible: bar.selectedBarIsIsland
resetStore: bar
resetKeys: ["islandSpringDamping"]
text: I18n.tr("Spring damping", "island settings: spring damping slider")
unit: ""
minimum: 10
maximum: 100
step: 1
value: Math.round(bar.islandSetting("islandSpringDamping"))
enabled: !bar.islandSetting("islandReducedMotion")
onSliderValueChanged: value => bar.apply("islandSpringDamping", value)
}
SettingsSliderRow {
settingKey: "islandSpringMass"
tags: ["island", "motion", "spring", "mass", "inertia", "animation"]
visible: bar.selectedBarIsIsland
resetStore: bar
resetKeys: ["islandSpringMass"]
text: I18n.tr("Spring mass", "island settings: spring mass slider")
minimum: 25
maximum: 300
step: 5
unit: ""
decimals: 2
value: Math.round(bar.islandSetting("islandSpringMass") * 100)
enabled: !bar.islandSetting("islandReducedMotion")
onSliderValueChanged: value => bar.apply("islandSpringMass", value / 100)
}
SettingsToggleRow {
settingKey: "barMaximizeDetection"
resetStore: bar
resetKeys: ["maximizeDetection"]
tags: ["maximize", "gaps", "border", "fullscreen"]
visible: CompositorService.supportsBarAutoHideReveal
text: I18n.tr("Maximize detection")
checked: bar.selectedBarConfig?.maximizeDetection ?? true
onToggled: toggled => SettingsData.updateBarConfig(bar.selectedBarId, {
maximizeDetection: toggled
})
}
}
}
}
@@ -1,292 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import qs.Common
import qs.Modules.Settings.Widgets
import qs.Services
import qs.Widgets
Item {
id: root
property var parentModal: null
LayoutMirroring.enabled: I18n.isRtl
LayoutMirroring.childrenInherit: true
BarSelectionState {
id: bar
}
readonly property string selectedIslandId: bar.selectedBarIsIsland ? bar.selectedBarId : ""
readonly property var config: bar.selectedBarConfig
readonly property bool islandEnabled: bar.selectedBarIsIsland && (bar.selectedBarConfig?.enabled ?? false)
readonly property bool isDot: SettingsData.isDotBarConfig(root.config)
readonly property bool isFree: SettingsData.islandFreePlacement(root.config)
readonly property var clockDisplayValues: ["time", "date", "both"]
readonly property var systemLevelDisplayValues: ["icon", "percentage", "both"]
readonly property var statusContentValues: ["battery", "connectivity"]
readonly property var satellitePositionValues: ["island", "edges"]
function valueIndex(values, value, fallback) {
const index = values.indexOf(value);
return index >= 0 ? index : Math.max(0, values.indexOf(fallback));
}
SettingsPage {
id: mainColumn
SettingsCard {
width: parent.width
iconName: "home"
title: I18n.tr("Home compact", "island settings: home face card title")
settingKey: "islandActivities"
visible: root.islandEnabled && !root.isDot
IslandHomeLayoutEditor {
width: parent.width
barId: root.selectedIslandId
}
SettingsButtonGroupRow {
settingKey: "islandHomeClockDisplay"
tags: ["island", "home", "compact", "clock", "time", "date"]
resetStore: bar
resetKeys: ["islandHomeClockDisplay"]
text: I18n.tr("Clock style", "island settings: clock display mode row")
model: [I18n.tr("Time", "island settings: clock shows time only"), I18n.tr("Date", "island settings: clock shows date only"), I18n.tr("Both", "island settings: clock shows time and date")]
currentIndex: root.valueIndex(root.clockDisplayValues, bar.islandSetting("islandHomeClockDisplay"), "both")
onSelectionChanged: (index, selected) => {
if (selected)
bar.apply("islandHomeClockDisplay", root.clockDisplayValues[index] ?? "both");
}
}
SettingsButtonGroupRow {
settingKey: "islandHomeVolumeDisplay"
tags: ["island", "home", "compact", "volume", "icon", "percentage"]
resetStore: bar
resetKeys: ["islandHomeVolumeDisplay"]
text: I18n.tr("Volume style", "island settings: volume display mode row")
visible: SettingsData.islandHomeGroupEnabled(root.config, "volume")
model: [I18n.tr("Icon", "island settings: level shown as icon only"), I18n.tr("Percentage", "island settings: level shown as percentage only"), I18n.tr("Both", "island settings: level shown as icon and percentage")]
currentIndex: root.valueIndex(root.systemLevelDisplayValues, bar.islandSetting("islandHomeVolumeDisplay"), "both")
onSelectionChanged: (index, selected) => {
if (selected)
bar.apply("islandHomeVolumeDisplay", root.systemLevelDisplayValues[index] ?? "both");
}
}
SettingsButtonGroupRow {
settingKey: "islandHomeBrightnessDisplay"
tags: ["island", "home", "compact", "brightness", "icon", "percentage"]
resetStore: bar
resetKeys: ["islandHomeBrightnessDisplay"]
text: I18n.tr("Brightness style", "island settings: brightness display mode row")
visible: SettingsData.islandHomeGroupEnabled(root.config, "brightness")
model: [I18n.tr("Icon", "island settings: level shown as icon only"), I18n.tr("Percentage", "island settings: level shown as percentage only"), I18n.tr("Both", "island settings: level shown as icon and percentage")]
currentIndex: root.valueIndex(root.systemLevelDisplayValues, bar.islandSetting("islandHomeBrightnessDisplay"), "both")
onSelectionChanged: (index, selected) => {
if (selected)
bar.apply("islandHomeBrightnessDisplay", root.systemLevelDisplayValues[index] ?? "both");
}
}
SettingsButtonGroupRow {
settingKey: "islandHomeStatusContent"
tags: ["island", "home", "compact", "status", "battery", "wifi", "bluetooth", "connectivity"]
text: I18n.tr("Control Center", "island settings: status group content row")
visible: SettingsData.islandHomeGroupEnabled(root.config, "status")
model: [I18n.tr("Battery", "island settings: status group battery content"), I18n.tr("Wi-Fi & Bluetooth", "island settings: status group connectivity content")]
currentIndex: root.valueIndex(root.statusContentValues, SettingsData.islandHomeStatusContent(root.config), "battery")
onSelectionChanged: (index, selected) => {
if (selected)
bar.apply("islandHomeStatusContent", root.statusContentValues[index] ?? "battery");
}
}
SettingsToggleRow {
settingKey: "islandHomeCompactTight"
tags: ["island", "home", "compact", "narrow", "width", "height", "clock"]
resetStore: bar
resetKeys: ["islandHomeCompactTight"]
text: I18n.tr("Compact pill", "island settings: tighter home pill toggle")
checked: bar.islandSetting("islandHomeCompactTight")
onToggled: checked => bar.apply("islandHomeCompactTight", checked)
}
SettingsRow {
body: Flow {
width: parent.width
spacing: Theme.spacingS
DankButton {
text: I18n.tr("Launcher", "island settings: button to launcher tab")
iconName: "grid_view"
onClicked: {
if (!root.parentModal)
return;
SettingsSearchService.navigateToSection("launcherStyle");
root.parentModal.navigateTo("launcher");
}
}
DankButton {
text: I18n.tr("Time & weather", "island settings: button to weather tab")
iconName: "cloud"
onClicked: {
if (!root.parentModal)
return;
SettingsSearchService.navigateToSection("weatherEnabled");
root.parentModal.navigateTo("time_weather");
}
}
}
}
}
SettingsCard {
width: parent.width
iconName: "notifications"
title: I18n.tr("Notifications", "island settings: notifications card title")
settingKey: "islandNotifications"
visible: root.islandEnabled
SettingsToggleRow {
settingKey: "islandNotificationPopups"
tags: ["island", "notifications", "popup", "standard", "bar", "stack", "arrival"]
resetStore: bar
resetKeys: ["islandNotificationPopups"]
text: I18n.tr("Use standard popups", "island settings: show arriving notifications as stacked popups instead of in the island")
checked: bar.islandSetting("islandNotificationPopups")
onToggled: checked => bar.apply("islandNotificationPopups", checked)
}
SettingsToggleRow {
settingKey: "islandNotificationExpand"
tags: ["island", "notifications", "expand", "arrival", "size"]
resetStore: bar
resetKeys: ["islandNotificationExpand"]
text: I18n.tr("Expand by default", "island settings: expanded notification toggle")
checked: bar.islandSetting("islandNotificationExpand")
onToggled: checked => bar.apply("islandNotificationExpand", checked)
}
SettingsToggleRow {
settingKey: "islandNotificationBadgeClearOnOpen"
tags: ["island", "home", "notifications", "badge", "unread", "clear", "dismiss", "open"]
resetStore: bar
resetKeys: ["islandNotificationBadgeClearOnOpen"]
text: I18n.tr("Clear badge on open", "island settings: clear the notification badge when the center opens")
checked: bar.islandSetting("islandNotificationBadgeClearOnOpen")
enabled: root.isDot || SettingsData.islandHomeGroupEnabled(root.config, "notifications")
onToggled: checked => bar.apply("islandNotificationBadgeClearOnOpen", checked)
}
}
SettingsCard {
width: parent.width
iconName: "widgets"
title: I18n.tr("Satellites", "island settings: satellite widgets card title")
settingKey: "islandSatellites"
collapsible: true
expanded: true
visible: root.islandEnabled && !root.isFree
SettingsToggleRow {
settingKey: "islandSatellitesEnabled"
tags: ["island", "satellite", "widgets", "left", "right"]
resetStore: bar
resetKeys: ["islandSatellitesEnabled"]
text: I18n.tr("Show", "island settings: satellite widgets toggle")
checked: bar.islandSetting("islandSatellitesEnabled")
onToggled: checked => bar.apply("islandSatellitesEnabled", checked)
}
SettingsButtonGroupRow {
settingKey: "islandSatellitePosition"
tags: ["island", "satellite", "widgets", "position", "edges", "center"]
resetStore: bar
resetKeys: ["islandSatellitePosition"]
text: I18n.tr("Position", "island settings: position card title")
model: [I18n.tr("Near island", "island settings: satellites hug the island"), I18n.tr("Display edges", "island settings: satellites sit at screen edges")]
currentIndex: root.valueIndex(root.satellitePositionValues, bar.islandSetting("islandSatellitePosition"), "island")
enabled: bar.islandSetting("islandSatellitesEnabled")
onSelectionChanged: (index, selected) => {
if (selected)
bar.apply("islandSatellitePosition", root.satellitePositionValues[index] ?? "island");
}
}
SettingsToggleRow {
settingKey: "islandSatelliteBackground"
tags: ["island", "satellite", "widgets", "background", "chrome"]
resetStore: bar
resetKeys: ["islandSatelliteBackground"]
text: I18n.tr("Background", "island settings: satellite background toggle")
checked: bar.islandSetting("islandSatelliteBackground")
visible: bar.islandSetting("islandSatellitesEnabled")
onToggled: checked => bar.apply("islandSatelliteBackground", checked)
}
SettingsToggleRow {
settingKey: "islandSatelliteGothCorners"
tags: ["island", "satellite", "goth", "corners", "wing", "sweep"]
resetStore: bar
resetKeys: ["islandSatelliteGothCorners"]
text: I18n.tr("Goth corners", "island settings: satellite goth corners toggle")
checked: bar.islandSetting("islandSatelliteGothCorners")
visible: bar.islandSetting("islandSatellitesEnabled")
enabled: bar.islandSetting("islandSatelliteBackground")
onToggled: checked => bar.apply("islandSatelliteGothCorners", checked)
}
SettingsSliderRow {
settingKey: "islandSatelliteSwoopRadius"
tags: ["island", "satellite", "goth", "corners", "radius", "sweep", "size"]
resetStore: bar
resetKeys: ["islandSatelliteSwoopRadius"]
text: I18n.tr("Goth corner radius", "island settings: satellite goth corner radius slider")
unit: "px"
minimum: 4
maximum: 64
step: 1
value: bar.islandSetting("islandSatelliteSwoopRadius")
visible: bar.islandSetting("islandSatellitesEnabled")
enabled: bar.islandSetting("islandSatelliteBackground") && bar.islandSetting("islandSatelliteGothCorners")
onSliderValueChanged: value => bar.apply("islandSatelliteSwoopRadius", value)
}
SettingsSliderRow {
settingKey: "islandSatelliteTransparency"
tags: ["island", "satellite", "background", "opacity", "transparency", "blur"]
resetStore: bar
resetKeys: ["islandSatelliteTransparency"]
text: I18n.tr("Opacity", "island settings: satellite background opacity slider")
minimum: 0
maximum: 100
step: 1
value: Math.round(bar.islandSetting("islandSatelliteTransparency") * 100)
visible: bar.islandSetting("islandSatellitesEnabled")
enabled: bar.islandSetting("islandSatelliteBackground")
onSliderValueChanged: value => bar.apply("islandSatelliteTransparency", value / 100)
}
SettingsSliderRow {
settingKey: "islandSatelliteGap"
tags: ["island", "satellite", "widgets", "gap", "spacing"]
resetStore: bar
resetKeys: ["islandSatelliteGap"]
text: I18n.tr("Gap", "island settings: satellite to island gap slider")
unit: "px"
minimum: 4
maximum: 48
step: 1
value: bar.islandSetting("islandSatelliteGap")
visible: bar.islandSetting("islandSatellitesEnabled")
enabled: bar.islandSetting("islandSatellitePosition") !== "edges"
onSliderValueChanged: value => bar.apply("islandSatelliteGap", value)
}
}
}
}
-222
View File
@@ -1,222 +0,0 @@
pragma ComponentBehavior: Bound
import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
import qs.Modules.Settings.Widgets
Item {
id: root
LayoutMirroring.enabled: I18n.isRtl
LayoutMirroring.childrenInherit: true
// Bar Inset Padding: resolve the "auto" sentinel (stored < 0) to the frame thickness for the slider display.
readonly property int frameInsetPaddingDisplay: Math.round(SettingsData.frameBarContentGap)
SettingsPage {
id: mainColumn
SettingsCard {
width: parent.width
iconName: "tune"
title: I18n.tr("Behavior")
settingKey: "frameEnabled"
tags: ["frame", "mode", "bar", "overview"]
visible: SettingsData.frameEnabled
SettingsButtonGroupRow {
settingKey: "frameModeSelector"
tags: ["frame", "mode", "connected", "separate", "popout", "flush", "float"]
resetKeys: ["frameMode"]
text: I18n.tr("Surfaces")
model: [I18n.tr("Separate", "adjective, frame surfaces mode option, opposite of connected"), I18n.tr("Connected")]
currentIndex: SettingsData.frameMode === "connected" ? 1 : 0
onSelectionChanged: (index, selected) => {
if (!selected)
return;
switch (index) {
case 1:
SettingsData.set("frameMode", "connected");
break;
default:
SettingsData.set("frameMode", "separate");
break;
}
}
}
SettingsToggleRow {
settingKey: "frameShowOnOverview"
tags: ["frame", "overview", "show", "hide", "niri"]
text: I18n.tr("Show on overview")
visible: CompositorService.supportsNativeOverview
checked: SettingsData.frameShowOnOverview
onToggled: checked => SettingsData.set("frameShowOnOverview", checked)
}
}
SettingsCard {
width: parent.width
iconName: "border_outer"
title: I18n.tr("Border")
settingKey: "frameBorder"
collapsible: true
visible: SettingsData.frameEnabled
SettingsSliderRow {
settingKey: "frameRounding"
tags: ["frame", "border", "rounding", "radius", "corner"]
text: I18n.tr("Radius", "corner radius slider label")
unit: "px"
minimum: 0
maximum: 100
step: 1
value: SettingsData.frameRounding
onSliderDragFinished: v => SettingsData.set("frameRounding", v)
}
SettingsSliderRow {
settingKey: "frameThickness"
tags: ["frame", "border", "thickness", "size", "width"]
text: I18n.tr("Width")
unit: "px"
minimum: 2
maximum: 100
step: 1
value: SettingsData.frameThickness
onSliderDragFinished: v => SettingsData.set("frameThickness", v)
}
SettingsSliderRow {
settingKey: "frameBarSize"
tags: ["frame", "bar", "thickness", "size", "height", "width"]
text: I18n.tr("Bar size")
unit: "px"
minimum: 24
maximum: 100
step: 1
value: SettingsData.frameBarSize
onSliderDragFinished: v => SettingsData.set("frameBarSize", v)
}
SettingsSliderRow {
settingKey: "frameBarInsetPadding"
tags: ["frame", "bar", "edge", "inset", "padding", "corner", "end"]
text: I18n.tr("Bar inset padding")
minimumLabel: I18n.tr("Edge to edge", "slider minimum label, bar touches the screen edges")
unit: "px"
minimum: 0
maximum: 48
step: 1
value: root.frameInsetPaddingDisplay
onSliderDragFinished: v => SettingsData.set("frameBarInsetPadding", v)
}
SettingsToggleRow {
id: frameBlurToggle
settingKey: "frameBlurEnabled"
tags: ["frame", "blur", "background", "glass", "transparency", "frosted"]
text: I18n.tr("Blur")
checked: SettingsData.frameBlurEnabled
onToggled: checked => SettingsData.set("frameBlurEnabled", checked)
enabled: BlurService.available && SettingsData.blurEnabled
visible: BlurService.available
}
SettingsRow {
visible: BlurService.available && !SettingsData.blurEnabled
body: Item {
width: parent.width
height: blurToggleNote.height + Theme.spacingM * 2
Row {
id: blurToggleNote
x: Theme.spacingM
width: parent.width - Theme.spacingM * 2
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankIcon {
name: "blur_on"
size: Theme.fontSizeMedium
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Frame Blur follows Background Blur in Theme & Colors")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
width: parent.width - Theme.fontSizeMedium - Theme.spacingS
}
}
}
}
}
SettingsCard {
width: parent.width
iconName: "blur_linear"
title: I18n.tr("Connected")
settingKey: "frameConnectedOptions"
collapsible: true
expanded: true
visible: SettingsData.frameEnabled && SettingsData.frameMode === "connected"
SettingsToggleRow {
settingKey: "frameCloseGaps"
tags: ["frame", "connected", "gap", "edge", "curves", "arcs", "expose", "popout", "notification"]
text: I18n.tr("Expose the arcs")
checked: !SettingsData.frameCloseGaps
onToggled: checked => SettingsData.set("frameCloseGaps", !checked)
}
SettingsButtonGroupRow {
settingKey: "frameLauncherEmergeSide"
tags: ["frame", "connected", "launcher", "modal", "emerge", "direction", "bottom", "top"]
text: I18n.tr("Launcher emerge side")
model: [I18n.tr("Bottom"), I18n.tr("Top")]
currentIndex: SettingsData.frameLauncherEmergeSide === "top" ? 1 : 0
onSelectionChanged: (index, selected) => {
if (!selected)
return;
SettingsData.set("frameLauncherEmergeSide", index === 1 ? "top" : "bottom");
}
}
SettingsToggleRow {
settingKey: "frameLauncherArcExtender"
tags: ["frame", "connected", "launcher", "arc", "extender", "center"]
text: I18n.tr("Arc extender")
checked: SettingsData.frameLauncherArcExtender
onToggled: checked => SettingsData.set("frameLauncherArcExtender", checked)
}
SettingsToggleRow {
settingKey: "frameLauncherEdgeHover"
tags: ["frame", "connected", "launcher", "hover", "edge", "reveal"]
text: I18n.tr("Edge hover reveal")
checked: SettingsData.frameLauncherEdgeHover
onToggled: checked => SettingsData.set("frameLauncherEdgeHover", checked)
}
}
SettingsCard {
width: parent.width
iconName: "monitor"
title: I18n.tr("Displays")
settingKey: "frameDisplays"
collapsible: true
expanded: false
visible: SettingsData.frameEnabled
SettingsDisplayPicker {
displayPreferences: SettingsData.frameScreenPreferences
onPreferencesChanged: prefs => SettingsData.set("frameScreenPreferences", prefs)
}
}
}
}
@@ -38,8 +38,8 @@ FocusScope {
required property var modelData
iconName: modelData.icon
title: (modelData.titleFrom ? SettingsUiState[modelData.titleFrom] : "") || modelData.text
hint: (modelData.hintFrom ? SettingsUiState[modelData.hintFrom] : "") || (modelData.hint ?? "")
title: modelData.text
hint: modelData.hint ?? ""
trailingBadge: modelData.kind === "plugin" && PluginService.loadedPlugins[modelData.pluginId] === undefined ? I18n.tr("Disabled") : ""
onClicked: root.parentModal?.navigateTo(modelData.id)
}
+1 -1
View File
@@ -234,7 +234,7 @@ Item {
visible: shadowCard.bars.length > 1
options: shadowCard.bars.map(config => config.name || config.id)
currentValue: bar.selectedBarConfig?.name || bar.selectedBarConfig?.id || ""
onValueChanged: value => bar.selectedBarId = shadowCard.bars.find(config => (config.name || config.id) === value)?.id ?? bar.selectedBarId
onValueChanged: value => bar.select(shadowCard.bars.find(config => (config.name || config.id) === value)?.id ?? bar.selectedBarId)
}
SettingsToggleRow {
@@ -29,7 +29,7 @@ Column {
readonly property var opacityTargets: {
SettingsData.barConfigs;
SettingsData.dockConfigs;
const bars = SettingsData.barConfigs.map(config => ({
const bars = SettingsData.barConfigs.filter(config => !SettingsData.isDotBarConfig(config)).map(config => ({
kind: "bar",
id: config.id,
name: config.name || config.id,
@@ -6,27 +6,15 @@ import qs.Services
Item {
id: root
property string selectedBarId: SettingsUiState.selectedBarId
readonly property string selectedBarId: SettingsUiState.selectedBarId
onSelectedBarIdChanged: {
if (SettingsUiState.selectedBarId !== selectedBarId)
SettingsUiState.selectedBarId = selectedBarId;
function select(id) {
SettingsUiState.selectedBarId = id;
}
Connections {
target: SettingsUiState
function onSelectedBarIdChanged() {
if (root.selectedBarId !== SettingsUiState.selectedBarId)
root.selectedBarId = SettingsUiState.selectedBarId;
}
}
property var selectedBarConfig: {
selectedBarId;
readonly property var selectedBarConfig: {
SettingsData.barConfigs;
const index = SettingsData.barConfigs.findIndex(cfg => cfg.id === selectedBarId);
return index !== -1 ? SettingsData.barConfigs[index] : SettingsData.barConfigs[0];
return SettingsData.getBarConfig(selectedBarId) ?? SettingsData.barConfigs[0] ?? null;
}
readonly property string selectedBarName: {
selectedBarId;
@@ -17,11 +17,9 @@ StyledRect {
property string reason: ""
property var parentModal: null
readonly property string resolvedTarget: target || (SettingsData.frameEnabled ? "frame" : "island")
readonly property string resolvedTarget: target || "frame"
readonly property string iconName: {
switch (resolvedTarget) {
case "island":
return "view_in_ar";
case "surfaces":
return "layers";
case "shadows":
@@ -32,8 +30,6 @@ StyledRect {
}
readonly property string buttonText: {
switch (resolvedTarget) {
case "island":
return I18n.tr("Open Island", "settings: button that opens the Dank Island tab");
case "surfaces":
return I18n.tr("Interface style");
case "shadows":
@@ -44,14 +40,12 @@ StyledRect {
}
readonly property string tabName: {
switch (resolvedTarget) {
case "island":
return "dank_island";
case "surfaces":
return "theme_surfaces";
case "shadows":
return "surface_shadows";
default:
return "frame";
return section === "frameConnectedOptions" ? "dankbar_settings" : "dankbar_appearance";
}
}
@@ -31,10 +31,6 @@ GridLayout {
{
"key": "island",
"label": I18n.tr("Island")
},
{
"key": "dot",
"label": I18n.tr("Dot", "bar layout: free-floating dot that opens island activities")
}
]
readonly property real cardHeightRatio: 7.5
@@ -44,13 +40,6 @@ GridLayout {
readonly property real previewIslandRatio: 0.42
readonly property real previewWidth: Math.round(Theme.iconSize * previewWidthRatio)
readonly property real minimumCardWidth: previewWidth + Theme.spacingL * 2
// The dot is a companion, not a mode: its card toggles a dot config alongside whatever the selected bar is.
readonly property var dotConfig: {
SettingsData.barConfigs;
return (SettingsData.barConfigs || []).find(cfg => SettingsData.isDotBarConfig(cfg)) ?? null;
}
readonly property bool dotActive: root.dotConfig?.enabled ?? false
readonly property bool dotSelected: !root.edgePlacement && !root.widgetStyle && SettingsData.isDotBarConfig(SettingsData.getBarConfig(SettingsUiState.selectedBarId))
readonly property var targetConfig: {
SettingsData.barConfigs;
SettingsUiState.selectedBarId;
@@ -60,40 +49,9 @@ GridLayout {
}
readonly property string activeBarMode: SettingsData.frameEnabled ? "frame" : (SettingsData.isIslandBarConfig(root.targetConfig) ? "island" : "standard")
function toggleDot() {
const existing = root.dotConfig;
if (existing) {
SettingsData.updateBarConfig(existing.id, {
enabled: !existing.enabled
});
SettingsUiState.selectedBarId = existing.enabled ? (root.targetConfig?.id ?? "default") : existing.id;
return;
}
const base = root.targetConfig ?? SettingsData.getBarConfig("default");
if (!base)
return;
const id = "dot" + Date.now();
const config = Object.assign(JSON.parse(JSON.stringify(base)), {
id,
name: I18n.tr("Dot", "bar layout: free-floating dot that opens island activities"),
enabled: true,
island: false,
dot: true,
screenPreferences: ["all"],
showOnLastDisplay: true
});
// An inherited "always here" would make the base island and the dot fight by config order.
delete config.islandSharedRouting;
SettingsData.addBarConfig(config);
SettingsUiState.selectedBarId = id;
}
function applyBarMode(mode) {
const target = root.targetConfig;
switch (mode) {
case "dot":
root.toggleDot();
return;
case "frame":
if (SettingsData.frameEnabled)
return;
@@ -130,10 +88,10 @@ GridLayout {
Rectangle {
id: modeCard
required property var modelData
enabled: (modelData.enabled ?? true) && (modelData.key === "dot" || !root.dotSelected)
enabled: modelData.enabled ?? true
opacity: enabled ? 1 : SettingsMetrics.disabledOpacity
readonly property bool isActive: modelData.key === "dot" && !root.edgePlacement && !root.widgetStyle ? root.dotActive : root.selectedKey === modelData.key
readonly property bool isActive: root.selectedKey === modelData.key
Layout.fillWidth: true
Layout.fillHeight: true
@@ -146,7 +104,7 @@ GridLayout {
border.color: isActive ? Theme.primary : Theme.outlineMedium
activeFocusOnTab: true
Accessible.role: modelData.key === "dot" ? Accessible.CheckBox : Accessible.RadioButton
Accessible.role: Accessible.RadioButton
Accessible.name: modelData.label
Accessible.checked: isActive
Accessible.onPressAction: root.selected(modelData.key)
@@ -247,16 +205,6 @@ GridLayout {
color: Theme.primary
}
Rectangle {
visible: !root.widgetStyle && modeCard.modelData.key === "dot"
x: Math.round(parent.width * 0.62)
y: Math.round(parent.height * 0.3)
width: Math.round(screenPreview.stripSize * 1.6)
height: width
radius: width / 2
color: Theme.primary
}
Rectangle {
visible: !root.widgetStyle && modeCard.modelData.key === "island"
anchors.top: parent.top
+24 -1
View File
@@ -167,7 +167,7 @@ test("free islands and dots keep their key but leave every band, reservation and
for (const options of [{}, { effectiveFrameEnabled: true }, { effectiveFrameEnabled: true, effectiveConnected: true }]) {
const layout = resolve(configs, options);
const dot = layout.instances.find(instance => instance.barId === "dot");
assert.deepEqual(plain({ ...dot, paintedBounds: undefined, margins: undefined }), { key: JSON.stringify(["DP-1", "dot"]), screenName: "DP-1", barId: "dot", configOrder: 1, edge: "", kind: "island", free: true, dot: true, row: 0, rowThickness: 0, rowOffset: 0, reservation: 0, exclusiveZone: -1, exclusionSize: 0 });
assert.deepEqual(plain({ ...dot, paintedBounds: undefined, margins: undefined }), { key: JSON.stringify(["DP-1", "dot"]), screenName: "DP-1", barId: "dot", configOrder: 1, edge: "", kind: "island", free: true, dot: true, satelliteEdge: "", row: 0, rowThickness: 0, rowOffset: 0, reservation: 0, exclusiveZone: -1, exclusionSize: 0 });
assert.equal(layout.instances.find(instance => instance.barId === "free").dot, false);
assert.equal(layout.edges.top.island, null);
assert.equal(layout.edges.top.islandThickness, 0);
@@ -180,3 +180,26 @@ test("free islands and dots keep their key but leave every band, reservation and
assert.deepEqual(plain(layout.instances.filter(instance => instance.free).map(instance => instance.barId)), ["dot", "free"]);
assert.equal(resolver.adjacentInfo(layout, configs[0], configs[0]).topBar, 0);
});
test("a free island keeps a bar window for its satellites on its edge without reserving or shadowing it", () => {
const top = bar("top");
const free = values => bar("free", 1, { island: true, islandFloating: true, islandPlacement: "free", ...values });
for (const options of [{}, { effectiveFrameEnabled: true }, { effectiveFrameEnabled: true, effectiveConnected: true }]) {
const baseline = resolve([top], options);
const layout = resolve([top, free({}), bar("dot", 1, { dot: true })], options);
const instance = layout.instances.find(instance => instance.barId === "free");
assert.equal(instance.satelliteEdge, "bottom");
assert.equal(instance.edge, "");
assert.equal(instance.reservation, 0);
assert.equal(instance.exclusiveZone, -1);
assert.equal(resolver.hostsBarWindow(instance), true);
assert.equal(resolver.hostsBarWindow(layout.instances.find(instance => instance.barId === "dot")), false);
assert.equal(layout.edges.bottom.island, null);
assert.equal(layout.edges.bottom.islandThickness, 0);
assert.deepEqual(plain(layout.edges), plain(resolve([top, bar("dot", 1, { dot: true })], options).edges));
assert.equal(layout.edges.top.occupancy, baseline.edges.top.occupancy);
assert.equal(layout.manualPlacement, false);
const off = resolve([top, free({ islandSatellitesEnabled: false })], options).instances.find(instance => instance.barId === "free");
assert.equal(resolver.hostsBarWindow(off), false);
}
});
+36 -1
View File
@@ -2,6 +2,7 @@ import QtQuick
import Quickshell
import qs.Common
import qs.Services
import qs.Modules.DankBar
import qs.Modules.DankIsland
import qs.DankCommon.Common as DC
@@ -9,6 +10,7 @@ ShellRoot {
id: root
property var hosts: []
property bool hostsChecked: false
Component {
id: hostComponent
@@ -34,7 +36,7 @@ ShellRoot {
SettingsData.frameEnabled = false;
SettingsData.barConfigs = [
{ id: "dot", enabled: true, visible: true, dot: true, position: 0 },
{ id: "vertical", enabled: true, visible: true, island: true, islandFloating: true, islandPlacement: "free", position: 2 }
{ id: "vertical", enabled: true, visible: true, island: true, islandFloating: true, islandPlacement: "free", position: 2, islandSatellitePosition: "island", leftWidgets: ["clock"], rightWidgets: ["clock"] }
];
root.hosts = SettingsData.barConfigs.map(config => hostComponent.createObject(root, { barId: config.id, screen: Quickshell.screens[0] }));
}
@@ -65,6 +67,39 @@ ShellRoot {
surface.surfaceMotion.settle();
root.check(!surface.motionRunning, "idle motion stops");
}
root.hostsChecked = true;
} catch (error) {
console.error("FIXTURE_FAIL", error.message);
Qt.quit();
}
}
}
Item {
Repeater {
id: bars
model: root.hostsChecked ? SettingsData.barConfigs : []
delegate: DankBar {
required property var modelData
barConfig: modelData
}
}
}
Timer {
interval: 0
readonly property var band: bars.count === 2 ? bars.itemAt(1).barVariants.instances[0] ?? null : null
running: !!band && band.height === band.screen.height && band.width < band.height
onTriggered: {
try {
root.check(bars.itemAt(0).barVariants.instances.length === 0, "a dot has no satellite window");
const band = bars.itemAt(1).barVariants.instances[0];
root.check(bars.itemAt(1).barVariants.instances.length === 1 && !band.islandHost, "a free island keeps one satellite window without a pill");
root.check(band.exclusiveZone <= 0, "the satellite window reserves nothing");
const leading = band.leadingSectionRect;
const trailing = band.trailingSectionRect;
root.check(leading.y + leading.h <= trailing.y, "near island keeps left before right");
root.check(Math.abs((leading.y + trailing.y + trailing.h) / 2 - band.height / 2) <= 2, "near island gathers at the edge centre");
console.log("FIXTURE_PASS");
} catch (error) {
console.error("FIXTURE_FAIL", error.message);
+1 -1
View File
@@ -139,7 +139,7 @@ with tempfile.TemporaryDirectory(prefix="dms-surface-test-") as temporary:
if mpris:
start_dbus(fixture_env, processes)
processes.append(subprocess.Popen([sys.executable, str(repo / "quickshell/tests/fixtures/mpris_player.py")] + (["--artwork"] if "--artwork" in sys.argv else []), env=fixture_env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL))
result = subprocess.run(["qs", "-p", str(home / "qml")], env=fixture_env, capture_output=True, text=True, timeout=60)
result = subprocess.run(["qs", "-p", str(home / "qml")], env=fixture_env, capture_output=True, text=True, timeout=180)
output = result.stdout + result.stderr
failed = bool(result.returncode) or "FIXTURE_PASS" not in output or "FIXTURE_FAIL" in output
except subprocess.TimeoutExpired as expired:
@@ -99,7 +99,6 @@ TAB_INDEX_MAP = {
"KeybindsTab.qml": 2,
"DankBarTab.qml": 3,
"DankDashTab.qml": 43,
"DankIslandTab.qml": 46,
"CompositorLayoutTab.qml": 37,
"WindowRulesTab.qml": 38,
"DockGeneralTab.qml": 5,
@@ -107,6 +106,7 @@ TAB_INDEX_MAP = {
"DockAppearanceTab.qml": 58,
"DockAdvancedTab.qml": 59,
"DankBarAppearanceTab.qml": 6,
"DankBarAdvancedTab.qml": 64,
"NetworkStatusTab.qml": 7,
"NetworkEthernetTab.qml": 39,
"NetworkWifiTab.qml": 40,
@@ -141,7 +141,6 @@ TAB_INDEX_MAP = {
"LocaleTab.qml": 30,
"GreeterTab.qml": 31,
"MuxTab.qml": 32,
"FrameTab.qml": 33,
"DefaultAppsTab.qml": 34,
"UsersTab.qml": 35,
"UserAccountsTab.qml": 60,
@@ -165,8 +164,6 @@ SIDEBAR_GATE_CONDITIONS = [
("pointerCapable", "pointerCapable"),
("windowRulesCapable", "windowRulesCapable"),
("layoutCapable", "layoutCapable"),
("frameOnly", "frameEnabled"),
("islandOnly", "islandEnabled"),
("cellularOnly", "cellularAvailable"),
]
@@ -183,6 +180,9 @@ FILE_PAGE_MAP = {
TAB_META_DEFAULT = ("Settings", None, None)
# Frame and island rows live on the bar pages; ungated ones still need their feature on.
BAR_TAB_FILES = {"DankBarTab.qml", "DankBarAppearanceTab.qml", "DankBarAdvancedTab.qml"}
SEARCHABLE_COMPONENTS = [
"SettingsCard",
"SettingsToggleRow",
@@ -383,7 +383,7 @@ def find_settings_components(content, filename, wrappers, tab_meta, hub_meta):
if tags_raw:
tags = extract_tags(tags_raw)
desc_raw = extract_property(block, "description") or defaults.get("description")
desc_raw = extract_property(block, "description") or extract_property(block, "summary") or defaults.get("description")
description = None
if desc_raw:
description = extract_i18n_string(desc_raw)
@@ -435,6 +435,11 @@ def find_settings_components(content, filename, wrappers, tab_meta, hub_meta):
condition_key = "dmsConnected"
elif "Theme.matugenAvailable" in visible_raw:
condition_key = "matugenAvailable"
if filename in BAR_TAB_FILES and not condition_key:
if setting_key.startswith("frame"):
condition_key = "frameEnabled"
elif setting_key.startswith("island"):
condition_key = "islandEnabled"
category, parent_label, _ = page_meta if page_meta else tab_meta.get(tab_index, TAB_META_DEFAULT)
enriched_keywords = enrich_keywords(label, description, category, tags, parent_label)
@@ -679,12 +684,12 @@ def extract_settings_index(root_dir, tab_meta, hub_meta):
)
if "islandHomeLayout" not in seen_keys:
category, parent_label, _ = tab_meta.get(46, TAB_META_DEFAULT)
category, parent_label, _ = tab_meta.get(3, TAB_META_DEFAULT)
all_entries.append(
{
"section": "islandHomeLayout",
"label": "Home Layout",
"tabIndex": 46,
"tabIndex": 3,
"category": category,
"parentLabel": parent_label,
"keywords": enrich_keywords(
File diff suppressed because it is too large Load Diff