1
// vim: set tabstop=4 shiftwidth=4 expandtab:
3
Gwenview: an image viewer
4
Copyright 2011 Aurélien Gâteau <agateau@kde.org>
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.
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.
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.
22
#include "hud/hudslider.moc"
25
#include <hud/hudtheme.h>
29
#include <KGlobalSettings>
30
#include <KIconLoader>
33
#include <QApplication>
34
#include <QGraphicsSceneEvent>
37
#include <QStyleOptionGraphicsItem>
43
static const int FIRST_REPEAT_DELAY = 500;
45
struct HudSliderPrivate
48
int mMin, mMax, mPageStep, mSingleStep;
51
QAbstractSlider::SliderAction mRepeatAction;
57
bool hasValidRange() const
62
void updateHandleRect()
64
static const HudTheme::RenderInfo renderInfo = HudTheme::renderInfo(HudTheme::SliderWidgetHandle);
65
static const int radius = renderInfo.borderRadius;
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);
73
int positionForX(qreal x) const
75
static const HudTheme::RenderInfo renderInfo = HudTheme::renderInfo(HudTheme::SliderWidgetHandle);
76
static const int radius = renderInfo.borderRadius;
78
const qreal sliderWidth = q->boundingRect().width();
81
if (QApplication::isRightToLeft()) {
82
x = sliderWidth - 2 * radius - x;
84
return mMin + int(x / (sliderWidth - 2 * radius) * (mMax - mMin));
87
qreal xForPosition(int pos) const
89
static const HudTheme::RenderInfo renderInfo = HudTheme::renderInfo(HudTheme::SliderWidgetHandle);
90
static const int radius = renderInfo.borderRadius;
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;
101
HudSlider::HudSlider(QGraphicsItem* parent)
102
: QGraphicsWidget(parent)
103
, d(new HudSliderPrivate)
110
d->mSliderPosition = d->mValue = 0;
112
d->mRepeatAction = QAbstractSlider::SliderNoAction;
113
d->updateHandleRect();
114
setCursor(Qt::ArrowCursor);
115
setAcceptHoverEvents(true);
116
setFocusPolicy(Qt::WheelFocus);
119
HudSlider::~HudSlider()
124
void HudSlider::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget*)
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;
131
state = HudTheme::NormalState;
133
painter->setRenderHint(QPainter::Antialiasing);
135
const QRectF sliderRect = boundingRect();
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,
145
2 * renderInfo.borderRadius
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);
155
painter->drawRoundedRect(grooveRect.adjusted(.5, .5, -.5, -.5), renderInfo.borderRadius, renderInfo.borderRadius);
159
painter->setClipping(false);
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);
168
void HudSlider::mousePressEvent(QGraphicsSceneMouseEvent* event)
170
if (!d->hasValidRange()) {
173
const int pos = d->positionForX(event->pos().x());
174
if (d->mHandleRect.contains(event->pos())) {
175
switch (event->button()) {
179
case Qt::MiddleButton:
180
setSliderPosition(pos);
181
triggerAction(QAbstractSlider::SliderMove);
187
d->mRepeatX = event->pos().x();
188
d->mRepeatAction = pos < d->mSliderPosition
189
? QAbstractSlider::SliderPageStepSub
190
: QAbstractSlider::SliderPageStepAdd;
191
doRepeatAction(FIRST_REPEAT_DELAY);
196
void HudSlider::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
198
if (!d->hasValidRange()) {
202
setSliderPosition(d->positionForX(event->pos().x()));
203
triggerAction(QAbstractSlider::SliderMove);
208
void HudSlider::mouseReleaseEvent(QGraphicsSceneMouseEvent* /*event*/)
210
if (!d->hasValidRange()) {
214
d->mRepeatAction = QAbstractSlider::SliderNoAction;
218
void HudSlider::wheelEvent(QGraphicsSceneWheelEvent* event)
220
if (!d->hasValidRange()) {
223
int step = qMin(QApplication::wheelScrollLines() * d->mSingleStep, d->mPageStep);
224
if ((event->modifiers() & Qt::ControlModifier) || (event->modifiers() & Qt::ShiftModifier)) {
227
setSliderPosition(d->mSliderPosition + event->delta() * step / 120);
228
triggerAction(QAbstractSlider::SliderMove);
231
void HudSlider::keyPressEvent(QKeyEvent* event)
233
if (!d->hasValidRange()) {
236
bool rtl = QApplication::isRightToLeft();
237
switch (event->key()) {
239
triggerAction(rtl ? QAbstractSlider::SliderSingleStepAdd : QAbstractSlider::SliderSingleStepSub);
242
triggerAction(rtl ? QAbstractSlider::SliderSingleStepSub : QAbstractSlider::SliderSingleStepAdd);
245
triggerAction(QAbstractSlider::SliderPageStepSub);
247
case Qt::Key_PageDown:
248
triggerAction(QAbstractSlider::SliderPageStepAdd);
251
triggerAction(QAbstractSlider::SliderToMinimum);
254
triggerAction(QAbstractSlider::SliderToMaximum);
262
void HudSlider::keyReleaseEvent(QKeyEvent* /*event*/)
264
if (!d->hasValidRange()) {
267
d->mRepeatAction = QAbstractSlider::SliderNoAction;
270
void HudSlider::setRange(int min, int max)
272
if (min == d->mMin && max == d->mMax) {
277
setValue(d->mValue); // ensure value is within min and max
278
d->updateHandleRect();
282
void HudSlider::setPageStep(int step)
287
void HudSlider::setSingleStep(int step)
289
d->mSingleStep = step;
292
void HudSlider::setValue(int value)
294
value = qBound(d->mMin, value, d->mMax);
295
if (value != d->mValue) {
297
setSliderPosition(value);
299
valueChanged(d->mValue);
303
int HudSlider::sliderPosition() const
305
return d->mSliderPosition;
308
void HudSlider::setSliderPosition(int pos)
310
pos = qBound(d->mMin, pos, d->mMax);
311
if (pos != d->mSliderPosition) {
312
d->mSliderPosition = pos;
313
d->updateHandleRect();
318
bool HudSlider::isSliderDown() const
323
void HudSlider::triggerAction(QAbstractSlider::SliderAction action)
326
case QAbstractSlider::SliderSingleStepAdd:
327
setSliderPosition(d->mValue + d->mSingleStep);
329
case QAbstractSlider::SliderSingleStepSub:
330
setSliderPosition(d->mValue - d->mSingleStep);
332
case QAbstractSlider::SliderPageStepAdd:
333
setSliderPosition(d->mValue + d->mPageStep);
335
case QAbstractSlider::SliderPageStepSub:
336
setSliderPosition(d->mValue - d->mPageStep);
338
case QAbstractSlider::SliderToMinimum:
339
setSliderPosition(d->mMin);
341
case QAbstractSlider::SliderToMaximum:
342
setSliderPosition(d->mMax);
344
case QAbstractSlider::SliderMove:
345
case QAbstractSlider::SliderNoAction:
348
actionTriggered(action);
349
setValue(d->mSliderPosition);
352
void HudSlider::doRepeatAction(int time)
355
switch (d->mRepeatAction) {
356
case QAbstractSlider::SliderSingleStepAdd:
357
case QAbstractSlider::SliderSingleStepSub:
358
step = d->mSingleStep;
360
case QAbstractSlider::SliderPageStepAdd:
361
case QAbstractSlider::SliderPageStepSub:
364
case QAbstractSlider::SliderToMinimum:
365
case QAbstractSlider::SliderToMaximum:
366
case QAbstractSlider::SliderMove:
367
kWarning() << "Not much point in repeating action of type" << d->mRepeatAction;
369
case QAbstractSlider::SliderNoAction:
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()));
380
// We are too close to the held down position, reach the position and
382
d->mRepeatAction = QAbstractSlider::SliderNoAction;
383
setSliderPosition(pos);
384
triggerAction(QAbstractSlider::SliderMove);