[graphics/krita] libs/ui: Add zoom preview scale setting, WIP zoom on reference image

Emmet O'Neill <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 4350486875166a6d9b7dd7e98b8a160fc8c7c022 by Emmet O'Neill, on behalf of Le Tien Dat.
Committed on 13/08/2026 at 23:16.
Pushed by emmetoneill into branch 'master'.

Add zoom preview scale setting, WIP zoom on reference image

M  +10   -0    libs/ui/dialogs/kis_dlg_preferences.cc
M  +1    -0    libs/ui/dialogs/kis_dlg_preferences.h
M  +46   -17   libs/ui/forms/wdggeneralsettings.ui
M  +13   -0    libs/ui/kis_config.cc
M  +3    -0    libs/ui/kis_config.h
M  +58   -12   libs/ui/tool/KisAsyncColorSamplerHelper.cpp

https://invent.kde.org/graphics/krita/-/commit/4350486875166a6d9b7dd7e98b8a160fc8c7c022

diff --git a/libs/ui/dialogs/kis_dlg_preferences.cc b/libs/ui/dialogs/kis_dlg_preferences.cc
index 5bbab4f626c..fb5aefd2e1a 100644
--- a/libs/ui/dialogs/kis_dlg_preferences.cc
+++ b/libs/ui/dialogs/kis_dlg_preferences.cc
@@ -329,6 +329,10 @@ GeneralTab::GeneralTab(QWidget *_parent, const char *_name)
 
     m_chkColorSamplerPreviewExtraCircles->setChecked(cfg.colorSamplerPreviewCircleExtraCirclesEnabled());
 
+    m_ssbColorSamplerZoomPreviewScale->setRange(100, 500);
+    m_ssbColorSamplerZoomPreviewScale->setSingleStep(25);
+    m_ssbColorSamplerZoomPreviewScale->setValue(cfg.colorSamplerZoomPreviewScale());
+
 
     KisSpinBoxI18nHelper::setText(m_ssbColorSamplerPreviewThickness, i18nc("{n} is the number value, % is the percent sign", "{n}%"));
 
@@ -788,6 +792,7 @@ void GeneralTab::setDefault()
     m_ssbColorSamplerPreviewThickness->setValue(cfg.colorSamplerPreviewCircleThickness(true));
     m_nmbColorSamplerPreviewSize->setValue(cfg.colorSamplerPreviewCircleDiameter(true));
     m_chkColorSamplerPreviewOutlineEnabled->setChecked(cfg.colorSamplerPreviewCircleOutlineEnabled(true));
+    m_ssbColorSamplerZoomPreviewScale->setValue(cfg.colorSamplerZoomPreviewScale(true));
 
 
     chkShowRootLayer->setChecked(cfg.showRootLayer(true));
@@ -971,6 +976,10 @@ bool GeneralTab::colorSamplerPreviewCircleExtraCirclesEnabled() const
     return m_chkColorSamplerPreviewExtraCircles->isChecked();
 }
 
