Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAsyncColorSamplerHelper Class Reference

#include <KisAsyncColorSamplerHelper.h>

+ Inheritance diagram for KisAsyncColorSamplerHelper:

Classes

struct  Private
 

Signals

void sigColorSelected (const KoColor &color)
 
void sigFinalColorSelected (const KoColor &color)
 
void sigRawColorSelected (const KoColor &color)
 
void sigRequestCursor (const QCursor &cursor)
 
void sigRequestCursorReset ()
 
void sigRequestUpdateOutline ()
 

Public Member Functions

void activate (bool sampleCurrentLayer, bool pickFgColor)
 
QRectF colorPreviewDocRect (const QPointF &docPoint)
 
void continueAction (const QPointF &docPoint)
 
void deactivate ()
 
void endAction ()
 
bool isActive () const
 
 KisAsyncColorSamplerHelper (KisCanvas2 *canvas)
 
void paint (QPainter &gc, const KoViewConverter &converter)
 
void setUpdateGlobalColor (bool value)
 
void startAction (const QPointF &docPoint, int radius, int blend)
 
void updateCursor (bool sampleCurrentLayer, bool pickFgColor)
 
bool updateGlobalColor () const
 
 ~KisAsyncColorSamplerHelper () override
 

Private Slots

void activateDelayedPreview ()
 
void slotAddSamplingJob (const QPointF &docPoint)
 
void slotCanvasZoomPreviewUpdated (const QImage &canvasImage, QRect canvasRect)
 
void slotColorSamplingFinished (const KoColor &rawColor)
 
void slotUpdateBgColor ()
 

Private Member Functions

void activatePreview ()
 
void paintCircle (QPainter &gc, const QRectF &viewRectF, const QColor &currentColor, const QColor &baseColor)
 
void paintCircleCanvasPreview (QPainter &gc, const QRectF &viewRectF, const QPainterPath &clip)
 
void paintCircleCrosshair (QPainter &gc, const QRectF &viewRectF, const QColor &currentColor)
 
void paintCircleReferenceImagePreview (QPainter &gc, const QRectF &viewRectF, const QPainterPath &clip)
 
void paintRectangle (QPainter &gc, const QRectF &viewRectF, const QColor &currentColor, const QColor &baseColor)
 
void prepareZoomPreview (const QRectF &docRect)
 

Private Attributes

QScopedPointer< Privatem_d
 

Detailed Description

Definition at line 24 of file KisAsyncColorSamplerHelper.h.

Constructor & Destructor Documentation

◆ KisAsyncColorSamplerHelper()

KisAsyncColorSamplerHelper::KisAsyncColorSamplerHelper ( KisCanvas2 * canvas)

Definition at line 278 of file KisAsyncColorSamplerHelper.cpp.

279 : m_d(new Private(canvas))
280{
281 using namespace std::placeholders; // For _1 placeholder
282 std::function<void(QPointF)> callback =
284 m_d->samplingCompressor.reset(
286
287 m_d->activationDelayTimer.setInterval(100);
288 m_d->activationDelayTimer.setSingleShot(true);
289 connect(&m_d->activationDelayTimer, SIGNAL(timeout()), this, SLOT(activateDelayedPreview()));
290 connect(m_d->canvas->displayColorConverter(), SIGNAL(displayConfigurationChanged()), this, SLOT(slotUpdateBgColor()));
292}
void slotAddSamplingJob(const QPointF &docPoint)
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)
KisSignalCompressorWithParam< QPointF > SamplingCompressor

References activateDelayedPreview(), KisSignalCompressor::FIRST_ACTIVE, m_d, slotAddSamplingJob(), slotUpdateBgColor(), and void().

◆ ~KisAsyncColorSamplerHelper()

KisAsyncColorSamplerHelper::~KisAsyncColorSamplerHelper ( )
override

Definition at line 294 of file KisAsyncColorSamplerHelper.cpp.

295{
297}
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130

References KIS_SAFE_ASSERT_RECOVER_NOOP, and m_d.

Member Function Documentation

◆ activate()

void KisAsyncColorSamplerHelper::activate ( bool sampleCurrentLayer,
bool pickFgColor )

Definition at line 304 of file KisAsyncColorSamplerHelper.cpp.

305{
306
308 m_d->isActive = true;
309
310 m_d->sampleResourceId =
311 pickFgColor ?
314
315 m_d->sampleCurrentLayer = sampleCurrentLayer;
316 m_d->haveSample = false;
317
318
319 KisConfig cfg(true);
320 m_d->style = cfg.colorSamplerPreviewStyle();
321
322 m_d->circlePreviewDiameter = cfg.colorSamplerPreviewCircleDiameter();
323 m_d->circlePreviewThickness = cfg.colorSamplerPreviewCircleThickness()/100.0; // saved in percentages
324 m_d->circlePreviewOutlineEnabled = cfg.colorSamplerPreviewCircleOutlineEnabled();
325 m_d->circlePreviewExtraCircles = cfg.colorSamplerPreviewCircleExtraCirclesEnabled();
326 m_d->circleZoomPreviewEnabled = cfg.colorSamplerZoomPreviewEnabled();
327 m_d->circleZoomPreviewScale = cfg.colorSamplerZoomPreviewScale();
328 m_d->circlePreviewPosition = cfg.colorSamplerPreviewCirclePosition();
329
330 m_d->activationDelayTimer.start();
331}
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
@ BackgroundColor
The active background color selected for this canvas.
@ ForegroundColor
The active foreground color selected for this canvas.

