From 0208f1e8402f6d0eb48bba6ba8fafa17855c51a5 Mon Sep 17 00:00:00 2001 From: bbedward Date: Thu, 24 Jul 2025 16:29:31 -0400 Subject: [PATCH] dankslider: tooltip with value --- Modules/ControlCenter/ControlCenterPopout.qml | 49 +++ Modules/Settings/AppearanceTab.qml | 4 +- Modules/Settings/WidgetsTab.qml | 4 +- Widgets/DankSlider.qml | 310 +++++++++--------- 4 files changed, 210 insertions(+), 157 deletions(-) diff --git a/Modules/ControlCenter/ControlCenterPopout.qml b/Modules/ControlCenter/ControlCenterPopout.qml index ca883a07..c02c0939 100644 --- a/Modules/ControlCenter/ControlCenterPopout.qml +++ b/Modules/ControlCenter/ControlCenterPopout.qml @@ -671,6 +671,55 @@ PanelWindow { visible: root.currentTab === "display" spacing: Theme.spacingL + property var brightnessDebounceTimer: Timer { + interval: BrightnessService.ddcAvailable ? 500 : 50 + repeat: false + property int pendingValue: 0 + onTriggered: { + BrightnessService.setBrightness(pendingValue); + } + } + + // Brightness Control + Column { + width: parent.width + spacing: Theme.spacingS + visible: BrightnessService.brightnessAvailable + + StyledText { + text: "Brightness" + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + font.weight: Font.Medium + } + + DankSlider { + width: parent.width + height: 24 + value: BrightnessService.brightnessLevel + leftIcon: "brightness_low" + rightIcon: "brightness_high" + enabled: BrightnessService.brightnessAvailable + showValue: true + onSliderValueChanged: function(newValue) { + parent.parent.brightnessDebounceTimer.pendingValue = newValue; + parent.parent.brightnessDebounceTimer.restart(); + } + onSliderDragFinished: function(finalValue) { + parent.parent.brightnessDebounceTimer.stop(); + BrightnessService.setBrightness(finalValue); + } + } + + StyledText { + text: "ddc changes can be slow to respond" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceVariantText + visible: BrightnessService.ddcAvailable && !BrightnessService.laptopBacklightAvailable + anchors.horizontalCenter: parent.horizontalCenter + } + } + DankToggle { width: parent.width text: "Night Mode" diff --git a/Modules/Settings/AppearanceTab.qml b/Modules/Settings/AppearanceTab.qml index 14415a08..69f78e55 100644 --- a/Modules/Settings/AppearanceTab.qml +++ b/Modules/Settings/AppearanceTab.qml @@ -145,7 +145,7 @@ ScrollView { minimum: 0 maximum: 100 unit: "" - showValue: false + showValue: true onSliderValueChanged: (newValue) => { Prefs.setTopBarTransparency(newValue / 100); } @@ -170,7 +170,7 @@ ScrollView { minimum: 0 maximum: 100 unit: "" - showValue: false + showValue: true onSliderValueChanged: (newValue) => { Prefs.setPopupTransparency(newValue / 100); } diff --git a/Modules/Settings/WidgetsTab.qml b/Modules/Settings/WidgetsTab.qml index 45d7f5d4..df16aca0 100644 --- a/Modules/Settings/WidgetsTab.qml +++ b/Modules/Settings/WidgetsTab.qml @@ -288,7 +288,7 @@ ScrollView { maximum: 100 value: Math.round(Prefs.osLogoBrightness * 100) unit: "" - showValue: false + showValue: true onSliderValueChanged: (newValue) => { Prefs.setOSLogoBrightness(newValue / 100); } @@ -313,7 +313,7 @@ ScrollView { maximum: 200 value: Math.round(Prefs.osLogoContrast * 100) unit: "" - showValue: false + showValue: true onSliderValueChanged: (newValue) => { Prefs.setOSLogoContrast(newValue / 100); } diff --git a/Widgets/DankSlider.qml b/Widgets/DankSlider.qml index aeb79991..62f008d1 100644 --- a/Widgets/DankSlider.qml +++ b/Widgets/DankSlider.qml @@ -18,195 +18,199 @@ Item { signal sliderValueChanged(int newValue) signal sliderDragFinished(int finalValue) - height: 80 + height: 40 - Column { - anchors.fill: parent + Row { + anchors.centerIn: parent + width: parent.width spacing: Theme.spacingM - // Value display - StyledText { - text: slider.value + slider.unit - font.pixelSize: Theme.fontSizeMedium + DankIcon { + name: slider.leftIcon + size: Theme.iconSize color: slider.enabled ? Theme.surfaceText : Theme.surfaceVariantText - font.weight: Font.Medium - visible: slider.showValue - anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + visible: slider.leftIcon.length > 0 } - // Slider row - Row { - width: parent.width - spacing: Theme.spacingM + StyledRect { + id: sliderTrack - // Left icon - DankIcon { - name: slider.leftIcon - size: Theme.iconSize - color: slider.enabled ? Theme.surfaceText : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - visible: slider.leftIcon.length > 0 + property int leftIconWidth: slider.leftIcon.length > 0 ? Theme.iconSize : 0 + property int rightIconWidth: slider.rightIcon.length > 0 ? Theme.iconSize : 0 + + width: parent.width - (leftIconWidth + rightIconWidth + (slider.leftIcon.length > 0 ? Theme.spacingM : 0) + (slider.rightIcon.length > 0 ? Theme.spacingM : 0)) + height: 6 + radius: 3 + color: slider.enabled ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.1) + anchors.verticalCenter: parent.verticalCenter + + StyledRect { + id: sliderFill + + width: parent.width * ((slider.value - slider.minimum) / (slider.maximum - slider.minimum)) + height: parent.height + radius: parent.radius + color: slider.enabled ? Theme.primary : Theme.surfaceVariantText + + Behavior on width { + NumberAnimation { + duration: Theme.shortDuration + easing.type: Theme.standardEasing + } + } } - // Slider track StyledRect { - id: sliderTrack + id: sliderHandle - property int leftIconWidth: slider.leftIcon.length > 0 ? Theme.iconSize : 0 - property int rightIconWidth: slider.rightIcon.length > 0 ? Theme.iconSize : 0 - - width: parent.width - (leftIconWidth + rightIconWidth + (slider.leftIcon.length > 0 ? Theme.spacingM : 0) + (slider.rightIcon.length > 0 ? Theme.spacingM : 0)) - height: 6 - radius: 3 - color: slider.enabled ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.1) + width: 18 + height: 18 + radius: 9 + color: slider.enabled ? Theme.primary : Theme.surfaceVariantText + border.color: slider.enabled ? Qt.lighter(Theme.primary, 1.3) : Qt.lighter(Theme.surfaceVariantText, 1.3) + border.width: 2 + x: Math.max(0, Math.min(parent.width - width, sliderFill.width - width / 2)) anchors.verticalCenter: parent.verticalCenter + scale: sliderMouseArea.containsMouse || sliderMouseArea.pressed ? 1.2 : 1 - // Fill StyledRect { - id: sliderFill - - width: parent.width * ((slider.value - slider.minimum) / (slider.maximum - slider.minimum)) - height: parent.height - radius: parent.radius - color: slider.enabled ? Theme.primary : Theme.surfaceVariantText - - Behavior on width { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - - } - - } - - // Draggable handle - StyledRect { - id: sliderHandle - - width: 18 - height: 18 - radius: 9 - color: slider.enabled ? Theme.primary : Theme.surfaceVariantText - border.color: slider.enabled ? Qt.lighter(Theme.primary, 1.3) : Qt.lighter(Theme.surfaceVariantText, 1.3) + anchors.centerIn: parent + width: parent.width + 4 + height: parent.height + 4 + radius: width / 2 + color: "transparent" + border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) border.width: 2 - x: Math.max(0, Math.min(parent.width - width, sliderFill.width - width / 2)) - anchors.verticalCenter: parent.verticalCenter - scale: sliderMouseArea.containsMouse || sliderMouseArea.pressed ? 1.2 : 1 + visible: sliderMouseArea.containsMouse && slider.enabled + } - // Handle glow effect when active - StyledRect { - anchors.centerIn: parent - width: parent.width + 4 - height: parent.height + 4 - radius: width / 2 - color: "transparent" - border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) - border.width: 2 - visible: sliderMouseArea.containsMouse && slider.enabled + Behavior on scale { + NumberAnimation { + duration: Theme.shortDuration + easing.type: Theme.standardEasing } - - Behavior on scale { + } + + StyledRect { + id: valueTooltip + width: tooltipText.contentWidth + Theme.spacingS * 2 + height: tooltipText.contentHeight + Theme.spacingXS * 2 + radius: Theme.cornerRadiusSmall + color: Theme.surfaceContainer + border.color: Theme.outline + border.width: 1 + anchors.bottom: parent.top + anchors.bottomMargin: Theme.spacingS + anchors.horizontalCenter: parent.horizontalCenter + visible: (sliderMouseArea.containsMouse && slider.showValue) || (slider.isDragging && slider.showValue) + opacity: visible ? 1 : 0 + + Text { + id: tooltipText + text: slider.value + slider.unit + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceText + font.weight: Font.Medium + anchors.centerIn: parent + font.hintingPreference: Font.PreferFullHinting + } + + Behavior on opacity { NumberAnimation { duration: Theme.shortDuration easing.type: Theme.standardEasing } - } - } + } - Item { - id: sliderContainer + Item { + id: sliderContainer + + anchors.fill: parent + + MouseArea { + id: sliderMouseArea + + property bool isDragging: false anchors.fill: parent - - MouseArea { - id: sliderMouseArea - - property bool isDragging: false - - anchors.fill: parent - hoverEnabled: true - cursorShape: slider.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: slider.enabled - preventStealing: true - onPressed: (mouse) => { - if (slider.enabled) { - slider.isDragging = true; - sliderMouseArea.isDragging = true; - let ratio = Math.max(0, Math.min(1, mouse.x / width)); - let newValue = Math.round(slider.minimum + ratio * (slider.maximum - slider.minimum)); - slider.value = newValue; - slider.sliderValueChanged(newValue); - } - } - onReleased: { - if (slider.enabled) { - slider.isDragging = false; - sliderMouseArea.isDragging = false; - slider.sliderDragFinished(slider.value); - } - } - onPositionChanged: (mouse) => { - if (pressed && slider.isDragging && slider.enabled) { - let ratio = Math.max(0, Math.min(1, mouse.x / width)); - let newValue = Math.round(slider.minimum + ratio * (slider.maximum - slider.minimum)); - slider.value = newValue; - slider.sliderValueChanged(newValue); - } - } - onClicked: (mouse) => { - if (slider.enabled && !slider.isDragging) { - let ratio = Math.max(0, Math.min(1, mouse.x / width)); - let newValue = Math.round(slider.minimum + ratio * (slider.maximum - slider.minimum)); - slider.value = newValue; - slider.sliderValueChanged(newValue); - } + anchors.topMargin: -10 + anchors.bottomMargin: -10 + hoverEnabled: true + cursorShape: slider.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor + enabled: slider.enabled + preventStealing: true + onPressed: (mouse) => { + if (slider.enabled) { + slider.isDragging = true; + sliderMouseArea.isDragging = true; + let ratio = Math.max(0, Math.min(1, mouse.x / width)); + let newValue = Math.round(slider.minimum + ratio * (slider.maximum - slider.minimum)); + slider.value = newValue; + slider.sliderValueChanged(newValue); } } - - // Global mouse area for drag tracking - MouseArea { - id: sliderGlobalMouseArea - - anchors.fill: sliderContainer - enabled: slider.isDragging - visible: false - preventStealing: true - onPositionChanged: (mouse) => { - if (slider.isDragging && slider.enabled) { - let globalPos = mapToItem(sliderTrack, mouse.x, mouse.y); - let ratio = Math.max(0, Math.min(1, globalPos.x / sliderTrack.width)); - let newValue = Math.round(slider.minimum + ratio * (slider.maximum - slider.minimum)); - slider.value = newValue; - slider.sliderValueChanged(newValue); - } - } - onReleased: { - if (slider.isDragging && slider.enabled) { - slider.isDragging = false; - sliderMouseArea.isDragging = false; - slider.sliderDragFinished(slider.value); - } + onReleased: { + if (slider.enabled) { + slider.isDragging = false; + sliderMouseArea.isDragging = false; + slider.sliderDragFinished(slider.value); + } + } + onPositionChanged: (mouse) => { + if (pressed && slider.isDragging && slider.enabled) { + let ratio = Math.max(0, Math.min(1, mouse.x / width)); + let newValue = Math.round(slider.minimum + ratio * (slider.maximum - slider.minimum)); + slider.value = newValue; + slider.sliderValueChanged(newValue); + } + } + onClicked: (mouse) => { + if (slider.enabled && !slider.isDragging) { + let ratio = Math.max(0, Math.min(1, mouse.x / width)); + let newValue = Math.round(slider.minimum + ratio * (slider.maximum - slider.minimum)); + slider.value = newValue; + slider.sliderValueChanged(newValue); } } - } - } + MouseArea { + id: sliderGlobalMouseArea - // Right icon - DankIcon { - name: slider.rightIcon - size: Theme.iconSize - color: slider.enabled ? Theme.surfaceText : Theme.surfaceVariantText - anchors.verticalCenter: parent.verticalCenter - visible: slider.rightIcon.length > 0 + anchors.fill: sliderContainer + enabled: slider.isDragging + visible: false + preventStealing: true + onPositionChanged: (mouse) => { + if (slider.isDragging && slider.enabled) { + let globalPos = mapToItem(sliderTrack, mouse.x, mouse.y); + let ratio = Math.max(0, Math.min(1, globalPos.x / sliderTrack.width)); + let newValue = Math.round(slider.minimum + ratio * (slider.maximum - slider.minimum)); + slider.value = newValue; + slider.sliderValueChanged(newValue); + } + } + onReleased: { + if (slider.isDragging && slider.enabled) { + slider.isDragging = false; + sliderMouseArea.isDragging = false; + slider.sliderDragFinished(slider.value); + } + } + } } - } + DankIcon { + name: slider.rightIcon + size: Theme.iconSize + color: slider.enabled ? Theme.surfaceText : Theme.surfaceVariantText + anchors.verticalCenter: parent.verticalCenter + visible: slider.rightIcon.length > 0 + } } }