File indexing completed on 2024-04-28 04:41:03

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