diff --git a/quickshell/Common/Anims.qml b/quickshell/Common/Anims.qml index f8e0c9a5..d3ed05de 100644 --- a/quickshell/Common/Anims.qml +++ b/quickshell/Common/Anims.qml @@ -11,6 +11,10 @@ Singleton { readonly property int durMed: 450 readonly property int durLong: 600 + // Navigation feedback stays responsive even when ambient shell motion is slow. + readonly property int settingsNavigationStateDuration: 180 + readonly property int settingsNavigationRippleDuration: 200 + readonly property int slidePx: 80 readonly property var emphasized: [0.05, 0.00, 0.133333, 0.06, 0.166667, 0.40, 0.208333, 0.82, 0.25, 1.00, 1.00, 1.00] diff --git a/quickshell/Common/SettingsUiState.qml b/quickshell/Common/SettingsUiState.qml new file mode 100644 index 00000000..0d3f9475 --- /dev/null +++ b/quickshell/Common/SettingsUiState.qml @@ -0,0 +1,25 @@ +pragma Singleton + +import QtQuick +import Quickshell +import qs.Common + +Singleton { + id: root + + property string selectedBarId: "default" + + function normalizeSelectedBar() { + if (SettingsData.getBarConfig(selectedBarId)) + return; + selectedBarId = SettingsData.barConfigs[0]?.id ?? "default"; + } + + Connections { + target: SettingsData + + function onBarConfigsChanged() { + root.normalizeSelectedBar(); + } + } +} diff --git a/quickshell/DMSShellIPC.qml b/quickshell/DMSShellIPC.qml index 55c41c2b..1586ad02 100644 --- a/quickshell/DMSShellIPC.qml +++ b/quickshell/DMSShellIPC.qml @@ -947,7 +947,7 @@ Item { function tabs(): string { if (!PopoutService.settingsModal) - return "wallpaper\ntheme\ntypography\ntime_weather\nsounds\ndankbar\ndankbar_settings\ndankbar_widgets\nworkspaces\nmedia_player\nnotifications\nosd\nrunning_apps\nupdater\ndock\nlauncher\nkeybinds\ndisplays\nnetwork\nprinters\nlock_screen\npower_sleep\nplugins\nabout"; + return "wallpaper\ntheme\ntypography\ntime_weather\nsounds\ndankbar\ndankbar_settings\ndankbar_appearance\ndankbar_widgets\nframe\nworkspaces\ncompositor\nmedia_player\nnotifications\nosd\nrunning_apps\nupdater\ndock\nlauncher\nkeybinds\ndisplays\nnetwork\nprinters\nlock_screen\npower_sleep\nplugins\nabout"; var modal = PopoutService.settingsModal; var ids = []; var structure = modal.sidebar?.categoryStructure ?? []; diff --git a/quickshell/Modals/Settings/SettingsContent.qml b/quickshell/Modals/Settings/SettingsContent.qml index 5a038716..90a01e6d 100644 --- a/quickshell/Modals/Settings/SettingsContent.qml +++ b/quickshell/Modals/Settings/SettingsContent.qml @@ -1,6 +1,7 @@ import QtQuick import qs.Common import qs.Modules.Settings +import qs.Widgets FocusScope { id: root @@ -97,7 +98,24 @@ FocusScope { visible: active focus: active - sourceComponent: WorkspacesTab {} + sourceComponent: CompositorTab {} + + onActiveChanged: { + if (active && item) + Qt.callLater(() => item.forceActiveFocus()); + } + } + + Loader { + id: dankBarAppearanceLoader + anchors.fill: parent + active: root.currentIndex === 6 + visible: active + focus: active + + sourceComponent: DankBarAppearanceTab { + parentModal: root.parentModal + } onActiveChanged: { if (active && item) @@ -432,19 +450,36 @@ FocusScope { Loader { id: widgetsLoader + + property bool loadedOnce: false + anchors.fill: parent - active: root.currentIndex === 22 - visible: active - focus: active + active: root.currentIndex === 22 || loadedOnce + visible: root.currentIndex === 22 && status === Loader.Ready + focus: visible + asynchronous: true sourceComponent: WidgetsTab { parentModal: root.parentModal } - onActiveChanged: { - if (active && item) + onLoaded: { + loadedOnce = true; + if (visible && item) Qt.callLater(() => item.forceActiveFocus()); } + onVisibleChanged: { + if (visible && item) + Qt.callLater(() => item.forceActiveFocus()); + } + } + + StyledText { + anchors.centerIn: parent + visible: root.currentIndex === 22 && widgetsLoader.status === Loader.Loading + text: I18n.tr("Loading...", "loading indicator") + color: Theme.surfaceVariantText + font.pixelSize: Theme.fontSizeMedium } Loader { @@ -479,23 +514,6 @@ FocusScope { } } - Loader { - id: windowRulesLoader - anchors.fill: parent - active: root.currentIndex === 28 - visible: active - focus: active - - sourceComponent: WindowRulesTab { - parentModal: root.parentModal - } - - onActiveChanged: { - if (active && item) - Qt.callLater(() => item.forceActiveFocus()); - } - } - Loader { id: audioLoader anchors.fill: parent diff --git a/quickshell/Modals/Settings/SettingsSidebar.qml b/quickshell/Modals/Settings/SettingsSidebar.qml index 303e185a..d53ede18 100644 --- a/quickshell/Modals/Settings/SettingsSidebar.qml +++ b/quickshell/Modals/Settings/SettingsSidebar.qml @@ -23,6 +23,7 @@ Rectangle { property bool searchActive: searchField.text.length > 0 property int searchSelectedIndex: 0 property int keyboardHighlightIndex: -1 + readonly property int navigationStateDuration: Theme.currentAnimationSpeed === SettingsData.AnimationSpeed.None ? 0 : Anims.settingsNavigationStateDuration function focusSearch() { searchField.forceActiveFocus(); @@ -115,6 +116,12 @@ Rectangle { "icon": "tune", "tabIndex": 3 }, + { + "id": "dankbar_appearance", + "text": I18n.tr("Appearance"), + "icon": "palette", + "tabIndex": 6 + }, { "id": "dankbar_widgets", "text": I18n.tr("Widgets"), @@ -131,16 +138,10 @@ Rectangle { }, { "id": "workspaces_widgets", - "text": I18n.tr("Workspaces & Widgets"), + "text": I18n.tr("Widgets & Notifications"), "icon": "dashboard", "collapsedByDefault": true, "children": [ - { - "id": "workspaces", - "text": I18n.tr("Workspaces"), - "icon": "view_module", - "tabIndex": 4 - }, { "id": "media_player", "text": I18n.tr("Media Player"), @@ -187,6 +188,12 @@ Rectangle { } ] }, + { + "id": "compositor", + "text": I18n.tr("Compositor"), + "icon": "layers", + "tabIndex": 4 + }, { "id": "keybinds", "text": I18n.tr("Keyboard Shortcuts"), @@ -305,13 +312,6 @@ Rectangle { "text": I18n.tr("Users"), "icon": "manage_accounts", "tabIndex": 35 - }, - { - "id": "window_rules", - "text": I18n.tr("Window Rules"), - "icon": "select_window", - "tabIndex": 28, - "windowRulesCapable": true } ] }, @@ -544,6 +544,8 @@ Rectangle { return -1; var normalized = name.toLowerCase().replace(/[_\-\s]/g, ""); + if (normalized === "workspaces") + normalized = "compositor"; for (var i = 0; i < categoryStructure.length; i++) { var cat = categoryStructure[i]; @@ -588,7 +590,7 @@ Rectangle { id: __m1 font.pixelSize: Theme.fontSizeMedium font.weight: Font.Medium - text: I18n.tr("Workspaces & Widgets") + text: I18n.tr("Widgets & Notifications") } StyledTextMetrics { id: __m2 @@ -782,6 +784,7 @@ Rectangle { id: resultRipple rippleColor: root.searchSelectedIndex === resultDelegate.index ? Theme.buttonText : Theme.surfaceText cornerRadius: resultDelegate.radius + animationDuration: Anims.settingsNavigationRippleDuration } Row { @@ -837,8 +840,9 @@ Rectangle { Behavior on color { ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing + duration: root.navigationStateDuration + easing.type: Easing.BezierSpline + easing.bezierCurve: Anims.expressiveEffects } } } @@ -912,6 +916,7 @@ Rectangle { id: categoryRipple rippleColor: categoryRow.isActive ? Theme.buttonText : Theme.surfaceText cornerRadius: categoryRow.radius + animationDuration: Anims.settingsNavigationRippleDuration } Row { @@ -967,8 +972,9 @@ Rectangle { Behavior on color { ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing + duration: root.navigationStateDuration + easing.type: Easing.BezierSpline + easing.bezierCurve: Anims.expressiveEffects } } } @@ -1009,6 +1015,7 @@ Rectangle { id: childRipple rippleColor: childDelegate.isActive ? Theme.buttonText : Theme.surfaceText cornerRadius: childDelegate.radius + animationDuration: Anims.settingsNavigationRippleDuration } Row { @@ -1049,8 +1056,9 @@ Rectangle { Behavior on color { ColorAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing + duration: root.navigationStateDuration + easing.type: Easing.BezierSpline + easing.bezierCurve: Anims.expressiveEffects } } } diff --git a/quickshell/Modules/Settings/CompositorLayoutTab.qml b/quickshell/Modules/Settings/CompositorLayoutTab.qml new file mode 100644 index 00000000..98add06b --- /dev/null +++ b/quickshell/Modules/Settings/CompositorLayoutTab.qml @@ -0,0 +1,324 @@ +import QtQuick +import qs.Common +import qs.Services +import qs.Widgets +import qs.Modules.Settings.Widgets + +Item { + DankFlickable { + anchors.fill: parent + clip: true + contentHeight: layoutColumn.height + Theme.spacingXL + contentWidth: width + + Column { + id: layoutColumn + + topPadding: Theme.spacingXL + bottomPadding: Theme.spacingXL + width: Math.min(550, parent.width - Theme.spacingL * 2) + anchors.horizontalCenter: parent.horizontalCenter + spacing: Theme.spacingXL + + SettingsCard { + width: parent.width + tags: ["niri", "layout", "gaps", "radius", "window", "border"] + title: I18n.tr("Niri Layout Overrides").replace("Niri", "niri") + settingKey: "niriLayout" + iconName: "crop_square" + visible: CompositorService.isNiri + + SettingsToggleRow { + tags: ["niri", "gaps", "override"] + settingKey: "niriLayoutGapsOverrideEnabled" + text: I18n.tr("Override Gaps") + description: I18n.tr("Use custom gaps instead of bar spacing") + checked: SettingsData.niriLayoutGapsOverride >= 0 + onToggled: checked => { + if (checked) { + const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); + SettingsData.set("niriLayoutGapsOverride", currentGaps); + return; + } + SettingsData.set("niriLayoutGapsOverride", -1); + } + } + + SettingsSliderRow { + tags: ["niri", "gaps", "override"] + settingKey: "niriLayoutGapsOverride" + text: I18n.tr("Window Gaps") + description: I18n.tr("Space between windows") + visible: SettingsData.niriLayoutGapsOverride >= 0 + value: Math.max(0, SettingsData.niriLayoutGapsOverride) + minimum: 0 + maximum: 50 + unit: "px" + defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) + onSliderValueChanged: newValue => SettingsData.set("niriLayoutGapsOverride", newValue) + } + + SettingsToggleRow { + tags: ["niri", "radius", "override"] + settingKey: "niriLayoutRadiusOverrideEnabled" + text: I18n.tr("Override Corner Radius") + description: I18n.tr("Use custom window radius instead of theme radius") + checked: SettingsData.niriLayoutRadiusOverride >= 0 + onToggled: checked => { + if (checked) { + SettingsData.set("niriLayoutRadiusOverride", SettingsData.cornerRadius); + return; + } + SettingsData.set("niriLayoutRadiusOverride", -1); + } + } + + SettingsSliderRow { + tags: ["niri", "radius", "override"] + settingKey: "niriLayoutRadiusOverride" + text: I18n.tr("Window Corner Radius") + description: I18n.tr("Rounded corners for windows") + visible: SettingsData.niriLayoutRadiusOverride >= 0 + value: Math.max(0, SettingsData.niriLayoutRadiusOverride) + minimum: 0 + maximum: 100 + unit: "px" + defaultValue: SettingsData.cornerRadius + onSliderValueChanged: newValue => SettingsData.set("niriLayoutRadiusOverride", newValue) + } + + SettingsToggleRow { + tags: ["niri", "border", "override"] + settingKey: "niriLayoutBorderSizeEnabled" + text: I18n.tr("Override Border Size") + description: I18n.tr("Use custom border/focus-ring width") + checked: SettingsData.niriLayoutBorderSize >= 0 + onToggled: checked => { + if (checked) { + SettingsData.set("niriLayoutBorderSize", 2); + return; + } + SettingsData.set("niriLayoutBorderSize", -1); + } + } + + SettingsSliderRow { + tags: ["niri", "border", "override"] + settingKey: "niriLayoutBorderSize" + text: I18n.tr("Border Size") + description: I18n.tr("Width of window border and focus ring") + visible: SettingsData.niriLayoutBorderSize >= 0 + value: Math.max(0, SettingsData.niriLayoutBorderSize) + minimum: 0 + maximum: 10 + unit: "px" + defaultValue: 2 + onSliderValueChanged: newValue => SettingsData.set("niriLayoutBorderSize", newValue) + } + } + + SettingsCard { + width: parent.width + tags: ["hyprland", "layout", "gaps", "radius", "window", "border", "rounding"] + title: I18n.tr("Hyprland Layout Overrides") + settingKey: "hyprlandLayout" + iconName: "crop_square" + visible: CompositorService.isHyprland + + SettingsToggleRow { + tags: ["hyprland", "gaps", "override"] + settingKey: "hyprlandLayoutGapsOverrideEnabled" + text: I18n.tr("Override Gaps") + description: I18n.tr("Use custom gaps instead of bar spacing") + checked: SettingsData.hyprlandLayoutGapsOverride >= 0 + onToggled: checked => { + if (checked) { + const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); + SettingsData.set("hyprlandLayoutGapsOverride", currentGaps); + return; + } + SettingsData.set("hyprlandLayoutGapsOverride", -1); + } + } + + SettingsSliderRow { + tags: ["hyprland", "gaps", "override"] + settingKey: "hyprlandLayoutGapsOverride" + text: I18n.tr("Window Gaps") + description: I18n.tr("Space between windows (gaps_in and gaps_out)") + visible: SettingsData.hyprlandLayoutGapsOverride >= 0 + value: Math.max(0, SettingsData.hyprlandLayoutGapsOverride) + minimum: 0 + maximum: 50 + unit: "px" + defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) + onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutGapsOverride", newValue) + } + + SettingsToggleRow { + tags: ["hyprland", "radius", "override", "rounding"] + settingKey: "hyprlandLayoutRadiusOverrideEnabled" + text: I18n.tr("Override Corner Radius") + description: I18n.tr("Use custom window rounding instead of theme radius") + checked: SettingsData.hyprlandLayoutRadiusOverride >= 0 + onToggled: checked => { + if (checked) { + SettingsData.set("hyprlandLayoutRadiusOverride", SettingsData.cornerRadius); + return; + } + SettingsData.set("hyprlandLayoutRadiusOverride", -1); + } + } + + SettingsSliderRow { + tags: ["hyprland", "radius", "override", "rounding"] + settingKey: "hyprlandLayoutRadiusOverride" + text: I18n.tr("Window Rounding") + description: I18n.tr("Rounded corners for windows (decoration.rounding)") + visible: SettingsData.hyprlandLayoutRadiusOverride >= 0 + value: Math.max(0, SettingsData.hyprlandLayoutRadiusOverride) + minimum: 0 + maximum: 100 + unit: "px" + defaultValue: SettingsData.cornerRadius + onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutRadiusOverride", newValue) + } + + SettingsToggleRow { + tags: ["hyprland", "border", "override"] + settingKey: "hyprlandLayoutBorderSizeEnabled" + text: I18n.tr("Override Border Size") + description: I18n.tr("Use custom border size") + checked: SettingsData.hyprlandLayoutBorderSize >= 0 + onToggled: checked => { + if (checked) { + SettingsData.set("hyprlandLayoutBorderSize", 2); + return; + } + SettingsData.set("hyprlandLayoutBorderSize", -1); + } + } + + SettingsSliderRow { + tags: ["hyprland", "border", "override"] + settingKey: "hyprlandLayoutBorderSize" + text: I18n.tr("Border Size") + description: I18n.tr("Width of window border (general.border_size)") + visible: SettingsData.hyprlandLayoutBorderSize >= 0 + value: Math.max(0, SettingsData.hyprlandLayoutBorderSize) + minimum: 0 + maximum: 10 + unit: "px" + defaultValue: 2 + onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutBorderSize", newValue) + } + + SettingsToggleRow { + tags: ["hyprland", "resize", "border", "mouse", "drag"] + settingKey: "hyprlandResizeOnBorder" + text: I18n.tr("Resize on Border") + description: I18n.tr("Resize windows by dragging their edges with the mouse") + checked: SettingsData.hyprlandResizeOnBorder + onToggled: checked => SettingsData.set("hyprlandResizeOnBorder", checked) + } + } + + SettingsCard { + width: parent.width + tags: ["mangowc", "mango", "dwl", "layout", "gaps", "radius", "window", "border"] + title: I18n.tr("MangoWC Layout Overrides") + settingKey: "mangoLayout" + iconName: "crop_square" + visible: CompositorService.isDwl || CompositorService.isMango + + SettingsToggleRow { + tags: ["mangowc", "mango", "gaps", "override"] + settingKey: "mangoLayoutGapsOverrideEnabled" + text: I18n.tr("Override Gaps") + description: I18n.tr("Use custom gaps instead of bar spacing") + checked: SettingsData.mangoLayoutGapsOverride >= 0 + onToggled: checked => { + if (checked) { + const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); + SettingsData.set("mangoLayoutGapsOverride", currentGaps); + return; + } + SettingsData.set("mangoLayoutGapsOverride", -1); + } + } + + SettingsSliderRow { + tags: ["mangowc", "mango", "gaps", "override"] + settingKey: "mangoLayoutGapsOverride" + text: I18n.tr("Window Gaps") + description: I18n.tr("Space between windows (gappih/gappiv/gappoh/gappov)") + visible: SettingsData.mangoLayoutGapsOverride >= 0 + value: Math.max(0, SettingsData.mangoLayoutGapsOverride) + minimum: 0 + maximum: 50 + unit: "px" + defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) + onSliderValueChanged: newValue => SettingsData.set("mangoLayoutGapsOverride", newValue) + } + + SettingsToggleRow { + tags: ["mangowc", "mango", "radius", "override"] + settingKey: "mangoLayoutRadiusOverrideEnabled" + text: I18n.tr("Override Corner Radius") + description: I18n.tr("Use custom window radius instead of theme radius") + checked: SettingsData.mangoLayoutRadiusOverride >= 0 + onToggled: checked => { + if (checked) { + SettingsData.set("mangoLayoutRadiusOverride", SettingsData.cornerRadius); + return; + } + SettingsData.set("mangoLayoutRadiusOverride", -1); + } + } + + SettingsSliderRow { + tags: ["mangowc", "mango", "radius", "override"] + settingKey: "mangoLayoutRadiusOverride" + text: I18n.tr("Window Corner Radius") + description: I18n.tr("Rounded corners for windows (border_radius)") + visible: SettingsData.mangoLayoutRadiusOverride >= 0 + value: Math.max(0, SettingsData.mangoLayoutRadiusOverride) + minimum: 0 + maximum: 100 + unit: "px" + defaultValue: SettingsData.cornerRadius + onSliderValueChanged: newValue => SettingsData.set("mangoLayoutRadiusOverride", newValue) + } + + SettingsToggleRow { + tags: ["mangowc", "mango", "border", "override"] + settingKey: "mangoLayoutBorderSizeEnabled" + text: I18n.tr("Override Border Size") + description: I18n.tr("Use custom border size") + checked: SettingsData.mangoLayoutBorderSize >= 0 + onToggled: checked => { + if (checked) { + SettingsData.set("mangoLayoutBorderSize", 2); + return; + } + SettingsData.set("mangoLayoutBorderSize", -1); + } + } + + SettingsSliderRow { + tags: ["mangowc", "mango", "border", "override"] + settingKey: "mangoLayoutBorderSize" + text: I18n.tr("Border Size") + description: I18n.tr("Width of window border (borderpx)") + visible: SettingsData.mangoLayoutBorderSize >= 0 + value: Math.max(0, SettingsData.mangoLayoutBorderSize) + minimum: 0 + maximum: 10 + unit: "px" + defaultValue: 2 + onSliderValueChanged: newValue => SettingsData.set("mangoLayoutBorderSize", newValue) + } + } + } + } +} diff --git a/quickshell/Modules/Settings/CompositorTab.qml b/quickshell/Modules/Settings/CompositorTab.qml new file mode 100644 index 00000000..9ca275ff --- /dev/null +++ b/quickshell/Modules/Settings/CompositorTab.qml @@ -0,0 +1,167 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import qs.Common +import qs.Services +import qs.Widgets + +Item { + id: root + + LayoutMirroring.enabled: I18n.isRtl + LayoutMirroring.childrenInherit: true + + property int subTabIndex: 0 + + readonly property var workspaceSections: ({ + "workspaceSettings": true, + "showWorkspaceIndex": true, + "showWorkspaceName": true, + "showWorkspacePadding": true, + "showWorkspaceApps": true, + "groupWorkspaceApps": true, + "groupActiveWorkspaceApps": true, + "workspaceActiveAppHighlightEnabled": true, + "workspaceFollowFocus": true, + "showOccupiedWorkspacesOnly": true, + "reverseScrolling": true, + "workspaceDragReorder": true, + "dwlShowAllTags": true, + "workspaceIcons": true + }) + readonly property var layoutSections: ({ + "niriLayout": true, + "niriLayoutGapsOverrideEnabled": true, + "niriLayoutGapsOverride": true, + "niriLayoutRadiusOverrideEnabled": true, + "niriLayoutRadiusOverride": true, + "niriLayoutBorderSizeEnabled": true, + "niriLayoutBorderSize": true, + "hyprlandLayout": true, + "hyprlandLayoutGapsOverrideEnabled": true, + "hyprlandLayoutGapsOverride": true, + "hyprlandLayoutRadiusOverrideEnabled": true, + "hyprlandLayoutRadiusOverride": true, + "hyprlandLayoutBorderSizeEnabled": true, + "hyprlandLayoutBorderSize": true, + "hyprlandResizeOnBorder": true, + "mangoLayout": true, + "mangoLayoutGapsOverrideEnabled": true, + "mangoLayoutGapsOverride": true, + "mangoLayoutRadiusOverrideEnabled": true, + "mangoLayoutRadiusOverride": true, + "mangoLayoutBorderSizeEnabled": true, + "mangoLayoutBorderSize": true + }) + + function routeSearchTarget(target) { + if (!target) + return; + if (workspaceSections[target]) { + subTabIndex = 0; + } else if (layoutSections[target]) { + subTabIndex = 1; + } else if (target === "windowRules" || target.startsWith("windowRule")) { + subTabIndex = 2; + } + } + + Component.onCompleted: routeSearchTarget(SettingsSearchService.targetSection) + + Connections { + target: SettingsSearchService + + function onTargetSectionChanged() { + root.routeSearchTarget(SettingsSearchService.targetSection); + } + } + + ColumnLayout { + anchors.fill: parent + spacing: 0 + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: 60 + color: "transparent" + + DankTabBar { + id: compositorTabBar + + width: Math.min(500, parent.width - Theme.spacingL * 2) + height: 45 + anchors.centerIn: parent + model: [ + { + "text": I18n.tr("Workspaces"), + "icon": "view_module" + }, + { + "text": I18n.tr("Window Layout"), + "icon": "crop_square" + }, + { + "text": I18n.tr("Window Rules"), + "icon": "select_window" + } + ] + currentIndex: root.subTabIndex + onTabClicked: index => root.subTabIndex = index + } + + Rectangle { + anchors.horizontalCenter: parent.horizontalCenter + y: compositorTabBar.y + compositorTabBar.height + 10 + width: compositorTabBar.width + height: 1 + color: Theme.surface + opacity: 0.56 + } + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + + Loader { + anchors.fill: parent + active: root.subTabIndex === 0 + visible: active + sourceComponent: WorkspacesTab {} + } + + Loader { + anchors.fill: parent + active: root.subTabIndex === 1 + visible: active + sourceComponent: CompositorLayoutTab {} + } + + Loader { + id: windowRulesLoader + + property bool loadedOnce: false + + anchors.fill: parent + active: root.subTabIndex === 2 || loadedOnce + visible: root.subTabIndex === 2 && status === Loader.Ready + asynchronous: true + sourceComponent: WindowRulesTab { + pageActive: root.subTabIndex === 2 + } + + onLoaded: loadedOnce = true + } + + StyledText { + anchors.centerIn: parent + visible: root.subTabIndex === 2 && windowRulesLoader.status === Loader.Loading + text: I18n.tr("Loading...", "loading indicator") + color: Theme.surfaceVariantText + font.pixelSize: Theme.fontSizeMedium + } + } + } +} diff --git a/quickshell/Modules/Settings/DankBarAppearanceTab.qml b/quickshell/Modules/Settings/DankBarAppearanceTab.qml new file mode 100644 index 00000000..0b74d5db --- /dev/null +++ b/quickshell/Modules/Settings/DankBarAppearanceTab.qml @@ -0,0 +1,5 @@ +import QtQuick + +DankBarTab { + appearanceOnly: true +} diff --git a/quickshell/Modules/Settings/DankBarTab.qml b/quickshell/Modules/Settings/DankBarTab.qml index 0944c665..9a338b09 100644 --- a/quickshell/Modules/Settings/DankBarTab.qml +++ b/quickshell/Modules/Settings/DankBarTab.qml @@ -13,7 +13,22 @@ Item { LayoutMirroring.childrenInherit: true property var parentModal: null - property string selectedBarId: "default" + property bool appearanceOnly: false + property string selectedBarId: SettingsUiState.selectedBarId + + onSelectedBarIdChanged: { + if (SettingsUiState.selectedBarId !== selectedBarId) + SettingsUiState.selectedBarId = selectedBarId; + } + + Connections { + target: SettingsUiState + + function onSelectedBarIdChanged() { + if (dankBarTab.selectedBarId !== SettingsUiState.selectedBarId) + dankBarTab.selectedBarId = SettingsUiState.selectedBarId; + } + } property var selectedBarConfig: { selectedBarId; @@ -21,6 +36,14 @@ Item { const index = SettingsData.barConfigs.findIndex(cfg => cfg.id === selectedBarId); return index !== -1 ? SettingsData.barConfigs[index] : SettingsData.barConfigs[0]; } + readonly property string selectedBarName: { + selectedBarId; + SettingsData.barConfigs; + const index = SettingsData.barConfigs.findIndex(config => config.id === selectedBarId); + if (index < 0) + return I18n.tr("Bar"); + return SettingsData.barConfigs[index].name || I18n.tr("Bar %1").arg(index + 1); + } property bool selectedBarIsVertical: { selectedBarId; @@ -210,10 +233,33 @@ Item { anchors.horizontalCenter: parent.horizontalCenter spacing: Theme.spacingXL + SettingsCard { + tab: "appearance" + iconName: "toolbar" + title: I18n.tr("Dank Bar") + settingKey: "barAppearance" + visible: dankBarTab.appearanceOnly + + SettingsButtonGroupRow { + text: I18n.tr("Editing changes on %1").arg(dankBarTab.selectedBarName) + model: SettingsData.barConfigs.map((config, index) => config.name || I18n.tr("Bar %1").arg(index + 1)) + currentIndex: { + const index = SettingsData.barConfigs.findIndex(config => config.id === dankBarTab.selectedBarId); + return Math.max(0, index); + } + onSelectionChanged: (index, selected) => { + if (!selected || index < 0 || index >= SettingsData.barConfigs.length) + return; + dankBarTab.selectedBarId = SettingsData.barConfigs[index].id; + } + } + } + SettingsCard { iconName: "dashboard" title: I18n.tr("Bar Configurations") settingKey: "barConfigurations" + visible: !dankBarTab.appearanceOnly RowLayout { width: parent.width @@ -410,7 +456,7 @@ Item { SettingsCard { iconName: selectedBarConfig?.enabled ? "visibility" : "visibility_off" title: I18n.tr("Enable Bar") - visible: selectedBarId !== "default" + visible: !dankBarTab.appearanceOnly && selectedBarId !== "default" SettingsToggleRow { text: I18n.tr("Toggle visibility of this bar configuration") @@ -426,7 +472,7 @@ Item { iconName: "vertical_align_center" title: I18n.tr("Position") settingKey: "barPosition" - visible: selectedBarConfig?.enabled + visible: !dankBarTab.appearanceOnly && selectedBarConfig?.enabled Item { width: parent.width @@ -486,7 +532,7 @@ Item { settingKey: "barDisplay" collapsible: true expanded: false - visible: selectedBarConfig?.enabled + visible: !dankBarTab.appearanceOnly && selectedBarConfig?.enabled StyledText { width: parent.width @@ -588,12 +634,12 @@ Item { } SettingsCard { - iconName: "visibility_off" + iconName: "visibility" title: I18n.tr("Visibility") settingKey: "barVisibility" collapsible: true - expanded: false - visible: selectedBarConfig?.enabled + expanded: true + visible: !dankBarTab.appearanceOnly && selectedBarConfig?.enabled SettingsToggleRow { text: I18n.tr("Auto-hide") @@ -751,7 +797,7 @@ Item { } SettingsControlledByFrame { - visible: SettingsData.frameEnabled + visible: !dankBarTab.appearanceOnly && SettingsData.frameEnabled parentModal: dankBarTab.parentModal settingLabel: I18n.tr("Bar spacing and size") reason: I18n.tr("Managed by Frame") @@ -761,7 +807,7 @@ Item { iconName: "space_bar" title: I18n.tr("Spacing") settingKey: "barSpacing" - visible: (selectedBarConfig?.enabled ?? false) && !SettingsData.frameEnabled + visible: !dankBarTab.appearanceOnly && (selectedBarConfig?.enabled ?? false) && !SettingsData.frameEnabled SettingsSliderRow { id: edgeSpacingSlider @@ -911,10 +957,11 @@ Item { } SettingsCard { + tab: "appearance" iconName: "opacity" title: I18n.tr("Transparency") settingKey: "barTransparency" - visible: selectedBarConfig?.enabled + visible: dankBarTab.appearanceOnly && selectedBarConfig?.enabled SettingsSliderRow { id: barTransparencySlider @@ -973,10 +1020,12 @@ Item { SettingsSliderCard { id: fontScaleSliderCard + tab: "appearance" + settingKey: "barFontScale" iconName: "text_fields" title: I18n.tr("Font Scale") description: I18n.tr("Scale DankBar font sizes independently") - visible: selectedBarConfig?.enabled + visible: dankBarTab.appearanceOnly && selectedBarConfig?.enabled minimum: 50 maximum: 200 value: Math.round((selectedBarConfig?.fontScale ?? 1.0) * 100) @@ -998,10 +1047,12 @@ Item { SettingsSliderCard { id: iconScaleSliderCard + tab: "appearance" + settingKey: "barIconScale" iconName: "interests" title: I18n.tr("Icon Scale") description: I18n.tr("Scale DankBar icon sizes independently") - visible: selectedBarConfig?.enabled + visible: dankBarTab.appearanceOnly && selectedBarConfig?.enabled minimum: 50 maximum: 200 value: Math.round((selectedBarConfig?.iconScale ?? 1.0) * 100) @@ -1021,13 +1072,18 @@ Item { } } + WorkspaceAppearanceCard { + visible: dankBarTab.appearanceOnly + } + SettingsCard { + tab: "appearance" iconName: "rounded_corner" title: I18n.tr("Corners & Background") settingKey: "barCorners" collapsible: true - expanded: false - visible: selectedBarConfig?.enabled + expanded: true + visible: dankBarTab.appearanceOnly && selectedBarConfig?.enabled SettingsControlledByFrame { visible: SettingsData.frameEnabled @@ -1144,7 +1200,7 @@ Item { iconName: "fit_screen" title: I18n.tr("Maximize Detection") description: I18n.tr("Remove gaps and border when windows are maximized") - visible: selectedBarConfig?.enabled && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isMango) + visible: !dankBarTab.appearanceOnly && selectedBarConfig?.enabled && (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isMango) checked: selectedBarConfig?.maximizeDetection ?? true onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { maximizeDetection: checked @@ -1152,10 +1208,11 @@ Item { } SettingsCard { + tab: "appearance" iconName: "filter_b_and_w" title: I18n.tr("System Tray Icon Tint") settingKey: "trayIconTint" - visible: selectedBarConfig?.enabled + visible: dankBarTab.appearanceOnly && selectedBarConfig?.enabled StyledText { text: I18n.tr("Choose monochrome or a theme color tint for system tray icons") @@ -1251,9 +1308,11 @@ Item { } SettingsToggleCard { + tab: "appearance" + settingKey: "barBorder" iconName: "border_style" title: I18n.tr("Border") - visible: selectedBarConfig?.enabled + visible: dankBarTab.appearanceOnly && selectedBarConfig?.enabled && !dankBarTab.connectedFrameModeActive checked: selectedBarConfig?.borderEnabled ?? false onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { borderEnabled: checked @@ -1344,9 +1403,11 @@ Item { } SettingsToggleCard { + tab: "appearance" + settingKey: "barWidgetOutline" iconName: "highlight" title: I18n.tr("Widget Outline") - visible: selectedBarConfig?.enabled + visible: dankBarTab.appearanceOnly && selectedBarConfig?.enabled checked: selectedBarConfig?.widgetOutlineEnabled ?? false onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { widgetOutlineEnabled: checked @@ -1437,7 +1498,7 @@ Item { } SettingsControlledByFrame { - visible: dankBarTab.connectedFrameModeActive + visible: dankBarTab.appearanceOnly && dankBarTab.connectedFrameModeActive parentModal: dankBarTab.parentModal settingLabel: I18n.tr("Bar shadow, border, and corners") reason: I18n.tr("Managed by Frame in Connected Mode") @@ -1445,12 +1506,13 @@ Item { SettingsCard { id: shadowCard + tab: "appearance" iconName: "layers" title: I18n.tr("Shadow Override", "bar shadow settings card") settingKey: "barShadow" collapsible: true expanded: false - visible: (selectedBarConfig?.enabled ?? false) && !dankBarTab.connectedFrameModeActive + visible: dankBarTab.appearanceOnly && (selectedBarConfig?.enabled ?? false) && !dankBarTab.connectedFrameModeActive readonly property bool shadowActive: (selectedBarConfig?.shadowIntensity ?? 0) > 0 readonly property bool isCustomColor: (selectedBarConfig?.shadowColorMode ?? "default") === "custom" @@ -1512,6 +1574,7 @@ Item { } SettingsDropdownRow { + tab: "appearance" visible: shadowCard.shadowActive text: I18n.tr("Direction Source", "bar shadow direction source") description: I18n.tr("Choose how this bar resolves shadow direction") @@ -1545,6 +1608,7 @@ Item { } SettingsDropdownRow { + tab: "appearance" visible: shadowCard.shadowActive && shadowCard.directionSource === "manual" text: I18n.tr("Manual Direction", "bar manual shadow direction") description: I18n.tr("Use a fixed shadow direction for this bar") @@ -1680,7 +1744,7 @@ Item { iconName: "mouse" title: I18n.tr("Scroll Wheel") description: I18n.tr("Control workspaces and columns by scrolling on the bar") - visible: selectedBarConfig?.enabled + visible: !dankBarTab.appearanceOnly && selectedBarConfig?.enabled checked: selectedBarConfig?.scrollEnabled ?? true onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { scrollEnabled: checked diff --git a/quickshell/Modules/Settings/ThemeColorsTab.qml b/quickshell/Modules/Settings/ThemeColorsTab.qml index 3380b7f2..beae61c6 100644 --- a/quickshell/Modules/Settings/ThemeColorsTab.qml +++ b/quickshell/Modules/Settings/ThemeColorsTab.qml @@ -1640,7 +1640,7 @@ Item { SettingsControlledByFrame { visible: themeColorsTab.connectedFrameModeActive parentModal: themeColorsTab.parentModal - settingLabel: I18n.tr("Surface Opacity") + settingLabel: I18n.tr("Transparency") reason: I18n.tr("Managed by Frame in Connected Mode") } @@ -1648,7 +1648,7 @@ Item { tab: "theme" tags: ["surface", "popup", "transparency", "opacity", "modal"] settingKey: "popupTransparency" - text: I18n.tr("Surface Opacity") + text: I18n.tr("Transparency") description: I18n.tr("Controls opacity of all popouts, modals, and their content layers") visible: !themeColorsTab.connectedFrameModeActive value: Math.round(SettingsData.popupTransparency * 100) @@ -1956,325 +1956,6 @@ Item { } } - SettingsCard { - tab: "theme" - tags: ["niri", "layout", "gaps", "radius", "window", "border"] - title: I18n.tr("Niri Layout Overrides").replace("Niri", "niri") - settingKey: "niriLayout" - iconName: "crop_square" - visible: CompositorService.isNiri - - SettingsToggleRow { - tab: "theme" - tags: ["niri", "gaps", "override"] - settingKey: "niriLayoutGapsOverrideEnabled" - text: I18n.tr("Override Gaps") - description: I18n.tr("Use custom gaps instead of bar spacing") - checked: SettingsData.niriLayoutGapsOverride >= 0 - onToggled: checked => { - if (checked) { - const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); - SettingsData.set("niriLayoutGapsOverride", currentGaps); - return; - } - SettingsData.set("niriLayoutGapsOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["niri", "gaps", "override"] - settingKey: "niriLayoutGapsOverride" - text: I18n.tr("Window Gaps") - description: I18n.tr("Space between windows") - visible: SettingsData.niriLayoutGapsOverride >= 0 - value: Math.max(0, SettingsData.niriLayoutGapsOverride) - minimum: 0 - maximum: 50 - unit: "px" - defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) - onSliderValueChanged: newValue => SettingsData.set("niriLayoutGapsOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["niri", "radius", "override"] - settingKey: "niriLayoutRadiusOverrideEnabled" - text: I18n.tr("Override Corner Radius") - description: I18n.tr("Use custom window radius instead of theme radius") - checked: SettingsData.niriLayoutRadiusOverride >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("niriLayoutRadiusOverride", SettingsData.cornerRadius); - return; - } - SettingsData.set("niriLayoutRadiusOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["niri", "radius", "override"] - settingKey: "niriLayoutRadiusOverride" - text: I18n.tr("Window Corner Radius") - description: I18n.tr("Rounded corners for windows") - visible: SettingsData.niriLayoutRadiusOverride >= 0 - value: Math.max(0, SettingsData.niriLayoutRadiusOverride) - minimum: 0 - maximum: 100 - unit: "px" - defaultValue: SettingsData.cornerRadius - onSliderValueChanged: newValue => SettingsData.set("niriLayoutRadiusOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["niri", "border", "override"] - settingKey: "niriLayoutBorderSizeEnabled" - text: I18n.tr("Override Border Size") - description: I18n.tr("Use custom border/focus-ring width") - checked: SettingsData.niriLayoutBorderSize >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("niriLayoutBorderSize", 2); - return; - } - SettingsData.set("niriLayoutBorderSize", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["niri", "border", "override"] - settingKey: "niriLayoutBorderSize" - text: I18n.tr("Border Size") - description: I18n.tr("Width of window border and focus ring") - visible: SettingsData.niriLayoutBorderSize >= 0 - value: Math.max(0, SettingsData.niriLayoutBorderSize) - minimum: 0 - maximum: 10 - unit: "px" - defaultValue: 2 - onSliderValueChanged: newValue => SettingsData.set("niriLayoutBorderSize", newValue) - } - } - - SettingsCard { - tab: "theme" - tags: ["hyprland", "layout", "gaps", "radius", "window", "border", "rounding"] - title: I18n.tr("Hyprland Layout Overrides") - settingKey: "hyprlandLayout" - iconName: "crop_square" - visible: CompositorService.isHyprland - - SettingsToggleRow { - tab: "theme" - tags: ["hyprland", "gaps", "override"] - settingKey: "hyprlandLayoutGapsOverrideEnabled" - text: I18n.tr("Override Gaps") - description: I18n.tr("Use custom gaps instead of bar spacing") - checked: SettingsData.hyprlandLayoutGapsOverride >= 0 - onToggled: checked => { - if (checked) { - const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); - SettingsData.set("hyprlandLayoutGapsOverride", currentGaps); - return; - } - SettingsData.set("hyprlandLayoutGapsOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["hyprland", "gaps", "override"] - settingKey: "hyprlandLayoutGapsOverride" - text: I18n.tr("Window Gaps") - description: I18n.tr("Space between windows (gaps_in and gaps_out)") - visible: SettingsData.hyprlandLayoutGapsOverride >= 0 - value: Math.max(0, SettingsData.hyprlandLayoutGapsOverride) - minimum: 0 - maximum: 50 - unit: "px" - defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) - onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutGapsOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["hyprland", "radius", "override", "rounding"] - settingKey: "hyprlandLayoutRadiusOverrideEnabled" - text: I18n.tr("Override Corner Radius") - description: I18n.tr("Use custom window rounding instead of theme radius") - checked: SettingsData.hyprlandLayoutRadiusOverride >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("hyprlandLayoutRadiusOverride", SettingsData.cornerRadius); - return; - } - SettingsData.set("hyprlandLayoutRadiusOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["hyprland", "radius", "override", "rounding"] - settingKey: "hyprlandLayoutRadiusOverride" - text: I18n.tr("Window Rounding") - description: I18n.tr("Rounded corners for windows (decoration.rounding)") - visible: SettingsData.hyprlandLayoutRadiusOverride >= 0 - value: Math.max(0, SettingsData.hyprlandLayoutRadiusOverride) - minimum: 0 - maximum: 100 - unit: "px" - defaultValue: SettingsData.cornerRadius - onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutRadiusOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["hyprland", "border", "override"] - settingKey: "hyprlandLayoutBorderSizeEnabled" - text: I18n.tr("Override Border Size") - description: I18n.tr("Use custom border size") - checked: SettingsData.hyprlandLayoutBorderSize >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("hyprlandLayoutBorderSize", 2); - return; - } - SettingsData.set("hyprlandLayoutBorderSize", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["hyprland", "border", "override"] - settingKey: "hyprlandLayoutBorderSize" - text: I18n.tr("Border Size") - description: I18n.tr("Width of window border (general.border_size)") - visible: SettingsData.hyprlandLayoutBorderSize >= 0 - value: Math.max(0, SettingsData.hyprlandLayoutBorderSize) - minimum: 0 - maximum: 10 - unit: "px" - defaultValue: 2 - onSliderValueChanged: newValue => SettingsData.set("hyprlandLayoutBorderSize", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["hyprland", "resize", "border", "mouse", "drag"] - settingKey: "hyprlandResizeOnBorder" - text: I18n.tr("Resize on Border") - description: I18n.tr("Resize windows by dragging their edges with the mouse") - checked: SettingsData.hyprlandResizeOnBorder - onToggled: checked => SettingsData.set("hyprlandResizeOnBorder", checked) - } - } - - SettingsCard { - tab: "theme" - tags: ["mangowc", "mango", "dwl", "layout", "gaps", "radius", "window", "border"] - title: I18n.tr("MangoWC Layout Overrides") - settingKey: "mangoLayout" - iconName: "crop_square" - visible: CompositorService.isDwl || CompositorService.isMango - - SettingsToggleRow { - tab: "theme" - tags: ["mangowc", "mango", "gaps", "override"] - settingKey: "mangoLayoutGapsOverrideEnabled" - text: I18n.tr("Override Gaps") - description: I18n.tr("Use custom gaps instead of bar spacing") - checked: SettingsData.mangoLayoutGapsOverride >= 0 - onToggled: checked => { - if (checked) { - const currentGaps = Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)); - SettingsData.set("mangoLayoutGapsOverride", currentGaps); - return; - } - SettingsData.set("mangoLayoutGapsOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["mangowc", "mango", "gaps", "override"] - settingKey: "mangoLayoutGapsOverride" - text: I18n.tr("Window Gaps") - description: I18n.tr("Space between windows (gappih/gappiv/gappoh/gappov)") - visible: SettingsData.mangoLayoutGapsOverride >= 0 - value: Math.max(0, SettingsData.mangoLayoutGapsOverride) - minimum: 0 - maximum: 50 - unit: "px" - defaultValue: Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) - onSliderValueChanged: newValue => SettingsData.set("mangoLayoutGapsOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["mangowc", "mango", "radius", "override"] - settingKey: "mangoLayoutRadiusOverrideEnabled" - text: I18n.tr("Override Corner Radius") - description: I18n.tr("Use custom window radius instead of theme radius") - checked: SettingsData.mangoLayoutRadiusOverride >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("mangoLayoutRadiusOverride", SettingsData.cornerRadius); - return; - } - SettingsData.set("mangoLayoutRadiusOverride", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["mangowc", "mango", "radius", "override"] - settingKey: "mangoLayoutRadiusOverride" - text: I18n.tr("Window Corner Radius") - description: I18n.tr("Rounded corners for windows (border_radius)") - visible: SettingsData.mangoLayoutRadiusOverride >= 0 - value: Math.max(0, SettingsData.mangoLayoutRadiusOverride) - minimum: 0 - maximum: 100 - unit: "px" - defaultValue: SettingsData.cornerRadius - onSliderValueChanged: newValue => SettingsData.set("mangoLayoutRadiusOverride", newValue) - } - - SettingsToggleRow { - tab: "theme" - tags: ["mangowc", "mango", "border", "override"] - settingKey: "mangoLayoutBorderSizeEnabled" - text: I18n.tr("Override Border Size") - description: I18n.tr("Use custom border size") - checked: SettingsData.mangoLayoutBorderSize >= 0 - onToggled: checked => { - if (checked) { - SettingsData.set("mangoLayoutBorderSize", 2); - return; - } - SettingsData.set("mangoLayoutBorderSize", -1); - } - } - - SettingsSliderRow { - tab: "theme" - tags: ["mangowc", "mango", "border", "override"] - settingKey: "mangoLayoutBorderSize" - text: I18n.tr("Border Size") - description: I18n.tr("Width of window border (borderpx)") - visible: SettingsData.mangoLayoutBorderSize >= 0 - value: Math.max(0, SettingsData.mangoLayoutBorderSize) - minimum: 0 - maximum: 10 - unit: "px" - defaultValue: 2 - onSliderValueChanged: newValue => SettingsData.set("mangoLayoutBorderSize", newValue) - } - } - SettingsCard { tab: "theme" tags: ["modal", "darken", "background", "overlay"] diff --git a/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml b/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml index 5bdd91a8..a672e57d 100644 --- a/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml +++ b/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import qs.Common +import qs.Services import qs.Widgets StyledRect { @@ -12,6 +13,7 @@ StyledRect { property string tab: "" property var tags: [] + property string settingKey: "" property string title: "" property string description: "" @@ -29,6 +31,34 @@ StyledRect { radius: Theme.cornerRadius color: Theme.surfaceContainerHigh + function findParentFlickable() { + let p = root.parent; + while (p) { + if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) + return p; + p = p.parent; + } + return null; + } + + Component.onCompleted: { + if (!settingKey) + return; + const key = settingKey; + Qt.callLater(() => { + if (!root.parent) + return; + const flickable = findParentFlickable(); + if (flickable) + SettingsSearchService.registerCard(key, root, flickable); + }); + } + + Component.onDestruction: { + if (settingKey) + SettingsSearchService.unregisterCard(settingKey); + } + Column { id: contentColumn anchors.left: parent.left diff --git a/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml b/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml index 343d5356..aa7ed658 100644 --- a/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml +++ b/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import qs.Common +import qs.Services import qs.Widgets StyledRect { @@ -12,6 +13,7 @@ StyledRect { property string tab: "" property var tags: [] + property string settingKey: "" property string title: "" property string description: "" @@ -28,6 +30,34 @@ StyledRect { radius: Theme.cornerRadius color: Theme.surfaceContainerHigh + function findParentFlickable() { + let p = root.parent; + while (p) { + if (p.hasOwnProperty("contentY") && p.hasOwnProperty("contentItem")) + return p; + p = p.parent; + } + return null; + } + + Component.onCompleted: { + if (!settingKey) + return; + const key = settingKey; + Qt.callLater(() => { + if (!root.parent) + return; + const flickable = findParentFlickable(); + if (flickable) + SettingsSearchService.registerCard(key, root, flickable); + }); + } + + Component.onDestruction: { + if (settingKey) + SettingsSearchService.unregisterCard(settingKey); + } + Column { id: mainColumn anchors.left: parent.left diff --git a/quickshell/Modules/Settings/WidgetsTab.qml b/quickshell/Modules/Settings/WidgetsTab.qml index 92137711..df072047 100644 --- a/quickshell/Modules/Settings/WidgetsTab.qml +++ b/quickshell/Modules/Settings/WidgetsTab.qml @@ -25,12 +25,14 @@ Item { } property bool hasMultipleBars: SettingsData.barConfigs.length > 1 + property int pluginCatalogRevision: 0 DankTooltipV2 { id: sharedTooltip } property var baseWidgetDefinitions: { + pluginCatalogRevision; var coreWidgets = [ { "id": "layout", @@ -274,6 +276,30 @@ Item { return coreWidgets; } + Connections { + target: PluginService + + function onPluginDataChanged() { + widgetsTab.pluginCatalogRevision++; + } + + function onPluginListUpdated() { + widgetsTab.pluginCatalogRevision++; + } + + function onPluginLoaded() { + widgetsTab.pluginCatalogRevision++; + } + + function onPluginStateChanged() { + widgetsTab.pluginCatalogRevision++; + } + + function onPluginUnloaded() { + widgetsTab.pluginCatalogRevision++; + } + } + property var defaultLeftWidgets: [ { "id": "launcherButton", diff --git a/quickshell/Modules/Settings/WindowRulesTab.qml b/quickshell/Modules/Settings/WindowRulesTab.qml index 661f6c84..ea8492ed 100644 --- a/quickshell/Modules/Settings/WindowRulesTab.qml +++ b/quickshell/Modules/Settings/WindowRulesTab.qml @@ -17,6 +17,8 @@ Item { LayoutMirroring.childrenInherit: true property var parentModal: null + property bool pageActive: true + property bool componentReady: false property var windowRulesIncludeStatus: ({ "exists": false, "included": false, @@ -32,6 +34,13 @@ Item { property string expandedExternalId: "" readonly property string dmsRulesFileName: CompositorService.isNiri ? "dms/windowrules.kdl" : CompositorService.isMango ? "dms/windowrules.conf" : "dms/windowrules.lua" + Component.onDestruction: SettingsSearchService.unregisterCard("windowRules") + + onPageActiveChanged: { + if (componentReady && pageActive) + loadWindowRules(); + } + readonly property var matchLabels: ({ "appId": I18n.tr("App ID"), "title": I18n.tr("Title"), @@ -182,12 +191,15 @@ Item { function loadWindowRules() { const compositor = CompositorService.compositor; if (compositor !== "niri" && compositor !== "hyprland" && compositor !== "mango") { + checkingInclude = false; windowRules = []; externalRules = []; return; } + checkingInclude = true; Proc.runCommand("load-windowrules", ["dms", "config", "windowrules", "list", compositor], (output, exitCode) => { + checkingInclude = false; if (exitCode !== 0) { windowRules = []; externalRules = []; @@ -258,44 +270,6 @@ Item { }); } - function checkWindowRulesIncludeStatus() { - const compositor = CompositorService.compositor; - if (compositor !== "niri" && compositor !== "hyprland" && compositor !== "mango") { - windowRulesIncludeStatus = { - "exists": false, - "included": false, - "configFormat": "", - "readOnly": false - }; - return; - } - - const filename = (compositor === "niri") ? "windowrules.kdl" : (compositor === "mango") ? "windowrules.conf" : "windowrules.lua"; - checkingInclude = true; - Proc.runCommand("check-windowrules-include", ["dms", "config", "resolve-include", compositor, filename], (output, exitCode) => { - checkingInclude = false; - if (exitCode !== 0) { - windowRulesIncludeStatus = { - "exists": false, - "included": false, - "configFormat": "", - "readOnly": false - }; - return; - } - try { - windowRulesIncludeStatus = JSON.parse(output.trim()); - } catch (e) { - windowRulesIncludeStatus = { - "exists": false, - "included": false, - "configFormat": "", - "readOnly": false - }; - } - }); - } - function fixWindowRulesInclude() { if (readOnly) { showHyprlandReadOnlyWarning(); @@ -320,7 +294,6 @@ Item { return; if (CompositorService.isMango) MangoService.reloadConfig(); - checkWindowRulesIncludeStatus(); loadWindowRules(); }); } @@ -372,10 +345,12 @@ Item { } Component.onCompleted: { - if (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isMango) { - checkWindowRulesIncludeStatus(); - loadWindowRules(); - } + componentReady = true; + Qt.callLater(() => { + SettingsSearchService.registerCard("windowRules", headerSection, flickable); + if (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isMango) + loadWindowRules(); + }); } DankFlickable { diff --git a/quickshell/Modules/Settings/WorkspaceAppearanceCard.qml b/quickshell/Modules/Settings/WorkspaceAppearanceCard.qml new file mode 100644 index 00000000..8f0e3e44 --- /dev/null +++ b/quickshell/Modules/Settings/WorkspaceAppearanceCard.qml @@ -0,0 +1,230 @@ +import QtQuick +import qs.Common +import qs.Services +import qs.Modules.Settings.Widgets + +SettingsCard { + iconName: "palette" + title: I18n.tr("Workspace Appearance") + settingKey: "workspaceAppearance" + collapsible: true + expanded: false + + SettingsButtonGroupRow { + text: I18n.tr("Focused Color") + model: ["pri", "s", "sc", "sch", "none"] + buttonHeight: 22 + minButtonWidth: 36 + buttonPadding: Theme.spacingS + checkIconSize: Theme.iconSizeSmall - 2 + textSize: Theme.fontSizeSmall - 1 + spacing: 1 + currentIndex: { + switch (SettingsData.workspaceColorMode) { + case "s": + return 1; + case "sc": + return 2; + case "sch": + return 3; + case "none": + return 4; + default: + return 0; + } + } + onSelectionChanged: (index, selected) => { + if (!selected) + return; + const modes = ["default", "s", "sc", "sch", "none"]; + SettingsData.set("workspaceColorMode", modes[index]); + } + } + + Rectangle { + width: parent.width + height: 1 + color: Theme.outline + opacity: 0.15 + } + + SettingsButtonGroupRow { + text: I18n.tr("Occupied Color") + model: ["none", "sec", "s", "sc", "sch", "schh"] + visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isMango + buttonHeight: 22 + minButtonWidth: 36 + buttonPadding: Theme.spacingS + checkIconSize: Theme.iconSizeSmall - 2 + textSize: Theme.fontSizeSmall - 1 + spacing: 1 + currentIndex: { + switch (SettingsData.workspaceOccupiedColorMode) { + case "sec": + return 1; + case "s": + return 2; + case "sc": + return 3; + case "sch": + return 4; + case "schh": + return 5; + default: + return 0; + } + } + onSelectionChanged: (index, selected) => { + if (!selected) + return; + const modes = ["none", "sec", "s", "sc", "sch", "schh"]; + SettingsData.set("workspaceOccupiedColorMode", modes[index]); + } + } + + Rectangle { + width: parent.width + height: 1 + color: Theme.outline + opacity: 0.15 + visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isMango + } + + SettingsButtonGroupRow { + text: I18n.tr("Unfocused Color") + model: ["def", "s", "sc", "sch"] + buttonHeight: 22 + minButtonWidth: 36 + buttonPadding: Theme.spacingS + checkIconSize: Theme.iconSizeSmall - 2 + textSize: Theme.fontSizeSmall - 1 + spacing: 1 + currentIndex: { + switch (SettingsData.workspaceUnfocusedColorMode) { + case "s": + return 1; + case "sc": + return 2; + case "sch": + return 3; + default: + return 0; + } + } + onSelectionChanged: (index, selected) => { + if (!selected) + return; + const modes = ["default", "s", "sc", "sch"]; + SettingsData.set("workspaceUnfocusedColorMode", modes[index]); + } + } + + Rectangle { + width: parent.width + height: 1 + color: Theme.outline + opacity: 0.15 + visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isMango || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle + } + + SettingsButtonGroupRow { + text: I18n.tr("Urgent Color") + visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isMango || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle + model: ["err", "pri", "sec", "s", "sc"] + buttonHeight: 22 + minButtonWidth: 36 + buttonPadding: Theme.spacingS + checkIconSize: Theme.iconSizeSmall - 2 + textSize: Theme.fontSizeSmall - 1 + spacing: 1 + currentIndex: { + switch (SettingsData.workspaceUrgentColorMode) { + case "primary": + return 1; + case "secondary": + return 2; + case "s": + return 3; + case "sc": + return 4; + default: + return 0; + } + } + onSelectionChanged: (index, selected) => { + if (!selected) + return; + const modes = ["default", "primary", "secondary", "s", "sc"]; + SettingsData.set("workspaceUrgentColorMode", modes[index]); + } + } + + Rectangle { + width: parent.width + height: 1 + color: Theme.outline + opacity: 0.15 + } + + SettingsToggleRow { + settingKey: "workspaceFocusedBorderEnabled" + tags: ["workspace", "border", "outline", "focused", "ring"] + text: I18n.tr("Focused Border") + description: I18n.tr("Show an outline ring around the focused workspace indicator") + checked: SettingsData.workspaceFocusedBorderEnabled + onToggled: checked => SettingsData.set("workspaceFocusedBorderEnabled", checked) + } + + Column { + width: parent.width + spacing: Theme.spacingS + visible: SettingsData.workspaceFocusedBorderEnabled + leftPadding: Theme.spacingM + + SettingsButtonGroupRow { + width: parent.width - parent.leftPadding + text: I18n.tr("Border Color") + model: [I18n.tr("Surface"), I18n.tr("Secondary"), I18n.tr("Primary")] + currentIndex: { + switch (SettingsData.workspaceFocusedBorderColor) { + case "surfaceText": + return 0; + case "secondary": + return 1; + case "primary": + return 2; + default: + return 2; + } + } + onSelectionChanged: (index, selected) => { + if (!selected) + return; + let newColor = "primary"; + switch (index) { + case 0: + newColor = "surfaceText"; + break; + case 1: + newColor = "secondary"; + break; + case 2: + newColor = "primary"; + break; + } + SettingsData.set("workspaceFocusedBorderColor", newColor); + } + } + + SettingsSliderRow { + width: parent.width - parent.leftPadding + text: I18n.tr("Thickness") + value: SettingsData.workspaceFocusedBorderThickness + minimum: 1 + maximum: 6 + unit: "px" + defaultValue: 2 + onSliderValueChanged: newValue => SettingsData.set("workspaceFocusedBorderThickness", newValue) + } + } +} diff --git a/quickshell/Modules/Settings/WorkspacesTab.qml b/quickshell/Modules/Settings/WorkspacesTab.qml index 8932cad3..2582825d 100644 --- a/quickshell/Modules/Settings/WorkspacesTab.qml +++ b/quickshell/Modules/Settings/WorkspacesTab.qml @@ -15,7 +15,9 @@ Item { Column { id: mainColumn - topPadding: 4 + + topPadding: Theme.spacingXL + bottomPadding: Theme.spacingXL width: Math.min(550, parent.width - Theme.spacingL * 2) anchors.horizontalCenter: parent.horizontalCenter spacing: Theme.spacingXL @@ -196,231 +198,6 @@ Item { } } - SettingsCard { - width: parent.width - iconName: "palette" - title: I18n.tr("Workspace Appearance") - settingKey: "workspaceAppearance" - - SettingsButtonGroupRow { - text: I18n.tr("Focused Color") - model: ["pri", "s", "sc", "sch", "none"] - buttonHeight: 22 - minButtonWidth: 36 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 1 - spacing: 1 - currentIndex: { - switch (SettingsData.workspaceColorMode) { - case "s": - return 1; - case "sc": - return 2; - case "sch": - return 3; - case "none": - return 4; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["default", "s", "sc", "sch", "none"]; - SettingsData.set("workspaceColorMode", modes[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsButtonGroupRow { - text: I18n.tr("Occupied Color") - model: ["none", "sec", "s", "sc", "sch", "schh"] - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isMango - buttonHeight: 22 - minButtonWidth: 36 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 1 - spacing: 1 - currentIndex: { - switch (SettingsData.workspaceOccupiedColorMode) { - case "sec": - return 1; - case "s": - return 2; - case "sc": - return 3; - case "sch": - return 4; - case "schh": - return 5; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["none", "sec", "s", "sc", "sch", "schh"]; - SettingsData.set("workspaceOccupiedColorMode", modes[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isMango - } - - SettingsButtonGroupRow { - text: I18n.tr("Unfocused Color") - model: ["def", "s", "sc", "sch"] - buttonHeight: 22 - minButtonWidth: 36 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 1 - spacing: 1 - currentIndex: { - switch (SettingsData.workspaceUnfocusedColorMode) { - case "s": - return 1; - case "sc": - return 2; - case "sch": - return 3; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["default", "s", "sc", "sch"]; - SettingsData.set("workspaceUnfocusedColorMode", modes[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isMango || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle - } - - SettingsButtonGroupRow { - text: I18n.tr("Urgent Color") - visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isMango || CompositorService.isSway || CompositorService.isScroll || CompositorService.isMiracle - model: ["err", "pri", "sec", "s", "sc"] - buttonHeight: 22 - minButtonWidth: 36 - buttonPadding: Theme.spacingS - checkIconSize: Theme.iconSizeSmall - 2 - textSize: Theme.fontSizeSmall - 1 - spacing: 1 - currentIndex: { - switch (SettingsData.workspaceUrgentColorMode) { - case "primary": - return 1; - case "secondary": - return 2; - case "s": - return 3; - case "sc": - return 4; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - const modes = ["default", "primary", "secondary", "s", "sc"]; - SettingsData.set("workspaceUrgentColorMode", modes[index]); - } - } - - Rectangle { - width: parent.width - height: 1 - color: Theme.outline - opacity: 0.15 - } - - SettingsToggleRow { - settingKey: "workspaceFocusedBorderEnabled" - tags: ["workspace", "border", "outline", "focused", "ring"] - text: I18n.tr("Focused Border") - description: I18n.tr("Show an outline ring around the focused workspace indicator") - checked: SettingsData.workspaceFocusedBorderEnabled - onToggled: checked => SettingsData.set("workspaceFocusedBorderEnabled", checked) - } - - Column { - width: parent.width - spacing: Theme.spacingS - visible: SettingsData.workspaceFocusedBorderEnabled - leftPadding: Theme.spacingM - - SettingsButtonGroupRow { - width: parent.width - parent.leftPadding - text: I18n.tr("Border Color") - model: [I18n.tr("Surface"), I18n.tr("Secondary"), I18n.tr("Primary")] - currentIndex: { - switch (SettingsData.workspaceFocusedBorderColor) { - case "surfaceText": - return 0; - case "secondary": - return 1; - case "primary": - return 2; - default: - return 2; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let newColor = "primary"; - switch (index) { - case 0: - newColor = "surfaceText"; - break; - case 1: - newColor = "secondary"; - break; - case 2: - newColor = "primary"; - break; - } - SettingsData.set("workspaceFocusedBorderColor", newColor); - } - } - - SettingsSliderRow { - width: parent.width - parent.leftPadding - text: I18n.tr("Thickness") - value: SettingsData.workspaceFocusedBorderThickness - minimum: 1 - maximum: 6 - unit: "px" - defaultValue: 2 - onSliderValueChanged: newValue => SettingsData.set("workspaceFocusedBorderThickness", newValue) - } - } - } - SettingsCard { width: parent.width iconName: "label" diff --git a/quickshell/Widgets/DankRipple.qml b/quickshell/Widgets/DankRipple.qml index 94501d15..2c749d93 100644 --- a/quickshell/Widgets/DankRipple.qml +++ b/quickshell/Widgets/DankRipple.qml @@ -7,6 +7,7 @@ Item { property color rippleColor: Theme.primary property real cornerRadius: 0 property bool enableRipple: typeof SettingsData !== "undefined" ? (SettingsData.enableRippleEffects ?? true) : true + property int animationDuration: Theme.expressiveDurations.expressiveDefaultSpatial property real _rippleX: 0 property real _rippleY: 0 @@ -58,18 +59,18 @@ Item { property: "rippleRadius" from: 0 to: root._rippleMaxRadius - duration: Theme.expressiveDurations.expressiveDefaultSpatial + duration: root.animationDuration easing.bezierCurve: Theme.expressiveCurves.standardDecel } SequentialAnimation { PauseAnimation { - duration: Math.round(Theme.expressiveDurations.expressiveDefaultSpatial * 0.6) + duration: Math.round(root.animationDuration * 0.6) } DankAnim { target: rippleFx property: "rippleOpacity" to: 0 - duration: Theme.expressiveDurations.expressiveDefaultSpatial + duration: root.animationDuration easing.bezierCurve: Theme.expressiveCurves.standard } } diff --git a/quickshell/translations/extract_settings_index.py b/quickshell/translations/extract_settings_index.py index e3b391f8..438bec20 100755 --- a/quickshell/translations/extract_settings_index.py +++ b/quickshell/translations/extract_settings_index.py @@ -62,7 +62,20 @@ CATEGORY_KEYWORDS = { "Time & Weather": ["clock", "forecast", "date"], "Keyboard Shortcuts": ["keys", "bindings", "hotkey"], "Dank Bar": ["panel", "topbar", "statusbar"], - "Workspaces": ["virtual desktops", "spaces"], + "Compositor": [ + "virtual desktops", + "spaces", + "window", + "rules", + "matching", + "floating", + "fullscreen", + "opacity", + "gaps", + "borders", + "corner rounding", + "overrides", + ], "Dock": ["taskbar", "launcher bar"], "Network": ["connectivity", "online"], "System": ["os", "linux"], @@ -82,14 +95,6 @@ CATEGORY_KEYWORDS = { "Displays": ["monitor", "screen", "resolution"], "Desktop Widgets": ["conky", "desktop clock"], "Audio": ["sound", "volume", "speaker", "microphone", "headphones", "pipewire"], - "Window Rules": [ - "window", - "rules", - "matching", - "floating", - "fullscreen", - "opacity", - ], "Locale": ["locale", "language", "country"], "Greeter": ["login", "greetd", "display manager"], "Multiplexers": ["tmux", "zellij", "terminal"], @@ -104,8 +109,13 @@ TAB_INDEX_MAP = { "TimeWeatherTab.qml": 1, "KeybindsTab.qml": 2, "DankBarTab.qml": 3, + "CompositorTab.qml": 4, + "CompositorLayoutTab.qml": 4, "WorkspacesTab.qml": 4, + "WindowRulesTab.qml": 4, "DockTab.qml": 5, + "DankBarAppearanceTab.qml": 6, + "WorkspaceAppearanceCard.qml": 6, "NetworkTab.qml": 7, "PrinterTab.qml": 8, "LauncherTab.qml": 9, @@ -127,7 +137,6 @@ TAB_INDEX_MAP = { "GammaControlTab.qml": 25, "DisplayWidgetsTab.qml": 26, "DesktopWidgetsTab.qml": 27, - "WindowRulesTab.qml": 28, "AudioTab.qml": 29, "LocaleTab.qml": 30, "GreeterTab.qml": 31, @@ -143,8 +152,9 @@ TAB_CATEGORY_MAP = { 1: "Time & Weather", 2: "Keyboard Shortcuts", 3: "Dank Bar", - 4: "Workspaces", + 4: "Compositor", 5: "Dock", + 6: "Dank Bar", 7: "Network", 8: "System", 9: "Launcher", @@ -166,7 +176,6 @@ TAB_CATEGORY_MAP = { 25: "Displays", 26: "Displays", 27: "Desktop Widgets", - 28: "Window Rules", 29: "Audio", 30: "Locale", 31: "Greeter", @@ -302,9 +311,9 @@ def extract_property(block, prop_name): def find_settings_components(content, filename): results = [] - tab_index = TAB_INDEX_MAP.get(filename, -1) + file_tab_index = TAB_INDEX_MAP.get(filename, -1) - if tab_index == -1: + if file_tab_index == -1: return results for component in SEARCHABLE_COMPONENTS: @@ -321,6 +330,11 @@ def find_settings_components(content, filename): if not setting_key: continue + tab_index = file_tab_index + tab_raw = extract_property(block, "tab") + if tab_raw and tab_raw.strip("\"'") == "appearance": + tab_index = 6 + title_raw = extract_property(block, "title") text_raw = extract_property(block, "text") label = None @@ -489,7 +503,7 @@ def extract_settings_index(root_dir): seen_keys = set() for qml_file in settings_dir.glob("*.qml"): - if not qml_file.name.endswith("Tab.qml"): + if qml_file.name not in TAB_INDEX_MAP: continue with open(qml_file, "r", encoding="utf-8") as f: @@ -502,6 +516,24 @@ def extract_settings_index(root_dir): seen_keys.add(key) all_entries.append(entry) + if "windowRules" not in seen_keys: + all_entries.append( + { + "section": "windowRules", + "label": "Window Rules", + "tabIndex": 4, + "category": "Compositor", + "keywords": enrich_keywords( + "Window Rules", + "Define compositor rules for window behavior", + "Compositor", + ["matching", "floating", "fullscreen", "opacity"], + ), + "icon": "select_window", + "description": "Define compositor rules for window behavior", + } + ) + return all_entries diff --git a/quickshell/translations/settings_search_index.json b/quickshell/translations/settings_search_index.json index 74947d47..824ae9b9 100644 --- a/quickshell/translations/settings_search_index.json +++ b/quickshell/translations/settings_search_index.json @@ -727,30 +727,6 @@ ], "icon": "dashboard" }, - { - "section": "barCorners", - "label": "Corners & Background", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "background", - "bar", - "corner", - "corners", - "dank", - "panel", - "radius", - "remove", - "round", - "rounded", - "rounding", - "statusbar", - "taskbar", - "topbar" - ], - "icon": "rounded_corner", - "description": "Remove corner rounding from the bar" - }, { "section": "_tab_3", "label": "Dank Bar", @@ -766,26 +742,6 @@ ], "icon": "toolbar" }, - { - "section": "barShadowDirectionSource", - "label": "Direction Source", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "bar", - "choose", - "dank", - "direction", - "panel", - "resolves", - "shadow", - "source", - "statusbar", - "taskbar", - "topbar" - ], - "description": "Choose how this bar resolves shadow direction" - }, { "section": "barDisplay", "label": "Display Assignment", @@ -805,25 +761,6 @@ ], "icon": "display_settings" }, - { - "section": "barShadowDirectionManual", - "label": "Manual Direction", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "bar", - "dank", - "direction", - "fixed", - "manual", - "panel", - "shadow", - "statusbar", - "taskbar", - "topbar" - ], - "description": "Use a fixed shadow direction for this bar" - }, { "section": "barPosition", "label": "Position", @@ -839,26 +776,6 @@ ], "icon": "vertical_align_center" }, - { - "section": "barShadow", - "label": "Shadow Override", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "bar", - "dank", - "global", - "override", - "panel", - "settings", - "shadow", - "statusbar", - "taskbar", - "topbar" - ], - "icon": "layers", - "description": "Override the global shadow with per-bar settings" - }, { "section": "barSpacing", "label": "Spacing", @@ -885,56 +802,6 @@ "icon": "space_bar", "description": "Space between the bar and screen edges" }, - { - "section": "trayIconTint", - "label": "System Tray Icon Tint", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "applying", - "bar", - "before", - "color", - "colour", - "controls", - "dank", - "hue", - "icon", - "much", - "original", - "panel", - "removed", - "statusbar", - "system", - "tint", - "topbar", - "tray" - ], - "icon": "filter_b_and_w", - "description": "Controls how much original icon color is removed before applying tint" - }, - { - "section": "barTransparency", - "label": "Transparency", - "tabIndex": 3, - "category": "Dank Bar", - "keywords": [ - "alpha", - "background", - "bar", - "dank", - "opacity", - "panel", - "statusbar", - "taskbar", - "topbar", - "translucent", - "transparency", - "transparent" - ], - "icon": "opacity", - "description": "Opacity of the bar background" - }, { "section": "barUseOverlayLayer", "label": "Use Overlay Layer", @@ -985,66 +852,172 @@ "icon": "visibility_off", "description": "Automatically hide the bar when the pointer moves away" }, + { + "section": "niriLayoutBorderSize", + "label": "Border Size", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "border", + "borders", + "compositor", + "corner rounding", + "floating", + "focus", + "fullscreen", + "gaps", + "matching", + "niri", + "opacity", + "override", + "overrides", + "ring", + "rules", + "size", + "spaces", + "virtual desktops", + "width", + "window" + ], + "description": "Width of window border and focus ring" + }, + { + "section": "hyprlandLayoutBorderSize", + "label": "Border Size", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "border", + "borders", + "compositor", + "corner rounding", + "floating", + "fullscreen", + "gaps", + "hyprland", + "matching", + "opacity", + "override", + "overrides", + "rules", + "size", + "spaces", + "virtual desktops", + "width", + "window" + ], + "description": "Width of window border (general.border_size)" + }, + { + "section": "mangoLayoutBorderSize", + "label": "Border Size", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "border", + "borders", + "compositor", + "corner rounding", + "floating", + "fullscreen", + "gaps", + "mango", + "mangowc", + "matching", + "opacity", + "override", + "overrides", + "rules", + "size", + "spaces", + "virtual desktops", + "width", + "window" + ], + "description": "Width of window border (borderpx)" + }, + { + "section": "_tab_4", + "label": "Compositor", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "borders", + "compositor", + "corner rounding", + "floating", + "fullscreen", + "gaps", + "matching", + "opacity", + "overrides", + "rules", + "spaces", + "virtual desktops", + "window" + ], + "icon": "layers", + "conditionKey": "keybindsAvailable" + }, { "section": "workspaceDragReorder", "label": "Drag to Reorder", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ + "borders", + "compositor", + "corner rounding", "desktop", "drag", + "floating", + "fullscreen", + "gaps", "indicators", + "matching", "move", + "opacity", + "overrides", "reorder", + "rules", "sort", "spaces", "virtual", "virtual desktops", - "workspace", - "workspaces" + "window", + "workspace" ], "description": "Drag workspace indicators to reorder them", "conditionKey": "isNiri" }, - { - "section": "workspaceFocusedBorderEnabled", - "label": "Focused Border", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "around", - "border", - "desktop", - "focused", - "indicator", - "outline", - "ring", - "show", - "spaces", - "virtual", - "virtual desktops", - "workspace", - "workspaces" - ], - "description": "Show an outline ring around the focused workspace indicator" - }, { "section": "workspaceFollowFocus", "label": "Follow Monitor Focus", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ + "borders", + "compositor", + "corner rounding", "currently", "desktop", "desktops", + "floating", "focus", "focused", "follow", + "fullscreen", + "gaps", + "matching", "monitor", + "opacity", + "overrides", + "rules", "show", "spaces", "virtual", "virtual desktops", + "window", "workspace", "workspaces" ], @@ -1055,24 +1028,34 @@ "section": "groupActiveWorkspaceApps", "label": "Group Active Workspace", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ "active", "app", "application", "apps", + "borders", + "compositor", + "corner rounding", "desktop", + "floating", "focused", + "fullscreen", + "gaps", "group", "grouped", "icons", + "matching", + "opacity", + "overrides", "program", "repeated", + "rules", "spaces", "virtual", "virtual desktops", - "workspace", - "workspaces" + "window", + "workspace" ], "description": "Also group repeated application icons on the active workspace" }, @@ -1080,23 +1063,34 @@ "section": "groupWorkspaceApps", "label": "Group Workspace Apps", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ "app", "application", "apps", + "borders", "collapse", + "compositor", + "corner rounding", "desktop", "desktops", + "floating", + "fullscreen", + "gaps", "group", "grouped", "icons", + "matching", + "opacity", + "overrides", "program", "repeated", + "rules", "spaces", "unfocused", "virtual", "virtual desktops", + "window", "workspace", "workspaces" ], @@ -1106,56 +1100,532 @@ "section": "workspaceActiveAppHighlightEnabled", "label": "Highlight Active Workspace App", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ "active", "app", "apps", + "borders", + "compositor", + "corner rounding", "currently", "day", "desktop", + "floating", "focused", + "fullscreen", + "gaps", "highlight", "icons", "indicators", "inside", "light mode", + "matching", + "opacity", + "overrides", + "rules", "spaces", "virtual", "virtual desktops", - "workspace", - "workspaces" + "window", + "workspace" ], "description": "Highlight the currently focused app inside workspace indicators" }, + { + "section": "hyprlandLayout", + "label": "Hyprland Layout Overrides", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "border", + "borders", + "compositor", + "corner rounding", + "custom", + "floating", + "fullscreen", + "gap", + "gaps", + "hyprland", + "layout", + "margin", + "margins", + "matching", + "opacity", + "overrides", + "padding", + "panel", + "radius", + "rounding", + "rules", + "spaces", + "spacing", + "statusbar", + "taskbar", + "topbar", + "virtual desktops", + "window" + ], + "icon": "crop_square", + "description": "Use custom gaps instead of bar spacing", + "conditionKey": "isHyprland" + }, + { + "section": "mangoLayout", + "label": "MangoWC Layout Overrides", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "border", + "borders", + "compositor", + "corner rounding", + "custom", + "dwl", + "floating", + "fullscreen", + "gap", + "gaps", + "layout", + "mango", + "mangowc", + "margin", + "margins", + "matching", + "opacity", + "overrides", + "padding", + "panel", + "radius", + "rules", + "spaces", + "spacing", + "statusbar", + "taskbar", + "topbar", + "virtual desktops", + "window" + ], + "icon": "crop_square", + "description": "Use custom gaps instead of bar spacing", + "conditionKey": "isDwl" + }, { "section": "workspaceIcons", "label": "Named Workspace Icons", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ + "borders", + "compositor", + "corner rounding", "desktop", + "floating", + "fullscreen", + "gaps", "icons", + "matching", "named", + "opacity", + "overrides", + "rules", "spaces", "virtual", "virtual desktops", - "workspace", - "workspaces" + "window", + "workspace" ], "icon": "label" }, + { + "section": "niriLayout", + "label": "Niri Layout Overrides", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "border", + "borders", + "compositor", + "corner rounding", + "custom", + "floating", + "fullscreen", + "gap", + "gaps", + "layout", + "margin", + "margins", + "matching", + "niri", + "opacity", + "overrides", + "padding", + "panel", + "radius", + "rules", + "spaces", + "spacing", + "statusbar", + "taskbar", + "topbar", + "virtual desktops", + "window" + ], + "icon": "crop_square", + "description": "Use custom gaps instead of bar spacing", + "conditionKey": "isNiri" + }, + { + "section": "niriLayoutBorderSizeEnabled", + "label": "Override Border Size", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "border", + "borders", + "compositor", + "corner rounding", + "custom", + "floating", + "focus", + "fullscreen", + "gaps", + "matching", + "niri", + "opacity", + "override", + "overrides", + "ring", + "rules", + "size", + "spaces", + "virtual desktops", + "width", + "window" + ], + "description": "Use custom border/focus-ring width" + }, + { + "section": "hyprlandLayoutBorderSizeEnabled", + "label": "Override Border Size", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "border", + "borders", + "compositor", + "corner rounding", + "custom", + "floating", + "fullscreen", + "gaps", + "hyprland", + "matching", + "opacity", + "override", + "overrides", + "rules", + "size", + "spaces", + "virtual desktops", + "window" + ], + "description": "Use custom border size" + }, + { + "section": "mangoLayoutBorderSizeEnabled", + "label": "Override Border Size", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "border", + "borders", + "compositor", + "corner rounding", + "custom", + "floating", + "fullscreen", + "gaps", + "mango", + "mangowc", + "matching", + "opacity", + "override", + "overrides", + "rules", + "size", + "spaces", + "virtual desktops", + "window" + ], + "description": "Use custom border size" + }, + { + "section": "niriLayoutRadiusOverrideEnabled", + "label": "Override Corner Radius", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "appearance", + "borders", + "colors", + "colour", + "compositor", + "corner", + "corner rounding", + "corners", + "custom", + "floating", + "fullscreen", + "gaps", + "look", + "matching", + "niri", + "opacity", + "override", + "overrides", + "radius", + "round", + "rounded", + "rules", + "spaces", + "style", + "theme", + "virtual desktops", + "window" + ], + "description": "Use custom window radius instead of theme radius" + }, + { + "section": "hyprlandLayoutRadiusOverrideEnabled", + "label": "Override Corner Radius", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "appearance", + "borders", + "colors", + "colour", + "compositor", + "corner", + "corner rounding", + "corners", + "custom", + "floating", + "fullscreen", + "gaps", + "hyprland", + "look", + "matching", + "opacity", + "override", + "overrides", + "radius", + "round", + "rounded", + "rounding", + "rules", + "spaces", + "style", + "theme", + "virtual desktops", + "window" + ], + "description": "Use custom window rounding instead of theme radius" + }, + { + "section": "mangoLayoutRadiusOverrideEnabled", + "label": "Override Corner Radius", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "appearance", + "borders", + "colors", + "colour", + "compositor", + "corner", + "corner rounding", + "corners", + "custom", + "floating", + "fullscreen", + "gaps", + "look", + "mango", + "mangowc", + "matching", + "opacity", + "override", + "overrides", + "radius", + "round", + "rounded", + "rules", + "spaces", + "style", + "theme", + "virtual desktops", + "window" + ], + "description": "Use custom window radius instead of theme radius" + }, + { + "section": "niriLayoutGapsOverrideEnabled", + "label": "Override Gaps", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "borders", + "compositor", + "corner rounding", + "custom", + "floating", + "fullscreen", + "gap", + "gaps", + "margin", + "margins", + "matching", + "niri", + "opacity", + "override", + "overrides", + "padding", + "panel", + "rules", + "spaces", + "spacing", + "statusbar", + "taskbar", + "topbar", + "virtual desktops", + "window" + ], + "description": "Use custom gaps instead of bar spacing" + }, + { + "section": "hyprlandLayoutGapsOverrideEnabled", + "label": "Override Gaps", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "borders", + "compositor", + "corner rounding", + "custom", + "floating", + "fullscreen", + "gap", + "gaps", + "hyprland", + "margin", + "margins", + "matching", + "opacity", + "override", + "overrides", + "padding", + "panel", + "rules", + "spaces", + "spacing", + "statusbar", + "taskbar", + "topbar", + "virtual desktops", + "window" + ], + "description": "Use custom gaps instead of bar spacing" + }, + { + "section": "mangoLayoutGapsOverrideEnabled", + "label": "Override Gaps", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "borders", + "compositor", + "corner rounding", + "custom", + "floating", + "fullscreen", + "gap", + "gaps", + "mango", + "mangowc", + "margin", + "margins", + "matching", + "opacity", + "override", + "overrides", + "padding", + "panel", + "rules", + "spaces", + "spacing", + "statusbar", + "taskbar", + "topbar", + "virtual desktops", + "window" + ], + "description": "Use custom gaps instead of bar spacing" + }, + { + "section": "hyprlandResizeOnBorder", + "label": "Resize on Border", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "border", + "borders", + "compositor", + "corner rounding", + "drag", + "dragging", + "edges", + "floating", + "fullscreen", + "gaps", + "hyprland", + "matching", + "mouse", + "opacity", + "overrides", + "resize", + "rules", + "spaces", + "their", + "virtual desktops", + "window", + "windows" + ], + "description": "Resize windows by dragging their edges with the mouse" + }, { "section": "reverseScrolling", "label": "Reverse Scrolling Direction", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ + "borders", + "compositor", + "corner rounding", "desktop", "direction", + "floating", + "fullscreen", + "gaps", + "matching", + "opacity", "over", + "overrides", "panel", "reverse", + "rules", "scroll", "scrolling", "spaces", @@ -1165,8 +1635,8 @@ "topbar", "virtual", "virtual desktops", - "workspace", - "workspaces" + "window", + "workspace" ], "description": "Reverse workspace switch direction when scrolling over the bar", "conditionKey": "isNiri" @@ -1175,40 +1645,61 @@ "section": "dwlShowAllTags", "label": "Show All Tags", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ "all", + "borders", + "compositor", + "corner rounding", "dwl", + "floating", + "fullscreen", + "gaps", + "matching", "occupied", + "opacity", + "overrides", + "rules", "show", "spaces", "tags", "virtual desktops", - "workspace", - "workspaces" + "window", + "workspace" ], - "description": "Show all 9 tags instead of only occupied tags (DWL only)", + "description": "Show all 9 tags instead of only occupied tags", "conditionKey": "isDwl" }, { "section": "showOccupiedWorkspacesOnly", "label": "Show Occupied Workspaces Only", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ "active", + "borders", + "compositor", "contain", + "corner rounding", "desktop", "desktops", "display", + "floating", + "fullscreen", + "gaps", + "matching", "monitor", "occupied", + "opacity", "output", + "overrides", + "rules", "screen", "show", "spaces", "virtual", "virtual desktops", + "window", "windows", "workspace", "workspaces" @@ -1220,66 +1711,261 @@ "section": "showWorkspaceApps", "label": "Show Workspace Apps", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ "app", "application", "applications", "apps", + "borders", + "compositor", + "corner rounding", "desktop", "display", + "floating", + "fullscreen", + "gaps", "icons", "indicators", + "matching", "monitor", + "opacity", "output", + "overrides", "program", + "rules", "screen", "show", "spaces", "virtual", "virtual desktops", - "workspace", - "workspaces" + "window", + "workspace" ], "description": "Display application icons in workspace indicators", "conditionKey": "isNiri" }, { - "section": "workspaceAppearance", - "label": "Workspace Appearance", + "section": "niriLayoutRadiusOverride", + "label": "Window Corner Radius", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ - "appearance", - "around", - "border", - "desktop", - "focused", - "indicator", - "outline", - "ring", - "show", + "borders", + "compositor", + "corner", + "corner rounding", + "corners", + "floating", + "fullscreen", + "gaps", + "matching", + "niri", + "opacity", + "override", + "overrides", + "radius", + "round", + "rounded", + "rules", "spaces", - "virtual", "virtual desktops", - "workspace", - "workspaces" + "window", + "windows" ], - "icon": "palette", - "description": "Show an outline ring around the focused workspace indicator", - "conditionKey": "isNiri" + "description": "Rounded corners for windows" + }, + { + "section": "mangoLayoutRadiusOverride", + "label": "Window Corner Radius", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "borders", + "compositor", + "corner", + "corner rounding", + "corners", + "floating", + "fullscreen", + "gaps", + "mango", + "mangowc", + "matching", + "opacity", + "override", + "overrides", + "radius", + "round", + "rounded", + "rules", + "spaces", + "virtual desktops", + "window", + "windows" + ], + "description": "Rounded corners for windows (border_radius)" + }, + { + "section": "niriLayoutGapsOverride", + "label": "Window Gaps", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "between", + "borders", + "compositor", + "corner rounding", + "floating", + "fullscreen", + "gaps", + "matching", + "niri", + "opacity", + "override", + "overrides", + "rules", + "space", + "spaces", + "virtual desktops", + "window", + "windows" + ], + "description": "Space between windows" + }, + { + "section": "hyprlandLayoutGapsOverride", + "label": "Window Gaps", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "between", + "borders", + "compositor", + "corner rounding", + "floating", + "fullscreen", + "gaps", + "hyprland", + "matching", + "opacity", + "override", + "overrides", + "rules", + "space", + "spaces", + "virtual desktops", + "window", + "windows" + ], + "description": "Space between windows (gaps_in and gaps_out)" + }, + { + "section": "mangoLayoutGapsOverride", + "label": "Window Gaps", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "between", + "borders", + "compositor", + "corner rounding", + "floating", + "fullscreen", + "gappiv", + "gappoh", + "gaps", + "mango", + "mangowc", + "matching", + "opacity", + "override", + "overrides", + "rules", + "space", + "spaces", + "virtual desktops", + "window", + "windows" + ], + "description": "Space between windows (gappih/gappiv/gappoh/gappov)" + }, + { + "section": "hyprlandLayoutRadiusOverride", + "label": "Window Rounding", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "borders", + "compositor", + "corner rounding", + "corners", + "floating", + "fullscreen", + "gaps", + "hyprland", + "matching", + "opacity", + "override", + "overrides", + "radius", + "round", + "rounded", + "rounding", + "rules", + "spaces", + "virtual desktops", + "window", + "windows" + ], + "description": "Rounded corners for windows (decoration.rounding)" + }, + { + "section": "windowRules", + "label": "Window Rules", + "tabIndex": 4, + "category": "Compositor", + "keywords": [ + "behavior", + "borders", + "compositor", + "corner rounding", + "define", + "floating", + "fullscreen", + "gaps", + "matching", + "opacity", + "overrides", + "rules", + "spaces", + "virtual desktops", + "window" + ], + "icon": "select_window", + "description": "Define compositor rules for window behavior" }, { "section": "showWorkspaceIndex", "label": "Workspace Index Numbers", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ + "borders", + "compositor", + "corner rounding", "desktop", + "floating", + "fullscreen", + "gaps", "index", "labels", + "matching", "numbers", + "opacity", + "overrides", "panel", + "rules", "show", "spaces", "statusbar", @@ -1288,8 +1974,8 @@ "topbar", "virtual", "virtual desktops", - "workspace", - "workspaces" + "window", + "workspace" ], "description": "Show workspace index numbers in the top bar workspace switcher" }, @@ -1297,17 +1983,27 @@ "section": "showWorkspaceName", "label": "Workspace Names", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ "bars", + "borders", + "compositor", + "corner rounding", "desktop", "first", + "floating", + "fullscreen", + "gaps", "horizontal", "labels", "letter", + "matching", "name", "names", + "opacity", + "overrides", "panel", + "rules", "show", "spaces", "statusbar", @@ -1316,8 +2012,8 @@ "vertical", "virtual", "virtual desktops", - "workspace", - "workspaces" + "window", + "workspace" ], "description": "Show workspace name on horizontal bars, and first letter on vertical bars" }, @@ -1325,20 +2021,31 @@ "section": "showWorkspacePadding", "label": "Workspace Padding", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ "always", "available", + "borders", + "compositor", + "corner rounding", "desktop", "desktops", "even", "fewer", + "floating", + "fullscreen", + "gaps", + "matching", "minimum", + "opacity", + "overrides", "padding", + "rules", "show", "spaces", "virtual", "virtual desktops", + "window", "workspace", "workspaces" ], @@ -1348,13 +2055,23 @@ "section": "workspaceSettings", "label": "Workspace Settings", "tabIndex": 4, - "category": "Workspaces", + "category": "Compositor", "keywords": [ + "borders", + "compositor", + "corner rounding", "desktop", + "floating", + "fullscreen", + "gaps", "index", "labels", + "matching", "numbers", + "opacity", + "overrides", "panel", + "rules", "settings", "show", "spaces", @@ -1364,32 +2081,13 @@ "topbar", "virtual", "virtual desktops", - "workspace", - "workspaces" + "window", + "workspace" ], "icon": "view_module", "description": "Show workspace index numbers in the top bar workspace switcher", "conditionKey": "isNiri" }, - { - "section": "_tab_4", - "label": "Workspaces & Widgets", - "tabIndex": 4, - "category": "Workspaces", - "keywords": [ - "components", - "desktop", - "desktops", - "modules", - "spaces", - "virtual", - "virtual desktops", - "widgets", - "workspace", - "workspaces" - ], - "icon": "dashboard" - }, { "section": "dockAutoHide", "label": "Auto-hide Dock", @@ -1958,6 +2656,312 @@ ], "description": "Place the dock on the Wayland overlay layer" }, + { + "section": "_tab_6", + "label": "Appearance", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "appearance", + "bar", + "dank", + "panel", + "statusbar", + "topbar" + ], + "icon": "palette" + }, + { + "section": "barBorder", + "label": "Border", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "appearance", + "bar", + "border", + "color", + "colors", + "colour", + "dank", + "hue", + "look", + "panel", + "statusbar", + "style", + "theme", + "tint", + "topbar" + ], + "icon": "border_style", + "description": "Theme color used for the border" + }, + { + "section": "barCorners", + "label": "Corners & Background", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "background", + "bar", + "corner", + "corners", + "dank", + "panel", + "radius", + "remove", + "round", + "rounded", + "rounding", + "statusbar", + "taskbar", + "topbar" + ], + "icon": "rounded_corner", + "description": "Remove corner rounding from the bar" + }, + { + "section": "barAppearance", + "label": "Dank Bar", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "bar", + "dank", + "panel", + "statusbar", + "taskbar", + "topbar" + ], + "icon": "toolbar" + }, + { + "section": "barShadowDirectionSource", + "label": "Direction Source", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "bar", + "choose", + "dank", + "direction", + "panel", + "resolves", + "shadow", + "source", + "statusbar", + "taskbar", + "topbar" + ], + "description": "Choose how this bar resolves shadow direction" + }, + { + "section": "workspaceFocusedBorderEnabled", + "label": "Focused Border", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "around", + "bar", + "border", + "dank", + "desktop", + "focused", + "indicator", + "outline", + "panel", + "ring", + "show", + "statusbar", + "topbar", + "virtual", + "workspace" + ], + "description": "Show an outline ring around the focused workspace indicator" + }, + { + "section": "barFontScale", + "label": "Font Scale", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "bar", + "dank", + "dankbar", + "font", + "independently", + "panel", + "scale", + "sizes", + "statusbar", + "taskbar", + "topbar" + ], + "icon": "text_fields", + "description": "Scale DankBar font sizes independently" + }, + { + "section": "barIconScale", + "label": "Icon Scale", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "bar", + "dank", + "dankbar", + "icon", + "independently", + "panel", + "scale", + "sizes", + "statusbar", + "taskbar", + "topbar" + ], + "icon": "interests", + "description": "Scale DankBar icon sizes independently" + }, + { + "section": "barShadowDirectionManual", + "label": "Manual Direction", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "bar", + "dank", + "direction", + "fixed", + "manual", + "panel", + "shadow", + "statusbar", + "taskbar", + "topbar" + ], + "description": "Use a fixed shadow direction for this bar" + }, + { + "section": "barShadow", + "label": "Shadow Override", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "bar", + "dank", + "global", + "override", + "panel", + "settings", + "shadow", + "statusbar", + "taskbar", + "topbar" + ], + "icon": "layers", + "description": "Override the global shadow with per-bar settings" + }, + { + "section": "trayIconTint", + "label": "System Tray Icon Tint", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "applying", + "bar", + "before", + "color", + "colour", + "controls", + "dank", + "hue", + "icon", + "much", + "original", + "panel", + "removed", + "statusbar", + "system", + "tint", + "topbar", + "tray" + ], + "icon": "filter_b_and_w", + "description": "Controls how much original icon color is removed before applying tint" + }, + { + "section": "barTransparency", + "label": "Transparency", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "alpha", + "background", + "bar", + "dank", + "opacity", + "panel", + "statusbar", + "taskbar", + "topbar", + "translucent", + "transparency", + "transparent" + ], + "icon": "opacity", + "description": "Opacity of the bar background" + }, + { + "section": "barWidgetOutline", + "label": "Widget Outline", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "appearance", + "bar", + "color", + "colors", + "colour", + "dank", + "hue", + "look", + "outline", + "panel", + "statusbar", + "style", + "theme", + "tint", + "topbar", + "widget" + ], + "icon": "highlight", + "description": "Theme color used for the widget outline" + }, + { + "section": "workspaceAppearance", + "label": "Workspace Appearance", + "tabIndex": 6, + "category": "Dank Bar", + "keywords": [ + "appearance", + "around", + "bar", + "border", + "dank", + "desktop", + "focused", + "indicator", + "outline", + "panel", + "ring", + "show", + "statusbar", + "topbar", + "virtual", + "workspace" + ], + "icon": "palette", + "description": "Show an outline ring around the focused workspace indicator" + }, { "section": "_tab_7", "label": "Network", @@ -2873,72 +3877,6 @@ ], "description": "Controls the outer edge of protocol-blurred windows" }, - { - "section": "niriLayoutBorderSize", - "label": "Border Size", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "focus", - "look", - "niri", - "override", - "ring", - "scheme", - "size", - "style", - "theme", - "width", - "window" - ], - "description": "Width of window border and focus ring" - }, - { - "section": "hyprlandLayoutBorderSize", - "label": "Border Size", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "hyprland", - "look", - "override", - "scheme", - "size", - "style", - "theme", - "width", - "window" - ], - "description": "Width of window border (general.border_size)" - }, - { - "section": "mangoLayoutBorderSize", - "label": "Border Size", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "look", - "mango", - "mangowc", - "override", - "scheme", - "size", - "style", - "theme", - "width", - "window" - ], - "description": "Width of window border (borderpx)" - }, { "section": "buttonColorMode", "label": "Button Color", @@ -3309,41 +4247,6 @@ "theme" ] }, - { - "section": "hyprlandLayout", - "label": "Hyprland Layout Overrides", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "custom", - "gap", - "gaps", - "hyprland", - "layout", - "look", - "margin", - "margins", - "overrides", - "padding", - "panel", - "radius", - "rounding", - "scheme", - "spacing", - "statusbar", - "style", - "taskbar", - "theme", - "topbar", - "window" - ], - "icon": "crop_square", - "description": "Use custom gaps instead of bar spacing", - "conditionKey": "isHyprland" - }, { "section": "iconTheme", "label": "Icon Theme", @@ -3471,42 +4374,6 @@ ], "description": "Use light theme instead of dark theme" }, - { - "section": "mangoLayout", - "label": "MangoWC Layout Overrides", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "custom", - "dwl", - "gap", - "gaps", - "layout", - "look", - "mango", - "mangowc", - "margin", - "margins", - "overrides", - "padding", - "panel", - "radius", - "scheme", - "spacing", - "statusbar", - "style", - "taskbar", - "theme", - "topbar", - "window" - ], - "icon": "crop_square", - "description": "Use custom gaps instead of bar spacing", - "conditionKey": "isDwl" - }, { "section": "matugenContrast", "label": "Matugen Contrast", @@ -3641,264 +4508,27 @@ "description": "Shadow elevation on modals and dialogs" }, { - "section": "niriLayout", - "label": "Niri Layout Overrides", + "section": "mangoTrackpadNaturalScrolling", + "label": "Natural Touchpad Scrolling", "tabIndex": 10, "category": "Theme & Colors", "keywords": [ "appearance", - "border", "colors", - "custom", - "gap", - "gaps", - "layout", - "look", - "margin", - "margins", - "niri", - "overrides", - "padding", - "panel", - "radius", - "scheme", - "spacing", - "statusbar", - "style", - "taskbar", - "theme", - "topbar", - "window" - ], - "icon": "crop_square", - "description": "Use custom gaps instead of bar spacing", - "conditionKey": "isNiri" - }, - { - "section": "niriLayoutBorderSizeEnabled", - "label": "Override Border Size", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "custom", - "focus", - "look", - "niri", - "override", - "ring", - "scheme", - "size", - "style", - "theme", - "width" - ], - "description": "Use custom border/focus-ring width" - }, - { - "section": "hyprlandLayoutBorderSizeEnabled", - "label": "Override Border Size", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "custom", - "hyprland", - "look", - "override", - "scheme", - "size", - "style", - "theme" - ], - "description": "Use custom border size" - }, - { - "section": "mangoLayoutBorderSizeEnabled", - "label": "Override Border Size", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "custom", + "direction", + "invert", "look", "mango", - "mangowc", - "override", - "scheme", - "size", - "style", - "theme" - ], - "description": "Use custom border size" - }, - { - "section": "niriLayoutRadiusOverrideEnabled", - "label": "Override Corner Radius", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "colour", - "corner", - "corners", - "custom", - "look", - "niri", - "override", - "radius", - "round", - "rounded", + "natural", "scheme", + "scroll", + "scrolling", "style", "theme", - "window" + "touchpad", + "trackpad" ], - "description": "Use custom window radius instead of theme radius" - }, - { - "section": "hyprlandLayoutRadiusOverrideEnabled", - "label": "Override Corner Radius", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "colour", - "corner", - "corners", - "custom", - "hyprland", - "look", - "override", - "radius", - "round", - "rounded", - "rounding", - "scheme", - "style", - "theme", - "window" - ], - "description": "Use custom window rounding instead of theme radius" - }, - { - "section": "mangoLayoutRadiusOverrideEnabled", - "label": "Override Corner Radius", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "colour", - "corner", - "corners", - "custom", - "look", - "mango", - "mangowc", - "override", - "radius", - "round", - "rounded", - "scheme", - "style", - "theme", - "window" - ], - "description": "Use custom window radius instead of theme radius" - }, - { - "section": "niriLayoutGapsOverrideEnabled", - "label": "Override Gaps", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "custom", - "gap", - "gaps", - "look", - "margin", - "margins", - "niri", - "override", - "padding", - "panel", - "scheme", - "spacing", - "statusbar", - "style", - "taskbar", - "theme", - "topbar" - ], - "description": "Use custom gaps instead of bar spacing" - }, - { - "section": "hyprlandLayoutGapsOverrideEnabled", - "label": "Override Gaps", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "custom", - "gap", - "gaps", - "hyprland", - "look", - "margin", - "margins", - "override", - "padding", - "panel", - "scheme", - "spacing", - "statusbar", - "style", - "taskbar", - "theme", - "topbar" - ], - "description": "Use custom gaps instead of bar spacing" - }, - { - "section": "mangoLayoutGapsOverrideEnabled", - "label": "Override Gaps", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "custom", - "gap", - "gaps", - "look", - "mango", - "mangowc", - "margin", - "margins", - "override", - "padding", - "panel", - "scheme", - "spacing", - "statusbar", - "style", - "taskbar", - "theme", - "topbar" - ], - "description": "Use custom gaps instead of bar spacing" + "description": "Invert touchpad scroll direction" }, { "section": "popoutElevationEnabled", @@ -3926,30 +4556,6 @@ ], "description": "Shadow elevation on popouts, OSDs, and dropdowns" }, - { - "section": "hyprlandResizeOnBorder", - "label": "Resize on Border", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "border", - "colors", - "drag", - "dragging", - "edges", - "hyprland", - "look", - "mouse", - "resize", - "scheme", - "style", - "their", - "theme", - "windows" - ], - "description": "Resize windows by dragging their edges with the mouse" - }, { "section": "runDmsMatugenTemplates", "label": "Run DMS Templates", @@ -4351,148 +4957,6 @@ "icon": "opacity", "description": "Change bar appearance" }, - { - "section": "niriLayoutRadiusOverride", - "label": "Window Corner Radius", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "corner", - "corners", - "look", - "niri", - "override", - "radius", - "round", - "rounded", - "scheme", - "style", - "theme", - "window", - "windows" - ], - "description": "Rounded corners for windows" - }, - { - "section": "mangoLayoutRadiusOverride", - "label": "Window Corner Radius", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "corner", - "corners", - "look", - "mango", - "mangowc", - "override", - "radius", - "round", - "rounded", - "scheme", - "style", - "theme", - "window", - "windows" - ], - "description": "Rounded corners for windows (border_radius)" - }, - { - "section": "niriLayoutGapsOverride", - "label": "Window Gaps", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "between", - "colors", - "gaps", - "look", - "niri", - "override", - "scheme", - "space", - "style", - "theme", - "window", - "windows" - ], - "description": "Space between windows" - }, - { - "section": "hyprlandLayoutGapsOverride", - "label": "Window Gaps", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "between", - "colors", - "gaps", - "hyprland", - "look", - "override", - "scheme", - "space", - "style", - "theme", - "window", - "windows" - ], - "description": "Space between windows (gaps_in and gaps_out)" - }, - { - "section": "mangoLayoutGapsOverride", - "label": "Window Gaps", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "between", - "colors", - "gappiv", - "gappoh", - "gaps", - "look", - "mango", - "mangowc", - "override", - "scheme", - "space", - "style", - "theme", - "window", - "windows" - ], - "description": "Space between windows (gappih/gappiv/gappoh/gappov)" - }, - { - "section": "hyprlandLayoutRadiusOverride", - "label": "Window Rounding", - "tabIndex": 10, - "category": "Theme & Colors", - "keywords": [ - "appearance", - "colors", - "corners", - "hyprland", - "look", - "override", - "radius", - "round", - "rounded", - "rounding", - "scheme", - "style", - "theme", - "window", - "windows" - ], - "description": "Rounded corners for windows (decoration.rounding)" - }, { "section": "matugenTemplateZed", "label": "Zed", @@ -4952,6 +5416,27 @@ ], "description": "Automatically lock the screen when DMS starts" }, + { + "section": "lockBeforeSuspend", + "label": "Lock before suspend", + "tabIndex": 11, + "category": "Lock Screen", + "keywords": [ + "automatic", + "automatically", + "before", + "lock", + "login", + "password", + "prepares", + "screen", + "security", + "sleep", + "suspend", + "system" + ], + "description": "Automatically lock the screen when the system prepares to suspend" + }, { "section": "lockScreenNotificationMode", "label": "Notification Display", @@ -5792,22 +6277,6 @@ ], "description": "Play sound when volume is adjusted" }, - { - "section": "_tab_16", - "label": "Media Player", - "tabIndex": 16, - "category": "Media Player", - "keywords": [ - "audio", - "media", - "mpris", - "music", - "playback", - "player", - "spotify" - ], - "icon": "music_note" - }, { "section": "mediaPlayer", "label": "Media Player Settings", @@ -5853,6 +6322,28 @@ ], "description": "Scroll wheel behavior on media widget" }, + { + "section": "_tab_16", + "label": "Widgets & Notifications", + "tabIndex": 16, + "category": "Media Player", + "keywords": [ + "alert", + "alerts", + "components", + "media", + "modules", + "mpris", + "music", + "notif", + "notifications", + "notifs", + "player", + "spotify", + "widgets" + ], + "icon": "dashboard" + }, { "section": "notificationCompactMode", "label": "Compact", @@ -7080,27 +7571,6 @@ "icon": "schedule", "description": "Gradually fade the screen before locking with a configurable grace period" }, - { - "section": "lockBeforeSuspend", - "label": "Lock before suspend", - "tabIndex": 21, - "category": "Power & Sleep", - "keywords": [ - "automatically", - "before", - "energy", - "lock", - "power", - "prepares", - "screen", - "security", - "shutdown", - "sleep", - "suspend", - "system" - ], - "description": "Automatically lock the screen when the system prepares to suspend" - }, { "section": "fadeToLockGracePeriod", "label": "Lock fade grace period", @@ -7621,21 +8091,6 @@ ], "icon": "widgets" }, - { - "section": "_tab_28", - "label": "Window Rules", - "tabIndex": 28, - "category": "Window Rules", - "keywords": [ - "floating", - "fullscreen", - "matching", - "opacity", - "rules", - "window" - ], - "icon": "select_window" - }, { "section": "audioInputDevices", "label": "Input Devices",