File indexing completed on 2025-02-02 14:19:58
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 1997 Martin Jones <mjones@kde.org> 0004 SPDX-FileCopyrightText: 2007 Pino Toscano <pino@kde.org> 0005 SPDX-FileCopyrightText: 2007 David Jarvie <djarvie@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "kcolorcombo.h" 0011 0012 #include <QAbstractItemDelegate> 0013 #include <QApplication> 0014 #include <QColorDialog> 0015 #include <QStylePainter> 0016 0017 class KColorComboDelegate : public QAbstractItemDelegate 0018 { 0019 Q_OBJECT 0020 public: 0021 enum ItemRoles { 0022 ColorRole = Qt::UserRole + 1, 0023 }; 0024 0025 enum LayoutMetrics { 0026 FrameMargin = 3, 0027 }; 0028 0029 KColorComboDelegate(QObject *parent = nullptr); 0030 ~KColorComboDelegate() override; 0031 0032 void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; 0033 QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; 0034 }; 0035 0036 static QBrush k_colorcombodelegate_brush(const QModelIndex &index, int role) 0037 { 0038 QBrush brush; 0039 QVariant v = index.data(role); 0040 if (v.type() == QVariant::Brush) { 0041 brush = v.value<QBrush>(); 0042 } else if (v.type() == QVariant::Color) { 0043 brush = QBrush(v.value<QColor>()); 0044 } 0045 return brush; 0046 } 0047 0048 KColorComboDelegate::KColorComboDelegate(QObject *parent) 0049 : QAbstractItemDelegate(parent) 0050 { 0051 } 0052 0053 KColorComboDelegate::~KColorComboDelegate() 0054 { 0055 } 0056 0057 void KColorComboDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const 0058 { 0059 // background 0060 QColor innercolor(Qt::white); 0061 bool isSelected = (option.state & QStyle::State_Selected); 0062 bool paletteBrush = (k_colorcombodelegate_brush(index, Qt::BackgroundRole).style() == Qt::NoBrush); 0063 if (isSelected) { 0064 innercolor = option.palette.color(QPalette::Highlight); 0065 } else { 0066 innercolor = option.palette.color(QPalette::Base); 0067 } 0068 // highlight selected item 0069 QStyleOptionViewItem opt(option); 0070 opt.showDecorationSelected = true; 0071 QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); 0072 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); 0073 QRect innerrect = option.rect.adjusted(FrameMargin, FrameMargin, -FrameMargin, -FrameMargin); 0074 // inner color 0075 QVariant cv = index.data(ColorRole); 0076 if (cv.type() == QVariant::Color) { 0077 QColor tmpcolor = cv.value<QColor>(); 0078 if (tmpcolor.isValid()) { 0079 innercolor = tmpcolor; 0080 paletteBrush = false; 0081 painter->setPen(Qt::transparent); 0082 painter->setBrush(innercolor); 0083 QPainter::RenderHints tmpHint = painter->renderHints(); 0084 painter->setRenderHint(QPainter::Antialiasing); 0085 painter->drawRoundedRect(innerrect, 2, 2); 0086 painter->setRenderHints(tmpHint); 0087 painter->setBrush(Qt::NoBrush); 0088 } 0089 } 0090 // text 0091 QVariant tv = index.data(Qt::DisplayRole); 0092 if (tv.type() == QVariant::String) { 0093 QString text = tv.toString(); 0094 QColor textColor; 0095 if (paletteBrush) { 0096 if (isSelected) { 0097 textColor = option.palette.color(QPalette::HighlightedText); 0098 } else { 0099 textColor = option.palette.color(QPalette::Text); 0100 } 0101 } else { 0102 int unused; 0103 int v; 0104 innercolor.getHsv(&unused, &unused, &v); 0105 if (v > 128) { 0106 textColor = Qt::black; 0107 } else { 0108 textColor = Qt::white; 0109 } 0110 } 0111 painter->setPen(textColor); 0112 painter->drawText(innerrect.adjusted(1, 1, -1, -1), text); 0113 } 0114 } 0115 0116 QSize KColorComboDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const 0117 { 0118 Q_UNUSED(index) 0119 0120 // the width does not matter, as the view will always use the maximum width available 0121 return QSize(100, option.fontMetrics.height() + 2 * FrameMargin); 0122 } 0123 0124 static const uchar standardPalette[][4] = { 0125 {255, 255, 255}, // white 0126 {192, 192, 192}, // light gray 0127 {160, 160, 160}, // gray 0128 {128, 128, 128}, // dark gray 0129 {0, 0, 0}, // black 0130 0131 {255, 128, 128}, // light red 0132 {255, 192, 128}, // light orange 0133 {255, 255, 128}, // light yellow 0134 {128, 255, 128}, // light green 0135 {128, 255, 255}, // cyan blue 0136 {128, 128, 255}, // light blue 0137 {255, 128, 255}, // light violet 0138 {255, 0, 0}, // red 0139 {255, 128, 0}, // orange 0140 {255, 255, 0}, // yellow 0141 {0, 255, 0}, // green 0142 {0, 255, 255}, // light blue 0143 {0, 0, 255}, // blue 0144 {255, 0, 255}, // violet 0145 {128, 0, 0}, // dark red 0146 {128, 64, 0}, // dark orange 0147 {128, 128, 0}, // dark yellow 0148 {0, 128, 0}, // dark green 0149 {0, 128, 128}, // dark light blue 0150 {0, 0, 128}, // dark blue 0151 {128, 0, 128} // dark violet 0152 }; 0153 0154 #define STANDARD_PALETTE_SIZE (int(sizeof(standardPalette) / sizeof(*standardPalette))) 0155 0156 static inline QColor standardColor(int i) 0157 { 0158 const uchar *entry = standardPalette[i]; 0159 return QColor(entry[0], entry[1], entry[2]); 0160 } 0161 0162 class KColorComboPrivate 0163 { 0164 public: 0165 KColorComboPrivate(KColorCombo *qq); 0166 0167 void addColors(); 0168 void setCustomColor(const QColor &color, bool lookupInPresets = true); 0169 0170 // slots 0171 void slotActivated(int index); 0172 void slotHighlighted(int index); 0173 0174 KColorCombo *q; 0175 QList<QColor> colorList; 0176 QColor customColor; 0177 QColor internalcolor; 0178 }; 0179 0180 KColorComboPrivate::KColorComboPrivate(KColorCombo *qq) 0181 : q(qq) 0182 , customColor(Qt::white) 0183 { 0184 } 0185 0186 void KColorComboPrivate::setCustomColor(const QColor &color, bool lookupInPresets) 0187 { 0188 if (lookupInPresets) { 0189 if (colorList.isEmpty()) { 0190 for (int i = 0; i < STANDARD_PALETTE_SIZE; ++i) { 0191 if (standardColor(i) == color) { 0192 q->setCurrentIndex(i + 1); 0193 internalcolor = color; 0194 return; 0195 } 0196 } 0197 } else { 0198 int i = colorList.indexOf(color); 0199 if (i >= 0) { 0200 q->setCurrentIndex(i + 1); 0201 internalcolor = color; 0202 return; 0203 } 0204 } 0205 } 0206 0207 internalcolor = color; 0208 customColor = color; 0209 q->setItemData(0, customColor, KColorComboDelegate::ColorRole); 0210 } 0211 0212 KColorCombo::KColorCombo(QWidget *parent) 0213 : QComboBox(parent) 0214 , d(new KColorComboPrivate(this)) 0215 { 0216 setItemDelegate(new KColorComboDelegate(this)); 0217 d->addColors(); 0218 0219 connect(this, qOverload<int>(&QComboBox::activated), this, [this](int index) { 0220 d->slotActivated(index); 0221 }); 0222 connect(this, qOverload<int>(&QComboBox::highlighted), this, [this](int index) { 0223 d->slotHighlighted(index); 0224 }); 0225 0226 // select the white color 0227 setCurrentIndex(1); 0228 d->slotActivated(1); 0229 0230 setMaxVisibleItems(13); 0231 } 0232 0233 KColorCombo::~KColorCombo() = default; 0234 0235 void KColorCombo::setColors(const QList<QColor> &colors) 0236 { 0237 clear(); 0238 d->colorList = colors; 0239 d->addColors(); 0240 } 0241 0242 QList<QColor> KColorCombo::colors() const 0243 { 0244 if (d->colorList.isEmpty()) { 0245 QList<QColor> list; 0246 list.reserve(STANDARD_PALETTE_SIZE); 0247 for (int i = 0; i < STANDARD_PALETTE_SIZE; ++i) { 0248 list += standardColor(i); 0249 } 0250 return list; 0251 } else { 0252 return d->colorList; 0253 } 0254 } 0255 0256 void KColorCombo::setColor(const QColor &col) 0257 { 0258 if (!col.isValid()) { 0259 return; 0260 } 0261 0262 if (count() == 0) { 0263 d->addColors(); 0264 } 0265 0266 d->setCustomColor(col, true); 0267 } 0268 0269 QColor KColorCombo::color() const 0270 { 0271 return d->internalcolor; 0272 } 0273 0274 bool KColorCombo::isCustomColor() const 0275 { 0276 return d->internalcolor == d->customColor; 0277 } 0278 0279 void KColorCombo::paintEvent(QPaintEvent *event) 0280 { 0281 Q_UNUSED(event) 0282 QStylePainter painter(this); 0283 painter.setPen(palette().color(QPalette::Text)); 0284 0285 QStyleOptionComboBox opt; 0286 initStyleOption(&opt); 0287 painter.drawComplexControl(QStyle::CC_ComboBox, opt); 0288 0289 QRect frame = style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this); 0290 painter.setRenderHint(QPainter::Antialiasing); 0291 painter.setPen(Qt::transparent); 0292 painter.setBrush(QBrush(d->internalcolor)); 0293 painter.drawRoundedRect(frame.adjusted(1, 1, -1, -1), 2, 2); 0294 } 0295 0296 void KColorCombo::showEmptyList() 0297 { 0298 clear(); 0299 } 0300 0301 void KColorComboPrivate::slotActivated(int index) 0302 { 0303 if (index == 0) { 0304 QColor c = QColorDialog::getColor(customColor, q); 0305 if (c.isValid()) { 0306 customColor = c; 0307 setCustomColor(customColor, false); 0308 } 0309 } else if (colorList.isEmpty()) { 0310 internalcolor = standardColor(index - 1); 0311 } else { 0312 internalcolor = colorList[index - 1]; 0313 } 0314 0315 Q_EMIT q->activated(internalcolor); 0316 } 0317 0318 void KColorComboPrivate::slotHighlighted(int index) 0319 { 0320 if (index == 0) { 0321 internalcolor = customColor; 0322 } else if (colorList.isEmpty()) { 0323 internalcolor = standardColor(index - 1); 0324 } else { 0325 internalcolor = colorList[index - 1]; 0326 } 0327 0328 Q_EMIT q->highlighted(internalcolor); 0329 } 0330 0331 void KColorComboPrivate::addColors() 0332 { 0333 q->addItem(KColorCombo::tr("Custom...", "@item:inlistbox Custom color")); 0334 0335 if (colorList.isEmpty()) { 0336 for (int i = 0; i < STANDARD_PALETTE_SIZE; ++i) { 0337 q->addItem(QString()); 0338 q->setItemData(i + 1, standardColor(i), KColorComboDelegate::ColorRole); 0339 } 0340 } else { 0341 for (int i = 0, count = colorList.count(); i < count; ++i) { 0342 q->addItem(QString()); 0343 q->setItemData(i + 1, colorList[i], KColorComboDelegate::ColorRole); 0344 } 0345 } 0346 } 0347 0348 #include "kcolorcombo.moc" 0349 #include "moc_kcolorcombo.cpp"