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
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 
94 using KDEPrivate::KColorTable;
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 {
423  QColor c = KColorMimeData::fromMimeData(event->mimeData());
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 
499 QColor KColorPatch::color() const
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 {
535  QColor c = KColorMimeData::fromMimeData(event->mimeData());
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;
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::error(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();
942  /**
943  * Write the settings of the dialog to config file.
944  **/
945  void slotWriteSettings();
946 
947  /**
948  * Returns the mode.
949  */
950  KColorChooserMode chooserMode();
951 
952  /**
953  * Sets a mode. Updates the color picker and the color bar.
954  */
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;
984  KColorCollection *palette;
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 
1345 QColor KColorDialog::defaultColor() const
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 
1365 bool KColorDialog::isAlphaChannelEnabled() const
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"
void setDefaultColor(const QColor &defaultCol)
Call this to make the dialog show a "Default Color" checkbox.
void append(const T &value)
A table of editable color cells.
Definition: kcolordialog.h:41
QPoint pos() const const
AlignLeft
bool isNull() const const
virtual bool eventFilter(QObject *o, QEvent *e) override
virtual void setData(int role, const QVariant &value)
virtual QSize sizeHint() const const override
void setPen(const QColor &color)
QWidget * mainWidget()
Definition: kdialog.cpp:380
virtual void mouseReleaseEvent(QMouseEvent *event) override
BackgroundRole
QDesktopWidget * desktop()
QWidget(QWidget *parent, Qt::WindowFlags f)
void setColor(const QColor &col)
Preselects a color.
SE_RadioButtonContents
QTextStream & endl(QTextStream &stream)
virtual bool event(QEvent *e) override
void resizeSection(int logicalIndex, int size)
void drawEllipse(const QRectF &rectangle)
int right() const const
int removeAll(const T &value)
T value() const const
QLayout * layout() const const
KGUIADDONS_EXPORT qreal hue(const QColor &)
void releaseMouse()
void setItemDelegate(QAbstractItemDelegate *delegate)
void update()
void setColor(const QColor &col)
Set the color to display and update the display.
QRgb rgb() const const
QIcon fromTheme(const QString &name)
void setDragEnabled(bool enable)
void setMainWidget(QWidget *widget)
Sets the main widget of the dialog.
Definition: kdialog.cpp:366
void setSelectionMode(QAbstractItemView::SelectionMode mode)
QByteArray trimmed() const const
void setFrameStyle(int style)
void initFrom(const QWidget *widget)
@ Ok
Show Ok button. (this button accept()s the dialog; result set to QDialog::Accepted)
Definition: kdialog.h:140
~KColorDialog() override
Destroys the color selection dialog.
ScrollBarAlwaysOff
QByteArray toLatin1() const const
void setColor(int index, const QColor &col)
Sets the color in the given index in the table.
int x() const const
int y() const const
const QMimeData * mimeData() const const
virtual bool event(QEvent *e) override
int column(const QTableWidgetItem *item) const const
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
void setFrameShape(QFrame::Shape)
void setHsv(int h, int s, int v, int a)
QColor fromRgbF(qreal r, qreal g, qreal b, qreal a)
LeftButton
QString locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
QPushButton * button(ButtonCode id) const
Returns the button that corresponds to the id.
Definition: kdialog.cpp:702
void setMinimumSize(const QSize &)
virtual void mousePressEvent(QMouseEvent *event) override
void addItem(QLayoutItem *item, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment)
void fillRect(const QRectF &rectangle, const QBrush &brush)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
int findColor(const QColor &color) const
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
int left() const const
void getRgb(int *r, int *g, int *b, int *a) const const
QString i18ncp(const char *context, const char *singular, const char *plural, const TYPE &arg...)
void hide()
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
int saturation() const const
void error(QWidget *parent, const QString &text, const QString &title=QString(), Options options=Notify)
#define I18N_NOOP2(context, text)
QTestData & newRow(const char *dataTag)
QVariant data(int role) const const
void setColumnCount(int columns)
void setColumnStretch(int column, int stretch)
RightArrow
QString & sprintf(const char *cformat,...)
void setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy)
QString i18n(const char *text, const TYPE &arg...)
KGUIADDONS_EXPORT qreal contrastRatio(const QColor &, const QColor &)
QStyle * style() const const
QRgb pixel(int x, int y) const const
int height() const const
KGUIADDONS_EXPORT QColor fromMimeData(const QMimeData *mimeData)
QTableWidgetItem * itemAt(const QPoint &point) const const
void setTabOrder(QWidget *first, QWidget *second)
void addLayout(QLayout *layout, int row, int column, Qt::Alignment alignment)
void setItem(int row, int column, QTableWidgetItem *item)
void colorDoubleClicked(int index, const QColor &color)
Emitted when a color in the table is double-clicked.
QByteArray mid(int pos, int len) const const
Horizontal
bool isEmpty() const const
Qt::MouseButtons buttons() const const
CrossCursor
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.
QColor color(int index) const
Returns the color at a given index in the table.
void setAlpha(int alpha)
int alpha() const const
int x() const const
int y() const const
void setBackgroundRole(QPalette::ColorRole role)
virtual QSize sizeHint() const const override
int value() const const
A dialog base class with standard buttons and predefined layouts.
Definition: kdialog.h:128
virtual int exec()
void setAcceptDrops(bool on)
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
void setMaximumSize(const QSize &)
void okClicked()
The OK button was pressed.
void releaseKeyboard()
Key_Escape
int result() const const
void buttonClicked(KDialog::ButtonCode button)
A button has been pressed.
QImage toImage() const const
void setFixedWidth(int w)
void setBrush(const QBrush &brush)
QColor darker(int factor) const const
virtual void mouseReleaseEvent(QMouseEvent *event)
void setIcon(const QIcon &icon)
void setFixedSize(const QSize &s)
QPixmap grabWindow(WId window, int x, int y, int width, int height)
int row(const QTableWidgetItem *item) const const
void setSelected(bool select)
A color selection dialog.
Definition: kcolordialog.h:211
void colorSelected(int index, const QColor &color)
Emitted when a color is selected in the table.
QHeaderView * verticalHeader() const const
int key() const const
virtual void paintEvent(QPaintEvent *) override
QString fromLatin1(const char *str, int size)
int count() const
Returns the total number of color cells in the table.
QEvent::Type type() const const
void setRgb(int r, int g, int b, int a)
void setObjectName(const QString &name)
QString name(StandardShortcut id)
void addWidget(QWidget *w)
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
QColor toRgb() const const
virtual QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const const=0
QPoint globalPos() const const
void drawLine(const QLineF &line)
void setRowCount(int rows)
KGUIADDONS_EXPORT QDrag * createDrag(const QColor &color, QObject *dragsource)
LeftToRight
void setContentsMargins(int left, int top, int right, int bottom)
QHeaderView * horizontalHeader() const const
void setSpacing(int)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void restore()
bool isValid() const const
virtual void setCaption(const QString &caption)
Make a KDE compliant caption.
Definition: kdialog.cpp:502
void addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment)
WId winId() const const
static QColor grabColor(const QPoint &p)
Gets the color from the pixel at point p on the screen.
@ Cancel
Show Cancel-button. (this button reject()s the dialog; result set to QDialog::Rejected)
Definition: kdialog.h:143
QTableWidgetItem * item(int row, int column) const const
virtual QVariant data(int role) const const
void save()
void addLayout(QLayout *layout, int stretch)
bool activate()
static QStringList installedCollections()
void colorSelected(const QColor &col)
Emitted when a color is selected.
void closeClicked()
The Close button was pressed.
void setSelected(int index)
Sets the currently selected cell to index.
KColorDialog(QWidget *parent=nullptr, bool modal=false)
Constructs a color selection dialog.
int hue() const const
void addSpacing(int size)
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
void getHsv(int *h, int *s, int *v, int *a) const const
QColor lighter(int factor) const const
int selectedIndex() const
Returns the index of the cell which is currently selected.
void setRenderHint(QPainter::RenderHint hint, bool on)
void setLayout(QLayout *layout)
KGUIADDONS_EXPORT bool canDecode(const QMimeData *mimeData)
SolidLine
virtual void mouseMoveEvent(QMouseEvent *event)
QSize sizeHint() const override
Reimplemented from QDialog.
Definition: kdialog.cpp:389
A color displayer.
Definition: kcolordialog.h:117
int addColor(const QColor &newColor, const QString &newColorName=QString())
QWidget * viewport() const const
void setAlphaChannelEnabled(bool alpha)
When set to true, the user is allowed to change the alpha component of the color.
void keyPressEvent(QKeyEvent *) override
Definition: kdialog.cpp:416
void setVerticalScrollBarPolicy(Qt::ScrollBarPolicy)
Qt::DropAction start(Qt::DropActions request)
QObject * parent() const const
void setText(const QString &text)
KColorCells(QWidget *parent, int rows, int columns)
Constructs a new table of color cells, consisting of rows * columns colors.
char * data()
void colorChanged(const QColor &)
This signal is emitted whenever the current color changes due to a drop event.
QRect contentsRect() const const
void accept()
QWIDGETSIZE_MAXQWIDGETSIZE_MAX
void sort(Qt::CaseSensitivity cs)
virtual void mouseMoveEvent(QMouseEvent *event) override
@ Close
Show Close-button. (this button closes the dialog)
Definition: kdialog.h:144
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Wed Sep 28 2022 03:56:32 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.