| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the tools applications of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qpixeltool.h" |
| |
| #include <qapplication.h> |
| #include <qdesktopwidget.h> |
| #include <qdir.h> |
| #include <qapplication.h> |
| #include <qscreen.h> |
| #if QT_CONFIG(clipboard) |
| #include <qclipboard.h> |
| #endif |
| #include <qpainter.h> |
| #include <qevent.h> |
| #include <qfiledialog.h> |
| #include <qmessagebox.h> |
| #include <qsettings.h> |
| #include <qmenu.h> |
| #include <qactiongroup.h> |
| #include <qimagewriter.h> |
| #include <qscreen.h> |
| #include <qstandardpaths.h> |
| #include <qtextstream.h> |
| #include <qwindow.h> |
| #include <private/qhighdpiscaling_p.h> |
| |
| #include <qdebug.h> |
| |
| QT_BEGIN_NAMESPACE |
| |
| static QPoint initialPos(const QSettings &settings, const QSize &initialSize) |
| { |
| const QPoint defaultPos = QGuiApplication::primaryScreen()->availableGeometry().topLeft(); |
| const QPoint savedPos = |
| settings.value(QLatin1String("position"), QVariant(defaultPos)).toPoint(); |
| auto savedScreen = QGuiApplication::screenAt(savedPos); |
| return savedScreen != nullptr |
| && savedScreen->availableGeometry().intersects(QRect(savedPos, initialSize)) |
| ? savedPos : defaultPos; |
| } |
| |
| QPixelTool::QPixelTool(QWidget *parent) |
| : QWidget(parent) |
| { |
| setWindowTitle(QCoreApplication::applicationName()); |
| QSettings settings(QLatin1String("QtProject"), QLatin1String("QPixelTool")); |
| m_autoUpdate = settings.value(QLatin1String("autoUpdate"), 0).toBool(); |
| m_gridSize = settings.value(QLatin1String("gridSize"), 1).toInt(); |
| m_gridActive = settings.value(QLatin1String("gridActive"), 1).toInt(); |
| m_zoom = settings.value(QLatin1String("zoom"), 4).toInt(); |
| m_initialSize = settings.value(QLatin1String("initialSize"), QSize(250, 200)).toSize(); |
| m_lcdMode = settings.value(QLatin1String("lcdMode"), 0).toInt(); |
| |
| move(initialPos(settings, m_initialSize)); |
| |
| setMouseTracking(true); |
| setAttribute(Qt::WA_OpaquePaintEvent); |
| m_updateId = startTimer(30); |
| } |
| |
| QPixelTool::~QPixelTool() |
| { |
| QSettings settings(QLatin1String("QtProject"), QLatin1String("QPixelTool")); |
| settings.setValue(QLatin1String("autoUpdate"), int(m_autoUpdate)); |
| settings.setValue(QLatin1String("gridSize"), m_gridSize); |
| settings.setValue(QLatin1String("gridActive"), m_gridActive); |
| settings.setValue(QLatin1String("zoom"), m_zoom); |
| settings.setValue(QLatin1String("initialSize"), size()); |
| settings.setValue(QLatin1String("position"), pos()); |
| settings.setValue(QLatin1String("lcdMode"), m_lcdMode); |
| } |
| |
| void QPixelTool::setPreviewImage(const QImage &image) |
| { |
| m_preview_mode = true; |
| m_preview_image = image; |
| m_freeze = true; |
| } |
| |
| void QPixelTool::timerEvent(QTimerEvent *event) |
| { |
| if (event->timerId() == m_updateId && !m_freeze) { |
| grabScreen(); |
| } else if (event->timerId() == m_displayZoomId) { |
| killTimer(m_displayZoomId); |
| setZoomVisible(false); |
| } else if (event->timerId() == m_displayGridSizeId) { |
| killTimer(m_displayGridSizeId); |
| m_displayGridSize = false; |
| } |
| } |
| |
| void render_string(QPainter *p, int w, int h, const QString &text, int flags) |
| { |
| p->setBrush(QColor(255, 255, 255, 191)); |
| p->setPen(Qt::black); |
| QRect bounds; |
| p->drawText(0, 0, w, h, Qt::TextDontPrint | flags, text, &bounds); |
| |
| if (bounds.x() == 0) bounds.adjust(0, 0, 10, 0); |
| else bounds.adjust(-10, 0, 0, 0); |
| |
| if (bounds.y() == 0) bounds.adjust(0, 0, 0, 10); |
| else bounds.adjust(0, -10, 0, 0); |
| |
| p->drawRect(bounds); |
| p->drawText(bounds, flags, text); |
| } |
| |
| static QImage imageLCDFilter(const QImage &image, int lcdMode) |
| { |
| Q_ASSERT(lcdMode > 0 && lcdMode < 5); |
| const bool vertical = (lcdMode > 2); |
| QImage scaled(image.width() * (vertical ? 1 : 3), |
| image.height() * (vertical ? 3 : 1), |
| image.format()); |
| |
| const int w = image.width(); |
| const int h = image.height(); |
| if (!vertical) { |
| for (int y = 0; y < h; ++y) { |
| const QRgb *in = reinterpret_cast<const QRgb *>(image.scanLine(y)); |
| QRgb *out = reinterpret_cast<QRgb *>(scaled.scanLine(y)); |
| if (lcdMode == 1) { |
| for (int x = 0; x < w; ++x) { |
| *out++ = in[x] & 0xffff0000; |
| *out++ = in[x] & 0xff00ff00; |
| *out++ = in[x] & 0xff0000ff; |
| } |
| } else { |
| for (int x = 0; x < w; ++x) { |
| *out++ = in[x] & 0xff0000ff; |
| *out++ = in[x] & 0xff00ff00; |
| *out++ = in[x] & 0xffff0000; |
| } |
| } |
| } |
| } else { |
| for (int y = 0; y < h; ++y) { |
| const QRgb *in = reinterpret_cast<const QRgb *>(image.scanLine(y)); |
| QRgb *out1 = reinterpret_cast<QRgb *>(scaled.scanLine(y * 3 + 0)); |
| QRgb *out2 = reinterpret_cast<QRgb *>(scaled.scanLine(y * 3 + 1)); |
| QRgb *out3 = reinterpret_cast<QRgb *>(scaled.scanLine(y * 3 + 2)); |
| if (lcdMode == 2) { |
| for (int x = 0; x < w; ++x) { |
| out1[x] = in[x] & 0xffff0000; |
| out2[x] = in[x] & 0xff00ff00; |
| out3[x] = in[x] & 0xff0000ff; |
| } |
| } else { |
| for (int x = 0; x < w; ++x) { |
| out1[x] = in[x] & 0xff0000ff; |
| out2[x] = in[x] & 0xff00ff00; |
| out3[x] = in[x] & 0xffff0000; |
| } |
| } |
| } |
| } |
| return scaled; |
| } |
| |
| void QPixelTool::paintEvent(QPaintEvent *) |
| { |
| QPainter p(this); |
| |
| if (m_preview_mode) { |
| QPixmap pixmap(40, 40); |
| QPainter pt(&pixmap); |
| pt.fillRect(0, 0, 20, 20, Qt::white); |
| pt.fillRect(20, 20, 20, 20, Qt::white); |
| pt.fillRect(20, 0, 20, 20, Qt::lightGray); |
| pt.fillRect(0, 20, 20, 20, Qt::lightGray); |
| pt.end(); |
| p.fillRect(0, 0, width(), height(), pixmap); |
| } |
| |
| int w = width(); |
| int h = height(); |
| |
| p.save(); |
| if (m_lcdMode == 0) { |
| p.scale(m_zoom, m_zoom); |
| p.drawPixmap(0, 0, m_buffer); |
| } else { |
| if (m_lcdMode <= 2) |
| p.scale(m_zoom / 3.0, m_zoom); |
| else |
| p.scale(m_zoom, m_zoom / 3.0); |
| p.drawImage(0, 0, imageLCDFilter(m_buffer.toImage(), m_lcdMode)); |
| } |
| p.restore(); |
| |
| // Draw the grid on top. |
| if (m_gridActive) { |
| p.setPen(m_gridActive == 1 ? Qt::black : Qt::white); |
| int incr = m_gridSize * m_zoom; |
| if (m_lcdMode == 0 || m_lcdMode > 2) { |
| for (int x=0; x<w; x+=incr) |
| p.drawLine(x, 0, x, h); |
| } |
| if (m_lcdMode <= 2) { |
| for (int y=0; y<h; y+=incr) |
| p.drawLine(0, y, w, y); |
| } |
| } |
| |
| QFont f(QLatin1String("courier")); |
| f.setBold(true); |
| p.setFont(f); |
| |
| if (m_displayZoom) { |
| render_string(&p, w, h, |
| QLatin1String("Zoom: x") + QString::number(m_zoom), |
| Qt::AlignTop | Qt::AlignRight); |
| } |
| |
| if (m_displayGridSize) { |
| render_string(&p, w, h, |
| QLatin1String("Grid size: ") + QString::number(m_gridSize), |
| Qt::AlignBottom | Qt::AlignLeft); |
| } |
| |
| if (m_freeze) { |
| QString str = QString::asprintf("%8X (%3d,%3d,%3d,%3d)", |
| m_currentColor, |
| (0xff000000 & m_currentColor) >> 24, |
| (0x00ff0000 & m_currentColor) >> 16, |
| (0x0000ff00 & m_currentColor) >> 8, |
| (0x000000ff & m_currentColor)); |
| render_string(&p, w, h, |
| str, |
| Qt::AlignBottom | Qt::AlignRight); |
| } |
| |
| if (m_mouseDown && m_dragStart != m_dragCurrent) { |
| int x1 = (m_dragStart.x() / m_zoom) * m_zoom; |
| int y1 = (m_dragStart.y() / m_zoom) * m_zoom; |
| int x2 = (m_dragCurrent.x() / m_zoom) * m_zoom; |
| int y2 = (m_dragCurrent.y() / m_zoom) * m_zoom; |
| QRect r = QRect(x1, y1, x2 - x1, y2 - y1).normalized(); |
| p.setBrush(Qt::NoBrush); |
| p.setPen(QPen(Qt::red, 3, Qt::SolidLine)); |
| p.drawRect(r); |
| p.setPen(QPen(Qt::black, 1, Qt::SolidLine)); |
| p.drawRect(r); |
| |
| QString str = QString::asprintf("Rect: x=%d, y=%d, w=%d, h=%d", |
| r.x() / m_zoom, |
| r.y() / m_zoom, |
| r.width() / m_zoom, |
| r.height() / m_zoom); |
| render_string(&p, w, h, str, Qt::AlignBottom | Qt::AlignLeft); |
| } |
| |
| |
| } |
| |
| void QPixelTool::keyPressEvent(QKeyEvent *e) |
| { |
| switch (e->key()) { |
| case Qt::Key_Space: |
| toggleFreeze(); |
| break; |
| case Qt::Key_Plus: |
| increaseZoom(); |
| break; |
| case Qt::Key_Minus: |
| decreaseZoom(); |
| break; |
| case Qt::Key_PageUp: |
| setGridSize(m_gridSize + 1); |
| break; |
| case Qt::Key_PageDown: |
| setGridSize(m_gridSize - 1); |
| break; |
| case Qt::Key_G: |
| toggleGrid(); |
| break; |
| case Qt::Key_A: |
| m_autoUpdate = !m_autoUpdate; |
| break; |
| #if QT_CONFIG(clipboard) |
| case Qt::Key_C: |
| if (e->modifiers().testFlag(Qt::ControlModifier)) |
| copyToClipboard(); |
| else |
| copyColorToClipboard(); |
| break; |
| #endif // QT_CONFIG(clipboard) |
| case Qt::Key_S: |
| if (e->modifiers() & Qt::ControlModifier) { |
| releaseKeyboard(); |
| saveToFile(); |
| } |
| break; |
| case Qt::Key_Control: |
| grabKeyboard(); |
| break; |
| case Qt::Key_F1: |
| aboutPixelTool(); |
| break; |
| } |
| } |
| |
| void QPixelTool::keyReleaseEvent(QKeyEvent *e) |
| { |
| switch(e->key()) { |
| case Qt::Key_Control: |
| releaseKeyboard(); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| void QPixelTool::resizeEvent(QResizeEvent *) |
| { |
| grabScreen(); |
| } |
| |
| void QPixelTool::mouseMoveEvent(QMouseEvent *e) |
| { |
| if (m_mouseDown) |
| m_dragCurrent = e->pos(); |
| |
| int x = e->x() / m_zoom; |
| int y = e->y() / m_zoom; |
| |
| QImage im = m_buffer.toImage().convertToFormat(QImage::Format_ARGB32); |
| if (x < im.width() && y < im.height() && x >= 0 && y >= 0) { |
| m_currentColor = im.pixel(x, y); |
| update(); |
| } |
| } |
| |
| void QPixelTool::mousePressEvent(QMouseEvent *e) |
| { |
| if (!m_freeze) |
| return; |
| m_mouseDown = true; |
| m_dragStart = e->pos(); |
| } |
| |
| void QPixelTool::mouseReleaseEvent(QMouseEvent *) |
| { |
| m_mouseDown = false; |
| } |
| |
| static QAction *addCheckableAction(QMenu &menu, const QString &title, |
| bool value, const QKeySequence &key) |
| { |
| QAction *result = menu.addAction(title); |
| result->setCheckable(true); |
| result->setChecked(value); |
| result->setShortcut(key); |
| return result; |
| } |
| |
| static QAction *addCheckableAction(QMenu &menu, const QString &title, |
| bool value, const QKeySequence &key, |
| QActionGroup *group) |
| { |
| QAction *result = addCheckableAction(menu, title, value, key); |
| result->setActionGroup(group); |
| return result; |
| } |
| |
| void QPixelTool::contextMenuEvent(QContextMenuEvent *e) |
| { |
| const bool tmpFreeze = m_freeze; |
| m_freeze = true; |
| |
| QMenu menu; |
| menu.addAction(QLatin1String("Qt Pixel Zooming Tool"))->setEnabled(false); |
| menu.addSeparator(); |
| |
| // Grid color options... |
| QActionGroup *gridGroup = new QActionGroup(&menu); |
| addCheckableAction(menu, QLatin1String("White grid"), m_gridActive == 2, |
| Qt::Key_W, gridGroup); |
| QAction *blackGrid = addCheckableAction(menu, QLatin1String("Black grid"), |
| m_gridActive == 1, Qt::Key_B, gridGroup); |
| QAction *noGrid = addCheckableAction(menu, QLatin1String("No grid"), m_gridActive == 0, |
| Qt::Key_N, gridGroup); |
| menu.addSeparator(); |
| |
| // Grid size options |
| menu.addAction(QLatin1String("Increase grid size"), |
| this, &QPixelTool::increaseGridSize, Qt::Key_PageUp); |
| menu.addAction(QLatin1String("Decrease grid size"), |
| this, &QPixelTool::decreaseGridSize, Qt::Key_PageDown); |
| menu.addSeparator(); |
| |
| QActionGroup *lcdGroup = new QActionGroup(&menu); |
| addCheckableAction(menu, QLatin1String("No subpixels"), m_lcdMode == 0, |
| QKeySequence(), lcdGroup); |
| QAction *rgbPixels = addCheckableAction(menu, QLatin1String("RGB subpixels"), |
| m_lcdMode == 1, QKeySequence(), lcdGroup); |
| QAction *bgrPixels = addCheckableAction(menu, QLatin1String("BGR subpixels"), |
| m_lcdMode == 2, QKeySequence(), lcdGroup); |
| QAction *vrgbPixels = addCheckableAction(menu, QLatin1String("VRGB subpixels"), |
| m_lcdMode == 3, QKeySequence(), lcdGroup); |
| QAction *vbgrPixels = addCheckableAction(menu, QLatin1String("VBGR subpixels"), |
| m_lcdMode == 4, QKeySequence(), lcdGroup); |
| menu.addSeparator(); |
| |
| // Zoom options |
| menu.addAction(QLatin1String("Zoom in"), |
| this, &QPixelTool::increaseZoom, Qt::Key_Plus); |
| menu.addAction(QLatin1String("Zoom out"), |
| this, &QPixelTool::decreaseZoom, Qt::Key_Minus); |
| menu.addSeparator(); |
| |
| // Freeze / Autoupdate |
| QAction *freeze = addCheckableAction(menu, QLatin1String("Frozen"), |
| tmpFreeze, Qt::Key_Space); |
| QAction *autoUpdate = addCheckableAction(menu, QLatin1String("Continuous update"), |
| m_autoUpdate, Qt::Key_A); |
| menu.addSeparator(); |
| |
| // Copy to clipboard / save |
| menu.addAction(QLatin1String("Save as image..."), |
| this, &QPixelTool::saveToFile, QKeySequence::SaveAs); |
| #if QT_CONFIG(clipboard) |
| menu.addAction(QLatin1String("Copy to clipboard"), |
| this, &QPixelTool::copyToClipboard, QKeySequence::Copy); |
| menu.addAction(QLatin1String("Copy color value to clipboard"), |
| this, &QPixelTool::copyColorToClipboard, Qt::Key_C); |
| #endif // QT_CONFIG(clipboard) |
| |
| menu.addSeparator(); |
| menu.addAction(QLatin1String("About Qt"), qApp, &QApplication::aboutQt); |
| menu.addAction(QLatin1String("About Qt Pixeltool"), this, &QPixelTool::aboutPixelTool); |
| |
| menu.exec(mapToGlobal(e->pos())); |
| |
| // Read out grid settings |
| if (noGrid->isChecked()) |
| m_gridActive = 0; |
| else if (blackGrid->isChecked()) |
| m_gridActive = 1; |
| else |
| m_gridActive = 2; |
| |
| // Read out lcd settings |
| if (rgbPixels->isChecked()) |
| m_lcdMode = 1; |
| else if (bgrPixels->isChecked()) |
| m_lcdMode = 2; |
| else if (vrgbPixels->isChecked()) |
| m_lcdMode = 3; |
| else if (vbgrPixels->isChecked()) |
| m_lcdMode = 4; |
| else |
| m_lcdMode = 0; |
| |
| m_autoUpdate = autoUpdate->isChecked(); |
| m_freeze = freeze->isChecked(); |
| |
| // LCD mode looks off unless zoom is dividable by 3 |
| if (m_lcdMode && m_zoom % 3) |
| setZoom(qMax(3, (m_zoom + 1) / 3)); |
| } |
| |
| QSize QPixelTool::sizeHint() const |
| { |
| return m_initialSize; |
| } |
| |
| static inline QString pixelToolTitle(QPoint pos, const QColor ¤tColor) |
| { |
| if (QHighDpiScaling::isActive()) { |
| if (auto screen = QGuiApplication::screenAt(pos)) |
| pos = QHighDpi::toNativePixels(pos, screen); |
| } |
| return QCoreApplication::applicationName() + QLatin1String(" [") |
| + QString::number(pos.x()) |
| + QLatin1String(", ") + QString::number(pos.y()) + QLatin1String("] ") |
| + currentColor.name(); |
| } |
| |
| void QPixelTool::grabScreen() |
| { |
| if (m_preview_mode) { |
| int w = qMin(width() / m_zoom + 1, m_preview_image.width()); |
| int h = qMin(height() / m_zoom + 1, m_preview_image.height()); |
| m_buffer = QPixmap::fromImage(m_preview_image).copy(0, 0, w, h); |
| update(); |
| return; |
| } |
| |
| QPoint mousePos = QCursor::pos(); |
| if (mousePos == m_lastMousePos && !m_autoUpdate) |
| return; |
| |
| if (m_lastMousePos != mousePos) |
| setWindowTitle(pixelToolTitle(mousePos, m_currentColor)); |
| |
| int w = int(width() / float(m_zoom)); |
| int h = int(height() / float(m_zoom)); |
| |
| if (width() % m_zoom > 0) |
| ++w; |
| if (height() % m_zoom > 0) |
| ++h; |
| |
| int x = mousePos.x() - w/2; |
| int y = mousePos.y() - h/2; |
| |
| const QBrush darkBrush = palette().color(QPalette::Dark); |
| const QDesktopWidget *desktopWidget = QApplication::desktop(); |
| if (QScreen *screen = QGuiApplication::screens().value(desktopWidget->screenNumber(this), nullptr)) { |
| m_buffer = screen->grabWindow(desktopWidget->winId(), x, y, w, h); |
| } else { |
| m_buffer = QPixmap(w, h); |
| m_buffer.fill(darkBrush.color()); |
| } |
| QRegion geom(x, y, w, h); |
| QRect screenRect; |
| const auto screens = QGuiApplication::screens(); |
| for (auto screen : screens) |
| screenRect |= screen->geometry(); |
| geom -= screenRect; |
| const auto rectsInRegion = geom.rectCount(); |
| if (rectsInRegion > 0) { |
| QPainter p(&m_buffer); |
| p.translate(-x, -y); |
| p.setPen(Qt::NoPen); |
| p.setBrush(darkBrush); |
| p.drawRects(geom.begin(), rectsInRegion); |
| } |
| |
| update(); |
| |
| m_currentColor = m_buffer.toImage().pixel(m_buffer.rect().center()); |
| m_lastMousePos = mousePos; |
| } |
| |
| void QPixelTool::startZoomVisibleTimer() |
| { |
| if (m_displayZoomId > 0) { |
| killTimer(m_displayZoomId); |
| } |
| m_displayZoomId = startTimer(5000); |
| setZoomVisible(true); |
| } |
| |
| void QPixelTool::startGridSizeVisibleTimer() |
| { |
| if (m_gridActive) { |
| if (m_displayGridSizeId > 0) |
| killTimer(m_displayGridSizeId); |
| m_displayGridSizeId = startTimer(5000); |
| m_displayGridSize = true; |
| update(); |
| } |
| } |
| |
| void QPixelTool::setZoomVisible(bool visible) |
| { |
| m_displayZoom = visible; |
| update(); |
| } |
| |
| void QPixelTool::toggleFreeze() |
| { |
| m_freeze = !m_freeze; |
| if (!m_freeze) |
| m_dragStart = m_dragCurrent = QPoint(); |
| } |
| |
| void QPixelTool::increaseZoom() |
| { |
| if (!m_lcdMode) |
| setZoom(m_zoom + 1); |
| else |
| setZoom(m_zoom + 3); |
| } |
| |
| void QPixelTool::decreaseZoom() |
| { |
| if (!m_lcdMode) |
| setZoom(m_zoom - 1); |
| else |
| setZoom(m_zoom - 3); |
| } |
| |
| void QPixelTool::setZoom(int zoom) |
| { |
| if (zoom > 0) { |
| QPoint pos = m_lastMousePos; |
| m_lastMousePos = QPoint(); |
| m_zoom = zoom; |
| grabScreen(); |
| m_lastMousePos = pos; |
| m_dragStart = m_dragCurrent = QPoint(); |
| startZoomVisibleTimer(); |
| } |
| } |
| |
| void QPixelTool::toggleGrid() |
| { |
| if (++m_gridActive > 2) |
| m_gridActive = 0; |
| update(); |
| } |
| |
| void QPixelTool::setGridSize(int gridSize) |
| { |
| if (m_gridActive && gridSize > 0) { |
| m_gridSize = gridSize; |
| startGridSizeVisibleTimer(); |
| update(); |
| } |
| } |
| |
| #if QT_CONFIG(clipboard) |
| void QPixelTool::copyToClipboard() |
| { |
| QGuiApplication::clipboard()->setPixmap(m_buffer); |
| } |
| |
| void QPixelTool::copyColorToClipboard() |
| { |
| QGuiApplication::clipboard()->setText(QColor(m_currentColor).name()); |
| } |
| #endif // QT_CONFIG(clipboard) |
| |
| void QPixelTool::saveToFile() |
| { |
| bool oldFreeze = m_freeze; |
| m_freeze = true; |
| |
| QFileDialog fileDialog(this); |
| fileDialog.setWindowTitle(QLatin1String("Save as image")); |
| fileDialog.setAcceptMode(QFileDialog::AcceptSave); |
| fileDialog.setDirectory(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); |
| QStringList mimeTypes; |
| const QByteArrayList supportedMimeTypes = QImageWriter::supportedMimeTypes(); |
| for (const QByteArray &mimeTypeB : supportedMimeTypes) |
| mimeTypes.append(QString::fromLatin1(mimeTypeB)); |
| fileDialog.setMimeTypeFilters(mimeTypes); |
| const QString pngType = QLatin1String("image/png"); |
| if (mimeTypes.contains(pngType)) { |
| fileDialog.selectMimeTypeFilter(pngType); |
| fileDialog.setDefaultSuffix(QLatin1String("png")); |
| } |
| |
| while (fileDialog.exec() == QDialog::Accepted |
| && !m_buffer.save(fileDialog.selectedFiles().constFirst())) { |
| QMessageBox::warning(this, QLatin1String("Unable to write image"), |
| QLatin1String("Unable to write ") |
| + QDir::toNativeSeparators(fileDialog.selectedFiles().first())); |
| } |
| m_freeze = oldFreeze; |
| } |
| |
| QTextStream &operator<<(QTextStream &str, const QScreen *screen) |
| { |
| const QRect geometry = screen->geometry(); |
| str << '"' << screen->name() << "\" " << geometry.width() |
| << 'x' << geometry.height() << forcesign << geometry.x() << geometry.y() |
| << noforcesign << ", " << qRound(screen->logicalDotsPerInch()) << "DPI" |
| << ", Depth: " << screen->depth() << ", " << screen->refreshRate() << "Hz"; |
| const qreal dpr = screen->devicePixelRatio(); |
| if (!qFuzzyCompare(dpr, qreal(1))) |
| str << ", DPR: " << dpr; |
| return str; |
| } |
| |
| QString QPixelTool::aboutText() const |
| { |
| const QList<QScreen *> screens = QGuiApplication::screens(); |
| const QScreen *windowScreen = windowHandle()->screen(); |
| |
| QString result; |
| QTextStream str(&result); |
| str << "<html></head><body><h2>Qt Pixeltool</h2><p>Qt " << QT_VERSION_STR |
| << "</p><p>Copyright (C) 2017 The Qt Company Ltd.</p><h3>Screens</h3><ul>"; |
| for (const QScreen *screen : screens) |
| str << "<li>" << (screen == windowScreen ? "* " : " ") << screen << "</li>"; |
| str << "<ul></body></html>"; |
| return result; |
| } |
| |
| void QPixelTool::aboutPixelTool() |
| { |
| QMessageBox aboutBox(QMessageBox::Information, tr("About Qt Pixeltool"), aboutText(), |
| QMessageBox::Close, this); |
| aboutBox.setWindowFlags(aboutBox.windowFlags() & ~Qt::WindowContextHelpButtonHint); |
| aboutBox.setTextInteractionFlags(Qt::TextBrowserInteraction); |
| aboutBox.exec(); |
| } |
| |
| QT_END_NAMESPACE |