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 @@ -175,7 +175,6 @@ bool isPickingAction(AlternateAction action); - struct PickingJob { PickingJob() {} PickingJob(QPointF _documentPixel, 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 @@ -399,8 +399,14 @@ KisPaintDeviceSP device = fromCurrentNode ? currentNode()->colorPickSourceDevice() : image()->projection(); + // Used for color picker blending. + KoColor currentColor = canvas()->resourceManager()->foregroundColor(); + if( pickingJob.action == PickBgNode || pickingJob.action == PickBgImage ){ + currentColor = canvas()->resourceManager()->backgroundColor(); + } + image()->addJob(m_pickerStrokeId, - new KisColorPickerStrokeStrategy::Data(device, imagePoint)); + new KisColorPickerStrokeStrategy::Data(device, imagePoint, currentColor)); } void KisToolPaint::beginAlternateAction(KoPointerEvent *event, AlternateAction action) 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 @@ -1,5 +1,6 @@ /* * Copyright (c) 2009 Boudewijn Rempt + * Copyright (c) 2018 Emmet & Eoin O'Neill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,16 +16,15 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + #ifndef KIS_TOOL_UTILS_H #define KIS_TOOL_UTILS_H -#include - -#include #include #include -#include +class QPoint; +class KoColor; namespace KisToolUtils { @@ -37,6 +37,7 @@ bool normaliseValues; bool sampleMerged; int radius; + int blend; void save(bool defaultActivation = true) const; void load(bool defaultActivation = true); @@ -47,7 +48,8 @@ /** * return the color at the given position on the given paint device. */ -bool KRITAUI_EXPORT pick(KisPaintDeviceSP dev, const QPoint& pos, KoColor *color, int radius = 1); +bool KRITAUI_EXPORT pick(KisPaintDeviceSP dev, const QPoint &pos, KoColor *color, + KoColor *previousColor = nullptr, int radius = 1, int blend = 100); /** * Recursively search a node with a non-transparent pixel 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 @@ -1,5 +1,6 @@ /* * Copyright (c) 2009 Boudewijn Rempt + * Copyright (c) 2018 Emmet & Eoin O'Neill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,29 +16,26 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + #include -#include #include -#include -#include #include -#include -#include #include #include #include #include #include namespace KisToolUtils { - bool pick(KisPaintDeviceSP dev, const QPoint& pos, KoColor *color, int radius) + bool pick(KisPaintDeviceSP dev, const QPoint &pos, KoColor *color, KoColor *previousColor, int radius, int blend) { KIS_ASSERT(dev); const KoColorSpace* cs = dev->colorSpace(); KoColor pickedColor(Qt::transparent, cs); + // Ctrl picker sampling radius. if (radius <= 1) { dev->pixel(pos.x(), pos.y(), &pickedColor); } else { @@ -59,9 +57,25 @@ } } - const quint8** cpixels = const_cast(pixels.constData()); + const quint8 **cpixels = const_cast(pixels.constData()); cs->mixColorsOp()->mixColors(cpixels, pixels.size(), pickedColor.data()); } + + // Ctrl picker color blending. + if (previousColor && 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] = previousColor->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()); @@ -146,6 +160,7 @@ , normaliseValues(false) , sampleMerged(true) , radius(1) + , blend(100) { } @@ -163,6 +178,7 @@ props.setProperty("normaliseValues", normaliseValues); props.setProperty("sampleMerged", sampleMerged); props.setProperty("radius", radius); + props.setProperty("blend", blend); KConfigGroup config = KSharedConfig::openConfig()->group(CONFIG_GROUP_NAME); @@ -182,6 +198,7 @@ normaliseValues = props.getBool("normaliseValues", false); sampleMerged = props.getBool("sampleMerged", !defaultActivation ? false : true); radius = props.getInt("radius", 1); + blend = props.getInt("blend", 100); } } 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 @@ -20,32 +20,30 @@ #define __KIS_COLOR_PICKER_STROKE_STRATEGY_H #include -#include #include "kis_simple_stroke_strategy.h" #include "kis_lod_transform.h" - -class KoColor; - +#include "KoColor.h" class KisColorPickerStrokeStrategy : public QObject, public KisSimpleStrokeStrategy { Q_OBJECT public: class Data : public KisStrokeJobData { public: - Data(KisPaintDeviceSP _dev, const QPoint _pt) - : dev(_dev), pt(_pt) + Data(KisPaintDeviceSP _dev, const QPoint _pt, KoColor _currentColor) + : dev(_dev), pt(_pt), currentColor(_currentColor) {} KisStrokeJobData* createLodClone(int levelOfDetail) override { KisLodTransform t(levelOfDetail); const QPoint realPoint = t.map(pt); - return new Data(dev, realPoint); + return new Data(dev, realPoint, currentColor); } KisPaintDeviceSP dev; QPoint pt; + KoColor currentColor; // Used for color picker blending. }; public: KisColorPickerStrokeStrategy(int lod = 0); 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 @@ -18,22 +18,16 @@ #include "kis_color_picker_stroke_strategy.h" -#include - - -#include "kis_debug.h" #include "kis_tool_utils.h" -#include -#include "kis_default_bounds.h" #include "kis_paint_device.h" - struct KisColorPickerStrokeStrategy::Private { Private() : shouldSkipWork(false) {} bool shouldSkipWork; int radius = 1; + int blend = 100; }; KisColorPickerStrokeStrategy::KisColorPickerStrokeStrategy(int lod) @@ -46,6 +40,7 @@ config.load(); m_d->radius = qMax(1, qRound(config.radius * KisLodTransform::lodToScale(lod))); + m_d->blend = config.blend; } KisColorPickerStrokeStrategy::~KisColorPickerStrokeStrategy() @@ -60,7 +55,8 @@ KIS_ASSERT_RECOVER_RETURN(d); KoColor color; - bool result = KisToolUtils::pick(d->dev, d->pt, &color, m_d->radius); + KoColor previous = d->currentColor; + bool result = KisToolUtils::pick(d->dev, d->pt, &color, &previous, m_d->radius, m_d->blend); Q_UNUSED(result); emit sigColorUpdated(color); @@ -76,4 +72,3 @@ Qt::DirectConnection); return lodStrategy; } - 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 @@ -2,6 +2,7 @@ * Copyright (c) 1999 Matthias Elter * Copyright (c) 2002 Patrick Julien * Copyright (c) 2010 Lukáš Tvrdý + * Copyright (c) 2018 Emmet & Eoin O'Neill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,16 +22,11 @@ #ifndef KIS_TOOL_COLOR_PICKER_H_ #define KIS_TOOL_COLOR_PICKER_H_ -#include #include - #include "KoToolFactoryBase.h" #include "ui_wdgcolorpicker.h" #include "kis_tool.h" -#include -#include #include -#include class KoResource; class KoColorSet; @@ -51,12 +47,11 @@ class KisToolColorPicker : public KisTool { - Q_OBJECT Q_PROPERTY(bool toForeground READ toForeground WRITE setToForeground NOTIFY toForegroundChanged) public: - KisToolColorPicker(KoCanvasBase* canvas); + KisToolColorPicker(KoCanvasBase *canvas); ~KisToolColorPicker() override; public: @@ -69,6 +64,7 @@ bool normaliseValues; bool sampleMerged; int radius; + int blend; void save(ToolActivation activation) const; void load(ToolActivation activation); @@ -81,7 +77,7 @@ void continuePrimaryAction(KoPointerEvent *event) override; void endPrimaryAction(KoPointerEvent *event) override; - void paint(QPainter& gc, const KoViewConverter &converter) override; + void paint(QPainter &gc, const KoViewConverter &converter) override; bool toForeground() const; @@ -98,22 +94,24 @@ void slotSetNormaliseValues(bool); void slotSetAddPalette(bool); void slotChangeRadius(int); + void slotChangeBlend(int); void slotAddPalette(KoResource* resource); void slotSetColorSource(int value); private: void displayPickedColor(); void pickColor(const QPointF& pos); void updateOptionWidget(); - //Configuration m_config; + // Configuration QScopedPointer m_config; + ToolActivation m_toolActivationSource; bool m_isActivated; KoColor m_pickedColor; - // used to skip some of the tablet events and don't update the colour that often + // Used to skip some tablet events and update color less often QTimer m_colorPickerDelayTimer; ColorPickerOptionsWidget *m_optionsWidget; @@ -123,7 +121,6 @@ class KisToolColorPickerFactory : public KoToolFactoryBase { - public: KisToolColorPickerFactory() : KoToolFactoryBase("KritaSelected/KisToolColorPicker") { @@ -137,11 +134,9 @@ ~KisToolColorPickerFactory() override {} - KoToolBase * createTool(KoCanvasBase *canvas) override { + KoToolBase *createTool(KoCanvasBase *canvas) override { return new KisToolColorPicker(canvas); } }; - #endif // KIS_TOOL_COLOR_PICKER_H_ - 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 @@ -2,6 +2,7 @@ * Copyright (c) 1999 Matthias Elter * Copyright (c) 2002 Patrick Julien * Copyright (c) 2010 Lukáš Tvrdý + * Copyright (c) 2018 Emmet & Eoin O'Neill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,55 +20,27 @@ */ #include "kis_tool_colorpicker.h" -#include #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - #include - -#include "kis_layer.h" #include "kis_cursor.h" -#include "kis_image.h" -#include "kis_paint_device.h" -#include "kis_properties_configuration.h" #include "KisDocument.h" #include "kis_canvas2.h" #include "KisReferenceImagesLayer.h" - -#include "KoPointerEvent.h" #include "KoCanvasBase.h" #include "kis_random_accessor_ng.h" -#include "KoColor.h" #include "KoResourceServerProvider.h" -#include -#include #include - #include "kis_wrapped_rect.h" #include "kis_tool_utils.h" - namespace { -// The location of the sample all visible layers in the combobox +// GUI ComboBox index constants const int SAMPLE_MERGED = 0; } -KisToolColorPicker::KisToolColorPicker(KoCanvasBase* canvas) +KisToolColorPicker::KisToolColorPicker(KoCanvasBase *canvas) : KisTool(canvas, KisCursor::pickerCursor()), m_config(new KisToolUtils::ColorPickerConfig) { @@ -84,7 +57,7 @@ } } -void KisToolColorPicker::paint(QPainter& gc, const KoViewConverter &converter) +void KisToolColorPicker::paint(QPainter &gc, const KoViewConverter &converter) { Q_UNUSED(gc); Q_UNUSED(converter); @@ -99,14 +72,15 @@ KisTool::activate(activation, shapes); } + void KisToolColorPicker::deactivate() { m_config->save(m_toolActivationSource == KisTool::DefaultActivation); m_isActivated = false; KisTool::deactivate(); } -void KisToolColorPicker::pickColor(const QPointF& pos) +void KisToolColorPicker::pickColor(const QPointF &pos) { if (m_colorPickerDelayTimer.isActive()) { return; @@ -116,8 +90,7 @@ m_colorPickerDelayTimer.start(100); } - - QScopedPointer > imageLocker; + QScopedPointer> imageLocker; m_pickedColor.setOpacity(0.0); @@ -147,6 +120,7 @@ dev = currentImage()->projection(); } + // Color sampling radius. if (m_config->radius == 1) { QPoint realPos = pos.toPoint(); if (currentImage()->wrapAroundModePermitted()) { @@ -156,7 +130,6 @@ dev->pixel(realPos.x(), realPos.y(), &m_pickedColor); } else { - const KoColorSpace *cs = dev->colorSpace(); int pixelSize = cs->pixelSize(); @@ -181,29 +154,46 @@ } } - const quint8 **cpixels = const_cast(pixels.constData()); cs->mixColorsOp()->mixColors(cpixels, pixels.size(), dstColor); m_pickedColor = KoColor(dstColor, cs); delete[] dstColor; } - m_pickedColor.convertTo(dev->compositionSourceColorSpace()); - } + // Color blending. + if(m_config->blend < 100){ + //Scale from 0..100% to 0..255 range for mixOp weights. + quint8 blendScaled = static_cast(m_config->blend * 2.55f); - if (m_config->updateColor && - m_pickedColor.opacityU8() != OPACITY_TRANSPARENT_U8) { + KoColor previousColor = canvas()->resourceManager()->foregroundColor(); - KoColor publicColor = m_pickedColor; - publicColor.setOpacity(OPACITY_OPAQUE_U8); + const quint8 *colors[2]; + colors[0] = previousColor.data(); + colors[1] = m_pickedColor.data(); + qint16 weights[2]; + weights[0] = 255 - blendScaled; + weights[1] = blendScaled; - if (m_config->toForegroundColor) { - canvas()->resourceManager()->setResource(KoCanvasResourceManager::ForegroundColor, publicColor); + const KoMixColorsOp *mixOp = dev->colorSpace()->mixColorsOp(); + mixOp->mixColors(colors, weights, 2, m_pickedColor.data()); } - else { - canvas()->resourceManager()->setResource(KoCanvasResourceManager::BackgroundColor, publicColor); + + m_pickedColor.convertTo(dev->compositionSourceColorSpace()); + + if (m_config->updateColor && + m_pickedColor.opacityU8() != OPACITY_TRANSPARENT_U8) { + + KoColor publicColor = m_pickedColor; + publicColor.setOpacity(OPACITY_OPAQUE_U8); + + if (m_config->toForegroundColor) { + canvas()->resourceManager()->setResource(KoCanvasResourceManager::ForegroundColor, publicColor); + } + else { + canvas()->resourceManager()->setResource(KoCanvasResourceManager::BackgroundColor, publicColor); + } } } } @@ -225,7 +215,7 @@ } QPoint pos = convertToImagePixelCoordFloored(event); - // the color picking has to start in the visible part of the layer + // Color picking has to start in the visible part of the layer if (!currentImage()->bounds().contains(pos) && !currentImage()->wrapAroundModePermitted()) { event->ignore(); @@ -256,16 +246,15 @@ ent.color = m_pickedColor; // We don't ask for a name, too intrusive here - KoColorSet* palette = m_palettes.at(m_optionsWidget->cmbPalette->currentIndex()); + KoColorSet *palette = m_palettes.at(m_optionsWidget->cmbPalette->currentIndex()); palette->add(ent); if (!palette->save()) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Cannot write to palette file %1. Maybe it is read-only.", palette->filename())); } } } - struct PickedChannel { QString name; QString valueText; @@ -318,18 +307,23 @@ specialSpacer->setFixedSize(0, 0); m_optionsWidget->layout()->addWidget(specialSpacer); + // Initialize blend KisSliderSpinBox + m_optionsWidget->blend->setRange(0,100); + 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(); + KoResourceServer *srv = KoResourceServerProvider::instance()->paletteServer(); if (!srv) { return m_optionsWidget; @@ -356,6 +350,7 @@ 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) @@ -374,7 +369,6 @@ m_config->updateColor = state; } - void KisToolColorPicker::slotSetNormaliseValues(bool state) { m_config->normaliseValues = state; @@ -391,17 +385,21 @@ m_config->radius = value; } +void KisToolColorPicker::slotChangeBlend(int value) +{ + m_config->blend = value; +} + void KisToolColorPicker::slotSetColorSource(int value) { m_config->sampleMerged = value == SAMPLE_MERGED; } -void KisToolColorPicker::slotAddPalette(KoResource* resource) +void KisToolColorPicker::slotAddPalette(KoResource *resource) { - KoColorSet* palette = dynamic_cast(resource); + KoColorSet *palette = dynamic_cast(resource); if (palette) { m_optionsWidget->cmbPalette->addSqueezedItem(palette->name()); m_palettes.append(palette); } } - 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 @@ -7,15 +7,102 @@ 0 0 263 - 307 + 323 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 + + 2 @@ -31,8 +118,21 @@ - - + + + + QFrame::Plain + + + 1 + + + Qt::Horizontal + + + + + 1 @@ -49,17 +149,29 @@ 0 - + - Sample radius: + Radius: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + 1 + + + + 0 + 0 + + + + <nobr>Radius controls the color picker's sampling area.</nobr> Pixel colors within this radius are mixed together. + px @@ -74,14 +186,7 @@ - - - Show colors as percentages - - - - - + 1 @@ -99,6 +204,9 @@ + + <nobr>Checking this box will add a new color swatch</nobr> to a palette each time you pick a color. + Add to palette: @@ -109,48 +217,41 @@ - - - - Update current color - - + + + + + + <nobr>Controls whether the color picker updates the</nobr> current foreground or not. + + + Update color + + + + - - - - - 0 - 0 - + + + + QFrame::Plain - - - 200 - 0 - + + 1 - - - 200 - 32767 - + + Qt::Horizontal - - - Sample All Visible Layers - - - - - Current Layer - - + + KisSliderSpinBox + QWidget +
kis_slider_spin_box.h
+
SqueezedComboBox QComboBox