diff --git a/tests/manual/qcursor/qcursor.pro b/tests/manual/qcursor/qcursor.pro index af082a4b82fddff24e9e65296027c6a61af4f684..0b5c2b194529efb7d2c2ae3cc6c823b8ace6ca20 100644 --- a/tests/manual/qcursor/qcursor.pro +++ b/tests/manual/qcursor/qcursor.pro @@ -1,3 +1,3 @@ TEMPLATE = subdirs -SUBDIRS = allcursors grab_override +SUBDIRS = allcursors grab_override qcursorhighdpi diff --git a/tests/manual/qcursor/qcursorhighdpi/main.cpp b/tests/manual/qcursor/qcursorhighdpi/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc45ae00d159e096514baee37630cbfec360a285 --- /dev/null +++ b/tests/manual/qcursor/qcursorhighdpi/main.cpp @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QAction> +#include <QApplication> +#include <QDesktopWidget> +#include <QGridLayout> +#include <QLabel> +#include <QMainWindow> +#include <QMenu> +#include <QMenuBar> +#include <QSharedPointer> +#include <QToolBar> + +#include <QBitmap> +#include <QCursor> +#include <QPainter> +#include <QPixmap> + +#include <QDebug> +#include <QStringList> +#include <QTextStream> + +#if QT_VERSION > 0x050000 +# include <QScreen> +# include <QWindow> +# include <private/qhighdpiscaling_p.h> +# include <qpa/qplatformwindow.h> +#else +# define Q_NULLPTR 0 +# define Q_DECL_OVERRIDE +#endif + +#ifdef Q_OS_WIN +# include <qt_windows.h> +#endif + +#include <algorithm> +#include <iterator> + +// 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 << "<null>"; + } +#else + QDesktopWidget *desktop = QApplication::desktop(); + int screenNumber = desktop->screenNumber(w); + str << "Screen #" <<screenNumber << ' ' << desktop->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<QBitmap, QBitmap> 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<QBitmap, QBitmap>(bitmap, mask); +} + +static QCursor bitmapCursor(int size) +{ + QPair<QBitmap, QBitmap> 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<QBitmap, QBitmap> 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 + +// 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 = QApplication::desktop()->screenGeometry(this).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; + QLabel *result = new QLabel(labelText); + result->setFrameShape(QFrame::Box); + 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<Qt::CursorShape>(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<MainWindow> MainWindowPtr; +typedef QList<MainWindowPtr> 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; + + QDesktopWidget *desktopWidget = app.desktop(); + + for (int s = desktopWidget->screenCount() - 1; s >= 0; --s) { + MainWindowPtr window(new MainWindow(desktopWidget->screen(s))); + const QPoint pos = desktopWidget->screenGeometry(s).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" diff --git a/tests/manual/qcursor/qcursorhighdpi/qcursorhighdpi.pro b/tests/manual/qcursor/qcursorhighdpi/qcursorhighdpi.pro new file mode 100644 index 0000000000000000000000000000000000000000..3a8fc25b333840d1c517050dce8be2a828a4025e --- /dev/null +++ b/tests/manual/qcursor/qcursorhighdpi/qcursorhighdpi.pro @@ -0,0 +1,6 @@ +TEMPLATE = app +QT = core gui +greaterThan(QT_MAJOR_VERSION, 4): QT += gui-private core-private widgets +CONFIG -= app_bundle +SOURCES += main.cpp +win32: LIBS += -lUser32