From e1acaaa27c567b744b319d9e815f9a9c9fc4c5e7 Mon Sep 17 00:00:00 2001 From: bbedward Date: Thu, 4 Dec 2025 08:56:04 -0500 Subject: [PATCH] dankbar: add option to disable maximize detection fixes #895 --- quickshell/Common/SettingsData.qml | 3 +- quickshell/Common/settings/SettingsSpec.js | 3 +- quickshell/Modules/DankBar/DankBarWindow.qml | 2 + quickshell/Modules/Settings/DankBarTab.qml | 376 ++++++++---------- .../Settings/Widgets/SettingsSliderCard.qml | 100 +++++ .../Settings/Widgets/SettingsToggleCard.qml | 113 ++++++ 6 files changed, 390 insertions(+), 207 deletions(-) create mode 100644 quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml create mode 100644 quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index 3697cdc2..658b8018 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -372,7 +372,8 @@ Singleton { openOnOverview: false, visible: true, popupGapsAuto: true, - popupGapsManual: 4 + popupGapsManual: 4, + maximizeDetection: true } ] diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index 60edb2bd..4dd5d318 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -270,7 +270,8 @@ var SPEC = { openOnOverview: false, visible: true, popupGapsAuto: true, - popupGapsManual: 4 + popupGapsManual: 4, + maximizeDetection: true }], onChange: "updateBarConfigs" } }; diff --git a/quickshell/Modules/DankBar/DankBarWindow.qml b/quickshell/Modules/DankBar/DankBarWindow.qml index 872ae207..0dc9ad8f 100644 --- a/quickshell/Modules/DankBar/DankBarWindow.qml +++ b/quickshell/Modules/DankBar/DankBarWindow.qml @@ -149,6 +149,8 @@ PanelWindow { property string screenName: modelData.name readonly property bool hasMaximizedToplevel: { + if (!(barConfig?.maximizeDetection ?? true)) + return false; if (!CompositorService.isHyprland && !CompositorService.isNiri) return false; diff --git a/quickshell/Modules/Settings/DankBarTab.qml b/quickshell/Modules/Settings/DankBarTab.qml index 9521ad5a..7ac8c61b 100644 --- a/quickshell/Modules/Settings/DankBarTab.qml +++ b/quickshell/Modules/Settings/DankBarTab.qml @@ -236,7 +236,8 @@ Item { openOnOverview: defaultBar.openOnOverview ?? false, visible: defaultBar.visible ?? true, popupGapsAuto: defaultBar.popupGapsAuto ?? true, - popupGapsManual: defaultBar.popupGapsManual ?? 4 + popupGapsManual: defaultBar.popupGapsManual ?? 4, + maximizeDetection: defaultBar.maximizeDetection ?? true }; SettingsData.addBarConfig(newBar); selectedBarId = newId; @@ -739,6 +740,17 @@ Item { } } + SettingsToggleCard { + 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) + checked: selectedBarConfig?.maximizeDetection ?? true + onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { + maximizeDetection: checked + }) + } + SettingsCard { iconName: "space_bar" title: I18n.tr("Spacing") @@ -932,220 +944,178 @@ Item { } } - SettingsCard { + SettingsToggleCard { iconName: "border_style" title: I18n.tr("Border") visible: selectedBarConfig?.enabled + checked: selectedBarConfig?.borderEnabled ?? false + onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { + borderEnabled: checked + }) - SettingsToggleRow { - text: I18n.tr("Enable Border") - checked: selectedBarConfig?.borderEnabled ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - borderEnabled: checked - }) + SettingsButtonGroupRow { + text: I18n.tr("Color") + model: ["Surface", "Secondary", "Primary"] + currentIndex: { + switch (selectedBarConfig?.borderColor || "surfaceText") { + case "surfaceText": + return 0; + case "secondary": + return 1; + case "primary": + return 2; + default: + return 0; + } + } + onSelectionChanged: (index, selected) => { + if (!selected) + return; + let newColor = "surfaceText"; + switch (index) { + case 0: + newColor = "surfaceText"; + break; + case 1: + newColor = "secondary"; + break; + case 2: + newColor = "primary"; + break; + } + SettingsData.updateBarConfig(selectedBarId, { + borderColor: newColor + }); + } } - Column { - width: parent.width - leftPadding: Theme.spacingM - spacing: Theme.spacingM - visible: selectedBarConfig?.borderEnabled ?? false - - Rectangle { - width: parent.width - parent.leftPadding - height: 1 - color: Theme.outline - opacity: 0.15 + SettingsSliderRow { + id: borderOpacitySlider + text: I18n.tr("Opacity") + value: (selectedBarConfig?.borderOpacity ?? 1.0) * 100 + minimum: 0 + maximum: 100 + unit: "%" + defaultValue: 100 + onSliderValueChanged: newValue => { + borderOpacityDebounce.pendingValue = newValue / 100; + borderOpacityDebounce.restart(); } - SettingsButtonGroupRow { - width: parent.width - parent.parent.leftPadding - text: I18n.tr("Color") - model: ["Surface", "Secondary", "Primary"] - currentIndex: { - switch (selectedBarConfig?.borderColor || "surfaceText") { - case "surfaceText": - return 0; - case "secondary": - return 1; - case "primary": - return 2; - default: - return 0; - } - } - onSelectionChanged: (index, selected) => { - if (!selected) - return; - let newColor = "surfaceText"; - switch (index) { - case 0: - newColor = "surfaceText"; - break; - case 1: - newColor = "secondary"; - break; - case 2: - newColor = "primary"; - break; - } - SettingsData.updateBarConfig(selectedBarId, { - borderColor: newColor - }); - } - } - - SettingsSliderRow { - id: borderOpacitySlider - width: parent.width - parent.parent.leftPadding - text: I18n.tr("Border Opacity") + Binding { + target: borderOpacitySlider + property: "value" value: (selectedBarConfig?.borderOpacity ?? 1.0) * 100 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => { - borderOpacityDebounce.pendingValue = newValue / 100; - borderOpacityDebounce.restart(); - } + restoreMode: Binding.RestoreBinding + } + } - Binding { - target: borderOpacitySlider - property: "value" - value: (selectedBarConfig?.borderOpacity ?? 1.0) * 100 - restoreMode: Binding.RestoreBinding - } + SettingsSliderRow { + id: borderThicknessSlider + text: I18n.tr("Thickness") + value: selectedBarConfig?.borderThickness ?? 1 + minimum: 1 + maximum: 10 + unit: "px" + defaultValue: 1 + onSliderValueChanged: newValue => { + borderThicknessDebounce.pendingValue = newValue; + borderThicknessDebounce.restart(); } - SettingsSliderRow { - id: borderThicknessSlider - width: parent.width - parent.parent.leftPadding - text: I18n.tr("Border Thickness") + Binding { + target: borderThicknessSlider + property: "value" value: selectedBarConfig?.borderThickness ?? 1 - minimum: 1 - maximum: 10 - unit: "px" - defaultValue: 1 - onSliderValueChanged: newValue => { - borderThicknessDebounce.pendingValue = newValue; - borderThicknessDebounce.restart(); - } - - Binding { - target: borderThicknessSlider - property: "value" - value: selectedBarConfig?.borderThickness ?? 1 - restoreMode: Binding.RestoreBinding - } + restoreMode: Binding.RestoreBinding } } } - SettingsCard { + SettingsToggleCard { iconName: "highlight" title: I18n.tr("Widget Outline") visible: selectedBarConfig?.enabled + checked: selectedBarConfig?.widgetOutlineEnabled ?? false + onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { + widgetOutlineEnabled: checked + }) - SettingsToggleRow { - text: I18n.tr("Enable Widget Outline") - checked: selectedBarConfig?.widgetOutlineEnabled ?? false - onToggled: checked => SettingsData.updateBarConfig(selectedBarId, { - widgetOutlineEnabled: checked - }) + SettingsButtonGroupRow { + text: I18n.tr("Color") + model: ["Surface", "Secondary", "Primary"] + currentIndex: { + switch (selectedBarConfig?.widgetOutlineColor || "primary") { + 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.updateBarConfig(selectedBarId, { + widgetOutlineColor: newColor + }); + } } - Column { - width: parent.width - leftPadding: Theme.spacingM - spacing: Theme.spacingM - visible: selectedBarConfig?.widgetOutlineEnabled ?? false - - Rectangle { - width: parent.width - parent.leftPadding - height: 1 - color: Theme.outline - opacity: 0.15 + SettingsSliderRow { + id: widgetOutlineOpacitySlider + text: I18n.tr("Opacity") + value: (selectedBarConfig?.widgetOutlineOpacity ?? 1.0) * 100 + minimum: 0 + maximum: 100 + unit: "%" + defaultValue: 100 + onSliderValueChanged: newValue => { + widgetOutlineOpacityDebounce.pendingValue = newValue / 100; + widgetOutlineOpacityDebounce.restart(); } - SettingsButtonGroupRow { - width: parent.width - parent.parent.leftPadding - text: I18n.tr("Color") - model: ["Surface", "Secondary", "Primary"] - currentIndex: { - switch (selectedBarConfig?.widgetOutlineColor || "primary") { - 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.updateBarConfig(selectedBarId, { - widgetOutlineColor: newColor - }); - } - } - - SettingsSliderRow { - id: widgetOutlineOpacitySlider - width: parent.width - parent.parent.leftPadding - text: I18n.tr("Outline Opacity") + Binding { + target: widgetOutlineOpacitySlider + property: "value" value: (selectedBarConfig?.widgetOutlineOpacity ?? 1.0) * 100 - minimum: 0 - maximum: 100 - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => { - widgetOutlineOpacityDebounce.pendingValue = newValue / 100; - widgetOutlineOpacityDebounce.restart(); - } + restoreMode: Binding.RestoreBinding + } + } - Binding { - target: widgetOutlineOpacitySlider - property: "value" - value: (selectedBarConfig?.widgetOutlineOpacity ?? 1.0) * 100 - restoreMode: Binding.RestoreBinding - } + SettingsSliderRow { + id: widgetOutlineThicknessSlider + text: I18n.tr("Thickness") + value: selectedBarConfig?.widgetOutlineThickness ?? 1 + minimum: 1 + maximum: 10 + unit: "px" + defaultValue: 1 + onSliderValueChanged: newValue => { + widgetOutlineThicknessDebounce.pendingValue = newValue; + widgetOutlineThicknessDebounce.restart(); } - SettingsSliderRow { - id: widgetOutlineThicknessSlider - width: parent.width - parent.parent.leftPadding - text: I18n.tr("Outline Thickness") + Binding { + target: widgetOutlineThicknessSlider + property: "value" value: selectedBarConfig?.widgetOutlineThickness ?? 1 - minimum: 1 - maximum: 10 - unit: "px" - defaultValue: 1 - onSliderValueChanged: newValue => { - widgetOutlineThicknessDebounce.pendingValue = newValue; - widgetOutlineThicknessDebounce.restart(); - } - - Binding { - target: widgetOutlineThicknessSlider - property: "value" - value: selectedBarConfig?.widgetOutlineThickness ?? 1 - restoreMode: Binding.RestoreBinding - } + restoreMode: Binding.RestoreBinding } } } @@ -1198,31 +1168,27 @@ Item { } } - SettingsCard { + SettingsSliderCard { + id: fontScaleSliderCard iconName: "text_fields" title: I18n.tr("Font Scale") + description: I18n.tr("Scale DankBar font sizes independently") visible: selectedBarConfig?.enabled + minimum: 50 + maximum: 200 + value: Math.round((selectedBarConfig?.fontScale ?? 1.0) * 100) + unit: "%" + defaultValue: 100 + onSliderValueChanged: newValue => { + fontScaleDebounce.pendingValue = newValue / 100; + fontScaleDebounce.restart(); + } - SettingsSliderRow { - id: fontScaleSlider - text: I18n.tr("DankBar Font Scale") - description: I18n.tr("Scale DankBar font sizes independently") - minimum: 50 - maximum: 200 + Binding { + target: fontScaleSliderCard + property: "value" value: Math.round((selectedBarConfig?.fontScale ?? 1.0) * 100) - unit: "%" - defaultValue: 100 - onSliderValueChanged: newValue => { - fontScaleDebounce.pendingValue = newValue / 100; - fontScaleDebounce.restart(); - } - - Binding { - target: fontScaleSlider - property: "value" - value: Math.round((selectedBarConfig?.fontScale ?? 1.0) * 100) - restoreMode: Binding.RestoreBinding - } + restoreMode: Binding.RestoreBinding } } } diff --git a/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml b/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml new file mode 100644 index 00000000..16839498 --- /dev/null +++ b/quickshell/Modules/Settings/Widgets/SettingsSliderCard.qml @@ -0,0 +1,100 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import qs.Common +import qs.Widgets + +StyledRect { + id: root + + property string tab: "" + property var tags: [] + + property string title: "" + property string description: "" + property string iconName: "" + property alias value: slider.value + property alias minimum: slider.minimum + property alias maximum: slider.maximum + property alias unit: slider.unit + property int defaultValue: -1 + + signal sliderValueChanged(int newValue) + + width: parent?.width ?? 0 + height: Theme.spacingL * 2 + contentColumn.height + radius: Theme.cornerRadius + color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) + + Column { + id: contentColumn + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Theme.spacingL + anchors.rightMargin: Theme.spacingL + spacing: Theme.spacingS + + Row { + width: parent.width + spacing: Theme.spacingM + + DankIcon { + id: headerIcon + name: root.iconName + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + visible: root.iconName !== "" + } + + Column { + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingXS + width: parent.width - headerIcon.width - (root.defaultValue >= 0 ? resetButton.width + Theme.spacingS : 0) - Theme.spacingM + + StyledText { + text: root.title + font.pixelSize: Theme.fontSizeLarge + font.weight: Font.Medium + color: Theme.surfaceText + visible: root.title !== "" + } + + StyledText { + text: root.description + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + wrapMode: Text.WordWrap + width: parent.width + visible: root.description !== "" + } + } + + DankActionButton { + id: resetButton + anchors.verticalCenter: parent.verticalCenter + buttonSize: 36 + iconName: "restart_alt" + iconSize: 20 + visible: root.defaultValue >= 0 && slider.value !== root.defaultValue + backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) + iconColor: Theme.surfaceVariantText + onClicked: { + slider.value = root.defaultValue; + root.sliderValueChanged(root.defaultValue); + } + } + } + + DankSlider { + id: slider + width: parent.width + height: 32 + showValue: true + wheelEnabled: false + thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) + onSliderValueChanged: newValue => root.sliderValueChanged(newValue) + } + } +} diff --git a/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml b/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml new file mode 100644 index 00000000..a9dbea46 --- /dev/null +++ b/quickshell/Modules/Settings/Widgets/SettingsToggleCard.qml @@ -0,0 +1,113 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import qs.Common +import qs.Widgets + +StyledRect { + id: root + + property string tab: "" + property var tags: [] + + property string title: "" + property string description: "" + property string iconName: "" + property bool checked: false + property bool enabled: true + + default property alias content: expandedContent.children + readonly property bool hasContent: expandedContent.children.length > 0 + + signal toggled(bool checked) + + width: parent?.width ?? 0 + height: Theme.spacingL * 2 + mainColumn.height + radius: Theme.cornerRadius + color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) + + Column { + id: mainColumn + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: Theme.spacingL + anchors.rightMargin: Theme.spacingL + spacing: Theme.spacingM + + Item { + width: parent.width + height: headerColumn.height + + Column { + id: headerColumn + anchors.left: parent.left + anchors.right: toggleSwitch.left + anchors.rightMargin: Theme.spacingM + spacing: Theme.spacingXS + + Row { + spacing: Theme.spacingM + + DankIcon { + id: headerIcon + name: root.iconName + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + visible: root.iconName !== "" + } + + StyledText { + id: headerText + text: root.title + font.pixelSize: Theme.fontSizeLarge + font.weight: Font.Medium + color: Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + visible: root.title !== "" + } + } + + StyledText { + id: descriptionText + text: root.description + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + wrapMode: Text.WordWrap + width: parent.width + visible: root.description !== "" + } + } + + DankToggle { + id: toggleSwitch + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + hideText: true + checked: root.checked + enabled: root.enabled + onToggled: checked => root.toggled(checked) + } + + StateLayer { + anchors.fill: parent + disabled: !root.enabled + stateColor: Theme.primary + cornerRadius: root.radius + onClicked: { + if (!root.enabled) + return; + root.toggled(!root.checked); + } + } + } + + Column { + id: expandedContent + width: parent.width + spacing: Theme.spacingM + visible: root.checked && root.hasContent + } + } +}