~ubuntu-branches/ubuntu/trusty/gwenview/trusty-proposed

« back to all changes in this revision

Viewing changes to lib/hud/hudslider.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2014-03-19 10:34:35 UTC
  • mto: This revision was merged to the branch mainline in revision 51.
  • Revision ID: package-import@ubuntu.com-20140319103435-r20hzcnkejmkcxp4
Tags: upstream-4.12.90
Import upstream version 4.12.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// vim: set tabstop=4 shiftwidth=4 expandtab:
 
2
/*
 
3
Gwenview: an image viewer
 
4
Copyright 2011 Aurélien Gâteau <agateau@kde.org>
 
5
 
 
6
This program is free software; you can redistribute it and/or
 
7
modify it under the terms of the GNU General Public License
 
8
as published by the Free Software Foundation; either version 2
 
9
of the License, or (at your option) any later version.
 
10
 
 
11
This program is distributed in the hope that it will be useful,
 
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
GNU General Public License for more details.
 
15
 
 
16
You should have received a copy of the GNU General Public License
 
17
along with this program; if not, write to the Free Software
 
18
Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA.
 
19
 
 
20
*/
 
21
// Self
 
22
#include "hud/hudslider.moc"
 
23
 
 
24
// Local
 
25
#include <hud/hudtheme.h>
 
26
 
 
27
// KDE
 
28
#include <KDebug>
 
29
#include <KGlobalSettings>
 
30
#include <KIconLoader>
 
31
 
 
32
// Qt
 
33
#include <QApplication>
 
34
#include <QGraphicsSceneEvent>
 
35
#include <QPainter>
 
36
#include <QStyle>
 
37
#include <QStyleOptionGraphicsItem>
 
38
#include <QTimer>
 
39
 
 
40
namespace Gwenview
 
41
{
 
42
 
 
43
static const int FIRST_REPEAT_DELAY = 500;
 
44
 
 
45
struct HudSliderPrivate
 
46
{
 
47
    HudSlider* q;
 
48
    int mMin, mMax, mPageStep, mSingleStep;
 
49
    int mSliderPosition;
 
50
    int mRepeatX;
 
51
    QAbstractSlider::SliderAction mRepeatAction;
 
52
    int mValue;
 
53
    bool mIsDown;
 
54
 
 
55
    QRectF mHandleRect;
 
56
 
 
57
    bool hasValidRange() const
 
58
    {
 
59
        return mMax > mMin;
 
60
    }
 
61
 
 
62
    void updateHandleRect()
 
63
    {
 
64
        static const HudTheme::RenderInfo renderInfo = HudTheme::renderInfo(HudTheme::SliderWidgetHandle);
 
65
        static const int radius = renderInfo.borderRadius;
 
66
 
 
67
        const QRectF sliderRect = q->boundingRect();
 
68
        const qreal posX = xForPosition(mSliderPosition) - radius;
 
69
        const qreal posY = sliderRect.height() / 2 - radius;
 
70
        mHandleRect = QRectF(posX, posY, radius * 2, radius * 2);
 
71
    }
 
72
 
 
73
    int positionForX(qreal x) const
 
74
    {
 
75
        static const HudTheme::RenderInfo renderInfo = HudTheme::renderInfo(HudTheme::SliderWidgetHandle);
 
76
        static const int radius = renderInfo.borderRadius;
 
77
 
 
78
        const qreal sliderWidth = q->boundingRect().width();
 
79
 
 
80
        x -= radius;
 
81
        if (QApplication::isRightToLeft()) {
 
82
            x = sliderWidth - 2 * radius - x;
 
83
        }
 
84
        return mMin + int(x / (sliderWidth - 2 * radius) * (mMax - mMin));
 
85
    }
 
86
 
 
87
    qreal xForPosition(int pos) const
 
88
    {
 
89
        static const HudTheme::RenderInfo renderInfo = HudTheme::renderInfo(HudTheme::SliderWidgetHandle);
 
90
        static const int radius = renderInfo.borderRadius;
 
91
 
 
92
        const qreal sliderWidth = q->boundingRect().width();
 
93
        qreal x = (qreal(pos - mMin) / (mMax - mMin)) * (sliderWidth - 2 * radius);
 
94
        if (QApplication::isRightToLeft()) {
 
95
            x = sliderWidth - 2 * radius - x;
 
96
        }
 
97
        return x + radius;
 
98
    }
 
99
};
 
100
 
 
101
HudSlider::HudSlider(QGraphicsItem* parent)
 
102
: QGraphicsWidget(parent)
 
103
, d(new HudSliderPrivate)
 
104
{
 
105
    d->q = this;
 
106
    d->mMin = 0;
 
107
    d->mMax = 100;
 
108
    d->mPageStep = 10;
 
109
    d->mSingleStep = 1;
 
110
    d->mSliderPosition = d->mValue = 0;
 
111
    d->mIsDown = false;
 
112
    d->mRepeatAction = QAbstractSlider::SliderNoAction;
 
113
    d->updateHandleRect();
 
114
    setCursor(Qt::ArrowCursor);
 
115
    setAcceptHoverEvents(true);
 
116
    setFocusPolicy(Qt::WheelFocus);
 
117
}
 
118
 
 
119
HudSlider::~HudSlider()
 
120
{
 
121
    delete d;
 
122
}
 
123
 
 
124
void HudSlider::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget*)
 
