summaryrefslogtreecommitdiffstats
path: root/examples/widgets
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@digia.com>2015-07-27 12:02:06 +0200
committerShawn Rutledge <shawn.rutledge@theqtcompany.com>2015-07-31 04:33:20 +0000
commit6a991f9cce9da6057c4a053e52e5956284805eea (patch)
treedd6b2fb68016c8723728ea9114f05b603196bfe9 /examples/widgets
parentad4d25589fcd5efd4faa3074c19928d195f615bb (diff)
Tablet example: smoother, rotation stylus, better airbrush
The drawing is antialiased and with rounded caps and joins. Rotation stylus acts like a felt marker. Airbrush sprays a radial gradient of color, and its alpha can depend on the tangential pressure if so chosen. Task-number: QTBUG-46694 Change-Id: I4fb16eb621707e3c56a75aa302dd0d3bf418a745 Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com> Reviewed-by: Topi Reiniö <topi.reinio@digia.com>
Diffstat (limited to 'examples/widgets')
-rw-r--r--examples/widgets/doc/src/tablet.qdoc24
-rw-r--r--examples/widgets/widgets/tablet/mainwindow.cpp11
-rw-r--r--examples/widgets/widgets/tablet/mainwindow.h1
-rw-r--r--examples/widgets/widgets/tablet/tabletcanvas.cpp107
-rw-r--r--examples/widgets/widgets/tablet/tabletcanvas.h8
5 files changed, 77 insertions, 74 deletions
diff --git a/examples/widgets/doc/src/tablet.qdoc b/examples/widgets/doc/src/tablet.qdoc
index 1ab2917b7e..bc03d46332 100644
--- a/examples/widgets/doc/src/tablet.qdoc
+++ b/examples/widgets/doc/src/tablet.qdoc
@@ -259,24 +259,18 @@
\snippet widgets/tablet/tabletcanvas.cpp 5
- In this function we draw on the pixmap based on the movement of the
- device. If the device used on the tablet is a stylus we want to draw a
- line between the positions of the stylus recorded in \c polyLine. We
- also assume that this is a reasonable handling of any unknown device,
- but update the statusbar with a warning so that the user can see that
- for his tablet he might have to implement special handling.
- If it is an airbrush we want to draw a circle of points with a
- point density based on the tangential pressure, which is the position
- of the finger wheel on the airbrush. We use the Qt::BrushStyle to
- draw the points as it has styles that draw points with different
- density; we select the style based on the tangential pressure in
- \c brushPattern().
+ In this function we draw on the pixmap based on the movement of the device.
+ If the device used on the tablet is a stylus, we want to draw a line from
+ the last-known position to the current position. We also assume that this
+ is a reasonable handling of any unknown device, but update the status bar
+ with a warning. If it is an airbrush, we want to draw a circle filled with
+ a soft gradient, whose density can depend on various event parameters.
+ By default it depends on the tangential pressure, which is the position of
+ the finger wheel on the airbrush. If it is a rotation stylus, we simulate
+ a felt marker by drawing trapezoidal strokes.
\snippet widgets/tablet/tabletcanvas.cpp 6
- We return a brush style with a point density that increases with
- the tangential pressure.
-
In \c updateBrush() we set the pen and brush used for drawing
to match \c alphaChannelType, \c lineWidthType, \c
colorSaturationType, and \c myColor. We will examine the code to
diff --git a/examples/widgets/widgets/tablet/mainwindow.cpp b/examples/widgets/widgets/tablet/mainwindow.cpp
index aed84c50df..5e84f5b6a2 100644
--- a/examples/widgets/widgets/tablet/mainwindow.cpp
+++ b/examples/widgets/widgets/tablet/mainwindow.cpp
@@ -52,7 +52,7 @@ MainWindow::MainWindow(TabletCanvas *canvas)
myCanvas->setColor(Qt::red);
myCanvas->setLineWidthType(TabletCanvas::LineWidthPressure);
- myCanvas->setAlphaChannelType(TabletCanvas::NoAlpha);
+ myCanvas->setAlphaChannelType(TabletCanvas::AlphaTangentialPressure);
myCanvas->setColorSaturationType(TabletCanvas::NoSaturation);
setWindowTitle(tr("Tablet Example"));
@@ -75,6 +75,8 @@ void MainWindow::alphaActionTriggered(QAction *action)
{
if (action == alphaChannelPressureAction) {
myCanvas->setAlphaChannelType(TabletCanvas::AlphaPressure);
+ } else if (action == alphaChannelTangentialPressureAction) {
+ myCanvas->setAlphaChannelType(TabletCanvas::AlphaTangentialPressure);
} else if (action == alphaChannelTiltAction) {
myCanvas->setAlphaChannelType(TabletCanvas::AlphaTilt);
} else {
@@ -157,15 +159,19 @@ void MainWindow::createActions()
alphaChannelPressureAction = new QAction(tr("&Pressure"), this);
alphaChannelPressureAction->setCheckable(true);
+ alphaChannelTangentialPressureAction = new QAction(tr("T&angential Pressure"), this);
+ alphaChannelTangentialPressureAction->setCheckable(true);
+ alphaChannelTangentialPressureAction->setChecked(true);
+
alphaChannelTiltAction = new QAction(tr("&Tilt"), this);
alphaChannelTiltAction->setCheckable(true);
noAlphaChannelAction = new QAction(tr("No Alpha Channel"), this);
noAlphaChannelAction->setCheckable(true);
- noAlphaChannelAction->setChecked(true);
alphaChannelGroup = new QActionGroup(this);
alphaChannelGroup->addAction(alphaChannelPressureAction);
+ alphaChannelGroup->addAction(alphaChannelTangentialPressureAction);
alphaChannelGroup->addAction(alphaChannelTiltAction);
alphaChannelGroup->addAction(noAlphaChannelAction);
connect(alphaChannelGroup, SIGNAL(triggered(QAction*)),
@@ -259,6 +265,7 @@ void MainWindow::createMenus()
alphaChannelMenu = tabletMenu->addMenu(tr("&Alpha Channel"));
alphaChannelMenu->addAction(alphaChannelPressureAction);
+ alphaChannelMenu->addAction(alphaChannelTangentialPressureAction);
alphaChannelMenu->addAction(alphaChannelTiltAction);
alphaChannelMenu->addAction(noAlphaChannelAction);
diff --git a/examples/widgets/widgets/tablet/mainwindow.h b/examples/widgets/widgets/tablet/mainwindow.h
index 5e77ea1acf..c6ac2e6026 100644
--- a/examples/widgets/widgets/tablet/mainwindow.h
+++ b/examples/widgets/widgets/tablet/mainwindow.h
@@ -79,6 +79,7 @@ private:
QActionGroup *alphaChannelGroup;
QAction *alphaChannelPressureAction;
+ QAction *alphaChannelTangentialPressureAction;
QAction *alphaChannelTiltAction;
QAction *noAlphaChannelAction;
diff --git a/examples/widgets/widgets/tablet/tabletcanvas.cpp b/examples/widgets/widgets/tablet/tabletcanvas.cpp
index 20d6291292..bf98a6d621 100644
--- a/examples/widgets/widgets/tablet/tabletcanvas.cpp
+++ b/examples/widgets/widgets/tablet/tabletcanvas.cpp
@@ -47,14 +47,13 @@
TabletCanvas::TabletCanvas()
{
resize(500, 500);
- myBrush = QBrush();
- myPen = QPen();
+ myColor = Qt::red;
+ myBrush = QBrush(myColor);
+ myPen = QPen(myBrush, 1.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
initPixmap();
setAutoFillBackground(true);
deviceDown = false;
- myColor = Qt::red;
- myTabletDevice = QTabletEvent::Stylus;
- alphaChannelType = NoAlpha;
+ alphaChannelType = AlphaTangentialPressure;
colorSaturationType = NoSaturation;
lineWidthType = LineWidthPressure;
}
@@ -99,24 +98,23 @@ void TabletCanvas::tabletEvent(QTabletEvent *event)
case QEvent::TabletPress:
if (!deviceDown) {
deviceDown = true;
- polyLine[0] = polyLine[1] = polyLine[2] = event->pos();
+ lastPoint.pos = event->posF();
+ lastPoint.rotation = event->rotation();
}
break;
- case QEvent::TabletRelease:
- if (deviceDown)
- deviceDown = false;
- break;
case QEvent::TabletMove:
- polyLine[2] = polyLine[1];
- polyLine[1] = polyLine[0];
- polyLine[0] = event->pos();
-
if (deviceDown) {
updateBrush(event);
QPainter painter(&pixmap);
paintPixmap(painter, event);
+ lastPoint.pos = event->posF();
+ lastPoint.rotation = event->rotation();
}
break;
+ case QEvent::TabletRelease:
+ if (deviceDown && event->buttons() == Qt::NoButton)
+ deviceDown = false;
+ break;
default:
break;
}
@@ -135,23 +133,44 @@ void TabletCanvas::paintEvent(QPaintEvent *)
//! [5]
void TabletCanvas::paintPixmap(QPainter &painter, QTabletEvent *event)
{
- QPoint brushAdjust(10, 10);
+ painter.setRenderHint(QPainter::Antialiasing);
- switch (myTabletDevice) {
+ switch (event->device()) {
+//! [6]
case QTabletEvent::Airbrush:
- myBrush.setColor(myColor);
- myBrush.setStyle(brushPattern(event->pressure()));
- painter.setPen(Qt::NoPen);
- painter.setBrush(myBrush);
-
- for (int i = 0; i < 3; ++i) {
- painter.drawEllipse(QRect(polyLine[i] - brushAdjust,
- polyLine[i] + brushAdjust));
+ {
+ painter.setPen(Qt::NoPen);
+ QRadialGradient grad(lastPoint.pos, myPen.widthF() * 10.0);
+ QColor color = myBrush.color();
+ color.setAlphaF(color.alphaF() * 0.25);
+ grad.setColorAt(0, myBrush.color());
+ grad.setColorAt(0.5, Qt::transparent);
+ painter.setBrush(grad);
+ qreal radius = grad.radius();
+ painter.drawEllipse(event->posF(), radius, radius);
}
break;
+ case QTabletEvent::RotationStylus:
+ {
+ myBrush.setStyle(Qt::SolidPattern);
+ painter.setPen(Qt::NoPen);
+ painter.setBrush(myBrush);
+ QPolygonF poly;
+ qreal halfWidth = myPen.widthF();
+ QPointF brushAdjust(qSin(qDegreesToRadians(lastPoint.rotation)) * halfWidth,
+ qCos(qDegreesToRadians(lastPoint.rotation)) * halfWidth);
+ poly << lastPoint.pos + brushAdjust;
+ poly << lastPoint.pos - brushAdjust;
+ brushAdjust = QPointF(qSin(qDegreesToRadians(event->rotation())) * halfWidth,
+ qCos(qDegreesToRadians(event->rotation())) * halfWidth);
+ poly << event->posF() - brushAdjust;
+ poly << event->posF() + brushAdjust;
+ painter.drawConvexPolygon(poly);
+ }
+ break;
+//! [6]
case QTabletEvent::Puck:
case QTabletEvent::FourDMouse:
- case QTabletEvent::RotationStylus:
{
const QString error(tr("This input device is not supported by the example."));
#ifndef QT_NO_STATUSTIP
@@ -174,40 +193,13 @@ void TabletCanvas::paintPixmap(QPainter &painter, QTabletEvent *event)
}
// FALL-THROUGH
case QTabletEvent::Stylus:
- painter.setBrush(myBrush);
painter.setPen(myPen);
- painter.drawLine(polyLine[1], event->pos());
+ painter.drawLine(lastPoint.pos, event->posF());
break;
}
}
//! [5]
-//! [6]
-Qt::BrushStyle TabletCanvas::brushPattern(qreal value)
-{
- int pattern = int((value) * 100.0) % 7;
-
- switch (pattern) {
- case 0:
- return Qt::SolidPattern;
- case 1:
- return Qt::Dense1Pattern;
- case 2:
- return Qt::Dense2Pattern;
- case 3:
- return Qt::Dense3Pattern;
- case 4:
- return Qt::Dense4Pattern;
- case 5:
- return Qt::Dense5Pattern;
- case 6:
- return Qt::Dense6Pattern;
- default:
- return Qt::Dense7Pattern;
- }
-}
-//! [6]
-
//! [7]
void TabletCanvas::updateBrush(QTabletEvent *event)
{
@@ -220,7 +212,13 @@ void TabletCanvas::updateBrush(QTabletEvent *event)
switch (alphaChannelType) {
case AlphaPressure:
- myColor.setAlpha(int(event->pressure() * 255.0));
+ myColor.setAlphaF(event->pressure());
+ break;
+ case AlphaTangentialPressure:
+ if (event->device() == QTabletEvent::Airbrush)
+ myColor.setAlphaF(qMax(0.01, (event->tangentialPressure() + 1.0) / 2.0));
+ else
+ myColor.setAlpha(255);
break;
case AlphaTilt:
myColor.setAlpha(maximum(abs(vValue - 127), abs(hValue - 127)));
@@ -271,5 +269,4 @@ void TabletCanvas::updateBrush(QTabletEvent *event)
void TabletCanvas::resizeEvent(QResizeEvent *)
{
initPixmap();
- polyLine[0] = polyLine[1] = polyLine[2] = QPoint();
}
diff --git a/examples/widgets/widgets/tablet/tabletcanvas.h b/examples/widgets/widgets/tablet/tabletcanvas.h
index 873f3a7ab0..06090a9052 100644
--- a/examples/widgets/widgets/tablet/tabletcanvas.h
+++ b/examples/widgets/widgets/tablet/tabletcanvas.h
@@ -61,7 +61,7 @@ class TabletCanvas : public QWidget
Q_OBJECT
public:
- enum AlphaChannelType { AlphaPressure, AlphaTilt, NoAlpha };
+ enum AlphaChannelType { AlphaPressure, AlphaTangentialPressure, AlphaTilt, NoAlpha };
enum ColorSaturationType { SaturationVTilt, SaturationHTilt,
SaturationPressure, NoSaturation };
enum LineWidthType { LineWidthPressure, LineWidthTilt, NoLineWidth };
@@ -107,7 +107,11 @@ private:
QBrush myBrush;
QPen myPen;
bool deviceDown;
- QPoint polyLine[3];
+
+ struct Point {
+ QPointF pos;
+ qreal rotation;
+ } lastPoint;
};
//! [0]