~ubuntu-branches/ubuntu/lucid/qt4-x11/lucid

« back to all changes in this revision

Viewing changes to demos/embedded/anomaly/src/flickcharm.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi, Jonathan Riddell, Alessandro Ghersi
  • Date: 2010-02-25 02:23:43 UTC
  • mfrom: (1.1.29 upstream)
  • Revision ID: james.westby@ubuntu.com-20100225022343-qy63knnsv86fi6tc
Tags: 4:4.6.2-0ubuntu1
[ Jonathan Riddell ]
* New upstream release
* Update kubuntu_07_phonon_4.3.80.diff
* Update 05_append_qt4_target.diff

[ Alessandro Ghersi ]
* Update patches:
  - 0180-window-role.diff
  - 15_fix_qmake_makefile_generation.diff
  - 18_enable_qt3support_qtwebkit_debug_info.diff
  - 81_hurd_architecture.diff
  - 82_hurd_SA_SIGINFO.diff
  - 96_powerpc_no_gc_sections.diff
* Sync 92_armel_gcc43_valist_compat.diff with Debian
* Add kubuntu_11_fix_main_window_without_central_widget.diff (LP: #515132)
  (backport from Qt 4.6.3)
* In libqt4-dbg add conflicts with qt-x11-free-dbg (LP: #517263)
* qt4-dev-tools replaces libqt4-core (<= 4.5.3really4.5.2-0ubuntu1)
  (LP: #527534)
* Sync manpages/qdbus.1 with Debian
  - Update libqt4-dev.manpages
* qt4-dev-tools conflicts with qt3-dev-tools-embedded
* qt4-dev-tools suggests qt4-doc-html
* Update all symbol files
* Bump build dependency of debhelper and pkg-kde-tools to version 0.6.4 as it
  is needed to handle symbol files and build with pkgkde symbolshelper and
  parallel addon
* Call dh_auto_build instead of $(MAKE) for parallel build
* In override_dh_makeshlibs: do not FTBS if there are lost symbols
* Drop rules to generating libphonon4 symbols, no longer need

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/****************************************************************************
2
2
**
3
 
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
 
3
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4
4
** All rights reserved.
5
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
6
**
49
49
#include <QList>
50
50
#include <QMouseEvent>
51
51
#include <QScrollBar>
 
52
#include <QTime>
52
53
#include <QWebFrame>
53
54
#include <QWebView>
54
55
 
55
56
#include <QDebug>
56
57
 
 
58
const int fingerAccuracyThreshold = 3;
 
59
 
57
60
struct FlickData {
58
 
    typedef enum { Steady, Pressed, ManualScroll, AutoScroll, Stop } State;
 
61
    typedef enum {
 
62
        Steady, // Interaction without scrolling
 
63
        ManualScroll, // Scrolling manually with the finger on the screen
 
64
        AutoScroll, // Scrolling automatically
 
65
        AutoScrollAcceleration // Scrolling automatically but a finger is on the screen
 
66
    } State;
59
67
    State state;
60
68
    QWidget *widget;
61
69
    QPoint pressPos;
62
 
    QPoint offset;
63
 
    QPoint dragPos;
 
70
    QPoint lastPos;
64
71
    QPoint speed;
 
72
    QTime speedTimer;
65
73
    QList<QEvent*> ignored;
 
74
    QTime accelerationTimer;
 
75
    bool lastPosValid:1;
 
76
    bool waitingAcceleration:1;
 
77
 
 
78
    FlickData()
 
79
        : lastPosValid(false)
 
80
        , waitingAcceleration(false)
 
81
    {}
 
82
 
 
83
    void resetSpeed()
 
84
    {
 
85
        speed = QPoint();
 
86
        lastPosValid = false;
 
87
    }
 
88
    void updateSpeed(const QPoint &newPosition)
 
89
    {
 
90
        if (lastPosValid) {
 
91
            const int timeElapsed = speedTimer.elapsed();
 
92
            if (timeElapsed) {
 
93
                const QPoint newPixelDiff = (newPosition - lastPos);
 
94
                const QPoint pixelsPerSecond = newPixelDiff * (1000 / timeElapsed);
 
95
                // fingers are inacurates, we ignore small changes to avoid stopping the autoscroll because
 
96
                // of a small horizontal offset when scrolling vertically
 
97
                const int newSpeedY = (qAbs(pixelsPerSecond.y()) > fingerAccuracyThreshold) ? pixelsPerSecond.y() : 0;
 
98
                const int newSpeedX = (qAbs(pixelsPerSecond.x()) > fingerAccuracyThreshold) ? pixelsPerSecond.x() : 0;
 
99
                if (state == AutoScrollAcceleration) {
 
100
                    const int max = 4000; // px by seconds
 
101
                    const int oldSpeedY = speed.y();
 
102
                    const int oldSpeedX = speed.x();
 
103
                    if ((oldSpeedY <= 0 && newSpeedY <= 0) ||  (oldSpeedY >= 0 && newSpeedY >= 0)
 
104
                        && (oldSpeedX <= 0 && newSpeedX <= 0) ||  (oldSpeedX >= 0 && newSpeedX >= 0)) {
 
105
                        speed.setY(qBound(-max, (oldSpeedY + (newSpeedY / 4)), max));
 
106
                        speed.setX(qBound(-max, (oldSpeedX + (newSpeedX / 4)), max));
 
107
                    } else {
 
108
                        speed = QPoint();
 
109
                    }
 
110
                } else {
 
111
                    const int max = 2500; // px by seconds
 
112
                    // we average the speed to avoid strange effects with the last delta
 
113
                    if (!speed.isNull()) {
 
114
                        speed.setX(qBound(-max, (speed.x() / 4) + (newSpeedX * 3 / 4), max));
 
115
                        speed.setY(qBound(-max, (speed.y() / 4) + (newSpeedY * 3 / 4), max));
 
116
                    } else {
 
117
                        speed = QPoint(newSpeedX, newSpeedY);
 
118
                    }
 
119
                }
 
120
            }
 
121
        } else {
 
122
            lastPosValid = true;
 
123
        }
 
124
        speedTimer.start();
 
125
        lastPos = newPosition;
 
126
    }
 
127
 
 
128
    // scroll by dx, dy
 
129
    // return true if the widget was scrolled
 
130
    bool scrollWidget(const int dx, const int dy)
 
131
    {
 
132
        QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget);
 
133
        if (scrollArea) {
 
134
            const int x = scrollArea->horizontalScrollBar()->value();
 
135
            const int y = scrollArea->verticalScrollBar()->value();
 
136
            scrollArea->horizontalScrollBar()->setValue(x - dx);
 
137
            scrollArea->verticalScrollBar()->setValue(y - dy);
 
138
            return (scrollArea->horizontalScrollBar()->value() != x
 
139
                    || scrollArea->verticalScrollBar()->value() != y);
 
140
        }
 
141
 
 
142
        QWebView *webView = qobject_cast<QWebView*>(widget);
 
143
        if (webView) {
 
144
            QWebFrame *frame = webView->page()->mainFrame();
 
145
            const QPoint position = frame->scrollPosition();
 
146
            frame->setScrollPosition(position - QPoint(dx, dy));
 
147
            return frame->scrollPosition() != position;
 
148
        }
 
149
        return false;
 
150
    }
 
151
 
 
152
    bool scrollTo(const QPoint &newPosition)
 
153
    {
 
154
        const QPoint delta = newPosition - lastPos;
 
155
        updateSpeed(newPosition);
 
156
        return scrollWidget(delta.x(), delta.y());
 
157
    }
66
158
};
67
159
 
68
160
class FlickCharmPrivate
70
162
public:
71
163
    QHash<QWidget*, FlickData*> flickData;
72
164
    QBasicTimer ticker;
 
165
    QTime timeCounter;
 
166
    void startTicker(QObject *object)
 
167
    {
 
168
        if (!ticker.isActive())
 
169
            ticker.start(15, object);
 
170
        timeCounter.start();
 
171
    }
73
172
};
74
173
 
75
174
FlickCharm::FlickCharm(QObject *parent): QObject(parent)
148
247
    }
149
248
}
150
249
 
151
 
static QPoint scrollOffset(QWidget *widget)
152
 
{
153
 
    int x = 0, y = 0;
154
 
 
155
 
    QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget);
156
 
    if (scrollArea) {
157
 
        x = scrollArea->horizontalScrollBar()->value();
158
 
        y = scrollArea->verticalScrollBar()->value();
159
 
    }
160
 
 
161
 
    QWebView *webView = qobject_cast<QWebView*>(widget);
162
 
    if (webView) {
163
 
        QWebFrame *frame = webView->page()->mainFrame();
164
 
        x = frame->evaluateJavaScript("window.scrollX").toInt();
165
 
        y = frame->evaluateJavaScript("window.scrollY").toInt();
166
 
    }
167
 
 
168
 
    return QPoint(x, y);
169
 
}
170
 
 
171
 
static void setScrollOffset(QWidget *widget, const QPoint &p)
172
 
{
173
 
    QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea*>(widget);
174
 
    if (scrollArea) {
175
 
        scrollArea->horizontalScrollBar()->setValue(p.x());
176
 
        scrollArea->verticalScrollBar()->setValue(p.y());
177
 
    }
178
 
 
179
 
    QWebView *webView = qobject_cast<QWebView*>(widget);
180
 
    QWebFrame *frame = webView ? webView->page()->mainFrame() : 0;
181
 
    if (frame)
182
 
        frame->evaluateJavaScript(QString("window.scrollTo(%1,%2);").arg(p.x()).arg(p.y()));
183
 
}
184
 
 
185
 
static QPoint deaccelerate(const QPoint &speed, int a = 1, int max = 64)
186
 
{
187
 
    int x = qBound(-max, speed.x(), max);
188
 
    int y = qBound(-max, speed.y(), max);
189
 
    x = (x == 0) ? x : (x > 0) ? qMax(0, x - a) : qMin(0, x + a);
190
 
    y = (y == 0) ? y : (y > 0) ? qMax(0, y - a) : qMin(0, y + a);
 
250
static QPoint deaccelerate(const QPoint &speed, const int deltatime)
 
251
{
 
252
    const int deltaSpeed = deltatime;
 
253
 
 
254
    int x = speed.x();
 
255
    int y = speed.y();
 
256
    x = (x == 0) ? x : (x > 0) ? qMax(0, x - deltaSpeed) : qMin(0, x + deltaSpeed);
 
257
    y = (y == 0) ? y : (y > 0) ? qMax(0, y - deltaSpeed) : qMin(0, y + deltaSpeed);
191
258
    return QPoint(x, y);
192
259
}
193
260
 
196
263
    if (!object->isWidgetType())
197
264
        return false;
198
265
 
199
 
    QEvent::Type type = event->type();
200
 
    if (type != QEvent::MouseButtonPress &&
201
 
            type != QEvent::MouseButtonRelease &&
202
 
            type != QEvent::MouseMove)
 
266
    const QEvent::Type type = event->type();
 
267
 
 
268
    switch (type) {
 
269
    case QEvent::MouseButtonPress:
 
270
    case QEvent::MouseMove:
 
271
    case QEvent::MouseButtonRelease:
 
272
        break;
 
273
    case QEvent::MouseButtonDblClick: // skip double click
 
274
        return true;
 
275
    default:
203
276
        return false;
204
 
 
205
 
    QMouseEvent *mouseEvent = 0;
206
 
    switch (event->type()) {
207
 
        case QEvent::MouseButtonPress:
208
 
        case QEvent::MouseButtonRelease:
209
 
        case QEvent::MouseMove:
210
 
            mouseEvent = static_cast<QMouseEvent*>(event);
211
 
            break;
212
277
    }
213
278
 
214
 
    if (!mouseEvent || mouseEvent->modifiers() != Qt::NoModifier)
 
279
    QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
 
280
    if (type == QEvent::MouseMove && mouseEvent->buttons() != Qt::LeftButton)
 
281
        return false;
 
282
 
 
283
    if (mouseEvent->modifiers() != Qt::NoModifier)
215
284
        return false;
216
285
 
217
286
    QWidget *viewport = qobject_cast<QWidget*>(object);
219
288
    if (!viewport || !data || data->ignored.removeAll(event))
220
289
        return false;
221
290
 
 
291
    const QPoint mousePos = mouseEvent->pos();
222
292
    bool consumed = false;
223
293
    switch (data->state) {
224
294
 
225
295
    case FlickData::Steady:
226
 
        if (mouseEvent->type() == QEvent::MouseButtonPress)
227
 
            if (mouseEvent->buttons() == Qt::LeftButton) {
228
 
                consumed = true;
229
 
                data->state = FlickData::Pressed;
230
 
                data->pressPos = mouseEvent->pos();
231
 
                data->offset = scrollOffset(data->widget);
232
 
            }
233
 
        break;
234
 
 
235
 
    case FlickData::Pressed:
236
 
        if (mouseEvent->type() == QEvent::MouseButtonRelease) {
237
 
            consumed = true;
238
 
            data->state = FlickData::Steady;
239
 
 
 
296
        if (type == QEvent::MouseButtonPress) {
 
297
            consumed = true;
 
298
            data->pressPos = mousePos;
 
299
        } else if (type == QEvent::MouseButtonRelease) {
 
300
            consumed = true;
240
301
            QMouseEvent *event1 = new QMouseEvent(QEvent::MouseButtonPress,
241
302
                                                  data->pressPos, Qt::LeftButton,
242
303
                                                  Qt::LeftButton, Qt::NoModifier);
243
 
            QMouseEvent *event2 = new QMouseEvent(*mouseEvent);
 
304
            QMouseEvent *event2 = new QMouseEvent(QEvent::MouseButtonRelease,
 
305
                                                  data->pressPos, Qt::LeftButton,
 
306
                                                  Qt::LeftButton, Qt::NoModifier);
244
307
 
245
308
            data->ignored << event1;
246
309
            data->ignored << event2;
247
310
            QApplication::postEvent(object, event1);
248
311
            QApplication::postEvent(object, event2);
249
 
        }
250
 
        if (mouseEvent->type() == QEvent::MouseMove) {
 
312
        } else if (type == QEvent::MouseMove) {
251
313
            consumed = true;
252
 
            data->state = FlickData::ManualScroll;
253
 
            data->dragPos = QCursor::pos();
254
 
            if (!d->ticker.isActive())
255
 
                d->ticker.start(20, this);
 
314
            data->scrollTo(mousePos);
 
315
 
 
316
            const QPoint delta = mousePos - data->pressPos;
 
317
            if (delta.x() > fingerAccuracyThreshold || delta.y() > fingerAccuracyThreshold)
 
318
                data->state = FlickData::ManualScroll;
256
319
        }
257
320
        break;
258
321
 
259
322
    case FlickData::ManualScroll:
260
 
        if (mouseEvent->type() == QEvent::MouseMove) {
 
323
        if (type == QEvent::MouseMove) {
261
324
            consumed = true;
262
 
            QPoint delta = mouseEvent->pos() - data->pressPos;
263
 
            setScrollOffset(data->widget, data->offset - delta);
264
 
        }
265
 
        if (mouseEvent->type() == QEvent::MouseButtonRelease) {
 
325
            data->scrollTo(mousePos);
 
326
        } else if (type == QEvent::MouseButtonRelease) {
266
327
            consumed = true;
267
328
            data->state = FlickData::AutoScroll;
 
329
            data->lastPosValid = false;
 
330
            d->startTicker(this);
268
331
        }
269
332
        break;
270
333
 
271
334
    case FlickData::AutoScroll:
272
 
        if (mouseEvent->type() == QEvent::MouseButtonPress) {
273
 
            consumed = true;
274
 
            data->state = FlickData::Stop;
275
 
            data->speed = QPoint(0, 0);
276
 
            data->pressPos = mouseEvent->pos();
277
 
            data->offset = scrollOffset(data->widget);
278
 
        }
279
 
        if (mouseEvent->type() == QEvent::MouseButtonRelease) {
280
 
            consumed = true;
281
 
            data->state = FlickData::Steady;
282
 
            data->speed = QPoint(0, 0);
283
 
        }
284
 
        break;
285
 
 
286
 
    case FlickData::Stop:
287
 
        if (mouseEvent->type() == QEvent::MouseButtonRelease) {
288
 
            consumed = true;
289
 
            data->state = FlickData::Steady;
290
 
        }
291
 
        if (mouseEvent->type() == QEvent::MouseMove) {
292
 
            consumed = true;
293
 
            data->state = FlickData::ManualScroll;
294
 
            data->dragPos = QCursor::pos();
295
 
            if (!d->ticker.isActive())
296
 
                d->ticker.start(20, this);
297
 
        }
298
 
        break;
299
 
 
 
335
        if (type == QEvent::MouseButtonPress) {
 
336
            consumed = true;
 
337
            data->state = FlickData::AutoScrollAcceleration;
 
338
            data->waitingAcceleration = true;
 
339
            data->accelerationTimer.start();
 
340
            data->updateSpeed(mousePos);
 
341
            data->pressPos = mousePos;
 
342
        } else if (type == QEvent::MouseButtonRelease) {
 
343
            consumed = true;
 
344
            data->state = FlickData::Steady;
 
345
            data->resetSpeed();
 
346
        }
 
347
        break;
 
348
 
 
349
    case FlickData::AutoScrollAcceleration:
 
350
        if (type == QEvent::MouseMove) {
 
351
            consumed = true;
 
352
            data->updateSpeed(mousePos);
 
353
            data->accelerationTimer.start();
 
354
            if (data->speed.isNull())
 
355
                data->state = FlickData::ManualScroll;
 
356
        } else if (type == QEvent::MouseButtonRelease) {
 
357
            consumed = true;
 
358
            data->state = FlickData::AutoScroll;
 
359
            data->waitingAcceleration = false;
 
360
            data->lastPosValid = false;
 
361
        }
 
362
        break;
300
363
    default:
301
364
        break;
302
365
    }
303
 
 
304
 
    return consumed;
 
366
    data->lastPos = mousePos;
 
367
    return true;
305
368
}
306
369
 
307
370
void FlickCharm::timerEvent(QTimerEvent *event)
311
374
    while (item.hasNext()) {
312
375
        item.next();
313
376
        FlickData *data = item.value();
314
 
 
315
 
        if (data->state == FlickData::ManualScroll) {
316
 
            count++;
317
 
            data->speed = QCursor::pos() - data->dragPos;
318
 
            data->dragPos = QCursor::pos();
 
377
        if (data->state == FlickData::AutoScrollAcceleration
 
378
            && data->waitingAcceleration
 
379
            && data->accelerationTimer.elapsed() > 40) {
 
380
            data->state = FlickData::ManualScroll;
 
381
            data->resetSpeed();
319
382
        }
 
383
        if (data->state == FlickData::AutoScroll || data->state == FlickData::AutoScrollAcceleration) {
 
384
            const int timeElapsed = d->timeCounter.elapsed();
 
385
            const QPoint delta = (data->speed) * timeElapsed / 1000;
 
386
            bool hasScrolled = data->scrollWidget(delta.x(), delta.y());
320
387
 
321
 
        if (data->state == FlickData::AutoScroll) {
322
 
            count++;
323
 
            data->speed = deaccelerate(data->speed);
324
 
            QPoint p = scrollOffset(data->widget);
325
 
            setScrollOffset(data->widget, p - data->speed);
326
 
            if (data->speed == QPoint(0, 0))
 
388
            if (data->speed.isNull() || !hasScrolled)
327
389
                data->state = FlickData::Steady;
 
390
            else
 
391
                count++;
 
392
            data->speed = deaccelerate(data->speed, timeElapsed);
328
393
        }
329
394
    }
330
395
 
331
396
    if (!count)
332
397
        d->ticker.stop();
 
398
    else
 
399
        d->timeCounter.start();
333
400
 
334
401
    QObject::timerEvent(event);
335
402
}