KDELibs4Support

kcolordialog.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 1997 Martin Jones ([email protected])
3  Copyright (C) 2007 Roberto Raggi ([email protected])
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 //-----------------------------------------------------------------------------
21 // KDE color selection dialog.
22 //
23 // 1999-09-27 Espen Sand <[email protected]>
24 // KColorDialog is now subclassed from KDialog. I have also extended
25 // KColorDialog::getColor() so that it contains a parent argument. This
26 // improves centering capability.
27 //
28 // layout management added Oct 1997 by Mario Weilguni
29 // <[email protected]>
30 //
31 
32 #include "kcolordialog.h"
33 #include "kcolordialog_p.h"
34 
35 #include <config-kdelibs4support.h>
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 
40 #include <QButtonGroup>
41 #include <QCheckBox>
42 #include <QDesktopWidget>
43 #include <QRadioButton>
44 #include <QFrame>
45 #include <qdrawutil.h>
46 #include <QActionEvent>
47 #include <QFile>
48 #include <QHeaderView>
49 #include <QImage>
50 #include <QHBoxLayout>
51 #include <QDrag>
52 #include <QStyledItemDelegate>
53 #include <QLabel>
54 #include <QLayout>
55 #include <QPainter>
56 #include <QPushButton>
57 #include <QScrollBar>
58 #include <QTimer>
59 #include <QListWidget>
60 #include <QApplication>
61 #include <QSpinBox>
62 
63 #include <kcombobox.h>
64 #include <kconfig.h>
65 #include <klineedit.h>
66 #include <klocalizedstring.h>
67 #include <kmessagebox.h>
68 #include <kseparator.h>
69 #include <qstandardpaths.h>
70 #include <kcolorcollection.h>
71 #include <kcolorutils.h>
72 
73 #include "kcolormimedata.h"
74 #include <kdebug.h>
75 
76 #include "kcolorchoosermode_p.h"
77 #include "kcolorhelpers_p.h"
78 #include "kselector.h"
79 #include "kcolorvalueselector.h"
80 #include "khuesaturationselect.h"
81 #include "kxyselector.h"
82 #include <kconfiggroup.h>
83 #include <ksharedconfig.h>
84 
85 #if HAVE_X11
86 #include <X11/Xlib.h>
87 #include <X11/Xutil.h>
88 #include <QX11Info>
89 #include <fixx11h.h>
90 #endif
91 
92 using namespace KDEPrivate;
93 
95 
96 struct ColorCollectionNameType {
97  const char *const m_fileName;
98  const char *const m_displayName;
99 };
100 
101 static const ColorCollectionNameType colorCollectionName[] = {
102  { "Recent_Colors", I18N_NOOP2("palette name", "* Recent Colors *") },
103  { "Custom_Colors", I18N_NOOP2("palette name", "* Custom Colors *") },
104  { "40.colors", I18N_NOOP2("palette name", "Forty Colors") },
105  { "Oxygen.colors", I18N_NOOP2("palette name", "Oxygen Colors") },
106  { "Rainbow.colors", I18N_NOOP2("palette name", "Rainbow Colors") },
107  { "Royal.colors", I18N_NOOP2("palette name", "Royal Colors") },
108  { "Web.colors", I18N_NOOP2("palette name", "Web Colors") },
109  { nullptr, nullptr } // end of data
110 };
111 
112 enum ColorCollectionIndices {
113  recentColorIndex,
114  customColorIndex,
115  fortyColorIndex
116 };
117 
118 //-----------------------------------------------------------------------------
119 
120 class Q_DECL_HIDDEN KColorCells::KColorCellsPrivate
121 {
122 public:
123  KColorCellsPrivate(KColorCells *q): q(q)
124  {
125  inMouse = false;
126  selected = -1;
127  shade = false;
128  }
129 
130  KColorCells *q;
131  QPoint mousePos;
132  int selected;
133  bool shade;
134  bool inMouse;
135 };
136 
137 class KColorCellsItemDelegate: public QStyledItemDelegate
138 {
139 public:
140  KColorCellsItemDelegate(KColorCells *parent): QStyledItemDelegate(parent) {}
141  void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
142  {
143  QStyleOptionViewItem opt(option);
144  initStyleOption(&opt, index);
145 
146  //Get the current cell color
147  QColor backgroundColor = index.data(Qt::BackgroundRole).value<QColor>();
148  if (backgroundColor.isValid()) {
149  //Paint the general background
150  painter->fillRect(opt.rect, backgroundColor);
151  //Paint the selection mark (circle)
152  if (opt.state & QStyle::State_Selected) {
153  //Use black or white, depending on the contrast
154  QColor color = QColor(0, 0, 0, 220);
155  if (KColorUtils::contrastRatio(color, backgroundColor) < 5) {
156  color = QColor(255, 255, 255, 220);
157  }
158  //Draw the selection (radiobutton-like) circle
159  painter->save();
160  painter->setRenderHint(QPainter::Antialiasing, true);
162  painter->setPen(QPen(color, 1.2, Qt::SolidLine));
163  painter->setBrush(QBrush());
164  painter->drawEllipse(opt.rect.adjusted(2, 2, -2, -2));
165  painter->restore();
166  }
167  } else {
168  //Paint the "X" (missing) cross on empty background color
169  backgroundColor = opt.palette.color(QPalette::Window);
170  painter->fillRect(opt.rect, backgroundColor);
171  painter->save();
172  QColor crossColor = qGray(backgroundColor.rgb()) > 192 ? backgroundColor.darker(106) :
173  backgroundColor.lighter(106);
174  painter->setPen(QPen(crossColor, 1.5));
175  painter->drawLine(opt.rect.topLeft(), opt.rect.bottomRight());
176  painter->drawLine(opt.rect.topRight(), opt.rect.bottomLeft());
177  painter->restore();
178  }
179  }
180 };
181 
182 KColorCells::KColorCells(QWidget *parent, int rows, int cols)
183  : QTableWidget(parent), d(new KColorCellsPrivate(this))
184 {
185  setItemDelegate(new KColorCellsItemDelegate(this));
186 
188  d->shade = true;
189  setRowCount(rows);
190  setColumnCount(cols);
191 
192  verticalHeader()->hide();
193  horizontalHeader()->hide();
194 
195  d->selected = 0;
196  d->inMouse = false;
197 
198  // Drag'n'Drop
199  setAcceptDrops(true);
200 
205 
207  setDragEnabled(false);
208 }
209 
210 KColorCells::~KColorCells()
211 {
212  delete d;
213 }
214 
215 QColor KColorCells::color(int index) const
216 {
217  QTableWidgetItem *tmpItem = item(index / columnCount(), index % columnCount());
218 
219  if (tmpItem != nullptr) {
220  return tmpItem->data(Qt::BackgroundRole).value<QColor>();
221  }
222 
223  return QColor();
224 }
225 
227 {
228  return rowCount() * columnCount();
229 }
230 
231 void KColorCells::setShading(bool _shade)
232 {
233  d->shade = _shade;
234 }
235 
236 bool KColorCells::shading() const
237 {
238  return d->shade;
239 }
240 
241 void KColorCells::setAcceptDrags(bool _acceptDrags)
242 {
243  this->setDragEnabled(_acceptDrags);
244 }
245 
246 bool KColorCells::acceptDrags() const
247 {
248  return this->dragEnabled();
249 }
250 
252 {
253  Q_ASSERT(index >= 0 && index < count());
254 
255  d->selected = index;
256 }
257 
259 {
260  return d->selected;
261 }
262 
263 void KColorCells::setColor(int column, const QColor &color)
264 {
265  const int tableRow = column / columnCount();
266  const int tableColumn = column % columnCount();
267 
268  Q_ASSERT(tableRow >= 0 && tableRow < rowCount());
269  Q_ASSERT(tableColumn >= 0 && tableColumn < columnCount());
270 
271  QTableWidgetItem *tableItem = item(tableRow, tableColumn);
272 
273  if (tableItem == nullptr) {
274  tableItem = new QTableWidgetItem();
275  setItem(tableRow, tableColumn, tableItem);
276  }
277 
278  tableItem->setData(Qt::BackgroundRole, color);
279 }
280 
281 /*void KColorCells::paintCell( QPainter *painter, int row, int col )
282 {
283  painter->setRenderHint( QPainter::Antialiasing , true );
284 
285  QBrush brush;
286  int w = 1;
287 
288  if (shade)
289  {
290  qDrawShadePanel( painter, 1, 1, cellWidth()-2,
291  cellHeight()-2, palette(), true, 1, &brush );
292  w = 2;
293  }
294  QColor color = colors[ row * numCols() + col ];
295  if (!color.isValid())
296  {
297  if (!shade) return;
298  color = palette().color(backgroundRole());
299  }
300 
301  const QRect colorRect( w, w, cellWidth()-w*2, cellHeight()-w*2 );
302  painter->fillRect( colorRect, color );
303 
304  if ( row * numCols() + col == selected ) {
305  painter->setPen( qGray(color.rgb())>=127 ? Qt::black : Qt::white );
306  painter->drawLine( colorRect.topLeft(), colorRect.bottomRight() );
307  painter->drawLine( colorRect.topRight(), colorRect.bottomLeft() );
308  }
309 }*/
310 
311 void KColorCells::resizeEvent(QResizeEvent *)
312 {
313  // According to the Qt doc:
314  // If you need to set the width of a given column to a fixed value, call
315  // QHeaderView::resizeSection() on the table's {horizontal,vertical}
316  // header.
317  // Therefore we iterate over each row and column and set the header section
318  // size, as the sizeHint does indeed appear to be ignored in favor of a
319  // minimum size that is larger than what we want.
320  for (int index = 0; index < columnCount(); index++) {
321  horizontalHeader()->resizeSection(index, sizeHintForColumn(index));
322  }
323  for (int index = 0; index < rowCount(); index++) {
324  verticalHeader()->resizeSection(index, sizeHintForRow(index));
325  }
326 }
327 
328 int KColorCells::sizeHintForColumn(int /*column*/) const
329 {
330  return width() / columnCount();
331 }
332 
333 int KColorCells::sizeHintForRow(int /*row*/) const
334 {
335  return height() / rowCount();
336 }
337 
338 void KColorCells::mousePressEvent(QMouseEvent *e)
339 {
340  d->inMouse = true;
341  d->mousePos = e->pos();
342 
344 }
345 
346 int KColorCells::positionToCell(const QPoint &pos, bool ignoreBorders) const
347 {
348  //TODO ignoreBorders not yet handled
349  Q_UNUSED(ignoreBorders)
350 
351  QTableWidgetItem *tableItem = itemAt(pos);
352 
353  if (!tableItem) {
354  return -1;
355  }
356 
357  const int itemRow = row(tableItem);
358  const int itemColumn = column(tableItem);
359  int cell = itemRow * columnCount() + itemColumn;
360 
361  /*if (!ignoreBorders)
362  {
363  int border = 2;
364  int x = pos.x() - col * cellWidth();
365  int y = pos.y() - row * cellHeight();
366  if ( (x < border) || (x > cellWidth()-border) ||
367  (y < border) || (y > cellHeight()-border))
368  return -1;
369  }*/
370 
371  return cell;
372 }
373 
374 void KColorCells::mouseMoveEvent(QMouseEvent *e)
375 {
376  if (this->dragEnabled() || this->acceptDrops()) {
377  if (!(e->buttons() & Qt::LeftButton)) {
378  return;
379  }
380 
381  if (d->inMouse) {
382  int delay = QApplication::startDragDistance();
383  if (e->x() > d->mousePos.x() + delay || e->x() < d->mousePos.x() - delay ||
384  e->y() > d->mousePos.y() + delay || e->y() < d->mousePos.y() - delay) {
385  // Drag color object
386  QTableWidgetItem *tableItem = itemAt(d->mousePos);
387 
388  if (tableItem) {
389  QVariant var = tableItem->data(Qt::BackgroundRole);
390  QColor tmpCol = var.value<QColor>();
391  if (tmpCol.isValid()) {
392  KColorMimeData::createDrag(tmpCol, this)->start();
393  }
394  }
395  }
396  }
397  } else {
399  }
400 }
401 
402 void KColorCells::dragEnterEvent(QDragEnterEvent *event)
403 {
404  kDebug() << "KColorCells::dragEnterEvent() acceptDrags="
405  << this->dragEnabled()
406  << " canDecode=" << KColorMimeData::canDecode(event->mimeData())
407  << endl;
408  event->setAccepted(this->dragEnabled() && KColorMimeData::canDecode(event->mimeData()));
409 }
410 
411 // Reimplemented to override QTableWidget's override. Else dropping doesn't work.
412 void KColorCells::dragMoveEvent(QDragMoveEvent *event)
413 {
414  kDebug() << "KColorCells::dragMoveEvent() acceptDrags="
415  << this->dragEnabled()
416  << " canDecode=" << KColorMimeData::canDecode(event->mimeData())
417  << endl;
418  event->setAccepted(this->dragEnabled() && KColorMimeData::canDecode(event->mimeData()));
419 }
420 
421 void KColorCells::dropEvent(QDropEvent *event)
422 {
424 
425  kDebug() << "KColorCells::dropEvent() color.isValid=" << c.isValid();
426  if (c.isValid()) {
427  QTableWidgetItem *tableItem = itemAt(event->pos());
428 
429  if (tableItem) {
430  tableItem->setData(Qt::BackgroundRole, c);
431  }
432  }
433 }
434 
435 void KColorCells::mouseReleaseEvent(QMouseEvent *e)
436 {
438  int cell = positionToCell(d->mousePos);
439  int currentCell = positionToCell(e->pos());
440 
441  // If we release the mouse in another cell and we don't have
442  // a drag we should ignore this event.
443  if (currentCell != cell) {
444  cell = -1;
445  }
446 
447  if ((cell != -1) && (d->selected != cell)) {
448  d->selected = cell;
449 
450  const int newRow = cell / columnCount();
451  const int newColumn = cell % columnCount();
452 
453  clearSelection(); // we do not want old violet selected cells
454 
455  item(newRow, newColumn)->setSelected(true);
456  }
457 
458  d->inMouse = false;
459  if (cell != -1) {
460  emit colorSelected(cell, color(cell));
461  }
462  }
463 
465 }
466 
467 void KColorCells::mouseDoubleClickEvent(QMouseEvent * /*e*/)
468 {
469  int cell = positionToCell(d->mousePos);
470 
471  if (cell != -1) {
472  emit colorDoubleClicked(cell, color(cell));
473  }
474 }
475 
476 //-----------------------------------------------------------------------------
477 
478 class Q_DECL_HIDDEN KColorPatch::KColorPatchPrivate
479 {
480 public:
481  KColorPatchPrivate(KColorPatch *q): q(q) {}
482 
483  KColorPatch *q;
484  QColor color;
485 };
486 
487 KColorPatch::KColorPatch(QWidget *parent) : QFrame(parent), d(new KColorPatchPrivate(this))
488 {
490  setAcceptDrops(true);
491  setMinimumSize(12, 12);
492 }
493 
494 KColorPatch::~KColorPatch()
495 {
496  delete d;
497 }
498 
500 {
501  return d->color;
502 }
503 
505 {
506  d->color = col.toRgb();
507 
508  update();
509 }
510 
511 void KColorPatch::paintEvent(QPaintEvent *pe)
512 {
513  QFrame::paintEvent(pe);
514  QPainter painter(this);
515 
516  fillOpaqueRect(&painter, contentsRect(), d->color);
517 }
518 
519 void KColorPatch::mouseMoveEvent(QMouseEvent *e)
520 {
521  // Drag color object
522  if (!(e->buttons() & Qt::LeftButton)) {
523  return;
524  }
525  KColorMimeData::createDrag(d->color, this)->start();
526 }
527 
528 void KColorPatch::dragEnterEvent(QDragEnterEvent *event)
529 {
530  event->setAccepted(KColorMimeData::canDecode(event->mimeData()));
531 }
532 
533 void KColorPatch::dropEvent(QDropEvent *event)
534 {
536  if (c.isValid()) {
537  setColor(c);
538  emit colorChanged(c);
539  }
540 }
541 
542 class KColorTable::KColorTablePrivate
543 {
544 public:
545  KColorTablePrivate(KColorTable *q): q(q) {}
546 
547  void slotColorCellSelected(int index, const QColor &);
548  void slotColorCellDoubleClicked(int index, const QColor &);
549  void slotColorTextSelected(const QString &colorText);
550  void slotSetColors(const QString &_collectionName);
551  void slotShowNamedColorReadError(void);
552 
553  KColorTable *q;
554  QString i18n_namedColors;
555  KComboBox *combo;
556  KColorCells *cells;
557  QScrollArea *sv;
558  QListWidget *mNamedColorList;
559  KColorCollection *mPalette;
560  int mMinWidth;
561  int mCols;
562  QMap<QString, QColor> m_namedColorMap;
563 };
564 
565 KColorTable::KColorTable(QWidget *parent, int minWidth, int cols)
566  : QWidget(parent), d(new KColorTablePrivate(this))
567 {
568  d->cells = nullptr;
569  d->mPalette = nullptr;
570  d->mMinWidth = minWidth;
571  d->mCols = cols;
572  d->i18n_namedColors = i18n("Named Colors");
573 
575  QStringList paletteList;
576 
577  // We must replace the untranslated file names by translate names (of course only for KDE's standard palettes)
578  for (int i = 0; colorCollectionName[i].m_fileName; ++i) {
579  diskPaletteList.removeAll(colorCollectionName[i].m_fileName);
580  paletteList.append(i18nc("palette name", colorCollectionName[i].m_displayName));
581  }
582  paletteList += diskPaletteList;
583  paletteList.append(d->i18n_namedColors);
584 
585  QVBoxLayout *layout = new QVBoxLayout(this);
586 
587  d->combo = new KComboBox(this);
588  d->combo->setEditable(false);
589  d->combo->addItems(paletteList);
590  layout->addWidget(d->combo);
591 
592  d->sv = new QScrollArea(this);
593  QSize cellSize = QSize(d->mMinWidth, 120);
594  d->sv->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
595  d->sv->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
596  QSize minSize = QSize(d->sv->verticalScrollBar()->sizeHint().width(), 0);
597  minSize += QSize(d->sv->frameWidth() * 2, 0);
598  minSize += QSize(cellSize);
599  d->sv->setFixedSize(minSize);
600  layout->addWidget(d->sv);
601 
602  d->mNamedColorList = new QListWidget(this);
603  d->mNamedColorList->setObjectName("namedColorList");
604  d->mNamedColorList->setFixedSize(minSize);
605  d->mNamedColorList->hide();
606  layout->addWidget(d->mNamedColorList);
607  connect(d->mNamedColorList, SIGNAL(currentTextChanged(QString)),
608  this, SLOT(slotColorTextSelected(QString)));
609 
611  connect(d->combo, SIGNAL(activated(QString)),
612  this, SLOT(slotSetColors(QString)));
613 }
614 
615 KColorTable::~KColorTable()
616 {
617  delete d->mPalette;
618  delete d;
619 }
620 
621 QString
622 KColorTable::name() const
623 {
624  return d->combo->currentText();
625 }
626 
627 static const char *const *namedColorFilePath(void)
628 {
629  //
630  // 2000-02-05 Espen Sand.
631  // Add missing filepaths here. Make sure the last entry is 0, 0!
632  //
633  // 2009-06-16 Pino Toscano
634  //
635  // You can specify either absolute paths or relative locations.
636  // Relative locations are relative to GenericDataLocation (XDG_DATA_DIRS).
637  //
638  static const char *const path[] = {
639 #if HAVE_X11
640 #ifdef X11_RGBFILE
641  X11_RGBFILE,
642 #endif
643  "/usr/share/X11/rgb.txt",
644  "/usr/X11R6/lib/X11/rgb.txt",
645  "/usr/openwin/lib/X11/rgb.txt", // for Solaris.
646 #else /* systems without X11 */
647  "kf5/kdeui/rgb.txt",
648 #endif
649  nullptr
650  };
651  return path;
652 }
653 
654 void
655 KColorTable::readNamedColor(void)
656 {
657  if (d->mNamedColorList->count() != 0) {
658  return; // Strings already present
659  }
660 
661  //
662  // Code somewhat inspired by KColorCollection.
663  //
664 
665  const char *const *path = namedColorFilePath();
666  for (int i = 0; path[i]; ++i) {
667  QString file;
668  if (path[i][0] != '/') { // relative path
670  if (file.isEmpty()) {
671  continue;
672  }
673  } else { // absolute path
674  file = QString::fromLatin1(path[i]);
675  }
676 
677  QFile paletteFile(file);
678  if (!paletteFile.open(QIODevice::ReadOnly)) {
679  continue;
680  }
681 
682  QByteArray line;
683  QStringList list;
684  while (!paletteFile.atEnd()) {
685  line = paletteFile.readLine();
686 
687  int red, green, blue;
688  int pos = 0;
689 
690  if (sscanf(line, "%d %d %d%n", &red, &green, &blue, &pos) == 3) {
691  //
692  // Remove duplicates. Every name with a space and every name
693  // that start with "gray".
694  //
695  QString name = line.mid(pos).trimmed();
696  QByteArray s1 = line.mid(pos);
697  if (name.isNull() || name.indexOf(' ') != -1 ||
698  name.indexOf("gray") != -1 || name.indexOf("grey") != -1) {
699  continue;
700  }
701 
702  const QColor color(red, green, blue);
703  if (color.isValid()) {
704  const QString colorName(i18nc("color", name.toLatin1().data()));
705  list.append(colorName);
706  d->m_namedColorMap[ colorName ] = color;
707  }
708  }
709  }
710 
711  list.sort();
712  d->mNamedColorList->addItems(list);
713  break;
714  }
715 
716  if (d->mNamedColorList->count() == 0) {
717  //
718  // Give the error dialog box a chance to center above the
719  // widget (or dialog). If we had displayed it now we could get a
720  // situation where the (modal) error dialog box pops up first
721  // preventing the real dialog to become visible until the
722  // error dialog box is removed (== bad UI).
723  //
724  QTimer::singleShot(10, this, SLOT(slotShowNamedColorReadError()));
725  }
726 }
727 
728 void
729 KColorTable::KColorTablePrivate::slotShowNamedColorReadError(void)
730 {
731  if (mNamedColorList->count() == 0) {
732  QString pathMsg;
733  int pathCount = 0;
734 
735  const char *const *path = namedColorFilePath();
736  for (int i = 0; path[i]; i += 2, ++pathCount) {
737  if (path[i + 1]) {
738  pathMsg += QLatin1String(path[i + 1]) + ", " + QString::fromLatin1(path[i]);
739  } else {
740  pathMsg += QLatin1String(path[i]);
741  }
742  pathMsg += '\n';
743  }
744 
745  QString finalMsg = i18ncp("%1 is the number of paths, %2 is the list of paths (with newlines between them)",
746  "Unable to read X11 RGB color strings. The following "
747  "file location was examined:\n%2",
748  "Unable to read X11 RGB color strings. The following "
749  "file locations were examined:\n%2",
750  pathCount, pathMsg);
751 
752  KMessageBox::sorry(q, finalMsg);
753  }
754 }
755 
756 //
757 // 2000-02-12 Espen Sand
758 // Set the color in two steps. The setColors() slot will not emit a signal
759 // with the current color setting. The reason is that setColors() is used
760 // by the color selector dialog on startup. In the color selector dialog
761 // we normally want to display a startup color which we specify
762 // when the dialog is started. The slotSetColors() slot below will
763 // set the palette and then use the information to emit a signal with the
764 // new color setting. It is only used by the combobox widget.
765 //
766 void
767 KColorTable::KColorTablePrivate::slotSetColors(const QString &_collectionName)
768 {
769  q->setColors(_collectionName);
770  if (mNamedColorList->count() && mNamedColorList->isVisible()) {
771  int item = mNamedColorList->currentRow();
772  mNamedColorList->setCurrentRow(item < 0 ? 0 : item);
773  slotColorTextSelected(mNamedColorList->currentItem()->text());
774  } else {
775  slotColorCellSelected(0, QColor()); // FIXME: We need to save the current value!!
776  }
777 }
778 
779 void
780 KColorTable::setColors(const QString &_collectionName)
781 {
782  QString collectionName(_collectionName);
783 
784  if (d->combo->currentText() != collectionName) {
785  bool found = false;
786  for (int i = 0; i < d->combo->count(); i++) {
787  if (d->combo->itemText(i) == collectionName) {
788  d->combo->setCurrentIndex(i);
789  found = true;
790  break;
791  }
792  }
793  if (!found) {
794  d->combo->addItem(collectionName);
795  d->combo->setCurrentIndex(d->combo->count() - 1);
796  }
797  }
798 
799  // We must again find the file name of the palette from the eventual translation
800  for (int i = 0; colorCollectionName[i].m_fileName; ++i) {
801  if (collectionName == i18nc("palette name", colorCollectionName[i].m_displayName)) {
802  collectionName = colorCollectionName[i].m_fileName;
803  break;
804  }
805  }
806 
807  //
808  // 2000-02-12 Espen Sand
809  // The palette mode "i18n_namedColors" does not use the KColorCollection
810  // class. In fact, 'mPalette' and 'cells' are 0 when in this mode. The reason
811  // for this is maninly that KColorCollection reads from and writes to files
812  // using "locate()". The colors used in "i18n_namedColors" mode comes from
813  // the X11 diretory and is not writable. I don't think this fit in
814  // KColorCollection.
815  //
816  if (!d->mPalette || d->mPalette->name() != collectionName) {
817  if (collectionName == d->i18n_namedColors) {
818  d->sv->hide();
819  d->mNamedColorList->show();
820  readNamedColor();
821 
822  delete d->cells; d->cells = nullptr;
823  delete d->mPalette; d->mPalette = nullptr;
824  } else {
825  d->mNamedColorList->hide();
826  d->sv->show();
827 
828  delete d->cells;
829  delete d->mPalette;
830  d->mPalette = new KColorCollection(collectionName);
831  int rows = (d->mPalette->count() + d->mCols - 1) / d->mCols;
832  if (rows < 1) {
833  rows = 1;
834  }
835  d->cells = new KColorCells(d->sv->viewport(), rows, d->mCols);
836  d->cells->setShading(false);
837  d->cells->setAcceptDrags(false);
838  QSize cellSize = QSize(d->mMinWidth, d->mMinWidth * rows / d->mCols);
839  d->cells->setFixedSize(cellSize);
840  for (int i = 0; i < d->mPalette->count(); i++) {
841  d->cells->setColor(i, d->mPalette->color(i));
842  }
843  connect(d->cells, SIGNAL(colorSelected(int,QColor)),
844  SLOT(slotColorCellSelected(int,QColor)));
845  connect(d->cells, SIGNAL(colorDoubleClicked(int,QColor)),
846  SLOT(slotColorCellDoubleClicked(int,QColor)));
847  d->sv->setWidget(d->cells);
848  d->cells->show();
849 
850  //d->sv->updateScrollBars();
851  }
852  }
853 }
854 
855 void
856 KColorTable::KColorTablePrivate::slotColorCellSelected(int index, const QColor & /*color*/)
857 {
858  if (!mPalette || (index >= mPalette->count())) {
859  return;
860  }
861  emit q->colorSelected(mPalette->color(index), mPalette->name(index));
862 }
863 
864 void
865 KColorTable::KColorTablePrivate::slotColorCellDoubleClicked(int index, const QColor & /*color*/)
866 {
867  if (!mPalette || (index >= mPalette->count())) {
868  return;
869  }
870  emit q->colorDoubleClicked(mPalette->color(index), mPalette->name(index));
871 }
872 
873 void
874 KColorTable::KColorTablePrivate::slotColorTextSelected(const QString &colorText)
875 {
876  emit q->colorSelected(m_namedColorMap[ colorText ], colorText);
877 }
878 
879 void
880 KColorTable::addToCustomColors(const QColor &color)
881 {
882  setColors(i18nc("palette name", colorCollectionName[customColorIndex].m_displayName));
883  d->mPalette->addColor(color);
884  d->mPalette->save();
885  delete d->mPalette;
886  d->mPalette = nullptr;
887  setColors(i18nc("palette name", colorCollectionName[customColorIndex].m_displayName));
888 }
889 
890 void
891 KColorTable::addToRecentColors(const QColor &color)
892 {
893  //
894  // 2000-02-12 Espen Sand.
895  // The 'mPalette' is always 0 when current mode is i18n_namedColors
896  //
897  bool recentIsSelected = false;
898  if (d->mPalette && d->mPalette->name() == colorCollectionName[ recentColorIndex ].m_fileName) {
899  delete d->mPalette;
900  d->mPalette = nullptr;
901  recentIsSelected = true;
902  }
903  KColorCollection *recentPal = new KColorCollection(colorCollectionName[ recentColorIndex ].m_fileName);
904  if (recentPal->findColor(color) == -1) {
905  recentPal->addColor(color);
906  recentPal->save();
907  }
908  delete recentPal;
909  if (recentIsSelected) {
910  setColors(i18nc("palette name", colorCollectionName[ recentColorIndex ].m_displayName));
911  }
912 }
913 
914 class KCDPickerFilter;
915 
916 class Q_DECL_HIDDEN KColorDialog::KColorDialogPrivate
917 {
918 public:
919  KColorDialogPrivate(KColorDialog *q): q(q) {}
920 
921  void setRgbEdit(const QColor &col);
922  void setHsvEdit(const QColor &col);
923  void setHtmlEdit(const QColor &col);
924  void _setColor(const QColor &col, const QString &name = QString());
925  void showColor(const QColor &color, const QString &name);
926 
927  void slotRGBChanged(void);
928  void slotAlphaChanged(void);
929  void slotHSVChanged(void);
930  void slotHtmlChanged(void);
931  void slotHSChanged(int, int);
932  void slotVChanged(int);
933  void slotAChanged(int);
934  void slotModeChanged(int);
935 
936  void slotColorSelected(const QColor &col);
937  void slotColorSelected(const QColor &col, const QString &name);
938  void slotColorDoubleClicked(const QColor &col, const QString &name);
939  void slotColorPicker();
940  void slotAddToCustomColors();
941  void slotDefaultColorClicked();
945  void slotWriteSettings();
946 
950  KColorChooserMode chooserMode();
951 
955  void setChooserMode(KColorChooserMode c);
956 
957  KColorDialog *q;
958  KColorTable *table;
959  QString originalPalette;
960  bool bRecursion;
961  bool bEditRgb;
962  bool bEditHsv;
963  bool bEditHtml;
964  bool bColorPicking;
965  bool bAlphaEnabled;
966  QLabel *colorName;
967  KLineEdit *htmlName;
968  QSpinBox *hedit;
969  QSpinBox *sedit;
970  QSpinBox *vedit;
971  QSpinBox *redit;
972  QSpinBox *gedit;
973  QSpinBox *bedit;
974  QWidget *alphaLabel;
975  QSpinBox *aedit;
976 
977  KColorPatch *patch;
978  KColorPatch *comparePatch;
979 
980  KColorChooserMode _mode;
981  QButtonGroup *modeGroup;
982 
983  KHueSaturationSelector *hsSelector;
985  KColorValueSelector *valuePal;
986  KGradientSelector *alphaSelector;
987  QVBoxLayout *l_right;
988  QGridLayout *tl_layout;
989  QCheckBox *cbDefaultColor;
990  QColor defaultColor;
991  QColor selColor;
992 };
993 
995  : KDialog(parent), d(new KColorDialogPrivate(this))
996 {
997  setCaption(i18n("Select Color"));
998  setButtons(modal ? Ok | Cancel : Close);
999  setModal(modal);
1000  d->bRecursion = true;
1001  d->bColorPicking = false;
1002  d->bAlphaEnabled = false;
1003  d->cbDefaultColor = nullptr;
1004  d->_mode = ChooserClassic;
1005  connect(this, SIGNAL(okClicked()), this, SLOT(slotWriteSettings()));
1006  connect(this, SIGNAL(closeClicked()), this, SLOT(slotWriteSettings()));
1007 
1008  QLabel *label;
1009 
1010  //
1011  // Create the top level page and its layout
1012  //
1013  QWidget *page = new QWidget(this);
1014  setMainWidget(page);
1015 
1016  QGridLayout *tl_layout = new QGridLayout(page);
1017  tl_layout->setContentsMargins(0, 0, 0, 0);
1018  d->tl_layout = tl_layout;
1019  tl_layout->addItem(new QSpacerItem(spacingHint() * 2, 0), 0, 1);
1020 
1021  //
1022  // the more complicated part: the left side
1023  // add a V-box
1024  //
1025  QVBoxLayout *l_left = new QVBoxLayout();
1026  tl_layout->addLayout(l_left, 0, 0);
1027 
1028  //
1029  // add a H-Box for the XY-Selector and a grid for the
1030  // entry fields
1031  //
1032  QHBoxLayout *l_ltop = new QHBoxLayout();
1033  l_left->addLayout(l_ltop);
1034 
1035  //
1036  // the palette and value selector go into the H-box
1037  //
1038  d->hsSelector = new KHueSaturationSelector(page);
1039  d->hsSelector->setMinimumSize(256, 256);
1040  l_ltop->addWidget(d->hsSelector, 8);
1041  connect(d->hsSelector, SIGNAL(valueChanged(int,int)),
1042  SLOT(slotHSChanged(int,int)));
1043 
1044  d->valuePal = new KColorValueSelector(page);
1045  d->valuePal->setMinimumSize(26, 70);
1046  d->valuePal->setIndent(false);
1047  d->valuePal->setArrowDirection(Qt::RightArrow);
1048  l_ltop->addWidget(d->valuePal, 1);
1049  connect(d->valuePal, SIGNAL(valueChanged(int)),
1050  SLOT(slotVChanged(int)));
1051 
1052  d->alphaSelector = new KGradientSelector(Qt::Horizontal, page);
1053  d->alphaSelector->setFixedSize(256, 26);
1054  d->alphaSelector->setIndent(false);
1055  d->alphaSelector->setArrowDirection(Qt::DownArrow);
1056  d->alphaSelector->setRange(0, 255);
1057  l_left->addWidget(d->alphaSelector, 1);
1058  connect(d->alphaSelector, SIGNAL(valueChanged(int)),
1059  SLOT(slotAChanged(int)));
1060 
1061  // a little space between
1062  l_left->addSpacing(10); // FIXME: remove hardcoded values
1063 
1064  QGridLayout *l_lbot = new QGridLayout();
1065  l_left->addLayout(l_lbot);
1066 
1067  // button group that manages the radio buttons
1068  QRadioButton *modeButton;
1069  d->modeGroup = new QButtonGroup(page);
1070  connect(d->modeGroup, SIGNAL(buttonClicked(int)), SLOT(slotModeChanged(int)));
1071 
1072  //
1073  // add the HSV fields
1074  //
1075  l_lbot->setColumnStretch(2, 10);
1076 
1077  modeButton = new QRadioButton(i18n("Hue:"), page);
1078  l_lbot->addWidget(modeButton, 0, 0);
1079  d->modeGroup->addButton(modeButton, ChooserHue);
1080 
1081  d->hedit = new QSpinBox(page);
1082  d->hedit->setMaximum(359);
1083  d->hedit->setSuffix(i18nc("The angular degree unit (for hue)", "\302\260")); // U+00B0 DEGREE SIGN
1084  l_lbot->addWidget(d->hedit, 0, 1);
1085  connect(d->hedit, SIGNAL(valueChanged(int)),
1086  SLOT(slotHSVChanged()));
1087 
1088  modeButton = new QRadioButton(i18n("Saturation:"), page);
1089  l_lbot->addWidget(modeButton, 1, 0);
1090  d->modeGroup->addButton(modeButton, ChooserSaturation);
1091 
1092  d->sedit = new QSpinBox(page);
1093  d->sedit->setMaximum(255);
1094  l_lbot->addWidget(d->sedit, 1, 1);
1095  connect(d->sedit, SIGNAL(valueChanged(int)),
1096  SLOT(slotHSVChanged()));
1097 
1098  modeButton = new QRadioButton(i18nc("This is the V of HSV", "Value:"), page);
1099  l_lbot->addWidget(modeButton, 2, 0);
1100  d->modeGroup->addButton(modeButton, ChooserValue);
1101 
1102  d->vedit = new QSpinBox(page);
1103  d->vedit->setMaximum(255);
1104  l_lbot->addWidget(d->vedit, 2, 1);
1105  connect(d->vedit, SIGNAL(valueChanged(int)),
1106  SLOT(slotHSVChanged()));
1107 
1108  //
1109  // add the RGB fields
1110  //
1111  modeButton = new QRadioButton(i18n("Red:"), page);
1112  l_lbot->addWidget(modeButton, 0, 3);
1113  d->modeGroup->addButton(modeButton, ChooserRed);
1114 
1115  d->redit = new QSpinBox(page);
1116  d->redit->setMaximum(255);
1117  l_lbot->addWidget(d->redit, 0, 4);
1118  connect(d->redit, SIGNAL(valueChanged(int)),
1119  SLOT(slotRGBChanged()));
1120 
1121  modeButton = new QRadioButton(i18n("Green:"), page);
1122  l_lbot->addWidget(modeButton, 1, 3);
1123  d->modeGroup->addButton(modeButton, ChooserGreen);
1124 
1125  d->gedit = new QSpinBox(page);
1126  d->gedit->setMaximum(255);
1127  l_lbot->addWidget(d->gedit, 1, 4);
1128  connect(d->gedit, SIGNAL(valueChanged(int)),
1129  SLOT(slotRGBChanged()));
1130 
1131  modeButton = new QRadioButton(i18n("Blue:"), page);
1132  l_lbot->addWidget(modeButton, 2, 3);
1133  d->modeGroup->addButton(modeButton, ChooserBlue);
1134 
1135  d->bedit = new QSpinBox(page);
1136  d->bedit->setMaximum(255);
1137  l_lbot->addWidget(d->bedit, 2, 4);
1138  connect(d->bedit, SIGNAL(valueChanged(int)),
1139  SLOT(slotRGBChanged()));
1140 
1141  //the layout
1142  QHBoxLayout *layout = new QHBoxLayout(this);
1143  layout->setSpacing(0);
1144  layout->setContentsMargins(0, 0, 0, 0);
1145 
1146  //the frame
1147  QFrame *frame = new QFrame(page);
1148  frame->setLayout(layout);
1149 
1150  d->alphaLabel = frame;
1151  QWidget *spacer = new QWidget(d->alphaLabel);
1152  label = new QLabel(i18n("Alpha:"), d->alphaLabel);
1153  QStyleOptionButton option;
1154  option.initFrom(modeButton);
1155  QRect labelRect = modeButton->style()->subElementRect(QStyle::SE_RadioButtonContents, &option, modeButton);
1156  int indent = layoutDirection() == Qt::LeftToRight ? labelRect.left() : modeButton->geometry().right() - labelRect.right();
1157  spacer->setFixedWidth(indent);
1158  l_lbot->addWidget(d->alphaLabel, 3, 3);
1159 
1160  d->aedit = new QSpinBox(page);
1161  d->aedit->setMaximum(255);
1162  label->setBuddy(d->aedit);
1163  l_lbot->addWidget(d->aedit, 3, 4);
1164  connect(d->aedit, SIGNAL(valueChanged(int)),
1165  SLOT(slotAlphaChanged()));
1166 
1167  d->aedit->setVisible(false);
1168  d->alphaLabel->setVisible(false);
1169  d->alphaSelector->setVisible(false);
1170 
1171  //
1172  // add a layout for the right side
1173  //
1174  d->l_right = new QVBoxLayout;
1175  tl_layout->addLayout(d->l_right, 0, 2);
1176 
1177  //
1178  // Add the palette table
1179  //
1180  d->table = new KColorTable(page);
1181  d->l_right->addWidget(d->table, 10);
1182 
1183  connect(d->table, SIGNAL(colorSelected(QColor,QString)),
1184  SLOT(slotColorSelected(QColor,QString)));
1185 
1186  connect(
1187  d->table,
1188  SIGNAL(colorDoubleClicked(QColor,QString)),
1189  SLOT(slotColorDoubleClicked(QColor,QString))
1190  );
1191  // Store the default value for saving time.
1192  d->originalPalette = d->table->name();
1193 
1194  //
1195  // a little space between
1196  //
1197  d->l_right->addSpacing(10);
1198 
1199  QHBoxLayout *l_hbox = new QHBoxLayout();
1200  d->l_right->addItem(l_hbox);
1201 
1202  //
1203  // The add to custom colors button
1204  //
1205  QPushButton *addButton = new QPushButton(page);
1206  addButton->setText(i18n("&Add to Custom Colors"));
1207  l_hbox->addWidget(addButton, 0, Qt::AlignLeft);
1208  connect(addButton, SIGNAL(clicked()), SLOT(slotAddToCustomColors()));
1209 
1210  //
1211  // The color picker button
1212  //
1213  QPushButton *button = new QPushButton(page);
1214  button->setIcon(QIcon::fromTheme("color-picker"));
1215  int commonHeight = addButton->sizeHint().height();
1216  button->setFixedSize(commonHeight, commonHeight);
1217  l_hbox->addWidget(button, 0, Qt::AlignHCenter);
1218  connect(button, SIGNAL(clicked()), SLOT(slotColorPicker()));
1219 
1220  //
1221  // a little space between
1222  //
1223  d->l_right->addSpacing(10);
1224 
1225  //
1226  // and now the entry fields and the patch (=colored box)
1227  //
1228  QGridLayout *l_grid = new QGridLayout();
1229  d->l_right->addLayout(l_grid);
1230 
1231  l_grid->setColumnStretch(2, 1);
1232 
1233  label = new QLabel(page);
1234  label->setText(i18n("Name:"));
1235  l_grid->addWidget(label, 0, 1, Qt::AlignLeft);
1236 
1237  d->colorName = new QLabel(page);
1238  l_grid->addWidget(d->colorName, 0, 2, Qt::AlignLeft);
1239 
1240  label = new QLabel(page);
1241  label->setText(i18n("HTML:"));
1242  l_grid->addWidget(label, 1, 1, Qt::AlignLeft);
1243 
1244  d->htmlName = new KLineEdit(page);
1245  d->htmlName->setMaxLength(13); // Qt's QColor allows 12 hexa-digits
1246  d->htmlName->setText("#FFFFFF"); // But HTML uses only 6, so do not worry about the size
1247  int w = d->htmlName->fontMetrics().width(QLatin1String("#DDDDDDD"));
1248  d->htmlName->setFixedWidth(w);
1249  l_grid->addWidget(d->htmlName, 1, 2, Qt::AlignLeft);
1250 
1251  connect(d->htmlName, SIGNAL(textChanged(QString)),
1252  SLOT(slotHtmlChanged()));
1253 
1254  d->patch = new KColorPatch(page);
1255  d->patch->setFixedSize(48, 48);
1256  l_grid->addWidget(d->patch, 0, 0, 2, 1, Qt::AlignHCenter | Qt::AlignVCenter);
1257  connect(d->patch, SIGNAL(colorChanged(QColor)),
1258  SLOT(setColor(QColor)));
1259 
1260  //
1261  // chain fields together
1262  //
1263  setTabOrder(d->hedit, d->sedit);
1264  setTabOrder(d->sedit, d->vedit);
1265  setTabOrder(d->vedit, d->redit);
1266  setTabOrder(d->redit, d->gedit);
1267  setTabOrder(d->gedit, d->bedit);
1268  setTabOrder(d->bedit, d->aedit);
1269 
1270  tl_layout->activate();
1271  page->setMinimumSize(page->sizeHint());
1272 
1273  readSettings();
1274  d->bRecursion = false;
1275  d->bEditHsv = false;
1276  d->bEditRgb = false;
1277  d->bEditHtml = false;
1278 
1280  QColor col;
1281  col.setHsv(0, 0, 255);
1282  d->_setColor(col);
1283 
1284 // FIXME: with enabled event filters, it crashes after ever enter of a drag.
1285 // better disable drag and drop than crashing it...
1286 // d->htmlName->installEventFilter(this);
1287 // d->hsSelector->installEventFilter(this);
1288  d->hsSelector->setAcceptDrops(true);
1289 
1290  d->setChooserMode(ChooserValue);
1291 }
1292 
1294 {
1295  delete d;
1296 }
1297 
1298 bool
1299 KColorDialog::eventFilter(QObject *obj, QEvent *ev)
1300 {
1301  if ((obj == d->htmlName) || (obj == d->hsSelector))
1302  switch (ev->type()) {
1303  case QEvent::DragEnter:
1304  case QEvent::DragMove:
1305  case QEvent::DragLeave:
1306  case QEvent::Drop:
1307  case QEvent::DragResponse:
1308  qApp->sendEvent(d->patch, ev);
1309  return true;
1310  default:
1311  break;
1312  }
1313  return KDialog::eventFilter(obj, ev);
1314 }
1315 
1316 void
1318 {
1319  if (!d->cbDefaultColor) {
1320  //
1321  // a little space between
1322  //
1323  d->l_right->addSpacing(10);
1324 
1325  //
1326  // and the "default color" checkbox, under all items on the right side
1327  //
1328  d->cbDefaultColor = new QCheckBox(i18n("Default color"), mainWidget());
1329 
1330  d->l_right->addWidget(d->cbDefaultColor);
1331 
1332  mainWidget()->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); // cancel setFixedSize()
1333  d->tl_layout->activate();
1336 
1337  connect(d->cbDefaultColor, SIGNAL(clicked()), SLOT(slotDefaultColorClicked()));
1338  }
1339 
1340  d->defaultColor = col;
1341 
1342  d->slotDefaultColorClicked();
1343 }
1344 
1346 {
1347  return d->defaultColor;
1348 }
1349 
1351 {
1352  if (d->bAlphaEnabled != alpha) {
1353  d->bAlphaEnabled = alpha;
1354  d->aedit->setVisible(d->bAlphaEnabled);
1355  d->alphaLabel->setVisible(d->bAlphaEnabled);
1356  d->alphaSelector->setVisible(d->bAlphaEnabled);
1357 
1358  mainWidget()->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); // cancel setFixedSize()
1359  d->tl_layout->activate();
1362  }
1363 }
1364 
1366 {
1367  return d->bAlphaEnabled;
1368 }
1369 
1370 void KColorDialog::KColorDialogPrivate::setChooserMode(KColorChooserMode c)
1371 {
1372  _mode = c;
1373  hsSelector->setChooserMode(c);
1374  valuePal->setChooserMode(c);
1375 
1376  modeGroup->button(valuePal->chooserMode())->setChecked(true);
1377  valuePal->updateContents();
1378  hsSelector->updateContents();
1379  valuePal->update();
1380  hsSelector->update();
1381  slotHSVChanged();
1382 }
1383 
1384 KColorChooserMode KColorDialog::KColorDialogPrivate::chooserMode()
1385 {
1386  return _mode;
1387 }
1388 
1389 void KColorDialog::KColorDialogPrivate::slotDefaultColorClicked()
1390 {
1391  if (cbDefaultColor->isChecked()) {
1392  selColor = defaultColor;
1393  showColor(selColor, i18n("-default-"));
1394  } else {
1395  showColor(selColor, QString());
1396  }
1397  emit q->colorSelected(selColor);
1398 }
1399 
1400 void
1401 KColorDialog::KColorDialogPrivate::slotModeChanged(int id)
1402 {
1403  setChooserMode(KColorChooserMode(id));
1404 }
1405 
1406 void
1407 KColorDialog::readSettings()
1408 {
1409  KConfigGroup group(KSharedConfig::openConfig(), "Colors");
1410 
1411  QString collectionName = group.readEntry("CurrentPalette");
1412  if (collectionName.isEmpty()) {
1413  collectionName = i18nc("palette name", colorCollectionName[fortyColorIndex].m_displayName);
1414  } else {
1415  for (int i = 0; colorCollectionName[i].m_fileName; ++i) {
1416  if (collectionName == colorCollectionName[i].m_displayName) {
1417  collectionName = i18nc("palette name", colorCollectionName[i].m_displayName);
1418  break;
1419  }
1420  }
1421  }
1422 
1423  d->table->setColors(collectionName);
1424 }
1425 
1426 void
1427 KColorDialog::KColorDialogPrivate::slotWriteSettings()
1428 {
1429  KConfigGroup group(KSharedConfig::openConfig(), "Colors");
1430 
1431  QString collectionName = table->name();
1432  if (!group.hasDefault("CurrentPalette") && table->name() == originalPalette) {
1433  group.revertToDefault("CurrentPalette");
1434  } else {
1435  QString collectionName(table->name());
1436  for (int i = 0; colorCollectionName[i].m_fileName; ++i) {
1437  if (collectionName == i18nc("palette name", colorCollectionName[i].m_displayName)) {
1438  collectionName = colorCollectionName[i].m_displayName;
1439  break;
1440  }
1441  }
1442  group.writeEntry("CurrentPalette", collectionName); //Make sure the untranslated name is saved, assuming there is one
1443  }
1444 }
1445 
1446 QColor
1447 KColorDialog::color() const
1448 {
1449  if (d->cbDefaultColor && d->cbDefaultColor->isChecked()) {
1450  return QColor();
1451  }
1452  if (d->selColor.isValid()) {
1453  d->table->addToRecentColors(d->selColor);
1454  }
1455  return d->selColor;
1456 }
1457 
1459 {
1460  d->_setColor(col);
1461 }
1462 
1463 //
1464 // static function to display dialog and return color
1465 //
1466 int KColorDialog::getColor(QColor &theColor, QWidget *parent)
1467 {
1468  KColorDialog dlg(parent, true);
1469  dlg.setObjectName("Color Selector");
1470  if (theColor.isValid()) {
1471  dlg.setColor(theColor);
1472  }
1473  int result = dlg.exec();
1474 
1475  if (result == Accepted) {
1476  theColor = dlg.color();
1477  }
1478 
1479  return result;
1480 }
1481 
1482 //
1483 // static function to display dialog and return color
1484 //
1485 int KColorDialog::getColor(QColor &theColor, const QColor &defaultCol, QWidget *parent)
1486 {
1487  KColorDialog dlg(parent, true);
1488  dlg.setObjectName("Color Selector");
1489  dlg.setDefaultColor(defaultCol);
1490  dlg.setColor(theColor);
1491  int result = dlg.exec();
1492 
1493  if (result == Accepted) {
1494  theColor = dlg.color();
1495  }
1496 
1497  return result;
1498 }
1499 
1500 void KColorDialog::KColorDialogPrivate::slotRGBChanged(void)
1501 {
1502  if (bRecursion) {
1503  return;
1504  }
1505  int red = redit->value();
1506  int grn = gedit->value();
1507  int blu = bedit->value();
1508 
1509  if (red > 255 || red < 0) {
1510  return;
1511  }
1512  if (grn > 255 || grn < 0) {
1513  return;
1514  }
1515  if (blu > 255 || blu < 0) {
1516  return;
1517  }
1518 
1519  QColor col;
1520  col.setRgb(red, grn, blu, aedit->value());
1521  bEditRgb = true;
1522  _setColor(col);
1523  bEditRgb = false;
1524 }
1525 
1526 void KColorDialog::KColorDialogPrivate::slotAlphaChanged(void)
1527 {
1528  if (bRecursion) {
1529  return;
1530  }
1531  int alpha = aedit->value();
1532 
1533  if (alpha > 255 || alpha < 0) {
1534  return;
1535  }
1536 
1537  QColor col = selColor;
1538  col.setAlpha(alpha);
1539  _setColor(col);
1540 }
1541 
1542 void KColorDialog::KColorDialogPrivate::slotHtmlChanged(void)
1543 {
1544  if (bRecursion || htmlName->text().isEmpty()) {
1545  return;
1546  }
1547 
1548  QString strColor(htmlName->text());
1549 
1550  // Assume that a user does not want to type the # all the time
1551  if (strColor[0] != '#') {
1552  bool signalsblocked = htmlName->blockSignals(true);
1553  strColor.prepend("#");
1554  htmlName->setText(strColor);
1555  htmlName->blockSignals(signalsblocked);
1556  }
1557 
1558  const QColor color(strColor);
1559 
1560  if (color.isValid()) {
1561  QColor col(color);
1562  bEditHtml = true;
1563  _setColor(col);
1564  bEditHtml = false;
1565  }
1566 }
1567 
1568 void KColorDialog::KColorDialogPrivate::slotHSVChanged(void)
1569 {
1570  if (bRecursion) {
1571  return;
1572  }
1573  int hue = hedit->value();
1574  int sat = sedit->value();
1575  int val = vedit->value();
1576 
1577  if (hue > 359 || hue < 0) {
1578  return;
1579  }
1580  if (sat > 255 || sat < 0) {
1581  return;
1582  }
1583  if (val > 255 || val < 0) {
1584  return;
1585  }
1586 
1587  QColor col;
1588  col.setHsv(hue, sat, val, aedit->value());
1589  bEditHsv = true;
1590  _setColor(col);
1591  bEditHsv = false;
1592 }
1593 
1594 void KColorDialog::KColorDialogPrivate::slotHSChanged(int x, int y)
1595 {
1596  QColor col = selColor;
1597  KColorChooserMode xMode = chooserXMode(chooserMode());
1598  KColorChooserMode yMode = chooserYMode(chooserMode());
1599  setComponentValue(col, xMode, x / (xMode == ChooserHue ? 360.0 : 255.0));
1600  setComponentValue(col, yMode, y / (yMode == ChooserHue ? 360.0 : 255.0));
1601  _setColor(col);
1602 }
1603 
1604 void KColorDialog::KColorDialogPrivate::slotVChanged(int v)
1605 {
1606  QColor col = selColor;
1607  setComponentValue(col, chooserMode(), v / (chooserMode() == ChooserHue ? 360.0 : 255.0));
1608  _setColor(col);
1609 }
1610 
1611 void KColorDialog::KColorDialogPrivate::slotAChanged(int value)
1612 {
1613  QColor col = selColor;
1614  col.setAlpha(value);
1615  _setColor(col);
1616 }
1617 
1618 void KColorDialog::KColorDialogPrivate::slotColorSelected(const QColor &color)
1619 {
1620  _setColor(color);
1621 }
1622 
1623 void KColorDialog::KColorDialogPrivate::slotAddToCustomColors()
1624 {
1625  table->addToCustomColors(selColor);
1626 }
1627 
1628 void KColorDialog::KColorDialogPrivate::slotColorSelected(const QColor &color, const QString &name)
1629 {
1630  _setColor(color, name);
1631 }
1632 
1633 void KColorDialog::KColorDialogPrivate::slotColorDoubleClicked
1634 (
1635  const QColor &color,
1636  const QString &name
1637 )
1638 {
1639  _setColor(color, name);
1640  q->accept();
1641 }
1642 
1643 void KColorDialog::KColorDialogPrivate::_setColor(const QColor &color, const QString &name)
1644 {
1645  if (color.isValid()) {
1646  if (cbDefaultColor && cbDefaultColor->isChecked()) {
1647  cbDefaultColor->setChecked(false);
1648  }
1649  selColor = color;
1650  } else {
1651  if (cbDefaultColor && cbDefaultColor->isChecked()) {
1652  cbDefaultColor->setChecked(true);
1653  }
1654  selColor = defaultColor;
1655  }
1656 
1657  showColor(selColor, name);
1658 
1659  emit q->colorSelected(selColor);
1660 }
1661 
1662 // show but don't set into selColor, nor emit colorSelected
1663 void KColorDialog::KColorDialogPrivate::showColor(const QColor &color, const QString &name)
1664 {
1665  bRecursion = true;
1666 
1667  if (name.isEmpty()) {
1668  colorName->setText(i18n("-unnamed-"));
1669  } else {
1670  colorName->setText(name);
1671  }
1672 
1673  patch->setColor(color);
1674 
1675  setRgbEdit(color);
1676  setHsvEdit(color);
1677  setHtmlEdit(color);
1678  aedit->setValue(color.alpha());
1679 
1680  QColor rgbColor = color.toRgb();
1681  bool ltr = q->layoutDirection() == Qt::LeftToRight;
1682  rgbColor.setAlpha(ltr ? 0 : 255);
1683  alphaSelector->setFirstColor(rgbColor);
1684  rgbColor.setAlpha(ltr ? 255 : 0);
1685  alphaSelector->setSecondColor(rgbColor);
1686  alphaSelector->setValue(color.alpha());
1687 
1688  KColorChooserMode xMode = chooserXMode(chooserMode());
1689  KColorChooserMode yMode = chooserYMode(chooserMode());
1690  int xValue = qRound(getComponentValue(color, xMode) * (xMode == ChooserHue ? 360.0 : 255.0));
1691  int yValue = qRound(getComponentValue(color, yMode) * (yMode == ChooserHue ? 360.0 : 255.0));
1692  int value = qRound(getComponentValue(color, chooserMode()) * (chooserMode() == ChooserHue ? 360.0 : 255.0));
1693  hsSelector->setValues(xValue, yValue);
1694  valuePal->setValue(value);
1695 
1696  bool blocked = valuePal->blockSignals(true);
1697 
1698  valuePal->setHue(color.hue());
1699  valuePal->setSaturation(color.saturation());
1700  valuePal->setColorValue(color.value());
1701  valuePal->updateContents();
1702  valuePal->blockSignals(blocked);
1703  valuePal->update();
1704 
1705  blocked = hsSelector->blockSignals(true);
1706 
1707  hsSelector->setHue(color.hue());
1708  hsSelector->setSaturation(color.saturation());
1709  hsSelector->setColorValue(color.value());
1710  hsSelector->updateContents();
1711  hsSelector->blockSignals(blocked);
1712  hsSelector->update();
1713 
1714  bRecursion = false;
1715 }
1716 
1717 void
1718 KColorDialog::KColorDialogPrivate::slotColorPicker()
1719 {
1720  bColorPicking = true;
1721  q->grabMouse(Qt::CrossCursor);
1722  q->grabKeyboard();
1723 }
1724 
1725 void
1726 KColorDialog::mouseMoveEvent(QMouseEvent *e)
1727 {
1728  if (d->bColorPicking) {
1729  d->_setColor(grabColor(e->globalPos()));
1730  return;
1731  }
1732 
1734 }
1735 
1736 void
1737 KColorDialog::mouseReleaseEvent(QMouseEvent *e)
1738 {
1739  if (d->bColorPicking) {
1740  d->bColorPicking = false;
1741  releaseMouse();
1742  releaseKeyboard();
1743  d->_setColor(grabColor(e->globalPos()));
1744  return;
1745  }
1747 }
1748 
1749 QColor
1751 {
1752  auto fallback = [p]() {
1753  QWidget *desktop = QApplication::desktop();
1754  QPixmap pm = QPixmap::grabWindow(desktop->winId(), p.x(), p.y(), 1, 1);
1755  QImage i = pm.toImage();
1756  return i.pixel(0, 0);
1757  };
1758 #if HAVE_X11
1759  if (!QX11Info::isPlatformX11()) {
1760  return fallback();
1761  }
1762  // we use the X11 API directly in this case as we are not getting back a valid
1763  // return from QPixmap::grabWindow in the case where the application is using
1764  // an argb visual
1765  if (!qApp->desktop()->geometry().contains(p)) {
1766  return QColor();
1767  }
1768  Window root = RootWindow(QX11Info::display(), QX11Info::appScreen());
1769  XImage *ximg = XGetImage(QX11Info::display(), root, p.x(), p.y(), 1, 1, -1, ZPixmap);
1770  unsigned long xpixel = XGetPixel(ximg, 0, 0);
1771  XDestroyImage(ximg);
1772  XColor xcol;
1773  xcol.pixel = xpixel;
1774  xcol.flags = DoRed | DoGreen | DoBlue;
1775  XQueryColor(QX11Info::display(),
1776  DefaultColormap(QX11Info::display(), QX11Info::appScreen()),
1777  &xcol);
1778  return QColor::fromRgbF(xcol.red / 65535.0, xcol.green / 65535.0, xcol.blue / 65535.0);
1779 #else
1780  return fallback();
1781 #endif
1782 }
1783 
1784 void
1785 KColorDialog::keyPressEvent(QKeyEvent *e)
1786 {
1787  if (d->bColorPicking) {
1788  if (e->key() == Qt::Key_Escape) {
1789  d->bColorPicking = false;
1790  releaseMouse();
1791  releaseKeyboard();
1792  }
1793  e->accept();
1794  return;
1795  }
1797 }
1798 
1799 void KColorDialog::KColorDialogPrivate::setRgbEdit(const QColor &col)
1800 {
1801  if (bEditRgb) {
1802  return;
1803  }
1804  int r, g, b;
1805  col.getRgb(&r, &g, &b);
1806 
1807  redit->setValue(r);
1808  gedit->setValue(g);
1809  bedit->setValue(b);
1810 }
1811 
1812 void KColorDialog::KColorDialogPrivate::setHtmlEdit(const QColor &col)
1813 {
1814  if (bEditHtml) {
1815  return;
1816  }
1817  int r, g, b;
1818  col.getRgb(&r, &g, &b);
1819  QString num;
1820 
1821  num.sprintf("#%02X%02X%02X", r, g, b);
1822  htmlName->setText(num);
1823 }
1824 
1825 void KColorDialog::KColorDialogPrivate::setHsvEdit(const QColor &col)
1826 {
1827  if (bEditHsv) {
1828  return;
1829  }
1830  int h, s, v;
1831  col.getHsv(&h, &s, &v);
1832 
1833  hedit->setValue(h);
1834  sedit->setValue(s);
1835  vedit->setValue(v);
1836 }
1837 
1838 #include "moc_kcolordialog.cpp"
1839 #include "moc_kcolordialog_p.cpp"
QLayout * layout() const const
QColor color() const
Returns the currently selected color.
QFrame(QWidget *parent, Qt::WindowFlags f)
void setSelected(int index)
Sets the currently selected cell to index.
static QColor grabColor(const QPoint &p)
Gets the color from the pixel at point p on the screen.
void releaseMouse()
ScrollBarAlwaysOff
RightArrow
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
#define I18N_NOOP2(context, text)
QEvent::Type type() const const
void setContentsMargins(int left, int top, int right, int bottom)
const QPalette & palette() const const
KColorDialog(QWidget *parent=nullptr, bool modal=false)
Constructs a color selection dialog.
QColor darker(int factor) const const
void setModal(bool modal)
void okClicked()
The OK button was pressed.
const QMimeData * mimeData() const const
void fillRect(const QRectF &rectangle, const QBrush &brush)
void setSelectionMode(QAbstractItemView::SelectionMode mode)
virtual QSize sizeHint() const const override
void setFixedWidth(int w)
void setRenderHint(QPainter::RenderHint hint, bool on)
SolidLine
void setRowCount(int rows)
KGUIADDONS_EXPORT qreal contrastRatio(const QColor &, const QColor &)
QByteArray trimmed() const const
void addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment)
int right() const const
Qt::DropAction start(Qt::DropActions request)
void setAlphaChannelEnabled(bool alpha)
When set to true, the user is allowed to change the alpha component of the color. ...
QRect contentsRect() const const
bool isAlphaChannelEnabled() const
Returns true when the user can change the alpha channel.
void setFrameShape(QFrame::Shape)
void setItem(int row, int column, QTableWidgetItem *item)
bool hasDefault(const QString &key) const
void setDefaultColor(const QColor &defaultCol)
Call this to make the dialog show a "Default Color" checkbox.
KGUIADDONS_EXPORT bool canDecode(const QMimeData *mimeData)
QString & prepend(QChar ch)
int value() const const
void setColumnCount(int columns)
QStyle * style() const const
Show Cancel-button. (this button reject()s the dialog; result set to QDialog::Rejected) ...
Definition: kdialog.h:143
int x() const const
int y() const const
QPoint pos() const const
int y() const const
void save()
SE_RadioButtonContents
LeftButton
T value() const const
virtual int exec()
QWidget * viewport() const const
void setAlpha(int alpha)
void setColor(const QColor &col)
Set the color to display and update the display.
void writeEntry(const QString &key, const QVariant &value, WriteConfigFlags pFlags=Normal)
A dialog base class with standard buttons and predefined layouts.
Definition: kdialog.h:128
QHeaderView * verticalHeader() const const
Qt::MouseButtons buttons() const const
void setFrameStyle(int style)
void drawLine(const QLineF &line)
void addSpacing(int size)
void setRgb(int r, int g, int b, int a)
LeftToRight
void buttonClicked(KDialog::ButtonCode button)
A button has been pressed.
virtual void mouseReleaseEvent(QMouseEvent *event)
virtual QVariant data(int role) const const
int hue() const const
void setIcon(const QIcon &icon)
int selectedIndex() const
Returns the index of the cell which is currently selected.
void setColor(int index, const QColor &col)
Sets the color in the given index in the table.
virtual void mouseReleaseEvent(QMouseEvent *event) override
void getHsv(int *h, int *s, int *v, int *a) const const
void update()
AlignLeft
virtual void setCaption(const QString &caption)
Make a KDE compliant caption.
Definition: kdialog.cpp:502
virtual QSize sizeHint() const const override
int x() const const
int y() const const
virtual void setData(int role, const QVariant &value)
bool isNull() const const
void setMainWidget(QWidget *widget)
Sets the main widget of the dialog.
Definition: kdialog.cpp:366
QString & sprintf(const char *cformat,...)
void colorDoubleClicked(int index, const QColor &color)
Emitted when a color in the table is double-clicked.
int rowCount() const const
void resizeSection(int logicalIndex, int size)
static int getColor(QColor &theColor, QWidget *parent=nullptr)
Creates a modal color dialog, let the user choose a color, and returns when the dialog is closed...
void initFrom(const QWidget *widget)
int width() const const
void setBuddy(QWidget *buddy)
int addColor(const QColor &newColor, const QString &newColorName=QString())
QPixmap grabWindow(WId window, int x, int y, int width, int height)
void setMinimumSize(const QSize &)
QColor toRgb() const const
QWidget * mainWidget()
Definition: kdialog.cpp:380
QRgb pixel(int x, int y) const const
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
static QStringList installedCollections()
void append(const T &value)
QPoint globalPos() const const
void setLayout(QLayout *layout)
int x() const const
Qt::LayoutDirection layoutDirection() const const
virtual void paintEvent(QPaintEvent *) override
void keyPressEvent(QKeyEvent *) override
Definition: kdialog.cpp:416
QRgb rgb() const const
static int spacingHint()
Returns the number of pixels that should be used between widgets inside a dialog according to the KDE...
Definition: kdialog.cpp:464
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void setPen(const QColor &color)
Show Close-button. (this button closes the dialog)
Definition: kdialog.h:144
void drawEllipse(const QRectF &rectangle)
int left() const const
KGUIADDONS_EXPORT QDrag * createDrag(const QColor &color, QObject *dragsource)
void setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy)
int columnCount() const const
void setObjectName(const QString &name)
BackgroundRole
void setTabOrder(QWidget *first, QWidget *second)
virtual void mouseMoveEvent(QMouseEvent *event)
bool isEmpty() const const
int removeAll(const T &value)
QPushButton * button(ButtonCode id) const
Returns the button that corresponds to the id.
Definition: kdialog.cpp:702
void setItemDelegate(QAbstractItemDelegate *delegate)
int column(const QTableWidgetItem *item) const const
QPoint pos() const const
QColor defaultColor() const
void setBrush(const QBrush &brush)
CrossCursor
void closeClicked()
The Close button was pressed.
A table of editable color cells.
Definition: kcolordialog.h:41
int result() const const
WId winId() const const
void setText(const QString &)
void hide()
KGUIADDONS_EXPORT QColor shade(const QColor &, qreal lumaAmount, qreal chromaAmount=0.0)
void setButtons(ButtonCodes buttonMask)
Creates (or recreates) the button box and all the buttons in it.
Definition: kdialog.cpp:216
QByteArray mid(int pos, int len) const const
virtual bool open(QIODevice::OpenMode mode) override
QColor color() const
Get the currently displayed color.
int alpha() const const
void setAcceptDrops(bool on)
Show Ok button. (this button accept()s the dialog; result set to QDialog::Accepted) ...
Definition: kdialog.h:140
int key() const const
void accept()
QColor fromRgbF(qreal r, qreal g, qreal b, qreal a)
void setFixedSize(const QSize &s)
QColor lighter(int factor) const const
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QString i18ncp(const char *context, const char *singular, const char *plural, const TYPE &arg...)
virtual bool atEnd() const const override
virtual void mouseMoveEvent(QMouseEvent *event) override
void setMaximumSize(const QSize &)
void restore()
void colorSelected(int index, const QColor &color)
Emitted when a color is selected in the table.
void activated(const QModelIndex &index)
KGUIADDONS_EXPORT QColor fromMimeData(const QMimeData *mimeData)
QString i18n(const char *text, const TYPE &arg...)
if(recurs()&&!first)
void addLayout(QLayout *layout, int row, int column, Qt::Alignment alignment)
void colorSelected(const QColor &col)
Emitted when a color is selected.
QTableWidgetItem * itemAt(const QPoint &point) const const
int findColor(const QColor &color) const
bool activate()
QByteArray toLatin1() const const
QVariant data(int role) const const
QDesktopWidget * desktop()
virtual void mousePressEvent(QMouseEvent *event) override
int row(const QTableWidgetItem *item) const const
void setColumnStretch(int column, int stretch)
void addItem(QLayoutItem *item, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment)
void releaseKeyboard()
QWidget(QWidget *parent, Qt::WindowFlags f)
void getRgb(int *r, int *g, int *b, int *a) const const
int height() const const
QTableWidgetItem * item(int row, int column) const const
void setSelected(bool select)
char * data()
void setHsv(int h, int s, int v, int a)
void setText(const QString &text)
QString fromLatin1(const char *str, int size)
void sort(Qt::CaseSensitivity cs)
QIcon fromTheme(const QString &name)
int count() const
Returns the total number of color cells in the table.
Horizontal
int saturation() const const
virtual QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const const =0
QPoint pos() const const
QColor color(int index) const
Returns the color at a given index in the table.
virtual bool eventFilter(QObject *o, QEvent *e) override
QImage toImage() const const
virtual bool event(QEvent *e) override
void setColor(const QColor &col)
Preselects a color.
void setBackgroundRole(QPalette::ColorRole role)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
~KColorDialog()
Destroys the color selection dialog.
QHeaderView * horizontalHeader() const const
QWIDGETSIZE_MAXQWIDGETSIZE_MAX
void setVerticalScrollBarPolicy(Qt::ScrollBarPolicy)
T readEntry(const QString &key, const T &aDefault) const
void revertToDefault(const QString &key)
Key_Escape
QSize sizeHint() const override
Reimplemented from QDialog.
Definition: kdialog.cpp:389
void setSpacing(int spacing)
int height() const const
int startDragDistance()
QString locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
bool isValid() const const
void addLayout(QLayout *layout, int stretch)
void setDragEnabled(bool enable)
qint64 readLine(char *data, qint64 maxSize)
KColorCells(QWidget *parent, int rows, int columns)
Constructs a new table of color cells, consisting of rows * columns colors.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Aug 7 2020 22:56:37 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.