summaryrefslogtreecommitdiffstats
path: root/src/imports/StudioControls/RealSpinBox.qml
diff options
context:
space:
mode:
authorHenning Gruendl <henning.gruendl@qt.io>2019-07-05 14:58:20 +0200
committerThomas Hartmann <thomas.hartmann@qt.io>2019-08-05 14:43:03 +0000
commit98085e69a6d250321b3012671c6b4ba50be4370a (patch)
tree848309d3bf0b6b8f12ce4c23640d2f3a012c77dd /src/imports/StudioControls/RealSpinBox.qml
parentbb54345474c928250f65f778fcfc2fb061f72406 (diff)
Add new controls for property editorHEADmaster
Adds new controls for the property editor based on Controls 2. The included controls are SpinBox (RealSpinBox), ComboBox, TextField, TextArea (experimental), CheckBox (with tri-state), Button (ButtonRow), ContextMenu, ScrollView and ScrollBar. Each control contains an ActionIndicator which can be hidden on demand. The ActionIndicator itself can also be used standalone. It also a flag to draw it without borders and background. The reason for two SpinBox implementations is the following bug QDS-806. Usage of SpinBox should be avoided rather use RealSpinBox. Change-Id: Ie647f05d02e8de8d31da9556126ce2cabe9009e9 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Diffstat (limited to 'src/imports/StudioControls/RealSpinBox.qml')
-rw-r--r--src/imports/StudioControls/RealSpinBox.qml354
1 files changed, 354 insertions, 0 deletions
diff --git a/src/imports/StudioControls/RealSpinBox.qml b/src/imports/StudioControls/RealSpinBox.qml
new file mode 100644
index 0000000..d1d738e
--- /dev/null
+++ b/src/imports/StudioControls/RealSpinBox.qml
@@ -0,0 +1,354 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQuick.Templates 2.12 as T
+import StudioTheme 1.0 as StudioTheme
+
+T.SpinBox {
+ id: mySpinBox
+
+ property real realFrom: 0.0
+ property real realTo: 99.0
+ property real realValue: 1.0
+ property real realStepSize: 1.0
+
+ property alias labelColor: spinBoxInput.color
+ property alias actionIndicator: actionIndicator
+
+ property int decimals: 0
+
+ property real minStepSize: {
+ var tmpMinStepSize = Number((mySpinBox.realStepSize * 0.1).toFixed(mySpinBox.decimals))
+ return (tmpMinStepSize) ? tmpMinStepSize : mySpinBox.realStepSize
+ }
+ property real maxStepSize: {
+ var tmpMaxStepSize = Number((mySpinBox.realStepSize * 10.0).toFixed(mySpinBox.decimals))
+ return (tmpMaxStepSize < mySpinBox.realTo) ? tmpMaxStepSize : mySpinBox.realStepSize
+ }
+
+ property bool edit: spinBoxInput.activeFocus
+ property bool hover: false // This property is used to indicate the global hover state
+ property bool drag: false
+
+ property real realDragRange: realTo - realFrom
+
+ property alias actionIndicatorVisible: actionIndicator.visible
+ property real __actionIndicatorWidth: StudioTheme.Values.squareComponentWidth
+ property real __actionIndicatorHeight: StudioTheme.Values.height
+
+ property bool spinBoxIndicatorVisible: true
+ property real __spinBoxIndicatorWidth: StudioTheme.Values.smallRectWidth - 2
+ * StudioTheme.Values.border
+ property real __spinBoxIndicatorHeight: StudioTheme.Values.height / 2
+ - StudioTheme.Values.border
+
+ property alias sliderIndicatorVisible: sliderIndicator.visible
+ property real __sliderIndicatorWidth: StudioTheme.Values.squareComponentWidth
+ property real __sliderIndicatorHeight: StudioTheme.Values.height
+
+ signal realValueModified
+ signal compressedRealValueModified
+ signal dragStarted
+ signal dragEnded
+
+ // Use custom wheel handling due to bugs
+ property bool __wheelEnabled: false
+ wheelEnabled: false
+
+ width: StudioTheme.Values.squareComponentWidth * 5
+ height: StudioTheme.Values.height
+
+ leftPadding: spinBoxIndicatorDown.x + spinBoxIndicatorDown.width
+ - (spinBoxIndicatorVisible ? 0 : StudioTheme.Values.border)
+ rightPadding: sliderIndicator.width - (sliderIndicatorVisible ? StudioTheme.Values.border : 0)
+
+ font.pixelSize: StudioTheme.Values.myFontSize
+ editable: true
+
+ // Leave this in for now
+ from: -99
+ value: 0
+ to: 99
+
+ validator: DoubleValidator {
+ id: doubleValidator
+ locale: mySpinBox.locale.name
+ notation: DoubleValidator.StandardNotation
+ decimals: mySpinBox.decimals
+ bottom: Math.min(mySpinBox.realFrom, mySpinBox.realTo)
+ top: Math.max(mySpinBox.realFrom, mySpinBox.realTo)
+ }
+
+ ActionIndicator {
+ id: actionIndicator
+ myControl: mySpinBox
+ x: 0
+ y: 0
+ width: actionIndicator.visible ? __actionIndicatorWidth : 0
+ height: actionIndicator.visible ? __actionIndicatorHeight : 0
+ }
+
+ up.indicator: RealSpinBoxIndicator {
+ id: spinBoxIndicatorUp
+ myControl: mySpinBox
+ iconFlip: -1
+ visible: spinBoxIndicatorVisible
+ onRealReleased: mySpinBox.realIncrease()
+ onRealPressAndHold: mySpinBox.realIncrease()
+ x: actionIndicator.width + (actionIndicatorVisible ? 0 : StudioTheme.Values.border)
+ y: StudioTheme.Values.border
+ width: spinBoxIndicatorVisible ? __spinBoxIndicatorWidth : 0
+ height: spinBoxIndicatorVisible ? __spinBoxIndicatorHeight : 0
+
+ realEnabled: (mySpinBox.realFrom < mySpinBox.realTo) ? (mySpinBox.realValue < mySpinBox.realTo) : (mySpinBox.realValue > mySpinBox.realTo)
+ }
+
+ down.indicator: RealSpinBoxIndicator {
+ id: spinBoxIndicatorDown
+ myControl: mySpinBox
+ visible: spinBoxIndicatorVisible
+ onRealReleased: mySpinBox.realDecrease()
+ onRealPressAndHold: mySpinBox.realDecrease()
+ x: actionIndicator.width + (actionIndicatorVisible ? 0 : StudioTheme.Values.border)
+ y: spinBoxIndicatorUp.y + spinBoxIndicatorUp.height
+ width: spinBoxIndicatorVisible ? __spinBoxIndicatorWidth : 0
+ height: spinBoxIndicatorVisible ? __spinBoxIndicatorHeight : 0
+
+ realEnabled: (mySpinBox.realFrom < mySpinBox.realTo) ? (mySpinBox.realValue > mySpinBox.realFrom) : (mySpinBox.realValue < mySpinBox.realFrom)
+ }
+
+ contentItem: RealSpinBoxInput {
+ id: spinBoxInput
+ myControl: mySpinBox
+ validator: doubleValidator
+ }
+
+ background: Rectangle {
+ id: spinBoxBackground
+ color: StudioTheme.Values.themeControlOutline
+ border.color: StudioTheme.Values.themeControlOutline
+ border.width: StudioTheme.Values.border
+ x: actionIndicator.width - (actionIndicatorVisible ? StudioTheme.Values.border : 0)
+ width: mySpinBox.width - actionIndicator.width
+ height: mySpinBox.height
+ }
+
+ CheckIndicator {
+ id: sliderIndicator
+ myControl: mySpinBox
+ myPopup: sliderPopup
+ x: spinBoxInput.x + spinBoxInput.width - StudioTheme.Values.border
+ width: sliderIndicator.visible ? __sliderIndicatorWidth : 0
+ height: sliderIndicator.visible ? __sliderIndicatorHeight : 0
+ visible: false // reasonable default
+ }
+
+ RealSliderPopup {
+ id: sliderPopup
+ myControl: mySpinBox
+ x: spinBoxInput.x
+ y: StudioTheme.Values.height - StudioTheme.Values.border
+ width: spinBoxInput.width + sliderIndicator.width - StudioTheme.Values.border
+ height: StudioTheme.Values.sliderHeight
+
+ enter: Transition {
+ }
+ exit: Transition {
+ }
+ }
+
+ textFromValue: function (value, locale) {
+ return Number(mySpinBox.realValue).toLocaleString(locale, 'f', mySpinBox.decimals)
+ }
+
+ valueFromText: function (text, locale) {
+ mySpinBox.setRealValue(Number.fromLocaleString(locale, spinBoxInput.text))
+ return 0
+ }
+
+ states: [
+ State {
+ name: "default"
+ when: mySpinBox.enabled && !mySpinBox.hover
+ && !mySpinBox.edit && !mySpinBox.drag
+ PropertyChanges {
+ target: mySpinBox
+ __wheelEnabled: false
+ }
+ PropertyChanges {
+ target: spinBoxInput
+ selectByMouse: false
+ }
+ PropertyChanges {
+ target: spinBoxBackground
+ color: StudioTheme.Values.themeControlOutline
+ border.color: StudioTheme.Values.themeControlOutline
+ }
+ },
+ State {
+ name: "edit"
+ when: mySpinBox.edit
+ PropertyChanges {
+ target: mySpinBox
+ __wheelEnabled: true
+ }
+ PropertyChanges {
+ target: spinBoxInput
+ selectByMouse: true
+ }
+ PropertyChanges {
+ target: spinBoxBackground
+ color: StudioTheme.Values.themeInteraction
+ border.color: StudioTheme.Values.themeInteraction
+ }
+ },
+ State {
+ name: "drag"
+ when: mySpinBox.drag
+ PropertyChanges {
+ target: spinBoxBackground
+ color: StudioTheme.Values.themeInteraction
+ border.color: StudioTheme.Values.themeInteraction
+ }
+ },
+ State {
+ name: "disabled"
+ when: !mySpinBox.enabled
+ PropertyChanges {
+ target: spinBoxBackground
+ color: StudioTheme.Values.themeControlOutlineDisabled
+ border.color: StudioTheme.Values.themeControlOutlineDisabled
+ }
+ }
+ ]
+
+ Timer {
+ id: myTimer
+ repeat: false
+ running: false
+ interval: 200
+ onTriggered: mySpinBox.compressedRealValueModified()
+ }
+
+ onRealValueChanged: {
+ spinBoxInput.text = mySpinBox.textFromValue(mySpinBox.realValue, mySpinBox.locale)
+ mySpinBox.value = 0 // Without setting value back to 0, it can happen that one of
+ // the indicator will be disabled due to range logic.
+ }
+ onRealValueModified: myTimer.restart()
+ onFocusChanged: mySpinBox.setValueFromInput()
+ onDisplayTextChanged: spinBoxInput.text = mySpinBox.displayText
+ onActiveFocusChanged: {
+ if (mySpinBox.activeFocus)
+ // QTBUG-75862 && mySpinBox.focusReason === Qt.TabFocusReason)
+ spinBoxInput.selectAll()
+
+ if (sliderPopup.opened && !mySpinBox.activeFocus)
+ sliderPopup.close()
+ }
+
+ Keys.onPressed: {
+ if (event.key === Qt.Key_Up || event.key === Qt.Key_Down) {
+ event.accepted = true
+
+ // Store current step size
+ var currStepSize = mySpinBox.realStepSize
+
+ // Set realStepSize according to used modifier key
+ if (event.modifiers & Qt.ControlModifier)
+ mySpinBox.realStepSize = mySpinBox.minStepSize
+
+ if (event.modifiers & Qt.ShiftModifier)
+ mySpinBox.realStepSize = mySpinBox.maxStepSize
+
+ if (event.key === Qt.Key_Up)
+ mySpinBox.realIncrease()
+ else
+ mySpinBox.realDecrease()
+
+ // Reset realStepSize
+ mySpinBox.realStepSize = currStepSize
+ }
+
+ if (event.key === Qt.Key_Escape)
+ mySpinBox.focus = false
+
+ // FIX: This is a temporary fix for QTBUG-74239
+ if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter)
+ mySpinBox.setValueFromInput()
+ }
+
+ function clamp(v, lo, hi) {
+ return (v < lo || v > hi) ? Math.min(Math.max(lo, v), hi) : v
+ }
+
+ function setValueFromInput() {
+ // FIX: This is a temporary fix for QTBUG-74239
+ var currValue = mySpinBox.realValue
+
+ // Call the function but don't use return value. The realValue property
+ // will be implicitly set inside the function/procedure.
+ mySpinBox.valueFromText(spinBoxInput.text, mySpinBox.locale)
+
+ if (mySpinBox.realValue !== currValue) {
+ mySpinBox.realValueModified()
+ } else {
+ // Check if input text differs in format from the current value
+ var tmpInputValue = mySpinBox.textFromValue(mySpinBox.realValue, mySpinBox.locale)
+
+ if (tmpInputValue !== spinBoxInput.text)
+ spinBoxInput.text = tmpInputValue
+ }
+ }
+
+ function setRealValue(value) {
+ mySpinBox.realValue = clamp(value,
+ mySpinBox.validator.bottom,
+ mySpinBox.validator.top)
+ }
+
+ function realDecrease() {
+ // Store the current value for comparison
+ var currValue = mySpinBox.realValue
+ mySpinBox.valueFromText(spinBoxInput.text, mySpinBox.locale)
+
+ setRealValue(mySpinBox.realValue - realStepSize)
+
+ if (mySpinBox.realValue !== currValue)
+ mySpinBox.realValueModified()
+ }
+
+ function realIncrease() {
+ // Store the current value for comparison
+ var currValue = mySpinBox.realValue
+ mySpinBox.valueFromText(spinBoxInput.text, mySpinBox.locale)
+
+ setRealValue(mySpinBox.realValue + realStepSize)
+
+ if (mySpinBox.realValue !== currValue)
+ mySpinBox.realValueModified()
+ }
+}