diff --git a/libs/ui/dialogs/kis_dlg_preferences.cc b/libs/ui/dialogs/kis_dlg_preferences.cc
--- a/libs/ui/dialogs/kis_dlg_preferences.cc
+++ b/libs/ui/dialogs/kis_dlg_preferences.cc
@@ -156,17 +156,21 @@
chkEnableTouch->setChecked(!cfg.disableTouchOnCanvas());
chkEnableTranformToolAfterPaste->setChecked(cfg.activateTransformToolAfterPaste());
- m_groupBoxKineticScrollingSettings->setChecked(cfg.kineticScrollingEnabled());
+ m_chkCtrlPickerUsesDedicatedPickerConfig->setChecked(cfg.ctrlPickerUsesDedicatedPickerConfig());
- m_cmbKineticScrollingGesture->addItem(i18n("On Touch Drag"));
- m_cmbKineticScrollingGesture->addItem(i18n("On Click Drag"));
- m_cmbKineticScrollingGesture->addItem(i18n("On Middle-Click Drag"));
- //m_cmbKineticScrollingGesture->addItem(i18n("On Right Click Drag"));
+ { // Kinetic Scrolling
+ m_groupBoxKineticScrollingSettings->setChecked(cfg.kineticScrollingEnabled());
- m_cmbKineticScrollingGesture->setCurrentIndex(cfg.kineticScrollingGesture());
- m_kineticScrollingSensitivitySlider->setRange(0, 100);
- m_kineticScrollingSensitivitySlider->setValue(cfg.kineticScrollingSensitivity());
- m_chkKineticScrollingHideScrollbars->setChecked(cfg.kineticScrollingHiddenScrollbars());
+ m_cmbKineticScrollingGesture->addItem(i18n("On Touch Drag"));
+ m_cmbKineticScrollingGesture->addItem(i18n("On Click Drag"));
+ m_cmbKineticScrollingGesture->addItem(i18n("On Middle-Click Drag"));
+ //m_cmbKineticScrollingGesture->addItem(i18n("On Right Click Drag"));
+
+ m_cmbKineticScrollingGesture->setCurrentIndex(cfg.kineticScrollingGesture());
+ m_kineticScrollingSensitivitySlider->setRange(0, 100);
+ m_kineticScrollingSensitivitySlider->setValue(cfg.kineticScrollingSensitivity());
+ m_chkKineticScrollingHideScrollbars->setChecked(cfg.kineticScrollingHiddenScrollbars());
+ }
//
@@ -243,10 +247,14 @@
m_chkHiDPI->setChecked(true);
m_radioToolOptionsInDocker->setChecked(cfg.toolOptionsInDocker(true));
+
+ m_chkCtrlPickerUsesDedicatedPickerConfig->setChecked(cfg.ctrlPickerUsesDedicatedPickerConfig(true));
+
m_groupBoxKineticScrollingSettings->setChecked(cfg.kineticScrollingEnabled(true));
m_cmbKineticScrollingGesture->setCurrentIndex(cfg.kineticScrollingGesture(true));
m_kineticScrollingSensitivitySlider->setValue(cfg.kineticScrollingSensitivity(true));
m_chkKineticScrollingHideScrollbars->setChecked(cfg.kineticScrollingHiddenScrollbars(true));
+
m_chkSwitchSelectionCtrlAlt->setChecked(cfg.switchSelectionCtrlAlt(true));
chkEnableTouch->setChecked(!cfg.disableTouchOnCanvas(true));
chkEnableTranformToolAfterPaste->setChecked(cfg.activateTransformToolAfterPaste(true));
@@ -255,9 +263,6 @@
KoColor cursorColor(KoColorSpaceRegistry::instance()->rgb8());
cursorColor.fromQColor(cfg.getCursorMainColor(true));
cursorColorBtutton->setColor(cursorColor);
-
-
-
}
CursorStyle GeneralTab::cursorStyle()
@@ -1345,6 +1350,8 @@
cfg.setToolOptionsInDocker(dialog->m_general->toolOptionsInDocker());
+ cfg.setCtrlPickerUsesDedicatedPickerConfig(dialog->m_general->m_chkCtrlPickerUsesDedicatedPickerConfig->isChecked());
+
cfg.setKineticScrollingEnabled(dialog->m_general->kineticScrollingEnabled());
cfg.setKineticScrollingGesture(dialog->m_general->kineticScrollingGesture());
cfg.setKineticScrollingSensitivity(dialog->m_general->kineticScrollingSensitivity());
diff --git a/libs/ui/forms/wdggeneralsettings.ui b/libs/ui/forms/wdggeneralsettings.ui
--- a/libs/ui/forms/wdggeneralsettings.ui
+++ b/libs/ui/forms/wdggeneralsettings.ui
@@ -26,7 +26,7 @@
-
- 0
+ 2
@@ -430,6 +430,16 @@
+ -
+
+
+ <html><head/><body><p>Enabling this option will allow the Paint Tool's Ctrl-Picker to use the current settings from the dedicated Color Picker's <span style=" font-style:italic;">Tool Options</span>. This allows features like radius and mixing to be used from both color pickers using the same settings.</p></body></html>
+
+
+ Use Color Picker's tool options for Ctrl-Picker
+
+
+
-
@@ -455,7 +465,7 @@
-
-
+
@@ -782,17 +792,17 @@
QSpinBox
-
- KisColorButton
- QPushButton
-
-
KisSliderSpinBox
- QWidget
+ QFrame
1
+
+ KisColorButton
+ QPushButton
+
+
diff --git a/libs/ui/kis_config.h b/libs/ui/kis_config.h
--- a/libs/ui/kis_config.h
+++ b/libs/ui/kis_config.h
@@ -513,6 +513,9 @@
bool toolOptionsInDocker(bool defaultValue = false) const;
void setToolOptionsInDocker(bool inDocker);
+ bool ctrlPickerUsesDedicatedPickerConfig(bool defaultValue = false) const;
+ void setCtrlPickerUsesDedicatedPickerConfig(bool enabled);
+
bool kineticScrollingEnabled(bool defaultValue = false) const;
void setKineticScrollingEnabled(bool enabled);
diff --git a/libs/ui/kis_config.cc b/libs/ui/kis_config.cc
--- a/libs/ui/kis_config.cc
+++ b/libs/ui/kis_config.cc
@@ -1733,14 +1733,24 @@
m_cfg.writeEntry("ToolOptionsInDocker", inDocker);
}
+bool KisConfig::ctrlPickerUsesDedicatedPickerConfig(bool defaultValue) const
+{
+ return (defaultValue ? false : m_cfg.readEntry("CtrlPickerUsesDedicatedPickerConfig", false));
+}
+
+void KisConfig::setCtrlPickerUsesDedicatedPickerConfig(bool enabled)
+{
+ m_cfg.writeEntry("CtrlPickerUsesDedicatedPickerConfig", enabled);
+}
+
bool KisConfig::kineticScrollingEnabled(bool defaultValue) const
{
return (defaultValue ? true : m_cfg.readEntry("KineticScrollingEnabled", true));
}
-void KisConfig::setKineticScrollingEnabled(bool value)
+void KisConfig::setKineticScrollingEnabled(bool enabled)
{
- m_cfg.writeEntry("KineticScrollingEnabled", value);
+ m_cfg.writeEntry("KineticScrollingEnabled", enabled);
}
int KisConfig::kineticScrollingGesture(bool defaultValue) const
diff --git a/libs/ui/tool/kis_tool_paint.h b/libs/ui/tool/kis_tool_paint.h
--- a/libs/ui/tool/kis_tool_paint.h
+++ b/libs/ui/tool/kis_tool_paint.h
@@ -36,6 +36,7 @@
#include "kis_signal_compressor_with_param.h"
#include
#include
+#include "kis_tool_utils.h"
class QGridLayout;
class KoCompositeOp;
@@ -43,7 +44,6 @@
class KRITAUI_EXPORT KisToolPaint : public KisTool
{
-
Q_OBJECT
public:
@@ -56,7 +56,6 @@
void mouseMoveEvent(KoPointerEvent *event) override;
protected:
-
void setMode(ToolMode mode) override;
void canvasResourceChanged(int key, const QVariant &v) override;
@@ -86,12 +85,9 @@
const KoPointerEvent *event,
KisPaintOpSettings::OutlineMode outlineMode);
-protected:
bool isOutlineEnabled() const;
void setOutlineEnabled(bool enabled);
- bool pickColor(const QPointF &documentPixel, AlternateAction action);
-
/// Add the tool-specific layout to the default option widget layout.
void addOptionWidgetLayout(QLayout *layout);
@@ -122,22 +118,6 @@
const KoCompositeOp* compositeOp();
-public Q_SLOTS:
- void activate(ToolActivation toolActivation, const QSet &shapes) override;
- void deactivate() override;
-
-private Q_SLOTS:
-
- void slotPopupQuickHelp();
-
- void increaseBrushSize();
- void decreaseBrushSize();
-
- void activatePickColorDelayed();
-
- void slotColorPickingFinished(const KoColor &color);
-
-protected:
quint8 m_opacity;
bool m_paintOutline;
QPointF m_outlineDocPoint;
@@ -162,6 +142,7 @@
int colorPreviewResourceId(AlternateAction action);
QRectF colorPreviewDocRect(const QPointF &outlineDocPoint);
+ bool pickColor(const QPointF &documentPixel, AlternateAction action);
bool isPickingAction(AlternateAction action);
struct PickingJob {
@@ -176,17 +157,11 @@
};
void addPickerJob(const PickingJob &pickingJob);
-private:
-
bool m_specialHoverModifier;
QGridLayout *m_optionsWidgetLayout;
bool m_supportOutline;
- /**
- * Used as a switch for pickColor
- */
-
// used to skip some of the tablet events and don't update the colour that often
QTimer m_colorPickerDelayTimer;
AlternateAction delayedAction;
@@ -196,15 +171,30 @@
KisStrokeId m_pickerStrokeId;
int m_pickingResource;
+ KisPickerUtils::ColorPickerConfig m_pickerSettings;
typedef KisSignalCompressorWithParam PickingCompressor;
QScopedPointer m_colorPickingCompressor;
qreal m_localOpacity {1.0};
qreal m_oldOpacity {1.0};
+ bool m_useDedicatePickerConfig;
+
+public Q_SLOTS:
+ void activate(ToolActivation toolActivation, const QSet &shapes) override;
+ void deactivate() override;
+
+private Q_SLOTS:
+ void slotPopupQuickHelp();
+
+ void increaseBrushSize();
+ void decreaseBrushSize();
+
+ void activatePickColorDelayed();
+ void slotColorPickingFinished(const KoColor &color);
+
Q_SIGNALS:
void sigPaintingFinished();
};
#endif // KIS_TOOL_PAINT_H_
-
diff --git a/libs/ui/tool/kis_tool_paint.cc b/libs/ui/tool/kis_tool_paint.cc
--- a/libs/ui/tool/kis_tool_paint.cc
+++ b/libs/ui/tool/kis_tool_paint.cc
@@ -83,11 +83,9 @@
m_colorPickerDelayTimer(),
m_isOutlineEnabled(true)
{
+ m_opacity = OPACITY_OPAQUE_U8;
m_specialHoverModifier = false;
m_optionsWidgetLayout = 0;
-
- m_opacity = OPACITY_OPAQUE_U8;
-
m_supportOutline = false;
{
@@ -110,14 +108,17 @@
m_colorPickerDelayTimer.setSingleShot(true);
connect(&m_colorPickerDelayTimer, SIGNAL(timeout()), this, SLOT(activatePickColorDelayed()));
+ m_pickerSettings.load();
+
using namespace std::placeholders; // For _1 placeholder
std::function callback =
std::bind(&KisToolPaint::addPickerJob, this, _1);
m_colorPickingCompressor.reset(
- new PickingCompressor(100, callback, KisSignalCompressor::FIRST_ACTIVE));
+ // "m_pickerSettings.resampleRateMS / 1.5" is a bit of magic number.
+ // It's a small hacky way to keep ctrl-picker speed roughly the same as dedicated kis_tool_colorpicker.
+ new PickingCompressor(m_pickerSettings.resampleRateMS / 1.5, callback, KisSignalCompressor::FIRST_ACTIVE));
}
-
KisToolPaint::~KisToolPaint()
{
}
@@ -140,7 +141,6 @@
}
connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(resetCursorStyle()), Qt::UniqueConnection);
-
}
@@ -160,6 +160,9 @@
KisCanvasResourceProvider *provider = qobject_cast(canvas())->viewManager()->resourceProvider();
m_oldOpacity = provider->opacity();
provider->setOpacity(m_localOpacity);
+
+ m_pickerSettings.load(); //Reload picker settings.
+ m_useDedicatePickerConfig = KSharedConfig::openConfig()->group("").readEntry("CtrlPickerUsesDedicatedPickerConfig", false);
}
void KisToolPaint::deactivate()
@@ -244,63 +247,46 @@
KisTool::setMode(mode);
}
-void KisToolPaint::activatePickColor(AlternateAction action)
-{
- m_showColorPreview = true;
-
- requestUpdateOutline(m_outlineDocPoint, 0);
-
- int resource = colorPreviewResourceId(action);
- KoColor color = canvas()->resourceManager()->koColorResource(resource);
-
- KisCanvas2 * kisCanvas = dynamic_cast(canvas());
- KIS_ASSERT_RECOVER_RETURN(kisCanvas);
-
- m_colorPreviewCurrentColor = kisCanvas->displayColorConverter()->toQColor(color);
-
- if (!m_colorPreviewBaseColor.isValid()) {
- m_colorPreviewBaseColor = m_colorPreviewCurrentColor;
- }
-}
-
-void KisToolPaint::deactivatePickColor(AlternateAction action)
-{
- Q_UNUSED(action);
-
- m_showColorPreview = false;
- m_oldColorPreviewRect = QRect();
- m_oldColorPreviewUpdateRect = QRect();
- m_colorPreviewCurrentColor = QColor();
-}
-
-void KisToolPaint::pickColorWasOverridden()
-{
- m_colorPreviewShowComparePlate = false;
- m_colorPreviewBaseColor = QColor();
-}
-
void KisToolPaint::activateAlternateAction(AlternateAction action)
{
switch (action) {
+ case Secondary:
+ // Falls through
case PickFgNode:
- /* Falls through */
+ // Falls through
case PickBgNode:
- /* Falls through */
+ // Falls through
case PickFgImage:
- /* Falls through */
+ // Falls through
case PickBgImage:
delayedAction = action;
m_colorPickerDelayTimer.start(100);
- /* Falls through */
+ // Falls through
default:
pickColorWasOverridden();
KisTool::activateAlternateAction(action);
};
}
+void KisToolPaint::deactivateAlternateAction(AlternateAction action)
+{
+ if (!isPickingAction(action)) {
+ KisTool::deactivateAlternateAction(action);
+ return;
+ }
+
+ delayedAction = KisTool::NONE;
+ m_colorPickerDelayTimer.stop();
+
+ resetCursorStyle();
+ deactivatePickColor(action);
+}
+
void KisToolPaint::activatePickColorDelayed()
{
switch (delayedAction) {
+ case Secondary:
+ //Falls through, for now.
case PickFgNode:
useCursor(KisCursor::pickerLayerForegroundCursor());
activatePickColor(delayedAction);
@@ -324,25 +310,47 @@
repaintDecorations();
}
-bool KisToolPaint::isPickingAction(AlternateAction action) {
- return action == PickFgNode ||
- action == PickBgNode ||
- action == PickFgImage ||
- action == PickBgImage;
+void KisToolPaint::activatePickColor(AlternateAction action)
+{
+ m_showColorPreview = true;
+
+ requestUpdateOutline(m_outlineDocPoint, 0);
+
+ int resource = colorPreviewResourceId(action);
+ KoColor color = canvas()->resourceManager()->koColorResource(resource);
+
+ KisCanvas2 *kisCanvas = dynamic_cast(canvas());
+ KIS_ASSERT_RECOVER_RETURN(kisCanvas);
+
+ m_colorPreviewCurrentColor = kisCanvas->displayColorConverter()->toQColor(color);
+
+ if (!m_colorPreviewBaseColor.isValid()) {
+ m_colorPreviewBaseColor = m_colorPreviewCurrentColor;
+ }
}
-void KisToolPaint::deactivateAlternateAction(AlternateAction action)
+void KisToolPaint::deactivatePickColor(AlternateAction action)
{
- if (!isPickingAction(action)) {
- KisTool::deactivateAlternateAction(action);
- return;
- }
+ Q_UNUSED(action);
- delayedAction = KisTool::NONE;
- m_colorPickerDelayTimer.stop();
+ m_showColorPreview = false;
+ m_oldColorPreviewRect = QRect();
+ m_oldColorPreviewUpdateRect = QRect();
+ m_colorPreviewCurrentColor = QColor();
+}
- resetCursorStyle();
- deactivatePickColor(action);
+void KisToolPaint::pickColorWasOverridden()
+{
+ m_colorPreviewShowComparePlate = false;
+ m_colorPreviewBaseColor = QColor();
+}
+
+bool KisToolPaint::isPickingAction(AlternateAction action) {
+ return action == PickFgNode
+ || action == PickBgNode
+ || action == PickFgImage
+ || action == PickBgImage
+ || action == Secondary;
}
void KisToolPaint::addPickerJob(const PickingJob &pickingJob)
@@ -357,6 +365,7 @@
const QPoint imagePoint = image()->documentToImagePixelFloored(pickingJob.documentPixel);
const bool fromCurrentNode = pickingJob.action == PickFgNode || pickingJob.action == PickBgNode;
+
m_pickingResource = colorPreviewResourceId(pickingJob.action);
if (!fromCurrentNode) {
@@ -375,14 +384,20 @@
KisPaintDeviceSP device = fromCurrentNode ?
currentNode()->colorPickSourceDevice() : image()->projection();
- // Used for color picker blending.
+ bool pure = !m_useDedicatePickerConfig;
+
+ // Used for color picker mixing.
KoColor currentColor = canvas()->resourceManager()->foregroundColor();
if( pickingJob.action == PickBgNode || pickingJob.action == PickBgImage ){
currentColor = canvas()->resourceManager()->backgroundColor();
}
+ auto *canv = dynamic_cast(canvas());
+ KIS_SAFE_ASSERT_RECOVER_RETURN(canv);
+
image()->addJob(m_pickerStrokeId,
- new KisColorPickerStrokeStrategy::Data(device, imagePoint, currentColor));
+ new KisColorPickerStrokeStrategy::Data(device, canv, imagePoint, currentColor,
+ m_pickerSettings.radius, m_pickerSettings.mix, pure));
}
void KisToolPaint::beginAlternateAction(KoPointerEvent *event, AlternateAction action)
@@ -429,11 +444,8 @@
int KisToolPaint::colorPreviewResourceId(AlternateAction action)
{
- bool toForegroundColor = action == PickFgNode || action == PickFgImage;
- int resource = toForegroundColor ?
- KoCanvasResourceProvider::ForegroundColor : KoCanvasResourceProvider::BackgroundColor;
-
- return resource;
+ bool toBackgroundColor = action == PickBgNode || action == PickBgImage;
+ return toBackgroundColor ? KoCanvasResourceProvider::BackgroundColor : KoCanvasResourceProvider::ForegroundColor;
}
void KisToolPaint::slotColorPickingFinished(const KoColor &color)
@@ -442,7 +454,7 @@
if (!m_showColorPreview) return;
- KisCanvas2 * kisCanvas = dynamic_cast(canvas());
+ KisCanvas2 *kisCanvas = dynamic_cast(canvas());
KIS_ASSERT_RECOVER_RETURN(kisCanvas);
QColor previewColor = kisCanvas->displayColorConverter()->toQColor(color);
@@ -561,7 +573,6 @@
m_optionsWidgetLayout->addLayout(layout, rowCount, 0, 1, 2);
}
-
void KisToolPaint::addOptionWidgetOption(QWidget *control, QWidget *label)
{
Q_ASSERT(m_optionsWidgetLayout != 0);
@@ -574,7 +585,6 @@
}
}
-
void KisToolPaint::setOpacity(qreal opacity)
{
m_opacity = quint8(opacity * OPACITY_OPAQUE_U8);
@@ -738,8 +748,7 @@
// DIRTY HACK ALERT: we should fetch the assistant's dirty rect when requesting
// the update, instead of just dumbly update the entire canvas!
-
- KisCanvas2 * kiscanvas = dynamic_cast(canvas());
+ KisCanvas2 *kiscanvas = dynamic_cast(canvas());
KisPaintingAssistantsDecorationSP decoration = kiscanvas->paintingAssistantsDecoration();
if (decoration && decoration->visible()) {
kiscanvas->updateCanvas();
@@ -779,4 +788,3 @@
return path;
}
-
diff --git a/libs/ui/tool/kis_tool_utils.h b/libs/ui/tool/kis_tool_utils.h
--- a/libs/ui/tool/kis_tool_utils.h
+++ b/libs/ui/tool/kis_tool_utils.h
@@ -23,21 +23,48 @@
#include
#include
-class QPoint;
+class KisCanvas2;
+class KoCanvasResourceProvider;
class KoColor;
+class QPoint;
+
+namespace KisToolUtils { // General tool utilities...
+/**
+ * Recursively search a node with a non-transparent pixel
+ */
+KisNodeSP KRITAUI_EXPORT findNode(KisNodeSP node, const QPoint &point, bool wholeGroup, bool editableOnly = true);
+
+/**
+ * return true if success
+ * Clears the image. Selection is optional, use 0 to clear everything.
+ */
+bool KRITAUI_EXPORT clearImage(KisImageSP image, KisNodeSP node, KisSelectionSP selection);
+}
-namespace KisToolUtils {
+//=============================================================================
+
+namespace KisPickerUtils { // Color picker utilities...
+enum SamplingSource {
+ MERGED_VISIBLE,
+ CURRENT_LAYER
+};
+
+enum UpdateTarget {
+ FOREGROUND,
+ BACKGROUND,
+ BOTH,
+ SHIFT, // Shift FG to BG and update FG.
+};
struct KRITAUI_EXPORT ColorPickerConfig {
ColorPickerConfig();
- bool toForegroundColor;
- bool updateColor;
- bool addPalette;
- bool normaliseValues;
- bool sampleMerged;
+ SamplingSource source;
+ int resampleRateMS;
+ bool update;
int radius;
- int blend;
+ int mix;
+ bool normalizeColorData;
void save(bool defaultActivation = true) const;
void load(bool defaultActivation = true);
@@ -51,27 +78,19 @@
* out_color - Output parameter returning newly picked color.
* dev - Paint device to pick from.
* pos - Position to pick from.
- * blendColor - Optional color to be blended with.
+ * mixColor - Optional color to be mixed with.
* radius - Picking area radius in pixels.
- * blend - Blend percentage. 100% all picked, 0% all blendColor.
- * pure - Whether to bypass radius, blending, and active layer settings for pure picking.
+ * mix - Mix percentage. 100% all picked, 0% all mixColor.
+ * pure - Whether to bypass radius, mixing, and active layer settings for pure picking.
*
* RETURN - Returns TRUE whenever a valid color is picked.
*/
-bool KRITAUI_EXPORT pickColor(KoColor &out_color, KisPaintDeviceSP dev, const QPoint &pos,
- KoColor const *const blendColor = nullptr, int radius = 1,
- int blend = 100, bool pure = false);
+bool KRITAUI_EXPORT pickColor(KoColor &out_color, KisPaintDeviceSP sourceDevice, KisCanvas2 *canvas, const QPoint &pos,
+ KoColor const *const mixColor = nullptr, int radius = 1, int mix = 100, bool pure = false);
-/**
- * Recursively search a node with a non-transparent pixel
- */
-KisNodeSP KRITAUI_EXPORT findNode(KisNodeSP node, const QPoint &point, bool wholeGroup, bool editableOnly = true);
+void sampleRadius(KoColor &out_color, const KisPaintDeviceSP device, const QPoint position, const int radius);
-/**
- * return true if success
- * Clears the image. Selection is optional, use 0 to clear everything.
- */
-bool KRITAUI_EXPORT clearImage(KisImageSP image, KisNodeSP node, KisSelectionSP selection);
+void KRITAUI_EXPORT submitColor(KoCanvasResourceProvider &resourceProvider, UpdateTarget target, KoColor &color);
}
#endif // KIS_TOOL_UTILS_H
diff --git a/libs/ui/tool/kis_tool_utils.cpp b/libs/ui/tool/kis_tool_utils.cpp
--- a/libs/ui/tool/kis_tool_utils.cpp
+++ b/libs/ui/tool/kis_tool_utils.cpp
@@ -20,83 +20,18 @@
#include
#include
+#include
+#include
#include
#include
#include
#include
#include
#include
+#include
+#include
namespace KisToolUtils {
-
- bool pickColor(KoColor &out_color, KisPaintDeviceSP dev, const QPoint &pos,
- KoColor const *const blendColor, int radius, int blend, bool pure)
- {
- KIS_ASSERT(dev);
-
- // Bugfix hack forcing pure on first sample to avoid wrong
- // format blendColor on newly initialized Krita.
- static bool firstTime = true;
- if (firstTime == true) {
- pure = true;
- firstTime = false;
- }
-
- const KoColorSpace *cs = dev->colorSpace();
- KoColor pickedColor(Qt::transparent, cs);
-
- // Sampling radius.
- if (!pure && radius > 1) {
- QVector pixels;
- const int effectiveRadius = radius - 1;
-
- const QRect pickRect(pos.x() - effectiveRadius, pos.y() - effectiveRadius,
- 2 * effectiveRadius + 1, 2 * effectiveRadius + 1);
- KisSequentialConstIterator it(dev, pickRect);
-
- const int radiusSq = pow2(effectiveRadius);
-
- while (it.nextPixel()) {
- const QPoint realPos(it.x(), it.y());
- const QPoint pt = realPos - pos;
- if (pow2(pt.x()) + pow2(pt.y()) < radiusSq) {
- pixels << it.oldRawData();
- }
- }
-
- const quint8 **cpixels = const_cast(pixels.constData());
- cs->mixColorsOp()->mixColors(cpixels, pixels.size(), pickedColor.data());
- } else {
- dev->pixel(pos.x(), pos.y(), &pickedColor);
- }
-
- // Color blending.
- if (!pure && blendColor && blend < 100) {
- //Scale from 0..100% to 0..255 range for mixOp weights.
- quint8 blendScaled = static_cast(blend * 2.55f);
-
- const quint8 *colors[2];
- colors[0] = blendColor->data();
- colors[1] = pickedColor.data();
- qint16 weights[2];
- weights[0] = 255 - blendScaled;
- weights[1] = blendScaled;
-
- const KoMixColorsOp *mixOp = dev->colorSpace()->mixColorsOp();
- mixOp->mixColors(colors, weights, 2, pickedColor.data());
- }
-
- pickedColor.convertTo(dev->compositionSourceColorSpace());
-
- bool validColorPicked = pickedColor.opacityU8() != OPACITY_TRANSPARENT_U8;
-
- if (validColorPicked) {
- out_color = pickedColor;
- }
-
- return validColorPicked;
- }
-
KisNodeSP findNode(KisNodeSP node, const QPoint &point, bool wholeGroup, bool editableOnly)
{
KisNodeSP foundNode = 0;
@@ -157,54 +92,163 @@
}
return false;
}
+}
- const QString ColorPickerConfig::CONFIG_GROUP_NAME = "tool_color_picker";
+//=============================================================================
- ColorPickerConfig::ColorPickerConfig()
- : toForegroundColor(true)
- , updateColor(true)
- , addPalette(false)
- , normaliseValues(false)
- , sampleMerged(true)
- , radius(1)
- , blend(100)
- {
+namespace KisPickerUtils { // Color picker utility functions.
+
+bool pickColor(KoColor &out_color, KisPaintDeviceSP sourceDevice, KisCanvas2 *canvas,
+ const QPoint &pos, KoColor const *const mixColor, int radius, int mix, bool pure)
+{
+ KIS_ASSERT(sourceDevice);
+
+ // Bugfix hack forcing pure on first sample to avoid wrong
+ // format mixColor on newly initialized Krita.
+ static bool firstTime = true;
+ if (firstTime == true) {
+ pure = true;
+ firstTime = false;
}
- inline QString getConfigKey(bool defaultActivation) {
- return defaultActivation ?
- "ColorPickerDefaultActivation" : "ColorPickerTemporaryActivation";
+ KoColor pickedColor(Qt::transparent, sourceDevice->colorSpace());
+
+ if (!pure && radius > 1) {
+ if (canvas && !canvas->image()->bounds().contains(pos)) {
+ //TODO: Implement proper radius sampling for reference images!
+ KisSharedPtr referenceImages = canvas->imageView()->document()->referenceImagesLayer();
+ if (referenceImages && canvas->referenceImagesDecoration()->visible()) {
+ pickedColor.fromQColor(referenceImages->getPixel(pos));
+ }
+ } else {
+ sampleRadius(pickedColor, sourceDevice, pos, radius);
+ }
+ } else {
+ if (canvas && !canvas->image()->bounds().contains(pos)) {
+ KisSharedPtr referenceImages = canvas->imageView()->document()->referenceImagesLayer();
+ if (referenceImages && canvas->referenceImagesDecoration()->visible()) {
+ pickedColor.fromQColor(referenceImages->getPixel(pos));
+ }
+ } else {
+ sourceDevice->pixel(pos.x(), pos.y(), &pickedColor);
+ }
}
- void ColorPickerConfig::save(bool defaultActivation) const
- {
- KisPropertiesConfiguration props;
- props.setProperty("toForegroundColor", toForegroundColor);
- props.setProperty("updateColor", updateColor);
- props.setProperty("addPalette", addPalette);
- props.setProperty("normaliseValues", normaliseValues);
- props.setProperty("sampleMerged", sampleMerged);
- props.setProperty("radius", radius);
- props.setProperty("blend", blend);
-
- KConfigGroup config = KSharedConfig::openConfig()->group(CONFIG_GROUP_NAME);
-
- config.writeEntry(getConfigKey(defaultActivation), props.toXML());
+ // Color picker mixing.
+ if (!pure && mixColor && mix < 100) {
+ //Scale from 0..100% to 0..255 range for mixOp weights.
+ quint8 scaledMix = static_cast(mix * 2.55f);
+
+ const quint8 *colors[2];
+ colors[0] = mixColor->data();
+ colors[1] = pickedColor.data();
+ qint16 weights[2];
+ weights[0] = 255 - scaledMix;
+ weights[1] = scaledMix;
+
+ const KoMixColorsOp *mixOp = sourceDevice->colorSpace()->mixColorsOp();
+ mixOp->mixColors(colors, weights, 2, pickedColor.data());
}
- void ColorPickerConfig::load(bool defaultActivation)
- {
- KisPropertiesConfiguration props;
-
- KConfigGroup config = KSharedConfig::openConfig()->group(CONFIG_GROUP_NAME);
- props.fromXML(config.readEntry(getConfigKey(defaultActivation)));
-
- toForegroundColor = props.getBool("toForegroundColor", true);
- updateColor = props.getBool("updateColor", true);
- addPalette = props.getBool("addPalette", false);
- normaliseValues = props.getBool("normaliseValues", false);
- sampleMerged = props.getBool("sampleMerged", !defaultActivation ? false : true);
- radius = props.getInt("radius", 1);
- blend = props.getInt("blend", 100);
+ pickedColor.convertTo(sourceDevice->compositionSourceColorSpace());
+
+ bool validColorPicked = pickedColor.opacityU8() != OPACITY_TRANSPARENT_U8;
+
+ if (validColorPicked) {
+ out_color = pickedColor;
+ }
+
+ return validColorPicked;
+}
+
+void sampleRadius(KoColor &out_color, const KisPaintDeviceSP device, const QPoint position, const int radius) {
+ QVector pixels;
+ const int effectiveRadius = radius - 1;
+
+ const QRect pickRect(position.x() - effectiveRadius, position.y() - effectiveRadius,
+ 2 * effectiveRadius + 1, 2 * effectiveRadius + 1);
+
+ KisSequentialConstIterator it(device, pickRect);
+
+ const int radiusSq = pow2(effectiveRadius);
+
+ while (it.nextPixel()) {
+ const QPoint realPos(it.x(), it.y());
+ const QPoint pt = realPos - position;
+ if (pow2(pt.x()) + pow2(pt.y()) < radiusSq) {
+ pixels << it.oldRawData();
+ }
+ }
+
+ const quint8 **cpixels = const_cast(pixels.constData());
+ device->colorSpace()->mixColorsOp()->mixColors(cpixels, pixels.size(), out_color.data());
+}
+
+void submitColor(KoCanvasResourceProvider &resourceProvider, UpdateTarget target, KoColor &color)
+{
+ color.setOpacity(OPACITY_OPAQUE_U8); //Strip unwanted alpha component.
+
+ switch (target) {
+ case FOREGROUND:
+ resourceProvider.setForegroundColor(color);
+ break;
+ case BACKGROUND:
+ resourceProvider.setBackgroundColor(color);
+ break;
+ case BOTH:
+ resourceProvider.setForegroundColor(color);
+ resourceProvider.setBackgroundColor(color);
+ break;
+ case SHIFT:
+ KoColor hold = resourceProvider.foregroundColor();
+ resourceProvider.setForegroundColor(color);
+ resourceProvider.setBackgroundColor(hold);
+ break;
}
}
+
+const QString ColorPickerConfig::CONFIG_GROUP_NAME = "tool_color_picker";
+
+ColorPickerConfig::ColorPickerConfig()
+ : source(MERGED_VISIBLE)
+ , resampleRateMS(200)
+ , update(true)
+ , radius(1)
+ , mix(100)
+ , normalizeColorData(false)
+{
+}
+
+inline QString getConfigKey(bool defaultActivation) {
+ return defaultActivation ?
+ "ColorPickerDefaultActivation" : "ColorPickerTemporaryActivation";
+}
+
+void ColorPickerConfig::save(bool defaultActivation) const
+{
+ KisPropertiesConfiguration props;
+ props.setProperty("update", update);
+ props.setProperty("samplingSource", source);
+ props.setProperty("radius", radius);
+ props.setProperty("mix", mix);
+ props.setProperty("normaliseValues", normalizeColorData);
+
+ KConfigGroup config = KSharedConfig::openConfig()->group(CONFIG_GROUP_NAME);
+
+ config.writeEntry(getConfigKey(defaultActivation), props.toXML());
+}
+
+void ColorPickerConfig::load(bool defaultActivation)
+{
+ KisPropertiesConfiguration props;
+
+ KConfigGroup config = KSharedConfig::openConfig()->group(CONFIG_GROUP_NAME);
+ props.fromXML(config.readEntry(getConfigKey(defaultActivation)));
+
+ update = props.getBool("update");
+ source = static_cast(props.getInt("samplingSource"));
+ radius = props.getInt("radius", 1);
+ mix = props.getInt("mix", 100);
+ normalizeColorData = props.getBool("normaliseValues");
+}
+}
diff --git a/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.h b/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.h
--- a/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.h
+++ b/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.h
@@ -23,6 +23,7 @@
#include "kis_simple_stroke_strategy.h"
#include "kis_lod_transform.h"
#include "KoColor.h"
+#include "kis_tool_utils.h"
class KisColorPickerStrokeStrategy : public QObject, public KisSimpleStrokeStrategy
{
@@ -30,23 +31,33 @@
public:
class Data : public KisStrokeJobData {
public:
- Data(KisPaintDeviceSP _dev, const QPoint _pt, KoColor _currentColor)
- : dev(_dev), pt(_pt), currentColor(_currentColor)
+ Data(KisPaintDeviceSP _dev, KisCanvas2 *_canvas, const QPoint _pt, KoColor _currentColor, int _radius, int _mix, bool _pure)
+ : dev(_dev)
+ , canvas(_canvas)
+ , pt(_pt)
+ , currentColor(_currentColor)
+ , radius(_radius)
+ , mix(_mix)
+ , pure(_pure)
{}
KisStrokeJobData* createLodClone(int levelOfDetail) override {
KisLodTransform t(levelOfDetail);
const QPoint realPoint = t.map(pt);
- return new Data(dev, realPoint, currentColor);
+ return new Data(dev, canvas, realPoint, currentColor, radius, mix, pure);
}
KisPaintDeviceSP dev;
- QPoint pt;
- KoColor currentColor; // Used for color picker blending.
+ KisCanvas2 *canvas;
+ QPoint pt;
+ KoColor currentColor; // Used for color picker mixing.
+ int radius;
+ int mix;
+ bool pure; // Used for temporary bypass of radius/mixing.
};
public:
- KisColorPickerStrokeStrategy(int lod = 0);
+ KisColorPickerStrokeStrategy();
~KisColorPickerStrokeStrategy() override;
void doStrokeCallback(KisStrokeJobData *data) override;
diff --git a/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.cpp b/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.cpp
--- a/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.cpp
+++ b/libs/ui/tool/strokes/kis_color_picker_stroke_strategy.cpp
@@ -26,21 +26,13 @@
Private() : shouldSkipWork(false) {}
bool shouldSkipWork;
- int radius = 1;
- int blend = 100;
};
-KisColorPickerStrokeStrategy::KisColorPickerStrokeStrategy(int lod)
+KisColorPickerStrokeStrategy::KisColorPickerStrokeStrategy()
: m_d(new Private)
{
setSupportsWrapAroundMode(true);
enableJob(KisSimpleStrokeStrategy::JOB_DOSTROKE);
-
- KisToolUtils::ColorPickerConfig config;
- config.load();
-
- m_d->radius = qMax(1, qRound(config.radius * KisLodTransform::lodToScale(lod)));
- m_d->blend = config.blend;
}
KisColorPickerStrokeStrategy::~KisColorPickerStrokeStrategy()
@@ -56,16 +48,18 @@
KoColor color;
KoColor previous = d->currentColor;
- if (KisToolUtils::pickColor(color, d->dev, d->pt, &previous, m_d->radius, m_d->blend) == true) {
+ if (KisPickerUtils::pickColor(color, d->dev, d->canvas, d->pt, &previous, d->radius, d->mix, d->pure) == true) {
emit sigColorUpdated(color);
}
}
KisStrokeStrategy* KisColorPickerStrokeStrategy::createLodClone(int levelOfDetail)
{
+ Q_UNUSED(levelOfDetail);
+
m_d->shouldSkipWork = true;
- KisColorPickerStrokeStrategy *lodStrategy = new KisColorPickerStrokeStrategy(levelOfDetail);
+ KisColorPickerStrokeStrategy *lodStrategy = new KisColorPickerStrokeStrategy();
connect(lodStrategy, &KisColorPickerStrokeStrategy::sigColorUpdated,
this, &KisColorPickerStrokeStrategy::sigColorUpdated,
Qt::DirectConnection);
diff --git a/libs/ui/widgets/kis_scratch_pad.cpp b/libs/ui/widgets/kis_scratch_pad.cpp
--- a/libs/ui/widgets/kis_scratch_pad.cpp
+++ b/libs/ui/widgets/kis_scratch_pad.cpp
@@ -257,7 +257,7 @@
void KisScratchPad::pick(KoPointerEvent *event)
{
KoColor color;
- if (KisToolUtils::pickColor(color, m_paintLayer->projection(), event->point.toPoint())) {
+ if (KisPickerUtils::pickColor(color, m_paintLayer->projection(), nullptr, event->point.toPoint())) {
emit colorSelected(color);
}
}
diff --git a/plugins/tools/basictools/kis_tool_colorpicker.h b/plugins/tools/basictools/kis_tool_colorpicker.h
--- a/plugins/tools/basictools/kis_tool_colorpicker.h
+++ b/plugins/tools/basictools/kis_tool_colorpicker.h
@@ -27,6 +27,7 @@
#include "ui_wdgcolorpicker.h"
#include "kis_tool.h"
#include
+#include "kis_tool_utils.h"
class KoResource;
class KoColorSet;
@@ -48,74 +49,47 @@
class KisToolColorPicker : public KisTool
{
Q_OBJECT
- Q_PROPERTY(bool toForeground READ toForeground WRITE setToForeground NOTIFY toForegroundChanged)
public:
KisToolColorPicker(KoCanvasBase *canvas);
~KisToolColorPicker() override;
-public:
- struct Configuration {
- Configuration();
-
- bool toForegroundColor;
- bool updateColor;
- bool addPalette;
- bool normaliseValues;
- bool sampleMerged;
- int radius;
- int blend;
-
- void save(ToolActivation activation) const;
- void load(ToolActivation activation);
- };
-
-public:
QWidget* createOptionWidget() override;
void beginPrimaryAction(KoPointerEvent *event) override;
void continuePrimaryAction(KoPointerEvent *event) override;
void endPrimaryAction(KoPointerEvent *event) override;
- void paint(QPainter &gc, const KoViewConverter &converter) override;
+ void beginAlternateAction(KoPointerEvent *event, AlternateAction action) override;
- bool toForeground() const;
+ void paint(QPainter &gc, const KoViewConverter &converter) override;
Q_SIGNALS:
void toForegroundChanged();
+public Q_SLOTS:
+ void slotSetSamplingSource(int);
+ void slotSetUpdate(bool);
+ void slotNormalizeColorData(bool);
+ void slotChangeRadius(int);
+ void slotChangeMix(int);
+
protected:
void activate(ToolActivation activation, const QSet &) override;
void deactivate() override;
-public Q_SLOTS:
- void setToForeground(bool newValue);
- void slotSetUpdateColor(bool);
- void slotSetNormaliseValues(bool);
- void slotSetAddPalette(bool);
- void slotChangeRadius(int);
- void slotChangeBlend(int);
- void slotAddPalette(KoResource* resource);
- void slotSetColorSource(int value);
-
private:
void displayPickedColor();
- bool pickColor(const QPointF& pos);
- void updateOptionWidget();
-
- // Configuration
- QScopedPointer m_config;
+ bool pickColor(const QPointF& pos, bool pure = false);
+ void updateCursor(KisPickerUtils::SamplingSource source);
+ void updateOptionsWidget();
+ QScopedPointer m_config;
ToolActivation m_toolActivationSource;
bool m_isActivated;
-
KoColor m_pickedColor;
-
- // Used to skip some tablet events and update color less often
- QTimer m_colorPickerDelayTimer;
-
+ QTimer m_resampleDelayTimer;
ColorPickerOptionsWidget *m_optionsWidget;
-
QList m_palettes;
};
@@ -124,7 +98,7 @@
public:
KisToolColorPickerFactory()
: KoToolFactoryBase("KritaSelected/KisToolColorPicker") {
- setToolTip(i18n("Color Selector Tool"));
+ setToolTip(i18n("Color Picker Tool"));
setSection(TOOL_TYPE_FILL);
setPriority(2);
setIconName(koIconNameCStr("krita_tool_color_picker"));
diff --git a/plugins/tools/basictools/kis_tool_colorpicker.cc b/plugins/tools/basictools/kis_tool_colorpicker.cc
--- a/plugins/tools/basictools/kis_tool_colorpicker.cc
+++ b/plugins/tools/basictools/kis_tool_colorpicker.cc
@@ -34,20 +34,15 @@
#include "kis_wrapped_rect.h"
#include "kis_tool_utils.h"
-namespace
-{
-// GUI ComboBox index constants
-const int SAMPLE_MERGED = 0;
-}
-
KisToolColorPicker::KisToolColorPicker(KoCanvasBase *canvas)
: KisTool(canvas, KisCursor::pickerCursor()),
- m_config(new KisToolUtils::ColorPickerConfig)
+ m_config(new KisPickerUtils::ColorPickerConfig)
{
setObjectName("tool_colorpicker");
m_isActivated = false;
m_optionsWidget = 0;
m_pickedColor = KoColor();
+ m_resampleDelayTimer.setSingleShot(true);
}
KisToolColorPicker::~KisToolColorPicker()
@@ -57,10 +52,73 @@
}
}
+QWidget* KisToolColorPicker::createOptionWidget()
+{
+ m_optionsWidget = new ColorPickerOptionsWidget(0);
+ m_optionsWidget->setObjectName(toolId() + " Options Widget");
+ m_optionsWidget->tableColorData->setSortingEnabled(false);
+
+ { // See https://bugs.kde.org/show_bug.cgi?id=316896
+ QWidget *specialSpacer = new QWidget(m_optionsWidget);
+ specialSpacer->setObjectName("SpecialSpacer");
+ specialSpacer->setFixedSize(0, 0);
+ m_optionsWidget->layout()->addWidget(specialSpacer);
+ }
+
+ // Initialize mix KisSliderSpinBox.
+ m_optionsWidget->mix->setRange(1,100);
+ m_optionsWidget->mix->setSuffix("%");
+
+ { // Initialize palette selector.
+ KoResourceServer *srv = KoResourceServerProvider::instance()->paletteServer();
+
+ if (!srv) {
+ return m_optionsWidget;
+ }
+
+ QList palettes = srv->resources();
+ Q_FOREACH (KoColorSet *palette, palettes) {
+ if (palette) {
+ m_optionsWidget->cmbPalettes->addSqueezedItem(palette->name());
+ m_palettes.append(palette);
+ }
+ }
+ }
+
+ connect(m_optionsWidget->cbUpdate, SIGNAL(toggled(bool)), SLOT(slotSetUpdate(bool)));
+ connect(m_optionsWidget->cmbSamplingSources, SIGNAL(currentIndexChanged(int)), SLOT(slotSetSamplingSource(int)));
+ connect(m_optionsWidget->radius, SIGNAL(valueChanged(int)), SLOT(slotChangeRadius(int)));
+ connect(m_optionsWidget->mix, SIGNAL(valueChanged(int)), SLOT(slotChangeMix(int)));
+ connect(m_optionsWidget->cbNormaliseValues, SIGNAL(toggled(bool)), SLOT(slotNormalizeColorData(bool)));
+
+ updateCursor(m_config->source);
+ updateOptionsWidget();
+ return m_optionsWidget;
+}
+
+void KisToolColorPicker::updateCursor(KisPickerUtils::SamplingSource source)
+{
+ if (source == KisPickerUtils::CURRENT_LAYER) {
+ useCursor(KisCursor::pickerLayerForegroundCursor());
+ } else {
+ useCursor(KisCursor::pickerImageForegroundCursor());
+ }
+}
+
+void KisToolColorPicker::updateOptionsWidget()
+{
+ if (!m_optionsWidget) return;
+
+ m_optionsWidget->cbUpdate->setChecked(m_config->update);
+ m_optionsWidget->cmbSamplingSources->setCurrentIndex(m_config->source);
+ m_optionsWidget->radius->setValue(m_config->radius);
+ m_optionsWidget->mix->setValue(m_config->mix);
+ m_optionsWidget->cbNormaliseValues->setChecked(m_config->normalizeColorData);
+}
+
void KisToolColorPicker::paint(QPainter &gc, const KoViewConverter &converter)
{
- Q_UNUSED(gc);
- Q_UNUSED(converter);
+ Q_UNUSED(gc); Q_UNUSED(converter);
}
void KisToolColorPicker::activate(ToolActivation activation, const QSet &shapes)
@@ -68,9 +126,10 @@
m_isActivated = true;
m_toolActivationSource = activation;
m_config->load(m_toolActivationSource == KisTool::DefaultActivation);
- updateOptionWidget();
-
KisTool::activate(activation, shapes);
+
+ updateCursor(m_config->source);
+ updateOptionsWidget();
}
void KisToolColorPicker::deactivate()
@@ -80,78 +139,75 @@
KisTool::deactivate();
}
-bool KisToolColorPicker::pickColor(const QPointF &pos)
+void KisToolColorPicker::beginPrimaryAction(KoPointerEvent *event) //Mouse down.
{
- // Timer check.
- if (m_colorPickerDelayTimer.isActive()) {
- return false;
- }
- else {
- m_colorPickerDelayTimer.setSingleShot(true);
- m_colorPickerDelayTimer.start(100);
+ bool sampleMerged = m_optionsWidget->cmbSamplingSources->currentIndex() == KisPickerUtils::MERGED_VISIBLE;
+ if (!sampleMerged) {
+ if (!currentNode()) {
+ QMessageBox::information(0, i18nc("@title:window", "Krita"), i18n("Cannot pick a color as no layer is active."));
+ event->ignore();
+ return;
+ }
+ if (!currentNode()->visible()) {
+ QMessageBox::information(0, i18nc("@title:window", "Krita"), i18n("Cannot pick a color as the active layer is not visible."));
+ event->ignore();
+ return;
+ }
}
- QScopedPointer> imageLocker;
+ setMode(KisTool::PAINT_MODE);
- m_pickedColor.setOpacity(0.0);
+ QPoint pos = convertToImagePixelCoordFloored(event);
- // Pick from reference images.
- if (m_optionsWidget->cmbSources->currentIndex() == SAMPLE_MERGED) {
- auto *kisCanvas = dynamic_cast(canvas());
- KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(kisCanvas, false);
- KisSharedPtr referenceImageLayer =
- kisCanvas->imageView()->document()->referenceImagesLayer();
-
- if (referenceImageLayer && kisCanvas->referenceImagesDecoration()->visible()) {
- QColor color = referenceImageLayer->getPixel(pos);
- if (color.isValid()) {
- m_pickedColor.fromQColor(color);
- }
- }
+ bool picked = pickColor(pos);
+ if (!picked) { // Color picking has to start in the visible part of the layer
+ event->ignore();
+ return;
}
- if (m_pickedColor.opacityU8() == OPACITY_TRANSPARENT_U8) {
- if (!currentImage()->bounds().contains(pos.toPoint()) &&
- !currentImage()->wrapAroundModePermitted()) {
- return false;
- }
-
- KisPaintDeviceSP dev;
+ displayPickedColor();
- if (m_optionsWidget->cmbSources->currentIndex() != SAMPLE_MERGED &&
- currentNode() && currentNode()->colorPickSourceDevice()) {
- dev = currentNode()->colorPickSourceDevice();
- }
- else {
- imageLocker.reset(new boost::lock_guard(*currentImage()));
- dev = currentImage()->projection();
- }
+ m_resampleDelayTimer.start(m_config->resampleRateMS);
+}
- KoColor previousColor = canvas()->resourceManager()->foregroundColor();
+void KisToolColorPicker::continuePrimaryAction(KoPointerEvent *event) //Mouse drag.
+{
+ CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE);
- KisToolUtils::pickColor(m_pickedColor, dev, pos.toPoint(), &previousColor, m_config->radius, m_config->blend);
+ if (m_resampleDelayTimer.isActive()) {
+ return;
+ }
+ else {
+ m_resampleDelayTimer.start(m_config->resampleRateMS);
}
- if (m_config->updateColor &&
- m_pickedColor.opacityU8() != OPACITY_TRANSPARENT_U8) {
+ QPoint pos = convertToImagePixelCoordFloored(event);
- KoColor publicColor = m_pickedColor;
- publicColor.setOpacity(OPACITY_OPAQUE_U8); // Alpha is unwanted for FG and BG colors.
+ pickColor(pos);
+ displayPickedColor();
+}
- if (m_config->toForegroundColor) {
- canvas()->resourceManager()->setResource(KoCanvasResourceProvider::ForegroundColor, publicColor);
- }
- else {
- canvas()->resourceManager()->setResource(KoCanvasResourceProvider::BackgroundColor, publicColor);
- }
- }
+void KisToolColorPicker::endPrimaryAction(KoPointerEvent *event) //Mouse up.
+{
+ Q_UNUSED(event);
+ CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE);
- return true;
+ // Add picked colors to selected palette.
+ if (m_optionsWidget->cbAddToPalette->isChecked()) {
+ KisSwatch entry;
+ entry.setColor(m_pickedColor);
+ entry.setName("Picked"); // Placeholder - better than nothing!
+
+ KoColorSet *palette = m_palettes.at(m_optionsWidget->cmbPalettes->currentIndex());
+ palette->add(entry);
+ }
}
-void KisToolColorPicker::beginPrimaryAction(KoPointerEvent *event)
-{
- bool sampleMerged = m_optionsWidget->cmbSources->currentIndex() == SAMPLE_MERGED;
+void KisToolColorPicker::beginAlternateAction(KoPointerEvent *event, AlternateAction action) {
+ Q_UNUSED(action);
+
+ // ***WARNING: Modified copy-paste from 'beginPrimaryAction'; it'd be nice to unify these later.***
+ bool sampleMerged = m_optionsWidget->cmbSamplingSources->currentIndex() == KisPickerUtils::MERGED_VISIBLE;
if (!sampleMerged) {
if (!currentNode()) {
QMessageBox::information(0, i18nc("@title:window", "Krita"), i18n("Cannot pick a color as no layer is active."));
@@ -165,59 +221,66 @@
}
}
- QPoint pos = convertToImagePixelCoordFloored(event);
-
setMode(KisTool::PAINT_MODE);
- bool picked = pickColor(pos);
- if (!picked) {
- // Color picking has to start in the visible part of the layer
+ QPoint pos = convertToImagePixelCoordFloored(event);
+
+ bool picked = pickColor(pos, false);
+ if (!picked) { // Color picking has to start in the visible part of the layer
event->ignore();
return;
}
displayPickedColor();
-}
-void KisToolColorPicker::continuePrimaryAction(KoPointerEvent *event)
-{
- CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE);
-
- QPoint pos = convertToImagePixelCoordFloored(event);
- pickColor(pos);
- displayPickedColor();
+ m_resampleDelayTimer.start(m_config->resampleRateMS);
}
-void KisToolColorPicker::endPrimaryAction(KoPointerEvent *event)
+bool KisToolColorPicker::pickColor(const QPointF &pos, bool pure)
{
- Q_UNUSED(event);
- CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE);
+ QScopedPointer> imageLocker;
+
+ m_pickedColor.setOpacity(0.0);
- if (m_config->addPalette) {
- KisSwatch ent;
- ent.setColor(m_pickedColor);
- // We don't ask for a name, too intrusive here
+ auto *canv = dynamic_cast(canvas());
+ KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(canv, false);
- KoColorSet *palette = m_palettes.at(m_optionsWidget->cmbPalette->currentIndex());
- palette->add(ent);
+ if (m_pickedColor.opacityU8() == OPACITY_TRANSPARENT_U8) {
+ KisPaintDeviceSP activeDevice;
- if (!palette->save()) {
- QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Cannot write to palette file %1. Maybe it is read-only.", palette->filename()));
+ if (m_config->source != KisPickerUtils::MERGED_VISIBLE
+ && currentNode() && currentNode()->colorPickSourceDevice()) {
+ activeDevice = currentNode()->colorPickSourceDevice();
+ }
+ else {
+ imageLocker.reset(new boost::lock_guard(*currentImage()));
+ activeDevice = currentImage()->projection();
}
+
+ KoColor previousColor = canvas()->resourceManager()->foregroundColor();
+
+ KisPickerUtils::pickColor(m_pickedColor, activeDevice, canv, pos.toPoint(), &previousColor, m_config->radius, m_config->mix, pure);
+ }
+
+ if (m_config->update && m_pickedColor.opacityU8() != OPACITY_TRANSPARENT_U8) {
+ KisPickerUtils::UpdateTarget target = KisPickerUtils::FOREGROUND;
+ KisPickerUtils::submitColor(*canvas()->resourceManager(), target, m_pickedColor);
}
-}
-struct PickedChannel {
- QString name;
- QString valueText;
-};
+ return true;
+}
void KisToolColorPicker::displayPickedColor()
{
+ struct PickedChannel {
+ QString name;
+ QString valueText;
+ };
+
if (m_pickedColor.data() && m_optionsWidget) {
QList channels = m_pickedColor.colorSpace()->channels();
- m_optionsWidget->listViewChannels->clear();
+ m_optionsWidget->tableColorData->clear();
QVector pickedChannels;
for (int i = 0; i < channels.count(); ++i) {
@@ -229,7 +292,7 @@
PickedChannel pc;
pc.name = channels[i]->name();
- if (m_config->normaliseValues) {
+ if (m_config->normalizeColorData) {
pc.valueText = m_pickedColor.colorSpace()->normalisedChannelValueText(m_pickedColor.data(), i);
} else {
pc.valueText = m_pickedColor.colorSpace()->channelValueText(m_pickedColor.data(), i);
@@ -240,119 +303,37 @@
}
Q_FOREACH (const PickedChannel &pc, pickedChannels) {
- QTreeWidgetItem *item = new QTreeWidgetItem(m_optionsWidget->listViewChannels);
+ QTreeWidgetItem *item = new QTreeWidgetItem(m_optionsWidget->tableColorData);
item->setText(0, pc.name);
item->setText(1, pc.valueText);
}
}
}
-QWidget* KisToolColorPicker::createOptionWidget()
-{
- m_optionsWidget = new ColorPickerOptionsWidget(0);
- m_optionsWidget->setObjectName(toolId() + " option widget");
- m_optionsWidget->listViewChannels->setSortingEnabled(false);
-
- // See https://bugs.kde.org/show_bug.cgi?id=316896
- QWidget *specialSpacer = new QWidget(m_optionsWidget);
- specialSpacer->setObjectName("SpecialSpacer");
- specialSpacer->setFixedSize(0, 0);
- m_optionsWidget->layout()->addWidget(specialSpacer);
-
- // Initialize blend KisSliderSpinBox
- m_optionsWidget->blend->setRange(0,100);
- m_optionsWidget->blend->setSuffix("%");
-
- updateOptionWidget();
-
- connect(m_optionsWidget->cbUpdateCurrentColor, SIGNAL(toggled(bool)), SLOT(slotSetUpdateColor(bool)));
- connect(m_optionsWidget->cbNormaliseValues, SIGNAL(toggled(bool)), SLOT(slotSetNormaliseValues(bool)));
- connect(m_optionsWidget->cbPalette, SIGNAL(toggled(bool)),
- SLOT(slotSetAddPalette(bool)));
- connect(m_optionsWidget->radius, SIGNAL(valueChanged(int)),
- SLOT(slotChangeRadius(int)));
- connect(m_optionsWidget->blend, SIGNAL(valueChanged(int)),
- SLOT(slotChangeBlend(int)));
- connect(m_optionsWidget->cmbSources, SIGNAL(currentIndexChanged(int)),
- SLOT(slotSetColorSource(int)));
-
- KoResourceServer *srv = KoResourceServerProvider::instance()->paletteServer();
-
- if (!srv) {
- return m_optionsWidget;
- }
-
- QList palettes = srv->resources();
-
- Q_FOREACH (KoColorSet *palette, palettes) {
- if (palette) {
- m_optionsWidget->cmbPalette->addSqueezedItem(palette->name());
- m_palettes.append(palette);
- }
- }
-
- return m_optionsWidget;
-}
-
-void KisToolColorPicker::updateOptionWidget()
-{
- if (!m_optionsWidget) return;
-
- m_optionsWidget->cbNormaliseValues->setChecked(m_config->normaliseValues);
- m_optionsWidget->cbUpdateCurrentColor->setChecked(m_config->updateColor);
- m_optionsWidget->cmbSources->setCurrentIndex(SAMPLE_MERGED + !m_config->sampleMerged);
- m_optionsWidget->cbPalette->setChecked(m_config->addPalette);
- m_optionsWidget->radius->setValue(m_config->radius);
- m_optionsWidget->blend->setValue(m_config->blend);
-}
-
-void KisToolColorPicker::setToForeground(bool newValue)
-{
- m_config->toForegroundColor = newValue;
- emit toForegroundChanged();
-}
-
-bool KisToolColorPicker::toForeground() const
+void KisToolColorPicker::slotSetSamplingSource(int source)
{
- return m_config->toForegroundColor;
+ auto src = static_cast(source);
+ updateCursor(src);
+ m_config->source = src;
}
-void KisToolColorPicker::slotSetUpdateColor(bool state)
+void KisToolColorPicker::slotSetUpdate(bool state)
{
- m_config->updateColor = state;
+ m_config->update = state;
}
-void KisToolColorPicker::slotSetNormaliseValues(bool state)
+void KisToolColorPicker::slotNormalizeColorData(bool state)
{
- m_config->normaliseValues = state;
+ m_config->normalizeColorData = state;
displayPickedColor();
}
-void KisToolColorPicker::slotSetAddPalette(bool state)
-{
- m_config->addPalette = state;
-}
-
void KisToolColorPicker::slotChangeRadius(int value)
{
m_config->radius = value;
}
-void KisToolColorPicker::slotChangeBlend(int value)
-{
- m_config->blend = value;
-}
-
-void KisToolColorPicker::slotSetColorSource(int value)
+void KisToolColorPicker::slotChangeMix(int value)
{
- m_config->sampleMerged = value == SAMPLE_MERGED;
-}
-
-void KisToolColorPicker::slotAddPalette(KoResource *resource)
-{
- KoColorSet *palette = dynamic_cast(resource);
- if (palette) {
- m_optionsWidget->cmbPalette->addSqueezedItem(palette->name());
- m_palettes.append(palette);
- }
+ m_config->mix = value;
}
diff --git a/plugins/tools/basictools/wdgcolorpicker.ui b/plugins/tools/basictools/wdgcolorpicker.ui
--- a/plugins/tools/basictools/wdgcolorpicker.ui
+++ b/plugins/tools/basictools/wdgcolorpicker.ui
@@ -6,101 +6,26 @@
0
0
- 263
- 323
+ 274
+ 498
Color Picker
- -
-
-
- 1
-
-
-
-
-
- Blend:
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- 1
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- <nobr>Blending controls the percentage of color that is picked</nobr> and mixed with your current brush color. A full blending value picks colors completely, ignoring brush color.
-
-
-
-
-
- -
-
+
-
+
-
+
0
0
-
-
- 200
- 0
-
-
-
-
- 200
- 32767
-
-
-
- <nobr>Determines whether the color picker will sample</nobr> colors from all visible layers or only the currently selected layer.
-
-
- 0
-
-
-
-
- Sample All Visible Layers
-
-
- -
-
- Sample Current Layer
-
-
-
-
- -
-
-
- Displays per-channel color information below as percentages instead of bytes.
-
-
- Show colors as percentages
-
-
-
- -
-
0
- 100
+ 128
@@ -118,23 +43,10 @@
- -
-
-
- QFrame::Plain
-
-
- 1
-
-
- Qt::Horizontal
-
-
-
- -
+
-
- 1
+ 8
0
@@ -150,11 +62,23 @@
-
+
+
+ 0
+ 0
+
+
+
+
+ 64
+ 0
+
+
- Radius:
+ Radius:
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
1
@@ -164,11 +88,17 @@
-
-
+
0
0
+
+
+ 0
+ 28
+
+
<nobr>Radius controls the color picker's sampling area.</nobr> Pixel colors within this radius are mixed together.
@@ -185,83 +115,195 @@
- -
-
+
-
+
+
+ Qt::Horizontal
+
+
+
+ -
+
- 1
+ 8
-
- 0
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 64
+ 0
+
+
+
+ Sample:
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 28
+
+
+
+ <nobr>Determines whether the color picker will sample</nobr> colors from all visible layers or only the currently selected layer.
+
+
+ 0
+
+
-
+
+ All Visible Layers
+
+
+ -
+
+ Current Layer
+
+
+
+
+
+
+ -
+
+
+ Displays per-channel color information below as percentages instead of integers.
-
- 0
+
+ Show color data as percentages.
-
- 0
+
+
+ -
+
+
+ Qt::Horizontal
-
- 0
+
+
+ -
+
+
+ 8
-
-
-
- <nobr>Checking this box will add a new color swatch</nobr> to a palette each time you pick a color.
+
+
+
+ 0
+ 0
+
+
+
+
+ 64
+ 0
+
- Add to palette:
+ Mix:
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ 1
-
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 28
+
+
+
+ <nobr>The mix value controls the percentage of color that is picked</nobr> and mixed with your current brush color. A full mix value picks colors completely, ignoring brush color.
+
+
- -
+
-
+
+
+ <nobr>If checked, Left Click will update your active foreground color and</nobr> Right Click will update your active background color. [Checked by default.]
+
+
+ Update Active Colors
+
+
+ true
+
+
+
+ -
-
-
+
- <nobr>Controls whether the color picker updates the</nobr> current foreground or not.
+ <nobr>Adds each picked color to an empty slot in the</nobr> currently selected palette.
- Update color
+ Add to palette:
+
+
+
+ -
+
+
+
+ 0
+ 28
+
- -
-
-
- QFrame::Plain
-
-
- 1
-
-
- Qt::Horizontal
-
-
-
+
+ KisIntParseSpinBox
+ QSpinBox
+
+
KisSliderSpinBox
- QWidget
+ QFrame
+ 1
SqueezedComboBox
QComboBox
-
- KisIntParseSpinBox
- QSpinBox
-
-