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