summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/dms/Modules/Settings/DankBarTab.qml
diff options
context:
space:
mode:
authorNippy <nippy@rp1.hu>2026-05-08 19:50:49 +0200
committerNippy <nippy@rp1.hu>2026-05-08 19:50:49 +0200
commit3462bcc46ecf74f576ea4397f16492c16bd75b10 (patch)
treec5ab7aef4498647e057bda8d49c11e5f9dda74c9 /raveos-hyprland-theme/theme-data/dms/Modules/Settings/DankBarTab.qml
parent56616f693b4f263cbf0d47da43b67424efa6022d (diff)
downloadRaveOS-PKGBUILD-3462bcc46ecf74f576ea4397f16492c16bd75b10.tar.gz
RaveOS-PKGBUILD-3462bcc46ecf74f576ea4397f16492c16bd75b10.zip
raveos update
Diffstat (limited to 'raveos-hyprland-theme/theme-data/dms/Modules/Settings/DankBarTab.qml')
-rw-r--r--raveos-hyprland-theme/theme-data/dms/Modules/Settings/DankBarTab.qml1563
1 files changed, 1563 insertions, 0 deletions
diff --git a/raveos-hyprland-theme/theme-data/dms/Modules/Settings/DankBarTab.qml b/raveos-hyprland-theme/theme-data/dms/Modules/Settings/DankBarTab.qml
new file mode 100644
index 0000000..a4bd87d
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/dms/Modules/Settings/DankBarTab.qml
@@ -0,0 +1,1563 @@
+import QtQuick
+import QtQuick.Layouts
+import Quickshell
+import qs.Common
+import qs.Services
+import qs.Widgets
+import qs.Modules.Settings.Widgets
+
+Item {
+ id: dankBarTab
+
+ LayoutMirroring.enabled: I18n.isRtl
+ LayoutMirroring.childrenInherit: true
+
+ property var parentModal: null
+ property string selectedBarId: "default"
+
+ property var selectedBarConfig: {
+ selectedBarId;
+ SettingsData.barConfigs;
+ const index = SettingsData.barConfigs.findIndex(cfg => cfg.id === selectedBarId);
+ return index !== -1 ? SettingsData.barConfigs[index] : SettingsData.barConfigs[0];
+ }
+
+ property bool selectedBarIsVertical: {
+ selectedBarId;
+ const pos = selectedBarConfig?.position ?? SettingsData.Position.Top;
+ return pos === SettingsData.Position.Left || pos === SettingsData.Position.Right;
+ }
+
+ Timer {
+ id: horizontalBarChangeDebounce
+ interval: 500
+ repeat: false
+ onTriggered: {
+ const verticalBars = SettingsData.barConfigs.filter(cfg => {
+ const pos = cfg.position ?? SettingsData.Position.Top;
+ return pos === SettingsData.Position.Left || pos === SettingsData.Position.Right;
+ });
+
+ verticalBars.forEach(bar => {
+ if (!bar.enabled)
+ return;
+ SettingsData.updateBarConfig(bar.id, {
+ enabled: false
+ });
+ Qt.callLater(() => SettingsData.updateBarConfig(bar.id, {
+ enabled: true
+ }));
+ });
+ }
+ }
+
+ function _isBarActive(c) {
+ if (!c.enabled)
+ return false;
+ const prefs = c.screenPreferences || ["all"];
+ if (prefs.length > 0)
+ return true;
+ return (c.showOnLastDisplay ?? true) && Quickshell.screens.length === 1;
+ }
+
+ function notifyHorizontalBarChange() {
+ const configs = SettingsData.barConfigs;
+ if (configs.length < 2)
+ return;
+
+ const hasHorizontal = configs.some(c => {
+ if (!_isBarActive(c))
+ return false;
+ const p = c.position ?? SettingsData.Position.Top;
+ return p === SettingsData.Position.Top || p === SettingsData.Position.Bottom;
+ });
+ if (!hasHorizontal)
+ return;
+
+ const hasVertical = configs.some(c => {
+ if (!_isBarActive(c))
+ return false;
+ const p = c.position ?? SettingsData.Position.Top;
+ return p === SettingsData.Position.Left || p === SettingsData.Position.Right;
+ });
+ if (!hasVertical)
+ return;
+
+ horizontalBarChangeDebounce.restart();
+ }
+
+ function createNewBar() {
+ if (SettingsData.barConfigs.length >= 4)
+ return;
+ const defaultBar = SettingsData.getBarConfig("default");
+ if (!defaultBar)
+ return;
+ const newId = "bar" + Date.now();
+ const newBar = {
+ id: newId,
+ name: "Bar " + (SettingsData.barConfigs.length + 1),
+ enabled: true,
+ position: defaultBar.position ?? 0,
+ screenPreferences: [],
+ showOnLastDisplay: false,
+ leftWidgets: defaultBar.leftWidgets || [],
+ centerWidgets: defaultBar.centerWidgets || [],
+ rightWidgets: defaultBar.rightWidgets || [],
+ spacing: defaultBar.spacing ?? 4,
+ innerPadding: defaultBar.innerPadding ?? 4,
+ bottomGap: defaultBar.bottomGap ?? 0,
+ transparency: defaultBar.transparency ?? 1.0,
+ widgetTransparency: defaultBar.widgetTransparency ?? 1.0,
+ squareCorners: defaultBar.squareCorners ?? false,
+ noBackground: defaultBar.noBackground ?? false,
+ gothCornersEnabled: defaultBar.gothCornersEnabled ?? false,
+ gothCornerRadiusOverride: defaultBar.gothCornerRadiusOverride ?? false,
+ gothCornerRadiusValue: defaultBar.gothCornerRadiusValue ?? 12,
+ borderEnabled: defaultBar.borderEnabled ?? false,
+ borderColor: defaultBar.borderColor || "surfaceText",
+ borderOpacity: defaultBar.borderOpacity ?? 1.0,
+ borderThickness: defaultBar.borderThickness ?? 1,
+ widgetOutlineEnabled: defaultBar.widgetOutlineEnabled ?? false,
+ widgetOutlineColor: defaultBar.widgetOutlineColor || "primary",
+ widgetOutlineOpacity: defaultBar.widgetOutlineOpacity ?? 1.0,
+ widgetOutlineThickness: defaultBar.widgetOutlineThickness ?? 1,
+ widgetPadding: defaultBar.widgetPadding ?? 8,
+ maximizeWidgetIcons: defaultBar.maximizeWidgetIcons ?? false,
+ maximizeWidgetText: defaultBar.maximizeWidgetText ?? false,
+ removeWidgetPadding: defaultBar.removeWidgetPadding ?? false,
+ fontScale: defaultBar.fontScale ?? 1.0,
+ iconScale: defaultBar.iconScale ?? 1.0,
+ autoHide: defaultBar.autoHide ?? false,
+ autoHideDelay: defaultBar.autoHideDelay ?? 250,
+ showOnWindowsOpen: defaultBar.showOnWindowsOpen ?? false,
+ openOnOverview: defaultBar.openOnOverview ?? false,
+ visible: defaultBar.visible ?? true,
+ popupGapsAuto: defaultBar.popupGapsAuto ?? true,
+ popupGapsManual: defaultBar.popupGapsManual ?? 4,
+ maximizeDetection: defaultBar.maximizeDetection ?? true,
+ scrollEnabled: defaultBar.scrollEnabled ?? true,
+ scrollXBehavior: defaultBar.scrollXBehavior ?? "column",
+ scrollYBehavior: defaultBar.scrollYBehavior ?? "workspace",
+ shadowIntensity: defaultBar.shadowIntensity ?? 0,
+ shadowOpacity: defaultBar.shadowOpacity ?? 60,
+ shadowDirectionMode: defaultBar.shadowDirectionMode ?? "inherit",
+ shadowDirection: defaultBar.shadowDirection ?? "top",
+ shadowColorMode: defaultBar.shadowColorMode ?? "default",
+ shadowCustomColor: defaultBar.shadowCustomColor ?? "#000000"
+ };
+ SettingsData.addBarConfig(newBar);
+ selectedBarId = newId;
+ }
+
+ function deleteBar(barId) {
+ if (barId === "default")
+ return;
+ if (SettingsData.barConfigs.length <= 1)
+ return;
+ SettingsData.deleteBarConfig(barId);
+ selectedBarId = "default";
+ }
+
+ function toggleBarEnabled(barId) {
+ if (barId === "default")
+ return;
+ const config = SettingsData.getBarConfig(barId);
+ if (!config)
+ return;
+ SettingsData.updateBarConfig(barId, {
+ enabled: !config.enabled
+ });
+ }
+
+ function getBarScreenPreferences(barId) {
+ const config = SettingsData.getBarConfig(barId);
+ return config?.screenPreferences || ["all"];
+ }
+
+ function setBarScreenPreferences(barId, prefs) {
+ SettingsData.updateBarConfig(barId, {
+ screenPreferences: prefs
+ });
+ notifyHorizontalBarChange();
+ }
+
+ function getBarShowOnLastDisplay(barId) {
+ const config = SettingsData.getBarConfig(barId);
+ return config?.showOnLastDisplay ?? true;
+ }
+
+ function setBarShowOnLastDisplay(barId, value) {
+ SettingsData.updateBarConfig(barId, {
+ showOnLastDisplay: value
+ });
+ if (Quickshell.screens.length === 1)
+ notifyHorizontalBarChange();
+ }
+
+ DankFlickable {
+ anchors.fill: parent
+ clip: true
+ contentHeight: mainColumn.height + Theme.spacingXL
+ contentWidth: width
+
+ Column {
+ id: mainColumn
+ topPadding: 4
+ width: Math.min(550, parent.width - Theme.spacingL * 2)
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: Theme.spacingXL
+
+ SettingsCard {
+ iconName: "dashboard"
+ title: I18n.tr("Bar Configurations")
+ settingKey: "barConfigurations"
+
+ RowLayout {
+ width: parent.width
+ spacing: Theme.spacingM
+
+ StyledText {
+ text: I18n.tr("Manage up to 4 independent bar configurations. Each bar has its own position, widgets, styling, and display assignment.")
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.surfaceVariantText
+ wrapMode: Text.WordWrap
+ Layout.fillWidth: true
+ }
+
+ DankButton {
+ text: I18n.tr("Add Bar")
+ iconName: "add"
+ buttonHeight: 32
+ visible: SettingsData.barConfigs.length < 4
+ onClicked: dankBarTab.createNewBar()
+ }
+ }
+
+ Column {
+ width: parent.width
+ spacing: Theme.spacingS
+
+ Repeater {
+ model: SettingsData.barConfigs
+
+ Rectangle {
+ id: barCard
+ required property var modelData
+ required property int index
+
+ width: parent.width
+ height: barCardContent.implicitHeight + Theme.spacingM * 2
+ radius: Theme.cornerRadius
+ color: dankBarTab.selectedBarId === modelData.id ? Theme.withAlpha(Theme.primary, 0.15) : Theme.surfaceVariant
+ border.width: dankBarTab.selectedBarId === modelData.id ? 2 : 0
+ border.color: Theme.primary
+
+ Row {
+ id: barCardContent
+ anchors.fill: parent
+ anchors.margins: Theme.spacingM
+ spacing: Theme.spacingM
+
+ Column {
+ width: parent.width - deleteBtn.width - Theme.spacingM
+ spacing: Theme.spacingXS / 2
+
+ StyledText {
+ text: barCard.modelData.name || "Bar " + (barCard.index + 1)
+ font.pixelSize: Theme.fontSizeMedium
+ font.weight: Font.Medium
+ color: Theme.surfaceText
+ width: parent.width
+ horizontalAlignment: Text.AlignLeft
+ }
+
+ Row {
+ width: parent.width
+ spacing: Theme.spacingS
+
+ StyledText {
+ text: {
+ SettingsData.barConfigs;
+ const cfg = SettingsData.getBarConfig(barCard.modelData.id);
+ switch (cfg?.position ?? SettingsData.Position.Top) {
+ case SettingsData.Position.Top:
+ return I18n.tr("Top");
+ case SettingsData.Position.Bottom:
+ return I18n.tr("Bottom");
+ case SettingsData.Position.Left:
+ return I18n.tr("Left");
+ case SettingsData.Position.Right:
+ return I18n.tr("Right");
+ default:
+ return I18n.tr("Top");
+ }
+ }
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.surfaceVariantText
+ horizontalAlignment: Text.AlignLeft
+ }
+
+ StyledText {
+ text: "•"
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.surfaceVariantText
+ horizontalAlignment: Text.AlignLeft
+ }
+
+ StyledText {
+ text: {
+ SettingsData.barConfigs;
+ const cfg = SettingsData.getBarConfig(barCard.modelData.id);
+ const prefs = cfg?.screenPreferences || ["all"];
+ if (prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all"))
+ return I18n.tr("All displays");
+ return prefs.length === 1
+ ? I18n.tr("%1 display").arg(prefs.length)
+ : I18n.tr("%1 displays").arg(prefs.length);
+ }
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.surfaceVariantText
+ horizontalAlignment: Text.AlignLeft
+ }
+
+ StyledText {
+ text: "•"
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.surfaceVariantText
+ horizontalAlignment: Text.AlignLeft
+ }
+
+ StyledText {
+ text: {
+ SettingsData.barConfigs;
+ const cfg = SettingsData.getBarConfig(barCard.modelData.id);
+ const left = cfg?.leftWidgets?.length || 0;
+ const center = cfg?.centerWidgets?.length || 0;
+ const right = cfg?.rightWidgets?.length || 0;
+ return I18n.tr("%1 widgets").replace("%1", left + center + right);
+ }
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.surfaceVariantText
+ horizontalAlignment: Text.AlignLeft
+ }
+
+ StyledText {
+ text: "•"
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.surfaceVariantText
+ horizontalAlignment: Text.AlignLeft
+ visible: {
+ SettingsData.barConfigs;
+ const cfg = SettingsData.getBarConfig(barCard.modelData.id);
+ return !cfg?.enabled && barCard.modelData.id !== "default";
+ }
+ }
+
+ StyledText {
+ text: I18n.tr("Disabled")
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.error
+ horizontalAlignment: Text.AlignLeft
+ visible: {
+ SettingsData.barConfigs;
+ const cfg = SettingsData.getBarConfig(barCard.modelData.id);
+ return !cfg?.enabled && barCard.modelData.id !== "default";
+ }
+ }
+ }
+ }
+
+ DankActionButton {
+ id: deleteBtn
+ buttonSize: 32
+ iconName: "delete"
+ iconSize: 16
+ backgroundColor: Theme.withAlpha(Theme.error, 0.15)
+ iconColor: Theme.error
+ visible: barCard.modelData.id !== "default"
+ enabled: SettingsData.barConfigs.length > 1
+ anchors.verticalCenter: parent.verticalCenter
+ onClicked: dankBarTab.deleteBar(barCard.modelData.id)
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ z: -1
+ cursorShape: Qt.PointingHandCursor
+ onClicked: dankBarTab.selectedBarId = barCard.modelData.id
+ }
+
+ Behavior on color {
+ ColorAnimation {
+ duration: Theme.shortDuration
+ easing.type: Theme.standardEasing
+ }
+ }
+
+ Behavior on border.width {
+ NumberAnimation {
+ duration: Theme.shortDuration
+ easing.type: Theme.standardEasing
+ }
+ }
+ }
+ }
+ }
+ }
+
+ SettingsCard {
+ iconName: selectedBarConfig?.enabled ? "visibility" : "visibility_off"
+ title: I18n.tr("Enable Bar")
+ visible: selectedBarId !== "default"
+
+ SettingsToggleRow {
+ text: I18n.tr("Toggle visibility of this bar configuration")
+ checked: {
+ selectedBarId;
+ return selectedBarConfig?.enabled ?? false;
+ }
+ onToggled: toggled => dankBarTab.toggleBarEnabled(selectedBarId)
+ }
+ }
+
+ SettingsCard {
+ iconName: "display_settings"
+ title: I18n.tr("Display Assignment")
+ settingKey: "barDisplay"
+ visible: selectedBarConfig?.enabled
+
+ StyledText {
+ width: parent.width
+ text: I18n.tr("Configure which displays show \"%1\"").replace("%1", selectedBarConfig?.name || "this bar")
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.surfaceVariantText
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignLeft
+ }
+
+ Column {
+ id: displayAssignmentColumn
+ width: parent.width
+ spacing: Theme.spacingS
+
+ property bool showingAll: {
+ const prefs = selectedBarConfig?.screenPreferences || ["all"];
+ return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all");
+ }
+
+ SettingsToggleRow {
+ text: I18n.tr("All displays")
+ checked: displayAssignmentColumn.showingAll
+ onToggled: checked => {
+ if (checked) {
+ dankBarTab.setBarScreenPreferences(selectedBarId, ["all"]);
+ } else {
+ dankBarTab.setBarScreenPreferences(selectedBarId, []);
+ }
+ }
+ }
+
+ SettingsToggleRow {
+ text: I18n.tr("Show on Last Display")
+ checked: selectedBarConfig?.showOnLastDisplay ?? true
+ visible: !displayAssignmentColumn.showingAll
+ onToggled: checked => dankBarTab.setBarShowOnLastDisplay(selectedBarId, checked)
+ }
+
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: Theme.outline
+ opacity: 0.15
+ visible: !displayAssignmentColumn.showingAll
+ }
+
+ Column {
+ width: parent.width
+ spacing: Theme.spacingXS
+ visible: !displayAssignmentColumn.showingAll
+
+ Repeater {
+ model: Quickshell.screens
+
+ delegate: SettingsToggleRow {
+ id: screenToggle
+ required property var modelData
+
+ text: SettingsData.getScreenDisplayName(modelData)
+ description: modelData.width + "×" + modelData.height + " • " + (SettingsData.displayNameMode === "system" ? (modelData.model || "Unknown Model") : modelData.name)
+ checked: {
+ const prefs = selectedBarConfig?.screenPreferences || [];
+ if (typeof prefs[0] === "string" && prefs[0] === "all")
+ return false;
+ return SettingsData.isScreenInPreferences(modelData, prefs);
+ }
+ onToggled: checked => {
+ let currentPrefs = selectedBarConfig?.screenPreferences || [];
+ if (typeof currentPrefs[0] === "string" && currentPrefs[0] === "all")
+ currentPrefs = [];
+
+ const screenModelIndex = SettingsData.getScreenModelIndex(modelData);
+
+ let newPrefs = currentPrefs.filter(pref => {
+ if (typeof pref === "string")
+ return false;
+ if (pref.modelIndex !== undefined && screenModelIndex >= 0)
+ return !(pref.model === modelData.model && pref.modelIndex === screenModelIndex);
+ return pref.name !== modelData.name || pref.model !== modelData.model;
+ });
+
+ if (checked) {
+ const prefObj = {
+ name: modelData.name,
+ model: modelData.model || ""
+ };
+ if (screenModelIndex >= 0)
+ prefObj.modelIndex = screenModelIndex;
+ newPrefs.push(prefObj);
+ }
+
+ dankBarTab.setBarScreenPreferences(selectedBarId, newPrefs);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ SettingsCard {
+ iconName: "vertical_align_center"
+ title: I18n.tr("Position")
+ settingKey: "barPosition"
+ visible: selectedBarConfig?.enabled
+
+ Item {
+ width: parent.width
+ height: positionButtonGroup.height
+
+ DankButtonGroup {
+ id: positionButtonGroup
+ anchors.horizontalCenter: parent.horizontalCenter
+ model: [I18n.tr("Top"), I18n.tr("Bottom"), I18n.tr("Left"), I18n.tr("Right")]
+ currentIndex: {
+ selectedBarId;
+ const config = SettingsData.getBarConfig(selectedBarId);
+ const pos = config?.position ?? 0;
+ switch (pos) {
+ case SettingsData.Position.Top:
+ return 0;
+ case SettingsData.Position.Bottom:
+ return 1;
+ case SettingsData.Position.Left:
+ return 2;
+ case SettingsData.Position.Right:
+ return 3;
+ default:
+ return 0;
+ }
+ }
+ onSelectionChanged: (index, selected) => {
+ if (!selected)
+ return;
+ let newPos = 0;
+ switch (index) {
+ case 0:
+ newPos = SettingsData.Position.Top;
+ break;
+ case 1:
+ newPos = SettingsData.Position.Bottom;
+ break;
+ case 2:
+ newPos = SettingsData.Position.Left;
+ break;
+ case 3:
+ newPos = SettingsData.Position.Right;
+ break;
+ }
+ SettingsData.updateBarConfig(selectedBarId, {
+ position: newPos
+ });
+ notifyHorizontalBarChange();
+ }
+ }
+ }
+ }
+
+ SettingsCard {
+ iconName: "visibility_off"
+ title: I18n.tr("Visibility")
+ settingKey: "barVisibility"
+ visible: selectedBarConfig?.enabled
+
+ SettingsToggleRow {
+ text: I18n.tr("Auto-hide")
+ checked: selectedBarConfig?.autoHide ?? false
+ onToggled: toggled => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ autoHide: toggled
+ });
+ notifyHorizontalBarChange();
+ }
+ }
+
+ Column {
+ width: parent.width
+ spacing: Theme.spacingS
+ visible: selectedBarConfig?.autoHide ?? false
+ leftPadding: Theme.spacingM
+
+ Rectangle {
+ width: parent.width - parent.leftPadding
+ height: 1
+ color: Theme.outline
+ opacity: 0.15
+ }
+
+ SettingsSliderRow {
+ id: hideDelaySlider
+ width: parent.width - parent.parent.leftPadding
+ text: I18n.tr("Hide Delay")
+ value: selectedBarConfig?.autoHideDelay ?? 250
+ minimum: 0
+ maximum: 2000
+ unit: "ms"
+ defaultValue: 250
+ onSliderValueChanged: newValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ autoHideDelay: newValue
+ });
+ }
+
+ Binding {
+ target: hideDelaySlider
+ property: "value"
+ value: selectedBarConfig?.autoHideDelay ?? 250
+ restoreMode: Binding.RestoreBinding
+ }
+ }
+
+ SettingsToggleRow {
+ width: parent.width - parent.leftPadding
+ visible: CompositorService.isNiri || CompositorService.isHyprland
+ text: I18n.tr("Hide When Windows Open")
+ checked: selectedBarConfig?.showOnWindowsOpen ?? false
+ onToggled: toggled => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ showOnWindowsOpen: toggled
+ });
+ }
+ }
+ }
+
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: Theme.outline
+ opacity: 0.15
+ }
+
+ SettingsToggleRow {
+ text: I18n.tr("Manual Show/Hide")
+ checked: selectedBarConfig?.visible ?? true
+ onToggled: toggled => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ visible: toggled
+ });
+ notifyHorizontalBarChange();
+ }
+ }
+
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: Theme.outline
+ opacity: 0.15
+ }
+
+ SettingsToggleRow {
+ text: I18n.tr("Click Through")
+ checked: selectedBarConfig?.clickThrough ?? false
+ onToggled: toggled => SettingsData.updateBarConfig(selectedBarId, {
+ clickThrough: toggled
+ })
+ }
+
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: Theme.outline
+ opacity: 0.15
+ visible: CompositorService.isNiri
+ }
+
+ SettingsToggleRow {
+ visible: CompositorService.isNiri
+ text: I18n.tr("Show on Overview")
+ checked: selectedBarConfig?.openOnOverview ?? false
+ onToggled: toggled => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ openOnOverview: toggled
+ });
+ }
+ }
+ }
+
+ 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
+ })
+ }
+
+ SettingsToggleCard {
+ iconName: "mouse"
+ title: I18n.tr("Scroll Wheel")
+ description: I18n.tr("Control workspaces and columns by scrolling on the bar")
+ visible: selectedBarConfig?.enabled
+ checked: selectedBarConfig?.scrollEnabled ?? true
+ onToggled: checked => SettingsData.updateBarConfig(selectedBarId, {
+ scrollEnabled: checked
+ })
+
+ SettingsButtonGroupRow {
+ text: I18n.tr("Y Axis")
+ model: CompositorService.isNiri ? [I18n.tr("None"), I18n.tr("Workspace"), I18n.tr("Column")] : [I18n.tr("None"), I18n.tr("Workspace")]
+ currentIndex: {
+ switch (selectedBarConfig?.scrollYBehavior || "workspace") {
+ case "none":
+ return 0;
+ case "workspace":
+ return 1;
+ case "column":
+ return 2;
+ default:
+ return 1;
+ }
+ }
+ onSelectionChanged: (index, selected) => {
+ if (!selected)
+ return;
+ let behavior = "workspace";
+ switch (index) {
+ case 0:
+ behavior = "none";
+ break;
+ case 1:
+ behavior = "workspace";
+ break;
+ case 2:
+ behavior = "column";
+ break;
+ }
+ SettingsData.updateBarConfig(selectedBarId, {
+ scrollYBehavior: behavior
+ });
+ }
+ }
+
+ SettingsButtonGroupRow {
+ text: I18n.tr("X Axis")
+ visible: CompositorService.isNiri
+ model: [I18n.tr("None"), I18n.tr("Workspace"), I18n.tr("Column")]
+ currentIndex: {
+ switch (selectedBarConfig?.scrollXBehavior || "column") {
+ case "none":
+ return 0;
+ case "workspace":
+ return 1;
+ case "column":
+ return 2;
+ default:
+ return 2;
+ }
+ }
+ onSelectionChanged: (index, selected) => {
+ if (!selected)
+ return;
+ let behavior = "column";
+ switch (index) {
+ case 0:
+ behavior = "none";
+ break;
+ case 1:
+ behavior = "workspace";
+ break;
+ case 2:
+ behavior = "column";
+ break;
+ }
+ SettingsData.updateBarConfig(selectedBarId, {
+ scrollXBehavior: behavior
+ });
+ }
+ }
+ }
+
+ SettingsCard {
+ iconName: "space_bar"
+ title: I18n.tr("Spacing")
+ settingKey: "barSpacing"
+ visible: selectedBarConfig?.enabled
+
+ SettingsSliderRow {
+ id: edgeSpacingSlider
+ text: I18n.tr("Edge Spacing")
+ value: selectedBarConfig?.spacing ?? 4
+ minimum: 0
+ maximum: 32
+ defaultValue: 4
+ onSliderDragFinished: finalValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ spacing: finalValue
+ });
+ }
+
+ Binding {
+ target: edgeSpacingSlider
+ property: "value"
+ value: selectedBarConfig?.spacing ?? 4
+ restoreMode: Binding.RestoreBinding
+ }
+ }
+
+ SettingsSliderRow {
+ id: exclusiveZoneSlider
+ text: I18n.tr("Exclusive Zone Offset")
+ value: selectedBarConfig?.bottomGap ?? 0
+ minimum: -50
+ maximum: 50
+ defaultValue: 0
+ onSliderDragFinished: finalValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ bottomGap: finalValue
+ });
+ }
+
+ Binding {
+ target: exclusiveZoneSlider
+ property: "value"
+ value: selectedBarConfig?.bottomGap ?? 0
+ restoreMode: Binding.RestoreBinding
+ }
+ }
+
+ SettingsSliderRow {
+ id: sizeSlider
+ text: I18n.tr("Size")
+ value: selectedBarConfig?.innerPadding ?? 4
+ minimum: -8
+ maximum: 24
+ defaultValue: 4
+ onSliderDragFinished: finalValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ innerPadding: finalValue
+ });
+ }
+
+ Binding {
+ target: sizeSlider
+ property: "value"
+ value: selectedBarConfig?.innerPadding ?? 4
+ restoreMode: Binding.RestoreBinding
+ }
+ }
+
+ SettingsSliderRow {
+ id: widgetPaddingSlider
+ text: I18n.tr("Padding")
+ value: selectedBarConfig?.widgetPadding ?? 8
+ minimum: 0
+ maximum: 32
+ unit: "px"
+ defaultValue: 8
+ opacity: (selectedBarConfig?.removeWidgetPadding ?? false) ? 0.5 : 1.0
+ enabled: !(selectedBarConfig?.removeWidgetPadding ?? false)
+ onSliderValueChanged: newValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ widgetPadding: newValue
+ });
+ }
+
+ Binding {
+ target: widgetPaddingSlider
+ property: "value"
+ value: selectedBarConfig?.widgetPadding ?? 12
+ restoreMode: Binding.RestoreBinding
+ }
+ }
+
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: Theme.outline
+ opacity: 0.15
+ }
+
+ SettingsToggleRow {
+ text: I18n.tr("Auto Popup Gaps")
+ checked: selectedBarConfig?.popupGapsAuto ?? true
+ onToggled: checked => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ popupGapsAuto: checked
+ });
+ }
+ }
+
+ Column {
+ width: parent.width
+ leftPadding: Theme.spacingM
+ spacing: Theme.spacingM
+ visible: !(selectedBarConfig?.popupGapsAuto ?? true)
+
+ Rectangle {
+ width: parent.width - parent.leftPadding
+ height: 1
+ color: Theme.outline
+ opacity: 0.15
+ }
+
+ SettingsSliderRow {
+ id: popupGapsManualSlider
+ width: parent.width - parent.parent.leftPadding
+ text: I18n.tr("Manual Gap Size")
+ value: selectedBarConfig?.popupGapsManual ?? 4
+ minimum: 0
+ maximum: 50
+ defaultValue: 4
+ onSliderDragFinished: finalValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ popupGapsManual: finalValue
+ });
+ }
+
+ Binding {
+ target: popupGapsManualSlider
+ property: "value"
+ value: selectedBarConfig?.popupGapsManual ?? 4
+ restoreMode: Binding.RestoreBinding
+ }
+ }
+ }
+ }
+
+ 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 => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ fontScale: newValue / 100
+ });
+ }
+
+ Binding {
+ target: fontScaleSliderCard
+ property: "value"
+ value: Math.round((selectedBarConfig?.fontScale ?? 1.0) * 100)
+ restoreMode: Binding.RestoreBinding
+ }
+ }
+
+ SettingsSliderCard {
+ id: iconScaleSliderCard
+ iconName: "interests"
+ title: I18n.tr("Icon Scale")
+ description: I18n.tr("Scale DankBar icon sizes independently")
+ visible: selectedBarConfig?.enabled
+ minimum: 50
+ maximum: 200
+ value: Math.round((selectedBarConfig?.iconScale ?? 1.0) * 100)
+ unit: "%"
+ defaultValue: 100
+ onSliderValueChanged: newValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ iconScale: newValue / 100
+ });
+ }
+
+ Binding {
+ target: iconScaleSliderCard
+ property: "value"
+ value: Math.round((selectedBarConfig?.iconScale ?? 1.0) * 100)
+ restoreMode: Binding.RestoreBinding
+ }
+ }
+
+ SettingsCard {
+ iconName: "opacity"
+ title: I18n.tr("Transparency")
+ settingKey: "barTransparency"
+ visible: selectedBarConfig?.enabled
+
+ SettingsSliderRow {
+ id: barTransparencySlider
+ text: I18n.tr("Bar Transparency")
+ value: (selectedBarConfig?.transparency ?? 1.0) * 100
+ minimum: 0
+ maximum: 100
+ unit: "%"
+ defaultValue: 100
+ onSliderDragFinished: finalValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ transparency: finalValue / 100
+ });
+ }
+
+ Binding {
+ target: barTransparencySlider
+ property: "value"
+ value: (selectedBarConfig?.transparency ?? 1.0) * 100
+ restoreMode: Binding.RestoreBinding
+ }
+ }
+
+ SettingsSliderRow {
+ id: widgetTransparencySlider
+ text: I18n.tr("Widget Transparency")
+ value: (selectedBarConfig?.widgetTransparency ?? 1.0) * 100
+ minimum: 0
+ maximum: 100
+ unit: "%"
+ defaultValue: 100
+ onSliderDragFinished: finalValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ widgetTransparency: finalValue / 100
+ });
+ }
+
+ Binding {
+ target: widgetTransparencySlider
+ property: "value"
+ value: (selectedBarConfig?.widgetTransparency ?? 1.0) * 100
+ restoreMode: Binding.RestoreBinding
+ }
+ }
+ }
+
+ SettingsCard {
+ id: shadowCard
+ iconName: "layers"
+ title: I18n.tr("Shadow Override", "bar shadow settings card")
+ settingKey: "barShadow"
+ collapsible: true
+ expanded: true
+ visible: selectedBarConfig?.enabled
+
+ readonly property bool shadowActive: (selectedBarConfig?.shadowIntensity ?? 0) > 0
+ readonly property bool isCustomColor: (selectedBarConfig?.shadowColorMode ?? "default") === "custom"
+ readonly property string directionSource: selectedBarConfig?.shadowDirectionMode ?? "inherit"
+
+ StyledText {
+ width: parent.width
+ text: I18n.tr("Enable a custom override below to set per-bar shadow intensity, opacity, and color.")
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.surfaceVariantText
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignLeft
+ }
+
+ SettingsToggleRow {
+ text: I18n.tr("Custom Shadow Override")
+ description: I18n.tr("Override the global shadow with per-bar settings")
+ checked: shadowCard.shadowActive
+ onToggled: checked => {
+ if (checked) {
+ SettingsData.updateBarConfig(selectedBarId, {
+ shadowIntensity: 12,
+ shadowOpacity: 60
+ });
+ } else {
+ SettingsData.updateBarConfig(selectedBarId, {
+ shadowIntensity: 0
+ });
+ }
+ }
+ }
+
+ SettingsSliderRow {
+ visible: shadowCard.shadowActive
+ text: I18n.tr("Intensity", "shadow intensity slider")
+ minimum: 0
+ maximum: 100
+ unit: "px"
+ defaultValue: 12
+ value: selectedBarConfig?.shadowIntensity ?? 0
+ onSliderValueChanged: newValue => SettingsData.updateBarConfig(selectedBarId, {
+ shadowIntensity: newValue
+ })
+ }
+
+ SettingsSliderRow {
+ visible: shadowCard.shadowActive
+ text: I18n.tr("Opacity")
+ minimum: 10
+ maximum: 100
+ unit: "%"
+ defaultValue: 60
+ value: selectedBarConfig?.shadowOpacity ?? 60
+ onSliderValueChanged: newValue => SettingsData.updateBarConfig(selectedBarId, {
+ shadowOpacity: newValue
+ })
+ }
+
+ SettingsDropdownRow {
+ visible: shadowCard.shadowActive
+ text: I18n.tr("Direction Source", "bar shadow direction source")
+ description: I18n.tr("Choose how this bar resolves shadow direction")
+ settingKey: "barShadowDirectionSource"
+ options: [I18n.tr("Inherit Global (Default)", "bar shadow direction source option"), I18n.tr("Auto (Bar-aware)", "bar shadow direction source option"), I18n.tr("Manual", "bar shadow direction source option")]
+ currentValue: {
+ switch (shadowCard.directionSource) {
+ case "autoBar":
+ return I18n.tr("Auto (Bar-aware)", "bar shadow direction source option");
+ case "manual":
+ return I18n.tr("Manual", "bar shadow direction source option");
+ default:
+ return I18n.tr("Inherit Global (Default)", "bar shadow direction source option");
+ }
+ }
+ onValueChanged: value => {
+ if (value === I18n.tr("Auto (Bar-aware)", "bar shadow direction source option")) {
+ SettingsData.updateBarConfig(selectedBarId, {
+ shadowDirectionMode: "autoBar"
+ });
+ } else if (value === I18n.tr("Manual", "bar shadow direction source option")) {
+ SettingsData.updateBarConfig(selectedBarId, {
+ shadowDirectionMode: "manual"
+ });
+ } else {
+ SettingsData.updateBarConfig(selectedBarId, {
+ shadowDirectionMode: "inherit"
+ });
+ }
+ }
+ }
+
+ SettingsDropdownRow {
+ 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")
+ settingKey: "barShadowDirectionManual"
+ options: [I18n.tr("Top", "shadow direction option"), I18n.tr("Top Left", "shadow direction option"), I18n.tr("Top Right", "shadow direction option"), I18n.tr("Bottom", "shadow direction option")]
+ currentValue: {
+ switch (selectedBarConfig?.shadowDirection) {
+ case "topLeft":
+ return I18n.tr("Top Left", "shadow direction option");
+ case "topRight":
+ return I18n.tr("Top Right", "shadow direction option");
+ case "bottom":
+ return I18n.tr("Bottom", "shadow direction option");
+ default:
+ return I18n.tr("Top", "shadow direction option");
+ }
+ }
+ onValueChanged: value => {
+ if (value === I18n.tr("Top Left", "shadow direction option")) {
+ SettingsData.updateBarConfig(selectedBarId, {
+ shadowDirection: "topLeft"
+ });
+ } else if (value === I18n.tr("Top Right", "shadow direction option")) {
+ SettingsData.updateBarConfig(selectedBarId, {
+ shadowDirection: "topRight"
+ });
+ } else if (value === I18n.tr("Bottom", "shadow direction option")) {
+ SettingsData.updateBarConfig(selectedBarId, {
+ shadowDirection: "bottom"
+ });
+ } else {
+ SettingsData.updateBarConfig(selectedBarId, {
+ shadowDirection: "top"
+ });
+ }
+ }
+ }
+
+ Column {
+ visible: shadowCard.shadowActive
+ width: parent.width
+ spacing: Theme.spacingS
+
+ StyledText {
+ text: I18n.tr("Color")
+ font.pixelSize: Theme.fontSizeMedium
+ color: Theme.surfaceText
+ horizontalAlignment: Text.AlignLeft
+ anchors.left: parent.left
+ anchors.leftMargin: Theme.spacingM
+ }
+
+ Item {
+ width: parent.width
+ height: shadowColorGroup.implicitHeight
+
+ DankButtonGroup {
+ id: shadowColorGroup
+ anchors.horizontalCenter: parent.horizontalCenter
+ buttonPadding: parent.width < 420 ? Theme.spacingXS : Theme.spacingS
+ minButtonWidth: parent.width < 420 ? 36 : 56
+ textSize: parent.width < 420 ? Theme.fontSizeSmall : Theme.fontSizeMedium
+ model: [I18n.tr("Default (Black)"), I18n.tr("Surface", "shadow color option"), I18n.tr("Primary"), I18n.tr("Secondary"), I18n.tr("Custom")]
+ selectionMode: "single"
+ currentIndex: {
+ switch (selectedBarConfig?.shadowColorMode || "default") {
+ case "surface":
+ return 1;
+ case "primary":
+ return 2;
+ case "secondary":
+ return 3;
+ case "custom":
+ return 4;
+ default:
+ return 0;
+ }
+ }
+ onSelectionChanged: (index, selected) => {
+ if (!selected)
+ return;
+ let mode = "default";
+ switch (index) {
+ case 1:
+ mode = "surface";
+ break;
+ case 2:
+ mode = "primary";
+ break;
+ case 3:
+ mode = "secondary";
+ break;
+ case 4:
+ mode = "custom";
+ break;
+ }
+ SettingsData.updateBarConfig(selectedBarId, {
+ shadowColorMode: mode
+ });
+ }
+ }
+ }
+
+ Rectangle {
+ visible: selectedBarConfig?.shadowColorMode === "custom"
+ width: 32
+ height: 32
+ radius: 16
+ color: selectedBarConfig?.shadowCustomColor ?? "#000000"
+ border.color: Theme.outline
+ border.width: 1
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ MouseArea {
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ PopoutService.colorPickerModal.selectedColor = selectedBarConfig?.shadowCustomColor ?? "#000000";
+ PopoutService.colorPickerModal.pickerTitle = I18n.tr("Color");
+ PopoutService.colorPickerModal.onColorSelectedCallback = function (color) {
+ SettingsData.updateBarConfig(selectedBarId, {
+ shadowCustomColor: color.toString()
+ });
+ };
+ PopoutService.colorPickerModal.show();
+ }
+ }
+ }
+ }
+ }
+
+ SettingsCard {
+ iconName: "rounded_corner"
+ title: I18n.tr("Corners & Background")
+ settingKey: "barCorners"
+ collapsible: true
+ expanded: false
+ visible: selectedBarConfig?.enabled
+
+ SettingsToggleRow {
+ text: I18n.tr("Square Corners")
+ checked: selectedBarConfig?.squareCorners ?? false
+ onToggled: checked => SettingsData.updateBarConfig(selectedBarId, {
+ squareCorners: checked
+ })
+ }
+
+ SettingsToggleRow {
+ text: I18n.tr("No Background")
+ checked: selectedBarConfig?.noBackground ?? false
+ onToggled: checked => SettingsData.updateBarConfig(selectedBarId, {
+ noBackground: checked
+ })
+ }
+
+ SettingsToggleRow {
+ text: I18n.tr("Maximize Widget Icons")
+ checked: selectedBarConfig?.maximizeWidgetIcons ?? false
+ onToggled: checked => SettingsData.updateBarConfig(selectedBarId, {
+ maximizeWidgetIcons: checked
+ })
+ }
+
+ SettingsToggleRow {
+ text: I18n.tr("Maximize Widget Text")
+ checked: selectedBarConfig?.maximizeWidgetText ?? false
+ onToggled: checked => SettingsData.updateBarConfig(selectedBarId, {
+ maximizeWidgetText: checked
+ })
+ }
+
+ SettingsToggleRow {
+ text: I18n.tr("Remove Widget Padding")
+ checked: selectedBarConfig?.removeWidgetPadding ?? false
+ onToggled: checked => SettingsData.updateBarConfig(selectedBarId, {
+ removeWidgetPadding: checked
+ })
+ }
+
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: Theme.outline
+ opacity: 0.15
+ }
+
+ SettingsToggleRow {
+ text: I18n.tr("Goth Corners")
+ checked: selectedBarConfig?.gothCornersEnabled ?? false
+ onToggled: checked => SettingsData.updateBarConfig(selectedBarId, {
+ gothCornersEnabled: checked
+ })
+ }
+
+ SettingsToggleRow {
+ text: I18n.tr("Corner Radius Override")
+ checked: selectedBarConfig?.gothCornerRadiusOverride ?? false
+ visible: selectedBarConfig?.gothCornersEnabled ?? false
+ onToggled: checked => SettingsData.updateBarConfig(selectedBarId, {
+ gothCornerRadiusOverride: checked
+ })
+ }
+
+ Column {
+ width: parent.width
+ spacing: Theme.spacingS
+ visible: (selectedBarConfig?.gothCornersEnabled ?? false) && (selectedBarConfig?.gothCornerRadiusOverride ?? false)
+ leftPadding: Theme.spacingM
+
+ SettingsSliderRow {
+ id: gothCornerRadiusSlider
+ width: parent.width - parent.leftPadding
+ text: I18n.tr("Goth Corner Radius")
+ value: selectedBarConfig?.gothCornerRadiusValue ?? 12
+ minimum: 0
+ maximum: 64
+ defaultValue: 12
+ onSliderDragFinished: finalValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ gothCornerRadiusValue: finalValue
+ });
+ }
+
+ Binding {
+ target: gothCornerRadiusSlider
+ property: "value"
+ value: selectedBarConfig?.gothCornerRadiusValue ?? 12
+ restoreMode: Binding.RestoreBinding
+ }
+ }
+ }
+ }
+
+ SettingsToggleCard {
+ iconName: "border_style"
+ title: I18n.tr("Border")
+ visible: selectedBarConfig?.enabled
+ 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
+ });
+ }
+ }
+
+ SettingsSliderRow {
+ id: borderOpacitySlider
+ text: I18n.tr("Opacity")
+ value: (selectedBarConfig?.borderOpacity ?? 1.0) * 100
+ minimum: 0
+ maximum: 100
+ unit: "%"
+ defaultValue: 100
+ onSliderDragFinished: finalValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ borderOpacity: finalValue / 100
+ });
+ }
+
+ 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
+ onSliderDragFinished: finalValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ borderThickness: finalValue
+ });
+ }
+
+ Binding {
+ target: borderThicknessSlider
+ property: "value"
+ value: selectedBarConfig?.borderThickness ?? 1
+ restoreMode: Binding.RestoreBinding
+ }
+ }
+ }
+
+ SettingsToggleCard {
+ iconName: "highlight"
+ title: I18n.tr("Widget Outline")
+ visible: selectedBarConfig?.enabled
+ 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
+ });
+ }
+ }
+
+ SettingsSliderRow {
+ id: widgetOutlineOpacitySlider
+ text: I18n.tr("Opacity")
+ value: (selectedBarConfig?.widgetOutlineOpacity ?? 1.0) * 100
+ minimum: 0
+ maximum: 100
+ unit: "%"
+ defaultValue: 100
+ onSliderDragFinished: finalValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ widgetOutlineOpacity: finalValue / 100
+ });
+ }
+
+ 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
+ onSliderDragFinished: finalValue => {
+ SettingsData.updateBarConfig(selectedBarId, {
+ widgetOutlineThickness: finalValue
+ });
+ }
+
+ Binding {
+ target: widgetOutlineThicknessSlider
+ property: "value"
+ value: selectedBarConfig?.widgetOutlineThickness ?? 1
+ restoreMode: Binding.RestoreBinding
+ }
+ }
+ }
+ }
+ }
+}