~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to demos/deform/pathdeform.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "pathdeform.h"
 
2
 
 
3
#include <qapplication.h>
 
4
#include <qdebug.h>
 
5
#include <qlayout.h>
 
6
#include <qlineedit.h>
 
7
#include <qevent.h>
 
8
 
 
9
#include <math.h>
 
10
 
 
11
 
 
12
PathDeformWidget::PathDeformWidget(QWidget *parent)
 
13
    : QWidget(parent)
 
14
{
 
15
    setWindowTitle("Vector Deformation");
 
16
 
 
17
    m_renderer = new PathDeformRenderer(this);
 
18
    m_renderer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
 
19
 
 
20
    ArthurGroupBox *mainGroup = new ArthurGroupBox(this);
 
21
    mainGroup->setTitle("Vector Deformation");
 
22
 
 
23
    ArthurGroupBox *radiusGroup = new ArthurGroupBox(mainGroup);
 
24
    radiusGroup->setAttribute(Qt::WA_ContentsPropagated);
 
25
    radiusGroup->setTitle("Lens radius");
 
26
    QSlider *radiusSlider = new QSlider(Qt::Horizontal, radiusGroup);
 
27
    radiusSlider->setRange(50, 150);
 
28
    radiusSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
 
29
 
 
30
    ArthurGroupBox *deformGroup = new ArthurGroupBox(mainGroup);
 
31
    deformGroup->setAttribute(Qt::WA_ContentsPropagated);
 
32
    deformGroup->setTitle("Deformation");
 
33
    QSlider *deformSlider = new QSlider(Qt::Horizontal, deformGroup);
 
34
    deformSlider->setRange(-100, 100);
 
35
    deformSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
 
36
 
 
37
    ArthurGroupBox *fontSizeGroup = new ArthurGroupBox(mainGroup);
 
38
    fontSizeGroup->setAttribute(Qt::WA_ContentsPropagated);
 
39
    fontSizeGroup->setTitle("Font Size");
 
40
    QSlider *fontSizeSlider = new QSlider(Qt::Horizontal, fontSizeGroup);
 
41
    fontSizeSlider->setRange(16, 200);
 
42
    fontSizeSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
 
43
 
 
44
    ArthurGroupBox *textGroup = new ArthurGroupBox(mainGroup);
 
45
    textGroup->setAttribute(Qt::WA_ContentsPropagated);
 
46
    textGroup->setTitle("Text");
 
47
    QLineEdit *textInput = new QLineEdit(textGroup);
 
48
 
 
49
    QPushButton *animateButton = new QPushButton(mainGroup);
 
50
    animateButton->setText("Animated");
 
51
    animateButton->setCheckable(true);
 
52
 
 
53
    QPushButton *showSourceButton = new QPushButton(mainGroup);
 
54
    showSourceButton->setText("Show Source");
 
55
//     showSourceButton->setCheckable(true);
 
56
 
 
57
    QPushButton *whatsThisButton = new QPushButton(mainGroup);
 
58
    whatsThisButton->setText("What's This?");
 
59
    whatsThisButton->setCheckable(true);
 
60
 
 
61
    // Layouts
 
62
    QHBoxLayout *mainLayout = new QHBoxLayout(this);
 
63
    mainLayout->addWidget(m_renderer);
 
64
    mainLayout->addWidget(mainGroup);
 
65
    mainGroup->setFixedWidth(180);
 
66
 
 
67
    QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
 
68
    mainGroupLayout->addWidget(radiusGroup);
 
69
    mainGroupLayout->addWidget(deformGroup);
 
70
    mainGroupLayout->addWidget(fontSizeGroup);
 
71
    mainGroupLayout->addWidget(textGroup);
 
72
    mainGroupLayout->addWidget(animateButton);
 
73
    mainGroupLayout->addStretch(1);
 
74
    mainGroupLayout->addWidget(showSourceButton);
 
75
    mainGroupLayout->addWidget(whatsThisButton);
 
76
 
 
77
    QVBoxLayout *radiusGroupLayout = new QVBoxLayout(radiusGroup);
 
78
    radiusGroupLayout->addWidget(radiusSlider);
 
79
 
 
80
    QVBoxLayout *deformGroupLayout = new QVBoxLayout(deformGroup);
 
81
    deformGroupLayout->addWidget(deformSlider);
 
82
 
 
83
    QVBoxLayout *fontSizeGroupLayout = new QVBoxLayout(fontSizeGroup);
 
84
    fontSizeGroupLayout->addWidget(fontSizeSlider);
 
85
 
 
86
    QVBoxLayout *textGroupLayout = new QVBoxLayout(textGroup);
 
87
    textGroupLayout->addWidget(textInput);
 
88
 
 
89
    connect(textInput, SIGNAL(textChanged(QString)), m_renderer, SLOT(setText(QString)));
 
90
    connect(radiusSlider, SIGNAL(valueChanged(int)), m_renderer, SLOT(setRadius(int)));
 
91
    connect(deformSlider, SIGNAL(valueChanged(int)), m_renderer, SLOT(setIntensity(int)));
 
92
    connect(fontSizeSlider, SIGNAL(valueChanged(int)), m_renderer, SLOT(setFontSize(int)));
 
93
    connect(animateButton, SIGNAL(clicked(bool)), m_renderer, SLOT(setAnimated(bool)));
 
94
    connect(whatsThisButton, SIGNAL(clicked(bool)), m_renderer, SLOT(setDescriptionEnabled(bool)));
 
95
    connect(showSourceButton, SIGNAL(clicked()), m_renderer, SLOT(showSource()));
 
96
    connect(m_renderer, SIGNAL(descriptionEnabledChanged(bool)),
 
97
            whatsThisButton, SLOT(setChecked(bool)));
 
98
 
 
99
    animateButton->animateClick();
 
100
    deformSlider->setValue(80);
 
101
    radiusSlider->setValue(100);
 
102
    fontSizeSlider->setValue(120);
 
103
    textInput->setText("Qt");
 
104
 
 
105
    m_renderer->loadSourceFile(":res/pathdeform.cpp");
 
106
    m_renderer->loadDescription(":res/pathdeform.html");
 
107
    m_renderer->setDescriptionEnabled(false);
 
108
}
 
