From d48eb9099b65bc1afa98fd1bfa2b6a571d94efbe Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Fri, 8 Aug 2025 14:23:04 +0200 Subject: [PATCH] Add ThemedSlider, change all Slider to ThemedSlider, add scaling to Display.qml, fix scaling for ToggleOption --- Components/ThemedSlider.qml | 45 +++++++++ Components/ToggleOption.qml | 2 + Settings/Settings.qml | 1 + Settings/Theme.qml | 11 ++- Widgets/SettingsWindow/Tabs/Display.qml | 33 +++++++ Widgets/SettingsWindow/Tabs/Wallpaper.qml | 108 ++-------------------- 6 files changed, 97 insertions(+), 103 deletions(-) create mode 100644 Components/ThemedSlider.qml diff --git a/Components/ThemedSlider.qml b/Components/ThemedSlider.qml new file mode 100644 index 0000000..1e737d6 --- /dev/null +++ b/Components/ThemedSlider.qml @@ -0,0 +1,45 @@ +import QtQuick +import QtQuick.Controls +import qs.Settings + +// Reusable themed slider styled like the sliders in Wallpaper.qml +Slider { + id: slider + + // Optional monitor screen for scaling context + property var screen + // Convenience flag mirroring Wallpaper sliders + property bool snapAlways: true + + snapMode: snapAlways ? Slider.SnapAlways : Slider.SnapOnRelease + + background: Rectangle { + x: slider.leftPadding + y: slider.topPadding + slider.availableHeight / 2 - height / 2 + implicitWidth: 200 + implicitHeight: 4 * Theme.scale(screen) + width: slider.availableWidth + height: implicitHeight + radius: height / 2 + color: Theme.surfaceVariant + + Rectangle { + width: slider.visualPosition * parent.width + height: parent.height + color: Theme.accentPrimary + radius: parent.radius + } + } + + handle: Rectangle { + x: slider.leftPadding + slider.visualPosition * (slider.availableWidth - width) + y: slider.topPadding + slider.availableHeight / 2 - height / 2 + implicitWidth: 20 * Theme.scale(screen) + implicitHeight: 20 * Theme.scale(screen) + radius: width / 2 + color: slider.pressed ? Theme.surfaceVariant : Theme.surface + border.color: Theme.accentPrimary + border.width: 2 * Theme.scale(screen) + } +} + diff --git a/Components/ToggleOption.qml b/Components/ToggleOption.qml index bf2f881..018607d 100644 --- a/Components/ToggleOption.qml +++ b/Components/ToggleOption.qml @@ -7,6 +7,8 @@ import qs.Settings ColumnLayout { id: root + property var screen + property string label: "" property string description: "" property bool value: false diff --git a/Settings/Settings.qml b/Settings/Settings.qml index 0d066bf..66db3a0 100644 --- a/Settings/Settings.qml +++ b/Settings/Settings.qml @@ -82,6 +82,7 @@ Singleton { property var barMonitors: [] // Array of monitor names to show the bar on property var dockMonitors: [] // Array of monitor names to show the dock on property var notificationMonitors: [] // Array of monitor names to show notifications on, "*" means all monitors + property var monitorScaleOverrides: {} // Map of monitor name -> scale override (e.g., 0.8..2.0). When set, Theme.scale() returns this value } } diff --git a/Settings/Theme.qml b/Settings/Theme.qml index 746ee38..e970327 100644 --- a/Settings/Theme.qml +++ b/Settings/Theme.qml @@ -13,7 +13,16 @@ Singleton { // Automatic scaling based on screen width function scale(currentScreen) { - if (currentScreen.width != 0) { + // Per-monitor override from settings + try { + const overrides = Settings.settings.monitorScaleOverrides || {}; + if (currentScreen && currentScreen.name && overrides[currentScreen.name] !== undefined) { + return overrides[currentScreen.name]; + } + } catch (e) { + // ignore + } + if (currentScreen && currentScreen.width != 0) { var ratio = currentScreen.width / designScreenWidth; // Limit the final scale range between [0.8...2] return Math.max(0.8, Math.min(2.0, ratio)); diff --git a/Widgets/SettingsWindow/Tabs/Display.qml b/Widgets/SettingsWindow/Tabs/Display.qml index 0cf946b..93cb9c5 100644 --- a/Widgets/SettingsWindow/Tabs/Display.qml +++ b/Widgets/SettingsWindow/Tabs/Display.qml @@ -4,6 +4,7 @@ import QtQuick.Layouts import Quickshell import qs.Components import qs.Settings +import qs.Components ColumnLayout { id: root @@ -417,6 +418,38 @@ ColumnLayout { Settings.settings.notificationMonitors = monitors; } } + + // Scale slider + ColumnLayout { + Layout.fillWidth: true + spacing: 4 * Theme.scale(screen) + Text { text: "Scale"; color: Theme.textSecondary; font.pixelSize: 10 * Theme.scale(screen) } + RowLayout { + Layout.fillWidth: true + spacing: 8 * Theme.scale(screen) + // Value read from settings override, default to Theme.scale(modelData) + property real currentValue: (Settings.settings.monitorScaleOverrides && Settings.settings.monitorScaleOverrides[monitorCard.monitorName] !== undefined) ? Settings.settings.monitorScaleOverrides[monitorCard.monitorName] : Theme.scale(modelData) + // Reusable slider component (exact style from Wallpaper.qml) + ThemedSlider { + id: scaleSlider + Layout.fillWidth: true + screen: modelData + from: 0.8 + to: 2.0 + stepSize: 0.05 + snapAlways: true + value: parent.currentValue + onValueChanged: { + let overrides = Settings.settings.monitorScaleOverrides || {}; + overrides = Object.assign({}, overrides); + overrides[monitorCard.monitorName] = value; + Settings.settings.monitorScaleOverrides = overrides; + parent.currentValue = value; + } + } + Text { text: parent.currentValue.toFixed(2); font.pixelSize: 12 * Theme.scale(screen); color: Theme.textPrimary; width: 36 } + } + } } } } diff --git a/Widgets/SettingsWindow/Tabs/Wallpaper.qml b/Widgets/SettingsWindow/Tabs/Wallpaper.qml index 583f1d1..c08331b 100644 --- a/Widgets/SettingsWindow/Tabs/Wallpaper.qml +++ b/Widgets/SettingsWindow/Tabs/Wallpaper.qml @@ -197,49 +197,17 @@ ColumnLayout { } - Slider { + ThemedSlider { id: intervalSlider - Layout.fillWidth: true from: 10 to: 900 stepSize: 10 value: Settings.settings.wallpaperInterval - snapMode: Slider.SnapAlways + snapAlways: true onMoved: { Settings.settings.wallpaperInterval = Math.round(value); } - - background: Rectangle { - x: intervalSlider.leftPadding - y: intervalSlider.topPadding + intervalSlider.availableHeight / 2 - height / 2 - implicitWidth: 200 - implicitHeight: 4 - width: intervalSlider.availableWidth - height: implicitHeight - radius: 2 - color: Theme.surfaceVariant - - Rectangle { - width: intervalSlider.visualPosition * parent.width - height: parent.height - color: Theme.accentPrimary - radius: 2 - } - - } - - handle: Rectangle { - x: intervalSlider.leftPadding + intervalSlider.visualPosition * (intervalSlider.availableWidth - width) - y: intervalSlider.topPadding + intervalSlider.availableHeight / 2 - height / 2 - implicitWidth: 20 - implicitHeight: 20 - radius: 10 - color: intervalSlider.pressed ? Theme.surfaceVariant : Theme.surface - border.color: Theme.accentPrimary - border.width: 2 - } - } } @@ -529,49 +497,17 @@ ColumnLayout { } - Slider { + ThemedSlider { id: fpsSlider - Layout.fillWidth: true from: 30 to: 500 stepSize: 5 value: Settings.settings.transitionFps - snapMode: Slider.SnapAlways + snapAlways: true onMoved: { Settings.settings.transitionFps = Math.round(value); } - - background: Rectangle { - x: fpsSlider.leftPadding - y: fpsSlider.topPadding + fpsSlider.availableHeight / 2 - height / 2 - implicitWidth: 200 - implicitHeight: 4 - width: fpsSlider.availableWidth - height: implicitHeight - radius: 2 - color: Theme.surfaceVariant - - Rectangle { - width: fpsSlider.visualPosition * parent.width - height: parent.height - color: Theme.accentPrimary - radius: 2 - } - - } - - handle: Rectangle { - x: fpsSlider.leftPadding + fpsSlider.visualPosition * (fpsSlider.availableWidth - width) - y: fpsSlider.topPadding + fpsSlider.availableHeight / 2 - height / 2 - implicitWidth: 20 - implicitHeight: 20 - radius: 10 - color: fpsSlider.pressed ? Theme.surfaceVariant : Theme.surface - border.color: Theme.accentPrimary - border.width: 2 - } - } } @@ -612,49 +548,17 @@ ColumnLayout { } - Slider { + ThemedSlider { id: durationSlider - Layout.fillWidth: true from: 0.25 to: 10 stepSize: 0.05 value: Settings.settings.transitionDuration - snapMode: Slider.SnapAlways + snapAlways: true onMoved: { Settings.settings.transitionDuration = value; } - - background: Rectangle { - x: durationSlider.leftPadding - y: durationSlider.topPadding + durationSlider.availableHeight / 2 - height / 2 - implicitWidth: 200 - implicitHeight: 4 - width: durationSlider.availableWidth - height: implicitHeight - radius: 2 - color: Theme.surfaceVariant - - Rectangle { - width: durationSlider.visualPosition * parent.width - height: parent.height - color: Theme.accentPrimary - radius: 2 - } - - } - - handle: Rectangle { - x: durationSlider.leftPadding + durationSlider.visualPosition * (durationSlider.availableWidth - width) - y: durationSlider.topPadding + durationSlider.availableHeight / 2 - height / 2 - implicitWidth: 20 - implicitHeight: 20 - radius: 10 - color: durationSlider.pressed ? Theme.surfaceVariant : Theme.surface - border.color: Theme.accentPrimary - border.width: 2 - } - } }