125
{
 
126
    bool drawHandle = d->hasValidRange();
 
127
    HudTheme::State state;
 
128
    if (drawHandle && option->state.testFlag(QStyle::State_MouseOver)) {
 
129
        state = d->mIsDown ? HudTheme::DownState : HudTheme::MouseOverState;
 
130
    } else {
 
131
        state = HudTheme::NormalState;
 
132
    }
 
133
    painter->setRenderHint(QPainter::Antialiasing);
 
134
 
 
135
    const QRectF sliderRect = boundingRect();
 
136
 
 
137
    // Groove
 
138
    HudTheme::RenderInfo renderInfo = HudTheme::renderInfo(HudTheme::SliderWidgetGroove, state);
 
139
    painter->setPen(renderInfo.borderPen);
 
140
    painter->setBrush(renderInfo.bgBrush);
 
141
    qreal centerY = d->mHandleRect.center().y();
 
142
    QRectF grooveRect = QRectF(
 
143
        0, centerY - renderInfo.borderRadius,
 
144
        sliderRect.width(),
 
145
        2 * renderInfo.borderRadius
 
146
        );
 
147
 
 
148
    if (drawHandle) {
 
149
        // Clip out handle
 
150
        QPainterPath clipPath;
 
151
        clipPath.addRect(QRectF(QPointF(0, 0), d->mHandleRect.bottomLeft()).adjusted(0, 0, 1, 0));
 
152
        clipPath.addRect(QRectF(d->mHandleRect.topRight(), sliderRect.bottomRight()).adjusted(-1, 0, 0, 0));
 
153
        painter->setClipPath(clipPath);
 
154
    }
 
155
    painter->drawRoundedRect(grooveRect.adjusted(.5, .5, -.5, -.5), renderInfo.borderRadius, renderInfo.borderRadius);
 
156
    if (!drawHandle) {
 
157
        return;
 
158
    }
 
159
    painter->setClipping(false);
 
160
 
 
161
    // Handle
 
162
    renderInfo = HudTheme::renderInfo(HudTheme::SliderWidgetHandle, state);
 
163
    painter->setPen(renderInfo.borderPen);
 
164
    painter->setBrush(renderInfo.bgBrush);
 
165
    painter->drawRoundedRect(d->mHandleRect.adjusted(.5, .5, -.5, -.5), renderInfo.borderRadius, renderInfo.borderRadius);
 
166
}
 
167
 
 
168
void HudSlider::mousePressEvent(QGraphicsSceneMouseEvent* event)
 