109
 
 
110
 
 
111
static inline QRect circle_bounds(const QPointF &center, double radius, double compensation)
 
112
{
 
113
    return QRect(qRound(center.x() - radius - compensation),
 
114
                 qRound(center.y() - radius - compensation),
 
115
                 qRound((radius + compensation) * 2),
 
116
                 qRound((radius + compensation) * 2));
 
117
 
 
118
}
 
119
 
 
120
const int LENS_EXTENT = 10;
 
121
 
 
122
PathDeformRenderer::PathDeformRenderer(QWidget *widget)
 
123
    : ArthurFrame(widget)
 
124
{
 
125
    m_radius = 100;
 
126
    m_pos = QPointF(m_radius, m_radius);
 
127
    m_direction = QPointF(1, 1);
 
128
    m_fontSize = 24;
 
129
    m_animated = true;
 
130
    m_repaintTimer.start(25, this);
 
131
    m_repaintTracker.start();
 
132
    m_intensity = 1;
 
133
 
 
134
//     m_fpsTimer.start(1000, this);
 
135
//     m_fpsCounter = 0;
 
136
 
 
137
    generateLensPixmap();
 
138
}
 
139
 
 
140
void PathDeformRenderer::setText(const QString &text)
 
141
{
 
142
    m_text = text;
 
143
 
 
144
    QFont f("times new roman,utopia");
 
145
    f.setStyleStrategy(QFont::ForceOutline);
 
146
    f.setPointSize(m_fontSize);
 
147
    f.setStyleHint(QFont::Times);
 
148
 
 
149
    QFontMetrics fm(f);
 
150
 
 
151
    m_paths.clear();
 
152
    m_pathBounds = QRect();
 
153
 
 
154
    QPointF advance(0, 0);
 
155
 
 
156
    bool do_quick = true;
 
157
    for (int i=0; i<text.size(); ++i) {
 
158
        if (text.at(i).unicode() >= 0x4ff && text.at(i).unicode() <= 0x1e00) {
 
159
            do_quick = false;
 
160
            break;
 
161
        }
 
162
    }
 
163
 
 
164
    if (do_quick) {
 
165
        for (int i=0; i<text.size(); ++i) {
 
166
            QPainterPath path;
 
167
            path.addText(advance, f, text.mid(i, 1));
 
168
            m_pathBounds |= path.boundingRect();
 
169
            m_paths << path;
 
170
            advance += QPointF(fm.width(text.mid(i, 1)), 0);
 
171
        }
 
172
    } else {
 
173
        QPainterPath path;
 
174
        path.addText(advance, f, text);
 
175
        m_pathBounds |= path.boundingRect();
 
176
        m_paths << path;
 
177
    }
 
178
 
 
179
    for (int i=0; i<m_paths.size(); ++i)
 
180
        m_paths[i] = m_paths[i] * QMatrix(1, 0, 0, 1, -m_pathBounds.x(), -m_pathBounds.y());
 
181
 
 
182
    update();
 
183
}
 
184
 
 
185
 
 
186
void PathDeformRenderer::generateLensPixmap()
 
