373 : QAbstractScrollArea(parent), d_ptr(
new QtGradientStopsWidgetPrivate)
376 d_ptr->m_backgroundCheckered =
true;
378 d_ptr->m_handleSize = 25.0;
379 d_ptr->m_scaleFactor = 1000;
380 d_ptr->m_moving =
false;
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;
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);
396 setAcceptDrops(
true);
398 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred));
438 if (e->button() != Qt::LeftButton)
441 d_ptr->m_moving =
true;
443 d_ptr->m_moveStops.clear();
444 d_ptr->m_moveOriginal.clear();
445 d_ptr->m_clickPos = e->position().toPoint();
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) {
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())
465 d_ptr->m_model->selectStop(stop,
true);
467 if (!d_ptr->m_model->isSelected(stop)) {
468 d_ptr->m_model->clearSelection();
469 d_ptr->m_model->selectStop(stop,
true);
472 d_ptr->setupMove(stop, e->position().toPoint().x());
474 d_ptr->m_model->clearSelection();
475 d_ptr->m_rubber->setGeometry(QRect(d_ptr->m_clickPos, QSize()));
476 d_ptr->m_rubber->show();
478 viewport()->update();
500 if (!(e->buttons() & Qt::LeftButton))
503 if (!d_ptr->m_moving)
506 if (!d_ptr->m_moveStops.isEmpty()) {
507 double maxOffset = 0.0;
508 double minOffset = 0.0;
510 auto itStop = d_ptr->m_moveStops.cbegin();
511 while (itStop != d_ptr->m_moveStops.constEnd()) {
512 double offset = itStop.value();
519 if (maxOffset < offset)
521 else if (minOffset > offset)
527 double viewportMin = d_ptr->toViewport(-minOffset);
528 double viewportMax = d_ptr->toViewport(1.0 - maxOffset);
530 QtGradientStopsModel::PositionStopMap newPositions;
532 int viewportX = e->position().toPoint().x() - d_ptr->m_moveOffset;
534 if (viewportX > viewport()->size().width())
535 viewportX = viewport()->size().width();
536 else if (viewportX < 0)
539 double posX = d_ptr->fromViewport(viewportX);
541 if (viewportX > viewportMax)
542 posX = 1.0 - maxOffset;
543 else if (viewportX < viewportMin)
546 itStop = d_ptr->m_moveStops.constBegin();
547 while (itStop != d_ptr->m_moveStops.constEnd()) {
550 newPositions[posX + itStop.value()] = stop;
556 auto itNewPos = newPositions.cbegin();
557 if (itNewPos.value()->position() < itNewPos.key())
560 itNewPos = forward ? newPositions.constBegin() : newPositions.constEnd();
561 while (itNewPos != (forward ? newPositions.constEnd() : newPositions.constBegin())) {
565 double newPos = itNewPos.key();
572 if (existingStop && !d_ptr->m_moveStops.contains(existingStop))
573 d_ptr->m_model->removeStop(existingStop);
574 d_ptr->m_model->moveStop(stop, newPos);
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());
590 QRect r(QRect(d_ptr->m_clickPos, e->position().toPoint()).normalized());
592 d_ptr->m_rubber->setGeometry(r);
595 int xv1 = d_ptr->m_clickPos.x();
596 int xv2 = e->position().toPoint().x();
602 int yv1 = d_ptr->m_clickPos.y();
603 int yv2 = e->position().toPoint().y();
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);
619 p1 = QPoint(xv1, qRound(d_ptr->m_handleSize / 2));
620 p2 = QPoint(xv2, qRound(d_ptr->m_handleSize / 2));
623 const auto beginList = d_ptr->stopsAt(p1);
624 const auto endList = d_ptr->stopsAt(p2);
626 double x1 = d_ptr->fromViewport(xv1);
627 double x2 = d_ptr->fromViewport(xv2);
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);
634 d_ptr->m_model->selectStop(stop,
false);
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();
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();
688 auto itStop = stops.cbegin();
689 while (itStop.value() != current)
691 if (e->key() == Qt::Key_Left && itStop != stops.constBegin())
693 else if (e->key() == Qt::Key_Right && itStop != --stops.constEnd())
695 newCurrent = itStop.value();
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();
714#ifndef QT_NO_DRAGANDDROP
715 if (d_ptr->m_dragModel)
716 model = d_ptr->m_dragModel;
719 QSize size = viewport()->size();
720 int w = size.width();
721 double h = size.height() - d_ptr->m_handleSize;
728 if (d_ptr->m_backgroundCheckered) {
730 QPixmap pm(2 * pixSize, 2 * pixSize);
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);
738 p.setBrushOrigin((size.width() % pixSize + pixSize) / 2, (size.height() % pixSize + pixSize) / 2);
739 p.fillRect(viewport()->rect(), pm);
740 p.setBrushOrigin(0, 0);
745 const double viewBegin =
double(w) * horizontalScrollBar()->value() / d_ptr->m_scaleFactor;
747 int val = horizontalScrollBar()->value();
748 int max = horizontalScrollBar()->maximum();
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;
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) {
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);
767 lg.setColorAt(0, model->color(begin));
768 lg.setColorAt(1, model->color(end));
769 QImage img(w, 1, QImage::Format_ARGB32_Premultiplied);
771 p1.setCompositionMode(QPainter::CompositionMode_Source);
774
775
776
777
778
779 p1.fillRect(0, 0, w, 1, lg);
781 p.fillRect(QRectF(0, d_ptr->m_handleSize, w, h), QPixmap::fromImage(img));
785 double handleWidth = d_ptr->m_handleSize * d_ptr->m_scaleFactor / (w * (d_ptr->m_scaleFactor + max));
787 QColor insideColor = QColor::fromRgb(0x20, 0x20, 0x20, 0xFF);
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);
796 p.setRenderHint(QPainter::Antialiasing);
797 for (
auto rit = d_ptr->m_stops.crbegin(), rend = d_ptr->m_stops.crend(); rit != rend; ++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;
803 QColor c = stop->color();
804#ifndef QT_NO_DRAGANDDROP
805 if (stop == d_ptr->m_dragStop)
806 c = d_ptr->m_dragColor;
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);
812 drawColor = QColor::fromRgb(0x40, 0x40, 0x40, 0x80);
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);
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);
825 p.drawLine(QPointF(viewX, d_ptr->m_handleSize), QPointF(viewX, d_ptr->m_handleSize + h / 2));
828 pen.setBrush(drawColor);
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)) {
837 pen.setBrush(insideColor);
840 p.setBrush(Qt::NoBrush);
843 pen.setBrush(inColor);
850 if (d_ptr->m_model->currentStop() == stop) {
851 p.setBrush(Qt::NoBrush);
853 pen.setBrush(drawColor);
855 if (!d_ptr->m_model->isSelected(stop)) {
860 p.drawEllipse(rect.adjusted(corr, corr, -corr, -corr));
867 if (d_ptr->m_backgroundCheckered) {
870 p.drawPixmap(0, 0, pix);
892 d_ptr->m_clickPos = e->pos();
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);
905 zoomOutAction->setEnabled(
false);
906 zoomAllAction->setEnabled(
false);
907 }
else if (
zoom() >= 100) {
908 zoomInAction->setEnabled(
false);
917 menu.addAction(newStopAction);
918 menu.addAction(deleteAction);
919 menu.addAction(flipAllAction);
920 menu.addAction(selectAllAction);
922 menu.addAction(zoomInAction);
923 menu.addAction(zoomOutAction);
924 menu.addAction(zoomAllAction);
925 menu.exec(e->globalPos());