kde-extraapps/kdeplasma-addons/libs/lancelot/widgets/ScrollPane.cpp

372 lines
9.8 KiB
C++
Raw Normal View History

/*
* Copyright (C) 2007, 2008, 2009, 2010 Ivan Cukic <ivan.cukic(at)kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser/Library General Public License version 2,
* or (at your option) any later version, as published by the Free
* Software Foundation
*
* 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 Lesser/Library General Public License for more details
*
* You should have received a copy of the GNU Lesser/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 "ScrollPane.h"
#include "ScrollBar.h"
#include "Widget.h"
#include <Plasma/Animator>
#include <QtGui/qgraphicssceneevent.h>
#include <lancelot/layouts/FullBorderLayout.h>
#include "kineticscroll_p.h"
namespace Lancelot
{
// Scrollable interface common functions implementation
//>
class Scrollable::Private {
public:
ScrollPane * pane;
};
Scrollable::Scrollable()
: d(new Private())
{
d->pane = NULL;
}
Scrollable::~Scrollable()
{
delete d;
}
void Scrollable::setScrollPane(ScrollPane * pane)
{
if (pane == d->pane) return;
d->pane = pane;
d->pane->setScrollableWidget(this);
}
ScrollPane * Scrollable::scrollPane() const
{
return d->pane;
}
//<
// ScrollPane implementation
class ScrollPane::Private { //>
public:
Private(ScrollPane * parent)
: q(parent), widget(NULL), layout(NULL),
vertical(NULL), horizontal(NULL),
flags(ScrollPane::ClipScrollable)
{
q->setAcceptTouchEvents(true);
}
void updateViewport()
{
widget->viewportChanged(QRectF(QPointF(horizontal->value(), vertical->value()),
q->currentViewportSize()));
}
ScrollPane * q;
Scrollable * widget;
/*FlipLayout <*/ FullBorderLayout /*>*/ * layout;
ScrollBar * vertical;
ScrollBar * horizontal;
QGraphicsWidget * centerContainer;
Flags flags;
}; //<
ScrollPane::ScrollPane(QGraphicsItem * parent) //>
: Widget(parent), d(new Private(this))
{
setAcceptsHoverEvents(true);
d->layout = new /*FlipLayout <*/ FullBorderLayout /*>*/ (this);
// d->layout->setParentLayoutItem(this);
d->vertical = new ScrollBar(this);
d->vertical->setOrientation(Qt::Vertical);
d->vertical->setZValue(1);
d->horizontal = new ScrollBar(this);
d->horizontal->setOrientation(Qt::Horizontal);
d->horizontal->setZValue(1);
d->centerContainer = new QGraphicsWidget(this);
d->centerContainer->setAcceptsHoverEvents(true);
d->centerContainer->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
connect (d->vertical, SIGNAL(valueChanged(int)),
this, SLOT(scrollVertical(int)));
connect (d->horizontal, SIGNAL(valueChanged(int)),
this, SLOT(scrollHorizontal(int)));
d->layout->addItem(d->vertical, FullBorderLayout::Right);
d->layout->addItem(d->horizontal, FullBorderLayout::Bottom);
d->layout->addItem(d->centerContainer, FullBorderLayout::Center);
d->layout->setContentsMargins(0, 0, 0, 0);
setLayout(d->layout);
new Plasma::KineticScrolling(this);
} //<
ScrollPane::~ScrollPane() //>
{
// delete d->layout;
setLayout(NULL);
delete d->horizontal;
delete d->vertical;
delete d->centerContainer;
delete d;
} //<
void ScrollPane::setScrollableWidget(Scrollable * widget) //>
{
if (d->widget == widget) {
return;
}
d->widget = widget;
widget->setScrollPane(this);
QGraphicsWidget * qgw = dynamic_cast<QGraphicsWidget *>(widget);
if (qgw) {
qgw->setParentItem(d->centerContainer);
scrollableWidgetSizeUpdateNeeded();
}
} //<
QSizeF ScrollPane::maximumViewportSize() const //>
{
return size();
} //<
QSizeF ScrollPane::currentViewportSize() const //>
{
return d->centerContainer->size();
} //<
void ScrollPane::scrollableWidgetSizeUpdateNeeded() //>
{
if (!d->widget || !layout()) {
return;
}
d->layout->setAutoSize(FullBorderLayout::RightBorder);
d->layout->setAutoSize(FullBorderLayout::BottomBorder);
bool hasHorizontal;
bool hasVertical;
QSizeF testSize = maximumViewportSize();
QSizeF neededSize = d->widget->sizeFor(testSize);
hasHorizontal = neededSize.width() > testSize.width();
hasVertical = neededSize.height() > testSize.height();
if (hasVertical) {
hasHorizontal = d->widget->sizeFor(currentViewportSize()).width() > testSize.width();
}
d->horizontal->setVisible(hasHorizontal);
d->vertical->setVisible(hasVertical);
if (!hasHorizontal) {
d->horizontal->setValue(0);
d->horizontal->setRange(0, 0);
d->layout->setSize(0, FullBorderLayout::BottomBorder);
}
if (!hasVertical) {
d->vertical->setValue(0);
d->horizontal->setRange(0, 0);
d->layout->setSize(0, FullBorderLayout::RightBorder);
}
int viewportSize;
if (hasHorizontal) {
viewportSize = currentViewportSize().width();
d->horizontal->setRange(0, d->widget->sizeFor(currentViewportSize()).width() - viewportSize);
d->horizontal->setPageStep(viewportSize);
d->horizontal->setSingleStep(d->widget->scrollUnit(Qt::Horizontal));
if ((d->flags & HoverShowScrollbars) && !isHovered()) {
d->horizontal->hide();
}
}
if (hasVertical) {
viewportSize = currentViewportSize().height();
d->vertical->setRange(0, d->widget->sizeFor(currentViewportSize()).height() - viewportSize);
d->vertical->setPageStep(viewportSize);
d->vertical->setSingleStep(d->widget->scrollUnit(Qt::Vertical));
if ((d->flags & HoverShowScrollbars) && !isHovered()) {
d->vertical->hide();
}
}
d->updateViewport();
} //<
void ScrollPane::resizeEvent(QGraphicsSceneResizeEvent * event) //>
{
Lancelot::Widget::resizeEvent(event);
scrollableWidgetSizeUpdateNeeded();
} //<
void ScrollPane::scrollHorizontal(int value) //>
{
d->horizontal->setValue(value);
d->updateViewport();
} //<
void ScrollPane::scrollVertical(int value) //>
{
d->vertical->setValue(value);
d->updateViewport();
} //<
void ScrollPane::setFlag(Flag flag) //>
{
d->flags |= flag;
setFlags(d->flags);
} //<
void ScrollPane::clearFlag(Flag flag) //>
{
d->flags &= ~ flag;
setFlags(d->flags);
} //<
ScrollPane::Flags ScrollPane::flags() const //>
{
return d->flags;
} //<
void ScrollPane::setFlags(Flags flags) //>
{
d->flags = flags;
if (d->flags & ClipScrollable) {
d->centerContainer->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
} else {
d->centerContainer->setFlags(
d->centerContainer->flags() & ~QGraphicsItem::ItemClipsChildrenToShape);
}
if ((d->flags & HoverShowScrollbars) && !isHovered()) {
d->horizontal->hide();
d->vertical->hide();
}
} //<
void ScrollPane::hoverEnterEvent(QGraphicsSceneHoverEvent * event) //>
{
Widget::hoverEnterEvent(event);
if (!(d->flags & HoverShowScrollbars)) {
return;
}
if (d->layout->size(FullBorderLayout::RightBorder) != 0) {
d->vertical->setVisible(true);
}
if (d->layout->size(FullBorderLayout::BottomBorder) != 0) {
d->horizontal->setVisible(true);
}
} //<
void ScrollPane::hoverLeaveEvent(QGraphicsSceneHoverEvent * event) //>
{
Widget::hoverLeaveEvent(event);
if (!(d->flags & HoverShowScrollbars)) {
return;
}
if (d->layout->size(FullBorderLayout::RightBorder) != 0) {
d->vertical->hide();
}
if (d->layout->size(FullBorderLayout::BottomBorder) != 0) {
d->horizontal->hide();
}
} //<
void ScrollPane::setFlip(Plasma::Flip flip) //>
{
if (flip & Plasma::HorizontalFlip) {
// TODO: Replace this with a real removeItem(...)
d->layout->addItem(NULL, FullBorderLayout::Right);
d->layout->addItem(d->vertical, FullBorderLayout::Left);
} else {
d->layout->addItem(NULL, FullBorderLayout::Left);
d->layout->addItem(d->vertical, FullBorderLayout::Right);
}
// d->layout->setFlip(flip);
} //<
void ScrollPane::scrollTo(QRectF rect) //>
{
QSizeF viewportSize = currentViewportSize();
QSizeF scrollableSize = d->widget->sizeFor(viewportSize);
// Vertical scroll
// TODO: It would be prettier to do this differently
// (a variable indicating whether pane can scroll or smth)
// We have this in a few places
if (d->layout->size(FullBorderLayout::RightBorder) != 0) {
if (d->vertical->value() > rect.top()) {
scrollVertical(rect.top());
} else if (d->vertical->value() + viewportSize.height() < rect.bottom()) {
scrollVertical(rect.bottom() - viewportSize.height());
}
}
// Horizontal scroll
if (d->layout->size(FullBorderLayout::BottomBorder) != 0) {
if (d->horizontal->value() > rect.left()) {
scrollHorizontal(rect.left());
} else if (d->horizontal->value() + viewportSize.width() < rect.right()) {
scrollHorizontal(rect.right() - viewportSize.width());
}
}
} //<
QSizeF ScrollPane::contentsSize() const //>
{
return d->widget->sizeFor(currentViewportSize());
} //<
void ScrollPane::setScrollPosition(const QPointF &position) //>
{
scrollTo(QRectF(position, currentViewportSize()));
} //<
QPointF ScrollPane::scrollPosition() const //>
{
if (!d || !d->horizontal || !d->vertical) {
return QPointF();
}
return QPointF(d->horizontal->value(), d->vertical->value());
} //<
QRectF ScrollPane::viewportGeometry() const //>
{
return QRectF(QPointF(), currentViewportSize());
} //<
} // namespace Lancelot