187
{
 
188
    double rad = m_radius + LENS_EXTENT;
 
189
 
 
190
    QRect bounds = circle_bounds(QPointF(), rad, 0);
 
191
 
 
192
    QPainter painter;
 
193
 
 
194
    if (preferImage()) {
 
195
        m_lens_image = QImage(bounds.size(), QImage::Format_ARGB32_Premultiplied);
 
196
        m_lens_image.fill(0);
 
197
        painter.begin(&m_lens_image);
 
198
    } else {
 
199
        m_lens_pixmap = QPixmap(bounds.size());
 
200
        m_lens_pixmap.fill(QColor(0, 0, 0, 0));
 
201
        painter.begin(&m_lens_pixmap);
 
202
    }
 
203
 
 
204
    QRadialGradient gr(rad, rad, rad, 3 * rad / 5, 3 * rad / 5);
 
205
    gr.setColorAt(0.0, QColor(255, 255, 255, 191));
 
206
    gr.setColorAt(0.2, QColor(255, 255, 127, 191));
 
207
    gr.setColorAt(0.9, QColor(150, 150, 200, 63));
 
208
    gr.setColorAt(0.95, QColor(0, 0, 0, 127));
 
209
    gr.setColorAt(1, QColor(0, 0, 0, 0));
 
210
    painter.setRenderHint(QPainter::Antialiasing);
 
211
    painter.setBrush(gr);
 
212
    painter.setPen(Qt::NoPen);
 
213
    painter.drawEllipse(0, 0, bounds.width(), bounds.height());
 
214
}
 
215
 
 
216
 
 
217
void PathDeformRenderer::setAnimated(bool animated)
 
218
{
 
219
    m_animated = animated;
 
220
 
 
221
    if (m_animated) {
 
222
//         m_fpsTimer.start(1000, this);
 
223
//         m_fpsCounter = 0;
 
224
        m_repaintTimer.start(25, this);
 
225
        m_repaintTracker.start();
 
226
    } else {
 
227
//         m_fpsTimer.stop();
 
228
        m_repaintTimer.stop();
 
229
    }
 
230
}
 
231
 
 
232
void PathDeformRenderer::timerEvent(QTimerEvent *e)
 
233
{
 
234
 
 
235
    if (e->timerId() == m_repaintTimer.timerId()) {
 
236
 
 
237
        if (QLineF(QPointF(0,0), m_direction).length() > 1)
 
238
            m_direction *= 0.995;
 
239
        double time = m_repaintTracker.restart();
 
240
 
 
241
        QRect rectBefore = circle_bounds(m_pos, m_radius, m_fontSize);
 
242
 
 
243
        double dx = m_direction.x();
 
244
        double dy = m_direction.y();
 
245
        if (time > 0) {
 
246
            dx = dx * time * .1;
 
247
            dy = dy * time * .1;
 
248
        }
 
249
 
 
250
        m_pos += QPointF(dx, dy);
 
251
 
 
252
 
 
253
 
 
254
        if (m_pos.x() - m_radius < 0) {
 
255
            m_direction.setX(-m_direction.x());
 
256
            m_pos.setX(m_radius);
 
257
        } else if (m_pos.x() + m_radius > width()) {
 
258
            m_direction.setX(-m_direction.x());
 
259
            m_pos.setX(width() - m_radius);
 
260
        }
 
261
 
 
262
        if (m_pos.y() - m_radius < 0) {
 
263
            m_direction.setY(-m_direction.y());
 
264
            m_pos.setY(m_radius);
 
265
        } else if (m_pos.y() + m_radius > height()) {
 
266
            m_direction.setY(-m_direction.y());
 
267
            m_pos.setY(height() - m_radius);
 
268
        }
 
269
 
 
270
        QRect rectAfter = circle_bounds(m_pos, m_radius, m_fontSize);
 
271
        update(QRect(rectBefore | rectAfter));
 
272
        QApplication::syncX();
 
273
    }
 
274
//     else if (e->timerId() == m_fpsTimer.timerId()) {
 
275
//         printf("fps: %d\n", m_fpsCounter);
 
276
//         emit frameRate(m_fpsCounter);
 
277
//         m_fpsCounter = 0;
 
278
 
 
279
//     }
 
280
}
 
281
 
 
282
void PathDeformRenderer::mousePressEvent(QMouseEvent *e)
 
283
{
 
284
    setDescriptionEnabled(false);
 
285
 
 
286
    m_repaintTimer.stop();
 
287
    m_offset = QPointF();
 
288
    if (QLineF(m_pos, e->pos()).length() <= m_radius)
 
289
        m_offset = m_pos - e->pos();
 
290
 
 
291
    mouseMoveEvent(e);
 
292
}
 
293
 
 
294
void PathDeformRenderer::mouseReleaseEvent(QMouseEvent *e)
 
