374 : QAbstractScrollArea(parent), d_ptr(
new QtGradientStopsWidgetPrivate)
377 d_ptr->m_backgroundCheckered =
true;
379 d_ptr->m_handleSize = 25.0;
380 d_ptr->m_scaleFactor = 1000;
381 d_ptr->m_moving =
false;
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;
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);
397 setAcceptDrops(
true);
399 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred));
439 if (e->button() != Qt::LeftButton)
442 d_ptr->m_moving =
true;
444 d_ptr->m_moveStops.clear();
445 d_ptr->m_moveOriginal.clear();
446 d_ptr->m_clickPos = e->position().toPoint();
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) {
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())
466 d_ptr->m_model->selectStop(stop,
true);
468 if (!d_ptr->m_model->isSelected(stop)) {
469 d_ptr->m_model->clearSelection();
470 d_ptr->m_model->selectStop(stop,
true);
473 d_ptr->setupMove(stop, e->position().toPoint().x());
475 d_ptr->m_model->clearSelection();
476 d_ptr->m_rubber->setGeometry(QRect(d_ptr->m_clickPos, QSize()));
477 d_ptr->m_rubber->show();
479 viewport()->update();
501 if (!(e->buttons() & Qt::LeftButton))
504 if (!d_ptr->m_moving)
507 if (!d_ptr->m_moveStops.isEmpty()) {
508 double maxOffset = 0.0;
509 double minOffset = 0.0;
511 auto itStop = d_ptr->m_moveStops.cbegin();
512 while (itStop != d_ptr->m_moveStops.constEnd()) {
513 double offset = itStop.value();
520 if (maxOffset < offset)
522 else if (minOffset > offset)
528 double viewportMin = d_ptr->toViewport(-minOffset);
529 double viewportMax = d_ptr->toViewport(1.0 - maxOffset);
531 QtGradientStopsModel::PositionStopMap newPositions;
533 int viewportX = e->position().toPoint().x() - d_ptr->m_moveOffset;
535 if (viewportX > viewport()->size().width())
536 viewportX = viewport()->size().width();
537 else if (viewportX < 0)
540 double posX = d_ptr->fromViewport(viewportX);
542 if (viewportX > viewportMax)
543 posX = 1.0 - maxOffset;
544 else if (viewportX < viewportMin)
547 itStop = d_ptr->m_moveStops.constBegin();
548 while (itStop != d_ptr->m_moveStops.constEnd()) {
551 newPositions[posX + itStop.value()] = stop;
557 auto itNewPos = newPositions.cbegin();
558 if (itNewPos.value()->position() < itNewPos.key())
561 itNewPos = forward ? newPositions.constBegin() : newPositions.constEnd();
562 while (itNewPos != (forward ? newPositions.constEnd() : newPositions.constBegin())) {
566 double newPos = itNewPos.key();
573 if (existingStop && !d_ptr->m_moveStops.contains(existingStop))
574 d_ptr->m_model->removeStop(existingStop);
575 d_ptr->m_model->moveStop(stop, newPos);
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());
591 QRect r(QRect(d_ptr->m_clickPos, e->position().toPoint()).normalized());
593 d_ptr->m_rubber->setGeometry(r);
596 int xv1 = d_ptr->m_clickPos.x();
597 int xv2 = e->position().toPoint().x();
603 int yv1 = d_ptr->m_clickPos.y();
604 int yv2 = e->position().toPoint().y();
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);
620 p1 = QPoint(xv1, qRound(d_ptr->m_handleSize / 2));
621 p2 = QPoint(xv2, qRound(d_ptr->m_handleSize / 2));
624 const auto beginList = d_ptr->stopsAt(p1);
625 const auto endList = d_ptr->stopsAt(p2);
627 double x1 = d_ptr->fromViewport(xv1);
628 double x2 = d_ptr->fromViewport(xv2);
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);
635 d_ptr->m_model->selectStop(stop,
false);
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();
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();
689 auto itStop = stops.cbegin();
690 while (itStop.value() != current)
692 if (e->key() == Qt::Key_Left && itStop != stops.constBegin())
694 else if (e->key() == Qt::Key_Right && itStop != --stops.constEnd())
696 newCurrent = itStop.value();
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();
715#ifndef QT_NO_DRAGANDDROP
716 if (d_ptr->m_dragModel)
717 model = d_ptr->m_dragModel;
720 QSize size = viewport()->size();
721 int w = size.width();
722 double h = size.height() - d_ptr->m_handleSize;
729 if (d_ptr->m_backgroundCheckered) {
731 QPixmap pm(2 * pixSize, 2 * pixSize);
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);
739 p.setBrushOrigin((size.width() % pixSize + pixSize) / 2, (size.height() % pixSize + pixSize) / 2);
740 p.fillRect(viewport()->rect(), pm);
741 p.setBrushOrigin(0, 0);
746 const double viewBegin =
double(w) * horizontalScrollBar()->value() / d_ptr->m_scaleFactor;
748 int val = horizontalScrollBar()->value();
749 int max = horizontalScrollBar()->maximum();
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;
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) {
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);
768 lg.setColorAt(0, model->color(begin));
769 lg.setColorAt(1, model->color(end));
770 QImage img(w, 1, QImage::Format_ARGB32_Premultiplied);
772 p1.setCompositionMode(QPainter::CompositionMode_Source);
775
776
777
778
779
780 p1.fillRect(0, 0, w, 1, lg);
782 p.fillRect(QRectF(0, d_ptr->m_handleSize, w, h), QPixmap::fromImage(img));
786 double handleWidth = d_ptr->m_handleSize * d_ptr->m_scaleFactor / (w * (d_ptr->m_scaleFactor + max));
788 QColor insideColor = QColor::fromRgb(0x20, 0x20, 0x20, 0xFF);
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);
797 p.setRenderHint(QPainter::Antialiasing);
798 for (
auto rit = d_ptr->m_stops.crbegin(), rend = d_ptr->m_stops.crend(); rit != rend; ++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;
804 QColor c = stop->color();
805#ifndef QT_NO_DRAGANDDROP
806 if (stop == d_ptr->m_dragStop)
807 c = d_ptr->m_dragColor;
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);
813 drawColor = QColor::fromRgb(0x40, 0x40, 0x40, 0x80);
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);
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);
826 p.drawLine(QPointF(viewX, d_ptr->m_handleSize), QPointF(viewX, d_ptr->m_handleSize + h / 2));
829 pen.setBrush(drawColor);
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)) {
838 pen.setBrush(insideColor);
841 p.setBrush(Qt::NoBrush);
844 pen.setBrush(inColor);
851 if (d_ptr->m_model->currentStop() == stop) {
852 p.setBrush(Qt::NoBrush);
854 pen.setBrush(drawColor);
856 if (!d_ptr->m_model->isSelected(stop)) {
861 p.drawEllipse(rect.adjusted(corr, corr, -corr, -corr));
868 if (d_ptr->m_backgroundCheckered) {
871 p.drawPixmap(0, 0, pix);
893 d_ptr->m_clickPos = e->pos();
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);
906 zoomOutAction->setEnabled(
false);
907 zoomAllAction->setEnabled(
false);
908 }
else if (
zoom() >= 100) {
909 zoomInAction->setEnabled(
false);
918 menu.addAction(newStopAction);
919 menu.addAction(deleteAction);
920 menu.addAction(flipAllAction);
921 menu.addAction(selectAllAction);
923 menu.addAction(zoomInAction);
924 menu.addAction(zoomOutAction);
925 menu.addAction(zoomAllAction);
926 menu.exec(e->globalPos());