added android components
[mardrone] / mardrone / imports / com / nokia / android.1.1 / Slider.qml
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the Qt Components project.
8 **
9 ** $QT_BEGIN_LICENSE:BSD$
10 ** You may use this file under the terms of the BSD license as follows:
11 **
12 ** "Redistribution and use in source and binary forms, with or without
13 ** modification, are permitted provided that the following conditions are
14 ** met:
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
20 **     distribution.
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
24 **     permission.
25 **
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."
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 import QtQuick 1.1
42 import "." 1.1
43 import Qt.labs.components 1.1 as QtComponents
44
45 Item {
46     id: root
47
48     // Common Public API
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
58
59     LayoutMirroring.enabled: false
60     LayoutMirroring.childrenInherit: true
61
62     // Symbian specific
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
67
68     onActiveFocusChanged: {
69         if (!root.activeFocus)
70             track.activeKey = undefined
71     }
72
73     QtComponents.RangeModel {
74         id: model
75         value: 0.0
76         stepSize: 0.0
77         minimumValue: 0.0
78         maximumValue: 1.0
79         positionAtMinimum: 0
80         positionAtMaximum: orientation == Qt.Horizontal ? track.width - handle.width : track.height - handle.height
81         onValueChanged: root.valueChanged(value)
82     }
83
84     BorderImage {
85         id: track
86         objectName: "track"
87         property bool tapOnTrack: false
88         property variant activeKey
89         property bool inputActive: handleMouseArea.pressed || !!track.activeKey
90         onInputActiveChanged: {
91             if (!valueIndicatorVisible)
92                 return
93             if (inputActive)
94                 valueIndicator.show = true
95             else
96                 indicatorTimer.restart()
97         }
98
99         states: [
100             State {
101                 name: "Horizontal"
102                 when: orientation == Qt.Horizontal
103
104                 PropertyChanges {
105                     target: track
106                     height: privateStyle.sliderThickness
107                     width: undefined
108                     source: privateStyle.imagePath("qtg_fr_slider_h_track_normal", root.platformInverted)
109                     border {
110                         left: 20
111                         right: 20
112                         top: 0
113                         bottom: 0
114                     }
115                     smooth: true
116                 }
117
118                 AnchorChanges {
119                     target: track
120                     anchors {
121                         left: root.left
122                         right: root.right
123                         top: undefined
124                         bottom: undefined
125                         horizontalCenter: undefined
126                         verticalCenter: root.verticalCenter
127                     }
128                 }
129             },
130             State {
131                 name: "Vertical"
132                 when: orientation == Qt.Vertical
133
134                 PropertyChanges {
135                     target: track
136                     height: undefined
137                     width: privateStyle.sliderThickness
138                     source: privateStyle.imagePath("qtg_fr_slider_v_track_normal", root.platformInverted)
139                     border {
140                         left: 0
141                         right: 0
142                         top: 20
143                         bottom: 20
144                     }
145                     smooth: true
146                 }
147
148                 AnchorChanges {
149                     target: track
150                     anchors {
151                         left: undefined
152                         right: undefined
153                         top: root.top
154                         bottom: root.bottom
155                         horizontalCenter: root.horizontalCenter
156                         verticalCenter: undefined
157                     }
158                 }
159             }
160         ]
161
162         anchors.leftMargin: platformStyle.paddingMedium
163         anchors.rightMargin: platformStyle.paddingMedium
164         anchors.topMargin: platformStyle.paddingMedium
165         anchors.bottomMargin: platformStyle.paddingMedium
166
167         MouseArea {
168             id: trackMouseArea
169             objectName: "trackMouseArea"
170
171             anchors.fill: parent
172
173             onClicked: {
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
179                         } else {
180                             model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
181                             handle.x = model.position
182                         }
183                     } else {
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
187                         } else {
188                             model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
189                             handle.y = model.position
190                         }
191                     }
192                 }
193             }
194
195             Image {
196                 id: handle
197                 objectName: "handle"
198                 x: orientation == Qt.Horizontal ? (handleMouseArea.pressed ? x : model.position) : 0
199                 y: orientation == Qt.Horizontal ? 0 : (handleMouseArea.pressed ? y : model.position)
200
201                 sourceSize.height: platformStyle.graphicSizeSmall
202                 sourceSize.width: platformStyle.graphicSizeSmall
203
204                 anchors.verticalCenter: orientation == Qt.Horizontal ? parent.verticalCenter : undefined
205                 anchors.horizontalCenter: orientation == Qt.Horizontal ? undefined : parent.horizontalCenter
206
207                 source: {
208                     var handleIcon = "qtg_graf_slider_"
209                         + (orientation == Qt.Horizontal ? "h" : "v")
210                         + "_handle_"
211                         + (handleMouseArea.pressed ? "pressed" : "normal")
212                     privateStyle.imagePath(handleIcon, root.platformInverted)
213                 }
214
215                 onXChanged: valueIndicator.position()
216                 onYChanged: valueIndicator.position()
217
218                 MouseArea {
219                     id: handleMouseArea
220                     objectName: "handleMouseArea"
221
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
226
227                     drag.target: handle
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
233
234                     onPositionChanged: model.position = orientation == Qt.Horizontal ? handle.x : handle.y
235                     onPressed: privateStyle.play(Android.BasicSlider)
236                     onReleased: privateStyle.play(Android.BasicSlider)
237                 }
238             }
239         }
240     }
241
242     Keys.onPressed: {
243         internal.handleKeyPressEvent(event)
244     }
245
246     Keys.onReleased: {
247         internal.handleKeyReleaseEvent(event)
248     }
249
250     Component {
251         id: valueIndicatorComponent
252         ToolTip {
253             text: root.valueIndicatorText == "" ? model.value : root.valueIndicatorText
254             platformInverted: root.platformInverted
255         }
256     }
257
258     Loader {
259         id: valueIndicator
260
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
266         onLoaded: position()
267
268         function position() {
269             if (!valueIndicatorVisible || status != Loader.Ready)
270                 return
271
272             var point = null
273             if (orientation == Qt.Horizontal) {
274                 point = root.mapFromItem(track, handle.x + handle.width / 2 - valueIndicator.item.width / 2, 0)
275
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)
283
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
288
289                 valueIndicator.item.x = point.x
290                 valueIndicator.item.y = point.y - valueIndicator.spacing - valueIndicator.item.height
291             } else {
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
295             }
296         }
297
298         Timer {
299             id: indicatorTimer
300             interval: 750
301             onTriggered: {
302                 if (!track.inputActive)
303                     valueIndicator.show = false
304             }
305         }
306     }
307
308     QtObject {
309         id: internal
310
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
318                 }
319             } else { //Vertical
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
324                 }
325             }
326             if (oldValue != model.value)
327                 keyEvent.accepted = true
328
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
334         }
335
336         function handleKeyReleaseEvent(keyEvent) {
337             if (track.activeKey == keyEvent.key) {
338                 if (!keyEvent.isAutoRepeat)
339                     track.activeKey = undefined
340                 keyEvent.accepted = true
341             }
342         }
343     }
344 }