295
{
 
296
    if (e->buttons() == Qt::NoButton && m_animated) {
 
297
        m_repaintTimer.start(10, this);
 
298
        m_repaintTracker.start();
 
299
    }
 
300
}
 
301
 
 
302
void PathDeformRenderer::mouseMoveEvent(QMouseEvent *e)
 
303
{
 
304
    QRect rectBefore = circle_bounds(m_pos, m_radius, m_fontSize);
 
305
    if (e->type() == QEvent::MouseMove) {
 
306
        QLineF line(m_pos, e->pos() + m_offset);
 
307
        line.setLength(line.length() * .1);
 
308
        QPointF dir(line.dx(), line.dy());
 
309
        m_direction = (m_direction + dir) / 2;
 
310
    }
 
311
    m_pos = e->pos() + m_offset;
 
312
    QRect rectAfter = circle_bounds(m_pos, m_radius, m_fontSize);
 
313
    update(rectBefore | rectAfter);
 
314
}
 
315
 
 
316
QPainterPath PathDeformRenderer::lensDeform(const QPainterPath &source, const QPointF &offset)
 
317
{
 
318
    QPainterPath path;
 
319
    path.addPath(source);
 
320
 
 
321
    double flip = m_intensity;
 
322
 
 
323
    for (int i=0; i<path.elementCount(); ++i) {
 
324
        QPainterPath::Element &e = const_cast<QPainterPath::Element &>(path.elementAt(i));
 
325
 
 
326
        double x = e.x + offset.x();
 
327
        double y = e.y + offset.y();
 
328
 
 
329
        double dx = x - m_pos.x();
 
330
        double dy = y - m_pos.y();
 
331
        double len = m_radius - sqrt(dx * dx + dy * dy);
 
332
 
 
333
        if (len > 0) {
 
334
            e.x = x + flip * dx * len / m_radius;
 
335
            e.y = y + flip * dy * len / m_radius;
 
336
        } else {
 
337
            e.x = x;
 
338
            e.y = y;
 
339
        }
 
340
 
 
341
    }
 
342
 
 
343
    return path;
 
344
}
 
345
 
 
346
 
 
347
void PathDeformRenderer::paint(QPainter *painter)
 
348
{
 
349
    int pad_x = 5;
 
350
    int pad_y = 5;
 
351
 
 
352
    int skip_x = qRound(m_pathBounds.width() + pad_x + m_fontSize/2);
 
353
    int skip_y = qRound(m_pathBounds.height() + pad_y);
 
354
 
 
355
    painter->setPen(Qt::NoPen);
 
356
    painter->setBrush(Qt::black);
 
357
 
 
358
    QRectF clip(painter->clipPath().boundingRect());
 
359
 
 
360
    int overlap = pad_x / 2;
 
361
 
 
362
    for (int start_y=0; start_y < height(); start_y += skip_y) {
 
363
 
 
364
        if (start_y > clip.bottom())
 
365
            break;
 
366
 
 
367
        int start_x = -overlap;
 
368
        for (; start_x < width(); start_x += skip_x) {
 
369
 
 
370
            if (start_y + skip_y >= clip.top() &&
 
371
                start_x + skip_x >= clip.left() &&
 
372
                start_x <= clip.right()) {
 
373
                for (int i=0; i<m_paths.size(); ++i) {
 
374
                    QPainterPath path = lensDeform(m_paths[i], QPointF(start_x, start_y));
 
375
                    painter->drawPath(path);
 
376
                }
 
377
            }
 
378
        }
 
379
        overlap = skip_x - (start_x - width());
 
380
 
 
381
    }
 
382
 
 
383
    if (preferImage()) {
 
384
        painter->drawImage(m_pos - QPointF(m_radius + LENS_EXTENT, m_radius + LENS_EXTENT),
 
385
                           m_lens_image);
 
386
    } else {
 
387
        painter->drawPixmap(m_pos - QPointF(m_radius + LENS_EXTENT, m_radius + LENS_EXTENT),
 
388
                            m_lens_pixmap);
 
389
    }
 
390
}
 
391
 
 
392
 
 
393
 
 
394
void PathDeformRenderer::setRadius(int radius)
 
395
{
 
396
    double max = qMax(m_radius, (double)radius);
 
397
    m_radius = radius;
 
398
    generateLensPixmap();
 
399
    if (!m_animated || m_radius < max)
 
400
        update(circle_bounds(m_pos, max, m_fontSize));
 
401
}
 
402
 
 
403
void PathDeformRenderer::setIntensity(int intensity)
 
404
{
 
405
    m_intensity = intensity / 100.0;
 
406
    if (!m_animated)
 
407
        update(circle_bounds(m_pos, m_radius, m_fontSize));
 
408
}