bouncy button group for toggles

This commit is contained in:
end-4 2025-05-24 13:10:49 +02:00
parent e7e55e7f95
commit 0cf12bc3be
6 changed files with 64 additions and 37 deletions

View file

@ -166,6 +166,7 @@ Singleton {
}
animationCurves: QtObject {
readonly property list<real> expressiveFastSpatial: [0.42, 1.67, 0.21, 0.90, 1, 1] // Default, 350ms
readonly property list<real> expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1.00, 1, 1] // Default, 500ms
readonly property list<real> expressiveEffects: [0.34, 0.80, 0.34, 1.00, 1, 1] // Default, 200ms
readonly property list<real> emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1]
@ -239,6 +240,18 @@ Singleton {
easing.bezierCurve: root.animation.elementMoveFast.bezierCurve
}}
}
property QtObject clickBounce: QtObject {
property int duration: 250
property int type: Easing.BezierSpline
property list<real> bezierCurve: animationCurves.expressiveFastSpatial
property int velocity: 850
property Component numberAnimation: Component { NumberAnimation {
duration: root.animation.clickBounce.duration
easing.type: root.animation.clickBounce.type
easing.bezierCurve: root.animation.clickBounce.bezierCurve
}}
}
property QtObject scroll: QtObject {
property int duration: 400
property int type: Easing.BezierSpline

View file

@ -14,7 +14,10 @@ Button {
property string buttonText
property real buttonRadius: Appearance?.rounding?.small ?? 4
property real buttonRadiusPressed: buttonRadius
property real buttonEffectiveRadius: root.down ? root.buttonRadiusPressed : root.buttonRadius
property int rippleDuration: 1200
property bool rippleEnabled: true
property var altAction
property color colBackground: ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1)
property color colBackgroundHover: Appearance.colors.colLayer1Hover
@ -52,18 +55,26 @@ Button {
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: (event) => {
if(event.button === Qt.RightButton) {
if (root.altAction) root.altAction();
return;
}
root.down = true
if (!root.rippleEnabled) return;
const {x,y} = event
startRipple(x, y)
}
onReleased: (event) => {
root.down = false
root.click() // Because the MouseArea already consumed the event
if (!root.rippleEnabled) return;
rippleFadeAnim.restart();
}
onCanceled: (event) => {
root.down = false
if (!root.rippleEnabled) return;
rippleFadeAnim.restart();
}
}
@ -109,7 +120,7 @@ Button {
background: Rectangle {
id: buttonBackground
radius: root.down ? root.buttonRadiusPressed : root.buttonRadius
radius: root.buttonEffectiveRadius
implicitHeight: 50
color: root.buttonColor
@ -122,7 +133,7 @@ Button {
maskSource: Rectangle {
width: buttonBackground.width
height: buttonBackground.height
radius: buttonBackground.radius
radius: root.buttonEffectiveRadius
}
}

View file

@ -137,7 +137,7 @@ Scope {
Layout.fillHeight: false
radius: Appearance.rounding.full
color: Appearance.colors.colLayer1
implicitWidth: sidebarQuickControlsRow.implicitWidth + 10
width: 40 * sidebarQuickControlsRow.children.length + sidebarQuickControlsRow.spacing * (sidebarQuickControlsRow.children.length-1) + 10
implicitHeight: sidebarQuickControlsRow.implicitHeight + 10
@ -146,13 +146,18 @@ Scope {
anchors.fill: parent
anchors.margins: 5
spacing: 5
width: 40 * sidebarQuickControlsRow.children.length
property int clickIndex: -1
onClickIndexChanged: {
console.log("Click index changed to: " + clickIndex);
}
NetworkToggle {}
BluetoothToggle {}
NightLight {}
GameMode {}
IdleInhibitor {}
}
}

View file

@ -11,22 +11,12 @@ import Quickshell.Hyprland
QuickToggleButton {
toggled: Bluetooth.bluetoothEnabled
buttonIcon: Bluetooth.bluetoothConnected ? "bluetooth_connected" : Bluetooth.bluetoothEnabled ? "bluetooth" : "bluetooth_disabled"
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton | Qt.LeftButton
onClicked: (mouse) => {
if (mouse.button === Qt.LeftButton) {
toggleBluetooth.running = true
}
if (mouse.button === Qt.RightButton) {
Hyprland.dispatch(`exec ${ConfigOptions.apps.bluetooth}`)
Hyprland.dispatch("global quickshell:sidebarRightClose")
}
}
hoverEnabled: false
propagateComposedEvents: true
cursorShape: Qt.PointingHandCursor
onClicked: {
toggleBluetooth.running = true
}
altAction: () => {
Hyprland.dispatch(`exec ${ConfigOptions.apps.bluetooth}`)
Hyprland.dispatch("global quickshell:sidebarRightClose")
}
Process {
id: toggleBluetooth

View file

@ -17,21 +17,12 @@ QuickToggleButton {
Network.networkStrength > 20 ? "network_wifi_1_bar" :
"signal_wifi_0_bar"
) : "signal_wifi_off"
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton | Qt.LeftButton
onClicked: (mouse) =>{
if (mouse.button === Qt.LeftButton) {
toggleNetwork.running = true
}
if (mouse.button === Qt.RightButton) {
Hyprland.dispatch(`exec ${ConfigOptions.apps.network}`)
Hyprland.dispatch("global quickshell:sidebarRightClose")
}
}
hoverEnabled: false
propagateComposedEvents: true
cursorShape: Qt.PointingHandCursor
onClicked: {
toggleNetwork.running = true
}
altAction: () => {
Hyprland.dispatch(`exec ${ConfigOptions.apps.network}`)
Hyprland.dispatch("global quickshell:sidebarRightClose")
}
Process {
id: toggleNetwork

View file

@ -3,17 +3,34 @@ import "root:/modules/common/widgets"
import "root:/modules/common/functions/color_utils.js" as ColorUtils
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell.Io
RippleButton {
id: button
rippleEnabled: false
property string buttonIcon
property int clickIndex: parent?.clickIndex ?? -1
toggled: false
buttonRadius: Appearance?.rounding?.full ?? 9999
buttonRadius: Appearance?.rounding?.full
buttonRadiusPressed: Appearance?.rounding?.small
implicitWidth: 40
Layout.fillWidth: (clickIndex - 1 <= parent.children.indexOf(button) && parent.children.indexOf(button) <= clickIndex + 1)
implicitWidth: button.down ? 60 : 40
implicitHeight: 40
Behavior on implicitWidth {
animation: Appearance.animation.clickBounce.numberAnimation.createObject(this)
}
onDownChanged: {
if (button.down) {
if (button.parent.clickIndex !== undefined) {
button.parent.clickIndex = parent.children.indexOf(button)
}
}
}
contentItem: MaterialSymbol {
anchors.centerIn: parent
iconSize: Appearance.font.pixelSize.larger