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 "UIConstants.js" as UI
46 * Class: ScrollDecorator
47 * A ScrollDecorator shows the current position in a scrollable area.
53 * Property: flickableItem
54 * [Flickable] The Item that should show the ScrollDecorator
56 property Flickable flickableItem
58 property int __topPageMargin: 0
59 property int __bottomPageMargin: 0
60 property int __leftPageMargin: 0
61 property int __rightPageMargin: 0
62 property bool __hasPageWidth : false
63 property bool __hasPageHeight: false
65 // These can also be modified (but probably shouldn't)
66 property int __minIndicatorSize: 20
67 property int __hideTimeout: 500
69 property bool __alwaysShowIndicator: true
71 property Style platformStyle: ScrollDecoratorStyle{}
73 //Deprecated, TODO Remove this on w13
74 property alias style: root.platformStyle
76 // This function ensures that we allways anchor the decorator correctly according
77 // to the page margins.
78 function __updatePageMargin() {
81 var p = flickableItem.parent
83 if (p.hasOwnProperty("__isPage")) {
84 __hasPageHeight = function() { return p.height == flickableItem.height }
85 __hasPageWidth = function() { return p.width == flickableItem.width }
86 __topPageMargin = function() { return p.anchors.topMargin }
87 __bottomPageMargin = function() { return p.anchors.bottomMargin }
88 __leftPageMargin = function() { return p.anchors.leftMargin }
89 __rightPageMargin = function() { return p.anchors.rightMargin }
97 onFlickableItemChanged: { __updatePageMargin() }
101 function canFlick(direction) {
102 return flickableItem.flickableDirection === direction
103 || flickableItem.flickableDirection === Flickable.HorizontalAndVerticalFlick
104 || flickableItem.flickableDirection === Flickable.AutoFlickDirection;
109 anchors.fill: flickableItem
112 // Hack to have the indicators flash when the view is shown the first time.
113 // Ideally we would wait until the Flickable is complete, but it doesn't look
114 // possible given the current limitations of QML.
119 if (verticalIndicator.shouldShow) {
120 verticalIndicator.state = "visible";
121 verticalIndicator.state = "";
123 if (horizontalIndicator.shouldShow) {
124 horizontalIndicator.state = "visible";
125 horizontalIndicator.state = "";
131 id: verticalSizerWrapper
132 ScrollDecoratorSizerCPP {
134 positionRatio: flickableItem ? flickableItem.visibleArea.yPosition : 0
135 sizeRatio: flickableItem ? flickableItem.visibleArea.heightRatio : 0
136 maxPosition: flickableItem ? flickableItem.height : 0
137 minSize: __minIndicatorSize
142 id: horizontalSizerWrapper
143 ScrollDecoratorSizerCPP {
145 positionRatio: flickableItem ? flickableItem.visibleArea.xPosition : 0
146 sizeRatio: flickableItem ? flickableItem.visibleArea.widthRatio : 0
147 maxPosition: flickableItem ? flickableItem.width : 0
148 minSize: __minIndicatorSize
152 Loader {id: verticalSizerLoader}
153 Loader {id: horizontalSizerLoader}
156 id: verticalIndicator
157 property bool shouldShow: flickableItem != null && ((__alwaysShowIndicator && privateApi.canFlick(Flickable.VerticalFlick)) && (flickableItem.height > 0 && flickableItem.contentHeight > flickableItem.height))
159 anchors.right: parent.right
160 anchors.rightMargin: UI.SCROLLDECORATOR_LONG_MARGIN - (__hasPageWidth ? __rightPageMargin : 0)
161 anchors.top: parent.top
162 anchors.topMargin: UI.SCROLLDECORATOR_SHORT_MARGIN - (__hasPageWidth ? __topPageMargin : 0)
163 anchors.bottom: parent.bottom
164 anchors.bottomMargin: UI.SCROLLDECORATOR_SHORT_MARGIN - (__hasPageWidth ? __bottomPageMargin : 0)
166 onShouldShowChanged: {
168 verticalSizerLoader.sourceComponent = verticalSizerWrapper;
170 verticalSizerLoader.sourceComponent = undefined;
174 source: platformStyle.background
175 height: parent.height
176 anchors.right: parent.right
179 source: platformStyle.indicator
180 border { left: 2; top: 4; right: 2; bottom: 4 }
181 anchors.right: parent.right
182 y: verticalIndicator.shouldShow && verticalSizerLoader.status == Loader.Ready ? verticalSizerLoader.item.position : 0
183 height: verticalIndicator.shouldShow && verticalSizerLoader.status == Loader.Ready ?
184 verticalSizerLoader.item.size - parent.anchors.topMargin - parent.anchors.bottomMargin : 0
189 when: verticalIndicator.shouldShow && flickableItem.moving
191 target: verticalIndicator
196 transitions: Transition {
197 from: "visible"; to: ""
199 properties: "opacity"
200 duration: root.__hideTimeout
206 id: horizontalIndicator
207 property bool shouldShow: flickableItem != null && ((__alwaysShowIndicator && privateApi.canFlick(Flickable.HorizontalFlick)) && (flickableItem.width > 0 && flickableItem.contentWidth > flickableItem.width))
209 anchors.bottom: parent.bottom
210 anchors.bottomMargin: UI.SCROLLDECORATOR_LONG_MARGIN - (__hasPageHeight ? __bottomPageMargin : 0)
211 anchors.right: parent.right
212 anchors.rightMargin: UI.SCROLLDECORATOR_SHORT_MARGIN - (__hasPageHeight ? __rightPageMargin : 0)
213 anchors.left: parent.left
214 anchors.leftMargin: UI.SCROLLDECORATOR_SHORT_MARGIN - (__hasPageHeight ? __leftPageMargin : 0)
216 onShouldShowChanged: {
218 horizontalSizerLoader.sourceComponent = horizontalSizerWrapper;
220 horizontalSizerLoader.sourceComponent = undefined;
224 source: platformStyle.backgroundHorizontal
226 anchors.left: parent.left
227 anchors.bottom: parent.bottom
230 source: platformStyle.indicatorHorizontal
231 border { left: 4; top: 2; right: 4; bottom: 2 }
232 anchors.bottom: parent.bottom
233 x: horizontalIndicator.shouldShow && horizontalSizerLoader.status == Loader.Ready ? horizontalSizerLoader.item.position : 0
234 width: horizontalIndicator.shouldShow && horizontalSizerLoader.status == Loader.Ready ?
235 horizontalSizerLoader.item.size - parent.anchors.leftMargin - parent.anchors.rightMargin : 0
240 when: horizontalIndicator.shouldShow && flickableItem.moving
242 target: horizontalIndicator
247 transitions: Transition {
248 from: "visible"; to: ""
250 properties: "opacity"
251 duration: root.__hideTimeout