libandroidplugin added
[mardrone] / mardrone / imports / com / meego / SectionScroller.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.0
43 import "SectionScroller.js" as Sections
44
45 Item {
46     id: root
47
48     property ListView listView
49
50     onListViewChanged: {
51         if (listView && listView.model) {
52             internal.initDirtyObserver();
53         } else if (listView) {
54             listView.modelChanged.connect(function() {
55                 if (listView.model) {
56                     internal.initDirtyObserver();
57                 }
58             });
59         }
60     }
61
62     property Style platformStyle: SectionScrollerStyle {}
63
64     //Deprecated, TODO Remove this on w13
65     property alias style: root.platformStyle
66
67     Rectangle {
68         id: container
69         color: "transparent"
70         width: 35
71         height: listView.height
72         x: listView.x + listView.width - width
73         property bool dragging: false
74
75         MouseArea {
76             id: dragArea
77             objectName: "dragArea"
78             anchors.fill: parent
79             drag.target: tooltip
80             drag.axis: Drag.YAxis
81             drag.minimumY: listView.y
82             drag.maximumY: listView.y + listView.height - tooltip.height
83
84             onPressed: {
85                 mouseDownTimer.restart()
86             }
87
88             onReleased: {
89                 container.dragging = false;
90                 mouseDownTimer.stop()
91             }
92
93             onPositionChanged: {
94                 internal.adjustContentPosition(dragArea.mouseY);
95             }
96
97             Timer {
98                 id: mouseDownTimer
99                 interval: 150
100
101                 onTriggered: {
102                     container.dragging = true;
103                     internal.adjustContentPosition(dragArea.mouseY);
104                     tooltip.positionAtY(dragArea.mouseY);
105                 }
106             }
107         }
108         Item {
109             id: tooltip
110             objectName: "popup"
111             opacity: container.dragging ? 1 : 0
112             anchors.right: parent.right
113             anchors.rightMargin: 50
114             width: childrenRect.width
115             height: childrenRect.height
116
117             function positionAtY(yCoord) {
118                 tooltip.y = Math.max(dragArea.drag.minimumY, Math.min(yCoord - tooltip.height/2, dragArea.drag.maximumY));
119             }
120
121             BorderImage {
122                 id: background
123                 width: childrenRect.width// + 20
124                 height: childrenRect.height// + 20
125                 anchors.left: parent.left
126                 source: platformStyle.backgroundImage
127                 border { left: 4; top: 4; right: 4; bottom: 4 }
128
129                 Column {
130                     width: Math.max(previousSectionLabel.width, currentSectionLabel.width, nextSectionLabel.width)
131                     height: childrenRect.height
132
133                     SectionScrollerLabel {
134                         id: previousSectionLabel
135                         objectName: "previousSectionLabel"
136                         text: internal.prevSection
137                         highlighted: internal.curSect === text
138                         up: !internal.down
139                     }
140
141                     Image {
142                         objectName: "divider1"
143                         source: platformStyle.dividerImage
144                         width: parent.width
145                         height: 1
146                         anchors.horizontalCenter: parent.horizontalCenter
147                     }
148
149                     SectionScrollerLabel {
150                         id: currentSectionLabel
151                         objectName: "currentSectionLabel"
152                         text: internal.currentSection
153                         highlighted: internal.curSect === text
154                         up: !internal.down
155                     }
156
157                     Image {
158                         objectName: "divider2"
159                         source: platformStyle.dividerImage
160                         width: parent.width
161                         height: 1
162                         anchors.horizontalCenter: parent.horizontalCenter
163                     }
164
165                     SectionScrollerLabel {
166                         id: nextSectionLabel
167                         objectName: "nextSectionLabel"
168                         text: internal.nextSection
169                         highlighted: internal.curSect === text
170                         up: !internal.down
171                     }
172                 }
173             }
174
175             Image {
176                 id: arrow
177                 objectName: "arrow"
178                 width: 8
179                 height: 16
180                 anchors.left: background.right
181                 property int threshold: currentSectionLabel.height
182                 property int yInitial: background.y + background.height/2 - height/2
183                 y: getYPosition()
184                 source: platformStyle.arrowImage
185
186                 function getYPosition() {
187                     var v = internal.curPos;
188                     var adjust = v === "first" ? -threshold :
189                                 v === "last" ? threshold : 0;
190
191                     return yInitial + adjust;
192                 }
193
194                 states: [
195                     State {
196                         when: root.dragging && dragArea.mouseY < (root.listView.y + threshold)
197                         PropertyChanges {
198                             target: arrow
199                             y: yInitial - threshold
200                         }
201                     }
202                 ]
203
204                 Behavior on y {
205                     NumberAnimation {
206                         duration: 100
207                     }
208                 }
209             }
210
211             states: [
212                 State {
213                     name: "visible"
214                     when: container.dragging
215                 },
216
217                 State {
218                     extend: "visible"
219                     name: "atTop"
220                     when: internal.curPos === "first"
221                     PropertyChanges {
222                         target: previousSectionLabel
223                         text: internal.currentSection
224                     }
225                     PropertyChanges {
226                         target: currentSectionLabel
227                         text: internal.nextSection
228                     }
229                     PropertyChanges {
230                         target: nextSectionLabel
231                         text: Sections.getNextSection(internal.nextSection)
232                     }
233                 },
234
235                 State {
236                     extend: "visible"
237                     name: "atBottom"
238                     when: internal.curPos === "last"
239                     PropertyChanges {
240                         target: previousSectionLabel
241                         text: Sections.getPreviousSection(internal.prevSection)
242                     }
243                     PropertyChanges {
244                         target: currentSectionLabel
245                         text: internal.prevSection
246                     }
247                     PropertyChanges {
248                         target: nextSectionLabel
249                         text: internal.currentSection
250                     }
251                 }
252             ]
253
254             Behavior on opacity {
255                 NumberAnimation { duration: 100 }
256             }
257         }
258     }
259
260     Timer {
261         id: dirtyTimer
262         interval: 100
263         running: false
264         onTriggered: {
265             Sections.initSectionData(listView);
266             internal.modelDirty = false;
267         }
268     }
269
270     Connections {
271         target: root.listView
272         onCurrentSectionChanged: internal.curSect = container.dragging ? internal.curSect : ""
273     }
274
275     QtObject {
276         id: internal
277
278         property string prevSection: ""
279         property string currentSection: listView.currentSection
280         property string nextSection: ""
281         property string curSect: ""
282         property string curPos: "first"
283         property int oldY: 0
284         property bool modelDirty: false
285         property bool down: true
286
287         function initDirtyObserver() {
288             Sections.initialize(listView);
289             function dirtyObserver() {
290                 if (!internal.modelDirty) {
291                     internal.modelDirty = true;
292                     dirtyTimer.running = true;
293                 }
294             }
295
296             if (listView.model.countChanged)
297                 listView.model.countChanged.connect(dirtyObserver);
298
299             if (listView.model.itemsChanged)
300                 listView.model.itemsChanged.connect(dirtyObserver);
301
302             if (listView.model.itemsInserted)
303                 listView.model.itemsInserted.connect(dirtyObserver);
304
305             if (listView.model.itemsMoved)
306                 listView.model.itemsMoved.connect(dirtyObserver);
307
308             if (listView.model.itemsRemoved)
309                 listView.model.itemsRemoved.connect(dirtyObserver);
310         }
311
312         function adjustContentPosition(y) {
313             if (y < 0 || y > dragArea.height) return;
314
315             internal.down = (y > internal.oldY);
316             var sect = Sections.getClosestSection((y / dragArea.height), internal.down);
317             internal.oldY = y;
318             if (internal.curSect != sect) {
319                 internal.curSect = sect;
320                 internal.curPos = Sections.getSectionPositionString(internal.curSect);
321                 var sec = Sections.getRelativeSections(internal.curSect);
322                 internal.prevSection = sec[0];
323                 internal.currentSection = sec[1];
324                 internal.nextSection = sec[2];
325                 var idx = Sections.getIndexFor(sect);
326                 listView.positionViewAtIndex(idx, ListView.Beginning);
327             }
328         }
329
330     }
331 }