+qreal GeneralTab::colorSamplerZoomPreviewScale() const
+{
+    return m_ssbColorSamplerZoomPreviewScale->value();
+}
 
 KisConfig::SessionOnStartup GeneralTab::sessionOnStartup() const
 {
@@ -3062,6 +3071,7 @@ bool KisDlgPreferences::editPreferences(std::optional<PageDesc>page)
         cfg.setColorSamplerPreviewCircleThickness(m_general->colorSamplerPreviewCircleThickness());
         cfg.setColorSamplerPreviewCircleOutlineEnabled(m_general->colorSamplerPreviewCircleOutlineEnabled());
         cfg.setColorSamplerPreviewCircleExtraCirclesEnabled(m_general->colorSamplerPreviewCircleExtraCirclesEnabled());
+        cfg.setColorSamplerZoomPreviewScale(m_general->colorSamplerZoomPreviewScale());
 
         cfg.setShowRootLayer(m_general->showRootLayer());
         cfg.setShowOutlineWhilePainting(m_general->showOutlineWhilePainting());
diff --git a/libs/ui/dialogs/kis_dlg_preferences.h b/libs/ui/dialogs/kis_dlg_preferences.h
index 881a8b2bed3..6421afc9877 100644
--- a/libs/ui/dialogs/kis_dlg_preferences.h
+++ b/libs/ui/dialogs/kis_dlg_preferences.h
@@ -73,6 +73,7 @@ public:
     qreal colorSamplerPreviewCircleThickness() const;
     bool colorSamplerPreviewCircleOutlineEnabled() const;
     bool colorSamplerPreviewCircleExtraCirclesEnabled() const;
+    qreal colorSamplerZoomPreviewScale() const;
 
     KisConfig::SessionOnStartup sessionOnStartup() const;
     KisConfig::IconsInMenu iconsInMenu() const;
diff --git a/libs/ui/forms/wdggeneralsettings.ui b/libs/ui/forms/wdggeneralsettings.ui
index 4f42fdca340..a4f1feb0ef6 100644
--- a/libs/ui/forms/wdggeneralsettings.ui
+++ b/libs/ui/forms/wdggeneralsettings.ui
@@ -10,8 +10,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>1699</width>
-    <height>663</height>
+    <width>1573</width>
+    <height>665</height>
    </rect>
   </property>
   <property name="sizePolicy">
@@ -42,7 +42,7 @@
    <item>
     <widget class="QTabWidget" name="tabWidget">
      <property name="currentIndex">
-      <number>5</number>
+      <number>3</number>
      </property>
      <property name="movable">
       <bool>false</bool>
@@ -973,6 +973,12 @@
        </item>
        <item row="5" column="0" colspan="2">
         <widget class="QFrame" name="m_frmColorSamplerCircleSettings">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
          <property name="frameShape">
           <enum>QFrame::StyledPanel</enum>
          </property>
@@ -980,16 +986,6 @@
           <enum>QFrame::Raised</enum>
          </property>
          <layout class="QFormLayout" name="m_frmColorSamplerCircleSettingsLayout">
-          <item row="1" column="0">
-           <widget class="QLabel" name="m_lblColorSamplerPreviewSize">
-            <property name="text">
-             <string>Diameter:</string>
-            </property>
-           </widget>
-          </item>
-          <item row="1" column="1">
-           <widget class="KisSliderSpinBox" name="m_nmbColorSamplerPreviewSize"/>
-          </item>
           <item row="0" column="0" colspan="2">
            <widget class="KisColorSamplerPreviewPreview" name="m_lblColorSamplerPreviewSizePreview">
             <property name="sizePolicy">
@@ -1006,6 +1002,16 @@
             </property>
            </widget>
           </item>
+          <item row="1" column="0">
+           <widget class="QLabel" name="m_lblColorSamplerPreviewSize">
+            <property name="text">
+             <string>Diameter:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="1" column="1">
+           <widget class="KisSliderSpinBox" name="m_nmbColorSamplerPreviewSize"/>
+          </item>
           <item row="2" column="0">
            <widget class="QLabel" name="m_lblColorSamplerPreviewThickness">
             <property name="text">
@@ -1016,20 +1022,43 @@
           <item row="2" column="1">
            <widget class="KisDoubleSliderSpinBox" name="m_ssbColorSamplerPreviewThickness"/>
           </item>
-          <item row="3" column="1">
+          <item row="3" column="0">
+           <widget class="QLabel" name="m_lblZoomPreviewScale">
+            <property name="text">
+             <string>Zoom Preview Scale:</string>
+            </property>
+           </widget>
+          </item>
+          <item row="4" column="1">
            <widget class="QCheckBox" name="m_chkColorSamplerPreviewOutlineEnabled">
             <property name="text">
              <string>Enable Outline</string>
             </property>
            </widget>
           </item>
-          <item row="4" column="1">
+          <item row="5" column="1">
            <widget class="QCheckBox" name="m_chkColorSamplerPreviewExtraCircles">
             <property name="text">
              <string>Extra Comparison Space</string>
             </property>
            </widget>
           </item>
+          <item row="3" column="1">
+           <widget class="KisSliderSpinBox" name="m_ssbColorSamplerZoomPreviewScale">
+            <property name="suffix">
+             <string>%</string>
+            </property>
+            <property name="minimum">
+             <number>100</number>
+            </property>
+            <property name="maximum">
+             <number>500</number>
+            </property>
+            <property name="singleStep">
+             <number>25</number>
+            </property>
+           </widget>
+          </item>
          </layout>
         </widget>
        </item>
@@ -1341,8 +1370,8 @@
            <rect>
             <x>0</x>
             <y>0</y>
-            <width>1675</width>
-            <height>624</height>
+            <width>1552</width>
+            <height>786</height>
            </rect>
           </property>
           <property name="sizePolicy">
diff --git a/libs/ui/kis_config.cc b/libs/ui/kis_config.cc
index 6b31920841b..155aa177014 100644
--- a/libs/ui/kis_config.cc
+++ b/libs/ui/kis_config.cc
@@ -569,6 +569,19 @@ void KisConfig::setColorSamplerPreviewCircleThickness(qreal thickness)
     m_cfg.writeEntry("colorSamplerPreviewCircleThickness", thickness);
 }
 
