diff --git a/src/kcolorcombo.h b/src/kcolorcombo.h --- a/src/kcolorcombo.h +++ b/src/kcolorcombo.h @@ -28,6 +28,7 @@ #include #include +#include #include @@ -48,14 +49,18 @@ Q_OBJECT Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY activated USER true) Q_PROPERTY(QList colors READ colors WRITE setColors) + Q_PROPERTY(QList> namedColors READ namedColors WRITE setNamedColors) public: /** * Constructs a color combo box. */ explicit KColorCombo(QWidget *parent = nullptr); ~KColorCombo() override; + /** ColorList used in named colors list */ + using ColorList = QList>; + /** * Selects the color @p col. */ @@ -80,12 +85,34 @@ **/ void setColors(const QList &colors); + /** + * Set a custom list of named colors to choose from, in place of the + * standard list. + * @param colors list os named colors. If empty, the selection list + * reverts to the standard list. + **/ + void setNamedColors(const ColorList &colors); + + /** + * Inserts a named color at a specific position in the standard list. + * @param index position in the list + * @param namedColor name and color + **/ + void insertNamedColor(int index, const QPair &namedColor); + /** * Return the list of colors available for selection. * @return list of colors **/ QList colors() const; + /** + * Return the list of named colors available for selection. + * If list of named color is empty, returns named colors in hex format. + * @return list of named colors + **/ + QList> namedColors() const; + /** * Clear the color list and don't show it, till the next setColor() call **/ diff --git a/src/kcolorcombo.cpp b/src/kcolorcombo.cpp --- a/src/kcolorcombo.cpp +++ b/src/kcolorcombo.cpp @@ -45,18 +45,6 @@ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; -static QBrush k_colorcombodelegate_brush(const QModelIndex &index, int role) -{ - QBrush brush; - QVariant v = index.data(role); - if (v.type() == QVariant::Brush) { - brush = v.value(); - } else if (v.type() == QVariant::Color) { - brush = QBrush(v.value()); - } - return brush; -} - KColorComboDelegate::KColorComboDelegate(QObject *parent) : QAbstractItemDelegate(parent) { @@ -68,68 +56,54 @@ void KColorComboDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - // background - QColor innercolor(Qt::white); - bool isSelected = (option.state & QStyle::State_Selected); - bool paletteBrush = (k_colorcombodelegate_brush(index, Qt::BackgroundRole).style() == Qt::NoBrush); - if (isSelected) { - innercolor = option.palette.color(QPalette::Highlight); - } else { - innercolor = option.palette.color(QPalette::Base); - } // highlight selected item QStyleOptionViewItem opt(option); opt.showDecorationSelected = true; QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); - QRect innerrect = option.rect.adjusted(FrameMargin, FrameMargin, -FrameMargin, -FrameMargin); + QRect innerRect = option.rect.adjusted(FrameMargin, FrameMargin, -FrameMargin, -FrameMargin); + // inner color - QVariant cv = index.data(ColorRole); + const QVariant tv = index.data(Qt::DisplayRole); + const QVariant cv = index.data(ColorRole); + const QColor innerColor = ((cv.type() == QVariant::Color) ? cv.value() : QPalette::Base); + + auto textColor = [innerColor]() -> QColor { + auto luma = (0.299 * innerColor.red() + 0.587 * innerColor.green() + 0.114 * innerColor.blue()) / 255; + return luma > 0.5 ? Qt::black : Qt::white; + }; + // color if (cv.type() == QVariant::Color) { - QColor tmpcolor = cv.value(); - if (tmpcolor.isValid()) { - innercolor = tmpcolor; - paletteBrush = false; + const QColor tmpColor = cv.value(); + if (tmpColor.isValid()) { painter->setPen(Qt::transparent); - painter->setBrush(innercolor); + painter->setBrush(tmpColor); QPainter::RenderHints tmpHint = painter->renderHints(); painter->setRenderHint(QPainter::Antialiasing); - painter->drawRoundedRect(innerrect, 2, 2); + const QRect colorRect = tv.toString().isEmpty() ? innerRect : QRect(innerRect.x(), innerRect.y() + innerRect.height() / 2, innerRect.width(), innerRect.height() / 2); + painter->drawRoundedRect(colorRect, 2, 2); + painter->setPen(textColor()); + painter->drawText(colorRect, tmpColor.name()); painter->setRenderHints(tmpHint); painter->setBrush(Qt::NoBrush); } } // text - QVariant tv = index.data(Qt::DisplayRole); if (tv.type() == QVariant::String) { QString text = tv.toString(); - QColor textColor; - if (paletteBrush) { - if (isSelected) { - textColor = option.palette.color(QPalette::HighlightedText); - } else { - textColor = option.palette.color(QPalette::Text); - } - } else { - int unused, v; - innercolor.getHsv(&unused, &unused, &v); - if (v > 128) { - textColor = Qt::black; - } else { - textColor = Qt::white; - } - } - painter->setPen(textColor); - painter->drawText(innerrect.adjusted(1, 1, -1, -1), text); + painter->setPen(Qt::black); + painter->drawText(innerRect.adjusted(1, 1, -1, -1), text); } } QSize KColorComboDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(index) // the width does not matter, as the view will always use the maximum width available - return QSize(100, option.fontMetrics.height() + 2 * FrameMargin); + const QVariant displayValue = index.model()->data(index); + const double height = option.fontMetrics.height() * (!displayValue.toString().isEmpty() ? 2 : 1) + 2 * FrameMargin; + return QSize(100, height); } static const uchar standardPalette[][4] = { @@ -183,7 +157,7 @@ void _k_slotHighlighted(int index); KColorCombo *q; - QList colorList; + KColorCombo::ColorList colorList; QColor customColor; QColor internalcolor; }; @@ -205,11 +179,12 @@ } } } else { - int i = colorList.indexOf(color); - if (i >= 0) { - q->setCurrentIndex(i + 1); - internalcolor = color; - return; + for (int i = 0; i < colorList.count(); ++i) { + if (colorList[i].second == color) { + q->setCurrentIndex(i + 1); + internalcolor = color; + return; + } } } } @@ -241,24 +216,57 @@ } void KColorCombo::setColors(const QList &colors) +{ + ColorList namedColors; + namedColors.reserve(colors.size()); + for (auto color : colors) { + namedColors.append({QString(), color}); + } + setNamedColors(namedColors); +} + +void KColorCombo::setNamedColors(const ColorList &colors) { clear(); d->colorList = colors; d->addColors(); } +void KColorCombo::insertNamedColor(int index, const QPair &namedColor) +{ + ColorList namedColorList = namedColors(); + namedColorList.insert(index, namedColor); + setNamedColors(namedColorList); +} + QList KColorCombo::colors() const { + QList list; if (d->colorList.isEmpty()) { - QList list; list.reserve(STANDARD_PALETTE_SIZE); for (int i = 0; i < STANDARD_PALETTE_SIZE; ++i) { list += standardColor(i); } return list; } else { - return d->colorList; + list.reserve(d->colorList.size()); + for (auto color : d->colorList) { + list.append({color.second}); + } + } + return list; +} + +QList> KColorCombo::namedColors() const +{ + if (d->colorList.isEmpty()) { + ColorList list; + for (int index = 0; index < STANDARD_PALETTE_SIZE; ++index) { + list += {QString(), standardColor(index)}; + } + return list; } + return d->colorList; } void KColorCombo::setColor(const QColor &col) @@ -317,7 +325,7 @@ } else if (colorList.isEmpty()) { internalcolor = standardColor(index - 1); } else { - internalcolor = colorList[index - 1]; + internalcolor = colorList[index - 1].second; } emit q->activated(internalcolor); @@ -330,25 +338,27 @@ } else if (colorList.isEmpty()) { internalcolor = standardColor(index - 1); } else { - internalcolor = colorList[index - 1]; + internalcolor = colorList[index - 1].second; } emit q->highlighted(internalcolor); } void KColorComboPrivate::addColors() { q->addItem(KColorCombo::tr("Custom...", "Custom color")); - if (colorList.isEmpty()) { for (int i = 0; i < STANDARD_PALETTE_SIZE; ++i) { q->addItem(QString()); q->setItemData(i + 1, standardColor(i), KColorComboDelegate::ColorRole); } } else { for (int i = 0, count = colorList.count(); i < count; ++i) { q->addItem(QString()); - q->setItemData(i + 1, colorList[i], KColorComboDelegate::ColorRole); + q->setItemData(i + 1, colorList[i].second, KColorComboDelegate::ColorRole); + if (!colorList[i].first.isEmpty()) { + q->setItemData(i + 1, colorList[i].first, Qt::DisplayRole); + } } } } diff --git a/tests/kcolorcombotest.cpp b/tests/kcolorcombotest.cpp --- a/tests/kcolorcombotest.cpp +++ b/tests/kcolorcombotest.cpp @@ -95,6 +95,10 @@ qCritical() << "Custom combo: setColors() != colors()"; } + mCustom->insertNamedColor(1, {QStringLiteral("information 1"), Qt::red}); + mCustom->insertNamedColor(4, {QStringLiteral("information 2"), Qt::blue}); + mCustom->insertNamedColor(7, {QStringLiteral("information 3"), Qt::gray}); + if (mStandard->colors() != standardList) { qCritical() << "Standard combo: colors()"; }