1
// vim: set tabstop=4 shiftwidth=4 noexpandtab:
3
Gwenview: an image viewer
4
Copyright 2009 Aurélien Gâteau <agateau@kde.org>
5
Copyright 2009 Kåre Sårs <kare.sars@iki.fi>
7
This program is free software; you can redistribute it and/or
8
modify it under the terms of the GNU General Public License
9
as published by the Free Software Foundation; either version 2
10
of the License, or (at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA.
23
#include "splittercollapser.h"
26
#include <QApplication>
28
#include <QMouseEvent>
30
#include <QStyleOptionToolButton>
31
#include <QStylePainter>
39
namespace KSaneIface {
46
TTB = Vertical + (1 << 0),
47
BTT = Vertical + (1 << 1)
50
const int TIMELINE_DURATION = 500;
52
const qreal MINIMUM_OPACITY = 0.3;
57
ArrowTypes(Qt::ArrowType t1, Qt::ArrowType t2)
58
: visible(t1), notVisible(t2) {}
60
Qt::ArrowType visible,
63
Qt::ArrowType get(bool isVisible) {
64
return isVisible ? visible : notVisible;
69
struct SplitterCollapserPrivate {
74
QTimeLine* mOpacityTimeLine;
77
bool isVertical() const {
78
return mDirection & Vertical;
81
bool isVisible() const {
82
bool isVisible = mWidget->isVisible();
83
QRect widgetRect = mWidget->geometry();
85
QPoint br = widgetRect.bottomRight();
86
if ((br.x() <= 0) || (br.y() <=0)) {
93
void updatePosition() {
95
QRect widgetRect = mWidget->geometry();
96
int splitterWidth = mSplitter->width();
97
int handleWidth = mSplitter->handleWidth();
98
int width = q->width();
101
// FIXME: Make this configurable
103
if (mDirection == LTR) {
105
x = widgetRect.right() + handleWidth;
111
x = widgetRect.left() - handleWidth - width;
113
x = splitterWidth - handleWidth - width;
126
static QMap<Direction, ArrowTypes> arrowForDirection;
127
if (arrowForDirection.isEmpty()) {
128
arrowForDirection[LTR] = ArrowTypes(Qt::LeftArrow, Qt::RightArrow);
129
arrowForDirection[RTL] = ArrowTypes(Qt::RightArrow, Qt::LeftArrow);
130
arrowForDirection[TTB] = ArrowTypes(Qt::UpArrow, Qt::DownArrow);
131
arrowForDirection[BTT] = ArrowTypes(Qt::DownArrow, Qt::UpArrow);
133
q->setArrowType(arrowForDirection[mDirection].get(isVisible()));
137
void widgetEventFilter(QEvent* event) {
138
switch (event->type()) {
158
void updateOpacity() {
159
QPoint pos = q->parentWidget()->mapFromGlobal(QCursor::pos());
160
QRect opaqueRect = q->geometry();
161
bool opaqueCollapser = opaqueRect.contains(pos);
162
int frame = mOpacityTimeLine->currentFrame();
163
if (opaqueCollapser && frame == mOpacityTimeLine->startFrame()) {
164
mOpacityTimeLine->setDirection(QTimeLine::Forward);
166
} else if (!opaqueCollapser && frame == mOpacityTimeLine->endFrame()) {
167
mOpacityTimeLine->setDirection(QTimeLine::Backward);
173
void startTimeLine() {
174
if (mOpacityTimeLine->state() != QTimeLine::Running) {
175
mOpacityTimeLine->start();
181
SplitterCollapser::SplitterCollapser(QSplitter* splitter, QWidget* widget)
183
d(new SplitterCollapserPrivate)
187
// We do not want our collapser to be added as a regular widget in the
189
setAttribute(Qt::WA_NoChildEventsForParent);
191
d->mOpacityTimeLine = new QTimeLine(TIMELINE_DURATION, this);
192
d->mOpacityTimeLine->setFrameRange(int(MINIMUM_OPACITY * 1000), 1000);
193
connect(d->mOpacityTimeLine, SIGNAL(valueChanged(qreal)), SLOT(update()));
196
d->mWidget->installEventFilter(this);
198
qApp->installEventFilter(this);
200
d->mSplitter = splitter;
201
setParent(d->mSplitter);
203
if (splitter->indexOf(widget) < splitter->count() / 2) {
208
if (splitter->orientation() == Qt::Vertical) {
210
d->mDirection = static_cast<Direction>(int(d->mDirection) + int(TTB));
213
connect(this, SIGNAL(clicked()), SLOT(slotClicked()));
219
SplitterCollapser::~SplitterCollapser() {
224
bool SplitterCollapser::eventFilter(QObject* object, QEvent* event) {
225
if (object == d->mWidget) {
226
d->widgetEventFilter(event);
228
if (event->type() == QEvent::MouseMove) {
236
QSize SplitterCollapser::sizeHint() const {
237
int extent = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
238
QSize sh(extent * 3 / 4, extent * 240 / 100);
239
if (d->isVertical()) {
246
void SplitterCollapser::slotClicked() {
247
QList<int> sizes = d->mSplitter->sizes();
248
int index = d->mSplitter->indexOf(d->mWidget);
249
if (d->isVisible()) {
250
d->mSizeAtCollaps = sizes[index];
254
if (d->mSizeAtCollaps != 0) {
255
sizes[index] = d->mSizeAtCollaps;
258
if (d->isVertical()) {
259
sizes[index] = d->mWidget->sizeHint().height();
262
sizes[index] = d->mWidget->sizeHint().width();
266
d->mSplitter->setSizes(sizes);
269
void SplitterCollapser::slotCollapse() {
270
if (d->isVisible()) slotClicked();
274
void SplitterCollapser::slotRestore() {
275
if (!d->isVisible()) slotClicked();
279
void SplitterCollapser::slotSetCollapsed(bool collapse) {
280
if (collapse == d->isVisible()) slotClicked();
284
void SplitterCollapser::paintEvent(QPaintEvent*) {
285
QStylePainter painter(this);
286
qreal opacity = d->mOpacityTimeLine->currentFrame() / 1000.;
287
painter.setOpacity(opacity);
289
QStyleOptionToolButton opt;
290
initStyleOption(&opt);
291
if (d->mDirection == LTR) {
292
opt.rect.setLeft(-width());
294
opt.rect.setWidth(width() * 2);
296
painter.drawPrimitive(QStyle::PE_PanelButtonTool, opt);
298
QStyleOptionToolButton opt2;
299
initStyleOption(&opt2);
300
painter.drawControl(QStyle::CE_ToolButtonLabel, opt2);