import QtQuick import QtQuick.Templates import ZShell.Config import qs.Services DoubleSpinBox { id: root property int cLayer: 1 property int repeatDecay: 50 property int repeatRate: 400 function decrease(): void { let newValue = Math.max(from, value - stepSize); const decimals = stepSize < 1 ? Math.max(1, Math.ceil(-Math.log10(stepSize))) : 0; newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals); value = newValue; valueModified(); } function increase(): void { let newValue = Math.min(to, value + stepSize); const decimals = stepSize < 1 ? Math.max(1, Math.ceil(-Math.log10(stepSize))) : 0; newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals); value = newValue; valueModified(); } decimals: stepSize < 1 ? Math.max(1, Math.ceil(-Math.log10(stepSize))) : 0 editable: true implicitHeight: Math.max(up.indicator.implicitHeight, down.indicator.implicitHeight, contentItem.implicitHeight) + topPadding + bottomPadding implicitWidth: contentItem.implicitWidth + leftPadding + rightPadding leftPadding: up.indicator.implicitWidth + Tokens.spacing.extraSmall / 2 rightPadding: down.indicator.implicitWidth + Tokens.spacing.extraSmall / 2 spacing: Tokens.spacing.small contentItem: TextFieldBase { horizontalAlignment: TextField.AlignHCenter implicitWidth: 65 inputMethodHints: Qt.ImhFormattedNumbersOnly leftPadding: Tokens.padding.small readOnly: !root.editable rightPadding: Tokens.padding.small text: root.textFromValue(root.value, root.locale) validator: root.validator background: CustomRect { color: Colors.layer(Colors.palette.m3surfaceContainerHighest, root.cLayer) radius: Tokens.rounding.extraSmall } } down.indicator: IconButton { id: downButton bottomRightRadius: pressed ? Tokens.rounding.small : Tokens.rounding.extraSmall color: enabled ? Colors.layer(Colors.palette.m3surfaceContainerHighest, root.cLayer) : disabledColor disabledColor: Qt.alpha(Colors.palette.m3surfaceContainerHighest, 0.4) icon: "remove" isRound: true label.anchors.horizontalCenterOffset: pressed ? 0 : 2 padding: Tokens.padding.extraSmall topRightRadius: pressed ? Tokens.rounding.small : Tokens.rounding.extraSmall type: IconButton.Text Behavior on bottomRightRadius { Anim { type: Anim.DefaultEffects } } Behavior on label.anchors.horizontalCenterOffset { Anim { type: Anim.DefaultEffects } } Behavior on topRightRadius { Anim { type: Anim.DefaultEffects } } } up.indicator: IconButton { id: upButton anchors.right: parent.right bottomLeftRadius: pressed ? Tokens.rounding.small : Tokens.rounding.extraSmall color: enabled ? Colors.layer(Colors.palette.m3surfaceContainerHighest, root.cLayer) : disabledColor disabledColor: Qt.alpha(Colors.palette.m3surfaceContainerHighest, 0.4) icon: "add" isRound: true label.anchors.horizontalCenterOffset: pressed ? 0 : -2 padding: Tokens.padding.extraSmall topLeftRadius: pressed ? Tokens.rounding.small : Tokens.rounding.extraSmall type: IconButton.Text Behavior on bottomLeftRadius { Anim { type: Anim.DefaultEffects } } Behavior on label.anchors.horizontalCenterOffset { Anim { type: Anim.DefaultEffects } } Behavior on topLeftRadius { Anim { type: Anim.DefaultEffects } } } Timer { id: timer interval: root.repeatRate repeat: true running: upButton.pressed || downButton.pressed triggeredOnStart: true onRunningChanged: { if (!running) interval = root.repeatRate; } onTriggered: { if (upButton.pressed) root.increase(); else if (downButton.pressed) root.decrease(); if (interval > root.repeatDecay) interval -= root.repeatDecay; } } }