pathstroke.cpp Example File
painting/pathstroke/pathstroke.cpp
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the demonstration applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "arthurstyle.h"
#include "arthurwidgets.h"
#include "pathstroke.h"
#include <stdio.h>
extern void draw_round_rect(QPainter * p, const QRect & bounds, int radius);
PathStrokeControls:: PathStrokeControls(QWidget * parent, PathStrokeRenderer* renderer, bool smallScreen)
: QWidget (parent)
{
m_renderer = renderer;
if (smallScreen)
layoutForSmallScreens();
else
layoutForDesktop();
}
void PathStrokeControls:: createCommonControls(QWidget * parent)
{
m_capGroup = new QGroupBox (parent);
m_capGroup- > setSizePolicy(QSizePolicy :: Minimum, QSizePolicy :: Fixed);
QRadioButton * flatCap = new QRadioButton (m_capGroup);
QRadioButton * squareCap = new QRadioButton (m_capGroup);
QRadioButton * roundCap = new QRadioButton (m_capGroup);
m_capGroup- > setTitle(tr("Cap Style" ));
flatCap- > setText(tr("Flat" ));
squareCap- > setText(tr("Square" ));
roundCap- > setText(tr("Round" ));
flatCap- > setSizePolicy(QSizePolicy :: Fixed, QSizePolicy :: Fixed);
squareCap- > setSizePolicy(QSizePolicy :: Fixed, QSizePolicy :: Fixed);
roundCap- > setSizePolicy(QSizePolicy :: Fixed, QSizePolicy :: Fixed);
m_joinGroup = new QGroupBox (parent);
m_joinGroup- > setSizePolicy(QSizePolicy :: Minimum, QSizePolicy :: Fixed);
QRadioButton * bevelJoin = new QRadioButton (m_joinGroup);
QRadioButton * miterJoin = new QRadioButton (m_joinGroup);
QRadioButton * svgMiterJoin = new QRadioButton (m_joinGroup);
QRadioButton * roundJoin = new QRadioButton (m_joinGroup);
m_joinGroup- > setTitle(tr("Join Style" ));
bevelJoin- > setText(tr("Bevel" ));
miterJoin- > setText(tr("Miter" ));
svgMiterJoin- > setText(tr("SvgMiter" ));
roundJoin- > setText(tr("Round" ));
m_styleGroup = new QGroupBox (parent);
m_styleGroup- > setSizePolicy(QSizePolicy :: Minimum, QSizePolicy :: Fixed);
QRadioButton * solidLine = new QRadioButton (m_styleGroup);
QRadioButton * dashLine = new QRadioButton (m_styleGroup);
QRadioButton * dotLine = new QRadioButton (m_styleGroup);
QRadioButton * dashDotLine = new QRadioButton (m_styleGroup);
QRadioButton * dashDotDotLine = new QRadioButton (m_styleGroup);
QRadioButton * customDashLine = new QRadioButton (m_styleGroup);
m_styleGroup- > setTitle(tr("Pen Style" ));
QPixmap line_solid(":res/images/line_solid.png" );
solidLine- > setIcon(line_solid);
solidLine- > setIconSize(line_solid. size());
QPixmap line_dashed(":res/images/line_dashed.png" );
dashLine- > setIcon(line_dashed);
dashLine- > setIconSize(line_dashed. size());
QPixmap line_dotted(":res/images/line_dotted.png" );
dotLine- > setIcon(line_dotted);
dotLine- > setIconSize(line_dotted. size());
QPixmap line_dash_dot(":res/images/line_dash_dot.png" );
dashDotLine- > setIcon(line_dash_dot);
dashDotLine- > setIconSize(line_dash_dot. size());
QPixmap line_dash_dot_dot(":res/images/line_dash_dot_dot.png" );
dashDotDotLine- > setIcon(line_dash_dot_dot);
dashDotDotLine- > setIconSize(line_dash_dot_dot. size());
customDashLine- > setText(tr("Custom" ));
int fixedHeight = bevelJoin- > sizeHint(). height();
solidLine- > setFixedHeight(fixedHeight);
dashLine- > setFixedHeight(fixedHeight);
dotLine- > setFixedHeight(fixedHeight);
dashDotLine- > setFixedHeight(fixedHeight);
dashDotDotLine- > setFixedHeight(fixedHeight);
m_pathModeGroup = new QGroupBox (parent);
m_pathModeGroup- > setSizePolicy(QSizePolicy :: Minimum, QSizePolicy :: Fixed);
QRadioButton * curveMode = new QRadioButton (m_pathModeGroup);
QRadioButton * lineMode = new QRadioButton (m_pathModeGroup);
m_pathModeGroup- > setTitle(tr("Line Style" ));
curveMode- > setText(tr("Curves" ));
lineMode- > setText(tr("Lines" ));
// Layouts
QVBoxLayout * capGroupLayout = new QVBoxLayout (m_capGroup);
capGroupLayout- > addWidget(flatCap);
capGroupLayout- > addWidget(squareCap);
capGroupLayout- > addWidget(roundCap);
QVBoxLayout * joinGroupLayout = new QVBoxLayout (m_joinGroup);
joinGroupLayout- > addWidget(bevelJoin);
joinGroupLayout- > addWidget(miterJoin);
joinGroupLayout- > addWidget(svgMiterJoin);
joinGroupLayout- > addWidget(roundJoin);
QVBoxLayout * styleGroupLayout = new QVBoxLayout (m_styleGroup);
styleGroupLayout- > addWidget(solidLine);
styleGroupLayout- > addWidget(dashLine);
styleGroupLayout- > addWidget(dotLine);
styleGroupLayout- > addWidget(dashDotLine);
styleGroupLayout- > addWidget(dashDotDotLine);
styleGroupLayout- > addWidget(customDashLine);
QVBoxLayout * pathModeGroupLayout = new QVBoxLayout (m_pathModeGroup);
pathModeGroupLayout- > addWidget(curveMode);
pathModeGroupLayout- > addWidget(lineMode);
// Connections
connect(flatCap, SIGNAL(clicked()), m_renderer, SLOT(setFlatCap()));
connect(squareCap, SIGNAL(clicked()), m_renderer, SLOT(setSquareCap()));
connect(roundCap, SIGNAL(clicked()), m_renderer, SLOT(setRoundCap()));
connect(bevelJoin, SIGNAL(clicked()), m_renderer, SLOT(setBevelJoin()));
connect(miterJoin, SIGNAL(clicked()), m_renderer, SLOT(setMiterJoin()));
connect(svgMiterJoin, SIGNAL(clicked()), m_renderer, SLOT(setSvgMiterJoin()));
connect(roundJoin, SIGNAL(clicked()), m_renderer, SLOT(setRoundJoin()));
connect(curveMode, SIGNAL(clicked()), m_renderer, SLOT(setCurveMode()));
connect(lineMode, SIGNAL(clicked()), m_renderer, SLOT(setLineMode()));
connect(solidLine, SIGNAL(clicked()), m_renderer, SLOT(setSolidLine()));
connect(dashLine, SIGNAL(clicked()), m_renderer, SLOT(setDashLine()));
connect(dotLine, SIGNAL(clicked()), m_renderer, SLOT(setDotLine()));
connect(dashDotLine, SIGNAL(clicked()), m_renderer, SLOT(setDashDotLine()));
connect(dashDotDotLine, SIGNAL(clicked()), m_renderer, SLOT(setDashDotDotLine()));
connect(customDashLine, SIGNAL(clicked()), m_renderer, SLOT(setCustomDashLine()));
// Set the defaults:
flatCap- > setChecked(true );
bevelJoin- > setChecked(true );
curveMode- > setChecked(true );
solidLine- > setChecked(true );
}
void PathStrokeControls:: layoutForDesktop()
{
QGroupBox * mainGroup = new QGroupBox (this );
mainGroup- > setFixedWidth(180 );
mainGroup- > setTitle(tr("Path Stroking" ));
createCommonControls(mainGroup);
QGroupBox * penWidthGroup = new QGroupBox (mainGroup);
QSlider * penWidth = new QSlider (Qt :: Horizontal, penWidthGroup);
penWidth- > setSizePolicy(QSizePolicy :: Preferred, QSizePolicy :: Fixed);
penWidthGroup- > setTitle(tr("Pen Width" ));
penWidth- > setRange(0 , 500 );
QPushButton * animated = new QPushButton (mainGroup);
animated- > setText(tr("Animate" ));
animated- > setCheckable(true );
QPushButton * showSourceButton = new QPushButton (mainGroup);
showSourceButton- > setText(tr("Show Source" ));
#if QT_CONFIG(opengl)
QPushButton * enableOpenGLButton = new QPushButton (mainGroup);
enableOpenGLButton- > setText(tr("Use OpenGL" ));
enableOpenGLButton- > setCheckable(true );
enableOpenGLButton- > setChecked(m_renderer- > usesOpenGL());
#endif
QPushButton * whatsThisButton = new QPushButton (mainGroup);
whatsThisButton- > setText(tr("What's This?" ));
whatsThisButton- > setCheckable(true );
// Layouts:
QVBoxLayout * penWidthLayout = new QVBoxLayout (penWidthGroup);
penWidthLayout- > addWidget(penWidth);
QVBoxLayout * mainLayout = new QVBoxLayout (this );
mainLayout- > setMargin(0 );
mainLayout- > addWidget(mainGroup);
QVBoxLayout * mainGroupLayout = new QVBoxLayout (mainGroup);
mainGroupLayout- > setMargin(3 );
mainGroupLayout- > addWidget(m_capGroup);
mainGroupLayout- > addWidget(m_joinGroup);
mainGroupLayout- > addWidget(m_styleGroup);
mainGroupLayout- > addWidget(penWidthGroup);
mainGroupLayout- > addWidget(m_pathModeGroup);
mainGroupLayout- > addWidget(animated);
mainGroupLayout- > addStretch(1 );
mainGroupLayout- > addWidget(showSourceButton);
#if QT_CONFIG(opengl)
mainGroupLayout- > addWidget(enableOpenGLButton);
#endif
mainGroupLayout- > addWidget(whatsThisButton);
// Set up connections
connect(animated, SIGNAL(toggled(bool)), m_renderer, SLOT(setAnimation(bool)));
connect(penWidth, SIGNAL(valueChanged(int )), m_renderer, SLOT(setPenWidth(int )));
connect(showSourceButton, SIGNAL(clicked()), m_renderer, SLOT(showSource()));
#if QT_CONFIG(opengl)
connect(enableOpenGLButton, SIGNAL(clicked(bool)), m_renderer, SLOT(enableOpenGL(bool)));
#endif
connect(whatsThisButton, SIGNAL(clicked(bool)), m_renderer, SLOT(setDescriptionEnabled(bool)));
connect(m_renderer, SIGNAL(descriptionEnabledChanged(bool)),
whatsThisButton, SLOT(setChecked(bool)));
// Set the defaults
animated- > setChecked(true );
penWidth- > setValue(50 );
}
void PathStrokeControls:: layoutForSmallScreens()
{
createCommonControls(this );
m_capGroup- > layout()- > setMargin(0 );
m_joinGroup- > layout()- > setMargin(0 );
m_styleGroup- > layout()- > setMargin(0 );
m_pathModeGroup- > layout()- > setMargin(0 );
QPushButton * okBtn = new QPushButton (tr("OK" ), this );
okBtn- > setSizePolicy(QSizePolicy :: Fixed, QSizePolicy :: Fixed);
okBtn- > setMinimumSize(100 , okBtn- > minimumSize(). height());
QPushButton * quitBtn = new QPushButton (tr("Quit" ), this );
quitBtn- > setSizePolicy(QSizePolicy :: Fixed, QSizePolicy :: Fixed);
quitBtn- > setMinimumSize(100 , okBtn- > minimumSize(). height());
QLabel * penWidthLabel = new QLabel (tr(" Width:" ));
QSlider * penWidth = new QSlider (Qt :: Horizontal, this );
penWidth- > setSizePolicy(QSizePolicy :: Preferred, QSizePolicy :: Fixed);
penWidth- > setRange(0 , 500 );
#if QT_CONFIG(opengl)
QPushButton * enableOpenGLButton = new QPushButton (this );
enableOpenGLButton- > setText(tr("Use OpenGL" ));
enableOpenGLButton- > setCheckable(true );
enableOpenGLButton- > setChecked(m_renderer- > usesOpenGL());
#endif
// Layouts:
QHBoxLayout * penWidthLayout = new QHBoxLayout (0 );
penWidthLayout- > addWidget(penWidthLabel, 0 , Qt :: AlignRight);
penWidthLayout- > addWidget(penWidth);
QVBoxLayout * leftLayout = new QVBoxLayout (0 );
leftLayout- > addWidget(m_capGroup);
leftLayout- > addWidget(m_joinGroup);
#if QT_CONFIG(opengl)
leftLayout- > addWidget(enableOpenGLButton);
#endif
leftLayout- > addLayout(penWidthLayout);
QVBoxLayout * rightLayout = new QVBoxLayout (0 );
rightLayout- > addWidget(m_styleGroup);
rightLayout- > addWidget(m_pathModeGroup);
QGridLayout * mainLayout = new QGridLayout (this );
mainLayout- > setMargin(0 );
// Add spacers around the form items so we don't look stupid at higher resolutions
mainLayout- > addItem(new QSpacerItem (0 , 0 ), 0 , 0 , 1 , 4 );
mainLayout- > addItem(new QSpacerItem (0 , 0 ), 1 , 0 , 2 , 1 );
mainLayout- > addItem(new QSpacerItem (0 , 0 ), 1 , 3 , 2 , 1 );
mainLayout- > addItem(new QSpacerItem (0 , 0 ), 3 , 0 , 1 , 4 );
mainLayout- > addLayout(leftLayout, 1 , 1 );
mainLayout- > addLayout(rightLayout, 1 , 2 );
mainLayout- > addWidget(quitBtn, 2 , 1 , Qt :: AlignHCenter | Qt :: AlignTop);
mainLayout- > addWidget(okBtn, 2 , 2 , Qt :: AlignHCenter | Qt :: AlignTop);
#if QT_CONFIG(opengl)
connect(enableOpenGLButton, SIGNAL(clicked(bool)), m_renderer, SLOT(enableOpenGL(bool)));
#endif
connect(penWidth, SIGNAL(valueChanged(int )), m_renderer, SLOT(setPenWidth(int )));
connect(quitBtn, SIGNAL(clicked()), this , SLOT(emitQuitSignal()));
connect(okBtn, SIGNAL(clicked()), this , SLOT(emitOkSignal()));
m_renderer- > setAnimation(true );
penWidth- > setValue(50 );
}
void PathStrokeControls:: emitQuitSignal()
{
emit quitPressed();
}
void PathStrokeControls:: emitOkSignal()
{
emit okPressed();
}
PathStrokeWidget:: PathStrokeWidget(bool smallScreen)
{
setWindowTitle(tr("Path Stroking" ));
// Widget construction and property setting
m_renderer = new PathStrokeRenderer(this , smallScreen);
m_controls = new PathStrokeControls(0 , m_renderer, smallScreen);
// Layouting
QHBoxLayout * viewLayout = new QHBoxLayout (this );
viewLayout- > addWidget(m_renderer);
if (! smallScreen)
viewLayout- > addWidget(m_controls);
m_renderer- > loadSourceFile(":res/pathstroke/pathstroke.cpp" );
m_renderer- > loadDescription(":res/pathstroke/pathstroke.html" );
connect(m_renderer, SIGNAL(clicked()), this , SLOT(showControls()));
connect(m_controls, SIGNAL(okPressed()), this , SLOT(hideControls()));
connect(m_controls, SIGNAL(quitPressed()), QApplication :: instance(), SLOT(quit()));
}
void PathStrokeWidget:: showControls()
{
m_controls- > showFullScreen();
}
void PathStrokeWidget:: hideControls()
{
m_controls- > hide();
}
void PathStrokeWidget:: setStyle( QStyle * style )
{
QWidget :: setStyle(style);
if (m_controls ! = 0 )
{
m_controls- > setStyle(style);
QList < QWidget * > widgets = m_controls- > findChildren< QWidget * > ();
foreach (QWidget * w, widgets)
w- > setStyle(style);
}
}
PathStrokeRenderer:: PathStrokeRenderer(QWidget * parent, bool smallScreen)
: ArthurFrame(parent)
{
m_smallScreen = smallScreen;
m_pointSize = 10 ;
m_activePoint = - 1 ;
m_capStyle = Qt :: FlatCap;
m_joinStyle = Qt :: BevelJoin;
m_pathMode = CurveMode;
m_penWidth = 1 ;
m_penStyle = Qt :: SolidLine;
m_wasAnimated = true ;
setSizePolicy(QSizePolicy :: Expanding, QSizePolicy :: Expanding);
setAttribute(Qt :: WA_AcceptTouchEvents);
}
void PathStrokeRenderer:: paint(QPainter * painter)
{
if (m_points. isEmpty())
initializePoints();
painter- > setRenderHint(QPainter :: Antialiasing);
QPalette pal = palette();
painter- > setPen(Qt :: NoPen);
// Construct the path
QPainterPath path;
path. moveTo(m_points. at(0 ));
if (m_pathMode = = LineMode) {
for (int i= 1 ; i< m_points. size(); + + i)
path. lineTo(m_points. at(i));
} else {
int i= 1 ;
while (i + 2 < m_points. size()) {
path. cubicTo(m_points. at(i), m_points. at(i+ 1 ), m_points. at(i+ 2 ));
i + = 3 ;
}
while (i < m_points. size()) {
path. lineTo(m_points. at(i));
+ + i;
}
}
// Draw the path
{
QColor lg = Qt :: red;
// The "custom" pen
if (m_penStyle = = Qt :: NoPen) {
QPainterPathStroker stroker;
stroker. setWidth(m_penWidth);
stroker. setJoinStyle(m_joinStyle);
stroker. setCapStyle(m_capStyle);
QVector < qreal > dashes;
qreal space = 4 ;
dashes < < 1 < < space
< < 3 < < space
< < 9 < < space
< < 27 < < space
< < 9 < < space
< < 3 < < space;
stroker. setDashPattern(dashes);
QPainterPath stroke = stroker. createStroke(path);
painter- > fillPath(stroke, lg);
} else {
QPen pen(lg, m_penWidth, m_penStyle, m_capStyle, m_joinStyle);
painter- > strokePath(path, pen);
}
}
if (1 ) {
// Draw the control points
painter- > setPen(QColor (50 , 100 , 120 , 200 ));
painter- > setBrush(QColor (200 , 200 , 210 , 120 ));
for (int i= 0 ; i< m_points. size(); + + i) {
QPointF pos = m_points. at(i);
painter- > drawEllipse(QRectF (pos. x() - m_pointSize,
pos. y() - m_pointSize,
m_pointSize* 2 , m_pointSize* 2 ));
}
painter- > setPen(QPen (Qt :: lightGray, 0 , Qt :: SolidLine));
painter- > setBrush(Qt :: NoBrush);
painter- > drawPolyline(m_points);
}
}
void PathStrokeRenderer:: initializePoints()
{
const int count = 7 ;
m_points. clear();
m_vectors. clear();
QMatrix m;
qreal rot = 360.0 / count;
QPointF center(width() / 2 , height() / 2 );
QMatrix vm;
vm. shear(2 , - 1 );
vm. scale(3 , 3 );
for (int i= 0 ; i< count; + + i) {
m_vectors < < QPointF (. 1f , . 25f ) * (m * vm);
m_points < < QPointF (0 , 100 ) * m + center;
m. rotate(rot);
}
}
void PathStrokeRenderer:: updatePoints()
{
qreal pad = 10 ;
qreal left = pad;
qreal right = width() - pad;
qreal top = pad;
qreal bottom = height() - pad;
Q_ASSERT(m_points. size() = = m_vectors. size());
for (int i= 0 ; i< m_points. size(); + + i) {
QPointF pos = m_points. at(i);
QPointF vec = m_vectors. at(i);
pos + = vec;
if (pos. x() < left | | pos. x() > right) {
vec. setX(- vec. x());
pos. setX(pos. x() < left ? left : right);
} if (pos. y() < top | | pos. y() > bottom) {
vec. setY(- vec. y());
pos. setY(pos. y() < top ? top : bottom);
}
m_points[ i] = pos;
m_vectors[ i] = vec;
}
update();
}
void PathStrokeRenderer:: mousePressEvent(QMouseEvent * e)
{
if (! m_fingerPointMapping. isEmpty())
return ;
setDescriptionEnabled(false );
m_activePoint = - 1 ;
qreal distance = - 1 ;
for (int i= 0 ; i< m_points. size(); + + i) {
qreal d = QLineF (e- > pos(), m_points. at(i)). length();
if ((distance < 0 & & d < 8 * m_pointSize) | | d < distance) {
distance = d;
m_activePoint = i;
}
}
if (m_activePoint ! = - 1 ) {
m_wasAnimated = m_timer. isActive();
setAnimation(false );
mouseMoveEvent(e);
}
// If we're not running in small screen mode, always assume we're dragging
m_mouseDrag = ! m_smallScreen;
m_mousePress = e- > pos();
}
void PathStrokeRenderer:: mouseMoveEvent(QMouseEvent * e)
{
if (! m_fingerPointMapping. isEmpty())
return ;
// If we've moved more then 25 pixels, assume user is dragging
if (! m_mouseDrag & & QPoint (m_mousePress - e- > pos()). manhattanLength() > 25 )
m_mouseDrag = true ;
if (m_mouseDrag & & m_activePoint > = 0 & & m_activePoint < m_points. size()) {
m_points[ m_activePoint] = e- > pos();
update();
}
}
void PathStrokeRenderer:: mouseReleaseEvent(QMouseEvent * )
{
if (! m_fingerPointMapping. isEmpty())
return ;
m_activePoint = - 1 ;
setAnimation(m_wasAnimated);
if (! m_mouseDrag & & m_smallScreen)
emit clicked();
}
void PathStrokeRenderer:: timerEvent(QTimerEvent * e)
{
if (e- > timerId() = = m_timer. timerId()) {
updatePoints();
} // else if (e->timerId() == m_fpsTimer.timerId()) {
// emit frameRate(m_frameCount);
// m_frameCount = 0;
// }
}
bool PathStrokeRenderer:: event(QEvent * e)
{
bool touchBegin = false ;
switch (e- > type()) {
case QEvent :: TouchBegin:
touchBegin = true ;
Q_FALLTHROUGH();
case QEvent :: TouchUpdate:
{
const QTouchEvent * const event = static_cast < const QTouchEvent * > (e);
const QList < QTouchEvent :: TouchPoint> points = event- > touchPoints();
foreach (const QTouchEvent :: TouchPoint & touchPoint, points) {
const int id = touchPoint. id();
switch (touchPoint. state()) {
case Qt :: TouchPointPressed:
{
// find the point, move it
QSet < int > activePoints = QSet < int > :: fromList(m_fingerPointMapping. values());
int activePoint = - 1 ;
qreal distance = - 1 ;
const int pointsCount = m_points. size();
for (int i= 0 ; i< pointsCount; + + i) {
if (activePoints. contains(i))
continue ;
qreal d = QLineF (touchPoint. pos(), m_points. at(i)). length();
if ((distance < 0 & & d < 12 * m_pointSize) | | d < distance) {
distance = d;
activePoint = i;
}
}
if (activePoint ! = - 1 ) {
m_fingerPointMapping. insert(touchPoint. id(), activePoint);
m_points[ activePoint] = touchPoint. pos();
}
break ;
}
case Qt :: TouchPointReleased:
{
// move the point and release
QHash < int , int > :: iterator it = m_fingerPointMapping. find(id);
m_points[ it. value()] = touchPoint. pos();
m_fingerPointMapping. erase(it);
break ;
}
case Qt :: TouchPointMoved:
{
// move the point
const int pointIdx = m_fingerPointMapping. value(id, - 1 );
if (pointIdx > = 0 )
m_points[ pointIdx] = touchPoint. pos();
break ;
}
default :
break ;
}
}
if (m_fingerPointMapping. isEmpty()) {
e- > ignore();
return false ;
} else {
if (touchBegin) {
m_wasAnimated = m_timer. isActive();
setAnimation(false );
}
update();
return true ;
}
}
break ;
case QEvent :: TouchEnd:
if (m_fingerPointMapping. isEmpty()) {
e- > ignore();
return false ;
}
m_fingerPointMapping. clear();
setAnimation(m_wasAnimated);
return true ;
break ;
default :
break ;
}
return QWidget :: event(e);
}
void PathStrokeRenderer:: setAnimation(bool animation)
{
m_timer. stop();
// m_fpsTimer.stop();
if (animation) {
m_timer. start(25 , this );
// m_fpsTimer.start(1000, this);
// m_frameCount = 0;
}
}