demos/deform/pathdeform.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 2005-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the demonstration applications of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "pathdeform.h"
00025 
00026 #include <QApplication>
00027 #include <QtDebug>
00028 #include <QMouseEvent>
00029 #include <QTimerEvent>
00030 #include <QLayout>
00031 #include <QLineEdit>
00032 #include <QPainter>
00033 #include <QSlider>
00034 
00035 #include <math.h>
00036 
00037 
00038 PathDeformWidget::PathDeformWidget(QWidget *parent)
00039     : QWidget(parent)
00040 {
00041     setWindowTitle("Vector Deformation");
00042 
00043     m_renderer = new PathDeformRenderer(this);
00044     m_renderer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00045 
00046     QGroupBox *mainGroup = new QGroupBox(this);
00047     mainGroup->setTitle("Vector Deformation");
00048 
00049     QGroupBox *radiusGroup = new QGroupBox(mainGroup);
00050     radiusGroup->setAttribute(Qt::WA_ContentsPropagated);
00051     radiusGroup->setTitle("Lens Radius");
00052     QSlider *radiusSlider = new QSlider(Qt::Horizontal, radiusGroup);
00053     radiusSlider->setRange(50, 150);
00054     radiusSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
00055 
00056     QGroupBox *deformGroup = new QGroupBox(mainGroup);
00057     deformGroup->setAttribute(Qt::WA_ContentsPropagated);
00058     deformGroup->setTitle("Deformation");
00059     QSlider *deformSlider = new QSlider(Qt::Horizontal, deformGroup);
00060     deformSlider->setRange(-100, 100);
00061     deformSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
00062 
00063     QGroupBox *fontSizeGroup = new QGroupBox(mainGroup);
00064     fontSizeGroup->setAttribute(Qt::WA_ContentsPropagated);
00065     fontSizeGroup->setTitle("Font Size");
00066     QSlider *fontSizeSlider = new QSlider(Qt::Horizontal, fontSizeGroup);
00067     fontSizeSlider->setRange(16, 200);
00068     fontSizeSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
00069 
00070     QGroupBox *textGroup = new QGroupBox(mainGroup);
00071     textGroup->setAttribute(Qt::WA_ContentsPropagated);
00072     textGroup->setTitle("Text");
00073     QLineEdit *textInput = new QLineEdit(textGroup);
00074 
00075     QPushButton *animateButton = new QPushButton(mainGroup);
00076     animateButton->setText("Animated");
00077     animateButton->setCheckable(true);
00078 
00079     QPushButton *showSourceButton = new QPushButton(mainGroup);
00080     showSourceButton->setText("Show Source");
00081 //     showSourceButton->setCheckable(true);
00082 #ifdef QT_OPENGL_SUPPORT
00083     QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
00084     enableOpenGLButton->setText("Use OpenGL");
00085     enableOpenGLButton->setCheckable(true);
00086     enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
00087     if (!QGLFormat::hasOpenGL())
00088         enableOpenGLButton->hide();
00089 #endif
00090     QPushButton *whatsThisButton = new QPushButton(mainGroup);
00091     whatsThisButton->setText("What's This?");
00092     whatsThisButton->setCheckable(true);
00093 
00094     // Layouts
00095     QHBoxLayout *mainLayout = new QHBoxLayout(this);
00096     mainLayout->addWidget(m_renderer);
00097     mainLayout->addWidget(mainGroup);
00098     mainGroup->setFixedWidth(180);
00099 
00100     QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
00101     mainGroupLayout->addWidget(radiusGroup);
00102     mainGroupLayout->addWidget(deformGroup);
00103     mainGroupLayout->addWidget(fontSizeGroup);
00104     mainGroupLayout->addWidget(textGroup);
00105     mainGroupLayout->addWidget(animateButton);
00106     mainGroupLayout->addStretch(1);
00107     mainGroupLayout->addWidget(showSourceButton);
00108 #ifdef QT_OPENGL_SUPPORT
00109     mainGroupLayout->addWidget(enableOpenGLButton);
00110 #endif
00111     mainGroupLayout->addWidget(whatsThisButton);
00112 
00113     QVBoxLayout *radiusGroupLayout = new QVBoxLayout(radiusGroup);
00114     radiusGroupLayout->addWidget(radiusSlider);
00115 
00116     QVBoxLayout *deformGroupLayout = new QVBoxLayout(deformGroup);
00117     deformGroupLayout->addWidget(deformSlider);
00118 
00119     QVBoxLayout *fontSizeGroupLayout = new QVBoxLayout(fontSizeGroup);
00120     fontSizeGroupLayout->addWidget(fontSizeSlider);
00121 
00122     QVBoxLayout *textGroupLayout = new QVBoxLayout(textGroup);
00123     textGroupLayout->addWidget(textInput);
00124 
00125     connect(textInput, SIGNAL(textChanged(QString)), m_renderer, SLOT(setText(QString)));
00126     connect(radiusSlider, SIGNAL(valueChanged(int)), m_renderer, SLOT(setRadius(int)));
00127     connect(deformSlider, SIGNAL(valueChanged(int)), m_renderer, SLOT(setIntensity(int)));
00128     connect(fontSizeSlider, SIGNAL(valueChanged(int)), m_renderer, SLOT(setFontSize(int)));
00129     connect(animateButton, SIGNAL(clicked(bool)), m_renderer, SLOT(setAnimated(bool)));
00130     connect(whatsThisButton, SIGNAL(clicked(bool)), m_renderer, SLOT(setDescriptionEnabled(bool)));
00131     connect(showSourceButton, SIGNAL(clicked()), m_renderer, SLOT(showSource()));
00132 #ifdef QT_OPENGL_SUPPORT
00133     connect(enableOpenGLButton, SIGNAL(clicked(bool)), m_renderer, SLOT(enableOpenGL(bool)));
00134 #endif
00135     connect(m_renderer, SIGNAL(descriptionEnabledChanged(bool)),
00136             whatsThisButton, SLOT(setChecked(bool)));
00137 
00138     animateButton->animateClick();
00139     deformSlider->setValue(80);
00140     radiusSlider->setValue(100);
00141     fontSizeSlider->setValue(120);
00142     textInput->setText("Qt");
00143 
00144     m_renderer->loadSourceFile(":res/pathdeform.cpp");
00145     m_renderer->loadDescription(":res/pathdeform.html");
00146     m_renderer->setDescriptionEnabled(false);
00147 }
00148 
00149 
00150 static inline QRect circle_bounds(const QPointF &center, double radius, double compensation)
00151 {
00152     return QRect(qRound(center.x() - radius - compensation),
00153                  qRound(center.y() - radius - compensation),
00154                  qRound((radius + compensation) * 2),
00155                  qRound((radius + compensation) * 2));
00156 
00157 }
00158 
00159 const int LENS_EXTENT = 10;
00160 
00161 PathDeformRenderer::PathDeformRenderer(QWidget *widget)
00162     : ArthurFrame(widget)
00163 {
00164     m_radius = 100;
00165     m_pos = QPointF(m_radius, m_radius);
00166     m_direction = QPointF(1, 1);
00167     m_fontSize = 24;
00168     m_animated = true;
00169     m_repaintTimer.start(25, this);
00170     m_repaintTracker.start();
00171     m_intensity = 100;
00172 
00173 //     m_fpsTimer.start(1000, this);
00174 //     m_fpsCounter = 0;
00175 
00176     generateLensPixmap();
00177 }
00178 
00179 void PathDeformRenderer::setText(const QString &text)
00180 {
00181     m_text = text;
00182 
00183     QFont f("times new roman,utopia");
00184     f.setStyleStrategy(QFont::ForceOutline);
00185     f.setPointSize(m_fontSize);
00186     f.setStyleHint(QFont::Times);
00187 
00188     QFontMetrics fm(f);
00189 
00190     m_paths.clear();
00191     m_pathBounds = QRect();
00192 
00193     QPointF advance(0, 0);
00194 
00195     bool do_quick = true;
00196     for (int i=0; i<text.size(); ++i) {
00197         if (text.at(i).unicode() >= 0x4ff && text.at(i).unicode() <= 0x1e00) {
00198             do_quick = false;
00199             break;
00200         }
00201     }
00202 
00203     if (do_quick) {
00204         for (int i=0; i<text.size(); ++i) {
00205             QPainterPath path;
00206             path.addText(advance, f, text.mid(i, 1));
00207             m_pathBounds |= path.boundingRect();
00208             m_paths << path;
00209             advance += QPointF(fm.width(text.mid(i, 1)), 0);
00210         }
00211     } else {
00212         QPainterPath path;
00213         path.addText(advance, f, text);
00214         m_pathBounds |= path.boundingRect();
00215         m_paths << path;
00216     }
00217 
00218     for (int i=0; i<m_paths.size(); ++i)
00219         m_paths[i] = m_paths[i] * QMatrix(1, 0, 0, 1, -m_pathBounds.x(), -m_pathBounds.y());
00220 
00221     update();
00222 }
00223 
00224 
00225 void PathDeformRenderer::generateLensPixmap()
00226 {
00227     double rad = m_radius + LENS_EXTENT;
00228 
00229     QRect bounds = circle_bounds(QPointF(), rad, 0);
00230 
00231     QPainter painter;
00232 
00233     if (preferImage()) {
00234         m_lens_image = QImage(bounds.size(), QImage::Format_ARGB32_Premultiplied);
00235         m_lens_image.fill(0);
00236         painter.begin(&m_lens_image);
00237     } else {
00238         m_lens_pixmap = QPixmap(bounds.size());
00239         m_lens_pixmap.fill(QColor(0, 0, 0, 0));
00240         painter.begin(&m_lens_pixmap);
00241     }
00242 
00243     QRadialGradient gr(rad, rad, rad, 3 * rad / 5, 3 * rad / 5);
00244     gr.setColorAt(0.0, QColor(255, 255, 255, 191));
00245     gr.setColorAt(0.2, QColor(255, 255, 127, 191));
00246     gr.setColorAt(0.9, QColor(150, 150, 200, 63));
00247     gr.setColorAt(0.95, QColor(0, 0, 0, 127));
00248     gr.setColorAt(1, QColor(0, 0, 0, 0));
00249     painter.setRenderHint(QPainter::Antialiasing);
00250     painter.setBrush(gr);
00251     painter.setPen(Qt::NoPen);
00252     painter.drawEllipse(0, 0, bounds.width(), bounds.height());
00253 }
00254 
00255 
00256 void PathDeformRenderer::setAnimated(bool animated)
00257 {
00258     m_animated = animated;
00259 
00260     if (m_animated) {
00261 //         m_fpsTimer.start(1000, this);
00262 //         m_fpsCounter = 0;
00263         m_repaintTimer.start(25, this);
00264         m_repaintTracker.start();
00265     } else {
00266 //         m_fpsTimer.stop();
00267         m_repaintTimer.stop();
00268     }
00269 }
00270 
00271 void PathDeformRenderer::timerEvent(QTimerEvent *e)
00272 {
00273 
00274     if (e->timerId() == m_repaintTimer.timerId()) {
00275 
00276         if (QLineF(QPointF(0,0), m_direction).length() > 1)
00277             m_direction *= 0.995;
00278         double time = m_repaintTracker.restart();
00279 
00280         QRect rectBefore = circle_bounds(m_pos, m_radius, m_fontSize);
00281 
00282         double dx = m_direction.x();
00283         double dy = m_direction.y();
00284         if (time > 0) {
00285             dx = dx * time * .1;
00286             dy = dy * time * .1;
00287         }
00288 
00289         m_pos += QPointF(dx, dy);
00290 
00291 
00292 
00293         if (m_pos.x() - m_radius < 0) {
00294             m_direction.setX(-m_direction.x());
00295             m_pos.setX(m_radius);
00296         } else if (m_pos.x() + m_radius > width()) {
00297             m_direction.setX(-m_direction.x());
00298             m_pos.setX(width() - m_radius);
00299         }
00300 
00301         if (m_pos.y() - m_radius < 0) {
00302             m_direction.setY(-m_direction.y());
00303             m_pos.setY(m_radius);
00304         } else if (m_pos.y() + m_radius > height()) {
00305             m_direction.setY(-m_direction.y());
00306             m_pos.setY(height() - m_radius);
00307         }
00308 
00309 #ifdef QT_OPENGL_SUPPORT
00310         if (usesOpenGL()) {
00311             update();
00312         } else
00313 #endif
00314         {
00315             QRect rectAfter = circle_bounds(m_pos, m_radius, m_fontSize);
00316             update(rectAfter | rectBefore);
00317             QApplication::syncX();
00318         }
00319     }
00320 //     else if (e->timerId() == m_fpsTimer.timerId()) {
00321 //         printf("fps: %d\n", m_fpsCounter);
00322 //         emit frameRate(m_fpsCounter);
00323 //         m_fpsCounter = 0;
00324 
00325 //     }
00326 }
00327 
00328 void PathDeformRenderer::mousePressEvent(QMouseEvent *e)
00329 {
00330     setDescriptionEnabled(false);
00331 
00332     m_repaintTimer.stop();
00333     m_offset = QPointF();
00334     if (QLineF(m_pos, e->pos()).length() <= m_radius)
00335         m_offset = m_pos - e->pos();
00336 
00337     mouseMoveEvent(e);
00338 }
00339 
00340 void PathDeformRenderer::mouseReleaseEvent(QMouseEvent *e)
00341 {
00342     if (e->buttons() == Qt::NoButton && m_animated) {
00343         m_repaintTimer.start(10, this);
00344         m_repaintTracker.start();
00345     }
00346 }
00347 
00348 void PathDeformRenderer::mouseMoveEvent(QMouseEvent *e)
00349 {
00350     QRect rectBefore = circle_bounds(m_pos, m_radius, m_fontSize);
00351     if (e->type() == QEvent::MouseMove) {
00352         QLineF line(m_pos, e->pos() + m_offset);
00353         line.setLength(line.length() * .1);
00354         QPointF dir(line.dx(), line.dy());
00355         m_direction = (m_direction + dir) / 2;
00356     }
00357     m_pos = e->pos() + m_offset;
00358 #ifdef QT_OPENGL_SUPPORT
00359     if (usesOpenGL()) {
00360         update();
00361     } else
00362 #endif
00363     {
00364         QRect rectAfter = circle_bounds(m_pos, m_radius, m_fontSize);
00365         update(rectBefore | rectAfter);
00366     }
00367 }
00368 
00369 QPainterPath PathDeformRenderer::lensDeform(const QPainterPath &source, const QPointF &offset)
00370 {
00371     QPainterPath path;
00372     path.addPath(source);
00373 
00374     double flip = m_intensity / 100.0;
00375 
00376     for (int i=0; i<path.elementCount(); ++i) {
00377         const QPainterPath::Element &e = path.elementAt(i);
00378 
00379         double x = e.x + offset.x();
00380         double y = e.y + offset.y();
00381 
00382         double dx = x - m_pos.x();
00383         double dy = y - m_pos.y();
00384         double len = m_radius - sqrt(dx * dx + dy * dy);
00385 
00386         if (len > 0) {
00387             path.setElementPositionAt(i,
00388                                       x + flip * dx * len / m_radius,
00389                                       y + flip * dy * len / m_radius);
00390         } else {
00391             path.setElementPositionAt(i, x, y);
00392         }
00393 
00394     }
00395 
00396     return path;
00397 }
00398 
00399 
00400 void PathDeformRenderer::paint(QPainter *painter)
00401 {
00402     int pad_x = 5;
00403     int pad_y = 5;
00404 
00405     int skip_x = qRound(m_pathBounds.width() + pad_x + m_fontSize/2);
00406     int skip_y = qRound(m_pathBounds.height() + pad_y);
00407 
00408     painter->setPen(Qt::NoPen);
00409     painter->setBrush(Qt::black);
00410 
00411     QRectF clip(painter->clipPath().boundingRect());
00412 
00413     int overlap = pad_x / 2;
00414 
00415     for (int start_y=0; start_y < height(); start_y += skip_y) {
00416 
00417         if (start_y > clip.bottom())
00418             break;
00419 
00420         int start_x = -overlap;
00421         for (; start_x < width(); start_x += skip_x) {
00422 
00423             if (start_y + skip_y >= clip.top() &&
00424                 start_x + skip_x >= clip.left() &&
00425                 start_x <= clip.right()) {
00426                 for (int i=0; i<m_paths.size(); ++i) {
00427                     QPainterPath path = lensDeform(m_paths[i], QPointF(start_x, start_y));
00428                     painter->drawPath(path);
00429                 }
00430             }
00431         }
00432         overlap = skip_x - (start_x - width());
00433 
00434     }
00435 
00436     if (preferImage()) {
00437         painter->drawImage(m_pos - QPointF(m_radius + LENS_EXTENT, m_radius + LENS_EXTENT),
00438                            m_lens_image);
00439     } else {
00440         painter->drawPixmap(m_pos - QPointF(m_radius + LENS_EXTENT, m_radius + LENS_EXTENT),
00441                             m_lens_pixmap);
00442     }
00443 }
00444 
00445 
00446 
00447 void PathDeformRenderer::setRadius(int radius)
00448 {
00449     double max = qMax(m_radius, (double)radius);
00450     m_radius = radius;
00451     generateLensPixmap();
00452     if (!m_animated || m_radius < max) {
00453 #ifdef QT_OPENGL_SUPPORT
00454         if (usesOpenGL()) {
00455             update();
00456         } else
00457 #endif
00458         {
00459             update(circle_bounds(m_pos, max, m_fontSize));
00460         }
00461     }
00462 }
00463 
00464 void PathDeformRenderer::setIntensity(int intensity)
00465 {
00466     m_intensity = intensity;
00467     if (!m_animated) {
00468 #ifdef QT_OPENGL_SUPPORT
00469         if (usesOpenGL()) {
00470             update();
00471         } else
00472 #endif
00473         {
00474             update(circle_bounds(m_pos, m_radius, m_fontSize));
00475         }
00476     }
00477 }

Generated on Thu Mar 15 11:52:32 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1