tools/pixeltool/qpixeltool.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the tools applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    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("Continous 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(&copy, 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(&copy);
       
   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