/thirdparty/qtcolorpicker-2.6/qtcolorpicker.cpp

https://code.google.com/p/dwarftherapist/ · C++ · 1145 lines · 666 code · 140 blank · 339 comment · 130 complexity · 807dede529b674e3ec409496e1c861a4 MD5 · raw file

  1. /****************************************************************************
  2. **
  3. ** This file is part of a Qt Solutions component.
  4. **
  5. ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
  6. **
  7. ** Contact: Qt Software Information (qt-info@nokia.com)
  8. **
  9. ** Commercial Usage
  10. ** Licensees holding valid Qt Commercial licenses may use this file in
  11. ** accordance with the Qt Solutions Commercial License Agreement provided
  12. ** with the Software or, alternatively, in accordance with the terms
  13. ** contained in a written agreement between you and Nokia.
  14. **
  15. ** GNU Lesser General Public License Usage
  16. ** Alternatively, this file may be used under the terms of the GNU Lesser
  17. ** General Public License version 2.1 as published by the Free Software
  18. ** Foundation and appearing in the file LICENSE.LGPL included in the
  19. ** packaging of this file. Please review the following information to
  20. ** ensure the GNU Lesser General Public License version 2.1 requirements
  21. ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  22. **
  23. ** In addition, as a special exception, Nokia gives you certain
  24. ** additional rights. These rights are described in the Nokia Qt LGPL
  25. ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
  26. ** package.
  27. **
  28. ** GNU General Public License Usage
  29. ** Alternatively, this file may be used under the terms of the GNU
  30. ** General Public License version 3.0 as published by the Free Software
  31. ** Foundation and appearing in the file LICENSE.GPL included in the
  32. ** packaging of this file. Please review the following information to
  33. ** ensure the GNU General Public License version 3.0 requirements will be
  34. ** met: http://www.gnu.org/copyleft/gpl.html.
  35. **
  36. ** Please note Third Party Software included with Qt Solutions may impose
  37. ** additional restrictions and it is the user's responsibility to ensure
  38. ** that they have met the licensing requirements of the GPL, LGPL, or Qt
  39. ** Solutions Commercial license and the relevant license of the Third
  40. ** Party Software they are using.
  41. **
  42. ** If you are unsure which license is appropriate for your use, please
  43. ** contact the sales department at qt-sales@nokia.com.
  44. **
  45. ****************************************************************************/
  46. #include <QtGui/QApplication>
  47. #include <QtGui/QDesktopWidget>
  48. #include <QtGui/QPainter>
  49. #include <QtGui/QPushButton>
  50. #include <QtGui/QColorDialog>
  51. #include <QtCore/QMap>
  52. #include <QtGui/QLayout>
  53. #include <QtGui/QStyle>
  54. #include <QtGui/QLabel>
  55. #include <QtGui/QToolTip>
  56. #include <QtGui/QPixmap>
  57. #include <QtGui/QFocusEvent>
  58. #include <QtGui/QPaintEvent>
  59. #include <QtGui/QGridLayout>
  60. #include <QtGui/QHideEvent>
  61. #include <QtGui/QKeyEvent>
  62. #include <QtGui/QShowEvent>
  63. #include <QtGui/QMouseEvent>
  64. #include <math.h>
  65. #include "utils.h"
  66. #include "qtcolorpicker.h"
  67. /*! \class QtColorPicker
  68. \brief The QtColorPicker class provides a widget for selecting
  69. colors from a popup color grid.
  70. Users can invoke the color picker by clicking on it, or by
  71. navigating to it and pressing Space. They can use the mouse or
  72. arrow keys to navigate between colors on the grid, and select a
  73. color by clicking or by pressing Enter or Space. The
  74. colorChanged() signal is emitted whenever the color picker's color
  75. changes.
  76. The widget also supports negative selection: Users can click and
  77. hold the mouse button on the QtColorPicker widget, then move the
  78. mouse over the color grid and release the mouse button over the
  79. color they wish to select.
  80. The color grid shows a customized selection of colors. An optional
  81. ellipsis "..." button (signifying "more") can be added at the
  82. bottom of the grid; if the user presses this, a QColorDialog pops
  83. up and lets them choose any color they like. This button is made
  84. available by using setColorDialogEnabled().
  85. When a color is selected, the QtColorPicker widget shows the color
  86. and its name. If the name cannot be determined, the translatable
  87. name "Custom" is used.
  88. The QtColorPicker object is optionally initialized with the number
  89. of columns in the color grid. Colors are then added left to right,
  90. top to bottom using insertColor(). If the number of columns is not
  91. set, QtColorPicker calculates the number of columns and rows that
  92. will make the grid as square as possible.
  93. \code
  94. DrawWidget::DrawWidget(QWidget *parent, const char *name)
  95. {
  96. QtColorPicker *picker = new QtColorPicker(this);
  97. picker->insertColor(red, "Red"));
  98. picker->insertColor(QColor("green"), "Green"));
  99. picker->insertColor(QColor(0, 0, 255), "Blue"));
  100. picker->insertColor(white);
  101. connect(colors, SIGNAL(colorChanged(const QColor &)), SLOT(setCurrentColor(const QColor &)));
  102. }
  103. \endcode
  104. An alternative to adding colors manually is to initialize the grid
  105. with QColorDialog's standard colors using setStandardColors().
  106. QtColorPicker also provides a the static function getColor(),
  107. which pops up the grid of standard colors at any given point.
  108. \img colorpicker1.png
  109. \img colorpicker2.png
  110. \sa QColorDialog
  111. */
  112. /*! \fn QtColorPicker::colorChanged(const QColor &color)
  113. This signal is emitted when the QtColorPicker's color is changed.
  114. \a color is the new color.
  115. To obtain the color's name, use text().
  116. */
  117. /*
  118. A class that acts very much like a QPushButton. It's not styled,
  119. so we can expect the exact same look, feel and geometry
  120. everywhere. Also, this button always emits clicked on
  121. mouseRelease, even if the mouse button was not pressed inside the
  122. widget.
  123. */
  124. class ColorPickerButton : public QFrame
  125. {
  126. Q_OBJECT
  127. public:
  128. ColorPickerButton(QWidget *parent);
  129. signals:
  130. void clicked();
  131. protected:
  132. void mousePressEvent(QMouseEvent *e);
  133. void mouseMoveEvent(QMouseEvent *e);
  134. void mouseReleaseEvent(QMouseEvent *e);
  135. void keyPressEvent(QKeyEvent *e);
  136. void keyReleaseEvent(QKeyEvent *e);
  137. void paintEvent(QPaintEvent *e);
  138. void focusInEvent(QFocusEvent *e);
  139. void focusOutEvent(QFocusEvent *e);
  140. };
  141. /*
  142. This class represents each "color" or item in the color grid.
  143. */
  144. class ColorPickerItem : public QFrame
  145. {
  146. Q_OBJECT
  147. public:
  148. ColorPickerItem(const QColor &color = Qt::white, const QString &text = QString::null,
  149. QWidget *parent = 0);
  150. ~ColorPickerItem();
  151. QColor color() const;
  152. QString text() const;
  153. void setSelected(bool);
  154. bool isSelected() const;
  155. signals:
  156. void clicked();
  157. void selected();
  158. public slots:
  159. void setColor(const QColor &color, const QString &text = QString());
  160. protected:
  161. void mousePressEvent(QMouseEvent *e);
  162. void mouseReleaseEvent(QMouseEvent *e);
  163. void mouseMoveEvent(QMouseEvent *e);
  164. void paintEvent(QPaintEvent *e);
  165. private:
  166. QColor c;
  167. QString t;
  168. bool sel;
  169. };
  170. /*
  171. */
  172. class ColorPickerPopup : public QFrame
  173. {
  174. Q_OBJECT
  175. public:
  176. ColorPickerPopup(int width, bool withColorDialog,
  177. QWidget *parent = 0);
  178. ~ColorPickerPopup();
  179. void insertColor(const QColor &col, const QString &text, int index);
  180. void exec();
  181. void setExecFlag();
  182. QColor lastSelected() const;
  183. ColorPickerItem *find(const QColor &col) const;
  184. QColor color(int index) const;
  185. signals:
  186. void selected(const QColor &);
  187. void hid();
  188. public slots:
  189. void getColorFromDialog();
  190. protected slots:
  191. void updateSelected();
  192. protected:
  193. void keyPressEvent(QKeyEvent *e);
  194. void showEvent(QShowEvent *e);
  195. void hideEvent(QHideEvent *e);
  196. void mouseReleaseEvent(QMouseEvent *e);
  197. void regenerateGrid();
  198. private:
  199. QMap<int, QMap<int, QWidget *> > widgetAt;
  200. QList<ColorPickerItem *> items;
  201. QGridLayout *grid;
  202. ColorPickerButton *moreButton;
  203. QEventLoop *eventLoop;
  204. int lastPos;
  205. int cols;
  206. QColor lastSel;
  207. };
  208. /*!
  209. Constructs a QtColorPicker widget. The popup will display a grid
  210. with \a cols columns, or if \a cols is -1, the number of columns
  211. will be calculated automatically.
  212. If \a enableColorDialog is true, the popup will also have a "More"
  213. button (signified by an ellipsis "...") that presents a
  214. QColorDialog when clicked.
  215. After constructing a QtColorPicker, call insertColor() to add
  216. individual colors to the popup grid, or call setStandardColors()
  217. to add all the standard colors in one go.
  218. The \a parent argument is passed to QFrame's constructor.
  219. \sa QFrame
  220. */
  221. QtColorPicker::QtColorPicker(QWidget *parent,
  222. int cols, bool enableColorDialog)
  223. : QPushButton(parent), popup(0), withColorDialog(enableColorDialog)
  224. {
  225. setFocusPolicy(Qt::StrongFocus);
  226. setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
  227. setAutoDefault(false);
  228. setAutoFillBackground(true);
  229. setCheckable(true);
  230. // Set text
  231. setText(tr("Black"));
  232. firstInserted = false;
  233. // Create and set icon
  234. col = Qt::black;
  235. dirty = true;
  236. // Create color grid popup and connect to it.
  237. popup = new ColorPickerPopup(cols, withColorDialog, this);
  238. connect(popup, SIGNAL(selected(const QColor &)),
  239. SLOT(setCurrentColor(const QColor &)));
  240. connect(popup, SIGNAL(hid()), SLOT(popupClosed()));
  241. // Connect this push button's pressed() signal.
  242. connect(this, SIGNAL(toggled(bool)), SLOT(buttonPressed(bool)));
  243. }
  244. /*!
  245. Destructs the QtColorPicker.
  246. */
  247. QtColorPicker::~QtColorPicker()
  248. {
  249. }
  250. /*! \internal
  251. Pops up the color grid, and makes sure the status of
  252. QtColorPicker's button is right.
  253. */
  254. void QtColorPicker::buttonPressed(bool toggled)
  255. {
  256. if (!toggled)
  257. return;
  258. const QRect desktop = QApplication::desktop()->geometry();
  259. // Make sure the popup is inside the desktop.
  260. QPoint pos = mapToGlobal(rect().bottomLeft());
  261. if (pos.x() < desktop.left())
  262. pos.setX(desktop.left());
  263. if (pos.y() < desktop.top())
  264. pos.setY(desktop.top());
  265. if ((pos.x() + popup->sizeHint().width()) > desktop.width())
  266. pos.setX(desktop.width() - popup->sizeHint().width());
  267. if ((pos.y() + popup->sizeHint().height()) > desktop.bottom())
  268. pos.setY(desktop.bottom() - popup->sizeHint().height());
  269. popup->move(pos);
  270. if (ColorPickerItem *item = popup->find(col))
  271. item->setSelected(true);
  272. // Remove focus from this widget, preventing the focus rect
  273. // from showing when the popup is shown. Order an update to
  274. // make sure the focus rect is cleared.
  275. clearFocus();
  276. update();
  277. // Allow keyboard navigation as soon as the popup shows.
  278. popup->setFocus();
  279. // Execute the popup. The popup will enter the event loop.
  280. popup->show();
  281. }
  282. /*!
  283. \internal
  284. */
  285. void QtColorPicker::paintEvent(QPaintEvent *e)
  286. {
  287. if (dirty) {
  288. int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize);
  289. QPixmap pix(iconSize, iconSize);
  290. pix.fill(palette().button().color());
  291. QPainter p(&pix);
  292. int w = pix.width(); // width of cell in pixels
  293. int h = pix.height(); // height of cell in pixels
  294. p.setPen(QPen(Qt::gray));
  295. p.setBrush(col);
  296. p.drawRect(2, 2, w - 5, h - 5);
  297. setIcon(QIcon(pix));
  298. dirty = false;
  299. }
  300. QPushButton::paintEvent(e);
  301. }
  302. /*! \internal
  303. Makes sure the button isn't pressed when the popup hides.
  304. */
  305. void QtColorPicker::popupClosed()
  306. {
  307. setChecked(false);
  308. setFocus();
  309. }
  310. /*!
  311. Returns the currently selected color.
  312. \sa text()
  313. */
  314. QColor QtColorPicker::currentColor() const
  315. {
  316. return col;
  317. }
  318. /*!
  319. Returns the color at position \a index.
  320. */
  321. QColor QtColorPicker::color(int index) const
  322. {
  323. return popup->color(index);
  324. }
  325. /*!
  326. Adds the 17 predefined colors from the Qt namespace.
  327. (The names given to the colors, "Black", "White", "Red", etc., are
  328. all translatable.)
  329. \sa insertColor()
  330. */
  331. void QtColorPicker::setStandardColors()
  332. {
  333. insertColor(Qt::black, tr("Black"));
  334. insertColor(Qt::white, tr("White"));
  335. insertColor(Qt::red, tr("Red"));
  336. insertColor(Qt::darkRed, tr("Dark red"));
  337. insertColor(Qt::green, tr("Green"));
  338. insertColor(Qt::darkGreen, tr("Dark green"));
  339. insertColor(Qt::blue, tr("Blue"));
  340. insertColor(Qt::darkBlue, tr("Dark blue"));
  341. insertColor(Qt::cyan, tr("Cyan"));
  342. insertColor(Qt::darkCyan, tr("Dark cyan"));
  343. insertColor(Qt::magenta, tr("Magenta"));
  344. insertColor(Qt::darkMagenta, tr("Dark magenta"));
  345. insertColor(Qt::yellow, tr("Yellow"));
  346. insertColor(Qt::darkYellow, tr("Dark yellow"));
  347. insertColor(Qt::gray, tr("Gray"));
  348. insertColor(Qt::darkGray, tr("Dark gray"));
  349. insertColor(Qt::lightGray, tr("Light gray"));
  350. }
  351. /*!
  352. Makes \a color current. If \a color is not already in the color grid, it
  353. is inserted with the text "Custom".
  354. This function emits the colorChanged() signal if the new color is
  355. valid, and different from the old one.
  356. */
  357. void QtColorPicker::setCurrentColor(const QColor &color)
  358. {
  359. if (col == color || !color.isValid())
  360. return;
  361. ColorPickerItem *item = popup->find(color);
  362. if (!item) {
  363. insertColor(color, tr("Custom HEX #%1").arg(to_hex(color)));
  364. item = popup->find(color);
  365. }
  366. col = color;
  367. setText(item->text());
  368. dirty = true;
  369. popup->hide();
  370. repaint();
  371. item->setSelected(true);
  372. emit colorChanged(color);
  373. }
  374. /*!
  375. Adds the color \a color with the name \a text to the color grid,
  376. at position \a index. If index is -1, the color is assigned
  377. automatically assigned a position, starting from left to right,
  378. top to bottom.
  379. */
  380. void QtColorPicker::insertColor(const QColor &color, const QString &text, int index)
  381. {
  382. popup->insertColor(color, text, index);
  383. if (!firstInserted) {
  384. col = color;
  385. setText(text);
  386. firstInserted = true;
  387. }
  388. }
  389. /*! \property QtColorPicker::colorDialog
  390. \brief Whether the ellipsis "..." (more) button is available.
  391. If this property is set to TRUE, the color grid popup will include
  392. a "More" button (signified by an ellipsis, "...") which pops up a
  393. QColorDialog when clicked. The user will then be able to select
  394. any custom color they like.
  395. */
  396. void QtColorPicker::setColorDialogEnabled(bool enabled)
  397. {
  398. withColorDialog = enabled;
  399. }
  400. bool QtColorPicker::colorDialogEnabled() const
  401. {
  402. return withColorDialog;
  403. }
  404. /*!
  405. Pops up a color grid with Qt default colors at \a point, using
  406. global coordinates. If \a allowCustomColors is true, there will
  407. also be a button on the popup that invokes QColorDialog.
  408. For example:
  409. \code
  410. void Drawer::mouseReleaseEvent(QMouseEvent *e)
  411. {
  412. if (e->button() & RightButton) {
  413. QColor color = QtColorPicker::getColor(mapToGlobal(e->pos()));
  414. }
  415. }
  416. \endcode
  417. */
  418. QColor QtColorPicker::getColor(const QPoint &point, bool allowCustomColors)
  419. {
  420. ColorPickerPopup popup(-1, allowCustomColors);
  421. popup.insertColor(Qt::black, tr("Black"), 0);
  422. popup.insertColor(Qt::white, tr("White"), 1);
  423. popup.insertColor(Qt::red, tr("Red"), 2);
  424. popup.insertColor(Qt::darkRed, tr("Dark red"), 3);
  425. popup.insertColor(Qt::green, tr("Green"), 4);
  426. popup.insertColor(Qt::darkGreen, tr("Dark green"), 5);
  427. popup.insertColor(Qt::blue, tr("Blue"), 6);
  428. popup.insertColor(Qt::darkBlue, tr("Dark blue"), 7);
  429. popup.insertColor(Qt::cyan, tr("Cyan"), 8);
  430. popup.insertColor(Qt::darkCyan, tr("Dark cyan"), 9);
  431. popup.insertColor(Qt::magenta, tr("Magenta"), 10);
  432. popup.insertColor(Qt::darkMagenta, tr("Dark magenta"), 11);
  433. popup.insertColor(Qt::yellow, tr("Yellow"), 12);
  434. popup.insertColor(Qt::darkYellow, tr("Dark yellow"), 13);
  435. popup.insertColor(Qt::gray, tr("Gray"), 14);
  436. popup.insertColor(Qt::darkGray, tr("Dark gray"), 15);
  437. popup.insertColor(Qt::lightGray, tr("Light gray"), 16);
  438. popup.move(point);
  439. popup.exec();
  440. return popup.lastSelected();
  441. }
  442. /*! \internal
  443. Constructs the popup widget.
  444. */
  445. ColorPickerPopup::ColorPickerPopup(int width, bool withColorDialog,
  446. QWidget *parent)
  447. : QFrame(parent, Qt::Popup)
  448. {
  449. setFrameStyle(QFrame::StyledPanel);
  450. setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
  451. setFocusPolicy(Qt::StrongFocus);
  452. setMouseTracking(true);
  453. cols = width;
  454. if (withColorDialog) {
  455. moreButton = new ColorPickerButton(this);
  456. moreButton->setFixedWidth(24);
  457. moreButton->setFixedHeight(21);
  458. moreButton->setFrameRect(QRect(2, 2, 20, 17));
  459. connect(moreButton, SIGNAL(clicked()), SLOT(getColorFromDialog()));
  460. } else {
  461. moreButton = 0;
  462. }
  463. eventLoop = 0;
  464. grid = 0;
  465. regenerateGrid();
  466. }
  467. /*! \internal
  468. Destructs the popup widget.
  469. */
  470. ColorPickerPopup::~ColorPickerPopup()
  471. {
  472. if (eventLoop)
  473. eventLoop->exit();
  474. }
  475. /*! \internal
  476. If there is an item whole color is equal to \a col, returns a
  477. pointer to this item; otherwise returns 0.
  478. */
  479. ColorPickerItem *ColorPickerPopup::find(const QColor &col) const
  480. {
  481. for (int i = 0; i < items.size(); ++i) {
  482. if (items.at(i) && items.at(i)->color() == col)
  483. return items.at(i);
  484. }
  485. return 0;
  486. }
  487. /*! \internal
  488. Adds \a item to the grid. The items are added from top-left to
  489. bottom-right.
  490. */
  491. void ColorPickerPopup::insertColor(const QColor &col, const QString &text, int index)
  492. {
  493. // Don't add colors that we have already.
  494. ColorPickerItem *existingItem = find(col);
  495. ColorPickerItem *lastSelectedItem = find(lastSelected());
  496. if (existingItem) {
  497. if (lastSelectedItem && existingItem != lastSelectedItem)
  498. lastSelectedItem->setSelected(false);
  499. existingItem->setFocus();
  500. existingItem->setSelected(true);
  501. return;
  502. }
  503. ColorPickerItem *item = new ColorPickerItem(col, text, this);
  504. if (lastSelectedItem) {
  505. lastSelectedItem->setSelected(false);
  506. }
  507. else {
  508. item->setSelected(true);
  509. lastSel = col;
  510. }
  511. item->setFocus();
  512. connect(item, SIGNAL(selected()), SLOT(updateSelected()));
  513. if (index == -1)
  514. index = items.count();
  515. items.insert((unsigned int)index, item);
  516. regenerateGrid();
  517. update();
  518. }
  519. /*! \internal
  520. */
  521. QColor ColorPickerPopup::color(int index) const
  522. {
  523. if (index < 0 || index > (int) items.count() - 1)
  524. return QColor();
  525. ColorPickerPopup *that = (ColorPickerPopup *)this;
  526. return that->items.at(index)->color();
  527. }
  528. /*! \internal
  529. */
  530. void ColorPickerPopup::exec()
  531. {
  532. show();
  533. QEventLoop e;
  534. eventLoop = &e;
  535. (void) e.exec();
  536. eventLoop = 0;
  537. }
  538. /*! \internal
  539. */
  540. void ColorPickerPopup::updateSelected()
  541. {
  542. QLayoutItem *layoutItem;
  543. int i = 0;
  544. while ((layoutItem = grid->itemAt(i)) != 0) {
  545. QWidget *w = layoutItem->widget();
  546. if (w && w->inherits("ColorPickerItem")) {
  547. ColorPickerItem *litem = reinterpret_cast<ColorPickerItem *>(layoutItem->widget());
  548. if (litem != sender())
  549. litem->setSelected(false);
  550. }
  551. ++i;
  552. }
  553. if (sender() && sender()->inherits("ColorPickerItem")) {
  554. ColorPickerItem *item = (ColorPickerItem *)sender();
  555. lastSel = item->color();
  556. emit selected(item->color());
  557. }
  558. hide();
  559. }
  560. /*! \internal
  561. */
  562. void ColorPickerPopup::mouseReleaseEvent(QMouseEvent *e)
  563. {
  564. if (!rect().contains(e->pos()))
  565. hide();
  566. }
  567. /*! \internal
  568. Controls keyboard navigation and selection on the color grid.
  569. */
  570. void ColorPickerPopup::keyPressEvent(QKeyEvent *e)
  571. {
  572. int curRow = 0;
  573. int curCol = 0;
  574. bool foundFocus = false;
  575. for (int j = 0; !foundFocus && j < grid->rowCount(); ++j) {
  576. for (int i = 0; !foundFocus && i < grid->columnCount(); ++i) {
  577. if (widgetAt[j][i] && widgetAt[j][i]->hasFocus()) {
  578. curRow = j;
  579. curCol = i;
  580. foundFocus = true;
  581. break;
  582. }
  583. }
  584. }
  585. switch (e->key()) {
  586. case Qt::Key_Left:
  587. if (curCol > 0) --curCol;
  588. else if (curRow > 0) { --curRow; curCol = grid->columnCount() - 1; }
  589. break;
  590. case Qt::Key_Right:
  591. if (curCol < grid->columnCount() - 1 && widgetAt[curRow][curCol + 1]) ++curCol;
  592. else if (curRow < grid->rowCount() - 1) { ++curRow; curCol = 0; }
  593. break;
  594. case Qt::Key_Up:
  595. if (curRow > 0) --curRow;
  596. else curCol = 0;
  597. break;
  598. case Qt::Key_Down:
  599. if (curRow < grid->rowCount() - 1) {
  600. QWidget *w = widgetAt[curRow + 1][curCol];
  601. if (w) {
  602. ++curRow;
  603. } else for (int i = 1; i < grid->columnCount(); ++i) {
  604. if (!widgetAt[curRow + 1][i]) {
  605. curCol = i - 1;
  606. ++curRow;
  607. break;
  608. }
  609. }
  610. }
  611. break;
  612. case Qt::Key_Space:
  613. case Qt::Key_Return:
  614. case Qt::Key_Enter: {
  615. QWidget *w = widgetAt[curRow][curCol];
  616. if (w && w->inherits("ColorPickerItem")) {
  617. ColorPickerItem *wi = reinterpret_cast<ColorPickerItem *>(w);
  618. wi->setSelected(true);
  619. QLayoutItem *layoutItem;
  620. int i = 0;
  621. while ((layoutItem = grid->itemAt(i)) != 0) {
  622. QWidget *w = layoutItem->widget();
  623. if (w && w->inherits("ColorPickerItem")) {
  624. ColorPickerItem *litem
  625. = reinterpret_cast<ColorPickerItem *>(layoutItem->widget());
  626. if (litem != wi)
  627. litem->setSelected(false);
  628. }
  629. ++i;
  630. }
  631. lastSel = wi->color();
  632. emit selected(wi->color());
  633. hide();
  634. } else if (w && w->inherits("QPushButton")) {
  635. ColorPickerItem *wi = reinterpret_cast<ColorPickerItem *>(w);
  636. wi->setSelected(true);
  637. QLayoutItem *layoutItem;
  638. int i = 0;
  639. while ((layoutItem = grid->itemAt(i)) != 0) {
  640. QWidget *w = layoutItem->widget();
  641. if (w && w->inherits("ColorPickerItem")) {
  642. ColorPickerItem *litem
  643. = reinterpret_cast<ColorPickerItem *>(layoutItem->widget());
  644. if (litem != wi)
  645. litem->setSelected(false);
  646. }
  647. ++i;
  648. }
  649. lastSel = wi->color();
  650. emit selected(wi->color());
  651. hide();
  652. }
  653. }
  654. break;
  655. case Qt::Key_Escape:
  656. hide();
  657. break;
  658. default:
  659. e->ignore();
  660. break;
  661. }
  662. widgetAt[curRow][curCol]->setFocus();
  663. }
  664. /*! \internal
  665. */
  666. void ColorPickerPopup::hideEvent(QHideEvent *e)
  667. {
  668. if (eventLoop) {
  669. eventLoop->exit();
  670. }
  671. setFocus();
  672. emit hid();
  673. QFrame::hideEvent(e);
  674. }
  675. /*! \internal
  676. */
  677. QColor ColorPickerPopup::lastSelected() const
  678. {
  679. return lastSel;
  680. }
  681. /*! \internal
  682. Sets focus on the popup to enable keyboard navigation. Draws
  683. focusRect and selection rect.
  684. */
  685. void ColorPickerPopup::showEvent(QShowEvent *)
  686. {
  687. bool foundSelected = false;
  688. for (int i = 0; i < grid->columnCount(); ++i) {
  689. for (int j = 0; j < grid->rowCount(); ++j) {
  690. QWidget *w = widgetAt[j][i];
  691. if (w && w->inherits("ColorPickerItem")) {
  692. if (((ColorPickerItem *)w)->isSelected()) {
  693. w->setFocus();
  694. foundSelected = true;
  695. break;
  696. }
  697. }
  698. }
  699. }
  700. if (!foundSelected) {
  701. if (items.count() == 0)
  702. setFocus();
  703. else
  704. widgetAt[0][0]->setFocus();
  705. }
  706. }
  707. /*!
  708. */
  709. void ColorPickerPopup::regenerateGrid()
  710. {
  711. widgetAt.clear();
  712. int columns = cols;
  713. if (columns == -1)
  714. columns = (int) ceil(sqrt((float) items.count()));
  715. // When the number of columns grows, the number of rows will
  716. // fall. There's no way to shrink a grid, so we create a new
  717. // one.
  718. if (grid) delete grid;
  719. grid = new QGridLayout(this);
  720. grid->setMargin(1);
  721. grid->setSpacing(0);
  722. int ccol = 0, crow = 0;
  723. for (int i = 0; i < items.size(); ++i) {
  724. if (items.at(i)) {
  725. widgetAt[crow][ccol] = items.at(i);
  726. grid->addWidget(items.at(i), crow, ccol++);
  727. if (ccol == columns) {
  728. ++crow;
  729. ccol = 0;
  730. }
  731. }
  732. }
  733. if (moreButton) {
  734. grid->addWidget(moreButton, crow, ccol);
  735. widgetAt[crow][ccol] = moreButton;
  736. }
  737. updateGeometry();
  738. }
  739. /*! \internal
  740. Copies the color dialog's currently selected item and emits
  741. itemSelected().
  742. */
  743. void ColorPickerPopup::getColorFromDialog()
  744. {
  745. bool ok;
  746. QRgb rgb = QColorDialog::getRgba(lastSel.rgba(), &ok, parentWidget());
  747. if (!ok)
  748. return;
  749. QColor col = QColor::fromRgba(rgb);
  750. insertColor(col, tr("Custom (#%1)").arg(to_hex(col)), -1);
  751. lastSel = col;
  752. emit selected(col);
  753. }
  754. /*!
  755. Constructs a ColorPickerItem whose color is set to \a color, and
  756. whose name is set to \a text.
  757. */
  758. ColorPickerItem::ColorPickerItem(const QColor &color, const QString &text,
  759. QWidget *parent)
  760. : QFrame(parent), c(color), t(text), sel(false)
  761. {
  762. setToolTip(t);
  763. setFixedWidth(24);
  764. setFixedHeight(21);
  765. }
  766. /*!
  767. Destructs a ColorPickerItem.
  768. */
  769. ColorPickerItem::~ColorPickerItem()
  770. {
  771. }
  772. /*!
  773. Returns the item's color.
  774. \sa text()
  775. */
  776. QColor ColorPickerItem::color() const
  777. {
  778. return c;
  779. }
  780. /*!
  781. Returns the item's text.
  782. \sa color()
  783. */
  784. QString ColorPickerItem::text() const
  785. {
  786. return t;
  787. }
  788. /*!
  789. */
  790. bool ColorPickerItem::isSelected() const
  791. {
  792. return sel;
  793. }
  794. /*!
  795. */
  796. void ColorPickerItem::setSelected(bool selected)
  797. {
  798. sel = selected;
  799. update();
  800. }
  801. /*!
  802. Sets the item's color to \a color, and its name to \a text.
  803. */
  804. void ColorPickerItem::setColor(const QColor &color, const QString &text)
  805. {
  806. c = color;
  807. t = text;
  808. setToolTip(t);
  809. update();
  810. }
  811. /*!
  812. */
  813. void ColorPickerItem::mouseMoveEvent(QMouseEvent *)
  814. {
  815. setFocus();
  816. update();
  817. }
  818. /*!
  819. */
  820. void ColorPickerItem::mouseReleaseEvent(QMouseEvent *)
  821. {
  822. sel = true;
  823. emit selected();
  824. }
  825. /*!
  826. */
  827. void ColorPickerItem::mousePressEvent(QMouseEvent *)
  828. {
  829. setFocus();
  830. update();
  831. }
  832. /*!
  833. */
  834. void ColorPickerItem::paintEvent(QPaintEvent *)
  835. {
  836. QPainter p(this);
  837. int w = width(); // width of cell in pixels
  838. int h = height(); // height of cell in pixels
  839. p.setPen( QPen( Qt::gray, 0, Qt::SolidLine ) );
  840. if (sel)
  841. p.drawRect(1, 1, w - 3, h - 3);
  842. p.setPen( QPen( Qt::black, 0, Qt::SolidLine ) );
  843. p.drawRect(3, 3, w - 7, h - 7);
  844. p.fillRect(QRect(4, 4, w - 8, h - 8), QBrush(c));
  845. if (hasFocus())
  846. p.drawRect(0, 0, w - 1, h - 1);
  847. }
  848. /*!
  849. */
  850. ColorPickerButton::ColorPickerButton(QWidget *parent)
  851. : QFrame(parent)
  852. {
  853. setFrameStyle(StyledPanel);
  854. }
  855. /*!
  856. */
  857. void ColorPickerButton::mousePressEvent(QMouseEvent *)
  858. {
  859. setFrameShadow(Sunken);
  860. update();
  861. }
  862. /*!
  863. */
  864. void ColorPickerButton::mouseMoveEvent(QMouseEvent *)
  865. {
  866. setFocus();
  867. update();
  868. }
  869. /*!
  870. */
  871. void ColorPickerButton::mouseReleaseEvent(QMouseEvent *)
  872. {
  873. setFrameShadow(Raised);
  874. repaint();
  875. emit clicked();
  876. }
  877. /*!
  878. */
  879. void ColorPickerButton::keyPressEvent(QKeyEvent *e)
  880. {
  881. if (e->key() == Qt::Key_Up
  882. || e->key() == Qt::Key_Down
  883. || e->key() == Qt::Key_Left
  884. || e->key() == Qt::Key_Right) {
  885. qApp->sendEvent(parent(), e);
  886. } else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Space || e->key() == Qt::Key_Return) {
  887. setFrameShadow(Sunken);
  888. update();
  889. } else {
  890. QFrame::keyPressEvent(e);
  891. }
  892. }
  893. /*!
  894. */
  895. void ColorPickerButton::keyReleaseEvent(QKeyEvent *e)
  896. {
  897. if (e->key() == Qt::Key_Up
  898. || e->key() == Qt::Key_Down
  899. || e->key() == Qt::Key_Left
  900. || e->key() == Qt::Key_Right) {
  901. qApp->sendEvent(parent(), e);
  902. } else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Space || e->key() == Qt::Key_Return) {
  903. setFrameShadow(Raised);
  904. repaint();
  905. emit clicked();
  906. } else {
  907. QFrame::keyReleaseEvent(e);
  908. }
  909. }
  910. /*!
  911. */
  912. void ColorPickerButton::focusInEvent(QFocusEvent *e)
  913. {
  914. setFrameShadow(Raised);
  915. update();
  916. QFrame::focusOutEvent(e);
  917. }
  918. /*!
  919. */
  920. void ColorPickerButton::focusOutEvent(QFocusEvent *e)
  921. {
  922. setFrameShadow(Raised);
  923. update();
  924. QFrame::focusOutEvent(e);
  925. }
  926. /*!
  927. */
  928. void ColorPickerButton::paintEvent(QPaintEvent *e)
  929. {
  930. QFrame::paintEvent(e);
  931. QPainter p(this);
  932. p.fillRect(contentsRect(), palette().button());
  933. QRect r = rect();
  934. int offset = frameShadow() == Sunken ? 1 : 0;
  935. QPen pen(palette().buttonText(), 1);
  936. p.setPen(pen);
  937. p.drawRect(r.center().x() + offset - 4, r.center().y() + offset, 1, 1);
  938. p.drawRect(r.center().x() + offset , r.center().y() + offset, 1, 1);
  939. p.drawRect(r.center().x() + offset + 4, r.center().y() + offset, 1, 1);
  940. if (hasFocus()) {
  941. p.setPen( QPen( Qt::black, 0, Qt::SolidLine ) );
  942. p.drawRect(0, 0, width() - 1, height() - 1);
  943. }
  944. p.end();
  945. }
  946. #include "qtcolorpicker.moc"