1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the Qt Components project.
9 ** $QT_BEGIN_LICENSE:BSD$
10 ** You may use this file under the terms of the BSD license as follows:
12 ** "Redistribution and use in source and binary forms, with or without
13 ** modification, are permitted provided that the following conditions are
15 ** * Redistributions of source code must retain the above copyright
16 ** notice, this list of conditions and the following disclaimer.
17 ** * Redistributions in binary form must reproduce the above copyright
18 ** notice, this list of conditions and the following disclaimer in
19 ** the documentation and/or other materials provided with the
21 ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22 ** the names of its contributors may be used to endorse or promote
23 ** products derived from this software without specific prior written
26 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
39 ****************************************************************************/
43 import Qt.labs.components 1.1 as QtComponents
49 property alias stepSize: model.stepSize
50 property alias minimumValue: model.minimumValue
51 property alias maximumValue: model.maximumValue
52 property alias value: model.value
53 property int orientation: Qt.Horizontal
54 property bool pressed: track.inputActive
55 property bool valueIndicatorVisible: false
56 property string valueIndicatorText: ""
57 property alias inverted: model.inverted
59 LayoutMirroring.enabled: false
60 LayoutMirroring.childrenInherit: true
63 property bool platformInverted: false
64 signal valueChanged(real value)
65 implicitWidth: orientation == Qt.Horizontal ? 150 : privateStyle.menuItemHeight
66 implicitHeight: orientation == Qt.Horizontal ? privateStyle.menuItemHeight : 150
68 onActiveFocusChanged: {
69 if (!root.activeFocus)
70 track.activeKey = undefined
73 QtComponents.RangeModel {
80 positionAtMaximum: orientation == Qt.Horizontal ? track.width - handle.width : track.height - handle.height
81 onValueChanged: root.valueChanged(value)
87 property bool tapOnTrack: false
88 property variant activeKey
89 property bool inputActive: handleMouseArea.pressed || !!track.activeKey
90 onInputActiveChanged: {
91 if (!valueIndicatorVisible)
94 valueIndicator.show = true
96 indicatorTimer.restart()
102 when: orientation == Qt.Horizontal
106 height: privateStyle.sliderThickness
108 source: privateStyle.imagePath("qtg_fr_slider_h_track_normal", root.platformInverted)
125 horizontalCenter: undefined
126 verticalCenter: root.verticalCenter
132 when: orientation == Qt.Vertical
137 width: privateStyle.sliderThickness
138 source: privateStyle.imagePath("qtg_fr_slider_v_track_normal", root.platformInverted)
155 horizontalCenter: root.horizontalCenter
156 verticalCenter: undefined
162 anchors.leftMargin: platformStyle.paddingMedium
163 anchors.rightMargin: platformStyle.paddingMedium
164 anchors.topMargin: platformStyle.paddingMedium
165 anchors.bottomMargin: platformStyle.paddingMedium
169 objectName: "trackMouseArea"
174 if (track.tapOnTrack) {
175 if (orientation == Qt.Horizontal) {
176 if (handle.x > (mouseX - handle.width / 2)) {
177 model.value = inverted ? model.value + model.stepSize : model.value - model.stepSize
178 handle.x = model.position
180 model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
181 handle.x = model.position
184 if (handle.y > (mouseY - handle.height / 2)) {
185 model.value = inverted ? model.value + model.stepSize : model.value - model.stepSize
186 handle.y = model.position
188 model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
189 handle.y = model.position
198 x: orientation == Qt.Horizontal ? (handleMouseArea.pressed ? x : model.position) : 0
199 y: orientation == Qt.Horizontal ? 0 : (handleMouseArea.pressed ? y : model.position)
201 sourceSize.height: platformStyle.graphicSizeSmall
202 sourceSize.width: platformStyle.graphicSizeSmall
204 anchors.verticalCenter: orientation == Qt.Horizontal ? parent.verticalCenter : undefined
205 anchors.horizontalCenter: orientation == Qt.Horizontal ? undefined : parent.horizontalCenter
208 var handleIcon = "qtg_graf_slider_"
209 + (orientation == Qt.Horizontal ? "h" : "v")
211 + (handleMouseArea.pressed ? "pressed" : "normal")
212 privateStyle.imagePath(handleIcon, root.platformInverted)
215 onXChanged: valueIndicator.position()
216 onYChanged: valueIndicator.position()
220 objectName: "handleMouseArea"
222 height: platformStyle.graphicSizeMedium
223 width: platformStyle.graphicSizeMedium
224 anchors.verticalCenter: orientation == Qt.Horizontal ? parent.verticalCenter : undefined
225 anchors.horizontalCenter: orientation == Qt.Horizontal ? undefined : parent.horizontalCenter
228 drag.axis: Drag.XandYAxis
229 drag.minimumX: orientation == Qt.Horizontal ? model.positionAtMinimum : 0
230 drag.maximumX: orientation == Qt.Horizontal ? model.positionAtMaximum : 0
231 drag.minimumY: orientation == Qt.Horizontal ? 0 : model.positionAtMinimum
232 drag.maximumY: orientation == Qt.Horizontal ? 0 : model.positionAtMaximum
234 onPositionChanged: model.position = orientation == Qt.Horizontal ? handle.x : handle.y
235 onPressed: privateStyle.play(Android.BasicSlider)
236 onReleased: privateStyle.play(Android.BasicSlider)
243 internal.handleKeyPressEvent(event)
247 internal.handleKeyReleaseEvent(event)
251 id: valueIndicatorComponent
253 text: root.valueIndicatorText == "" ? model.value : root.valueIndicatorText
254 platformInverted: root.platformInverted
261 property int spacing: 2 * platformStyle.paddingLarge
262 // Must match with the "maxWidth" padding defined in ToolTip
263 property int toolTipPadding: platformStyle.paddingLarge
264 property bool show: false
265 sourceComponent: valueIndicator.show ? valueIndicatorComponent : undefined
268 function position() {
269 if (!valueIndicatorVisible || status != Loader.Ready)
273 if (orientation == Qt.Horizontal) {
274 point = root.mapFromItem(track, handle.x + handle.width / 2 - valueIndicator.item.width / 2, 0)
276 // Check if valueIndicator will be positioned beyond the right or
277 // left boundaries and adjust if needed to keep it fully
278 // visible on screen. In case the valueIndicator is so wide that it
279 // does not fit the screen, it's positioned to left of the screen.
280 var rightStop = screen.width - toolTipPadding
281 var valueIndicatorLeftEdge = root.mapToItem(null, point.x, 0)
282 var valueIndicatorRightEdge = root.mapToItem(null, point.x + valueIndicator.item.width, 0)
284 if (valueIndicatorLeftEdge.x < toolTipPadding)
285 point.x = root.mapFromItem(null, toolTipPadding, 0).x
286 else if (valueIndicatorRightEdge.x > rightStop)
287 point.x = root.mapFromItem(null, rightStop - valueIndicator.item.width, 0).x
289 valueIndicator.item.x = point.x
290 valueIndicator.item.y = point.y - valueIndicator.spacing - valueIndicator.item.height
292 point = root.mapFromItem(track, 0, handle.y + handle.height / 2 - valueIndicator.item.height / 2)
293 valueIndicator.item.x = point.x - valueIndicator.spacing - valueIndicator.item.width
294 valueIndicator.item.y = point.y
302 if (!track.inputActive)
303 valueIndicator.show = false
311 function handleKeyPressEvent(keyEvent) {
312 var oldValue = model.value
313 if (orientation == Qt.Horizontal) {
314 if (keyEvent.key == Qt.Key_Left) {
315 model.value = inverted ? model.value + model.stepSize : model.value - model.stepSize
316 } else if (keyEvent.key == Qt.Key_Right) {
317 model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
320 if (keyEvent.key == Qt.Key_Up) {
321 model.value = inverted ? model.value + model.stepSize : model.value - model.stepSize
322 } else if (keyEvent.key == Qt.Key_Down) {
323 model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
326 if (oldValue != model.value)
327 keyEvent.accepted = true
329 if (keyEvent.accepted ||
330 keyEvent.key == Qt.Key_Select ||
331 keyEvent.key == Qt.Key_Return ||
332 keyEvent.key == Qt.Key_Enter)
333 track.activeKey = keyEvent.key
336 function handleKeyReleaseEvent(keyEvent) {
337 if (track.activeKey == keyEvent.key) {
338 if (!keyEvent.isAutoRepeat)
339 track.activeKey = undefined
340 keyEvent.accepted = true