Changeset View
Changeset View
Standalone View
Standalone View
libs/ui/tool/kis_tool_utils.cpp
1 | /* | 1 | /* | ||
---|---|---|---|---|---|
2 | * Copyright (c) 2009 Boudewijn Rempt <boud@valdyas.org> | 2 | * Copyright (c) 2009 Boudewijn Rempt <boud@valdyas.org> | ||
3 | * Copyright (c) 2018 Emmet & Eoin O'Neill <emmetoneill.pdx@gmail.com> | ||||
3 | * | 4 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | 7 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | 8 | * (at your option) any later version. | ||
8 | * | 9 | * | ||
9 | * This program is distributed in the hope that it will be useful, | 10 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. | ||
13 | * | 14 | * | ||
14 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
17 | */ | 18 | */ | ||
19 | | ||||
18 | #include <kis_tool_utils.h> | 20 | #include <kis_tool_utils.h> | ||
19 | 21 | | |||
20 | #include <KoColorSpace.h> | | |||
21 | #include <KoMixColorsOp.h> | 22 | #include <KoMixColorsOp.h> | ||
22 | #include <kis_paint_device.h> | | |||
23 | #include <kis_layer.h> | | |||
24 | #include <kis_group_layer.h> | 23 | #include <kis_group_layer.h> | ||
25 | #include <kis_wrapped_rect.h> | | |||
26 | #include <kis_image.h> | | |||
27 | #include <kis_transaction.h> | 24 | #include <kis_transaction.h> | ||
28 | #include <kis_sequential_iterator.h> | 25 | #include <kis_sequential_iterator.h> | ||
29 | #include <kis_properties_configuration.h> | 26 | #include <kis_properties_configuration.h> | ||
30 | #include <kconfiggroup.h> | 27 | #include <kconfiggroup.h> | ||
31 | #include <ksharedconfig.h> | 28 | #include <ksharedconfig.h> | ||
32 | 29 | | |||
33 | namespace KisToolUtils { | 30 | namespace KisToolUtils { | ||
34 | 31 | | |||
35 | bool pick(KisPaintDeviceSP dev, const QPoint& pos, KoColor *color, int radius) | 32 | bool pick(KisPaintDeviceSP dev, const QPoint &pos, KoColor *color, KoColor *previousColor, int radius, int blend) | ||
36 | { | 33 | { | ||
37 | KIS_ASSERT(dev); | 34 | KIS_ASSERT(dev); | ||
38 | const KoColorSpace* cs = dev->colorSpace(); | 35 | const KoColorSpace* cs = dev->colorSpace(); | ||
39 | KoColor pickedColor(Qt::transparent, cs); | 36 | KoColor pickedColor(Qt::transparent, cs); | ||
40 | 37 | | |||
38 | // Ctrl picker sampling radius. | ||||
41 | if (radius <= 1) { | 39 | if (radius <= 1) { | ||
42 | dev->pixel(pos.x(), pos.y(), &pickedColor); | 40 | dev->pixel(pos.x(), pos.y(), &pickedColor); | ||
43 | } else { | 41 | } else { | ||
44 | QVector<const quint8*> pixels; | 42 | QVector<const quint8*> pixels; | ||
45 | 43 | | |||
46 | const int effectiveRadius = radius - 1; | 44 | const int effectiveRadius = radius - 1; | ||
47 | 45 | | |||
48 | const QRect pickRect(pos.x() - effectiveRadius, pos.y() - effectiveRadius, | 46 | const QRect pickRect(pos.x() - effectiveRadius, pos.y() - effectiveRadius, | ||
49 | 2 * effectiveRadius + 1, 2 * effectiveRadius + 1); | 47 | 2 * effectiveRadius + 1, 2 * effectiveRadius + 1); | ||
50 | KisSequentialConstIterator it(dev, pickRect); | 48 | KisSequentialConstIterator it(dev, pickRect); | ||
51 | 49 | | |||
52 | const int radiusSq = pow2(effectiveRadius); | 50 | const int radiusSq = pow2(effectiveRadius); | ||
53 | 51 | | |||
54 | while (it.nextPixel()) { | 52 | while (it.nextPixel()) { | ||
55 | const QPoint realPos(it.x(), it.y()); | 53 | const QPoint realPos(it.x(), it.y()); | ||
56 | const QPoint pt = realPos - pos; | 54 | const QPoint pt = realPos - pos; | ||
57 | if (pow2(pt.x()) + pow2(pt.y()) < radiusSq) { | 55 | if (pow2(pt.x()) + pow2(pt.y()) < radiusSq) { | ||
58 | pixels << it.oldRawData(); | 56 | pixels << it.oldRawData(); | ||
59 | } | 57 | } | ||
60 | } | 58 | } | ||
61 | 59 | | |||
62 | const quint8** cpixels = const_cast<const quint8**>(pixels.constData()); | 60 | const quint8 **cpixels = const_cast<const quint8**>(pixels.constData()); | ||
63 | cs->mixColorsOp()->mixColors(cpixels, pixels.size(), pickedColor.data()); | 61 | cs->mixColorsOp()->mixColors(cpixels, pixels.size(), pickedColor.data()); | ||
64 | } | 62 | } | ||
65 | 63 | | |||
64 | // Ctrl picker color blending. | ||||
65 | if (previousColor && blend < 100) { | ||||
66 | //Scale from 0..100% to 0..255 range for mixOp weights. | ||||
67 | quint8 blendScaled = static_cast<quint8>(blend * 2.55f); | ||||
68 | | ||||
69 | const quint8 *colors[2]; | ||||
70 | colors[0] = previousColor->data(); | ||||
71 | colors[1] = pickedColor.data(); | ||||
72 | qint16 weights[2]; | ||||
73 | weights[0] = 255 - blendScaled; | ||||
74 | weights[1] = blendScaled; | ||||
75 | | ||||
76 | const KoMixColorsOp *mixOp = dev->colorSpace()->mixColorsOp(); | ||||
77 | mixOp->mixColors(colors, weights, 2, pickedColor.data()); | ||||
78 | } | ||||
79 | | ||||
66 | pickedColor.convertTo(dev->compositionSourceColorSpace()); | 80 | pickedColor.convertTo(dev->compositionSourceColorSpace()); | ||
67 | 81 | | |||
68 | bool validColorPicked = | 82 | bool validColorPicked = | ||
69 | pickedColor.opacityU8() != OPACITY_TRANSPARENT_U8; | 83 | pickedColor.opacityU8() != OPACITY_TRANSPARENT_U8; | ||
70 | 84 | | |||
71 | if (validColorPicked) { | 85 | if (validColorPicked) { | ||
72 | pickedColor.setOpacity(OPACITY_OPAQUE_U8); | 86 | pickedColor.setOpacity(OPACITY_OPAQUE_U8); | ||
73 | *color = pickedColor; | 87 | *color = pickedColor; | ||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Line(s) | |||||
141 | 155 | | |||
142 | ColorPickerConfig::ColorPickerConfig() | 156 | ColorPickerConfig::ColorPickerConfig() | ||
143 | : toForegroundColor(true) | 157 | : toForegroundColor(true) | ||
144 | , updateColor(true) | 158 | , updateColor(true) | ||
145 | , addPalette(false) | 159 | , addPalette(false) | ||
146 | , normaliseValues(false) | 160 | , normaliseValues(false) | ||
147 | , sampleMerged(true) | 161 | , sampleMerged(true) | ||
148 | , radius(1) | 162 | , radius(1) | ||
163 | , blend(100) | ||||
149 | { | 164 | { | ||
150 | } | 165 | } | ||
151 | 166 | | |||
152 | inline QString getConfigKey(bool defaultActivation) { | 167 | inline QString getConfigKey(bool defaultActivation) { | ||
153 | return defaultActivation ? | 168 | return defaultActivation ? | ||
154 | "ColorPickerDefaultActivation" : "ColorPickerTemporaryActivation"; | 169 | "ColorPickerDefaultActivation" : "ColorPickerTemporaryActivation"; | ||
155 | } | 170 | } | ||
156 | 171 | | |||
157 | void ColorPickerConfig::save(bool defaultActivation) const | 172 | void ColorPickerConfig::save(bool defaultActivation) const | ||
158 | { | 173 | { | ||
159 | KisPropertiesConfiguration props; | 174 | KisPropertiesConfiguration props; | ||
160 | props.setProperty("toForegroundColor", toForegroundColor); | 175 | props.setProperty("toForegroundColor", toForegroundColor); | ||
161 | props.setProperty("updateColor", updateColor); | 176 | props.setProperty("updateColor", updateColor); | ||
162 | props.setProperty("addPalette", addPalette); | 177 | props.setProperty("addPalette", addPalette); | ||
163 | props.setProperty("normaliseValues", normaliseValues); | 178 | props.setProperty("normaliseValues", normaliseValues); | ||
164 | props.setProperty("sampleMerged", sampleMerged); | 179 | props.setProperty("sampleMerged", sampleMerged); | ||
165 | props.setProperty("radius", radius); | 180 | props.setProperty("radius", radius); | ||
181 | props.setProperty("blend", blend); | ||||
166 | 182 | | |||
167 | KConfigGroup config = KSharedConfig::openConfig()->group(CONFIG_GROUP_NAME); | 183 | KConfigGroup config = KSharedConfig::openConfig()->group(CONFIG_GROUP_NAME); | ||
168 | 184 | | |||
169 | config.writeEntry(getConfigKey(defaultActivation), props.toXML()); | 185 | config.writeEntry(getConfigKey(defaultActivation), props.toXML()); | ||
170 | } | 186 | } | ||
171 | 187 | | |||
172 | void ColorPickerConfig::load(bool defaultActivation) | 188 | void ColorPickerConfig::load(bool defaultActivation) | ||
173 | { | 189 | { | ||
174 | KisPropertiesConfiguration props; | 190 | KisPropertiesConfiguration props; | ||
175 | 191 | | |||
176 | KConfigGroup config = KSharedConfig::openConfig()->group(CONFIG_GROUP_NAME); | 192 | KConfigGroup config = KSharedConfig::openConfig()->group(CONFIG_GROUP_NAME); | ||
177 | props.fromXML(config.readEntry(getConfigKey(defaultActivation))); | 193 | props.fromXML(config.readEntry(getConfigKey(defaultActivation))); | ||
178 | 194 | | |||
179 | toForegroundColor = props.getBool("toForegroundColor", true); | 195 | toForegroundColor = props.getBool("toForegroundColor", true); | ||
180 | updateColor = props.getBool("updateColor", true); | 196 | updateColor = props.getBool("updateColor", true); | ||
181 | addPalette = props.getBool("addPalette", false); | 197 | addPalette = props.getBool("addPalette", false); | ||
182 | normaliseValues = props.getBool("normaliseValues", false); | 198 | normaliseValues = props.getBool("normaliseValues", false); | ||
183 | sampleMerged = props.getBool("sampleMerged", !defaultActivation ? false : true); | 199 | sampleMerged = props.getBool("sampleMerged", !defaultActivation ? false : true); | ||
184 | radius = props.getInt("radius", 1); | 200 | radius = props.getInt("radius", 1); | ||
201 | blend = props.getInt("blend", 100); | ||||
185 | } | 202 | } | ||
186 | 203 | | |||
187 | } | 204 | } |