From 9ada66a78ea58d8b498f1dd26bf0783e1a442c51 Mon Sep 17 00:00:00 2001 From: Laurens Duin <85798751+Laurens256@users.noreply.github.com> Date: Tue, 5 Aug 2025 08:04:53 +0200 Subject: bar/popouts: add audio device switcher (#319) * feat: basic audio switcher * feat: replace VerticalSlider with StyledSlider * fix: styling * fix: formatting * chore: make sound icons consistent, change slider styling * feat: styled slider component variants * chore: cleanup * chore: cleanup * fix: pr fixes * fix: remove redundant code * chore: remove old code * fix: controls styling * fixes * more tweaks * radiobtn: add interaction stuff Anim slider --------- Co-authored-by: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> --- components/controls/FilledSlider.qml | 137 ++++++++++++++++++++++++++++++ components/controls/StyledRadioButton.qml | 58 +++++++++++++ components/controls/StyledSlider.qml | 59 +++++++++++++ components/controls/VerticalSlider.qml | 137 ------------------------------ 4 files changed, 254 insertions(+), 137 deletions(-) create mode 100644 components/controls/FilledSlider.qml create mode 100644 components/controls/StyledRadioButton.qml create mode 100644 components/controls/StyledSlider.qml delete mode 100644 components/controls/VerticalSlider.qml (limited to 'components') diff --git a/components/controls/FilledSlider.qml b/components/controls/FilledSlider.qml new file mode 100644 index 0000000..8d0e547 --- /dev/null +++ b/components/controls/FilledSlider.qml @@ -0,0 +1,137 @@ +import ".." +import "../effects" +import qs.services +import qs.config +import QtQuick +import QtQuick.Controls + +Slider { + id: root + + required property string icon + property real oldValue + + orientation: Qt.Vertical + + background: StyledRect { + color: Colours.alpha(Colours.palette.m3surfaceContainer, true) + radius: Appearance.rounding.full + + StyledRect { + anchors.left: parent.left + anchors.right: parent.right + + y: root.handle.y + implicitHeight: parent.height - y + + color: Colours.alpha(Colours.palette.m3secondary, true) + radius: parent.radius + } + } + + handle: Item { + id: handle + + property bool moving + + y: root.visualPosition * (root.availableHeight - height) + implicitWidth: root.width + implicitHeight: root.width + + Elevation { + anchors.fill: parent + radius: rect.radius + level: handleInteraction.containsMouse ? 2 : 1 + } + + StyledRect { + id: rect + + anchors.fill: parent + + color: Colours.alpha(Colours.palette.m3inverseSurface, true) + radius: Appearance.rounding.full + + MouseArea { + id: handleInteraction + + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + acceptedButtons: Qt.NoButton + } + + MaterialIcon { + id: icon + + property bool moving: handle.moving + + function update(): void { + animate = !moving; + text = moving ? Qt.binding(() => Math.round(root.value * 100)) : Qt.binding(() => root.icon); + font.pointSize = moving ? Appearance.font.size.small : Appearance.font.size.larger; + font.family = moving ? Appearance.font.family.sans : Appearance.font.family.material; + } + + animate: true + text: root.icon + color: Colours.palette.m3inverseOnSurface + anchors.centerIn: parent + + Behavior on moving { + SequentialAnimation { + NumberAnimation { + target: icon + property: "scale" + from: 1 + to: 0 + duration: Appearance.anim.durations.normal / 2 + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + ScriptAction { + script: icon.update() + } + NumberAnimation { + target: icon + property: "scale" + from: 0 + to: 1 + duration: Appearance.anim.durations.normal / 2 + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + } + } + } + } + + onPressedChanged: handle.moving = pressed + + onValueChanged: { + if (Math.abs(value - oldValue) < 0.01) + return; + oldValue = value; + handle.moving = true; + stateChangeDelay.restart(); + } + + Timer { + id: stateChangeDelay + + interval: 500 + onTriggered: { + if (!root.pressed) + handle.moving = false; + } + } + + Behavior on value { + NumberAnimation { + duration: Appearance.anim.durations.large + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } +} diff --git a/components/controls/StyledRadioButton.qml b/components/controls/StyledRadioButton.qml new file mode 100644 index 0000000..73fc836 --- /dev/null +++ b/components/controls/StyledRadioButton.qml @@ -0,0 +1,58 @@ +import qs.components +import qs.services +import qs.config +import QtQuick +import QtQuick.Controls + +RadioButton { + id: root + + font.pointSize: Appearance.font.size.smaller + + indicator: Rectangle { + id: outerCircle + + implicitWidth: 20 + implicitHeight: 20 + radius: Appearance.rounding.full + color: "transparent" + border.color: root.checked ? Colours.palette.m3primary : Colours.palette.m3onSurfaceVariant + border.width: 2 + anchors.verticalCenter: parent.verticalCenter + + StateLayer { + anchors.margins: -Appearance.padding.smaller + color: root.checked ? Colours.palette.m3onSurface : Colours.palette.m3primary + z: -1 + + function onClicked(): void { + root.click(); + } + } + + StyledRect { + anchors.centerIn: parent + implicitWidth: 8 + implicitHeight: 8 + + radius: Appearance.rounding.full + color: root.checked ? Colours.palette.m3primary : "transparent" + } + + Behavior on border.color { + ColorAnimation { + duration: Appearance.anim.durations.normal + easing.type: Easing.BezierSpline + easing.bezierCurve: Appearance.anim.curves.standard + } + } + } + + contentItem: StyledText { + text: root.text + font.pointSize: root.font.pointSize + anchors.verticalCenter: parent.verticalCenter + anchors.left: outerCircle.right + anchors.leftMargin: Appearance.spacing.smaller + } +} diff --git a/components/controls/StyledSlider.qml b/components/controls/StyledSlider.qml new file mode 100644 index 0000000..0352cef --- /dev/null +++ b/components/controls/StyledSlider.qml @@ -0,0 +1,59 @@ +import qs.components +import qs.config +import qs.services +import QtQuick.Controls +import QtQuick + +Slider { + id: slider + + background: Item { + StyledRect { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.topMargin: slider.implicitHeight / 3 + anchors.bottomMargin: slider.implicitHeight / 3 + + implicitWidth: slider.handle.x - slider.implicitHeight / 6 + + color: Colours.palette.m3primary + radius: Appearance.rounding.full + topRightRadius: slider.implicitHeight / 15 + bottomRightRadius: slider.implicitHeight / 15 + } + + StyledRect { + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.topMargin: slider.implicitHeight / 3 + anchors.bottomMargin: slider.implicitHeight / 3 + + implicitWidth: parent.width - slider.handle.x - slider.handle.implicitWidth - slider.implicitHeight / 6 + + color: Colours.palette.m3surfaceContainer + radius: Appearance.rounding.full + topLeftRadius: slider.implicitHeight / 15 + bottomLeftRadius: slider.implicitHeight / 15 + } + } + + handle: StyledRect { + id: rect + + x: slider.visualPosition * slider.availableWidth + + implicitWidth: slider.implicitHeight / 4.5 + implicitHeight: slider.implicitHeight + + color: Colours.palette.m3primary + radius: Appearance.rounding.full + + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onPressed: event => event.accepted = false + } + } +} diff --git a/components/controls/VerticalSlider.qml b/components/controls/VerticalSlider.qml deleted file mode 100644 index 306cc24..0000000 --- a/components/controls/VerticalSlider.qml +++ /dev/null @@ -1,137 +0,0 @@ -import ".." -import "../effects" -import qs.services -import qs.config -import QtQuick -import QtQuick.Controls - -Slider { - id: root - - required property string icon - property real oldValue - - orientation: Qt.Vertical - - background: StyledRect { - color: Colours.alpha(Colours.palette.m3surfaceContainer, true) - radius: Appearance.rounding.full - - StyledRect { - anchors.left: parent.left - anchors.right: parent.right - - y: root.handle.y - implicitHeight: parent.height - y - - color: Colours.alpha(Colours.palette.m3secondary, true) - radius: Appearance.rounding.full - } - } - - handle: Item { - id: handle - - property bool moving - - y: root.visualPosition * (root.availableHeight - height) - implicitWidth: root.width - implicitHeight: root.width - - Elevation { - anchors.fill: parent - radius: rect.radius - level: handleInteraction.containsMouse ? 2 : 1 - } - - StyledRect { - id: rect - - anchors.fill: parent - - color: Colours.alpha(Colours.palette.m3inverseSurface, true) - radius: Appearance.rounding.full - - MouseArea { - id: handleInteraction - - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - acceptedButtons: Qt.NoButton - } - - MaterialIcon { - id: icon - - property bool moving: handle.moving - - function update(): void { - animate = !moving; - text = moving ? Qt.binding(() => Math.round(root.value * 100)) : Qt.binding(() => root.icon); - font.pointSize = moving ? Appearance.font.size.small : Appearance.font.size.larger; - font.family = moving ? Appearance.font.family.sans : Appearance.font.family.material; - } - - animate: true - text: root.icon - color: Colours.palette.m3inverseOnSurface - anchors.centerIn: parent - - Behavior on moving { - SequentialAnimation { - NumberAnimation { - target: icon - property: "scale" - from: 1 - to: 0 - duration: Appearance.anim.durations.normal / 2 - easing.type: Easing.BezierSpline - easing.bezierCurve: Appearance.anim.curves.standardAccel - } - ScriptAction { - script: icon.update() - } - NumberAnimation { - target: icon - property: "scale" - from: 0 - to: 1 - duration: Appearance.anim.durations.normal / 2 - easing.type: Easing.BezierSpline - easing.bezierCurve: Appearance.anim.curves.standardDecel - } - } - } - } - } - } - - onPressedChanged: handle.moving = pressed - - onValueChanged: { - if (Math.abs(value - oldValue) < 0.01) - return; - oldValue = value; - handle.moving = true; - stateChangeDelay.restart(); - } - - Timer { - id: stateChangeDelay - - interval: 500 - onTriggered: { - if (!root.pressed) - handle.moving = false; - } - } - - Behavior on value { - NumberAnimation { - duration: Appearance.anim.durations.large - easing.type: Easing.BezierSpline - easing.bezierCurve: Appearance.anim.curves.standard - } - } -} -- cgit v1.2.3-freya