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

Last change on this file since 397 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 36.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department 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)
364{
365 d_ptr = new QtGradientStopsWidgetPrivate;
366 d_ptr->q_ptr = this;
367 d_ptr->m_backgroundCheckered = true;
368 d_ptr->m_model = 0;
369 d_ptr->m_handleSize = 25.0;
370 d_ptr->m_scaleFactor = 1000;
371 d_ptr->m_moving = false;
372 d_ptr->m_zoom = 1;
373 d_ptr->m_rubber = new QRubberBand(QRubberBand::Rectangle, this);
374#ifndef QT_NO_DRAGANDDROP
375 d_ptr->m_dragStop = 0;
376 d_ptr->m_changedStop = 0;
377 d_ptr->m_clonedStop = 0;
378 d_ptr->m_dragModel = 0;
379#endif
380 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
381 setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
382 horizontalScrollBar()->setRange(0, (int)(d_ptr->m_scaleFactor * (d_ptr->m_zoom - 1) + 0.5));
383 horizontalScrollBar()->setPageStep(d_ptr->m_scaleFactor);
384 horizontalScrollBar()->setSingleStep(4);
385 viewport()->setAutoFillBackground(false);
386
387 setAcceptDrops(true);
388
389 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred));
390}
391
392QtGradientStopsWidget::~QtGradientStopsWidget()
393{
394 delete d_ptr;
395}
396
397QSize QtGradientStopsWidget::sizeHint() const
398{
399 return QSize(qRound(2 * d_ptr->m_handleSize), qRound(3 * d_ptr->m_handleSize) + horizontalScrollBar()->sizeHint().height());
400}
401
402QSize QtGradientStopsWidget::minimumSizeHint() const
403{
404 return QSize(qRound(2 * d_ptr->m_handleSize), qRound(3 * d_ptr->m_handleSize) + horizontalScrollBar()->minimumSizeHint().height());
405}
406
407void QtGradientStopsWidget::setBackgroundCheckered(bool checkered)
408{
409 if (d_ptr->m_backgroundCheckered == checkered)
410 return;
411 d_ptr->m_backgroundCheckered = checkered;
412 update();
413}
414
415bool QtGradientStopsWidget::isBackgroundCheckered() const
416{
417 return d_ptr->m_backgroundCheckered;
418}
419
420void QtGradientStopsWidget::setGradientStopsModel(QtGradientStopsModel *model)
421{
422 if (d_ptr->m_model == model)
423 return;
424
425 if (d_ptr->m_model) {
426 disconnect(d_ptr->m_model, SIGNAL(stopAdded(QtGradientStop *)),
427 this, SLOT(slotStopAdded(QtGradientStop *)));
428 disconnect(d_ptr->m_model, SIGNAL(stopRemoved(QtGradientStop *)),
429 this, SLOT(slotStopRemoved(QtGradientStop *)));
430 disconnect(d_ptr->m_model, SIGNAL(stopMoved(QtGradientStop *, qreal)),
431 this, SLOT(slotStopMoved(QtGradientStop *, qreal)));
432 disconnect(d_ptr->m_model, SIGNAL(stopsSwapped(QtGradientStop *, QtGradientStop *)),
433 this, SLOT(slotStopsSwapped(QtGradientStop *, QtGradientStop *)));
434 disconnect(d_ptr->m_model, SIGNAL(stopChanged(QtGradientStop *, const QColor &)),
435 this, SLOT(slotStopChanged(QtGradientStop *, const QColor &)));
436 disconnect(d_ptr->m_model, SIGNAL(stopSelected(QtGradientStop *, bool)),
437 this, SLOT(slotStopSelected(QtGradientStop *, bool)));
438 disconnect(d_ptr->m_model, SIGNAL(currentStopChanged(QtGradientStop *)),
439 this, SLOT(slotCurrentStopChanged(QtGradientStop *)));
440
441 d_ptr->m_stops.clear();
442 }
443
444 d_ptr->m_model = model;
445
446 if (d_ptr->m_model) {
447 connect(d_ptr->m_model, SIGNAL(stopAdded(QtGradientStop *)),
448 this, SLOT(slotStopAdded(QtGradientStop *)));
449 connect(d_ptr->m_model, SIGNAL(stopRemoved(QtGradientStop *)),
450 this, SLOT(slotStopRemoved(QtGradientStop *)));
451 connect(d_ptr->m_model, SIGNAL(stopMoved(QtGradientStop *, qreal)),
452 this, SLOT(slotStopMoved(QtGradientStop *, qreal)));
453 connect(d_ptr->m_model, SIGNAL(stopsSwapped(QtGradientStop *, QtGradientStop *)),
454 this, SLOT(slotStopsSwapped(QtGradientStop *, QtGradientStop *)));
455 connect(d_ptr->m_model, SIGNAL(stopChanged(QtGradientStop *, const QColor &)),
456 this, SLOT(slotStopChanged(QtGradientStop *, const QColor &)));
457 connect(d_ptr->m_model, SIGNAL(stopSelected(QtGradientStop *, bool)),
458 this, SLOT(slotStopSelected(QtGradientStop *, bool)));
459 connect(d_ptr->m_model, SIGNAL(currentStopChanged(QtGradientStop *)),
460 this, SLOT(slotCurrentStopChanged(QtGradientStop *)));
461
462 QList<QtGradientStop *> stops = d_ptr->m_model->stops().values();
463 QListIterator<QtGradientStop *> itStop(stops);
464 while (itStop.hasNext())
465 d_ptr->slotStopAdded(itStop.next());
466
467 QList<QtGradientStop *> selected = d_ptr->m_model->selectedStops();
468 QListIterator<QtGradientStop *> itSelect(selected);
469 while (itSelect.hasNext())
470 d_ptr->slotStopSelected(itSelect.next(), true);
471
472 d_ptr->slotCurrentStopChanged(d_ptr->m_model->currentStop());
473 }
474}
475
476void QtGradientStopsWidget::mousePressEvent(QMouseEvent *e)
477{
478 typedef QtGradientStopsModel::PositionStopMap PositionStopMap;
479 if (!d_ptr->m_model)
480 return;
481
482 if (e->button() != Qt::LeftButton)
483 return;
484
485 d_ptr->m_moving = true;
486
487 d_ptr->m_moveStops.clear();
488 d_ptr->m_moveOriginal.clear();
489 d_ptr->m_clickPos = e->pos();
490 QtGradientStop *stop = d_ptr->stopAt(e->pos());
491 if (stop) {
492 if (e->modifiers() & Qt::ControlModifier) {
493 d_ptr->m_model->selectStop(stop, !d_ptr->m_model->isSelected(stop));
494 } else if (e->modifiers() & Qt::ShiftModifier) {
495 QtGradientStop *oldCurrent = d_ptr->m_model->currentStop();
496 if (oldCurrent) {
497 PositionStopMap stops = d_ptr->m_model->stops();
498 PositionStopMap::ConstIterator itSt = stops.constFind(oldCurrent->position());
499 if (itSt != stops.constEnd()) {
500 while (itSt != stops.constFind(stop->position())) {
501 d_ptr->m_model->selectStop(itSt.value(), true);
502 if (oldCurrent->position() < stop->position())
503 ++itSt;
504 else
505 --itSt;
506 }
507 }
508 }
509 d_ptr->m_model->selectStop(stop, true);
510 } else {
511 if (!d_ptr->m_model->isSelected(stop)) {
512 d_ptr->m_model->clearSelection();
513 d_ptr->m_model->selectStop(stop, true);
514 }
515 }
516 d_ptr->setupMove(stop, e->pos().x());
517 } else {
518 d_ptr->m_model->clearSelection();
519 d_ptr->m_rubber->setGeometry(QRect(d_ptr->m_clickPos, QSize()));
520 d_ptr->m_rubber->show();
521 }
522 viewport()->update();
523}
524
525void QtGradientStopsWidget::mouseReleaseEvent(QMouseEvent *e)
526{
527 if (!d_ptr->m_model)
528 return;
529
530 if (e->button() != Qt::LeftButton)
531 return;
532
533 d_ptr->m_moving = false;
534 d_ptr->m_rubber->hide();
535 d_ptr->m_moveStops.clear();
536 d_ptr->m_moveOriginal.clear();
537}
538
539void QtGradientStopsWidget::mouseMoveEvent(QMouseEvent *e)
540{
541 typedef QtGradientStopsWidgetPrivate::PositionColorMap PositionColorMap;
542 typedef QtGradientStopsModel::PositionStopMap PositionStopMap;
543 typedef QtGradientStopsWidgetPrivate::StopPositionMap StopPositionMap;
544 if (!d_ptr->m_model)
545 return;
546
547 if (!(e->buttons() & Qt::LeftButton))
548 return;
549
550 if (!d_ptr->m_moving)
551 return;
552
553 if (!d_ptr->m_moveStops.isEmpty()) {
554 double maxOffset = 0.0;
555 double minOffset = 0.0;
556 bool first = true;
557 StopPositionMap::ConstIterator itStop = d_ptr->m_moveStops.constBegin();
558 while (itStop != d_ptr->m_moveStops.constEnd()) {
559 double offset = itStop.value();
560
561 if (first) {
562 maxOffset = offset;
563 minOffset = offset;
564 first = false;
565 } else {
566 if (maxOffset < offset)
567 maxOffset = offset;
568 else if (minOffset > offset)
569 minOffset = offset;
570 }
571 ++itStop;
572 }
573
574 double viewportMin = d_ptr->toViewport(-minOffset);
575 double viewportMax = d_ptr->toViewport(1.0 - maxOffset);
576
577 PositionStopMap newPositions;
578
579 int viewportX = e->pos().x() - d_ptr->m_moveOffset;
580
581 if (viewportX > viewport()->size().width())
582 viewportX = viewport()->size().width();
583 else if (viewportX < 0)
584 viewportX = 0;
585
586 double posX = d_ptr->fromViewport(viewportX);
587
588 if (viewportX > viewportMax)
589 posX = 1.0 - maxOffset;
590 else if (viewportX < viewportMin)
591 posX = -minOffset;
592
593 itStop = d_ptr->m_moveStops.constBegin();
594 while (itStop != d_ptr->m_moveStops.constEnd()) {
595 QtGradientStop *stop = itStop.key();
596
597 newPositions[posX + itStop.value()] = stop;
598
599 ++itStop;
600 }
601
602 bool forward = true;
603 PositionStopMap::ConstIterator itNewPos = newPositions.constBegin();
604 if (itNewPos.value()->position() < itNewPos.key())
605 forward = false;
606
607 itNewPos = forward ? newPositions.constBegin() : newPositions.constEnd();
608 while (itNewPos != (forward ? newPositions.constEnd() : newPositions.constBegin())) {
609 if (!forward)
610 --itNewPos;
611 QtGradientStop *stop = itNewPos.value();
612 double newPos = itNewPos.key();
613 if (newPos > 1)
614 newPos = 1;
615 else if (newPos < 0)
616 newPos = 0;
617
618 QtGradientStop *existingStop = d_ptr->m_model->at(newPos);
619 if (existingStop && !d_ptr->m_moveStops.contains(existingStop))
620 d_ptr->m_model->removeStop(existingStop);
621 d_ptr->m_model->moveStop(stop, newPos);
622
623 if (forward)
624 ++itNewPos;
625 }
626
627 PositionColorMap::ConstIterator itOld = d_ptr->m_moveOriginal.constBegin();
628 while (itOld != d_ptr->m_moveOriginal.constEnd()) {
629 double position = itOld.key();
630 if (!d_ptr->m_model->at(position))
631 d_ptr->m_model->addStop(position, itOld.value());
632
633 ++itOld;
634 }
635
636 } else {
637 QRect r(QRect(d_ptr->m_clickPos, e->pos()).normalized());
638 r.translate(1, 0);
639 d_ptr->m_rubber->setGeometry(r);
640 //d_ptr->m_model->clearSelection();
641
642 int xv1 = d_ptr->m_clickPos.x();
643 int xv2 = e->pos().x();
644 if (xv1 > xv2) {
645 int temp = xv1;
646 xv1 = xv2;
647 xv2 = temp;
648 }
649 int yv1 = d_ptr->m_clickPos.y();
650 int yv2 = e->pos().y();
651 if (yv1 > yv2) {
652 int temp = yv1;
653 yv1 = yv2;
654 yv2 = temp;
655 }
656
657 QPoint p1, p2;
658
659 if (yv2 < d_ptr->m_handleSize / 2) {
660 p1 = QPoint(xv1, yv2);
661 p2 = QPoint(xv2, yv2);
662 } else if (yv1 > d_ptr->m_handleSize / 2) {
663 p1 = QPoint(xv1, yv1);
664 p2 = QPoint(xv2, yv1);
665 } else {
666 p1 = QPoint(xv1, qRound(d_ptr->m_handleSize / 2));
667 p2 = QPoint(xv2, qRound(d_ptr->m_handleSize / 2));
668 }
669
670 QList<QtGradientStop *> beginList = d_ptr->stopsAt(p1);
671 QList<QtGradientStop *> endList = d_ptr->stopsAt(p2);
672
673 double x1 = d_ptr->fromViewport(xv1);
674 double x2 = d_ptr->fromViewport(xv2);
675
676 QListIterator<QtGradientStop *> itStop(d_ptr->m_stops);
677 while (itStop.hasNext()) {
678 QtGradientStop *stop = itStop.next();
679 if ((stop->position() >= x1 && stop->position() <= x2) ||
680 beginList.contains(stop) || endList.contains(stop))
681 d_ptr->m_model->selectStop(stop, true);
682 else
683 d_ptr->m_model->selectStop(stop, false);
684 }
685 }
686}
687
688void QtGradientStopsWidget::mouseDoubleClickEvent(QMouseEvent *e)
689{
690 if (!d_ptr->m_model)
691 return;
692
693 if (e->button() != Qt::LeftButton)
694 return;
695
696 if (d_ptr->m_clickPos != e->pos()) {
697 mousePressEvent(e);
698 return;
699 }
700 d_ptr->m_moving = true;
701 d_ptr->m_moveStops.clear();
702 d_ptr->m_moveOriginal.clear();
703
704 QtGradientStop *stop = d_ptr->newStop(e->pos());
705
706 if (!stop)
707 return;
708
709 d_ptr->m_model->clearSelection();
710 d_ptr->m_model->selectStop(stop, true);
711
712 d_ptr->setupMove(stop, e->pos().x());
713
714 viewport()->update();
715}
716
717void QtGradientStopsWidget::keyPressEvent(QKeyEvent *e)
718{
719 typedef QtGradientStopsModel::PositionStopMap PositionStopMap;
720 if (!d_ptr->m_model)
721 return;
722
723 if (e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace) {
724 d_ptr->m_model->deleteStops();
725 } else if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right ||
726 e->key() == Qt::Key_Home || e->key() == Qt::Key_End) {
727 PositionStopMap stops = d_ptr->m_model->stops();
728 if (stops.isEmpty())
729 return;
730 QtGradientStop *newCurrent = 0;
731 QtGradientStop *current = d_ptr->m_model->currentStop();
732 if (!current || e->key() == Qt::Key_Home || e->key() == Qt::Key_End) {
733 if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Home)
734 newCurrent = stops.constBegin().value();
735 else if (e->key() == Qt::Key_Right || e->key() == Qt::Key_End)
736 newCurrent = (--stops.constEnd()).value();
737 } else {
738 PositionStopMap::ConstIterator itStop = stops.constBegin();
739 while (itStop.value() != current)
740 ++itStop;
741 if (e->key() == Qt::Key_Left && itStop != stops.constBegin())
742 --itStop;
743 else if (e->key() == Qt::Key_Right && itStop != --stops.constEnd())
744 ++itStop;
745 newCurrent = itStop.value();
746 }
747 d_ptr->m_model->clearSelection();
748 d_ptr->m_model->selectStop(newCurrent, true);
749 d_ptr->m_model->setCurrentStop(newCurrent);
750 d_ptr->ensureVisible(newCurrent);
751 } else if (e->key() == Qt::Key_A) {
752 if (e->modifiers() & Qt::ControlModifier)
753 d_ptr->m_model->selectAll();
754 }
755}
756
757void QtGradientStopsWidget::paintEvent(QPaintEvent *e)
758{
759 Q_UNUSED(e)
760 if (!d_ptr->m_model)
761 return;
762
763 QtGradientStopsModel *model = d_ptr->m_model;
764#ifndef QT_NO_DRAGANDDROP
765 if (d_ptr->m_dragModel)
766 model = d_ptr->m_dragModel;
767#endif
768
769 QSize size = viewport()->size();
770 int w = size.width();
771 double h = size.height() - d_ptr->m_handleSize;
772 if (w <= 0)
773 return;
774
775 QPixmap pix(size);
776 QPainter p;
777
778 if (d_ptr->m_backgroundCheckered) {
779 int pixSize = 20;
780 QPixmap pm(2 * pixSize, 2 * pixSize);
781 QPainter pmp(&pm);
782 pmp.fillRect(0, 0, pixSize, pixSize, Qt::white);
783 pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white);
784 pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black);
785 pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black);
786
787 p.begin(&pix);
788 p.setBrushOrigin((size.width() % pixSize + pixSize) / 2, (size.height() % pixSize + pixSize) / 2);
789 p.fillRect(viewport()->rect(), pm);
790 p.setBrushOrigin(0, 0);
791 } else {
792 p.begin(viewport());
793 }
794
795 double viewBegin = (double)w * horizontalScrollBar()->value() / d_ptr->m_scaleFactor;
796
797 int val = horizontalScrollBar()->value();
798 int max = horizontalScrollBar()->maximum();
799
800 double begin = (double)val / (d_ptr->m_scaleFactor + max);
801 double end = (double)(val + d_ptr->m_scaleFactor) / (d_ptr->m_scaleFactor + max);
802 double width = end - begin;
803
804 if (h > 0) {
805 QLinearGradient lg(0, 0, w, 0);
806 QMap<qreal, QtGradientStop *> stops = model->stops();
807 QMapIterator<qreal, QtGradientStop *> itStop(stops);
808 while (itStop.hasNext()) {
809 QtGradientStop *stop = itStop.next().value();
810 double pos = stop->position();
811 if (pos >= begin && pos <= end) {
812 double gradPos = (pos - begin) / width;
813 QColor c = stop->color();
814 lg.setColorAt(gradPos, c);
815 }
816 //lg.setColorAt(stop->position(), stop->color());
817 }
818 lg.setColorAt(0, model->color(begin));
819 lg.setColorAt(1, model->color(end));
820 QImage img(w, 1, QImage::Format_ARGB32_Premultiplied);
821 QPainter p1(&img);
822 p1.setCompositionMode(QPainter::CompositionMode_Source);
823
824 /*
825 if (viewBegin != 0)
826 p1.translate(-viewBegin, 0);
827 if (d_ptr->m_zoom != 1)
828 p1.scale(d_ptr->m_zoom, 1);
829 */
830 p1.fillRect(0, 0, w, 1, lg);
831
832 p.fillRect(QRectF(0, d_ptr->m_handleSize, w, h), QPixmap::fromImage(img));
833 }
834
835
836 double handleWidth = d_ptr->m_handleSize * d_ptr->m_scaleFactor / (w * (d_ptr->m_scaleFactor + max));
837
838 QColor insideColor = QColor::fromRgb(0x20, 0x20, 0x20, 0xFF);
839 QColor borderColor = QColor(Qt::white);
840 QColor drawColor;
841 QColor back1 = QColor(Qt::lightGray);
842 QColor back2 = QColor(Qt::darkGray);
843 QColor back = QColor::fromRgb((back1.red() + back2.red()) / 2,
844 (back1.green() + back2.green()) / 2,
845 (back1.blue() + back2.blue()) / 2);
846
847 QPen pen;
848 p.setRenderHint(QPainter::Antialiasing);
849 QListIterator<QtGradientStop *> itStop(d_ptr->m_stops);
850 itStop.toBack();
851 while (itStop.hasPrevious()) {
852 QtGradientStop *stop = itStop.previous();
853 double x = stop->position();
854 if (x >= begin - handleWidth / 2 && x <= end + handleWidth / 2) {
855 double viewX = x * w * (d_ptr->m_scaleFactor + max) / d_ptr->m_scaleFactor - viewBegin;
856 p.save();
857 QColor c = stop->color();
858#ifndef QT_NO_DRAGANDDROP
859 if (stop == d_ptr->m_dragStop)
860 c = d_ptr->m_dragColor;
861#endif
862 if ((0.3 * c.redF() + 0.59 * c.greenF() + 0.11 * c.blueF()) * c.alphaF() +
863 (0.3 * back.redF() + 0.59 * back.greenF() + 0.11 * back.blueF()) * (1.0 - c.alphaF()) < 0.5) {
864 drawColor = QColor::fromRgb(0xC0, 0xC0, 0xC0, 0xB0);
865 } else {
866 drawColor = QColor::fromRgb(0x40, 0x40, 0x40, 0x80);
867 }
868 QRectF rect(viewX - d_ptr->m_handleSize / 2, 0, d_ptr->m_handleSize, d_ptr->m_handleSize);
869 rect.adjust(0.5, 0.5, -0.5, -0.5);
870 if (h > 0) {
871 pen.setWidthF(1);
872 QLinearGradient lg(0, d_ptr->m_handleSize, 0, d_ptr->m_handleSize + h / 2);
873 lg.setColorAt(0, drawColor);
874 QColor alphaZero = drawColor;
875 alphaZero.setAlpha(0);
876 lg.setColorAt(1, alphaZero);
877 pen.setBrush(lg);
878 p.setPen(pen);
879 p.drawLine(QPointF(viewX, d_ptr->m_handleSize), QPointF(viewX, d_ptr->m_handleSize + h / 2));
880
881 pen.setWidthF(1);
882 pen.setBrush(drawColor);
883 p.setPen(pen);
884 QRectF r1 = rect.adjusted(0.5, 0.5, -0.5, -0.5);
885 QRectF r2 = rect.adjusted(1.5, 1.5, -1.5, -1.5);
886 QColor inColor = QColor::fromRgb(0x80, 0x80, 0x80, 0x80);
887 if (!d_ptr->m_model->isSelected(stop)) {
888 p.setBrush(c);
889 p.drawEllipse(rect);
890 } else {
891 pen.setBrush(insideColor);
892 pen.setWidthF(2);
893 p.setPen(pen);
894 p.setBrush(Qt::NoBrush);
895 p.drawEllipse(r1);
896
897 pen.setBrush(inColor);
898 pen.setWidthF(1);
899 p.setPen(pen);
900 p.setBrush(c);
901 p.drawEllipse(r2);
902 }
903
904 if (d_ptr->m_model->currentStop() == stop) {
905 p.setBrush(Qt::NoBrush);
906 pen.setWidthF(5);
907 pen.setBrush(drawColor);
908 int corr = 4;
909 if (!d_ptr->m_model->isSelected(stop)) {
910 corr = 3;
911 pen.setWidthF(7);
912 }
913 p.setPen(pen);
914 p.drawEllipse(rect.adjusted(corr, corr, -corr, -corr));
915 }
916
917 }
918 p.restore();
919 }
920 }
921 if (d_ptr->m_backgroundCheckered) {
922 p.end();
923 p.begin(viewport());
924 p.drawPixmap(0, 0, pix);
925 }
926 p.end();
927}
928
929void QtGradientStopsWidget::focusInEvent(QFocusEvent *e)
930{
931 Q_UNUSED(e)
932 viewport()->update();
933}
934
935void QtGradientStopsWidget::focusOutEvent(QFocusEvent *e)
936{
937 Q_UNUSED(e)
938 viewport()->update();
939}
940
941void QtGradientStopsWidget::contextMenuEvent(QContextMenuEvent *e)
942{
943 if (!d_ptr->m_model)
944 return;
945
946 d_ptr->m_clickPos = e->pos();
947
948 QMenu menu(this);
949 QAction *newStopAction = new QAction(tr("New Stop"), &menu);
950 QAction *deleteAction = new QAction(tr("Delete"), &menu);
951 QAction *flipAllAction = new QAction(tr("Flip All"), &menu);
952 QAction *selectAllAction = new QAction(tr("Select All"), &menu);
953 QAction *zoomInAction = new QAction(tr("Zoom In"), &menu);
954 QAction *zoomOutAction = new QAction(tr("Zoom Out"), &menu);
955 QAction *zoomAllAction = new QAction(tr("Reset Zoom"), &menu);
956 if (d_ptr->m_model->selectedStops().isEmpty() && !d_ptr->m_model->currentStop())
957 deleteAction->setEnabled(false);
958 if (zoom() <= 1) {
959 zoomOutAction->setEnabled(false);
960 zoomAllAction->setEnabled(false);
961 } else if (zoom() >= 100) {
962 zoomInAction->setEnabled(false);
963 }
964 connect(newStopAction, SIGNAL(triggered()), this, SLOT(slotNewStop()));
965 connect(deleteAction, SIGNAL(triggered()), this, SLOT(slotDelete()));
966 connect(flipAllAction, SIGNAL(triggered()), this, SLOT(slotFlipAll()));
967 connect(selectAllAction, SIGNAL(triggered()), this, SLOT(slotSelectAll()));
968 connect(zoomInAction, SIGNAL(triggered()), this, SLOT(slotZoomIn()));
969 connect(zoomOutAction, SIGNAL(triggered()), this, SLOT(slotZoomOut()));
970 connect(zoomAllAction, SIGNAL(triggered()), this, SLOT(slotResetZoom()));
971 menu.addAction(newStopAction);
972 menu.addAction(deleteAction);
973 menu.addAction(flipAllAction);
974 menu.addAction(selectAllAction);
975 menu.addSeparator();
976 menu.addAction(zoomInAction);
977 menu.addAction(zoomOutAction);
978 menu.addAction(zoomAllAction);
979 menu.exec(e->globalPos());
980}
981
982void QtGradientStopsWidget::wheelEvent(QWheelEvent *e)
983{
984 int numDegrees = e->delta() / 8;
985 int numSteps = numDegrees / 15;
986
987 int shift = numSteps;
988 if (shift < 0)
989 shift = -shift;
990 int pow = 1 << shift;
991 //const double c = 0.7071067; // 2 steps per doubled value
992 const double c = 0.5946036; // 4 steps pre doubled value
993 // in general c = pow(2, 1 / n) / 2; where n is the step
994 double factor = pow * c;
995
996 double newZoom = zoom();
997 if (numSteps < 0)
998 newZoom /= factor;
999 else
1000 newZoom *= factor;
1001 if (newZoom > 100)
1002 newZoom = 100;
1003 if (newZoom < 1)
1004 newZoom = 1;
1005
1006 if (newZoom == zoom())
1007 return;
1008
1009 setZoom(newZoom);
1010 emit zoomChanged(zoom());
1011}
1012
1013#ifndef QT_NO_DRAGANDDROP
1014void QtGradientStopsWidget::dragEnterEvent(QDragEnterEvent *event)
1015{
1016 const QMimeData *mime = event->mimeData();
1017 if (!mime->hasColor())
1018 return;
1019 event->accept();
1020 d_ptr->m_dragModel = d_ptr->m_model->clone();
1021
1022 d_ptr->m_dragColor = qvariant_cast<QColor>(mime->colorData());
1023 update();
1024}
1025
1026void QtGradientStopsWidget::dragMoveEvent(QDragMoveEvent *event)
1027{
1028 QRectF rect = viewport()->rect();
1029 rect.adjust(0, d_ptr->m_handleSize, 0, 0);
1030 double x = d_ptr->fromViewport(event->pos().x());
1031 QtGradientStop *dragStop = d_ptr->stopAt(event->pos());
1032 if (dragStop) {
1033 event->accept();
1034 d_ptr->removeClonedStop();
1035 d_ptr->changeStop(dragStop->position());
1036 } else if (rect.contains(event->pos())) {
1037 event->accept();
1038 if (d_ptr->m_model->at(x)) {
1039 d_ptr->removeClonedStop();
1040 d_ptr->changeStop(x);
1041 } else {
1042 d_ptr->restoreChangedStop();
1043 d_ptr->cloneStop(x);
1044 }
1045 } else {
1046 event->ignore();
1047 d_ptr->removeClonedStop();
1048 d_ptr->restoreChangedStop();
1049 }
1050
1051 update();
1052}
1053
1054void QtGradientStopsWidget::dragLeaveEvent(QDragLeaveEvent *event)
1055{
1056 event->accept();
1057 d_ptr->clearDrag();
1058 update();
1059}
1060
1061void QtGradientStopsWidget::dropEvent(QDropEvent *event)
1062{
1063 event->accept();
1064 if (!d_ptr->m_dragModel)
1065 return;
1066
1067 if (d_ptr->m_changedStop)
1068 d_ptr->m_model->changeStop(d_ptr->m_model->at(d_ptr->m_changedStop->position()), d_ptr->m_dragColor);
1069 else if (d_ptr->m_clonedStop)
1070 d_ptr->m_model->addStop(d_ptr->m_clonedStop->position(), d_ptr->m_dragColor);
1071
1072 d_ptr->clearDrag();
1073 update();
1074}
1075
1076void QtGradientStopsWidgetPrivate::clearDrag()
1077{
1078 removeClonedStop();
1079 restoreChangedStop();
1080 delete m_dragModel;
1081 m_dragModel = 0;
1082}
1083
1084void QtGradientStopsWidgetPrivate::removeClonedStop()
1085{
1086 if (!m_clonedStop)
1087 return;
1088 m_dragModel->removeStop(m_clonedStop);
1089 m_clonedStop = 0;
1090}
1091
1092void QtGradientStopsWidgetPrivate::restoreChangedStop()
1093{
1094 if (!m_changedStop)
1095 return;
1096 m_dragModel->changeStop(m_changedStop, m_model->at(m_changedStop->position())->color());
1097 m_changedStop = 0;
1098 m_dragStop = 0;
1099}
1100
1101void QtGradientStopsWidgetPrivate::changeStop(qreal pos)
1102{
1103 QtGradientStop *stop = m_dragModel->at(pos);
1104 if (!stop)
1105 return;
1106
1107 m_dragModel->changeStop(stop, m_dragColor);
1108 m_changedStop = stop;
1109 m_dragStop = m_model->at(stop->position());
1110}
1111
1112void QtGradientStopsWidgetPrivate::cloneStop(qreal pos)
1113{
1114 if (m_clonedStop) {
1115 m_dragModel->moveStop(m_clonedStop, pos);
1116 return;
1117 }
1118 QtGradientStop *stop = m_dragModel->at(pos);
1119 if (stop)
1120 return;
1121
1122 m_clonedStop = m_dragModel->addStop(pos, m_dragColor);
1123}
1124
1125#endif
1126
1127void QtGradientStopsWidget::setZoom(double zoom)
1128{
1129 double z = zoom;
1130 if (z < 1)
1131 z = 1;
1132 else if (z > 100)
1133 z = 100;
1134
1135 if (d_ptr->m_zoom == z)
1136 return;
1137
1138 d_ptr->m_zoom = z;
1139 int oldMax = horizontalScrollBar()->maximum();
1140 int oldVal = horizontalScrollBar()->value();
1141 horizontalScrollBar()->setRange(0, qRound(d_ptr->m_scaleFactor * (d_ptr->m_zoom - 1)));
1142 int newMax = horizontalScrollBar()->maximum();
1143 double newVal = (oldVal + (double)d_ptr->m_scaleFactor / 2) * (newMax + d_ptr->m_scaleFactor)
1144 / (oldMax + d_ptr->m_scaleFactor) - (double)d_ptr->m_scaleFactor / 2;
1145 horizontalScrollBar()->setValue(qRound(newVal));
1146 viewport()->update();
1147}
1148
1149double QtGradientStopsWidget::zoom() const
1150{
1151 return d_ptr->m_zoom;
1152}
1153
1154QT_END_NAMESPACE
1155
1156#include "moc_qtgradientstopswidget.cpp"
Note: See TracBrowser for help on using the repository browser.