Merge lp:~dandrader/unity/phablet_edgeDragGesture into lp:unity/phablet
- phablet_edgeDragGesture
- Merge into phablet
Status: | Merged |
---|---|
Approved by: | Daniel d'Andrada |
Approved revision: | no longer in the source branch. |
Merged at revision: | 681 |
Proposed branch: | lp:~dandrader/unity/phablet_edgeDragGesture |
Merge into: | lp:unity/phablet |
Diff against target: |
1849 lines (+1729/-0) 22 files modified
debian/qml-phone-shell.install (+1/-0) doc/DirectionalDragArea.svg (+311/-0) plugins/CMakeLists.txt (+1/-0) plugins/Ubuntu/CMakeLists.txt (+1/-0) plugins/Ubuntu/Gestures/CMakeLists.txt (+30/-0) plugins/Ubuntu/Gestures/Damper.h (+85/-0) plugins/Ubuntu/Gestures/DirectionalDragArea.cpp (+292/-0) plugins/Ubuntu/Gestures/DirectionalDragArea.h (+179/-0) plugins/Ubuntu/Gestures/UbuntuGesturesGlobal.h (+23/-0) plugins/Ubuntu/Gestures/plugin.cpp (+25/-0) plugins/Ubuntu/Gestures/plugin.h (+31/-0) plugins/Ubuntu/Gestures/qmldir (+2/-0) tests/plugins/CMakeLists.txt (+1/-0) tests/plugins/Ubuntu/CMakeLists.txt (+1/-0) tests/plugins/Ubuntu/Gestures/CMakeLists.txt (+38/-0) tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml (+87/-0) tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml (+90/-0) tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml (+86/-0) tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml (+90/-0) tests/plugins/Ubuntu/Gestures/edgeDragExample.qml (+40/-0) tests/plugins/Ubuntu/Gestures/tst_Damper.cpp (+40/-0) tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp (+275/-0) |
To merge this branch: | bzr merge lp:~dandrader/unity/phablet_edgeDragGesture |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Michał Sawicz | Approve | ||
Review via email: mp+162883@code.launchpad.net |
Commit message
New: DirectionalDragArea component
An area that detects axis-aligned single-finger drag gestures.
Description of the change
New: DirectionalDragArea component
An area that detects axis-aligned single-finger drag gestures.
To be used for edge-drag gestures (like bringing in the launcher).
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:663
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:664
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:665
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:667
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:668
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:668
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:669
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:670
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:670
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : | # |
* instead of the pair direction, positiveDirection, I'd go for a single enum with 4 values, what do you think?
* we talked yesterday about the possibility to add a time threshold as well (within which the touch must cross the distance threshold), do you think you could add it here or in a later change?
* there seems to be a bunch of things common with the QtWidgets QGestureRecognizer (state names, for example) [1] - do you think it would make sense to converge on the same terminology?
* could you add some newlines to tests/plugins/
=====
360 +add_definition
361 +
362 +add_library(
749 +class UBUNTUGESTURES_
856 +#if defined(
857 +# define UBUNTUGESTURES_
858 +#else
859 +# define UBUNTUGESTURES_
860 +#endif
973 + LD_LIBRARY_
982 +target_
maybe directly use the .cpp in test sources instead? We don't really want it to be a library, do we.
=====
538 + if (touchPoint-
is it not possible here for touchPoint to be invalid? why wouldn't QTouchEvent:
=====
I'm wondering if the "pointInside..." calculations couldn't be simplified by using a qreal factor instead of the angle - you'd just need to make sure that:
-d <= Δy <= Δx * f + d
where y is perpendicular to the gesture direction (horizontal positive / left-to-right in that case), d is max deviation, f is the factor; with f = 1 that would mean 45° widening angle; what do you think?
=====
666 +bool DirectionalDrag
667 +{
668 + if (m_orientation == Horizontal) {
669 + if (m_positiveDire
670 + return point.x() >= m_previousPos.x();
shouldn't this take some deviation into account? i.e. if your finger goes slightly back in Recognizing state, won't that mean rejecting the gesture altogether?
=====
744 + recognition will fail. It will also fail it the drag or flick is too short. E.g. a
→ "...fail if the drag..."
=====
740 +/*
741 + An area that detects axis-aligned single-finger drag gestures
could we ask for a little more documentation on the properties?
=====
755 + // stuff that will be set in stone at some point
as discussed, I do agree we need strong defaults here, but allowing advanced use where those would be modifiable could be possible as well
=====
768 + bool positiveDirection() const { return m_positiveDirec
773 + qreal maxDeviation() const {return m_maxDeviation;}
776 + qreal wideningAngle() const {return m_wideningAngle;}
779 + qreal distanceThreshold() const {return m_distanceThres
please use spaces after/before curly braces consistently
=====
764 + enum Orientation { Horizontal = Qt::Horizontal, Vertical = Qt::Vertical };
812 + enum {
please consider using strongly-typed enums (although I don't think we've c...
Michał Sawicz (saviq) wrote : | # |
One more thing:
972 +add_subdirecto
973
974 === added directory 'tests/
Please mimic the same directory structure as the source - so 'tests/
Daniel d'Andrada (dandrader) wrote : | # |
> hmm... any way to make the example work with a pointer? can we enable pointer
> composition?
I'm afraid we will have to add code that manually synthesizes QTouchEvents out of QMouseEvents as Qt::AA_
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:671
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:672
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:673
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:687
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : | # |
W dniu 14.05.2013 14:58, Daniel d'Andrada pisze:
>> hmm... any way to make the example work with a pointer? can we enable pointer
>> > composition?
> I'm afraid we will have to add code that manually synthesizes QTouchEvents out of QMouseEvents as Qt::AA_
Why is that? If I read [1] correctly that should work? Although the
"Unhandled" part might be tricky...
[1]
http://
--
Michał Sawicz <email address hidden>
Canonical Services Ltd.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:688
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:691
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
> One more thing:
>
> 972 +add_subdirecto
> 973
> 974 === added directory 'tests/
>
> Please mimic the same directory structure as the source - so
> 'tests/
Done.
Daniel d'Andrada (dandrader) wrote : | # |
> * instead of the pair direction, positiveDirection, I'd go for a single enum
> with 4 values, what do you think?
Done.
> * we talked yesterday about the possibility to add a time threshold as well
> (within which the touch must cross the distance threshold), do you think you
> could add it here or in a later change?
I can add it in a later change.
> * there seems to be a bunch of things common with the QtWidgets
> QGestureRecognizer (state names, for example) [1] - do you think it would make
> sense to converge on the same terminology?
You mean those signals?
void dragStarted();
void directionalDrag
void dragRejected();
void dragEnded();
Compared to this enum?
enum ResultFlag { Ignore, MayBeGesture, TriggerGesture, FinishGesture, CancelGesture, ConsumeEventHint }
Well, they are intented for different audiences (the former for application code and the latter for the gesture fw engine) in a bit different contexts. I preffer the signal naming the way they are, as they look very clear in meaning IMHO. One thing I see could change though is s/dragRejected/
> * could you add some newlines to tests/plugins/
> for readability?
Done.
>
> =====
>
> 360 +add_definition
> 361 +
> 362 +add_library(
>
> 749 +class UBUNTUGESTURES_
>
> 856 +#if defined(
> 857 +# define UBUNTUGESTURES_
> 858 +#else
> 859 +# define UBUNTUGESTURES_
> 860 +#endif
>
> 973 + LD_LIBRARY_
>
> 982 +target_
>
> maybe directly use the .cpp in test sources instead? We don't really want it
> to be a library, do we.
Why not? Makes testing simpler. Recompiling the whole plugin in the test directory seems wasteful.
>
> =====
>
> 538 + if (touchPoint-
>
> is it not possible here for touchPoint to be invalid?
No. A point has to be released before it disappears from the list of active points.
> why wouldn't QTouchEvent:
We are tracking a specific touch point. Further touch points might come in after the gesture is recgonized but we just don't care.
>
> =====
>
> I'm wondering if the "pointInside..." calculations couldn't be simplified by
> using a qreal factor instead of the angle - you'd just need to make sure that:
>
> -d <= Δy <= Δx * f + d
>
> where y is perpendicular to the gesture direction (horizontal positive / left-
> to-right in that case), d is max deviation, f is the factor; with f = 1 that
> would mean 45° widening angle; what do you think?
I think you mean:
Δx >= -d && abs(Δy) <= (Δx * f) + d
Yes, we can skip use of trigonometric functions by using a widening factor parameter instead of a widening angle.
Done.
>
> =====
>
> 666 +bool DirectionalDrag
> 667 +{
> 668 + if (m_orientation == Horizontal) {
> 669 + if (m_positiveDi...
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:692
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:694
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:694
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : | # |
W dniu 16.05.2013 01:04, Daniel d'Andrada pisze:
>> * there seems to be a bunch of things common with the QtWidgets
>> QGestureRecognizer (state names, for example) [1] - do you think it would make
>> sense to converge on the same terminology?
>
> You mean those signals?
>
> void dragStarted();
> void directionalDrag
> void dragRejected();
> void dragEnded();
>
> Compared to this enum?
>
> enum ResultFlag { Ignore, MayBeGesture, TriggerGesture, FinishGesture, CancelGesture, ConsumeEventHint }
>
> Well, they are intented for different audiences (the former for application code and the latter for the gesture fw engine) in a bit different contexts. I preffer the signal naming the way they are, as they look very clear in meaning IMHO. One thing I see could change though is s/dragRejected/
Your call.
>> =====
>>
>> 360 +add_definition
>> 361 +
>> 362 +add_library(
>>
>> 749 +class UBUNTUGESTURES_
>>
>> 856 +#if defined(
>> 857 +# define UBUNTUGESTURES_
>> 858 +#else
>> 859 +# define UBUNTUGESTURES_
>> 860 +#endif
>>
>> 973 + LD_LIBRARY_
>>
>> 982 +target_
>>
>> maybe directly use the .cpp in test sources instead? We don't really want it
>> to be a library, do we.
>
> Why not? Makes testing simpler. Recompiling the whole plugin in the test directory seems wasteful.
There's just a lot here that suggests this is meant to be used as a
shared library, which it isn't. But I can live with that. We should
probably simply find a way to use the plugins from C++.
>> 764 + enum Orientation { Horizontal = Qt::Horizontal, Vertical =
>> Qt::Vertical };
>>
>> 812 + enum {
>>
>> please consider using strongly-typed enums (although I don't think we've
>> checked how QML currently deals with passing them to/from QML - so we might
>> need to wait there)
>
> Yeah, I think we might need to wait indeed.
I've used them successfully in [1] - they end up as numbers in QML, so
there's some casting involved, but they seem to work fine.
>> do you have a Nexus 10 to try it out? I'm getting quite some false negatives
>> with the examples
>
> No, I don't. Do you have a Galaxy Nexus to try it out and see if results differ? That's the device I have.
>
> It seems that drags coming from the top, left and right borders are being filtered out by mir as those borders are reserved for the shell and qmlscene is not the shell? Because no input events come at all in those situations. If you start dragging already from withing the window it works.
> Also from the bottom border it always works, I guess it's because the bottom edge is for application's tool bars.
You can stop qml-phone-shell by removing its line from
/etc/phone-services on the device and `sudo restart ubuntu-session`.
You'll get all the input then.
>> also, tapping in the edge area results in the red rectangle to stay on screen
>
> Details, deta...
Daniel d'Andrada (dandrader) wrote : | # |
> > It seems that drags coming from the top, left and right borders are being
> filtered out by mir as those borders are reserved for the shell and qmlscene
> is not the shell? Because no input events come at all in those situations. If
> you start dragging already from withing the window it works.
> > Also from the bottom border it always works, I guess it's because the bottom
> edge is for application's tool bars.
>
> You can stop qml-phone-shell by removing its line from
> /etc/phone-services on the device and `sudo restart ubuntu-session`.
> You'll get all the input then.
>
qml-phone-shell wasn't running while I was trying out the example/test app on the device.
Michał Sawicz (saviq) wrote : | # |
1087 + COMMAND cp "${CMAKE_
This should use ${qmlFiles}, too.
Michał Sawicz (saviq) wrote : | # |
522 +qreal DirectionalDrag
523 +{
524 + // convert factor (which is in fact a tangent value) to its corresponding
525 + // angle in degrees
526 + return qAtan(m_
527 +}
528 +
529 +void DirectionalDrag
530 +{
531 + qreal newFactor = qTan(angle * M_PI / 180.0);
532 +
533 + if (m_wideningFactor != newFactor) {
534 + m_wideningFactor = newFactor;
535 + Q_EMIT wideningAngleCh
536 + }
537 +}
Depending on rounding errors, wideningAngle() might return a different value than was set (and emitted).
Shouldn't this be int now that we're doing degrees?
Daniel d'Andrada (dandrader) wrote : | # |
> 522 +qreal DirectionalDrag
> 523 +{
> 524 + // convert factor (which is in fact a tangent value) to its
> corresponding
> 525 + // angle in degrees
> 526 + return qAtan(m_
> 527 +}
> 528 +
> 529 +void DirectionalDrag
> 530 +{
> 531 + qreal newFactor = qTan(angle * M_PI / 180.0);
> 532 +
> 533 + if (m_wideningFactor != newFactor) {
> 534 + m_wideningFactor = newFactor;
> 535 + Q_EMIT wideningAngleCh
> 536 + }
> 537 +}
>
> Depending on rounding errors, wideningAngle() might return a different value
> than was set (and emitted).
Fixed.
> Shouldn't this be int now that we're doing degrees?
No. Nothing stops you from having widening angles such as 9.36 degrees
Daniel d'Andrada (dandrader) wrote : | # |
> 1087 + COMMAND cp "${CMAKE_
> ${CMAKE_
>
> This should use ${qmlFiles}, too.
Done.
Michał Sawicz (saviq) wrote : | # |
694 + case Upwards:
695 + return dY <= m_maxDeviation && qFabs(dX) <= (m_maxDeviation + dY) * m_wideningFactor + m_maxDeviation;
696 + case Downwards:
697 + return dY >= -m_maxDeviation && qFabs(dX) <= (m_maxDeviation + dY) * m_wideningFactor + m_maxDeviation;
698 + case Leftwards:
699 + return dX <= m_maxDeviation && qFabs(dY) <= (m_maxDeviation + dX) * m_wideningFactor + m_maxDeviation;
700 + default: // Rightwards:
701 + return dX >= -m_maxDeviation && qFabs(dY) <= (m_maxDeviation + dX) * m_wideningFactor + m_maxDeviation;
Why adding maxDeviation before multiplying by the factor?
Michał Sawicz (saviq) wrote : | # |
W dniu 16.05.2013 15:52, Daniel d'Andrada pisze:
> No. Nothing stops you from having widening angles such as 9.36 degrees
But we can ;)
--
Michał Sawicz <email address hidden>
Canonical Services Ltd.
Michał Sawicz (saviq) wrote : | # |
I'll have a fresh overview look tomorrow morning, but this looks good!
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:696
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
> 694 + case Upwards:
> 695 + return dY <= m_maxDeviation && qFabs(dX) <= (m_maxDeviation + dY) *
> m_wideningFactor + m_maxDeviation;
> 696 + case Downwards:
> 697 + return dY >= -m_maxDeviation && qFabs(dX) <= (m_maxDeviation + dY) *
> m_wideningFactor + m_maxDeviation;
> 698 + case Leftwards:
> 699 + return dX <= m_maxDeviation && qFabs(dY) <= (m_maxDeviation + dX) *
> m_wideningFactor + m_maxDeviation;
> 700 + default: // Rightwards:
> 701 + return dX >= -m_maxDeviation && qFabs(dY) <= (m_maxDeviation + dX) *
> m_wideningFactor + m_maxDeviation;
>
> Why adding maxDeviation before multiplying by the factor?
Because the widening starts from startPos - maxDeviation, not from startPos itself (see doc/Directional
Michał Sawicz (saviq) wrote : | # |
803 +#include <QQuickItem>
1025 +#include <QQmlExtensionP
1513 +#include <QtTest/QtTest>
1514 +#include <QObject>
1515 +#include <qpa/qwindowsys
1516 +#include <QQuickView>
1517 +#include <QQmlEngine>
Please use <QtQuick/
=====
Damper.h should #include <QtCore/QPointF>.
=====
407 + void setMaxDelta(Type maxDelta) {
408 + m_maxDelta = maxDelta;
409 + }
418 + if (delta > 0 && delta > m_maxDelta) {
419 + m_value += delta - m_maxDelta;
420 + } else if (delta < 0 && delta < -m_maxDelta) {
421 + m_value += delta - m_maxDelta;
422 + }
The > 0, < 0 seem unnecessary? Although setMaxDelta() should make sure that it's > 0?
=====
434 +/*
435 + A point that has its movement dampened.
436 + */
437 +class DampedPointF {
438 +public:
439 + void setMaxDelta(qreal maxDelta) {
440 + m_x.setMaxDelta
441 + m_y.setMaxDelta
442 + }
443 +
444 + qreal maxDelta() const { return m_x.maxDelta(); }
445 +
446 + void reset(const QPointF &point) {
447 + m_x.reset(
448 + m_y.reset(
449 + }
450 +
451 + void update(const QPointF &point) {
452 + m_x.update(
453 + m_y.update(
454 + }
455 +
456 + qreal x() const { return m_x.value(); }
457 + qreal y() const { return m_y.value(); }
458 +private:
459 + Damper<qreal> m_x;
460 + Damper<qreal> m_y;
461 +};
I know it's probably minor (square vs. circular dampening area), but shouldn't we use QPointF::operator- and QPointF:
=====
561 + if (m_state == Rejected)
562 + return 0.0;
Please wrap all blocks in braces.
=====
633 + if (!pointInsideAl
634 + setState(Rejected);
635 + return;
636 + }
637 +
638 + m_previousDampe
639 + m_previousDampe
640 + m_dampedPos.
641 +
642 + if (!movingInRight
643 + setState(Rejected);
644 + return;
645 + }
704 +bool DirectionalDrag
705 +{
706 + switch (m_direction) {
707 + case Upwards:
708 + return m_dampedPos.y() <= m_previousDampe
709 + case Downwards:
710 + return m_dampedPos.y() >= m_previousDampe
711 + case Leftwards:
712 + return m_dampedPos.x() <= m_previousDampe
713 + default: // Rightwards:
714 + return m_dampedPos.x() >= m_previousDampe
715 + }
716 +}
I would think I should be able to move within maxDeviation from the start point in Recognizing state and that would not cause a rejection. But if I'm reading the above correctly, I'm only really allowed to move within movementDamperM
=====
851 + Q_PROPERTY(qreal movementDamperM
852 + READ movementDamperM
853 + WRITE setMovementDamp
854 + NOTIFY movementDamperM
I'd probably go for ...
Daniel d'Andrada (dandrader) wrote : | # |
> 803 +#include <QQuickItem>
>
> 1025 +#include <QQmlExtensionP
>
> 1513 +#include <QtTest/QtTest>
> 1514 +#include <QObject>
> 1515 +#include <qpa/qwindowsys
> 1516 +#include <QQuickView>
> 1517 +#include <QQmlEngine>
>
> Please use <QtQuick/
Done.
>
> =====
>
> Damper.h should #include <QtCore/QPointF>.
Done.
>
> =====
>
> 407 + void setMaxDelta(Type maxDelta) {
> 408 + m_maxDelta = maxDelta;
> 409 + }
>
> 418 + if (delta > 0 && delta > m_maxDelta) {
> 419 + m_value += delta - m_maxDelta;
> 420 + } else if (delta < 0 && delta < -m_maxDelta) {
> 421 + m_value += delta - m_maxDelta;
> 422 + }
>
> The > 0, < 0 seem unnecessary?
No, it's necessary. I do have to distinguish between a negative and a positive delta. Speaking of which, I just spotted a bug in diff line 421. It should be "m_value += delta + m_maxDelta;" instead. Fixed it.
> Although setMaxDelta() should make sure that
> it's > 0?
Yeah, added the check.
>
> =====
>
> 434 +/*
> 435 + A point that has its movement dampened.
> 436 + */
> 437 +class DampedPointF {
> 438 +public:
> 439 + void setMaxDelta(qreal maxDelta) {
> 440 + m_x.setMaxDelta
> 441 + m_y.setMaxDelta
> 442 + }
> 443 +
> 444 + qreal maxDelta() const { return m_x.maxDelta(); }
> 445 +
> 446 + void reset(const QPointF &point) {
> 447 + m_x.reset(
> 448 + m_y.reset(
> 449 + }
> 450 +
> 451 + void update(const QPointF &point) {
> 452 + m_x.update(
> 453 + m_y.update(
> 454 + }
> 455 +
> 456 + qreal x() const { return m_x.value(); }
> 457 + qreal y() const { return m_y.value(); }
> 458 +private:
> 459 + Damper<qreal> m_x;
> 460 + Damper<qreal> m_y;
> 461 +};
>
> I know it's probably minor (square vs. circular dampening area), but shouldn't
> we use QPointF::operator- and QPointF:
Using a circular area is computationally more expensive and we're just fine with this less accurate method.
Using a manhattan lenght would result in an area defined by a square rotated by 45 degrees instead of an axis-aligned square as it is now. So, in the end, these two approaches are equivalent (a square area).
>
> =====
>
> 561 + if (m_state == Rejected)
> 562 + return 0.0;
>
> Please wrap all blocks in braces.
Done.
>
> =====
>
> 633 + if (!pointInsideAl
> 634 + setState(Rejected);
> 635 + return;
> 636 + }
> 637 +
> 638 + m_previousDampe
> 639 + m_previousDampe
> 640 + m_dampedPos.
> 641 +
> 642 + if (!movingInRight
> 643 + setState(Rejected);
> 644 + return;
> 645 + }
>
> 704 +bool DirectionalDrag
> 705 +{
> 706 + switch (m_direction) {
> 707 + case Upwards:
> 708 + return m_dampedPos.y() <= m_previousDampe
> 709 + case Downwards:
> 710 + return m_dampedPo...
Daniel d'Andrada (dandrader) wrote : | # |
Ah, and thanks for the thorough reviews. Code is getting better and better!
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:704
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:704
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : | # |
W dniu 17.05.2013 20:37, Daniel d'Andrada pisze:
>> I wonder if DirectionalDrag
>> be exposed to QML? Or maybe a "dragging" boolean?
>
> Yeah, we could expose the state variable indeed.
> Done.
818 + // The current state of the directional drag gesture.
819 + Q_PROPERTY(
gestureStateCha
Could we go with "status" to be consistent with other QML components?
And I would still like a boolean "dragging" more in favor of dragEnded,
dragStarted and dragRecognized signals.
>> Shouldn't dragValue be reset to 0 when going back to WaitingForTouch? Or maybe
>> that's a higher level's responsibility to make sure of that...
>
> No, I think it should stay as it is. It's up to the application to decide what to do once the gesture ends.
731 + default: // Rejected
732 + Q_EMIT dragRejected();
733 + Q_EMIT distanceChanged
Shouldn't that not emit the distance then? I'm just worried that people
might rely on it to cancel the movement, but then the dragRejected
signal (or draggingChanged
should already be enough to say "the gesture is uninteresting, do what
you need to cancel".
>> 1070 + LD_LIBRARY_
>>
>> This should be set as an ENVIRONMENT property on the test instead.
>
> Why? So you want CMake to pass it as a DEFINE to tst_Directional
No, I mean it should be possible to use set_target_
that environment var to the target, just as we do in add_qml_test() to
set the QPA platform to "minimal".
--
Michał Sawicz <email address hidden>
Canonical Services Ltd.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:704
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
> 818 + // The current state of the directional drag gesture.
> 819 + Q_PROPERTY(
> gestureStateCha
>
> Could we go with "status" to be consistent with other QML components?
Done.
>
> And I would still like a boolean "dragging" more in favor of dragEnded,
> dragStarted and dragRecognized signals.
Done.
>
> >> Shouldn't dragValue be reset to 0 when going back to WaitingForTouch? Or
> maybe
> >> that's a higher level's responsibility to make sure of that...
> >
> > No, I think it should stay as it is. It's up to the application to decide
> what to do once the gesture ends.
>
> 731 + default: // Rejected
> 732 + Q_EMIT dragRejected();
> 733 + Q_EMIT distanceChanged
>
> Shouldn't that not emit the distance then? I'm just worried that people
> might rely on it to cancel the movement, but then the dragRejected
> signal (or draggingChanged
> should already be enough to say "the gesture is uninteresting, do what
> you need to cancel".
For the sake of consistency with the transition to WaitingForTouch, I made it keep its last valid value while on Rejected state.
>
> >> 1070 + LD_LIBRARY_
> >>
> >> This should be set as an ENVIRONMENT property on the test instead.
> >
> > Why? So you want CMake to pass it as a DEFINE to tst_Directional
> during compilation?
>
> No, I mean it should be possible to use set_target_
> that environment var to the target, just as we do in add_qml_test() to
> set the QPA platform to "minimal".
The test for DirectionalDragArea is a custom target (using add_custom_
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:707
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : | # |
889 + bool dragging() const { return m_status && (Undecided || Recognized); }
This looks incorrect. Undecided || Recognized is always true (assuming their values are 1 and 2, respectively) so dragging becomes (bool)m_status, which will, only be false in WaitingForTouch status.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:708
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
> 889 + bool dragging() const { return m_status && (Undecided ||
> Recognized); }
>
> This looks incorrect. Undecided || Recognized is always true (assuming their
> values are 1 and 2, respectively) so dragging becomes (bool)m_status, which
> will, only be false in WaitingForTouch status.
Right, they're not flags. Silly mistake. Fixed.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:709
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'debian/qml-phone-shell.install' | |||
2 | --- debian/qml-phone-shell.install 2013-05-16 12:02:23 +0000 | |||
3 | +++ debian/qml-phone-shell.install 2013-05-20 13:14:26 +0000 | |||
4 | @@ -16,3 +16,4 @@ | |||
5 | 16 | /usr/share/qml-phone-shell/plugins/LightDM/* | 16 | /usr/share/qml-phone-shell/plugins/LightDM/* |
6 | 17 | /usr/share/qml-phone-shell/plugins/Unity/* | 17 | /usr/share/qml-phone-shell/plugins/Unity/* |
7 | 18 | /usr/share/qml-phone-shell/plugins/Utils/* | 18 | /usr/share/qml-phone-shell/plugins/Utils/* |
8 | 19 | /usr/share/qml-phone-shell/plugins/Ubuntu/* | ||
9 | 19 | 20 | ||
10 | === added file 'doc/DirectionalDragArea.svg' | |||
11 | --- doc/DirectionalDragArea.svg 1970-01-01 00:00:00 +0000 | |||
12 | +++ doc/DirectionalDragArea.svg 2013-05-20 13:14:26 +0000 | |||
13 | @@ -0,0 +1,311 @@ | |||
14 | 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
15 | 2 | <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||
16 | 3 | |||
17 | 4 | <svg | ||
18 | 5 | xmlns:dc="http://purl.org/dc/elements/1.1/" | ||
19 | 6 | xmlns:cc="http://creativecommons.org/ns#" | ||
20 | 7 | xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||
21 | 8 | xmlns:svg="http://www.w3.org/2000/svg" | ||
22 | 9 | xmlns="http://www.w3.org/2000/svg" | ||
23 | 10 | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||
24 | 11 | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||
25 | 12 | width="644.35803" | ||
26 | 13 | height="626.32886" | ||
27 | 14 | id="svg2" | ||
28 | 15 | version="1.1" | ||
29 | 16 | inkscape:version="0.48.4 r9939" | ||
30 | 17 | sodipodi:docname="DirectionalDragArea.svg"> | ||
31 | 18 | <defs | ||
32 | 19 | id="defs4"> | ||
33 | 20 | <linearGradient | ||
34 | 21 | id="linearGradient6853"> | ||
35 | 22 | <stop | ||
36 | 23 | style="stop-color:#00adff;stop-opacity:1;" | ||
37 | 24 | offset="0" | ||
38 | 25 | id="stop6855" /> | ||
39 | 26 | <stop | ||
40 | 27 | id="stop6861" | ||
41 | 28 | offset="0.82191783" | ||
42 | 29 | style="stop-color:#00adff;stop-opacity:0.49803922;" /> | ||
43 | 30 | <stop | ||
44 | 31 | style="stop-color:#000000;stop-opacity:0;" | ||
45 | 32 | offset="1" | ||
46 | 33 | id="stop6857" /> | ||
47 | 34 | </linearGradient> | ||
48 | 35 | <marker | ||
49 | 36 | inkscape:stockid="Arrow1Send" | ||
50 | 37 | orient="auto" | ||
51 | 38 | refY="0" | ||
52 | 39 | refX="0" | ||
53 | 40 | id="Arrow1Send" | ||
54 | 41 | style="overflow:visible"> | ||
55 | 42 | <path | ||
56 | 43 | id="path4958" | ||
57 | 44 | d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" | ||
58 | 45 | style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" | ||
59 | 46 | transform="matrix(-0.2,0,0,-0.2,-1.2,0)" | ||
60 | 47 | inkscape:connector-curvature="0" /> | ||
61 | 48 | </marker> | ||
62 | 49 | <marker | ||
63 | 50 | inkscape:stockid="Arrow1Sstart" | ||
64 | 51 | orient="auto" | ||
65 | 52 | refY="0" | ||
66 | 53 | refX="0" | ||
67 | 54 | id="Arrow1Sstart" | ||
68 | 55 | style="overflow:visible"> | ||
69 | 56 | <path | ||
70 | 57 | id="path4955" | ||
71 | 58 | d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" | ||
72 | 59 | style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" | ||
73 | 60 | transform="matrix(0.2,0,0,0.2,1.2,0)" | ||
74 | 61 | inkscape:connector-curvature="0" /> | ||
75 | 62 | </marker> | ||
76 | 63 | <marker | ||
77 | 64 | inkscape:stockid="Arrow1Mstart" | ||
78 | 65 | orient="auto" | ||
79 | 66 | refY="0" | ||
80 | 67 | refX="0" | ||
81 | 68 | id="Arrow1Mstart" | ||
82 | 69 | style="overflow:visible"> | ||
83 | 70 | <path | ||
84 | 71 | id="path4949" | ||
85 | 72 | d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" | ||
86 | 73 | style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" | ||
87 | 74 | transform="matrix(0.4,0,0,0.4,4,0)" | ||
88 | 75 | inkscape:connector-curvature="0" /> | ||
89 | 76 | </marker> | ||
90 | 77 | <marker | ||
91 | 78 | inkscape:stockid="Arrow1Sstart" | ||
92 | 79 | orient="auto" | ||
93 | 80 | refY="0" | ||
94 | 81 | refX="0" | ||
95 | 82 | id="Arrow1Sstart-4" | ||
96 | 83 | style="overflow:visible"> | ||
97 | 84 | <path | ||
98 | 85 | inkscape:connector-curvature="0" | ||
99 | 86 | id="path4955-5" | ||
100 | 87 | d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" | ||
101 | 88 | style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" | ||
102 | 89 | transform="matrix(0.2,0,0,0.2,1.2,0)" /> | ||
103 | 90 | </marker> | ||
104 | 91 | <marker | ||
105 | 92 | inkscape:stockid="Arrow1Send" | ||
106 | 93 | orient="auto" | ||
107 | 94 | refY="0" | ||
108 | 95 | refX="0" | ||
109 | 96 | id="Arrow1Send-4" | ||
110 | 97 | style="overflow:visible"> | ||
111 | 98 | <path | ||
112 | 99 | inkscape:connector-curvature="0" | ||
113 | 100 | id="path4958-6" | ||
114 | 101 | d="M 0,0 5,-5 -12.5,0 5,5 0,0 z" | ||
115 | 102 | style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt" | ||
116 | 103 | transform="matrix(-0.2,0,0,-0.2,-1.2,0)" /> | ||
117 | 104 | </marker> | ||
118 | 105 | </defs> | ||
119 | 106 | <sodipodi:namedview | ||
120 | 107 | id="base" | ||
121 | 108 | pagecolor="#ffffff" | ||
122 | 109 | bordercolor="#666666" | ||
123 | 110 | borderopacity="1.0" | ||
124 | 111 | inkscape:pageopacity="1" | ||
125 | 112 | inkscape:pageshadow="2" | ||
126 | 113 | inkscape:zoom="1.4158879" | ||
127 | 114 | inkscape:cx="311.5" | ||
128 | 115 | inkscape:cy="313" | ||
129 | 116 | inkscape:document-units="px" | ||
130 | 117 | inkscape:current-layer="layer1" | ||
131 | 118 | showgrid="false" | ||
132 | 119 | showguides="true" | ||
133 | 120 | inkscape:guide-bbox="true" | ||
134 | 121 | fit-margin-top="5" | ||
135 | 122 | fit-margin-left="5" | ||
136 | 123 | fit-margin-right="5" | ||
137 | 124 | fit-margin-bottom="5" | ||
138 | 125 | inkscape:window-width="1920" | ||
139 | 126 | inkscape:window-height="1056" | ||
140 | 127 | inkscape:window-x="0" | ||
141 | 128 | inkscape:window-y="24" | ||
142 | 129 | inkscape:window-maximized="1" /> | ||
143 | 130 | <metadata | ||
144 | 131 | id="metadata7"> | ||
145 | 132 | <rdf:RDF> | ||
146 | 133 | <cc:Work | ||
147 | 134 | rdf:about=""> | ||
148 | 135 | <dc:format>image/svg+xml</dc:format> | ||
149 | 136 | <dc:type | ||
150 | 137 | rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||
151 | 138 | <dc:title /> | ||
152 | 139 | </cc:Work> | ||
153 | 140 | </rdf:RDF> | ||
154 | 141 | </metadata> | ||
155 | 142 | <g | ||
156 | 143 | inkscape:label="Layer 1" | ||
157 | 144 | inkscape:groupmode="layer" | ||
158 | 145 | id="layer1" | ||
159 | 146 | transform="translate(-253.65772,218.97803)"> | ||
160 | 147 | <path | ||
161 | 148 | style="fill:#00adff;fill-opacity:0.75686275;stroke:none" | ||
162 | 149 | d="M 259.64804,57.193502 792.57928,-142.14719 793.2573,341.96589 259.60777,174.1189 z" | ||
163 | 150 | id="path6851" | ||
164 | 151 | inkscape:connector-curvature="0" | ||
165 | 152 | sodipodi:nodetypes="ccccc" /> | ||
166 | 153 | <path | ||
167 | 154 | style="fill:none;stroke:#000000;stroke-width:2.09098315;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" | ||
168 | 155 | d="m 890.84952,-178.96696 -631.14314,236.973167 0,116.242063 630.29325,197.35579" | ||
169 | 156 | id="path4887" | ||
170 | 157 | inkscape:connector-curvature="0" | ||
171 | 158 | sodipodi:nodetypes="cccc" /> | ||
172 | 159 | <path | ||
173 | 160 | style="fill:none;stroke:#000000;stroke-width:2.09098315;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:12.5458998, 12.5458998;stroke-dashoffset:0" | ||
174 | 161 | d="m 260.83781,59.275793 630.97079,0" | ||
175 | 162 | id="path4891" | ||
176 | 163 | inkscape:connector-curvature="0" /> | ||
177 | 164 | <path | ||
178 | 165 | style="fill:none;stroke:#000000;stroke-width:2.09098315;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:12.5458998, 12.5458998;stroke-dashoffset:0" | ||
179 | 166 | d="m 260.99944,172.08634 630.97079,0" | ||
180 | 167 | id="path4891-7" | ||
181 | 168 | inkscape:connector-curvature="0" /> | ||
182 | 169 | <path | ||
183 | 170 | style="fill:none;stroke:#000000;stroke-width:2.09098315;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:8.3639332, 8.3639332;stroke-dashoffset:0" | ||
184 | 171 | d="m 793.23579,-189.85001 0,591.15535" | ||
185 | 172 | id="path4911" | ||
186 | 173 | inkscape:connector-curvature="0" | ||
187 | 174 | sodipodi:nodetypes="cc" /> | ||
188 | 175 | <path | ||
189 | 176 | sodipodi:type="arc" | ||
190 | 177 | style="fill:none;stroke:#000000;stroke-width:0.69999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" | ||
191 | 178 | id="path4915" | ||
192 | 179 | sodipodi:cx="259.74588" | ||
193 | 180 | sodipodi:cy="211.80014" | ||
194 | 181 | sodipodi:rx="18.943148" | ||
195 | 182 | sodipodi:ry="18.943148" | ||
196 | 183 | d="m 277.40703,204.94983 a 18.943148,18.943148 0 0 1 1.28197,6.81725" | ||
197 | 184 | transform="matrix(2.987119,0,0,2.987119,-515.9493,-573.75675)" | ||
198 | 185 | sodipodi:open="true" | ||
199 | 186 | sodipodi:start="5.9131755" | ||
200 | 187 | sodipodi:end="6.28144" /> | ||
201 | 188 | <path | ||
202 | 189 | sodipodi:type="arc" | ||
203 | 190 | style="fill:none;stroke:#000000;stroke-width:0.69999999;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" | ||
204 | 191 | id="path4915-5" | ||
205 | 192 | sodipodi:cx="259.74588" | ||
206 | 193 | sodipodi:cy="211.80014" | ||
207 | 194 | sodipodi:rx="18.943148" | ||
208 | 195 | sodipodi:ry="18.943148" | ||
209 | 196 | d="m 278.67886,211.17971 a 18.943148,18.943148 0 0 1 -0.8432,6.24205" | ||
210 | 197 | transform="matrix(2.987119,0,0,2.987119,-517.22894,-458.90756)" | ||
211 | 198 | sodipodi:start="6.250427" | ||
212 | 199 | sodipodi:end="6.5844864" | ||
213 | 200 | sodipodi:open="true" /> | ||
214 | 201 | <path | ||
215 | 202 | sodipodi:type="arc" | ||
216 | 203 | style="fill:#000000;fill-opacity:1;stroke:none" | ||
217 | 204 | id="path4935" | ||
218 | 205 | sodipodi:cx="282.05548" | ||
219 | 206 | sodipodi:cy="227.78796" | ||
220 | 207 | sodipodi:rx="1.00761" | ||
221 | 208 | sodipodi:ry="1.00761" | ||
222 | 209 | d="m 283.06309,227.78796 a 1.00761,1.00761 0 1 1 -2.01522,0 1.00761,1.00761 0 1 1 2.01522,0 z" | ||
223 | 210 | transform="matrix(2.987119,0,0,2.987119,-525.77343,-564.0127)" /> | ||
224 | 211 | <path | ||
225 | 212 | style="fill:none;stroke:#000000;stroke-width:2.09098315;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#Arrow1Sstart);marker-end:url(#Arrow1Send)" | ||
226 | 213 | d="m 317.09757,65.254063 0,42.548767" | ||
227 | 214 | id="path4937" | ||
228 | 215 | inkscape:connector-curvature="0" /> | ||
229 | 216 | <path | ||
230 | 217 | style="fill:none;stroke:#000000;stroke-width:2.09098315;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#Arrow1Sstart);marker-end:url(#Arrow1Send)" | ||
231 | 218 | d="m 308.28828,116.39919 -42.54876,0" | ||
232 | 219 | id="path4937-9" | ||
233 | 220 | inkscape:connector-curvature="0" /> | ||
234 | 221 | <text | ||
235 | 222 | xml:space="preserve" | ||
236 | 223 | style="font-size:29.87118912px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold" | ||
237 | 224 | x="321.45822" | ||
238 | 225 | y="92.085648" | ||
239 | 226 | id="text5787" | ||
240 | 227 | sodipodi:linespacing="125%"><tspan | ||
241 | 228 | sodipodi:role="line" | ||
242 | 229 | id="tspan5789" | ||
243 | 230 | x="321.45822" | ||
244 | 231 | y="92.085648" | ||
245 | 232 | style="font-size:11.94847584px">maxDeviation</tspan></text> | ||
246 | 233 | <text | ||
247 | 234 | xml:space="preserve" | ||
248 | 235 | style="font-size:29.87118912px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold" | ||
249 | 236 | x="322.99289" | ||
250 | 237 | y="48.58828" | ||
251 | 238 | id="text5787-2" | ||
252 | 239 | sodipodi:linespacing="125%"><tspan | ||
253 | 240 | sodipodi:role="line" | ||
254 | 241 | id="tspan5789-5" | ||
255 | 242 | x="322.99289" | ||
256 | 243 | y="48.58828" | ||
257 | 244 | style="font-size:11.94847584px">wideningAngle</tspan></text> | ||
258 | 245 | <path | ||
259 | 246 | inkscape:connector-curvature="0" | ||
260 | 247 | id="path5830" | ||
261 | 248 | d="m 315.70321,-189.85001 0,225.307165" | ||
262 | 249 | style="fill:none;stroke:#000000;stroke-width:2.09098315;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:8.3639332, 8.3639332;stroke-dashoffset:0" | ||
263 | 250 | sodipodi:nodetypes="cc" /> | ||
264 | 251 | <path | ||
265 | 252 | style="fill:none;stroke:#000000;stroke-width:2.09098315;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" | ||
266 | 253 | d="m 315.79005,-204.37393 476.77774,0" | ||
267 | 254 | id="path5832" | ||
268 | 255 | inkscape:connector-curvature="0" | ||
269 | 256 | sodipodi:nodetypes="cc" /> | ||
270 | 257 | <path | ||
271 | 258 | style="fill:none;stroke:#000000;stroke-width:2.09098315;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" | ||
272 | 259 | d="m 315.303,-212.93254 0,17.24097" | ||
273 | 260 | id="path6839" | ||
274 | 261 | inkscape:connector-curvature="0" /> | ||
275 | 262 | <path | ||
276 | 263 | inkscape:connector-curvature="0" | ||
277 | 264 | id="path6841" | ||
278 | 265 | d="m 792.91626,-212.93254 0,17.24097" | ||
279 | 266 | style="fill:none;stroke:#000000;stroke-width:2.09098315;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> | ||
280 | 267 | <text | ||
281 | 268 | sodipodi:linespacing="125%" | ||
282 | 269 | id="text6843" | ||
283 | 270 | y="-188.72206" | ||
284 | 271 | x="483.68591" | ||
285 | 272 | style="font-size:29.87118912px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold" | ||
286 | 273 | xml:space="preserve"><tspan | ||
287 | 274 | style="font-size:11.94847584px" | ||
288 | 275 | y="-188.72206" | ||
289 | 276 | x="483.68591" | ||
290 | 277 | id="tspan6845" | ||
291 | 278 | sodipodi:role="line">distanceThreshold</tspan></text> | ||
292 | 279 | <text | ||
293 | 280 | sodipodi:linespacing="125%" | ||
294 | 281 | id="text6847" | ||
295 | 282 | y="121.95684" | ||
296 | 283 | x="321.45822" | ||
297 | 284 | style="font-size:29.87118912px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold" | ||
298 | 285 | xml:space="preserve"><tspan | ||
299 | 286 | style="font-size:11.94847584px" | ||
300 | 287 | y="121.95684" | ||
301 | 288 | x="321.45822" | ||
302 | 289 | id="tspan6849" | ||
303 | 290 | sodipodi:role="line">Position of touch press</tspan></text> | ||
304 | 291 | <rect | ||
305 | 292 | style="fill:#00adff;fill-opacity:0.75686275;stroke:none" | ||
306 | 293 | id="rect6863" | ||
307 | 294 | width="35.257538" | ||
308 | 295 | height="35.935566" | ||
309 | 296 | x="295.58365" | ||
310 | 297 | y="318.91293" /> | ||
311 | 298 | <text | ||
312 | 299 | xml:space="preserve" | ||
313 | 300 | style="font-size:29.87118912px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold" | ||
314 | 301 | x="335.01886" | ||
315 | 302 | y="340.96045" | ||
316 | 303 | id="text6865" | ||
317 | 304 | sodipodi:linespacing="125%"><tspan | ||
318 | 305 | sodipodi:role="line" | ||
319 | 306 | id="tspan6867" | ||
320 | 307 | x="335.01886" | ||
321 | 308 | y="340.96045" | ||
322 | 309 | style="font-size:11.94847584px">Valid area for touch position during recognition</tspan></text> | ||
323 | 310 | </g> | ||
324 | 311 | </svg> | ||
325 | 0 | 312 | ||
326 | === modified file 'plugins/CMakeLists.txt' | |||
327 | --- plugins/CMakeLists.txt 2013-04-19 15:06:41 +0000 | |||
328 | +++ plugins/CMakeLists.txt 2013-05-20 13:14:26 +0000 | |||
329 | @@ -1,3 +1,4 @@ | |||
330 | 1 | add_subdirectory(Ubuntu) | ||
331 | 1 | add_subdirectory(Utils) | 2 | add_subdirectory(Utils) |
332 | 2 | add_subdirectory(Unity) | 3 | add_subdirectory(Unity) |
333 | 3 | add_subdirectory(HudClient) | 4 | add_subdirectory(HudClient) |
334 | 4 | 5 | ||
335 | === added directory 'plugins/Ubuntu' | |||
336 | === added file 'plugins/Ubuntu/CMakeLists.txt' | |||
337 | --- plugins/Ubuntu/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
338 | +++ plugins/Ubuntu/CMakeLists.txt 2013-05-20 13:14:26 +0000 | |||
339 | @@ -0,0 +1,1 @@ | |||
340 | 1 | add_subdirectory(Gestures) | ||
341 | 0 | 2 | ||
342 | === added directory 'plugins/Ubuntu/Gestures' | |||
343 | === added file 'plugins/Ubuntu/Gestures/CMakeLists.txt' | |||
344 | --- plugins/Ubuntu/Gestures/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
345 | +++ plugins/Ubuntu/Gestures/CMakeLists.txt 2013-05-20 13:14:26 +0000 | |||
346 | @@ -0,0 +1,30 @@ | |||
347 | 1 | set(CMAKE_AUTOMOC ON) | ||
348 | 2 | |||
349 | 3 | include(FindPkgConfig) | ||
350 | 4 | find_package(Qt5Core REQUIRED) | ||
351 | 5 | find_package(Qt5Quick REQUIRED) | ||
352 | 6 | |||
353 | 7 | set(UbuntuGestureQml_SOURCES | ||
354 | 8 | plugin.cpp | ||
355 | 9 | DirectionalDragArea.cpp | ||
356 | 10 | ) | ||
357 | 11 | |||
358 | 12 | add_definitions(-DUBUNTUGESTURES_LIBRARY) | ||
359 | 13 | |||
360 | 14 | add_library(UbuntuGestureQml MODULE ${UbuntuGestureQml_SOURCES}) | ||
361 | 15 | |||
362 | 16 | qt5_use_modules(UbuntuGestureQml Core Quick) | ||
363 | 17 | |||
364 | 18 | # copy files into build directory for shadow builds | ||
365 | 19 | add_custom_target(UbuntuGestureQmlDirFile ALL | ||
366 | 20 | COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/qmldir" ${CMAKE_CURRENT_BINARY_DIR} | ||
367 | 21 | DEPENDS qmldir | ||
368 | 22 | ) | ||
369 | 23 | |||
370 | 24 | install(TARGETS UbuntuGestureQml | ||
371 | 25 | DESTINATION ${SHELL_APP_DIR}/plugins/Ubuntu/Gestures | ||
372 | 26 | ) | ||
373 | 27 | |||
374 | 28 | install(FILES qmldir | ||
375 | 29 | DESTINATION ${SHELL_APP_DIR}/plugins/Ubuntu/Gestures | ||
376 | 30 | ) | ||
377 | 0 | 31 | ||
378 | === added file 'plugins/Ubuntu/Gestures/Damper.h' | |||
379 | --- plugins/Ubuntu/Gestures/Damper.h 1970-01-01 00:00:00 +0000 | |||
380 | +++ plugins/Ubuntu/Gestures/Damper.h 2013-05-20 13:14:26 +0000 | |||
381 | @@ -0,0 +1,85 @@ | |||
382 | 1 | /* | ||
383 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
384 | 3 | * | ||
385 | 4 | * This program is free software; you can redistribute it and/or modify | ||
386 | 5 | * it under the terms of the GNU General Public License as published by | ||
387 | 6 | * the Free Software Foundation; version 3. | ||
388 | 7 | * | ||
389 | 8 | * This program is distributed in the hope that it will be useful, | ||
390 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
391 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
392 | 11 | * GNU General Public License for more details. | ||
393 | 12 | * | ||
394 | 13 | * You should have received a copy of the GNU General Public License | ||
395 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
396 | 15 | */ | ||
397 | 16 | |||
398 | 17 | #ifndef UBUNTU_GESTURES_DAMPER_H | ||
399 | 18 | #define UBUNTU_GESTURES_DAMPER_H | ||
400 | 19 | |||
401 | 20 | #include <QtCore/QPointF> | ||
402 | 21 | |||
403 | 22 | /* | ||
404 | 23 | Decreases the oscillations of a value along an axis. | ||
405 | 24 | */ | ||
406 | 25 | template <class Type> class Damper { | ||
407 | 26 | public: | ||
408 | 27 | // Maximum delta between the raw value and its dampened counterpart. | ||
409 | 28 | void setMaxDelta(Type maxDelta) { | ||
410 | 29 | if (maxDelta < 0) qFatal("Damper::maxDelta must be a positive number."); | ||
411 | 30 | m_maxDelta = maxDelta; | ||
412 | 31 | } | ||
413 | 32 | Type maxDelta() const { return m_maxDelta; } | ||
414 | 33 | |||
415 | 34 | void reset(Type value) { | ||
416 | 35 | m_value = value; | ||
417 | 36 | } | ||
418 | 37 | |||
419 | 38 | Type update(Type value) { | ||
420 | 39 | Type delta = value - m_value; | ||
421 | 40 | if (delta > 0 && delta > m_maxDelta) { | ||
422 | 41 | m_value += delta - m_maxDelta; | ||
423 | 42 | } else if (delta < 0 && delta < -m_maxDelta) { | ||
424 | 43 | m_value += delta + m_maxDelta; | ||
425 | 44 | } | ||
426 | 45 | |||
427 | 46 | return m_value; | ||
428 | 47 | } | ||
429 | 48 | |||
430 | 49 | Type value() const { return m_value; } | ||
431 | 50 | |||
432 | 51 | private: | ||
433 | 52 | Type m_value; | ||
434 | 53 | Type m_maxDelta; | ||
435 | 54 | }; | ||
436 | 55 | |||
437 | 56 | /* | ||
438 | 57 | A point that has its movement dampened. | ||
439 | 58 | */ | ||
440 | 59 | class DampedPointF { | ||
441 | 60 | public: | ||
442 | 61 | void setMaxDelta(qreal maxDelta) { | ||
443 | 62 | m_x.setMaxDelta(maxDelta); | ||
444 | 63 | m_y.setMaxDelta(maxDelta); | ||
445 | 64 | } | ||
446 | 65 | |||
447 | 66 | qreal maxDelta() const { return m_x.maxDelta(); } | ||
448 | 67 | |||
449 | 68 | void reset(const QPointF &point) { | ||
450 | 69 | m_x.reset(point.x()); | ||
451 | 70 | m_y.reset(point.y()); | ||
452 | 71 | } | ||
453 | 72 | |||
454 | 73 | void update(const QPointF &point) { | ||
455 | 74 | m_x.update(point.x()); | ||
456 | 75 | m_y.update(point.y()); | ||
457 | 76 | } | ||
458 | 77 | |||
459 | 78 | qreal x() const { return m_x.value(); } | ||
460 | 79 | qreal y() const { return m_y.value(); } | ||
461 | 80 | private: | ||
462 | 81 | Damper<qreal> m_x; | ||
463 | 82 | Damper<qreal> m_y; | ||
464 | 83 | }; | ||
465 | 84 | |||
466 | 85 | #endif // UBUNTU_GESTURES_DAMPER_H | ||
467 | 0 | 86 | ||
468 | === added file 'plugins/Ubuntu/Gestures/DirectionalDragArea.cpp' | |||
469 | --- plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 1970-01-01 00:00:00 +0000 | |||
470 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 2013-05-20 13:14:26 +0000 | |||
471 | @@ -0,0 +1,292 @@ | |||
472 | 1 | /* | ||
473 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
474 | 3 | * | ||
475 | 4 | * This program is free software; you can redistribute it and/or modify | ||
476 | 5 | * it under the terms of the GNU General Public License as published by | ||
477 | 6 | * the Free Software Foundation; version 3. | ||
478 | 7 | * | ||
479 | 8 | * This program is distributed in the hope that it will be useful, | ||
480 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
481 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
482 | 11 | * GNU General Public License for more details. | ||
483 | 12 | * | ||
484 | 13 | * You should have received a copy of the GNU General Public License | ||
485 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
486 | 15 | */ | ||
487 | 16 | |||
488 | 17 | #include "DirectionalDragArea.h" | ||
489 | 18 | |||
490 | 19 | #include <QtCore/qmath.h> | ||
491 | 20 | |||
492 | 21 | DirectionalDragArea::DirectionalDragArea(QQuickItem *parent) | ||
493 | 22 | : QQuickItem(parent) | ||
494 | 23 | , m_status(WaitingForTouch) | ||
495 | 24 | , m_touchId(-1) | ||
496 | 25 | , m_direction(DirectionalDragArea::Rightwards) | ||
497 | 26 | , m_wideningAngle(0) | ||
498 | 27 | , m_wideningFactor(0) | ||
499 | 28 | , m_distanceThreshold(0) | ||
500 | 29 | { | ||
501 | 30 | } | ||
502 | 31 | |||
503 | 32 | DirectionalDragArea::Direction DirectionalDragArea::direction() const | ||
504 | 33 | { | ||
505 | 34 | return m_direction; | ||
506 | 35 | } | ||
507 | 36 | |||
508 | 37 | void DirectionalDragArea::setDirection(DirectionalDragArea::Direction direction) | ||
509 | 38 | { | ||
510 | 39 | if (direction != m_direction) { | ||
511 | 40 | m_direction = direction; | ||
512 | 41 | Q_EMIT directionChanged(m_direction); | ||
513 | 42 | } | ||
514 | 43 | } | ||
515 | 44 | |||
516 | 45 | void DirectionalDragArea::setMaxDeviation(qreal value) | ||
517 | 46 | { | ||
518 | 47 | if (m_dampedPos.maxDelta() != value) { | ||
519 | 48 | m_dampedPos.setMaxDelta(value); | ||
520 | 49 | Q_EMIT maxDeviationChanged(value); | ||
521 | 50 | } | ||
522 | 51 | } | ||
523 | 52 | |||
524 | 53 | qreal DirectionalDragArea::wideningAngle() const | ||
525 | 54 | { | ||
526 | 55 | return m_wideningAngle; | ||
527 | 56 | } | ||
528 | 57 | |||
529 | 58 | void DirectionalDragArea::setWideningAngle(qreal angle) | ||
530 | 59 | { | ||
531 | 60 | if (angle == m_wideningAngle) | ||
532 | 61 | return; | ||
533 | 62 | |||
534 | 63 | m_wideningAngle = angle; | ||
535 | 64 | m_wideningFactor = qTan(angle * M_PI / 180.0); | ||
536 | 65 | Q_EMIT wideningAngleChanged(angle); | ||
537 | 66 | } | ||
538 | 67 | |||
539 | 68 | void DirectionalDragArea::setDistanceThreshold(qreal value) | ||
540 | 69 | { | ||
541 | 70 | if (m_distanceThreshold != value) { | ||
542 | 71 | m_distanceThreshold = value; | ||
543 | 72 | Q_EMIT distanceThresholdChanged(value); | ||
544 | 73 | } | ||
545 | 74 | } | ||
546 | 75 | |||
547 | 76 | qreal DirectionalDragArea::distance() const | ||
548 | 77 | { | ||
549 | 78 | if (directionIsHorizontal()) { | ||
550 | 79 | return m_previousPos.x() - m_startPos.x(); | ||
551 | 80 | } else { | ||
552 | 81 | return m_previousPos.y() - m_startPos.y(); | ||
553 | 82 | } | ||
554 | 83 | } | ||
555 | 84 | |||
556 | 85 | qreal DirectionalDragArea::touchX() const | ||
557 | 86 | { | ||
558 | 87 | return m_previousPos.x(); | ||
559 | 88 | } | ||
560 | 89 | |||
561 | 90 | qreal DirectionalDragArea::touchY() const | ||
562 | 91 | { | ||
563 | 92 | return m_previousPos.y(); | ||
564 | 93 | } | ||
565 | 94 | |||
566 | 95 | void DirectionalDragArea::touchEvent(QTouchEvent *event) | ||
567 | 96 | { | ||
568 | 97 | if (!isEnabled() || !isVisible()) { | ||
569 | 98 | QQuickItem::touchEvent(event); | ||
570 | 99 | return; | ||
571 | 100 | } | ||
572 | 101 | |||
573 | 102 | switch (m_status) { | ||
574 | 103 | case WaitingForTouch: | ||
575 | 104 | touchEvent_absent(event); | ||
576 | 105 | break; | ||
577 | 106 | case Undecided: | ||
578 | 107 | touchEvent_undecided(event); | ||
579 | 108 | break; | ||
580 | 109 | case Recognized: | ||
581 | 110 | touchEvent_recognized(event); | ||
582 | 111 | break; | ||
583 | 112 | default: // Rejected | ||
584 | 113 | touchEvent_rejected(event); | ||
585 | 114 | break; | ||
586 | 115 | } | ||
587 | 116 | } | ||
588 | 117 | |||
589 | 118 | void DirectionalDragArea::touchEvent_absent(QTouchEvent *event) | ||
590 | 119 | { | ||
591 | 120 | if ((event->touchPointStates() && (Qt::TouchPointPressed || Qt::TouchPointMoved)) | ||
592 | 121 | && event->touchPoints().count() == 1) { | ||
593 | 122 | m_startPos = event->touchPoints()[0].pos(); | ||
594 | 123 | m_touchId = event->touchPoints()[0].id(); | ||
595 | 124 | m_dampedPos.reset(m_startPos); | ||
596 | 125 | setStatus(Undecided); | ||
597 | 126 | setPreviousPos(m_startPos); | ||
598 | 127 | } | ||
599 | 128 | } | ||
600 | 129 | |||
601 | 130 | void DirectionalDragArea::touchEvent_undecided(QTouchEvent *event) | ||
602 | 131 | { | ||
603 | 132 | const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event); | ||
604 | 133 | const QPointF &touchPos = touchPoint->pos(); | ||
605 | 134 | |||
606 | 135 | if (touchPoint->state() == Qt::TouchPointReleased) { | ||
607 | 136 | // touch has ended before recognition concluded | ||
608 | 137 | setStatus(WaitingForTouch); | ||
609 | 138 | return; | ||
610 | 139 | } | ||
611 | 140 | |||
612 | 141 | if (event->touchPointStates().testFlag(Qt::TouchPointPressed) | ||
613 | 142 | || event->touchPoints().count() > 1) { | ||
614 | 143 | // multi-finger drags are not accepted | ||
615 | 144 | setStatus(Rejected); | ||
616 | 145 | return; | ||
617 | 146 | } | ||
618 | 147 | |||
619 | 148 | m_previousDampedPos.setX(m_dampedPos.x()); | ||
620 | 149 | m_previousDampedPos.setY(m_dampedPos.y()); | ||
621 | 150 | m_dampedPos.update(touchPos); | ||
622 | 151 | |||
623 | 152 | if (!pointInsideAllowedArea()) { | ||
624 | 153 | setStatus(Rejected); | ||
625 | 154 | return; | ||
626 | 155 | } | ||
627 | 156 | |||
628 | 157 | if (!movingInRightDirection()) { | ||
629 | 158 | setStatus(Rejected); | ||
630 | 159 | return; | ||
631 | 160 | } | ||
632 | 161 | |||
633 | 162 | setPreviousPos(touchPos); | ||
634 | 163 | |||
635 | 164 | if (movedFarEnough(touchPos)) { | ||
636 | 165 | setStatus(Recognized); | ||
637 | 166 | } | ||
638 | 167 | } | ||
639 | 168 | |||
640 | 169 | void DirectionalDragArea::touchEvent_recognized(QTouchEvent *event) | ||
641 | 170 | { | ||
642 | 171 | const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event); | ||
643 | 172 | |||
644 | 173 | setPreviousPos(touchPoint->pos()); | ||
645 | 174 | |||
646 | 175 | if (touchPoint->state() == Qt::TouchPointReleased) { | ||
647 | 176 | setStatus(WaitingForTouch); | ||
648 | 177 | } | ||
649 | 178 | } | ||
650 | 179 | |||
651 | 180 | void DirectionalDragArea::touchEvent_rejected(QTouchEvent *event) | ||
652 | 181 | { | ||
653 | 182 | const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event); | ||
654 | 183 | |||
655 | 184 | if (!touchPoint || touchPoint->state() == Qt::TouchPointReleased) { | ||
656 | 185 | setStatus(WaitingForTouch); | ||
657 | 186 | } | ||
658 | 187 | } | ||
659 | 188 | |||
660 | 189 | const QTouchEvent::TouchPoint *DirectionalDragArea::fetchTargetTouchPoint(QTouchEvent *event) | ||
661 | 190 | { | ||
662 | 191 | const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints(); | ||
663 | 192 | const QTouchEvent::TouchPoint *touchPoint = 0; | ||
664 | 193 | for (int i = 0; i < touchPoints.size(); ++i) { | ||
665 | 194 | if (touchPoints.at(i).id() == m_touchId) { | ||
666 | 195 | touchPoint = &touchPoints.at(i); | ||
667 | 196 | break; | ||
668 | 197 | } | ||
669 | 198 | } | ||
670 | 199 | return touchPoint; | ||
671 | 200 | } | ||
672 | 201 | |||
673 | 202 | bool DirectionalDragArea::pointInsideAllowedArea() const | ||
674 | 203 | { | ||
675 | 204 | qreal dX = m_dampedPos.x() - m_startPos.x(); | ||
676 | 205 | qreal dY = m_dampedPos.y() - m_startPos.y(); | ||
677 | 206 | |||
678 | 207 | switch (m_direction) { | ||
679 | 208 | case Upwards: | ||
680 | 209 | return dY <= 0 && qFabs(dX) <= qFabs(dY) * m_wideningFactor; | ||
681 | 210 | case Downwards: | ||
682 | 211 | return dY >= 0 && qFabs(dX) <= dY * m_wideningFactor; | ||
683 | 212 | case Leftwards: | ||
684 | 213 | return dX <= 0 && qFabs(dY) <= qFabs(dX) * m_wideningFactor; | ||
685 | 214 | default: // Rightwards: | ||
686 | 215 | return dX >= 0 && qFabs(dY) <= dX * m_wideningFactor; | ||
687 | 216 | } | ||
688 | 217 | } | ||
689 | 218 | |||
690 | 219 | bool DirectionalDragArea::movingInRightDirection() const | ||
691 | 220 | { | ||
692 | 221 | switch (m_direction) { | ||
693 | 222 | case Upwards: | ||
694 | 223 | return m_dampedPos.y() <= m_previousDampedPos.y(); | ||
695 | 224 | case Downwards: | ||
696 | 225 | return m_dampedPos.y() >= m_previousDampedPos.y(); | ||
697 | 226 | case Leftwards: | ||
698 | 227 | return m_dampedPos.x() <= m_previousDampedPos.x(); | ||
699 | 228 | default: // Rightwards: | ||
700 | 229 | return m_dampedPos.x() >= m_previousDampedPos.x(); | ||
701 | 230 | } | ||
702 | 231 | } | ||
703 | 232 | |||
704 | 233 | bool DirectionalDragArea::movedFarEnough(const QPointF &point) const | ||
705 | 234 | { | ||
706 | 235 | if (directionIsHorizontal()) | ||
707 | 236 | return qFabs(point.x() - m_startPos.x()) > m_distanceThreshold; | ||
708 | 237 | else | ||
709 | 238 | return qFabs(point.y() - m_startPos.y()) > m_distanceThreshold; | ||
710 | 239 | } | ||
711 | 240 | |||
712 | 241 | void DirectionalDragArea::setStatus(DirectionalDragArea::Status newStatus) | ||
713 | 242 | { | ||
714 | 243 | if (newStatus == m_status) | ||
715 | 244 | return; | ||
716 | 245 | |||
717 | 246 | m_status = newStatus; | ||
718 | 247 | Q_EMIT statusChanged(m_status); | ||
719 | 248 | |||
720 | 249 | switch (newStatus) { | ||
721 | 250 | case WaitingForTouch: | ||
722 | 251 | Q_EMIT draggingChanged(false); | ||
723 | 252 | break; | ||
724 | 253 | case Undecided: | ||
725 | 254 | Q_EMIT draggingChanged(true); | ||
726 | 255 | break; | ||
727 | 256 | default: // Rejected | ||
728 | 257 | // no-op | ||
729 | 258 | break; | ||
730 | 259 | } | ||
731 | 260 | } | ||
732 | 261 | |||
733 | 262 | void DirectionalDragArea::setPreviousPos(QPointF point) | ||
734 | 263 | { | ||
735 | 264 | Q_ASSERT(m_status != Rejected); | ||
736 | 265 | |||
737 | 266 | bool xChanged = m_previousPos.x() != point.x(); | ||
738 | 267 | bool yChanged = m_previousPos.y() != point.y(); | ||
739 | 268 | |||
740 | 269 | m_previousPos = point; | ||
741 | 270 | |||
742 | 271 | if (xChanged) { | ||
743 | 272 | Q_EMIT touchXChanged(point.x()); | ||
744 | 273 | if (directionIsHorizontal()) | ||
745 | 274 | Q_EMIT distanceChanged(distance()); | ||
746 | 275 | } | ||
747 | 276 | |||
748 | 277 | if (yChanged) { | ||
749 | 278 | Q_EMIT touchYChanged(point.y()); | ||
750 | 279 | if (directionIsVertical()) | ||
751 | 280 | Q_EMIT distanceChanged(distance()); | ||
752 | 281 | } | ||
753 | 282 | } | ||
754 | 283 | |||
755 | 284 | bool DirectionalDragArea::directionIsHorizontal() const | ||
756 | 285 | { | ||
757 | 286 | return m_direction == Leftwards || m_direction == Rightwards; | ||
758 | 287 | } | ||
759 | 288 | |||
760 | 289 | bool DirectionalDragArea::directionIsVertical() const | ||
761 | 290 | { | ||
762 | 291 | return m_direction == Upwards || m_direction == Downwards; | ||
763 | 292 | } | ||
764 | 0 | 293 | ||
765 | === added file 'plugins/Ubuntu/Gestures/DirectionalDragArea.h' | |||
766 | --- plugins/Ubuntu/Gestures/DirectionalDragArea.h 1970-01-01 00:00:00 +0000 | |||
767 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea.h 2013-05-20 13:14:26 +0000 | |||
768 | @@ -0,0 +1,179 @@ | |||
769 | 1 | /* | ||
770 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
771 | 3 | * | ||
772 | 4 | * This program is free software; you can redistribute it and/or modify | ||
773 | 5 | * it under the terms of the GNU General Public License as published by | ||
774 | 6 | * the Free Software Foundation; version 3. | ||
775 | 7 | * | ||
776 | 8 | * This program is distributed in the hope that it will be useful, | ||
777 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
778 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
779 | 11 | * GNU General Public License for more details. | ||
780 | 12 | * | ||
781 | 13 | * You should have received a copy of the GNU General Public License | ||
782 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
783 | 15 | */ | ||
784 | 16 | |||
785 | 17 | #ifndef DIRECTIONAL_DRAG_AREA_H | ||
786 | 18 | #define DIRECTIONAL_DRAG_AREA_H | ||
787 | 19 | |||
788 | 20 | #include <QtQuick/QQuickItem> | ||
789 | 21 | #include "UbuntuGesturesGlobal.h" | ||
790 | 22 | #include "Damper.h" | ||
791 | 23 | |||
792 | 24 | /* | ||
793 | 25 | An area that detects axis-aligned single-finger drag gestures | ||
794 | 26 | |||
795 | 27 | If a drag deviates too much from the components' direction recognition will | ||
796 | 28 | fail. It will also fail if the drag or flick is too short. E.g. a noisy or | ||
797 | 29 | fidgety click | ||
798 | 30 | |||
799 | 31 | See doc/DirectionalDragArea.svg | ||
800 | 32 | */ | ||
801 | 33 | class UBUNTUGESTURES_EXPORT DirectionalDragArea : public QQuickItem { | ||
802 | 34 | Q_OBJECT | ||
803 | 35 | |||
804 | 36 | // The direction in which the gesture should move in order to be recognized. | ||
805 | 37 | Q_PROPERTY(Direction direction READ direction WRITE setDirection NOTIFY directionChanged) | ||
806 | 38 | |||
807 | 39 | // The distance travelled by the finger along the axis specified by | ||
808 | 40 | // DirectionalDragArea's direction. | ||
809 | 41 | Q_PROPERTY(qreal distance READ distance NOTIFY distanceChanged) | ||
810 | 42 | |||
811 | 43 | // Position of the touch point performing the drag. | ||
812 | 44 | Q_PROPERTY(qreal touchX READ touchX NOTIFY touchXChanged) | ||
813 | 45 | Q_PROPERTY(qreal touchY READ touchY NOTIFY touchYChanged) | ||
814 | 46 | |||
815 | 47 | // The current status of the directional drag gesture area. | ||
816 | 48 | Q_PROPERTY(Status status READ status NOTIFY statusChanged) | ||
817 | 49 | |||
818 | 50 | // Whether a drag gesture is taking place (regardless of whether it's a correct | ||
819 | 51 | // single-finger directional drag or not) | ||
820 | 52 | Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged) | ||
821 | 53 | |||
822 | 54 | ///// | ||
823 | 55 | // stuff that will be set in stone at some point | ||
824 | 56 | |||
825 | 57 | // How far the touch point can move away from its expected position before | ||
826 | 58 | // it causes a rejection in the gesture recognition. This is to compensate | ||
827 | 59 | // for both noise in the touch input signal and for the natural irregularities | ||
828 | 60 | // in the finger movement. | ||
829 | 61 | // Proper value is likely device-specific. | ||
830 | 62 | Q_PROPERTY(qreal maxDeviation READ maxDeviation WRITE setMaxDeviation NOTIFY maxDeviationChanged) | ||
831 | 63 | |||
832 | 64 | // Widening angle, in degrees | ||
833 | 65 | // It's roughly the maximum angle a touch point can make relative to the | ||
834 | 66 | // axis defined by the compoment's direction for it to be recognized as a | ||
835 | 67 | // directional drag. | ||
836 | 68 | Q_PROPERTY(qreal wideningAngle READ wideningAngle WRITE setWideningAngle | ||
837 | 69 | NOTIFY wideningAngleChanged) | ||
838 | 70 | |||
839 | 71 | // How far a touch point has to move from its initial position in order for | ||
840 | 72 | // it to be recognized as a directional drag. | ||
841 | 73 | Q_PROPERTY(qreal distanceThreshold READ distanceThreshold WRITE setDistanceThreshold | ||
842 | 74 | NOTIFY distanceThresholdChanged) | ||
843 | 75 | |||
844 | 76 | // | ||
845 | 77 | ///// | ||
846 | 78 | |||
847 | 79 | Q_ENUMS(Direction) | ||
848 | 80 | Q_ENUMS(Status) | ||
849 | 81 | public: | ||
850 | 82 | DirectionalDragArea(QQuickItem *parent = 0); | ||
851 | 83 | |||
852 | 84 | enum Direction { Rightwards, // Along the positive direction of the X axis | ||
853 | 85 | Leftwards, // Along the negative direction of the X axis | ||
854 | 86 | Downwards, // Along the positive direction of the Y axis | ||
855 | 87 | Upwards }; // Along the negative direction of the Y axis | ||
856 | 88 | Direction direction() const; | ||
857 | 89 | void setDirection(Direction); | ||
858 | 90 | |||
859 | 91 | // Describes the state of the directional drag gesture. | ||
860 | 92 | enum Status { | ||
861 | 93 | // There's no touch point over this area. | ||
862 | 94 | WaitingForTouch, | ||
863 | 95 | |||
864 | 96 | // A touch point has landed on this area but it's not know yet whether it is | ||
865 | 97 | // performing a drag in the correct direction. | ||
866 | 98 | Undecided, //Recognizing, | ||
867 | 99 | |||
868 | 100 | // There's a touch point in this area and it performed a drag in the correct | ||
869 | 101 | // direction. | ||
870 | 102 | // | ||
871 | 103 | // Once recognized, the gesture state will move back to Absent only once | ||
872 | 104 | // that touch point ends. The gesture will remain in the Recognized state even if | ||
873 | 105 | // the touch point starts moving in other directions or halts. | ||
874 | 106 | Recognized, | ||
875 | 107 | |||
876 | 108 | // A gesture was performed but it wasn't a single-touch drag in the correct | ||
877 | 109 | // direction. | ||
878 | 110 | // It will remain in this state until there are no more touch points over this | ||
879 | 111 | // area, at which point it will move to Absent state. | ||
880 | 112 | Rejected | ||
881 | 113 | }; | ||
882 | 114 | Status status() const { return m_status; } | ||
883 | 115 | |||
884 | 116 | qreal distance() const; | ||
885 | 117 | |||
886 | 118 | qreal touchX() const; | ||
887 | 119 | qreal touchY() const; | ||
888 | 120 | |||
889 | 121 | bool dragging() const { return (m_status == Undecided) || (m_status == Recognized); } | ||
890 | 122 | |||
891 | 123 | qreal maxDeviation() const { return m_dampedPos.maxDelta(); } | ||
892 | 124 | void setMaxDeviation(qreal value); | ||
893 | 125 | |||
894 | 126 | qreal wideningAngle() const; | ||
895 | 127 | void setWideningAngle(qreal value); | ||
896 | 128 | |||
897 | 129 | qreal distanceThreshold() const { return m_distanceThreshold; } | ||
898 | 130 | void setDistanceThreshold(qreal value); | ||
899 | 131 | |||
900 | 132 | Q_SIGNALS: | ||
901 | 133 | void directionChanged(Direction direction); | ||
902 | 134 | void statusChanged(Status value); | ||
903 | 135 | void draggingChanged(bool value); | ||
904 | 136 | void distanceChanged(qreal value); | ||
905 | 137 | void maxDeviationChanged(qreal value); | ||
906 | 138 | void wideningAngleChanged(qreal value); | ||
907 | 139 | void distanceThresholdChanged(qreal value); | ||
908 | 140 | void touchXChanged(qreal value); | ||
909 | 141 | void touchYChanged(qreal value); | ||
910 | 142 | |||
911 | 143 | protected: | ||
912 | 144 | virtual void touchEvent(QTouchEvent *event); | ||
913 | 145 | |||
914 | 146 | private: | ||
915 | 147 | void touchEvent_absent(QTouchEvent *event); | ||
916 | 148 | void touchEvent_undecided(QTouchEvent *event); | ||
917 | 149 | void touchEvent_recognized(QTouchEvent *event); | ||
918 | 150 | void touchEvent_rejected(QTouchEvent *event); | ||
919 | 151 | bool pointInsideAllowedArea() const; | ||
920 | 152 | bool movingInRightDirection() const; | ||
921 | 153 | bool movedFarEnough(const QPointF &point) const; | ||
922 | 154 | const QTouchEvent::TouchPoint *fetchTargetTouchPoint(QTouchEvent *event); | ||
923 | 155 | void setStatus(Status newStatus); | ||
924 | 156 | void setPreviousPos(QPointF point); | ||
925 | 157 | |||
926 | 158 | // convenience functions | ||
927 | 159 | bool directionIsHorizontal() const; | ||
928 | 160 | bool directionIsVertical() const; | ||
929 | 161 | |||
930 | 162 | Status m_status; | ||
931 | 163 | |||
932 | 164 | QPointF m_startPos; | ||
933 | 165 | QPointF m_previousPos; | ||
934 | 166 | int m_touchId; | ||
935 | 167 | |||
936 | 168 | // A movement damper is used in some of the gesture recognition calculations | ||
937 | 169 | // to get rid of noise or small oscillations in the touch position. | ||
938 | 170 | DampedPointF m_dampedPos; | ||
939 | 171 | QPointF m_previousDampedPos; | ||
940 | 172 | |||
941 | 173 | Direction m_direction; | ||
942 | 174 | qreal m_wideningAngle; // in degrees | ||
943 | 175 | qreal m_wideningFactor; // it's tan(degreesToRadian(m_wideningAngle)) | ||
944 | 176 | qreal m_distanceThreshold; | ||
945 | 177 | }; | ||
946 | 178 | |||
947 | 179 | #endif // DIRECTIONAL_DRAG_AREA_H | ||
948 | 0 | 180 | ||
949 | === added file 'plugins/Ubuntu/Gestures/UbuntuGesturesGlobal.h' | |||
950 | --- plugins/Ubuntu/Gestures/UbuntuGesturesGlobal.h 1970-01-01 00:00:00 +0000 | |||
951 | +++ plugins/Ubuntu/Gestures/UbuntuGesturesGlobal.h 2013-05-20 13:14:26 +0000 | |||
952 | @@ -0,0 +1,23 @@ | |||
953 | 1 | /* | ||
954 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
955 | 3 | * | ||
956 | 4 | * This program is free software; you can redistribute it and/or modify | ||
957 | 5 | * it under the terms of the GNU General Public License as published by | ||
958 | 6 | * the Free Software Foundation; version 3. | ||
959 | 7 | * | ||
960 | 8 | * This program is distributed in the hope that it will be useful, | ||
961 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
962 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
963 | 11 | * GNU General Public License for more details. | ||
964 | 12 | * | ||
965 | 13 | * You should have received a copy of the GNU General Public License | ||
966 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
967 | 15 | */ | ||
968 | 16 | |||
969 | 17 | #include <QtCore/QtGlobal> | ||
970 | 18 | |||
971 | 19 | #if defined(UBUNTUGESTURES_LIBRARY) | ||
972 | 20 | # define UBUNTUGESTURES_EXPORT Q_DECL_EXPORT | ||
973 | 21 | #else | ||
974 | 22 | # define UBUNTUGESTURES_EXPORT Q_DECL_IMPORT | ||
975 | 23 | #endif | ||
976 | 0 | 24 | ||
977 | === added file 'plugins/Ubuntu/Gestures/plugin.cpp' | |||
978 | --- plugins/Ubuntu/Gestures/plugin.cpp 1970-01-01 00:00:00 +0000 | |||
979 | +++ plugins/Ubuntu/Gestures/plugin.cpp 2013-05-20 13:14:26 +0000 | |||
980 | @@ -0,0 +1,25 @@ | |||
981 | 1 | /* | ||
982 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
983 | 3 | * | ||
984 | 4 | * This program is free software; you can redistribute it and/or modify | ||
985 | 5 | * it under the terms of the GNU General Public License as published by | ||
986 | 6 | * the Free Software Foundation; version 3. | ||
987 | 7 | * | ||
988 | 8 | * This program is distributed in the hope that it will be useful, | ||
989 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
990 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
991 | 11 | * GNU General Public License for more details. | ||
992 | 12 | * | ||
993 | 13 | * You should have received a copy of the GNU General Public License | ||
994 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
995 | 15 | */ | ||
996 | 16 | |||
997 | 17 | #include "plugin.h" | ||
998 | 18 | #include "DirectionalDragArea.h" | ||
999 | 19 | |||
1000 | 20 | #include <qqml.h> | ||
1001 | 21 | |||
1002 | 22 | void UbuntuGestureQmlPlugin::registerTypes(const char *uri) | ||
1003 | 23 | { | ||
1004 | 24 | qmlRegisterType<DirectionalDragArea>(uri, 0, 1, "DirectionalDragArea"); | ||
1005 | 25 | } | ||
1006 | 0 | 26 | ||
1007 | === added file 'plugins/Ubuntu/Gestures/plugin.h' | |||
1008 | --- plugins/Ubuntu/Gestures/plugin.h 1970-01-01 00:00:00 +0000 | |||
1009 | +++ plugins/Ubuntu/Gestures/plugin.h 2013-05-20 13:14:26 +0000 | |||
1010 | @@ -0,0 +1,31 @@ | |||
1011 | 1 | /* | ||
1012 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
1013 | 3 | * | ||
1014 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1015 | 5 | * it under the terms of the GNU General Public License as published by | ||
1016 | 6 | * the Free Software Foundation; version 3. | ||
1017 | 7 | * | ||
1018 | 8 | * This program is distributed in the hope that it will be useful, | ||
1019 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1020 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1021 | 11 | * GNU General Public License for more details. | ||
1022 | 12 | * | ||
1023 | 13 | * You should have received a copy of the GNU General Public License | ||
1024 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1025 | 15 | */ | ||
1026 | 16 | |||
1027 | 17 | #ifndef PLUGIN_H | ||
1028 | 18 | #define PLUGIN_H | ||
1029 | 19 | |||
1030 | 20 | #include <QtQml/QQmlExtensionPlugin> | ||
1031 | 21 | |||
1032 | 22 | class UbuntuGestureQmlPlugin : public QQmlExtensionPlugin | ||
1033 | 23 | { | ||
1034 | 24 | Q_OBJECT | ||
1035 | 25 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") | ||
1036 | 26 | public: | ||
1037 | 27 | void registerTypes(const char *uri); | ||
1038 | 28 | }; | ||
1039 | 29 | |||
1040 | 30 | |||
1041 | 31 | #endif | ||
1042 | 0 | 32 | ||
1043 | === added file 'plugins/Ubuntu/Gestures/qmldir' | |||
1044 | --- plugins/Ubuntu/Gestures/qmldir 1970-01-01 00:00:00 +0000 | |||
1045 | +++ plugins/Ubuntu/Gestures/qmldir 2013-05-20 13:14:26 +0000 | |||
1046 | @@ -0,0 +1,2 @@ | |||
1047 | 1 | module Ubuntu.Gestures | ||
1048 | 2 | plugin UbuntuGestureQml | ||
1049 | 0 | 3 | ||
1050 | === modified file 'tests/plugins/CMakeLists.txt' | |||
1051 | --- tests/plugins/CMakeLists.txt 2013-04-16 14:22:23 +0000 | |||
1052 | +++ tests/plugins/CMakeLists.txt 2013-05-20 13:14:26 +0000 | |||
1053 | @@ -1,1 +1,2 @@ | |||
1054 | 1 | add_subdirectory(Utils) | 1 | add_subdirectory(Utils) |
1055 | 2 | add_subdirectory(Ubuntu) | ||
1056 | 2 | 3 | ||
1057 | === added directory 'tests/plugins/Ubuntu' | |||
1058 | === added file 'tests/plugins/Ubuntu/CMakeLists.txt' | |||
1059 | --- tests/plugins/Ubuntu/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
1060 | +++ tests/plugins/Ubuntu/CMakeLists.txt 2013-05-20 13:14:26 +0000 | |||
1061 | @@ -0,0 +1,1 @@ | |||
1062 | 1 | add_subdirectory(Gestures) | ||
1063 | 0 | 2 | ||
1064 | === added directory 'tests/plugins/Ubuntu/Gestures' | |||
1065 | === added file 'tests/plugins/Ubuntu/Gestures/CMakeLists.txt' | |||
1066 | --- tests/plugins/Ubuntu/Gestures/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
1067 | +++ tests/plugins/Ubuntu/Gestures/CMakeLists.txt 2013-05-20 13:14:26 +0000 | |||
1068 | @@ -0,0 +1,38 @@ | |||
1069 | 1 | ########## tst_DirectionalDragArea | ||
1070 | 2 | |||
1071 | 3 | include_directories( | ||
1072 | 4 | ${CMAKE_SOURCE_DIR}/plugins/Ubuntu/Gestures | ||
1073 | 5 | ${CMAKE_CURRENT_BINARY_DIR} | ||
1074 | 6 | ) | ||
1075 | 7 | |||
1076 | 8 | set(testCommand | ||
1077 | 9 | LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures | ||
1078 | 10 | ${CMAKE_CURRENT_BINARY_DIR}/DirectionalDragAreaTestExec | ||
1079 | 11 | -o ${CMAKE_BINARY_DIR}/DirectionalDragAreaTest.xml,xunitxml | ||
1080 | 12 | -o -,txt) | ||
1081 | 13 | |||
1082 | 14 | add_custom_target(DirectionalDragAreaTest ${testCommand}) | ||
1083 | 15 | add_dependencies(qmluitests DirectionalDragAreaTest) | ||
1084 | 16 | add_dependencies(DirectionalDragAreaTest DirectionalDragAreaTestExec UbutunGesturesTestQmlFiles) | ||
1085 | 17 | |||
1086 | 18 | add_executable(DirectionalDragAreaTestExec tst_DirectionalDragArea.cpp) | ||
1087 | 19 | qt5_use_modules(DirectionalDragAreaTestExec Test Core Qml Gui Quick) | ||
1088 | 20 | target_link_libraries(DirectionalDragAreaTestExec UbuntuGestureQml) | ||
1089 | 21 | |||
1090 | 22 | add_definitions(-DUBUNTU_GESTURES_PLUGIN_DIR="${CMAKE_BINARY_DIR}/plugins") | ||
1091 | 23 | |||
1092 | 24 | file(GLOB qmlFiles *.qml) | ||
1093 | 25 | add_custom_target(UbuntuGesturesTestQmlFiles ALL | ||
1094 | 26 | COMMAND cp ${qmlFiles} ${CMAKE_CURRENT_BINARY_DIR} | ||
1095 | 27 | DEPENDS ${qmlFiles} | ||
1096 | 28 | ) | ||
1097 | 29 | |||
1098 | 30 | ########## tst_Damper | ||
1099 | 31 | |||
1100 | 32 | set(damperTestCommand | ||
1101 | 33 | DamperTestExec -o ${CMAKE_BINARY_DIR}/DamperTest.xml,xunitxml -o -,txt) | ||
1102 | 34 | |||
1103 | 35 | add_test(NAME DamperTest COMMAND ${damperTestCommand}) | ||
1104 | 36 | |||
1105 | 37 | add_executable(DamperTestExec tst_Damper.cpp) | ||
1106 | 38 | qt5_use_modules(DamperTestExec Test Core) | ||
1107 | 0 | 39 | ||
1108 | === added file 'tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml' | |||
1109 | --- tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml 1970-01-01 00:00:00 +0000 | |||
1110 | +++ tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml 2013-05-20 13:14:26 +0000 | |||
1111 | @@ -0,0 +1,87 @@ | |||
1112 | 1 | /* | ||
1113 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
1114 | 3 | * | ||
1115 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1116 | 5 | * it under the terms of the GNU General Public License as published by | ||
1117 | 6 | * the Free Software Foundation; version 3. | ||
1118 | 7 | * | ||
1119 | 8 | * This program is distributed in the hope that it will be useful, | ||
1120 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1121 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1122 | 11 | * GNU General Public License for more details. | ||
1123 | 12 | * | ||
1124 | 13 | * You should have received a copy of the GNU General Public License | ||
1125 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1126 | 15 | */ | ||
1127 | 16 | |||
1128 | 17 | import QtQuick 2.0 | ||
1129 | 18 | import Ubuntu.Gestures 0.1 | ||
1130 | 19 | import Ubuntu.Components 0.1 | ||
1131 | 20 | |||
1132 | 21 | Item { | ||
1133 | 22 | |||
1134 | 23 | function reset() { launcher.y = -launcher.height } | ||
1135 | 24 | |||
1136 | 25 | Rectangle { | ||
1137 | 26 | id: launcher | ||
1138 | 27 | color: "blue" | ||
1139 | 28 | width: parent.width | ||
1140 | 29 | height: units.gu(15) | ||
1141 | 30 | x: 0 | ||
1142 | 31 | y: followDragArea() | ||
1143 | 32 | |||
1144 | 33 | function followDragArea() { | ||
1145 | 34 | if (dragArea.status === DirectionalDragArea.Rejected) | ||
1146 | 35 | return -height | ||
1147 | 36 | else | ||
1148 | 37 | return dragArea.distance < height ? -height + dragArea.distance : 0 | ||
1149 | 38 | } | ||
1150 | 39 | } | ||
1151 | 40 | |||
1152 | 41 | Rectangle { | ||
1153 | 42 | id: dragAreaRect | ||
1154 | 43 | color: "yellow" | ||
1155 | 44 | opacity: 0.0 | ||
1156 | 45 | anchors.fill: dragArea | ||
1157 | 46 | } | ||
1158 | 47 | |||
1159 | 48 | DirectionalDragArea { | ||
1160 | 49 | id: dragArea | ||
1161 | 50 | objectName: "vpDragArea" | ||
1162 | 51 | |||
1163 | 52 | height: units.gu(5) | ||
1164 | 53 | |||
1165 | 54 | direction: DirectionalDragArea.Downwards | ||
1166 | 55 | maxDeviation: units.gu(2) | ||
1167 | 56 | wideningAngle: 10 | ||
1168 | 57 | distanceThreshold: units.gu(4) | ||
1169 | 58 | |||
1170 | 59 | onStatusChanged: { | ||
1171 | 60 | switch (status) { | ||
1172 | 61 | case DirectionalDragArea.WaitingForTouch: | ||
1173 | 62 | dragAreaRect.opacity = 0.0 | ||
1174 | 63 | break; | ||
1175 | 64 | case DirectionalDragArea.Undecided: | ||
1176 | 65 | dragAreaRect.color = "yellow" | ||
1177 | 66 | dragAreaRect.opacity = 0.3 | ||
1178 | 67 | launcher.y = Qt.binding(launcher.followDragArea) | ||
1179 | 68 | break; | ||
1180 | 69 | case DirectionalDragArea.Recognized: | ||
1181 | 70 | dragAreaRect.color = "green" | ||
1182 | 71 | dragAreaRect.opacity = 0.5 | ||
1183 | 72 | break; | ||
1184 | 73 | default: //case DirectionalDragArea.Rejected: | ||
1185 | 74 | dragAreaRect.color = "red" | ||
1186 | 75 | dragAreaRect.opacity = 0.5 | ||
1187 | 76 | launcher.y = -launcher.height | ||
1188 | 77 | break; | ||
1189 | 78 | } | ||
1190 | 79 | } | ||
1191 | 80 | |||
1192 | 81 | anchors { | ||
1193 | 82 | left: parent.left | ||
1194 | 83 | right: parent.right | ||
1195 | 84 | top: parent.top | ||
1196 | 85 | } | ||
1197 | 86 | } | ||
1198 | 87 | } | ||
1199 | 0 | 88 | ||
1200 | === added file 'tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml' | |||
1201 | --- tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml 1970-01-01 00:00:00 +0000 | |||
1202 | +++ tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml 2013-05-20 13:14:26 +0000 | |||
1203 | @@ -0,0 +1,90 @@ | |||
1204 | 1 | /* | ||
1205 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
1206 | 3 | * | ||
1207 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1208 | 5 | * it under the terms of the GNU General Public License as published by | ||
1209 | 6 | * the Free Software Foundation; version 3. | ||
1210 | 7 | * | ||
1211 | 8 | * This program is distributed in the hope that it will be useful, | ||
1212 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1213 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1214 | 11 | * GNU General Public License for more details. | ||
1215 | 12 | * | ||
1216 | 13 | * You should have received a copy of the GNU General Public License | ||
1217 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1218 | 15 | */ | ||
1219 | 16 | |||
1220 | 17 | import QtQuick 2.0 | ||
1221 | 18 | import Ubuntu.Gestures 0.1 | ||
1222 | 19 | import Ubuntu.Components 0.1 | ||
1223 | 20 | |||
1224 | 21 | Item { | ||
1225 | 22 | id: root | ||
1226 | 23 | |||
1227 | 24 | function reset() { launcher.x = root.width } | ||
1228 | 25 | |||
1229 | 26 | Rectangle { | ||
1230 | 27 | id: launcher | ||
1231 | 28 | color: "blue" | ||
1232 | 29 | width: units.gu(15) | ||
1233 | 30 | height: parent.height | ||
1234 | 31 | x: root.width | ||
1235 | 32 | y: 0 | ||
1236 | 33 | |||
1237 | 34 | function followDragArea() { | ||
1238 | 35 | if (dragArea.status === DirectionalDragArea.Rejected) | ||
1239 | 36 | return root.width | ||
1240 | 37 | else | ||
1241 | 38 | return dragArea.distance > -width ? | ||
1242 | 39 | root.width + dragArea.distance | ||
1243 | 40 | : | ||
1244 | 41 | root.width - width | ||
1245 | 42 | } | ||
1246 | 43 | } | ||
1247 | 44 | |||
1248 | 45 | Rectangle { | ||
1249 | 46 | id: dragAreaRect | ||
1250 | 47 | opacity: 0.0 | ||
1251 | 48 | anchors.fill: dragArea | ||
1252 | 49 | } | ||
1253 | 50 | |||
1254 | 51 | DirectionalDragArea { | ||
1255 | 52 | id: dragArea | ||
1256 | 53 | objectName: "hnDragArea" | ||
1257 | 54 | |||
1258 | 55 | width: units.gu(5) | ||
1259 | 56 | |||
1260 | 57 | direction: DirectionalDragArea.Leftwards | ||
1261 | 58 | maxDeviation: units.gu(2) | ||
1262 | 59 | wideningAngle: 10 | ||
1263 | 60 | distanceThreshold: units.gu(4) | ||
1264 | 61 | |||
1265 | 62 | onStatusChanged: { | ||
1266 | 63 | switch (status) { | ||
1267 | 64 | case DirectionalDragArea.WaitingForTouch: | ||
1268 | 65 | dragAreaRect.opacity = 0.0 | ||
1269 | 66 | break; | ||
1270 | 67 | case DirectionalDragArea.Undecided: | ||
1271 | 68 | dragAreaRect.color = "yellow" | ||
1272 | 69 | dragAreaRect.opacity = 0.3 | ||
1273 | 70 | launcher.x = Qt.binding(launcher.followDragArea) | ||
1274 | 71 | break; | ||
1275 | 72 | case DirectionalDragArea.Recognized: | ||
1276 | 73 | dragAreaRect.color = "green" | ||
1277 | 74 | dragAreaRect.opacity = 0.5 | ||
1278 | 75 | break; | ||
1279 | 76 | default: //case DirectionalDragArea.Rejected: | ||
1280 | 77 | dragAreaRect.color = "red" | ||
1281 | 78 | dragAreaRect.opacity = 0.5 | ||
1282 | 79 | launcher.x = -launcher.height | ||
1283 | 80 | break; | ||
1284 | 81 | } | ||
1285 | 82 | } | ||
1286 | 83 | |||
1287 | 84 | anchors { | ||
1288 | 85 | right: parent.right | ||
1289 | 86 | top: parent.top | ||
1290 | 87 | bottom: parent.bottom | ||
1291 | 88 | } | ||
1292 | 89 | } | ||
1293 | 90 | } | ||
1294 | 0 | 91 | ||
1295 | === added file 'tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml' | |||
1296 | --- tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml 1970-01-01 00:00:00 +0000 | |||
1297 | +++ tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml 2013-05-20 13:14:26 +0000 | |||
1298 | @@ -0,0 +1,86 @@ | |||
1299 | 1 | /* | ||
1300 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
1301 | 3 | * | ||
1302 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1303 | 5 | * it under the terms of the GNU General Public License as published by | ||
1304 | 6 | * the Free Software Foundation; version 3. | ||
1305 | 7 | * | ||
1306 | 8 | * This program is distributed in the hope that it will be useful, | ||
1307 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1308 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1309 | 11 | * GNU General Public License for more details. | ||
1310 | 12 | * | ||
1311 | 13 | * You should have received a copy of the GNU General Public License | ||
1312 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1313 | 15 | */ | ||
1314 | 16 | |||
1315 | 17 | import QtQuick 2.0 | ||
1316 | 18 | import Ubuntu.Gestures 0.1 | ||
1317 | 19 | import Ubuntu.Components 0.1 | ||
1318 | 20 | |||
1319 | 21 | Item { | ||
1320 | 22 | |||
1321 | 23 | function reset() { launcher.x = -launcher.width } | ||
1322 | 24 | |||
1323 | 25 | Rectangle { | ||
1324 | 26 | id: launcher | ||
1325 | 27 | color: "blue" | ||
1326 | 28 | width: units.gu(15) | ||
1327 | 29 | height: parent.height | ||
1328 | 30 | x: followDragArea() | ||
1329 | 31 | y: 0 | ||
1330 | 32 | |||
1331 | 33 | function followDragArea() { | ||
1332 | 34 | if (dragArea.status === DirectionalDragArea.Rejected) | ||
1333 | 35 | return -width | ||
1334 | 36 | else | ||
1335 | 37 | return dragArea.distance < width ? -width + dragArea.distance : 0 | ||
1336 | 38 | } | ||
1337 | 39 | } | ||
1338 | 40 | |||
1339 | 41 | Rectangle { | ||
1340 | 42 | id: dragAreaRect | ||
1341 | 43 | opacity: 0.0 | ||
1342 | 44 | anchors.fill: dragArea | ||
1343 | 45 | } | ||
1344 | 46 | |||
1345 | 47 | DirectionalDragArea { | ||
1346 | 48 | id: dragArea | ||
1347 | 49 | objectName: "hpDragArea" | ||
1348 | 50 | |||
1349 | 51 | width: units.gu(5) | ||
1350 | 52 | |||
1351 | 53 | direction: DirectionalDragArea.Rightwards | ||
1352 | 54 | maxDeviation: units.gu(2) | ||
1353 | 55 | wideningAngle: 10 | ||
1354 | 56 | distanceThreshold: units.gu(4) | ||
1355 | 57 | |||
1356 | 58 | onStatusChanged: { | ||
1357 | 59 | switch (status) { | ||
1358 | 60 | case DirectionalDragArea.WaitingForTouch: | ||
1359 | 61 | dragAreaRect.opacity = 0.0 | ||
1360 | 62 | break; | ||
1361 | 63 | case DirectionalDragArea.Undecided: | ||
1362 | 64 | dragAreaRect.color = "yellow" | ||
1363 | 65 | dragAreaRect.opacity = 0.3 | ||
1364 | 66 | launcher.x = Qt.binding(launcher.followDragArea) | ||
1365 | 67 | break; | ||
1366 | 68 | case DirectionalDragArea.Recognized: | ||
1367 | 69 | dragAreaRect.color = "green" | ||
1368 | 70 | dragAreaRect.opacity = 0.5 | ||
1369 | 71 | break; | ||
1370 | 72 | default: //case DirectionalDragArea.Rejected: | ||
1371 | 73 | dragAreaRect.color = "red" | ||
1372 | 74 | dragAreaRect.opacity = 0.5 | ||
1373 | 75 | launcher.x = -launcher.height | ||
1374 | 76 | break; | ||
1375 | 77 | } | ||
1376 | 78 | } | ||
1377 | 79 | |||
1378 | 80 | anchors { | ||
1379 | 81 | left: parent.left | ||
1380 | 82 | top: parent.top | ||
1381 | 83 | bottom: parent.bottom | ||
1382 | 84 | } | ||
1383 | 85 | } | ||
1384 | 86 | } | ||
1385 | 0 | 87 | ||
1386 | === added file 'tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml' | |||
1387 | --- tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml 1970-01-01 00:00:00 +0000 | |||
1388 | +++ tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml 2013-05-20 13:14:26 +0000 | |||
1389 | @@ -0,0 +1,90 @@ | |||
1390 | 1 | /* | ||
1391 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
1392 | 3 | * | ||
1393 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1394 | 5 | * it under the terms of the GNU General Public License as published by | ||
1395 | 6 | * the Free Software Foundation; version 3. | ||
1396 | 7 | * | ||
1397 | 8 | * This program is distributed in the hope that it will be useful, | ||
1398 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1399 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1400 | 11 | * GNU General Public License for more details. | ||
1401 | 12 | * | ||
1402 | 13 | * You should have received a copy of the GNU General Public License | ||
1403 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1404 | 15 | */ | ||
1405 | 16 | |||
1406 | 17 | import QtQuick 2.0 | ||
1407 | 18 | import Ubuntu.Gestures 0.1 | ||
1408 | 19 | import Ubuntu.Components 0.1 | ||
1409 | 20 | |||
1410 | 21 | Item { | ||
1411 | 22 | id: root | ||
1412 | 23 | |||
1413 | 24 | function reset() { launcher.y = root.height } | ||
1414 | 25 | |||
1415 | 26 | Rectangle { | ||
1416 | 27 | id: launcher | ||
1417 | 28 | color: "blue" | ||
1418 | 29 | width: parent.width | ||
1419 | 30 | height: units.gu(15) | ||
1420 | 31 | x: 0 | ||
1421 | 32 | y: root.height | ||
1422 | 33 | |||
1423 | 34 | function followDragArea() { | ||
1424 | 35 | if (dragArea.status === DirectionalDragArea.Rejected) | ||
1425 | 36 | return root.height | ||
1426 | 37 | else | ||
1427 | 38 | return dragArea.distance > -height ? | ||
1428 | 39 | root.height + dragArea.distance | ||
1429 | 40 | : | ||
1430 | 41 | root.height - height | ||
1431 | 42 | } | ||
1432 | 43 | } | ||
1433 | 44 | |||
1434 | 45 | Rectangle { | ||
1435 | 46 | id: dragAreaRect | ||
1436 | 47 | opacity: 0.0 | ||
1437 | 48 | anchors.fill: dragArea | ||
1438 | 49 | } | ||
1439 | 50 | |||
1440 | 51 | DirectionalDragArea { | ||
1441 | 52 | id: dragArea | ||
1442 | 53 | objectName: "vnDragArea" | ||
1443 | 54 | |||
1444 | 55 | height: units.gu(5) | ||
1445 | 56 | |||
1446 | 57 | direction: DirectionalDragArea.Upwards | ||
1447 | 58 | maxDeviation: units.gu(2) | ||
1448 | 59 | wideningAngle: 10 | ||
1449 | 60 | distanceThreshold: units.gu(4) | ||
1450 | 61 | |||
1451 | 62 | onStatusChanged: { | ||
1452 | 63 | switch (status) { | ||
1453 | 64 | case DirectionalDragArea.WaitingForTouch: | ||
1454 | 65 | dragAreaRect.opacity = 0.0 | ||
1455 | 66 | break; | ||
1456 | 67 | case DirectionalDragArea.Undecided: | ||
1457 | 68 | dragAreaRect.color = "yellow" | ||
1458 | 69 | dragAreaRect.opacity = 0.3 | ||
1459 | 70 | launcher.y = Qt.binding(launcher.followDragArea) | ||
1460 | 71 | break; | ||
1461 | 72 | case DirectionalDragArea.Recognized: | ||
1462 | 73 | dragAreaRect.color = "green" | ||
1463 | 74 | dragAreaRect.opacity = 0.5 | ||
1464 | 75 | break; | ||
1465 | 76 | default: //case DirectionalDragArea.Rejected: | ||
1466 | 77 | dragAreaRect.color = "red" | ||
1467 | 78 | dragAreaRect.opacity = 0.5 | ||
1468 | 79 | launcher.y = -launcher.height | ||
1469 | 80 | break; | ||
1470 | 81 | } | ||
1471 | 82 | } | ||
1472 | 83 | |||
1473 | 84 | anchors { | ||
1474 | 85 | left: parent.left | ||
1475 | 86 | right: parent.right | ||
1476 | 87 | bottom: parent.bottom | ||
1477 | 88 | } | ||
1478 | 89 | } | ||
1479 | 90 | } | ||
1480 | 0 | 91 | ||
1481 | === added file 'tests/plugins/Ubuntu/Gestures/edgeDragExample.qml' | |||
1482 | --- tests/plugins/Ubuntu/Gestures/edgeDragExample.qml 1970-01-01 00:00:00 +0000 | |||
1483 | +++ tests/plugins/Ubuntu/Gestures/edgeDragExample.qml 2013-05-20 13:14:26 +0000 | |||
1484 | @@ -0,0 +1,40 @@ | |||
1485 | 1 | /* | ||
1486 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
1487 | 3 | * | ||
1488 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1489 | 5 | * it under the terms of the GNU General Public License as published by | ||
1490 | 6 | * the Free Software Foundation; version 3. | ||
1491 | 7 | * | ||
1492 | 8 | * This program is distributed in the hope that it will be useful, | ||
1493 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1494 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1495 | 11 | * GNU General Public License for more details. | ||
1496 | 12 | * | ||
1497 | 13 | * You should have received a copy of the GNU General Public License | ||
1498 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1499 | 15 | */ | ||
1500 | 16 | |||
1501 | 17 | import QtQuick 2.0 | ||
1502 | 18 | import Ubuntu.Components 0.1 | ||
1503 | 19 | |||
1504 | 20 | Rectangle { | ||
1505 | 21 | //width: units.gu(40) | ||
1506 | 22 | //height: units.gu(71) | ||
1507 | 23 | color: "white" | ||
1508 | 24 | |||
1509 | 25 | MouseArea { | ||
1510 | 26 | id: mouseArea | ||
1511 | 27 | anchors.fill: parent | ||
1512 | 28 | onClicked: { | ||
1513 | 29 | hpLauncher.reset() | ||
1514 | 30 | hnLauncher.reset() | ||
1515 | 31 | vpLauncher.reset() | ||
1516 | 32 | vnLauncher.reset() | ||
1517 | 33 | } | ||
1518 | 34 | } | ||
1519 | 35 | |||
1520 | 36 | RightwardsLauncher { id: hpLauncher; anchors.fill: parent } | ||
1521 | 37 | LeftwardsLauncher { id: hnLauncher; anchors.fill: parent } | ||
1522 | 38 | DownwardsLauncher { id: vpLauncher; anchors.fill: parent } | ||
1523 | 39 | UpwardsLauncher { id: vnLauncher; anchors.fill: parent } | ||
1524 | 40 | } | ||
1525 | 0 | 41 | ||
1526 | === added file 'tests/plugins/Ubuntu/Gestures/tst_Damper.cpp' | |||
1527 | --- tests/plugins/Ubuntu/Gestures/tst_Damper.cpp 1970-01-01 00:00:00 +0000 | |||
1528 | +++ tests/plugins/Ubuntu/Gestures/tst_Damper.cpp 2013-05-20 13:14:26 +0000 | |||
1529 | @@ -0,0 +1,40 @@ | |||
1530 | 1 | /* | ||
1531 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
1532 | 3 | * | ||
1533 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1534 | 5 | * it under the terms of the GNU General Public License as published by | ||
1535 | 6 | * the Free Software Foundation; version 3. | ||
1536 | 7 | * | ||
1537 | 8 | * This program is distributed in the hope that it will be useful, | ||
1538 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1539 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1540 | 11 | * GNU General Public License for more details. | ||
1541 | 12 | * | ||
1542 | 13 | * You should have received a copy of the GNU General Public License | ||
1543 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1544 | 15 | */ | ||
1545 | 16 | |||
1546 | 17 | #include <QtTest/QtTest> | ||
1547 | 18 | |||
1548 | 19 | #include <Damper.h> | ||
1549 | 20 | |||
1550 | 21 | class tst_Damper : public QObject | ||
1551 | 22 | { | ||
1552 | 23 | Q_OBJECT | ||
1553 | 24 | private Q_SLOTS: | ||
1554 | 25 | void negativeMovement(); | ||
1555 | 26 | }; | ||
1556 | 27 | |||
1557 | 28 | void tst_Damper::negativeMovement() | ||
1558 | 29 | { | ||
1559 | 30 | Damper<qreal> damper; | ||
1560 | 31 | |||
1561 | 32 | damper.setMaxDelta(3.0); | ||
1562 | 33 | damper.reset(0.0); | ||
1563 | 34 | damper.update(-5.0); | ||
1564 | 35 | QCOMPARE(damper.value(), -2.0); | ||
1565 | 36 | } | ||
1566 | 37 | |||
1567 | 38 | QTEST_MAIN(tst_Damper) | ||
1568 | 39 | |||
1569 | 40 | #include "tst_Damper.moc" | ||
1570 | 0 | 41 | ||
1571 | === added file 'tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp' | |||
1572 | --- tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp 1970-01-01 00:00:00 +0000 | |||
1573 | +++ tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp 2013-05-20 13:14:26 +0000 | |||
1574 | @@ -0,0 +1,275 @@ | |||
1575 | 1 | /* | ||
1576 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
1577 | 3 | * | ||
1578 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1579 | 5 | * it under the terms of the GNU General Public License as published by | ||
1580 | 6 | * the Free Software Foundation; version 3. | ||
1581 | 7 | * | ||
1582 | 8 | * This program is distributed in the hope that it will be useful, | ||
1583 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1584 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1585 | 11 | * GNU General Public License for more details. | ||
1586 | 12 | * | ||
1587 | 13 | * You should have received a copy of the GNU General Public License | ||
1588 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1589 | 15 | */ | ||
1590 | 16 | |||
1591 | 17 | #include <QtTest/QtTest> | ||
1592 | 18 | #include <QtCore/QObject> | ||
1593 | 19 | #include <qpa/qwindowsysteminterface.h> | ||
1594 | 20 | #include <QtQuick/QQuickView> | ||
1595 | 21 | #include <QtQml/QQmlEngine> | ||
1596 | 22 | |||
1597 | 23 | #include <DirectionalDragArea.h> | ||
1598 | 24 | |||
1599 | 25 | class tst_DirectionalDragArea: public QObject | ||
1600 | 26 | { | ||
1601 | 27 | Q_OBJECT | ||
1602 | 28 | public: | ||
1603 | 29 | tst_DirectionalDragArea() : device(0) { } | ||
1604 | 30 | private Q_SLOTS: | ||
1605 | 31 | void initTestCase(); // will be called before the first test function is executed | ||
1606 | 32 | void cleanupTestCase(); // will be called after the last test function was executed. | ||
1607 | 33 | |||
1608 | 34 | void edgeDrag(); | ||
1609 | 35 | void edgeDrag_data(); | ||
1610 | 36 | void dragWithShortDirectionChange(); | ||
1611 | 37 | |||
1612 | 38 | private: | ||
1613 | 39 | QQuickView *createView(); | ||
1614 | 40 | QTouchDevice *device; | ||
1615 | 41 | }; | ||
1616 | 42 | |||
1617 | 43 | void tst_DirectionalDragArea::initTestCase() | ||
1618 | 44 | { | ||
1619 | 45 | if (!device) { | ||
1620 | 46 | device = new QTouchDevice; | ||
1621 | 47 | device->setType(QTouchDevice::TouchScreen); | ||
1622 | 48 | QWindowSystemInterface::registerTouchDevice(device); | ||
1623 | 49 | } | ||
1624 | 50 | } | ||
1625 | 51 | |||
1626 | 52 | void tst_DirectionalDragArea::cleanupTestCase() | ||
1627 | 53 | { | ||
1628 | 54 | } | ||
1629 | 55 | |||
1630 | 56 | QQuickView *tst_DirectionalDragArea::createView() | ||
1631 | 57 | { | ||
1632 | 58 | QQuickView *window = new QQuickView(0); | ||
1633 | 59 | window->setResizeMode(QQuickView::SizeRootObjectToView); | ||
1634 | 60 | window->resize(600, 600); | ||
1635 | 61 | window->engine()->addImportPath(QLatin1String(UBUNTU_GESTURES_PLUGIN_DIR)); | ||
1636 | 62 | |||
1637 | 63 | return window; | ||
1638 | 64 | } | ||
1639 | 65 | |||
1640 | 66 | namespace { | ||
1641 | 67 | QPointF calculateInitialTouchPos(DirectionalDragArea *edgeDragArea, QQuickView *view) | ||
1642 | 68 | { | ||
1643 | 69 | switch (edgeDragArea->direction()) { | ||
1644 | 70 | case DirectionalDragArea::Upwards: | ||
1645 | 71 | return QPointF(view->width()/2.0f, view->height() - (edgeDragArea->height()/2.0f)); | ||
1646 | 72 | case DirectionalDragArea::Downwards: | ||
1647 | 73 | return QPointF(view->width()/2.0f, edgeDragArea->height()/2.0f); | ||
1648 | 74 | case DirectionalDragArea::Leftwards: | ||
1649 | 75 | return QPointF(view->width() - (edgeDragArea->width()/2.0f), view->height()/2.0f); | ||
1650 | 76 | default: // DirectionalDragArea::Rightwards: | ||
1651 | 77 | return QPointF(edgeDragArea->width()/2.0f, view->height()/2.0f); | ||
1652 | 78 | } | ||
1653 | 79 | } | ||
1654 | 80 | |||
1655 | 81 | QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea, | ||
1656 | 82 | qreal wideningAngleMultiplier) | ||
1657 | 83 | { | ||
1658 | 84 | qreal angleRadians = edgeDragArea->wideningAngle() * wideningAngleMultiplier | ||
1659 | 85 | * M_PI / 180.0; | ||
1660 | 86 | |||
1661 | 87 | qreal angleCos = qCos(angleRadians); | ||
1662 | 88 | qreal angleSin = qSin(angleRadians); | ||
1663 | 89 | |||
1664 | 90 | switch (edgeDragArea->direction()) { | ||
1665 | 91 | case DirectionalDragArea::Upwards: | ||
1666 | 92 | return QPointF(angleSin, -angleCos); | ||
1667 | 93 | case DirectionalDragArea::Downwards: | ||
1668 | 94 | return QPointF(angleSin, angleCos); | ||
1669 | 95 | case DirectionalDragArea::Leftwards: | ||
1670 | 96 | return QPointF(-angleCos, angleSin); | ||
1671 | 97 | default: // DirectionalDragArea::Rightwards: | ||
1672 | 98 | return QPointF(angleCos, angleSin); | ||
1673 | 99 | } | ||
1674 | 100 | } | ||
1675 | 101 | |||
1676 | 102 | QPointF createTouchDeviation(DirectionalDragArea *edgeDragArea) | ||
1677 | 103 | { | ||
1678 | 104 | qreal deviation = edgeDragArea->maxDeviation() * 0.8; | ||
1679 | 105 | |||
1680 | 106 | if (edgeDragArea->direction() == DirectionalDragArea::Leftwards | ||
1681 | 107 | || edgeDragArea->direction() == DirectionalDragArea::Rightwards) { | ||
1682 | 108 | return QPointF(0, deviation); | ||
1683 | 109 | } else { | ||
1684 | 110 | return QPointF(deviation, 0); | ||
1685 | 111 | } | ||
1686 | 112 | } | ||
1687 | 113 | } | ||
1688 | 114 | |||
1689 | 115 | void tst_DirectionalDragArea::edgeDrag() | ||
1690 | 116 | { | ||
1691 | 117 | QFETCH(QString, dragAreaObjectName); | ||
1692 | 118 | QFETCH(qreal, wideningAngleMultiplier); | ||
1693 | 119 | QFETCH(qreal, dragDistanceFactor); | ||
1694 | 120 | QFETCH(int, expectedGestureRecognition); | ||
1695 | 121 | |||
1696 | 122 | QQuickView *view = createView(); | ||
1697 | 123 | QScopedPointer<QQuickView> scope(view); | ||
1698 | 124 | view->setSource(QUrl::fromLocalFile("edgeDragExample.qml")); | ||
1699 | 125 | view->show(); | ||
1700 | 126 | QVERIFY(QTest::qWaitForWindowExposed(view)); | ||
1701 | 127 | QVERIFY(view->rootObject() != 0); | ||
1702 | 128 | qApp->processEvents(); | ||
1703 | 129 | |||
1704 | 130 | DirectionalDragArea *edgeDragArea = | ||
1705 | 131 | view->rootObject()->findChild<DirectionalDragArea*>(dragAreaObjectName); | ||
1706 | 132 | QVERIFY(edgeDragArea != 0); | ||
1707 | 133 | |||
1708 | 134 | QSignalSpy draggingSpy(edgeDragArea, SIGNAL(draggingChanged(bool))); | ||
1709 | 135 | |||
1710 | 136 | QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view); | ||
1711 | 137 | QPointF touchPoint = initialTouchPos; | ||
1712 | 138 | |||
1713 | 139 | qreal desiredDragDistance = edgeDragArea->distanceThreshold()*dragDistanceFactor; | ||
1714 | 140 | QPointF dragDirectionVector = calculateDirectionVector(edgeDragArea, | ||
1715 | 141 | wideningAngleMultiplier); | ||
1716 | 142 | QPointF touchMovement = dragDirectionVector * (edgeDragArea->distanceThreshold() * 0.1f); | ||
1717 | 143 | |||
1718 | 144 | QTest::touchEvent(view, device).press(0, touchPoint.toPoint()); | ||
1719 | 145 | |||
1720 | 146 | QCOMPARE(draggingSpy.count(), 1); | ||
1721 | 147 | QCOMPARE(edgeDragArea->dragging(), true); | ||
1722 | 148 | |||
1723 | 149 | if (wideningAngleMultiplier > 0) { | ||
1724 | 150 | // go close to the border of the valid area for this touch point | ||
1725 | 151 | // in order to make it easier to leave it by dragging at an angle | ||
1726 | 152 | // slightly bigger than the widening angle | ||
1727 | 153 | touchPoint += createTouchDeviation(edgeDragArea); | ||
1728 | 154 | QTest::touchEvent(view, device).move(0, touchPoint.toPoint()); | ||
1729 | 155 | } | ||
1730 | 156 | |||
1731 | 157 | do { | ||
1732 | 158 | touchPoint += touchMovement; | ||
1733 | 159 | QTest::touchEvent(view, device).move(0, touchPoint.toPoint()); | ||
1734 | 160 | } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance); | ||
1735 | 161 | |||
1736 | 162 | if (expectedGestureRecognition) | ||
1737 | 163 | QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized); | ||
1738 | 164 | |||
1739 | 165 | if (edgeDragArea->status() == DirectionalDragArea::Rejected) | ||
1740 | 166 | QCOMPARE(edgeDragArea->dragging(), false); | ||
1741 | 167 | |||
1742 | 168 | QTest::touchEvent(view, device).release(0, touchPoint.toPoint()); | ||
1743 | 169 | |||
1744 | 170 | QCOMPARE(draggingSpy.count(), 2); | ||
1745 | 171 | QCOMPARE(edgeDragArea->dragging(), false); | ||
1746 | 172 | } | ||
1747 | 173 | |||
1748 | 174 | void tst_DirectionalDragArea::edgeDrag_data() | ||
1749 | 175 | { | ||
1750 | 176 | QTest::addColumn<QString>("dragAreaObjectName"); | ||
1751 | 177 | QTest::addColumn<qreal>("wideningAngleMultiplier"); | ||
1752 | 178 | QTest::addColumn<qreal>("dragDistanceFactor"); | ||
1753 | 179 | QTest::addColumn<int>("expectedGestureRecognition"); | ||
1754 | 180 | |||
1755 | 181 | QTest::newRow("rightwards, tiny drag") | ||
1756 | 182 | << "hpDragArea" << 0.0 << 0.2 << 0; | ||
1757 | 183 | |||
1758 | 184 | QTest::newRow("rightwards, straight drag") | ||
1759 | 185 | << "hpDragArea" << 0.0 << 3.0 << 1; | ||
1760 | 186 | |||
1761 | 187 | QTest::newRow("rightwards, diagonal drag") | ||
1762 | 188 | << "hpDragArea" << 0.9 << 3.0 << 1; | ||
1763 | 189 | |||
1764 | 190 | QTest::newRow("rightwards, overly diagonal drag") | ||
1765 | 191 | << "hpDragArea" << 2.0 << 3.0 << 0; | ||
1766 | 192 | |||
1767 | 193 | QTest::newRow("leftwards, tiny drag") | ||
1768 | 194 | << "hnDragArea" << 0.0 << 0.2 << 0; | ||
1769 | 195 | |||
1770 | 196 | QTest::newRow("leftwards, straight drag") | ||
1771 | 197 | << "hnDragArea" << 0.0 << 3.0 << 1; | ||
1772 | 198 | |||
1773 | 199 | QTest::newRow("leftwards, diagonal drag") | ||
1774 | 200 | << "hnDragArea" << 0.9 << 3.0 << 1; | ||
1775 | 201 | |||
1776 | 202 | QTest::newRow("downwards, tiny drag") | ||
1777 | 203 | << "vpDragArea" << 0.0 << 0.2 << 0; | ||
1778 | 204 | |||
1779 | 205 | QTest::newRow("downwards, straight drag") | ||
1780 | 206 | << "vpDragArea" << 0.0 << 3.0 << 1; | ||
1781 | 207 | |||
1782 | 208 | QTest::newRow("downwards, diagonal drag") | ||
1783 | 209 | << "vpDragArea" << 0.9 << 3.0 << 1; | ||
1784 | 210 | |||
1785 | 211 | QTest::newRow("upwards, tiny drag") | ||
1786 | 212 | << "vnDragArea" << 0.0 << 0.2 << 0; | ||
1787 | 213 | |||
1788 | 214 | QTest::newRow("upwards, straight drag") | ||
1789 | 215 | << "vnDragArea" << 0.0 << 3.0 << 1; | ||
1790 | 216 | |||
1791 | 217 | QTest::newRow("upwards, diagonal drag") | ||
1792 | 218 | << "vnDragArea" << 0.9 << 3.0 << 1; | ||
1793 | 219 | |||
1794 | 220 | QTest::newRow("upwards, overly diagonal drag") | ||
1795 | 221 | << "vnDragArea" << 2.0 << 3.0 << 0; | ||
1796 | 222 | } | ||
1797 | 223 | |||
1798 | 224 | /* | ||
1799 | 225 | A directional drag should still be recognized if there is a momentaneous, small, | ||
1800 | 226 | change in the direction of a drag. That should be accounted as input noise and | ||
1801 | 227 | therefore ignored. | ||
1802 | 228 | */ | ||
1803 | 229 | void tst_DirectionalDragArea::dragWithShortDirectionChange() | ||
1804 | 230 | { | ||
1805 | 231 | QQuickView *view = createView(); | ||
1806 | 232 | QScopedPointer<QQuickView> scope(view); | ||
1807 | 233 | view->setSource(QUrl::fromLocalFile("edgeDragExample.qml")); | ||
1808 | 234 | view->show(); | ||
1809 | 235 | QVERIFY(QTest::qWaitForWindowExposed(view)); | ||
1810 | 236 | QVERIFY(view->rootObject() != 0); | ||
1811 | 237 | qApp->processEvents(); | ||
1812 | 238 | |||
1813 | 239 | DirectionalDragArea *edgeDragArea = | ||
1814 | 240 | view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea"); | ||
1815 | 241 | QVERIFY(edgeDragArea != 0); | ||
1816 | 242 | |||
1817 | 243 | QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view); | ||
1818 | 244 | QPointF touchPoint = initialTouchPos; | ||
1819 | 245 | |||
1820 | 246 | qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0; | ||
1821 | 247 | QPointF dragDirectionVector(1.0, 0.0); | ||
1822 | 248 | QPointF touchMovement = dragDirectionVector * (edgeDragArea->distanceThreshold() * 0.1f); | ||
1823 | 249 | |||
1824 | 250 | QTest::touchEvent(view, device).press(0, touchPoint.toPoint()); | ||
1825 | 251 | |||
1826 | 252 | // Move a bit in the proper direction | ||
1827 | 253 | for (int i=0; i < 3; ++i) { | ||
1828 | 254 | touchPoint += touchMovement; | ||
1829 | 255 | QTest::touchEvent(view, device).move(0, touchPoint.toPoint()); | ||
1830 | 256 | } | ||
1831 | 257 | |||
1832 | 258 | // Then a sudden and small movement to the opposite direction | ||
1833 | 259 | touchPoint -= dragDirectionVector * (edgeDragArea->maxDeviation() * 0.7); | ||
1834 | 260 | QTest::touchEvent(view, device).move(0, touchPoint.toPoint()); | ||
1835 | 261 | |||
1836 | 262 | // And then resume movment in the correct direction until it crosses the distance threshold. | ||
1837 | 263 | do { | ||
1838 | 264 | touchPoint += touchMovement; | ||
1839 | 265 | QTest::touchEvent(view, device).move(0, touchPoint.toPoint()); | ||
1840 | 266 | } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance); | ||
1841 | 267 | |||
1842 | 268 | QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized); | ||
1843 | 269 | |||
1844 | 270 | QTest::touchEvent(view, device).release(0, touchPoint.toPoint()); | ||
1845 | 271 | } | ||
1846 | 272 | |||
1847 | 273 | QTEST_MAIN(tst_DirectionalDragArea) | ||
1848 | 274 | |||
1849 | 275 | #include "tst_DirectionalDragArea.moc" |
FAILED: Continuous integration, rev:662 jenkins. qa.ubuntu. com/job/ unity-phablet- ci/865/ s-jenkins: 8080/job/ unity-phablet- qmluitests/ 790/console jenkins. qa.ubuntu. com/job/ unity-phablet- raring- armhf-ci/ 741/console jenkins. qa.ubuntu. com/job/ unity-phablet- raring- i386-ci/ 745/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ unity-phablet- ci/865/ rebuild
http://