169
{
 
170
    if (!d->hasValidRange()) {
 
171
        return;
 
172
    }
 
173
    const int pos = d->positionForX(event->pos().x());
 
174
    if (d->mHandleRect.contains(event->pos())) {
 
175
        switch (event->button()) {
 
176
        case Qt::LeftButton:
 
177
            d->mIsDown = true;
 
178
            break;
 
179
        case Qt::MiddleButton:
 
180
            setSliderPosition(pos);
 
181
            triggerAction(QAbstractSlider::SliderMove);
 
182
            break;
 
183
        default:
 
184
            break;
 
185
        }
 
186
    } else {
 
187
        d->mRepeatX = event->pos().x();
 
188
        d->mRepeatAction = pos < d->mSliderPosition
 
189
            ? QAbstractSlider::SliderPageStepSub
 
190
            : QAbstractSlider::SliderPageStepAdd;
 
191
        doRepeatAction(FIRST_REPEAT_DELAY);
 
192
    }
 
193
    update();
 
194
}
 
195
 
 
196
void HudSlider::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
 
197
{
 
198
    if (!d->hasValidRange()) {
 
199
        return;
 
200
    }
 
201
    if (d->mIsDown) {
 
202
        setSliderPosition(d->positionForX(event->pos().x()));
 
203
        triggerAction(QAbstractSlider::SliderMove);
 
204
        update();
 
205
    }
 
206
}
 
207
 
 
208
void HudSlider::mouseReleaseEvent(QGraphicsSceneMouseEvent* /*event*/)
 
209
{
 
210
    if (!d->hasValidRange()) {
 
211
        return;
 
212
    }
 
213
    d->mIsDown = false;
 
214
    d->mRepeatAction = QAbstractSlider::SliderNoAction;
 
215
    update();
 
216
}
 
217
 
 
218
void HudSlider::wheelEvent(QGraphicsSceneWheelEvent* event)
 
219
{
 
220
    if (!d->hasValidRange()) {
 
221
        return;
 
222
    }
 
223
    int step = qMin(QApplication::wheelScrollLines() * d->mSingleStep, d->mPageStep);
 
224
    if ((event->modifiers() & Qt::ControlModifier) || (event->modifiers() & Qt::ShiftModifier)) {
 
225
        step = d->mPageStep;
 
226
    }
 
227
    setSliderPosition(d->mSliderPosition + event->delta() * step / 120);
 
228
    triggerAction(QAbstractSlider::SliderMove);
 
229
}
 
230
 
 
231
void HudSlider::keyPressEvent(QKeyEvent* event)
 
232
{
 
233
    if (!d->hasValidRange()) {
 
234
        return;
 
235
    }
 
236
    bool rtl = QApplication::isRightToLeft();
 
237
    switch (event->key()) {
 
238
    case Qt::Key_Left:
 
239
        triggerAction(rtl ? QAbstractSlider::SliderSingleStepAdd : QAbstractSlider::SliderSingleStepSub);
 
240
        break;
 
241
    case Qt::Key_Right:
 
242
        triggerAction(rtl ? QAbstractSlider::SliderSingleStepSub : QAbstractSlider::SliderSingleStepAdd);
 
243
        break;
 
244
    case Qt::Key_PageUp:
 
245
        triggerAction(QAbstractSlider::SliderPageStepSub);
 
246
        break;
 
247
    case Qt::Key_PageDown:
 
248
        triggerAction(QAbstractSlider::SliderPageStepAdd);
 
249
        break;
 
250
    case Qt::Key_Home:
 
251
        triggerAction(QAbstractSlider::SliderToMinimum);
 
252
        break;
 
253
    case Qt::Key_End:
 
254
        triggerAction(QAbstractSlider::SliderToMaximum);
 
255
        break;
 
256
    default:
 
257
        event->ignore();
 
258
        break;
 
259
    }
 
260
}
 
261
 
 
262
void HudSlider::keyReleaseEvent(QKeyEvent* /*event*/)
 
263
{
 
264
    if (!d->hasValidRange()) {
 
265
        return;
 
266
    }
 
267
    d->mRepeatAction = QAbstractSlider::SliderNoAction;
 
268
}
 
269
 
 
270
void HudSlider::setRange(int min, int max)
 
271
{
 
272
    if (min == d->mMin && max == d->mMax) {
 
273
        return;
 
274
    }
 
275
    d->mMin = min;
 
276
    d->mMax = max;
 
277
    setValue(d->mValue); // ensure value is within min and max
 
278
    d->updateHandleRect();
 
279
    update();
 
280
}
 
281
 
 
282
void HudSlider::setPageStep(int step)
 
283
{
 
284
    d->mPageStep = step;
 
285
}
 
