1 /////////////////////////////////////////////////////////////////////////
4 // Copyright(C) 2009 Igor Trindade Oliveira <igor.oliveira@indt.org.br>//
5 // Copyright(C) 2009 Adenilson Cavalcanti <adenilson.silva@idnt.org.br>//
7 // This library is free software; you can redistribute it and/or //
8 // modify it under the terms of the GNU Lesser General Public //
9 // License as published by the Free Software Foundation; either //
10 // version 2.1 of the License, or (at your option) any later version. //
12 // This library is distributed in the hope that it will be useful, //
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of //
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU //
15 // Lesser General Public License for more details. //
17 // You should have received a copy of the GNU Lesser General Public //
18 // License along with this library; if not, write to the Free Software //
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA //
21 /////////////////////////////////////////////////////////////////////////
22 #include "kineticview.h"
23 #include "scrollbar.h"
27 #include <QGraphicsGridLayout>
29 #include <QPropertyAnimation>
33 * - fix velocity( create a new easing curve? )
34 * - kinetic velocity parameterized upon count of list items
35 * - horizontal scrolling
36 * - parameterize dimensions
37 * - ringbuffer (minimize number of items in the QGV).
40 class KineticScrollingPrivate
43 KineticScrollingPrivate(): mScrollVelocity(0), timerID(0),
44 overshoot(40), bounceFlag(0), bounceStatus( Finished
)
49 t
= QTime::currentTime();
53 unsigned int elapsed()
58 void verticalScroll(int value
)
60 widget
->setPos(QPoint(0, -value
*10));
63 void horizontalScroll(int value
)
65 widget
->setPos(QPoint(-value
*10, 0));
68 /* Just for backport sake */
84 void mousePressEvent(QGraphicsSceneMouseEvent
*event
)
93 void mouseMoveEvent(QGraphicsSceneMouseEvent
*event
)
95 int temp
= event
->lastPos().y() - event
->pos().y();
102 void mouseReleaseEvent(QGraphicsSceneMouseEvent
*event
)
104 timeDelta
= elapsed();
105 int temp
= event
->lastPos().y() - event
->pos().y();
107 kin_movement
+= temp
;
109 if (timeDelta
> 200) {
110 if (kin_movement
> 0)
117 void wheelReleaseEvent(QGraphicsSceneWheelEvent
*event
)
119 timeDelta
= elapsed();
120 int temp
= event
->delta();
122 kin_movement
+= temp
;
124 /* Just for backport sake */
126 unsigned int timeDelta
;
127 qreal scrollVelocity
;
131 qreal mScrollVelocity
;
132 enum { None
, Up
, Down
};
133 enum BounceStatus
{ Running
, Finished
};
134 int timerID
, overshoot
, cposition
, direction
, minimalPos
, maximumPos
;
136 BounceStatus bounceStatus
;
138 QGraphicsWidget
*widget
;
139 QGraphicsWidget
*scrollingWidget
;
145 KineticView::KineticView(QGraphicsWidget
*parent
)
146 : QGraphicsWidget(parent
)
148 d
= new KineticScrollingPrivate
;
149 setSizePolicy(QSizePolicy::Expanding
, QSizePolicy::Expanding
);
150 d
->scrollingWidget
= new QGraphicsWidget(this);
151 d
->scrollingWidget
->setSizePolicy(QSizePolicy::Expanding
, QSizePolicy::Expanding
);
152 d
->scrollingWidget
->setFlag(QGraphicsItem::ItemClipsChildrenToShape
, true);
153 layout
= new QGraphicsGridLayout(this);
154 layout
->addItem(d
->scrollingWidget
, 0, 0);
156 verticalScrollbar
= new ScrollBar(this);
157 connect(verticalScrollbar
, SIGNAL(valueChanged(int)), this, SLOT(setVerticalScrollValue(int)));
158 layout
->addItem(verticalScrollbar
, 0, 1);
160 setAcceptedMouseButtons(Qt::LeftButton
);
163 KineticView::~KineticView()
167 delete scrollAnimation
;
170 void KineticView::adjustScrollBar()
172 verticalScrollbar
->setMaximum( qMax( 0,
173 int( d
->widget
->size().height() - d
->scrollingWidget
->size().height())));
176 void KineticView::setWidget(QGraphicsWidget
*item
)
179 d
->widget
->setSizePolicy(QSizePolicy::Expanding
, QSizePolicy::Fixed
);
180 d
->widget
->setParentItem(d
->scrollingWidget
);
181 d
->widget
->setPos(0, 0);
182 d
->widget
->setAcceptedMouseButtons(Qt::LeftButton
);
184 scrollAnimation
= new QPropertyAnimation(d
->widget
, "geometry");
185 connect(scrollAnimation
, SIGNAL(finished()), this, SLOT(overshoot()));
186 scrollAnimation
->setEasingCurve(QEasingCurve::OutCirc
);
188 d
->widget
->installEventFilter( this );
193 void KineticView::overshoot()
195 /* Detect if bouncer */
196 if( d
->bounceStatus
!= KineticScrollingPrivate::Running
) {
197 if( ( d
->cposition
> 0 ) || ( d
->cposition
< d
->minimalPos
+ d
->overshoot
) ) {
199 scrollAnimation
->setEasingCurve( QEasingCurve::OutBounce
);
201 if (d
->cposition
> 0)
204 finalPosition
= -d
->widget
->size().height( ) + d
->scrollingWidget
->size().height();
206 resetAnimation( finalPosition
, 900 );
207 d
->bounceStatus
= KineticScrollingPrivate::Running
;
210 d
->bounceStatus
= KineticScrollingPrivate::Finished
;
211 scrollAnimation
->setEasingCurve( QEasingCurve::OutCirc
);
216 void KineticView::setVerticalScrollValue(int value
)
218 const int pos
= thresholdPosition( -value
);
219 d
->widget
->setPos(0, pos
);
221 if( ( pos
== d
->overshoot
) || ( pos
== d
->minimalPos
) )
225 int KineticView::thresholdPosition(int value
)
228 d
->minimalPos
= -d
->widget
->size().height() + d
->scrollingWidget
->size().height()
230 d
->minimalPos
= qMin(d
->overshoot
, d
->minimalPos
);
231 d
->maximumPos
= value
;
233 d
->cposition
= qBound(d
->minimalPos
, d
->maximumPos
, d
->overshoot
);
238 void KineticView::resetAnimation(int finalPosition
, int duration
)
240 if (scrollAnimation
->state() != QAbstractAnimation::Stopped
)
241 scrollAnimation
->stop();
242 d
->cposition
= finalPosition
;
243 QRectF tmpGeometry
= d
->widget
->geometry();
244 scrollAnimation
->setStartValue(tmpGeometry
);
245 tmpGeometry
.setY(d
->cposition
);
246 scrollAnimation
->setEndValue(tmpGeometry
);
247 scrollAnimation
->setDuration(duration
);
248 scrollAnimation
->start();
253 void KineticView::mousePressEvent(QGraphicsSceneMouseEvent
*event
)
255 if (scrollAnimation
->state() != QAbstractAnimation::Stopped
)
256 scrollAnimation
->stop();
259 d
->mousePressEvent(event
);
262 void KineticView::mouseMoveEvent(QGraphicsSceneMouseEvent
*event
)
264 d
->mouseMoveEvent(event
);
265 setVerticalScrollValue(-(d
->widget
->pos().y() - d
->normalMovement()));
268 void KineticView::mouseReleaseEvent(QGraphicsSceneMouseEvent
*event
)
271 if( scrollAnimation
->state() != QAbstractAnimation::Running
) {
272 d
->mouseReleaseEvent(event
);
274 const int finalPos
= thresholdPosition(d
->widget
->pos().y() - d
->kinMovement()*6);
275 resetAnimation( finalPos
, d
->duration()*8 );
279 void KineticView::wheelEvent(QGraphicsSceneWheelEvent
*event
)
282 d
->mousePressEvent(NULL
);
283 d
->wheelReleaseEvent(event
);
284 const int finalPos
= thresholdPosition(d
->widget
->pos().y() - d
->kinMovement()*6);
285 resetAnimation( finalPos
, 900 );
288 void KineticView::resizeEvent(QGraphicsSceneResizeEvent
*event
)
292 QGraphicsWidget::resizeEvent(event
);
295 bool KineticView::eventFilter(QObject
*watched
, QEvent
*event
)
301 if (watched
== d
->widget
&& event
->type() == QEvent::GraphicsSceneMove
) {
302 verticalScrollbar
->blockSignals(true);
303 verticalScrollbar
->setValue(d
->widget
->pos().y());
304 verticalScrollbar
->blockSignals(false);