KWidgetsAddons

kcolorcombo.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1997 Martin Jones <mjones@kde.org>
4 SPDX-FileCopyrightText: 2007 Pino Toscano <pino@kde.org>
5 SPDX-FileCopyrightText: 2007 David Jarvie <djarvie@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "kcolorcombo.h"
11
12#include <QAbstractItemDelegate>
13#include <QApplication>
14#include <QColorDialog>
15#include <QStylePainter>
16
17class KColorComboDelegate : public QAbstractItemDelegate
18{
20public:
21 enum ItemRoles {
22 ColorRole = Qt::UserRole + 1,
23 };
24
25 enum LayoutMetrics {
26 FrameMargin = 3,
27 };
28
29 KColorComboDelegate(QObject *parent = nullptr);
30 ~KColorComboDelegate() override;
31
32 void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
33 QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
34};
35
36static QBrush k_colorcombodelegate_brush(const QModelIndex &index, int role)
37{
38 QBrush brush;
39 QVariant v = index.data(role);
40 if (v.userType() == QMetaType::QBrush) {
41 brush = v.value<QBrush>();
42 } else if (v.userType() == QMetaType::QColor) {
43 brush = QBrush(v.value<QColor>());
44 }
45 return brush;
46}
47
48KColorComboDelegate::KColorComboDelegate(QObject *parent)
49 : QAbstractItemDelegate(parent)
50{
51}
52
53KColorComboDelegate::~KColorComboDelegate()
54{
55}
56
57void KColorComboDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
58{
59 // background
61 bool isSelected = (option.state & QStyle::State_Selected);
62 bool paletteBrush = (k_colorcombodelegate_brush(index, Qt::BackgroundRole).style() == Qt::NoBrush);
63 if (isSelected) {
64 innercolor = option.palette.color(QPalette::Highlight);
65 } else {
66 innercolor = option.palette.color(QPalette::Base);
67 }
68 // highlight selected item
70 opt.showDecorationSelected = true;
71 QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
72 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget);
73 QRect innerrect = option.rect.adjusted(FrameMargin, FrameMargin, -FrameMargin, -FrameMargin);
74 // inner color
75 QVariant cv = index.data(ColorRole);
76 if (cv.userType() == QMetaType::QColor) {
77 QColor tmpcolor = cv.value<QColor>();
78 if (tmpcolor.isValid()) {
80 paletteBrush = false;
81 painter->setPen(Qt::transparent);
82 painter->setBrush(innercolor);
85 painter->drawRoundedRect(innerrect, 2, 2);
86 painter->setRenderHints(tmpHint);
87 painter->setBrush(Qt::NoBrush);
88 }
89 }
90 // text
92 if (tv.userType() == QMetaType::QString) {
93 QString text = tv.toString();
94 QColor textColor;
95 if (paletteBrush) {
96 if (isSelected) {
97 textColor = option.palette.color(QPalette::HighlightedText);
98 } else {
99 textColor = option.palette.color(QPalette::Text);
100 }
101 } else {
102 int unused;
103 int v;
104 innercolor.getHsv(&unused, &unused, &v);
105 if (v > 128) {
106 textColor = Qt::black;
107 } else {
108 textColor = Qt::white;
109 }
110 }
111 painter->setPen(textColor);
112 painter->drawText(innerrect.adjusted(1, 1, -1, -1), text);
113 }
114}
115
116QSize KColorComboDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
117{
118 Q_UNUSED(index)
119
120 // the width does not matter, as the view will always use the maximum width available
121 return QSize(100, option.fontMetrics.height() + 2 * FrameMargin);
122}
123
124static const uchar standardPalette[][4] = {
125 {255, 255, 255}, // white
126 {192, 192, 192}, // light gray
127 {160, 160, 160}, // gray
128 {128, 128, 128}, // dark gray
129 {0, 0, 0}, // black
130
131 {255, 128, 128}, // light red
132 {255, 192, 128}, // light orange
133 {255, 255, 128}, // light yellow
134 {128, 255, 128}, // light green
135 {128, 255, 255}, // cyan blue
136 {128, 128, 255}, // light blue
137 {255, 128, 255}, // light violet
138 {255, 0, 0}, // red
139 {255, 128, 0}, // orange
140 {255, 255, 0}, // yellow
141 {0, 255, 0}, // green
142 {0, 255, 255}, // light blue
143 {0, 0, 255}, // blue
144 {255, 0, 255}, // violet
145 {128, 0, 0}, // dark red
146 {128, 64, 0}, // dark orange
147 {128, 128, 0}, // dark yellow
148 {0, 128, 0}, // dark green
149 {0, 128, 128}, // dark light blue
150 {0, 0, 128}, // dark blue
151 {128, 0, 128} // dark violet
152};
153
154#define STANDARD_PALETTE_SIZE (int(sizeof(standardPalette) / sizeof(*standardPalette)))
155
156static inline QColor standardColor(int i)
157{
158 const uchar *entry = standardPalette[i];
159 return QColor(entry[0], entry[1], entry[2]);
160}
161
162class KColorComboPrivate
163{
164public:
165 KColorComboPrivate(KColorCombo *qq);
166
167 void addColors();
168 void setCustomColor(const QColor &color, bool lookupInPresets = true);
169
170 // slots
171 void slotActivated(int index);
172 void slotHighlighted(int index);
173
174 KColorCombo *q;
175 QList<QColor> colorList;
176 QColor customColor;
177 QColor internalcolor;
178};
179
180KColorComboPrivate::KColorComboPrivate(KColorCombo *qq)
181 : q(qq)
182 , customColor(Qt::white)
183{
184}
185
186void KColorComboPrivate::setCustomColor(const QColor &color, bool lookupInPresets)
187{
188 if (lookupInPresets) {
189 if (colorList.isEmpty()) {
190 for (int i = 0; i < STANDARD_PALETTE_SIZE; ++i) {
191 if (standardColor(i) == color) {
192 q->setCurrentIndex(i + 1);
193 internalcolor = color;
194 return;
195 }
196 }
197 } else {
198 int i = colorList.indexOf(color);
199 if (i >= 0) {
200 q->setCurrentIndex(i + 1);
201 internalcolor = color;
202 return;
203 }
204 }
205 }
206
207 internalcolor = color;
208 customColor = color;
209 q->setItemData(0, customColor, KColorComboDelegate::ColorRole);
210}
211
213 : QComboBox(parent)
214 , d(new KColorComboPrivate(this))
215{
216 setItemDelegate(new KColorComboDelegate(this));
217 d->addColors();
218
219 connect(this, &QComboBox::activated, this, [this](int index) {
220 d->slotActivated(index);
221 });
222 connect(this, &QComboBox::highlighted, this, [this](int index) {
223 d->slotHighlighted(index);
224 });
225
226 // select the white color
228 d->slotActivated(1);
229
231}
232
233KColorCombo::~KColorCombo() = default;
234
236{
237 clear();
238 d->colorList = colors;
239 d->addColors();
240}
241
242QList<QColor> KColorCombo::colors() const
243{
244 if (d->colorList.isEmpty()) {
245 QList<QColor> list;
246 list.reserve(STANDARD_PALETTE_SIZE);
247 for (int i = 0; i < STANDARD_PALETTE_SIZE; ++i) {
248 list += standardColor(i);
249 }
250 return list;
251 } else {
252 return d->colorList;
253 }
254}
255
257{
258 if (!col.isValid()) {
259 return;
260 }
261
262 if (count() == 0) {
263 d->addColors();
264 }
265
266 d->setCustomColor(col, true);
267}
268
269QColor KColorCombo::color() const
270{
271 return d->internalcolor;
272}
273
275{
276 return d->internalcolor == d->customColor;
277}
278
279void KColorCombo::paintEvent(QPaintEvent *event)
280{
282 QStylePainter painter(this);
283 painter.setPen(palette().color(QPalette::Text));
284
287 painter.drawComplexControl(QStyle::CC_ComboBox, opt);
288
291 painter.setPen(Qt::transparent);
292 painter.setBrush(QBrush(d->internalcolor));
293 painter.drawRoundedRect(frame.adjusted(1, 1, -1, -1), 2, 2);
294}
295
297{
298 clear();
299}
300
301void KColorComboPrivate::slotActivated(int index)
302{
303 if (index == 0) {
304 QColor c = QColorDialog::getColor(customColor, q);
305 if (c.isValid()) {
306 customColor = c;
307 setCustomColor(customColor, false);
308 }
309 } else if (colorList.isEmpty()) {
310 internalcolor = standardColor(index - 1);
311 } else {
312 internalcolor = colorList[index - 1];
313 }
314
315 Q_EMIT q->activated(internalcolor);
316}
317
318void KColorComboPrivate::slotHighlighted(int index)
319{
320 if (index == 0) {
321 internalcolor = customColor;
322 } else if (colorList.isEmpty()) {
323 internalcolor = standardColor(index - 1);
324 } else {
325 internalcolor = colorList[index - 1];
326 }
327
328 Q_EMIT q->highlighted(internalcolor);
329}
330
331void KColorComboPrivate::addColors()
332{
333 q->addItem(KColorCombo::tr("Custom...", "@item:inlistbox Custom color"));
334
335 if (colorList.isEmpty()) {
336 for (int i = 0; i < STANDARD_PALETTE_SIZE; ++i) {
337 q->addItem(QString());
338 q->setItemData(i + 1, standardColor(i), KColorComboDelegate::ColorRole);
339 }
340 } else {
341 for (int i = 0, count = colorList.count(); i < count; ++i) {
342 q->addItem(QString());
343 q->setItemData(i + 1, colorList[i], KColorComboDelegate::ColorRole);
344 }
345 }
346}
347
348#include "kcolorcombo.moc"
349#include "moc_kcolorcombo.cpp"
Combobox for colors.
Definition kcolorcombo.h:35
void setColors(const QList< QColor > &colors)
Set a custom list of colors to choose from, in place of the standard list.
void showEmptyList()
Clear the color list and don't show it, till the next setColor() call.
KColorCombo(QWidget *parent=nullptr)
Constructs a color combo box.
void activated(const QColor &col)
Emitted when a new color box has been selected.
void setColor(const QColor &col)
Selects the color col.
bool isCustomColor() const
Find whether the currently selected color is a custom color selected using a color dialog.
void highlighted(const QColor &col)
Emitted when a new item has been highlighted.
QStyle * style()
Qt::BrushStyle style() const const
bool isValid() const const
QColor getColor(const QColor &initial, QWidget *parent, const QString &title, ColorDialogOptions options)
void activated(int index)
void addItem(const QIcon &icon, const QString &text, const QVariant &userData)
void clear()
void setCurrentIndex(int index)
virtual bool event(QEvent *event) override
void highlighted(int index)
virtual void initStyleOption(QStyleOptionComboBox *option) const const
void setMaxVisibleItems(int maxItems)
void setItemData(int index, const QVariant &value, int role)
void setItemDelegate(QAbstractItemDelegate *delegate)
qsizetype count() const const
qsizetype indexOf(const AT &value, qsizetype from) const const
bool isEmpty() const const
void reserve(qsizetype size)
QVariant data(int role) const const
Q_OBJECTQ_OBJECT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
T qobject_cast(QObject *object)
QString tr(const char *sourceText, const char *disambiguation, int n)
typedef RenderHints
void drawRoundedRect(const QRect &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
void drawText(const QPoint &position, const QString &text)
RenderHints renderHints() const const
void setBrush(Qt::BrushStyle style)
void setPen(Qt::PenStyle style)
void setRenderHint(RenderHint hint, bool on)
void setRenderHints(RenderHints hints, bool on)
PE_PanelItemViewItem
SC_ComboBoxEditField
virtual void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const=0
virtual QRect subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const const=0
UserRole
int userType() const const
T value() const const
QStyle * style() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:43 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.