/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION > 0x050000 # include # include # include # include #else # define Q_NULLPTR 0 # define Q_DECL_OVERRIDE #endif #ifdef Q_OS_WIN # include #endif #include #include #if QT_VERSION < 0x050000 QDebug operator<<(QDebug d, const QPixmap &p) { d.nospace() << "QPixmap(" << p.size() << ')'; return d; } #endif // Qt 4 // High DPI cursor test for testing cursor sizes in multi-screen setups. // It creates one widget per screen with a grid of standard cursors, // pixmap / bitmap cursors and pixmap / bitmap cursors with device pixel ratio 2. // On the left, there is a ruler with 10 DIP marks. // The code is meant to compile with Qt 4 also. static QString screenInfo(const QWidget *w) { QString result; QTextStream str(&result); #if QT_VERSION > 0x050000 QScreen *screen = Q_NULLPTR; if (const QWindow *window = w->windowHandle()) screen = window->screen(); if (screen) { str << '"' << screen->name() << "\" " << screen->size().width() << 'x' << screen->size().height() << ", DPR=" << screen->devicePixelRatio() << ", " << screen->logicalDotsPerInchX() << "DPI "; if (QHighDpiScaling::isActive()) str << ", factor=" << QHighDpiScaling::factor(screen); else str << ", no scaling"; } else { str << ""; } #else QDesktopWidget *desktop = QApplication::desktop(); int screenNumber = desktop->screenNumber(w); str << "Screen #" <screenGeometry(screenNumber).width() << 'x' << desktop->screenGeometry(screenNumber).height() << " PD: " << w->logicalDpiX() << "DPI"; #endif #ifdef Q_OS_WIN str << ", SM_C_CURSOR: " << GetSystemMetrics(SM_CXCURSOR) << 'x' << GetSystemMetrics(SM_CYCURSOR); #endif return result; } // Helpers for painting pixmaps and creating cursors static QPixmap paintPixmap(int size, QColor c) { QPixmap result(size, size); result.fill(c); QPainter p(&result); p.drawRect(QRect(QPoint(0, 0), result.size() - QSize(1, 1))); p.drawLine(0, 0, size, size); p.drawLine(0, size, size, 0); return result; } static QCursor pixmapCursor(int size) { QCursor result(paintPixmap(size, Qt::red), size / 2, size / 2); return result; } static QPair paintBitmaps(int size) { QBitmap bitmap(size, size); bitmap.fill(Qt::color1); QBitmap mask(size, size); mask.fill(Qt::color1); { QPainter mp(&mask); mp.fillRect(QRect(0, 0, size / 2, size / 2), Qt::color0); } return QPair(bitmap, mask); } static QCursor bitmapCursor(int size) { QPair bitmaps = paintBitmaps(size); return QCursor(bitmaps.first, bitmaps.second, size / 2, size / 2); } #if QT_VERSION > 0x050000 static QCursor pixmapCursorDevicePixelRatio(int size, int dpr) { QPixmap pixmap = paintPixmap(dpr * size, Qt::yellow); pixmap.setDevicePixelRatio(dpr); return QCursor(pixmap, size / 2, size / 2); } static QCursor bitmapCursorDevicePixelRatio(int size, int dpr) { QPair bitmaps = paintBitmaps(dpr * size); bitmaps.first.setDevicePixelRatio(dpr); bitmaps.second.setDevicePixelRatio(dpr); return QCursor(bitmaps.first, bitmaps.second, size / 2, size / 2); } #endif // Qt 5 // A label from which a pixmap can be dragged for testing drag with pixmaps/DPR. class DraggableLabel : public QLabel { public: explicit DraggableLabel(const QPixmap &p, const QString &text, QWidget *parent = Q_NULLPTR) : QLabel(text, parent), m_pixmap(p) { setToolTip(QLatin1String("Click to drag away the pixmap. Press Shift to set a circular mask.")); } protected: void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; private: const QPixmap m_pixmap; }; void DraggableLabel::mousePressEvent(QMouseEvent *) { QMimeData *mimeData = new QMimeData; mimeData->setImageData(QVariant::fromValue(m_pixmap)); QDrag *drag = new QDrag(this); QPixmap pixmap = m_pixmap; if (QApplication::keyboardModifiers() & Qt::ShiftModifier) { QBitmap mask(pixmap.width(), pixmap.height()); mask.clear(); QPainter painter(&mask); painter.setBrush(Qt::color1); const int hx = pixmap.width() / 2; const int hy = pixmap.width() / 2; painter.drawEllipse(QPoint(hx, hy), hx, hy); pixmap.setMask(mask); } drag->setMimeData(mimeData); drag->setPixmap(pixmap); QPoint sizeP = QPoint(m_pixmap.width(), m_pixmap.height()); #if QT_VERSION > 0x050000 sizeP /= int(m_pixmap.devicePixelRatio()); #endif // Qt 5 drag->setHotSpot(sizeP / 2); qDebug() << "Dragging:" << m_pixmap; drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction); } // Vertical ruler widget with 10 px marks class VerticalRuler : public QWidget { public: VerticalRuler(QWidget *parent = Q_NULLPTR); protected: void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE; }; VerticalRuler::VerticalRuler(QWidget *parent) : QWidget(parent) { const int screenWidth = screen()->geometry().width(); setFixedWidth(screenWidth / 48); // 1920 pixel monitor ->40 } void VerticalRuler::paintEvent(QPaintEvent *) { const QSize sizeS(size()); const QPoint sizeP(sizeS.width(), sizeS.height()); const QPoint center = sizeP / 2; QPainter painter(this); painter.fillRect(QRect(QPoint(0, 0), sizeS), Qt::white); painter.drawLine(center.x(), 0, center.x(), sizeP.y()); for (int y = 0; y < sizeP.y(); y += 10) painter.drawLine(center.x() - 5, y, center.x() + 5, y); } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = Q_NULLPTR); void updateScreenInfo() { m_screenInfoLabel->setText(screenInfo(this)); } public slots: void screenChanged() { updateScreenInfo(); } private: QLabel *m_screenInfoLabel; }; static QLabel *createCursorLabel(const QCursor &cursor, const QString &additionalText = QString()) { QString labelText; QDebug(&labelText).nospace() << cursor.shape(); #if QT_VERSION > 0x050000 labelText.remove(0, labelText.indexOf('(') + 1); labelText.chop(1); #endif // Qt 5 if (!additionalText.isEmpty()) labelText += ' ' + additionalText; const QPixmap cursorPixmap = cursor.pixmap(); QLabel *result = Q_NULLPTR; if (cursorPixmap.size().isEmpty()) { result = new QLabel(labelText); result->setFrameShape(QFrame::Box); } else { result = new DraggableLabel(cursor.pixmap(), labelText); result->setFrameShape(QFrame::StyledPanel); } result->setCursor(cursor); return result; } static void addToGrid(QWidget *w, QGridLayout *gridLayout, int columnCount, int &row, int &col) { gridLayout->addWidget(w, row, col); if (col >= columnCount) { col = 0; row++; } else { col++; } } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , m_screenInfoLabel(new QLabel) { QString title = "Cursors "; #if QT_VERSION > 0x050000 title += '(' + QGuiApplication::platformName() + ") "; #endif title += QT_VERSION_STR; setWindowTitle(title); QMenu *fileMenu = menuBar()->addMenu("File"); QAction *quitAction = fileMenu->addAction("Quit"); quitAction->setShortcut(Qt::CTRL + Qt::Key_Q); connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); QToolBar *fileToolBar = addToolBar("File"); fileToolBar->addAction(quitAction); QWidget *cw = new QWidget; QHBoxLayout *hLayout = new QHBoxLayout(cw); hLayout->addWidget(new VerticalRuler(cw)); QGridLayout *gridLayout = new QGridLayout; hLayout->addLayout(gridLayout); const int columnCount = 5; const int size = 32; int row = 0; int col = 0; for (int i = 0; i < Qt::BitmapCursor; ++i) addToGrid(createCursorLabel(QCursor(static_cast(i))), gridLayout, columnCount, row, col); addToGrid(createCursorLabel(QCursor(pixmapCursor(size)), QLatin1String("Plain PX ") + QString::number(size)), gridLayout, columnCount, row, col); addToGrid(createCursorLabel(bitmapCursor(size), QLatin1String("Plain BM ") + QString::number(size)), gridLayout, columnCount, row, col); #if QT_VERSION > 0x050000 addToGrid(createCursorLabel(QCursor(pixmapCursorDevicePixelRatio(size, 2)), "PX with DPR 2 " + QString::number(size)), gridLayout, columnCount, row, col); addToGrid(createCursorLabel(QCursor(bitmapCursorDevicePixelRatio(size, 2)), "BM with DPR 2 " + QString::number(size)), gridLayout, columnCount, row, col); #endif // Qt 5 gridLayout->addWidget(m_screenInfoLabel, row + 1, 0, 1, columnCount); setCentralWidget(cw); } typedef QSharedPointer MainWindowPtr; typedef QList MainWindowPtrList; int main(int argc, char *argv[]) { QStringList arguments; std::copy(argv + 1, argv + argc, std::back_inserter(arguments)); #if QT_VERSION > 0x050000 if (arguments.contains("-s")) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); else if (arguments.contains("-n")) QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); #endif // Qt 5 QApplication app(argc, argv); MainWindowPtrList windows; const int lastScreen = arguments.contains("-p") ? 0 // Primary screen only : QGuiApplication::screens().size() - 1; // All screens for (int s = lastScreen; s >= 0; --s) { MainWindowPtr window(new MainWindow()); const QPoint pos = QGuiApplication::screens().at(s)->geometry().center() - QPoint(200, 100); window->move(pos); windows.append(window); window->show(); window->updateScreenInfo(); #if QT_VERSION > 0x050000 QObject::connect(window->windowHandle(), &QWindow::screenChanged, window.data(), &MainWindow::updateScreenInfo); #endif } return app.exec(); } #include "main.moc"