Warning, /graphics/spectacle/src/Gui/DelaySpinBox.qml is written in an unsupported language. File is not indexed.

0001 /* SPDX-FileCopyrightText: 2022 Noah Davis <noahadvs@gmail.com>
0002  * SPDX-License-Identifier: LGPL-2.0-or-later
0003  */
0004 
0005 import QtQuick
0006 import QtQuick.Controls as QQC
0007 import QtQuick.Templates as T
0008 import org.kde.spectacle.private
0009 
0010 /**
0011  * Meant to mimic the behavior of SmartSpinBox, a custom Qt Widget spinbox created for Spectacle.
0012  */
0013 QQC.SpinBox {
0014     id: root
0015     readonly property string noDelayString: i18nc("0 second delay", "No Delay")
0016 
0017     function getDisplayText(value) {
0018         if (value === 0) {
0019             return noDelayString
0020         }
0021         const text = textFromValue(value)
0022         if (value % 100 === 0) {
0023             return i18ncp("Integer number of seconds",
0024                 "%2 second", "%2 seconds", value / 100, text)
0025         } else {
0026             return i18nc("Decimal number of seconds", "%2 seconds", text)
0027         }
0028     }
0029 
0030     // QQC Spinbox uses ints for some reason,
0031     // so I need to multiply by 10^decimals to get n decimal places of precision.
0032     from: 0
0033     to: 9900 // not 9999 to prevent stepping up by 1 at 99 from going to 99.99
0034     stepSize: 100
0035     value: Settings.captureDelay * 100
0036     onValueModified: Settings.captureDelay = value / 100
0037     onValueChanged: contentItem.text = getDisplayText(value)
0038 
0039     Connections {
0040         target: Settings
0041         function onCaptureDelayChanged() {
0042             root.value = Settings.captureDelay * 100
0043         }
0044     }
0045 
0046     validator: DoubleValidator {
0047         locale: root.locale.name
0048         bottom: root.from
0049         top: root.to / 100
0050         decimals: 2
0051         notation: DoubleValidator.StandardNotation
0052     }
0053 
0054     textFromValue: (value, locale = root.locale) => {
0055         let precision = 2
0056         if (value % 100 === 0) {
0057             precision = 0
0058         } else if (value % 10 === 0) {
0059             precision = 1
0060         }
0061         return Number(value / 100).toLocaleString(locale, 'f', precision)
0062     }
0063 
0064     valueFromText: (text, locale = root.locale) => {
0065         if (text === noDelayString) {
0066             return 0
0067         }
0068         let decimal = locale.decimalPoint
0069         if (decimal === '.') {
0070             decimal = "\\."
0071         }
0072         let t = text.replace(RegExp(`[^0-9${decimal}]+`, 'g'), ' ')
0073         let filtered = t.match(RegExp(`\\d{0,2}${decimal}\\d{1,2}`, 'g'))
0074         if (filtered === null) {
0075             filtered = t.match(/\d{1,2}/g)
0076         }
0077         if (filtered === null) {
0078             return -1 // unaccepted input
0079         }
0080         return Number.fromLocaleString(locale, filtered[0]) * 100
0081     }
0082 
0083     contentItem: T.TextField {
0084         text: root.getDisplayText(root.value)
0085         color: palette.text
0086         selectionColor: palette.highlight
0087         selectedTextColor: palette.highlightedText
0088         selectByMouse: true
0089         readOnly: !root.editable
0090         validator: root.validator
0091         inputMethodHints: root.inputMethodHints
0092         leftPadding: QmlUtils.fontMetrics.descent
0093         rightPadding: QmlUtils.fontMetrics.descent
0094         horizontalAlignment: TextInput.AlignLeft
0095         verticalAlignment: TextInput.AlignVCenter
0096         implicitWidth: {
0097             const noDelay = QmlUtils.fontMetrics.boundingRect(root.noDelayString).width
0098             const largest = QmlUtils.fontMetrics.boundingRect(root.getDisplayText(9999)).width
0099             return Math.max(noDelay, largest) + leftPadding + rightPadding
0100         }
0101         implicitHeight: QmlUtils.fontMetrics.height
0102         onTextEdited: {
0103             validator.changed()
0104             if (cursorPosition > 2) {
0105                 const pos1 = cursorPosition - 1
0106                 const char1 = text[pos1]
0107                 if (char1 === '.' || char1 === ',') {
0108                     const pos2 = cursorPosition - 2
0109                     const char2 = text[pos2]
0110                     if (char2 === '.' || char2 === ',') {
0111                         remove(pos2, pos1)
0112                     } else {
0113                         let index = text.indexOf('.')
0114                         if (index === -1) {
0115                             index = text.indexOf(',')
0116                         }
0117                         if (index !== -1 && index < pos2) {
0118                             remove(index, pos1)
0119                         }
0120                     }
0121                 }
0122             }
0123             let seconds = root.valueFromText(text) / 100
0124             if (acceptableInput || seconds >= 0) {
0125                 const oldCursorPos = cursorPosition
0126                 Settings.captureDelay = seconds
0127                 cursorPosition = oldCursorPos
0128             }
0129         }
0130     }
0131 }