1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qtcolorbutton.h" |
5 | #include <QtWidgets/QColorDialog> |
6 | #include <QtGui/QPainter> |
7 | #include <QtCore/QMimeData> |
8 | #include <QtGui/QDragEnterEvent> |
9 | #include <QtGui/QDrag> |
10 | #include <QtWidgets/QApplication> |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | class QtColorButtonPrivate : public QObject |
15 | { |
16 | Q_OBJECT |
17 | QtColorButton *q_ptr; |
18 | Q_DECLARE_PUBLIC(QtColorButton) |
19 | public: |
20 | QColor m_color; |
21 | #ifndef QT_NO_DRAGANDDROP |
22 | QColor m_dragColor; |
23 | QPoint m_dragStart; |
24 | bool m_dragging; |
25 | #endif |
26 | bool m_backgroundCheckered; |
27 | |
28 | void slotEditColor(); |
29 | QColor shownColor() const; |
30 | QPixmap generatePixmap() const; |
31 | }; |
32 | |
33 | void QtColorButtonPrivate::slotEditColor() |
34 | { |
35 | const QColor newColor = QColorDialog::getColor(initial: m_color, parent: q_ptr, title: QString(), options: QColorDialog::ShowAlphaChannel); |
36 | if (!newColor.isValid() || newColor == q_ptr->color()) |
37 | return; |
38 | q_ptr->setColor(newColor); |
39 | emit q_ptr->colorChanged(color: m_color); |
40 | } |
41 | |
42 | QColor QtColorButtonPrivate::shownColor() const |
43 | { |
44 | #ifndef QT_NO_DRAGANDDROP |
45 | if (m_dragging) |
46 | return m_dragColor; |
47 | #endif |
48 | return m_color; |
49 | } |
50 | |
51 | QPixmap QtColorButtonPrivate::generatePixmap() const |
52 | { |
53 | QPixmap pix(24, 24); |
54 | |
55 | int pixSize = 20; |
56 | QBrush br(shownColor()); |
57 | |
58 | QPixmap pm(2 * pixSize, 2 * pixSize); |
59 | QPainter pmp(&pm); |
60 | pmp.fillRect(x: 0, y: 0, w: pixSize, h: pixSize, c: Qt::lightGray); |
61 | pmp.fillRect(x: pixSize, y: pixSize, w: pixSize, h: pixSize, c: Qt::lightGray); |
62 | pmp.fillRect(x: 0, y: pixSize, w: pixSize, h: pixSize, c: Qt::darkGray); |
63 | pmp.fillRect(x: pixSize, y: 0, w: pixSize, h: pixSize, c: Qt::darkGray); |
64 | pmp.fillRect(x: 0, y: 0, w: 2 * pixSize, h: 2 * pixSize, b: shownColor()); |
65 | br = QBrush(pm); |
66 | |
67 | QPainter p(&pix); |
68 | int corr = 1; |
69 | QRect r = pix.rect().adjusted(xp1: corr, yp1: corr, xp2: -corr, yp2: -corr); |
70 | p.setBrushOrigin(x: (r.width() % pixSize + pixSize) / 2 + corr, y: (r.height() % pixSize + pixSize) / 2 + corr); |
71 | p.fillRect(r, br); |
72 | |
73 | p.fillRect(x: r.width() / 4 + corr, y: r.height() / 4 + corr, |
74 | w: r.width() / 2, h: r.height() / 2, |
75 | b: QColor(shownColor().rgb())); |
76 | p.drawRect(r: pix.rect().adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1)); |
77 | |
78 | return pix; |
79 | } |
80 | |
81 | /////////////// |
82 | |
83 | QtColorButton::QtColorButton(QWidget *parent) |
84 | : QToolButton(parent), d_ptr(new QtColorButtonPrivate) |
85 | { |
86 | d_ptr->q_ptr = this; |
87 | d_ptr->m_dragging = false; |
88 | d_ptr->m_backgroundCheckered = true; |
89 | |
90 | setAcceptDrops(true); |
91 | |
92 | connect(sender: this, signal: &QToolButton::clicked, context: d_ptr.data(), slot: &QtColorButtonPrivate::slotEditColor); |
93 | setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)); |
94 | } |
95 | |
96 | QtColorButton::~QtColorButton() |
97 | { |
98 | } |
99 | |
100 | void QtColorButton::setColor(const QColor &color) |
101 | { |
102 | if (d_ptr->m_color == color) |
103 | return; |
104 | d_ptr->m_color = color; |
105 | update(); |
106 | } |
107 | |
108 | QColor QtColorButton::color() const |
109 | { |
110 | return d_ptr->m_color; |
111 | } |
112 | |
113 | void QtColorButton::setBackgroundCheckered(bool checkered) |
114 | { |
115 | if (d_ptr->m_backgroundCheckered == checkered) |
116 | return; |
117 | d_ptr->m_backgroundCheckered = checkered; |
118 | update(); |
119 | } |
120 | |
121 | bool QtColorButton::isBackgroundCheckered() const |
122 | { |
123 | return d_ptr->m_backgroundCheckered; |
124 | } |
125 | |
126 | void QtColorButton::paintEvent(QPaintEvent *event) |
127 | { |
128 | QToolButton::paintEvent(event); |
129 | if (!isEnabled()) |
130 | return; |
131 | |
132 | const int pixSize = 10; |
133 | QBrush br(d_ptr->shownColor()); |
134 | if (d_ptr->m_backgroundCheckered) { |
135 | QPixmap pm(2 * pixSize, 2 * pixSize); |
136 | QPainter pmp(&pm); |
137 | pmp.fillRect(x: 0, y: 0, w: pixSize, h: pixSize, c: Qt::white); |
138 | pmp.fillRect(x: pixSize, y: pixSize, w: pixSize, h: pixSize, c: Qt::white); |
139 | pmp.fillRect(x: 0, y: pixSize, w: pixSize, h: pixSize, c: Qt::black); |
140 | pmp.fillRect(x: pixSize, y: 0, w: pixSize, h: pixSize, c: Qt::black); |
141 | pmp.fillRect(x: 0, y: 0, w: 2 * pixSize, h: 2 * pixSize, b: d_ptr->shownColor()); |
142 | br = QBrush(pm); |
143 | } |
144 | |
145 | QPainter p(this); |
146 | const int corr = 4; |
147 | QRect r = rect().adjusted(xp1: corr, yp1: corr, xp2: -corr, yp2: -corr); |
148 | p.setBrushOrigin(x: (r.width() % pixSize + pixSize) / 2 + corr, y: (r.height() % pixSize + pixSize) / 2 + corr); |
149 | p.fillRect(r, br); |
150 | |
151 | //const int adjX = qRound(r.width() / 4.0); |
152 | //const int adjY = qRound(r.height() / 4.0); |
153 | //p.fillRect(r.adjusted(adjX, adjY, -adjX, -adjY), |
154 | // QColor(d_ptr->shownColor().rgb())); |
155 | /* |
156 | p.fillRect(r.adjusted(0, r.height() * 3 / 4, 0, 0), |
157 | QColor(d_ptr->shownColor().rgb())); |
158 | p.fillRect(r.adjusted(0, 0, 0, -r.height() * 3 / 4), |
159 | QColor(d_ptr->shownColor().rgb())); |
160 | */ |
161 | /* |
162 | const QColor frameColor0(0, 0, 0, qRound(0.2 * (0xFF - d_ptr->shownColor().alpha()))); |
163 | p.setPen(frameColor0); |
164 | p.drawRect(r.adjusted(adjX, adjY, -adjX - 1, -adjY - 1)); |
165 | */ |
166 | |
167 | const QColor frameColor1(0, 0, 0, 26); |
168 | p.setPen(frameColor1); |
169 | p.drawRect(r: r.adjusted(xp1: 1, yp1: 1, xp2: -2, yp2: -2)); |
170 | const QColor frameColor2(0, 0, 0, 51); |
171 | p.setPen(frameColor2); |
172 | p.drawRect(r: r.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1)); |
173 | } |
174 | |
175 | void QtColorButton::mousePressEvent(QMouseEvent *event) |
176 | { |
177 | #ifndef QT_NO_DRAGANDDROP |
178 | if (event->button() == Qt::LeftButton) |
179 | d_ptr->m_dragStart = event->pos(); |
180 | #endif |
181 | QToolButton::mousePressEvent(event); |
182 | } |
183 | |
184 | void QtColorButton::mouseMoveEvent(QMouseEvent *event) |
185 | { |
186 | #ifndef QT_NO_DRAGANDDROP |
187 | if (event->buttons() & Qt::LeftButton && |
188 | (d_ptr->m_dragStart - event->pos()).manhattanLength() > QApplication::startDragDistance()) { |
189 | QMimeData *mime = new QMimeData; |
190 | mime->setColorData(color()); |
191 | QDrag *drg = new QDrag(this); |
192 | drg->setMimeData(mime); |
193 | drg->setPixmap(d_ptr->generatePixmap()); |
194 | setDown(false); |
195 | event->accept(); |
196 | drg->exec(supportedActions: Qt::CopyAction); |
197 | return; |
198 | } |
199 | #endif |
200 | QToolButton::mouseMoveEvent(e: event); |
201 | } |
202 | |
203 | #ifndef QT_NO_DRAGANDDROP |
204 | void QtColorButton::dragEnterEvent(QDragEnterEvent *event) |
205 | { |
206 | const QMimeData *mime = event->mimeData(); |
207 | if (!mime->hasColor()) |
208 | return; |
209 | |
210 | event->accept(); |
211 | d_ptr->m_dragColor = qvariant_cast<QColor>(v: mime->colorData()); |
212 | d_ptr->m_dragging = true; |
213 | update(); |
214 | } |
215 | |
216 | void QtColorButton::dragLeaveEvent(QDragLeaveEvent *event) |
217 | { |
218 | event->accept(); |
219 | d_ptr->m_dragging = false; |
220 | update(); |
221 | } |
222 | |
223 | void QtColorButton::dropEvent(QDropEvent *event) |
224 | { |
225 | event->accept(); |
226 | d_ptr->m_dragging = false; |
227 | if (d_ptr->m_dragColor == color()) |
228 | return; |
229 | setColor(d_ptr->m_dragColor); |
230 | emit colorChanged(color: color()); |
231 | } |
232 | #endif |
233 | |
234 | QT_END_NAMESPACE |
235 | |
236 | #include "qtcolorbutton.moc" |
237 | |