~ubuntu-branches/ubuntu/maverick/kdegraphics/maverick-proposed

« back to all changes in this revision

Viewing changes to libs/libksane/libksane/splittercollapser.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Thomas
  • Date: 2009-12-02 14:03:43 UTC
  • mfrom: (1.1.35 upstream)
  • Revision ID: james.westby@ubuntu.com-20091202140343-2732gbkj69g89arq
Tags: 4:4.3.80-0ubuntu1
* New upstream beta release:
  - Add build-depend on shared-desktop-ontologies for nepomuk integration
  - Bump .so versions for libkexiv, libkdcraw and libkipi
  - Update various .install files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// vim: set tabstop=4 shiftwidth=4 noexpandtab:
 
2
/*
 
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>
 
6
 
 
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.
 
11
 
 
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.
 
16
 
 
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.
 
20
 
 
21
*/
 
22
// Self
 
23
#include "splittercollapser.h"
 
24
 
 
25
// Qt
 
26
#include <QApplication>
 
27
#include <QEvent>
 
28
#include <QMouseEvent>
 
29
#include <QSplitter>
 
30
#include <QStyleOptionToolButton>
 
31
#include <QStylePainter>
 
32
#include <QTimeLine>
 
33
 
 
34
// KDE
 
35
#include <kdebug.h>
 
36
 
 
37
// Local
 
38
 
 
39
namespace KSaneIface {
 
40
 
 
41
 
 
42
enum Direction {
 
43
        LTR      = 1 << 0,
 
44
        RTL      = 1 << 1,
 
45
        Vertical = 1 << 2,
 
46
        TTB      = Vertical + (1 << 0),
 
47
        BTT      = Vertical + (1 << 1)
 
48
};
 
49
 
 
50
const int TIMELINE_DURATION = 500;
 
51
 
 
52
const qreal MINIMUM_OPACITY = 0.3;
 
53
 
 
54
struct ArrowTypes {
 
55
        ArrowTypes() {}
 
56
 
 
57
        ArrowTypes(Qt::ArrowType t1, Qt::ArrowType t2)
 
58
        : visible(t1), notVisible(t2) {}
 
59
 
 
60
        Qt::ArrowType visible,
 
61
        notVisible;
 
62
 
 
63
        Qt::ArrowType get(bool isVisible) {
 
64
                return isVisible ? visible : notVisible;
 
65
        }
 
66
};
 
67
 
 
68
 
 
69
struct SplitterCollapserPrivate {
 
70
        SplitterCollapser* q;
 
71
        QSplitter* mSplitter;
 
72
        QWidget* mWidget;
 
73
        Direction mDirection;
 
74
        QTimeLine* mOpacityTimeLine;
 
75
        int mSizeAtCollaps;
 
76
        
 
77
        bool isVertical() const {
 
78
                return mDirection & Vertical;
 
79
        }
 
80
        
 
81
        bool isVisible() const {
 
82
                bool isVisible = mWidget->isVisible();
 
83
                QRect widgetRect = mWidget->geometry();
 
84
                if (isVisible) {
 
85
                        QPoint br = widgetRect.bottomRight();
 
86
                        if ((br.x() <= 0) || (br.y() <=0)) {
 
87
                                isVisible = false;
 
88
                        }
 
89
                }
 
90
                return isVisible;
 
91
        }
 
92
        
 
93
        void updatePosition() {
 
94
                int x, y;
 
95
                QRect widgetRect = mWidget->geometry();
 
96
                int splitterWidth = mSplitter->width();
 
97
                int handleWidth = mSplitter->handleWidth();
 
98
                int width = q->width();
 
99
                
 
100
                if (!isVertical()) {
 
101
                        // FIXME: Make this configurable
 
102
                        y = 30;
 
103
                        if (mDirection == LTR) {
 
104
                                if (isVisible()) {
 
105
                                        x = widgetRect.right() + handleWidth;
 
106
                                } else {
 
107
                                        x = 0;
 
108
                                }
 
109
                        } else { // RTL
 
110
                                if (isVisible()) {
 
111
                                        x = widgetRect.left() - handleWidth - width;
 
112
                                } else {
 
113
                                        x = splitterWidth - handleWidth - width;
 
114
                                }
 
115
                        }
 
116
                } else {
 
117
                        // FIXME
 
118
                        x = 0;
 
119
                        y = 0;
 
120
                }
 
121
                q->move(x, y);
 
122
        }
 
123
 
 
124
 
 
125
        void updateArrow() {
 
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);
 
132
                }
 
133
                q->setArrowType(arrowForDirection[mDirection].get(isVisible()));
 
134
        }
 
135
 
 
136
 
 
137
        void widgetEventFilter(QEvent* event) {
 
138
                switch (event->type()) {
 
139
                        case QEvent::Resize:
 
140
                                updatePosition();
 
141
                                updateOpacity();
 
142
                                break;
 
143
                                
 
144
                        case QEvent::Move:
 
145
                        case QEvent::Show:
 
146
                        case QEvent::Hide:
 
147
                                updatePosition();
 
148
                                updateOpacity();
 
149
                                updateArrow();
 
150
                                break;
 
151
                                
 
152
                        default:
 
153
                                break;
 
154
                }
 
155
        }
 
156
 
 
157
 
 
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);
 
165
                        startTimeLine();
 
166
                } else if (!opaqueCollapser && frame == mOpacityTimeLine->endFrame()) {
 
167
                        mOpacityTimeLine->setDirection(QTimeLine::Backward);
 
168
                        startTimeLine();
 
169
                }
 
170
        }
 
171
 
 
172
 
 
173
        void startTimeLine() {
 
174
                if (mOpacityTimeLine->state() != QTimeLine::Running) {
 
175
                        mOpacityTimeLine->start();
 
176
                }
 
177
        }
 
178
};
 
179
 
 
180
 
 
181
SplitterCollapser::SplitterCollapser(QSplitter* splitter, QWidget* widget)
 
182
: QToolButton(),
 
183
d(new SplitterCollapserPrivate)
 
184
{
 
185
        d->q = this;
 
186
 
 
187
        // We do not want our collapser to be added as a regular widget in the
 
188
        // splitter!
 
189
        setAttribute(Qt::WA_NoChildEventsForParent);
 
190
 
 
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()));
 
194
 
 
195
        d->mWidget = widget;
 
196
        d->mWidget->installEventFilter(this);
 
197
 
 
198
        qApp->installEventFilter(this);
 
199
 
 
200
        d->mSplitter = splitter;
 
201
        setParent(d->mSplitter);
 
202
 
 
203
        if (splitter->indexOf(widget) < splitter->count() / 2) {
 
204
                d->mDirection = LTR;
 
205
        } else {
 
206
                d->mDirection = RTL;
 
207
        }
 
208
        if (splitter->orientation() == Qt::Vertical) {
 
209
                // FIXME: Ugly!
 
210
                d->mDirection = static_cast<Direction>(int(d->mDirection) + int(TTB));
 
211
        }
 
212
 
 
213
        connect(this, SIGNAL(clicked()), SLOT(slotClicked()));
 
214
 
 
215
        show();
 
216
}
 
217
 
 
218
 
 
219
SplitterCollapser::~SplitterCollapser() {
 
220
        delete d;
 
221
}
 
222
 
 
223
 
 
224
bool SplitterCollapser::eventFilter(QObject* object, QEvent* event) {
 
225
        if (object == d->mWidget) {
 
226
                d->widgetEventFilter(event);
 
227
        } else { /* app */
 
228
                if (event->type() == QEvent::MouseMove) {
 
229
                        d->updateOpacity();
 
230
                }
 
231
        }
 
232
        return false;
 
233
}
 
234
 
 
235
 
 
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()) {
 
240
                sh.transpose();
 
241
        }
 
242
        return sh;
 
243
}
 
244
 
 
245
 
 
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];
 
251
                sizes[index] = 0;
 
252
        }
 
253
        else {
 
254
                if (d->mSizeAtCollaps != 0) {
 
255
                        sizes[index] = d->mSizeAtCollaps;
 
256
                }
 
257
                else {
 
258
                        if (d->isVertical()) {
 
259
                                sizes[index] = d->mWidget->sizeHint().height();
 
260
                        }
 
261
                        else {
 
262
                                sizes[index] = d->mWidget->sizeHint().width();
 
263
                        }
 
264
                }
 
265
        }
 
266
        d->mSplitter->setSizes(sizes);
 
267
}
 
268
 
 
269
void SplitterCollapser::slotCollapse() {
 
270
    if (d->isVisible()) slotClicked();
 
271
    // else do nothing
 
272
}
 
273
 
 
274
void SplitterCollapser::slotRestore() {
 
275
    if (!d->isVisible()) slotClicked();
 
276
    // else do nothing
 
277
}
 
278
 
 
279
void SplitterCollapser::slotSetCollapsed(bool collapse) {
 
280
    if (collapse == d->isVisible()) slotClicked();
 
281
    // else do nothing
 
282
}
 
283
 
 
284
void SplitterCollapser::paintEvent(QPaintEvent*) {
 
285
        QStylePainter painter(this);
 
286
        qreal opacity = d->mOpacityTimeLine->currentFrame() / 1000.;
 
287
        painter.setOpacity(opacity);
 
288
 
 
289
        QStyleOptionToolButton opt;
 
290
        initStyleOption(&opt);
 
291
        if (d->mDirection == LTR) {
 
292
                opt.rect.setLeft(-width());
 
293
        } else {
 
294
                opt.rect.setWidth(width() * 2);
 
295
        }
 
296
        painter.drawPrimitive(QStyle::PE_PanelButtonTool, opt);
 
297
 
 
298
        QStyleOptionToolButton opt2;
 
299
        initStyleOption(&opt2);
 
300
        painter.drawControl(QStyle::CE_ToolButtonLabel, opt2);
 
301
}
 
302
 
 
303
 
 
304
} // namespace