Krita Source Code Documentation
Loading...
Searching...
No Matches
KisUniqueColorSet.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2021 Mathias Wein <lynx.mw+kde@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
7#include "KisUniqueColorSet.h"
8
9#include <QHash>
10#include <deque>
11#include <algorithm>
12
13uint qHash(const KoColor &color, uint seed = 0)
14{
15 // hash the color data bytes, while using the hash of the colorspace pointer as seed
16 // TODO: take pixelSize directly from the color.m_size (private member)
17 return qHashBits(color.data(), color.colorSpace()->pixelSize(), qHash(color.colorSpace(), seed));
18}
19
21{
23 {
24 // larger key == more recent == earlier in list
25 return (lhs->key > rhs->key);
26 }
27
29 quint64 key;
30};
31
33{
35 Private (const Private &rhs)
36 : maxSize(rhs.maxSize)
37 , key(rhs.key)
38 {
39 for (auto it = rhs.history.begin(); it != rhs.history.end(); ++it) {
40 history.push_back(new ColorEntry(*(*it)));
41 colorHash.insert(history.back()->color, history.back());
42 }
43 }
44
45 QHash<KoColor, KisUniqueColorSet::ColorEntry*> colorHash;
46 std::deque<ColorEntry*> history;
47 size_t maxSize {200};
48 quint64 key {0};
49};
50
52 : QObject(parent)
53 , d(new Private())
54{ }
55
57{
58 for (ColorEntry *entry: d->history) {
59 delete entry;
60 }
61}
62
64 : QObject(parent)
65 , d(new Private(*rhs.d))
66{
67
68}
69
71{
72 auto hashEntry = d->colorHash.find(color);
73 if (hashEntry != d->colorHash.end()) {
74 auto historyEl = std::lower_bound(d->history.begin(), d->history.end(), *hashEntry, &ColorEntry::less);
75 if (historyEl != d->history.end()) {
76 int oldPos = historyEl - d->history.begin();
77 if (historyEl == d->history.begin()) {
78 KIS_ASSERT((*historyEl)->key == d->key);
79 return;
80 }
81 ColorEntry *node = *historyEl;
82 d->history.erase(historyEl);
83 node->key = ++d->key;
84 d->history.push_front(node);
85 Q_EMIT sigColorMoved(oldPos, 0);
86 }
87 else {
88 qDebug() << "inconsistent color history state!";
89 }
90 }
91 else {
92 ColorEntry *entry;
93 if (d->history.size() >= d->maxSize) {
94 entry = d->history.back();
95 d->history.pop_back();
96 KIS_ASSERT(d->colorHash.remove(entry->color) == 1);
97 entry->color = color;
98 entry->key = ++d->key;
99 Q_EMIT sigColorRemoved(d->maxSize - 1);
100 }
101 else {
102 entry = new ColorEntry {color, ++d->key};
103 }
104 d->colorHash.insert(color, entry);
105 d->history.push_front(entry);
106 Q_EMIT sigColorAdded(0);
107 }
108}
109
111{
112 if (index < 0 || index >= static_cast<int>(d->history.size())) {
113 return KoColor();
114 }
115 return d->history.at(index)->color;
116}
117
119{
120 return static_cast<int>(d->history.size());
121}
122
124{
125 QList<KoColor> colors;
126 for (int i = 0; i < static_cast<int>(d->history.size()); i++) {
127 colors.append(d->history.at(i)->color);
128 }
129 return colors;
130}
131
133{
134 clear();
135 Q_FOREACH(KoColor c, colors) {
136 addColor(c);
137 }
138}
139
141{
142 for (ColorEntry *entry: d->history) {
143 delete entry;
144 }
145 d->history.clear();
146 d->colorHash.clear();
147 d->key = 0;
148 Q_EMIT sigReset();
149}
uint qHash(const KoColor &color, uint seed=0)
unsigned int uint
void sigColorRemoved(int position)
void sigColorAdded(int position)
QScopedPointer< Private > d
void setColorList(const QList< KoColor > &colors)
void addColor(const KoColor &color)
KoColor color(int index) const
void sigColorMoved(int from, int to)
KisUniqueColorSet(QObject *parent=nullptr)
QList< KoColor > colorList() const
virtual quint32 pixelSize() const =0
quint8 * data()
Definition KoColor.h:144
const KoColorSpace * colorSpace() const
return the current colorSpace
Definition KoColor.h:82
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
static bool less(const KisUniqueColorSet::ColorEntry *lhs, const KisUniqueColorSet::ColorEntry *rhs)
QHash< KoColor, KisUniqueColorSet::ColorEntry * > colorHash
std::deque< ColorEntry * > history