371 : QAbstractScrollArea(parent), d_ptr(
new QtGradientStopsWidgetPrivate)
374 d_ptr->m_backgroundCheckered =
true;
376 d_ptr->m_handleSize = 25.0;
377 d_ptr->m_scaleFactor = 1000;
378 d_ptr->m_moving =
false;
380 d_ptr->m_rubber =
new QRubberBand(QRubberBand::Rectangle,
this);
381#ifndef QT_NO_DRAGANDDROP
382 d_ptr->m_dragStop = 0;
383 d_ptr->m_changedStop = 0;
384 d_ptr->m_clonedStop = 0;
385 d_ptr->m_dragModel = 0;
387 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
388 setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
389 horizontalScrollBar()->setRange(0, (
int)(d_ptr->m_scaleFactor * (d_ptr->m_zoom - 1) + 0.5));
390 horizontalScrollBar()->setPageStep(d_ptr->m_scaleFactor);
391 horizontalScrollBar()->setSingleStep(4);
392 viewport()->setAutoFillBackground(
false);
394 setAcceptDrops(
true);
396 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred));
436 if (e->button() != Qt::LeftButton)
439 d_ptr->m_moving =
true;
441 d_ptr->m_moveStops.clear();
442 d_ptr->m_moveOriginal.clear();
443 d_ptr->m_clickPos = e->position().toPoint();
446 if (e->modifiers() & Qt::ControlModifier) {
447 d_ptr->m_model->selectStop(stop, !d_ptr->m_model->isSelected(stop));
448 }
else if (e->modifiers() & Qt::ShiftModifier) {
451 const auto stops = d_ptr->m_model->stops();
452 auto itSt = stops.constFind(oldCurrent->position());
453 if (itSt != stops.constEnd()) {
454 while (itSt != stops.constFind(stop->position())) {
455 d_ptr->m_model->selectStop(itSt.value(),
true);
456 if (oldCurrent->position() < stop->position())
463 d_ptr->m_model->selectStop(stop,
true);
465 if (!d_ptr->m_model->isSelected(stop)) {
466 d_ptr->m_model->clearSelection();
467 d_ptr->m_model->selectStop(stop,
true);
470 d_ptr->setupMove(stop, e->position().toPoint().x());
472 d_ptr->m_model->clearSelection();
473 d_ptr->m_rubber->setGeometry(QRect(d_ptr->m_clickPos, QSize()));
474 d_ptr->m_rubber->show();
476 viewport()->update();
498 if (!(e->buttons() & Qt::LeftButton))
501 if (!d_ptr->m_moving)
504 if (!d_ptr->m_moveStops.isEmpty()) {
505 double maxOffset = 0.0;
506 double minOffset = 0.0;
508 auto itStop = d_ptr->m_moveStops.cbegin();
509 while (itStop != d_ptr->m_moveStops.constEnd()) {
510 double offset = itStop.value();
517 if (maxOffset < offset)
519 else if (minOffset > offset)
525 double viewportMin = d_ptr->toViewport(-minOffset);
526 double viewportMax = d_ptr->toViewport(1.0 - maxOffset);
528 QtGradientStopsModel::PositionStopMap newPositions;
530 int viewportX = e->position().toPoint().x() - d_ptr->m_moveOffset;
532 if (viewportX > viewport()->size().width())
533 viewportX = viewport()->size().width();
534 else if (viewportX < 0)
537 double posX = d_ptr->fromViewport(viewportX);
539 if (viewportX > viewportMax)
540 posX = 1.0 - maxOffset;
541 else if (viewportX < viewportMin)
544 itStop = d_ptr->m_moveStops.constBegin();
545 while (itStop != d_ptr->m_moveStops.constEnd()) {
548 newPositions[posX + itStop.value()] = stop;
554 auto itNewPos = newPositions.cbegin();
555 if (itNewPos.value()->position() < itNewPos.key())
558 itNewPos = forward ? newPositions.constBegin() : newPositions.constEnd();
559 while (itNewPos != (forward ? newPositions.constEnd() : newPositions.constBegin())) {
563 double newPos = itNewPos.key();
570 if (existingStop && !d_ptr->m_moveStops.contains(existingStop))
571 d_ptr->m_model->removeStop(existingStop);
572 d_ptr->m_model->moveStop(stop, newPos);
578 auto itOld = d_ptr->m_moveOriginal.cbegin();
579 while (itOld != d_ptr->m_moveOriginal.constEnd()) {
580 double position = itOld.key();
581 if (!d_ptr->m_model->at(position))
582 d_ptr->m_model->addStop(position, itOld.value());
588 QRect r(QRect(d_ptr->m_clickPos, e->position().toPoint()).normalized());
590 d_ptr->m_rubber->setGeometry(r);
593 int xv1 = d_ptr->m_clickPos.x();
594 int xv2 = e->position().toPoint().x();
600 int yv1 = d_ptr->m_clickPos.y();
601 int yv2 = e->position().toPoint().y();
610 if (yv2 < d_ptr->m_handleSize / 2) {
611 p1 = QPoint(xv1, yv2);
612 p2 = QPoint(xv2, yv2);
613 }
else if (yv1 > d_ptr->m_handleSize / 2) {
614 p1 = QPoint(xv1, yv1);
615 p2 = QPoint(xv2, yv1);
617 p1 = QPoint(xv1, qRound(d_ptr->m_handleSize / 2));
618 p2 = QPoint(xv2, qRound(d_ptr->m_handleSize / 2));
621 const auto beginList = d_ptr->stopsAt(p1);
622 const auto endList = d_ptr->stopsAt(p2);
624 double x1 = d_ptr->fromViewport(xv1);
625 double x2 = d_ptr->fromViewport(xv2);
627 for (QtGradientStop *stop : std::as_const(d_ptr->m_stops)) {
628 if ((stop->position() >= x1 && stop->position() <= x2) ||
629 beginList.contains(stop) || endList.contains(stop))
630 d_ptr->m_model->selectStop(stop,
true);
632 d_ptr->m_model->selectStop(stop,
false);
671 if (e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace) {
672 d_ptr->m_model->deleteStops();
673 }
else if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Right ||
674 e->key() == Qt::Key_Home || e->key() == Qt::Key_End) {
675 const auto stops = d_ptr->m_model->stops();
680 if (!current || e->key() == Qt::Key_Home || e->key() == Qt::Key_End) {
681 if (e->key() == Qt::Key_Left || e->key() == Qt::Key_Home)
682 newCurrent = stops.constBegin().value();
683 else if (e->key() == Qt::Key_Right || e->key() == Qt::Key_End)
684 newCurrent = (--stops.constEnd()).value();
686 auto itStop = stops.cbegin();
687 while (itStop.value() != current)
689 if (e->key() == Qt::Key_Left && itStop != stops.constBegin())
691 else if (e->key() == Qt::Key_Right && itStop != --stops.constEnd())
693 newCurrent = itStop.value();
695 d_ptr->m_model->clearSelection();
696 d_ptr->m_model->selectStop(newCurrent,
true);
697 d_ptr->m_model->setCurrentStop(newCurrent);
698 d_ptr->ensureVisible(newCurrent);
699 }
else if (e->key() == Qt::Key_A) {
700 if (e->modifiers() & Qt::ControlModifier)
701 d_ptr->m_model->selectAll();
712#ifndef QT_NO_DRAGANDDROP
713 if (d_ptr->m_dragModel)
714 model = d_ptr->m_dragModel;
717 QSize size = viewport()->size();
718 int w = size.width();
719 double h = size.height() - d_ptr->m_handleSize;
726 if (d_ptr->m_backgroundCheckered) {
728 QPixmap pm(2 * pixSize, 2 * pixSize);
730 pmp.fillRect(0, 0, pixSize, pixSize, Qt::white);
731 pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white);
732 pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black);
733 pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black);
736 p.setBrushOrigin((size.width() % pixSize + pixSize) / 2, (size.height() % pixSize + pixSize) / 2);
737 p.fillRect(viewport()->rect(), pm);
738 p.setBrushOrigin(0, 0);
743 const double viewBegin =
double(w) * horizontalScrollBar()->value() / d_ptr->m_scaleFactor;
745 int val = horizontalScrollBar()->value();
746 int max = horizontalScrollBar()->maximum();
748 const double begin =
double(val) / (d_ptr->m_scaleFactor + max);
749 const double end =
double(val + d_ptr->m_scaleFactor) / (d_ptr->m_scaleFactor + max);
750 double width = end - begin;
753 QLinearGradient lg(0, 0, w, 0);
754 QMap<qreal, QtGradientStop *> stops = model->stops();
755 for (
auto itStop = stops.cbegin(), send = stops.cend(); itStop != send; ++itStop) {
757 double pos = stop->position();
758 if (pos >= begin && pos <= end) {
759 double gradPos = (pos - begin) / width;
760 QColor c = stop->color();
761 lg.setColorAt(gradPos, c);
765 lg.setColorAt(0, model->color(begin));
766 lg.setColorAt(1, model->color(end));
767 QImage img(w, 1, QImage::Format_ARGB32_Premultiplied);
769 p1.setCompositionMode(QPainter::CompositionMode_Source);
772
773
774
775
776
777 p1.fillRect(0, 0, w, 1, lg);
779 p.fillRect(QRectF(0, d_ptr->m_handleSize, w, h), QPixmap::fromImage(img));
783 double handleWidth = d_ptr->m_handleSize * d_ptr->m_scaleFactor / (w * (d_ptr->m_scaleFactor + max));
785 QColor insideColor = QColor::fromRgb(0x20, 0x20, 0x20, 0xFF);
787 QColor back1 = QColor(Qt::lightGray);
788 QColor back2 = QColor(Qt::darkGray);
789 QColor back = QColor::fromRgb((back1.red() + back2.red()) / 2,
790 (back1.green() + back2.green()) / 2,
791 (back1.blue() + back2.blue()) / 2);
794 p.setRenderHint(QPainter::Antialiasing);
795 for (
auto rit = d_ptr->m_stops.crbegin(), rend = d_ptr->m_stops.crend(); rit != rend; ++rit) {
797 double x = stop->position();
798 if (x >= begin - handleWidth / 2 && x <= end + handleWidth / 2) {
799 double viewX = x * w * (d_ptr->m_scaleFactor + max) / d_ptr->m_scaleFactor - viewBegin;
801 QColor c = stop->color();
802#ifndef QT_NO_DRAGANDDROP
803 if (stop == d_ptr->m_dragStop)
804 c = d_ptr->m_dragColor;
806 if ((0.3 * c.redF() + 0.59 * c.greenF() + 0.11 * c.blueF()) * c.alphaF() +
807 (0.3 * back.redF() + 0.59 * back.greenF() + 0.11 * back.blueF()) * (1.0 - c.alphaF()) < 0.5) {
808 drawColor = QColor::fromRgb(0xC0, 0xC0, 0xC0, 0xB0);
810 drawColor = QColor::fromRgb(0x40, 0x40, 0x40, 0x80);
812 QRectF rect(viewX - d_ptr->m_handleSize / 2, 0, d_ptr->m_handleSize, d_ptr->m_handleSize);
813 rect.adjust(0.5, 0.5, -0.5, -0.5);
816 QLinearGradient lg(0, d_ptr->m_handleSize, 0, d_ptr->m_handleSize + h / 2);
817 lg.setColorAt(0, drawColor);
818 QColor alphaZero = drawColor;
819 alphaZero.setAlpha(0);
820 lg.setColorAt(1, alphaZero);
823 p.drawLine(QPointF(viewX, d_ptr->m_handleSize), QPointF(viewX, d_ptr->m_handleSize + h / 2));
826 pen.setBrush(drawColor);
828 QRectF r1 = rect.adjusted(0.5, 0.5, -0.5, -0.5);
829 QRectF r2 = rect.adjusted(1.5, 1.5, -1.5, -1.5);
830 QColor inColor = QColor::fromRgb(0x80, 0x80, 0x80, 0x80);
831 if (!d_ptr->m_model->isSelected(stop)) {
835 pen.setBrush(insideColor);
838 p.setBrush(Qt::NoBrush);
841 pen.setBrush(inColor);
848 if (d_ptr->m_model->currentStop() == stop) {
849 p.setBrush(Qt::NoBrush);
851 pen.setBrush(drawColor);
853 if (!d_ptr->m_model->isSelected(stop)) {
858 p.drawEllipse(rect.adjusted(corr, corr, -corr, -corr));
865 if (d_ptr->m_backgroundCheckered) {
868 p.drawPixmap(0, 0, pix);
890 d_ptr->m_clickPos = e->pos();
893 QAction *newStopAction =
new QAction(tr(
"New Stop"), &menu);
894 QAction *deleteAction =
new QAction(tr(
"Delete"), &menu);
895 QAction *flipAllAction =
new QAction(tr(
"Flip All"), &menu);
896 QAction *selectAllAction =
new QAction(tr(
"Select All"), &menu);
897 QAction *zoomInAction =
new QAction(tr(
"Zoom In"), &menu);
898 QAction *zoomOutAction =
new QAction(tr(
"Zoom Out"), &menu);
899 QAction *zoomAllAction =
new QAction(tr(
"Reset Zoom"), &menu);
900 if (d_ptr->m_model->selectedStops().isEmpty() && !d_ptr->m_model->currentStop())
901 deleteAction->setEnabled(
false);
903 zoomOutAction->setEnabled(
false);
904 zoomAllAction->setEnabled(
false);
905 }
else if (
zoom() >= 100) {
906 zoomInAction->setEnabled(
false);
908 connect(newStopAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotNewStop);
909 connect(deleteAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotDelete);
910 connect(flipAllAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotFlipAll);
911 connect(selectAllAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotSelectAll);
912 connect(zoomInAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotZoomIn);
913 connect(zoomOutAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotZoomOut);
914 connect(zoomAllAction, &QAction::triggered, d_ptr.data(), &QtGradientStopsWidgetPrivate::slotResetZoom);
915 menu.addAction(newStopAction);
916 menu.addAction(deleteAction);
917 menu.addAction(flipAllAction);
918 menu.addAction(selectAllAction);
920 menu.addAction(zoomInAction);
921 menu.addAction(zoomOutAction);
922 menu.addAction(zoomAllAction);
923 menu.exec(e->globalPos());