added android components
[mardrone] / mardrone / imports / com / nokia / android.1.1 / ListItem.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
44 Item {
45     id: root
46     property string mode: "normal" // Read-only
47     property alias paddingItem: paddingItem // Read-only
48
49     property bool enabled: true
50     property bool subItemIndicator: false
51     property bool platformInverted: false
52
53     signal clicked
54     signal pressAndHold
55
56     implicitWidth: ListView.view ? ListView.view.width : screen.width
57     implicitHeight: platformStyle.graphicSizeLarge
58
59     Item {
60         id: background
61         anchors.fill: parent
62
63         Rectangle {
64             height: 1
65             color: root.platformInverted ? platformStyle.colorDisabledLightInverted
66                                          : platformStyle.colorDisabledMid
67             anchors {
68                 bottom: parent.bottom
69                 left: parent.left
70                 right: parent.right
71             }
72         }
73         Loader {
74             id: faderLoader
75             opacity: 0
76             anchors.fill: background
77             sourceComponent: root.mode != "normal" && root.mode != "pressed" ? fader : undefined
78         }
79
80         BorderImage {
81             id: highlight
82             border {
83                 left: platformStyle.borderSizeMedium
84                 top: platformStyle.borderSizeMedium
85                 right: platformStyle.borderSizeMedium
86                 bottom: platformStyle.borderSizeMedium
87             }
88             opacity: 0
89             anchors.fill: background
90         }
91     }
92
93     Component {
94         id: fader
95
96         BorderImage {
97             source: privateStyle.imagePath("qtg_fr_list_" + mode, root.platformInverted)
98             border {
99                 left: platformStyle.borderSizeMedium
100                 top: platformStyle.borderSizeMedium
101                 right: platformStyle.borderSizeMedium
102                 bottom: platformStyle.borderSizeMedium
103             }
104         }
105     }
106
107     MouseArea {
108         id: mouseArea
109         anchors.fill: parent
110         enabled: root.enabled
111         onPressed: {
112             android.listInteractionMode = Android.TouchInteraction
113             internal.state = "Pressed"
114         }
115         onClicked: {
116             internal.state = ""
117             root.clicked()
118         }
119         onCanceled: {
120             internal.state = "Canceled"
121         }
122         onPressAndHold: {
123             internal.state = "PressAndHold"
124         }
125         onReleased: {
126             internal.state = ""
127         }
128         onExited: {
129             internal.state = ""
130         }
131     }
132
133     Loader {
134         id: iconLoader
135         sourceComponent: root.subItemIndicator ? subItemIcon : undefined
136         anchors {
137             right: parent.right
138             rightMargin: privateStyle.scrollBarThickness
139             verticalCenter: parent.verticalCenter
140         }
141     }
142
143     Component {
144         id: subItemIcon
145
146         Image {
147             source: privateStyle.imagePath(
148                 root.enabled ? "qtg_graf_drill_down_indicator"
149                              : "qtg_graf_drill_down_indicator_disabled",
150                 root.platformInverted)
151             mirror: LayoutMirroring.enabled
152             sourceSize.width: platformStyle.graphicSizeSmall
153             sourceSize.height: platformStyle.graphicSizeSmall
154         }
155     }
156
157     Keys.onReleased: {
158         if (!event.isAutoRepeat && root.enabled) {
159             if (event.key == Qt.Key_Select || event.key == Qt.Key_Return || event.key == Qt.Key_Enter) {
160                 event.accepted = true
161                 internal.state = "Focused"
162             }
163         }
164     }
165
166     Keys.onPressed: {
167         if (!event.isAutoRepeat) {
168             switch (event.key) {
169                 case Qt.Key_Select:
170                 case Qt.Key_Enter:
171                 case Qt.Key_Return: {
172                     if (android.listInteractionMode != Android.KeyNavigation)
173                         android.listInteractionMode = Android.KeyNavigation
174                     else
175                         if (root.enabled) {
176                             highlight.source = privateStyle.imagePath("qtg_fr_list_pressed",
177                                                                       root.platformInverted)
178                             highlight.opacity = 1
179                             releasedEffect.restart()
180                             root.clicked()
181                         }
182                     event.accepted = true
183                     break
184                 }
185
186                 case Qt.Key_Up: {
187                     if (android.listInteractionMode != Android.KeyNavigation) {
188                         android.listInteractionMode = Android.KeyNavigation
189                         internal.state = "Focused"
190                         ListView.view.positionViewAtIndex(index, ListView.Beginning)
191                     } else
192                         ListView.view.decrementCurrentIndex()
193                     event.accepted = true
194                     break
195                 }
196
197                 case Qt.Key_Down: {
198                     if (android.listInteractionMode != Android.KeyNavigation) {
199                         android.listInteractionMode = Android.KeyNavigation
200                         ListView.view.positionViewAtIndex(index, ListView.Beginning)
201                         internal.state = "Focused"
202                     } else
203                         ListView.view.incrementCurrentIndex()
204                     event.accepted = true
205                     break
206                 }
207                 default: {
208                     event.accepted = false
209                     break
210                 }
211             }
212         }
213
214         if (event.key == Qt.Key_Up || event.key == Qt.Key_Down)
215             android.privateListItemKeyNavigation(ListView.view)
216     }
217
218     ListView.onRemove: SequentialAnimation {
219         PropertyAction { target: root; property: "ListView.delayRemove"; value: true }
220         ParallelAnimation {
221             SequentialAnimation {
222                 PauseAnimation { duration: 50 }
223                 NumberAnimation {
224                     target: root
225                     property: "height"
226                     to: 0
227                     duration: 200
228                     easing.type: Easing.OutQuad
229                 }
230             }
231             NumberAnimation {
232                 target: root
233                 property: "opacity"
234                 from: 1
235                 to: 0
236                 duration: 200
237                 easing.type: Easing.Linear
238             }
239         }
240         PropertyAction { target: root; property: "ListView.delayRemove"; value: false }
241     }
242
243     ListView.onAdd: SequentialAnimation {
244         PropertyAction { target: root; property: "height"; value: 0 }
245         ParallelAnimation {
246             NumberAnimation {
247                 target: root
248                 property: "height"
249                 to: root.height
250                 duration: 250
251                 easing.type: Easing.OutQuad
252             }
253             NumberAnimation {
254                 target: root
255                 property: "opacity"
256                 from: 0
257                 to: 1
258                 duration: 250
259                 easing.type: Easing.Linear
260             }
261         }
262     }
263
264     SequentialAnimation {
265         id: releasedEffect
266         PropertyAnimation {
267             target: highlight
268             property: "opacity"
269             to: 0
270             easing.type: Easing.Linear
271             duration: 150
272         }
273     }
274
275     Item {
276         // non-visible item to create a padding boundary that content items can bind to
277         id: paddingItem
278         anchors {
279             fill: parent
280             leftMargin: platformStyle.paddingLarge
281             rightMargin: iconLoader.status == Loader.Ready ?
282                     privateStyle.scrollBarThickness + iconLoader.width + platformStyle.paddingMedium :
283                     privateStyle.scrollBarThickness
284             topMargin: platformStyle.paddingLarge
285             bottomMargin: platformStyle.paddingLarge
286         }
287     }
288
289     StateGroup {
290         id: internal
291
292         function getMode() {
293             if (internal.state == "Pressed" || internal.state == "PressAndHold")
294                 return "pressed"
295             else if (internal.state == "Focused")
296                 return "highlighted"
297             else if (internal.state == "Disabled")
298                 return "disabled"
299             else
300                 return "normal"
301         }
302
303         // Performance optimization:
304         // Use value assignment when property changes instead of binding to js function
305         onStateChanged: { root.mode = internal.getMode() }
306
307         function press() {
308             privateStyle.play(Android.BasicItem)
309             highlight.source = privateStyle.imagePath("qtg_fr_list_pressed", root.platformInverted)
310             highlight.opacity = 1
311             if (root.ListView.view)
312                 root.ListView.view.currentIndex = index
313         }
314
315         function release() {
316             if (android.listInteractionMode != Android.KeyNavigation)
317                 privateStyle.play(Android.BasicItem)
318             releasedEffect.restart()
319         }
320
321         function releaseHold() {
322             releasedEffect.restart()
323         }
324
325         function hold() {
326             root.pressAndHold()
327         }
328
329         function disable() {
330             faderLoader.opacity = 1
331         }
332
333         function focus() {
334             faderLoader.opacity = 1
335         }
336
337         function canceled() {
338             releasedEffect.restart()
339         }
340
341         states: [
342             State { name: "Pressed" },
343             State { name: "PressAndHold" },
344             State { name: "Disabled"; when: !root.enabled },
345             State { name: "Focused"; when: (root.ListView.isCurrentItem &&
346                 android.listInteractionMode == Android.KeyNavigation) },
347             State { name: "Canceled" },
348             State { name: "" }
349         ]
350
351         transitions: [
352             Transition {
353                 to: "Pressed"
354                 ScriptAction { script: internal.press() }
355             },
356             Transition {
357                 from: "Pressed"
358                 to: "PressAndHold"
359                 ScriptAction { script: internal.hold() }
360             },
361             Transition {
362                 from: "PressAndHold"
363                 to: ""
364                 ScriptAction { script: internal.releaseHold() }
365             },
366             Transition {
367                 to: ""
368                 ScriptAction { script: internal.release() }
369             },
370             Transition {
371                 to: "Disabled"
372                 ScriptAction { script: internal.disable() }
373             },
374             Transition {
375                 to: "Focused"
376                 ScriptAction { script: internal.focus() }
377             },
378             Transition {
379                 to: "Canceled"
380                 ScriptAction { script: internal.canceled() }
381             }
382         ]
383     }
384 }