File indexing completed on 2024-04-21 05:48:17

0001 /**
0002  * SPDX-FileCopyrightText: (C) 2005 Sébastien Laoût <slaout@linux62.org>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kcolorcombo2.h"
0008 
0009 #ifndef USE_OLD_KCOLORCOMBO
0010 
0011 #include <QApplication>
0012 #include <QtGui/QBitmap>
0013 #include <QtGui/QPainter>
0014 #include <QtGui/QPixmap>
0015 
0016 #include <QColorDialog>
0017 #include <QDesktopWidget>
0018 #include <QDrag>
0019 #include <QLocale>
0020 #include <QMimeData>
0021 #include <QtGui/QClipboard>
0022 #include <QtGui/QDragEnterEvent>
0023 #include <QtGui/QDropEvent>
0024 #include <QtGui/QKeyEvent>
0025 #include <QtGui/QMouseEvent>
0026 #include <QtGui/QPaintEvent>
0027 
0028 #include <KLocalizedString>
0029 #include <KStandardShortcut>
0030 
0031 //#define DEBUG_COLOR_ARRAY
0032 //#define OUTPUT_GIMP_PALETTE
0033 
0034 /** class KColorPopup: */
0035 
0036 const int KColorPopup::MARGIN = 1;
0037 const int KColorPopup::FRAME_WIDTH = 1;
0038 
0039 KColorPopup::KColorPopup(KColorCombo2 *parent)
0040     : QWidget(/*parent=*/nullptr, Qt::Popup)
0041     , m_selector(parent)
0042     , m_pixmap(nullptr)
0043 {
0044     hide();
0045     setMouseTracking(true);
0046     // resize(20, 20);
0047 }
0048 
0049 KColorPopup::~KColorPopup()
0050 {
0051     delete m_pixmap;
0052 }
0053 
0054 #include <qcursor.h>
0055 
0056 void KColorPopup::relayout() // FIXME: relayout should NOT redraw the pixmap!
0057 {
0058     int columnCount = m_selector->columnCount();
0059     int rowCount = m_selector->rowCount();
0060     int colorHeight = m_selector->colorRectHeight();
0061     int colorWidth = m_selector->colorRectWidthForHeight(colorHeight);
0062     bool haveDefault = m_selector->defaultColor().isValid();
0063 
0064     int width = 2 + MARGIN + (colorWidth + MARGIN) * columnCount;
0065     int height = 2 + MARGIN + (colorHeight + MARGIN) * rowCount + (colorHeight + MARGIN);
0066 
0067     resize(width, height);
0068 
0069     // Initialize the pixmap:
0070     delete m_pixmap;
0071     m_pixmap = new QPixmap(width, height);
0072     QPainter painter(m_pixmap);
0073     painter.fillRect(0, 0, width, height, palette().color(QPalette::Base));
0074     painter.setPen(palette().color(QPalette::Text));
0075     painter.drawRect(0, 0, width, height);
0076 
0077     // Needed to draw:
0078     int x, y;
0079     QRect selectionRect;
0080 
0081     // Draw the color array:
0082     for (int i = 0; i < columnCount; ++i) {
0083         for (int j = 0; j < rowCount; ++j) {
0084             x = 1 + MARGIN + (colorWidth + MARGIN) * i;
0085             y = 1 + MARGIN + (colorHeight + MARGIN) * j;
0086             if (i == m_selectedColumn && j == m_selectedRow) {
0087                 selectionRect = QRect(x - 2, y - 2, colorWidth + 4, colorHeight + 4);
0088                 painter.fillRect(selectionRect, palette().color(QPalette::Highlight));
0089             }
0090             m_selector->drawColorRect(painter, x, y, m_selector->colorAt(i, j), /*isDefault=*/false, colorWidth, colorHeight);
0091         }
0092     }
0093 
0094     m_columnOther = (haveDefault ? columnCount / 2 : 0); // "(Default)" is allowed, paint "Other..." on the right
0095     int defaultCellWidth = (colorWidth + MARGIN) * m_columnOther;
0096     int otherCellWidth = (colorWidth + MARGIN) * (columnCount - m_columnOther);
0097 
0098     // Draw the "(Default)" and "Other..." colors:
0099     y = height - (colorHeight + MARGIN) - 1;
0100     QColor textColor;
0101     if (m_selector->defaultColor().isValid()) {
0102         x = 1 + MARGIN;
0103         if (m_selectedColumn < m_columnOther && rowCount == m_selectedRow) {
0104             selectionRect = QRect(x - 2, y - 2, defaultCellWidth, colorHeight + 4);
0105             painter.fillRect(selectionRect, palette().color(QPalette::Highlight));
0106             textColor = palette().color(QPalette::HighlightedText);
0107         } else
0108             textColor = palette().color(QPalette::Text);
0109         m_selector->drawColorRect(painter, x, y, m_selector->defaultColor(), /*isDefault=*/true, colorWidth, colorHeight);
0110         painter.setFont(m_selector->font());
0111         painter.setPen(textColor);
0112         painter.drawText(x + 2 + colorWidth, y, /*width=*/5000, colorHeight, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip, i18n("(Default)"));
0113     }
0114     x = 1 + MARGIN + m_columnOther * (colorWidth + MARGIN);
0115     if (m_selectedColumn >= m_columnOther && rowCount == m_selectedRow) {
0116         selectionRect = QRect(x - 2, y - 2, otherCellWidth, colorHeight + 4);
0117         painter.fillRect(selectionRect, palette().color(QPalette::Highlight));
0118         textColor = palette().color(QPalette::HighlightedText);
0119     } else
0120         textColor = palette().color(QPalette::Text);
0121     m_selector->drawColorRect(painter, x, y, m_otherColor, /*isDefault=*/false, colorWidth, colorHeight);
0122     painter.setFont(m_selector->font());
0123     painter.setPen(textColor);
0124     painter.drawText(x + 2 + colorWidth, y, /*width=*/5000, colorHeight, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip, i18n("Other..."));
0125 
0126     //  QPoint pos = mapFromGlobal(QCursor::pos());
0127     //  painter.drawRect(pos.x(), pos.y(), 5000, 5000);
0128 }
0129 
0130 void KColorPopup::updateCell(int column, int row)
0131 {
0132     int colorHeight = m_selector->colorRectHeight();
0133     int colorWidth = m_selector->colorRectWidthForHeight(colorHeight);
0134 
0135     int x = 1 + MARGIN + -2 + column * (colorWidth + MARGIN);
0136     int y = 1 + MARGIN + -2 + row * (colorHeight + MARGIN);
0137     int width = colorWidth + MARGIN;
0138     int height = colorHeight + MARGIN;
0139 
0140     if (row == m_selector->rowCount()) {
0141         if (m_selectedColumn < m_columnOther) // The "(Default)" cell:
0142             width = (colorWidth + MARGIN) * m_columnOther;
0143         else // The "Other..." cell:
0144             width = (colorWidth + MARGIN) * (m_selector->columnCount() - m_columnOther);
0145     }
0146 
0147     update(x, y, width, height);
0148 }
0149 
0150 void KColorPopup::doSelection()
0151 {
0152     m_otherColor = QColor();
0153 
0154     // If the selected color is not the default one, try to find it in the array:
0155     if (m_selector->color().isValid()) {
0156         bool isInArray = false;
0157         for (int column = 0; column < m_selector->columnCount(); ++column)
0158             for (int row = 0; row < m_selector->rowCount(); ++row)
0159                 if (m_selector->color() == m_selector->colorAt(column, row)) {
0160                     m_selectedColumn = column;
0161                     m_selectedRow = row;
0162                     isInArray = true;
0163                 }
0164         // If not found in array, it's another one:
0165         if (!isInArray) {
0166             m_selectedColumn = m_columnOther;
0167             m_selectedRow = m_selector->rowCount();
0168             m_otherColor = m_selector->color();
0169         }
0170         // If it's the default one:
0171     } else {
0172         m_selectedColumn = 0;
0173         m_selectedRow = m_selector->rowCount();
0174     }
0175 }
0176 
0177 void KColorPopup::validate()
0178 {
0179     hide();
0180     close();
0181     Q_EMIT closed();
0182 
0183     if (m_selectedRow != m_selector->rowCount()) // A normal row:
0184         m_selector->setColor(m_selector->colorAt(m_selectedColumn, m_selectedRow));
0185     else if (m_selectedColumn < m_columnOther) // The default color:
0186         m_selector->setColor(QColor());
0187     else { // The user want to choose one:
0188         QColor color = m_selector->effectiveColor();
0189         color = QColorDialog::getColor(color, this);
0190         if (color.isValid())
0191             m_selector->setColor(color);
0192     }
0193 }
0194 
0195 void KColorPopup::mousePressEvent(QMouseEvent *event)
0196 {
0197     int x = event->pos().x();
0198     int y = event->pos().y();
0199     if (x < 0 || y < 0 || x >= width() || y >= height()) {
0200         hide();
0201         close();
0202         Q_EMIT closed();
0203     } else
0204         validate();
0205 
0206     event->accept();
0207 }
0208 
0209 void KColorPopup::paintEvent(QPaintEvent *event)
0210 {
0211     QPainter painter(this);
0212     if (m_pixmap)
0213         painter.drawPixmap(0, 0, *m_pixmap);
0214     painter.setPen(Qt::black);
0215     painter.drawRect(event->rect());
0216 }
0217 
0218 void KColorPopup::mouseMoveEvent(QMouseEvent *event)
0219 {
0220     int x = event->pos().x();
0221     int y = event->pos().y();
0222     if (x < FRAME_WIDTH + 2 || y < FRAME_WIDTH + 2 || x > width() - 2 - 2 * FRAME_WIDTH || y > height() - 2 - 2 * FRAME_WIDTH)
0223         return;
0224 
0225     int colorHeight = m_selector->colorRectHeight();
0226     int colorWidth = m_selector->colorRectWidthForHeight(colorHeight);
0227 
0228     //  int oldSelectedColumn = m_selectedColumn;
0229     //  int oldSelectedRow    = m_selectedRow;
0230     m_selectedColumn = (x - FRAME_WIDTH - MARGIN + 2) / (colorWidth + MARGIN);
0231     m_selectedRow = (y - FRAME_WIDTH - MARGIN + 2) / (colorHeight + MARGIN);
0232 
0233     relayout();
0234     update();
0235 }
0236 
0237 void KColorPopup::keyPressEvent(QKeyEvent *event)
0238 {
0239     int column = m_selectedColumn;
0240     int row = m_selectedRow;
0241     int columnCount = m_selector->columnCount();
0242     int rowCount = m_selector->rowCount();
0243 
0244     switch (event->key()) {
0245     case Qt::Key_Right:
0246         if (m_selectedRow != rowCount) // A normal row:
0247             column = (column + 1) % columnCount;
0248         else {
0249             // The last row, if there are two choices, switch. Else, do nothing:
0250             if (m_selector->defaultColor().isValid())
0251                 column = (m_selectedColumn < m_columnOther ? m_columnOther : 0);
0252         }
0253         break;
0254     case Qt::Key_Left:
0255         if (m_selectedRow != rowCount) { // A normal row:
0256             column = (column - 1);
0257             if (column < 0)
0258                 column = columnCount - 1;
0259         } else {
0260             // The last row, if there are two choices, switch. Else, do nothing:
0261             if (m_selector->defaultColor().isValid())
0262                 column = (m_selectedColumn < m_columnOther ? m_columnOther : 0);
0263         }
0264         break;
0265     case Qt::Key_Up:
0266         row = (row - 1);
0267         if (row < 0)
0268             row = rowCount;
0269         break;
0270     case Qt::Key_Down:
0271         row = (row + 1) % (rowCount + 1);
0272         break;
0273     case Qt::Key_PageDown:
0274         row += 10;
0275         if (row > rowCount)
0276             row = rowCount;
0277         break;
0278     case Qt::Key_PageUp:
0279         row -= 10;
0280         if (row < 0)
0281             row = 0;
0282         break;
0283     case Qt::Key_Home:
0284         row = 0;
0285         column = 0;
0286         break;
0287     case Qt::Key_End:
0288         row = rowCount;
0289         column = columnCount - 1;
0290         break;
0291     case Qt::Key_Return:
0292         validate();
0293         break;
0294     default:
0295         QWidget::keyPressEvent(event);
0296     }
0297 
0298     if (row != m_selectedRow || column != m_selectedColumn) {
0299         m_selectedRow = row;
0300         m_selectedColumn = column;
0301         relayout();
0302         update();
0303     }
0304 }
0305 
0306 /** Helper function: */
0307 
0308 QColor Tool_mixColors(const QColor &color1, const QColor &color2)
0309 {
0310     QColor mixedColor;
0311     mixedColor.setRgb((color1.red() + color2.red()) / 2, (color1.green() + color2.green()) / 2, (color1.blue() + color2.blue()) / 2);
0312     return mixedColor;
0313 }
0314 
0315 /** class KColorCombo2Private */
0316 
0317 class KColorCombo2::KColorCombo2Private
0318 {
0319 };
0320 
0321 /** class KColorCombo2: */
0322 
0323 /* All code for the popup management (including the constructor, popup() and eventFilter())
0324  * has been copied from the KDateEdit widget (in libkdepim).
0325  *
0326  * Some other piece of code comes from KColorButton (in libkdeui) to enable color drag, drop, copy and paste.
0327  */
0328 
0329 KColorCombo2::KColorCombo2(const QColor &color, const QColor &defaultColor, QWidget *parent)
0330     : KComboBox(parent)
0331     , m_color(color)
0332     , m_defaultColor(defaultColor)
0333 {
0334     setEditable(false);
0335     init();
0336 }
0337 
0338 KColorCombo2::KColorCombo2(const QColor &color, QWidget *parent)
0339     : KComboBox(parent)
0340     , m_color(color)
0341     , m_defaultColor()
0342 {
0343     setEditable(false);
0344     init();
0345 }
0346 
0347 void KColorCombo2::init()
0348 {
0349     m_colorArray = nullptr;
0350     d = new KColorCombo2Private();
0351 
0352     setDefaultColor(m_defaultColor);
0353     insertItem(/*index=*/0, QString());
0354     updateComboBox(); // It need an item of index 0 to exists, so we created it.
0355     setAcceptDrops(true);
0356 
0357     m_popup = new KColorPopup(this);
0358     m_popup->installEventFilter(this);
0359     connect(m_popup, &KColorPopup::closed, this, &KColorCombo2::popupClosed);
0360 
0361     // By default, the array is filled with setRainbowPreset().
0362     // But we allocate it on demand (the later as possible) to avoid performances issues if the developer set another array.
0363     // However, to keep columnCount() rowCount() const, we define theme here:
0364     m_columnCount = 13;
0365     m_rowCount = 9;
0366 }
0367 
0368 KColorCombo2::~KColorCombo2()
0369 {
0370     deleteColorArray();
0371 }
0372 
0373 void KColorCombo2::setColor(const QColor &color)
0374 {
0375     // Do nothing if the color should be set to the default one and there is no such default color allowed:
0376     if (!color.isValid() && !m_defaultColor.isValid()) {
0377         // kdebug << this::FUNCTION << "Trying to assign the default color (an invalid one) whereas no such default color is allowed";
0378         return;
0379     }
0380 
0381     if (m_color != color) {
0382         m_color = color;
0383         updateComboBox();
0384         Q_EMIT colorChanged(color);
0385     }
0386 }
0387 
0388 QColor KColorCombo2::color() const
0389 {
0390     return m_color;
0391 }
0392 
0393 QColor KColorCombo2::effectiveColor() const
0394 {
0395     if (m_color.isValid())
0396         return m_color;
0397     else
0398         return m_defaultColor;
0399 }
0400 
0401 void KColorCombo2::setRainbowPreset(int colorColumnCount, int lightRowCount, int darkRowCount, bool withGray)
0402 {
0403     // At least one row and one column:
0404     if (colorColumnCount < 1 - (withGray ? 1 : 0))
0405         colorColumnCount = 1 - (withGray ? 1 : 0);
0406     if (lightRowCount < 0)
0407         lightRowCount = 0;
0408     if (darkRowCount < 0)
0409         darkRowCount = 0;
0410 
0411     // Create the array:
0412     int columnCount = colorColumnCount + (withGray ? 1 : 0);
0413     int rowCount = lightRowCount + 1 + darkRowCount;
0414     newColorArray(columnCount, rowCount);
0415 
0416     // Fill the array:
0417     for (int i = 0; i < colorColumnCount; ++i) {
0418         int hue = i * 360 / colorColumnCount;
0419         // With light colors:
0420         for (int j = 1; j <= lightRowCount; ++j) { // Start to 1 because we don't want a row full of white!
0421             int saturation = j * 255 / (lightRowCount + 1);
0422             setColorAt(i, j - 1, QColor::fromHsv(hue, saturation, 255));
0423         }
0424         // With pure colors:
0425         setColorAt(i, lightRowCount, QColor::fromHsv(hue, 255, 255));
0426         // With dark colors:
0427         for (int j = 1; j <= darkRowCount; ++j) {
0428             int value = 255 - j * 255 / (darkRowCount + 1);
0429             setColorAt(i, lightRowCount + j, QColor::fromHsv(hue, 255, value));
0430         }
0431     }
0432 
0433     // Fill the gray column:
0434     if (withGray) {
0435         for (int i = 0; i < rowCount; ++i) {
0436             int gray = (rowCount == 1 ? 128 : 255 - (i * 255 / (rowCount - 1)));
0437             setColorAt(columnCount - 1, i, QColor(gray, gray, gray));
0438         }
0439     }
0440 
0441 #ifdef DEBUG_COLOR_ARRAY
0442     qDebug() << "KColorCombo2::setColorPreset";
0443     for (int j = 0; j < rowCount; ++j) {
0444         for (int i = 0; i < columnCount; ++i) {
0445             int h, s, v;
0446             m_colorArray[i][j].getHsv(&h, &s, &v);
0447             qDebug() << QString("(%1,%2,%3)").arg(h, 3).arg(s, 3).arg(v, 3);
0448             // qDebug() << colorArray[i][j].name() << " ";
0449         }
0450         qDebug();
0451     }
0452 #endif
0453 #ifdef OUTPUT_GIMP_PALETTE
0454     qDebug() << "GIMP Palette";
0455     for (int j = 0; j < rowCount; ++j) {
0456         for (int i = 0; i < columnCount; ++i) {
0457             qDebug() << QString("(%1,%2,%3)").arg(m_colorArray[i][j].red(), 3).arg(m_colorArray[i][j].green(), 3).arg(m_colorArray[i][j].blue(), 3);
0458         }
0459     }
0460 #endif
0461 }
0462 
0463 int KColorCombo2::columnCount() const
0464 {
0465     return m_columnCount;
0466 }
0467 
0468 int KColorCombo2::rowCount() const
0469 {
0470     return m_rowCount;
0471 }
0472 
0473 QColor KColorCombo2::colorAt(int column, int row) /* const*/
0474 {
0475     if (!m_colorArray)
0476         setRainbowPreset();
0477 
0478     if (column < 0 || row < 0 || column >= m_columnCount || row >= m_rowCount)
0479         return QColor();
0480 
0481     return m_colorArray[column][row];
0482 }
0483 
0484 QColor KColorCombo2::defaultColor() const
0485 {
0486     return m_defaultColor;
0487 }
0488 
0489 void KColorCombo2::newColorArray(int columnCount, int rowCount)
0490 {
0491     if (columnCount <= 0 || rowCount <= 0) {
0492         // kdebug << this::FUNCTION << "Trying to create an empty new color array (with %d columns and %d rows)";
0493         return;
0494     }
0495 
0496     // Delete any previous array (if any):
0497     deleteColorArray();
0498 
0499     // Create a new array of the wanted dimensions:
0500     m_columnCount = columnCount;
0501     m_rowCount = rowCount;
0502     m_colorArray = new QColor *[columnCount];
0503     for (int i = 0; i < columnCount; ++i)
0504         m_colorArray[i] = new QColor[rowCount];
0505 }
0506 
0507 void KColorCombo2::setColorAt(int column, int row, const QColor &color)
0508 {
0509     if (!m_colorArray)
0510         setRainbowPreset();
0511 
0512     if (column < 0 || row < 0 || column >= m_columnCount || row >= m_rowCount) {
0513         // kdebug << this::FUNCTION << "Trying to set a color at an invalid index (at column %d and row %d, whereas the array have %d columns and %d rows)";
0514         return;
0515     }
0516 
0517     m_colorArray[column][row] = color;
0518 }
0519 
0520 void KColorCombo2::setDefaultColor(const QColor &color)
0521 {
0522     m_defaultColor = color;
0523     if (!m_defaultColor.isValid() && !m_color.isValid()) {
0524         m_color = Qt::white; // FIXME: Use the first one.
0525         Q_EMIT defaultColorChanged(color);
0526     }
0527 }
0528 
0529 QPixmap KColorCombo2::colorRectPixmap(const QColor &color, bool isDefault, int width, int height)
0530 {
0531     // Prepare to draw:
0532     QPixmap pixmap(width, height);
0533     QBitmap mask(width, height);
0534     QPainter painter(&pixmap);
0535     QPainter maskPainter(&mask);
0536 
0537     // Draw pixmap:
0538     drawColorRect(painter, 0, 0, color, isDefault, width, height);
0539 
0540     // Draw mask (make the four corners transparent):
0541     maskPainter.fillRect(0, 0, width, height, Qt::color1); // opaque
0542     maskPainter.setPen(Qt::color0);                        // transparent
0543     maskPainter.drawPoint(0, 0);
0544     maskPainter.drawPoint(0, height - 1);
0545     maskPainter.drawPoint(width - 1, height - 1);
0546     maskPainter.drawPoint(width - 1, 0);
0547 
0548     // Finish:
0549     painter.end();
0550     maskPainter.end();
0551     pixmap.setMask(mask);
0552     return pixmap;
0553 }
0554 
0555 void KColorCombo2::drawColorRect(QPainter &painter, int x, int y, const QColor &color, bool isDefault, int width, int height)
0556 {
0557     // Fill:
0558     if (color.isValid())
0559         painter.fillRect(x /*+ 1*/, y /*+ 1*/, width /*- 2*/, height /*- 2*/, color);
0560     else {
0561         // If it's an invalid color, it's for the "Other..." entry: draw a rainbow.
0562         // If it wasn't for the "Other..." entry, the programmer made a fault, so (s)he will be informed about that visually.
0563         for (int i = 0; i < width - 2; ++i) {
0564             int hue = i * 360 / (width - 2);
0565             for (int j = 0; j < height - 2; ++j) {
0566                 int saturation = 255 - (j * 255 / (height - 2));
0567                 painter.setPen(QColor::fromHsv(hue, saturation, /*value=*/255));
0568                 painter.drawPoint(x + i + 1, y + j + 1);
0569             }
0570         }
0571     }
0572 
0573     // Stroke:
0574     int dontCare, value;
0575     color.getHsv(/*hue:*/ &dontCare, /*saturation:*/ &dontCare, &value);
0576     QColor stroke = (color.isValid() ? color.darker(125) : palette().color(QPalette::Text));
0577     painter.setPen(/*color);//*/ stroke);
0578     painter.drawLine(x + 1, y, x + width - 2, y);
0579     painter.drawLine(x, y + 1, x, y + height - 2);
0580     painter.drawLine(x + 1, y + height - 1, x + width - 2, y + height - 1);
0581     painter.drawLine(x + width - 1, y + 1, x + width - 1, y + height - 2);
0582 
0583     // Round corners:
0584     QColor antialiasing;
0585     if (color.isValid()) {
0586         antialiasing = Tool_mixColors(color, stroke);
0587         painter.setPen(antialiasing);
0588         painter.drawPoint(x + 1, y + 1);
0589         painter.drawPoint(x + 1, y + height - 2);
0590         painter.drawPoint(x + width - 2, y + height - 2);
0591         painter.drawPoint(x + width - 2, y + 1);
0592     } else {
0593         // The two top corners:
0594         antialiasing = Tool_mixColors(Qt::red, stroke);
0595         painter.setPen(antialiasing);
0596         painter.drawPoint(x + 1, y + 1);
0597         painter.drawPoint(x + width - 2, y + 1);
0598         // The two bottom ones:
0599         antialiasing = Tool_mixColors(Qt::white, stroke);
0600         painter.setPen(antialiasing);
0601         painter.drawPoint(x + 1, y + height - 2);
0602         painter.drawPoint(x + width - 2, y + height - 2);
0603     }
0604 
0605     // Mark default color:
0606     if (isDefault) {
0607         painter.setPen(stroke);
0608         painter.drawLine(x + 1, y + height - 2, x + width - 2, y + 1);
0609     }
0610 }
0611 
0612 int KColorCombo2::colorRectHeight() const
0613 {
0614     return (fontMetrics().boundingRect(i18n("(Default)")).height() + 2) * 3 / 2;
0615 }
0616 
0617 int KColorCombo2::colorRectWidthForHeight(int height) const
0618 {
0619     return height * 14 / 10; // 1.4 times the height, like A4 papers.
0620 }
0621 
0622 void KColorCombo2::deleteColorArray()
0623 {
0624     if (m_colorArray) {
0625         for (int i = 0; i < m_columnCount; ++i)
0626             delete[] m_colorArray[i];
0627         delete[] m_colorArray;
0628         m_colorArray = nullptr;
0629     }
0630 }
0631 
0632 void KColorCombo2::updateComboBox()
0633 {
0634     int height = colorRectHeight() * 2 / 3;                                                 // fontMetrics().boundingRect(i18n("(Default)")).height() + 2
0635     QPixmap pixmap = colorRectPixmap(effectiveColor(), !m_color.isValid(), height, height); // TODO: isDefaultColorSelected()
0636     setItemIcon(/*index=*/0, pixmap);
0637     setItemText(/*index=*/0, (m_color.isValid() ? QString(i18n("R:%1, G:%2, B:%3", m_color.red(), m_color.green(), m_color.blue())) : i18nc("color", "(Default)")));
0638 }
0639 
0640 void KColorCombo2::showPopup()
0641 {
0642     if (!m_colorArray)
0643         setRainbowPreset();
0644 
0645     // Compute where to show the popup:
0646     QRect desk = qApp->desktop()->screenGeometry(this);
0647 
0648     QPoint popupPoint = mapToGlobal(QPoint(0, 0));
0649 
0650     int popupHeight = m_popup->size().height();
0651     if (popupPoint.y() + height() + popupHeight > desk.bottom())
0652         popupPoint.setY(popupPoint.y() - popupHeight);
0653     else
0654         popupPoint.setY(popupPoint.y() + height());
0655 
0656     int popupWidth = m_popup->size().width();
0657     if (popupPoint.x() + popupWidth > desk.right())
0658         popupPoint.setX(desk.right() - popupWidth);
0659 
0660     if (popupPoint.x() < desk.left())
0661         popupPoint.setX(desk.left());
0662 
0663     if (popupPoint.y() < desk.top())
0664         popupPoint.setY(desk.top());
0665 
0666     // Configure the popup:
0667     m_popup->move(popupPoint);
0668     // m_popup->setColor(m_color);
0669     m_popup->doSelection();
0670     m_popup->relayout(); // FIXME: In aboutToShow() ?
0671 #if 0
0672 //#ifndef QT_NO_EFFECTS
0673     if (QApplication::isEffectEnabled(UI_AnimateCombo)) {
0674         if (m_popup->y() < mapToGlobal(QPoint(0, 0)).y())
0675             qScrollEffect(m_popup, QEffects::UpScroll);
0676         else
0677             qScrollEffect(m_popup);
0678     } else
0679 #endif
0680     m_popup->show();
0681 
0682     // The combo box is now shown pressed. Make it show not pressed again
0683     // by causing its (invisible) list box to emit a 'selected' signal.
0684     // Simulate an Enter to unpress it:
0685     /*QListWidget *lb = listBox();
0686     if (lb) {
0687         lb->setCurrentItem(0);
0688         QKeyEvent* keyEvent = new QKeyEvent(QEvent::KeyPress, Qt::Key_Enter, 0, 0);
0689         QApplication::postEvent(lb, keyEvent);
0690     }*/
0691 }
0692 
0693 void KColorCombo2::mouseMoveEvent(QMouseEvent *event)
0694 {
0695     if ((event->buttons() & Qt::LeftButton) && (event->pos() - m_dragStartPos).manhattanLength() > qApp->startDragDistance()) {
0696         // Drag color object:
0697         QMimeData *mimeData = new QMimeData;
0698         QDrag *colorDrag = new QDrag(this);
0699         mimeData->setColorData(effectiveColor());
0700         // Replace the drag pixmap with our own rounded one, at the same position and dimensions:
0701         QPixmap pixmap = colorDrag->pixmap();
0702         pixmap = colorRectPixmap(effectiveColor(), /*isDefault=*/false, pixmap.width(), pixmap.height());
0703         colorDrag->setPixmap(pixmap);
0704         colorDrag->setHotSpot(colorDrag->hotSpot());
0705         colorDrag->exec(Qt::CopyAction, Qt::CopyAction);
0706         // setDown(false);
0707     }
0708 }
0709 
0710 void KColorCombo2::dragEnterEvent(QDragEnterEvent *event)
0711 {
0712     if (isEnabled() && event->mimeData()->hasColor())
0713         event->accept();
0714 }
0715 
0716 void KColorCombo2::dropEvent(QDropEvent *event)
0717 {
0718     QColor color;
0719     color = qvariant_cast<QColor>(event->mimeData()->colorData());
0720     if (color.isValid())
0721         setColor(color);
0722 }
0723 
0724 void KColorCombo2::keyPressEvent(QKeyEvent *event)
0725 {
0726     QKeySequence key(event->key());
0727 
0728     if (KStandardShortcut::copy().contains(key)) {
0729         QMimeData *mime = new QMimeData;
0730         mime->setColorData(effectiveColor());
0731         QApplication::clipboard()->setMimeData(mime, QClipboard::Clipboard);
0732     } else if (KStandardShortcut::paste().contains(key)) {
0733         QColor color;
0734         color = qvariant_cast<QColor>(QApplication::clipboard()->mimeData(QClipboard::Clipboard)->colorData());
0735         setColor(color);
0736     } else
0737         KComboBox::keyPressEvent(event);
0738 }
0739 
0740 void KColorCombo2::fontChange(const QFont &)
0741 {
0742     // Since the color-rectangle is the same height of the text, we should resize it if the font change:
0743     updateComboBox();
0744 }
0745 
0746 void KColorCombo2::virtual_hook(int /*id*/, void * /*data*/)
0747 {
0748     /* KBASE::virtual_hook(id, data); */
0749 }
0750 
0751 void KColorCombo2::popupClosed()
0752 {
0753     hidePopup();
0754 }
0755 
0756 #include "moc_kcolorcombo2.cpp"
0757 
0758 #endif // USE_OLD_KCOLORCOMBO