KWidgetsAddons

kcolorbutton.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 1997 Martin Jones <[email protected]>
4  SPDX-FileCopyrightText: 1999 Cristian Tibirna <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "kcolorbutton.h"
10 
11 #include <QPointer>
12 #include <QPainter>
13 #include <qdrawutil.h>
14 #include <QApplication>
15 #include <QColorDialog>
16 #include <QClipboard>
17 #include <QMimeData>
18 #include <QDrag>
19 #include <QStyle>
20 #include <QMouseEvent>
21 #include <QStyleOptionButton>
22 
23 class Q_DECL_HIDDEN KColorButton::KColorButtonPrivate
24 {
25 public:
26  KColorButtonPrivate(KColorButton *q);
27 
28  void _k_chooseColor();
29  void _k_colorChosen();
30 
31  KColorButton *q;
32  QColor m_defaultColor;
33  bool m_bdefaultColor : 1;
34  bool m_alphaChannel : 1;
35 
36  QColor col;
37  QPoint mPos;
38 
39  QPointer<QColorDialog> dialogPtr;
40 
41  void initStyleOption(QStyleOptionButton *opt) const;
42 };
43 
45 // Functions duplicated from KColorMimeData
46 // Should be kept in sync
47 void _k_populateMimeData(QMimeData *mimeData, const QColor &color)
48 {
49  mimeData->setColorData(color);
50  mimeData->setText(color.name());
51 }
52 
53 bool _k_canDecode(const QMimeData *mimeData)
54 {
55  if (mimeData->hasColor()) {
56  return true;
57  }
58  if (mimeData->hasText()) {
59  const QString colorName = mimeData->text();
60  if ((colorName.length() >= 4) && (colorName[0] == QLatin1Char('#'))) {
61  return true;
62  }
63  }
64  return false;
65 }
66 
67 QColor _k_fromMimeData(const QMimeData *mimeData)
68 {
69  if (mimeData->hasColor()) {
70  return mimeData->colorData().value<QColor>();
71  }
72  if (_k_canDecode(mimeData)) {
73  return QColor(mimeData->text());
74  }
75  return QColor();
76 }
77 
78 QDrag *_k_createDrag(const QColor &color, QObject *dragsource)
79 {
80  QDrag *drag = new QDrag(dragsource);
81  QMimeData *mime = new QMimeData;
82  _k_populateMimeData(mime, color);
83  drag->setMimeData(mime);
84  QPixmap colorpix(25, 20);
85  colorpix.fill(color);
86  QPainter p(&colorpix);
87  p.setPen(Qt::black);
88  p.drawRect(0, 0, 24, 19);
89  p.end();
90  drag->setPixmap(colorpix);
91  drag->setHotSpot(QPoint(-5, -7));
92  return drag;
93 }
95 
96 KColorButton::KColorButtonPrivate::KColorButtonPrivate(KColorButton *q)
97  : q(q)
98 {
99  m_bdefaultColor = false;
100  m_alphaChannel = false;
101  q->setAcceptDrops(true);
102 
103  connect(q, &KColorButton::clicked, q, [this]() { _k_chooseColor(); });
104 }
105 
107  : QPushButton(parent)
108  , d(new KColorButtonPrivate(this))
109 {
110 }
111 
113  : QPushButton(parent)
114  , d(new KColorButtonPrivate(this))
115 {
116  d->col = c;
117 }
118 
120  : QPushButton(parent)
121  , d(new KColorButtonPrivate(this))
122 {
123  d->col = c;
124  setDefaultColor(defaultColor);
125 }
126 
127 KColorButton::~KColorButton()
128 {
129  delete d;
130 }
131 
133 {
134  return d->col;
135 }
136 
138 {
139  if (d->col != c) {
140  d->col = c;
141  update();
142  emit changed(d->col);
143  }
144 }
145 
147 {
148  d->m_alphaChannel = alpha;
149 }
150 
152 {
153  return d->m_alphaChannel;
154 }
155 
157 {
158  return d->m_defaultColor;
159 }
160 
162 {
163  d->m_bdefaultColor = c.isValid();
164  d->m_defaultColor = c;
165 }
166 
167 void KColorButton::KColorButtonPrivate::initStyleOption(QStyleOptionButton *opt) const
168 {
169  opt->initFrom(q);
170  opt->state |= q->isDown() ? QStyle::State_Sunken : QStyle::State_Raised;
171  opt->features = QStyleOptionButton::None;
172  if (q->isDefault()) {
173  opt->features |= QStyleOptionButton::DefaultButton;
174  }
175  opt->text.clear();
176  opt->icon = QIcon();
177 }
178 
179 void KColorButton::paintEvent(QPaintEvent *)
180 {
181  QPainter painter(this);
183 
184  //First, we need to draw the bevel.
185  QStyleOptionButton butOpt;
186  d->initStyleOption(&butOpt);
187  style->drawControl(QStyle::CE_PushButtonBevel, &butOpt, &painter, this);
188 
189  //OK, now we can muck around with drawing out pretty little color box
190  //First, sort out where it goes
192  &butOpt, this);
193  int shift = style->pixelMetric(QStyle::PM_ButtonMargin, &butOpt, this) / 2;
194  labelRect.adjust(shift, shift, -shift, -shift);
195  int x, y, w, h;
196  labelRect.getRect(&x, &y, &w, &h);
197 
198  if (isChecked() || isDown()) {
199  x += style->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &butOpt, this);
200  y += style->pixelMetric(QStyle::PM_ButtonShiftVertical, &butOpt, this);
201  }
202 
203  QColor fillCol = isEnabled() ? d->col : palette().color(backgroundRole());
204  qDrawShadePanel(&painter, x, y, w, h, palette(), true, 1, nullptr);
205  if (fillCol.isValid()) {
206  const QRect rect(x + 1, y + 1, w - 2, h - 2);
207  if (fillCol.alpha() < 255) {
208  QPixmap chessboardPattern(16, 16);
209  QPainter patternPainter(&chessboardPattern);
210  patternPainter.fillRect(0, 0, 8, 8, Qt::black);
211  patternPainter.fillRect(8, 8, 8, 8, Qt::black);
212  patternPainter.fillRect(0, 8, 8, 8, Qt::white);
213  patternPainter.fillRect(8, 0, 8, 8, Qt::white);
214  patternPainter.end();
215  painter.fillRect(rect, QBrush(chessboardPattern));
216  }
217  painter.fillRect(rect, fillCol);
218  }
219 
220  if (hasFocus()) {
221  QRect focusRect = style->subElementRect(QStyle::SE_PushButtonFocusRect, &butOpt, this);
222  QStyleOptionFocusRect focusOpt;
223  focusOpt.init(this);
224  focusOpt.rect = focusRect;
225  focusOpt.backgroundColor = palette().window().color();
226  style->drawPrimitive(QStyle::PE_FrameFocusRect, &focusOpt, &painter, this);
227  }
228 }
229 
230 QSize KColorButton::sizeHint() const
231 {
232  QStyleOptionButton opt;
233  d->initStyleOption(&opt);
234  return style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(40, 15), this);
235 }
236 
237 QSize KColorButton::minimumSizeHint() const
238 {
239  QStyleOptionButton opt;
240  d->initStyleOption(&opt);
241  return style()->sizeFromContents(QStyle::CT_PushButton, &opt, QSize(3, 3), this);
242 }
243 
244 void KColorButton::dragEnterEvent(QDragEnterEvent *event)
245 {
246  event->setAccepted(_k_canDecode(event->mimeData()) && isEnabled());
247 }
248 
249 void KColorButton::dropEvent(QDropEvent *event)
250 {
251  QColor c = _k_fromMimeData(event->mimeData());
252  if (c.isValid()) {
253  setColor(c);
254  }
255 }
256 
257 void KColorButton::keyPressEvent(QKeyEvent *e)
258 {
259  int key = e->key() | e->modifiers();
260 
261  if (QKeySequence::keyBindings(QKeySequence::Copy).contains(key)) {
262  QMimeData *mime = new QMimeData;
263  _k_populateMimeData(mime, color());
265  } else if (QKeySequence::keyBindings(QKeySequence::Paste).contains(key)) {
266  QColor color = _k_fromMimeData(QApplication::clipboard()->mimeData(QClipboard::Clipboard));
267  setColor(color);
268  } else {
270  }
271 }
272 
273 void KColorButton::mousePressEvent(QMouseEvent *e)
274 {
275  d->mPos = e->pos();
277 }
278 
279 void KColorButton::mouseMoveEvent(QMouseEvent *e)
280 {
281  if ((e->buttons() & Qt::LeftButton) &&
282  (e->pos() - d->mPos).manhattanLength() > QApplication::startDragDistance()) {
283  _k_createDrag(color(), this)->exec();
284  setDown(false);
285  }
286 }
287 
288 void KColorButton::KColorButtonPrivate::_k_chooseColor()
289 {
290  QColorDialog *dialog = dialogPtr.data();
291  if (dialog) {
292  dialog->show();
293  dialog->raise();
294  dialog->activateWindow();
295  return;
296  }
297 
298  dialog = new QColorDialog(q);
299  dialog->setCurrentColor(q->color());
300  dialog->setOption(QColorDialog::ShowAlphaChannel, m_alphaChannel);
302  connect(dialog, SIGNAL(accepted()), q, SLOT(_k_colorChosen()));
303  dialogPtr = dialog;
304  dialog->show();
305 }
306 
307 void KColorButton::KColorButtonPrivate::_k_colorChosen()
308 {
309  QColorDialog *dialog = dialogPtr.data();
310  if (!dialog) {
311  return;
312  }
313 
314  if (dialog->selectedColor().isValid()) {
315  q->setColor(dialog->selectedColor());
316  } else if (m_bdefaultColor) {
317  q->setColor(m_defaultColor);
318  }
319 }
320 
321 #include "moc_kcolorbutton.cpp"
bool isDown() const const
void changed(const QColor &newColor)
Emitted when the color of the widget is changed, either with setColor() or via user selection...
void setHotSpot(const QPoint &hotspot)
Qt::KeyboardModifiers modifiers() const const
const QPalette & palette() const const
CE_PushButtonBevel
bool end()
const QMimeData * mimeData() const const
void fillRect(const QRectF &rectangle, const QBrush &brush)
void setOption(QColorDialog::ColorDialogOption option, bool on)
void setAlphaChannelEnabled(bool alpha)
When set to true, allow the user to change the alpha component of the color.
void setMimeData(QMimeData *data)
QString name() const const
void setColor(const QColor &c)
Sets the current color to c.
QStyle * style() const const
virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const =0
void setColorData(const QVariant &color)
void setPixmap(const QPixmap &pixmap)
const QColor & color(QPalette::ColorGroup group, QPalette::ColorRole role) const const
KColorButton(QWidget *parent=nullptr)
Creates a color button.
int y() const const
SE_PushButtonContents
LeftButton
void setAttribute(Qt::WidgetAttribute attribute, bool on)
T value() const const
bool hasFocus() const const
Qt::MouseButtons buttons() const const
bool hasText() const const
void update()
void initFrom(const QWidget *widget)
QColor color() const
Returns the currently chosen color.
const QColor & color() const const
Qt::DropAction exec(Qt::DropActions supportedActions)
bool isEnabled() const const
QString text() const const
int x() const const
QPalette::ColorRole backgroundRole() const const
void raise()
void clicked(bool checked)
void setCurrentColor(const QColor &color)
void setText(const QString &text)
virtual void mousePressEvent(QMouseEvent *e) override
PE_FrameFocusRect
void setMimeData(QMimeData *src, QClipboard::Mode mode)
QVariant colorData() const const
int alpha() const const
QRect rect() const const
void setAcceptDrops(bool on)
int key() const const
QColor selectedColor() const const
void setDefaultColor(const QColor &c)
Sets the default color to c.
bool isChecked() const const
WA_DeleteOnClose
A pushbutton to display or allow user selection of a color.
Definition: kcolorbutton.h:27
void activateWindow()
virtual void drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const =0
void adjust(int dx1, int dy1, int dx2, int dy2)
virtual bool event(QEvent *e) override
int length() const const
void init(const QWidget *widget)
virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const =0
bool isAlphaChannelEnabled() const
Returns true if the user is allowed to change the alpha component.
QList< QKeySequence > keyBindings(QKeySequence::StandardKey key)
void show()
virtual QRect subElementRect(QStyle::SubElement element, const QStyleOption *option, const QWidget *widget) const const =0
QPoint pos() const const
virtual void keyPressEvent(QKeyEvent *e) override
const QBrush & window() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
bool isDefault() const const
QClipboard * clipboard()
void getRect(int *x, int *y, int *width, int *height) const const
QColor defaultColor() const
Returns the default color or an invalid color if no default color is set.
virtual QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption *option, const QSize &contentsSize, const QWidget *widget) const const =0
int startDragDistance()
bool isValid() const const
bool hasColor() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Thu Jul 9 2020 22:43:30 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.