source: trunk/tools/shared/qtgradienteditor/qtgradientstopswidget.cpp@ 1030

Last change on this file since 1030 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 36.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qtgradientstopswidget.h"
43#include "qtgradientstopsmodel.h"
44
45#include <QtCore/QMap>
46#include <QtGui/QImage>
47#include <QtGui/QPainter>
48#include <QtGui/QScrollBar>
49#include <QtGui/QMouseEvent>
50#include <QtGui/QRubberBand>
51#include <QtGui/QMenu>
52
53QT_BEGIN_NAMESPACE
54
55class QtGradientStopsWidgetPrivate
56{
57 QtGradientStopsWidget *q_ptr;
58 Q_DECLARE_PUBLIC(QtGradientStopsWidget)
59public:
60 typedef QMap<qreal, QColor> PositionColorMap;
61 typedef QMap<QtGradientStop *, qreal> StopPositionMap;
62
63 void slotStopAdded(QtGradientStop *stop);
64 void slotStopRemoved(QtGradientStop *stop);
65 void slotStopMoved(QtGradientStop *stop, qreal newPos);
66 void slotStopsSwapped(QtGradientStop *stop1, QtGradientStop *stop2);
67 void slotStopChanged(QtGradientStop *stop, const QColor &newColor);
68 void slotStopSelected(QtGradientStop *stop, bool selected);
69 void slotCurrentStopChanged(QtGradientStop *stop);
70 void slotNewStop();
71 void slotDelete();
72 void slotFlipAll();
73 void slotSelectAll();
74 void slotZoomIn();
75 void slotZoomOut();
76 void slotResetZoom();
77
78 double fromViewport(int x) const;
79 double toViewport(double x) const;
80 QtGradientStop *stopAt(const QPoint &viewportPos) const;
81 QList<QtGradientStop *> stopsAt(const QPoint &viewportPos) const;
82 void setupMove(QtGradientStop *stop, int x);
83 void ensureVisible(double x); // x = stop position
84 void ensureVisible(QtGradientStop *stop);
85 QtGradientStop *newStop(const QPoint &viewportPos);
86
87 bool m_backgroundCheckered;
88 QtGradientStopsModel *m_model;
89 double m_handleSize;
90 int m_scaleFactor;
91 double m_zoom;
92
93#ifndef QT_NO_DRAGANDDROP
94 QtGradientStop *m_dragStop;
95 QtGradientStop *m_changedStop;
96 QtGradientStop *m_clonedStop;
97 QtGradientStopsModel *m_dragModel;
98 QColor m_dragColor;
99 void clearDrag();
100 void removeClonedStop();
101 void restoreChangedStop();
102 void changeStop(qreal pos);
103 void cloneStop(qreal pos);
104#endif
105
106 QRubberBand *m_rubber;
107 QPoint m_clickPos;
108
109 QList<QtGradientStop *> m_stops;
110
111 bool m_moving;
112 int m_moveOffset;
113 StopPositionMap m_moveStops;
114
115 PositionColorMap m_moveOriginal;
116};
117
118double QtGradientStopsWidgetPrivate::fromViewport(int x) const
119{
120 QSize size = q_ptr->viewport()->size();
121 int w = size.width();
122 int max = q_ptr->horizontalScrollBar()->maximum();
123 int val = q_ptr->horizontalScrollBar()->value();
124 return ((double)x * m_scaleFactor + w * val) / (w * (m_scaleFactor + max));
125}
126
127double QtGradientStopsWidgetPrivate::toViewport(double x) const
128{
129 QSize size = q_ptr->viewport()->size();
130 int w = size.width();
131 int max = q_ptr->horizontalScrollBar()->maximum();
132 int val = q_ptr->horizontalScrollBar()->value();
133 return w * (x * (m_scaleFactor + max) - val) / m_scaleFactor;
134}
135
136QtGradientStop *QtGradientStopsWidgetPrivate::stopAt(const QPoint &viewportPos) const
137{
138 double posY = m_handleSize / 2;
139 QListIterator<QtGradientStop *> itStop(m_stops);
140 while (itStop.hasNext()) {
141 QtGradientStop *stop = itStop.next();
142
143 double posX = toViewport(stop->position());
144
145 double x = viewportPos.x() - posX;
146 double y = viewportPos.y() - posY;
147
148 if ((m_handleSize * m_handleSize / 4) > (x * x + y * y))
149 return stop;
150 }
151 return 0;
152}
153
154QList<QtGradientStop *> QtGradientStopsWidgetPrivate::stopsAt(const QPoint &viewportPos) const
155{
156 QList<QtGradientStop *> stops;
157 double posY = m_handleSize / 2;
158 QListIterator<QtGradientStop *> itStop(m_stops);
159 while (itStop.hasNext()) {
160 QtGradientStop *stop = itStop.next();
161
162 double posX = toViewport(stop->position());
163
164 double x = viewportPos.x() - posX;
165 double y = viewportPos.y() - posY;
166
167 if ((m_handleSize * m_handleSize / 4) > (x * x + y * y))
168 stops.append(stop);
169 }
170 return stops;
171}
172
173void QtGradientStopsWidgetPrivate::setupMove(QtGradientStop *stop, int x)
174{
175 m_model->setCurrentStop(stop);
176
177 int viewportX = qRound(toViewport(stop->position()));
178 m_moveOffset = x - viewportX;
179
180 QList<QtGradientStop *> stops = m_stops;
181 m_stops.clear();
182 QListIterator<QtGradientStop *> itStop(stops);
183 while (itStop.hasNext()) {
184 QtGradientStop *s = itStop.next();
185 if (m_model->isSelected(s) || s == stop) {
186 m_moveStops[s] = s->position() - stop->position();
187 m_stops.append(s);
188 } else {
189 m_moveOriginal[s->position()] = s->color();
190 }
191 }
192 itStop.toFront();
193 while (itStop.hasNext()) {
194 QtGradientStop *s = itStop.next();
195 if (!m_model->isSelected(s))
196 m_stops.append(s);
197 }
198 m_stops.removeAll(stop);
199 m_stops.prepend(stop);
200}
201
202void QtGradientStopsWidgetPrivate::ensureVisible(double x)
203{
204 double viewX = toViewport(x);
205 if (viewX < 0 || viewX > q_ptr->viewport()->size().width()) {
206 int max = q_ptr->horizontalScrollBar()->maximum();
207 int newVal = qRound(x * (max + m_scaleFactor) - m_scaleFactor / 2);
208 q_ptr->horizontalScrollBar()->setValue(newVal);
209 }
210}
211
212void QtGradientStopsWidgetPrivate::ensureVisible(QtGradientStop *stop)
213{
214 if (!stop)
215 return;
216 ensureVisible(stop->position());
217}
218
219QtGradientStop *QtGradientStopsWidgetPrivate::newStop(const QPoint &viewportPos)
220{
221 QtGradientStop *copyStop = stopAt(viewportPos);
222 double posX = fromViewport(viewportPos.x());
223 QtGradientStop *stop = m_model->at(posX);
224 if (!stop) {
225 QColor newColor;
226 if (copyStop)
227 newColor = copyStop->color();
228 else
229 newColor = m_model->color(posX);
230 if (!newColor.isValid())
231 newColor = Qt::white;
232 stop = m_model->addStop(posX, newColor);
233 }
234 return stop;
235}
236
237void QtGradientStopsWidgetPrivate::slotStopAdded(QtGradientStop *stop)
238{
239 m_stops.append(stop);
240 q_ptr->viewport()->update();
241}
242
243void QtGradientStopsWidgetPrivate::slotStopRemoved(QtGradientStop *stop)
244{
245 m_stops.removeAll(stop);
246 q_ptr->viewport()->update();
247}
248
249void QtGradientStopsWidgetPrivate::slotStopMoved(QtGradientStop *stop, qreal newPos)
250{
251 Q_UNUSED(stop)
252 Q_UNUSED(newPos)
253 q_ptr->viewport()->update();
254}
255
256void QtGradientStopsWidgetPrivate::slotStopsSwapped(QtGradientStop *stop1, QtGradientStop *stop2)
257{
258 Q_UNUSED(stop1)
259 Q_UNUSED(stop2)
260 q_ptr->viewport()->update();
261}
262
263void QtGradientStopsWidgetPrivate::slotStopChanged(QtGradientStop *stop, const QColor &newColor)
264{
265 Q_UNUSED(stop)
266 Q_UNUSED(newColor)
267 q_ptr->viewport()->update();
268}
269
270void QtGradientStopsWidgetPrivate::slotStopSelected(QtGradientStop *stop, bool selected)
271{
272 Q_UNUSED(stop)
273 Q_UNUSED(selected)
274 q_ptr->viewport()->update();
275}
276
277void QtGradientStopsWidgetPrivate::slotCurrentStopChanged(QtGradientStop *stop)
278{
279 Q_UNUSED(stop)
280
281 if (!m_model)
282 return;
283 q_ptr->viewport()->update();
284 if (stop) {
285 m_stops.removeAll(stop);
286 m_stops.prepend(stop);
287 }
288}
289
290void QtGradientStopsWidgetPrivate::slotNewStop()
291{
292 if (!m_model)
293 return;
294
295 QtGradientStop *stop = newStop(m_clickPos);
296
297 if (!stop)
298 return;
299
300 m_model->clearSelection();
301 m_model->selectStop(stop, true);
302 m_model->setCurrentStop(stop);
303}
304
305void QtGradientStopsWidgetPrivate::slotDelete()
306{
307 if (!m_model)
308 return;
309
310 m_model->deleteStops();
311}
312
313void QtGradientStopsWidgetPrivate::slotFlipAll()
314{
315 if (!m_model)
316 return;
317
318 m_model->flipAll();
319}
320
321void QtGradientStopsWidgetPrivate::slotSelectAll()
322{
323 if (!m_model)
324 return;
325
326 m_model->selectAll();
327}
328
329void QtGradientStopsWidgetPrivate::slotZoomIn()
330{
331 double newZoom = q_ptr->zoom() * 2;
332 if (newZoom > 100)
333 newZoom = 100;
334 if (newZoom == q_ptr->zoom())
335 return;
336
337 q_ptr->setZoom(newZoom);
338 emit q_ptr->zoomChanged(q_ptr->zoom());
339}
340
341void QtGradientStopsWidgetPrivate::slotZoomOut()
342{
343 double newZoom = q_ptr->zoom() / 2;
344 if (newZoom < 1)
345 newZoom = 1;
346 if (newZoom == q_ptr->zoom())
347 return;
348
349 q_ptr->setZoom(newZoom);
350 emit q_ptr->zoomChanged(q_ptr->zoom());
351}
352
353void QtGradientStopsWidgetPrivate::slotResetZoom()
354{
355 if (1 == q_ptr->zoom())
356 return;
357
358 q_ptr->setZoom(1);
359 emit q_ptr->zoomChanged(1);
360}
361
362QtGradientStopsWidget::QtGradientStopsWidget(QWidget *parent)
363 : QAbstractScrollArea(parent), d_ptr(new QtGradientStopsWidgetPrivate)
364{
365 d_ptr->q_ptr = this;
366 d_ptr->m_backgroundCheckered = true;
367 d_ptr->m_model = 0;
368 d_ptr->m_handleSize = 25.0;
369 d_ptr->m_scaleFactor = 1000;
370 d_ptr->m_moving = false;
371 d_ptr->m_zoom = 1;
372 d_ptr->m_rubber = new QRubberBand(QRubberBand::Rectangle, this);
373#ifndef QT_NO_DRAGANDDROP
374 d_ptr->m_dragStop = 0;
375 d_ptr->m_changedStop = 0;
376 d_ptr->m_clonedStop = 0;
377 d_ptr->m_dragModel = 0;
378#endif
379 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
380 setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
381 horizontalScrollBar()->setRange(0, (int)(d_ptr->m_scaleFactor * (d_ptr->m_zoom - 1) + 0.5));
382 horizontalScrollBar()->setPageStep(d_ptr->m_scaleFactor);
383 horizontalScrollBar()->setSingleStep(4);
384 viewport()->setAutoFillBackground(false);
385
386 setAcceptDrops(true);
387
388 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred));
389}
390
391QtGradientStopsWidget::~QtGradientStopsWidget()
392{
393}
394
395QSize QtGradientStopsWidget::sizeHint() const
396{
397 return QSize(qRound(2 * d_ptr->m_handleSize), qRound(3 * d_ptr->m_handleSize) + horizontalScrollBar()->sizeHint().height());
398}
399
400QSize QtGradientStopsWidget::minimumSizeHint() const
401{
402 return QSize(qRound(2 * d_ptr->m_handleSize), qRound(3 * d_ptr->m_handleSize) + horizontalScrollBar()->minimumSizeHint().height());
403}
404
405void QtGradientStopsWidget::setBackgroundCheckered(bool checkered)
406{
407 if (d_ptr->m_backgroundCheckered == checkered)
408 return;
409 d_ptr->m_backgroundCheckered = checkered;
410 update();
411}
412
413bool QtGradientStopsWidget::isBackgroundCheckered() const
414{
415 return d_ptr->m_backgroundCheckered;
416}
417
418void QtGradientStopsWidget::setGradientStopsModel(QtGradientStopsModel *model)
419{
420 if (d_ptr->m_model == model)
421 return;
422
423 if (d_ptr->m_model) {
424 disconnect(d_ptr->m_model, SIGNAL(stopAdded(QtGradientStop*)),
425 this, SLOT(slotStopAdded(QtGradientStop*)));
426 disconnect(d_ptr->m_model, SIGNAL(stopRemoved(QtGradientStop*)),
427 this, SLOT(slotStopRemoved(QtGradientStop*)));
428 disconnect(d_ptr->m_model, SIGNAL(stopMoved(QtGradientStop*,qreal)),
429 this, SLOT(slotStopMoved(QtGradientStop*,qreal)));
430 disconnect(d_ptr->m_model, SIGNAL(stopsSwapped(QtGradientStop*,QtGradientStop*)),
431 this, SLOT(slotStopsSwapped(QtGradientStop*,QtGradientStop*)));
432 disconnect(d_ptr->m_model, SIGNAL(stopChanged(QtGradientStop*,QColor)),
433 this, SLOT(slotStopChanged(QtGradientStop*,QColor)));
434 disconnect(d_ptr->m_model, SIGNAL(stopSelected(QtGradientStop*,bool)),
435 this, SLOT(slotStopSelected(QtGradientStop*,bool)));
436 disconnect(d_ptr->m_model, SIGNAL(currentStopChanged(QtGradientStop*)),
437 this, SLOT(slotCurrentStopChanged(QtGradientStop*)));
438
439 d_ptr->m_stops.clear();
440 }
441
442 d_ptr->m_model = model;
443
444 if (d_ptr->m_model) {
445 connect(d_ptr->m_model, SIGNAL(stopAdded(QtGradientStop*)),
446 this, SLOT(slotStopAdded(QtGradientStop*)));
447 connect(d_ptr->m_model, SIGNAL(stopRemoved(QtGradientStop*)),
448 this, SLOT(slotStopRemoved(QtGradientStop*)));
449 connect(d_ptr->m_model, SIGNAL(stopMoved(QtGradientStop*,qreal)),
450 this, SLOT(slotStopMoved(QtGradientStop*,qreal)));
451 connect(d_ptr->m_model, SIGNAL(stopsSwapped(QtGradientStop*,QtGradientStop*)),
452 this, SLOT(slotStopsSwapped(QtGradientStop*,QtGradientStop*)));
453 connect(d_ptr->m_model, SIGNAL(stopChanged(QtGradientStop*,QColor)),
454 this, SLOT(slotStopChanged(QtGradientStop*,QColor)));
455 connect(d_ptr->m_model, SIGNAL(stopSelected(QtGradientStop*,bool)),
456 this, SLOT(slotStopSelected(QtGradientStop*,bool)));
457 connect(d_ptr->m_model, SIGNAL(currentStopChanged(QtGradientStop*)),
458 this, SLOT(slotCurrentStopChanged(QtGradientStop*)));
459
460 QList<QtGradientStop *> stops = d_ptr->m_model->stops().values();
461 QListIterator<QtGradientStop *> itStop(stops);
462 while (itStop.hasNext())
463 d_ptr->slotStopAdded(itStop.next());
464
465 QList<QtGradientStop *> selected = d_ptr->m_model->selectedStops();
466 QListIterator<QtGradientStop *> itSelect(selected);
467 while (itSelect.hasNext())
468 d_ptr->slotStopSelected(itSelect.next(), true);
469
470 d_ptr->slotCurrentStopChanged(d_ptr->m_model->currentStop());
471 }
472}
473
474void QtGradientStopsWidget::mousePressEvent(QMouseEvent *e)
475{
476 typedef QtGradientStopsModel::PositionStopMap PositionStopMap;
477 if (!d_ptr->m_model)
478 return;
479
480 if (e->button() != Qt::LeftButton)
481 return;
482
483 d_ptr->m_moving = true;
484
485 d_ptr->m_moveStops.clear();
486 d_ptr->m_moveOriginal.clear();
487 d_ptr->m_clickPos = e->pos();
488 QtGradientStop *stop = d_ptr->stopAt(e->pos());
489 if (stop) {
490 if (e->modifiers() & Qt::ControlModifier) {
491 d_ptr->m_model->selectStop(stop, !d_ptr->m_model->isSelected(stop));
492 } else if (e->modifiers() & Qt::ShiftModifier) {
493 QtGradientStop *oldCurrent = d_ptr->m_model->currentStop();
494 if (oldCurrent) {
495 PositionStopMap stops = d_ptr->m_model->stops();
496 PositionStopMap::ConstIterator itSt = stops.constFind(oldCurrent->position());
497 if (itSt != stops.constEnd()) {
498 while (itSt != stops.constFind(stop->position())) {
499 d_ptr->m_model->selectStop(itSt.value(), true);
500 if (oldCurrent->position() < stop->position())
501 ++itSt;
502 else
503 --itSt;
504 }
505 }
506 }
507 d_ptr->m_model->selectStop(stop, true);
508 } else {
509 if (!d_ptr->m_model->isSelected(stop)) {
510 d_ptr->m_model->clearSelection();
511 d_ptr->m_model->selectStop(stop, true);
512 }
513 }
514 d_ptr->setupMove(stop, e->pos().x());
515 } else {
516 d_ptr->m_model->clearSelection();
517 d_ptr->m_rubber->setGeometry(QRect(d_ptr->m_clickPos, QSize()));
518 d_ptr->m_rubber->show();
519 }
520 viewport()->update();
521}
522
523void QtGradientStopsWidget::mouseReleaseEvent(QMouseEvent *e)
524{
525 if (!d_ptr->m_model)
526 return;
527
528 if (e->button() != Qt::LeftButton)
529 return;
530
531 d_ptr->m_moving = false;
532 d_ptr->m_rubber->hide();
533 d_ptr->m_moveStops.clear();
534 d_ptr->m_moveOriginal.clear();
535}
536
537void QtGradientStopsWidget::mouseMoveEvent(QMouseEvent *e)
538{
539 typedef QtGradientStopsWidgetPrivate::PositionColorMap PositionColorMap;
540 typedef QtGradientStopsModel::PositionStopMap PositionStopMap;
541 typedef QtGradientStopsWidgetPrivate::StopPositionMap StopPositionMap;
542 if (!d_ptr->m_model)
543 return;
544
545 if (!(e->buttons() & Qt::LeftButton))
546 return;
547
548 if (!d_ptr->m_moving)
549 return;
550
551 if (!d_ptr->m_moveStops.isEmpty()) {
552 double maxOffset = 0.0;
553 double minOffset = 0.0;
554 bool first = true;
555 StopPositionMap::ConstIterator itStop = d_ptr->m_moveStops.constBegin();
556 while (itStop != d_ptr->m_moveStops.constEnd()) {
557 double offset = itStop.value();
558
559 if (first) {
560 maxOffset = offset;
561 minOffset = offset;
562 first = false;
563 } else {
564 if (maxOffset < offset)
565 maxOffset = offset;
566 else if (minOffset > offset)
567 minOffset = offset;
568 }
569 ++itStop;
570 }
571
572 double viewportMin = d_ptr->toViewport(-minOffset);
573 double viewportMax = d_ptr->toViewport(1.0 - maxOffset);
574
575 PositionStopMap newPositions;
576
577 int viewportX = e->pos().x() - d_ptr->m_moveOffset;
578
579 if (viewportX > viewport()->size().width())
580 viewportX = viewport()->size().width();
581 else if (viewportX < 0)
582 viewportX = 0;
583
584 double posX = d_ptr->fromViewport(viewportX);
585
586 if (viewportX > viewportMax)
587 posX = 1.0 - maxOffset;
588 else if (viewportX < viewportMin)
589 posX = -minOffset;
590
591 itStop = d_ptr->m_moveStops.constBegin();
592 while (itStop != d_ptr->m_moveStops.constEnd()) {
593 QtGradientStop *stop = itStop.key();
594
595 newPositions[posX + itStop.value()] = stop;
596
597 ++itStop;
598 }
599
600 bool forward = true;
601 PositionStopMap::ConstIterator itNewPos = newPositions.constBegin();
602 if (itNewPos.value()->position() < itNewPos.key())
603 forward = false;
604
605 itNewPos = forward ? newPositions.constBegin() : newPositions.constEnd();
606 while (itNewPos != (forward ? newPositions.constEnd() : newPositions.constBegin())) {
607 if (!forward)
608 --itNewPos;
609 QtGradientStop *stop = itNewPos.value();
610 double newPos = itNewPos.key();
611 if (newPos > 1)
612 newPos = 1;
613 else if (newPos < 0)
614 newPos = 0;
615
616 QtGradientStop *existingStop = d_ptr->m_model->at(newPos);
617 if (existingStop && !d_ptr->m_moveStops.contains(existingStop))
618 d_ptr->m_model->removeStop(existingStop);
619 d_ptr->m_model->moveStop(stop, newPos);
620
621 if (forward)
622 ++itNewPos;
623 }
624
625 PositionColorMap::ConstIterator itOld = d_ptr->m_moveOriginal.constBegin();
626 while (itOld != d_ptr->m_moveOriginal.constEnd()) {
627 double position = itOld.key();
628 if (!d_ptr->m_model->at(position))
629 d_ptr->m_model->addStop(position, itOld.value());
630
631 ++itOld;
632 }
633
634 } else {
635 QRect r(QRect(d_ptr->m_clickPos, e->pos()).normalized());
636 r.translate(1, 0);
637 d_ptr->m_rubber->setGeometry(r);
638 //d_ptr->m_model->clearSelection();
639
640 int xv1 = d_ptr->m_clickPos.x();
641 int xv2 = e->pos().x();
642 if (xv1 > xv2) {
643 int temp = xv1;
644 xv1 = xv2;
645 xv2 = temp;
646 }
647 int yv1 = d_ptr->m_clickPos.y();
648 int yv2 = e->pos().y();
649 if (yv1 > yv2) {
650 int temp = yv1;
651 yv1 = yv2;
652 yv2 = temp;
653 }
654
655 QPoint p1, p2;
656
657 if (yv2 < d_ptr->m_handleSize / 2) {
658 p1 = QPoint(xv1, yv2);
659 p2 = QPoint(xv2, yv2);
660 } else if (yv1 > d_ptr->m_handleSize / 2) {
661 p1 = QPoint(xv1, yv1);
662 p2 = QPoint(xv2, yv1);
663 } else {
664 p1 = QPoint(xv1, qRound(d_ptr->m_handleSize / 2));
665 p2 = QPoint(xv2, qRound(d_ptr->m_handleSize / 2));
666 }
667
668 QList<QtGradientStop *> beginList = d_ptr->stopsAt(p1);
669 QList<QtGradientStop *> endList = d_ptr->stopsAt(p2);
670
671 double x1 = d_ptr->fromViewport(xv1);
672 double x2 = d_ptr->fromViewport(xv2);
673
674 QListIterator<QtGradientStop *> itStop(d_ptr->m_stops);
675 while (itStop.hasNext()) {
676 QtGradientStop *stop = itStop.next();
677 if ((stop->position() >= x1 && stop->position() <= x2) ||
678 beginList.contains(stop) || endList.contains(stop))
679 d_ptr->m_model->selectStop(stop, true);
680 else
681 d_ptr->m_model->selectStop(stop, false);
682 }
683 }
684}
685
686void QtGradientStopsWidget::mouseDoubleClickEvent(QMouseEvent *e)
687{
688 if (!d_ptr->m_model)
689 return;
690
691 if (e->button() != Qt::LeftButton)
692 return;
693
694 if (d_ptr->m_clickPos != e->pos()) {
695 mousePressEvent(e);
696 return;
697 }
698 d_ptr->m_moving = true;
699 d_ptr->m_moveStops.clear();
700 d_ptr->m_moveOriginal.clear();
701
702 QtGradientStop *stop = d_ptr->newStop(e->pos());
703
704 if (!stop)
705 return;
706
707 d_ptr->m_model->clearSelection();
708 d_ptr->m_model->selectStop(stop, true);
709
710 d_ptr->setupMove(stop, e->pos().x());
711
712 viewport()->update();
713}
714
715void QtGradientStopsWidget::keyPressEvent(QKeyEvent *e)
716{
717 typedef QtGradientStopsModel::PositionStopMap PositionStopMap;
718 if (!d_ptr->m_model)
719 return;
720
721 if (e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace) {
722 d_ptr->m_model->deleteStops();
723 } else if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right ||
724 e->key() == Qt::Key_Home || e->key() == Qt::Key_End) {
725 PositionStopMap stops = d_ptr->m_model->stops();
726 if (stops.isEmpty())
727 return;
728 QtGradientStop *newCurrent = 0;
729 QtGradientStop *current = d_ptr->m_model->currentStop();
730 if (!current || e->key() == Qt::Key_Home || e->key() == Qt::Key_End) {
731 if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Home)
732 newCurrent = stops.constBegin().value();
733 else if (e->key() == Qt::Key_Right || e->key() == Qt::Key_End)
734 newCurrent = (--stops.constEnd()).value();
735 } else {
736 PositionStopMap::ConstIterator itStop = stops.constBegin();
737 while (itStop.value() != current)
738 ++itStop;
739 if (e->key() == Qt::Key_Left && itStop != stops.constBegin())
740 --itStop;
741 else if (e->key() == Qt::Key_Right && itStop != --stops.constEnd())
742 ++itStop;
743 newCurrent = itStop.value();
744 }
745 d_ptr->m_model->clearSelection();
746 d_ptr->m_model->selectStop(newCurrent, true);
747 d_ptr->m_model->setCurrentStop(newCurrent);
748 d_ptr->ensureVisible(newCurrent);
749 } else if (e->key() == Qt::Key_A) {
750 if (e->modifiers() & Qt::ControlModifier)
751 d_ptr->m_model->selectAll();
752 }
753}
754
755void QtGradientStopsWidget::paintEvent(QPaintEvent *e)
756{
757 Q_UNUSED(e)
758 if (!d_ptr->m_model)
759 return;
760
761 QtGradientStopsModel *model = d_ptr->m_model;
762#ifndef QT_NO_DRAGANDDROP
763 if (d_ptr->m_dragModel)
764 model = d_ptr->m_dragModel;
765#endif
766
767 QSize size = viewport()->size();
768 int w = size.width();
769 double h = size.height() - d_ptr->m_handleSize;
770 if (w <= 0)
771 return;
772
773 QPixmap pix(size);
774 QPainter p;
775
776 if (d_ptr->m_backgroundCheckered) {
777 int pixSize = 20;
778 QPixmap pm(2 * pixSize, 2 * pixSize);
779 QPainter pmp(&pm);
780 pmp.fillRect(0, 0, pixSize, pixSize, Qt::white);
781 pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white);
782 pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black);
783 pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black);
784
785 p.begin(&pix);
786 p.setBrushOrigin((size.width() % pixSize + pixSize) / 2, (size.height() % pixSize + pixSize) / 2);
787 p.fillRect(viewport()->rect(), pm);
788 p.setBrushOrigin(0, 0);
789 } else {
790 p.begin(viewport());
791 }
792
793 double viewBegin = (double)w * horizontalScrollBar()->value() / d_ptr->m_scaleFactor;
794
795 int val = horizontalScrollBar()->value();
796 int max = horizontalScrollBar()->maximum();
797
798 double begin = (double)val / (d_ptr->m_scaleFactor + max);
799 double end = (double)(val + d_ptr->m_scaleFactor) / (d_ptr->m_scaleFactor + max);
800 double width = end - begin;
801
802 if (h > 0) {
803 QLinearGradient lg(0, 0, w, 0);
804 QMap<qreal, QtGradientStop *> stops = model->stops();
805 QMapIterator<qreal, QtGradientStop *> itStop(stops);
806 while (itStop.hasNext()) {
807 QtGradientStop *stop = itStop.next().value();
808 double pos = stop->position();
809 if (pos >= begin && pos <= end) {
810 double gradPos = (pos - begin) / width;
811 QColor c = stop->color();
812 lg.setColorAt(gradPos, c);
813 }
814 //lg.setColorAt(stop->position(), stop->color());
815 }
816 lg.setColorAt(0, model->color(begin));
817 lg.setColorAt(1, model->color(end));
818 QImage img(w, 1, QImage::Format_ARGB32_Premultiplied);
819 QPainter p1(&img);
820 p1.setCompositionMode(QPainter::CompositionMode_Source);
821
822 /*
823 if (viewBegin != 0)
824 p1.translate(-viewBegin, 0);
825 if (d_ptr->m_zoom != 1)
826 p1.scale(d_ptr->m_zoom, 1);
827 */
828 p1.fillRect(0, 0, w, 1, lg);
829
830 p.fillRect(QRectF(0, d_ptr->m_handleSize, w, h), QPixmap::fromImage(img));
831 }
832
833
834 double handleWidth = d_ptr->m_handleSize * d_ptr->m_scaleFactor / (w * (d_ptr->m_scaleFactor + max));
835
836 QColor insideColor = QColor::fromRgb(0x20, 0x20, 0x20, 0xFF);
837 QColor borderColor = QColor(Qt::white);
838 QColor drawColor;
839 QColor back1 = QColor(Qt::lightGray);
840 QColor back2 = QColor(Qt::darkGray);
841 QColor back = QColor::fromRgb((back1.red() + back2.red()) / 2,
842 (back1.green() + back2.green()) / 2,
843 (back1.blue() + back2.blue()) / 2);
844
845 QPen pen;
846 p.setRenderHint(QPainter::Antialiasing);
847 QListIterator<QtGradientStop *> itStop(d_ptr->m_stops);
848 itStop.toBack();
849 while (itStop.hasPrevious()) {
850 QtGradientStop *stop = itStop.previous();
851 double x = stop->position();
852 if (x >= begin - handleWidth / 2 && x <= end + handleWidth / 2) {
853 double viewX = x * w * (d_ptr->m_scaleFactor + max) / d_ptr->m_scaleFactor - viewBegin;
854 p.save();
855 QColor c = stop->color();
856#ifndef QT_NO_DRAGANDDROP
857 if (stop == d_ptr->m_dragStop)
858 c = d_ptr->m_dragColor;
859#endif
860 if ((0.3 * c.redF() + 0.59 * c.greenF() + 0.11 * c.blueF()) * c.alphaF() +
861 (0.3 * back.redF() + 0.59 * back.greenF() + 0.11 * back.blueF()) * (1.0 - c.alphaF()) < 0.5) {
862 drawColor = QColor::fromRgb(0xC0, 0xC0, 0xC0, 0xB0);
863 } else {
864 drawColor = QColor::fromRgb(0x40, 0x40, 0x40, 0x80);
865 }
866 QRectF rect(viewX - d_ptr->m_handleSize / 2, 0, d_ptr->m_handleSize, d_ptr->m_handleSize);
867 rect.adjust(0.5, 0.5, -0.5, -0.5);
868 if (h > 0) {
869 pen.setWidthF(1);
870 QLinearGradient lg(0, d_ptr->m_handleSize, 0, d_ptr->m_handleSize + h / 2);
871 lg.setColorAt(0, drawColor);
872 QColor alphaZero = drawColor;
873 alphaZero.setAlpha(0);
874 lg.setColorAt(1, alphaZero);
875 pen.setBrush(lg);
876 p.setPen(pen);
877 p.drawLine(QPointF(viewX, d_ptr->m_handleSize), QPointF(viewX, d_ptr->m_handleSize + h / 2));
878
879 pen.setWidthF(1);
880 pen.setBrush(drawColor);
881 p.setPen(pen);
882 QRectF r1 = rect.adjusted(0.5, 0.5, -0.5, -0.5);
883 QRectF r2 = rect.adjusted(1.5, 1.5, -1.5, -1.5);
884 QColor inColor = QColor::fromRgb(0x80, 0x80, 0x80, 0x80);
885 if (!d_ptr->m_model->isSelected(stop)) {
886 p.setBrush(c);
887 p.drawEllipse(rect);
888 } else {
889 pen.setBrush(insideColor);
890 pen.setWidthF(2);
891 p.setPen(pen);
892 p.setBrush(Qt::NoBrush);
893 p.drawEllipse(r1);
894
895 pen.setBrush(inColor);
896 pen.setWidthF(1);
897 p.setPen(pen);
898 p.setBrush(c);
899 p.drawEllipse(r2);
900 }
901
902 if (d_ptr->m_model->currentStop() == stop) {
903 p.setBrush(Qt::NoBrush);
904 pen.setWidthF(5);
905 pen.setBrush(drawColor);
906 int corr = 4;
907 if (!d_ptr->m_model->isSelected(stop)) {
908 corr = 3;
909 pen.setWidthF(7);
910 }
911 p.setPen(pen);
912 p.drawEllipse(rect.adjusted(corr, corr, -corr, -corr));
913 }
914
915 }
916 p.restore();
917 }
918 }
919 if (d_ptr->m_backgroundCheckered) {
920 p.end();
921 p.begin(viewport());
922 p.drawPixmap(0, 0, pix);
923 }
924 p.end();
925}
926
927void QtGradientStopsWidget::focusInEvent(QFocusEvent *e)
928{
929 Q_UNUSED(e)
930 viewport()->update();
931}
932
933void QtGradientStopsWidget::focusOutEvent(QFocusEvent *e)
934{
935 Q_UNUSED(e)
936 viewport()->update();
937}
938
939void QtGradientStopsWidget::contextMenuEvent(QContextMenuEvent *e)
940{
941 if (!d_ptr->m_model)
942 return;
943
944 d_ptr->m_clickPos = e->pos();
945
946 QMenu menu(this);
947 QAction *newStopAction = new QAction(tr("New Stop"), &menu);
948 QAction *deleteAction = new QAction(tr("Delete"), &menu);
949 QAction *flipAllAction = new QAction(tr("Flip All"), &menu);
950 QAction *selectAllAction = new QAction(tr("Select All"), &menu);
951 QAction *zoomInAction = new QAction(tr("Zoom In"), &menu);
952 QAction *zoomOutAction = new QAction(tr("Zoom Out"), &menu);
953 QAction *zoomAllAction = new QAction(tr("Reset Zoom"), &menu);
954 if (d_ptr->m_model->selectedStops().isEmpty() && !d_ptr->m_model->currentStop())
955 deleteAction->setEnabled(false);
956 if (zoom() <= 1) {
957 zoomOutAction->setEnabled(false);
958 zoomAllAction->setEnabled(false);
959 } else if (zoom() >= 100) {
960 zoomInAction->setEnabled(false);
961 }
962 connect(newStopAction, SIGNAL(triggered()), this, SLOT(slotNewStop()));
963 connect(deleteAction, SIGNAL(triggered()), this, SLOT(slotDelete()));
964 connect(flipAllAction, SIGNAL(triggered()), this, SLOT(slotFlipAll()));
965 connect(selectAllAction, SIGNAL(triggered()), this, SLOT(slotSelectAll()));
966 connect(zoomInAction, SIGNAL(triggered()), this, SLOT(slotZoomIn()));
967 connect(zoomOutAction, SIGNAL(triggered()), this, SLOT(slotZoomOut()));
968 connect(zoomAllAction, SIGNAL(triggered()), this, SLOT(slotResetZoom()));
969 menu.addAction(newStopAction);
970 menu.addAction(deleteAction);
971 menu.addAction(flipAllAction);
972 menu.addAction(selectAllAction);
973 menu.addSeparator();
974 menu.addAction(zoomInAction);
975 menu.addAction(zoomOutAction);
976 menu.addAction(zoomAllAction);
977 menu.exec(e->globalPos());
978}
979
980void QtGradientStopsWidget::wheelEvent(QWheelEvent *e)
981{
982 int numDegrees = e->delta() / 8;
983 int numSteps = numDegrees / 15;
984
985 int shift = numSteps;
986 if (shift < 0)
987 shift = -shift;
988 int pow = 1 << shift;
989 //const double c = 0.7071067; // 2 steps per doubled value
990 const double c = 0.5946036; // 4 steps pre doubled value
991 // in general c = pow(2, 1 / n) / 2; where n is the step
992 double factor = pow * c;
993
994 double newZoom = zoom();
995 if (numSteps < 0)
996 newZoom /= factor;
997 else
998 newZoom *= factor;
999 if (newZoom > 100)
1000 newZoom = 100;
1001 if (newZoom < 1)
1002 newZoom = 1;
1003
1004 if (newZoom == zoom())
1005 return;
1006
1007 setZoom(newZoom);
1008 emit zoomChanged(zoom());
1009}
1010
1011#ifndef QT_NO_DRAGANDDROP
1012void QtGradientStopsWidget::dragEnterEvent(QDragEnterEvent *event)
1013{
1014 const QMimeData *mime = event->mimeData();
1015 if (!mime->hasColor())
1016 return;
1017 event->accept();
1018 d_ptr->m_dragModel = d_ptr->m_model->clone();
1019
1020 d_ptr->m_dragColor = qvariant_cast<QColor>(mime->colorData());
1021 update();
1022}
1023
1024void QtGradientStopsWidget::dragMoveEvent(QDragMoveEvent *event)
1025{
1026 QRectF rect = viewport()->rect();
1027 rect.adjust(0, d_ptr->m_handleSize, 0, 0);
1028 double x = d_ptr->fromViewport(event->pos().x());
1029 QtGradientStop *dragStop = d_ptr->stopAt(event->pos());
1030 if (dragStop) {
1031 event->accept();
1032 d_ptr->removeClonedStop();
1033 d_ptr->changeStop(dragStop->position());
1034 } else if (rect.contains(event->pos())) {
1035 event->accept();
1036 if (d_ptr->m_model->at(x)) {
1037 d_ptr->removeClonedStop();
1038 d_ptr->changeStop(x);
1039 } else {
1040 d_ptr->restoreChangedStop();
1041 d_ptr->cloneStop(x);
1042 }
1043 } else {
1044 event->ignore();
1045 d_ptr->removeClonedStop();
1046 d_ptr->restoreChangedStop();
1047 }
1048
1049 update();
1050}
1051
1052void QtGradientStopsWidget::dragLeaveEvent(QDragLeaveEvent *event)
1053{
1054 event->accept();
1055 d_ptr->clearDrag();
1056 update();
1057}
1058
1059void QtGradientStopsWidget::dropEvent(QDropEvent *event)
1060{
1061 event->accept();
1062 if (!d_ptr->m_dragModel)
1063 return;
1064
1065 if (d_ptr->m_changedStop)
1066 d_ptr->m_model->changeStop(d_ptr->m_model->at(d_ptr->m_changedStop->position()), d_ptr->m_dragColor);
1067 else if (d_ptr->m_clonedStop)
1068 d_ptr->m_model->addStop(d_ptr->m_clonedStop->position(), d_ptr->m_dragColor);
1069
1070 d_ptr->clearDrag();
1071 update();
1072}
1073
1074void QtGradientStopsWidgetPrivate::clearDrag()
1075{
1076 removeClonedStop();
1077 restoreChangedStop();
1078 delete m_dragModel;
1079 m_dragModel = 0;
1080}
1081
1082void QtGradientStopsWidgetPrivate::removeClonedStop()
1083{
1084 if (!m_clonedStop)
1085 return;
1086 m_dragModel->removeStop(m_clonedStop);
1087 m_clonedStop = 0;
1088}
1089
1090void QtGradientStopsWidgetPrivate::restoreChangedStop()
1091{
1092 if (!m_changedStop)
1093 return;
1094 m_dragModel->changeStop(m_changedStop, m_model->at(m_changedStop->position())->color());
1095 m_changedStop = 0;
1096 m_dragStop = 0;
1097}
1098
1099void QtGradientStopsWidgetPrivate::changeStop(qreal pos)
1100{
1101 QtGradientStop *stop = m_dragModel->at(pos);
1102 if (!stop)
1103 return;
1104
1105 m_dragModel->changeStop(stop, m_dragColor);
1106 m_changedStop = stop;
1107 m_dragStop = m_model->at(stop->position());
1108}
1109
1110void QtGradientStopsWidgetPrivate::cloneStop(qreal pos)
1111{
1112 if (m_clonedStop) {
1113 m_dragModel->moveStop(m_clonedStop, pos);
1114 return;
1115 }
1116 QtGradientStop *stop = m_dragModel->at(pos);
1117 if (stop)
1118 return;
1119
1120 m_clonedStop = m_dragModel->addStop(pos, m_dragColor);
1121}
1122
1123#endif
1124
1125void QtGradientStopsWidget::setZoom(double zoom)
1126{
1127 double z = zoom;
1128 if (z < 1)
1129 z = 1;
1130 else if (z > 100)
1131 z = 100;
1132
1133 if (d_ptr->m_zoom == z)
1134 return;
1135
1136 d_ptr->m_zoom = z;
1137 int oldMax = horizontalScrollBar()->maximum();
1138 int oldVal = horizontalScrollBar()->value();
1139 horizontalScrollBar()->setRange(0, qRound(d_ptr->m_scaleFactor * (d_ptr->m_zoom - 1)));
1140 int newMax = horizontalScrollBar()->maximum();
1141 double newVal = (oldVal + (double)d_ptr->m_scaleFactor / 2) * (newMax + d_ptr->m_scaleFactor)
1142 / (oldMax + d_ptr->m_scaleFactor) - (double)d_ptr->m_scaleFactor / 2;
1143 horizontalScrollBar()->setValue(qRound(newVal));
1144 viewport()->update();
1145}
1146
1147double QtGradientStopsWidget::zoom() const
1148{
1149 return d_ptr->m_zoom;
1150}
1151
1152QT_END_NAMESPACE
1153
1154#include "moc_qtgradientstopswidget.cpp"
Note: See TracBrowser for help on using the repository browser.