demos/pathstroke/pathstroke.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the demonstration applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "pathstroke.h"
       
    43 #include "arthurstyle.h"
       
    44 #include "arthurwidgets.h"
       
    45 
       
    46 #include <stdio.h>
       
    47 
       
    48 extern void draw_round_rect(QPainter *p, const QRect &bounds, int radius);
       
    49 
       
    50 
       
    51 PathStrokeControls::PathStrokeControls(QWidget* parent, PathStrokeRenderer* renderer, bool smallScreen)
       
    52       : QWidget(parent)
       
    53 {
       
    54     m_renderer = renderer;
       
    55 
       
    56     if (smallScreen)
       
    57         layoutForSmallScreens();
       
    58     else
       
    59         layoutForDesktop();
       
    60 }
       
    61 
       
    62 void PathStrokeControls::createCommonControls(QWidget* parent)
       
    63 {
       
    64     m_capGroup = new QGroupBox(parent);
       
    65     m_capGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
       
    66     QRadioButton *flatCap = new QRadioButton(m_capGroup);
       
    67     QRadioButton *squareCap = new QRadioButton(m_capGroup);
       
    68     QRadioButton *roundCap = new QRadioButton(m_capGroup);
       
    69     m_capGroup->setTitle(tr("Cap Style"));
       
    70     flatCap->setText(tr("Flat"));
       
    71     squareCap->setText(tr("Square"));
       
    72     roundCap->setText(tr("Round"));
       
    73     flatCap->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
       
    74     squareCap->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
       
    75     roundCap->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
       
    76 
       
    77     m_joinGroup = new QGroupBox(parent);
       
    78     m_joinGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
       
    79     QRadioButton *bevelJoin = new QRadioButton(m_joinGroup);
       
    80     QRadioButton *miterJoin = new QRadioButton(m_joinGroup);
       
    81     QRadioButton *roundJoin = new QRadioButton(m_joinGroup);
       
    82     m_joinGroup->setTitle(tr("Join Style"));
       
    83     bevelJoin->setText(tr("Bevel"));
       
    84     miterJoin->setText(tr("Miter"));
       
    85     roundJoin->setText(tr("Round"));
       
    86 
       
    87     m_styleGroup = new QGroupBox(parent);
       
    88     m_styleGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
       
    89     QRadioButton *solidLine = new QRadioButton(m_styleGroup);
       
    90     QRadioButton *dashLine = new QRadioButton(m_styleGroup);
       
    91     QRadioButton *dotLine = new QRadioButton(m_styleGroup);
       
    92     QRadioButton *dashDotLine = new QRadioButton(m_styleGroup);
       
    93     QRadioButton *dashDotDotLine = new QRadioButton(m_styleGroup);
       
    94     QRadioButton *customDashLine = new QRadioButton(m_styleGroup);
       
    95     m_styleGroup->setTitle(tr("Pen Style"));
       
    96 
       
    97     QPixmap line_solid(":res/images/line_solid.png");
       
    98     solidLine->setIcon(line_solid);
       
    99     solidLine->setIconSize(line_solid.size());
       
   100     QPixmap line_dashed(":res/images/line_dashed.png");
       
   101     dashLine->setIcon(line_dashed);
       
   102     dashLine->setIconSize(line_dashed.size());
       
   103     QPixmap line_dotted(":res/images/line_dotted.png");
       
   104     dotLine->setIcon(line_dotted);
       
   105     dotLine->setIconSize(line_dotted.size());
       
   106     QPixmap line_dash_dot(":res/images/line_dash_dot.png");
       
   107     dashDotLine->setIcon(line_dash_dot);
       
   108     dashDotLine->setIconSize(line_dash_dot.size());
       
   109     QPixmap line_dash_dot_dot(":res/images/line_dash_dot_dot.png");
       
   110     dashDotDotLine->setIcon(line_dash_dot_dot);
       
   111     dashDotDotLine->setIconSize(line_dash_dot_dot.size());
       
   112     customDashLine->setText(tr("Custom"));
       
   113 
       
   114     int fixedHeight = bevelJoin->sizeHint().height();
       
   115     solidLine->setFixedHeight(fixedHeight);
       
   116     dashLine->setFixedHeight(fixedHeight);
       
   117     dotLine->setFixedHeight(fixedHeight);
       
   118     dashDotLine->setFixedHeight(fixedHeight);
       
   119     dashDotDotLine->setFixedHeight(fixedHeight);
       
   120 
       
   121     m_pathModeGroup = new QGroupBox(parent);
       
   122     m_pathModeGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
       
   123     QRadioButton *curveMode = new QRadioButton(m_pathModeGroup);
       
   124     QRadioButton *lineMode = new QRadioButton(m_pathModeGroup);
       
   125     m_pathModeGroup->setTitle(tr("Line Style"));
       
   126     curveMode->setText(tr("Curves"));
       
   127     lineMode->setText(tr("Lines"));
       
   128 
       
   129 
       
   130     // Layouts
       
   131     QVBoxLayout *capGroupLayout = new QVBoxLayout(m_capGroup);
       
   132     capGroupLayout->addWidget(flatCap);
       
   133     capGroupLayout->addWidget(squareCap);
       
   134     capGroupLayout->addWidget(roundCap);
       
   135 
       
   136     QVBoxLayout *joinGroupLayout = new QVBoxLayout(m_joinGroup);
       
   137     joinGroupLayout->addWidget(bevelJoin);
       
   138     joinGroupLayout->addWidget(miterJoin);
       
   139     joinGroupLayout->addWidget(roundJoin);
       
   140 
       
   141     QVBoxLayout *styleGroupLayout = new QVBoxLayout(m_styleGroup);
       
   142     styleGroupLayout->addWidget(solidLine);
       
   143     styleGroupLayout->addWidget(dashLine);
       
   144     styleGroupLayout->addWidget(dotLine);
       
   145     styleGroupLayout->addWidget(dashDotLine);
       
   146     styleGroupLayout->addWidget(dashDotDotLine);
       
   147     styleGroupLayout->addWidget(customDashLine);
       
   148 
       
   149     QVBoxLayout *pathModeGroupLayout = new QVBoxLayout(m_pathModeGroup);
       
   150     pathModeGroupLayout->addWidget(curveMode);
       
   151     pathModeGroupLayout->addWidget(lineMode);
       
   152 
       
   153 
       
   154     // Connections
       
   155     connect(flatCap, SIGNAL(clicked()), m_renderer, SLOT(setFlatCap()));
       
   156     connect(squareCap, SIGNAL(clicked()), m_renderer, SLOT(setSquareCap()));
       
   157     connect(roundCap, SIGNAL(clicked()), m_renderer, SLOT(setRoundCap()));
       
   158 
       
   159     connect(bevelJoin, SIGNAL(clicked()), m_renderer, SLOT(setBevelJoin()));
       
   160     connect(miterJoin, SIGNAL(clicked()), m_renderer, SLOT(setMiterJoin()));
       
   161     connect(roundJoin, SIGNAL(clicked()), m_renderer, SLOT(setRoundJoin()));
       
   162 
       
   163     connect(curveMode, SIGNAL(clicked()), m_renderer, SLOT(setCurveMode()));
       
   164     connect(lineMode, SIGNAL(clicked()), m_renderer, SLOT(setLineMode()));
       
   165 
       
   166     connect(solidLine, SIGNAL(clicked()), m_renderer, SLOT(setSolidLine()));
       
   167     connect(dashLine, SIGNAL(clicked()), m_renderer, SLOT(setDashLine()));
       
   168     connect(dotLine, SIGNAL(clicked()), m_renderer, SLOT(setDotLine()));
       
   169     connect(dashDotLine, SIGNAL(clicked()), m_renderer, SLOT(setDashDotLine()));
       
   170     connect(dashDotDotLine, SIGNAL(clicked()), m_renderer, SLOT(setDashDotDotLine()));
       
   171     connect(customDashLine, SIGNAL(clicked()), m_renderer, SLOT(setCustomDashLine()));
       
   172 
       
   173     // Set the defaults:
       
   174     flatCap->setChecked(true);
       
   175     bevelJoin->setChecked(true);
       
   176     curveMode->setChecked(true);
       
   177     solidLine->setChecked(true);
       
   178 }
       
   179 
       
   180 
       
   181 void PathStrokeControls::layoutForDesktop()
       
   182 {
       
   183     QGroupBox *mainGroup = new QGroupBox(this);
       
   184     mainGroup->setFixedWidth(180);
       
   185     mainGroup->setTitle(tr("Path Stroking"));
       
   186 
       
   187     createCommonControls(mainGroup);
       
   188 
       
   189     QGroupBox* penWidthGroup = new QGroupBox(mainGroup);
       
   190     QSlider *penWidth = new QSlider(Qt::Horizontal, penWidthGroup);
       
   191     penWidth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
       
   192     penWidthGroup->setTitle(tr("Pen Width"));
       
   193     penWidth->setRange(0, 500);
       
   194 
       
   195     QPushButton *animated = new QPushButton(mainGroup);
       
   196     animated->setText(tr("Animate"));
       
   197     animated->setCheckable(true);
       
   198 
       
   199     QPushButton *showSourceButton = new QPushButton(mainGroup);
       
   200     showSourceButton->setText(tr("Show Source"));
       
   201 #ifdef QT_OPENGL_SUPPORT
       
   202     QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
       
   203     enableOpenGLButton->setText(tr("Use OpenGL"));
       
   204     enableOpenGLButton->setCheckable(true);
       
   205     enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
       
   206     if (!QGLFormat::hasOpenGL())
       
   207         enableOpenGLButton->hide();
       
   208 #endif
       
   209     QPushButton *whatsThisButton = new QPushButton(mainGroup);
       
   210     whatsThisButton->setText(tr("What's This?"));
       
   211     whatsThisButton->setCheckable(true);
       
   212 
       
   213 
       
   214     // Layouts:
       
   215     QVBoxLayout *penWidthLayout = new QVBoxLayout(penWidthGroup);
       
   216     penWidthLayout->addWidget(penWidth);
       
   217 
       
   218     QVBoxLayout * mainLayout = new QVBoxLayout(this);
       
   219     mainLayout->setMargin(0);
       
   220     mainLayout->addWidget(mainGroup);
       
   221 
       
   222     QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
       
   223     mainGroupLayout->setMargin(3);
       
   224     mainGroupLayout->addWidget(m_capGroup);
       
   225     mainGroupLayout->addWidget(m_joinGroup);
       
   226     mainGroupLayout->addWidget(m_styleGroup);
       
   227     mainGroupLayout->addWidget(penWidthGroup);
       
   228     mainGroupLayout->addWidget(m_pathModeGroup);
       
   229     mainGroupLayout->addWidget(animated);
       
   230     mainGroupLayout->addStretch(1);
       
   231     mainGroupLayout->addWidget(showSourceButton);
       
   232 #ifdef QT_OPENGL_SUPPORT
       
   233     mainGroupLayout->addWidget(enableOpenGLButton);
       
   234 #endif
       
   235     mainGroupLayout->addWidget(whatsThisButton);
       
   236 
       
   237 
       
   238     // Set up connections
       
   239     connect(animated, SIGNAL(toggled(bool)),
       
   240             m_renderer, SLOT(setAnimation(bool)));
       
   241 
       
   242     connect(penWidth, SIGNAL(valueChanged(int)),
       
   243             m_renderer, SLOT(setPenWidth(int)));
       
   244 
       
   245     connect(showSourceButton, SIGNAL(clicked()), m_renderer, SLOT(showSource()));
       
   246 #ifdef QT_OPENGL_SUPPORT
       
   247     connect(enableOpenGLButton, SIGNAL(clicked(bool)), m_renderer, SLOT(enableOpenGL(bool)));
       
   248 #endif
       
   249     connect(whatsThisButton, SIGNAL(clicked(bool)), m_renderer, SLOT(setDescriptionEnabled(bool)));
       
   250     connect(m_renderer, SIGNAL(descriptionEnabledChanged(bool)),
       
   251             whatsThisButton, SLOT(setChecked(bool)));
       
   252 
       
   253 
       
   254     // Set the defaults
       
   255     animated->setChecked(true);
       
   256     penWidth->setValue(50);
       
   257 
       
   258 }
       
   259 
       
   260 void PathStrokeControls::layoutForSmallScreens()
       
   261 {
       
   262     createCommonControls(this);
       
   263 
       
   264     m_capGroup->layout()->setMargin(0);
       
   265     m_joinGroup->layout()->setMargin(0);
       
   266     m_styleGroup->layout()->setMargin(0);
       
   267     m_pathModeGroup->layout()->setMargin(0);
       
   268 
       
   269     QPushButton* okBtn = new QPushButton(tr("OK"), this);
       
   270     okBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
       
   271     okBtn->setMinimumSize(100,okBtn->minimumSize().height());
       
   272 
       
   273     QPushButton* quitBtn = new QPushButton(tr("Quit"), this);
       
   274     quitBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
       
   275     quitBtn->setMinimumSize(100, okBtn->minimumSize().height());
       
   276 
       
   277     QLabel *penWidthLabel = new QLabel(tr(" Width:"));
       
   278     QSlider *penWidth = new QSlider(Qt::Horizontal, this);
       
   279     penWidth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
       
   280     penWidth->setRange(0, 500);
       
   281 
       
   282 #ifdef QT_OPENGL_SUPPORT
       
   283     QPushButton *enableOpenGLButton = new QPushButton(this);
       
   284     enableOpenGLButton->setText(tr("Use OpenGL"));
       
   285     enableOpenGLButton->setCheckable(true);
       
   286     enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
       
   287     if (!QGLFormat::hasOpenGL())
       
   288         enableOpenGLButton->hide();
       
   289 #endif
       
   290 
       
   291     // Layouts:
       
   292     QHBoxLayout *penWidthLayout = new QHBoxLayout(0);
       
   293     penWidthLayout->addWidget(penWidthLabel, 0, Qt::AlignRight);
       
   294     penWidthLayout->addWidget(penWidth);
       
   295 
       
   296     QVBoxLayout *leftLayout = new QVBoxLayout(0);
       
   297     leftLayout->addWidget(m_capGroup);
       
   298     leftLayout->addWidget(m_joinGroup);
       
   299 #ifdef QT_OPENGL_SUPPORT
       
   300     leftLayout->addWidget(enableOpenGLButton);
       
   301 #endif
       
   302     leftLayout->addLayout(penWidthLayout);
       
   303 
       
   304     QVBoxLayout *rightLayout = new QVBoxLayout(0);
       
   305     rightLayout->addWidget(m_styleGroup);
       
   306     rightLayout->addWidget(m_pathModeGroup);
       
   307 
       
   308     QGridLayout *mainLayout = new QGridLayout(this);
       
   309     mainLayout->setMargin(0);
       
   310 
       
   311     // Add spacers around the form items so we don't look stupid at higher resolutions
       
   312     mainLayout->addItem(new QSpacerItem(0,0), 0, 0, 1, 4);
       
   313     mainLayout->addItem(new QSpacerItem(0,0), 1, 0, 2, 1);
       
   314     mainLayout->addItem(new QSpacerItem(0,0), 1, 3, 2, 1);
       
   315     mainLayout->addItem(new QSpacerItem(0,0), 3, 0, 1, 4);
       
   316 
       
   317     mainLayout->addLayout(leftLayout, 1, 1);
       
   318     mainLayout->addLayout(rightLayout, 1, 2);
       
   319     mainLayout->addWidget(quitBtn, 2, 1, Qt::AlignHCenter | Qt::AlignTop);
       
   320     mainLayout->addWidget(okBtn, 2, 2, Qt::AlignHCenter | Qt::AlignTop);
       
   321 
       
   322 #ifdef QT_OPENGL_SUPPORT
       
   323     connect(enableOpenGLButton, SIGNAL(clicked(bool)), m_renderer, SLOT(enableOpenGL(bool)));
       
   324 #endif
       
   325 
       
   326     connect(penWidth, SIGNAL(valueChanged(int)), m_renderer, SLOT(setPenWidth(int)));
       
   327     connect(quitBtn, SIGNAL(clicked()), this, SLOT(emitQuitSignal()));
       
   328     connect(okBtn, SIGNAL(clicked()), this, SLOT(emitOkSignal()));
       
   329 
       
   330     m_renderer->setAnimation(true);
       
   331     penWidth->setValue(50);
       
   332 }
       
   333 
       
   334 void PathStrokeControls::emitQuitSignal()
       
   335 {   emit quitPressed();  }
       
   336 
       
   337 void PathStrokeControls::emitOkSignal()
       
   338 {   emit okPressed();   }
       
   339 
       
   340 
       
   341 PathStrokeWidget::PathStrokeWidget(bool smallScreen)
       
   342 {
       
   343     setWindowTitle(tr("Path Stroking"));
       
   344 
       
   345     // Widget construction and property setting
       
   346     m_renderer = new PathStrokeRenderer(this, smallScreen);
       
   347 
       
   348     m_controls = new PathStrokeControls(0, m_renderer, smallScreen);
       
   349 
       
   350     // Layouting
       
   351     QHBoxLayout *viewLayout = new QHBoxLayout(this);
       
   352     viewLayout->addWidget(m_renderer);
       
   353 
       
   354     if (!smallScreen)
       
   355         viewLayout->addWidget(m_controls);
       
   356 
       
   357     m_renderer->loadSourceFile(":res/pathstroke/pathstroke.cpp");
       
   358     m_renderer->loadDescription(":res/pathstroke/pathstroke.html");
       
   359 
       
   360     connect(m_renderer, SIGNAL(clicked()), this, SLOT(showControls()));
       
   361     connect(m_controls, SIGNAL(okPressed()), this, SLOT(hideControls()));
       
   362     connect(m_controls, SIGNAL(quitPressed()), QApplication::instance(), SLOT(quit()));
       
   363 }
       
   364 
       
   365 
       
   366 void PathStrokeWidget::showControls()
       
   367 {
       
   368     m_controls->showFullScreen();
       
   369 }
       
   370 
       
   371 
       
   372 void PathStrokeWidget::hideControls()
       
   373 {
       
   374     m_controls->hide();
       
   375 }
       
   376 
       
   377 
       
   378 void PathStrokeWidget::setStyle( QStyle * style )
       
   379 {
       
   380     QWidget::setStyle(style);
       
   381     if (m_controls != 0)
       
   382     {
       
   383         m_controls->setStyle(style);
       
   384         
       
   385         QList<QWidget *> widgets = qFindChildren<QWidget *>(m_controls);
       
   386         foreach (QWidget *w, widgets)
       
   387             w->setStyle(style);
       
   388     }
       
   389 }
       
   390 
       
   391 
       
   392 PathStrokeRenderer::PathStrokeRenderer(QWidget *parent, bool smallScreen)
       
   393     : ArthurFrame(parent)
       
   394 {
       
   395     m_smallScreen = smallScreen;
       
   396     m_pointSize = 10;
       
   397     m_activePoint = -1;
       
   398     m_capStyle = Qt::FlatCap;
       
   399     m_joinStyle = Qt::BevelJoin;
       
   400     m_pathMode = CurveMode;
       
   401     m_penWidth = 1;
       
   402     m_penStyle = Qt::SolidLine;
       
   403     m_wasAnimated = true;
       
   404     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
       
   405     setAttribute(Qt::WA_AcceptTouchEvents);
       
   406 }
       
   407 
       
   408 void PathStrokeRenderer::paint(QPainter *painter)
       
   409 {
       
   410     if (m_points.isEmpty())
       
   411         initializePoints();
       
   412 
       
   413     painter->setRenderHint(QPainter::Antialiasing);
       
   414 
       
   415     QPalette pal = palette();
       
   416     painter->setPen(Qt::NoPen);
       
   417 
       
   418     // Construct the path
       
   419     QPainterPath path;
       
   420     path.moveTo(m_points.at(0));
       
   421 
       
   422     if (m_pathMode == LineMode) {
       
   423         for (int i=1; i<m_points.size(); ++i) {
       
   424             path.lineTo(m_points.at(i));
       
   425         }
       
   426     } else {
       
   427         int i=1;
       
   428         while (i + 2 < m_points.size()) {
       
   429             path.cubicTo(m_points.at(i), m_points.at(i+1), m_points.at(i+2));
       
   430             i += 3;
       
   431         }
       
   432         while (i < m_points.size()) {
       
   433             path.lineTo(m_points.at(i));
       
   434             ++i;
       
   435         }
       
   436     }
       
   437 
       
   438     // Draw the path
       
   439     {
       
   440         QColor lg = Qt::red;
       
   441 
       
   442         // The "custom" pen
       
   443         if (m_penStyle == Qt::NoPen) {
       
   444             QPainterPathStroker stroker;
       
   445             stroker.setWidth(m_penWidth);
       
   446             stroker.setJoinStyle(m_joinStyle);
       
   447             stroker.setCapStyle(m_capStyle);
       
   448 
       
   449             QVector<qreal> dashes;
       
   450             qreal space = 4;
       
   451             dashes << 1 << space
       
   452                    << 3 << space
       
   453                    << 9 << space
       
   454                    << 27 << space
       
   455                    << 9 << space
       
   456                    << 3 << space;
       
   457             stroker.setDashPattern(dashes);
       
   458             QPainterPath stroke = stroker.createStroke(path);
       
   459             painter->fillPath(stroke, lg);
       
   460 
       
   461         } else {
       
   462             QPen pen(lg, m_penWidth, m_penStyle, m_capStyle, m_joinStyle);
       
   463             painter->strokePath(path, pen);
       
   464         }
       
   465     }
       
   466 
       
   467     if (1) {
       
   468         // Draw the control points
       
   469         painter->setPen(QColor(50, 100, 120, 200));
       
   470         painter->setBrush(QColor(200, 200, 210, 120));
       
   471         for (int i=0; i<m_points.size(); ++i) {
       
   472             QPointF pos = m_points.at(i);
       
   473             painter->drawEllipse(QRectF(pos.x() - m_pointSize,
       
   474                                        pos.y() - m_pointSize,
       
   475                                        m_pointSize*2, m_pointSize*2));
       
   476         }
       
   477         painter->setPen(QPen(Qt::lightGray, 0, Qt::SolidLine));
       
   478         painter->setBrush(Qt::NoBrush);
       
   479         painter->drawPolyline(m_points);
       
   480     }
       
   481 
       
   482 }
       
   483 
       
   484 void PathStrokeRenderer::initializePoints()
       
   485 {
       
   486     const int count = 7;
       
   487     m_points.clear();
       
   488     m_vectors.clear();
       
   489 
       
   490     QMatrix m;
       
   491     qreal rot = 360 / count;
       
   492     QPointF center(width() / 2, height() / 2);
       
   493     QMatrix vm;
       
   494     vm.shear(2, -1);
       
   495     vm.scale(3, 3);
       
   496 
       
   497     for (int i=0; i<count; ++i) {
       
   498         m_vectors << QPointF(.1f, .25f) * (m * vm);
       
   499         m_points << QPointF(0, 100) * m + center;
       
   500         m.rotate(rot);
       
   501     }
       
   502 }
       
   503 
       
   504 void PathStrokeRenderer::updatePoints()
       
   505 {
       
   506     qreal pad = 10;
       
   507     qreal left = pad;
       
   508     qreal right = width() - pad;
       
   509     qreal top = pad;
       
   510     qreal bottom = height() - pad;
       
   511 
       
   512     Q_ASSERT(m_points.size() == m_vectors.size());
       
   513     for (int i=0; i<m_points.size(); ++i) {
       
   514         QPointF pos = m_points.at(i);
       
   515         QPointF vec = m_vectors.at(i);
       
   516         pos += vec;
       
   517         if (pos.x() < left || pos.x() > right) {
       
   518             vec.setX(-vec.x());
       
   519             pos.setX(pos.x() < left ? left : right);
       
   520         } if (pos.y() < top || pos.y() > bottom) {
       
   521             vec.setY(-vec.y());
       
   522             pos.setY(pos.y() < top ? top : bottom);
       
   523         }
       
   524         m_points[i] = pos;
       
   525         m_vectors[i] = vec;
       
   526     }
       
   527     update();
       
   528 }
       
   529 
       
   530 void PathStrokeRenderer::mousePressEvent(QMouseEvent *e)
       
   531 {
       
   532     if (!m_fingerPointMapping.isEmpty())
       
   533         return;
       
   534     setDescriptionEnabled(false);
       
   535     m_activePoint = -1;
       
   536     qreal distance = -1;
       
   537     for (int i=0; i<m_points.size(); ++i) {
       
   538         qreal d = QLineF(e->pos(), m_points.at(i)).length();
       
   539         if ((distance < 0 && d < 8 * m_pointSize) || d < distance) {
       
   540             distance = d;
       
   541             m_activePoint = i;
       
   542         }
       
   543     }
       
   544 
       
   545     if (m_activePoint != -1) {
       
   546         m_wasAnimated = m_timer.isActive();
       
   547         setAnimation(false);
       
   548         mouseMoveEvent(e);
       
   549     }
       
   550     
       
   551     // If we're not running in small screen mode, always assume we're dragging
       
   552     m_mouseDrag = !m_smallScreen;
       
   553     m_mousePress = e->pos();
       
   554 }
       
   555 
       
   556 void PathStrokeRenderer::mouseMoveEvent(QMouseEvent *e)
       
   557 {
       
   558     if (!m_fingerPointMapping.isEmpty())
       
   559         return;
       
   560     // If we've moved more then 25 pixels, assume user is dragging
       
   561     if (!m_mouseDrag && QPoint(m_mousePress - e->pos()).manhattanLength() > 25)
       
   562         m_mouseDrag = true;
       
   563 
       
   564     if (m_mouseDrag && m_activePoint >= 0 && m_activePoint < m_points.size()) {
       
   565         m_points[m_activePoint] = e->pos();
       
   566         update();
       
   567     }
       
   568 }
       
   569 
       
   570 void PathStrokeRenderer::mouseReleaseEvent(QMouseEvent *)
       
   571 {
       
   572     if (!m_fingerPointMapping.isEmpty())
       
   573         return;
       
   574     m_activePoint = -1;
       
   575     setAnimation(m_wasAnimated);
       
   576 
       
   577     if (!m_mouseDrag && m_smallScreen)
       
   578         emit clicked();
       
   579 }
       
   580 
       
   581 void PathStrokeRenderer::timerEvent(QTimerEvent *e)
       
   582 {
       
   583     if (e->timerId() == m_timer.timerId()) {
       
   584         updatePoints();
       
   585         QApplication::syncX();
       
   586     } // else if (e->timerId() == m_fpsTimer.timerId()) {
       
   587 //         emit frameRate(m_frameCount);
       
   588 //         m_frameCount = 0;
       
   589 //     }
       
   590 }
       
   591 
       
   592 bool PathStrokeRenderer::event(QEvent *e)
       
   593 {
       
   594     bool touchBegin = false;
       
   595     switch (e->type()) {
       
   596     case QEvent::TouchBegin:
       
   597         touchBegin = true;
       
   598     case QEvent::TouchUpdate:
       
   599         {
       
   600             const QTouchEvent *const event = static_cast<const QTouchEvent*>(e);
       
   601             const QList<QTouchEvent::TouchPoint> points = event->touchPoints();
       
   602             foreach (const QTouchEvent::TouchPoint &touchPoint, points) {
       
   603                 const int id = touchPoint.id();
       
   604                 switch (touchPoint.state()) {
       
   605                 case Qt::TouchPointPressed:
       
   606                     {
       
   607                         // find the point, move it
       
   608                         QSet<int> activePoints = QSet<int>::fromList(m_fingerPointMapping.values());
       
   609                         int activePoint = -1;
       
   610                         qreal distance = -1;
       
   611                         const int pointsCount = m_points.size();
       
   612                         for (int i=0; i<pointsCount; ++i) {
       
   613                             if (activePoints.contains(i))
       
   614                                 continue;
       
   615 
       
   616                             qreal d = QLineF(touchPoint.pos(), m_points.at(i)).length();
       
   617                             if ((distance < 0 && d < 12 * m_pointSize) || d < distance) {
       
   618                                 distance = d;
       
   619                                 activePoint = i;
       
   620                             }
       
   621                         }
       
   622                         if (activePoint != -1) {
       
   623                             m_fingerPointMapping.insert(touchPoint.id(), activePoint);
       
   624                             m_points[activePoint] = touchPoint.pos();
       
   625                         }
       
   626                     }
       
   627                     break;
       
   628                 case Qt::TouchPointReleased:
       
   629                     {
       
   630                         // move the point and release
       
   631                         QHash<int,int>::iterator it = m_fingerPointMapping.find(id);
       
   632                         m_points[it.value()] = touchPoint.pos();
       
   633                         m_fingerPointMapping.erase(it);
       
   634                     }
       
   635                     break;
       
   636                 case Qt::TouchPointMoved:
       
   637                     {
       
   638                         // move the point
       
   639                         const int pointIdx = m_fingerPointMapping.value(id, -1);
       
   640                         if (pointIdx >= 0)
       
   641                             m_points[pointIdx] = touchPoint.pos();
       
   642                     }
       
   643                     break;
       
   644                 default:
       
   645                     break;
       
   646                 }
       
   647             }
       
   648             if (m_fingerPointMapping.isEmpty()) {
       
   649                 e->ignore();
       
   650                 return false;
       
   651             } else {
       
   652                 if (touchBegin) {
       
   653                     m_wasAnimated = m_timer.isActive();
       
   654                     setAnimation(false);
       
   655                 }
       
   656                 update();
       
   657                 return true;
       
   658             }
       
   659         }
       
   660         break;
       
   661     case QEvent::TouchEnd:
       
   662         if (m_fingerPointMapping.isEmpty()) {
       
   663             e->ignore();
       
   664             return false;
       
   665         }
       
   666         m_fingerPointMapping.clear();
       
   667         setAnimation(m_wasAnimated);
       
   668         return true;
       
   669         break;
       
   670     default:
       
   671         break;
       
   672     }
       
   673     return QWidget::event(e);
       
   674 }
       
   675 
       
   676 void PathStrokeRenderer::setAnimation(bool animation)
       
   677 {
       
   678     m_timer.stop();
       
   679 //     m_fpsTimer.stop();
       
   680 
       
   681     if (animation) {
       
   682         m_timer.start(25, this);
       
   683 //         m_fpsTimer.start(1000, this);
       
   684 //         m_frameCount = 0;
       
   685     }
       
   686 }