From ff578a8af4400b7e487c97248502773bcc44dc4c Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Tue, 3 Mar 2009 17:31:54 +0000 Subject: [PATCH] a widget that allows the contents to scroll when content is bigger than the widget itself by adding scrollbars svn path=/trunk/KDE/kdelibs/; revision=934731 --- CMakeLists.txt | 2 + widgets/scrollwidget.cpp | 280 +++++++++++++++++++++++++++++++++++++++ widgets/scrollwidget.h | 131 ++++++++++++++++++ 3 files changed, 413 insertions(+) create mode 100644 widgets/scrollwidget.cpp create mode 100644 widgets/scrollwidget.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e0c11f1f6..47c19e178 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,6 +116,7 @@ set(plasma_LIB_SRCS widgets/spinbox.cpp widgets/toolbutton.cpp widgets/busywidget.cpp + widgets/scrollwidget.cpp widgets/svgwidget.cpp widgets/tabbar.cpp widgets/treeview.cpp @@ -251,6 +252,7 @@ install(FILES widgets/spinbox.h widgets/busywidget.h widgets/svgwidget.h + widgets/scrollwidget.h widgets/tabbar.h widgets/treeview.h widgets/textedit.h diff --git a/widgets/scrollwidget.cpp b/widgets/scrollwidget.cpp new file mode 100644 index 000000000..bae0e66ea --- /dev/null +++ b/widgets/scrollwidget.cpp @@ -0,0 +1,280 @@ +/* + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "scrollwidget.h" + +//Qt +#include +#include +#include +#include + +//KDE +#include +#include + +//Plasma +#include + +namespace Plasma +{ + +class ScrollWidgetPrivate +{ +public: + ScrollWidgetPrivate(ScrollWidget *parent) + : q(parent), + widget(0), + dragging(false) + { + } + + ~ScrollWidgetPrivate() + { + } + + void adjustScrollbars() + { + verticalScrollBar->nativeWidget()->setMaximum(qMax(0, int((widget->size().height() - scrollingWidget->size().height())/10))); + + if (verticalScrollBarPolicy == Qt::ScrollBarAlwaysOff || + verticalScrollBar->nativeWidget()->maximum() == 0) { + if (layout->itemAt(2) == verticalScrollBar) { + layout->removeAt(2); + } else if (layout->itemAt(1) == verticalScrollBar) { + layout->removeAt(1); + } + verticalScrollBar->hide(); + } else if (!verticalScrollBar->isVisible()) { + layout->addItem(verticalScrollBar, 0, 1); + verticalScrollBar->show(); + } + + + horizontalScrollBar->nativeWidget()->setMaximum(qMax(0, int((widget->size().width() - scrollingWidget->size().width())/10))); + + if (horizontalScrollBarPolicy == Qt::ScrollBarAlwaysOff || + horizontalScrollBar->nativeWidget()->maximum() == 0) { + if (layout->itemAt(2) == horizontalScrollBar) { + layout->removeAt(2); + } else if (layout->itemAt(1) == horizontalScrollBar) { + layout->removeAt(1); + } + horizontalScrollBar->hide(); + } else if (!horizontalScrollBar->isVisible()) { + layout->addItem(horizontalScrollBar, 1, 0); + horizontalScrollBar->show(); + } + } + + void verticalScroll(int value) + { + if (!dragging) { + widget->setPos(QPoint(0, -value*10)); + } + } + + void horizontalScroll(int value) + { + if (!dragging) { + widget->setPos(QPoint(-value*10, 0)); + } + } + + void adjustClipping() + { + const bool clip = widget->size().width() > scrollingWidget->size().width() || + widget->size().height() > scrollingWidget->size().height(); + + scrollingWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, clip); + } + + ScrollWidget *q; + QGraphicsWidget *scrollingWidget; + QGraphicsWidget *widget; + QGraphicsGridLayout *layout; + ScrollBar *verticalScrollBar; + Qt::ScrollBarPolicy verticalScrollBarPolicy; + ScrollBar *horizontalScrollBar; + Qt::ScrollBarPolicy horizontalScrollBarPolicy; + QString styleSheet; + bool dragging; +}; + + +ScrollWidget::ScrollWidget(QGraphicsWidget *parent) + : QGraphicsWidget(parent), + d(new ScrollWidgetPrivate(this)) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + d->layout = new QGraphicsGridLayout(this); + d->scrollingWidget = new QGraphicsWidget(this); + d->layout->addItem(d->scrollingWidget, 0, 0); + + d->verticalScrollBarPolicy = Qt::ScrollBarAsNeeded; + d->verticalScrollBar = new Plasma::ScrollBar(this); + d->layout->addItem(d->verticalScrollBar, 0, 1); + d->verticalScrollBar->nativeWidget()->setMinimum(0); + d->verticalScrollBar->nativeWidget()->setMaximum(100); + connect(d->verticalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(verticalScroll(int))); + + d->horizontalScrollBarPolicy = Qt::ScrollBarAsNeeded; + d->horizontalScrollBar = new Plasma::ScrollBar(this); + d->horizontalScrollBar->setOrientation(Qt::Horizontal); + d->layout->addItem(d->horizontalScrollBar, 1, 0); + d->horizontalScrollBar->nativeWidget()->setMinimum(0); + d->horizontalScrollBar->nativeWidget()->setMaximum(100); + connect(d->horizontalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(horizontalScroll(int))); +} + +ScrollWidget::~ScrollWidget() +{ + delete d; +} + + +void ScrollWidget::setWidget(QGraphicsWidget *widget) +{ + if (d->widget && d->widget != widget) { + d->widget->removeEventFilter(this); + delete d->widget; + } + + d->widget = widget; + widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + widget->setParentItem(d->scrollingWidget); + widget->setPos(QPoint(0,0)); + widget->installEventFilter(this); + d->adjustScrollbars(); +} + +QGraphicsWidget *ScrollWidget::widget() const +{ + return d->widget; +} + + +void ScrollWidget::setHorizontalScrollbarPolicy(const Qt::ScrollBarPolicy policy) +{ + d->horizontalScrollBarPolicy = policy; +} + + +Qt::ScrollBarPolicy ScrollWidget::horizontalScrollbarPolicy() const +{ + return d->horizontalScrollBarPolicy; +} + + +void ScrollWidget::setVerticalScrollbarPolicy(const Qt::ScrollBarPolicy policy) +{ + d->verticalScrollBarPolicy = policy; +} + +Qt::ScrollBarPolicy ScrollWidget::verticalScrollbarPolicy() const +{ + return d->verticalScrollBarPolicy; +} + + +void ScrollWidget::setStyleSheet(const QString &styleSheet) +{ + d->styleSheet = styleSheet; + d->verticalScrollBar->setStyleSheet(styleSheet); + d->horizontalScrollBar->setStyleSheet(styleSheet); +} + +QString ScrollWidget::styleSheet() const +{ + return d->styleSheet; +} + +QWidget *ScrollWidget::nativeWidget() const +{ + return 0; +} + + +void ScrollWidget::resizeEvent(QGraphicsSceneResizeEvent *event) +{ + if (!d->widget) { + return; + } + + d->widget->resize(d->scrollingWidget->size()); + + d->adjustScrollbars(); + + d->adjustClipping(); + + QGraphicsWidget::resizeEvent(event); +} + +void ScrollWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + if (!d->widget) { + return; + } + + QPointF deltaPos = event->pos() - event->lastPos(); + + d->widget->setPos(qBound(-d->widget->size().width()+d->scrollingWidget->size().width(), d->widget->pos().x()+deltaPos.x(), (qreal)0), + qBound(-d->widget->size().height()+d->scrollingWidget->size().height(), d->widget->pos().y()+deltaPos.y(), (qreal)0)); + + d->dragging = true; + d->horizontalScrollBar->setValue(-d->widget->pos().x()/10); + d->verticalScrollBar->setValue(-d->widget->pos().y()/10); + d->dragging = false; + + QGraphicsWidget::mouseMoveEvent(event); +} + +void ScrollWidget::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + event->accept(); +} + +void ScrollWidget::wheelEvent(QGraphicsSceneWheelEvent *event) +{ + if (event->delta() < 0) { + d->verticalScrollBar->setValue(d->verticalScrollBar->value()+10); + } else { + d->verticalScrollBar->setValue(d->verticalScrollBar->value()-10); + } + QGraphicsWidget::wheelEvent(event); +} + +bool ScrollWidget::eventFilter(QObject *watched, QEvent *event) +{ + if (!d->widget) { + return false; + } + + if (watched == d->widget && event->type() == QEvent::GraphicsSceneResize) { + d->adjustScrollbars(); + d->adjustClipping(); + } + + return false; +} + +} // namespace Plasma + +#include + diff --git a/widgets/scrollwidget.h b/widgets/scrollwidget.h new file mode 100644 index 000000000..c6b9eb62e --- /dev/null +++ b/widgets/scrollwidget.h @@ -0,0 +1,131 @@ +/* + * Copyright 2009 Marco Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef PLASMA_SCROLLWIDGET_H +#define PLASMA_SCROLLWIDGET_H + +#include + +#include + + +namespace Plasma +{ + +class ScrollWidgetPrivate; + +/** + * @class ScrollWidget plasma/widgets/ScrollWidget.h + * + * @short A container of widgets that can have scrollbars + * + * A container of widgets that can have horizontal and vertical scrollbars if the content is bigger than the widget itself + */ +class PLASMA_EXPORT ScrollWidget : public QGraphicsWidget +{ + Q_OBJECT + 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(QString styleSheet READ styleSheet WRITE setStyleSheet) + +public: + + /** + * Constructs a new ScrollWidget + * + * @arg parent the parent of this widget + */ + explicit ScrollWidget(QGraphicsWidget *parent = 0); + ~ScrollWidget(); + + /** + * Sets the widget this ScrollWidget will contain + * ownership is transferred to this scrollwidget, + * if an old one was already in, it will be deleted + * + * @arg widget the new main sub widget + */ + void setWidget(QGraphicsWidget *widget); + + /** + * @return the main widget + */ + QGraphicsWidget *widget() const; + + /** + * Sets the horizontal scrollbar policy + * + * @arg policy desired policy + */ + void setHorizontalScrollbarPolicy(const Qt::ScrollBarPolicy policy); + + /** + * @return the horizontal scrollbar policy + */ + Qt::ScrollBarPolicy horizontalScrollbarPolicy() const; + + /** + * Sets the vertical scrollbar policy + * + * @arg policy desired policy + */ + void setVerticalScrollbarPolicy(const Qt::ScrollBarPolicy policy); + + /** + * @return the vertical scrollbar policy + */ + Qt::ScrollBarPolicy verticalScrollbarPolicy() const; + + /** + * Sets the stylesheet used to control the visual display of this ScrollWidget + * + * @arg stylesheet a CSS string + */ + void setStyleSheet(const QString &stylesheet); + + /** + * @return the stylesheet currently used with this widget + */ + QString styleSheet() const; + + /** + * @return the native widget wrapped by this ScrollWidget + */ + QWidget *nativeWidget() const; + +protected: + + void resizeEvent(QGraphicsSceneResizeEvent *event); + + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void wheelEvent(QGraphicsSceneWheelEvent *event); + bool eventFilter(QObject *watched, QEvent *event); + +private: + ScrollWidgetPrivate * const d; + + Q_PRIVATE_SLOT(d, void verticalScroll(int value)) + Q_PRIVATE_SLOT(d, void horizontalScroll(int value)) +}; + +} // namespace Plasma + +#endif // multiple inclusion guard