Warning: That file was not part of the compilation database. It may have many parsing errors.
1 | /**************************************************************************** |
---|---|
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the tools applications of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #include "qpixeltool.h" |
43 | |
44 | #include <qapplication.h> |
45 | #include <qdesktopwidget.h> |
46 | #include <qapplication.h> |
47 | #include <qclipboard.h> |
48 | #include <qpainter.h> |
49 | #include <qevent.h> |
50 | #include <qfiledialog.h> |
51 | #include <qsettings.h> |
52 | #include <qmenu.h> |
53 | #include <qactiongroup.h> |
54 | |
55 | #include <qdebug.h> |
56 | |
57 | QT_BEGIN_NAMESPACE |
58 | |
59 | QPixelTool::QPixelTool(QWidget *parent) |
60 | : QWidget(parent) |
61 | { |
62 | setWindowTitle(QLatin1String("PixelTool")); |
63 | QSettings settings(QLatin1String("Trolltech"), QLatin1String( "QPixelTool")); |
64 | |
65 | m_freeze = false; |
66 | |
67 | m_autoUpdate = settings.value(QLatin1String("autoUpdate"), 0).toBool(); |
68 | |
69 | m_gridSize = settings.value(QLatin1String("gridSize"), 1).toInt(); |
70 | m_gridActive = settings.value(QLatin1String("gridActive"), 1).toInt(); |
71 | m_displayGridSize = false; |
72 | m_displayGridSizeId = 0; |
73 | |
74 | m_zoom = settings.value(QLatin1String("zoom"), 4).toInt(); |
75 | |
76 | m_displayZoom = false; |
77 | m_displayZoomId = 0; |
78 | |
79 | m_preview_mode = false; |
80 | |
81 | m_currentColor = 0; |
82 | |
83 | m_mouseDown = false; |
84 | |
85 | m_initialSize = settings.value(QLatin1String("initialSize"), QSize(250, 200)).toSize(); |
86 | |
87 | move(settings.value(QLatin1String("position")).toPoint()); |
88 | |
89 | setMouseTracking(true); |
90 | setAttribute(Qt::WA_NoBackground); |
91 | m_updateId = startTimer(30); |
92 | } |
93 | |
94 | QPixelTool::~QPixelTool() |
95 | { |
96 | QSettings settings(QLatin1String("Trolltech"), QLatin1String( "QPixelTool")); |
97 | settings.setValue(QLatin1String("autoUpdate"), int(m_autoUpdate)); |
98 | settings.setValue(QLatin1String("gridSize"), m_gridSize); |
99 | settings.setValue(QLatin1String("gridActive"), m_gridActive); |
100 | settings.setValue(QLatin1String("zoom"), m_zoom); |
101 | settings.setValue(QLatin1String("initialSize"), size()); |
102 | settings.setValue(QLatin1String("position"), pos()); |
103 | } |
104 | |
105 | void QPixelTool::setPreviewImage(const QImage &image) |
106 | { |
107 | m_preview_mode = true; |
108 | m_preview_image = image; |
109 | m_freeze = true; |
110 | } |
111 | |
112 | void QPixelTool::timerEvent(QTimerEvent *event) |
113 | { |
114 | if (event->timerId() == m_updateId && !m_freeze) { |
115 | grabScreen(); |
116 | } else if (event->timerId() == m_displayZoomId) { |
117 | killTimer(m_displayZoomId); |
118 | setZoomVisible(false); |
119 | } else if (event->timerId() == m_displayGridSizeId) { |
120 | killTimer(m_displayGridSizeId); |
121 | m_displayGridSize = false; |
122 | } |
123 | } |
124 | |
125 | void render_string(QPainter *p, int w, int h, const QString &text, int flags) |
126 | { |
127 | p->setBrush(QColor(255, 255, 255, 191)); |
128 | p->setPen(Qt::black); |
129 | QRect bounds; |
130 | p->drawText(0, 0, w, h, Qt::TextDontPrint | flags, text, &bounds); |
131 | |
132 | if (bounds.x() == 0) bounds.adjust(0, 0, 10, 0); |
133 | else bounds.adjust(-10, 0, 0, 0); |
134 | |
135 | if (bounds.y() == 0) bounds.adjust(0, 0, 0, 10); |
136 | else bounds.adjust(0, -10, 0, 0); |
137 | |
138 | p->drawRect(bounds); |
139 | p->drawText(bounds, flags, text); |
140 | } |
141 | |
142 | void QPixelTool::paintEvent(QPaintEvent *) |
143 | { |
144 | QPainter p(this); |
145 | |
146 | if (m_preview_mode) { |
147 | QPixmap pixmap(40, 40); |
148 | QPainter pt(&pixmap); |
149 | pt.fillRect(0, 0, 20, 20, Qt::white); |
150 | pt.fillRect(20, 20, 20, 20, Qt::white); |
151 | pt.fillRect(20, 0, 20, 20, Qt::lightGray); |
152 | pt.fillRect(0, 20, 20, 20, Qt::lightGray); |
153 | pt.end(); |
154 | p.fillRect(0, 0, width(), height(), pixmap); |
155 | } |
156 | |
157 | int w = width(); |
158 | int h = height(); |
159 | |
160 | p.save(); |
161 | p.scale(m_zoom, m_zoom); |
162 | p.drawPixmap(0, 0, m_buffer); |
163 | p.scale(1/m_zoom, 1/m_zoom); |
164 | p.restore(); |
165 | |
166 | // Draw the grid on top. |
167 | if (m_gridActive) { |
168 | p.setPen(m_gridActive == 1 ? Qt::black : Qt::white); |
169 | int incr = m_gridSize * m_zoom; |
170 | for (int x=0; x<w; x+=incr) |
171 | p.drawLine(x, 0, x, h); |
172 | for (int y=0; y<h; y+=incr) |
173 | p.drawLine(0, y, w, y); |
174 | } |
175 | |
176 | QFont f(QLatin1String("courier")); |
177 | f.setBold(true); |
178 | p.setFont(f); |
179 | |
180 | if (m_displayZoom) { |
181 | render_string(&p, w, h, |
182 | QString::fromLatin1("Zoom: x%1").arg(m_zoom), |
183 | Qt::AlignTop | Qt::AlignRight); |
184 | } |
185 | |
186 | if (m_displayGridSize) { |
187 | render_string(&p, w, h, |
188 | QString::fromLatin1("Grid size: %1").arg(m_gridSize), |
189 | Qt::AlignBottom | Qt::AlignLeft); |
190 | } |
191 | |
192 | if (m_freeze) { |
193 | QString str; |
194 | str.sprintf("%8X (%3d,%3d,%3d,%3d)", |
195 | m_currentColor, |
196 | (0xff000000 & m_currentColor) >> 24, |
197 | (0x00ff0000 & m_currentColor) >> 16, |
198 | (0x0000ff00 & m_currentColor) >> 8, |
199 | (0x000000ff & m_currentColor)); |
200 | render_string(&p, w, h, |
201 | str, |
202 | Qt::AlignBottom | Qt::AlignRight); |
203 | } |
204 | |
205 | if (m_mouseDown && m_dragStart != m_dragCurrent) { |
206 | int x1 = (m_dragStart.x() / m_zoom) * m_zoom; |
207 | int y1 = (m_dragStart.y() / m_zoom) * m_zoom; |
208 | int x2 = (m_dragCurrent.x() / m_zoom) * m_zoom; |
209 | int y2 = (m_dragCurrent.y() / m_zoom) * m_zoom; |
210 | QRect r = QRect(x1, y1, x2 - x1, y2 - y1).normalized(); |
211 | p.setBrush(Qt::NoBrush); |
212 | p.setPen(QPen(Qt::red, 3, Qt::SolidLine)); |
213 | p.drawRect(r); |
214 | p.setPen(QPen(Qt::black, 1, Qt::SolidLine)); |
215 | p.drawRect(r); |
216 | |
217 | QString str; |
218 | str.sprintf("Rect: x=%d, y=%d, w=%d, h=%d", |
219 | r.x() / m_zoom, |
220 | r.y() / m_zoom, |
221 | r.width() / m_zoom, |
222 | r.height() / m_zoom); |
223 | render_string(&p, w, h, str, Qt::AlignBottom | Qt::AlignLeft); |
224 | } |
225 | |
226 | |
227 | } |
228 | |
229 | void QPixelTool::keyPressEvent(QKeyEvent *e) |
230 | { |
231 | switch (e->key()) { |
232 | case Qt::Key_Space: |
233 | toggleFreeze(); |
234 | break; |
235 | case Qt::Key_Plus: |
236 | setZoom(m_zoom + 1); |
237 | break; |
238 | case Qt::Key_Minus: |
239 | setZoom(m_zoom - 1); |
240 | break; |
241 | case Qt::Key_PageUp: |
242 | setGridSize(m_gridSize + 1); |
243 | break; |
244 | case Qt::Key_PageDown: |
245 | setGridSize(m_gridSize - 1); |
246 | break; |
247 | case Qt::Key_G: |
248 | toggleGrid(); |
249 | break; |
250 | case Qt::Key_A: |
251 | m_autoUpdate = !m_autoUpdate; |
252 | break; |
253 | case Qt::Key_C: |
254 | if (e->modifiers() & Qt::ControlModifier) |
255 | copyToClipboard(); |
256 | break; |
257 | case Qt::Key_S: |
258 | if (e->modifiers() & Qt::ControlModifier) { |
259 | releaseKeyboard(); |
260 | saveToFile(); |
261 | } |
262 | break; |
263 | case Qt::Key_Control: |
264 | grabKeyboard(); |
265 | break; |
266 | } |
267 | } |
268 | |
269 | void QPixelTool::keyReleaseEvent(QKeyEvent *e) |
270 | { |
271 | switch(e->key()) { |
272 | case Qt::Key_Control: |
273 | releaseKeyboard(); |
274 | break; |
275 | default: |
276 | break; |
277 | } |
278 | } |
279 | |
280 | void QPixelTool::resizeEvent(QResizeEvent *) |
281 | { |
282 | grabScreen(); |
283 | } |
284 | |
285 | void QPixelTool::mouseMoveEvent(QMouseEvent *e) |
286 | { |
287 | if (m_mouseDown) |
288 | m_dragCurrent = e->pos(); |
289 | |
290 | int x = e->x() / m_zoom; |
291 | int y = e->y() / m_zoom; |
292 | |
293 | QImage im = m_buffer.toImage().convertToFormat(QImage::Format_ARGB32); |
294 | if (x < im.width() && y < im.height() && x >= 0 && y >= 0) { |
295 | m_currentColor = im.pixel(x, y); |
296 | update(); |
297 | } |
298 | } |
299 | |
300 | void QPixelTool::mousePressEvent(QMouseEvent *e) |
301 | { |
302 | if (!m_freeze) |
303 | return; |
304 | m_mouseDown = true; |
305 | m_dragStart = e->pos(); |
306 | } |
307 | |
308 | void QPixelTool::mouseReleaseEvent(QMouseEvent *) |
309 | { |
310 | m_mouseDown = false; |
311 | } |
312 | |
313 | void QPixelTool::contextMenuEvent(QContextMenuEvent *e) |
314 | { |
315 | bool tmpFreeze = m_freeze; |
316 | m_freeze = true; |
317 | |
318 | QMenu menu; |
319 | |
320 | QAction title(QLatin1String("Qt Pixel Zooming Tool"), &menu); |
321 | title.setEnabled(false); |
322 | |
323 | // Grid color options... |
324 | QActionGroup gridGroup(this); |
325 | QAction whiteGrid(QLatin1String("White grid"), &gridGroup); |
326 | whiteGrid.setCheckable(true); |
327 | whiteGrid.setChecked(m_gridActive == 2); |
328 | whiteGrid.setShortcut(QKeySequence(Qt::Key_G)); |
329 | QAction blackGrid(QLatin1String("Black grid"), &gridGroup); |
330 | blackGrid.setCheckable(true); |
331 | blackGrid.setChecked(m_gridActive == 1); |
332 | blackGrid.setShortcut(QKeySequence(Qt::Key_G)); |
333 | QAction noGrid(QLatin1String("No grid"), &gridGroup); |
334 | noGrid.setCheckable(true); |
335 | noGrid.setChecked(m_gridActive == 0); |
336 | noGrid.setShortcut(QKeySequence(Qt::Key_G)); |
337 | |
338 | // Grid size options |
339 | QAction incrGrid(QLatin1String("Increase grid size"), &menu); |
340 | incrGrid.setShortcut(QKeySequence(Qt::Key_PageUp)); |
341 | connect(&incrGrid, SIGNAL(triggered()), this, SLOT(increaseGridSize())); |
342 | QAction decrGrid(QLatin1String("Decrease grid size"), &menu); |
343 | decrGrid.setShortcut(QKeySequence(Qt::Key_PageDown)); |
344 | connect(&decrGrid, SIGNAL(triggered()), this, SLOT(decreaseGridSize())); |
345 | |
346 | // Zoom options |
347 | QAction incrZoom(QLatin1String("Zoom in"), &menu); |
348 | incrZoom.setShortcut(QKeySequence(Qt::Key_Plus)); |
349 | connect(&incrZoom, SIGNAL(triggered()), this, SLOT(increaseZoom())); |
350 | QAction decrZoom(QLatin1String("Zoom out"), &menu); |
351 | decrZoom.setShortcut(QKeySequence(Qt::Key_Minus)); |
352 | connect(&decrZoom, SIGNAL(triggered()), this, SLOT(decreaseZoom())); |
353 | |
354 | // Freeze / Autoupdate |
355 | QAction freeze(QLatin1String("Frozen"), &menu); |
356 | freeze.setCheckable(true); |
357 | freeze.setChecked(tmpFreeze); |
358 | freeze.setShortcut(QKeySequence(Qt::Key_Space)); |
359 | QAction autoUpdate(QLatin1String("Continuous update"), &menu); |
360 | autoUpdate.setCheckable(true); |
361 | autoUpdate.setChecked(m_autoUpdate); |
362 | autoUpdate.setShortcut(QKeySequence(Qt::Key_A)); |
363 | |
364 | // Copy to clipboard / save |
365 | QAction save(QLatin1String("Save as image"), &menu); |
366 | save.setShortcut(QKeySequence(QLatin1String("Ctrl+S"))); |
367 | connect(&save, SIGNAL(triggered()), this, SLOT(saveToFile())); |
368 | QAction copy(QLatin1String("Copy to clipboard"), &menu); |
369 | copy.setShortcut(QKeySequence(QLatin1String("Ctrl+C"))); |
370 | connect(©, SIGNAL(triggered()), this, SLOT(copyToClipboard())); |
371 | |
372 | menu.addAction(&title); |
373 | menu.addSeparator(); |
374 | menu.addAction(&whiteGrid); |
375 | menu.addAction(&blackGrid); |
376 | menu.addAction(&noGrid); |
377 | menu.addSeparator(); |
378 | menu.addAction(&incrGrid); |
379 | menu.addAction(&decrGrid); |
380 | menu.addSeparator(); |
381 | menu.addAction(&incrZoom); |
382 | menu.addAction(&decrZoom); |
383 | menu.addSeparator(); |
384 | menu.addAction(&freeze); |
385 | menu.addAction(&autoUpdate); |
386 | menu.addSeparator(); |
387 | menu.addAction(&save); |
388 | menu.addAction(©); |
389 | |
390 | menu.exec(mapToGlobal(e->pos())); |
391 | |
392 | // Read out grid settings |
393 | if (noGrid.isChecked()) m_gridActive = 0; |
394 | else if (blackGrid.isChecked()) m_gridActive = 1; |
395 | else m_gridActive = 2; |
396 | |
397 | m_autoUpdate = autoUpdate.isChecked(); |
398 | tmpFreeze = freeze.isChecked(); |
399 | |
400 | |
401 | m_freeze = tmpFreeze; |
402 | } |
403 | |
404 | QSize QPixelTool::sizeHint() const |
405 | { |
406 | return m_initialSize; |
407 | } |
408 | |
409 | void QPixelTool::grabScreen() |
410 | { |
411 | if (m_preview_mode) { |
412 | int w = qMin(width() / m_zoom + 1, m_preview_image.width()); |
413 | int h = qMin(height() / m_zoom + 1, m_preview_image.height()); |
414 | m_buffer = QPixmap::fromImage(m_preview_image).copy(0, 0, w, h); |
415 | update(); |
416 | return; |
417 | } |
418 | |
419 | QPoint mousePos = QCursor::pos(); |
420 | if (mousePos == m_lastMousePos && !m_autoUpdate) |
421 | return; |
422 | |
423 | int w = int(width() / float(m_zoom)); |
424 | int h = int(height() / float(m_zoom)); |
425 | |
426 | if (width() % m_zoom > 0) |
427 | ++w; |
428 | if (height() % m_zoom > 0) |
429 | ++h; |
430 | |
431 | int x = mousePos.x() - w/2; |
432 | int y = mousePos.y() - h/2; |
433 | |
434 | m_buffer = QPixmap::grabWindow(qApp->desktop()->winId(), x, y, w, h); |
435 | |
436 | QRegion geom(x, y, w, h); |
437 | QRect screenRect; |
438 | for (int i=0; i<qApp->desktop()->numScreens(); ++i) |
439 | screenRect |= qApp->desktop()->screenGeometry(i); |
440 | geom -= screenRect; |
441 | QVector<QRect> rects = geom.rects(); |
442 | if (rects.size() > 0) { |
443 | QPainter p(&m_buffer); |
444 | p.translate(-x, -y); |
445 | p.setPen(Qt::NoPen); |
446 | p.setBrush(palette().color(QPalette::Dark)); |
447 | p.drawRects(rects); |
448 | } |
449 | |
450 | update(); |
451 | |
452 | m_lastMousePos = mousePos; |
453 | } |
454 | |
455 | void QPixelTool::startZoomVisibleTimer() |
456 | { |
457 | if (m_displayZoomId > 0) { |
458 | killTimer(m_displayZoomId); |
459 | } |
460 | m_displayZoomId = startTimer(5000); |
461 | setZoomVisible(true); |
462 | } |
463 | |
464 | void QPixelTool::startGridSizeVisibleTimer() |
465 | { |
466 | if (m_gridActive) { |
467 | if (m_displayGridSizeId > 0) |
468 | killTimer(m_displayGridSizeId); |
469 | m_displayGridSizeId = startTimer(5000); |
470 | m_displayGridSize = true; |
471 | update(); |
472 | } |
473 | } |
474 | |
475 | void QPixelTool::setZoomVisible(bool visible) |
476 | { |
477 | m_displayZoom = visible; |
478 | update(); |
479 | } |
480 | |
481 | void QPixelTool::toggleFreeze() |
482 | { |
483 | m_freeze = !m_freeze; |
484 | if (!m_freeze) |
485 | m_dragStart = m_dragCurrent = QPoint(); |
486 | } |
487 | |
488 | void QPixelTool::setZoom(int zoom) |
489 | { |
490 | if (zoom > 0) { |
491 | QPoint pos = m_lastMousePos; |
492 | m_lastMousePos = QPoint(); |
493 | m_zoom = zoom; |
494 | grabScreen(); |
495 | m_lastMousePos = pos; |
496 | m_dragStart = m_dragCurrent = QPoint(); |
497 | startZoomVisibleTimer(); |
498 | } |
499 | } |
500 | |
501 | void QPixelTool::toggleGrid() |
502 | { |
503 | if (++m_gridActive > 2) |
504 | m_gridActive = 0; |
505 | update(); |
506 | } |
507 | |
508 | void QPixelTool::setGridSize(int gridSize) |
509 | { |
510 | if (m_gridActive && gridSize > 0) { |
511 | m_gridSize = gridSize; |
512 | startGridSizeVisibleTimer(); |
513 | update(); |
514 | } |
515 | } |
516 | |
517 | void QPixelTool::copyToClipboard() |
518 | { |
519 | QClipboard *cb = QApplication::clipboard(); |
520 | cb->setPixmap(m_buffer); |
521 | } |
522 | |
523 | void QPixelTool::saveToFile() |
524 | { |
525 | bool oldFreeze = m_freeze; |
526 | m_freeze = true; |
527 | QString name = QFileDialog::getSaveFileName(this, QLatin1String("Save as image"), QString(), QLatin1String( "*.png")); |
528 | if (!name.isEmpty()) { |
529 | if (!name.endsWith(QLatin1String(".png"))) |
530 | name.append(QLatin1String(".png")); |
531 | m_buffer.save(name, "PNG"); |
532 | } |
533 | m_freeze = oldFreeze; |
534 | } |
535 | |
536 | QT_END_NAMESPACE |
537 |
Warning: That file was not part of the compilation database. It may have many parsing errors.