2
* Copyright (C) 2013 Canonical, Ltd.
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; version 3.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18
import "Math.js" as MathLocal
22
property Item pageHeader: null
23
property Component sectionDelegate: null
24
property string sectionProperty: ""
25
property alias model: listView.model
26
property alias delegate: listView.delegate
27
property ListView view: listView
28
property alias moving: flicker.moving
29
property alias atYEnd: flicker.atYEnd
30
property bool clipListView: true
32
readonly property real __headerHeight: (pageHeader) ? pageHeader.implicitHeight : 0
33
property real __headerVisibleHeight: __headerHeight
34
readonly property real __overshootHeight: (flicker.contentY < 0) ? -flicker.contentY : 0
37
// TODO move to AnimationController
40
property real targetContentY
43
property: "__headerVisibleHeight"
44
to: root.__headerHeight
46
easing.type: Easing.OutQuad
51
to: headerAnimation.targetContentY
53
easing.type: Easing.OutQuad
57
function positionAtBeginning() {
58
__headerVisibleHeight = __headerHeight
62
function showHeader() {
63
headerAnimation.targetContentY = listView.contentY + (__headerHeight - __headerVisibleHeight)
64
headerAnimation.start()
67
function flick(xVelocity, yVelocity) {
68
flicker.flick(xVelocity, yVelocity);
71
onPageHeaderChanged: {
72
pageHeader.parent = pageHeaderContainer;
73
pageHeader.anchors.fill = pageHeaderContainer;
78
parent: flicker // parent to Flickable so mouse click events passed through to the header component
84
height: __headerVisibleHeight + __overshootHeight
87
id: pageHeaderContainer
93
height: __headerHeight + __overshootHeight
99
parent: flicker // parent to Flickable so mouse click events passed through to List delegates
104
topMargin: __headerVisibleHeight
108
// FIXME scrolling workaround, see below
109
cacheBuffer: height*10
111
section.property: sectionProperty
112
section.criteria: ViewSection.FullString
113
section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart
114
section.delegate: sectionDelegate
117
clip: root.clipListView
119
property int __sectionDelegateHeight: __getHeight(section.delegate)
120
function __getHeight(component) {
121
// want height (minus allowed overlap) of the section delegate as is needed for clipping
122
if (component === null) return 0;
123
var object = component.createObject(); //FIXME: throws 'section' not defined error
124
var value = object.height - object.bottomBorderAllowedOverlap;
129
property real previousOriginY: 0
131
var deltaOriginY = originY - previousOriginY;
132
previousOriginY = originY;
133
/* When originY changes, it causes the top of the flicker and the top of the list to fall
134
out of sync - and thus the contentY positioning will be broken. To correct for this we
135
manually change the flickable's contentY here */
136
flicker.contentY -= deltaOriginY;
139
/* For case when list content greater than container height and list scrolled down so header
140
hidden. If content shrinks to be smaller than the container height, we want the header to
142
property real __previousContentHeight: 0
143
onContentHeightChanged: {
144
var deltaContentHeight = contentHeight - __previousContentHeight;
145
__previousContentHeight = contentHeight;
146
if (contentHeight < height && deltaContentHeight < 0 && __headerVisibleHeight < height - contentHeight) {
147
__headerVisibleHeight = Math.min(height - contentHeight, __headerHeight);
155
contentHeight: listView.contentHeight + __headerHeight
156
maximumFlickVelocity: height * 10
157
flickDeceleration: height * 2
159
var deltaContentY = contentY - __previousContentY;
160
__previousContentY = contentY;
162
// first decide if movement will prompt the page header to change height
163
if ((deltaContentY < 0 && __headerVisibleHeight >= 0) ||
164
(deltaContentY > 0 && __headerVisibleHeight <= __headerHeight)) {
166
// calculate header height - but prevent bounce from changing it
167
if (contentY > 0 && contentY < contentHeight - height) {
168
__headerVisibleHeight = MathLocal.clamp(__headerVisibleHeight - deltaContentY, 0, __headerHeight);
172
// now we move list position, taking into account page header height
174
// BUG: With section headers enabled, the values of originY and contentY appear not
175
// correct at the exact point originY changes. originY changes when the ListView
176
// deletes/creates hidden delegates which are above the visible delegates.
177
// As a result of this bug, you experience jittering scrolling when rapidly moving
178
// around in large lists. See https://bugreports.qt-project.org/browse/QTBUG-27997
179
// A workaround is to use a large enough cacheBuffer to prevent deletions/creations
180
// so effectively originY is always zero.
181
var newContentY = flicker.contentY + listView.originY - __headerHeight + __headerVisibleHeight
182
if (newContentY < listView.contentHeight) {
183
listView.contentY = newContentY;
187
property real __previousContentY: 0