QtBase  v6.3.1
main.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28 
29 #include <QAction>
30 #include <QApplication>
31 #include <QCursor>
32 #include <QDebug>
33 #include <QDialog>
34 #include <QDialogButtonBox>
35 #include <QList>
36 #include <QMainWindow>
37 #include <QMenu>
38 #include <QMenuBar>
39 #include <QMouseEvent>
40 #include <QPainter>
41 #include <QPainterPath>
42 #include <QPlainTextEdit>
43 #include <QPointingDevice>
44 #include <QPointer>
45 #include <QPushButton>
46 #include <QStatusBar>
47 #include <QTabletEvent>
48 #include <QVBoxLayout>
49 
50 #ifdef Q_OS_WIN
51 # include <QtGui/private/qguiapplication_p.h>
52 # include <QtGui/qpa/qplatformintegration.h>
53 #endif
54 
59 };
60 
61 #ifdef Q_OS_WIN
63 
64 static void setWinTabEnabled(bool e)
65 {
66  if (auto nativeWindowsApp = dynamic_cast<QWindowsApplication *>(QGuiApplicationPrivate::platformIntegration()))
67  nativeWindowsApp->setWinTabEnabled(e);
68 }
69 
70 static bool isWinTabEnabled()
71 {
72  auto nativeWindowsApp = dynamic_cast<QWindowsApplication *>(QGuiApplicationPrivate::platformIntegration());
73  return nativeWindowsApp && nativeWindowsApp->isWinTabEnabled();
74 }
75 #endif // Q_OS_WIN
76 
78 {
81  pos(p), type(t), button(b), ptype(pt), pressure(prs), angle(rotation) {}
82 
89 };
90 
92 {
93  Q_OBJECT
94 public:
96 
97  bool eventFilter(QObject *, QEvent *event) override;
98 
99  static bool tabletPenProximity() { return m_tabletPenProximity; }
100 
101 signals:
103 
104 private:
105  static bool m_tabletPenProximity;
106 };
107 
109 {
110  switch (event->type()) {
113  ProximityEventFilter::m_tabletPenProximity = event->type() == QEvent::TabletEnterProximity;
115  qDebug() << event;
116  break;
117  default:
118  break;
119  }
120  return false;
121 }
122 
123 bool ProximityEventFilter::m_tabletPenProximity = false;
124 
126 {
127  Q_OBJECT
128 public:
130 
131 public slots:
132  void clearPoints() { m_points.clear(); update(); }
133 
134 signals:
135  void stats(QString s, int timeOut = 0);
136 
137 protected:
138  void mouseDoubleClickEvent(QMouseEvent *event) override { outputMouseEvent(event); }
139  void mouseMoveEvent(QMouseEvent *event) override { outputMouseEvent(event); }
140  void mousePressEvent(QMouseEvent *event) override { outputMouseEvent(event); }
141  void mouseReleaseEvent(QMouseEvent *event) override { outputMouseEvent(event); }
142 
143  void tabletEvent(QTabletEvent *) override;
144 
145  bool event(QEvent *event) override;
146 
147  void paintEvent(QPaintEvent *) override;
148  void timerEvent(QTimerEvent *) override;
149 
150 private:
151  void outputMouseEvent(QMouseEvent *event);
152 
153  bool m_lastIsMouseMove = false;
154  bool m_lastIsTabletMove = false;
155  Qt::MouseButton m_lastButton = Qt::NoButton;
156  QList<TabletPoint> m_points;
157  QList<QPointF> m_touchPoints;
158  QPointF m_tabletPos;
159  int m_tabletMoveCount = 0;
160  int m_paintEventCount = 0;
161 };
162 
164 {
166  startTimer(1000);
167 }
168 
170 {
171  QPainter p(this);
172  int lineSpacing = fontMetrics().lineSpacing();
173  int halfLineSpacing = lineSpacing / 2;
174  const QRectF geom = QRectF(QPoint(0, 0), size());
175  p.fillRect(geom, Qt::white);
176  p.drawRect(QRectF(geom.topLeft(), geom.bottomRight() - QPointF(1,1)));
177  p.setPen(Qt::white);
179  ellipse.addEllipse(0, 0, halfLineSpacing * 5, halfLineSpacing);
180  for (const TabletPoint &t : qAsConst(m_points)) {
181  if (geom.contains(t.pos)) {
182  QPainterPath pp;
183  pp.addEllipse(t.pos, halfLineSpacing, halfLineSpacing);
184  QRectF pointBounds(t.pos.x() - halfLineSpacing, t.pos.y() - halfLineSpacing, lineSpacing, lineSpacing);
185  switch (t.type) {
186  case TabletButtonPress:
187  p.fillPath(pp, Qt::darkGreen);
188  if (t.button != Qt::NoButton)
189  p.drawText(pointBounds, Qt::AlignCenter, QString::number(t.button));
190  break;
191  case TabletButtonRelease:
192  p.fillPath(pp, Qt::red);
193  if (t.button != Qt::NoButton)
194  p.drawText(pointBounds, Qt::AlignCenter, QString::number(t.button));
195  break;
196  case TabletMove:
197  if (t.pressure > 0.0) {
199  if (t.angle != 0.0) {
200  p.save();
201  p.translate(t.pos);
202  p.scale(t.pressure, t.pressure);
203  p.rotate(t.angle);
204  p.drawPath(ellipse);
205  p.restore();
206  } else {
207  p.drawEllipse(t.pos, t.pressure * halfLineSpacing, t.pressure * halfLineSpacing);
208  }
209  p.setPen(Qt::white);
210  } else {
211  p.fillRect(t.pos.x() - 2, t.pos.y() - 2, 4, 4, Qt::black);
212  }
213  break;
214  }
215  }
216  }
217 
218  // Draw haircross when tablet pen is in proximity
219  if (ProximityEventFilter::tabletPenProximity() && geom.contains(m_tabletPos)) {
220  p.setPen(Qt::black);
221  p.drawLine(QPointF(0, m_tabletPos.y()), QPointF(geom.width(), m_tabletPos.y()));
222  p.drawLine(QPointF(m_tabletPos.x(), 0), QPointF(m_tabletPos.x(), geom.height()));
223  }
224  p.setPen(Qt::blue);
225  for (QPointF t : m_touchPoints) {
226  p.drawLine(t.x() - 40, t.y(), t.x() + 40, t.y());
227  p.drawLine(t.x(), t.y() - 40, t.x(), t.y() + 40);
228  }
229  ++m_paintEventCount;
230 }
231 
233 {
234  QWidget::tabletEvent(event);
235  bool isMove = false;
236  m_tabletPos = event->position();
237  switch (event->type()) {
238  case QEvent::TabletMove:
239  m_points.push_back(TabletPoint(m_tabletPos, TabletMove, m_lastButton, event->pointerType(), event->pressure(), event->rotation()));
240  update();
241  isMove = true;
242  ++m_tabletMoveCount;
243  break;
244  case QEvent::TabletPress:
245  m_points.push_back(TabletPoint(m_tabletPos, TabletButtonPress, event->button(), event->pointerType(), event->rotation()));
246  m_lastButton = event->button();
247  update();
248  break;
250  m_points.push_back(TabletPoint(m_tabletPos, TabletButtonRelease, event->button(), event->pointerType(), event->rotation()));
251  update();
252  break;
253  default:
254  Q_ASSERT(false);
255  break;
256  }
257 
258  if (!(isMove && m_lastIsTabletMove)) {
259  QDebug d = qDebug();
260  d << event << " global position = " << event->globalPosition()
261  << " cursor at " << QCursor::pos();
262  if (event->button() != Qt::NoButton)
263  d << " changed button " << event->button();
264  }
265  m_lastIsTabletMove = isMove;
266 }
267 
269 {
270  switch (event->type()) {
271  case QEvent::TouchBegin:
272  case QEvent::TouchUpdate:
273  event->accept();
274  m_touchPoints.clear();
275  for (const QEventPoint &p : static_cast<const QPointerEvent *>(event)->points())
276  m_touchPoints.append(p.position());
277  update();
278  break;
279  case QEvent::TouchEnd:
280  m_touchPoints.clear();
281  update();
282  break;
283  default:
284  return QWidget::event(event);
285  }
286  return true;
287 }
288 
289 void EventReportWidget::outputMouseEvent(QMouseEvent *event)
290 {
291  if (event->type() == QEvent::MouseMove) {
292  if (m_lastIsMouseMove)
293  return; // only show one move to keep things readable
294  m_lastIsMouseMove = true;
295  }
296  qDebug() << event;
297 }
298 
300 {
301  emit stats(QString("%1 moves/sec, %2 frames/sec").arg(m_tabletMoveCount).arg(m_paintEventCount));
302  m_tabletMoveCount = 0;
303  m_paintEventCount = 0;
304 }
305 
306 class DevicesDialog : public QDialog
307 {
308  Q_OBJECT
309 public:
310  explicit DevicesDialog(QWidget *p);
311 
312 public slots:
313  void refresh();
314 
315 private:
316  QPlainTextEdit *m_edit;
317 };
318 
320 {
321  auto layout = new QVBoxLayout(this);
322  m_edit = new QPlainTextEdit(this);
323  m_edit->setReadOnly(true);
324  layout->addWidget(m_edit);
325  auto box = new QDialogButtonBox(QDialogButtonBox::Close, this);
327  auto refreshButton = box->addButton("Refresh", QDialogButtonBox::ActionRole);
329  layout->addWidget(box);
330  setWindowTitle("Devices");
331  refresh();
332 }
333 
335 {
336  QString text;
337  QDebug d(&text);
338  d.noquote();
339  d.nospace();
340  for (auto device : QInputDevice::devices())
341  d << device<< "\n\n";
342  m_edit->setPlainText(text);
343 }
344 
345 class MainWindow : public QMainWindow
346 {
347  Q_OBJECT
348 public:
349  explicit MainWindow(ProximityEventFilter *proximityEventFilter);
350 
351 public slots:
352  void showDevices();
353 
354 private:
355  QPointer<DevicesDialog> m_devicesDialog;
356 };
357 
359 {
360  setWindowTitle(QString::fromLatin1("Tablet Test %1").arg(QT_VERSION_STR));
361  auto widget = new EventReportWidget;
363  widget, QOverload<>::of(&QWidget::update));
364  widget->setMinimumSize(640, 480);
365  auto fileMenu = menuBar()->addMenu("File");
366  fileMenu->addAction("Clear", widget, &EventReportWidget::clearPoints);
367  auto showAction = fileMenu->addAction("Show Devices", this, &MainWindow::showDevices);
368  showAction->setShortcut(Qt::CTRL | Qt::Key_D);
371  QAction *quitAction = fileMenu->addAction("Quit", qApp, &QCoreApplication::quit);
372  quitAction->setShortcut(Qt::CTRL | Qt::Key_Q);
373 
374  auto settingsMenu = menuBar()->addMenu("Settings");
375  auto winTabAction = settingsMenu->addAction("WinTab");
376  winTabAction->setCheckable(true);
377 #ifdef Q_OS_WIN
378  winTabAction->setChecked(isWinTabEnabled());
379  connect(winTabAction, &QAction::toggled, this, setWinTabEnabled);
380 #else
381  winTabAction->setEnabled(false);
382 #endif
383 
385 }
386 
388 {
389  if (m_devicesDialog.isNull()) {
390  m_devicesDialog = new DevicesDialog(nullptr);
391  m_devicesDialog->setModal(false);
392  m_devicesDialog->resize(500, 300);
393  m_devicesDialog->move(frameGeometry().topRight() + QPoint(20, 0));
394  m_devicesDialog->setAttribute(Qt::WA_DeleteOnClose);
395  }
396  m_devicesDialog->show();
397  m_devicesDialog->raise();
398  m_devicesDialog->refresh();
399 }
400 
401 int main(int argc, char *argv[])
402 {
403  QApplication app(argc, argv);
404 
405  ProximityEventFilter *proximityEventFilter = new ProximityEventFilter(&app);
406  app.installEventFilter(proximityEventFilter);
407  MainWindow mainWindow(proximityEventFilter);
408  mainWindow.show();
409  return app.exec();
410 }
411 
412 #include "main.moc"
DevicesDialog(QWidget *p)
Definition: main.cpp:319
void refresh()
Definition: main.cpp:334
bool event(QEvent *event) override
Definition: main.cpp:268
void clearPoints()
Definition: main.cpp:132
void mouseMoveEvent(QMouseEvent *event) override
Definition: main.cpp:139
void timerEvent(QTimerEvent *) override
Definition: main.cpp:299
void mousePressEvent(QMouseEvent *event) override
Definition: main.cpp:140
void mouseDoubleClickEvent(QMouseEvent *event) override
Definition: main.cpp:138
void stats(QString s, int timeOut=0)
void paintEvent(QPaintEvent *) override
Definition: main.cpp:169
void tabletEvent(QTabletEvent *) override
Definition: main.cpp:232
void mouseReleaseEvent(QMouseEvent *event) override
Definition: main.cpp:141
MainWindow()
[0]
Definition: mainwindow.cpp:55
void showDevices()
Definition: main.cpp:387
static bool tabletPenProximity()
Definition: main.cpp:99
ProximityEventFilter(QObject *parent)
Definition: main.cpp:95
bool eventFilter(QObject *, QEvent *event) override
Definition: main.cpp:108
void clicked(bool checked=false)
The QAction class provides an abstraction for user commands that can be added to different user inter...
Definition: qaction.h:65
void toggled(bool)
void setCheckable(bool)
Definition: qaction.cpp:862
The QApplication class manages the GUI application's control flow and main settings.
Definition: qapplication.h:68
static int exec()
static QPoint pos()
Definition: qcursor.cpp:224
The QDebug class provides an output stream for debugging information.
Definition: qdebug.h:65
The QDialogButtonBox class is a widget that presents buttons in a layout that is appropriate to the c...
The QDialog class is the base class of dialog windows.
Definition: qdialog.h:55
virtual void reject()
Definition: qdialog.cpp:678
void setModal(bool modal)
Definition: qdialog.cpp:1038
The QEvent class is the base class of all event classes. Event objects contain event parameters.
Definition: qcoreevent.h:58
@ TabletMove
Definition: qcoreevent.h:134
@ TabletEnterProximity
Definition: qcoreevent.h:222
@ MouseMove
Definition: qcoreevent.h:76
@ TouchEnd
Definition: qcoreevent.h:256
@ TouchUpdate
Definition: qcoreevent.h:255
@ TouchBegin
Definition: qcoreevent.h:254
@ TabletRelease
Definition: qcoreevent.h:140
@ TabletPress
Definition: qcoreevent.h:139
@ TabletLeaveProximity
Definition: qcoreevent.h:223
The QEventPoint class provides information about a point in a QPointerEvent.
Definition: qeventpoint.h:56
int lineSpacing() const
static QPlatformIntegration * platformIntegration()
static QList< const QInputDevice * > devices()
void addWidget(QWidget *w)
Definition: qlayout.cpp:223
void push_back(parameter_type t)
Definition: qlist.h:687
void append(parameter_type t)
Definition: qlist.h:469
void clear()
Definition: qlist.h:445
The QMainWindow class provides a main application window.\inmodule QtWidgets.
Definition: qmainwindow.h:61
void setCentralWidget(QWidget *widget)
QAction * addMenu(QMenu *menu)
Definition: qmenubar.cpp:789
void addAction(QAction *action)
Definition: qwidget.cpp:3129
The QMouseEvent class contains parameters that describe a mouse event.
Definition: qevent.h:231
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
int startTimer(int interval, Qt::TimerType timerType=Qt::CoarseTimer)
Definition: qobject.cpp:1765
void installEventFilter(QObject *filterObj)
Definition: qobject.cpp:2235
QObject * parent() const
Definition: qobject.h:409
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Definition: qobject.cpp:2772
virtual bool event(QEvent *event)
Definition: qobject.cpp:1329
The QPaintEvent class contains event parameters for paint events. \inmodule QtGui.
Definition: qevent.h:539
The QPainter class performs low-level painting on widgets and other paint devices.
Definition: qpainter.h:82
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:65
void addEllipse(const QRectF &rect)
The QPlainTextEdit class provides a widget that is used to edit and display plain text.
void setPlainText(const QString &text)
void setReadOnly(bool ro)
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:242
constexpr qreal x() const noexcept
Definition: qpoint.h:361
constexpr qreal y() const noexcept
Definition: qpoint.h:366
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:52
A base class for pointer events.
Definition: qevent.h:102
bool isNull() const
Definition: qpointer.h:87
The QRectF class defines a finite rectangle in the plane using floating point precision.
Definition: qrect.h:511
constexpr qreal height() const noexcept
Definition: qrect.h:741
constexpr qreal width() const noexcept
Definition: qrect.h:738
bool contains(const QRectF &r) const noexcept
Definition: qrect.cpp:2006
constexpr QPointF topLeft() const noexcept
Definition: qrect.h:538
constexpr QPointF bottomRight() const noexcept
Definition: qrect.h:539
void showMessage(const QString &text, int timeout=0)
Definition: qstatusbar.cpp:536
The QString class provides a Unicode character string.
Definition: qstring.h:388
static QString fromLatin1(QByteArrayView ba)
Definition: qstring.cpp:5488
static QString number(int, int base=10)
Definition: qstring.cpp:7538
The QTimerEvent class contains parameters that describe a timer event.
Definition: qcoreevent.h:367
The QVBoxLayout class lines up widgets vertically.
Definition: qboxlayout.h:127
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:133
void setAttribute(Qt::WidgetAttribute, bool on=true)
Definition: qwidget.cpp:11088
void raise()
Definition: qwidget.cpp:11707
void setMinimumSize(const QSize &)
Definition: qwidget.h:865
QSize size
the size of the widget excluding any window frame
Definition: qwidget.h:147
QLayout * layout() const
Definition: qwidget.cpp:10115
void move(int x, int y)
Definition: qwidget.h:913
QFontMetrics fontMetrics() const
Definition: qwidget.h:880
void show()
Definition: qwidget.cpp:7825
void update()
Definition: qwidget.cpp:10977
void setWindowTitle(const QString &)
Definition: qwidget.cpp:6119
bool event(QEvent *event) override
Definition: qwidget.cpp:8772
void resize(int w, int h)
Definition: qwidget.h:916
QRect frameGeometry
geometry of the widget relative to its parent including any window frame
Definition: qwidget.h:141
bool isWinTabEnabled() const override
int main(int argc, char **argv)
Definition: main.cpp:1
float rotation
QOpenGLWidget * widget
[1]
double e
@ AlignCenter
Definition: qnamespace.h:188
@ CTRL
Definition: qnamespace.h:1096
MouseButton
Definition: qnamespace.h:81
@ LeftButton
Definition: qnamespace.h:83
@ NoButton
Definition: qnamespace.h:82
@ WA_AcceptTouchEvents
Definition: qnamespace.h:429
@ WA_DeleteOnClose
Definition: qnamespace.h:346
@ white
Definition: qnamespace.h:62
@ blue
Definition: qnamespace.h:68
@ black
Definition: qnamespace.h:61
@ red
Definition: qnamespace.h:66
@ darkGreen
Definition: qnamespace.h:73
@ Key_D
Definition: qnamespace.h:575
@ Key_Q
Definition: qnamespace.h:588
#define QString()
Definition: parse-defines.h:51
#define qApp
QT_END_INCLUDE_NAMESPACE typedef double qreal
Definition: qglobal.h:341
@ text
#define qDebug
[1]
Definition: qlogging.h:177
GLenum type
Definition: qopengl.h:270
GLboolean GLboolean GLboolean b
GLfloat angle
struct _cl_event * event
Definition: qopenglext.h:2998
GLfixed GLfixed GLint GLint GLfixed points
Definition: qopenglext.h:5206
GLdouble GLdouble t
[9]
Definition: qopenglext.h:243
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
SSL_CTX int(*) void arg)
#define Q_OBJECT
Definition: qtmetamacros.h:158
#define slots
Definition: qtmetamacros.h:76
#define signals
Definition: qtmetamacros.h:77
#define emit
Definition: qtmetamacros.h:85
QGraphicsEllipseItem * ellipse
QApplication app(argc, argv)
[0]
QMenuBar * menuBar
[0]
statusBar() -> addWidget(new MyReadWriteIndication)
[0]
QPointF pos
Definition: main.cpp:83
TabletPoint(const QPointF &p=QPointF(), TabletPointType t=TabletMove, Qt::MouseButton b=Qt::LeftButton, QPointingDevice::PointerType pt=QPointingDevice::PointerType::Unknown, qreal prs=0, qreal rotation=0)
Definition: main.cpp:79
qreal angle
Definition: main.cpp:88
TabletPointType type
Definition: main.cpp:84
qreal pressure
Definition: main.cpp:87
QPointingDevice::PointerType ptype
Definition: main.cpp:86
Qt::MouseButton button
Definition: main.cpp:85
Definition: jquant2.c:237
TabletPointType
Definition: main.cpp:55
@ TabletButtonPress
Definition: main.cpp:56
@ TabletMove
Definition: main.cpp:58
@ TabletButtonRelease
Definition: main.cpp:57