References KoCanvasResource::BackgroundColor, KisConfig::colorSamplerPreviewCircleDiameter(), KisConfig::colorSamplerPreviewCircleExtraCirclesEnabled(), KisConfig::colorSamplerPreviewCircleOutlineEnabled(), KisConfig::colorSamplerPreviewCirclePosition(), KisConfig::colorSamplerPreviewCircleThickness(), KisConfig::colorSamplerPreviewStyle(), KisConfig::colorSamplerZoomPreviewEnabled(), KisConfig::colorSamplerZoomPreviewScale(), KoCanvasResource::ForegroundColor, KIS_SAFE_ASSERT_RECOVER_RETURN, and m_d.

◆ activateDelayedPreview

void KisAsyncColorSamplerHelper::activateDelayedPreview ( )
privateslot

Definition at line 333 of file KisAsyncColorSamplerHelper.cpp.

334{
335 // the event may come after we have started or even
336 // finished color picking if the user is quick
337 if (!m_d->isActive || m_d->showPreview) {
338 return;
339 }
340
342
344}

References activatePreview(), m_d, and sigRequestUpdateOutline().

◆ activatePreview()

void KisAsyncColorSamplerHelper::activatePreview ( )
private

Definition at line 346 of file KisAsyncColorSamplerHelper.cpp.

347{
348 m_d->activationDelayTimer.stop();
349 m_d->showPreview = true;
350
351 const KoColor currentColor =
352 m_d->canvas->resourceManager()->koColorResource(m_d->sampleResourceId);
353 const QColor previewColor = m_d->canvas->displayColorConverter()->convertColorToDisplayColorSpace(currentColor, true);
354
355 m_d->currentColor = previewColor;
356 m_d->baseColor = previewColor;
357 m_d->cache = QPixmap();
358
359 updateCursor(m_d->sampleCurrentLayer, m_d->sampleResourceId == KoCanvasResource::ForegroundColor);
360}
void updateCursor(bool sampleCurrentLayer, bool pickFgColor)
KoColor currentColor(ResourceProvider *provider, ColorRole role)

References KoCanvasResource::ForegroundColor, m_d, and updateCursor().

◆ colorPreviewDocRect()

QRectF KisAsyncColorSamplerHelper::colorPreviewDocRect ( const QPointF & docPoint)

Definition at line 459 of file KisAsyncColorSamplerHelper.cpp.

460{
461 if (!m_d->showPreview) return QRectF();
462
463 m_d->sampleDocPoint = docPoint;
464
465 KisConfig cfg(true);
466 m_d->style = cfg.colorSamplerPreviewStyle();
467 QRectF previewDocRect = m_d->colorPreviewDocRect(docPoint);
468
469 if (previewDocRect != m_d->previewDocRect) prepareZoomPreview(previewDocRect);
470
471 m_d->previewDocRect = previewDocRect;
472
473 return m_d->previewDocRect;
474}
void prepareZoomPreview(const QRectF &docRect)

References KisConfig::colorSamplerPreviewStyle(), m_d, and prepareZoomPreview().

◆ continueAction()

void KisAsyncColorSamplerHelper::continueAction ( const QPointF & docPoint)

Definition at line 442 of file KisAsyncColorSamplerHelper.cpp.

443{
445 m_d->samplingCompressor->start(docPoint);
446}

References KIS_SAFE_ASSERT_RECOVER_RETURN, and m_d.

◆ deactivate()

void KisAsyncColorSamplerHelper::deactivate ( )

Definition at line 398 of file KisAsyncColorSamplerHelper.cpp.

399{
400 KIS_SAFE_ASSERT_RECOVER(!m_d->strokeId) {
401 endAction();
402 }
403
404 m_d->activationDelayTimer.stop();
405
406 m_d->showPreview = false;
407 m_d->haveSample = false;
408
409 m_d->previewDocRect = QRectF();
410 m_d->currentColor = QColor();
411 m_d->baseColor = QColor();
412 m_d->cache = QPixmap();
413
414 // Reset the cached zoom preview image and rect
415 m_d->cacheCanvasPreviewImage = QImage();
416 m_d->cacheCanvasPreviewRect = QRect();
417 m_d->zoomPreviewHasPainted = false;
418 m_d->zoomDocRectF = QRectF();
419
420 m_d->isActive = false;
421
422 Q_EMIT sigRequestCursorReset();
424}
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126

References endAction(), KIS_SAFE_ASSERT_RECOVER, m_d, sigRequestCursorReset(), and sigRequestUpdateOutline().

◆ endAction()

void KisAsyncColorSamplerHelper::endAction ( )

