Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtgradientstopswidget.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
7
8#include <QtWidgets/qmenu.h>
9#include <QtWidgets/qrubberband.h>
10#include <QtWidgets/qscrollbar.h>
11
12#include <QtGui/qevent.h>
13#include <QtGui/qimage.h>
14#include <QtGui/qpainter.h>
15
16#include <QtCore/qhash.h>
17#include <QtCore/qmap.h>
18#include <QtCore/qmimedata.h>
19
21
23{
24 Q_OBJECT
25 QtGradientStopsWidget *q_ptr;
27public:
29
32 void slotStopMoved(QtGradientStop *stop, qreal newPos);
34 void slotStopChanged(QtGradientStop *stop, QColor newColor);
35 void slotStopSelected(QtGradientStop *stop, bool selected);
38 void slotDelete();
41 void slotZoomIn();
44
45 double fromViewport(int x) const;
46 double toViewport(double x) const;
47 QtGradientStop *stopAt(QPoint viewportPos) const;
48 QList<QtGradientStop *> stopsAt(QPoint viewportPos) const;
49 void setupMove(QtGradientStop *stop, int x);
50 void ensureVisible(double x); // x = stop position
52 QtGradientStop *newStop(QPoint viewportPos);
53
58 double m_zoom;
59
60#ifndef QT_NO_DRAGANDDROP
66 void clearDrag();
69 void changeStop(qreal pos);
70 void cloneStop(qreal pos);
71#endif
72
75
77
81
83};
84
85void QtGradientStopsWidgetPrivate::setGradientStopsModel(QtGradientStopsModel *model)
86{
87 if (m_model == model)
88 return;
89
90 if (m_model) {
91 disconnect(m_model, &QtGradientStopsModel::stopAdded,
95 disconnect(m_model, &QtGradientStopsModel::stopMoved,
96 this, &QtGradientStopsWidgetPrivate::slotStopMoved);
105
106 m_stops.clear();
107 }
108
109 m_model = model;
110
111 if (m_model) {
112 connect(m_model, &QtGradientStopsModel::stopAdded,
116 connect(m_model, &QtGradientStopsModel::stopMoved,
117 this, &QtGradientStopsWidgetPrivate::slotStopMoved);
126
127 const auto stopsMap = m_model->stops();
128 for (auto it = stopsMap.cbegin(), end = stopsMap.cend(); it != end; ++it)
129 slotStopAdded(it.value());
130
131 const auto selected = m_model->selectedStops();
132 for (QtGradientStop *stop : selected)
133 slotStopSelected(stop, true);
134
136 }
137}
138
140{
141 QSize size = q_ptr->viewport()->size();
142 int w = size.width();
143 int max = q_ptr->horizontalScrollBar()->maximum();
144 int val = q_ptr->horizontalScrollBar()->value();
145 return (double(x) * m_scaleFactor + w * val) / (w * (m_scaleFactor + max));
146}
147
149{
150 QSize size = q_ptr->viewport()->size();
151 int w = size.width();
152 int max = q_ptr->horizontalScrollBar()->maximum();
153 int val = q_ptr->horizontalScrollBar()->value();
154 return w * (x * (m_scaleFactor + max) - val) / m_scaleFactor;
155}
156
158{
159 double posY = m_handleSize / 2;
160 for (QtGradientStop *stop : m_stops) {
161 double posX = toViewport(stop->position());
162
163 double x = viewportPos.x() - posX;
164 double y = viewportPos.y() - posY;
165
166 if ((m_handleSize * m_handleSize / 4) > (x * x + y * y))
167 return stop;
168 }
169 return 0;
170}
171
173{
174 QList<QtGradientStop *> stops;
175 double posY = m_handleSize / 2;
176 for (QtGradientStop *stop : m_stops) {
177 double posX = toViewport(stop->position());
178
179 double x = viewportPos.x() - posX;
180 double y = viewportPos.y() - posY;
181
182 if ((m_handleSize * m_handleSize / 4) > (x * x + y * y))
183 stops.append(stop);
184 }
185 return stops;
186}
187
189{
191
192 int viewportX = qRound(toViewport(stop->position()));
193 m_moveOffset = x - viewportX;
194
195 const auto stops = m_stops;
196 m_stops.clear();
197 for (QtGradientStop *s : stops) {
198 if (m_model->isSelected(s) || s == stop) {
199 m_moveStops[s] = s->position() - stop->position();
200 m_stops.append(s);
201 } else {
202 m_moveOriginal[s->position()] = s->color();
203 }
204 }
205 for (QtGradientStop *s : stops) {
206 if (!m_model->isSelected(s))
207 m_stops.append(s);
208 }
209 m_stops.removeAll(stop);
210 m_stops.prepend(stop);
211}
212
214{
215 double viewX = toViewport(x);
216 if (viewX < 0 || viewX > q_ptr->viewport()->size().width()) {
217 int max = q_ptr->horizontalScrollBar()->maximum();
218 int newVal = qRound(x * (max + m_scaleFactor) - m_scaleFactor / 2);
219 q_ptr->horizontalScrollBar()->setValue(newVal);
220 }
221}
222
224{
225 if (!stop)
226 return;
227 ensureVisible(stop->position());
228}
229
231{
232 QtGradientStop *copyStop = stopAt(viewportPos);
233 double posX = fromViewport(viewportPos.x());
234 QtGradientStop *stop = m_model->at(posX);
235 if (!stop) {
236 QColor newColor;
237 if (copyStop)
238 newColor = copyStop->color();
239 else
240 newColor = m_model->color(posX);
241 if (!newColor.isValid())
242 newColor = Qt::white;
243 stop = m_model->addStop(posX, newColor);
244 }
245 return stop;
246}
247
249{
250 m_stops.append(stop);
251 q_ptr->viewport()->update();
252}
253
255{
256 m_stops.removeAll(stop);
257 q_ptr->viewport()->update();
258}
259
261{
262 Q_UNUSED(stop);
263 Q_UNUSED(newPos);
264 q_ptr->viewport()->update();
265}
266
268{
269 Q_UNUSED(stop1);
270 Q_UNUSED(stop2);
271 q_ptr->viewport()->update();
272}
273
275{
276 Q_UNUSED(stop);
277 Q_UNUSED(newColor);
278 q_ptr->viewport()->update();
279}
280
282{
283 Q_UNUSED(stop);
284 Q_UNUSED(selected);
285 q_ptr->viewport()->update();
286}
287
289{
290 Q_UNUSED(stop);
291
292 if (!m_model)
293 return;
294 q_ptr->viewport()->update();
295 if (stop) {
296 m_stops.removeAll(stop);
297 m_stops.prepend(stop);
298 }
299}
300
302{
303 if (!m_model)
304 return;
305
306 QtGradientStop *stop = newStop(m_clickPos);
307
308 if (!stop)
309 return;
310
312 m_model->selectStop(stop, true);
314}
315
317{
318 if (!m_model)
319 return;
320
322}
323
325{
326 if (!m_model)
327 return;
328
330}
331
333{
334 if (!m_model)
335 return;
336
338}
339
341{
342 double newZoom = q_ptr->zoom() * 2;
343 if (newZoom > 100)
344 newZoom = 100;
345 if (newZoom == q_ptr->zoom())
346 return;
347
348 q_ptr->setZoom(newZoom);
349 emit q_ptr->zoomChanged(q_ptr->zoom());
350}
351
353{
354 double newZoom = q_ptr->zoom() / 2;
355 if (newZoom < 1)
356 newZoom = 1;
357 if (newZoom == q_ptr->zoom())
358 return;
359
360 q_ptr->setZoom(newZoom);
361 emit q_ptr->zoomChanged(q_ptr->zoom());
362}
363
365{
366 if (1 == q_ptr->zoom())
367 return;
368
369 q_ptr->setZoom(1);
370 emit q_ptr->zoomChanged(1);
371}
372
373QtGradientStopsWidget::QtGradientStopsWidget(QWidget *parent)
374 : QAbstractScrollArea(parent), d_ptr(new QtGradientStopsWidgetPrivate)
375{
376 d_ptr->q_ptr = this;
377 d_ptr->m_backgroundCheckered = true;
378 d_ptr->m_model = 0;
379 d_ptr->m_handleSize = 25.0;
380 d_ptr->m_scaleFactor = 1000;
381 d_ptr->m_moving = false;
382 d_ptr->m_zoom = 1;
383 d_ptr->m_rubber = new QRubberBand(QRubberBand::Rectangle, this);
384#ifndef QT_NO_DRAGANDDROP
385 d_ptr->m_dragStop = 0;
386 d_ptr->m_changedStop = 0;
387 d_ptr->m_clonedStop = 0;
388 d_ptr->m_dragModel = 0;
389#endif
390 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
391 setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
392 horizontalScrollBar()->setRange(0, (int)(d_ptr->m_scaleFactor * (d_ptr->m_zoom - 1) + 0.5));
393 horizontalScrollBar()->setPageStep(d_ptr->m_scaleFactor);
394 horizontalScrollBar()->setSingleStep(4);
395 viewport()->setAutoFillBackground(false);
396
397 setAcceptDrops(true);
398
399 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred));
400}
401
405
407{
408 return QSize(qRound(2 * d_ptr->m_handleSize), qRound(3 * d_ptr->m_handleSize) + horizontalScrollBar()->sizeHint().height());
409}
410
412{
413 return QSize(qRound(2 * d_ptr->m_handleSize), qRound(3 * d_ptr->m_handleSize) + horizontalScrollBar()->minimumSizeHint().height());
414}
415
417{
418 if (d_ptr->m_backgroundCheckered == checkered)
419 return;
420 d_ptr->m_backgroundCheckered = checkered;
421 update();
422}
423
425{
426 return d_ptr->m_backgroundCheckered;
427}
428
430{
431 d_ptr->setGradientStopsModel(model);
432}
433
435{
436 if (!d_ptr->m_model)
437 return;
438
439 if (e->button() != Qt::LeftButton)
440 return;
441
442 d_ptr->m_moving = true;
443
444 d_ptr->m_moveStops.clear();
445 d_ptr->m_moveOriginal.clear();
446 d_ptr->m_clickPos = e->position().toPoint();
447 QtGradientStop *stop = d_ptr->stopAt(e->position().toPoint());
448 if (stop) {
449 if (e->modifiers() & Qt::ControlModifier) {
450 d_ptr->m_model->selectStop(stop, !d_ptr->m_model->isSelected(stop));
451 } else if (e->modifiers() & Qt::ShiftModifier) {
452 QtGradientStop *oldCurrent = d_ptr->m_model->currentStop();
453 if (oldCurrent) {
454 const auto stops = d_ptr->m_model->stops();
455 auto itSt = stops.constFind(oldCurrent->position());
456 if (itSt != stops.constEnd()) {
457 while (itSt != stops.constFind(stop->position())) {
458 d_ptr->m_model->selectStop(itSt.value(), true);
459 if (oldCurrent->position() < stop->position())
460 ++itSt;
461 else
462 --itSt;
463 }
464 }
465 }
466 d_ptr->m_model->selectStop(stop, true);
467 } else {
468 if (!d_ptr->m_model->isSelected(stop)) {
469 d_ptr->m_model->clearSelection();
470 d_ptr->m_model->selectStop(stop, true);
471 }
472 }
473 d_ptr->setupMove(stop, e->position().toPoint().x());
474 } else {
475 d_ptr->m_model->clearSelection();
476 d_ptr->m_rubber->setGeometry(QRect(d_ptr->m_clickPos, QSize()));
477 d_ptr->m_rubber->show();
478 }
479 viewport()->update();
480}
481
483{
484 if (!d_ptr->m_model)
485 return;
486
487 if (e->button() != Qt::LeftButton)
488 return;
489
490 d_ptr->m_moving = false;
491 d_ptr->m_rubber->hide();
492 d_ptr->m_moveStops.clear();
493 d_ptr->m_moveOriginal.clear();
494}
495
497{
498 if (!d_ptr->m_model)
499 return;
500
501 if (!(e->buttons() & Qt::LeftButton))
502 return;
503
504 if (!d_ptr->m_moving)
505 return;
506
507 if (!d_ptr->m_moveStops.isEmpty()) {
508 double maxOffset = 0.0;
509 double minOffset = 0.0;
510 bool first = true;
511 auto itStop = d_ptr->m_moveStops.cbegin();
512 while (itStop != d_ptr->m_moveStops.constEnd()) {
513 double offset = itStop.value();
514
515 if (first) {
516 maxOffset = offset;
517 minOffset = offset;
518 first = false;
519 } else {
520 if (maxOffset < offset)
521 maxOffset = offset;
522 else if (minOffset > offset)
523 minOffset = offset;
524 }
525 ++itStop;
526 }
527
528 double viewportMin = d_ptr->toViewport(-minOffset);
529 double viewportMax = d_ptr->toViewport(1.0 - maxOffset);
530
531 QtGradientStopsModel::PositionStopMap newPositions;
532
533 int viewportX = e->position().toPoint().x() - d_ptr->m_moveOffset;
534
535 if (viewportX > viewport()->size().width())
536 viewportX = viewport()->size().width();
537 else if (viewportX < 0)
538 viewportX = 0;
539
540 double posX = d_ptr->fromViewport(viewportX);
541
542 if (viewportX > viewportMax)
543 posX = 1.0 - maxOffset;
544 else if (viewportX < viewportMin)
545 posX = -minOffset;
546
547 itStop = d_ptr->m_moveStops.constBegin();
548 while (itStop != d_ptr->m_moveStops.constEnd()) {
549 QtGradientStop *stop = itStop.key();
550
551 newPositions[posX + itStop.value()] = stop;
552
553 ++itStop;
554 }
555
556 bool forward = true;
557 auto itNewPos = newPositions.cbegin();
558 if (itNewPos.value()->position() < itNewPos.key())
559 forward = false;
560
561 itNewPos = forward ? newPositions.constBegin() : newPositions.constEnd();
562 while (itNewPos != (forward ? newPositions.constEnd() : newPositions.constBegin())) {
563 if (!forward)
564 --itNewPos;
565 QtGradientStop *stop = itNewPos.value();
566 double newPos = itNewPos.key();
567 if (newPos > 1)
568 newPos = 1;
569 else if (newPos < 0)
570 newPos = 0;
571
572 QtGradientStop *existingStop = d_ptr->m_model->at(newPos);
573 if (existingStop && !d_ptr->m_moveStops.contains(existingStop))
574 d_ptr->m_model->removeStop(existingStop);
575 d_ptr->m_model->moveStop(stop, newPos);
576
577 if (forward)
578 ++itNewPos;
579 }
580
581 auto itOld = d_ptr->m_moveOriginal.cbegin();
582 while (itOld != d_ptr->m_moveOriginal.constEnd()) {
583 double position = itOld.key();
584 if (!d_ptr->m_model->at(position))
585 d_ptr->m_model->addStop(position, itOld.value());
586
587 ++itOld;
588 }
589
590 } else {
591 QRect r(QRect(d_ptr->m_clickPos, e->position().toPoint()).normalized());
592 r.translate(1, 0);
593 d_ptr->m_rubber->setGeometry(r);
594 //d_ptr->m_model->clearSelection();
595
596 int xv1 = d_ptr->m_clickPos.x();
597 int xv2 = e->position().toPoint().x();
598 if (xv1 > xv2) {
599 int temp = xv1;
600 xv1 = xv2;
601 xv2 = temp;
602 }
603 int yv1 = d_ptr->m_clickPos.y();
604 int yv2 = e->position().toPoint().y();
605 if (yv1 > yv2) {
606 int temp = yv1;
607 yv1 = yv2;
608 yv2 = temp;
609 }
610
611 QPoint p1, p2;
612
613 if (yv2 < d_ptr->m_handleSize / 2) {
614 p1 = QPoint(xv1, yv2);
615 p2 = QPoint(xv2, yv2);
616 } else if (yv1 > d_ptr->m_handleSize / 2) {
617 p1 = QPoint(xv1, yv1);
618 p2 = QPoint(xv2, yv1);
619 } else {
620 p1 = QPoint(xv1, qRound(d_ptr->m_handleSize / 2));
621 p2 = QPoint(xv2, qRound(d_ptr->m_handleSize / 2));
622 }
623
624 const auto beginList = d_ptr->stopsAt(p1);
625 const auto endList = d_ptr->stopsAt(p2);
626
627 double x1 = d_ptr->fromViewport(xv1);
628 double x2 = d_ptr->fromViewport(xv2);
629
630 for (QtGradientStop *stop : std::as_const(d_ptr->m_stops)) {
631 if ((stop->position() >= x1 && stop->position() <= x2) ||
632 beginList.contains(stop) || endList.contains(stop))
633 d_ptr->m_model->selectStop(stop, true);
634 else
635 d_ptr->m_model->selectStop(stop, false);
636 }
637 }
638}
639
641{
642 if (!d_ptr->m_model)
643 return;
644
645 if (e->button() != Qt::LeftButton)
646 return;
647
648 if (d_ptr->m_clickPos != e->position().toPoint()) {
649 mousePressEvent(e);
650 return;
651 }
652 d_ptr->m_moving = true;
653 d_ptr->m_moveStops.clear();
654 d_ptr->m_moveOriginal.clear();
655
656 QtGradientStop *stop = d_ptr->newStop(e->position().toPoint());
657
658 if (!stop)
659 return;
660
661 d_ptr->m_model->clearSelection();
662 d_ptr->m_model->selectStop(stop, true);
663
664 d_ptr->setupMove(stop, e->position().toPoint().x());
665
666 viewport()->update();
667}
668
670{
671 if (!d_ptr->m_model)
672 return;
673
674 if (e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace) {
675 d_ptr->m_model->deleteStops();
676 } else if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right ||
677 e->key() == Qt::Key_Home || e->key() == Qt::Key_End) {
678 const auto stops = d_ptr->m_model->stops();
679 if (stops.isEmpty())
680 return;
681 QtGradientStop *newCurrent = nullptr;
682 QtGradientStop *current = d_ptr->m_model->currentStop();
683 if (!current || e->key() == Qt::Key_Home || e->key() == Qt::Key_End) {
684 if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Home)
685 newCurrent = stops.constBegin().value();
686 else if (e->key() == Qt::Key_Right || e->key() == Qt::Key_End)
687 newCurrent = (--stops.constEnd()).value();
688 } else {
689 auto itStop = stops.cbegin();
690 while (itStop.value() != current)
691 ++itStop;
692 if (e->key() == Qt::Key_Left && itStop != stops.constBegin())
693 --itStop;
694 else if (e->key() == Qt::Key_Right && itStop != --stops.constEnd())
695 ++itStop;
696 newCurrent = itStop.value();
697 }
698 d_ptr->m_model->clearSelection();
699 d_ptr->m_model->selectStop(newCurrent, true);
700 d_ptr->m_model->setCurrentStop(newCurrent);
701 d_ptr->ensureVisible(newCurrent);
702 } else if (e->key() == Qt::Key_A) {
703 if (e->modifiers() & Qt::ControlModifier)
704 d_ptr->m_model->selectAll();
705 }
706}
707
709{
710 Q_UNUSED(e);
711 if (!d_ptr->m_model)
712 return;
713
714 QtGradientStopsModel *model = d_ptr->m_model;
715#ifndef QT_NO_DRAGANDDROP
716 if (d_ptr->m_dragModel)
717 model = d_ptr->m_dragModel;
718#endif
719
720 QSize size = viewport()->size();
721 int w = size.width();
722 double h = size.height() - d_ptr->m_handleSize;
723 if (w <= 0)
724 return;
725
726 QPixmap pix(size);
727 QPainter p;
728
729 if (d_ptr->m_backgroundCheckered) {
730 int pixSize = 20;
731 QPixmap pm(2 * pixSize, 2 * pixSize);
732 QPainter pmp(&pm);
733 pmp.fillRect(0, 0, pixSize, pixSize, Qt::white);
734 pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white);
735 pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black);
736 pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black);
737
738 p.begin(&pix);
739 p.setBrushOrigin((size.width() % pixSize + pixSize) / 2, (size.height() % pixSize + pixSize) / 2);
740 p.fillRect(viewport()->rect(), pm);
741 p.setBrushOrigin(0, 0);
742 } else {
743 p.begin(viewport());
744 }
745
746 const double viewBegin = double(w) * horizontalScrollBar()->value() / d_ptr->m_scaleFactor;
747
748 int val = horizontalScrollBar()->value();
749 int max = horizontalScrollBar()->maximum();
750
751 const double begin = double(val) / (d_ptr->m_scaleFactor + max);
752 const double end = double(val + d_ptr->m_scaleFactor) / (d_ptr->m_scaleFactor + max);
753 double width = end - begin;
754
755 if (h > 0) {
756 QLinearGradient lg(0, 0, w, 0);
757 QMap<qreal, QtGradientStop *> stops = model->stops();
758 for (auto itStop = stops.cbegin(), send = stops.cend(); itStop != send; ++itStop) {
759 QtGradientStop *stop = itStop.value();
760 double pos = stop->position();
761 if (pos >= begin && pos <= end) {
762 double gradPos = (pos - begin) / width;
763 QColor c = stop->color();
764 lg.setColorAt(gradPos, c);
765 }
766 //lg.setColorAt(stop->position(), stop->color());
767 }
768 lg.setColorAt(0, model->color(begin));
769 lg.setColorAt(1, model->color(end));
770 QImage img(w, 1, QImage::Format_ARGB32_Premultiplied);
771 QPainter p1(&img);
772 p1.setCompositionMode(QPainter::CompositionMode_Source);
773
774 /*
775 if (viewBegin != 0)
776 p1.translate(-viewBegin, 0);
777 if (d_ptr->m_zoom != 1)
778 p1.scale(d_ptr->m_zoom, 1);
779 */
780 p1.fillRect(0, 0, w, 1, lg);
781
782 p.fillRect(QRectF(0, d_ptr->m_handleSize, w, h), QPixmap::fromImage(img));
783 }
784
785
786 double handleWidth = d_ptr->m_handleSize * d_ptr->m_scaleFactor / (w * (d_ptr->m_scaleFactor + max));
787
788 QColor insideColor = QColor::fromRgb(0x20, 0x20, 0x20, 0xFF);
789 QColor drawColor;
790 QColor back1 = QColor(Qt::lightGray);
791 QColor back2 = QColor(Qt::darkGray);
792 QColor back = QColor::fromRgb((back1.red() + back2.red()) / 2,
793 (back1.green() + back2.green()) / 2,
794 (back1.blue() + back2.blue()) / 2);
795
796 QPen pen;
797 p.setRenderHint(QPainter::Antialiasing);
798 for (auto rit = d_ptr->m_stops.crbegin(), rend = d_ptr->m_stops.crend(); rit != rend; ++rit) {
799 QtGradientStop *stop = *rit;
800 double x = stop->position();
801 if (x >= begin - handleWidth / 2 && x <= end + handleWidth / 2) {
802 double viewX = x * w * (d_ptr->m_scaleFactor + max) / d_ptr->m_scaleFactor - viewBegin;
803 p.save();
804 QColor c = stop->color();
805#ifndef QT_NO_DRAGANDDROP
806 if (stop == d_ptr->m_dragStop)
807 c = d_ptr->m_dragColor;
808#endif
809 if ((0.3 * c.redF() + 0.59 * c.greenF() + 0.11 * c.blueF()) * c.alphaF() +
810 (0.3 * back.redF() + 0.59 * back.greenF() + 0.11 * back.blueF()) * (1.0 - c.alphaF()) < 0.5) {
811 drawColor = QColor::fromRgb(0xC0, 0xC0, 0xC0, 0xB0);
812 } else {
813 drawColor = QColor::fromRgb(0x40, 0x40, 0x40, 0x80);
814 }
815 QRectF rect(viewX - d_ptr->m_handleSize / 2, 0, d_ptr->m_handleSize, d_ptr->m_handleSize);
816 rect.adjust(0.5, 0.5, -0.5, -0.5);
817 if (h > 0) {
818 pen.setWidthF(1);
819 QLinearGradient lg(0, d_ptr->m_handleSize, 0, d_ptr->m_handleSize + h / 2);
820 lg.setColorAt(0, drawColor);
821 QColor alphaZero = drawColor;
822 alphaZero.setAlpha(0);
823 lg.setColorAt(1, alphaZero);
824 pen.setBrush(lg);
825 p.setPen(pen);
826 p.drawLine(QPointF(viewX, d_ptr->m_handleSize), QPointF(viewX, d_ptr->m_handleSize + h / 2));
827
828 pen.setWidthF(1);
829 pen.setBrush(drawColor);
830 p.setPen(pen);
831 QRectF r1 = rect.adjusted(0.5, 0.5, -0.5, -0.5);
832 QRectF r2 = rect.adjusted(1.5, 1.5, -1.5, -1.5);
833 QColor inColor = QColor::fromRgb(0x80, 0x80, 0x80, 0x80);
834 if (!d_ptr->m_model->isSelected(stop)) {
835 p.setBrush(c);
836 p.drawEllipse(rect);
837 } else {
838 pen.setBrush(insideColor);
839 pen.setWidthF(2);
840 p.setPen(pen);
841 p.setBrush(Qt::NoBrush);
842 p.drawEllipse(r1);
843
844 pen.setBrush(inColor);
845 pen.setWidthF(1);
846 p.setPen(pen);
847 p.setBrush(c);
848 p.drawEllipse(r2);
849 }
850
851 if (d_ptr->m_model->currentStop() == stop) {
852 p.setBrush(Qt::NoBrush);
853 pen.setWidthF(5);
854 pen.setBrush(drawColor);
855 int corr = 4;
856 if (!d_ptr->m_model->isSelected(stop)) {
857 corr = 3;
858 pen.setWidthF(7);
859 }
860 p.setPen(pen);
861 p.drawEllipse(rect.adjusted(corr, corr, -corr, -corr));
862 }
863
864 }
865 p.restore();
866 }
867 }
868 if (d_ptr->m_backgroundCheckered) {
869 p.end();
870 p.begin(viewport());
871 p.drawPixmap(0, 0, pix);
872 }
873 p.end();
874}
875
877{
878 Q_UNUSED(e);
879 viewport()->update();
880}
881
883{
884 Q_UNUSED(e);
885 viewport()->update();
886}
887
888void QtGradientStopsWidget::contextMenuEvent(QContextMenuEvent *e)
889{
890 if (!d_ptr->m_model)
891 return;
892
893 d_ptr->m_clickPos = e->pos();
894
895 QMenu menu(this);
896 QAction *newStopAction = new QAction(tr("New Stop"), &menu);
897 QAction *deleteAction = new QAction(tr("Delete"), &menu);
898 QAction *flipAllAction = new QAction(tr("Flip All"), &menu);
899 QAction *selectAllAction = new QAction(tr("Select All"), &menu);
900 QAction *zoomInAction = new QAction(tr("Zoom In"), &menu);
901 QAction *zoomOutAction = new QAction(tr("Zoom Out"), &menu);
902 QAction *zoomAllAction = new QAction(tr("Reset Zoom"), &menu);
903 if (d_ptr->m_model->selectedStops().isEmpty() && !d_ptr->m_model->currentStop())
904 deleteAction->setEnabled(false);
905 if (zoom() <= 1) {
906 zoomOutAction->setEnabled(false);
907 zoomAllAction->setEnabled(false);
908 } else if (zoom() >= 100) {
909 zoomInAction->setEnabled(false);
910 }
911 connect(newStopAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotNewStop);
912 connect(deleteAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotDelete);
913 connect(flipAllAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotFlipAll);
914 connect(selectAllAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotSelectAll);
915 connect(zoomInAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotZoomIn);
916 connect(zoomOutAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotZoomOut);
917 connect(zoomAllAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotResetZoom);
918 menu.addAction(newStopAction);
919 menu.addAction(deleteAction);
920 menu.addAction(flipAllAction);
921 menu.addAction(selectAllAction);
922 menu.addSeparator();
923 menu.addAction(zoomInAction);
924 menu.addAction(zoomOutAction);
925 menu.addAction(zoomAllAction);
926 menu.exec(e->globalPos());
927}
928
930{
931 int numDegrees = e->angleDelta().y() / 8;
932 int numSteps = numDegrees / 15;
933
934 int shift = numSteps;
935 if (shift < 0)
936 shift = -shift;
937 int pow = 1 << shift;
938 //const double c = 0.7071067; // 2 steps per doubled value
939 const double c = 0.5946036; // 4 steps pre doubled value
940 // in general c = pow(2, 1 / n) / 2; where n is the step
941 double factor = pow * c;
942
943 double newZoom = zoom();
944 if (numSteps < 0)
945 newZoom /= factor;
946 else
947 newZoom *= factor;
948 if (newZoom > 100)
949 newZoom = 100;
950 if (newZoom < 1)
951 newZoom = 1;
952
953 if (newZoom == zoom())
954 return;
955
956 setZoom(newZoom);
957 emit zoomChanged(zoom());
958}
959
960#ifndef QT_NO_DRAGANDDROP
961void QtGradientStopsWidget::dragEnterEvent(QDragEnterEvent *event)
962{
963 const QMimeData *mime = event->mimeData();
964 if (!mime->hasColor())
965 return;
966 event->accept();
967 d_ptr->m_dragModel = d_ptr->m_model->clone();
968
969 d_ptr->m_dragColor = qvariant_cast<QColor>(mime->colorData());
970 update();
971}
972
973void QtGradientStopsWidget::dragMoveEvent(QDragMoveEvent *event)
974{
975 QRectF rect = viewport()->rect();
976 rect.adjust(0, d_ptr->m_handleSize, 0, 0);
977 double x = d_ptr->fromViewport(event->position().toPoint().x());
978 QtGradientStop *dragStop = d_ptr->stopAt(event->position().toPoint());
979 if (dragStop) {
980 event->accept();
981 d_ptr->removeClonedStop();
982 d_ptr->changeStop(dragStop->position());
983 } else if (rect.contains(event->position().toPoint())) {
984 event->accept();
985 if (d_ptr->m_model->at(x)) {
986 d_ptr->removeClonedStop();
987 d_ptr->changeStop(x);
988 } else {
989 d_ptr->restoreChangedStop();
990 d_ptr->cloneStop(x);
991 }
992 } else {
993 event->ignore();
994 d_ptr->removeClonedStop();
995 d_ptr->restoreChangedStop();
996 }
997
998 update();
999}
1000
1001void QtGradientStopsWidget::dragLeaveEvent(QDragLeaveEvent *event)
1002{
1003 event->accept();
1004 d_ptr->clearDrag();
1005 update();
1006}
1007
1008void QtGradientStopsWidget::dropEvent(QDropEvent *event)
1009{
1010 event->accept();
1011 if (!d_ptr->m_dragModel)
1012 return;
1013
1014 if (d_ptr->m_changedStop)
1015 d_ptr->m_model->changeStop(d_ptr->m_model->at(d_ptr->m_changedStop->position()), d_ptr->m_dragColor);
1016 else if (d_ptr->m_clonedStop)
1017 d_ptr->m_model->addStop(d_ptr->m_clonedStop->position(), d_ptr->m_dragColor);
1018
1019 d_ptr->clearDrag();
1020 update();
1021}
1022
1030
1038
1040{
1041 if (!m_changedStop)
1042 return;
1044 m_changedStop = 0;
1045 m_dragStop = 0;
1046}
1047
1049{
1050 QtGradientStop *stop = m_dragModel->at(pos);
1051 if (!stop)
1052 return;
1053
1054 m_dragModel->changeStop(stop, m_dragColor);
1055 m_changedStop = stop;
1056 m_dragStop = m_model->at(stop->position());
1057}
1058
1060{
1061 if (m_clonedStop) {
1062 m_dragModel->moveStop(m_clonedStop, pos);
1063 return;
1064 }
1065 QtGradientStop *stop = m_dragModel->at(pos);
1066 if (stop)
1067 return;
1068
1069 m_clonedStop = m_dragModel->addStop(pos, m_dragColor);
1070}
1071
1072#endif
1073
1075{
1076 double z = zoom;
1077 if (z < 1)
1078 z = 1;
1079 else if (z > 100)
1080 z = 100;
1081
1082 if (d_ptr->m_zoom == z)
1083 return;
1084
1085 d_ptr->m_zoom = z;
1086 int oldMax = horizontalScrollBar()->maximum();
1087 int oldVal = horizontalScrollBar()->value();
1088 horizontalScrollBar()->setRange(0, qRound(d_ptr->m_scaleFactor * (d_ptr->m_zoom - 1)));
1089 int newMax = horizontalScrollBar()->maximum();
1090 const double newVal = (oldVal + double(d_ptr->m_scaleFactor) / 2) * (newMax + d_ptr->m_scaleFactor)
1091 / (oldMax + d_ptr->m_scaleFactor) - double(d_ptr->m_scaleFactor) / 2;
1092 horizontalScrollBar()->setValue(qRound(newVal));
1093 viewport()->update();
1094}
1095
1097{
1098 return d_ptr->m_zoom;
1099}
1100
1101QT_END_NAMESPACE
1102
1103#include "qtgradientstopswidget.moc"
void selectStop(QtGradientStop *stop, bool select)
void stopSelected(QtGradientStop *stop, bool selected)
void removeStop(QtGradientStop *stop)
void changeStop(QtGradientStop *stop, QColor newColor)
QtGradientStop * currentStop() const
void stopChanged(QtGradientStop *stop, const QColor &newColor)
void stopRemoved(QtGradientStop *stop)
void currentStopChanged(QtGradientStop *stop)
void stopsSwapped(QtGradientStop *stop1, QtGradientStop *stop2)
void setCurrentStop(QtGradientStop *stop)
void setupMove(QtGradientStop *stop, int x)
void ensureVisible(QtGradientStop *stop)
void slotCurrentStopChanged(QtGradientStop *stop)
void slotStopSelected(QtGradientStop *stop, bool selected)
QList< QtGradientStop * > m_stops
void slotStopMoved(QtGradientStop *stop, qreal newPos)
QHash< QtGradientStop *, qreal > m_moveStops
void slotStopAdded(QtGradientStop *stop)
QtGradientStop * stopAt(QPoint viewportPos) const
void slotStopChanged(QtGradientStop *stop, QColor newColor)
QList< QtGradientStop * > stopsAt(QPoint viewportPos) const
void slotStopRemoved(QtGradientStop *stop)
QtGradientStop * newStop(QPoint viewportPos)
void slotStopsSwapped(QtGradientStop *stop1, QtGradientStop *stop2)
void setBackgroundCheckered(bool checkered)
void focusInEvent(QFocusEvent *e) override
void mouseMoveEvent(QMouseEvent *e) override
void dragMoveEvent(QDragMoveEvent *event) override
void mousePressEvent(QMouseEvent *e) override
void mouseDoubleClickEvent(QMouseEvent *e) override
void paintEvent(QPaintEvent *e) override
void wheelEvent(QWheelEvent *e) override
void dropEvent(QDropEvent *event) override
void contextMenuEvent(QContextMenuEvent *e) override
void dragEnterEvent(QDragEnterEvent *event) override
void keyPressEvent(QKeyEvent *e) override
void dragLeaveEvent(QDragLeaveEvent *event) override
void mouseReleaseEvent(QMouseEvent *e) override
QSize sizeHint() const override
void focusOutEvent(QFocusEvent *e) override
void setGradientStopsModel(QtGradientStopsModel *model)
QSize minimumSizeHint() const override
Combined button and popup list for selecting options.