+
+qreal KisConfig::colorSamplerZoomPreviewScale(bool defaultValue) const {
+    qreal def = 200;
+    if (!defaultValue) {
+        return m_cfg.readEntry("colorSamplerZoomPreviewScale", def);
+    }
+    return def;
+}
+
+void KisConfig::setColorSamplerZoomPreviewScale(qreal scale) {
+    m_cfg.writeEntry("colorSamplerZoomPreviewScale", scale);
+}
+
 bool KisConfig::colorSamplerPreviewCircleOutlineEnabled(bool defaultValue) const
 {
     bool def = true;
diff --git a/libs/ui/kis_config.h b/libs/ui/kis_config.h
index 78b01aac01e..323bba25eab 100644
--- a/libs/ui/kis_config.h
+++ b/libs/ui/kis_config.h
@@ -153,6 +153,9 @@ public:
     qreal colorSamplerPreviewCircleThickness(bool defaultValue = false) const;
     void setColorSamplerPreviewCircleThickness(qreal thickness);
 
+    qreal colorSamplerZoomPreviewScale(bool defaultValue = false) const;
+    void setColorSamplerZoomPreviewScale(qreal scale);
+
     bool colorSamplerPreviewCircleOutlineEnabled(bool defaultValue = false) const;
     void setColorSamplerPreviewCircleOutlineEnabled(bool enabled);
 
diff --git a/libs/ui/tool/KisAsyncColorSamplerHelper.cpp b/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
index 39bb2e00b51..bfea94c4bbd 100644
--- a/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
+++ b/libs/ui/tool/KisAsyncColorSamplerHelper.cpp
@@ -68,8 +68,8 @@ struct KisAsyncColorSamplerHelper::Private
     qreal circlePreviewThickness {0.12};
     bool circlePreviewOutlineEnabled {true};
     bool circlePreviewExtraCircles {true};
+    qreal circleZoomPreviewScale {2};
     QRectF previewDocRect;
-    QPointF docPoint;
     QPainterPath cacheInnerPath;
 
     QColor currentColor;
@@ -220,6 +220,7 @@ void KisAsyncColorSamplerHelper::activate(bool sampleCurrentLayer, bool pickFgCo
     m_d->circlePreviewThickness = cfg.colorSamplerPreviewCircleThickness()/100.0; // saved in percentages
     m_d->circlePreviewOutlineEnabled = cfg.colorSamplerPreviewCircleOutlineEnabled();
     m_d->circlePreviewExtraCircles = cfg.colorSamplerPreviewCircleExtraCirclesEnabled();
+    m_d->circleZoomPreviewScale = cfg.colorSamplerZoomPreviewScale()/100.0; // saved in percentages
 
     m_d->activationDelayTimer.start();
 }
@@ -344,7 +345,6 @@ void KisAsyncColorSamplerHelper::endAction()
 
 QRectF KisAsyncColorSamplerHelper::colorPreviewDocRect(const QPointF &docPoint)
 {
-    m_d->docPoint = docPoint;
     if (!m_d->showPreview) return QRectF();
 
     KisConfig cfg(true);
@@ -536,22 +536,68 @@ void KisAsyncColorSamplerHelper::paintCircle(QPainter &gc,
         }
     }
 
+    // When sampler leave the canvas, cache won't update so always need to clear the center
+    // TODO: Check why zoom still show after leaving canvas
+    cachePainter.setPen(Qt::NoPen);
+    cachePainter.setCompositionMode(QPainter::CompositionMode_Clear);
+    cachePainter.drawPath(tf.map(m_d->cacheInnerPath));
+
+    QRectF sampleDocRectF = m_d->previewDocRect;
+    sampleDocRectF.setHeight(sampleDocRectF.height() / m_d->circleZoomPreviewScale);
+    sampleDocRectF.setWidth(sampleDocRectF.width() / m_d->circleZoomPreviewScale);
+    sampleDocRectF.moveCenter(m_d->previewDocRect.center());
+    QRectF canvasSampleRectF = m_d->canvas->image()->documentToPixel(sampleDocRectF);
+
     dbgUI << "View rect: " << viewRectF;
-    QRectF docRectF = m_d->converter().viewToDocument(viewRectF);
-    QRectF docSampleRectF = QRectF(m_d->docPoint.x() - docRectF.width()/4, m_d->docPoint.y() - docRectF.height()/4, docRectF.width()/2, docRectF.height()/2);
-    QRectF canvasSampleRectF = m_d->canvas->image()->documentToPixel(docSampleRectF);
-    dbgUI << "Doc point: " << m_d->docPoint;
-    dbgUI << "Doc view rect: " << docRectF;
-    dbgUI << "Canvas point: " << canvasSampleRectF.topLeft();
-    // Copy a piece of canvas image with size = (cacheRect document size) / (zoom preview scale)
-    QImage cacheCanvasImage = m_d->canvas->image()->convertToQImage(canvasSampleRectF.toRect(), nullptr);
+    dbgUI << "Preview doc rect: " << m_d->previewDocRect;
+    dbgUI << "Sample doc rect: " << sampleDocRectF;
+    dbgUI << "Canvas sample rect: " << canvasSampleRectF;
+    dbgUI << "Sample doc point: " << sampleDocRectF.center();
+
+    QImage cacheCanvasImage;
+    bool sampledRefImage = false;
+
+    // Check if doc coord is on canvas or reference image
+    KisDocument *doc = m_d->canvas->viewManager()->document();
+    if (doc) {
+        KisReferenceImagesLayerSP refLayer = doc->referenceImagesLayer();
+        if (refLayer) {
+            for(int i=0;i<refLayer->referenceImages().count();i++) {
+                KisReferenceImage *refImage = refLayer->referenceImages().at(i);
+                QPolygonF outline = refImage->outline().toFillPolygon().translated(refImage->position());
+                if (outline.containsPoint(sampleDocRectF.center(), Qt::OddEvenFill)) {
+                    dbgUI << "Sampling on reference image no " << i;
+                    // TODO: Figure out how to convert shape coordinate to pixel coordinate
+                    // Just need to divide by scale. How to find the scale though
+                    QImage image = refImage->getImage();
+                    QRectF refRectF = refImage->documentToShape(sampleDocRectF);
+                    dbgUI << "Shape coordinate: " << refRectF;
+                    QPointF topLeft = refRectF.topLeft();
+                    topLeft.setX(topLeft.x() * image.width());
+                    topLeft.setY(topLeft.y() * image.height());
+                    QPointF bottomRight = refRectF.bottomRight();
+                    bottomRight.setX(bottomRight.x() * image.width());
+                    bottomRight.setY(bottomRight.y() * image.height());
+
+                    dbgUI << "Shape pixel coordinate: " << QRectF(topLeft, bottomRight);
+
+                    cacheCanvasImage = refImage->getImage().copy(QRectF(topLeft, bottomRight).toRect());
+                    sampledRefImage = true;
+                }
+            }
+        }
+    }
+
+    if (!sampledRefImage)
+        // Copy a piece of canvas image with size = (previewDocRect size) / (zoom preview scale)
+        cacheCanvasImage = m_d->canvas->image()->convertToQImage(canvasSampleRectF.toRect(), nullptr);
 
     cachePainter.setClipPath(tf.map(m_d->cacheInnerPath));
     cachePainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
 
-    // QtDoc: Note: The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
+    // QtDoc: The image is scaled to fit the rectangle, if both the image and rectangle size disagree.
     // Since the piece of canvas is (zoom preview scale) times smaller than cacheRect
-    // Draw image will scale it up that many times, thus achieving the zoom effect
+    // drawImage will scale it up that many times, thus achieving the zoom effect
     cachePainter.drawImage(cacheRect, cacheCanvasImage);
 
     cachePainter.setClipPath(QPainterPath(), Qt::NoClip);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.