Definition at line 448 of file KisAsyncColorSamplerHelper.cpp.

449{
451
452 m_d->strokesFacade()->addJob(m_d->strokeId,
454
455 m_d->strokesFacade()->endStroke(m_d->strokeId);
456 m_d->strokeId.clear();
457}

References KIS_SAFE_ASSERT_RECOVER_RETURN, and m_d.

◆ isActive()

bool KisAsyncColorSamplerHelper::isActive ( ) const

Definition at line 299 of file KisAsyncColorSamplerHelper.cpp.

300{
301 return m_d->isActive;
302}

References m_d.

◆ paint()

void KisAsyncColorSamplerHelper::paint ( QPainter & gc,
const KoViewConverter & converter )

Definition at line 517 of file KisAsyncColorSamplerHelper.cpp.

518{
519 if (!m_d->showPreview) {
520 return;
521 }
522
523 QRectF viewRectF = converter.documentToView(m_d->previewDocRect);
524 QColor currentColor = colorWithAlpha(m_d->currentColor, OPACITY_OPAQUE_U8);
525 QColor baseColor = m_d->haveSample ? colorWithAlpha(m_d->baseColor, OPACITY_OPAQUE_U8) : currentColor;
526
527 switch (m_d->style) {
531 paintRectangle(gc, viewRectF, currentColor, baseColor);
532 break;
533 default:
534 // See comment in colorPreviewDocRect.
535 if (m_d->haveSample) {
536 paintCircle(gc, viewRectF, currentColor, baseColor);
537 } else {
538 paintRectangle(gc, viewRectF, currentColor, baseColor);
539 }
540 break;
541 }
542}
const quint8 OPACITY_OPAQUE_U8
void paintRectangle(QPainter &gc, const QRectF &viewRectF, const QColor &currentColor, const QColor &baseColor)
void paintCircle(QPainter &gc, const QRectF &viewRectF, const QColor &currentColor, const QColor &baseColor)
virtual QPointF documentToView(const QPointF &documentPoint) const

References KoViewConverter::documentToView(), m_d, OPACITY_OPAQUE_U8, paintCircle(), paintRectangle(), KisConfig::RectangleAbove, KisConfig::RectangleLeft, and KisConfig::RectangleRight.

◆ paintCircle()

void KisAsyncColorSamplerHelper::paintCircle ( QPainter & gc,
const QRectF & viewRectF,
const QColor & currentColor,
const QColor & baseColor )
private

Definition at line 594 of file KisAsyncColorSamplerHelper.cpp.

598{
599 if (!m_d->haveSample) {
600 return;
601 }
602
603 gc.save();
604
605 qreal dpr = gc.device()->devicePixelRatioF();
606 QSizeF cacheSizeF = viewRectF.size() * dpr;
607 QSize cacheSize(qCeil(cacheSizeF.width()), qCeil(cacheSizeF.height()));
608 bool needsNewCache = m_d->cache.isNull() || m_d->cache.size() != cacheSize;
609 if (needsNewCache) {
610 m_d->cache = QPixmap(cacheSize);
611 m_d->cache.fill(Qt::transparent);
612 }
613
614 qreal canvasRotationAngle = m_d->canvas->rotationAngle();
615 if (m_d->canvas->xAxisMirrored()) {
616 canvasRotationAngle = -canvasRotationAngle;
617 }
618
619 QPainter cachePainter(&m_d->cache);
620 cachePainter.setRenderHint(QPainter::Antialiasing);
621
622 QRectF cacheRect = m_d->cache.rect();
623
624 // The color sampler preview is an outline and those rotate along
625 // with the canvas. That's undesirable for the sampler preview
626 // though, so we calculate the transformation to counter the rotation here
627 QPointF cacheCenter = cacheRect.center();
628 QTransform tf;
629 tf.translate(cacheCenter.x(), cacheCenter.y());
630 tf.rotate(-canvasRotationAngle);
631 tf.translate(-cacheCenter.x(), -cacheCenter.y());
632
633 bool needsDualColor = currentColor != baseColor;
634 if (needsNewCache || (needsDualColor && !qFuzzyCompare(m_d->cacheRotation, canvasRotationAngle))) {
635 m_d->cacheRotation = canvasRotationAngle;
636
637 QColor backgroundColor = colorWithAlpha(m_d->backgroundColor, OPACITY_OPAQUE_U8 / 2 + 1);
638 qreal penWidth = m_d->circlePreviewDiameter > 100 ? (2.0 * dpr) : (1.0 * dpr);
639 QPen pen = QPen(backgroundColor, penWidth);
640 if (m_d->circlePreviewOutlineEnabled) {
641 cachePainter.setPen(pen);
642 } else {
643 cachePainter.setPen(Qt::NoPen);
644 }
645
646 QRectF outerRect = cacheRect.marginsRemoved(QMarginsF(penWidth, penWidth, penWidth, penWidth));
647
648 if (needsDualColor) {
649 // The color sampler preview is an outline and those rotate along
650 // with the canvas. That's undesirable for the sampler preview
651 // though, so we un-rotate its contents here accordingly.
652
653 QPainterPath clipPath;
654 clipPath.addPolygon(tf.map(QPolygonF(QRectF(0, 0, cacheRect.width(), cacheRect.height() / 2.0 + 1.0))));
655 cachePainter.setClipPath(clipPath);
656
657 bool flipped = m_d->canvas->yAxisMirrored();
658 cachePainter.setBrush(flipped ? baseColor : currentColor);
659 cachePainter.drawEllipse(outerRect);
660
661 cachePainter.setBrush(baseColor);
662 clipPath.clear();
663 clipPath.addPolygon(
664 tf.map(QRectF(0, cacheRect.height() / 2.0, cacheRect.width(), cacheRect.height() / 2.0)));
665 cachePainter.setClipPath(clipPath);
666
667 cachePainter.setBrush(flipped ? currentColor : baseColor);
668 cachePainter.drawEllipse(outerRect);
669
670 cachePainter.setClipPath(QPainterPath(), Qt::NoClip);
671 } else {
672 cachePainter.setBrush(currentColor);
673 cachePainter.drawEllipse(outerRect);
674 }
675
676 qreal innerX = cacheRect.width() * (1.0 - m_d->circlePreviewThickness);
677 qreal innerY = cacheRect.height() * (1.0 - m_d->circlePreviewThickness);
678 QRectF innerRect = cacheRect.marginsRemoved(QMarginsF(innerX, innerY, innerX, innerY));
679 QPainterPath innerEllipse;
680 innerEllipse.addEllipse(innerRect);
681
682 QPainterPath innerPath;
683 innerPath.addPath(innerEllipse);
684
685 if (m_d->circlePreviewThickness < 0.5 && m_d->circlePreviewExtraCircles) {
686 qreal extraMargin = 0.1*m_d->circlePreviewThickness*innerRect.width(); // looks better
687 QPointF leftCenter = QPointF(innerRect.left() - extraMargin, innerRect.top() + innerRect.height()/2.0);
688 QPointF rightCenter = QPointF(innerRect.right() + extraMargin, innerRect.top() + innerRect.height()/2.0);
689
690 innerPath.setFillRule(Qt::OddEvenFill);
691 innerPath.addEllipse(leftCenter, m_d->circlePreviewThickness*cacheRect.width(), m_d->circlePreviewThickness*cacheRect.width());
692 innerPath.addEllipse(rightCenter, m_d->circlePreviewThickness*cacheRect.width(), m_d->circlePreviewThickness*cacheRect.width());
693
694 innerPath = innerPath.intersected(innerEllipse);
695 }
696
697 m_d->cacheCircleInnerClip = innerPath;
698
699 // Draw inner circle outline if enabled
700 if (m_d->circlePreviewOutlineEnabled) {
701 cachePainter.setBrush(Qt::transparent);
702 cachePainter.setPen(pen);
703 cachePainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
704 cachePainter.drawPath(tf.map(m_d->cacheCircleInnerClip));
705 }
706 }
707
708 cachePainter.setPen(Qt::NoPen);
709 cachePainter.setBrush(m_d->backgroundColor);
710
711 // Clear the center
712 cachePainter.setCompositionMode(QPainter::CompositionMode_Clear);
713 cachePainter.drawPath(tf.map(m_d->cacheCircleInnerClip));
714
715 // If canvas preview image is null and it's being fetched (which means canvas preview is needed),
716 // don't paint preview until it's done to avoid flickering
717 bool shouldPaintPreview = !(m_d->cacheCanvasPreviewImage.isNull() && m_d->canvasPreviewFetchCookie);
718
719 // But if zoom preview has already been painted, keeps painting to avoid flickering
720 if (m_d->circleZoomPreviewEnabled && (shouldPaintPreview || m_d->zoomPreviewHasPainted)) {
721 paintCircleCanvasPreview(cachePainter, cacheRect, tf.map(m_d->cacheCircleInnerClip));
722 paintCircleReferenceImagePreview(cachePainter, cacheRect, tf.map(m_d->cacheCircleInnerClip));
723
724 // Draw crosshair if preview is offseted
725 if (m_d->circlePreviewPosition != KisConfig::ColorSamplerPreviewCirclePosition::Center) {
726 paintCircleCrosshair(cachePainter, cacheRect, currentColor);
727 }
728
729 // Fill empty spaces to hide the underlying canvas
730 cachePainter.setCompositionMode(QPainter::CompositionMode_DestinationOver);
731 cachePainter.drawPath(tf.map(m_d->cacheCircleInnerClip));
732
733 m_d->zoomPreviewHasPainted = true;
734 }
735
736 gc.drawPixmap(viewRectF.toRect(), m_d->cache);
737
738 gc.restore();
739}
void paintCircleCrosshair(QPainter &gc, const QRectF &viewRectF, const QColor &currentColor)
void paintCircleReferenceImagePreview(QPainter &gc, const QRectF &viewRectF, const QPainterPath &clip)
void paintCircleCanvasPreview(QPainter &gc, const QRectF &viewRectF, const QPainterPath &clip)
static bool qFuzzyCompare(half p1, half p2)

References KisConfig::Center, m_d, OPACITY_OPAQUE_U8, paintCircleCanvasPreview(), paintCircleCrosshair(), paintCircleReferenceImagePreview(), and qFuzzyCompare().

◆ paintCircleCanvasPreview()

void KisAsyncColorSamplerHelper::paintCircleCanvasPreview ( QPainter & gc,
const QRectF & viewRectF,
const QPainterPath & clip )
private

Definition at line 761 of file KisAsyncColorSamplerHelper.cpp.

761 {
762 QRect canvasPixelRect = m_d->cacheCanvasPreviewRect;
763 QImage cachedImage = m_d->cacheCanvasPreviewImage;
764
765 if (cachedImage.isNull()) return;
766
767 gc.save();
768 gc.setCompositionMode(QPainter::CompositionMode_SourceOver);
769
770 gc.setClipPath(clip);
771
772 // QtDoc: The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
773 // Since the piece of canvas is (zoomPreviewScale) times smaller than cacheRect
774 // drawImage will scale it up that many times, thus achieving the zoom effect
775 gc.drawImage(viewRectF, cachedImage, canvasPixelRect);
776
777 gc.restore();
778}

References m_d.

◆ paintCircleCrosshair()

void KisAsyncColorSamplerHelper::paintCircleCrosshair ( QPainter & gc,
const QRectF & viewRectF,
const QColor & currentColor )
private

Definition at line 741 of file KisAsyncColorSamplerHelper.cpp.

742{
743 QColor crosshairColor = Qt::black;
744 qreal luminance = KisPaintingTweaks::luminosityCoarse(currentColor);
745 if (luminance < 0.5) crosshairColor = Qt::white;
746
747 gc.save();
748
749 gc.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
750 gc.setCompositionMode(QPainter::CompositionMode_SourceOver);
751 gc.setPen(crosshairColor);
752
753 QTransform tf;
754 tf.translate(viewRectF.center().x(), viewRectF.center().y());
755 tf.rotate(-m_d->cacheRotation);
756 gc.drawPath(tf.map(m_d->crosshairForOffsettedCircle()));
757
758 gc.restore();
759}
qreal luminosityCoarse(const QColor &c, bool sRGBtrc)
luminosityCoarse This calculates the luminosity of the given QColor. It uses a very coarse (10 step) ...

References KisPaintingTweaks::luminosityCoarse(), and m_d.

◆ paintCircleReferenceImagePreview()

void KisAsyncColorSamplerHelper::paintCircleReferenceImagePreview ( QPainter & gc,
const QRectF & viewRectF,
const QPainterPath & clip )
private

Definition at line 782 of file KisAsyncColorSamplerHelper.cpp.

782 {
783 KisDocument *document = m_d->canvas->viewManager()->document();
784 if (!document || !document->referenceImagesLayer()) return;
785
786 gc.save();
787
788 gc.setCompositionMode(QPainter::CompositionMode_SourceOver);
789 gc.setClipPath(clip);
790
791 QRectF zoomDocRectF = m_d->zoomDocRectF;
792
793 QList<KoShape*> shapeList = document->referenceImagesLayer()->shapeManager()->shapesAt(zoomDocRectF);
794 if (shapeList.size() > 1) std::sort(shapeList.begin(), shapeList.end(), KoShape::compareShapeZIndex);
795
796 Q_FOREACH(KoShape *shape, shapeList) {
797 KisReferenceImage *refImage = dynamic_cast<KisReferenceImage*>(shape);
798 if (!refImage) continue;
799
800 if (refImage->transparency() == 1.0) continue;
801
802 gc.save();
803
804 QImage image = refImage->getCachedImage();
805
806 QPoint refPixelPoint = refImage->documentToPixelFloored(zoomDocRectF.center());
807
808 // Avoid using KisReferenceImage::documentToPixel because it use absoluteTransformation.invert()
809 // Which will take rotation into account and cause some quirks when ref image is rotated
810 qreal xScale = refImage->size().width() / image.width();
811 qreal yScale = refImage->size().height() / image.height();
812
813 // This only happens when refImage size is 0, so painting it probably won't make senses
814 if (xScale == 0 || yScale == 0) continue;
815
816 QRect refPixelRect = QRect(refPixelPoint, QSize(zoomDocRectF.width() / xScale, zoomDocRectF.height() / yScale));
817
818 refPixelRect = m_d->standardizeZoomPreviewPixelRect(refPixelRect);
819
820 refPixelRect.moveCenter(refPixelPoint);
821
822 // Rotate the painter, draw, rotate back is seemingly easier than
823 // trying to rotate the image and the shenanighens that follow
824 gc.translate(viewRectF.center());
825 gc.rotate(refImage->rotation());
826 gc.translate(-viewRectF.center());
827
828 gc.drawImage(viewRectF, image, refPixelRect);
829
830 gc.restore();
831 }
832
833 gc.restore();
834}
KisViewManager * viewManager() const
The KisReferenceImage class represents a single reference image.
QPoint documentToPixelFloored(const QPointF &docPoint)
KisDocument * document() const
virtual QSizeF size() const
Get the size of the shape in pt.
Definition KoShape.cpp:735
qreal rotation() const
Definition KoShape.cpp:715
static bool compareShapeZIndex(KoShape *s1, KoShape *s2)
Definition KoShape.cpp:388
qreal transparency(bool recursive=false) const
Definition KoShape.cpp:645
KisCanvas2 * canvas

References Private::canvas, KoShape::compareShapeZIndex(), KisViewManager::document(), KisReferenceImage::documentToPixelFloored(), KisReferenceImage::getCachedImage(), m_d, KoShape::rotation(), KoShape::size(), KoShape::transparency(), and KisCanvas2::viewManager().

◆ paintRectangle()

void KisAsyncColorSamplerHelper::paintRectangle ( QPainter & gc,
const QRectF & viewRectF,
const QColor & currentColor,
const QColor & baseColor )
private

Definition at line 544 of file KisAsyncColorSamplerHelper.cpp.

548{
549 qreal dpr = gc.device()->devicePixelRatioF();
550 QSizeF cacheSizeF = viewRectF.size() * dpr;
551 QSize cacheSize(qCeil(cacheSizeF.width()), qCeil(cacheSizeF.height()));
552 bool needsNewCache = m_d->cache.isNull() || m_d->cache.size() != cacheSize;
553 if (needsNewCache) {
554 m_d->cache = QPixmap(cacheSize);
555 m_d->cache.fill(Qt::transparent);
556 }
557
558 qreal canvasRotationAngle = m_d->canvas->rotationAngle();
559 bool canvasMirror = m_d->canvas->xAxisMirrored();
560 if (needsNewCache || !qFuzzyCompare(canvasRotationAngle, m_d->cacheRotation) || canvasMirror != m_d->cacheMirror) {
561 m_d->cacheRotation = canvasRotationAngle;
562 m_d->cacheMirror = canvasMirror;
563
564 QPainter cachePainter(&m_d->cache);
565 cachePainter.setRenderHint(QPainter::Antialiasing);
566
567 qreal size = Private::PREVIEW_RECT_SIZE * dpr;
568 QRectF rect(0.0, 0.0, m_d->haveSample ? size * 2.0 : size, size);
569 rect.moveTopLeft(-rect.center());
570
571 QTransform tf;
572 QPointF offset = QRectF(m_d->cache.rect()).center();
573 tf.translate(offset.x(), offset.y());
574 tf.rotate(canvasMirror ? canvasRotationAngle : -canvasRotationAngle);
575 cachePainter.setTransform(tf);
576
577 if (m_d->haveSample) {
578 qreal centerX = rect.center().x();
579 QRectF currentRect(rect.topLeft(), QPointF(centerX + 1.0, rect.bottom()));
580 QRectF baseRect(QPointF(centerX, rect.top()), rect.bottomRight());
581 if (m_d->canvas->xAxisMirrored()) {
582 std::swap(currentRect, baseRect);
583 }
584 cachePainter.fillRect(currentRect, currentColor);
585 cachePainter.fillRect(baseRect, baseColor);
586 } else {
587 cachePainter.fillRect(rect, currentColor);
588 }
589 }
590
591 gc.drawPixmap(viewRectF.toRect(), m_d->cache);
592}
int size(const Forest< T > &forest)
Definition KisForest.h:1232

References m_d, KisAsyncColorSamplerHelper::Private::PREVIEW_RECT_SIZE, and qFuzzyCompare().

◆ prepareZoomPreview()

void KisAsyncColorSamplerHelper::prepareZoomPreview ( const QRectF & docRect)
private

Definition at line 476 of file KisAsyncColorSamplerHelper.cpp.

476 {
477 // This can be called before startAction(), so there may not be a strokeId
478 if (!m_d->circleZoomPreviewEnabled || !m_d->strokeId) return;
479
480 KisImageSP image = m_d->canvas->image();
481 if (!image) return;
482
483 // Prepare zoomed doc rect
484 QRectF zoomDocRectF = docRect;
485
486 zoomDocRectF.setSize(zoomDocRectF.size() / m_d->circleZoomPreviewScale);
487 zoomDocRectF.moveCenter(m_d->sampleDocPoint);
488
489 m_d->zoomDocRectF = zoomDocRectF;
490
491 // Prepare canvas preview because it takes time
492 QRectF canvasPixelRectF = image->documentToPixel(zoomDocRectF);
493 // Floor manually to avoid width != height when using toRect()
494 QRect canvasPixelRect = QRect(canvasPixelRectF.topLeft().toPoint(), QSize(qFloor(canvasPixelRectF.width()), qFloor(canvasPixelRectF.height())));
495
496 canvasPixelRect = m_d->standardizeZoomPreviewPixelRect(canvasPixelRect);
497 // Make sure the center is the pixel currently sampled because standardizing may change the shape
498 canvasPixelRect.moveCenter(image->documentToImagePixelFloored(zoomDocRectF.center()));
499
500 if (!image->bounds().intersects(canvasPixelRect) && !image->wrapAroundModeActive()) {
501 m_d->cacheCanvasPreviewRect = QRect();
502 m_d->cacheCanvasPreviewImage = QImage();
503 return;
504 }
505
506 // If not already have a job fetching canvas image, then do it
507 if (!m_d->canvasPreviewFetchCookie && m_d->cacheCanvasPreviewRect != canvasPixelRect) {
509 new KisColorSamplerStrokeStrategy::GenerateCanvasZoomPreviewData(image->projection(), canvasPixelRect, m_d->canvas->displayColorConverter());
510
511 m_d->canvasPreviewFetchCookie = data->cookie();
512
513 m_d->strokesFacade()->addJob(m_d->strokeId, data);
514 }
515}
KisImageWSP image() const
bool wrapAroundModeActive() const
QPointF documentToPixel(const QPointF &documentCoord) const
KisPaintDeviceSP projection() const
QPoint documentToImagePixelFloored(const QPointF &documentCoord) const
QRect bounds() const override

References KisImage::bounds(), Private::canvas, KisColorSamplerStrokeStrategy::GenerateCanvasZoomPreviewData::cookie(), KisImage::documentToImagePixelFloored(), KisImage::documentToPixel(), KisCanvas2::image(), m_d, KisImage::projection(), and KisImage::wrapAroundModeActive().

◆ setUpdateGlobalColor()

void KisAsyncColorSamplerHelper::setUpdateGlobalColor ( bool value)

Definition at line 388 of file KisAsyncColorSamplerHelper.cpp.

389{
390 m_d->updateGlobalColor = value;
391}
float value(const T *src, size_t ch)

References m_d, and value().

◆ sigColorSelected

void KisAsyncColorSamplerHelper::sigColorSelected ( const KoColor & color)
signal

Notifies about the "palette" color picked from the layer, that is, with the alpha channel set to OPACITY_OPAQUE.

◆ sigFinalColorSelected

void KisAsyncColorSamplerHelper::sigFinalColorSelected ( const KoColor & color)
signal

Notifies about the "palette" color picked from the layer, that is, with the alpha channel set to OPACITY_OPAQUE.

This notification is emitted only once at the very end of the color picking stroke.

◆ sigRawColorSelected

void KisAsyncColorSamplerHelper::sigRawColorSelected ( const KoColor & color)
signal

Notifies about the raw color picked from the layer, including its alpha channel.

◆ sigRequestCursor

void KisAsyncColorSamplerHelper::sigRequestCursor ( const QCursor & cursor)
signal

◆ sigRequestCursorReset

void KisAsyncColorSamplerHelper::sigRequestCursorReset ( )
signal

◆ sigRequestUpdateOutline

void KisAsyncColorSamplerHelper::sigRequestUpdateOutline ( )
signal

◆ slotAddSamplingJob

void KisAsyncColorSamplerHelper::slotAddSamplingJob ( const QPointF & docPoint)
privateslot

The actual sampling is delayed by a compressor, so we can get this event when the stroke is already closed

Definition at line 843 of file KisAsyncColorSamplerHelper.cpp.

844{
849 if (!m_d->strokeId) return;
850
851 KisImageSP image = m_d->canvas->image();
852 const QPoint imagePoint = image->documentToImagePixelFloored(docPoint);
853
854 if (!m_d->sampleCurrentLayer) {
855 KisSharedPtr<KisReferenceImagesLayer> referencesLayer = m_d->canvas->imageView()->document()->referenceImagesLayer();
856 if (referencesLayer && m_d->canvas->referenceImagesDecoration()->visible()) {
857 KoColor color = referencesLayer->getPixelForDocPoint(docPoint);
858 if (color.opacityU8() > 0) {
860 return;
861 }
862 }
863 }
864
865 KisPaintDeviceSP device = m_d->sampleCurrentLayer ?
866 m_d->canvas->imageView()->currentNode()->colorSampleSourceDevice() :
867 image->projection();
868
869 if (device) {
870 // Used for color sampler blending.
871 const KoColor currentColor =
872 m_d->canvas->resourceManager()->koColorResource(m_d->sampleResourceId);
873
874 m_d->strokesFacade()->addJob(m_d->strokeId,
875 new KisColorSamplerStrokeStrategy::Data(device, imagePoint, currentColor));
876 } else {
877 QString message = i18n("Color sampler does not work on this layer.");
878 m_d->canvas->viewManager()->showFloatingMessage(message, koIcon("object-locked"));
879 }
880}
void slotColorSamplingFinished(const KoColor &rawColor)
quint8 opacityU8() const
Definition KoColor.cpp:341
#define koIcon(name)
Use these macros for icons without any issues.
Definition kis_icon.h:25

References Private::canvas, KisImage::documentToImagePixelFloored(), KisCanvas2::image(), koIcon, m_d, KoColor::opacityU8(), KisImage::projection(), and slotColorSamplingFinished().

◆ slotCanvasZoomPreviewUpdated

void KisAsyncColorSamplerHelper::slotCanvasZoomPreviewUpdated ( const QImage & canvasImage,
QRect canvasRect )
privateslot

Definition at line 836 of file KisAsyncColorSamplerHelper.cpp.

836 {
837 m_d->cacheCanvasPreviewRect = canvasRect;
838 m_d->cacheCanvasPreviewImage = canvasImage;
839
841}

References m_d, and sigRequestUpdateOutline().

◆ slotColorSamplingFinished

void KisAsyncColorSamplerHelper::slotColorSamplingFinished ( const KoColor & rawColor)
privateslot

Definition at line 882 of file KisAsyncColorSamplerHelper.cpp.

883{
884 KoColor color(rawColor);
885
886 color.setOpacity(OPACITY_OPAQUE_U8);
887
888 if (m_d->updateGlobalColor) {
889 m_d->canvas->resourceManager()->setResource(m_d->sampleResourceId, color);
890 }
891
892 Q_EMIT sigRawColorSelected(rawColor);
893 Q_EMIT sigColorSelected(color);
894
895 if (!m_d->showPreview) return;
896
897 const QColor previewColor = m_d->canvas->displayColorConverter()->convertColorToDisplayColorSpace(color, true);
898
899 if (!m_d->haveSample || m_d->currentColor != previewColor) {
900 m_d->haveSample = true;
901 m_d->currentColor = previewColor;
902 m_d->cache = QPixmap();
903 }
904
906}
void sigColorSelected(const KoColor &color)
void sigRawColorSelected(const KoColor &color)

References m_d, OPACITY_OPAQUE_U8, KoColor::setOpacity(), sigColorSelected(), sigRawColorSelected(), and sigRequestUpdateOutline().

◆ slotUpdateBgColor

void KisAsyncColorSamplerHelper::slotUpdateBgColor ( )
privateslot

Definition at line 908 of file KisAsyncColorSamplerHelper.cpp.

909{
910 KoColor bgColor;
911 bgColor.fromQColor(qApp->palette().color(QPalette::Base));
912 m_d->backgroundColor = m_d->canvas->displayColorConverter()->convertColorToDisplayColorSpace(bgColor);
913}
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213

References KoColor::fromQColor(), and m_d.

◆ startAction()

void KisAsyncColorSamplerHelper::startAction ( const QPointF & docPoint,
int radius,
int blend )

Definition at line 426 of file KisAsyncColorSamplerHelper.cpp.

427{
435
437 m_d->haveSample = true;
438 m_d->strokeId = m_d->strokesFacade()->startStroke(strategy);
439 m_d->samplingCompressor->start(docPoint);
440}
void sigFinalColorSelected(const KoColor &color)
void slotCanvasZoomPreviewUpdated(const QImage &canvasImage, QRect canvasRect)
void sigCanvasZoomPreviewUpdated(const QImage &canvasImage, const QRect &canvasRect)
void sigFinalColorSelected(const KoColor &color)
void sigColorUpdated(const KoColor &color)

References activatePreview(), m_d, KisColorSamplerStrokeStrategy::sigCanvasZoomPreviewUpdated(), KisColorSamplerStrokeStrategy::sigColorUpdated(), sigFinalColorSelected(), KisColorSamplerStrokeStrategy::sigFinalColorSelected(), slotCanvasZoomPreviewUpdated(), and slotColorSamplingFinished().

◆ updateCursor()

void KisAsyncColorSamplerHelper::updateCursor ( bool sampleCurrentLayer,
bool pickFgColor )

Definition at line 362 of file KisAsyncColorSamplerHelper.cpp.

363{
364 const int sampleResourceId =
365 pickFgColor ?
368
369 QCursor cursor;
370
371 if (sampleCurrentLayer) {
372 if (sampleResourceId == KoCanvasResource::ForegroundColor) {
374 } else {
376 }
377 } else {
378 if (sampleResourceId == KoCanvasResource::ForegroundColor) {
380 } else {
382 }
383 }
384
385 Q_EMIT sigRequestCursor(cursor);
386}
void sigRequestCursor(const QCursor &cursor)
static QCursor samplerImageBackgroundCursor()
static QCursor samplerLayerBackgroundCursor()
static QCursor samplerLayerForegroundCursor()
static QCursor samplerImageForegroundCursor()

References KoCanvasResource::BackgroundColor, KoCanvasResource::ForegroundColor, KisCursor::samplerImageBackgroundCursor(), KisCursor::samplerImageForegroundCursor(), KisCursor::samplerLayerBackgroundCursor(), KisCursor::samplerLayerForegroundCursor(), and sigRequestCursor().

◆ updateGlobalColor()

bool KisAsyncColorSamplerHelper::updateGlobalColor ( ) const

Definition at line 393 of file KisAsyncColorSamplerHelper.cpp.

394{
395 return m_d->updateGlobalColor;
396}

References m_d.

Member Data Documentation

◆ m_d

QScopedPointer<Private> KisAsyncColorSamplerHelper::m_d
private

Definition at line 92 of file KisAsyncColorSamplerHelper.h.


The documentation for this class was generated from the following files: