Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
color-set.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
/*
5 * Copyright (C) 2024 Authors
6 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
7 */
8
9#include "color-set.h"
10
11#include <algorithm>
12
13#include "colors/color.h"
14#include "colors/spaces/base.h"
16
17namespace Inkscape::Colors {
18
26ColorSet::ColorSet(std::shared_ptr<Space::AnySpace> space, std::optional<bool> alpha)
27 : _space_constraint(std::move(space))
28 , _alpha_constraint(alpha)
29{}
30
35{
37 throw ColorError("Components are only available on a color space constrained ColorSet.");
38 return _space_constraint->getComponents(_alpha_constraint && *_alpha_constraint);
39}
40
45{
46 if (!_colors.empty()) {
47 _colors.clear();
49 }
50}
51
56{
57 if (!_blocked && !_grabbed) {
58 block();
59 signal_grabbed.emit();
60 unblock();
61 _grabbed = true;
62 }
63}
64
69{
70 if (!_blocked && _grabbed) {
71 _grabbed = false;
72 block();
73 signal_released.emit();
74 unblock();
75 }
76}
77
82{
83 // Send signals about this change
84 if (!_blocked) {
85 block();
86 signal_changed.emit();
87 unblock();
88 }
89}
90
95{
96 if (!_blocked) {
97 block();
98 signal_cleared.emit();
99 unblock();
100 }
101}
102
107{
108 if (_colors.empty())
109 return true;
110 for (auto const &[id, color] : _colors) {
111 if (color != _colors[0].second)
112 return false;
113 }
114 return true;
115}
116
124unsigned ColorSet::setAll(Color const &other)
125{
126 unsigned changed = 0;
127 for (auto &[id, color] : _colors) {
128 auto was = color;
129 color.set(other, true);
130 // Comparison after possible color space conversion
131 changed += (was != color);
132 }
133 if (changed) {
135 }
136 return changed;
137}
138
146unsigned ColorSet::setAll(ColorSet const &other)
147{
148 unsigned changed = 0;
149 for (auto &[id, color] : other) {
150 changed += _set(id, color);
151 }
152 if (changed > 0) {
154 }
155 return changed;
156}
157
166bool ColorSet::set(std::string id, Color const &other)
167{
168 if (_set(std::move(id), other)) {
170 return true;
171 }
172 return false;
173}
174
182bool ColorSet::set(Color const &other)
183{
184 // Always clear the colors if it's being used differently
185 if (_colors.size() != 1 || _colors[0].first != "single")
186 _colors.clear();
187 return set("single", other);
188}
189
195std::optional<Color> ColorSet::get() const
196{
197 return get("single");
198}
199
200/*
201 * Internal function for setting a color by id without calling the changed singal.
202 */
203bool ColorSet::_set(std::string id, Color const &other)
204{
205 for (auto &[cid, color] : _colors) {
206 if (cid == id) {
207 auto was = color;
208 color.set(other, true);
209 return was != color;
210 }
211 }
212 // Add a new entry for this id
213 Color copy = other;
214
215 // Enforce constraints on space and alpha if any
217 copy.convert(_space_constraint);
218
219 if (_alpha_constraint) {
220 copy.enableOpacity(*_alpha_constraint);
221 }
222
223 _colors.emplace_back(std::move(id), copy);
224 return true;
225}
226
236std::optional<Color> ColorSet::get(std::string const &id) const
237{
238 for (auto &[cid, color] : _colors) {
239 if (cid == id)
240 return color.normalized();
241 }
242 return {};
243}
244
253unsigned ColorSet::setAll(Space::Component const &c, double value)
254{
255 if (!isValid(c)) {
256 throw ColorError("Incompatible color component used in ColorSet::set.");
257 }
258 unsigned changed = 0;
259 for (auto &[id, color] : _colors) {
260 auto was = color;
261 color.set(c.index, value);
262 // Comparison after possible color space conversion
263 changed += (was != color);
264 }
265 if (changed) {
267 }
268 return changed;
269}
270
282void ColorSet::setAverage(Space::Component const &c, double value)
283{
284 if (!_space_constraint || _space_constraint->getType() != c.type)
285 throw ColorError("Incompatible color component used in ColorSet::moveAverageTo.");
286 auto delta = value - getAverage(c);
287 for (auto &[id, color] : _colors) {
288 color.set(c.index, color[c.index] + delta);
289 }
291}
292
301 if (!isValid(c)) {
302 throw ColorError("Incompatible color component used in ColorSet::get.");
303 }
304 double value = 0.0;
305 for (auto const &[id, color] : _colors) {
306 value += color[c.index];
307 }
308 return c.normalize(value / _colors.size());
309}
310
318std::vector<double> ColorSet::getAll(Space::Component const &c) const
319{
320 if (!isValid(c)) {
321 throw ColorError("Incompatible color component used in ColorSet::getAll.");
322 }
323 std::vector<double> ret(_colors.size());
324 std::transform(_colors.begin(), _colors.end(), ret.begin(),
325 [c](auto &iter) { return c.normalize(iter.second[c.index]); });
326 return ret;
327}
328
334std::shared_ptr<Space::AnySpace> ColorSet::getBestSpace() const
335{
337 return _space_constraint;
338
339 unsigned biggest = 0;
340 std::shared_ptr<Space::AnySpace> ret;
341 std::map<std::shared_ptr<Space::AnySpace>, unsigned> counts;
342 for (auto const &[id, color] : _colors) {
343 if (++counts[color.getSpace()] > biggest) {
344 biggest = counts[color.getSpace()];
345 ret = color.getSpace();
346 }
347 }
348 return ret;
349}
350
351bool ColorSet::isValid(const Space::Component& component) const {
352 return _space_constraint && _space_constraint->getType() == component.type;
353}
354
362{
363 if (isEmpty())
364 throw ColorError("Can't get the average color of no colors.");
365
366 auto avg_space = getBestSpace();
367 auto avg_alpha = _alpha_constraint.value_or(true);
368
369 std::vector<double> values(avg_space->getComponentCount() + avg_alpha);
370
371 for (auto const &[id, color] : _colors) {
372 // Colors::Color will return the alpha channel as 1.0 if it doesn't exist.
373 if (color.getSpace() == avg_space) {
374 for (unsigned int i = 0; i < values.size(); i++) {
375 values[i] += color[i];
376 }
377 } else if (auto copy = color.converted(avg_space)) {
378 for (unsigned int i = 0; i < values.size(); i++) {
379 values[i] += (*copy)[i];
380 }
381 }
382 }
383 for (double &value : values) {
384 value /= _colors.size();
385 }
386 return Color(avg_space, values);
387}
388
392unsigned ColorSet::size() const
393{
394 return _colors.size();
395}
396
397} // namespace Inkscape::Colors
398
399/*
400 Local Variables:
401 mode:c++
402 c-file-style:"stroustrup"
403 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
404 indent-tabs-mode:nil
405 fill-column:99
406 End:
407*/
408// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Space::Components const & getComponents() const
Get a list of components for the color space set to this color set.
Definition color-set.cpp:34
std::vector< double > getAll(Space::Component const &c) const
Get a list of all normalized values for this one component.
void grab()
Set this color to being grabbed for a continuous set of changes.
Definition color-set.cpp:55
std::optional< bool > const _alpha_constraint
Definition color-set.h:98
bool set(Color const &color)
Remove any other colors and set to just this one color.
sigc::signal< void()> signal_grabbed
Definition color-set.h:46
sigc::signal< void()> signal_released
Definition color-set.h:47
sigc::signal< void()> signal_changed
Definition color-set.h:48
void clear()
Reset the color set and remove all colors from it.
Definition color-set.cpp:44
unsigned size() const
Return the number of items in the color set.
std::optional< Color > get() const
Get the color if there is only one color set with set(Color)
unsigned setAll(ColorSet const &other)
Set each of the colors from the other color set by id.
void colors_changed()
Called when the colors change in some way.
Definition color-set.cpp:81
void release()
Set the color as being released from continuous changes.
Definition color-set.cpp:68
void colors_cleared()
Called when the list of colors changes (add or clear)
Definition color-set.cpp:94
std::shared_ptr< Space::AnySpace > getBestSpace() const
Return the best color space from this collection of colors.
ColorSet(std::shared_ptr< Space::AnySpace > space={}, std::optional< bool > alpha={})
Construct a new ColorSet object to contain a group of colors which will be modified collectively.
Definition color-set.cpp:26
bool _set(std::string id, Color const &color)
std::shared_ptr< Space::AnySpace > const _space_constraint
Definition color-set.h:97
Color getAverage() const
Return the average color between this set of colors.
sigc::signal< void()> signal_cleared
Definition color-set.h:49
bool isValid(const Space::Component &component) const
void setAverage(Space::Component const &c, double value)
Set the average value in this component by taking the average finding the delta and moving all colors...
bool isSame() const
Returns true if all of the colors are the same color.
A set of colors which can be modified together used for color pickers.
double c[8][4]
A set of useful color modifying functions which do not fit as generic methods on the color class itse...
Definition profile.cpp:24
STL namespace.
int delta