now the api is similar to what webkit offers and horizontal and vertical

scroll is done in pixels and in a single pass.                                          
we have 3 properties in widgets that wants to support scroll:
scrollPosition
viewportGeometry
constentsSize


svn path=/trunk/KDE/kdelibs/; revision=1032821
This commit is contained in:
Marco Martin 2009-10-08 16:04:56 +00:00
parent 2ea0319b74
commit 38884ccd1a
5 changed files with 175 additions and 185 deletions

View File

@ -27,6 +27,8 @@
#include <QGraphicsWidget>
#include <QPoint>
#include <kdebug.h>
#include "kineticscroll_p.h"
/* TODO:
@ -44,9 +46,20 @@ namespace Plasma
class KineticScrollingPrivate
{
public:
KineticScrollingPrivate(): timerID(0),
overshoot(20), bounceFlag(0), hasOvershoot(true),
friction(0.8)
enum Direction {
None,
Up,
Down,
Left,
Right
};
KineticScrollingPrivate()
: timerID(0),
overshoot(20),
bounceFlag(0),
hasOvershoot(true),
friction(0.8)
{
maximum = 100 + overshoot;
minimum = -overshoot;
@ -59,22 +72,48 @@ public:
void applyFriction()
{
qreal tmp(kinMovement.y());
tmp *= friction;
kinMovement.setY(tmp);
kinMovement *= friction;
}
void syncViewportRect()
{
contentsSize = parent->property("contentsSize").toSizeF();
viewportGeometry = parent->property("viewportGeometry").toRectF();
//TODO: overshoot and friction will have to be independent horizontal and vertical
overshoot = 20*(1.0 - viewportGeometry.height()/contentsSize.height());
}
bool canScroll(Direction direction, bool hasOvershoot = false) const
{
QPointF scrollPosition = -parent->property("scrollPosition").value<QPointF>();
int offset = (hasOvershoot?overshoot*2:0);
switch (direction) {
case Up:
return (scrollPosition.y() < offset);
case Down:
return (scrollPosition.y() + contentsSize.height() + offset >= viewportGeometry.bottom());
case Left:
return (scrollPosition.x() < offset);
case Right:
return (scrollPosition.x() + contentsSize.width() + offset >= viewportGeometry.right());
default:
return true;
}
}
unsigned int timeDelta;
qreal scrollVelocity;
QPointF kinMovement;
enum { None, Up, Down };
int timerID, overshoot, direction;
QPointF cposition;
char bounceFlag;
bool hasOvershoot;
QObject *parent;
QRectF geo;
QRectF viewportGeometry;
QSizeF contentsSize;
int maximum, minimum;
qreal friction;
@ -104,6 +143,8 @@ void KineticScrolling::duration()
void KineticScrolling::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
d->syncViewportRect();
d->cposition = -d->parent->property("scrollPosition").value<QPointF>();
doneOvershoot();
Q_UNUSED(event);
d->count();
@ -114,11 +155,12 @@ void KineticScrolling::mousePressEvent(QGraphicsSceneMouseEvent *event)
void KineticScrolling::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QPointF temp = event->lastPos().toPoint() - event->pos().toPoint();
if (!temp.isNull()) {
d->kinMovement += temp;
}
/* After */
setKineticScrollValue(d->kinMovement/4);
setKineticScrollValue(d->kinMovement);
}
void KineticScrolling::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
@ -127,13 +169,13 @@ void KineticScrolling::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
duration();
/* slow down a bit */
d->kinMovement /= 4;
d->kinMovement *= d->geo.height();
if (d->timeDelta > 600) {
if (d->kinMovement.y() > 0)
d->kinMovement.setY(6 * d->geo.height());
else
d->kinMovement.setY(-6 * d->geo.height());
if (d->kinMovement.y() > 0) {
d->kinMovement.setY(6);
} else {
d->kinMovement.setY(-6);
}
}
d->direction = KineticScrollingPrivate::None;
@ -143,16 +185,12 @@ void KineticScrolling::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
void KineticScrolling::wheelReleaseEvent(QGraphicsSceneWheelEvent *event)
{
doneOvershoot();
d->geo = d->parent->property("viewport").toRectF();
d->syncViewportRect();
if (d->direction == KineticScrollingPrivate::None) {
mousePressEvent(0);
duration();
/* scroll down is negative in pixels */
qreal temp = event->delta();
if (temp < 0)
temp = d->geo.height() * 30;
else
temp = d->geo.height() * -30;
int temp = -event->delta();
d->kinMovement.setY(kinMovement().y() + temp);
@ -168,40 +206,55 @@ void KineticScrolling::startAnimationTimer(int interval)
d->timerID = 0;
}
/* factor in friction X viewport/widget ratio */
if (d->geo.height() < 0.30)
d->friction = 0.85;
else
d->friction = 0.80;
d->syncViewportRect();
d->geo = d->parent->property("viewport").toRectF();
d->timerID = QObject::startTimer(interval);
}
void KineticScrolling::timerEvent(QTimerEvent *event)
{
Q_UNUSED(event);
d->cposition.setY(d->parent->property("verticalScrollValue").value<qreal>());
d->cposition = -d->parent->property("scrollPosition").value<QPointF>();
if (d->direction == KineticScrollingPrivate::None) {
if ((qAbs(d->kinMovement.y()) < 2)) {
if ((d->cposition.y() > 100) ||
(d->cposition.y() < 0)) {
if (d->cposition.y() < 0)
d->kinMovement.setY(1.0);
else
d->kinMovement.setY(-1.0);
d->parent->setProperty("verticalScrollValue", d->cposition.y()
+ d->kinMovement.y());
if (qAbs(d->kinMovement.y()) < 5.0 &&
qAbs(d->kinMovement.x()) < 5.0 ) {
d->kinMovement = QPoint(0,0);
if (d->canScroll(KineticScrollingPrivate::Down) && !d->canScroll(KineticScrollingPrivate::Up)) {
if (d->cposition.y() > 2) {
d->kinMovement.setY(-2);
}
} else if (d->canScroll(KineticScrollingPrivate::Up) && !d->canScroll(KineticScrollingPrivate::Down)) {
if (d->cposition.y() + d->contentsSize.height() < d->viewportGeometry.bottom()) {
d->kinMovement.setY(1.0);
}
}
if (d->canScroll(KineticScrollingPrivate::Right) && !d->canScroll(KineticScrollingPrivate::Left)) {
if (d->cposition.x() > 2) {
d->kinMovement.setX(-2);
}
} else if (d->canScroll(KineticScrollingPrivate::Left) && !d->canScroll(KineticScrollingPrivate::Right)) {
if (d->cposition.x() + d->contentsSize.width() < d->viewportGeometry.right()) {
d->kinMovement.setX(2);
}
}
if (!d->kinMovement.isNull()) {
d->parent->setProperty("scrollPosition", -(d->cposition
+ d->kinMovement));
return;
}
if (d->timerID) {
killTimer(d->timerID);
}
} else
} else {
d->applyFriction();
}
setKineticScrollValue(d->kinMovement);
@ -212,26 +265,41 @@ void KineticScrolling::timerEvent(QTimerEvent *event)
void KineticScrolling::setKineticScrollValue(QPointF value)
{
if (!(d->geo.height())) {
d->kinMovement.setY(0);
if (d->viewportGeometry.isEmpty()) {
d->kinMovement = QPoint();
return;
}
qreal movement = value.y();
qreal final;
QPointF scrollPosition = -d->parent->property("scrollPosition").value<QPointF>();
movement += d->cposition.y();
QPointF movement = d->cposition - value;
if (movement > d->maximum) {
d->kinMovement.setY(-(d->overshoot) * d->geo.height());
} else if (movement < d->minimum) {
d->kinMovement.setY(d->overshoot * d->geo.height());
} else {
final = qBound((qreal)d->minimum, movement, (qreal)d->maximum);
d->parent->setProperty("verticalScrollValue", final);
if (d->kinMovement.y() < 0 && !d->canScroll(KineticScrollingPrivate::Up, true)) {
if (d->canScroll(KineticScrollingPrivate::Down, false)) {
d->kinMovement.setY(d->overshoot/2);
}
movement.setY(scrollPosition.y());
} else if (d->kinMovement.y() > 0 && !d->canScroll(KineticScrollingPrivate::Down, true)) {
if (d->canScroll(KineticScrollingPrivate::Up, false)) {
d->kinMovement.setY(-d->overshoot/2);
}
movement.setY(scrollPosition.y());
}
/* TODO: use 'ScrollWidget::HorizontalScrollValue */
if (d->kinMovement.x() < 0 && !d->canScroll(KineticScrollingPrivate::Left, true)) {
if (d->canScroll(KineticScrollingPrivate::Right, false)) {
d->kinMovement.setX(d->overshoot/2);
}
movement.setX(scrollPosition.x());
} else if (d->kinMovement.x() > 0 && !d->canScroll(KineticScrollingPrivate::Right, true)) {
if (d->canScroll(KineticScrollingPrivate::Left, false)) {
d->kinMovement.setX(-d->overshoot/2);
}
movement.setX(scrollPosition.x());
}
d->parent->setProperty("scrollPosition", -movement);
}

View File

@ -343,58 +343,29 @@ void ScrollWidget::ensureItemVisible(QGraphicsItem *item)
QTimer::singleShot(0, this, SLOT(makeRectVisible()));
}
qreal ScrollWidget::horizontalScrollValue() const
{
if (!d->widget) {
return 0;
}
return (d->widget->x()*100)/(d->widget->size().width() -
d->scrollingWidget->size().width());
}
void ScrollWidget::setHorizontalScrollValue(qreal value)
{
if (!d->widget) {
return;
}
d->widget->setPos((value * (d->widget->size().width() -
d->scrollingWidget->size().width()))/100,
d->widget->pos().y());
}
qreal ScrollWidget::verticalScrollValue() const
{
if (!d->widget) {
return 0;
}
return (-1 * d->widget->y()*100)/(d->widget->size().height() -
d->scrollingWidget->size().height());
}
void ScrollWidget::setVerticalScrollValue(qreal value)
{
if (!d->widget) {
return;
}
d->widget->setPos(d->widget->pos().x(),
(-1 * value * (d->widget->size().height() -
d->scrollingWidget->size().height()))/100);
}
QRectF ScrollWidget::viewport() const
QRectF ScrollWidget::viewportGeometry() const
{
QRectF result;
if (!d->widget) {
return result;
}
result = d->scrollingWidget->boundingRect();
result.setHeight(result.height()/d->widget->boundingRect().height());
result.setWidth(result.width()/d->widget->boundingRect().width());
return result;
return d->scrollingWidget->boundingRect();
}
QSizeF ScrollWidget::contentsSize() const
{
return d->widget->size();
}
void ScrollWidget::setScrollPosition(const QPointF &position)
{
d->widget->setPos(-position);
}
QPointF ScrollWidget::scrollPosition() const
{
return -d->widget->pos();
}
void ScrollWidget::setStyleSheet(const QString &styleSheet)

View File

@ -45,9 +45,9 @@ class PLASMA_EXPORT ScrollWidget : public QGraphicsWidget
Q_PROPERTY(QGraphicsWidget *widget READ widget WRITE setWidget)
Q_PROPERTY(Qt::ScrollBarPolicy horizontalScrollBarPolicy READ horizontalScrollBarPolicy WRITE setHorizontalScrollBarPolicy)
Q_PROPERTY(Qt::ScrollBarPolicy verticalScrollBarPolicy READ verticalScrollBarPolicy WRITE setVerticalScrollBarPolicy)
Q_PROPERTY(qreal horizontalScrollValue READ horizontalScrollValue WRITE setHorizontalScrollValue)
Q_PROPERTY(qreal verticalScrollValue READ verticalScrollValue WRITE setVerticalScrollValue)
Q_PROPERTY(QRectF viewport READ viewport)
Q_PROPERTY(QPointF scrollPosition READ scrollPosition WRITE setScrollPosition)
Q_PROPERTY(QSizeF contentsSize READ contentsSize)
Q_PROPERTY(QRectF viewportGeometry READ viewportGeometry)
Q_PROPERTY(QString styleSheet READ styleSheet WRITE setStyleSheet)
public:
@ -114,35 +114,31 @@ public:
*/
void ensureItemVisible(QGraphicsItem *item);
/**
* The horizontal scroll value, between 0 and 100
/**
* The geometry of the viewport.
* @since 4.4
*/
qreal horizontalScrollValue() const;
QRectF viewportGeometry() const;
/**
* Set the horizontal scroll value, between 0 and 100
* @return the size of the internal widget
* @since 4.4
*/
void setHorizontalScrollValue(qreal value);
QSizeF contentsSize() const;
/**
* The horizontal scroll value, between 0 and 100
* Sets the position of the internal widget relative to this widget
* @since 4.4
*/
qreal verticalScrollValue() const;
void setScrollPosition(const QPointF &position);
/**
* Set the horizontal scroll value, between 0 and 100
* @return the position of the internal widget relative to this widget
* @since 4.4
*/
void setVerticalScrollValue(qreal value);
QPointF scrollPosition() const;
/**
* The scrollable widget size.
* @since 4.4
*/
QRectF viewport() const;
/**
* Sets the stylesheet used to control the visual display of this ScrollWidget

View File

@ -134,82 +134,41 @@ QRectF WebView::geometry() const
return QGraphicsWidget::geometry();
}
qreal WebView::horizontalScrollValue() const
QSizeF WebView::contentsSize() const
{
if (!d->page) {
return 0;
return QSizeF();
} else {
return d->page->mainFrame()->contentsSize();
}
const qreal value = d->page->mainFrame()->contentsSize().width() -
d->page->mainFrame()->geometry().width();
if(!value)
return 0;
return ((d->page->mainFrame()->geometry().x()*100)/value);
}
void WebView::setHorizontalScrollValue(qreal value)
void WebView::setScrollPosition(const QPointF &position)
{
if (!d->page) {
return;
} else {
d->page->mainFrame()->setScrollPosition(position.toPoint());
}
qreal xValue = value * (d->page->mainFrame()->contentsSize().width() -
d->page->mainFrame()->geometry().width())/100;
if (!xValue)
xValue = 0;
d->page->mainFrame()->setScrollBarValue(Qt::Horizontal, xValue);
}
qreal WebView::verticalScrollValue() const
QPointF WebView::scrollPosition() const
{
if (!d->page) {
return 0;
return QPointF();
} else {
return d->page->mainFrame()->scrollPosition();
}
const qreal value = d->page->mainFrame()->contentsSize().height() -
d->page->mainFrame()->geometry().height();
if (!value)
return 0;
return ((d->page->mainFrame()->scrollPosition().y()*100)/value);
}
void WebView::setVerticalScrollValue(qreal value)
{
if (!d->page) {
return;
}
qreal yValue = value *
(d->page->mainFrame()->contentsSize().height() -
d->page->mainFrame()->geometry().height())/100;
if (!yValue)
yValue = 0;
const QPoint point(d->page->mainFrame()->scrollPosition().x(), yValue);
d->page->mainFrame()->setScrollPosition(point);
}
QRectF WebView::viewport() const
QRectF WebView::viewportGeometry() const
{
QRectF result;
if (!d->page) {
return result;
} else {
return d->page->mainFrame()->geometry();
}
result.setWidth(d->page->mainFrame()->contentsSize().width());
result.setHeight(d->page->mainFrame()->contentsSize().height());
result.setHeight(d->page->mainFrame()->geometry().height()/result.height());
result.setWidth(d->page->mainFrame()->geometry().width()/result.width());
return result;
}

View File

@ -50,9 +50,9 @@ class PLASMA_EXPORT WebView : public QGraphicsWidget
Q_PROPERTY(KUrl url READ url WRITE setUrl)
Q_PROPERTY(QString html READ html WRITE setHtml)
Q_PROPERTY(bool dragToScroll READ dragToScroll WRITE setDragToScroll)
Q_PROPERTY(int horizontalScrollValue READ horizontalScrollValue WRITE setHorizontalScrollValue)
Q_PROPERTY(int verticalScrollValue READ verticalScrollValue WRITE setVerticalScrollValue)
Q_PROPERTY(QRectF viewport READ viewport)
Q_PROPERTY(QPointF scrollPosition READ scrollPosition WRITE setScrollPosition)
Q_PROPERTY(QSizeF contentsSize READ contentsSize)
Q_PROPERTY(QRectF viewportGeometry READ viewportGeometry)
public:
explicit WebView(QGraphicsItem *parent = 0);
@ -97,35 +97,31 @@ class PLASMA_EXPORT WebView : public QGraphicsWidget
* Reimplementation
*/
QRectF geometry() const;
/**
* The horizontal scroll value, between 0 and 100
* @since 4.4
*/
qreal horizontalScrollValue() const;
/**
* Set the horizontal scroll value, between 0 and 100
* @return the size of the internal widget
* @since 4.4
*/
void setHorizontalScrollValue(qreal value);
QSizeF contentsSize() const;
/**
* The horizontal scroll value, between 0 and 100
* Sets the position of the webpage relative to this widget
* @since 4.4
*/
qreal verticalScrollValue() const;
void setScrollPosition(const QPointF &position);
/**
* Set the horizontal scroll value, between 0 and 100
* @return the position of the webpage relative to this widget
* @since 4.4
*/
void setVerticalScrollValue(qreal value);
QPointF scrollPosition() const;
/**
* The scrollable widget size.
* The geometry of the area that actually displays the web page
* @since 4.4
*/
QRectF viewport() const;
QRectF viewportGeometry() const;
/**
* Sets the page to use in this item. The owner of the webpage remains,
* however if this WebView object is the owner of the current page,