286
 
 
287
void HudSlider::setSingleStep(int step)
 
288
{
 
289
    d->mSingleStep = step;
 
290
}
 
291
 
 
292
void HudSlider::setValue(int value)
 
293
{
 
294
    value = qBound(d->mMin, value, d->mMax);
 
295
    if (value != d->mValue) {
 
296
        d->mValue = value;
 
297
        setSliderPosition(value);
 
298
        update();
 
299
        valueChanged(d->mValue);
 
300
    }
 
301
}
 
302
 
 
303
int HudSlider::sliderPosition() const
 
304
{
 
305
    return d->mSliderPosition;
 
306
}
 
307
 
 
308
void HudSlider::setSliderPosition(int pos)
 
309
{
 
310
    pos = qBound(d->mMin, pos, d->mMax);
 
311
    if (pos != d->mSliderPosition) {
 
312
        d->mSliderPosition = pos;
 
313
        d->updateHandleRect();
 
314
        update();
 
315
    }
 
316
}
 
317
 
 
318
bool HudSlider::isSliderDown() const
 
319
{
 
320
    return d->mIsDown;
 
321
}
 
322
 
 
323
void HudSlider::triggerAction(QAbstractSlider::SliderAction action)
 
324
{
 
325
    switch (action) {
 
326
    case QAbstractSlider::SliderSingleStepAdd:
 
327
        setSliderPosition(d->mValue + d->mSingleStep);
 
328
        break;
 
329
    case QAbstractSlider::SliderSingleStepSub:
 
330
        setSliderPosition(d->mValue - d->mSingleStep);
 
331
        break;
 
332
    case QAbstractSlider::SliderPageStepAdd:
 
333
        setSliderPosition(d->mValue + d->mPageStep);
 
334
        break;
 
335
    case QAbstractSlider::SliderPageStepSub:
 
336
        setSliderPosition(d->mValue - d->mPageStep);
 
337
        break;
 
338
    case QAbstractSlider::SliderToMinimum:
 
339
        setSliderPosition(d->mMin);
 
340
        break;
 
341
    case QAbstractSlider::SliderToMaximum:
 
342
        setSliderPosition(d->mMax);
 
343
        break;
 
344
    case QAbstractSlider::SliderMove:
 
345
    case QAbstractSlider::SliderNoAction:
 
346
        break;
 
347
    };
 
348
    actionTriggered(action);
 
349
    setValue(d->mSliderPosition);
 
350
}
 
351
 
 
352
void HudSlider::doRepeatAction(int time)
 
353
{
 
354
    int step = 0;
 
355
    switch (d->mRepeatAction) {
 
356
    case QAbstractSlider::SliderSingleStepAdd:
 
357
    case QAbstractSlider::SliderSingleStepSub:
 
358
        step = d->mSingleStep;
 
359
        break;
 
360
    case QAbstractSlider::SliderPageStepAdd:
 
361
    case QAbstractSlider::SliderPageStepSub:
 
362
        step = d->mPageStep;
 
363
        break;
 
364
    case QAbstractSlider::SliderToMinimum:
 
365
    case QAbstractSlider::SliderToMaximum:
 
366
    case QAbstractSlider::SliderMove:
 
367
        kWarning() << "Not much point in repeating action of type" << d->mRepeatAction;
 
368
        return;
 
369
    case QAbstractSlider::SliderNoAction:
 
370
        return;
 
371
    }
 
372
 
 
373
    int pos = d->positionForX(d->mRepeatX);
 
374
    if (qAbs(pos - d->mSliderPosition) >= step) {
 
375
        // We are far enough from the position where the mouse button was held
 
376
        // down to be able to repeat the action one more time
 
377
        triggerAction(d->mRepeatAction);
 
378
        QTimer::singleShot(time, this, SLOT(doRepeatAction()));
 
379
    } else {
 
380
        // We are too close to the held down position, reach the position and
 
381
        // don't repeat
 
382
        d->mRepeatAction = QAbstractSlider::SliderNoAction;
 
383
        setSliderPosition(pos);
 
384
        triggerAction(QAbstractSlider::SliderMove);
 
385
        return;
 
386
    }
 
387
}
 
388
 
 
389
} // namespace