2012-11-20 10:34:52 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2016-01-15 12:36:27 +00:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2012-11-20 10:34:52 +00:00
|
|
|
**
|
2013-05-24 13:49:24 +00:00
|
|
|
** This file is part of the test suite of the Qt Toolkit.
|
2012-11-20 10:34:52 +00:00
|
|
|
**
|
2016-01-15 12:36:27 +00:00
|
|
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
2012-11-20 10:34:52 +00:00
|
|
|
** 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
|
2015-01-28 08:44:43 +00:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
2016-01-15 12:36:27 +00:00
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2012-11-20 10:34:52 +00:00
|
|
|
**
|
2016-01-15 12:36:27 +00:00
|
|
|
** 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.
|
2012-11-20 10:34:52 +00:00
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
2014-07-18 12:22:14 +00:00
|
|
|
#include <QMainWindow>
|
2015-06-18 15:00:27 +00:00
|
|
|
#include <QMenuBar>
|
2014-07-18 12:22:14 +00:00
|
|
|
#include <QLabel>
|
|
|
|
#include <QHBoxLayout>
|
2019-11-27 08:59:33 +00:00
|
|
|
#include <QFormLayout>
|
2014-07-18 12:22:14 +00:00
|
|
|
#include <QApplication>
|
|
|
|
#include <QAction>
|
|
|
|
#include <QStyle>
|
|
|
|
#include <QToolBar>
|
|
|
|
#include <QPushButton>
|
2015-06-18 15:00:27 +00:00
|
|
|
#include <QButtonGroup>
|
2014-07-18 12:22:14 +00:00
|
|
|
#include <QLineEdit>
|
2016-04-26 23:15:48 +00:00
|
|
|
#include <QPlainTextEdit>
|
2014-07-18 12:22:14 +00:00
|
|
|
#include <QScrollBar>
|
|
|
|
#include <QSlider>
|
|
|
|
#include <QSpinBox>
|
|
|
|
#include <QTabBar>
|
2016-04-26 23:15:48 +00:00
|
|
|
#include <QTextBrowser>
|
2014-07-18 12:22:14 +00:00
|
|
|
#include <QIcon>
|
|
|
|
#include <QPainter>
|
|
|
|
#include <QWindow>
|
|
|
|
#include <QScreen>
|
2016-11-25 12:57:48 +00:00
|
|
|
#include <QGraphicsView>
|
|
|
|
#include <QGraphicsTextItem>
|
2014-07-18 12:22:14 +00:00
|
|
|
#include <QFile>
|
2015-06-18 15:00:27 +00:00
|
|
|
#include <QMouseEvent>
|
2014-07-18 12:22:14 +00:00
|
|
|
#include <QTemporaryDir>
|
2015-06-18 15:00:27 +00:00
|
|
|
#include <QTimer>
|
2014-07-18 12:22:14 +00:00
|
|
|
#include <QCommandLineParser>
|
|
|
|
#include <QCommandLineOption>
|
2015-06-18 15:00:27 +00:00
|
|
|
#include <QDebug>
|
|
|
|
#include <private/qhighdpiscaling_p.h>
|
2016-04-26 23:15:48 +00:00
|
|
|
#include <qpa/qplatformscreen.h>
|
2012-11-20 10:34:52 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
#include "dragwidget.h"
|
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
#include <utility>
|
|
|
|
|
2016-04-26 23:15:48 +00:00
|
|
|
static QTextStream &operator<<(QTextStream &str, const QRect &r)
|
|
|
|
{
|
|
|
|
str << r.width() << 'x' << r.height() << forcesign << r.x() << r.y() << noforcesign;
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2019-11-27 08:59:33 +00:00
|
|
|
static QString formatWindowTitle(const QString &title)
|
|
|
|
{
|
|
|
|
QString result;
|
|
|
|
QTextStream(&result) << title << ' ' << QT_VERSION_STR << " ("
|
|
|
|
<< QGuiApplication::platformName()
|
|
|
|
<< '/' << QApplication::style()->objectName() << ')';
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
class DemoContainerBase
|
|
|
|
{
|
|
|
|
public:
|
2019-11-27 08:40:08 +00:00
|
|
|
DemoContainerBase() = default;
|
|
|
|
virtual ~DemoContainerBase() = default;
|
|
|
|
QString name() { return option().names().constFirst(); }
|
2015-06-18 15:00:27 +00:00
|
|
|
virtual QCommandLineOption &option() = 0;
|
|
|
|
virtual void makeVisible(bool visible, QWidget *parent) = 0;
|
2019-11-27 08:40:08 +00:00
|
|
|
QWidget *widget() const { return m_widget; }
|
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
protected:
|
2019-11-27 08:40:08 +00:00
|
|
|
QWidget *m_widget = nullptr;
|
2015-06-18 15:00:27 +00:00
|
|
|
};
|
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
using DemoContainerList = QVector<DemoContainerBase*>;
|
2015-06-18 15:00:27 +00:00
|
|
|
|
|
|
|
template <class T>
|
|
|
|
class DemoContainer : public DemoContainerBase
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
DemoContainer(const QString &optionName, const QString &description)
|
|
|
|
: m_option(optionName, description)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
~DemoContainer() { delete m_widget; }
|
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
QCommandLineOption &option() override { return m_option; }
|
2015-06-18 15:00:27 +00:00
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
void makeVisible(bool visible, QWidget *parent) override
|
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
if (visible && !m_widget) {
|
|
|
|
m_widget = new T;
|
2019-11-27 08:59:33 +00:00
|
|
|
if (m_widget->windowTitle().isEmpty()) {
|
|
|
|
QString title = m_option.description();
|
|
|
|
if (title.startsWith("Test ", Qt::CaseInsensitive))
|
|
|
|
title.remove(0, 5);
|
|
|
|
title[0] = title.at(0).toUpper();
|
|
|
|
m_widget->setWindowTitle(formatWindowTitle(title));
|
|
|
|
}
|
2015-06-18 15:00:27 +00:00
|
|
|
m_widget->installEventFilter(parent);
|
|
|
|
}
|
|
|
|
if (m_widget)
|
|
|
|
m_widget->setVisible(visible);
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
private:
|
|
|
|
QCommandLineOption m_option;
|
|
|
|
};
|
|
|
|
|
|
|
|
class LabelSlider : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
LabelSlider(QObject *parent, const QString &text, QGridLayout *layout, int row)
|
|
|
|
: QObject(parent)
|
|
|
|
{
|
|
|
|
QLabel *textLabel = new QLabel(text);
|
|
|
|
m_slider = new QSlider();
|
|
|
|
m_slider->setOrientation(Qt::Horizontal);
|
|
|
|
m_slider->setMinimum(1);
|
|
|
|
m_slider->setMaximum(40);
|
|
|
|
m_slider->setValue(10);
|
|
|
|
m_slider->setTracking(false);
|
|
|
|
m_slider->setTickInterval(5);
|
|
|
|
m_slider->setTickPosition(QSlider::TicksBelow);
|
|
|
|
m_label = new QLabel("1.0");
|
|
|
|
|
|
|
|
// set up layouts
|
|
|
|
layout->addWidget(textLabel, row, 0);
|
|
|
|
layout->addWidget(m_slider, row, 1);
|
|
|
|
layout->addWidget(m_label, row, 2);
|
|
|
|
|
|
|
|
// handle slider position change
|
|
|
|
connect(m_slider, &QSlider::sliderMoved, this, &LabelSlider::updateLabel);
|
|
|
|
connect(m_slider, &QSlider::valueChanged, this, &LabelSlider::valueChanged);
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
void setValue(int scaleFactor)
|
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
m_slider->setValue(scaleFactor);
|
|
|
|
updateLabel(scaleFactor);
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
private slots:
|
2019-11-27 08:40:08 +00:00
|
|
|
void updateLabel(int scaleFactor)
|
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
// slider value is scale factor times ten;
|
|
|
|
qreal scalefactorF = qreal(scaleFactor) / 10.0;
|
|
|
|
|
|
|
|
// update label, add ".0" if needed.
|
|
|
|
QString number = QString::number(scalefactorF);
|
2015-10-13 07:46:56 +00:00
|
|
|
if (!number.contains(QLatin1Char('.')))
|
2015-06-18 15:00:27 +00:00
|
|
|
number.append(".0");
|
|
|
|
m_label->setText(number);
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
signals:
|
|
|
|
void valueChanged(int scaleFactor);
|
2019-11-27 08:40:08 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
private:
|
|
|
|
QSlider *m_slider;
|
|
|
|
QLabel *m_label;
|
|
|
|
};
|
|
|
|
|
|
|
|
static qreal getScreenFactorWithoutPixelDensity(const QScreen *screen)
|
|
|
|
{
|
|
|
|
// this is a hack that relies on knowing the internals of QHighDpiScaling
|
|
|
|
static const char *scaleFactorProperty = "_q_scaleFactor";
|
|
|
|
QVariant screenFactor = screen->property(scaleFactorProperty);
|
|
|
|
return screenFactor.isValid() ? screenFactor.toReal() : 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline qreal getGlobalScaleFactor()
|
|
|
|
{
|
2018-06-24 07:58:50 +00:00
|
|
|
QScreen *noScreen = nullptr;
|
2015-06-18 15:00:27 +00:00
|
|
|
return QHighDpiScaling::factor(noScreen);
|
|
|
|
}
|
|
|
|
|
|
|
|
class DemoController : public QWidget
|
|
|
|
{
|
2019-11-27 08:40:08 +00:00
|
|
|
Q_OBJECT
|
2015-06-18 15:00:27 +00:00
|
|
|
public:
|
2019-11-27 08:40:08 +00:00
|
|
|
DemoController(DemoContainerList demos, QCommandLineParser *parser);
|
2015-06-18 15:00:27 +00:00
|
|
|
~DemoController();
|
2019-11-27 08:40:08 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
protected:
|
2019-11-27 08:40:08 +00:00
|
|
|
bool eventFilter(QObject *object, QEvent *event) override;
|
|
|
|
void closeEvent(QCloseEvent *) override { QCoreApplication::quit(); }
|
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
private slots:
|
|
|
|
void handleButton(int id, bool toggled);
|
2019-11-27 08:40:08 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
private:
|
2019-11-27 08:40:08 +00:00
|
|
|
DemoContainerList m_demos;
|
2015-06-18 15:00:27 +00:00
|
|
|
QButtonGroup *m_group;
|
|
|
|
};
|
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
DemoController::DemoController(DemoContainerList demos, QCommandLineParser *parser)
|
|
|
|
: m_demos(std::move(demos))
|
2015-06-18 15:00:27 +00:00
|
|
|
{
|
2019-11-27 08:59:33 +00:00
|
|
|
setWindowTitle(formatWindowTitle("Screen Scale Factors"));
|
2015-06-18 15:00:27 +00:00
|
|
|
setObjectName("controller"); // make WindowScaleFactorSetter skip this window
|
|
|
|
|
2019-11-27 08:59:33 +00:00
|
|
|
auto mainLayout = new QVBoxLayout(this);
|
|
|
|
auto scaleLayout = new QGridLayout;
|
|
|
|
mainLayout->addLayout(scaleLayout);
|
2015-06-18 15:00:27 +00:00
|
|
|
|
|
|
|
int layoutRow = 0;
|
2019-11-27 08:59:33 +00:00
|
|
|
LabelSlider *globalScaleSlider = new LabelSlider(this, "Global scale factor", scaleLayout, layoutRow++);
|
2015-06-18 15:00:27 +00:00
|
|
|
globalScaleSlider->setValue(int(getGlobalScaleFactor() * 10));
|
|
|
|
connect(globalScaleSlider, &LabelSlider::valueChanged, [](int scaleFactor){
|
|
|
|
// slider value is scale factor times ten;
|
|
|
|
qreal scalefactorF = qreal(scaleFactor) / 10.0;
|
|
|
|
QHighDpiScaling::setGlobalFactor(scalefactorF);
|
|
|
|
});
|
|
|
|
|
|
|
|
// set up one scale control line per screen
|
2019-11-27 08:40:08 +00:00
|
|
|
const auto screens = QGuiApplication::screens();
|
|
|
|
for (QScreen *screen : screens) {
|
2015-06-18 15:00:27 +00:00
|
|
|
// create scale control line
|
|
|
|
QSize screenSize = screen->geometry().size();
|
2015-10-13 07:46:56 +00:00
|
|
|
QString screenId = screen->name() + QLatin1Char(' ') + QString::number(screenSize.width())
|
|
|
|
+ QLatin1Char(' ') + QString::number(screenSize.height());
|
2019-11-27 08:59:33 +00:00
|
|
|
LabelSlider *slider = new LabelSlider(this, screenId, scaleLayout, layoutRow++);
|
2015-06-18 15:00:27 +00:00
|
|
|
slider->setValue(getScreenFactorWithoutPixelDensity(screen) * 10);
|
|
|
|
|
|
|
|
// handle slider value change
|
|
|
|
connect(slider, &LabelSlider::valueChanged, [screen](int scaleFactor){
|
|
|
|
// slider value is scale factor times ten;
|
|
|
|
qreal scalefactorF = qreal(scaleFactor) / 10.0;
|
|
|
|
|
|
|
|
// set scale factor for screen
|
|
|
|
qreal oldFactor = QHighDpiScaling::factor(screen);
|
|
|
|
QHighDpiScaling::setScreenFactor(screen, scalefactorF);
|
|
|
|
qreal newFactor = QHighDpiScaling::factor(screen);
|
|
|
|
|
|
|
|
qDebug() << "factor was / is" << oldFactor << newFactor;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-11-27 08:59:33 +00:00
|
|
|
auto demoLayout = new QFormLayout;
|
|
|
|
mainLayout->addLayout(demoLayout);
|
2015-06-18 15:00:27 +00:00
|
|
|
m_group = new QButtonGroup(this);
|
|
|
|
m_group->setExclusive(false);
|
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
for (int i = 0; i < m_demos.size(); ++i) {
|
|
|
|
DemoContainerBase *demo = m_demos.at(i);
|
2019-11-27 08:59:33 +00:00
|
|
|
QString name = demo->name();
|
|
|
|
name[0] = name.at(0).toUpper();
|
|
|
|
auto button = new QPushButton(name);
|
2015-06-18 15:00:27 +00:00
|
|
|
button->setCheckable(true);
|
2019-11-27 08:59:33 +00:00
|
|
|
demoLayout->addRow(demo->option().description(), button);
|
2015-06-18 15:00:27 +00:00
|
|
|
m_group->addButton(button, i);
|
|
|
|
|
|
|
|
if (parser->isSet(demo->option())) {
|
|
|
|
demo->makeVisible(true, this);
|
|
|
|
button->setChecked(true);
|
|
|
|
}
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
connect(m_group, QOverload<int,bool>::of(&QButtonGroup::buttonToggled),
|
|
|
|
this, &DemoController::handleButton);
|
2015-06-18 15:00:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DemoController::~DemoController()
|
|
|
|
{
|
2019-11-27 08:40:08 +00:00
|
|
|
qDeleteAll(m_demos);
|
2015-06-18 15:00:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DemoController::eventFilter(QObject *object, QEvent *event)
|
|
|
|
{
|
|
|
|
if (event->type() == QEvent::Close) {
|
2019-11-27 08:40:08 +00:00
|
|
|
for (int i = 0; i < m_demos.size(); ++i) {
|
|
|
|
DemoContainerBase *demo = m_demos.at(i);
|
2015-06-18 15:00:27 +00:00
|
|
|
if (demo->widget() == object) {
|
|
|
|
m_group->button(i)->setChecked(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DemoController::handleButton(int id, bool toggled)
|
|
|
|
{
|
2019-11-27 08:40:08 +00:00
|
|
|
m_demos.at(id)->makeVisible(toggled, this);
|
2015-06-18 15:00:27 +00:00
|
|
|
}
|
2012-11-20 10:34:52 +00:00
|
|
|
|
|
|
|
class PixmapPainter : public QWidget
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
PixmapPainter();
|
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
void paintEvent(QPaintEvent *event) override;
|
|
|
|
|
|
|
|
private:
|
2012-11-20 10:34:52 +00:00
|
|
|
QPixmap pixmap1X;
|
|
|
|
QPixmap pixmap2X;
|
|
|
|
QPixmap pixmapLarge;
|
|
|
|
QImage image1X;
|
|
|
|
QImage image2X;
|
|
|
|
QImage imageLarge;
|
|
|
|
QIcon qtIcon;
|
|
|
|
};
|
|
|
|
|
|
|
|
PixmapPainter::PixmapPainter()
|
|
|
|
{
|
2013-03-01 11:41:43 +00:00
|
|
|
pixmap1X = QPixmap(":/qticon32.png");
|
|
|
|
pixmap2X = QPixmap(":/qticon32@2x.png");
|
|
|
|
pixmapLarge = QPixmap(":/qticon64.png");
|
2012-11-20 10:34:52 +00:00
|
|
|
|
2013-03-01 11:41:43 +00:00
|
|
|
image1X = QImage(":/qticon32.png");
|
|
|
|
image2X = QImage(":/qticon32@2x.png");
|
|
|
|
imageLarge = QImage(":/qticon64.png");
|
2012-11-20 10:34:52 +00:00
|
|
|
|
2013-03-01 11:41:43 +00:00
|
|
|
qtIcon.addFile(":/qticon32.png");
|
|
|
|
qtIcon.addFile(":/qticon32@2x.png");
|
2012-11-20 10:34:52 +00:00
|
|
|
}
|
|
|
|
|
2014-07-18 12:22:14 +00:00
|
|
|
void PixmapPainter::paintEvent(QPaintEvent *)
|
2012-11-20 10:34:52 +00:00
|
|
|
{
|
|
|
|
QPainter p(this);
|
|
|
|
p.fillRect(QRect(QPoint(0, 0), size()), QBrush(Qt::gray));
|
|
|
|
|
2013-03-01 11:41:43 +00:00
|
|
|
int pixmapPointSize = 32;
|
2012-11-20 10:34:52 +00:00
|
|
|
int y = 30;
|
2013-03-01 11:41:43 +00:00
|
|
|
int dy = 90;
|
2012-11-20 10:34:52 +00:00
|
|
|
|
|
|
|
int x = 10;
|
2013-03-01 11:41:43 +00:00
|
|
|
int dx = 40;
|
2012-11-20 10:34:52 +00:00
|
|
|
// draw at point
|
|
|
|
// qDebug() << "paint pixmap" << pixmap1X.devicePixelRatio();
|
|
|
|
p.drawPixmap(x, y, pixmap1X);
|
|
|
|
x+=dx;p.drawPixmap(x, y, pixmap2X);
|
|
|
|
x+=dx;p.drawPixmap(x, y, pixmapLarge);
|
|
|
|
x+=dx*2;p.drawPixmap(x, y, qtIcon.pixmap(QSize(pixmapPointSize, pixmapPointSize)));
|
|
|
|
x+=dx;p.drawImage(x, y, image1X);
|
|
|
|
x+=dx;p.drawImage(x, y, image2X);
|
|
|
|
x+=dx;p.drawImage(x, y, imageLarge);
|
|
|
|
|
2013-03-01 11:41:43 +00:00
|
|
|
// draw at 32x32 rect
|
2012-11-20 10:34:52 +00:00
|
|
|
y+=dy;
|
|
|
|
x = 10;
|
|
|
|
p.drawPixmap(QRect(x, y, pixmapPointSize, pixmapPointSize), pixmap1X);
|
|
|
|
x+=dx;p.drawPixmap(QRect(x, y, pixmapPointSize, pixmapPointSize), pixmap2X);
|
|
|
|
x+=dx;p.drawPixmap(QRect(x, y, pixmapPointSize, pixmapPointSize), pixmapLarge);
|
|
|
|
x+=dx;p.drawPixmap(QRect(x, y, pixmapPointSize, pixmapPointSize), qtIcon.pixmap(QSize(pixmapPointSize, pixmapPointSize)));
|
|
|
|
x+=dx;p.drawImage(QRect(x, y, pixmapPointSize, pixmapPointSize), image1X);
|
|
|
|
x+=dx;p.drawImage(QRect(x, y, pixmapPointSize, pixmapPointSize), image2X);
|
|
|
|
x+=dx;p.drawImage(QRect(x, y, pixmapPointSize, pixmapPointSize), imageLarge);
|
|
|
|
|
|
|
|
|
2013-03-01 11:41:43 +00:00
|
|
|
// draw at 64x64 rect
|
2012-11-20 10:34:52 +00:00
|
|
|
y+=dy - 50;
|
|
|
|
x = 10;
|
|
|
|
p.drawPixmap(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), pixmap1X);
|
|
|
|
x+=dx * 2; p.drawPixmap(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), pixmap2X);
|
|
|
|
x+=dx * 2; p.drawPixmap(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), pixmapLarge);
|
|
|
|
x+=dx * 2; p.drawPixmap(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), qtIcon.pixmap(QSize(pixmapPointSize, pixmapPointSize)));
|
|
|
|
x+=dx * 2; p.drawImage(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), image1X);
|
|
|
|
x+=dx * 2; p.drawImage(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), image2X);
|
|
|
|
x+=dx * 2; p.drawImage(QRect(x, y, pixmapPointSize * 2, pixmapPointSize * 2), imageLarge);
|
|
|
|
}
|
|
|
|
|
High-dpi drawTiledPixmap (raster paint engine)
Implement more consistent behavior for drawTiledPixmap(),
which should produce the same visual tiling pattern
independent of display devicePixelRatio
Consider the following pixmaps and draw calls:
QPixmap px32; // 32x32
QPixmap px64; // 64x64
drawTiledPixmap(QRect(0, 0, 128, 128), px32);
drawTiledPixmap(QRect(0, 0, 128, 128), px64);
On 1x displays this will produce 4x4 and 2x2 tiles,
respectively.
On 2x displays this would previously produce a different
tiling pattern, where the paint engine would tile in
the device pixel coordinate system. Change this to
tile in the device independent coordinate system,
producing the same visual tiling pattern as the 1x case.
It is possible to produce a 4x4 tiling pattern with
high-resolution output from the 64x64 pixmap by setting
the devicePixelRatio:
QPixmap px64;
px64.setDevicePixelRatio(2);
drawTiledPixmap(QRect(0, 0, 128, 128), px64);
This change adds an inverse scale to the image filler
transform that accounts for the pixmap devicePixelRatio.
[ChangeLog][QtGui] QPainter::drawTiledPixmap() now
tiles in the device independent coordinate system.
Change-Id: I4918d274192967f222f181b374571c7c597dcd76
Reviewed-by: Jonathan Courtois <jonathan.courtois@gmail.com>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: 石博文 <sbw@sbw.so>
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
2015-02-24 10:13:31 +00:00
|
|
|
class TiledPixmapPainter : public QWidget
|
|
|
|
{
|
|
|
|
public:
|
2019-11-27 08:40:08 +00:00
|
|
|
TiledPixmapPainter();
|
|
|
|
|
|
|
|
void paintEvent(QPaintEvent *event) override;
|
|
|
|
|
|
|
|
private:
|
High-dpi drawTiledPixmap (raster paint engine)
Implement more consistent behavior for drawTiledPixmap(),
which should produce the same visual tiling pattern
independent of display devicePixelRatio
Consider the following pixmaps and draw calls:
QPixmap px32; // 32x32
QPixmap px64; // 64x64
drawTiledPixmap(QRect(0, 0, 128, 128), px32);
drawTiledPixmap(QRect(0, 0, 128, 128), px64);
On 1x displays this will produce 4x4 and 2x2 tiles,
respectively.
On 2x displays this would previously produce a different
tiling pattern, where the paint engine would tile in
the device pixel coordinate system. Change this to
tile in the device independent coordinate system,
producing the same visual tiling pattern as the 1x case.
It is possible to produce a 4x4 tiling pattern with
high-resolution output from the 64x64 pixmap by setting
the devicePixelRatio:
QPixmap px64;
px64.setDevicePixelRatio(2);
drawTiledPixmap(QRect(0, 0, 128, 128), px64);
This change adds an inverse scale to the image filler
transform that accounts for the pixmap devicePixelRatio.
[ChangeLog][QtGui] QPainter::drawTiledPixmap() now
tiles in the device independent coordinate system.
Change-Id: I4918d274192967f222f181b374571c7c597dcd76
Reviewed-by: Jonathan Courtois <jonathan.courtois@gmail.com>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: 石博文 <sbw@sbw.so>
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
2015-02-24 10:13:31 +00:00
|
|
|
QPixmap pixmap1X;
|
|
|
|
QPixmap pixmap2X;
|
|
|
|
QPixmap pixmapLarge;
|
|
|
|
};
|
|
|
|
|
|
|
|
TiledPixmapPainter::TiledPixmapPainter()
|
|
|
|
{
|
|
|
|
pixmap1X = QPixmap(":/qticon32.png");
|
|
|
|
pixmap2X = QPixmap(":/qticon32@2x.png");
|
|
|
|
pixmapLarge = QPixmap(":/qticon64.png");
|
|
|
|
}
|
|
|
|
|
|
|
|
void TiledPixmapPainter::paintEvent(QPaintEvent *event)
|
|
|
|
{
|
2018-06-24 07:58:50 +00:00
|
|
|
Q_UNUSED(event);
|
High-dpi drawTiledPixmap (raster paint engine)
Implement more consistent behavior for drawTiledPixmap(),
which should produce the same visual tiling pattern
independent of display devicePixelRatio
Consider the following pixmaps and draw calls:
QPixmap px32; // 32x32
QPixmap px64; // 64x64
drawTiledPixmap(QRect(0, 0, 128, 128), px32);
drawTiledPixmap(QRect(0, 0, 128, 128), px64);
On 1x displays this will produce 4x4 and 2x2 tiles,
respectively.
On 2x displays this would previously produce a different
tiling pattern, where the paint engine would tile in
the device pixel coordinate system. Change this to
tile in the device independent coordinate system,
producing the same visual tiling pattern as the 1x case.
It is possible to produce a 4x4 tiling pattern with
high-resolution output from the 64x64 pixmap by setting
the devicePixelRatio:
QPixmap px64;
px64.setDevicePixelRatio(2);
drawTiledPixmap(QRect(0, 0, 128, 128), px64);
This change adds an inverse scale to the image filler
transform that accounts for the pixmap devicePixelRatio.
[ChangeLog][QtGui] QPainter::drawTiledPixmap() now
tiles in the device independent coordinate system.
Change-Id: I4918d274192967f222f181b374571c7c597dcd76
Reviewed-by: Jonathan Courtois <jonathan.courtois@gmail.com>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: 石博文 <sbw@sbw.so>
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
2015-02-24 10:13:31 +00:00
|
|
|
QPainter p(this);
|
|
|
|
|
|
|
|
int xoff = 10;
|
|
|
|
int yoff = 10;
|
|
|
|
int tiles = 4;
|
|
|
|
int pixmapEdge = 32;
|
|
|
|
int tileAreaEdge = pixmapEdge * tiles;
|
|
|
|
|
|
|
|
// Expected behavior for both 1x and 2x dislays:
|
|
|
|
// 1x pixmap : 4 x 4 tiles
|
|
|
|
// large pixmap: 2 x 2 tiles
|
|
|
|
// 2x pixmap : 4 x 4 tiles
|
|
|
|
//
|
2019-09-23 07:26:51 +00:00
|
|
|
// On a 2x display the 2x pixmap tiles
|
High-dpi drawTiledPixmap (raster paint engine)
Implement more consistent behavior for drawTiledPixmap(),
which should produce the same visual tiling pattern
independent of display devicePixelRatio
Consider the following pixmaps and draw calls:
QPixmap px32; // 32x32
QPixmap px64; // 64x64
drawTiledPixmap(QRect(0, 0, 128, 128), px32);
drawTiledPixmap(QRect(0, 0, 128, 128), px64);
On 1x displays this will produce 4x4 and 2x2 tiles,
respectively.
On 2x displays this would previously produce a different
tiling pattern, where the paint engine would tile in
the device pixel coordinate system. Change this to
tile in the device independent coordinate system,
producing the same visual tiling pattern as the 1x case.
It is possible to produce a 4x4 tiling pattern with
high-resolution output from the 64x64 pixmap by setting
the devicePixelRatio:
QPixmap px64;
px64.setDevicePixelRatio(2);
drawTiledPixmap(QRect(0, 0, 128, 128), px64);
This change adds an inverse scale to the image filler
transform that accounts for the pixmap devicePixelRatio.
[ChangeLog][QtGui] QPainter::drawTiledPixmap() now
tiles in the device independent coordinate system.
Change-Id: I4918d274192967f222f181b374571c7c597dcd76
Reviewed-by: Jonathan Courtois <jonathan.courtois@gmail.com>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: 石博文 <sbw@sbw.so>
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
2015-02-24 10:13:31 +00:00
|
|
|
// will be drawn in high resolution.
|
|
|
|
p.drawTiledPixmap(QRect(xoff, yoff, tileAreaEdge, tileAreaEdge), pixmap1X);
|
|
|
|
yoff += tiles * pixmapEdge + 10;
|
|
|
|
p.drawTiledPixmap(QRect(xoff, yoff, tileAreaEdge, tileAreaEdge), pixmapLarge);
|
|
|
|
yoff += tiles * pixmapEdge + 10;
|
|
|
|
p.drawTiledPixmap(QRect(xoff, yoff, tileAreaEdge, tileAreaEdge), pixmap2X);
|
|
|
|
|
|
|
|
// Again, with an offset. The offset is in
|
|
|
|
// device-independent pixels.
|
|
|
|
QPoint offset(40, 40); // larger than the pixmap edge size to exercise that code path
|
|
|
|
yoff = 10;
|
|
|
|
xoff = 20 + tiles * pixmapEdge ;
|
|
|
|
p.drawTiledPixmap(QRect(xoff, yoff, tileAreaEdge, tileAreaEdge), pixmap1X, offset);
|
|
|
|
yoff += tiles * pixmapEdge + 10;
|
|
|
|
p.drawTiledPixmap(QRect(xoff, yoff, tileAreaEdge, tileAreaEdge), pixmapLarge, offset);
|
|
|
|
yoff += tiles * pixmapEdge + 10;
|
|
|
|
p.drawTiledPixmap(QRect(xoff, yoff, tileAreaEdge, tileAreaEdge), pixmap2X, offset);
|
|
|
|
}
|
|
|
|
|
2012-11-20 10:34:52 +00:00
|
|
|
class Labels : public QWidget
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Labels();
|
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
private:
|
2012-11-20 10:34:52 +00:00
|
|
|
QPixmap pixmap1X;
|
|
|
|
QPixmap pixmap2X;
|
|
|
|
QPixmap pixmapLarge;
|
|
|
|
QIcon qtIcon;
|
|
|
|
};
|
|
|
|
|
|
|
|
Labels::Labels()
|
|
|
|
{
|
2013-03-01 11:41:43 +00:00
|
|
|
pixmap1X = QPixmap(":/qticon32.png");
|
|
|
|
pixmap2X = QPixmap(":/qticon32@2x.png");
|
|
|
|
pixmapLarge = QPixmap(":/qticon64.png");
|
2012-11-20 10:34:52 +00:00
|
|
|
|
2013-03-01 11:41:43 +00:00
|
|
|
qtIcon.addFile(":/qticon32.png");
|
|
|
|
qtIcon.addFile(":/qticon32@2x.png");
|
2012-11-20 10:34:52 +00:00
|
|
|
setWindowIcon(qtIcon);
|
2019-11-27 08:59:33 +00:00
|
|
|
setWindowTitle(formatWindowTitle("Labels"));
|
2012-11-20 10:34:52 +00:00
|
|
|
|
|
|
|
QLabel *label1x = new QLabel();
|
|
|
|
label1x->setPixmap(pixmap1X);
|
|
|
|
QLabel *label2x = new QLabel();
|
|
|
|
label2x->setPixmap(pixmap2X);
|
|
|
|
QLabel *labelIcon = new QLabel();
|
2013-03-01 11:41:43 +00:00
|
|
|
labelIcon->setPixmap(qtIcon.pixmap(QSize(32,32)));
|
2012-11-20 10:34:52 +00:00
|
|
|
QLabel *labelLarge = new QLabel();
|
|
|
|
labelLarge->setPixmap(pixmapLarge);
|
|
|
|
|
|
|
|
QHBoxLayout *layout = new QHBoxLayout(this);
|
2013-03-01 11:41:43 +00:00
|
|
|
layout->addWidget(label1x); //expected low-res on high-dpi displays
|
|
|
|
layout->addWidget(label2x); //expected high-res on high-dpi displays
|
|
|
|
layout->addWidget(labelIcon); //expected high-res on high-dpi displays
|
|
|
|
layout->addWidget(labelLarge); // expected large size and low-res
|
2012-11-20 10:34:52 +00:00
|
|
|
setLayout(layout);
|
|
|
|
}
|
|
|
|
|
|
|
|
class MainWindow : public QMainWindow
|
|
|
|
{
|
2016-02-09 12:40:42 +00:00
|
|
|
Q_OBJECT
|
2012-11-20 10:34:52 +00:00
|
|
|
public:
|
|
|
|
MainWindow();
|
2015-06-18 15:00:27 +00:00
|
|
|
QMenu *addNewMenu(const QString &title, int itemCount = 5);
|
2012-11-20 10:34:52 +00:00
|
|
|
|
2016-02-09 12:40:42 +00:00
|
|
|
private slots:
|
|
|
|
void maskActionToggled(bool t);
|
|
|
|
|
|
|
|
private:
|
2012-11-20 10:34:52 +00:00
|
|
|
QIcon qtIcon;
|
|
|
|
QIcon qtIcon1x;
|
|
|
|
QIcon qtIcon2x;
|
|
|
|
|
|
|
|
QToolBar *fileToolBar;
|
2016-02-09 12:40:42 +00:00
|
|
|
QAction *m_maskAction;
|
2019-11-27 08:40:08 +00:00
|
|
|
int menuCount = 0;
|
2012-11-20 10:34:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
MainWindow::MainWindow()
|
|
|
|
{
|
2013-03-01 11:41:43 +00:00
|
|
|
// beware that QIcon auto-loads the @2x versions.
|
|
|
|
qtIcon1x.addFile(":/qticon16.png");
|
|
|
|
qtIcon2x.addFile(":/qticon32.png");
|
2012-11-20 10:34:52 +00:00
|
|
|
setWindowIcon(qtIcon);
|
2019-11-27 08:59:33 +00:00
|
|
|
setWindowTitle(formatWindowTitle("MainWindow"));
|
2012-11-20 10:34:52 +00:00
|
|
|
|
|
|
|
fileToolBar = addToolBar(tr("File"));
|
|
|
|
// fileToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
|
|
|
|
fileToolBar->addAction(new QAction(qtIcon1x, QString("1x"), this));
|
|
|
|
fileToolBar->addAction(new QAction(qtIcon2x, QString("2x"), this));
|
2015-06-18 15:00:27 +00:00
|
|
|
addNewMenu("&Edit");
|
|
|
|
addNewMenu("&Build");
|
|
|
|
addNewMenu("&Debug", 4);
|
2016-02-09 12:40:42 +00:00
|
|
|
QMenu *menu = addNewMenu("&Transmogrify", 7);
|
|
|
|
menu->addSeparator();
|
|
|
|
m_maskAction = menu->addAction("Mask");
|
|
|
|
m_maskAction->setCheckable(true);
|
|
|
|
connect(m_maskAction, &QAction::toggled, this, &MainWindow::maskActionToggled);
|
|
|
|
fileToolBar->addAction(m_maskAction);
|
2015-06-18 15:00:27 +00:00
|
|
|
addNewMenu("T&ools");
|
|
|
|
addNewMenu("&Help", 2);
|
2012-11-20 10:34:52 +00:00
|
|
|
}
|
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
QMenu *MainWindow::addNewMenu(const QString &title, int itemCount)
|
|
|
|
{
|
|
|
|
QMenu *menu = menuBar()->addMenu(title);
|
|
|
|
for (int i = 0; i < itemCount; i++) {
|
|
|
|
menuCount++;
|
|
|
|
QString s = "Menu item " + QString::number(menuCount);
|
|
|
|
if (i == 3) {
|
|
|
|
QMenu *subMenu = menu->addMenu(s);
|
|
|
|
for (int j = 1; j < 4; j++)
|
|
|
|
subMenu->addAction(QString::fromLatin1("SubMenu item %1.%2").arg(menuCount).arg(j));
|
|
|
|
} else {
|
|
|
|
menu->addAction(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return menu;
|
|
|
|
}
|
|
|
|
|
2016-02-09 12:40:42 +00:00
|
|
|
void MainWindow::maskActionToggled(bool t)
|
|
|
|
{
|
|
|
|
if (t) {
|
|
|
|
QVector<QPoint> upperLeftTriangle;
|
|
|
|
upperLeftTriangle << QPoint(0, 0) << QPoint(width(), 0) << QPoint(0, height());
|
|
|
|
setMask(QRegion(QPolygon(upperLeftTriangle)));
|
|
|
|
} else {
|
|
|
|
clearMask();
|
|
|
|
}
|
|
|
|
}
|
2015-06-18 15:00:27 +00:00
|
|
|
|
2012-11-20 10:34:52 +00:00
|
|
|
class StandardIcons : public QWidget
|
|
|
|
{
|
|
|
|
public:
|
2019-11-27 08:40:08 +00:00
|
|
|
void paintEvent(QPaintEvent *) override
|
2012-11-20 10:34:52 +00:00
|
|
|
{
|
|
|
|
int x = 10;
|
|
|
|
int y = 10;
|
|
|
|
int dx = 50;
|
|
|
|
int dy = 50;
|
|
|
|
int maxX = 500;
|
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
for (uint iconIndex = QStyle::SP_TitleBarMenuButton; iconIndex < QStyle::SP_MediaVolumeMuted; ++iconIndex) {
|
2012-11-20 10:34:52 +00:00
|
|
|
QIcon icon = qApp->style()->standardIcon(QStyle::StandardPixmap(iconIndex));
|
|
|
|
QPainter p(this);
|
|
|
|
p.drawPixmap(x, y, icon.pixmap(dx - 5, dy - 5));
|
|
|
|
if (x + dx > maxX)
|
|
|
|
y+=dy;
|
|
|
|
x = ((x + dx) % maxX);
|
|
|
|
}
|
2014-07-18 12:22:14 +00:00
|
|
|
}
|
2012-11-20 10:34:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class Caching : public QWidget
|
|
|
|
{
|
|
|
|
public:
|
2019-11-27 08:40:08 +00:00
|
|
|
void paintEvent(QPaintEvent *) override
|
2012-11-20 10:34:52 +00:00
|
|
|
{
|
|
|
|
QSize layoutSize(75, 75);
|
|
|
|
|
|
|
|
QPainter widgetPainter(this);
|
|
|
|
widgetPainter.fillRect(QRect(QPoint(0, 0), this->size()), Qt::gray);
|
|
|
|
|
|
|
|
{
|
|
|
|
const qreal devicePixelRatio = this->windowHandle()->devicePixelRatio();
|
|
|
|
QPixmap cache(layoutSize * devicePixelRatio);
|
|
|
|
cache.setDevicePixelRatio(devicePixelRatio);
|
|
|
|
|
|
|
|
QPainter cachedPainter(&cache);
|
|
|
|
cachedPainter.fillRect(QRect(0,0, 75, 75), Qt::blue);
|
|
|
|
cachedPainter.fillRect(QRect(10,10, 55, 55), Qt::red);
|
|
|
|
cachedPainter.drawEllipse(QRect(10,10, 55, 55));
|
|
|
|
|
|
|
|
QPainter widgetPainter(this);
|
|
|
|
widgetPainter.drawPixmap(QPoint(10, 10), cache);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
const qreal devicePixelRatio = this->windowHandle()->devicePixelRatio();
|
2014-07-18 12:22:14 +00:00
|
|
|
QImage cache = QImage(layoutSize * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
|
2012-11-20 10:34:52 +00:00
|
|
|
cache.setDevicePixelRatio(devicePixelRatio);
|
|
|
|
|
|
|
|
QPainter cachedPainter(&cache);
|
|
|
|
cachedPainter.fillRect(QRect(0,0, 75, 75), Qt::blue);
|
|
|
|
cachedPainter.fillRect(QRect(10,10, 55, 55), Qt::red);
|
|
|
|
cachedPainter.drawEllipse(QRect(10,10, 55, 55));
|
|
|
|
|
|
|
|
QPainter widgetPainter(this);
|
|
|
|
widgetPainter.drawImage(QPoint(95, 10), cache);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
class Style : public QWidget
|
|
|
|
{
|
2012-11-20 10:34:52 +00:00
|
|
|
public:
|
2019-11-27 08:40:08 +00:00
|
|
|
Style()
|
|
|
|
{
|
|
|
|
row1 = new QHBoxLayout(this);
|
2012-11-20 10:34:52 +00:00
|
|
|
|
|
|
|
button = new QPushButton();
|
|
|
|
button->setText("Test Button");
|
|
|
|
row1->addWidget(button);
|
|
|
|
|
|
|
|
lineEdit = new QLineEdit();
|
|
|
|
lineEdit->setText("Test Lineedit");
|
|
|
|
row1->addWidget(lineEdit);
|
|
|
|
|
|
|
|
slider = new QSlider();
|
|
|
|
row1->addWidget(slider);
|
|
|
|
|
|
|
|
row1->addWidget(new QSpinBox);
|
|
|
|
row1->addWidget(new QScrollBar);
|
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
auto tab = new QTabBar();
|
2012-11-20 10:34:52 +00:00
|
|
|
tab->addTab("Foo");
|
|
|
|
tab->addTab("Bar");
|
|
|
|
row1->addWidget(tab);
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
QPushButton *button;
|
|
|
|
QLineEdit *lineEdit;
|
|
|
|
QSlider *slider;
|
|
|
|
QHBoxLayout *row1;
|
2012-11-20 10:34:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class Fonts : public QWidget
|
|
|
|
{
|
|
|
|
public:
|
2019-11-27 08:40:08 +00:00
|
|
|
void paintEvent(QPaintEvent *) override
|
2012-11-20 10:34:52 +00:00
|
|
|
{
|
|
|
|
QPainter painter(this);
|
2015-06-18 15:00:27 +00:00
|
|
|
|
|
|
|
// Points
|
|
|
|
int y = 10;
|
|
|
|
for (int fontSize = 6; fontSize < 18; fontSize += 2) {
|
2012-11-20 10:34:52 +00:00
|
|
|
QFont font;
|
|
|
|
font.setPointSize(fontSize);
|
2015-06-18 15:00:27 +00:00
|
|
|
QString string = QString(QStringLiteral("This text is in point size %1")).arg(fontSize);
|
|
|
|
painter.setFont(font);
|
|
|
|
y += (painter.fontMetrics().lineSpacing());
|
|
|
|
painter.drawText(10, y, string);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pixels
|
|
|
|
y += painter.fontMetrics().lineSpacing();
|
|
|
|
for (int fontSize = 6; fontSize < 18; fontSize += 2) {
|
|
|
|
QFont font;
|
|
|
|
font.setPixelSize(fontSize);
|
|
|
|
QString string = QString(QStringLiteral("This text is in pixel size %1")).arg(fontSize);
|
2012-11-20 10:34:52 +00:00
|
|
|
painter.setFont(font);
|
2015-06-18 15:00:27 +00:00
|
|
|
y += (painter.fontMetrics().lineSpacing());
|
2012-11-20 10:34:52 +00:00
|
|
|
painter.drawText(10, y, string);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void apiTestdevicePixelRatioGetter()
|
|
|
|
{
|
|
|
|
if (0) {
|
2018-06-24 07:58:50 +00:00
|
|
|
T *t = nullptr;
|
2012-11-20 10:34:52 +00:00
|
|
|
t->devicePixelRatio();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void apiTestdevicePixelRatioSetter()
|
|
|
|
{
|
|
|
|
if (0) {
|
2018-06-24 07:58:50 +00:00
|
|
|
T *t = nullptr;
|
2012-11-20 10:34:52 +00:00
|
|
|
t->setDevicePixelRatio(2.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void apiTest()
|
|
|
|
{
|
|
|
|
// compile call to devicePixelRatio getter and setter (verify spelling)
|
|
|
|
apiTestdevicePixelRatioGetter<QWindow>();
|
|
|
|
apiTestdevicePixelRatioGetter<QScreen>();
|
|
|
|
apiTestdevicePixelRatioGetter<QGuiApplication>();
|
|
|
|
|
|
|
|
apiTestdevicePixelRatioGetter<QImage>();
|
|
|
|
apiTestdevicePixelRatioSetter<QImage>();
|
|
|
|
apiTestdevicePixelRatioGetter<QPixmap>();
|
|
|
|
apiTestdevicePixelRatioSetter<QPixmap>();
|
|
|
|
}
|
|
|
|
|
2013-03-01 11:41:43 +00:00
|
|
|
// Request and draw an icon at different sizes
|
|
|
|
class IconDrawing : public QWidget
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
IconDrawing()
|
|
|
|
{
|
2014-07-18 12:22:14 +00:00
|
|
|
const QString tempPath = m_temporaryDir.path();
|
|
|
|
const QString path32 = tempPath + "/qticon32.png";
|
|
|
|
const QString path32_2 = tempPath + "/qticon32-2.png";
|
|
|
|
const QString path32_2x = tempPath + "/qticon32@2x.png";
|
2013-03-01 11:41:43 +00:00
|
|
|
|
2014-07-18 12:22:14 +00:00
|
|
|
QFile::copy(":/qticon32.png", path32_2);
|
|
|
|
QFile::copy(":/qticon32.png", path32);
|
|
|
|
QFile::copy(":/qticon32@2x.png", path32_2x);
|
2013-03-01 11:41:43 +00:00
|
|
|
|
2014-07-18 12:22:14 +00:00
|
|
|
iconHighDPI.reset(new QIcon(path32)); // will auto-load @2x version.
|
|
|
|
iconNormalDpi.reset(new QIcon(path32_2)); // does not have a 2x version.
|
2013-03-01 11:41:43 +00:00
|
|
|
}
|
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
void paintEvent(QPaintEvent *) override
|
2013-03-01 11:41:43 +00:00
|
|
|
{
|
|
|
|
int x = 10;
|
|
|
|
int y = 10;
|
|
|
|
int dx = 50;
|
|
|
|
int dy = 50;
|
|
|
|
int maxX = 600;
|
|
|
|
int minSize = 5;
|
|
|
|
int maxSize = 64;
|
|
|
|
int sizeIncrement = 5;
|
|
|
|
|
|
|
|
// Disable high-dpi icons
|
2014-07-18 12:22:14 +00:00
|
|
|
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, false);
|
2013-03-01 11:41:43 +00:00
|
|
|
|
|
|
|
// normal icon
|
|
|
|
for (int size = minSize; size < maxSize; size += sizeIncrement) {
|
|
|
|
QPainter p(this);
|
|
|
|
p.drawPixmap(x, y, iconNormalDpi->pixmap(size, size));
|
|
|
|
if (x + dx > maxX)
|
|
|
|
y+=dy;
|
|
|
|
x = ((x + dx) % maxX);
|
|
|
|
}
|
|
|
|
x = 10;
|
|
|
|
y+=dy;
|
|
|
|
|
|
|
|
// high-dpi icon
|
|
|
|
for (int size = minSize; size < maxSize; size += sizeIncrement) {
|
|
|
|
QPainter p(this);
|
|
|
|
p.drawPixmap(x, y, iconHighDPI->pixmap(size, size));
|
|
|
|
if (x + dx > maxX)
|
|
|
|
y+=dy;
|
|
|
|
x = ((x + dx) % maxX);
|
|
|
|
}
|
|
|
|
|
|
|
|
x = 10;
|
|
|
|
y+=dy;
|
|
|
|
|
|
|
|
// Enable high-dpi icons
|
2014-07-18 12:22:14 +00:00
|
|
|
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
|
2013-03-01 11:41:43 +00:00
|
|
|
|
|
|
|
// normal icon
|
|
|
|
for (int size = minSize; size < maxSize; size += sizeIncrement) {
|
|
|
|
QPainter p(this);
|
|
|
|
p.drawPixmap(x, y, iconNormalDpi->pixmap(size, size));
|
|
|
|
if (x + dx > maxX)
|
|
|
|
y+=dy;
|
|
|
|
x = ((x + dx) % maxX);
|
|
|
|
}
|
|
|
|
x = 10;
|
|
|
|
y+=dy;
|
|
|
|
|
|
|
|
// high-dpi icon (draw point)
|
|
|
|
for (int size = minSize; size < maxSize; size += sizeIncrement) {
|
|
|
|
QPainter p(this);
|
|
|
|
p.drawPixmap(x, y, iconHighDPI->pixmap(size, size));
|
|
|
|
if (x + dx > maxX)
|
|
|
|
y+=dy;
|
|
|
|
x = ((x + dx) % maxX);
|
|
|
|
}
|
|
|
|
|
|
|
|
x = 10;
|
|
|
|
y+=dy;
|
|
|
|
|
2014-07-18 12:22:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
QTemporaryDir m_temporaryDir;
|
|
|
|
QScopedPointer<QIcon> iconHighDPI;
|
|
|
|
QScopedPointer<QIcon> iconNormalDpi;
|
2013-03-01 11:41:43 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Icons on buttons
|
|
|
|
class Buttons : public QWidget
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Buttons()
|
|
|
|
{
|
|
|
|
QIcon icon;
|
|
|
|
icon.addFile(":/qticon16@2x.png");
|
|
|
|
|
|
|
|
QPushButton *button = new QPushButton(this);
|
|
|
|
button->setIcon(icon);
|
|
|
|
button->setText("16@2x");
|
|
|
|
|
|
|
|
QTabBar *tab = new QTabBar(this);
|
|
|
|
tab->addTab(QIcon(":/qticon16.png"), "16@1x");
|
|
|
|
tab->addTab(QIcon(":/qticon16@2x.png"), "16@2x");
|
|
|
|
tab->addTab(QIcon(":/qticon16.png"), "");
|
|
|
|
tab->addTab(QIcon(":/qticon16@2x.png"), "");
|
|
|
|
tab->move(10, 100);
|
|
|
|
tab->show();
|
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
auto toolBar = new QToolBar(this);
|
2013-03-01 11:41:43 +00:00
|
|
|
toolBar->addAction(QIcon(":/qticon16.png"), "16");
|
|
|
|
toolBar->addAction(QIcon(":/qticon16@2x.png"), "16@2x");
|
|
|
|
toolBar->addAction(QIcon(":/qticon32.png"), "32");
|
|
|
|
toolBar->addAction(QIcon(":/qticon32@2x.png"), "32@2x");
|
|
|
|
|
|
|
|
toolBar->move(10, 200);
|
|
|
|
toolBar->show();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
class LinePainter : public QWidget
|
|
|
|
{
|
|
|
|
public:
|
2019-11-27 08:40:08 +00:00
|
|
|
void paintEvent(QPaintEvent *event) override;
|
|
|
|
void mousePressEvent(QMouseEvent *event) override;
|
|
|
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
|
|
|
void mouseMoveEvent(QMouseEvent *event) override;
|
2015-06-18 15:00:27 +00:00
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
private:
|
2015-06-18 15:00:27 +00:00
|
|
|
QPoint lastMousePoint;
|
|
|
|
QVector<QPoint> linePoints;
|
|
|
|
};
|
2013-03-01 11:41:43 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
void LinePainter::paintEvent(QPaintEvent *)
|
2012-11-20 10:34:52 +00:00
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
QPainter p(this);
|
|
|
|
p.fillRect(QRect(QPoint(0, 0), size()), QBrush(Qt::gray));
|
2014-07-18 12:22:14 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
// Default antialiased line
|
|
|
|
p.setRenderHint(QPainter::Antialiasing);
|
|
|
|
p.drawLines(linePoints);
|
|
|
|
|
|
|
|
// Cosmetic 1 antialiased line
|
|
|
|
QPen pen;
|
|
|
|
pen.setCosmetic(true);
|
|
|
|
pen.setWidth(1);
|
|
|
|
p.setPen(pen);
|
|
|
|
p.translate(3, 3);
|
|
|
|
p.drawLines(linePoints);
|
|
|
|
|
|
|
|
// Aliased cosmetic 1 line
|
|
|
|
p.setRenderHint(QPainter::Antialiasing, false);
|
|
|
|
p.translate(3, 3);
|
|
|
|
p.drawLines(linePoints);
|
|
|
|
}
|
2014-07-18 12:22:14 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
void LinePainter::mousePressEvent(QMouseEvent *event)
|
|
|
|
{
|
|
|
|
lastMousePoint = event->pos();
|
|
|
|
}
|
2014-07-18 12:22:14 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
void LinePainter::mouseReleaseEvent(QMouseEvent *)
|
|
|
|
{
|
|
|
|
lastMousePoint = QPoint();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LinePainter::mouseMoveEvent(QMouseEvent *event)
|
|
|
|
{
|
|
|
|
if (lastMousePoint.isNull())
|
|
|
|
return;
|
|
|
|
|
|
|
|
QPoint newMousePoint = event->pos();
|
|
|
|
if (lastMousePoint == newMousePoint)
|
|
|
|
return;
|
|
|
|
linePoints.append(lastMousePoint);
|
|
|
|
linePoints.append(newMousePoint);
|
|
|
|
lastMousePoint = newMousePoint;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
class CursorTester : public QWidget
|
|
|
|
{
|
|
|
|
public:
|
2019-11-27 08:40:08 +00:00
|
|
|
CursorTester() = default;
|
2012-11-20 10:34:52 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
inline QRect getRect(int idx) const
|
|
|
|
{
|
|
|
|
int h = height() / 2;
|
|
|
|
return QRect(10, 10 + h * (idx - 1), width() - 20, h - 20);
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
|
|
|
void paintEvent(QPaintEvent *) override
|
2015-06-18 15:00:27 +00:00
|
|
|
{
|
|
|
|
QPainter p(this);
|
|
|
|
QRect r1 = getRect(1);
|
|
|
|
QRect r2 = getRect(2);
|
|
|
|
p.fillRect(r1, QColor(200, 200, 250));
|
|
|
|
p.drawText(r1, "Drag from here to move a window based on QCursor::pos()");
|
|
|
|
p.fillRect(r2, QColor(250, 200, 200));
|
|
|
|
p.drawText(r2, "Drag from here to move a window based on mouse event position");
|
|
|
|
|
|
|
|
if (moving) {
|
|
|
|
p.setPen(Qt::darkGray);
|
|
|
|
QFont f = font();
|
|
|
|
f.setPointSize(8);
|
|
|
|
p.setFont(f);
|
|
|
|
p.drawEllipse(mousePos, 30,60);
|
|
|
|
QPoint pt = mousePos - QPoint(0, 60);
|
|
|
|
QPoint pt2 = pt - QPoint(30,10);
|
|
|
|
QPoint offs(30, 0);
|
|
|
|
p.drawLine(pt, pt2);
|
|
|
|
p.drawLine(pt2 - offs, pt2 + offs);
|
|
|
|
p.drawText(pt2 - offs, "mouse pos");
|
|
|
|
|
|
|
|
p.setPen(QColor(50,130,70));
|
|
|
|
QPoint cursorPos = mapFromGlobal(QCursor::pos());
|
|
|
|
pt = cursorPos - QPoint(0, 30);
|
|
|
|
pt2 = pt + QPoint(60, -20);
|
|
|
|
p.drawEllipse(cursorPos, 60, 30);
|
|
|
|
p.drawLine(pt, pt2);
|
|
|
|
p.drawLine(pt2 - offs, pt2 + offs);
|
|
|
|
p.drawText(pt2 - offs, "cursor pos");
|
|
|
|
}
|
2014-07-18 12:22:14 +00:00
|
|
|
}
|
2012-11-20 10:34:52 +00:00
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
void mousePressEvent(QMouseEvent *e) override
|
2015-06-18 15:00:27 +00:00
|
|
|
{
|
|
|
|
if (moving)
|
|
|
|
return;
|
|
|
|
QRect r1 = getRect(1);
|
|
|
|
QRect r2 = getRect(2);
|
|
|
|
|
|
|
|
moving = r1.contains(e->pos()) || r2.contains(e->pos());
|
|
|
|
if (!moving)
|
|
|
|
return;
|
|
|
|
useCursorPos = r1.contains(e->pos());
|
|
|
|
|
|
|
|
if (!moveLabel)
|
|
|
|
moveLabel = new QLabel(this,Qt::BypassWindowManagerHint|Qt::FramelessWindowHint|Qt::Window );
|
|
|
|
|
|
|
|
if (useCursorPos)
|
|
|
|
moveLabel->setText("I'm following QCursor::pos()");
|
|
|
|
else
|
|
|
|
moveLabel->setText("I'm following QMouseEvent::globalPos()");
|
|
|
|
moveLabel->adjustSize();
|
|
|
|
mouseMoveEvent(e);
|
|
|
|
moveLabel->show();
|
2014-07-18 12:22:14 +00:00
|
|
|
}
|
2012-11-20 10:34:52 +00:00
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
void mouseReleaseEvent(QMouseEvent *) override
|
2015-06-18 15:00:27 +00:00
|
|
|
{
|
|
|
|
if (moveLabel)
|
|
|
|
moveLabel->hide();
|
|
|
|
update();
|
|
|
|
moving = false;
|
2014-07-18 12:22:14 +00:00
|
|
|
}
|
2012-11-20 10:34:52 +00:00
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
void mouseMoveEvent(QMouseEvent *e) override
|
2015-06-18 15:00:27 +00:00
|
|
|
{
|
|
|
|
if (!moving)
|
|
|
|
return;
|
|
|
|
QPoint pos = useCursorPos ? QCursor::pos() : e->globalPos();
|
|
|
|
pos -= moveLabel->rect().center();
|
|
|
|
moveLabel->move(pos);
|
|
|
|
mousePos = e->pos();
|
|
|
|
update();
|
2014-07-18 12:22:14 +00:00
|
|
|
}
|
2012-11-20 10:34:52 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
private:
|
2019-11-27 08:40:08 +00:00
|
|
|
QLabel *moveLabel = nullptr;
|
2015-06-18 15:00:27 +00:00
|
|
|
QPoint mousePos;
|
2019-11-27 08:40:08 +00:00
|
|
|
bool useCursorPos = false;
|
|
|
|
bool moving = false;
|
2015-06-18 15:00:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class ScreenDisplayer : public QWidget
|
|
|
|
{
|
|
|
|
public:
|
2019-11-27 08:40:08 +00:00
|
|
|
ScreenDisplayer() = default;
|
2012-11-20 10:34:52 +00:00
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
void timerEvent(QTimerEvent *) override
|
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
update();
|
2014-07-18 12:22:14 +00:00
|
|
|
}
|
2013-03-01 11:41:43 +00:00
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
void mousePressEvent(QMouseEvent *) override
|
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
if (!moveLabel)
|
|
|
|
moveLabel = new QLabel(this,Qt::BypassWindowManagerHint|Qt::FramelessWindowHint|Qt::Window );
|
|
|
|
moveLabel->setText("Hello, Qt this is a label\nwith some text");
|
|
|
|
moveLabel->show();
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
|
|
|
void mouseMoveEvent(QMouseEvent *e) override
|
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
if (!moveLabel)
|
|
|
|
return;
|
|
|
|
moveLabel->move(e->pos() / scaleFactor);
|
|
|
|
QString str;
|
|
|
|
QDebug dbg(&str);
|
|
|
|
dbg.setAutoInsertSpaces(false);
|
|
|
|
dbg << moveLabel->geometry();
|
|
|
|
moveLabel->setText(str);
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
|
|
|
void mouseReleaseEvent(QMouseEvent *) override
|
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
if (moveLabel)
|
|
|
|
moveLabel->hide();
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
|
|
|
void showEvent(QShowEvent *) override
|
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
refreshTimer.start(300, this);
|
2014-07-18 12:22:14 +00:00
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
|
|
|
void hideEvent(QHideEvent *) override
|
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
refreshTimer.stop();
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
|
|
|
void paintEvent(QPaintEvent *) override
|
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
QPainter p(this);
|
|
|
|
QRectF total;
|
2019-11-27 08:40:08 +00:00
|
|
|
const auto screens = QGuiApplication::screens();
|
|
|
|
for (const QScreen *screen : screens)
|
2015-06-18 15:00:27 +00:00
|
|
|
total |= screen->geometry();
|
|
|
|
if (total.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
scaleFactor = qMin(width()/total.width(), height()/total.height());
|
|
|
|
|
|
|
|
p.fillRect(rect(), Qt::black);
|
|
|
|
p.scale(scaleFactor, scaleFactor);
|
|
|
|
p.translate(-total.topLeft());
|
|
|
|
p.setPen(QPen(Qt::white, 10));
|
|
|
|
p.setBrush(Qt::gray);
|
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
for (const QScreen *screen : screens) {
|
2015-06-18 15:00:27 +00:00
|
|
|
p.drawRect(screen->geometry());
|
|
|
|
QFont f = font();
|
|
|
|
f.setPixelSize(screen->geometry().height() / 8);
|
|
|
|
p.setFont(f);
|
|
|
|
p.drawText(screen->geometry(), Qt::AlignCenter, screen->name());
|
|
|
|
}
|
|
|
|
p.setBrush(QColor(200,220,255,127));
|
2019-11-27 08:40:08 +00:00
|
|
|
|
|
|
|
const auto topLevels = QApplication::topLevelWidgets();
|
|
|
|
for (QWidget *widget : topLevels) {
|
2015-06-18 15:00:27 +00:00
|
|
|
if (!widget->isHidden())
|
|
|
|
p.drawRect(widget->geometry());
|
|
|
|
}
|
|
|
|
|
|
|
|
QPolygon cursorShape;
|
|
|
|
cursorShape << QPoint(0,0) << QPoint(20, 60)
|
|
|
|
<< QPoint(30, 50) << QPoint(60, 80)
|
|
|
|
<< QPoint(80, 60) << QPoint(50, 30)
|
|
|
|
<< QPoint(60, 20);
|
|
|
|
cursorShape.translate(QCursor::pos());
|
|
|
|
p.drawPolygon(cursorShape);
|
2014-07-18 12:22:14 +00:00
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
private:
|
2019-11-27 08:40:08 +00:00
|
|
|
QLabel *moveLabel = nullptr;
|
|
|
|
qreal scaleFactor = 1;
|
2015-06-18 15:00:27 +00:00
|
|
|
QBasicTimer refreshTimer;
|
|
|
|
};
|
|
|
|
|
|
|
|
class PhysicalSizeTest : public QWidget
|
|
|
|
{
|
2019-11-27 08:40:08 +00:00
|
|
|
Q_OBJECT
|
2015-06-18 15:00:27 +00:00
|
|
|
public:
|
2019-11-27 08:40:08 +00:00
|
|
|
PhysicalSizeTest() = default;
|
|
|
|
|
|
|
|
void paintEvent(QPaintEvent *event) override;
|
|
|
|
|
|
|
|
void resizeEvent(QResizeEvent *) override
|
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
qreal ppi = window()->windowHandle()->screen()->physicalDotsPerInchX();
|
|
|
|
QSizeF s = size();
|
|
|
|
if (!m_ignoreResize)
|
|
|
|
m_physicalSize = s / ppi;
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
|
|
|
bool event(QEvent *event) override
|
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
if (event->type() == QEvent::ScreenChangeInternal) {
|
|
|
|
// we will get resize events when the scale factor changes
|
|
|
|
m_ignoreResize = true;
|
2019-11-27 08:40:08 +00:00
|
|
|
QTimer::singleShot(100, this, &PhysicalSizeTest::handleScreenChange);
|
2015-06-18 15:00:27 +00:00
|
|
|
}
|
|
|
|
return QWidget::event(event);
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
public slots:
|
2019-11-27 08:40:08 +00:00
|
|
|
void handleScreenChange()
|
|
|
|
{
|
2015-06-18 15:00:27 +00:00
|
|
|
qreal ppi = window()->windowHandle()->screen()->physicalDotsPerInchX();
|
|
|
|
QSizeF newSize = m_physicalSize * ppi;
|
|
|
|
resize(newSize.toSize());
|
|
|
|
m_ignoreResize = false;
|
|
|
|
}
|
2019-11-27 08:40:08 +00:00
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
private:
|
|
|
|
QSizeF m_physicalSize;
|
2019-11-27 08:40:08 +00:00
|
|
|
bool m_ignoreResize = false;
|
2015-06-18 15:00:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
void PhysicalSizeTest::paintEvent(QPaintEvent *)
|
|
|
|
{
|
|
|
|
QPainter p(this);
|
|
|
|
p.setRenderHint(QPainter::Antialiasing);
|
|
|
|
|
|
|
|
qreal ppi = window()->windowHandle()->screen()->physicalDotsPerInchX();
|
|
|
|
qreal ppmm = ppi / 25.4;
|
|
|
|
qreal h = 15 * ppmm;
|
|
|
|
QRectF rulerRect(0,0, width(), h);
|
|
|
|
rulerRect.moveCenter(rect().center());
|
|
|
|
|
|
|
|
QFont f = font();
|
|
|
|
f.setPixelSize(18);
|
|
|
|
p.setFont(f);
|
|
|
|
|
|
|
|
// draw a rectangle in (Qt) pixel coordinates, for comparison
|
|
|
|
QRect pixelRect(0, 0, 300, 50);
|
|
|
|
pixelRect.moveTopLeft(QPoint(5 * ppmm, rulerRect.bottom() + 5 * ppmm));
|
|
|
|
p.fillRect(pixelRect, QColor(199,222,255));
|
|
|
|
p.drawText(pixelRect, "This rectangle is 300x50 pixels");
|
|
|
|
|
|
|
|
f.setPixelSize(4 * ppmm);
|
|
|
|
p.setFont(f);
|
|
|
|
|
|
|
|
QRectF topRect(0, 0, width(), rulerRect.top());
|
|
|
|
p.drawText(topRect, Qt::AlignCenter, "The ruler is drawn in physical units.\nThis window tries to keep its physical size\nwhen moved between screens.");
|
|
|
|
|
|
|
|
// draw a ruler in real physical coordinates
|
|
|
|
|
|
|
|
p.fillRect(rulerRect, QColor(255, 222, 111));
|
|
|
|
|
|
|
|
QPen linePen(Qt::black, 0.3 * ppmm);
|
|
|
|
p.setPen(linePen);
|
|
|
|
f.setBold(true);
|
|
|
|
p.setFont(f);
|
|
|
|
|
|
|
|
qreal vCenter = rulerRect.center().y();
|
|
|
|
p.drawLine(0, vCenter, width(), vCenter);
|
|
|
|
|
|
|
|
// cm
|
|
|
|
for (int i = 0;;) {
|
|
|
|
i++;
|
|
|
|
qreal x = i * ppmm;
|
|
|
|
if (x > width())
|
|
|
|
break;
|
|
|
|
qreal y = rulerRect.bottom();
|
|
|
|
qreal len;
|
|
|
|
if (i % 5)
|
|
|
|
len = 2 * ppmm;
|
|
|
|
else if (i % 10)
|
|
|
|
len = 3 * ppmm;
|
|
|
|
else
|
|
|
|
len = h / 2;
|
|
|
|
|
|
|
|
p.drawLine(QPointF(x, y), QPointF(x, y - len));
|
|
|
|
if (i % 10 == 5) {
|
|
|
|
QRectF textR(0, 0, 5 * ppmm, h / 2 - 2 * ppmm);
|
|
|
|
textR.moveTopLeft(QPointF(x, vCenter));
|
|
|
|
int n = i / 10 + 1;
|
|
|
|
if (n % 10 == 0)
|
|
|
|
p.setPen(Qt::red);
|
|
|
|
p.drawText(textR, Qt::AlignCenter, QString::number(n));
|
|
|
|
p.setPen(linePen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//inches
|
|
|
|
for (int i = 0;;) {
|
|
|
|
i++;
|
|
|
|
qreal x = i * ppi / 16;
|
|
|
|
if (x > width())
|
|
|
|
break;
|
|
|
|
qreal y = rulerRect.top();
|
|
|
|
|
|
|
|
qreal d = h / 10;
|
|
|
|
qreal len;
|
|
|
|
if (i % 2)
|
|
|
|
len = 1 * d;
|
|
|
|
else if (i % 4)
|
|
|
|
len = 2 * d;
|
|
|
|
else if (i % 8)
|
|
|
|
len = 3 * d;
|
|
|
|
else if (i % 16)
|
|
|
|
len = 4 * d;
|
|
|
|
else
|
|
|
|
len = h / 2;
|
|
|
|
|
|
|
|
p.drawLine(QPointF(x, y), QPointF(x, y + len));
|
|
|
|
if (i % 16 == 12) {
|
|
|
|
QRectF textR(0, 0, 0.25 * ppi, h / 2 - 2 * d);
|
|
|
|
textR.moveBottomLeft(QPointF(x, vCenter));
|
|
|
|
p.drawText(textR, Qt::AlignCenter, QString::number(1 + i/16));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-11-25 12:57:48 +00:00
|
|
|
class GraphicsViewCaching : public QGraphicsView
|
|
|
|
{
|
|
|
|
public:
|
2019-11-27 08:40:08 +00:00
|
|
|
GraphicsViewCaching()
|
|
|
|
{
|
|
|
|
auto scene = new QGraphicsScene(0, 0, 400, 400);
|
2016-11-25 12:57:48 +00:00
|
|
|
|
2018-06-24 07:58:50 +00:00
|
|
|
QGraphicsTextItem *item = scene->addText("NoCache");
|
2016-11-25 12:57:48 +00:00
|
|
|
item->setCacheMode(QGraphicsItem::NoCache);
|
|
|
|
item->setPos(10, 10);
|
|
|
|
|
|
|
|
item = scene->addText("ItemCoordinateCache");
|
|
|
|
item->setCacheMode(QGraphicsItem::ItemCoordinateCache);
|
|
|
|
item->setPos(10, 30);
|
|
|
|
|
|
|
|
item = scene->addText("DeviceCoordinateCache");
|
|
|
|
item->setCacheMode(QGraphicsItem::DeviceCoordinateCache);
|
|
|
|
item->setPos(10, 50);
|
|
|
|
|
|
|
|
setScene(scene);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-04-26 23:15:48 +00:00
|
|
|
class MetricsTest : public QWidget
|
|
|
|
{
|
2019-11-27 08:59:33 +00:00
|
|
|
Q_OBJECT
|
2016-04-26 23:15:48 +00:00
|
|
|
public:
|
|
|
|
MetricsTest()
|
|
|
|
{
|
2019-11-27 08:59:33 +00:00
|
|
|
qDebug().noquote().nospace() << "MetricsTest " << QT_VERSION_STR
|
|
|
|
<< ' ' << QGuiApplication::platformName() << '\n'
|
|
|
|
<< R"(Relevant environment variables are:
|
2016-04-26 23:15:48 +00:00
|
|
|
QT_FONT_DPI=N
|
|
|
|
QT_SCALE_FACTOR=n
|
|
|
|
QT_ENABLE_HIGHDPI_SCALING=0|1
|
|
|
|
QT_USE_PHYSICAL_DPI=0|1
|
|
|
|
QT_SCREEN_SCALE_FACTORS=N;N;N or QT_SCREEN_SCALE_FACTORS=name:N
|
|
|
|
QT_SCALE_FACTOR_ROUNDING_POLICY=Round|Ceil|Floor|RoundPreferFloor|PassThrough
|
|
|
|
QT_DPI_ADJUSTMENT_POLICY=AdjustDpi|DontAdjustDpi|AdjustUpOnly)";
|
|
|
|
|
|
|
|
resize(480, 360);
|
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
auto layout = new QVBoxLayout(this);
|
2016-04-26 23:15:48 +00:00
|
|
|
|
|
|
|
m_textEdit = new QPlainTextEdit;
|
|
|
|
m_textEdit->setReadOnly(true);
|
|
|
|
layout->addWidget(m_textEdit);
|
2019-11-27 08:59:33 +00:00
|
|
|
setWindowTitle(formatWindowTitle("Screens"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void setVisible(bool visible) override
|
|
|
|
{
|
|
|
|
QWidget::setVisible(visible);
|
|
|
|
if (visible && !m_screenChangedConnected) {
|
|
|
|
m_screenChangedConnected = true;
|
|
|
|
QObject::connect(windowHandle(), &QWindow::screenChanged,
|
|
|
|
this, &MetricsTest::screenChanged);
|
|
|
|
updateMetrics();
|
|
|
|
}
|
2016-04-26 23:15:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void updateMetrics()
|
|
|
|
{
|
|
|
|
QString text;
|
|
|
|
QTextStream str(&text);
|
|
|
|
|
|
|
|
auto currentScreen = windowHandle()->screen();
|
|
|
|
const auto screens = QGuiApplication::screens();
|
|
|
|
for (int i = 0, size = screens.size(); i < size; ++i) {
|
|
|
|
auto screen = screens.at(i);
|
|
|
|
auto platformScreen = screen->handle();
|
|
|
|
str << "Screen #" << i << " \"" << screen->name() << '"';
|
|
|
|
if (screen == currentScreen)
|
|
|
|
str << " [current]";
|
|
|
|
if (screen == QGuiApplication::primaryScreen())
|
|
|
|
str << " [primary]";
|
|
|
|
str << "\n screen geometry: " << screen->geometry()
|
|
|
|
<< "\n platform screen geometry: " << platformScreen->geometry()
|
|
|
|
<< "\n platform screen logicalDpi: " << platformScreen->logicalDpi().first;
|
|
|
|
|
|
|
|
#ifdef HAVE_SCREEN_BASE_DPI
|
|
|
|
str << "\n platform screen logicalBaseDpi: " << platformScreen->logicalBaseDpi().first;
|
|
|
|
#endif
|
|
|
|
str << "\n platform screen devicePixelRatio: " <<platformScreen->devicePixelRatio()
|
|
|
|
<< "\n platform screen physicalDpi: " << screen->physicalDotsPerInch()
|
|
|
|
<< "\n\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
str << "widget devicePixelRatio: " << this->devicePixelRatioF()
|
|
|
|
<< "\nwidget logicalDpi: " << this->logicalDpiX()
|
|
|
|
<< "\n\nQT_FONT_DPI: " << qgetenv("QT_FONT_DPI")
|
|
|
|
<< "\nQT_SCALE_FACTOR: " << qgetenv("QT_SCALE_FACTOR")
|
|
|
|
<< "\nQT_ENABLE_HIGHDPI_SCALING: " << qgetenv("QT_ENABLE_HIGHDPI_SCALING")
|
|
|
|
<< "\nQT_SCREEN_SCALE_FACTORS: " << qgetenv("QT_SCREEN_SCALE_FACTORS")
|
|
|
|
<< "\nQT_USE_PHYSICAL_DPI: " << qgetenv("QT_USE_PHYSICAL_DPI")
|
|
|
|
<< "\nQT_SCALE_FACTOR_ROUNDING_POLICY: " << qgetenv("QT_SCALE_FACTOR_ROUNDING_POLICY")
|
|
|
|
<< "\nQT_DPI_ADJUSTMENT_POLICY: " << qgetenv("QT_DPI_ADJUSTMENT_POLICY")
|
|
|
|
<< '\n';
|
|
|
|
|
|
|
|
m_textEdit->setPlainText(text);
|
|
|
|
}
|
|
|
|
|
2019-11-27 08:59:33 +00:00
|
|
|
private slots:
|
|
|
|
void screenChanged()
|
2016-04-26 23:15:48 +00:00
|
|
|
{
|
2019-11-27 08:59:33 +00:00
|
|
|
qDebug().noquote() << __FUNCTION__ << windowHandle()->screen()->name();
|
2016-04-26 23:15:48 +00:00
|
|
|
updateMetrics();
|
|
|
|
}
|
2019-11-27 08:59:33 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
QPlainTextEdit *m_textEdit;
|
|
|
|
bool m_screenChangedConnected = false;
|
2016-04-26 23:15:48 +00:00
|
|
|
};
|
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2019-11-27 08:59:33 +00:00
|
|
|
#define NOSCALINGOPTION "noscaling"
|
|
|
|
#define SCALINGOPTION "scaling"
|
|
|
|
|
|
|
|
qInfo("High DPI tester %s", QT_VERSION_STR);
|
|
|
|
|
|
|
|
int preAppOptionCount = 0;
|
|
|
|
for (int a = 1; a < argc; ++a) {
|
|
|
|
if (qstrcmp(argv[a], "--" NOSCALINGOPTION) == 0) {
|
|
|
|
QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
|
|
|
|
preAppOptionCount++;
|
|
|
|
qInfo("AA_DisableHighDpiScaling");
|
|
|
|
} else if (qstrcmp(argv[a], "--" SCALINGOPTION) == 0) {
|
|
|
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
|
|
|
preAppOptionCount++;
|
|
|
|
qInfo("AA_EnableHighDpiScaling");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-18 15:00:27 +00:00
|
|
|
QApplication app(argc, argv);
|
|
|
|
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
|
|
|
QCoreApplication::setApplicationVersion(QT_VERSION_STR);
|
|
|
|
|
|
|
|
QCommandLineParser parser;
|
|
|
|
parser.setApplicationDescription("High DPI tester. Pass one or more of the options to\n"
|
|
|
|
"test various high-dpi aspects. \n"
|
|
|
|
"--interactive is a special option and opens a configuration"
|
|
|
|
" window.");
|
|
|
|
parser.addHelpOption();
|
|
|
|
parser.addVersionOption();
|
|
|
|
QCommandLineOption controllerOption("interactive", "Show configuration window.");
|
|
|
|
parser.addOption(controllerOption);
|
2019-11-27 08:59:33 +00:00
|
|
|
parser.addOption(QCommandLineOption(NOSCALINGOPTION, "Set AA_DisableHighDpiScaling"));
|
|
|
|
parser.addOption(QCommandLineOption(SCALINGOPTION, "Set AA_EnableHighDpiScaling"));
|
2015-06-18 15:00:27 +00:00
|
|
|
|
|
|
|
DemoContainerList demoList;
|
|
|
|
demoList << new DemoContainer<PixmapPainter>("pixmap", "Test pixmap painter");
|
High-dpi drawTiledPixmap (raster paint engine)
Implement more consistent behavior for drawTiledPixmap(),
which should produce the same visual tiling pattern
independent of display devicePixelRatio
Consider the following pixmaps and draw calls:
QPixmap px32; // 32x32
QPixmap px64; // 64x64
drawTiledPixmap(QRect(0, 0, 128, 128), px32);
drawTiledPixmap(QRect(0, 0, 128, 128), px64);
On 1x displays this will produce 4x4 and 2x2 tiles,
respectively.
On 2x displays this would previously produce a different
tiling pattern, where the paint engine would tile in
the device pixel coordinate system. Change this to
tile in the device independent coordinate system,
producing the same visual tiling pattern as the 1x case.
It is possible to produce a 4x4 tiling pattern with
high-resolution output from the 64x64 pixmap by setting
the devicePixelRatio:
QPixmap px64;
px64.setDevicePixelRatio(2);
drawTiledPixmap(QRect(0, 0, 128, 128), px64);
This change adds an inverse scale to the image filler
transform that accounts for the pixmap devicePixelRatio.
[ChangeLog][QtGui] QPainter::drawTiledPixmap() now
tiles in the device independent coordinate system.
Change-Id: I4918d274192967f222f181b374571c7c597dcd76
Reviewed-by: Jonathan Courtois <jonathan.courtois@gmail.com>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: 石博文 <sbw@sbw.so>
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
2015-02-24 10:13:31 +00:00
|
|
|
demoList << new DemoContainer<TiledPixmapPainter>("tiledpixmap", "Test tiled pixmap painter");
|
2015-06-18 15:00:27 +00:00
|
|
|
demoList << new DemoContainer<Labels>("label", "Test Labels");
|
|
|
|
demoList << new DemoContainer<MainWindow>("mainwindow", "Test QMainWindow");
|
|
|
|
demoList << new DemoContainer<StandardIcons>("standard-icons", "Test standard icons");
|
|
|
|
demoList << new DemoContainer<Caching>("caching", "Test caching");
|
|
|
|
demoList << new DemoContainer<Style>("styles", "Test style");
|
|
|
|
demoList << new DemoContainer<Fonts>("fonts", "Test fonts");
|
|
|
|
demoList << new DemoContainer<IconDrawing>("icondrawing", "Test icon drawing");
|
|
|
|
demoList << new DemoContainer<Buttons>("buttons", "Test buttons");
|
|
|
|
demoList << new DemoContainer<LinePainter>("linepainter", "Test line painting");
|
|
|
|
demoList << new DemoContainer<DragWidget>("draganddrop", "Test drag and drop");
|
|
|
|
demoList << new DemoContainer<CursorTester>("cursorpos", "Test cursor and window positioning");
|
|
|
|
demoList << new DemoContainer<ScreenDisplayer>("screens", "Test screen and window positioning");
|
|
|
|
demoList << new DemoContainer<PhysicalSizeTest>("physicalsize", "Test manual highdpi support using physicalDotsPerInch");
|
2016-11-25 12:57:48 +00:00
|
|
|
demoList << new DemoContainer<GraphicsViewCaching>("graphicsview", "Test QGraphicsView caching");
|
2019-11-27 08:59:33 +00:00
|
|
|
demoList << new DemoContainer<MetricsTest>("metrics", "Show screen metrics");
|
2015-06-18 15:00:27 +00:00
|
|
|
|
2019-11-27 08:40:08 +00:00
|
|
|
for (DemoContainerBase *demo : qAsConst(demoList))
|
2015-06-18 15:00:27 +00:00
|
|
|
parser.addOption(demo->option());
|
|
|
|
|
|
|
|
parser.process(app);
|
|
|
|
|
|
|
|
//controller takes ownership of all demos
|
2019-11-27 08:40:08 +00:00
|
|
|
DemoController controller(demoList, &parser);
|
2015-06-18 15:00:27 +00:00
|
|
|
|
2019-11-27 08:59:33 +00:00
|
|
|
if (parser.isSet(controllerOption) || (QCoreApplication::arguments().count() - preAppOptionCount) <= 1)
|
2015-06-18 15:00:27 +00:00
|
|
|
controller.show();
|
2013-03-01 11:41:43 +00:00
|
|
|
|
2014-07-18 12:22:14 +00:00
|
|
|
if (QApplication::topLevelWidgets().isEmpty())
|
|
|
|
parser.showHelp(0);
|
2012-11-20 10:34:52 +00:00
|
|
|
|
|
|
|
return app.exec();
|
|
|
|
}
|
2015-06-18 15:00:27 +00:00
|
|
|
|
|
|
|
#include "main.moc"
|