From f224b7ee96b67c22402de3a9625d3e2756d9a815 Mon Sep 17 00:00:00 2001 From: Adriano Rezende Date: Thu, 19 Nov 2009 18:57:08 -0300 Subject: Shared: Added ScrollArea widget The ScrollArea can be used to display generic contents inside a kinetic container. Signed-off-by: Adriano Rezende --- shared/scrollarea.cpp | 280 ++++++++++++++++++++++++++++++++++++++++++++++++++ shared/scrollarea.h | 79 ++++++++++++++ 2 files changed, 359 insertions(+) create mode 100644 shared/scrollarea.cpp create mode 100644 shared/scrollarea.h diff --git a/shared/scrollarea.cpp b/shared/scrollarea.cpp new file mode 100644 index 0000000..3e26993 --- /dev/null +++ b/shared/scrollarea.cpp @@ -0,0 +1,280 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: openBossa - INdT (renato.chencarek@openbossa.org) +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** the openBossa stream from INdT (renato.chencarek@openbossa.org). +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "scrollarea.h" +#include "kineticscroll.h" + + +class ScrollAreaPrivate +{ +public: + ScrollAreaPrivate(ScrollArea *q); + + int offset; + int maximumOffset; + QGraphicsWidget *widget; + KineticScroll *kinetic; + + bool isDragging; + int mouseDownPos; + int moveConstant; + int clickConstant; + ScrollArea *q; + + QList ignoreList; + + void reconfigure(); + int smoothPos(int y); + bool isClickPossible(int y); + void sendClick(int x, int y); + void updateMaximumOffset(); +}; + + +ScrollAreaPrivate::ScrollAreaPrivate(ScrollArea *q) + : offset(0), + maximumOffset(0), + widget(0), + kinetic(0), + isDragging(false), + mouseDownPos(-1), + moveConstant(15), + clickConstant(25), + q(q) +{ + +} + +int ScrollAreaPrivate::smoothPos(int y) +{ + if (abs(mouseDownPos - y) <= moveConstant) + return y; + else if (mouseDownPos - y < 0) + return y - moveConstant; + else + return y + moveConstant; +} + +bool ScrollAreaPrivate::isClickPossible(int y) +{ + if (isDragging || mouseDownPos < 0) + return false; + else + return abs(y - mouseDownPos) <= clickConstant; +} + +void ScrollAreaPrivate::updateMaximumOffset() +{ + const int value = (!widget) ? 0 : + qMax(0, widget->size().height() - q->size().height()); + + if (value != maximumOffset) { + maximumOffset = value; + emit q->maximumOffsetChanged(); + } +} + +void ScrollAreaPrivate::reconfigure() +{ + if (widget) { + widget->resize(q->size().width(), widget->size().height()); + updateMaximumOffset(); + q->setOffset(offset); + } +} + +void ScrollAreaPrivate::sendClick(int x, int y) +{ + if (!q->scene()) + return; + + QGraphicsSceneMouseEvent *event; + + event = new QGraphicsSceneMouseEvent(QEvent::GraphicsSceneMousePress); + event->setButton(Qt::LeftButton); + event->setScenePos(QPointF(x, y)); + ignoreList << event; + QCoreApplication::postEvent(q->scene(), event); + + event = new QGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseRelease); + event->setButton(Qt::LeftButton); + event->setScenePos(QPointF(x, y)); + ignoreList << event; + QCoreApplication::postEvent(q->scene(), event); +} + + + +ScrollArea::ScrollArea(QGraphicsItem *parent) + : QGraphicsWidget(parent), + d(new ScrollAreaPrivate(this)) +{ + setFlag(QGraphicsItem::ItemHasNoContents); + setFlag(QGraphicsItem::ItemClipsChildrenToShape); + + d->kinetic = new KineticScroll(this); + connect(d->kinetic, SIGNAL(signalMoveOffset(int)), SLOT(kineticMove(int))); +} + +ScrollArea::~ScrollArea() +{ + delete d; +} + +QGraphicsWidget *ScrollArea::widget() const +{ + return d->widget; +} + +void ScrollArea::setWidget(QGraphicsWidget *widget) +{ + if (d->widget) { + d->widget->setParentItem(0); + d->widget->removeEventFilter(this); + d->widget = 0; + } + + if (widget) { + d->widget = widget; + d->widget->setParentItem(this); + d->widget->installEventFilter(this); + d->widget->setPos(0, 0); + d->widget->setFlag(QGraphicsItem::ItemStacksBehindParent); + + d->reconfigure(); + } +} + +int ScrollArea::offset() const +{ + return d->offset; +} + +void ScrollArea::setOffset(int offset) +{ + if (d->widget) { + const int value = qBound(0, offset, d->maximumOffset); + + if (value != d->offset) { + d->offset = value; + d->widget->setY(-value); + offsetChanged(); + } + } +} + +int ScrollArea::maximumOffset() const +{ + return d->maximumOffset; +} + +void ScrollArea::resizeEvent(QGraphicsSceneResizeEvent *event) +{ + QGraphicsWidget::resizeEvent(event); + d->reconfigure(); +} + +bool ScrollArea::eventFilter(QObject *object, QEvent *event) +{ + if (object == d->widget && event->type() == QEvent::GraphicsSceneResize) + d->reconfigure(); + + return false; +} + +void ScrollArea::mousePressEvent(QGraphicsSceneMouseEvent *e) +{ + if (d->ignoreList.contains(e)) { + d->ignoreList.removeOne(e); + e->ignore(); + return; + } + + int y = e->pos().y(); + d->mouseDownPos = y; + d->isDragging = !d->kinetic->mouseDown(y); +} + +void ScrollArea::stopKinetic() +{ + d->kinetic->kineticStop(); +} + +void ScrollArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) +{ + if (d->ignoreList.contains(e)) { + d->ignoreList.removeOne(e); + e->ignore(); + return; + } + + if (d->mouseDownPos >= 0) { + int y = e->pos().y(); + if (d->isClickPossible(y)) { + d->sendClick(e->scenePos().x(), e->scenePos().y()); + d->kinetic->mouseCancel(); + } else { + d->kinetic->mouseUp(d->smoothPos(y)); + } + } + + d->mouseDownPos = -1; +} + +void ScrollArea::mouseMoveEvent(QGraphicsSceneMouseEvent *e) +{ + if (d->mouseDownPos >= 0) { + int y = e->pos().y(); + if (!d->isClickPossible(y)) + d->isDragging = true; + + if (abs(d->mouseDownPos - y) > d->moveConstant) + d->kinetic->mouseMove(d->smoothPos(y)); + } +} + +bool ScrollArea::kineticMove(int value) +{ + int finalOffset = offset() - value; + + setOffset(finalOffset); + + if (value == 0 || finalOffset != offset()) { + d->kinetic->kineticStop(); + return false; + } + + return true; +} diff --git a/shared/scrollarea.h b/shared/scrollarea.h new file mode 100644 index 0000000..436c3a6 --- /dev/null +++ b/shared/scrollarea.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: openBossa - INdT (renato.chencarek@openbossa.org) +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** the openBossa stream from INdT (renato.chencarek@openbossa.org). +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SCROLLAREA_H +#define SCROLLAREA_H + +#include + +class KineticScroll; +class ScrollAreaPrivate; + + +class ScrollArea : public QGraphicsWidget +{ + Q_OBJECT + +public: + ScrollArea(QGraphicsItem *parent = 0); + ~ScrollArea(); + + QGraphicsWidget *widget() const; + void setWidget(QGraphicsWidget *widget); + + int offset() const; + void setOffset(int offset); + + int maximumOffset() const; + + void stopKinetic(); + +signals: + void offsetChanged(); + void maximumOffsetChanged(); + +protected slots: + bool kineticMove(int value); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + void resizeEvent(QGraphicsSceneResizeEvent *event); + + void mousePressEvent(QGraphicsSceneMouseEvent *e); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *e); + void mouseMoveEvent(QGraphicsSceneMouseEvent *e); + +private: + ScrollAreaPrivate *d; + friend class ScrollAreaPrivate; +}; + +#endif -- cgit v1.2.3