/* * 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" #include //Qt #include #include #include #include #include #include #include #include #include #include #include #include //KDE #include #include #include #include #include //Plasma #include #include #include #include #include #include #include static const qreal MaxVelocity = 2000; // time it takes the widget to flick back to its // bounds when overshot static const qreal FixupDuration = 600; namespace Plasma { class ScrollWidgetPrivate { public: ScrollWidgetPrivate(ScrollWidget *parent) : q(parent), topBorder(0), bottomBorder(0), leftBorder(0), rightBorder(0), overflowBordersVisible(true) { } void commonConstructor() { q->setFocusPolicy(Qt::StrongFocus); q->setFiltersChildEvents(true); layout = new QGraphicsGridLayout(q); q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); layout->setContentsMargins(0, 0, 0, 0); scrollingWidget = new QGraphicsWidget(q); scrollingWidget->setFlag(QGraphicsItem::ItemHasNoContents); scrollingWidget->installEventFilter(q); layout->addItem(scrollingWidget, 0, 0); borderSvg = new Plasma::Svg(q); borderSvg->setImagePath("widgets/scrollwidget"); wheelTimer = new QTimer(q); wheelTimer->setSingleShot(true); verticalScrollBarPolicy = Qt::ScrollBarAsNeeded; verticalScrollBar = new Plasma::ScrollBar(q); verticalScrollBar->setFocusPolicy(Qt::NoFocus); layout->addItem(verticalScrollBar, 0, 1); verticalScrollBar->nativeWidget()->setMinimum(0); verticalScrollBar->nativeWidget()->setMaximum(100); QObject::connect(verticalScrollBar, SIGNAL(valueChanged(int)), q, SLOT(verticalScroll(int))); horizontalScrollBarPolicy = Qt::ScrollBarAsNeeded; horizontalScrollBar = new Plasma::ScrollBar(q); verticalScrollBar->setFocusPolicy(Qt::NoFocus); horizontalScrollBar->setOrientation(Qt::Horizontal); layout->addItem(horizontalScrollBar, 1, 0); horizontalScrollBar->nativeWidget()->setMinimum(0); horizontalScrollBar->nativeWidget()->setMaximum(100); QObject::connect(horizontalScrollBar, SIGNAL(valueChanged(int)), q, SLOT(horizontalScroll(int))); layout->setColumnSpacing(0, 0); layout->setColumnSpacing(1, 0); layout->setRowSpacing(0, 0); layout->setRowSpacing(1, 0); flickAnimationX = 0; flickAnimationY = 0; fixupAnimation.groupX = 0; fixupAnimation.startX = 0; fixupAnimation.endX = 0; fixupAnimation.groupY = 0; fixupAnimation.startY = 0; fixupAnimation.endY = 0; fixupAnimation.snapX = 0; fixupAnimation.snapY = 0; directMoveAnimation = 0; hasOvershoot = true; alignment = (Qt::AlignLeft | Qt::AlignTop); } void adjustScrollbars() { if (!widget) { return; } const bool verticalVisible = widget.data()->size().height() > q->size().height(); const bool horizontalVisible = widget.data()->size().width() > q->size().width(); verticalScrollBar->nativeWidget()->setMaximum(qMax(0, int((widget.data()->size().height() - scrollingWidget->size().height())/10))); verticalScrollBar->nativeWidget()->setPageStep(int(scrollingWidget->size().height())/10); if (verticalScrollBarPolicy == Qt::ScrollBarAlwaysOff || !verticalVisible) { if (layout->count() > 2 && layout->itemAt(2) == verticalScrollBar) { layout->removeAt(2); } else if (layout->count() > 1 && 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.data()->size().width() - scrollingWidget->size().width())/10))); horizontalScrollBar->nativeWidget()->setPageStep(int(scrollingWidget->size().width())/10); if (horizontalScrollBarPolicy == Qt::ScrollBarAlwaysOff || !horizontalVisible) { if (layout->count() > 2 && layout->itemAt(2) == horizontalScrollBar) { layout->removeAt(2); } else if (layout->count() > 1 && layout->itemAt(1) == horizontalScrollBar) { layout->removeAt(1); } horizontalScrollBar->hide(); } else if (!horizontalScrollBar->isVisible()) { layout->addItem(horizontalScrollBar, 1, 0); horizontalScrollBar->show(); } if (widget && !topBorder && verticalVisible) { topBorder = new Plasma::SvgWidget(q); topBorder->setSvg(borderSvg); topBorder->setElementID("border-top"); topBorder->setZValue(900); topBorder->resize(topBorder->effectiveSizeHint(Qt::PreferredSize)); topBorder->setVisible(overflowBordersVisible); bottomBorder = new Plasma::SvgWidget(q); bottomBorder->setSvg(borderSvg); bottomBorder->setElementID("border-bottom"); bottomBorder->setZValue(900); bottomBorder->resize(bottomBorder->effectiveSizeHint(Qt::PreferredSize)); bottomBorder->setVisible(overflowBordersVisible); } else if (topBorder && widget && !verticalVisible) { //FIXME: in some cases topBorder->deleteLater() is deleteNever(), why? topBorder->hide(); bottomBorder->hide(); topBorder->deleteLater(); bottomBorder->deleteLater(); topBorder = 0; bottomBorder = 0; } if (widget && !leftBorder && horizontalVisible) { leftBorder = new Plasma::SvgWidget(q); leftBorder->setSvg(borderSvg); leftBorder->setElementID("border-left"); leftBorder->setZValue(900); leftBorder->resize(leftBorder->effectiveSizeHint(Qt::PreferredSize)); leftBorder->setVisible(overflowBordersVisible); rightBorder = new Plasma::SvgWidget(q); rightBorder->setSvg(borderSvg); rightBorder->setElementID("border-right"); rightBorder->setZValue(900); rightBorder->resize(rightBorder->effectiveSizeHint(Qt::PreferredSize)); rightBorder->setVisible(overflowBordersVisible); } else if (leftBorder && widget && !horizontalVisible) { leftBorder->hide(); rightBorder->hide(); leftBorder->deleteLater(); rightBorder->deleteLater(); leftBorder = 0; rightBorder = 0; } layout->activate(); if (topBorder) { topBorder->resize(q->size().width(), topBorder->size().height()); bottomBorder->resize(q->size().width(), bottomBorder->size().height()); bottomBorder->setPos(0, q->size().height() - topBorder->size().height()); } if (leftBorder) { leftBorder->resize(leftBorder->size().width(), q->size().height()); rightBorder->resize(rightBorder->size().width(), q->size().height()); rightBorder->setPos(q->size().width() - rightBorder->size().width(), 0); } QSizeF widgetSize = widget.data()->size(); if (widget.data()->sizePolicy().expandingDirections() & Qt::Horizontal) { //keep a 1 pixel border widgetSize.setWidth(scrollingWidget->size().width()); } if (widget.data()->sizePolicy().expandingDirections() & Qt::Vertical) { widgetSize.setHeight(scrollingWidget->size().height()); } widget.data()->resize(widgetSize); adjustClipping(); } void verticalScroll(int value) { if (!widget) { return; } widget.data()->setPos(QPoint(widget.data()->pos().x(), -value*10)); } void horizontalScroll(int value) { if (!widget) { return; } widget.data()->setPos(QPoint(-value*10, widget.data()->pos().y())); } void adjustClipping() { if (!widget) { return; } const bool clip = widget.data()->size().width() > scrollingWidget->size().width() || widget.data()->size().height() > scrollingWidget->size().height(); scrollingWidget->setFlag(QGraphicsItem::ItemClipsChildrenToShape, clip); } qreal overShootDistance(qreal velocity, qreal size) const { if (MaxVelocity <= 0) return 0.0; velocity = qAbs(velocity); if (velocity > MaxVelocity) velocity = MaxVelocity; qreal dist = size / 4 * velocity / MaxVelocity; return dist; } void animateMoveTo(const QPointF &pos) { qreal duration = 800; QPointF start = q->scrollPosition(); QSizeF threshold = q->viewportGeometry().size(); QPointF diff = pos - start; //reduce if it's within the viewport if (qAbs(diff.x()) < threshold.width() || qAbs(diff.y()) < threshold.height()) duration /= 2; fixupAnimation.groupX->stop(); fixupAnimation.groupY->stop(); fixupAnimation.snapX->stop(); fixupAnimation.snapY->stop(); directMoveAnimation->setStartValue(start); directMoveAnimation->setEndValue(pos); directMoveAnimation->setDuration(duration); directMoveAnimation->start(); } void flick(QPropertyAnimation *anim, qreal velocity, qreal val, qreal minExtent, qreal maxExtent, qreal size) { qreal deceleration = 500; qreal maxDistance = -1; qreal target = 0; // -ve velocity means list is moving up if (velocity > 0) { if (val < minExtent) maxDistance = qAbs(minExtent - val + (hasOvershoot ? overShootDistance(velocity,size) : 0)); target = minExtent; deceleration = -deceleration; } else { if (val > maxExtent) maxDistance = qAbs(maxExtent - val) + (hasOvershoot ? overShootDistance(velocity,size) : 0); target = maxExtent; } if (maxDistance > 0) { qreal v = velocity; if (MaxVelocity != -1 && MaxVelocity < qAbs(v)) { if (v < 0) v = -MaxVelocity; else v = MaxVelocity; } qreal duration = qAbs(v / deceleration); qreal diffY = v * duration + (0.5 * deceleration * duration * duration); qreal startY = val; qreal endY = startY + diffY; if (velocity > 0) { if (endY > target) endY = startY + maxDistance; } else { if (endY < target) endY = startY - maxDistance; } duration = qAbs((endY-startY)/ (-v/2)); #ifndef NDEBUG qDebug() <<"XXX velocity = "<delta()/3; //ifthe widget can scroll in a single axis and the wheel is the other one, scroll the other one Qt::Orientation orientation = event->orientation(); if (orientation == Qt::Vertical) { if (!canYFlick() && canXFlick()) { end += QPointF(step, 0); } else if (canYFlick()) { end += QPointF(0, step); } else { return; } } else { if (canYFlick() && !canXFlick()) { end += QPointF(0, step); } else if (canXFlick()) { end += QPointF(step, 0); } else { return; } } fixupAnimation.groupX->stop(); fixupAnimation.groupY->stop(); fixupAnimation.snapX->stop(); fixupAnimation.snapY->stop(); directMoveAnimation->setStartValue(start); directMoveAnimation->setEndValue(end); directMoveAnimation->setDuration(200); directMoveAnimation->start(); wheelTimer->start(50); } qreal minXExtent() const { if (alignment & Qt::AlignLeft) { return 0; } qreal vWidth = q->viewportGeometry().width(); qreal cWidth = q->contentsSize().width(); if (cWidth < vWidth) { if (alignment & Qt::AlignRight) { return vWidth - cWidth; } else if (alignment & Qt::AlignHCenter) { return vWidth / 2 - cWidth / 2; } } return 0; } qreal maxXExtent() const { return q->viewportGeometry().width() - q->contentsSize().width(); } qreal minYExtent() const { if (alignment & Qt::AlignTop) { return 0; } qreal vHeight = q->viewportGeometry().height(); qreal cHeight = q->contentsSize().height(); if (cHeight < vHeight) { if (alignment & Qt::AlignBottom) { return vHeight - cHeight; } else if (alignment & Qt::AlignVCenter) { return vHeight / 2 - cHeight / 2; } } return 0; } qreal maxYExtent() const { return q->viewportGeometry().height() - q->contentsSize().height(); } bool canXFlick() const { // make the thing feel quite "fixed" don't permit to flick when the contents size is less than the viewport return q->contentsSize().width() > q->viewportGeometry().width(); } bool canYFlick() const { return q->contentsSize().height() > q->viewportGeometry().height(); } void createFlickAnimations() { if (widget.data()) { const QByteArray xProp("x"); const QByteArray yProp("y"); flickAnimationX = new QPropertyAnimation(widget.data(), xProp, widget.data()); flickAnimationY = new QPropertyAnimation(widget.data(), yProp, widget.data()); QObject::connect(flickAnimationX, SIGNAL(finished()), q, SLOT(fixupX())); QObject::connect(flickAnimationY, SIGNAL(finished()), q, SLOT(fixupY())); QObject::connect(flickAnimationX, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), q, SIGNAL(scrollStateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); QObject::connect(flickAnimationY, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), q, SIGNAL(scrollStateChanged(QAbstractAnimation::State, QAbstractAnimation::State))); flickAnimationX->setEasingCurve(QEasingCurve::OutCirc); flickAnimationY->setEasingCurve(QEasingCurve::OutCirc); fixupAnimation.groupX = new QSequentialAnimationGroup(widget.data()); fixupAnimation.groupY = new QSequentialAnimationGroup(widget.data()); fixupAnimation.startX = new QPropertyAnimation(widget.data(), xProp, widget.data()); fixupAnimation.startY = new QPropertyAnimation(widget.data(), yProp, widget.data()); fixupAnimation.endX = new QPropertyAnimation(widget.data(), xProp, widget.data()); fixupAnimation.endY = new QPropertyAnimation(widget.data(), yProp, widget.data()); fixupAnimation.groupX->addAnimation(fixupAnimation.startX); fixupAnimation.groupY->addAnimation(fixupAnimation.startY); fixupAnimation.groupX->addAnimation(fixupAnimation.endX); fixupAnimation.groupY->addAnimation(fixupAnimation.endY); fixupAnimation.startX->setEasingCurve(QEasingCurve::InQuad); fixupAnimation.endX->setEasingCurve(QEasingCurve::OutQuint); fixupAnimation.startY->setEasingCurve(QEasingCurve::InQuad); fixupAnimation.endY->setEasingCurve(QEasingCurve::OutQuint); fixupAnimation.snapX = new QPropertyAnimation(widget.data(), xProp, widget.data()); fixupAnimation.snapY = new QPropertyAnimation(widget.data(), yProp, widget.data()); fixupAnimation.snapX->setEasingCurve(QEasingCurve::InOutQuad); fixupAnimation.snapY->setEasingCurve(QEasingCurve::InOutQuad); QObject::connect( fixupAnimation.groupX, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), q, SIGNAL(scrollStateChanged(QAbstractAnimation::State, QAbstractAnimation::State)) ); QObject::connect( fixupAnimation.groupY, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), q, SIGNAL(scrollStateChanged(QAbstractAnimation::State, QAbstractAnimation::State)) ); directMoveAnimation = new QPropertyAnimation(q, "scrollPosition", q); QObject::connect(directMoveAnimation, SIGNAL(finished()), q, SLOT(fixupX())); QObject::connect(directMoveAnimation, SIGNAL(finished()), q, SLOT(fixupY())); QObject::connect( directMoveAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), q, SIGNAL(scrollStateChanged(QAbstractAnimation::State, QAbstractAnimation::State)) ); directMoveAnimation->setEasingCurve(QEasingCurve::OutCirc); } } void deleteFlickAnimations() { if (flickAnimationX) { flickAnimationX->stop(); } if (flickAnimationY) { flickAnimationY->stop(); } delete flickAnimationX; flickAnimationX = nullptr; delete flickAnimationY; flickAnimationY = nullptr; delete fixupAnimation.groupX; fixupAnimation.groupX = nullptr; delete fixupAnimation.groupY; fixupAnimation.groupY = nullptr; delete directMoveAnimation; directMoveAnimation = nullptr; delete fixupAnimation.snapX; fixupAnimation.snapX = nullptr; delete fixupAnimation.snapY; fixupAnimation.snapY = nullptr; } void setScrollX() { if (horizontalScrollBarPolicy != Qt::ScrollBarAlwaysOff) { horizontalScrollBar->blockSignals(true); horizontalScrollBar->setValue(-widget.data()->pos().x() / 10.0); horizontalScrollBar->blockSignals(false); } } void setScrollY() { if (verticalScrollBarPolicy != Qt::ScrollBarAlwaysOff) { verticalScrollBar->blockSignals(true); verticalScrollBar->setValue(-widget.data()->pos().y() / 10.0); verticalScrollBar->blockSignals(false); } } ScrollWidget *q; QGraphicsWidget *scrollingWidget; QWeakPointer widget; Plasma::Svg *borderSvg; Plasma::SvgWidget *topBorder; Plasma::SvgWidget *bottomBorder; Plasma::SvgWidget *leftBorder; Plasma::SvgWidget *rightBorder; QGraphicsGridLayout *layout; ScrollBar *verticalScrollBar; Qt::ScrollBarPolicy verticalScrollBarPolicy; ScrollBar *horizontalScrollBar; Qt::ScrollBarPolicy horizontalScrollBarPolicy; QWeakPointer widgetToBeVisible; QRectF rectToBeVisible; QTimer *wheelTimer; QPropertyAnimation *flickAnimationX; QPropertyAnimation *flickAnimationY; struct { QAnimationGroup *groupX; QPropertyAnimation *startX; QPropertyAnimation *endX; QAnimationGroup *groupY; QPropertyAnimation *startY; QPropertyAnimation *endY; QPropertyAnimation *snapX; QPropertyAnimation *snapY; } fixupAnimation; QPropertyAnimation *directMoveAnimation; QSizeF snapSize; bool hasOvershoot; bool overflowBordersVisible; Qt::Alignment alignment; }; ScrollWidget::ScrollWidget(QGraphicsItem *parent) : QGraphicsWidget(parent), d(new ScrollWidgetPrivate(this)) { d->commonConstructor(); } ScrollWidget::ScrollWidget(QGraphicsWidget *parent) : QGraphicsWidget(parent), d(new ScrollWidgetPrivate(this)) { d->commonConstructor(); } ScrollWidget::~ScrollWidget() { delete d; } void ScrollWidget::setWidget(QGraphicsWidget *widget) { if (d->widget && d->widget.data() != widget) { d->deleteFlickAnimations(); d->widget.data()->removeEventFilter(this); delete d->widget.data(); } d->widget = widget; // it's not good it's setting a size policy here, but it's done to be retrocompatible with older applications if (widget) { d->createFlickAnimations(); connect(widget, SIGNAL(xChanged()), this, SLOT(setScrollX())); connect(widget, SIGNAL(yChanged()), this, SLOT(setScrollY())); widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); widget->setParentItem(d->scrollingWidget); widget->setPos(d->minXExtent(), d->minYExtent()); widget->installEventFilter(this); d->adjustScrollbars(); } } QGraphicsWidget *ScrollWidget::widget() const { return d->widget.data(); } 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; } bool ScrollWidget::overflowBordersVisible() const { return d->overflowBordersVisible; } void ScrollWidget::setOverflowBordersVisible(const bool visible) { if (d->overflowBordersVisible == visible) { return; } d->overflowBordersVisible = visible; d->adjustScrollbars(); } void ScrollWidget::ensureRectVisible(const QRectF &rect) { if (!d->widget) { return; } d->rectToBeVisible = rect; d->makeRectVisible(); } void ScrollWidget::ensureItemVisible(QGraphicsItem *item) { if (!d->widget || !item) { return; } QGraphicsItem *parentOfItem = item->parentItem(); while (parentOfItem != d->widget.data()) { if (!parentOfItem) { return; } parentOfItem = parentOfItem->parentItem(); } //since we can't ensure it'll stay alive we can delay only if it's a qgraphicswidget QGraphicsWidget *widget = qgraphicsitem_cast(item); if (widget) { d->widgetToBeVisible = widget; // We need to wait for the parent item to resize... QTimer::singleShot(0, this, SLOT(makeItemVisible())); } else { d->makeItemVisible(item); } } QRectF ScrollWidget::viewportGeometry() const { if (d->widget) { d->scrollingWidget->boundingRect(); } return QRectF(); } QSizeF ScrollWidget::contentsSize() const { if (d->widget) { return d->widget.data()->size(); } return QSizeF(); } void ScrollWidget::setScrollPosition(const QPointF &position) { if (d->widget) { d->widget.data()->setPos(-position.toPoint()); } } QPointF ScrollWidget::scrollPosition() const { if (d->widget) { return -d->widget.data()->pos(); } return QPointF(); } void ScrollWidget::setSnapSize(const QSizeF &size) { d->snapSize = size; } QSizeF ScrollWidget::snapSize() const { return d->snapSize; } void ScrollWidget::focusInEvent(QFocusEvent *event) { if (d->widget) { d->widget.data()->setFocus(event->reason()); } } void ScrollWidget::resizeEvent(QGraphicsSceneResizeEvent *event) { if (!d->widget) { QGraphicsWidget::resizeEvent(event); return; } d->adjustScrollbars(); //if topBorder exists bottomBorder too if (d->topBorder) { d->topBorder->resize(event->newSize().width(), d->topBorder->size().height()); d->bottomBorder->resize(event->newSize().width(), d->bottomBorder->size().height()); d->bottomBorder->setPos(0, event->newSize().height() - d->bottomBorder->size().height()); } if (d->leftBorder) { d->leftBorder->resize(d->leftBorder->size().width(), event->newSize().height()); d->rightBorder->resize(d->rightBorder->size().width(), event->newSize().height()); d->rightBorder->setPos(event->newSize().width() - d->rightBorder->size().width(), 0); } QGraphicsWidget::resizeEvent(event); } void ScrollWidget::keyPressEvent(QKeyEvent *event) { d->handleKeyPressEvent(event); } void ScrollWidget::wheelEvent(QGraphicsSceneWheelEvent *event) { if (!d->widget) { return; } else if (!d->canYFlick() && !d->canXFlick()) { event->ignore(); return; } d->handleWheelEvent(event); event->accept(); } bool ScrollWidget::eventFilter(QObject *watched, QEvent *event) { if (!d->widget) { return false; } if (watched == d->scrollingWidget && (event->type() == QEvent::GraphicsSceneResize || event->type() == QEvent::Move)) { emit viewportGeometryChanged(viewportGeometry()); } else if (watched == d->widget.data() && event->type() == QEvent::GraphicsSceneResize) { d->stopAnimations(); d->adjustScrollbars(); updateGeometry(); QPointF newPos = d->widget.data()->pos(); if (d->widget.data()->size().width() <= viewportGeometry().width()) { newPos.setX(d->minXExtent()); } if (d->widget.data()->size().height() <= viewportGeometry().height()) { newPos.setY(d->minYExtent()); } //check if the content is visible if (d->widget.data()->geometry().right() < 0) { newPos.setX(-d->widget.data()->geometry().width()+viewportGeometry().width()); } if (d->widget.data()->geometry().bottom() < 0) { newPos.setY(-d->widget.data()->geometry().height()+viewportGeometry().height()); } d->widget.data()->setPos(newPos); } else if (watched == d->widget.data() && event->type() == QEvent::GraphicsSceneMove) { d->horizontalScrollBar->blockSignals(true); d->verticalScrollBar->blockSignals(true); d->horizontalScrollBar->setValue(-d->widget.data()->pos().x()/10); d->verticalScrollBar->setValue(-d->widget.data()->pos().y()/10); d->horizontalScrollBar->blockSignals(false); d->verticalScrollBar->blockSignals(false); } return false; } QSizeF ScrollWidget::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const { if (!d->widget || which == Qt::MaximumSize) { return QGraphicsWidget::sizeHint(which, constraint); //FIXME: it should ake the minimum hint of the contained widget, but the result is in a ridiculously big widget } else if (which == Qt::MinimumSize) { return QSizeF(KIconLoader::SizeEnormous, KIconLoader::SizeEnormous); } QSizeF hint = d->widget.data()->effectiveSizeHint(which, constraint); if (d->horizontalScrollBar && d->horizontalScrollBar->isVisible()) { hint += QSize(0, d->horizontalScrollBar->size().height()); } if (d->verticalScrollBar && d->verticalScrollBar->isVisible()) { hint += QSize(d->verticalScrollBar->size().width(), 0); } return hint; } void Plasma::ScrollWidget::setAlignment(Qt::Alignment align) { d->alignment = align; if (d->widget.data() && d->widget.data()->isVisible()) { d->widget.data()->setPos(d->minXExtent(), d->minYExtent()); } } Qt::Alignment Plasma::ScrollWidget::alignment() const { return d->alignment; } void ScrollWidget::setOverShoot(bool enable) { d->hasOvershoot = enable; } bool ScrollWidget::hasOverShoot() const { return d->hasOvershoot; } } // namespace Plasma #include "moc_scrollwidget.cpp"