Merge lp:~ci-train-bot/unity8/unity8-ubuntu-yakkety-landing-059 into lp:unity8
- unity8-ubuntu-yakkety-landing-059
- Merge into trunk
Proposed by
Michał Sawicz
Status: | Merged | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Merged at revision: | 2440 | ||||||||||||||||
Proposed branch: | lp:~ci-train-bot/unity8/unity8-ubuntu-yakkety-landing-059 | ||||||||||||||||
Merge into: | lp:unity8 | ||||||||||||||||
Diff against target: |
14480 lines (+2342/-7398) 240 files modified
CMakeLists.txt (+13/-2) debian/changelog (+65/-0) debian/control (+5/-3) debian/unity8-private.install (+0/-1) libs/CMakeLists.txt (+0/-1) libs/UbuntuGestures/CMakeLists.txt (+0/-41) libs/UbuntuGestures/CandidateInactivityTimer.cpp (+0/-46) libs/UbuntuGestures/CandidateInactivityTimer.h (+0/-51) libs/UbuntuGestures/DebugHelpers.cpp (+0/-95) libs/UbuntuGestures/DebugHelpers.h (+0/-31) libs/UbuntuGestures/Pool.h (+0/-124) libs/UbuntuGestures/TimeSource.cpp (+0/-49) libs/UbuntuGestures/TimeSource.h (+0/-64) libs/UbuntuGestures/Timer.cpp (+0/-152) libs/UbuntuGestures/Timer.h (+0/-122) libs/UbuntuGestures/TouchOwnershipEvent.cpp (+0/-35) libs/UbuntuGestures/TouchOwnershipEvent.h (+0/-50) libs/UbuntuGestures/TouchRegistry.cpp (+0/-553) libs/UbuntuGestures/TouchRegistry.h (+0/-201) libs/UbuntuGestures/UbuntuGesturesGlobal.h (+0/-23) libs/UbuntuGestures/UnownedTouchEvent.cpp (+0/-39) libs/UbuntuGestures/UnownedTouchEvent.h (+0/-45) plugins/Cursor/CMakeLists.txt (+2/-1) plugins/Cursor/Cursor.qml (+21/-5) plugins/Cursor/Cursor.qmltypes (+0/-78) plugins/Cursor/CursorImageInfo.cpp (+106/-0) plugins/Cursor/CursorImageInfo.h (+76/-0) plugins/Cursor/CursorImageProvider.cpp (+52/-23) plugins/Cursor/CursorImageProvider.h (+12/-4) plugins/Cursor/MousePointer.cpp (+29/-24) plugins/Cursor/MousePointer.h (+5/-6) plugins/Cursor/plugin.cpp (+4/-2) plugins/Cursor/qmldir (+1/-1) plugins/Dash/AudioProgressBar.qml (+1/-1) plugins/Dash/CardCreator.js (+64/-48) plugins/Dash/CardCreatorCache.qml (+2/-2) plugins/Dash/ScopeStyle.qml (+1/-1) plugins/Dash/listviewwithpageheader.cpp (+14/-17) plugins/Ubuntu/Gestures/AxisVelocityCalculator.h (+1/-1) plugins/Ubuntu/Gestures/CMakeLists.txt (+5/-5) plugins/Ubuntu/Gestures/Damper.cpp (+0/-24) plugins/Ubuntu/Gestures/Damper.h (+0/-89) plugins/Ubuntu/Gestures/Direction.h (+1/-0) plugins/Ubuntu/Gestures/DirectionalDragArea.cpp (+0/-932) plugins/Ubuntu/Gestures/DirectionalDragArea.h (+0/-143) plugins/Ubuntu/Gestures/DirectionalDragArea_p.h (+0/-169) plugins/Ubuntu/Gestures/Gestures.qmltypes (+0/-132) plugins/Ubuntu/Gestures/MouseEventGenerator.cpp (+48/-134) plugins/Ubuntu/Gestures/MouseEventGenerator.h (+23/-61) plugins/Ubuntu/Gestures/PressedOutsideNotifier.h (+1/-1) plugins/Ubuntu/Gestures/TouchGate.cpp (+2/-2) plugins/Ubuntu/Gestures/TouchGestureArea.cpp (+9/-6) plugins/Ubuntu/Gestures/TouchGestureArea.h (+2/-3) plugins/Ubuntu/Gestures/plugin.cpp (+3/-5) plugins/Unity/InputInfo/plugin.h (+1/-1) plugins/Unity/InputInfo/qdeclarativeinputdevicemodel_p.h (+3/-3) plugins/Unity/Session/dbusunitysessionservice.cpp (+7/-0) plugins/Utils/WindowInputMonitor.cpp (+8/-8) plugins/Utils/WindowInputMonitor.h (+8/-2) plugins/Utils/windowstatestorage.h (+13/-3) po/unity8.pot (+22/-22) qml/Components/Dialogs.qml (+2/-2) qml/Components/DragHandle.qml (+44/-26) qml/Components/FloatingFlickable.qml (+59/-0) qml/Components/Header.qml (+0/-28) qml/Components/ModeSwitchWarningDialog.qml (+1/-1) qml/Components/PanelState/PanelState.qml (+3/-3) qml/Components/Rating.qml (+1/-0) qml/Components/RatingStyle.qml (+3/-0) qml/Components/WindowControlButtons.qml (+18/-7) qml/Dash/CardCarousel.qml (+0/-1) qml/Dash/CardGrid.qml (+0/-2) qml/Dash/CardTool.qml (+6/-2) qml/Dash/Dash.qml (+3/-3) qml/Dash/DashApplication.qml (+0/-3) qml/Dash/DashCategoryBase.qml (+3/-11) qml/Dash/DashPageHeader.qml (+32/-37) qml/Dash/Filters/FilterOptionSelector.qml (+4/-0) qml/Dash/Filters/FilterWidgetFactory.qml (+8/-0) qml/Dash/GenericScopeView.qml (+14/-4) qml/Dash/PageHeaderExtraPanel.qml (+35/-11) qml/Dash/Previews/PreviewActions.qml (+1/-1) qml/Dash/Previews/PreviewPayments.qml (+1/-1) qml/Dash/Previews/PreviewRatingInput.qml (+42/-43) qml/Dash/ScopesList.qml (+1/-13) qml/Launcher/Launcher.qml (+16/-24) qml/Launcher/LauncherDelegate.qml (+2/-2) qml/Notifications/Notification.qml (+20/-5) qml/Notifications/NotificationMenuItemFactory.qml (+3/-0) qml/Notifications/Notifications.qml (+18/-9) qml/Panel/Indicators/MessageMenuItemFactory.qml (+1/-5) qml/Panel/IndicatorsMenu.qml (+17/-13) qml/Panel/Panel.qml (+15/-5) qml/Shell.qml (+4/-3) qml/Stages/DecoratedWindow.qml (+11/-7) qml/Stages/DesktopSpread.qml (+1/-1) qml/Stages/DesktopSpreadDelegate.qml (+1/-1) qml/Stages/DesktopStage.qml (+57/-45) qml/Stages/PhoneStage.qml (+4/-4) qml/Stages/SideStage.qml (+1/-2) qml/Stages/Splash.qml (+6/-17) qml/Stages/SpreadDelegate.qml (+1/-1) qml/Stages/TabletStage.qml (+4/-4) qml/Stages/WindowDecoration.qml (+12/-8) qml/Stages/WindowResizeArea.qml (+25/-5) qml/Tutorial/TutorialBottom.qml (+3/-3) qml/Wizard/Pages/50-timezone.qml (+5/-2) src/CMakeLists.txt (+1/-4) src/Dash/CMakeLists.txt (+1/-0) src/Dash/main.cpp (+6/-0) src/UnixSignalHandler.cpp (+1/-1) src/main.cpp (+6/-0) tests/CMakeLists.txt (+0/-1) tests/autopilot/unity8/dash.py (+2/-3) tests/libs/CMakeLists.txt (+0/-1) tests/libs/UbuntuGestures/CMakeLists.txt (+0/-16) tests/libs/UbuntuGestures/tst_TouchRegistry.cpp (+0/-974) tests/mocks/Cursor/qmldir (+1/-1) tests/mocks/GSettings.1.0/fake_gsettings.cpp (+1/-0) tests/mocks/GSettings.1.0/fake_gsettings.h (+2/-2) tests/mocks/IntegratedLightDM/liblightdm/GreeterPrivate.h (+0/-1) tests/mocks/QtMultimedia/audio.cpp (+3/-3) tests/mocks/QtMultimedia/audio.h (+12/-6) tests/mocks/Ubuntu/Payments/MockPayments.cpp (+1/-0) tests/mocks/Ubuntu/SystemSettings/TimeDate/CMakeLists.txt (+1/-1) tests/mocks/Ubuntu/SystemSettings/TimeDate/MockTimeDate.qml (+16/-4) tests/mocks/Ubuntu/SystemSettings/TimeDate/qmldir (+1/-1) tests/mocks/Unity/Application/ApplicationInfo.h (+1/-1) tests/mocks/Unity/Application/MirSurface.h (+2/-2) tests/mocks/Unity/Application/MirSurfaceItem.cpp (+1/-0) tests/mocks/Unity/InputInfo/plugin.h (+1/-1) tests/mocks/Unity/Screens/plugin.h (+1/-1) tests/mocks/Unity/fake_scope.cpp (+6/-3) tests/mocks/Unity/fake_scope.h (+1/-1) tests/mocks/Unity/fake_scopes.cpp (+11/-0) tests/mocks/Utils/plugin.h (+1/-1) tests/mocks/Utils/windowstatestorage.h (+14/-3) tests/mocks/libusermetrics/UserMetrics.cpp (+1/-1) tests/plugins/CMakeLists.txt (+2/-1) tests/plugins/Cursor/CMakeLists.txt (+8/-0) tests/plugins/Cursor/TextEntry.qml (+34/-0) tests/plugins/Cursor/tst_Cursor.qml (+144/-0) tests/plugins/Dash/cardcreator/1.res (+8/-26) tests/plugins/Dash/cardcreator/1.res.cardcreator (+8/-26) tests/plugins/Dash/cardcreator/1.tst (+1/-0) tests/plugins/Dash/cardcreator/10.res (+0/-9) tests/plugins/Dash/cardcreator/10.res.cardcreator (+0/-9) tests/plugins/Dash/cardcreator/10.tst (+1/-0) tests/plugins/Dash/cardcreator/11.res (+11/-29) tests/plugins/Dash/cardcreator/11.res.cardcreator (+10/-28) tests/plugins/Dash/cardcreator/11.tst (+1/-0) tests/plugins/Dash/cardcreator/12.res (+8/-26) tests/plugins/Dash/cardcreator/12.res.cardcreator (+10/-28) tests/plugins/Dash/cardcreator/12.tst (+1/-0) tests/plugins/Dash/cardcreator/2.res (+0/-9) tests/plugins/Dash/cardcreator/2.res.cardcreator (+0/-9) tests/plugins/Dash/cardcreator/2.tst (+1/-0) tests/plugins/Dash/cardcreator/3.res (+5/-33) tests/plugins/Dash/cardcreator/3.res.cardcreator (+5/-33) tests/plugins/Dash/cardcreator/3.tst (+1/-0) tests/plugins/Dash/cardcreator/4.res (+1/-2) tests/plugins/Dash/cardcreator/4.res.cardcreator (+1/-2) tests/plugins/Dash/cardcreator/4.tst (+1/-0) tests/plugins/Dash/cardcreator/5.res (+2/-35) tests/plugins/Dash/cardcreator/5.res.cardcreator (+2/-35) tests/plugins/Dash/cardcreator/5.tst (+1/-0) tests/plugins/Dash/cardcreator/6.res (+1/-2) tests/plugins/Dash/cardcreator/6.res.cardcreator (+1/-2) tests/plugins/Dash/cardcreator/6.tst (+1/-0) tests/plugins/Dash/cardcreator/7.res (+0/-9) tests/plugins/Dash/cardcreator/7.res.cardcreator (+0/-9) tests/plugins/Dash/cardcreator/7.tst (+1/-0) tests/plugins/Dash/cardcreator/8.res (+1/-2) tests/plugins/Dash/cardcreator/8.res.cardcreator (+1/-2) tests/plugins/Dash/cardcreator/8.tst (+1/-0) tests/plugins/Dash/cardcreator/9.res (+1/-2) tests/plugins/Dash/cardcreator/9.res.cardcreator (+1/-2) tests/plugins/Dash/cardcreator/9.tst (+1/-0) tests/plugins/Dash/cardcreatortest.cpp (+9/-6) tests/plugins/Dash/cardcreatortest.qml (+4/-4) tests/plugins/Dash/listviewwithpageheadersectionexternalmodeltest.cpp (+2/-2) tests/plugins/Dash/listviewwithpageheadersectiontest.cpp (+2/-2) tests/plugins/Dash/listviewwithpageheadertest.cpp (+5/-0) tests/plugins/Dash/listviewwithpageheadertestsection.qml (+3/-2) tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml (+2/-1) tests/plugins/Dash/tst_ListViewWithPageHeaderQML.qml (+4/-2) tests/plugins/Dash/tst_ScopeStyle.qml (+1/-1) tests/plugins/Ubuntu/Gestures/CMakeLists.txt (+4/-4) tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml (+0/-72) tests/plugins/Ubuntu/Gestures/GestureTest.cpp (+2/-2) tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml (+0/-76) tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml (+0/-76) tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml (+0/-76) tests/plugins/Ubuntu/Gestures/tst_Damper.cpp (+0/-40) tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp (+0/-1250) tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml (+0/-76) tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.cpp (+26/-19) tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.qml (+1/-0) tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp (+1/-1) tests/plugins/Unity/Indicators/MenuContentActivatorTest.cpp (+1/-0) tests/plugins/Unity/Session/sessionbackendtest.cpp (+0/-15) tests/plugins/Utils/WindowInputMonitorTest.cpp (+51/-10) tests/qmltests/Components/CMakeLists.txt (+6/-3) tests/qmltests/Components/tst_DragHandle.cpp (+28/-24) tests/qmltests/Components/tst_DragHandle.qml (+27/-9) tests/qmltests/Components/tst_DragHandle/BottomEdgeShowable.qml (+108/-0) tests/qmltests/Components/tst_DragHandle/RightEdgeShowable.qml (+108/-0) tests/qmltests/Components/tst_DragHandle/TopEdgeShowable.qml (+7/-7) tests/qmltests/Components/tst_EdgeDragEvaluator.cpp (+1/-1) tests/qmltests/Dash/Previews/tst_Preview.qml (+0/-1) tests/qmltests/Dash/Previews/tst_PreviewRatingEdit.qml (+5/-1) tests/qmltests/Dash/Previews/tst_PreviewRatingInput.qml (+18/-6) tests/qmltests/Dash/Previews/tst_PreviewWidgetFactory.qml (+1/-1) tests/qmltests/Dash/tst_Card.qml (+22/-10) tests/qmltests/Dash/tst_CardTool.qml (+1/-1) tests/qmltests/Dash/tst_Dash.qml (+76/-62) tests/qmltests/Dash/tst_DashContent.qml (+65/-6) tests/qmltests/Dash/tst_DashPageHeader.qml (+0/-24) tests/qmltests/Dash/tst_DashShell.qml (+1/-1) tests/qmltests/Dash/tst_GenericScopeView.qml (+2/-2) tests/qmltests/Dash/tst_PreviewView.qml (+3/-3) tests/qmltests/Greeter/tst_Greeter.qml (+1/-1) tests/qmltests/Greeter/tst_NarrowView.qml (+1/-1) tests/qmltests/Greeter/tst_WideView.qml (+1/-1) tests/qmltests/Launcher/tst_Launcher.qml (+13/-1) tests/qmltests/Notifications/tst_Notifications.qml (+89/-0) tests/qmltests/Panel/Indicators/tst_MessageMenuItemFactory.qml (+1/-0) tests/qmltests/Stages/tst_DesktopStage.qml (+31/-1) tests/qmltests/Stages/tst_WindowResizeArea.qml (+16/-5) tests/qmltests/Tutorial/tst_Tutorial.qml (+2/-2) tests/qmltests/Wizard/tst_Wizard.qml (+4/-3) tests/qmltests/tst_OrientedShell.qml (+1/-1) tests/qmltests/tst_Shell.qml (+32/-5) tests/qmltests/tst_ShellWithPin.qml (+1/-1) tests/uqmlscene/main.cpp (+0/-1) tests/utils/modules/Unity/Test/CMakeLists.txt (+4/-2) tests/utils/modules/Unity/Test/UnityTestCase.qml (+34/-15) tests/utils/modules/Unity/Test/testutil.cpp (+2/-2) tools/CMakeLists.txt (+1/-1) tools/scopetool.cpp (+1/-1) |
||||||||||||||||
To merge this branch: | bzr merge lp:~ci-train-bot/unity8/unity8-ubuntu-yakkety-landing-059 | ||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Unity Team | Pending | ||
Review via email: mp+296236@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'CMakeLists.txt' | |||
2 | --- CMakeLists.txt 2016-05-18 11:17:20 +0000 | |||
3 | +++ CMakeLists.txt 2016-06-01 16:58:47 +0000 | |||
4 | @@ -57,12 +57,24 @@ | |||
5 | 57 | find_package(Qt5Concurrent 5.4 REQUIRED) | 57 | find_package(Qt5Concurrent 5.4 REQUIRED) |
6 | 58 | find_package(Qt5Sql 5.4 REQUIRED) | 58 | find_package(Qt5Sql 5.4 REQUIRED) |
7 | 59 | 59 | ||
9 | 60 | pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=16) | 60 | pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=17) |
10 | 61 | pkg_check_modules(GEONAMES REQUIRED geonames>=0.2) | 61 | pkg_check_modules(GEONAMES REQUIRED geonames>=0.2) |
11 | 62 | pkg_check_modules(GIO REQUIRED gio-2.0>=2.32) | 62 | pkg_check_modules(GIO REQUIRED gio-2.0>=2.32) |
12 | 63 | pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32) | 63 | pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32) |
13 | 64 | pkg_check_modules(QMENUMODEL REQUIRED qmenumodel) | 64 | pkg_check_modules(QMENUMODEL REQUIRED qmenumodel) |
14 | 65 | 65 | ||
15 | 66 | pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures) | ||
16 | 67 | |||
17 | 68 | ### Check UbuntuGestures private headers. No pkg-config (.pc) file is provided for them | ||
18 | 69 | find_path(UBUNTUGESTUREPRIV | ||
19 | 70 | NAMES UbuntuGestures/private/damper_p.h UbuntuGestures/private/ucswipearea_p.h UbuntuGestures/private/ucswipearea_p_p.h | ||
20 | 71 | PATHS ${UBUNTUGESTURES_INCLUDEDIR}/UbuntuGestures/${UBUNTUGESTURES_VERSION} | ||
21 | 72 | NO_DEFAULT_PATH) | ||
22 | 73 | if (${UBUNTUGESTUREPRIV} STREQUAL UBUNTUGESTUREPRIV-NOTFOUND) | ||
23 | 74 | message(FATAL_ERROR "UbuntuGestures private headers not found.") | ||
24 | 75 | endif() | ||
25 | 76 | # end of UbuntuGesture private headers check | ||
26 | 77 | |||
27 | 66 | # Standard install paths | 78 | # Standard install paths |
28 | 67 | include(GNUInstallDirs) | 79 | include(GNUInstallDirs) |
29 | 68 | 80 | ||
30 | @@ -144,7 +156,6 @@ | |||
31 | 144 | 156 | ||
32 | 145 | # add subdirectories to build | 157 | # add subdirectories to build |
33 | 146 | add_subdirectory(include) | 158 | add_subdirectory(include) |
34 | 147 | add_subdirectory(libs) | ||
35 | 148 | add_subdirectory(src) | 159 | add_subdirectory(src) |
36 | 149 | add_subdirectory(tools) | 160 | add_subdirectory(tools) |
37 | 150 | add_subdirectory(qml) | 161 | add_subdirectory(qml) |
38 | 151 | 162 | ||
39 | === modified file 'debian/changelog' | |||
40 | --- debian/changelog 2016-05-20 08:44:19 +0000 | |||
41 | +++ debian/changelog 2016-06-01 16:58:47 +0000 | |||
42 | @@ -1,3 +1,68 @@ | |||
43 | 1 | unity8 (8.12+16.10.20160527-0ubuntu1) yakkety; urgency=medium | ||
44 | 2 | |||
45 | 3 | [ Albert Astals Cid ] | ||
46 | 4 | * Activate on click for SimpleMessages (LP: #1421696) | ||
47 | 5 | * Add override | ||
48 | 6 | * Change the art back to the cardData value if it changes from broken | ||
49 | 7 | to valid image (LP: #1533577) | ||
50 | 8 | * Concierge mode generated code optimization | ||
51 | 9 | * Don't use context properties but properties of the delegates | ||
52 | 10 | * Listen to contentItem::widthChanged instead of | ||
53 | 11 | Flickable::contentWidthChanged (LP: #1565763) | ||
54 | 12 | * Make some AP code faster | ||
55 | 13 | * Make tests a bit more stable | ||
56 | 14 | * Make unity8 and unity8-dash handle termination signals | ||
57 | 15 | * Remove workaround not needed anymore (LP: #1475643) | ||
58 | 16 | * Resolve cardArtStyle on compile time | ||
59 | 17 | * Set the theme earlier (LP: #1574048) | ||
60 | 18 | |||
61 | 19 | [ Albert Astals Cid, Daniel d'Andrada ] | ||
62 | 20 | * Remove DirectionalDragArea and libs/UbuntuGestures and port to SDK | ||
63 | 21 | equivalents | ||
64 | 22 | |||
65 | 23 | [ Andrea Cimitan ] | ||
66 | 24 | * Hide the preview review input field when a rating is required (LP: | ||
67 | 25 | #1541971) | ||
68 | 26 | |||
69 | 27 | [ CI Train Bot ] | ||
70 | 28 | * Resync trunk. | ||
71 | 29 | |||
72 | 30 | [ Daniel d'Andrada ] | ||
73 | 31 | * Fix DragHandle so it works in all directions | ||
74 | 32 | * Support animated cursors | ||
75 | 33 | * WindowInputMonitor - also map Qt::Key_HomePage to our home key | ||
76 | 34 | * plugins/Cursor: properly register to the screen's QPlatformCursor | ||
77 | 35 | when screen changes (LP: #1579742) | ||
78 | 36 | |||
79 | 37 | [ Josh Arenson ] | ||
80 | 38 | * Close the PageHeaderExtraPanel when a filter option is selected (LP: | ||
81 | 39 | #1569498) | ||
82 | 40 | * Wrap primaryFilter in a flickable to make it behave nicely. (LP: | ||
83 | 41 | #1569492) | ||
84 | 42 | |||
85 | 43 | [ Lukáš Tinkl ] | ||
86 | 44 | * First snap decision should always be expanded, unless user decides | ||
87 | 45 | otherwise (LP: #1580090, #1575045) | ||
88 | 46 | * Fullscreen notification bug fixes (LP: #1583944, #1581498, #1422711) | ||
89 | 47 | * Implement maximizing windows horizontally/vertically | ||
90 | 48 | * Lock the session when putting the laptop into sleep (LP: #1581063) | ||
91 | 49 | |||
92 | 50 | [ Lukáš Tinkl, Michael Terry ] | ||
93 | 51 | * With a maximized window, "dragging" the panel down should restore it | ||
94 | 52 | |||
95 | 53 | [ Michael Terry ] | ||
96 | 54 | * Change some dash button colors from orange to green. (LP: #1581047) | ||
97 | 55 | * Use PageHeader instead Ambiance's PageHeadStyle | ||
98 | 56 | * Use new setTimeZone method to set user-friendly timezone name in the | ||
99 | 57 | wizard. (LP: #1566295) | ||
100 | 58 | |||
101 | 59 | [ Michael Zanetti ] | ||
102 | 60 | * Remove the background dimming when the launcher is revealed by a | ||
103 | 61 | drag (LP: #1575137) | ||
104 | 62 | * reenable or drop disabled tests | ||
105 | 63 | |||
106 | 64 | -- Michael Terry <michael.terry@canonical.com> Fri, 27 May 2016 13:54:44 +0000 | ||
107 | 65 | |||
108 | 1 | unity8 (8.12+16.10.20160520.1-0ubuntu1) yakkety; urgency=medium | 66 | unity8 (8.12+16.10.20160520.1-0ubuntu1) yakkety; urgency=medium |
109 | 2 | 67 | ||
110 | 3 | [ Lukáš Tinkl ] | 68 | [ Lukáš Tinkl ] |
111 | 4 | 69 | ||
112 | === modified file 'debian/control' | |||
113 | --- debian/control 2016-05-17 19:42:10 +0000 | |||
114 | +++ debian/control 2016-06-01 16:58:47 +0000 | |||
115 | @@ -29,8 +29,10 @@ | |||
116 | 29 | libqt5svg5-dev, | 29 | libqt5svg5-dev, |
117 | 30 | libqt5xmlpatterns5-dev, | 30 | libqt5xmlpatterns5-dev, |
118 | 31 | libsystemsettings-dev, | 31 | libsystemsettings-dev, |
119 | 32 | libubuntugestures5-dev, | ||
120 | 33 | libubuntugestures5-private-dev, | ||
121 | 32 | libudev-dev, | 34 | libudev-dev, |
123 | 33 | libunity-api-dev (>= 7.112), | 35 | libunity-api-dev (>= 7.113), |
124 | 34 | libusermetricsoutput1-dev, | 36 | libusermetricsoutput1-dev, |
125 | 35 | # Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop | 37 | # Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop |
126 | 36 | libx11-dev[!armhf], | 38 | libx11-dev[!armhf], |
127 | @@ -106,7 +108,7 @@ | |||
128 | 106 | qtdeclarative5-qtmir-plugin (>= 0.4.8), | 108 | qtdeclarative5-qtmir-plugin (>= 0.4.8), |
129 | 107 | qtdeclarative5-ubuntu-telephony0.1, | 109 | qtdeclarative5-ubuntu-telephony0.1, |
130 | 108 | qtdeclarative5-ubuntu-web-plugin, | 110 | qtdeclarative5-ubuntu-web-plugin, |
132 | 109 | ubuntu-system-settings, | 111 | ubuntu-system-settings (>= 0.4), |
133 | 110 | unity-launcher-impl-7, | 112 | unity-launcher-impl-7, |
134 | 111 | unity8-common (= ${source:Version}), | 113 | unity8-common (= ${source:Version}), |
135 | 112 | unity8-private (= ${binary:Version}), | 114 | unity8-private (= ${binary:Version}), |
136 | @@ -133,7 +135,7 @@ | |||
137 | 133 | qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1845) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1845), | 135 | qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1845) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1845), |
138 | 134 | qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl, | 136 | qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl, |
139 | 135 | ubuntu-thumbnailer-impl-0, | 137 | ubuntu-thumbnailer-impl-0, |
141 | 136 | unity-application-impl-16, | 138 | unity-application-impl-17, |
142 | 137 | unity-notifications-impl-3, | 139 | unity-notifications-impl-3, |
143 | 138 | unity-plugin-scopes | unity-scopes-impl, | 140 | unity-plugin-scopes | unity-scopes-impl, |
144 | 139 | unity-scopes-impl-12, | 141 | unity-scopes-impl-12, |
145 | 140 | 142 | ||
146 | === modified file 'debian/unity8-private.install' | |||
147 | --- debian/unity8-private.install 2016-04-28 12:06:22 +0000 | |||
148 | +++ debian/unity8-private.install 2016-06-01 16:58:47 +0000 | |||
149 | @@ -1,5 +1,4 @@ | |||
150 | 1 | usr/lib/*/libunity8-private.* | 1 | usr/lib/*/libunity8-private.* |
151 | 2 | usr/lib/*/unity8/libUbuntuGestures* | ||
152 | 3 | usr/lib/*/unity8/qml/AccountsService | 2 | usr/lib/*/unity8/qml/AccountsService |
153 | 4 | usr/lib/*/unity8/qml/Cursor | 3 | usr/lib/*/unity8/qml/Cursor |
154 | 5 | usr/lib/*/unity8/qml/Dash | 4 | usr/lib/*/unity8/qml/Dash |
155 | 6 | 5 | ||
156 | === removed directory 'libs' | |||
157 | === removed file 'libs/CMakeLists.txt' | |||
158 | --- libs/CMakeLists.txt 2014-10-01 13:20:32 +0000 | |||
159 | +++ libs/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
160 | @@ -1,1 +0,0 @@ | |||
161 | 1 | add_subdirectory(UbuntuGestures) | ||
162 | 2 | 0 | ||
163 | === removed directory 'libs/UbuntuGestures' | |||
164 | === removed file 'libs/UbuntuGestures/CMakeLists.txt' | |||
165 | --- libs/UbuntuGestures/CMakeLists.txt 2015-04-10 21:16:37 +0000 | |||
166 | +++ libs/UbuntuGestures/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
167 | @@ -1,41 +0,0 @@ | |||
168 | 1 | # in order to include Qt's private headers | ||
169 | 2 | remove_definitions(-DQT_NO_KEYWORDS) | ||
170 | 3 | |||
171 | 4 | set(UbuntuGestures_SOURCES | ||
172 | 5 | CandidateInactivityTimer.cpp | ||
173 | 6 | DebugHelpers.cpp | ||
174 | 7 | Timer.cpp | ||
175 | 8 | TimeSource.cpp | ||
176 | 9 | TouchOwnershipEvent.cpp | ||
177 | 10 | TouchRegistry.cpp | ||
178 | 11 | UnownedTouchEvent.cpp | ||
179 | 12 | ) | ||
180 | 13 | |||
181 | 14 | add_definitions(-DUBUNTUGESTURES_LIBRARY) | ||
182 | 15 | |||
183 | 16 | add_library(UbuntuGestures SHARED ${UbuntuGestures_SOURCES}) | ||
184 | 17 | |||
185 | 18 | qt5_use_modules(UbuntuGestures Core Quick) | ||
186 | 19 | |||
187 | 20 | # So that Foo.cpp can #include "Foo.moc" | ||
188 | 21 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) | ||
189 | 22 | |||
190 | 23 | install(TARGETS UbuntuGestures | ||
191 | 24 | DESTINATION ${SHELL_PRIVATE_LIBDIR}) | ||
192 | 25 | |||
193 | 26 | |||
194 | 27 | # There's no cmake var for v8 include path :-/ so create one | ||
195 | 28 | LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0) | ||
196 | 29 | if(${Qt5Core_VERSION_STRING} VERSION_LESS "5.1.0") | ||
197 | 30 | SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8) | ||
198 | 31 | else() | ||
199 | 32 | SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/QtV8/${Qt5Core_VERSION_STRING}/QtV8) | ||
200 | 33 | endif() | ||
201 | 34 | |||
202 | 35 | # DANGER! DANGER! Using Qt's private API! | ||
203 | 36 | include_directories( | ||
204 | 37 | ${Qt5Qml_PRIVATE_INCLUDE_DIRS} | ||
205 | 38 | ${Qt5Quick_INCLUDE_DIRS} | ||
206 | 39 | ${Qt5Quick_PRIVATE_INCLUDE_DIRS} | ||
207 | 40 | ${Qt5V8_PRIVATE_INCLUDE_DIR} | ||
208 | 41 | ) | ||
209 | 42 | 0 | ||
210 | === removed file 'libs/UbuntuGestures/CandidateInactivityTimer.cpp' | |||
211 | --- libs/UbuntuGestures/CandidateInactivityTimer.cpp 2015-04-17 18:31:12 +0000 | |||
212 | +++ libs/UbuntuGestures/CandidateInactivityTimer.cpp 1970-01-01 00:00:00 +0000 | |||
213 | @@ -1,46 +0,0 @@ | |||
214 | 1 | /* | ||
215 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
216 | 3 | * | ||
217 | 4 | * This program is free software; you can redistribute it and/or modify | ||
218 | 5 | * it under the terms of the GNU General Public License as published by | ||
219 | 6 | * the Free Software Foundation; version 3. | ||
220 | 7 | * | ||
221 | 8 | * This program is distributed in the hope that it will be useful, | ||
222 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
223 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
224 | 11 | * GNU General Public License for more details. | ||
225 | 12 | * | ||
226 | 13 | * You should have received a copy of the GNU General Public License | ||
227 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
228 | 15 | */ | ||
229 | 16 | |||
230 | 17 | #include "CandidateInactivityTimer.h" | ||
231 | 18 | |||
232 | 19 | namespace UbuntuGestures { | ||
233 | 20 | |||
234 | 21 | CandidateInactivityTimer::CandidateInactivityTimer(int touchId, QQuickItem *candidate, | ||
235 | 22 | AbstractTimer *timer, QObject *parent) | ||
236 | 23 | : QObject(parent) | ||
237 | 24 | , m_timer(timer) | ||
238 | 25 | , m_touchId(touchId) | ||
239 | 26 | , m_candidate(candidate) | ||
240 | 27 | { | ||
241 | 28 | connect(m_timer, &AbstractTimer::timeout, | ||
242 | 29 | this, &CandidateInactivityTimer::onTimeout); | ||
243 | 30 | m_timer->setInterval(durationMs); | ||
244 | 31 | m_timer->setSingleShot(true); | ||
245 | 32 | m_timer->start(); | ||
246 | 33 | } | ||
247 | 34 | |||
248 | 35 | CandidateInactivityTimer::~CandidateInactivityTimer() | ||
249 | 36 | { | ||
250 | 37 | delete m_timer; | ||
251 | 38 | } | ||
252 | 39 | |||
253 | 40 | void CandidateInactivityTimer::onTimeout() | ||
254 | 41 | { | ||
255 | 42 | qWarning("[TouchRegistry] Candidate for touch %d defaulted!", m_touchId); | ||
256 | 43 | Q_EMIT candidateDefaulted(m_touchId, m_candidate); | ||
257 | 44 | } | ||
258 | 45 | |||
259 | 46 | } // namespace UbuntuGestures | ||
260 | 47 | 0 | ||
261 | === removed file 'libs/UbuntuGestures/CandidateInactivityTimer.h' | |||
262 | --- libs/UbuntuGestures/CandidateInactivityTimer.h 2015-04-17 18:31:12 +0000 | |||
263 | +++ libs/UbuntuGestures/CandidateInactivityTimer.h 1970-01-01 00:00:00 +0000 | |||
264 | @@ -1,51 +0,0 @@ | |||
265 | 1 | /* | ||
266 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
267 | 3 | * | ||
268 | 4 | * This program is free software; you can redistribute it and/or modify | ||
269 | 5 | * it under the terms of the GNU General Public License as published by | ||
270 | 6 | * the Free Software Foundation; version 3. | ||
271 | 7 | * | ||
272 | 8 | * This program is distributed in the hope that it will be useful, | ||
273 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
274 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
275 | 11 | * GNU General Public License for more details. | ||
276 | 12 | * | ||
277 | 13 | * You should have received a copy of the GNU General Public License | ||
278 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
279 | 15 | */ | ||
280 | 16 | |||
281 | 17 | #ifndef UBUNTUGESTURES_CANDIDATE_INACTIVITY_TIMER_H | ||
282 | 18 | #define UBUNTUGESTURES_CANDIDATE_INACTIVITY_TIMER_H | ||
283 | 19 | |||
284 | 20 | #include <QObject> | ||
285 | 21 | |||
286 | 22 | class QQuickItem; | ||
287 | 23 | |||
288 | 24 | #include "Timer.h" | ||
289 | 25 | |||
290 | 26 | namespace UbuntuGestures { | ||
291 | 27 | |||
292 | 28 | class UBUNTUGESTURES_EXPORT CandidateInactivityTimer : public QObject { | ||
293 | 29 | Q_OBJECT | ||
294 | 30 | public: | ||
295 | 31 | CandidateInactivityTimer(int touchId, QQuickItem *candidate, | ||
296 | 32 | AbstractTimer *timer, | ||
297 | 33 | QObject *parent = nullptr); | ||
298 | 34 | |||
299 | 35 | virtual ~CandidateInactivityTimer(); | ||
300 | 36 | |||
301 | 37 | const int durationMs = 1000; | ||
302 | 38 | |||
303 | 39 | Q_SIGNALS: | ||
304 | 40 | void candidateDefaulted(int touchId, QQuickItem *candidate); | ||
305 | 41 | private Q_SLOTS: | ||
306 | 42 | void onTimeout(); | ||
307 | 43 | private: | ||
308 | 44 | AbstractTimer *m_timer; | ||
309 | 45 | int m_touchId; | ||
310 | 46 | QQuickItem *m_candidate; | ||
311 | 47 | }; | ||
312 | 48 | |||
313 | 49 | } // namespace UbuntuGestures | ||
314 | 50 | |||
315 | 51 | #endif // UBUNTUGESTURES_CANDIDATE_INACTIVITY_TIMER_H | ||
316 | 52 | 0 | ||
317 | === removed file 'libs/UbuntuGestures/DebugHelpers.cpp' | |||
318 | --- libs/UbuntuGestures/DebugHelpers.cpp 2015-09-14 09:11:08 +0000 | |||
319 | +++ libs/UbuntuGestures/DebugHelpers.cpp 1970-01-01 00:00:00 +0000 | |||
320 | @@ -1,95 +0,0 @@ | |||
321 | 1 | /* | ||
322 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
323 | 3 | * | ||
324 | 4 | * This program is free software; you can redistribute it and/or modify | ||
325 | 5 | * it under the terms of the GNU General Public License as published by | ||
326 | 6 | * the Free Software Foundation; version 3. | ||
327 | 7 | * | ||
328 | 8 | * This program is distributed in the hope that it will be useful, | ||
329 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
330 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
331 | 11 | * GNU General Public License for more details. | ||
332 | 12 | * | ||
333 | 13 | * You should have received a copy of the GNU General Public License | ||
334 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
335 | 15 | */ | ||
336 | 16 | |||
337 | 17 | #include "DebugHelpers.h" | ||
338 | 18 | #include <QTouchEvent> | ||
339 | 19 | #include <QMouseEvent> | ||
340 | 20 | |||
341 | 21 | QString touchPointStateToString(Qt::TouchPointState state) | ||
342 | 22 | { | ||
343 | 23 | switch (state) { | ||
344 | 24 | case Qt::TouchPointPressed: | ||
345 | 25 | return QStringLiteral("pressed"); | ||
346 | 26 | case Qt::TouchPointMoved: | ||
347 | 27 | return QStringLiteral("moved"); | ||
348 | 28 | case Qt::TouchPointStationary: | ||
349 | 29 | return QStringLiteral("stationary"); | ||
350 | 30 | case Qt::TouchPointReleased: | ||
351 | 31 | return QStringLiteral("released"); | ||
352 | 32 | default: | ||
353 | 33 | return QStringLiteral("INVALID_STATE"); | ||
354 | 34 | } | ||
355 | 35 | } | ||
356 | 36 | |||
357 | 37 | QString touchEventToString(const QTouchEvent *ev) | ||
358 | 38 | { | ||
359 | 39 | QString message; | ||
360 | 40 | |||
361 | 41 | switch (ev->type()) { | ||
362 | 42 | case QEvent::TouchBegin: | ||
363 | 43 | message.append("TouchBegin "); | ||
364 | 44 | break; | ||
365 | 45 | case QEvent::TouchUpdate: | ||
366 | 46 | message.append("TouchUpdate "); | ||
367 | 47 | break; | ||
368 | 48 | case QEvent::TouchEnd: | ||
369 | 49 | message.append("TouchEnd "); | ||
370 | 50 | break; | ||
371 | 51 | case QEvent::TouchCancel: | ||
372 | 52 | message.append("TouchCancel "); | ||
373 | 53 | break; | ||
374 | 54 | default: | ||
375 | 55 | message.append("INVALID_TOUCH_EVENT_TYPE "); | ||
376 | 56 | } | ||
377 | 57 | |||
378 | 58 | foreach(const QTouchEvent::TouchPoint& touchPoint, ev->touchPoints()) { | ||
379 | 59 | message.append( | ||
380 | 60 | QStringLiteral("(id:%1, state:%2, scenePos:(%3,%4)) ") | ||
381 | 61 | .arg(touchPoint.id()) | ||
382 | 62 | .arg(touchPointStateToString(touchPoint.state())) | ||
383 | 63 | .arg(touchPoint.scenePos().x()) | ||
384 | 64 | .arg(touchPoint.scenePos().y()) | ||
385 | 65 | ); | ||
386 | 66 | } | ||
387 | 67 | |||
388 | 68 | return message; | ||
389 | 69 | } | ||
390 | 70 | |||
391 | 71 | QString mouseEventToString(const QMouseEvent *ev) | ||
392 | 72 | { | ||
393 | 73 | QString message; | ||
394 | 74 | |||
395 | 75 | switch (ev->type()) { | ||
396 | 76 | case QEvent::MouseButtonPress: | ||
397 | 77 | message.append("MouseButtonPress "); | ||
398 | 78 | break; | ||
399 | 79 | case QEvent::MouseButtonRelease: | ||
400 | 80 | message.append("MouseButtonRelease "); | ||
401 | 81 | break; | ||
402 | 82 | case QEvent::MouseButtonDblClick: | ||
403 | 83 | message.append("MouseButtonDblClick "); | ||
404 | 84 | break; | ||
405 | 85 | case QEvent::MouseMove: | ||
406 | 86 | message.append("MouseMove "); | ||
407 | 87 | break; | ||
408 | 88 | default: | ||
409 | 89 | message.append("INVALID_MOUSE_EVENT_TYPE "); | ||
410 | 90 | } | ||
411 | 91 | |||
412 | 92 | message.append(QStringLiteral("pos(%1, %2)").arg(ev->x()).arg(ev->y())); | ||
413 | 93 | |||
414 | 94 | return message; | ||
415 | 95 | } | ||
416 | 96 | 0 | ||
417 | === removed file 'libs/UbuntuGestures/DebugHelpers.h' | |||
418 | --- libs/UbuntuGestures/DebugHelpers.h 2014-10-17 11:01:53 +0000 | |||
419 | +++ libs/UbuntuGestures/DebugHelpers.h 1970-01-01 00:00:00 +0000 | |||
420 | @@ -1,31 +0,0 @@ | |||
421 | 1 | /* | ||
422 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
423 | 3 | * | ||
424 | 4 | * This program is free software; you can redistribute it and/or modify | ||
425 | 5 | * it under the terms of the GNU General Public License as published by | ||
426 | 6 | * the Free Software Foundation; version 3. | ||
427 | 7 | * | ||
428 | 8 | * This program is distributed in the hope that it will be useful, | ||
429 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
430 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
431 | 11 | * GNU General Public License for more details. | ||
432 | 12 | * | ||
433 | 13 | * You should have received a copy of the GNU General Public License | ||
434 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
435 | 15 | */ | ||
436 | 16 | |||
437 | 17 | #ifndef UBUNTUGESTURES_DEBUG_HELPER_H | ||
438 | 18 | #define UBUNTUGESTURES_DEBUG_HELPER_H | ||
439 | 19 | |||
440 | 20 | #include <QString> | ||
441 | 21 | |||
442 | 22 | #include "UbuntuGesturesGlobal.h" | ||
443 | 23 | |||
444 | 24 | class QMouseEvent; | ||
445 | 25 | class QTouchEvent; | ||
446 | 26 | |||
447 | 27 | UBUNTUGESTURES_EXPORT QString touchPointStateToString(Qt::TouchPointState state); | ||
448 | 28 | UBUNTUGESTURES_EXPORT QString touchEventToString(const QTouchEvent *ev); | ||
449 | 29 | UBUNTUGESTURES_EXPORT QString mouseEventToString(const QMouseEvent *ev); | ||
450 | 30 | |||
451 | 31 | #endif // UBUNTUGESTURES_DEBUG_HELPER_H | ||
452 | 32 | 0 | ||
453 | === removed file 'libs/UbuntuGestures/Pool.h' | |||
454 | --- libs/UbuntuGestures/Pool.h 2015-11-20 15:01:39 +0000 | |||
455 | +++ libs/UbuntuGestures/Pool.h 1970-01-01 00:00:00 +0000 | |||
456 | @@ -1,124 +0,0 @@ | |||
457 | 1 | /* | ||
458 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
459 | 3 | * | ||
460 | 4 | * This program is free software; you can redistribute it and/or modify | ||
461 | 5 | * it under the terms of the GNU General Public License as published by | ||
462 | 6 | * the Free Software Foundation; version 3. | ||
463 | 7 | * | ||
464 | 8 | * This program is distributed in the hope that it will be useful, | ||
465 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
466 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
467 | 11 | * GNU General Public License for more details. | ||
468 | 12 | * | ||
469 | 13 | * You should have received a copy of the GNU General Public License | ||
470 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
471 | 15 | */ | ||
472 | 16 | |||
473 | 17 | #ifndef UBUNTUGESTURES_POOL_H | ||
474 | 18 | #define UBUNTUGESTURES_POOL_H | ||
475 | 19 | |||
476 | 20 | #include <QVector> | ||
477 | 21 | |||
478 | 22 | #include "UbuntuGesturesGlobal.h" | ||
479 | 23 | |||
480 | 24 | /* | ||
481 | 25 | An object pool. | ||
482 | 26 | Avoids unnecessary creations/initializations and deletions/destructions of items. Useful | ||
483 | 27 | in a scenario where items are created and destroyed very frequently but the total number | ||
484 | 28 | of items at any given time remains small. They're stored in a unordered fashion. | ||
485 | 29 | |||
486 | 30 | To be used in Pool, ItemType needs to have the following methods: | ||
487 | 31 | |||
488 | 32 | - ItemType(); | ||
489 | 33 | |||
490 | 34 | A constructor that takes no parameters. An object contructed with it must return false if | ||
491 | 35 | isValid() is called. | ||
492 | 36 | |||
493 | 37 | - bool isValid() const; | ||
494 | 38 | |||
495 | 39 | Returns wheter the object holds a valid , "filled" state or is empty. | ||
496 | 40 | Used by Pool to check if the slot occupied by this object is actually available. | ||
497 | 41 | |||
498 | 42 | - void reset(); | ||
499 | 43 | |||
500 | 44 | Resets the object to its initial, empty, state. After calling this method, isValid() must | ||
501 | 45 | return false. | ||
502 | 46 | */ | ||
503 | 47 | template <class ItemType> class Pool | ||
504 | 48 | { | ||
505 | 49 | public: | ||
506 | 50 | Pool() : m_lastUsedIndex(-1) { | ||
507 | 51 | } | ||
508 | 52 | |||
509 | 53 | class Iterator { | ||
510 | 54 | public: | ||
511 | 55 | Iterator() : index(-1), item(nullptr) {} | ||
512 | 56 | Iterator(int index, ItemType *item) | ||
513 | 57 | : index(index), item(item) {} | ||
514 | 58 | |||
515 | 59 | ItemType *operator->() const { return item; } | ||
516 | 60 | ItemType &operator*() const { return *item; } | ||
517 | 61 | ItemType &value() const { return *item; } | ||
518 | 62 | |||
519 | 63 | operator bool() const { return item != nullptr; } | ||
520 | 64 | |||
521 | 65 | int index; | ||
522 | 66 | ItemType *item; | ||
523 | 67 | }; | ||
524 | 68 | |||
525 | 69 | ItemType &getEmptySlot() { | ||
526 | 70 | Q_ASSERT(m_lastUsedIndex < m_slots.size()); | ||
527 | 71 | |||
528 | 72 | // Look for an in-between vacancy first | ||
529 | 73 | for (int i = 0; i < m_lastUsedIndex; ++i) { | ||
530 | 74 | ItemType &item = m_slots[i]; | ||
531 | 75 | if (!item.isValid()) { | ||
532 | 76 | return item; | ||
533 | 77 | } | ||
534 | 78 | } | ||
535 | 79 | |||
536 | 80 | ++m_lastUsedIndex; | ||
537 | 81 | if (m_lastUsedIndex >= m_slots.size()) { | ||
538 | 82 | m_slots.resize(m_lastUsedIndex + 1); | ||
539 | 83 | } | ||
540 | 84 | |||
541 | 85 | return m_slots[m_lastUsedIndex]; | ||
542 | 86 | } | ||
543 | 87 | |||
544 | 88 | void freeSlot(Iterator &iterator) { | ||
545 | 89 | m_slots[iterator.index].reset(); | ||
546 | 90 | if (iterator.index == m_lastUsedIndex) { | ||
547 | 91 | do { | ||
548 | 92 | --m_lastUsedIndex; | ||
549 | 93 | } while (m_lastUsedIndex >= 0 && !m_slots.at(m_lastUsedIndex).isValid()); | ||
550 | 94 | } | ||
551 | 95 | } | ||
552 | 96 | |||
553 | 97 | // Iterates through all valid items (i.e. the occupied slots) | ||
554 | 98 | // calling the given function, with the option of ending the loop early. | ||
555 | 99 | // | ||
556 | 100 | // bool Func(Iterator& item) | ||
557 | 101 | // | ||
558 | 102 | // Returning true means it wants to continue the "for" loop, false | ||
559 | 103 | // terminates the loop. | ||
560 | 104 | template<typename Func> void forEach(Func func) { | ||
561 | 105 | Iterator it; | ||
562 | 106 | for (it.index = 0; it.index <= m_lastUsedIndex; ++it.index) { | ||
563 | 107 | it.item = &m_slots[it.index]; | ||
564 | 108 | if (!it.item->isValid()) | ||
565 | 109 | continue; | ||
566 | 110 | |||
567 | 111 | if (!func(it)) | ||
568 | 112 | break; | ||
569 | 113 | } | ||
570 | 114 | } | ||
571 | 115 | |||
572 | 116 | bool isEmpty() const { return m_lastUsedIndex == -1; } | ||
573 | 117 | |||
574 | 118 | |||
575 | 119 | private: | ||
576 | 120 | QVector<ItemType> m_slots; | ||
577 | 121 | int m_lastUsedIndex; | ||
578 | 122 | }; | ||
579 | 123 | |||
580 | 124 | #endif // UBUNTUGESTURES_POOL_H | ||
581 | 125 | 0 | ||
582 | === removed file 'libs/UbuntuGestures/TimeSource.cpp' | |||
583 | --- libs/UbuntuGestures/TimeSource.cpp 2015-04-10 21:16:37 +0000 | |||
584 | +++ libs/UbuntuGestures/TimeSource.cpp 1970-01-01 00:00:00 +0000 | |||
585 | @@ -1,49 +0,0 @@ | |||
586 | 1 | /* | ||
587 | 2 | * Copyright (C) 2013 - Canonical Ltd. | ||
588 | 3 | * | ||
589 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
590 | 5 | * under the terms of the GNU Lesser General Public License, as | ||
591 | 6 | * published by the Free Software Foundation; either version 2.1 or 3.0 | ||
592 | 7 | * of the License. | ||
593 | 8 | * | ||
594 | 9 | * This program is distributed in the hope that it will be useful, but | ||
595 | 10 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
596 | 11 | * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR | ||
597 | 12 | * PURPOSE. See the applicable version of the GNU Lesser General Public | ||
598 | 13 | * License for more details. | ||
599 | 14 | * | ||
600 | 15 | * You should have received a copy of both the GNU Lesser General Public | ||
601 | 16 | * License along with this program. If not, see <http://www.gnu.org/licenses/> | ||
602 | 17 | * | ||
603 | 18 | * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> | ||
604 | 19 | */ | ||
605 | 20 | |||
606 | 21 | #include "TimeSource.h" | ||
607 | 22 | |||
608 | 23 | #include <QElapsedTimer> | ||
609 | 24 | |||
610 | 25 | namespace UbuntuGestures { | ||
611 | 26 | class RealTimeSourcePrivate { | ||
612 | 27 | public: | ||
613 | 28 | QElapsedTimer timer; | ||
614 | 29 | }; | ||
615 | 30 | } | ||
616 | 31 | |||
617 | 32 | using namespace UbuntuGestures; | ||
618 | 33 | |||
619 | 34 | RealTimeSource::RealTimeSource() | ||
620 | 35 | : UbuntuGestures::TimeSource() | ||
621 | 36 | , d(new RealTimeSourcePrivate) | ||
622 | 37 | { | ||
623 | 38 | d->timer.start(); | ||
624 | 39 | } | ||
625 | 40 | |||
626 | 41 | RealTimeSource::~RealTimeSource() | ||
627 | 42 | { | ||
628 | 43 | delete d; | ||
629 | 44 | } | ||
630 | 45 | |||
631 | 46 | qint64 RealTimeSource::msecsSinceReference() | ||
632 | 47 | { | ||
633 | 48 | return d->timer.elapsed(); | ||
634 | 49 | } | ||
635 | 50 | 0 | ||
636 | === removed file 'libs/UbuntuGestures/TimeSource.h' | |||
637 | --- libs/UbuntuGestures/TimeSource.h 2015-04-10 21:16:37 +0000 | |||
638 | +++ libs/UbuntuGestures/TimeSource.h 1970-01-01 00:00:00 +0000 | |||
639 | @@ -1,64 +0,0 @@ | |||
640 | 1 | /* | ||
641 | 2 | * Copyright (C) 2013,2015 Canonical Ltd. | ||
642 | 3 | * | ||
643 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
644 | 5 | * under the terms of the GNU Lesser General Public License, as | ||
645 | 6 | * published by the Free Software Foundation; either version 2.1 or 3.0 | ||
646 | 7 | * of the License. | ||
647 | 8 | * | ||
648 | 9 | * This program is distributed in the hope that it will be useful, but | ||
649 | 10 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
650 | 11 | * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR | ||
651 | 12 | * PURPOSE. See the applicable version of the GNU Lesser General Public | ||
652 | 13 | * License for more details. | ||
653 | 14 | * | ||
654 | 15 | * You should have received a copy of both the GNU Lesser General Public | ||
655 | 16 | * License along with this program. If not, see <http://www.gnu.org/licenses/> | ||
656 | 17 | * | ||
657 | 18 | * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com> | ||
658 | 19 | */ | ||
659 | 20 | |||
660 | 21 | #ifndef UBUNTUGESTURES_TIMESOURCE_H | ||
661 | 22 | #define UBUNTUGESTURES_TIMESOURCE_H | ||
662 | 23 | |||
663 | 24 | #include "UbuntuGesturesGlobal.h" | ||
664 | 25 | #include <QSharedPointer> | ||
665 | 26 | |||
666 | 27 | namespace UbuntuGestures { | ||
667 | 28 | /* | ||
668 | 29 | Interface for a time source. | ||
669 | 30 | */ | ||
670 | 31 | class UBUNTUGESTURES_EXPORT TimeSource { | ||
671 | 32 | public: | ||
672 | 33 | virtual ~TimeSource() {} | ||
673 | 34 | /* Returns the current time in milliseconds since some reference time in the past. */ | ||
674 | 35 | virtual qint64 msecsSinceReference() = 0; | ||
675 | 36 | }; | ||
676 | 37 | typedef QSharedPointer<TimeSource> SharedTimeSource; | ||
677 | 38 | |||
678 | 39 | /* | ||
679 | 40 | Implementation of a time source | ||
680 | 41 | */ | ||
681 | 42 | class RealTimeSourcePrivate; | ||
682 | 43 | class UBUNTUGESTURES_EXPORT RealTimeSource : public TimeSource { | ||
683 | 44 | public: | ||
684 | 45 | RealTimeSource(); | ||
685 | 46 | virtual ~RealTimeSource(); | ||
686 | 47 | qint64 msecsSinceReference() override; | ||
687 | 48 | private: | ||
688 | 49 | RealTimeSourcePrivate *d; | ||
689 | 50 | }; | ||
690 | 51 | |||
691 | 52 | /* | ||
692 | 53 | A fake time source, useful for tests | ||
693 | 54 | */ | ||
694 | 55 | class FakeTimeSource : public TimeSource { | ||
695 | 56 | public: | ||
696 | 57 | FakeTimeSource() { m_msecsSinceReference = 0; } | ||
697 | 58 | qint64 msecsSinceReference() override { return m_msecsSinceReference; } | ||
698 | 59 | qint64 m_msecsSinceReference; | ||
699 | 60 | }; | ||
700 | 61 | |||
701 | 62 | } // namespace UbuntuGestures | ||
702 | 63 | |||
703 | 64 | #endif // UBUNTUGESTURES_TIMESOURCE_H | ||
704 | 65 | 0 | ||
705 | === removed file 'libs/UbuntuGestures/Timer.cpp' | |||
706 | --- libs/UbuntuGestures/Timer.cpp 2015-04-24 13:19:24 +0000 | |||
707 | +++ libs/UbuntuGestures/Timer.cpp 1970-01-01 00:00:00 +0000 | |||
708 | @@ -1,152 +0,0 @@ | |||
709 | 1 | /* | ||
710 | 2 | * Copyright (C) 2014-2015 Canonical, Ltd. | ||
711 | 3 | * | ||
712 | 4 | * This program is free software; you can redistribute it and/or modify | ||
713 | 5 | * it under the terms of the GNU General Public License as published by | ||
714 | 6 | * the Free Software Foundation; version 3. | ||
715 | 7 | * | ||
716 | 8 | * This program is distributed in the hope that it will be useful, | ||
717 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
718 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
719 | 11 | * GNU General Public License for more details. | ||
720 | 12 | * | ||
721 | 13 | * You should have received a copy of the GNU General Public License | ||
722 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
723 | 15 | */ | ||
724 | 16 | |||
725 | 17 | #include "Timer.h" | ||
726 | 18 | |||
727 | 19 | namespace UbuntuGestures { | ||
728 | 20 | |||
729 | 21 | Timer::Timer(QObject *parent) : AbstractTimer(parent) | ||
730 | 22 | { | ||
731 | 23 | m_timer.setSingleShot(false); | ||
732 | 24 | connect(&m_timer, &QTimer::timeout, this, &AbstractTimer::timeout); | ||
733 | 25 | } | ||
734 | 26 | |||
735 | 27 | int Timer::interval() const | ||
736 | 28 | { | ||
737 | 29 | return m_timer.interval(); | ||
738 | 30 | } | ||
739 | 31 | |||
740 | 32 | void Timer::setInterval(int msecs) | ||
741 | 33 | { | ||
742 | 34 | m_timer.setInterval(msecs); | ||
743 | 35 | } | ||
744 | 36 | |||
745 | 37 | void Timer::start() | ||
746 | 38 | { | ||
747 | 39 | m_timer.start(); | ||
748 | 40 | AbstractTimer::start(); | ||
749 | 41 | } | ||
750 | 42 | |||
751 | 43 | void Timer::stop() | ||
752 | 44 | { | ||
753 | 45 | m_timer.stop(); | ||
754 | 46 | AbstractTimer::stop(); | ||
755 | 47 | } | ||
756 | 48 | |||
757 | 49 | bool Timer::isSingleShot() const | ||
758 | 50 | { | ||
759 | 51 | return m_timer.isSingleShot(); | ||
760 | 52 | } | ||
761 | 53 | |||
762 | 54 | void Timer::setSingleShot(bool value) | ||
763 | 55 | { | ||
764 | 56 | m_timer.setSingleShot(value); | ||
765 | 57 | } | ||
766 | 58 | |||
767 | 59 | /////////////////////////////////// FakeTimer ////////////////////////////////// | ||
768 | 60 | |||
769 | 61 | FakeTimer::FakeTimer(const SharedTimeSource &timeSource, QObject *parent) | ||
770 | 62 | : UbuntuGestures::AbstractTimer(parent) | ||
771 | 63 | , m_interval(0) | ||
772 | 64 | , m_singleShot(false) | ||
773 | 65 | , m_timeSource(timeSource) | ||
774 | 66 | { | ||
775 | 67 | } | ||
776 | 68 | |||
777 | 69 | void FakeTimer::update() | ||
778 | 70 | { | ||
779 | 71 | if (!isRunning()) { | ||
780 | 72 | return; | ||
781 | 73 | } | ||
782 | 74 | |||
783 | 75 | if (m_nextTimeoutTime <= m_timeSource->msecsSinceReference()) { | ||
784 | 76 | if (isSingleShot()) { | ||
785 | 77 | stop(); | ||
786 | 78 | } else { | ||
787 | 79 | m_nextTimeoutTime += interval(); | ||
788 | 80 | } | ||
789 | 81 | Q_EMIT timeout(); | ||
790 | 82 | } | ||
791 | 83 | } | ||
792 | 84 | |||
793 | 85 | void FakeTimer::start() | ||
794 | 86 | { | ||
795 | 87 | AbstractTimer::start(); | ||
796 | 88 | m_nextTimeoutTime = m_timeSource->msecsSinceReference() + (qint64)interval(); | ||
797 | 89 | } | ||
798 | 90 | |||
799 | 91 | int FakeTimer::interval() const | ||
800 | 92 | { | ||
801 | 93 | return m_interval; | ||
802 | 94 | } | ||
803 | 95 | |||
804 | 96 | void FakeTimer::setInterval(int msecs) | ||
805 | 97 | { | ||
806 | 98 | m_interval = msecs; | ||
807 | 99 | } | ||
808 | 100 | |||
809 | 101 | bool FakeTimer::isSingleShot() const | ||
810 | 102 | { | ||
811 | 103 | return m_singleShot; | ||
812 | 104 | } | ||
813 | 105 | |||
814 | 106 | void FakeTimer::setSingleShot(bool value) | ||
815 | 107 | { | ||
816 | 108 | m_singleShot = value; | ||
817 | 109 | } | ||
818 | 110 | |||
819 | 111 | /////////////////////////////////// FakeTimerFactory ////////////////////////////////// | ||
820 | 112 | |||
821 | 113 | FakeTimerFactory::FakeTimerFactory() | ||
822 | 114 | { | ||
823 | 115 | m_timeSource.reset(new FakeTimeSource); | ||
824 | 116 | } | ||
825 | 117 | |||
826 | 118 | void FakeTimerFactory::updateTime(qint64 targetTime) | ||
827 | 119 | { | ||
828 | 120 | qint64 minTimeoutTime = targetTime; | ||
829 | 121 | |||
830 | 122 | for (int i = 0; i < timers.count(); ++i) { | ||
831 | 123 | FakeTimer *timer = timers[i].data(); | ||
832 | 124 | if (timer && timer->isRunning() && timer->nextTimeoutTime() < minTimeoutTime) { | ||
833 | 125 | minTimeoutTime = timer->nextTimeoutTime(); | ||
834 | 126 | } | ||
835 | 127 | } | ||
836 | 128 | |||
837 | 129 | m_timeSource->m_msecsSinceReference = minTimeoutTime; | ||
838 | 130 | |||
839 | 131 | for (int i = 0; i < timers.count(); ++i) { | ||
840 | 132 | FakeTimer *timer = timers[i].data(); | ||
841 | 133 | if (timer) { | ||
842 | 134 | timer->update(); | ||
843 | 135 | } | ||
844 | 136 | } | ||
845 | 137 | |||
846 | 138 | if (m_timeSource->msecsSinceReference() < targetTime) { | ||
847 | 139 | updateTime(targetTime); | ||
848 | 140 | } | ||
849 | 141 | } | ||
850 | 142 | |||
851 | 143 | AbstractTimer *FakeTimerFactory::createTimer(QObject *parent) | ||
852 | 144 | { | ||
853 | 145 | FakeTimer *fakeTimer = new FakeTimer(m_timeSource, parent); | ||
854 | 146 | |||
855 | 147 | timers.append(fakeTimer); | ||
856 | 148 | |||
857 | 149 | return fakeTimer; | ||
858 | 150 | } | ||
859 | 151 | |||
860 | 152 | } // namespace UbuntuGestures | ||
861 | 153 | 0 | ||
862 | === removed file 'libs/UbuntuGestures/Timer.h' | |||
863 | --- libs/UbuntuGestures/Timer.h 2016-03-29 03:47:39 +0000 | |||
864 | +++ libs/UbuntuGestures/Timer.h 1970-01-01 00:00:00 +0000 | |||
865 | @@ -1,122 +0,0 @@ | |||
866 | 1 | /* | ||
867 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
868 | 3 | * | ||
869 | 4 | * This program is free software; you can redistribute it and/or modify | ||
870 | 5 | * it under the terms of the GNU General Public License as published by | ||
871 | 6 | * the Free Software Foundation; version 3. | ||
872 | 7 | * | ||
873 | 8 | * This program is distributed in the hope that it will be useful, | ||
874 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
875 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
876 | 11 | * GNU General Public License for more details. | ||
877 | 12 | * | ||
878 | 13 | * You should have received a copy of the GNU General Public License | ||
879 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
880 | 15 | */ | ||
881 | 16 | |||
882 | 17 | #ifndef UBUNTUGESTURES_TIMER_H | ||
883 | 18 | #define UBUNTUGESTURES_TIMER_H | ||
884 | 19 | |||
885 | 20 | #include "UbuntuGesturesGlobal.h" | ||
886 | 21 | #include "TimeSource.h" | ||
887 | 22 | |||
888 | 23 | #include <QObject> | ||
889 | 24 | #include <QPointer> | ||
890 | 25 | #include <QTimer> | ||
891 | 26 | |||
892 | 27 | namespace UbuntuGestures { | ||
893 | 28 | |||
894 | 29 | /* Defines an interface for a Timer. Useful for tests. */ | ||
895 | 30 | class UBUNTUGESTURES_EXPORT AbstractTimer : public QObject | ||
896 | 31 | { | ||
897 | 32 | Q_OBJECT | ||
898 | 33 | public: | ||
899 | 34 | AbstractTimer(QObject *parent) : QObject(parent), m_isRunning(false) {} | ||
900 | 35 | virtual int interval() const = 0; | ||
901 | 36 | virtual void setInterval(int msecs) = 0; | ||
902 | 37 | virtual void start() { m_isRunning = true; } | ||
903 | 38 | virtual void start(int msecs) | ||
904 | 39 | { | ||
905 | 40 | setInterval(msecs); | ||
906 | 41 | start(); | ||
907 | 42 | } | ||
908 | 43 | virtual void stop() { m_isRunning = false; } | ||
909 | 44 | bool isRunning() const { return m_isRunning; } | ||
910 | 45 | virtual bool isSingleShot() const = 0; | ||
911 | 46 | virtual void setSingleShot(bool value) = 0; | ||
912 | 47 | Q_SIGNALS: | ||
913 | 48 | void timeout(); | ||
914 | 49 | private: | ||
915 | 50 | bool m_isRunning; | ||
916 | 51 | }; | ||
917 | 52 | |||
918 | 53 | /* Essentially a QTimer wrapper */ | ||
919 | 54 | class UBUNTUGESTURES_EXPORT Timer : public AbstractTimer | ||
920 | 55 | { | ||
921 | 56 | Q_OBJECT | ||
922 | 57 | public: | ||
923 | 58 | Timer(QObject *parent = nullptr); | ||
924 | 59 | |||
925 | 60 | int interval() const override; | ||
926 | 61 | void setInterval(int msecs) override; | ||
927 | 62 | void start() override; | ||
928 | 63 | void stop() override; | ||
929 | 64 | bool isSingleShot() const override; | ||
930 | 65 | void setSingleShot(bool value) override; | ||
931 | 66 | private: | ||
932 | 67 | QTimer m_timer; | ||
933 | 68 | }; | ||
934 | 69 | |||
935 | 70 | /* For tests */ | ||
936 | 71 | class UBUNTUGESTURES_EXPORT FakeTimer : public AbstractTimer | ||
937 | 72 | { | ||
938 | 73 | Q_OBJECT | ||
939 | 74 | public: | ||
940 | 75 | FakeTimer(const SharedTimeSource &timeSource, QObject *parent = nullptr); | ||
941 | 76 | |||
942 | 77 | void update(); | ||
943 | 78 | qint64 nextTimeoutTime() const { return m_nextTimeoutTime; } | ||
944 | 79 | |||
945 | 80 | int interval() const override; | ||
946 | 81 | void setInterval(int msecs) override; | ||
947 | 82 | void start() override; | ||
948 | 83 | bool isSingleShot() const override; | ||
949 | 84 | void setSingleShot(bool value) override; | ||
950 | 85 | private: | ||
951 | 86 | int m_interval; | ||
952 | 87 | bool m_singleShot; | ||
953 | 88 | SharedTimeSource m_timeSource; | ||
954 | 89 | qint64 m_nextTimeoutTime; | ||
955 | 90 | }; | ||
956 | 91 | |||
957 | 92 | class UBUNTUGESTURES_EXPORT AbstractTimerFactory | ||
958 | 93 | { | ||
959 | 94 | public: | ||
960 | 95 | virtual ~AbstractTimerFactory() {} | ||
961 | 96 | virtual AbstractTimer *createTimer(QObject *parent = nullptr) = 0; | ||
962 | 97 | }; | ||
963 | 98 | |||
964 | 99 | class UBUNTUGESTURES_EXPORT TimerFactory : public AbstractTimerFactory | ||
965 | 100 | { | ||
966 | 101 | public: | ||
967 | 102 | AbstractTimer *createTimer(QObject *parent = nullptr) override { return new Timer(parent); } | ||
968 | 103 | }; | ||
969 | 104 | |||
970 | 105 | class UBUNTUGESTURES_EXPORT FakeTimerFactory : public AbstractTimerFactory | ||
971 | 106 | { | ||
972 | 107 | public: | ||
973 | 108 | FakeTimerFactory(); | ||
974 | 109 | virtual ~FakeTimerFactory() {} | ||
975 | 110 | |||
976 | 111 | void updateTime(qint64 msecsSinceReference); | ||
977 | 112 | QSharedPointer<TimeSource> timeSource() { return m_timeSource; } | ||
978 | 113 | |||
979 | 114 | AbstractTimer *createTimer(QObject *parent = nullptr) override; | ||
980 | 115 | QList<QPointer<FakeTimer>> timers; | ||
981 | 116 | private: | ||
982 | 117 | QSharedPointer<FakeTimeSource> m_timeSource; | ||
983 | 118 | }; | ||
984 | 119 | |||
985 | 120 | } // namespace UbuntuGestures | ||
986 | 121 | |||
987 | 122 | #endif // UBUNTUGESTURES_TIMER_H | ||
988 | 123 | 0 | ||
989 | === removed file 'libs/UbuntuGestures/TouchOwnershipEvent.cpp' | |||
990 | --- libs/UbuntuGestures/TouchOwnershipEvent.cpp 2014-10-01 13:20:32 +0000 | |||
991 | +++ libs/UbuntuGestures/TouchOwnershipEvent.cpp 1970-01-01 00:00:00 +0000 | |||
992 | @@ -1,35 +0,0 @@ | |||
993 | 1 | /* | ||
994 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
995 | 3 | * | ||
996 | 4 | * This program is free software; you can redistribute it and/or modify | ||
997 | 5 | * it under the terms of the GNU General Public License as published by | ||
998 | 6 | * the Free Software Foundation; version 3. | ||
999 | 7 | * | ||
1000 | 8 | * This program is distributed in the hope that it will be useful, | ||
1001 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1002 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1003 | 11 | * GNU General Public License for more details. | ||
1004 | 12 | * | ||
1005 | 13 | * You should have received a copy of the GNU General Public License | ||
1006 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1007 | 15 | */ | ||
1008 | 16 | |||
1009 | 17 | #include "TouchOwnershipEvent.h" | ||
1010 | 18 | |||
1011 | 19 | QEvent::Type TouchOwnershipEvent::m_touchOwnershipType = (QEvent::Type)-1; | ||
1012 | 20 | |||
1013 | 21 | TouchOwnershipEvent::TouchOwnershipEvent(int touchId, bool gained) | ||
1014 | 22 | : QEvent(touchOwnershipEventType()) | ||
1015 | 23 | , m_touchId(touchId) | ||
1016 | 24 | , m_gained(gained) | ||
1017 | 25 | { | ||
1018 | 26 | } | ||
1019 | 27 | |||
1020 | 28 | QEvent::Type TouchOwnershipEvent::touchOwnershipEventType() | ||
1021 | 29 | { | ||
1022 | 30 | if (m_touchOwnershipType == (QEvent::Type)-1) { | ||
1023 | 31 | m_touchOwnershipType = (QEvent::Type)registerEventType(); | ||
1024 | 32 | } | ||
1025 | 33 | |||
1026 | 34 | return m_touchOwnershipType; | ||
1027 | 35 | } | ||
1028 | 36 | 0 | ||
1029 | === removed file 'libs/UbuntuGestures/TouchOwnershipEvent.h' | |||
1030 | --- libs/UbuntuGestures/TouchOwnershipEvent.h 2014-10-01 13:20:32 +0000 | |||
1031 | +++ libs/UbuntuGestures/TouchOwnershipEvent.h 1970-01-01 00:00:00 +0000 | |||
1032 | @@ -1,50 +0,0 @@ | |||
1033 | 1 | /* | ||
1034 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
1035 | 3 | * | ||
1036 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1037 | 5 | * it under the terms of the GNU General Public License as published by | ||
1038 | 6 | * the Free Software Foundation; version 3. | ||
1039 | 7 | * | ||
1040 | 8 | * This program is distributed in the hope that it will be useful, | ||
1041 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1042 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1043 | 11 | * GNU General Public License for more details. | ||
1044 | 12 | * | ||
1045 | 13 | * You should have received a copy of the GNU General Public License | ||
1046 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1047 | 15 | */ | ||
1048 | 16 | |||
1049 | 17 | #ifndef UBUNTU_TOUCHOWNERSHIPEVENT_H | ||
1050 | 18 | #define UBUNTU_TOUCHOWNERSHIPEVENT_H | ||
1051 | 19 | |||
1052 | 20 | #include <QEvent> | ||
1053 | 21 | #include "UbuntuGesturesGlobal.h" | ||
1054 | 22 | |||
1055 | 23 | /* | ||
1056 | 24 | When an item get an ownership event for a touch it can grab/steal that touch | ||
1057 | 25 | with a clean conscience. | ||
1058 | 26 | */ | ||
1059 | 27 | class UBUNTUGESTURES_EXPORT TouchOwnershipEvent : public QEvent | ||
1060 | 28 | { | ||
1061 | 29 | public: | ||
1062 | 30 | TouchOwnershipEvent(int touchId, bool gained); | ||
1063 | 31 | |||
1064 | 32 | static Type touchOwnershipEventType(); | ||
1065 | 33 | |||
1066 | 34 | /* | ||
1067 | 35 | Whether ownership was gained (true) or lost (false) | ||
1068 | 36 | */ | ||
1069 | 37 | bool gained() const { return m_gained; } | ||
1070 | 38 | |||
1071 | 39 | /* | ||
1072 | 40 | Id of the touch whose ownership was granted. | ||
1073 | 41 | */ | ||
1074 | 42 | int touchId() const { return m_touchId; } | ||
1075 | 43 | |||
1076 | 44 | private: | ||
1077 | 45 | static Type m_touchOwnershipType; | ||
1078 | 46 | int m_touchId; | ||
1079 | 47 | bool m_gained; | ||
1080 | 48 | }; | ||
1081 | 49 | |||
1082 | 50 | #endif // UBUNTU_TOUCHOWNERSHIPEVENT_H | ||
1083 | 51 | 0 | ||
1084 | === removed file 'libs/UbuntuGestures/TouchRegistry.cpp' | |||
1085 | --- libs/UbuntuGestures/TouchRegistry.cpp 2016-03-29 03:47:39 +0000 | |||
1086 | +++ libs/UbuntuGestures/TouchRegistry.cpp 1970-01-01 00:00:00 +0000 | |||
1087 | @@ -1,553 +0,0 @@ | |||
1088 | 1 | /* | ||
1089 | 2 | * Copyright (C) 2014-2015 Canonical, Ltd. | ||
1090 | 3 | * | ||
1091 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1092 | 5 | * it under the terms of the GNU General Public License as published by | ||
1093 | 6 | * the Free Software Foundation; version 3. | ||
1094 | 7 | * | ||
1095 | 8 | * This program is distributed in the hope that it will be useful, | ||
1096 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1097 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1098 | 11 | * GNU General Public License for more details. | ||
1099 | 12 | * | ||
1100 | 13 | * You should have received a copy of the GNU General Public License | ||
1101 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1102 | 15 | */ | ||
1103 | 16 | |||
1104 | 17 | #include "TouchRegistry.h" | ||
1105 | 18 | |||
1106 | 19 | #include <QCoreApplication> | ||
1107 | 20 | #include <QDebug> | ||
1108 | 21 | |||
1109 | 22 | #pragma GCC diagnostic push | ||
1110 | 23 | #pragma GCC diagnostic ignored "-pedantic" | ||
1111 | 24 | #include <private/qquickitem_p.h> | ||
1112 | 25 | #pragma GCC diagnostic pop | ||
1113 | 26 | |||
1114 | 27 | #include "CandidateInactivityTimer.h" | ||
1115 | 28 | #include "Timer.h" | ||
1116 | 29 | #include "TouchOwnershipEvent.h" | ||
1117 | 30 | #include "UnownedTouchEvent.h" | ||
1118 | 31 | |||
1119 | 32 | #define TOUCHREGISTRY_DEBUG 0 | ||
1120 | 33 | |||
1121 | 34 | #if TOUCHREGISTRY_DEBUG | ||
1122 | 35 | #include "DebugHelpers.h" | ||
1123 | 36 | #define UG_DEBUG qDebug() << "[TouchRegistry]" | ||
1124 | 37 | #endif // TOUCHREGISTRY_DEBUG | ||
1125 | 38 | |||
1126 | 39 | using namespace UbuntuGestures; | ||
1127 | 40 | |||
1128 | 41 | TouchRegistry *TouchRegistry::m_instance = nullptr; | ||
1129 | 42 | |||
1130 | 43 | TouchRegistry::TouchRegistry(QObject *parent) | ||
1131 | 44 | : QObject(parent) | ||
1132 | 45 | , m_inDispatchLoop(false) | ||
1133 | 46 | , m_timerFactory(new TimerFactory) | ||
1134 | 47 | { | ||
1135 | 48 | } | ||
1136 | 49 | |||
1137 | 50 | TouchRegistry::~TouchRegistry() | ||
1138 | 51 | { | ||
1139 | 52 | Q_ASSERT(m_instance != nullptr); | ||
1140 | 53 | m_instance = nullptr; | ||
1141 | 54 | delete m_timerFactory; | ||
1142 | 55 | } | ||
1143 | 56 | |||
1144 | 57 | TouchRegistry *TouchRegistry::instance() | ||
1145 | 58 | { | ||
1146 | 59 | if (m_instance == nullptr) { | ||
1147 | 60 | m_instance = new TouchRegistry; | ||
1148 | 61 | } | ||
1149 | 62 | return m_instance; | ||
1150 | 63 | } | ||
1151 | 64 | |||
1152 | 65 | void TouchRegistry::setTimerFactory(AbstractTimerFactory *timerFactory) | ||
1153 | 66 | { | ||
1154 | 67 | delete m_timerFactory; | ||
1155 | 68 | m_timerFactory = timerFactory; | ||
1156 | 69 | } | ||
1157 | 70 | |||
1158 | 71 | void TouchRegistry::update(const QTouchEvent *event) | ||
1159 | 72 | { | ||
1160 | 73 | #if TOUCHREGISTRY_DEBUG | ||
1161 | 74 | UG_DEBUG << "got" << qPrintable(touchEventToString(event)); | ||
1162 | 75 | #endif | ||
1163 | 76 | |||
1164 | 77 | const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints(); | ||
1165 | 78 | for (int i = 0; i < touchPoints.count(); ++i) { | ||
1166 | 79 | const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i); | ||
1167 | 80 | if (touchPoint.state() == Qt::TouchPointPressed) { | ||
1168 | 81 | TouchInfo &touchInfo = m_touchInfoPool.getEmptySlot(); | ||
1169 | 82 | touchInfo.init(touchPoint.id()); | ||
1170 | 83 | } else if (touchPoint.state() == Qt::TouchPointReleased) { | ||
1171 | 84 | Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchPoint.id()); | ||
1172 | 85 | |||
1173 | 86 | touchInfo->physicallyEnded = true; | ||
1174 | 87 | } | ||
1175 | 88 | } | ||
1176 | 89 | |||
1177 | 90 | deliverTouchUpdatesToUndecidedCandidatesAndWatchers(event); | ||
1178 | 91 | |||
1179 | 92 | freeEndedTouchInfos(); | ||
1180 | 93 | } | ||
1181 | 94 | |||
1182 | 95 | void TouchRegistry::deliverTouchUpdatesToUndecidedCandidatesAndWatchers(const QTouchEvent *event) | ||
1183 | 96 | { | ||
1184 | 97 | // TODO: Look into how we could optimize this whole thing. | ||
1185 | 98 | // Although it's not really a problem as we should have at most two candidates | ||
1186 | 99 | // for each point and there should not be many active points at any given moment. | ||
1187 | 100 | // But having three nested for-loops does scare. | ||
1188 | 101 | |||
1189 | 102 | const QList<QTouchEvent::TouchPoint> &updatedTouchPoints = event->touchPoints(); | ||
1190 | 103 | |||
1191 | 104 | // Maps an item to the touches in this event he should be informed about. | ||
1192 | 105 | // E.g.: a QTouchEvent might have three touches but a given item might be interested in only | ||
1193 | 106 | // one of them. So he will get a UnownedTouchEvent from this QTouchEvent containing only that | ||
1194 | 107 | // touch point. | ||
1195 | 108 | QHash<QQuickItem*, QList<int>> touchIdsForItems; | ||
1196 | 109 | |||
1197 | 110 | // Build touchIdsForItems | ||
1198 | 111 | m_touchInfoPool.forEach([&](Pool<TouchInfo>::Iterator &touchInfo) { | ||
1199 | 112 | if (touchInfo->isOwned() && touchInfo->watchers.isEmpty()) | ||
1200 | 113 | return true; | ||
1201 | 114 | |||
1202 | 115 | for (int j = 0; j < updatedTouchPoints.count(); ++j) { | ||
1203 | 116 | if (updatedTouchPoints[j].id() == touchInfo->id) { | ||
1204 | 117 | if (!touchInfo->isOwned()) { | ||
1205 | 118 | for (int i = 0; i < touchInfo->candidates.count(); ++i) { | ||
1206 | 119 | CandidateInfo &candidate = touchInfo->candidates[i]; | ||
1207 | 120 | Q_ASSERT(!candidate.item.isNull()); | ||
1208 | 121 | if (candidate.state != CandidateInfo::InterimOwner) { | ||
1209 | 122 | touchIdsForItems[candidate.item.data()].append(touchInfo->id); | ||
1210 | 123 | } | ||
1211 | 124 | } | ||
1212 | 125 | } | ||
1213 | 126 | |||
1214 | 127 | const QList<QPointer<QQuickItem>> &watchers = touchInfo->watchers; | ||
1215 | 128 | for (int i = 0; i < watchers.count(); ++i) { | ||
1216 | 129 | if (!watchers[i].isNull()) { | ||
1217 | 130 | touchIdsForItems[watchers[i].data()].append(touchInfo->id); | ||
1218 | 131 | } | ||
1219 | 132 | } | ||
1220 | 133 | |||
1221 | 134 | return true; | ||
1222 | 135 | } | ||
1223 | 136 | } | ||
1224 | 137 | |||
1225 | 138 | return true; | ||
1226 | 139 | }); | ||
1227 | 140 | |||
1228 | 141 | // TODO: Consider what happens if an item calls any of TouchRegistry's public methods | ||
1229 | 142 | // from the event handler callback. | ||
1230 | 143 | m_inDispatchLoop = true; | ||
1231 | 144 | auto it = touchIdsForItems.constBegin(); | ||
1232 | 145 | while (it != touchIdsForItems.constEnd()) { | ||
1233 | 146 | QQuickItem *item = it.key(); | ||
1234 | 147 | const QList<int> &touchIds = it.value(); | ||
1235 | 148 | dispatchPointsToItem(event, touchIds, item); | ||
1236 | 149 | ++it; | ||
1237 | 150 | }; | ||
1238 | 151 | m_inDispatchLoop = false; | ||
1239 | 152 | } | ||
1240 | 153 | |||
1241 | 154 | void TouchRegistry::freeEndedTouchInfos() | ||
1242 | 155 | { | ||
1243 | 156 | m_touchInfoPool.forEach([&](Pool<TouchInfo>::Iterator &touchInfo) { | ||
1244 | 157 | if (touchInfo->ended()) { | ||
1245 | 158 | m_touchInfoPool.freeSlot(touchInfo); | ||
1246 | 159 | } | ||
1247 | 160 | return true; | ||
1248 | 161 | }); | ||
1249 | 162 | } | ||
1250 | 163 | |||
1251 | 164 | /* | ||
1252 | 165 | Extracts the touches with the given touchIds from event and send them in a | ||
1253 | 166 | UnownedTouchEvent to the given item | ||
1254 | 167 | */ | ||
1255 | 168 | void TouchRegistry::dispatchPointsToItem(const QTouchEvent *event, const QList<int> &touchIds, | ||
1256 | 169 | QQuickItem *item) | ||
1257 | 170 | { | ||
1258 | 171 | Qt::TouchPointStates touchPointStates = 0; | ||
1259 | 172 | QList<QTouchEvent::TouchPoint> touchPoints; | ||
1260 | 173 | |||
1261 | 174 | const QList<QTouchEvent::TouchPoint> &allTouchPoints = event->touchPoints(); | ||
1262 | 175 | |||
1263 | 176 | QTransform windowToCandidateTransform = QQuickItemPrivate::get(item)->windowToItemTransform(); | ||
1264 | 177 | QMatrix4x4 windowToCandidateMatrix(windowToCandidateTransform); | ||
1265 | 178 | |||
1266 | 179 | for (int i = 0; i < allTouchPoints.count(); ++i) { | ||
1267 | 180 | const QTouchEvent::TouchPoint &originalTouchPoint = allTouchPoints[i]; | ||
1268 | 181 | if (touchIds.contains(originalTouchPoint.id())) { | ||
1269 | 182 | QTouchEvent::TouchPoint touchPoint = originalTouchPoint; | ||
1270 | 183 | |||
1271 | 184 | translateTouchPointFromScreenToWindowCoords(touchPoint); | ||
1272 | 185 | |||
1273 | 186 | // Set the point's local coordinates to that of the item | ||
1274 | 187 | touchPoint.setRect(windowToCandidateTransform.mapRect(touchPoint.sceneRect())); | ||
1275 | 188 | touchPoint.setStartPos(windowToCandidateTransform.map(touchPoint.startScenePos())); | ||
1276 | 189 | touchPoint.setLastPos(windowToCandidateTransform.map(touchPoint.lastScenePos())); | ||
1277 | 190 | touchPoint.setVelocity(windowToCandidateMatrix.mapVector(touchPoint.velocity()).toVector2D()); | ||
1278 | 191 | |||
1279 | 192 | touchPoints.append(touchPoint); | ||
1280 | 193 | touchPointStates |= touchPoint.state(); | ||
1281 | 194 | } | ||
1282 | 195 | } | ||
1283 | 196 | |||
1284 | 197 | QTouchEvent *eventForItem = new QTouchEvent(event->type(), | ||
1285 | 198 | event->device(), | ||
1286 | 199 | event->modifiers(), | ||
1287 | 200 | touchPointStates, | ||
1288 | 201 | touchPoints); | ||
1289 | 202 | eventForItem->setWindow(event->window()); | ||
1290 | 203 | eventForItem->setTimestamp(event->timestamp()); | ||
1291 | 204 | eventForItem->setTarget(event->target()); | ||
1292 | 205 | |||
1293 | 206 | UnownedTouchEvent unownedTouchEvent(eventForItem); | ||
1294 | 207 | |||
1295 | 208 | #if TOUCHREGISTRY_DEBUG | ||
1296 | 209 | UG_DEBUG << "Sending unowned" << qPrintable(touchEventToString(eventForItem)) | ||
1297 | 210 | << "to" << item; | ||
1298 | 211 | #endif | ||
1299 | 212 | |||
1300 | 213 | QCoreApplication::sendEvent(item, &unownedTouchEvent); | ||
1301 | 214 | } | ||
1302 | 215 | |||
1303 | 216 | void TouchRegistry::translateTouchPointFromScreenToWindowCoords(QTouchEvent::TouchPoint &touchPoint) | ||
1304 | 217 | { | ||
1305 | 218 | touchPoint.setScreenRect(touchPoint.sceneRect()); | ||
1306 | 219 | touchPoint.setStartScreenPos(touchPoint.startScenePos()); | ||
1307 | 220 | touchPoint.setLastScreenPos(touchPoint.lastScenePos()); | ||
1308 | 221 | |||
1309 | 222 | touchPoint.setSceneRect(touchPoint.rect()); | ||
1310 | 223 | touchPoint.setStartScenePos(touchPoint.startPos()); | ||
1311 | 224 | touchPoint.setLastScenePos(touchPoint.lastPos()); | ||
1312 | 225 | } | ||
1313 | 226 | |||
1314 | 227 | bool TouchRegistry::eventFilter(QObject *watched, QEvent *event) | ||
1315 | 228 | { | ||
1316 | 229 | Q_UNUSED(watched); | ||
1317 | 230 | |||
1318 | 231 | switch (event->type()) { | ||
1319 | 232 | case QEvent::TouchBegin: | ||
1320 | 233 | case QEvent::TouchUpdate: | ||
1321 | 234 | case QEvent::TouchEnd: | ||
1322 | 235 | case QEvent::TouchCancel: | ||
1323 | 236 | update(static_cast<QTouchEvent*>(event)); | ||
1324 | 237 | break; | ||
1325 | 238 | default: | ||
1326 | 239 | // do nothing | ||
1327 | 240 | break; | ||
1328 | 241 | } | ||
1329 | 242 | |||
1330 | 243 | // Do not filter out the event. i.e., let it be handled further as | ||
1331 | 244 | // we're just monitoring events | ||
1332 | 245 | return false; | ||
1333 | 246 | } | ||
1334 | 247 | |||
1335 | 248 | void TouchRegistry::addCandidateOwnerForTouch(int id, QQuickItem *candidate) | ||
1336 | 249 | { | ||
1337 | 250 | #if TOUCHREGISTRY_DEBUG | ||
1338 | 251 | UG_DEBUG << "addCandidateOwnerForTouch id" << id << "candidate" << candidate; | ||
1339 | 252 | #endif | ||
1340 | 253 | |||
1341 | 254 | Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id); | ||
1342 | 255 | if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); } | ||
1343 | 256 | |||
1344 | 257 | if (touchInfo->isOwned()) { | ||
1345 | 258 | qWarning("TouchRegistry: trying to add candidate owner for a touch that's already owned"); | ||
1346 | 259 | return; | ||
1347 | 260 | } | ||
1348 | 261 | |||
1349 | 262 | // TODO: Check if candidate already exists | ||
1350 | 263 | |||
1351 | 264 | CandidateInfo candidateInfo; | ||
1352 | 265 | candidateInfo.state = CandidateInfo::Undecided; | ||
1353 | 266 | candidateInfo.item = candidate; | ||
1354 | 267 | candidateInfo.inactivityTimer = new CandidateInactivityTimer(id, candidate, | ||
1355 | 268 | m_timerFactory->createTimer(), | ||
1356 | 269 | this); | ||
1357 | 270 | connect(candidateInfo.inactivityTimer, &CandidateInactivityTimer::candidateDefaulted, | ||
1358 | 271 | this, &TouchRegistry::rejectCandidateOwnerForTouch); | ||
1359 | 272 | |||
1360 | 273 | touchInfo->candidates.append(candidateInfo); | ||
1361 | 274 | |||
1362 | 275 | connect(candidate, &QObject::destroyed, this, [=](){ pruneNullCandidatesForTouch(id); }); | ||
1363 | 276 | } | ||
1364 | 277 | |||
1365 | 278 | void TouchRegistry::addTouchWatcher(int touchId, QQuickItem *watcher) | ||
1366 | 279 | { | ||
1367 | 280 | #if TOUCHREGISTRY_DEBUG | ||
1368 | 281 | UG_DEBUG << "addTouchWatcher id" << touchId << "watcher" << watcher; | ||
1369 | 282 | #endif | ||
1370 | 283 | |||
1371 | 284 | Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchId); | ||
1372 | 285 | if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); } | ||
1373 | 286 | |||
1374 | 287 | // TODO: Check if watcher already exists | ||
1375 | 288 | |||
1376 | 289 | touchInfo->watchers.append(watcher); | ||
1377 | 290 | } | ||
1378 | 291 | |||
1379 | 292 | void TouchRegistry::removeCandidateOwnerForTouch(int id, QQuickItem *candidate) | ||
1380 | 293 | { | ||
1381 | 294 | #if TOUCHREGISTRY_DEBUG | ||
1382 | 295 | UG_DEBUG << "removeCandidateOwnerForTouch id" << id << "candidate" << candidate; | ||
1383 | 296 | #endif | ||
1384 | 297 | |||
1385 | 298 | Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id); | ||
1386 | 299 | if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); } | ||
1387 | 300 | |||
1388 | 301 | |||
1389 | 302 | // TODO: check if the candidate is in fact the owner of the touch | ||
1390 | 303 | |||
1391 | 304 | bool removed = false; | ||
1392 | 305 | for (int i = 0; i < touchInfo->candidates.count() && !removed; ++i) { | ||
1393 | 306 | if (touchInfo->candidates[i].item == candidate) { | ||
1394 | 307 | removeCandidateOwnerForTouchByIndex(touchInfo, i); | ||
1395 | 308 | removed = true; | ||
1396 | 309 | } | ||
1397 | 310 | } | ||
1398 | 311 | } | ||
1399 | 312 | |||
1400 | 313 | void TouchRegistry::pruneNullCandidatesForTouch(int touchId) | ||
1401 | 314 | { | ||
1402 | 315 | #if TOUCHREGISTRY_DEBUG | ||
1403 | 316 | UG_DEBUG << "pruneNullCandidatesForTouch touchId" << touchId; | ||
1404 | 317 | #endif | ||
1405 | 318 | |||
1406 | 319 | Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchId); | ||
1407 | 320 | if (!touchInfo) { | ||
1408 | 321 | // doesn't matter as touch is already gone. | ||
1409 | 322 | return; | ||
1410 | 323 | } | ||
1411 | 324 | |||
1412 | 325 | int i = 0; | ||
1413 | 326 | while (i < touchInfo->candidates.count()) { | ||
1414 | 327 | if (touchInfo->candidates[i].item.isNull()) { | ||
1415 | 328 | removeCandidateOwnerForTouchByIndex(touchInfo, i); | ||
1416 | 329 | } else { | ||
1417 | 330 | ++i; | ||
1418 | 331 | } | ||
1419 | 332 | } | ||
1420 | 333 | } | ||
1421 | 334 | |||
1422 | 335 | void TouchRegistry::removeCandidateOwnerForTouchByIndex(Pool<TouchRegistry::TouchInfo>::Iterator &touchInfo, | ||
1423 | 336 | int candidateIndex) | ||
1424 | 337 | { | ||
1425 | 338 | // TODO: check if the candidate is in fact the owner of the touch | ||
1426 | 339 | |||
1427 | 340 | Q_ASSERT(candidateIndex < touchInfo->candidates.count()); | ||
1428 | 341 | |||
1429 | 342 | if (candidateIndex == 0 && touchInfo->candidates[candidateIndex].state != CandidateInfo::Undecided) { | ||
1430 | 343 | qCritical("TouchRegistry: touch owner is being removed."); | ||
1431 | 344 | } | ||
1432 | 345 | removeCandidateHelper(touchInfo, candidateIndex); | ||
1433 | 346 | |||
1434 | 347 | if (candidateIndex == 0) { | ||
1435 | 348 | // the top candidate has been removed. if the new top candidate | ||
1436 | 349 | // wants the touch let him know he's now the owner. | ||
1437 | 350 | if (touchInfo->isOwned()) { | ||
1438 | 351 | touchInfo->notifyCandidatesOfOwnershipResolution(); | ||
1439 | 352 | } | ||
1440 | 353 | } | ||
1441 | 354 | |||
1442 | 355 | if (!m_inDispatchLoop && touchInfo->ended()) { | ||
1443 | 356 | m_touchInfoPool.freeSlot(touchInfo); | ||
1444 | 357 | } | ||
1445 | 358 | } | ||
1446 | 359 | |||
1447 | 360 | void TouchRegistry::requestTouchOwnership(int id, QQuickItem *candidate) | ||
1448 | 361 | { | ||
1449 | 362 | Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id); | ||
1450 | 363 | if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); } | ||
1451 | 364 | |||
1452 | 365 | Q_ASSERT(!touchInfo->isOwned()); | ||
1453 | 366 | |||
1454 | 367 | int candidateIndex = -1; | ||
1455 | 368 | for (int i = 0; i < touchInfo->candidates.count(); ++i) { | ||
1456 | 369 | CandidateInfo &candidateInfo = touchInfo->candidates[i]; | ||
1457 | 370 | if (candidateInfo.item == candidate) { | ||
1458 | 371 | candidateInfo.state = CandidateInfo::Requested; | ||
1459 | 372 | delete candidateInfo.inactivityTimer; | ||
1460 | 373 | candidateInfo.inactivityTimer = nullptr; | ||
1461 | 374 | candidateIndex = i; | ||
1462 | 375 | break; | ||
1463 | 376 | } | ||
1464 | 377 | } | ||
1465 | 378 | #if TOUCHREGISTRY_DEBUG | ||
1466 | 379 | UG_DEBUG << "requestTouchOwnership id " << id << "candidate" << candidate << "index: " << candidateIndex; | ||
1467 | 380 | #endif | ||
1468 | 381 | |||
1469 | 382 | // add it as a candidate if not present yet | ||
1470 | 383 | if (candidateIndex < 0) { | ||
1471 | 384 | CandidateInfo candidateInfo; | ||
1472 | 385 | candidateInfo.state = CandidateInfo::InterimOwner; | ||
1473 | 386 | candidateInfo.item = candidate; | ||
1474 | 387 | candidateInfo.inactivityTimer = nullptr; | ||
1475 | 388 | touchInfo->candidates.append(candidateInfo); | ||
1476 | 389 | // it's the last one | ||
1477 | 390 | candidateIndex = touchInfo->candidates.count() - 1; | ||
1478 | 391 | connect(candidate, &QObject::destroyed, this, [=](){ pruneNullCandidatesForTouch(id); }); | ||
1479 | 392 | } | ||
1480 | 393 | |||
1481 | 394 | // If it's the top candidate it means it's now the owner. Let | ||
1482 | 395 | // it know about it. | ||
1483 | 396 | if (candidateIndex == 0) { | ||
1484 | 397 | touchInfo->notifyCandidatesOfOwnershipResolution(); | ||
1485 | 398 | } | ||
1486 | 399 | } | ||
1487 | 400 | |||
1488 | 401 | Pool<TouchRegistry::TouchInfo>::Iterator TouchRegistry::findTouchInfo(int id) | ||
1489 | 402 | { | ||
1490 | 403 | Pool<TouchInfo>::Iterator touchInfo; | ||
1491 | 404 | |||
1492 | 405 | m_touchInfoPool.forEach([&](Pool<TouchInfo>::Iterator &someTouchInfo) -> bool { | ||
1493 | 406 | if (someTouchInfo->id == id) { | ||
1494 | 407 | touchInfo = someTouchInfo; | ||
1495 | 408 | return false; | ||
1496 | 409 | } else { | ||
1497 | 410 | return true; | ||
1498 | 411 | } | ||
1499 | 412 | }); | ||
1500 | 413 | |||
1501 | 414 | return touchInfo; | ||
1502 | 415 | } | ||
1503 | 416 | |||
1504 | 417 | |||
1505 | 418 | void TouchRegistry::rejectCandidateOwnerForTouch(int id, QQuickItem *candidate) | ||
1506 | 419 | { | ||
1507 | 420 | // NB: It's technically possible that candidate is a dangling pointer at this point. | ||
1508 | 421 | // Although that would most likely be due to a bug in our code. | ||
1509 | 422 | // In any case, only dereference it after it's confirmed that it indeed exists. | ||
1510 | 423 | |||
1511 | 424 | #if TOUCHREGISTRY_DEBUG | ||
1512 | 425 | UG_DEBUG << "rejectCandidateOwnerForTouch id" << id << "candidate" << (void*)candidate; | ||
1513 | 426 | #endif | ||
1514 | 427 | |||
1515 | 428 | Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id); | ||
1516 | 429 | if (!touchInfo) { | ||
1517 | 430 | #if TOUCHREGISTRY_DEBUG | ||
1518 | 431 | UG_DEBUG << "Failed to find TouchInfo for id" << id; | ||
1519 | 432 | #endif | ||
1520 | 433 | return; | ||
1521 | 434 | } | ||
1522 | 435 | |||
1523 | 436 | int rejectedCandidateIndex = -1; | ||
1524 | 437 | |||
1525 | 438 | // Check if the given candidate is valid and still undecided | ||
1526 | 439 | for (int i = 0; i < touchInfo->candidates.count() && rejectedCandidateIndex == -1; ++i) { | ||
1527 | 440 | CandidateInfo &candidateInfo = touchInfo->candidates[i]; | ||
1528 | 441 | if (candidateInfo.item == candidate) { | ||
1529 | 442 | Q_ASSERT(i > 0 || candidateInfo.state == CandidateInfo::Undecided); | ||
1530 | 443 | if (i == 0 && candidateInfo.state != CandidateInfo::Undecided) { | ||
1531 | 444 | qCritical() << "TouchRegistry: Can't reject item (" << (void*)candidate | ||
1532 | 445 | << ") as it already owns touch" << id; | ||
1533 | 446 | return; | ||
1534 | 447 | } else { | ||
1535 | 448 | // we found the guy and it's all fine. | ||
1536 | 449 | rejectedCandidateIndex = i; | ||
1537 | 450 | } | ||
1538 | 451 | } | ||
1539 | 452 | } | ||
1540 | 453 | |||
1541 | 454 | // If we reached this point it's because the given candidate exists and is indeed undecided. | ||
1542 | 455 | |||
1543 | 456 | Q_ASSERT(rejectedCandidateIndex >= 0 && rejectedCandidateIndex < touchInfo->candidates.size()); | ||
1544 | 457 | |||
1545 | 458 | { | ||
1546 | 459 | TouchOwnershipEvent lostOwnershipEvent(id, false /*gained*/); | ||
1547 | 460 | QCoreApplication::sendEvent(candidate, &lostOwnershipEvent); | ||
1548 | 461 | } | ||
1549 | 462 | |||
1550 | 463 | removeCandidateHelper(touchInfo, rejectedCandidateIndex); | ||
1551 | 464 | |||
1552 | 465 | if (rejectedCandidateIndex == 0) { | ||
1553 | 466 | // the top candidate has been removed. if the new top candidate | ||
1554 | 467 | // wants the touch let him know he's now the owner. | ||
1555 | 468 | if (touchInfo->isOwned()) { | ||
1556 | 469 | touchInfo->notifyCandidatesOfOwnershipResolution(); | ||
1557 | 470 | } | ||
1558 | 471 | } | ||
1559 | 472 | } | ||
1560 | 473 | |||
1561 | 474 | void TouchRegistry::removeCandidateHelper(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex) | ||
1562 | 475 | { | ||
1563 | 476 | { | ||
1564 | 477 | CandidateInfo &candidateInfo = touchInfo->candidates[candidateIndex]; | ||
1565 | 478 | |||
1566 | 479 | delete candidateInfo.inactivityTimer; | ||
1567 | 480 | candidateInfo.inactivityTimer = nullptr; | ||
1568 | 481 | |||
1569 | 482 | if (candidateInfo.item) { | ||
1570 | 483 | disconnect(candidateInfo.item.data(), nullptr, this, nullptr); | ||
1571 | 484 | } | ||
1572 | 485 | } | ||
1573 | 486 | touchInfo->candidates.removeAt(candidateIndex); | ||
1574 | 487 | } | ||
1575 | 488 | |||
1576 | 489 | ////////////////////////////////////// TouchRegistry::TouchInfo //////////////////////////////////// | ||
1577 | 490 | |||
1578 | 491 | TouchRegistry::TouchInfo::TouchInfo(int id) | ||
1579 | 492 | { | ||
1580 | 493 | init(id); | ||
1581 | 494 | } | ||
1582 | 495 | |||
1583 | 496 | void TouchRegistry::TouchInfo::reset() | ||
1584 | 497 | { | ||
1585 | 498 | id = -1; | ||
1586 | 499 | |||
1587 | 500 | for (int i = 0; i < candidates.count(); ++i) { | ||
1588 | 501 | CandidateInfo &candidate = candidates[i]; | ||
1589 | 502 | delete candidate.inactivityTimer; | ||
1590 | 503 | candidate.inactivityTimer.clear(); // shoundn't be needed but anyway... | ||
1591 | 504 | } | ||
1592 | 505 | } | ||
1593 | 506 | |||
1594 | 507 | void TouchRegistry::TouchInfo::init(int id) | ||
1595 | 508 | { | ||
1596 | 509 | this->id = id; | ||
1597 | 510 | physicallyEnded = false; | ||
1598 | 511 | candidates.clear(); | ||
1599 | 512 | watchers.clear(); | ||
1600 | 513 | } | ||
1601 | 514 | |||
1602 | 515 | bool TouchRegistry::TouchInfo::isOwned() const | ||
1603 | 516 | { | ||
1604 | 517 | return !candidates.isEmpty() && candidates.first().state != CandidateInfo::Undecided; | ||
1605 | 518 | } | ||
1606 | 519 | |||
1607 | 520 | bool TouchRegistry::TouchInfo::ended() const | ||
1608 | 521 | { | ||
1609 | 522 | Q_ASSERT(isValid()); | ||
1610 | 523 | return physicallyEnded && (isOwned() || candidates.isEmpty()); | ||
1611 | 524 | } | ||
1612 | 525 | |||
1613 | 526 | void TouchRegistry::TouchInfo::notifyCandidatesOfOwnershipResolution() | ||
1614 | 527 | { | ||
1615 | 528 | Q_ASSERT(isOwned()); | ||
1616 | 529 | |||
1617 | 530 | #if TOUCHREGISTRY_DEBUG | ||
1618 | 531 | UG_DEBUG << "sending TouchOwnershipEvent(id =" << id | ||
1619 | 532 | << " gained) to candidate" << candidates[0].item; | ||
1620 | 533 | #endif | ||
1621 | 534 | |||
1622 | 535 | // need to take a copy of the item list in case | ||
1623 | 536 | // we call back in to remove candidate during the lost ownership event. | ||
1624 | 537 | QList<QPointer<QQuickItem>> items; | ||
1625 | 538 | Q_FOREACH(const CandidateInfo& info, candidates) { | ||
1626 | 539 | items << info.item; | ||
1627 | 540 | } | ||
1628 | 541 | |||
1629 | 542 | TouchOwnershipEvent gainedOwnershipEvent(id, true /*gained*/); | ||
1630 | 543 | QCoreApplication::sendEvent(items[0], &gainedOwnershipEvent); | ||
1631 | 544 | |||
1632 | 545 | TouchOwnershipEvent lostOwnershipEvent(id, false /*gained*/); | ||
1633 | 546 | for (int i = 1; i < items.count(); ++i) { | ||
1634 | 547 | #if TOUCHREGISTRY_DEBUG | ||
1635 | 548 | UG_DEBUG << "sending TouchOwnershipEvent(id =" << id << " lost) to candidate" | ||
1636 | 549 | << items[i]; | ||
1637 | 550 | #endif | ||
1638 | 551 | QCoreApplication::sendEvent(items[i], &lostOwnershipEvent); | ||
1639 | 552 | } | ||
1640 | 553 | } | ||
1641 | 554 | 0 | ||
1642 | === removed file 'libs/UbuntuGestures/TouchRegistry.h' | |||
1643 | --- libs/UbuntuGestures/TouchRegistry.h 2015-07-20 16:30:40 +0000 | |||
1644 | +++ libs/UbuntuGestures/TouchRegistry.h 1970-01-01 00:00:00 +0000 | |||
1645 | @@ -1,201 +0,0 @@ | |||
1646 | 1 | /* | ||
1647 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
1648 | 3 | * | ||
1649 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1650 | 5 | * it under the terms of the GNU General Public License as published by | ||
1651 | 6 | * the Free Software Foundation; version 3. | ||
1652 | 7 | * | ||
1653 | 8 | * This program is distributed in the hope that it will be useful, | ||
1654 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1655 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1656 | 11 | * GNU General Public License for more details. | ||
1657 | 12 | * | ||
1658 | 13 | * You should have received a copy of the GNU General Public License | ||
1659 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1660 | 15 | */ | ||
1661 | 16 | |||
1662 | 17 | #ifndef UNITY_TOUCHREGISTRY_H | ||
1663 | 18 | #define UNITY_TOUCHREGISTRY_H | ||
1664 | 19 | |||
1665 | 20 | #include <QQuickItem> | ||
1666 | 21 | #include <QObject> | ||
1667 | 22 | #include <QPointer> | ||
1668 | 23 | #include <QTouchEvent> | ||
1669 | 24 | #include <QVector> | ||
1670 | 25 | |||
1671 | 26 | #include "UbuntuGesturesGlobal.h" | ||
1672 | 27 | #include "CandidateInactivityTimer.h" | ||
1673 | 28 | #include "Timer.h" | ||
1674 | 29 | #include "Pool.h" | ||
1675 | 30 | |||
1676 | 31 | namespace UbuntuGestures { | ||
1677 | 32 | class AbstractTimerFactory; | ||
1678 | 33 | } | ||
1679 | 34 | |||
1680 | 35 | /* | ||
1681 | 36 | Where the ownership of touches is registered. | ||
1682 | 37 | |||
1683 | 38 | Singleton used for adding a touch point ownership model analogous to the one | ||
1684 | 39 | described in the XInput 2.2 protocol[1] on top of the existing input dispatch logic in QQuickWindow. | ||
1685 | 40 | |||
1686 | 41 | It provides a much more flexible and powerful way of dealing with pointer ownership than the existing | ||
1687 | 42 | mechanisms in Qt. Namely QQuickItem::grabTouchPoints, QuickItem::keepTouchGrab, | ||
1688 | 43 | QQuickItem::setFiltersChildMouseEvents, QQuickItem::ungrabTouchPoints and QQuickItem::touchUngrabEvent. | ||
1689 | 44 | |||
1690 | 45 | Usage: | ||
1691 | 46 | |||
1692 | 47 | 1- An item receives a a new touch point. If he's not sure whether he wants it yet, he calls: | ||
1693 | 48 | TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, this); | ||
1694 | 49 | touchEvent->ignore(); | ||
1695 | 50 | Ignoring the event is crucial so that it can be seen by other interested parties, which will | ||
1696 | 51 | behave similarly. | ||
1697 | 52 | |||
1698 | 53 | 2- That item will then start receiving UnownedTouchEvents for that touch from step 1. Once he's | ||
1699 | 54 | made a decision he calls either: | ||
1700 | 55 | TouchRegistry::instance()->requestTouchOwnership(touchId, this); | ||
1701 | 56 | If he wants the touch point or: | ||
1702 | 57 | TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, this); | ||
1703 | 58 | if he does not want it. | ||
1704 | 59 | |||
1705 | 60 | Candidates are put in a priority queue. The first one to call addCandidateOwnerForTouch() will | ||
1706 | 61 | take precedence over the others for receiving ownership over the touch point (from now on called | ||
1707 | 62 | simply top-candidate). | ||
1708 | 63 | |||
1709 | 64 | If the top-candidate calls requestTouchOwnership() he will immediately receive a | ||
1710 | 65 | TouchOwnershipEvent(gained=true) for that touch point. He can then safely call | ||
1711 | 66 | QQuickItem::grabTouchPoints to actually get the owned touch points. The other candidates | ||
1712 | 67 | will receive TouchOwnershipEvent(gained=false) and will no longer receive UnownedTouchEvents | ||
1713 | 68 | for that touch point. They will have to undo whatever action they were performing with that | ||
1714 | 69 | touch point. | ||
1715 | 70 | |||
1716 | 71 | But if the top-candidate calls removeCandidateOwnerForTouch() instead, he's popped from the | ||
1717 | 72 | candidacy queue and ownership is given to the new top-most candidate if he has already | ||
1718 | 73 | made his decision, that is. | ||
1719 | 74 | |||
1720 | 75 | The TouchRegistry cannot enforce the results of this pointer ownership negotiation (i.e., | ||
1721 | 76 | who gets to grab the touch points) as that would clash with QQuickWindow's input event | ||
1722 | 77 | dispatching logic. The candidates have to respect the decision and grab the touch points | ||
1723 | 78 | themselves. | ||
1724 | 79 | |||
1725 | 80 | If an item wants ownership over touches as soon as he receives the TouchBegin for them, his step 1 | ||
1726 | 81 | would be instead: | ||
1727 | 82 | TouchRegistry::instance()->requestTouchOwnership(touchId, this); | ||
1728 | 83 | touchEvent->accept(); | ||
1729 | 84 | He won't get any UnownedTouchEvent for that touch as he is already the interim owner (ie, QQuickWindow | ||
1730 | 85 | will keep sending touch updates to him already). Eventually he will be notified once ownership has | ||
1731 | 86 | been granted to him (from TouchRegistry perspective), from which point onwards he could safely assume | ||
1732 | 87 | other TouchRegistry users wouldn't snatch this touch away from him. | ||
1733 | 88 | |||
1734 | 89 | Items oblivious to TouchRegistry will lose their touch points without warning, just like in plain Qt. | ||
1735 | 90 | |||
1736 | 91 | [1] - http://www.x.org/releases/X11R7.7/doc/inputproto/XI2proto.txt (see multitouch-ownership) | ||
1737 | 92 | */ | ||
1738 | 93 | class UBUNTUGESTURES_EXPORT TouchRegistry : public QObject | ||
1739 | 94 | { | ||
1740 | 95 | Q_OBJECT | ||
1741 | 96 | public: | ||
1742 | 97 | virtual ~TouchRegistry(); | ||
1743 | 98 | |||
1744 | 99 | // Returns a pointer to the application's TouchRegistry instance. | ||
1745 | 100 | static TouchRegistry *instance(); | ||
1746 | 101 | |||
1747 | 102 | void update(const QTouchEvent *event); | ||
1748 | 103 | |||
1749 | 104 | // Calls update() if the given event is a QTouchEvent | ||
1750 | 105 | bool eventFilter(QObject *watched, QEvent *event) override; | ||
1751 | 106 | |||
1752 | 107 | // An item that might later request ownership over the given touch point. | ||
1753 | 108 | // He will be kept informed about that touch point through UnownedTouchEvents | ||
1754 | 109 | // All candidates must eventually decide whether they want to own the touch point | ||
1755 | 110 | // or not. That decision is informed through requestTouchOwnership() or | ||
1756 | 111 | // removeCandidateOwnerForTouch() | ||
1757 | 112 | void addCandidateOwnerForTouch(int id, QQuickItem *candidate); | ||
1758 | 113 | |||
1759 | 114 | // The same as rejecting ownership of a touch | ||
1760 | 115 | void removeCandidateOwnerForTouch(int id, QQuickItem *candidate); | ||
1761 | 116 | |||
1762 | 117 | // The candidate object wants to be the owner of the touch with the given id. | ||
1763 | 118 | // If he's currently the oldest/top-most candidate, he will get an ownership | ||
1764 | 119 | // event immediately. If not, he will get ownership if (or once) he becomes the | ||
1765 | 120 | // top-most candidate. | ||
1766 | 121 | void requestTouchOwnership(int id, QQuickItem *candidate); | ||
1767 | 122 | |||
1768 | 123 | // An item that has no interest (effective or potential) in owning a touch point | ||
1769 | 124 | // but would nonetheless like to be kept up-to-date on its state. | ||
1770 | 125 | void addTouchWatcher(int touchId, QQuickItem *watcherItem); | ||
1771 | 126 | |||
1772 | 127 | // Useful for tests, where you should use fake timers | ||
1773 | 128 | void setTimerFactory(UbuntuGestures::AbstractTimerFactory *timerFactory); | ||
1774 | 129 | |||
1775 | 130 | private Q_SLOTS: | ||
1776 | 131 | void rejectCandidateOwnerForTouch(int id, QQuickItem *candidate); | ||
1777 | 132 | |||
1778 | 133 | private: | ||
1779 | 134 | // Only instance() can cronstruct one | ||
1780 | 135 | TouchRegistry(QObject *parent = nullptr); | ||
1781 | 136 | |||
1782 | 137 | class CandidateInfo { | ||
1783 | 138 | public: | ||
1784 | 139 | enum { | ||
1785 | 140 | // A candidate owner that doesn't yet know for sure whether he wants the touch point | ||
1786 | 141 | // (gesture recognition is stilll going on) | ||
1787 | 142 | Undecided = 0, | ||
1788 | 143 | // A candidate owner that wants the touch but hasn't been granted it yet, | ||
1789 | 144 | // most likely because there's an undecided candidate with higher priority | ||
1790 | 145 | Requested = 1, | ||
1791 | 146 | // An item that is the interim owner of the touch, receiving QTouchEvents of it | ||
1792 | 147 | // from QQuickWindow. Ie, it's the actual touch owner from Qt's point of view. | ||
1793 | 148 | // It wants to keep its touch ownership but hasn't been granted it by TouchRegistry | ||
1794 | 149 | // yet because of undecided candidates higher up. | ||
1795 | 150 | InterimOwner = 2 | ||
1796 | 151 | } state; | ||
1797 | 152 | QPointer<QQuickItem> item; | ||
1798 | 153 | QPointer<UbuntuGestures::CandidateInactivityTimer> inactivityTimer; | ||
1799 | 154 | }; | ||
1800 | 155 | |||
1801 | 156 | class TouchInfo { | ||
1802 | 157 | public: | ||
1803 | 158 | TouchInfo() : id(-1) {} | ||
1804 | 159 | TouchInfo(int id); | ||
1805 | 160 | bool isValid() const { return id >= 0; } | ||
1806 | 161 | void reset(); | ||
1807 | 162 | void init(int id); | ||
1808 | 163 | int id; | ||
1809 | 164 | bool physicallyEnded; | ||
1810 | 165 | bool isOwned() const; | ||
1811 | 166 | bool ended() const; | ||
1812 | 167 | void notifyCandidatesOfOwnershipResolution(); | ||
1813 | 168 | |||
1814 | 169 | // TODO optimize storage (s/QList/Pool) | ||
1815 | 170 | QList<CandidateInfo> candidates; | ||
1816 | 171 | QList<QPointer<QQuickItem>> watchers; | ||
1817 | 172 | }; | ||
1818 | 173 | |||
1819 | 174 | void pruneNullCandidatesForTouch(int touchId); | ||
1820 | 175 | void removeCandidateOwnerForTouchByIndex(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex); | ||
1821 | 176 | void removeCandidateHelper(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex); | ||
1822 | 177 | |||
1823 | 178 | Pool<TouchInfo>::Iterator findTouchInfo(int id); | ||
1824 | 179 | |||
1825 | 180 | void deliverTouchUpdatesToUndecidedCandidatesAndWatchers(const QTouchEvent *event); | ||
1826 | 181 | |||
1827 | 182 | static void translateTouchPointFromScreenToWindowCoords(QTouchEvent::TouchPoint &touchPoint); | ||
1828 | 183 | |||
1829 | 184 | static void dispatchPointsToItem(const QTouchEvent *event, const QList<int> &touchIds, | ||
1830 | 185 | QQuickItem *item); | ||
1831 | 186 | void freeEndedTouchInfos(); | ||
1832 | 187 | |||
1833 | 188 | Pool<TouchInfo> m_touchInfoPool; | ||
1834 | 189 | |||
1835 | 190 | // the singleton instance | ||
1836 | 191 | static TouchRegistry *m_instance; | ||
1837 | 192 | |||
1838 | 193 | bool m_inDispatchLoop; | ||
1839 | 194 | |||
1840 | 195 | UbuntuGestures::AbstractTimerFactory *m_timerFactory; | ||
1841 | 196 | |||
1842 | 197 | friend class tst_TouchRegistry; | ||
1843 | 198 | friend class tst_DirectionalDragArea; | ||
1844 | 199 | }; | ||
1845 | 200 | |||
1846 | 201 | #endif // UNITY_TOUCHREGISTRY_H | ||
1847 | 202 | 0 | ||
1848 | === removed file 'libs/UbuntuGestures/UbuntuGesturesGlobal.h' | |||
1849 | --- libs/UbuntuGestures/UbuntuGesturesGlobal.h 2014-10-01 13:20:32 +0000 | |||
1850 | +++ libs/UbuntuGestures/UbuntuGesturesGlobal.h 1970-01-01 00:00:00 +0000 | |||
1851 | @@ -1,23 +0,0 @@ | |||
1852 | 1 | /* | ||
1853 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
1854 | 3 | * | ||
1855 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1856 | 5 | * it under the terms of the GNU General Public License as published by | ||
1857 | 6 | * the Free Software Foundation; version 3. | ||
1858 | 7 | * | ||
1859 | 8 | * This program is distributed in the hope that it will be useful, | ||
1860 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1861 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1862 | 11 | * GNU General Public License for more details. | ||
1863 | 12 | * | ||
1864 | 13 | * You should have received a copy of the GNU General Public License | ||
1865 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1866 | 15 | */ | ||
1867 | 16 | |||
1868 | 17 | #include <QtCore/QtGlobal> | ||
1869 | 18 | |||
1870 | 19 | #if defined(UBUNTUGESTURES_LIBRARY) | ||
1871 | 20 | # define UBUNTUGESTURES_EXPORT Q_DECL_EXPORT | ||
1872 | 21 | #else | ||
1873 | 22 | # define UBUNTUGESTURES_EXPORT Q_DECL_IMPORT | ||
1874 | 23 | #endif | ||
1875 | 24 | 0 | ||
1876 | === removed file 'libs/UbuntuGestures/UnownedTouchEvent.cpp' | |||
1877 | --- libs/UbuntuGestures/UnownedTouchEvent.cpp 2014-10-01 13:20:32 +0000 | |||
1878 | +++ libs/UbuntuGestures/UnownedTouchEvent.cpp 1970-01-01 00:00:00 +0000 | |||
1879 | @@ -1,39 +0,0 @@ | |||
1880 | 1 | /* | ||
1881 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
1882 | 3 | * | ||
1883 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1884 | 5 | * it under the terms of the GNU General Public License as published by | ||
1885 | 6 | * the Free Software Foundation; version 3. | ||
1886 | 7 | * | ||
1887 | 8 | * This program is distributed in the hope that it will be useful, | ||
1888 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1889 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1890 | 11 | * GNU General Public License for more details. | ||
1891 | 12 | * | ||
1892 | 13 | * You should have received a copy of the GNU General Public License | ||
1893 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1894 | 15 | */ | ||
1895 | 16 | |||
1896 | 17 | #include "UnownedTouchEvent.h" | ||
1897 | 18 | |||
1898 | 19 | QEvent::Type UnownedTouchEvent::m_unownedTouchEventType = (QEvent::Type)-1; | ||
1899 | 20 | |||
1900 | 21 | UnownedTouchEvent::UnownedTouchEvent(QTouchEvent *touchEvent) | ||
1901 | 22 | : QEvent(unownedTouchEventType()) | ||
1902 | 23 | , m_touchEvent(touchEvent) | ||
1903 | 24 | { | ||
1904 | 25 | } | ||
1905 | 26 | |||
1906 | 27 | QEvent::Type UnownedTouchEvent::unownedTouchEventType() | ||
1907 | 28 | { | ||
1908 | 29 | if (m_unownedTouchEventType == (QEvent::Type)-1) { | ||
1909 | 30 | m_unownedTouchEventType = (QEvent::Type)registerEventType(); | ||
1910 | 31 | } | ||
1911 | 32 | |||
1912 | 33 | return m_unownedTouchEventType; | ||
1913 | 34 | } | ||
1914 | 35 | |||
1915 | 36 | QTouchEvent *UnownedTouchEvent::touchEvent() | ||
1916 | 37 | { | ||
1917 | 38 | return m_touchEvent.data(); | ||
1918 | 39 | } | ||
1919 | 40 | 0 | ||
1920 | === removed file 'libs/UbuntuGestures/UnownedTouchEvent.h' | |||
1921 | --- libs/UbuntuGestures/UnownedTouchEvent.h 2014-10-01 13:20:32 +0000 | |||
1922 | +++ libs/UbuntuGestures/UnownedTouchEvent.h 1970-01-01 00:00:00 +0000 | |||
1923 | @@ -1,45 +0,0 @@ | |||
1924 | 1 | /* | ||
1925 | 2 | * Copyright (C) 2014 Canonical, Ltd. | ||
1926 | 3 | * | ||
1927 | 4 | * This program is free software; you can redistribute it and/or modify | ||
1928 | 5 | * it under the terms of the GNU General Public License as published by | ||
1929 | 6 | * the Free Software Foundation; version 3. | ||
1930 | 7 | * | ||
1931 | 8 | * This program is distributed in the hope that it will be useful, | ||
1932 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1933 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1934 | 11 | * GNU General Public License for more details. | ||
1935 | 12 | * | ||
1936 | 13 | * You should have received a copy of the GNU General Public License | ||
1937 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1938 | 15 | */ | ||
1939 | 16 | |||
1940 | 17 | #ifndef UBUNTU_UNOWNEDTOUCHEVENT_H | ||
1941 | 18 | #define UBUNTU_UNOWNEDTOUCHEVENT_H | ||
1942 | 19 | |||
1943 | 20 | #include <QTouchEvent> | ||
1944 | 21 | #include <QScopedPointer> | ||
1945 | 22 | #include "UbuntuGesturesGlobal.h" | ||
1946 | 23 | |||
1947 | 24 | /* | ||
1948 | 25 | A touch event with touch points that do not belong the item receiving it. | ||
1949 | 26 | |||
1950 | 27 | See TouchRegistry::addCandidateOwnerForTouch and TouchRegistry::addTouchWatcher | ||
1951 | 28 | */ | ||
1952 | 29 | class UBUNTUGESTURES_EXPORT UnownedTouchEvent : public QEvent | ||
1953 | 30 | { | ||
1954 | 31 | public: | ||
1955 | 32 | UnownedTouchEvent(QTouchEvent *touchEvent); | ||
1956 | 33 | static Type unownedTouchEventType(); | ||
1957 | 34 | |||
1958 | 35 | // TODO: It might be cleaner to store the information directly in UnownedTouchEvent | ||
1959 | 36 | // instead of carrying around a synthesized QTouchEvent. But the latter option | ||
1960 | 37 | // is very convenient. | ||
1961 | 38 | QTouchEvent *touchEvent(); | ||
1962 | 39 | |||
1963 | 40 | private: | ||
1964 | 41 | static Type m_unownedTouchEventType; | ||
1965 | 42 | QScopedPointer<QTouchEvent> m_touchEvent; | ||
1966 | 43 | }; | ||
1967 | 44 | |||
1968 | 45 | #endif // UBUNTU_UNOWNEDTOUCHEVENT_H | ||
1969 | 46 | 0 | ||
1970 | === modified file 'plugins/Cursor/CMakeLists.txt' | |||
1971 | --- plugins/Cursor/CMakeLists.txt 2015-09-29 13:45:05 +0000 | |||
1972 | +++ plugins/Cursor/CMakeLists.txt 2016-06-01 16:58:47 +0000 | |||
1973 | @@ -8,8 +8,9 @@ | |||
1974 | 8 | 8 | ||
1975 | 9 | set(QMLPLUGIN_SRC | 9 | set(QMLPLUGIN_SRC |
1976 | 10 | plugin.cpp | 10 | plugin.cpp |
1977 | 11 | CursorImageInfo.cpp | ||
1978 | 12 | CursorImageProvider.cpp | ||
1979 | 11 | MousePointer.cpp | 13 | MousePointer.cpp |
1980 | 12 | CursorImageProvider.cpp | ||
1981 | 13 | # We need to run moc on this header | 14 | # We need to run moc on this header |
1982 | 14 | ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirMousePointerInterface.h | 15 | ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirMousePointerInterface.h |
1983 | 15 | ) | 16 | ) |
1984 | 16 | 17 | ||
1985 | === modified file 'plugins/Cursor/Cursor.qml' | |||
1986 | --- plugins/Cursor/Cursor.qml 2015-12-03 15:00:04 +0000 | |||
1987 | +++ plugins/Cursor/Cursor.qml 2016-06-01 16:58:47 +0000 | |||
1988 | @@ -1,5 +1,5 @@ | |||
1989 | 1 | /* | 1 | /* |
1991 | 2 | * Copyright (C) 2015 Canonical, Ltd. | 2 | * Copyright (C) 2015-2016 Canonical, Ltd. |
1992 | 3 | * | 3 | * |
1993 | 4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
1994 | 5 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
1995 | @@ -15,14 +15,30 @@ | |||
1996 | 15 | */ | 15 | */ |
1997 | 16 | 16 | ||
1998 | 17 | import QtQuick 2.4 | 17 | import QtQuick 2.4 |
2000 | 18 | import Cursor 1.0 // For MousePointer | 18 | import Cursor 1.1 |
2001 | 19 | 19 | ||
2002 | 20 | MousePointer { | 20 | MousePointer { |
2003 | 21 | id: mousePointer | 21 | id: mousePointer |
2004 | 22 | 22 | ||
2008 | 23 | Image { | 23 | CursorImageInfo { |
2009 | 24 | x: -mousePointer.hotspotX | 24 | id: imageInfo |
2010 | 25 | y: -mousePointer.hotspotY | 25 | themeName: mousePointer.themeName |
2011 | 26 | cursorName: mousePointer.cursorName | ||
2012 | 27 | } | ||
2013 | 28 | |||
2014 | 29 | AnimatedSprite { | ||
2015 | 30 | x: -imageInfo.hotspot.x | ||
2016 | 31 | y: -imageInfo.hotspot.y | ||
2017 | 26 | source: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName | 32 | source: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName |
2018 | 33 | |||
2019 | 34 | interpolate: false | ||
2020 | 35 | |||
2021 | 36 | width: imageInfo.frameWidth | ||
2022 | 37 | height: imageInfo.frameHeight | ||
2023 | 38 | |||
2024 | 39 | frameCount: imageInfo.frameCount | ||
2025 | 40 | frameDuration: imageInfo.frameDuration | ||
2026 | 41 | frameWidth: imageInfo.frameWidth | ||
2027 | 42 | frameHeight: imageInfo.frameHeight | ||
2028 | 27 | } | 43 | } |
2029 | 28 | } | 44 | } |
2030 | 29 | 45 | ||
2031 | === removed file 'plugins/Cursor/Cursor.qmltypes' | |||
2032 | --- plugins/Cursor/Cursor.qmltypes 2016-03-11 20:18:12 +0000 | |||
2033 | +++ plugins/Cursor/Cursor.qmltypes 1970-01-01 00:00:00 +0000 | |||
2034 | @@ -1,78 +0,0 @@ | |||
2035 | 1 | import QtQuick.tooling 1.1 | ||
2036 | 2 | |||
2037 | 3 | // This file describes the plugin-supplied types contained in the library. | ||
2038 | 4 | // It is used for QML tooling purposes only. | ||
2039 | 5 | // | ||
2040 | 6 | // This file was auto-generated by: | ||
2041 | 7 | // 'qmlplugindump -notrelocatable Cursor 1.0 plugins' | ||
2042 | 8 | |||
2043 | 9 | Module { | ||
2044 | 10 | Component { | ||
2045 | 11 | name: "MirMousePointerInterface" | ||
2046 | 12 | defaultProperty: "data" | ||
2047 | 13 | prototype: "QQuickItem" | ||
2048 | 14 | Property { name: "cursorName"; type: "string"; isReadonly: true } | ||
2049 | 15 | Property { name: "themeName"; type: "string"; isReadonly: true } | ||
2050 | 16 | Property { name: "hotspotX"; type: "double"; isReadonly: true } | ||
2051 | 17 | Property { name: "hotspotY"; type: "double"; isReadonly: true } | ||
2052 | 18 | Signal { | ||
2053 | 19 | name: "cursorNameChanged" | ||
2054 | 20 | Parameter { name: "name"; type: "string" } | ||
2055 | 21 | } | ||
2056 | 22 | Signal { | ||
2057 | 23 | name: "themeNameChanged" | ||
2058 | 24 | Parameter { name: "name"; type: "string" } | ||
2059 | 25 | } | ||
2060 | 26 | Signal { | ||
2061 | 27 | name: "hotspotXChanged" | ||
2062 | 28 | Parameter { name: "value"; type: "double" } | ||
2063 | 29 | } | ||
2064 | 30 | Signal { | ||
2065 | 31 | name: "hotspotYChanged" | ||
2066 | 32 | Parameter { name: "value"; type: "double" } | ||
2067 | 33 | } | ||
2068 | 34 | Method { | ||
2069 | 35 | name: "handleMouseEvent" | ||
2070 | 36 | Parameter { name: "timestamp"; type: "ulong" } | ||
2071 | 37 | Parameter { name: "movement"; type: "QPointF" } | ||
2072 | 38 | Parameter { name: "buttons"; type: "Qt::MouseButtons" } | ||
2073 | 39 | Parameter { name: "modifiers"; type: "Qt::KeyboardModifiers" } | ||
2074 | 40 | } | ||
2075 | 41 | Method { | ||
2076 | 42 | name: "handleWheelEvent" | ||
2077 | 43 | Parameter { name: "timestamp"; type: "ulong" } | ||
2078 | 44 | Parameter { name: "angleDelta"; type: "QPoint" } | ||
2079 | 45 | Parameter { name: "modifiers"; type: "Qt::KeyboardModifiers" } | ||
2080 | 46 | } | ||
2081 | 47 | } | ||
2082 | 48 | Component { | ||
2083 | 49 | name: "MousePointer" | ||
2084 | 50 | defaultProperty: "data" | ||
2085 | 51 | prototype: "MirMousePointerInterface" | ||
2086 | 52 | exports: ["Cursor/MousePointer 1.0"] | ||
2087 | 53 | exportMetaObjectRevisions: [0] | ||
2088 | 54 | Signal { | ||
2089 | 55 | name: "pushedLeftBoundary" | ||
2090 | 56 | Parameter { name: "amount"; type: "double" } | ||
2091 | 57 | Parameter { name: "buttons"; type: "Qt::MouseButtons" } | ||
2092 | 58 | } | ||
2093 | 59 | Signal { | ||
2094 | 60 | name: "pushedRightBoundary" | ||
2095 | 61 | Parameter { name: "amount"; type: "double" } | ||
2096 | 62 | Parameter { name: "buttons"; type: "Qt::MouseButtons" } | ||
2097 | 63 | } | ||
2098 | 64 | Method { | ||
2099 | 65 | name: "handleMouseEvent" | ||
2100 | 66 | Parameter { name: "timestamp"; type: "ulong" } | ||
2101 | 67 | Parameter { name: "movement"; type: "QPointF" } | ||
2102 | 68 | Parameter { name: "buttons"; type: "Qt::MouseButtons" } | ||
2103 | 69 | Parameter { name: "modifiers"; type: "Qt::KeyboardModifiers" } | ||
2104 | 70 | } | ||
2105 | 71 | Method { | ||
2106 | 72 | name: "handleWheelEvent" | ||
2107 | 73 | Parameter { name: "timestamp"; type: "ulong" } | ||
2108 | 74 | Parameter { name: "angleDelta"; type: "QPoint" } | ||
2109 | 75 | Parameter { name: "modifiers"; type: "Qt::KeyboardModifiers" } | ||
2110 | 76 | } | ||
2111 | 77 | } | ||
2112 | 78 | } | ||
2113 | 79 | 0 | ||
2114 | === added file 'plugins/Cursor/CursorImageInfo.cpp' | |||
2115 | --- plugins/Cursor/CursorImageInfo.cpp 1970-01-01 00:00:00 +0000 | |||
2116 | +++ plugins/Cursor/CursorImageInfo.cpp 2016-06-01 16:58:47 +0000 | |||
2117 | @@ -0,0 +1,106 @@ | |||
2118 | 1 | /* | ||
2119 | 2 | * Copyright (C) 2016 Canonical, Ltd. | ||
2120 | 3 | * | ||
2121 | 4 | * This program is free software; you can redistribute it and/or modify | ||
2122 | 5 | * it under the terms of the GNU General Public License as published by | ||
2123 | 6 | * the Free Software Foundation; version 3. | ||
2124 | 7 | * | ||
2125 | 8 | * This program is distributed in the hope that it will be useful, | ||
2126 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2127 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2128 | 11 | * GNU General Public License for more details. | ||
2129 | 12 | * | ||
2130 | 13 | * You should have received a copy of the GNU General Public License | ||
2131 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2132 | 15 | */ | ||
2133 | 16 | |||
2134 | 17 | #include "CursorImageInfo.h" | ||
2135 | 18 | |||
2136 | 19 | CursorImageInfo::CursorImageInfo(QObject *parent) | ||
2137 | 20 | : QObject(parent) | ||
2138 | 21 | { | ||
2139 | 22 | m_updateTimer.setInterval(0); | ||
2140 | 23 | m_updateTimer.setSingleShot(true); | ||
2141 | 24 | connect(&m_updateTimer, &QTimer::timeout, this, &CursorImageInfo::update); | ||
2142 | 25 | } | ||
2143 | 26 | |||
2144 | 27 | void CursorImageInfo::setCursorName(const QString &cursorName) | ||
2145 | 28 | { | ||
2146 | 29 | if (cursorName != m_cursorName) { | ||
2147 | 30 | m_cursorName = cursorName; | ||
2148 | 31 | Q_EMIT cursorNameChanged(); | ||
2149 | 32 | scheduleUpdate(); | ||
2150 | 33 | } | ||
2151 | 34 | } | ||
2152 | 35 | |||
2153 | 36 | void CursorImageInfo::setThemeName(const QString &themeName) | ||
2154 | 37 | { | ||
2155 | 38 | if (m_themeName != themeName) { | ||
2156 | 39 | m_themeName = themeName; | ||
2157 | 40 | Q_EMIT themeNameChanged(); | ||
2158 | 41 | scheduleUpdate(); | ||
2159 | 42 | } | ||
2160 | 43 | } | ||
2161 | 44 | |||
2162 | 45 | void CursorImageInfo::scheduleUpdate() | ||
2163 | 46 | { | ||
2164 | 47 | if (!m_updateTimer.isActive()) { | ||
2165 | 48 | m_updateTimer.start(); | ||
2166 | 49 | } | ||
2167 | 50 | } | ||
2168 | 51 | |||
2169 | 52 | void CursorImageInfo::update() | ||
2170 | 53 | { | ||
2171 | 54 | m_cursorImage = CursorImageProvider::instance()->fetchCursor(m_themeName, m_cursorName); | ||
2172 | 55 | |||
2173 | 56 | Q_EMIT hotspotChanged(); | ||
2174 | 57 | Q_EMIT frameWidthChanged(); | ||
2175 | 58 | Q_EMIT frameHeightChanged(); | ||
2176 | 59 | Q_EMIT frameCountChanged(); | ||
2177 | 60 | Q_EMIT frameDurationChanged(); | ||
2178 | 61 | } | ||
2179 | 62 | |||
2180 | 63 | QPoint CursorImageInfo::hotspot() const | ||
2181 | 64 | { | ||
2182 | 65 | if (m_cursorImage) { | ||
2183 | 66 | return m_cursorImage->hotspot; | ||
2184 | 67 | } else { | ||
2185 | 68 | return QPoint(); | ||
2186 | 69 | } | ||
2187 | 70 | } | ||
2188 | 71 | |||
2189 | 72 | qreal CursorImageInfo::frameWidth() const | ||
2190 | 73 | { | ||
2191 | 74 | if (m_cursorImage) { | ||
2192 | 75 | return m_cursorImage->frameWidth; | ||
2193 | 76 | } else { | ||
2194 | 77 | return 0; | ||
2195 | 78 | } | ||
2196 | 79 | } | ||
2197 | 80 | |||
2198 | 81 | qreal CursorImageInfo::frameHeight() const | ||
2199 | 82 | { | ||
2200 | 83 | if (m_cursorImage) { | ||
2201 | 84 | return m_cursorImage->frameHeight; | ||
2202 | 85 | } else { | ||
2203 | 86 | return 0; | ||
2204 | 87 | } | ||
2205 | 88 | } | ||
2206 | 89 | |||
2207 | 90 | int CursorImageInfo::frameCount() const | ||
2208 | 91 | { | ||
2209 | 92 | if (m_cursorImage) { | ||
2210 | 93 | return m_cursorImage->frameCount; | ||
2211 | 94 | } else { | ||
2212 | 95 | return 0; | ||
2213 | 96 | } | ||
2214 | 97 | } | ||
2215 | 98 | |||
2216 | 99 | int CursorImageInfo::frameDuration() const | ||
2217 | 100 | { | ||
2218 | 101 | if (m_cursorImage) { | ||
2219 | 102 | return m_cursorImage->frameDuration; | ||
2220 | 103 | } else { | ||
2221 | 104 | return 0; | ||
2222 | 105 | } | ||
2223 | 106 | } | ||
2224 | 0 | 107 | ||
2225 | === added file 'plugins/Cursor/CursorImageInfo.h' | |||
2226 | --- plugins/Cursor/CursorImageInfo.h 1970-01-01 00:00:00 +0000 | |||
2227 | +++ plugins/Cursor/CursorImageInfo.h 2016-06-01 16:58:47 +0000 | |||
2228 | @@ -0,0 +1,76 @@ | |||
2229 | 1 | /* | ||
2230 | 2 | * Copyright (C) 2016 Canonical, Ltd. | ||
2231 | 3 | * | ||
2232 | 4 | * This program is free software; you can redistribute it and/or modify | ||
2233 | 5 | * it under the terms of the GNU General Public License as published by | ||
2234 | 6 | * the Free Software Foundation; version 3. | ||
2235 | 7 | * | ||
2236 | 8 | * This program is distributed in the hope that it will be useful, | ||
2237 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2238 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2239 | 11 | * GNU General Public License for more details. | ||
2240 | 12 | * | ||
2241 | 13 | * You should have received a copy of the GNU General Public License | ||
2242 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2243 | 15 | */ | ||
2244 | 16 | |||
2245 | 17 | #ifndef CURSOR_IMAGE_INFO_H | ||
2246 | 18 | #define CURSOR_IMAGE_INFO_H | ||
2247 | 19 | |||
2248 | 20 | #include "CursorImageProvider.h" | ||
2249 | 21 | |||
2250 | 22 | #include <QObject> | ||
2251 | 23 | #include <QString> | ||
2252 | 24 | #include <QTimer> | ||
2253 | 25 | |||
2254 | 26 | class CursorImageInfo : public QObject | ||
2255 | 27 | { | ||
2256 | 28 | Q_OBJECT | ||
2257 | 29 | |||
2258 | 30 | Q_PROPERTY(QString themeName READ themeName WRITE setThemeName NOTIFY themeNameChanged) | ||
2259 | 31 | Q_PROPERTY(QString cursorName READ cursorName WRITE setCursorName NOTIFY cursorNameChanged) | ||
2260 | 32 | |||
2261 | 33 | Q_PROPERTY(QPoint hotspot READ hotspot NOTIFY hotspotChanged) | ||
2262 | 34 | Q_PROPERTY(qreal frameWidth READ frameWidth NOTIFY frameWidthChanged) | ||
2263 | 35 | Q_PROPERTY(qreal frameHeight READ frameHeight NOTIFY frameHeightChanged) | ||
2264 | 36 | Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged) | ||
2265 | 37 | Q_PROPERTY(int frameDuration READ frameDuration NOTIFY frameDurationChanged) | ||
2266 | 38 | |||
2267 | 39 | public: | ||
2268 | 40 | CursorImageInfo(QObject *parent = nullptr); | ||
2269 | 41 | |||
2270 | 42 | QString themeName() const { return m_themeName; } | ||
2271 | 43 | void setThemeName(const QString &); | ||
2272 | 44 | |||
2273 | 45 | QString cursorName() const { return m_cursorName; } | ||
2274 | 46 | void setCursorName(const QString &); | ||
2275 | 47 | |||
2276 | 48 | QPoint hotspot() const; | ||
2277 | 49 | qreal frameWidth() const; | ||
2278 | 50 | qreal frameHeight() const; | ||
2279 | 51 | int frameCount() const; | ||
2280 | 52 | int frameDuration() const; | ||
2281 | 53 | |||
2282 | 54 | Q_SIGNALS: | ||
2283 | 55 | void themeNameChanged(); | ||
2284 | 56 | void cursorNameChanged(); | ||
2285 | 57 | void hotspotChanged(); | ||
2286 | 58 | void frameWidthChanged(); | ||
2287 | 59 | void frameHeightChanged(); | ||
2288 | 60 | void frameCountChanged(); | ||
2289 | 61 | void frameDurationChanged(); | ||
2290 | 62 | |||
2291 | 63 | private Q_SLOTS: | ||
2292 | 64 | void update(); | ||
2293 | 65 | |||
2294 | 66 | private: | ||
2295 | 67 | void scheduleUpdate(); | ||
2296 | 68 | QTimer m_updateTimer; | ||
2297 | 69 | |||
2298 | 70 | QString m_themeName; | ||
2299 | 71 | QString m_cursorName; | ||
2300 | 72 | |||
2301 | 73 | CursorImage *m_cursorImage{nullptr}; | ||
2302 | 74 | }; | ||
2303 | 75 | |||
2304 | 76 | #endif // CURSOR_IMAGE_INFO_H | ||
2305 | 0 | 77 | ||
2306 | === modified file 'plugins/Cursor/CursorImageProvider.cpp' | |||
2307 | --- plugins/Cursor/CursorImageProvider.cpp 2015-11-30 17:38:20 +0000 | |||
2308 | +++ plugins/Cursor/CursorImageProvider.cpp 2016-06-01 16:58:47 +0000 | |||
2309 | @@ -1,5 +1,5 @@ | |||
2310 | 1 | /* | 1 | /* |
2312 | 2 | * Copyright (C) 2015 Canonical, Ltd. | 2 | * Copyright (C) 2015-2016 Canonical, Ltd. |
2313 | 3 | * | 3 | * |
2314 | 4 | * This program is free software: you can redistribute it and/or modify it under | 4 | * This program is free software: you can redistribute it and/or modify it under |
2315 | 5 | * the terms of the GNU Lesser General Public License version 3, as published by | 5 | * the terms of the GNU Lesser General Public License version 3, as published by |
2316 | @@ -46,6 +46,9 @@ | |||
2317 | 46 | qimage.fill(Qt::transparent); | 46 | qimage.fill(Qt::transparent); |
2318 | 47 | QPainter imagePainter(&qimage); | 47 | QPainter imagePainter(&qimage); |
2319 | 48 | 48 | ||
2320 | 49 | frameWidth = qimage.width(); | ||
2321 | 50 | frameHeight = qimage.height(); | ||
2322 | 51 | |||
2323 | 49 | QSvgRenderer *svgRenderer = new QSvgRenderer(QByteArray(svgString)); | 52 | QSvgRenderer *svgRenderer = new QSvgRenderer(QByteArray(svgString)); |
2324 | 50 | svgRenderer->render(&imagePainter); | 53 | svgRenderer->render(&imagePainter); |
2325 | 51 | delete svgRenderer; | 54 | delete svgRenderer; |
2326 | @@ -59,6 +62,8 @@ | |||
2327 | 59 | { | 62 | { |
2328 | 60 | qimage = QImage(1, 1, QImage::Format_ARGB32); | 63 | qimage = QImage(1, 1, QImage::Format_ARGB32); |
2329 | 61 | qimage.fill(Qt::transparent); | 64 | qimage.fill(Qt::transparent); |
2330 | 65 | frameWidth = qimage.width(); | ||
2331 | 66 | frameHeight = qimage.height(); | ||
2332 | 62 | } | 67 | } |
2333 | 63 | 68 | ||
2334 | 64 | ///// | 69 | ///// |
2335 | @@ -69,40 +74,74 @@ | |||
2336 | 69 | { | 74 | { |
2337 | 70 | qimage = cursor.pixmap().toImage(); | 75 | qimage = cursor.pixmap().toImage(); |
2338 | 71 | hotspot = cursor.hotSpot(); | 76 | hotspot = cursor.hotSpot(); |
2339 | 77 | frameWidth = qimage.width(); | ||
2340 | 78 | frameHeight = qimage.height(); | ||
2341 | 72 | } | 79 | } |
2342 | 73 | 80 | ||
2343 | 74 | ///// | 81 | ///// |
2344 | 75 | // XCursorImage | 82 | // XCursorImage |
2345 | 76 | 83 | ||
2346 | 77 | XCursorImage::XCursorImage(const QString &theme, const QString &file) | 84 | XCursorImage::XCursorImage(const QString &theme, const QString &file) |
2347 | 78 | : xcursorImages(nullptr) | ||
2348 | 79 | { | 85 | { |
2349 | 80 | // TODO: Consider grid unit value | 86 | // TODO: Consider grid unit value |
2350 | 81 | // Hardcoding to a medium size for now | 87 | // Hardcoding to a medium size for now |
2351 | 82 | int preferredCursorHeightPx = 32; | 88 | int preferredCursorHeightPx = 32; |
2352 | 83 | 89 | ||
2354 | 84 | xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme), | 90 | XcursorImages *xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme), |
2355 | 85 | preferredCursorHeightPx); | 91 | preferredCursorHeightPx); |
2357 | 86 | if (!xcursorImages) { | 92 | if (!xcursorImages || xcursorImages->nimage == 0) { |
2358 | 87 | return; | 93 | return; |
2359 | 88 | } | 94 | } |
2360 | 89 | 95 | ||
2369 | 90 | // Just take the first one. It will have multiple images in case of an animated cursor. | 96 | frameCount = xcursorImages->nimage; |
2370 | 91 | // TODO: Support animated cursors | 97 | |
2371 | 92 | if ( xcursorImages->nimage > 0) { | 98 | for (int i = 0; i < xcursorImages->nimage; ++i) { |
2372 | 93 | XcursorImage *xcursorImage = xcursorImages->images[0]; | 99 | XcursorImage *xcursorImage = xcursorImages->images[0]; |
2373 | 94 | 100 | if (frameWidth < (int)xcursorImage->width) { | |
2374 | 95 | qimage = QImage((uchar*)xcursorImage->pixels, | 101 | frameWidth = xcursorImage->width; |
2375 | 96 | xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32); | 102 | } |
2376 | 97 | 103 | if (frameHeight < (int)xcursorImage->height) { | |
2377 | 104 | frameHeight = xcursorImage->height; | ||
2378 | 105 | } | ||
2379 | 106 | if (i == 0) { | ||
2380 | 107 | frameDuration = (int)xcursorImage->delay; | ||
2381 | 108 | } else { | ||
2382 | 109 | if (frameDuration != (int)xcursorImage->delay) { | ||
2383 | 110 | qWarning().nospace() << "CursorImageProvider: XCursorImage("<<theme<<","<<file<<") has" | ||
2384 | 111 | " varying delays in its animation. Animation won't look right."; | ||
2385 | 112 | } | ||
2386 | 113 | } | ||
2387 | 114 | } | ||
2388 | 115 | |||
2389 | 116 | { | ||
2390 | 117 | // Assume that the hotspot position does not animate | ||
2391 | 118 | XcursorImage *xcursorImage = xcursorImages->images[0]; | ||
2392 | 98 | hotspot.setX(xcursorImage->xhot); | 119 | hotspot.setX(xcursorImage->xhot); |
2393 | 99 | hotspot.setY(xcursorImage->yhot); | 120 | hotspot.setY(xcursorImage->yhot); |
2394 | 100 | } | 121 | } |
2395 | 122 | |||
2396 | 123 | // Build the sprite as a single row of frames | ||
2397 | 124 | qimage = QImage(frameWidth*frameCount, frameHeight, QImage::Format_ARGB32); | ||
2398 | 125 | qimage.fill(Qt::transparent); | ||
2399 | 126 | |||
2400 | 127 | { | ||
2401 | 128 | QPainter painter(&qimage); | ||
2402 | 129 | |||
2403 | 130 | for (int i = 0; i < xcursorImages->nimage; ++i) { | ||
2404 | 131 | XcursorImage *xcursorImage = xcursorImages->images[i]; | ||
2405 | 132 | |||
2406 | 133 | auto frameImage = QImage((uchar*)xcursorImage->pixels, | ||
2407 | 134 | xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32); | ||
2408 | 135 | |||
2409 | 136 | painter.drawImage(QPoint(i*frameWidth, 0), frameImage); | ||
2410 | 137 | } | ||
2411 | 138 | } | ||
2412 | 139 | |||
2413 | 140 | XcursorImagesDestroy(xcursorImages); | ||
2414 | 101 | } | 141 | } |
2415 | 102 | 142 | ||
2416 | 103 | XCursorImage::~XCursorImage() | 143 | XCursorImage::~XCursorImage() |
2417 | 104 | { | 144 | { |
2418 | 105 | XcursorImagesDestroy(xcursorImages); | ||
2419 | 106 | } | 145 | } |
2420 | 107 | 146 | ||
2421 | 108 | ///// | 147 | ///// |
2422 | @@ -205,16 +244,6 @@ | |||
2423 | 205 | return cursorImage->qimage; | 244 | return cursorImage->qimage; |
2424 | 206 | } | 245 | } |
2425 | 207 | 246 | ||
2426 | 208 | QPoint CursorImageProvider::hotspot(const QString &themeName, const QString &cursorName) | ||
2427 | 209 | { | ||
2428 | 210 | CursorImage *cursorImage = fetchCursor(themeName, cursorName); | ||
2429 | 211 | if (cursorImage) { | ||
2430 | 212 | return cursorImage->hotspot; | ||
2431 | 213 | } else { | ||
2432 | 214 | return QPoint(0,0); | ||
2433 | 215 | } | ||
2434 | 216 | } | ||
2435 | 217 | |||
2436 | 218 | CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName) | 247 | CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName) |
2437 | 219 | { | 248 | { |
2438 | 220 | QString themeName; | 249 | QString themeName; |
2439 | 221 | 250 | ||
2440 | === modified file 'plugins/Cursor/CursorImageProvider.h' | |||
2441 | --- plugins/Cursor/CursorImageProvider.h 2015-11-16 14:27:31 +0000 | |||
2442 | +++ plugins/Cursor/CursorImageProvider.h 2016-06-01 16:58:47 +0000 | |||
2443 | @@ -31,15 +31,23 @@ | |||
2444 | 31 | virtual ~CursorImage() {} | 31 | virtual ~CursorImage() {} |
2445 | 32 | 32 | ||
2446 | 33 | QImage qimage; | 33 | QImage qimage; |
2447 | 34 | |||
2448 | 35 | // TODO: consider if there's a need to animate the hotspot | ||
2449 | 36 | // ie, if there's a need to make it an array of points, one for each frame. | ||
2450 | 37 | // Maybe no single xcursor (or at least the ones we know of or use) | ||
2451 | 38 | // vary its hotspot position through its animation. | ||
2452 | 34 | QPoint hotspot; | 39 | QPoint hotspot; |
2453 | 40 | |||
2454 | 41 | int frameWidth{0}; | ||
2455 | 42 | int frameHeight{0}; | ||
2456 | 43 | int frameCount{1}; | ||
2457 | 44 | int frameDuration{40}; | ||
2458 | 35 | }; | 45 | }; |
2459 | 36 | 46 | ||
2460 | 37 | class XCursorImage : public CursorImage { | 47 | class XCursorImage : public CursorImage { |
2461 | 38 | public: | 48 | public: |
2462 | 39 | XCursorImage(const QString &theme, const QString &file); | 49 | XCursorImage(const QString &theme, const QString &file); |
2463 | 40 | virtual ~XCursorImage(); | 50 | virtual ~XCursorImage(); |
2464 | 41 | |||
2465 | 42 | XcursorImages *xcursorImages; | ||
2466 | 43 | }; | 51 | }; |
2467 | 44 | 52 | ||
2468 | 45 | class BuiltInCursorImage : public CursorImage { | 53 | class BuiltInCursorImage : public CursorImage { |
2469 | @@ -68,16 +76,16 @@ | |||
2470 | 68 | 76 | ||
2471 | 69 | QImage requestImage(const QString &cursorName, QSize *size, const QSize &requestedSize) override; | 77 | QImage requestImage(const QString &cursorName, QSize *size, const QSize &requestedSize) override; |
2472 | 70 | 78 | ||
2474 | 71 | QPoint hotspot(const QString &themeName, const QString &cursorName); | 79 | CursorImage *fetchCursor(const QString &themeName, const QString &cursorName); |
2475 | 72 | 80 | ||
2476 | 73 | void setCustomCursor(const QCursor &customCursor); | 81 | void setCustomCursor(const QCursor &customCursor); |
2477 | 74 | 82 | ||
2478 | 75 | private: | 83 | private: |
2479 | 76 | CursorImage *fetchCursor(const QString &cursorThemeAndName); | 84 | CursorImage *fetchCursor(const QString &cursorThemeAndName); |
2480 | 77 | CursorImage *fetchCursor(const QString &themeName, const QString &cursorName); | ||
2481 | 78 | CursorImage *fetchCursorHelper(const QString &themeName, const QString &cursorName); | 85 | CursorImage *fetchCursorHelper(const QString &themeName, const QString &cursorName); |
2482 | 79 | 86 | ||
2483 | 80 | // themeName -> (cursorName -> cursorImage) | 87 | // themeName -> (cursorName -> cursorImage) |
2484 | 88 | // TODO: discard old, unused, cursors | ||
2485 | 81 | QMap<QString, QMap<QString, CursorImage*> > m_cursors; | 89 | QMap<QString, QMap<QString, CursorImage*> > m_cursors; |
2486 | 82 | 90 | ||
2487 | 83 | QScopedPointer<CursorImage> m_builtInCursorImage; | 91 | QScopedPointer<CursorImage> m_builtInCursorImage; |
2488 | 84 | 92 | ||
2489 | === modified file 'plugins/Cursor/MousePointer.cpp' | |||
2490 | --- plugins/Cursor/MousePointer.cpp 2015-12-01 21:54:18 +0000 | |||
2491 | +++ plugins/Cursor/MousePointer.cpp 2016-06-01 16:58:47 +0000 | |||
2492 | @@ -29,10 +29,7 @@ | |||
2493 | 29 | : MirMousePointerInterface(parent) | 29 | : MirMousePointerInterface(parent) |
2494 | 30 | , m_cursorName(QStringLiteral("left_ptr")) | 30 | , m_cursorName(QStringLiteral("left_ptr")) |
2495 | 31 | , m_themeName(QStringLiteral("default")) | 31 | , m_themeName(QStringLiteral("default")) |
2496 | 32 | , m_hotspotX(0) | ||
2497 | 33 | , m_hotspotY(0) | ||
2498 | 34 | { | 32 | { |
2499 | 35 | updateHotspot(); | ||
2500 | 36 | } | 33 | } |
2501 | 37 | 34 | ||
2502 | 38 | void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons, | 35 | void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons, |
2503 | @@ -89,8 +86,32 @@ | |||
2504 | 89 | 86 | ||
2505 | 90 | void MousePointer::registerWindow(QWindow *window) | 87 | void MousePointer::registerWindow(QWindow *window) |
2506 | 91 | { | 88 | { |
2509 | 92 | if (m_registeredWindow && window != m_registeredWindow) { | 89 | if (window == m_registeredWindow) { |
2510 | 93 | auto previousCursor = dynamic_cast<MirPlatformCursor*>(m_registeredWindow->screen()->handle()->cursor()); | 90 | return; |
2511 | 91 | } | ||
2512 | 92 | |||
2513 | 93 | if (m_registeredWindow) { | ||
2514 | 94 | m_registeredWindow->disconnect(this); | ||
2515 | 95 | } | ||
2516 | 96 | |||
2517 | 97 | m_registeredWindow = window; | ||
2518 | 98 | |||
2519 | 99 | if (m_registeredWindow) { | ||
2520 | 100 | connect(window, &QWindow::screenChanged, this, &MousePointer::registerScreen); | ||
2521 | 101 | registerScreen(window->screen()); | ||
2522 | 102 | } else { | ||
2523 | 103 | registerScreen(nullptr); | ||
2524 | 104 | } | ||
2525 | 105 | } | ||
2526 | 106 | |||
2527 | 107 | void MousePointer::registerScreen(QScreen *screen) | ||
2528 | 108 | { | ||
2529 | 109 | if (m_registeredScreen == screen) { | ||
2530 | 110 | return; | ||
2531 | 111 | } | ||
2532 | 112 | |||
2533 | 113 | if (m_registeredScreen) { | ||
2534 | 114 | auto previousCursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor()); | ||
2535 | 94 | if (previousCursor) { | 115 | if (previousCursor) { |
2536 | 95 | previousCursor->setMousePointer(nullptr); | 116 | previousCursor->setMousePointer(nullptr); |
2537 | 96 | } else { | 117 | } else { |
2538 | @@ -98,10 +119,10 @@ | |||
2539 | 98 | } | 119 | } |
2540 | 99 | } | 120 | } |
2541 | 100 | 121 | ||
2543 | 101 | m_registeredWindow = window; | 122 | m_registeredScreen = screen; |
2544 | 102 | 123 | ||
2547 | 103 | if (m_registeredWindow) { | 124 | if (m_registeredScreen) { |
2548 | 104 | auto cursor = dynamic_cast<MirPlatformCursor*>(window->screen()->handle()->cursor()); | 125 | auto cursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor()); |
2549 | 105 | if (cursor) { | 126 | if (cursor) { |
2550 | 106 | cursor->setMousePointer(this); | 127 | cursor->setMousePointer(this); |
2551 | 107 | } else { | 128 | } else { |
2552 | @@ -115,22 +136,6 @@ | |||
2553 | 115 | if (cursorName != m_cursorName) { | 136 | if (cursorName != m_cursorName) { |
2554 | 116 | m_cursorName = cursorName; | 137 | m_cursorName = cursorName; |
2555 | 117 | Q_EMIT cursorNameChanged(m_cursorName); | 138 | Q_EMIT cursorNameChanged(m_cursorName); |
2556 | 118 | updateHotspot(); | ||
2557 | 119 | } | ||
2558 | 120 | } | ||
2559 | 121 | |||
2560 | 122 | void MousePointer::updateHotspot() | ||
2561 | 123 | { | ||
2562 | 124 | QPoint newHotspot = CursorImageProvider::instance()->hotspot(m_themeName, m_cursorName); | ||
2563 | 125 | |||
2564 | 126 | if (m_hotspotX != newHotspot.x()) { | ||
2565 | 127 | m_hotspotX = newHotspot.x(); | ||
2566 | 128 | Q_EMIT hotspotXChanged(m_hotspotX); | ||
2567 | 129 | } | ||
2568 | 130 | |||
2569 | 131 | if (m_hotspotY != newHotspot.y()) { | ||
2570 | 132 | m_hotspotY = newHotspot.y(); | ||
2571 | 133 | Q_EMIT hotspotYChanged(m_hotspotY); | ||
2572 | 134 | } | 139 | } |
2573 | 135 | } | 140 | } |
2574 | 136 | 141 | ||
2575 | 137 | 142 | ||
2576 | === modified file 'plugins/Cursor/MousePointer.h' | |||
2577 | --- plugins/Cursor/MousePointer.h 2015-12-01 21:40:13 +0000 | |||
2578 | +++ plugins/Cursor/MousePointer.h 2016-06-01 16:58:47 +0000 | |||
2579 | @@ -20,6 +20,7 @@ | |||
2580 | 20 | // Qt | 20 | // Qt |
2581 | 21 | #include <QPointer> | 21 | #include <QPointer> |
2582 | 22 | #include <QWindow> | 22 | #include <QWindow> |
2583 | 23 | #include <QScreen> | ||
2584 | 23 | 24 | ||
2585 | 24 | // Unity API | 25 | // Unity API |
2586 | 25 | #include <unity/shell/application/MirMousePointerInterface.h> | 26 | #include <unity/shell/application/MirMousePointerInterface.h> |
2587 | @@ -35,9 +36,6 @@ | |||
2588 | 35 | void setThemeName(const QString &themeName) override; | 36 | void setThemeName(const QString &themeName) override; |
2589 | 36 | QString themeName() const override { return m_themeName; } | 37 | QString themeName() const override { return m_themeName; } |
2590 | 37 | 38 | ||
2591 | 38 | qreal hotspotX() const override { return m_hotspotX; } | ||
2592 | 39 | qreal hotspotY() const override { return m_hotspotY; } | ||
2593 | 40 | |||
2594 | 41 | void setCustomCursor(const QCursor &) override; | 39 | void setCustomCursor(const QCursor &) override; |
2595 | 42 | 40 | ||
2596 | 43 | public Q_SLOTS: | 41 | public Q_SLOTS: |
2597 | @@ -53,15 +51,16 @@ | |||
2598 | 53 | protected: | 51 | protected: |
2599 | 54 | void itemChange(ItemChange change, const ItemChangeData &value) override; | 52 | void itemChange(ItemChange change, const ItemChangeData &value) override; |
2600 | 55 | 53 | ||
2601 | 54 | private Q_SLOTS: | ||
2602 | 55 | void registerScreen(QScreen *screen); | ||
2603 | 56 | |||
2604 | 56 | private: | 57 | private: |
2605 | 57 | void registerWindow(QWindow *window); | 58 | void registerWindow(QWindow *window); |
2606 | 58 | void updateHotspot(); | ||
2607 | 59 | 59 | ||
2608 | 60 | QPointer<QWindow> m_registeredWindow; | 60 | QPointer<QWindow> m_registeredWindow; |
2609 | 61 | QPointer<QScreen> m_registeredScreen; | ||
2610 | 61 | QString m_cursorName; | 62 | QString m_cursorName; |
2611 | 62 | QString m_themeName; | 63 | QString m_themeName; |
2612 | 63 | int m_hotspotX; | ||
2613 | 64 | int m_hotspotY; | ||
2614 | 65 | }; | 64 | }; |
2615 | 66 | 65 | ||
2616 | 67 | #endif // MOUSEPOINTER_H | 66 | #endif // MOUSEPOINTER_H |
2617 | 68 | 67 | ||
2618 | === modified file 'plugins/Cursor/plugin.cpp' | |||
2619 | --- plugins/Cursor/plugin.cpp 2015-11-20 15:01:39 +0000 | |||
2620 | +++ plugins/Cursor/plugin.cpp 2016-06-01 16:58:47 +0000 | |||
2621 | @@ -1,5 +1,5 @@ | |||
2622 | 1 | /* | 1 | /* |
2624 | 2 | * Copyright (C) 2015 Canonical, Ltd. | 2 | * Copyright (C) 2015-2016 Canonical, Ltd. |
2625 | 3 | * | 3 | * |
2626 | 4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
2627 | 5 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
2628 | @@ -22,13 +22,15 @@ | |||
2629 | 22 | #include "plugin.h" | 22 | #include "plugin.h" |
2630 | 23 | 23 | ||
2631 | 24 | // local | 24 | // local |
2632 | 25 | #include "CursorImageInfo.h" | ||
2633 | 25 | #include "CursorImageProvider.h" | 26 | #include "CursorImageProvider.h" |
2634 | 26 | #include "MousePointer.h" | 27 | #include "MousePointer.h" |
2635 | 27 | 28 | ||
2636 | 28 | void CursorPlugin::registerTypes(const char *uri) | 29 | void CursorPlugin::registerTypes(const char *uri) |
2637 | 29 | { | 30 | { |
2638 | 30 | Q_ASSERT(uri == QLatin1String("Cursor")); | 31 | Q_ASSERT(uri == QLatin1String("Cursor")); |
2640 | 31 | qmlRegisterType<MousePointer>(uri, 1, 0, "MousePointer"); | 32 | qmlRegisterType<CursorImageInfo>(uri, 1, 1, "CursorImageInfo"); |
2641 | 33 | qmlRegisterType<MousePointer>(uri, 1, 1, "MousePointer"); | ||
2642 | 32 | } | 34 | } |
2643 | 33 | 35 | ||
2644 | 34 | void CursorPlugin::initializeEngine(QQmlEngine *engine, const char *uri) | 36 | void CursorPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
2645 | 35 | 37 | ||
2646 | === modified file 'plugins/Cursor/qmldir' | |||
2647 | --- plugins/Cursor/qmldir 2015-09-29 13:45:05 +0000 | |||
2648 | +++ plugins/Cursor/qmldir 2016-06-01 16:58:47 +0000 | |||
2649 | @@ -1,3 +1,3 @@ | |||
2650 | 1 | module Cursor | 1 | module Cursor |
2651 | 2 | plugin Cursor-qml | 2 | plugin Cursor-qml |
2653 | 3 | Cursor 1.0 Cursor.qml | 3 | Cursor 1.1 Cursor.qml |
2654 | 4 | 4 | ||
2655 | === modified file 'plugins/Dash/AudioProgressBar.qml' | |||
2656 | --- plugins/Dash/AudioProgressBar.qml 2016-01-18 22:56:16 +0000 | |||
2657 | +++ plugins/Dash/AudioProgressBar.qml 2016-06-01 16:58:47 +0000 | |||
2658 | @@ -49,6 +49,6 @@ | |||
2659 | 49 | rightMargin: maxWidth - (maxWidth * root.progress) | 49 | rightMargin: maxWidth - (maxWidth * root.progress) |
2660 | 50 | } | 50 | } |
2661 | 51 | height: units.dp(2) | 51 | height: units.dp(2) |
2663 | 52 | backgroundColor: UbuntuColors.orange | 52 | backgroundColor: theme.palette.normal.activity |
2664 | 53 | } | 53 | } |
2665 | 54 | } | 54 | } |
2666 | 55 | 55 | ||
2667 | === modified file 'plugins/Dash/CardCreator.js' | |||
2668 | --- plugins/Dash/CardCreator.js 2016-05-04 14:09:00 +0000 | |||
2669 | +++ plugins/Dash/CardCreator.js 2016-06-01 16:58:47 +0000 | |||
2670 | @@ -59,14 +59,30 @@ | |||
2671 | 59 | } \n\ | 59 | } \n\ |
2672 | 60 | }\n'; | 60 | }\n'; |
2673 | 61 | 61 | ||
2674 | 62 | // %1 is the aspect of the UbuntuShape | ||
2675 | 63 | var kArtUbuntuShapeCode = 'UbuntuShape { \n\ | ||
2676 | 64 | anchors.fill: parent; \n\ | ||
2677 | 65 | source: artImage; \n\ | ||
2678 | 66 | sourceFillMode: UbuntuShape.PreserveAspectCrop; \n\ | ||
2679 | 67 | radius: "medium"; \n\ | ||
2680 | 68 | aspect: %1; \n\ | ||
2681 | 69 | }'; | ||
2682 | 70 | |||
2683 | 71 | var kArtProportionalShapeCode = 'ProportionalShape { \n\ | ||
2684 | 72 | anchors.fill: parent; \n\ | ||
2685 | 73 | source: artImage; \n\ | ||
2686 | 74 | aspect: UbuntuShape.DropShadow; \n\ | ||
2687 | 75 | }'; | ||
2688 | 76 | |||
2689 | 62 | // %1 is used as anchors of artShapeHolder | 77 | // %1 is used as anchors of artShapeHolder |
2690 | 63 | // %2 is used as image width | 78 | // %2 is used as image width |
2691 | 64 | // %3 is used as image height | 79 | // %3 is used as image height |
2693 | 65 | // %4 is whether the image or the Loader with the UbuntuShape/ProportionalShape should be visible | 80 | // %4 is whether the image should be visible |
2694 | 66 | // %5 is used as aspect ratio fallback | 81 | // %5 is used as aspect ratio fallback |
2695 | 67 | // %6 is whether the loader should be asynchronous or not | 82 | // %6 is whether the loader should be asynchronous or not |
2698 | 68 | // %7 is injected as code to artImage | 83 | // %7 is the shape code we want to use |
2699 | 69 | // %8 is used as image fallback | 84 | // %8 is injected as code to artImage |
2700 | 85 | // %9 is used as image fallback | ||
2701 | 70 | var kArtShapeHolderCode = 'Item { \n\ | 86 | var kArtShapeHolderCode = 'Item { \n\ |
2702 | 71 | id: artShapeHolder; \n\ | 87 | id: artShapeHolder; \n\ |
2703 | 72 | height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\ | 88 | height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\ |
2704 | @@ -75,7 +91,8 @@ | |||
2705 | 75 | Loader { \n\ | 91 | Loader { \n\ |
2706 | 76 | id: artShapeLoader; \n\ | 92 | id: artShapeLoader; \n\ |
2707 | 77 | objectName: "artShapeLoader"; \n\ | 93 | objectName: "artShapeLoader"; \n\ |
2709 | 78 | readonly property string cardArt: cardData && cardData["art"] || %8; \n\ | 94 | readonly property string cardArt: cardData && cardData["art"] || %9; \n\ |
2710 | 95 | onCardArtChanged: { if (item) { item.image.source = cardArt; } } \n\ | ||
2711 | 79 | active: cardArt != ""; \n\ | 96 | active: cardArt != ""; \n\ |
2712 | 80 | asynchronous: %6; \n\ | 97 | asynchronous: %6; \n\ |
2713 | 81 | visible: status == Loader.Ready; \n\ | 98 | visible: status == Loader.Ready; \n\ |
2714 | @@ -84,31 +101,7 @@ | |||
2715 | 84 | objectName: "artShape"; \n\ | 101 | objectName: "artShape"; \n\ |
2716 | 85 | visible: image.status == Image.Ready; \n\ | 102 | visible: image.status == Image.Ready; \n\ |
2717 | 86 | readonly property alias image: artImage; \n\ | 103 | readonly property alias image: artImage; \n\ |
2743 | 87 | Loader { \n\ | 104 | %7 \n\ |
2719 | 88 | anchors.fill: parent; \n\ | ||
2720 | 89 | visible: %4; \n\ | ||
2721 | 90 | sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent; \n\ | ||
2722 | 91 | Component { \n\ | ||
2723 | 92 | id: artShapeShapeComponent; \n\ | ||
2724 | 93 | UbuntuShape { \n\ | ||
2725 | 94 | source: artImage; \n\ | ||
2726 | 95 | sourceFillMode: UbuntuShape.PreserveAspectCrop; \n\ | ||
2727 | 96 | radius: "medium"; \n\ | ||
2728 | 97 | aspect: { \n\ | ||
2729 | 98 | switch (root.artShapeStyle) { \n\ | ||
2730 | 99 | case "inset": return UbuntuShape.Inset; \n\ | ||
2731 | 100 | case "shadow": return UbuntuShape.DropShadow; \n\ | ||
2732 | 101 | default: \n\ | ||
2733 | 102 | case "flat": return UbuntuShape.Flat; \n\ | ||
2734 | 103 | } \n\ | ||
2735 | 104 | } \n\ | ||
2736 | 105 | } \n\ | ||
2737 | 106 | } \n\ | ||
2738 | 107 | Component { \n\ | ||
2739 | 108 | id: artShapeIconComponent; \n\ | ||
2740 | 109 | ProportionalShape { source: artImage; aspect: UbuntuShape.DropShadow; } \n\ | ||
2741 | 110 | } \n\ | ||
2742 | 111 | } \n\ | ||
2744 | 112 | readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1; \n\ | 105 | readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1; \n\ |
2745 | 113 | readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : %5; \n\ | 106 | readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : %5; \n\ |
2746 | 114 | Component.onCompleted: { updateWidthHeightBindings(); } \n\ | 107 | Component.onCompleted: { updateWidthHeightBindings(); } \n\ |
2747 | @@ -127,10 +120,10 @@ | |||
2748 | 127 | objectName: "artImage"; \n\ | 120 | objectName: "artImage"; \n\ |
2749 | 128 | source: artShapeLoader.cardArt; \n\ | 121 | source: artShapeLoader.cardArt; \n\ |
2750 | 129 | asynchronous: %6; \n\ | 122 | asynchronous: %6; \n\ |
2752 | 130 | visible: !%4; \n\ | 123 | visible: %4; \n\ |
2753 | 131 | width: %2; \n\ | 124 | width: %2; \n\ |
2754 | 132 | height: %3; \n\ | 125 | height: %3; \n\ |
2756 | 133 | %7 \n\ | 126 | %8 \n\ |
2757 | 134 | } \n\ | 127 | } \n\ |
2758 | 135 | } \n\ | 128 | } \n\ |
2759 | 136 | } \n\ | 129 | } \n\ |
2760 | @@ -318,7 +311,7 @@ | |||
2761 | 318 | id: touchdown; \n\ | 311 | id: touchdown; \n\ |
2762 | 319 | objectName: "touchdown"; \n\ | 312 | objectName: "touchdown"; \n\ |
2763 | 320 | anchors { %1 } \n\ | 313 | anchors { %1 } \n\ |
2765 | 321 | visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed; \n\ | 314 | visible: root.pressed; \n\ |
2766 | 322 | radius: "medium"; \n\ | 315 | radius: "medium"; \n\ |
2767 | 323 | borderSource: "radius_pressed.sci" \n\ | 316 | borderSource: "radius_pressed.sci" \n\ |
2768 | 324 | }\n'; | 317 | }\n'; |
2769 | @@ -412,7 +405,7 @@ | |||
2770 | 412 | return colorString; | 405 | return colorString; |
2771 | 413 | } | 406 | } |
2772 | 414 | 407 | ||
2774 | 415 | function cardString(template, components, isCardTool) { | 408 | function cardString(template, components, isCardTool, artShapeStyle) { |
2775 | 416 | var code; | 409 | var code; |
2776 | 417 | 410 | ||
2777 | 418 | var templateInteractive = (template == null ? true : (template["non-interactive"] !== undefined ? !template["non-interactive"] : true)) ? "true" : "false"; | 411 | var templateInteractive = (template == null ? true : (template["non-interactive"] !== undefined ? !template["non-interactive"] : true)) ? "true" : "false"; |
2778 | @@ -420,7 +413,6 @@ | |||
2779 | 420 | code = 'AbstractButton { \n\ | 413 | code = 'AbstractButton { \n\ |
2780 | 421 | id: root; \n\ | 414 | id: root; \n\ |
2781 | 422 | property var cardData; \n\ | 415 | property var cardData; \n\ |
2782 | 423 | property string artShapeStyle: "inset"; \n\ | ||
2783 | 424 | property string backgroundShapeStyle: "inset"; \n\ | 416 | property string backgroundShapeStyle: "inset"; \n\ |
2784 | 425 | property real fontScale: 1.0; \n\ | 417 | property real fontScale: 1.0; \n\ |
2785 | 426 | property var scopeStyle: null; \n\ | 418 | property var scopeStyle: null; \n\ |
2786 | @@ -519,17 +511,35 @@ | |||
2787 | 519 | var fallbackStatusCode = ""; | 511 | var fallbackStatusCode = ""; |
2788 | 520 | var fallbackURICode = '""'; | 512 | var fallbackURICode = '""'; |
2789 | 521 | if (fallback !== "") { | 513 | if (fallback !== "") { |
2793 | 522 | // fallbackStatusCode has %6 in it because we want to substitute it for fallbackURICode | 514 | // fallbackStatusCode has %9 in it because we want to substitute it for fallbackURICode |
2794 | 523 | // which in kArtShapeHolderCode is %8 | 515 | // which in kArtShapeHolderCode is %9 |
2795 | 524 | fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %8;'; | 516 | fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %9;'; |
2796 | 525 | fallbackURICode = 'decodeURI("%1")'.arg(fallback); | 517 | fallbackURICode = 'decodeURI("%1")'.arg(fallback); |
2797 | 526 | } | 518 | } |
2798 | 519 | var artShapeHolderShapeCode; | ||
2799 | 520 | if (!isConciergeMode) { | ||
2800 | 521 | if (artShapeStyle === "icon") { | ||
2801 | 522 | artShapeHolderShapeCode = kArtProportionalShapeCode; | ||
2802 | 523 | } else { | ||
2803 | 524 | var artShapeHolderShapeAspect; | ||
2804 | 525 | switch (artShapeStyle) { | ||
2805 | 526 | case "inset": artShapeHolderShapeAspect = "UbuntuShape.Inset"; break; | ||
2806 | 527 | case "shadow": artShapeHolderShapeAspect = "UbuntuShape.DropShadow"; break; | ||
2807 | 528 | default: | ||
2808 | 529 | case "flat": artShapeHolderShapeAspect = "UbuntuShape.Flat"; break; | ||
2809 | 530 | } | ||
2810 | 531 | artShapeHolderShapeCode = kArtUbuntuShapeCode.arg(artShapeHolderShapeAspect); | ||
2811 | 532 | } | ||
2812 | 533 | } else { | ||
2813 | 534 | artShapeHolderShapeCode = ""; | ||
2814 | 535 | } | ||
2815 | 527 | code += kArtShapeHolderCode.arg(artAnchors) | 536 | code += kArtShapeHolderCode.arg(artAnchors) |
2816 | 528 | .arg(widthCode) | 537 | .arg(widthCode) |
2817 | 529 | .arg(heightCode) | 538 | .arg(heightCode) |
2819 | 530 | .arg(isConciergeMode ? "false" : "true") | 539 | .arg(isConciergeMode ? "true" : "false") |
2820 | 531 | .arg(aspectRatio) | 540 | .arg(aspectRatio) |
2821 | 532 | .arg(asynchronous) | 541 | .arg(asynchronous) |
2822 | 542 | .arg(artShapeHolderShapeCode) | ||
2823 | 533 | .arg(fallbackStatusCode) | 543 | .arg(fallbackStatusCode) |
2824 | 534 | .arg(fallbackURICode); | 544 | .arg(fallbackURICode); |
2825 | 535 | } else { | 545 | } else { |
2826 | @@ -854,6 +864,10 @@ | |||
2827 | 854 | code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(summaryColor); | 864 | code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(summaryColor); |
2828 | 855 | } | 865 | } |
2829 | 856 | 866 | ||
2830 | 867 | // <<<<<<< TREE | ||
2831 | 868 | // if (artShapeStyle != "shadow" && artShapeStyle != "icon") { | ||
2832 | 869 | // var touchdownAnchors; | ||
2833 | 870 | // ======= | ||
2834 | 857 | if (hasSocialActions) { | 871 | if (hasSocialActions) { |
2835 | 858 | var socialAnchors; | 872 | var socialAnchors; |
2836 | 859 | var socialTopAnchor; | 873 | var socialTopAnchor; |
2837 | @@ -882,15 +896,17 @@ | |||
2838 | 882 | code += kSocialActionsRowCode.arg(socialAnchors).arg(socialColor); | 896 | code += kSocialActionsRowCode.arg(socialAnchors).arg(socialColor); |
2839 | 883 | } | 897 | } |
2840 | 884 | 898 | ||
2848 | 885 | var touchdownAnchors; | 899 | if (artShapeStyle != "shadow" && artShapeStyle != "icon") { |
2849 | 886 | if (hasBackground) { | 900 | var touchdownAnchors; |
2850 | 887 | touchdownAnchors = 'fill: backgroundLoader'; | 901 | if (hasBackground) { |
2851 | 888 | } else if (touchdownOnArtShape) { | 902 | touchdownAnchors = 'fill: backgroundLoader'; |
2852 | 889 | touchdownAnchors = 'fill: artShapeHolder'; | 903 | } else if (touchdownOnArtShape) { |
2853 | 890 | } else { | 904 | touchdownAnchors = 'fill: artShapeHolder'; |
2854 | 891 | touchdownAnchors = 'fill: root' | 905 | } else { |
2855 | 906 | touchdownAnchors = 'fill: root' | ||
2856 | 907 | } | ||
2857 | 908 | code += kTouchdownCode.arg(touchdownAnchors); | ||
2858 | 892 | } | 909 | } |
2859 | 893 | code += kTouchdownCode.arg(touchdownAnchors); | ||
2860 | 894 | 910 | ||
2861 | 895 | var implicitHeight = 'implicitHeight: '; | 911 | var implicitHeight = 'implicitHeight: '; |
2862 | 896 | if (hasSocialActions) { | 912 | if (hasSocialActions) { |
2863 | @@ -925,13 +941,13 @@ | |||
2864 | 925 | return code; | 941 | return code; |
2865 | 926 | } | 942 | } |
2866 | 927 | 943 | ||
2868 | 928 | function createCardComponent(parent, template, components, isCardTool, identifier) { | 944 | function createCardComponent(parent, template, components, isCardTool, artShapeStyle, identifier) { |
2869 | 929 | var imports = 'import QtQuick 2.4; \n\ | 945 | var imports = 'import QtQuick 2.4; \n\ |
2870 | 930 | import Ubuntu.Components 1.3; \n\ | 946 | import Ubuntu.Components 1.3; \n\ |
2871 | 931 | import Ubuntu.Settings.Components 0.1; \n\ | 947 | import Ubuntu.Settings.Components 0.1; \n\ |
2872 | 932 | import Dash 0.1;\n\ | 948 | import Dash 0.1;\n\ |
2873 | 933 | import Utils 0.1;\n'; | 949 | import Utils 0.1;\n'; |
2875 | 934 | var card = cardString(template, components, isCardTool); | 950 | var card = cardString(template, components, isCardTool, artShapeStyle); |
2876 | 935 | var code = imports + 'Component {\n' + card + '}\n'; | 951 | var code = imports + 'Component {\n' + card + '}\n'; |
2877 | 936 | 952 | ||
2878 | 937 | try { | 953 | try { |
2879 | 938 | 954 | ||
2880 | === modified file 'plugins/Dash/CardCreatorCache.qml' | |||
2881 | --- plugins/Dash/CardCreatorCache.qml 2016-02-16 14:26:58 +0000 | |||
2882 | +++ plugins/Dash/CardCreatorCache.qml 2016-06-01 16:58:47 +0000 | |||
2883 | @@ -23,7 +23,7 @@ | |||
2884 | 23 | 23 | ||
2885 | 24 | property var cache: new Object(); | 24 | property var cache: new Object(); |
2886 | 25 | 25 | ||
2888 | 26 | function getCardComponent(template, components, isCardTool) { | 26 | function getCardComponent(template, components, isCardTool, artShapeStyle) { |
2889 | 27 | if (template === undefined || components === undefined) | 27 | if (template === undefined || components === undefined) |
2890 | 28 | return undefined; | 28 | return undefined; |
2891 | 29 | 29 | ||
2892 | @@ -32,7 +32,7 @@ | |||
2893 | 32 | var allString = tString + cString + isCardTool; | 32 | var allString = tString + cString + isCardTool; |
2894 | 33 | var component = cache[allString]; | 33 | var component = cache[allString]; |
2895 | 34 | if (component === undefined) { | 34 | if (component === undefined) { |
2897 | 35 | component = CardCreator.createCardComponent(root, template, components, isCardTool, allString); | 35 | component = CardCreator.createCardComponent(root, template, components, isCardTool, artShapeStyle, allString); |
2898 | 36 | cache[allString] = component; | 36 | cache[allString] = component; |
2899 | 37 | } | 37 | } |
2900 | 38 | return component; | 38 | return component; |
2901 | 39 | 39 | ||
2902 | === modified file 'plugins/Dash/ScopeStyle.qml' | |||
2903 | --- plugins/Dash/ScopeStyle.qml 2016-03-29 03:47:39 +0000 | |||
2904 | +++ plugins/Dash/ScopeStyle.qml 2016-06-01 16:58:47 +0000 | |||
2905 | @@ -70,7 +70,7 @@ | |||
2906 | 70 | readonly property url navigationBackground: "navigation-background" in d.headerStyle ? d.headerStyle["navigation-background"] : "color:///#f5f5f5" | 70 | readonly property url navigationBackground: "navigation-background" in d.headerStyle ? d.headerStyle["navigation-background"] : "color:///#f5f5f5" |
2907 | 71 | 71 | ||
2908 | 72 | /// Color of the primary preview button | 72 | /// Color of the primary preview button |
2910 | 73 | readonly property color previewButtonColor: "preview-button-color" in style ? style["preview-button-color"] : UbuntuColors.orange | 73 | readonly property color previewButtonColor: "preview-button-color" in style ? style["preview-button-color"] : theme.palette.normal.positive |
2911 | 74 | 74 | ||
2912 | 75 | //! @cond | 75 | //! @cond |
2913 | 76 | property var d: QtObject { | 76 | property var d: QtObject { |
2914 | 77 | 77 | ||
2915 | === modified file 'plugins/Dash/listviewwithpageheader.cpp' | |||
2916 | --- plugins/Dash/listviewwithpageheader.cpp 2016-04-27 14:59:24 +0000 | |||
2917 | +++ plugins/Dash/listviewwithpageheader.cpp 2016-06-01 16:58:47 +0000 | |||
2918 | @@ -97,6 +97,7 @@ | |||
2919 | 97 | #include <qqmlengine.h> | 97 | #include <qqmlengine.h> |
2920 | 98 | #pragma GCC diagnostic push | 98 | #pragma GCC diagnostic push |
2921 | 99 | #pragma GCC diagnostic ignored "-pedantic" | 99 | #pragma GCC diagnostic ignored "-pedantic" |
2922 | 100 | #include <private/qqmlcontext_p.h> | ||
2923 | 100 | #include <private/qqmldelegatemodel_p.h> | 101 | #include <private/qqmldelegatemodel_p.h> |
2924 | 101 | #include <private/qqmlglobal_p.h> | 102 | #include <private/qqmlglobal_p.h> |
2925 | 102 | #include <private/qquickitem_p.h> | 103 | #include <private/qquickitem_p.h> |
2926 | @@ -168,7 +169,7 @@ | |||
2927 | 168 | m_contentYAnimation->setDuration(200); | 169 | m_contentYAnimation->setDuration(200); |
2928 | 169 | m_contentYAnimation->setTargetObject(this); | 170 | m_contentYAnimation->setTargetObject(this); |
2929 | 170 | 171 | ||
2931 | 171 | connect(this, &ListViewWithPageHeader::contentWidthChanged, this, &ListViewWithPageHeader::onContentWidthChanged); | 172 | connect(contentItem(), &QQuickItem::widthChanged, this, &ListViewWithPageHeader::onContentWidthChanged); |
2932 | 172 | connect(this, &ListViewWithPageHeader::contentHeightChanged, this, &ListViewWithPageHeader::onContentHeightChanged); | 173 | connect(this, &ListViewWithPageHeader::contentHeightChanged, this, &ListViewWithPageHeader::onContentHeightChanged); |
2933 | 173 | connect(this, &ListViewWithPageHeader::heightChanged, this, &ListViewWithPageHeader::onHeightChanged); | 174 | connect(this, &ListViewWithPageHeader::heightChanged, this, &ListViewWithPageHeader::onHeightChanged); |
2934 | 174 | connect(m_contentYAnimation, &QQuickNumberAnimation::runningChanged, this, &ListViewWithPageHeader::contentYAnimationRunningChanged); | 175 | connect(m_contentYAnimation, &QQuickNumberAnimation::runningChanged, this, &ListViewWithPageHeader::contentYAnimationRunningChanged); |
2935 | @@ -757,8 +758,6 @@ | |||
2936 | 757 | 758 | ||
2937 | 758 | QQmlContext *creationContext = m_sectionDelegate->creationContext(); | 759 | QQmlContext *creationContext = m_sectionDelegate->creationContext(); |
2938 | 759 | QQmlContext *context = new QQmlContext(creationContext ? creationContext : qmlContext(this)); | 760 | QQmlContext *context = new QQmlContext(creationContext ? creationContext : qmlContext(this)); |
2939 | 760 | context->setContextProperty(QStringLiteral("section"), sectionText); | ||
2940 | 761 | context->setContextProperty(QStringLiteral("delegateIndex"), -1); | ||
2941 | 762 | QObject *nobj = m_sectionDelegate->beginCreate(context); | 761 | QObject *nobj = m_sectionDelegate->beginCreate(context); |
2942 | 763 | if (nobj) { | 762 | if (nobj) { |
2943 | 764 | QQml_setParent_noEvent(context, nobj); | 763 | QQml_setParent_noEvent(context, nobj); |
2944 | @@ -766,6 +765,8 @@ | |||
2945 | 766 | if (!sectionItem) { | 765 | if (!sectionItem) { |
2946 | 767 | delete nobj; | 766 | delete nobj; |
2947 | 768 | } else { | 767 | } else { |
2948 | 768 | sectionItem->setProperty("text", sectionText); | ||
2949 | 769 | sectionItem->setProperty("delegateIndex", -1); | ||
2950 | 769 | sectionItem->setZ(2); | 770 | sectionItem->setZ(2); |
2951 | 770 | QQml_setParent_noEvent(sectionItem, m_clipItem); | 771 | QQml_setParent_noEvent(sectionItem, m_clipItem); |
2952 | 771 | sectionItem->setParentItem(m_clipItem); | 772 | sectionItem->setParentItem(m_clipItem); |
2953 | @@ -801,8 +802,7 @@ | |||
2954 | 801 | if (!item->sectionItem()) { | 802 | if (!item->sectionItem()) { |
2955 | 802 | item->setSectionItem(getSectionItem(sectionText)); | 803 | item->setSectionItem(getSectionItem(sectionText)); |
2956 | 803 | } else { | 804 | } else { |
2959 | 804 | QQmlContext *context = QQmlEngine::contextForObject(item->sectionItem())->parentContext(); | 805 | item->sectionItem()->setProperty("text", sectionText); |
2958 | 805 | context->setContextProperty(QStringLiteral("section"), sectionText); | ||
2960 | 806 | } | 806 | } |
2961 | 807 | } else { | 807 | } else { |
2962 | 808 | if (item->sectionItem()) { | 808 | if (item->sectionItem()) { |
2963 | @@ -923,8 +923,7 @@ | |||
2964 | 923 | polish(); | 923 | polish(); |
2965 | 924 | } | 924 | } |
2966 | 925 | if (listItem->sectionItem()) { | 925 | if (listItem->sectionItem()) { |
2969 | 926 | QQmlContext *context = QQmlEngine::contextForObject(listItem->sectionItem())->parentContext(); | 926 | listItem->sectionItem()->setProperty("delegateIndex", modelIndex); |
2968 | 927 | context->setContextProperty(QStringLiteral("delegateIndex"), modelIndex); | ||
2970 | 928 | } | 927 | } |
2971 | 929 | adjustMinYExtent(); | 928 | adjustMinYExtent(); |
2972 | 930 | m_contentHeightDirty = true; | 929 | m_contentHeightDirty = true; |
2973 | @@ -948,9 +947,10 @@ | |||
2974 | 948 | return; | 947 | return; |
2975 | 949 | 948 | ||
2976 | 950 | item->setParentItem(m_clipItem); | 949 | item->setParentItem(m_clipItem); |
2977 | 950 | // FIXME Why do we need the refreshExpressions call? | ||
2978 | 951 | QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext(); | 951 | QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext(); |
2981 | 952 | context->setContextProperty(QStringLiteral("ListViewWithPageHeader"), this); | 952 | QQmlContextPrivate::get(context)->data->refreshExpressions(); |
2982 | 953 | context->setContextProperty(QStringLiteral("heightToClip"), QVariant::fromValue<int>(0)); | 953 | item->setProperty("heightToClip", QVariant::fromValue<int>(0)); |
2983 | 954 | if (modelIndex == m_asyncRequestedIndex) { | 954 | if (modelIndex == m_asyncRequestedIndex) { |
2984 | 955 | createItem(modelIndex, false); | 955 | createItem(modelIndex, false); |
2985 | 956 | refill(); | 956 | refill(); |
2986 | @@ -1116,8 +1116,7 @@ | |||
2987 | 1116 | for (int i = 0; i < m_visibleItems.count(); ++i) { | 1116 | for (int i = 0; i < m_visibleItems.count(); ++i) { |
2988 | 1117 | ListItem *item = m_visibleItems[i]; | 1117 | ListItem *item = m_visibleItems[i]; |
2989 | 1118 | if (item->sectionItem()) { | 1118 | if (item->sectionItem()) { |
2992 | 1119 | QQmlContext *context = QQmlEngine::contextForObject(item->sectionItem())->parentContext(); | 1119 | item->sectionItem()->setProperty("delegateIndex", m_firstVisibleIndex + i); |
2991 | 1120 | context->setContextProperty(QStringLiteral("delegateIndex"), m_firstVisibleIndex + i); | ||
2993 | 1121 | } | 1120 | } |
2994 | 1122 | } | 1121 | } |
2995 | 1123 | 1122 | ||
2996 | @@ -1287,8 +1286,7 @@ | |||
2997 | 1287 | } else { | 1286 | } else { |
2998 | 1288 | // Update the top sticky section header | 1287 | // Update the top sticky section header |
2999 | 1289 | const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty); | 1288 | const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty); |
3002 | 1290 | QQmlContext *context = QQmlEngine::contextForObject(m_topSectionItem)->parentContext(); | 1289 | m_topSectionItem->setProperty("text", section); |
3001 | 1291 | context->setContextProperty(QStringLiteral("section"), section); | ||
3003 | 1292 | 1290 | ||
3004 | 1293 | QQuickItemPrivate::get(m_topSectionItem)->setCulled(false); | 1291 | QQuickItemPrivate::get(m_topSectionItem)->setCulled(false); |
3005 | 1294 | m_topSectionItem->setY(topSectionStickPos); | 1292 | m_topSectionItem->setY(topSectionStickPos); |
3006 | @@ -1300,19 +1298,18 @@ | |||
3007 | 1300 | break; | 1298 | break; |
3008 | 1301 | delegateIndex--; | 1299 | delegateIndex--; |
3009 | 1302 | } | 1300 | } |
3011 | 1303 | context->setContextProperty(QStringLiteral("delegateIndex"), delegateIndex); | 1301 | m_topSectionItem->setProperty("delegateIndex", delegateIndex); |
3012 | 1304 | if (item->sectionItem()) { | 1302 | if (item->sectionItem()) { |
3013 | 1305 | QQuickItemPrivate::get(item->sectionItem())->setCulled(true); | 1303 | QQuickItemPrivate::get(item->sectionItem())->setCulled(true); |
3014 | 1306 | } | 1304 | } |
3015 | 1307 | } | 1305 | } |
3016 | 1308 | } | 1306 | } |
3017 | 1309 | } | 1307 | } |
3018 | 1310 | QQmlContext *context = QQmlEngine::contextForObject(item->m_item)->parentContext(); | ||
3019 | 1311 | const qreal clipFrom = visibleFrom + (!item->sectionItem() && m_topSectionItem && !QQuickItemPrivate::get(m_topSectionItem)->culled ? m_topSectionItem->height() : 0); | 1308 | const qreal clipFrom = visibleFrom + (!item->sectionItem() && m_topSectionItem && !QQuickItemPrivate::get(m_topSectionItem)->culled ? m_topSectionItem->height() : 0); |
3020 | 1312 | if (!cull && pos < clipFrom) { | 1309 | if (!cull && pos < clipFrom) { |
3022 | 1313 | context->setContextProperty(QStringLiteral("heightToClip"), clipFrom - pos); | 1310 | item->m_item->setProperty("heightToClip", clipFrom - pos); |
3023 | 1314 | } else { | 1311 | } else { |
3025 | 1315 | context->setContextProperty(QStringLiteral("heightToClip"), QVariant::fromValue<int>(0)); | 1312 | item->m_item->setProperty("heightToClip", QVariant::fromValue<int>(0)); |
3026 | 1316 | } | 1313 | } |
3027 | 1317 | // qDebug() << "ListViewWithPageHeader::layout" << item->m_item; | 1314 | // qDebug() << "ListViewWithPageHeader::layout" << item->m_item; |
3028 | 1318 | pos += item->height(); | 1315 | pos += item->height(); |
3029 | 1319 | 1316 | ||
3030 | === modified file 'plugins/Ubuntu/Gestures/AxisVelocityCalculator.h' | |||
3031 | --- plugins/Ubuntu/Gestures/AxisVelocityCalculator.h 2014-10-01 13:20:32 +0000 | |||
3032 | +++ plugins/Ubuntu/Gestures/AxisVelocityCalculator.h 2016-06-01 16:58:47 +0000 | |||
3033 | @@ -24,7 +24,7 @@ | |||
3034 | 24 | #include "UbuntuGesturesQmlGlobal.h" | 24 | #include "UbuntuGesturesQmlGlobal.h" |
3035 | 25 | #include <stdint.h> | 25 | #include <stdint.h> |
3036 | 26 | #include <QtCore/QObject> | 26 | #include <QtCore/QObject> |
3038 | 27 | #include "TimeSource.h" | 27 | #include <TimeSource> |
3039 | 28 | 28 | ||
3040 | 29 | /* | 29 | /* |
3041 | 30 | Estimates the current velocity of a finger based on recent movement along an axis | 30 | Estimates the current velocity of a finger based on recent movement along an axis |
3042 | 31 | 31 | ||
3043 | === modified file 'plugins/Ubuntu/Gestures/CMakeLists.txt' | |||
3044 | --- plugins/Ubuntu/Gestures/CMakeLists.txt 2016-03-29 03:47:39 +0000 | |||
3045 | +++ plugins/Ubuntu/Gestures/CMakeLists.txt 2016-06-01 16:58:47 +0000 | |||
3046 | @@ -4,27 +4,27 @@ | |||
3047 | 4 | set(UbuntuGesturesQml_SOURCES | 4 | set(UbuntuGesturesQml_SOURCES |
3048 | 5 | plugin.cpp | 5 | plugin.cpp |
3049 | 6 | AxisVelocityCalculator.cpp | 6 | AxisVelocityCalculator.cpp |
3050 | 7 | Damper.cpp | ||
3051 | 8 | Direction.cpp | 7 | Direction.cpp |
3054 | 9 | DirectionalDragArea.cpp | 8 | MouseEventGenerator.cpp |
3053 | 10 | FloatingFlickable.cpp | ||
3055 | 11 | PressedOutsideNotifier.cpp | 9 | PressedOutsideNotifier.cpp |
3056 | 12 | TouchDispatcher.cpp | 10 | TouchDispatcher.cpp |
3057 | 13 | TouchGate.cpp | 11 | TouchGate.cpp |
3058 | 14 | TouchGestureArea.cpp | 12 | TouchGestureArea.cpp |
3059 | 15 | ) | 13 | ) |
3060 | 16 | 14 | ||
3061 | 15 | pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures) | ||
3062 | 16 | |||
3063 | 17 | add_definitions(-DUBUNTUGESTURESQML_LIBRARY) | 17 | add_definitions(-DUBUNTUGESTURESQML_LIBRARY) |
3064 | 18 | 18 | ||
3065 | 19 | add_library(UbuntuGesturesQml MODULE ${UbuntuGesturesQml_SOURCES}) | 19 | add_library(UbuntuGesturesQml MODULE ${UbuntuGesturesQml_SOURCES}) |
3067 | 20 | target_link_libraries(UbuntuGesturesQml UbuntuGestures) | 20 | target_link_libraries(UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES}) |
3068 | 21 | 21 | ||
3069 | 22 | qt5_use_modules(UbuntuGesturesQml Core Quick) | 22 | qt5_use_modules(UbuntuGesturesQml Core Quick) |
3070 | 23 | 23 | ||
3071 | 24 | # So that Foo.cpp can #include "Foo.moc" | 24 | # So that Foo.cpp can #include "Foo.moc" |
3072 | 25 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) | 25 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) |
3073 | 26 | 26 | ||
3075 | 27 | include_directories(${CMAKE_SOURCE_DIR}/libs/UbuntuGestures) | 27 | include_directories(${UBUNTUGESTURES_INCLUDE_DIRS}) |
3076 | 28 | 28 | ||
3077 | 29 | # There's no cmake var for v8 include path :-/ so create one | 29 | # There's no cmake var for v8 include path :-/ so create one |
3078 | 30 | LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0) | 30 | LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0) |
3079 | 31 | 31 | ||
3080 | === removed file 'plugins/Ubuntu/Gestures/Damper.cpp' | |||
3081 | --- plugins/Ubuntu/Gestures/Damper.cpp 2015-04-10 21:16:37 +0000 | |||
3082 | +++ plugins/Ubuntu/Gestures/Damper.cpp 1970-01-01 00:00:00 +0000 | |||
3083 | @@ -1,24 +0,0 @@ | |||
3084 | 1 | /* | ||
3085 | 2 | * Copyright (C) 2015 Canonical, Ltd. | ||
3086 | 3 | * | ||
3087 | 4 | * This program is free software; you can redistribute it and/or modify | ||
3088 | 5 | * it under the terms of the GNU General Public License as published by | ||
3089 | 6 | * the Free Software Foundation; version 3. | ||
3090 | 7 | * | ||
3091 | 8 | * This program is distributed in the hope that it will be useful, | ||
3092 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3093 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3094 | 11 | * GNU General Public License for more details. | ||
3095 | 12 | * | ||
3096 | 13 | * You should have received a copy of the GNU General Public License | ||
3097 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
3098 | 15 | */ | ||
3099 | 16 | |||
3100 | 17 | #include "Damper.h" | ||
3101 | 18 | #include <QDebug> | ||
3102 | 19 | |||
3103 | 20 | QDebug operator<<(QDebug dbg, const DampedPointF &p) | ||
3104 | 21 | { | ||
3105 | 22 | dbg.nospace() << "(" << p.x() << ", " << p.y() << ")"; | ||
3106 | 23 | return dbg.space(); | ||
3107 | 24 | } | ||
3108 | 25 | 0 | ||
3109 | === removed file 'plugins/Ubuntu/Gestures/Damper.h' | |||
3110 | --- plugins/Ubuntu/Gestures/Damper.h 2015-11-20 15:01:39 +0000 | |||
3111 | +++ plugins/Ubuntu/Gestures/Damper.h 1970-01-01 00:00:00 +0000 | |||
3112 | @@ -1,89 +0,0 @@ | |||
3113 | 1 | /* | ||
3114 | 2 | * Copyright (C) 2013 Canonical, Ltd. | ||
3115 | 3 | * | ||
3116 | 4 | * This program is free software; you can redistribute it and/or modify | ||
3117 | 5 | * it under the terms of the GNU General Public License as published by | ||
3118 | 6 | * the Free Software Foundation; version 3. | ||
3119 | 7 | * | ||
3120 | 8 | * This program is distributed in the hope that it will be useful, | ||
3121 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3122 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3123 | 11 | * GNU General Public License for more details. | ||
3124 | 12 | * | ||
3125 | 13 | * You should have received a copy of the GNU General Public License | ||
3126 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
3127 | 15 | */ | ||
3128 | 16 | |||
3129 | 17 | #ifndef UBUNTU_GESTURES_DAMPER_H | ||
3130 | 18 | #define UBUNTU_GESTURES_DAMPER_H | ||
3131 | 19 | |||
3132 | 20 | #include <QtCore/QPointF> | ||
3133 | 21 | |||
3134 | 22 | /* | ||
3135 | 23 | Decreases the oscillations of a value along an axis. | ||
3136 | 24 | */ | ||
3137 | 25 | template <class Type> class Damper { | ||
3138 | 26 | public: | ||
3139 | 27 | Damper() : m_value(0), m_maxDelta(0) { } | ||
3140 | 28 | |||
3141 | 29 | // Maximum delta between the raw value and its dampened counterpart. | ||
3142 | 30 | void setMaxDelta(Type maxDelta) { | ||
3143 | 31 | if (maxDelta < 0) qFatal("Damper::maxDelta must be a positive number."); | ||
3144 | 32 | m_maxDelta = maxDelta; | ||
3145 | 33 | } | ||
3146 | 34 | Type maxDelta() const { return m_maxDelta; } | ||
3147 | 35 | |||
3148 | 36 | void reset(Type value) { | ||
3149 | 37 | m_value = value; | ||
3150 | 38 | } | ||
3151 | 39 | |||
3152 | 40 | Type update(Type value) { | ||
3153 | 41 | Type delta = value - m_value; | ||
3154 | 42 | if (delta > 0 && delta > m_maxDelta) { | ||
3155 | 43 | m_value += delta - m_maxDelta; | ||
3156 | 44 | } else if (delta < 0 && delta < -m_maxDelta) { | ||
3157 | 45 | m_value += delta + m_maxDelta; | ||
3158 | 46 | } | ||
3159 | 47 | |||
3160 | 48 | return m_value; | ||
3161 | 49 | } | ||
3162 | 50 | |||
3163 | 51 | Type value() const { return m_value; } | ||
3164 | 52 | |||
3165 | 53 | private: | ||
3166 | 54 | Type m_value; | ||
3167 | 55 | Type m_maxDelta; | ||
3168 | 56 | }; | ||
3169 | 57 | |||
3170 | 58 | /* | ||
3171 | 59 | A point that has its movement dampened. | ||
3172 | 60 | */ | ||
3173 | 61 | class DampedPointF { | ||
3174 | 62 | public: | ||
3175 | 63 | void setMaxDelta(qreal maxDelta) { | ||
3176 | 64 | m_x.setMaxDelta(maxDelta); | ||
3177 | 65 | m_y.setMaxDelta(maxDelta); | ||
3178 | 66 | } | ||
3179 | 67 | |||
3180 | 68 | qreal maxDelta() const { return m_x.maxDelta(); } | ||
3181 | 69 | |||
3182 | 70 | void reset(const QPointF point) { | ||
3183 | 71 | m_x.reset(point.x()); | ||
3184 | 72 | m_y.reset(point.y()); | ||
3185 | 73 | } | ||
3186 | 74 | |||
3187 | 75 | void update(const QPointF point) { | ||
3188 | 76 | m_x.update(point.x()); | ||
3189 | 77 | m_y.update(point.y()); | ||
3190 | 78 | } | ||
3191 | 79 | |||
3192 | 80 | qreal x() const { return m_x.value(); } | ||
3193 | 81 | qreal y() const { return m_y.value(); } | ||
3194 | 82 | private: | ||
3195 | 83 | Damper<qreal> m_x; | ||
3196 | 84 | Damper<qreal> m_y; | ||
3197 | 85 | }; | ||
3198 | 86 | |||
3199 | 87 | QDebug operator<<(QDebug dbg, const DampedPointF &p); | ||
3200 | 88 | |||
3201 | 89 | #endif // UBUNTU_GESTURES_DAMPER_H | ||
3202 | 90 | 0 | ||
3203 | === modified file 'plugins/Ubuntu/Gestures/Direction.h' | |||
3204 | --- plugins/Ubuntu/Gestures/Direction.h 2015-04-17 14:21:43 +0000 | |||
3205 | +++ plugins/Ubuntu/Gestures/Direction.h 2016-06-01 16:58:47 +0000 | |||
3206 | @@ -29,6 +29,7 @@ | |||
3207 | 29 | Q_ENUMS(Type) | 29 | Q_ENUMS(Type) |
3208 | 30 | 30 | ||
3209 | 31 | public: | 31 | public: |
3210 | 32 | // Make sure it is kept synchronized with SDK UCSwipeArea::Direction | ||
3211 | 32 | enum Type { | 33 | enum Type { |
3212 | 33 | Rightwards, // Along the positive direction of the X axis | 34 | Rightwards, // Along the positive direction of the X axis |
3213 | 34 | Leftwards, // Along the negative direction of the X axis | 35 | Leftwards, // Along the negative direction of the X axis |
3214 | 35 | 36 | ||
3215 | === removed file 'plugins/Ubuntu/Gestures/DirectionalDragArea.cpp' | |||
3216 | --- plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 2016-03-29 03:47:39 +0000 | |||
3217 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 1970-01-01 00:00:00 +0000 | |||
3218 | @@ -1,932 +0,0 @@ | |||
3219 | 1 | /* | ||
3220 | 2 | * Copyright (C) 2013-2015 Canonical, Ltd. | ||
3221 | 3 | * | ||
3222 | 4 | * This program is free software; you can redistribute it and/or modify | ||
3223 | 5 | * it under the terms of the GNU General Public License as published by | ||
3224 | 6 | * the Free Software Foundation; version 3. | ||
3225 | 7 | * | ||
3226 | 8 | * This program is distributed in the hope that it will be useful, | ||
3227 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3228 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3229 | 11 | * GNU General Public License for more details. | ||
3230 | 12 | * | ||
3231 | 13 | * You should have received a copy of the GNU General Public License | ||
3232 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
3233 | 15 | */ | ||
3234 | 16 | |||
3235 | 17 | #define ACTIVETOUCHESINFO_DEBUG 0 | ||
3236 | 18 | #define DIRECTIONALDRAGAREA_DEBUG 0 | ||
3237 | 19 | |||
3238 | 20 | #include "DirectionalDragArea.h" | ||
3239 | 21 | |||
3240 | 22 | #include <QQuickWindow> | ||
3241 | 23 | #include <QtCore/qmath.h> | ||
3242 | 24 | #include <QScreen> | ||
3243 | 25 | #include <QDebug> | ||
3244 | 26 | |||
3245 | 27 | #pragma GCC diagnostic push | ||
3246 | 28 | #pragma GCC diagnostic ignored "-pedantic" | ||
3247 | 29 | #include <private/qquickwindow_p.h> | ||
3248 | 30 | #pragma GCC diagnostic pop | ||
3249 | 31 | |||
3250 | 32 | // local | ||
3251 | 33 | #include "TouchOwnershipEvent.h" | ||
3252 | 34 | #include "TouchRegistry.h" | ||
3253 | 35 | #include "UnownedTouchEvent.h" | ||
3254 | 36 | |||
3255 | 37 | #include "DirectionalDragArea_p.h" | ||
3256 | 38 | |||
3257 | 39 | using namespace UbuntuGestures; | ||
3258 | 40 | |||
3259 | 41 | #if DIRECTIONALDRAGAREA_DEBUG | ||
3260 | 42 | #define ddaDebug(params) qDebug().nospace() << "[DDA(" << qPrintable(objectName()) << ")] " << params | ||
3261 | 43 | #include "DebugHelpers.h" | ||
3262 | 44 | |||
3263 | 45 | namespace { | ||
3264 | 46 | const char *statusToString(DirectionalDragAreaPrivate::Status status) | ||
3265 | 47 | { | ||
3266 | 48 | if (status == DirectionalDragAreaPrivate::WaitingForTouch) { | ||
3267 | 49 | return "WaitingForTouch"; | ||
3268 | 50 | } else if (status == DirectionalDragAreaPrivate::Undecided) { | ||
3269 | 51 | return "Undecided"; | ||
3270 | 52 | } else { | ||
3271 | 53 | return "Recognized"; | ||
3272 | 54 | } | ||
3273 | 55 | } | ||
3274 | 56 | |||
3275 | 57 | } // namespace { | ||
3276 | 58 | #else // DIRECTIONALDRAGAREA_DEBUG | ||
3277 | 59 | #define ddaDebug(params) ((void)0) | ||
3278 | 60 | #endif // DIRECTIONALDRAGAREA_DEBUG | ||
3279 | 61 | |||
3280 | 62 | DirectionalDragArea::DirectionalDragArea(QQuickItem *parent) | ||
3281 | 63 | : QQuickItem(parent) | ||
3282 | 64 | , d(new DirectionalDragAreaPrivate(this)) | ||
3283 | 65 | { | ||
3284 | 66 | d->setRecognitionTimer(new Timer(this)); | ||
3285 | 67 | d->recognitionTimer->setInterval(d->maxTime); | ||
3286 | 68 | d->recognitionTimer->setSingleShot(true); | ||
3287 | 69 | |||
3288 | 70 | connect(this, &QQuickItem::enabledChanged, d, &DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible); | ||
3289 | 71 | connect(this, &QQuickItem::visibleChanged, d, &DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible); | ||
3290 | 72 | } | ||
3291 | 73 | |||
3292 | 74 | Direction::Type DirectionalDragArea::direction() const | ||
3293 | 75 | { | ||
3294 | 76 | return d->direction; | ||
3295 | 77 | } | ||
3296 | 78 | |||
3297 | 79 | void DirectionalDragArea::setDirection(Direction::Type direction) | ||
3298 | 80 | { | ||
3299 | 81 | if (direction != d->direction) { | ||
3300 | 82 | d->direction = direction; | ||
3301 | 83 | Q_EMIT directionChanged(d->direction); | ||
3302 | 84 | } | ||
3303 | 85 | } | ||
3304 | 86 | |||
3305 | 87 | void DirectionalDragAreaPrivate::setDistanceThreshold(qreal value) | ||
3306 | 88 | { | ||
3307 | 89 | if (distanceThreshold != value) { | ||
3308 | 90 | distanceThreshold = value; | ||
3309 | 91 | distanceThresholdSquared = distanceThreshold * distanceThreshold; | ||
3310 | 92 | } | ||
3311 | 93 | } | ||
3312 | 94 | |||
3313 | 95 | void DirectionalDragAreaPrivate::setMaxTime(int value) | ||
3314 | 96 | { | ||
3315 | 97 | if (maxTime != value) { | ||
3316 | 98 | maxTime = value; | ||
3317 | 99 | recognitionTimer->setInterval(maxTime); | ||
3318 | 100 | } | ||
3319 | 101 | } | ||
3320 | 102 | |||
3321 | 103 | void DirectionalDragAreaPrivate::setRecognitionTimer(UbuntuGestures::AbstractTimer *timer) | ||
3322 | 104 | { | ||
3323 | 105 | int interval = 0; | ||
3324 | 106 | bool timerWasRunning = false; | ||
3325 | 107 | bool wasSingleShot = false; | ||
3326 | 108 | |||
3327 | 109 | // can be null when called from the constructor | ||
3328 | 110 | if (recognitionTimer) { | ||
3329 | 111 | interval = recognitionTimer->interval(); | ||
3330 | 112 | timerWasRunning = recognitionTimer->isRunning(); | ||
3331 | 113 | if (recognitionTimer->parent() == this) { | ||
3332 | 114 | delete recognitionTimer; | ||
3333 | 115 | } | ||
3334 | 116 | } | ||
3335 | 117 | |||
3336 | 118 | recognitionTimer = timer; | ||
3337 | 119 | timer->setInterval(interval); | ||
3338 | 120 | timer->setSingleShot(wasSingleShot); | ||
3339 | 121 | connect(timer, &UbuntuGestures::AbstractTimer::timeout, | ||
3340 | 122 | this, &DirectionalDragAreaPrivate::rejectGesture); | ||
3341 | 123 | if (timerWasRunning) { | ||
3342 | 124 | recognitionTimer->start(); | ||
3343 | 125 | } | ||
3344 | 126 | } | ||
3345 | 127 | |||
3346 | 128 | void DirectionalDragAreaPrivate::setTimeSource(const SharedTimeSource &timeSource) | ||
3347 | 129 | { | ||
3348 | 130 | this->timeSource = timeSource; | ||
3349 | 131 | activeTouches.m_timeSource = timeSource; | ||
3350 | 132 | } | ||
3351 | 133 | |||
3352 | 134 | qreal DirectionalDragArea::distance() const | ||
3353 | 135 | { | ||
3354 | 136 | if (Direction::isHorizontal(d->direction)) { | ||
3355 | 137 | return d->publicPos.x() - d->startPos.x(); | ||
3356 | 138 | } else { | ||
3357 | 139 | return d->publicPos.y() - d->startPos.y(); | ||
3358 | 140 | } | ||
3359 | 141 | } | ||
3360 | 142 | |||
3361 | 143 | void DirectionalDragAreaPrivate::updateSceneDistance() | ||
3362 | 144 | { | ||
3363 | 145 | QPointF totalMovement = publicScenePos - startScenePos; | ||
3364 | 146 | sceneDistance = projectOntoDirectionVector(totalMovement); | ||
3365 | 147 | } | ||
3366 | 148 | |||
3367 | 149 | qreal DirectionalDragArea::sceneDistance() const | ||
3368 | 150 | { | ||
3369 | 151 | return d->sceneDistance; | ||
3370 | 152 | } | ||
3371 | 153 | |||
3372 | 154 | qreal DirectionalDragArea::touchX() const | ||
3373 | 155 | { | ||
3374 | 156 | return d->publicPos.x(); | ||
3375 | 157 | } | ||
3376 | 158 | |||
3377 | 159 | qreal DirectionalDragArea::touchY() const | ||
3378 | 160 | { | ||
3379 | 161 | return d->publicPos.y(); | ||
3380 | 162 | } | ||
3381 | 163 | |||
3382 | 164 | qreal DirectionalDragArea::touchSceneX() const | ||
3383 | 165 | { | ||
3384 | 166 | return d->publicScenePos.x(); | ||
3385 | 167 | } | ||
3386 | 168 | |||
3387 | 169 | qreal DirectionalDragArea::touchSceneY() const | ||
3388 | 170 | { | ||
3389 | 171 | return d->publicScenePos.y(); | ||
3390 | 172 | } | ||
3391 | 173 | |||
3392 | 174 | bool DirectionalDragArea::dragging() const | ||
3393 | 175 | { | ||
3394 | 176 | return d->status == DirectionalDragAreaPrivate::Recognized; | ||
3395 | 177 | } | ||
3396 | 178 | |||
3397 | 179 | bool DirectionalDragArea::pressed() const | ||
3398 | 180 | { | ||
3399 | 181 | return d->status != DirectionalDragAreaPrivate::WaitingForTouch; | ||
3400 | 182 | } | ||
3401 | 183 | |||
3402 | 184 | bool DirectionalDragArea::immediateRecognition() const | ||
3403 | 185 | { | ||
3404 | 186 | return d->immediateRecognition; | ||
3405 | 187 | } | ||
3406 | 188 | |||
3407 | 189 | void DirectionalDragArea::setImmediateRecognition(bool enabled) | ||
3408 | 190 | { | ||
3409 | 191 | if (d->immediateRecognition != enabled) { | ||
3410 | 192 | d->immediateRecognition = enabled; | ||
3411 | 193 | Q_EMIT immediateRecognitionChanged(enabled); | ||
3412 | 194 | } | ||
3413 | 195 | } | ||
3414 | 196 | |||
3415 | 197 | bool DirectionalDragArea::monitorOnly() const | ||
3416 | 198 | { | ||
3417 | 199 | return d->monitorOnly; | ||
3418 | 200 | } | ||
3419 | 201 | |||
3420 | 202 | void DirectionalDragArea::setMonitorOnly(bool monitorOnly) | ||
3421 | 203 | { | ||
3422 | 204 | if (d->monitorOnly != monitorOnly) { | ||
3423 | 205 | d->monitorOnly = monitorOnly; | ||
3424 | 206 | |||
3425 | 207 | if (monitorOnly && d->status == DirectionalDragAreaPrivate::Undecided) { | ||
3426 | 208 | TouchRegistry::instance()->removeCandidateOwnerForTouch(d->touchId, this); | ||
3427 | 209 | // We still wanna know when it ends for keeping the composition time window up-to-date | ||
3428 | 210 | TouchRegistry::instance()->addTouchWatcher(d->touchId, this); | ||
3429 | 211 | } | ||
3430 | 212 | |||
3431 | 213 | Q_EMIT monitorOnlyChanged(monitorOnly); | ||
3432 | 214 | } | ||
3433 | 215 | } | ||
3434 | 216 | |||
3435 | 217 | void DirectionalDragArea::removeTimeConstraints() | ||
3436 | 218 | { | ||
3437 | 219 | d->setMaxTime(60 * 60 * 1000); | ||
3438 | 220 | d->compositionTime = 0; | ||
3439 | 221 | ddaDebug("removed time constraints"); | ||
3440 | 222 | } | ||
3441 | 223 | |||
3442 | 224 | bool DirectionalDragArea::event(QEvent *event) | ||
3443 | 225 | { | ||
3444 | 226 | if (event->type() == TouchOwnershipEvent::touchOwnershipEventType()) { | ||
3445 | 227 | d->touchOwnershipEvent(static_cast<TouchOwnershipEvent *>(event)); | ||
3446 | 228 | return true; | ||
3447 | 229 | } else if (event->type() == UnownedTouchEvent::unownedTouchEventType()) { | ||
3448 | 230 | d->unownedTouchEvent(static_cast<UnownedTouchEvent *>(event)); | ||
3449 | 231 | return true; | ||
3450 | 232 | } else { | ||
3451 | 233 | return QQuickItem::event(event); | ||
3452 | 234 | } | ||
3453 | 235 | } | ||
3454 | 236 | |||
3455 | 237 | void DirectionalDragAreaPrivate::touchOwnershipEvent(TouchOwnershipEvent *event) | ||
3456 | 238 | { | ||
3457 | 239 | if (event->gained()) { | ||
3458 | 240 | QVector<int> ids; | ||
3459 | 241 | ids.append(event->touchId()); | ||
3460 | 242 | ddaDebug("grabbing touch"); | ||
3461 | 243 | q->grabTouchPoints(ids); | ||
3462 | 244 | |||
3463 | 245 | // Work around for Qt bug. If we grab a touch that is being used for mouse pointer | ||
3464 | 246 | // emulation it will cause the emulation logic to go nuts. | ||
3465 | 247 | // Thus we have to also grab the mouse in this case. | ||
3466 | 248 | // | ||
3467 | 249 | // The fix for this bug has landed in Qt 5.4 (https://codereview.qt-project.org/96887) | ||
3468 | 250 | // TODO: Remove this workaround once we start using Qt 5.4 | ||
3469 | 251 | if (q->window()) { | ||
3470 | 252 | QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(q->window()); | ||
3471 | 253 | if (windowPrivate->touchMouseId == event->touchId() && q->window()->mouseGrabberItem()) { | ||
3472 | 254 | ddaDebug("removing mouse grabber"); | ||
3473 | 255 | q->window()->mouseGrabberItem()->ungrabMouse(); | ||
3474 | 256 | } | ||
3475 | 257 | } | ||
3476 | 258 | } else { | ||
3477 | 259 | // We still wanna know when it ends for keeping the composition time window up-to-date | ||
3478 | 260 | TouchRegistry::instance()->addTouchWatcher(touchId, q); | ||
3479 | 261 | |||
3480 | 262 | setStatus(WaitingForTouch); | ||
3481 | 263 | } | ||
3482 | 264 | } | ||
3483 | 265 | |||
3484 | 266 | void DirectionalDragAreaPrivate::unownedTouchEvent(UnownedTouchEvent *unownedTouchEvent) | ||
3485 | 267 | { | ||
3486 | 268 | QTouchEvent *event = unownedTouchEvent->touchEvent(); | ||
3487 | 269 | |||
3488 | 270 | Q_ASSERT(!event->touchPointStates().testFlag(Qt::TouchPointPressed)); | ||
3489 | 271 | |||
3490 | 272 | ddaDebug("Unowned " << timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event))); | ||
3491 | 273 | |||
3492 | 274 | switch (status) { | ||
3493 | 275 | case WaitingForTouch: | ||
3494 | 276 | // do nothing | ||
3495 | 277 | break; | ||
3496 | 278 | case Undecided: | ||
3497 | 279 | Q_ASSERT(q->isEnabled() && q->isVisible()); | ||
3498 | 280 | unownedTouchEvent_undecided(unownedTouchEvent); | ||
3499 | 281 | break; | ||
3500 | 282 | default: // Recognized: | ||
3501 | 283 | if (monitorOnly) { | ||
3502 | 284 | // Treat unowned event as if we owned it, but we are really just watching it | ||
3503 | 285 | touchEvent_recognized(event); | ||
3504 | 286 | } | ||
3505 | 287 | break; | ||
3506 | 288 | } | ||
3507 | 289 | |||
3508 | 290 | activeTouches.update(event); | ||
3509 | 291 | } | ||
3510 | 292 | |||
3511 | 293 | void DirectionalDragAreaPrivate::unownedTouchEvent_undecided(UnownedTouchEvent *unownedTouchEvent) | ||
3512 | 294 | { | ||
3513 | 295 | const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(unownedTouchEvent->touchEvent()); | ||
3514 | 296 | if (!touchPoint) { | ||
3515 | 297 | qCritical() << "DirectionalDragArea[status=Undecided]: touch " << touchId | ||
3516 | 298 | << "missing from UnownedTouchEvent without first reaching state Qt::TouchPointReleased. " | ||
3517 | 299 | "Considering it as released."; | ||
3518 | 300 | |||
3519 | 301 | TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); | ||
3520 | 302 | setStatus(WaitingForTouch); | ||
3521 | 303 | return; | ||
3522 | 304 | } | ||
3523 | 305 | |||
3524 | 306 | const QPointF &touchScenePos = touchPoint->scenePos(); | ||
3525 | 307 | |||
3526 | 308 | if (touchPoint->state() == Qt::TouchPointReleased) { | ||
3527 | 309 | // touch has ended before recognition concluded | ||
3528 | 310 | ddaDebug("Touch has ended before recognition concluded"); | ||
3529 | 311 | TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); | ||
3530 | 312 | setStatus(WaitingForTouch); | ||
3531 | 313 | return; | ||
3532 | 314 | } | ||
3533 | 315 | |||
3534 | 316 | previousDampedScenePos.setX(dampedScenePos.x()); | ||
3535 | 317 | previousDampedScenePos.setY(dampedScenePos.y()); | ||
3536 | 318 | dampedScenePos.update(touchScenePos); | ||
3537 | 319 | |||
3538 | 320 | if (!movingInRightDirection()) { | ||
3539 | 321 | ddaDebug("Rejecting gesture because touch point is moving in the wrong direction."); | ||
3540 | 322 | TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); | ||
3541 | 323 | // We still wanna know when it ends for keeping the composition time window up-to-date | ||
3542 | 324 | TouchRegistry::instance()->addTouchWatcher(touchId, q); | ||
3543 | 325 | setStatus(WaitingForTouch); | ||
3544 | 326 | return; | ||
3545 | 327 | } | ||
3546 | 328 | |||
3547 | 329 | if (isWithinTouchCompositionWindow()) { | ||
3548 | 330 | // There's still time for some new touch to appear and ruin our party as it would be combined | ||
3549 | 331 | // with our touchId one and therefore deny the possibility of a single-finger gesture. | ||
3550 | 332 | ddaDebug("Sill within composition window. Let's wait more."); | ||
3551 | 333 | return; | ||
3552 | 334 | } | ||
3553 | 335 | |||
3554 | 336 | if (movedFarEnoughAlongGestureAxis()) { | ||
3555 | 337 | if (!monitorOnly) { | ||
3556 | 338 | TouchRegistry::instance()->requestTouchOwnership(touchId, q); | ||
3557 | 339 | } | ||
3558 | 340 | setStatus(Recognized); | ||
3559 | 341 | setPublicPos(touchPoint->pos()); | ||
3560 | 342 | setPublicScenePos(touchScenePos); | ||
3561 | 343 | } else if (isPastMaxDistance()) { | ||
3562 | 344 | ddaDebug("Rejecting gesture because it went farther than maxDistance without getting recognized."); | ||
3563 | 345 | TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); | ||
3564 | 346 | // We still wanna know when it ends for keeping the composition time window up-to-date | ||
3565 | 347 | TouchRegistry::instance()->addTouchWatcher(touchId, q); | ||
3566 | 348 | setStatus(WaitingForTouch); | ||
3567 | 349 | } else { | ||
3568 | 350 | ddaDebug("Didn't move far enough yet. Let's wait more."); | ||
3569 | 351 | } | ||
3570 | 352 | } | ||
3571 | 353 | |||
3572 | 354 | void DirectionalDragArea::touchEvent(QTouchEvent *event) | ||
3573 | 355 | { | ||
3574 | 356 | // TODO: Consider when more than one touch starts in the same event (although it's not possible | ||
3575 | 357 | // with Mir's android-input). Have to track them all. Consider it a plus/bonus. | ||
3576 | 358 | |||
3577 | 359 | ddaDebug(d->timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event))); | ||
3578 | 360 | |||
3579 | 361 | if (!isEnabled() || !isVisible()) { | ||
3580 | 362 | QQuickItem::touchEvent(event); | ||
3581 | 363 | return; | ||
3582 | 364 | } | ||
3583 | 365 | |||
3584 | 366 | switch (d->status) { | ||
3585 | 367 | case DirectionalDragAreaPrivate::WaitingForTouch: | ||
3586 | 368 | d->touchEvent_absent(event); | ||
3587 | 369 | break; | ||
3588 | 370 | case DirectionalDragAreaPrivate::Undecided: | ||
3589 | 371 | d->touchEvent_undecided(event); | ||
3590 | 372 | break; | ||
3591 | 373 | default: // Recognized: | ||
3592 | 374 | d->touchEvent_recognized(event); | ||
3593 | 375 | break; | ||
3594 | 376 | } | ||
3595 | 377 | |||
3596 | 378 | d->activeTouches.update(event); | ||
3597 | 379 | } | ||
3598 | 380 | |||
3599 | 381 | void DirectionalDragAreaPrivate::touchEvent_absent(QTouchEvent *event) | ||
3600 | 382 | { | ||
3601 | 383 | // TODO: accept/reject is for the whole event, not per touch id. See how that affects us. | ||
3602 | 384 | |||
3603 | 385 | if (!event->touchPointStates().testFlag(Qt::TouchPointPressed)) { | ||
3604 | 386 | // Nothing to see here. No touch starting in this event. | ||
3605 | 387 | return; | ||
3606 | 388 | } | ||
3607 | 389 | |||
3608 | 390 | // to be proven wrong, if that's the case | ||
3609 | 391 | bool allGood = true; | ||
3610 | 392 | |||
3611 | 393 | if (isWithinTouchCompositionWindow()) { | ||
3612 | 394 | // too close to the last touch start. So we consider them as starting roughly at the same time. | ||
3613 | 395 | // Can't be a single-touch gesture. | ||
3614 | 396 | ddaDebug("A new touch point came in but we're still within time composition window. Ignoring it."); | ||
3615 | 397 | allGood = false; | ||
3616 | 398 | } | ||
3617 | 399 | |||
3618 | 400 | const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints(); | ||
3619 | 401 | |||
3620 | 402 | const QTouchEvent::TouchPoint *newTouchPoint = nullptr; | ||
3621 | 403 | for (int i = 0; i < touchPoints.count() && allGood; ++i) { | ||
3622 | 404 | const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i); | ||
3623 | 405 | if (touchPoint.state() == Qt::TouchPointPressed) { | ||
3624 | 406 | if (newTouchPoint) { | ||
3625 | 407 | // more than one touch starting in this QTouchEvent. Can't be a single-touch gesture | ||
3626 | 408 | allGood = false; | ||
3627 | 409 | } else { | ||
3628 | 410 | // that's our candidate | ||
3629 | 411 | newTouchPoint = &touchPoint; | ||
3630 | 412 | } | ||
3631 | 413 | } | ||
3632 | 414 | } | ||
3633 | 415 | |||
3634 | 416 | if (allGood) { | ||
3635 | 417 | allGood = sanityCheckRecognitionProperties(); | ||
3636 | 418 | if (!allGood) { | ||
3637 | 419 | qWarning("DirectionalDragArea: recognition properties are wrongly set. Gesture recognition" | ||
3638 | 420 | " is impossible"); | ||
3639 | 421 | } | ||
3640 | 422 | } | ||
3641 | 423 | |||
3642 | 424 | if (allGood) { | ||
3643 | 425 | Q_ASSERT(newTouchPoint); | ||
3644 | 426 | |||
3645 | 427 | startPos = newTouchPoint->pos(); | ||
3646 | 428 | startScenePos = newTouchPoint->scenePos(); | ||
3647 | 429 | touchId = newTouchPoint->id(); | ||
3648 | 430 | dampedScenePos.reset(startScenePos); | ||
3649 | 431 | setPublicPos(startPos); | ||
3650 | 432 | |||
3651 | 433 | setPublicScenePos(startScenePos); | ||
3652 | 434 | updateSceneDirectionVector(); | ||
3653 | 435 | |||
3654 | 436 | if (recognitionIsDisabled()) { | ||
3655 | 437 | // Behave like a dumb TouchArea | ||
3656 | 438 | ddaDebug("Gesture recognition is disabled. Requesting touch ownership immediately."); | ||
3657 | 439 | setStatus(Recognized); | ||
3658 | 440 | if (monitorOnly) { | ||
3659 | 441 | watchPressedTouchPoints(touchPoints); | ||
3660 | 442 | event->ignore(); | ||
3661 | 443 | } else { | ||
3662 | 444 | TouchRegistry::instance()->requestTouchOwnership(touchId, q); | ||
3663 | 445 | event->accept(); | ||
3664 | 446 | } | ||
3665 | 447 | } else { | ||
3666 | 448 | // just monitor the touch points for now. | ||
3667 | 449 | if (monitorOnly) { | ||
3668 | 450 | watchPressedTouchPoints(touchPoints); | ||
3669 | 451 | } else { | ||
3670 | 452 | TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, q); | ||
3671 | 453 | } | ||
3672 | 454 | |||
3673 | 455 | setStatus(Undecided); | ||
3674 | 456 | // Let the item below have it. We will monitor it and grab it later if a gesture | ||
3675 | 457 | // gets recognized. | ||
3676 | 458 | event->ignore(); | ||
3677 | 459 | } | ||
3678 | 460 | } else { | ||
3679 | 461 | watchPressedTouchPoints(touchPoints); | ||
3680 | 462 | event->ignore(); | ||
3681 | 463 | } | ||
3682 | 464 | } | ||
3683 | 465 | |||
3684 | 466 | void DirectionalDragAreaPrivate::touchEvent_undecided(QTouchEvent *event) | ||
3685 | 467 | { | ||
3686 | 468 | Q_ASSERT(fetchTargetTouchPoint(event) == nullptr); | ||
3687 | 469 | |||
3688 | 470 | // We're not interested in new touch points. We already have our candidate (touchId). | ||
3689 | 471 | // But we do want to know when those new touches end for keeping the composition time | ||
3690 | 472 | // window up-to-date | ||
3691 | 473 | event->ignore(); | ||
3692 | 474 | watchPressedTouchPoints(event->touchPoints()); | ||
3693 | 475 | |||
3694 | 476 | if (event->touchPointStates().testFlag(Qt::TouchPointPressed) && isWithinTouchCompositionWindow()) { | ||
3695 | 477 | // multi-finger drags are not accepted | ||
3696 | 478 | ddaDebug("Multi-finger drags are not accepted"); | ||
3697 | 479 | |||
3698 | 480 | TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); | ||
3699 | 481 | // We still wanna know when it ends for keeping the composition time window up-to-date | ||
3700 | 482 | TouchRegistry::instance()->addTouchWatcher(touchId, q); | ||
3701 | 483 | |||
3702 | 484 | setStatus(WaitingForTouch); | ||
3703 | 485 | } | ||
3704 | 486 | } | ||
3705 | 487 | |||
3706 | 488 | void DirectionalDragAreaPrivate::touchEvent_recognized(QTouchEvent *event) | ||
3707 | 489 | { | ||
3708 | 490 | const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event); | ||
3709 | 491 | |||
3710 | 492 | if (!touchPoint) { | ||
3711 | 493 | qCritical() << "DirectionalDragArea[status=Recognized]: touch " << touchId | ||
3712 | 494 | << "missing from QTouchEvent without first reaching state Qt::TouchPointReleased. " | ||
3713 | 495 | "Considering it as released."; | ||
3714 | 496 | setStatus(WaitingForTouch); | ||
3715 | 497 | } else { | ||
3716 | 498 | setPublicPos(touchPoint->pos()); | ||
3717 | 499 | setPublicScenePos(touchPoint->scenePos()); | ||
3718 | 500 | |||
3719 | 501 | if (touchPoint->state() == Qt::TouchPointReleased) { | ||
3720 | 502 | setStatus(WaitingForTouch); | ||
3721 | 503 | } | ||
3722 | 504 | } | ||
3723 | 505 | } | ||
3724 | 506 | |||
3725 | 507 | void DirectionalDragAreaPrivate::watchPressedTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints) | ||
3726 | 508 | { | ||
3727 | 509 | for (int i = 0; i < touchPoints.count(); ++i) { | ||
3728 | 510 | const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i); | ||
3729 | 511 | if (touchPoint.state() == Qt::TouchPointPressed) { | ||
3730 | 512 | TouchRegistry::instance()->addTouchWatcher(touchPoint.id(), q); | ||
3731 | 513 | } | ||
3732 | 514 | } | ||
3733 | 515 | } | ||
3734 | 516 | |||
3735 | 517 | bool DirectionalDragAreaPrivate::recognitionIsDisabled() const | ||
3736 | 518 | { | ||
3737 | 519 | return immediateRecognition || (distanceThreshold <= 0 && compositionTime <= 0); | ||
3738 | 520 | } | ||
3739 | 521 | |||
3740 | 522 | bool DirectionalDragAreaPrivate::sanityCheckRecognitionProperties() | ||
3741 | 523 | { | ||
3742 | 524 | return recognitionIsDisabled() | ||
3743 | 525 | || (distanceThreshold < maxDistance && compositionTime < maxTime); | ||
3744 | 526 | } | ||
3745 | 527 | |||
3746 | 528 | const QTouchEvent::TouchPoint *DirectionalDragAreaPrivate::fetchTargetTouchPoint(QTouchEvent *event) | ||
3747 | 529 | { | ||
3748 | 530 | const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints(); | ||
3749 | 531 | const QTouchEvent::TouchPoint *touchPoint = 0; | ||
3750 | 532 | for (int i = 0; i < touchPoints.size(); ++i) { | ||
3751 | 533 | if (touchPoints.at(i).id() == touchId) { | ||
3752 | 534 | touchPoint = &touchPoints.at(i); | ||
3753 | 535 | break; | ||
3754 | 536 | } | ||
3755 | 537 | } | ||
3756 | 538 | return touchPoint; | ||
3757 | 539 | } | ||
3758 | 540 | |||
3759 | 541 | bool DirectionalDragAreaPrivate::movingInRightDirection() const | ||
3760 | 542 | { | ||
3761 | 543 | if (direction == Direction::Horizontal || direction == Direction::Vertical) { | ||
3762 | 544 | return true; | ||
3763 | 545 | } else { | ||
3764 | 546 | QPointF movementVector(dampedScenePos.x() - previousDampedScenePos.x(), | ||
3765 | 547 | dampedScenePos.y() - previousDampedScenePos.y()); | ||
3766 | 548 | |||
3767 | 549 | qreal scalarProjection = projectOntoDirectionVector(movementVector); | ||
3768 | 550 | |||
3769 | 551 | return scalarProjection >= 0.; | ||
3770 | 552 | } | ||
3771 | 553 | } | ||
3772 | 554 | |||
3773 | 555 | bool DirectionalDragAreaPrivate::movedFarEnoughAlongGestureAxis() const | ||
3774 | 556 | { | ||
3775 | 557 | if (distanceThreshold <= 0.) { | ||
3776 | 558 | // distance threshold check is disabled | ||
3777 | 559 | return true; | ||
3778 | 560 | } else { | ||
3779 | 561 | QPointF totalMovement(dampedScenePos.x() - startScenePos.x(), | ||
3780 | 562 | dampedScenePos.y() - startScenePos.y()); | ||
3781 | 563 | |||
3782 | 564 | qreal scalarProjection = projectOntoDirectionVector(totalMovement); | ||
3783 | 565 | |||
3784 | 566 | ddaDebug(" movedFarEnoughAlongGestureAxis: scalarProjection=" << scalarProjection | ||
3785 | 567 | << ", distanceThreshold=" << distanceThreshold); | ||
3786 | 568 | |||
3787 | 569 | if (direction == Direction::Horizontal || direction == Direction::Vertical) { | ||
3788 | 570 | return qAbs(scalarProjection) > distanceThreshold; | ||
3789 | 571 | } else { | ||
3790 | 572 | return scalarProjection > distanceThreshold; | ||
3791 | 573 | } | ||
3792 | 574 | } | ||
3793 | 575 | } | ||
3794 | 576 | |||
3795 | 577 | bool DirectionalDragAreaPrivate::isPastMaxDistance() const | ||
3796 | 578 | { | ||
3797 | 579 | QPointF totalMovement(dampedScenePos.x() - startScenePos.x(), | ||
3798 | 580 | dampedScenePos.y() - startScenePos.y()); | ||
3799 | 581 | |||
3800 | 582 | qreal squaredDistance = totalMovement.x()*totalMovement.x() + totalMovement.y()*totalMovement.y(); | ||
3801 | 583 | return squaredDistance > maxDistance*maxDistance; | ||
3802 | 584 | } | ||
3803 | 585 | |||
3804 | 586 | void DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible() | ||
3805 | 587 | { | ||
3806 | 588 | if (!q->isEnabled() || !q->isVisible()) { | ||
3807 | 589 | if (status == Undecided) { | ||
3808 | 590 | TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); | ||
3809 | 591 | // We still wanna know when it ends for keeping the composition time window up-to-date | ||
3810 | 592 | TouchRegistry::instance()->addTouchWatcher(touchId, q); | ||
3811 | 593 | } | ||
3812 | 594 | |||
3813 | 595 | if (status != WaitingForTouch) { | ||
3814 | 596 | ddaDebug("Resetting status because got disabled or made invisible"); | ||
3815 | 597 | setStatus(WaitingForTouch); | ||
3816 | 598 | } | ||
3817 | 599 | } | ||
3818 | 600 | } | ||
3819 | 601 | |||
3820 | 602 | void DirectionalDragAreaPrivate::rejectGesture() | ||
3821 | 603 | { | ||
3822 | 604 | if (status == Undecided) { | ||
3823 | 605 | ddaDebug("Rejecting gesture because it's taking too long to drag beyond the threshold."); | ||
3824 | 606 | |||
3825 | 607 | TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q); | ||
3826 | 608 | // We still wanna know when it ends for keeping the composition time window up-to-date | ||
3827 | 609 | TouchRegistry::instance()->addTouchWatcher(touchId, q); | ||
3828 | 610 | |||
3829 | 611 | setStatus(WaitingForTouch); | ||
3830 | 612 | } | ||
3831 | 613 | } | ||
3832 | 614 | |||
3833 | 615 | void DirectionalDragAreaPrivate::setStatus(Status newStatus) | ||
3834 | 616 | { | ||
3835 | 617 | if (newStatus == status) | ||
3836 | 618 | return; | ||
3837 | 619 | |||
3838 | 620 | Status oldStatus = status; | ||
3839 | 621 | |||
3840 | 622 | if (oldStatus == Undecided) { | ||
3841 | 623 | recognitionTimer->stop(); | ||
3842 | 624 | } | ||
3843 | 625 | |||
3844 | 626 | status = newStatus; | ||
3845 | 627 | Q_EMIT statusChanged(status); | ||
3846 | 628 | |||
3847 | 629 | ddaDebug(statusToString(oldStatus) << " -> " << statusToString(newStatus)); | ||
3848 | 630 | |||
3849 | 631 | switch (newStatus) { | ||
3850 | 632 | case WaitingForTouch: | ||
3851 | 633 | if (oldStatus == Recognized) { | ||
3852 | 634 | Q_EMIT q->draggingChanged(false); | ||
3853 | 635 | } | ||
3854 | 636 | Q_EMIT q->pressedChanged(false); | ||
3855 | 637 | break; | ||
3856 | 638 | case Undecided: | ||
3857 | 639 | recognitionTimer->start(); | ||
3858 | 640 | Q_EMIT q->pressedChanged(true); | ||
3859 | 641 | break; | ||
3860 | 642 | case Recognized: | ||
3861 | 643 | if (oldStatus == WaitingForTouch) { // for immediate recognition | ||
3862 | 644 | Q_EMIT q->pressedChanged(true); | ||
3863 | 645 | } | ||
3864 | 646 | Q_EMIT q->draggingChanged(true); | ||
3865 | 647 | break; | ||
3866 | 648 | default: | ||
3867 | 649 | // no-op | ||
3868 | 650 | break; | ||
3869 | 651 | } | ||
3870 | 652 | } | ||
3871 | 653 | |||
3872 | 654 | void DirectionalDragAreaPrivate::setPublicPos(const QPointF point) | ||
3873 | 655 | { | ||
3874 | 656 | bool xChanged = publicPos.x() != point.x(); | ||
3875 | 657 | bool yChanged = publicPos.y() != point.y(); | ||
3876 | 658 | |||
3877 | 659 | // Public position should not get updated while the gesture is still being recognized | ||
3878 | 660 | // (ie, Undecided status). | ||
3879 | 661 | Q_ASSERT(status == WaitingForTouch || status == Recognized); | ||
3880 | 662 | |||
3881 | 663 | if (status == Recognized && !recognitionIsDisabled()) { | ||
3882 | 664 | // When the gesture finally gets recognized, the finger will likely be | ||
3883 | 665 | // reasonably far from the edge. If we made the contentX immediately | ||
3884 | 666 | // follow the finger position it would be visually unpleasant as it | ||
3885 | 667 | // would appear right next to the user's finger out of nowhere (ie, | ||
3886 | 668 | // it would jump). Instead, we make contentX go towards the user's | ||
3887 | 669 | // finger in several steps. ie., in an animated way. | ||
3888 | 670 | QPointF delta = point - publicPos; | ||
3889 | 671 | // the trick is not to go all the way (1.0) as it would cause a sudden jump | ||
3890 | 672 | publicPos.rx() += 0.4 * delta.x(); | ||
3891 | 673 | publicPos.ry() += 0.4 * delta.y(); | ||
3892 | 674 | } else { | ||
3893 | 675 | // no smoothing when initializing or if gesture recognition was immediate as there will | ||
3894 | 676 | // be no jump. | ||
3895 | 677 | publicPos = point; | ||
3896 | 678 | } | ||
3897 | 679 | |||
3898 | 680 | if (xChanged) { | ||
3899 | 681 | Q_EMIT q->touchXChanged(publicPos.x()); | ||
3900 | 682 | if (Direction::isHorizontal(direction)) | ||
3901 | 683 | Q_EMIT q->distanceChanged(q->distance()); | ||
3902 | 684 | } | ||
3903 | 685 | |||
3904 | 686 | if (yChanged) { | ||
3905 | 687 | Q_EMIT q->touchYChanged(publicPos.y()); | ||
3906 | 688 | if (Direction::isVertical(direction)) | ||
3907 | 689 | Q_EMIT q->distanceChanged(q->distance()); | ||
3908 | 690 | } | ||
3909 | 691 | } | ||
3910 | 692 | |||
3911 | 693 | void DirectionalDragAreaPrivate::setPublicScenePos(const QPointF point) | ||
3912 | 694 | { | ||
3913 | 695 | bool xChanged = publicScenePos.x() != point.x(); | ||
3914 | 696 | bool yChanged = publicScenePos.y() != point.y(); | ||
3915 | 697 | |||
3916 | 698 | if (!xChanged && !yChanged) | ||
3917 | 699 | return; | ||
3918 | 700 | |||
3919 | 701 | // Public position should not get updated while the gesture is still being recognized | ||
3920 | 702 | // (ie, Undecided status). | ||
3921 | 703 | Q_ASSERT(status == WaitingForTouch || status == Recognized); | ||
3922 | 704 | |||
3923 | 705 | qreal oldSceneDistance = sceneDistance; | ||
3924 | 706 | |||
3925 | 707 | if (status == Recognized && !recognitionIsDisabled()) { | ||
3926 | 708 | // When the gesture finally gets recognized, the finger will likely be | ||
3927 | 709 | // reasonably far from the edge. If we made the contentX immediately | ||
3928 | 710 | // follow the finger position it would be visually unpleasant as it | ||
3929 | 711 | // would appear right next to the user's finger out of nowhere (ie, | ||
3930 | 712 | // it would jump). Instead, we make contentX go towards the user's | ||
3931 | 713 | // finger in several steps. ie., in an animated way. | ||
3932 | 714 | QPointF delta = point - publicScenePos; | ||
3933 | 715 | // the trick is not to go all the way (1.0) as it would cause a sudden jump | ||
3934 | 716 | publicScenePos.rx() += 0.4 * delta.x(); | ||
3935 | 717 | publicScenePos.ry() += 0.4 * delta.y(); | ||
3936 | 718 | } else { | ||
3937 | 719 | // no smoothing when initializing or if gesture recognition was immediate as there will | ||
3938 | 720 | // be no jump. | ||
3939 | 721 | publicScenePos = point; | ||
3940 | 722 | } | ||
3941 | 723 | |||
3942 | 724 | updateSceneDistance(); | ||
3943 | 725 | |||
3944 | 726 | if (oldSceneDistance != sceneDistance) { | ||
3945 | 727 | Q_EMIT q->sceneDistanceChanged(sceneDistance); | ||
3946 | 728 | } | ||
3947 | 729 | |||
3948 | 730 | if (xChanged) { | ||
3949 | 731 | Q_EMIT q->touchSceneXChanged(publicScenePos.x()); | ||
3950 | 732 | } | ||
3951 | 733 | |||
3952 | 734 | if (yChanged) { | ||
3953 | 735 | Q_EMIT q->touchSceneYChanged(publicScenePos.y()); | ||
3954 | 736 | } | ||
3955 | 737 | } | ||
3956 | 738 | |||
3957 | 739 | bool DirectionalDragAreaPrivate::isWithinTouchCompositionWindow() | ||
3958 | 740 | { | ||
3959 | 741 | return | ||
3960 | 742 | compositionTime > 0 && | ||
3961 | 743 | !activeTouches.isEmpty() && | ||
3962 | 744 | timeSource->msecsSinceReference() <= | ||
3963 | 745 | activeTouches.mostRecentStartTime() + (qint64)compositionTime; | ||
3964 | 746 | } | ||
3965 | 747 | |||
3966 | 748 | void DirectionalDragArea::itemChange(ItemChange change, const ItemChangeData &value) | ||
3967 | 749 | { | ||
3968 | 750 | if (change == QQuickItem::ItemSceneChange) { | ||
3969 | 751 | if (value.window != nullptr) { | ||
3970 | 752 | value.window->installEventFilter(TouchRegistry::instance()); | ||
3971 | 753 | |||
3972 | 754 | // TODO: Handle window->screen() changes (ie window changing screens) | ||
3973 | 755 | |||
3974 | 756 | qreal pixelsPerInch = value.window->screen()->physicalDotsPerInch(); | ||
3975 | 757 | if (pixelsPerInch < 0) { | ||
3976 | 758 | // It can return garbage when run in a XVFB server (Virtual Framebuffer 'fake' X server) | ||
3977 | 759 | pixelsPerInch = 72; | ||
3978 | 760 | } | ||
3979 | 761 | |||
3980 | 762 | d->setPixelsPerMm(pixelsPerInch / 25.4); | ||
3981 | 763 | } | ||
3982 | 764 | } | ||
3983 | 765 | } | ||
3984 | 766 | |||
3985 | 767 | void DirectionalDragAreaPrivate::setPixelsPerMm(qreal pixelsPerMm) | ||
3986 | 768 | { | ||
3987 | 769 | dampedScenePos.setMaxDelta(1. * pixelsPerMm); | ||
3988 | 770 | setDistanceThreshold(4. * pixelsPerMm); | ||
3989 | 771 | maxDistance = 10. * pixelsPerMm; | ||
3990 | 772 | } | ||
3991 | 773 | |||
3992 | 774 | //************************** ActiveTouchesInfo ************************** | ||
3993 | 775 | |||
3994 | 776 | ActiveTouchesInfo::ActiveTouchesInfo(const SharedTimeSource &timeSource) | ||
3995 | 777 | : m_timeSource(timeSource) | ||
3996 | 778 | { | ||
3997 | 779 | } | ||
3998 | 780 | |||
3999 | 781 | void ActiveTouchesInfo::update(QTouchEvent *event) | ||
4000 | 782 | { | ||
4001 | 783 | if (!(event->touchPointStates() & (Qt::TouchPointPressed | Qt::TouchPointReleased))) { | ||
4002 | 784 | // nothing to update | ||
4003 | 785 | #if ACTIVETOUCHESINFO_DEBUG | ||
4004 | 786 | qDebug("[DDA::ActiveTouchesInfo] Nothing to Update"); | ||
4005 | 787 | #endif | ||
4006 | 788 | return; | ||
4007 | 789 | } | ||
4008 | 790 | |||
4009 | 791 | const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints(); | ||
4010 | 792 | for (int i = 0; i < touchPoints.count(); ++i) { | ||
4011 | 793 | const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i); | ||
4012 | 794 | if (touchPoint.state() == Qt::TouchPointPressed) { | ||
4013 | 795 | addTouchPoint(touchPoint.id()); | ||
4014 | 796 | } else if (touchPoint.state() == Qt::TouchPointReleased) { | ||
4015 | 797 | removeTouchPoint(touchPoint.id()); | ||
4016 | 798 | } | ||
4017 | 799 | } | ||
4018 | 800 | } | ||
4019 | 801 | |||
4020 | 802 | #if ACTIVETOUCHESINFO_DEBUG | ||
4021 | 803 | QString ActiveTouchesInfo::toString() | ||
4022 | 804 | { | ||
4023 | 805 | QString string = "("; | ||
4024 | 806 | |||
4025 | 807 | { | ||
4026 | 808 | QTextStream stream(&string); | ||
4027 | 809 | m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &touchInfo) { | ||
4028 | 810 | stream << "(id=" << touchInfo->id << ",startTime=" << touchInfo->startTime << ")"; | ||
4029 | 811 | return true; | ||
4030 | 812 | }); | ||
4031 | 813 | } | ||
4032 | 814 | |||
4033 | 815 | string.append(")"); | ||
4034 | 816 | |||
4035 | 817 | return string; | ||
4036 | 818 | } | ||
4037 | 819 | #endif // ACTIVETOUCHESINFO_DEBUG | ||
4038 | 820 | |||
4039 | 821 | void ActiveTouchesInfo::addTouchPoint(int touchId) | ||
4040 | 822 | { | ||
4041 | 823 | ActiveTouchInfo &activeTouchInfo = m_touchInfoPool.getEmptySlot(); | ||
4042 | 824 | activeTouchInfo.id = touchId; | ||
4043 | 825 | activeTouchInfo.startTime = m_timeSource->msecsSinceReference(); | ||
4044 | 826 | |||
4045 | 827 | #if ACTIVETOUCHESINFO_DEBUG | ||
4046 | 828 | qDebug() << "[DDA::ActiveTouchesInfo]" << qPrintable(toString()); | ||
4047 | 829 | #endif | ||
4048 | 830 | } | ||
4049 | 831 | |||
4050 | 832 | qint64 ActiveTouchesInfo::touchStartTime(int touchId) | ||
4051 | 833 | { | ||
4052 | 834 | qint64 result = -1; | ||
4053 | 835 | |||
4054 | 836 | m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &touchInfo) { | ||
4055 | 837 | if (touchId == touchInfo->id) { | ||
4056 | 838 | result = touchInfo->startTime; | ||
4057 | 839 | return false; | ||
4058 | 840 | } else { | ||
4059 | 841 | return true; | ||
4060 | 842 | } | ||
4061 | 843 | }); | ||
4062 | 844 | |||
4063 | 845 | Q_ASSERT(result != -1); | ||
4064 | 846 | return result; | ||
4065 | 847 | } | ||
4066 | 848 | |||
4067 | 849 | void ActiveTouchesInfo::removeTouchPoint(int touchId) | ||
4068 | 850 | { | ||
4069 | 851 | m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &touchInfo) { | ||
4070 | 852 | if (touchId == touchInfo->id) { | ||
4071 | 853 | m_touchInfoPool.freeSlot(touchInfo); | ||
4072 | 854 | return false; | ||
4073 | 855 | } else { | ||
4074 | 856 | return true; | ||
4075 | 857 | } | ||
4076 | 858 | }); | ||
4077 | 859 | |||
4078 | 860 | #if ACTIVETOUCHESINFO_DEBUG | ||
4079 | 861 | qDebug() << "[DDA::ActiveTouchesInfo]" << qPrintable(toString()); | ||
4080 | 862 | #endif | ||
4081 | 863 | } | ||
4082 | 864 | |||
4083 | 865 | qint64 ActiveTouchesInfo::mostRecentStartTime() | ||
4084 | 866 | { | ||
4085 | 867 | Q_ASSERT(!m_touchInfoPool.isEmpty()); | ||
4086 | 868 | |||
4087 | 869 | qint64 highestStartTime = -1; | ||
4088 | 870 | |||
4089 | 871 | m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &activeTouchInfo) { | ||
4090 | 872 | if (activeTouchInfo->startTime > highestStartTime) { | ||
4091 | 873 | highestStartTime = activeTouchInfo->startTime; | ||
4092 | 874 | } | ||
4093 | 875 | return true; | ||
4094 | 876 | }); | ||
4095 | 877 | |||
4096 | 878 | return highestStartTime; | ||
4097 | 879 | } | ||
4098 | 880 | |||
4099 | 881 | void DirectionalDragAreaPrivate::updateSceneDirectionVector() | ||
4100 | 882 | { | ||
4101 | 883 | QPointF localOrigin(0., 0.); | ||
4102 | 884 | QPointF localDirection; | ||
4103 | 885 | switch (direction) { | ||
4104 | 886 | case Direction::Upwards: | ||
4105 | 887 | localDirection.rx() = 0.; | ||
4106 | 888 | localDirection.ry() = -1.; | ||
4107 | 889 | break; | ||
4108 | 890 | case Direction::Downwards: | ||
4109 | 891 | case Direction::Vertical: | ||
4110 | 892 | localDirection.rx() = 0.; | ||
4111 | 893 | localDirection.ry() = 1; | ||
4112 | 894 | break; | ||
4113 | 895 | case Direction::Leftwards: | ||
4114 | 896 | localDirection.rx() = -1.; | ||
4115 | 897 | localDirection.ry() = 0.; | ||
4116 | 898 | break; | ||
4117 | 899 | default: // Direction::Rightwards || Direction.Horizontal | ||
4118 | 900 | localDirection.rx() = 1.; | ||
4119 | 901 | localDirection.ry() = 0.; | ||
4120 | 902 | break; | ||
4121 | 903 | } | ||
4122 | 904 | QPointF sceneOrigin = q->mapToScene(localOrigin); | ||
4123 | 905 | QPointF sceneDirection = q->mapToScene(localDirection); | ||
4124 | 906 | sceneDirectionVector = sceneDirection - sceneOrigin; | ||
4125 | 907 | } | ||
4126 | 908 | |||
4127 | 909 | qreal DirectionalDragAreaPrivate::projectOntoDirectionVector(const QPointF sceneVector) const | ||
4128 | 910 | { | ||
4129 | 911 | // same as dot product as sceneDirectionVector is a unit vector | ||
4130 | 912 | return sceneVector.x() * sceneDirectionVector.x() + | ||
4131 | 913 | sceneVector.y() * sceneDirectionVector.y(); | ||
4132 | 914 | } | ||
4133 | 915 | |||
4134 | 916 | DirectionalDragAreaPrivate::DirectionalDragAreaPrivate(DirectionalDragArea *q) | ||
4135 | 917 | : q(q) | ||
4136 | 918 | , status(WaitingForTouch) | ||
4137 | 919 | , sceneDistance(0) | ||
4138 | 920 | , touchId(-1) | ||
4139 | 921 | , direction(Direction::Rightwards) | ||
4140 | 922 | , distanceThreshold(0) | ||
4141 | 923 | , distanceThresholdSquared(0.) | ||
4142 | 924 | , maxTime(400) | ||
4143 | 925 | , compositionTime(60) | ||
4144 | 926 | , immediateRecognition(false) | ||
4145 | 927 | , recognitionTimer(nullptr) | ||
4146 | 928 | , timeSource(new RealTimeSource) | ||
4147 | 929 | , activeTouches(timeSource) | ||
4148 | 930 | , monitorOnly(false) | ||
4149 | 931 | { | ||
4150 | 932 | } | ||
4151 | 933 | 0 | ||
4152 | === removed file 'plugins/Ubuntu/Gestures/DirectionalDragArea.h' | |||
4153 | --- plugins/Ubuntu/Gestures/DirectionalDragArea.h 2016-03-29 03:47:39 +0000 | |||
4154 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea.h 1970-01-01 00:00:00 +0000 | |||
4155 | @@ -1,143 +0,0 @@ | |||
4156 | 1 | /* | ||
4157 | 2 | * Copyright (C) 2013,2014 Canonical, Ltd. | ||
4158 | 3 | * | ||
4159 | 4 | * This program is free software; you can redistribute it and/or modify | ||
4160 | 5 | * it under the terms of the GNU General Public License as published by | ||
4161 | 6 | * the Free Software Foundation; version 3. | ||
4162 | 7 | * | ||
4163 | 8 | * This program is distributed in the hope that it will be useful, | ||
4164 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
4165 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
4166 | 11 | * GNU General Public License for more details. | ||
4167 | 12 | * | ||
4168 | 13 | * You should have received a copy of the GNU General Public License | ||
4169 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
4170 | 15 | */ | ||
4171 | 16 | |||
4172 | 17 | #ifndef DIRECTIONAL_DRAG_AREA_H | ||
4173 | 18 | #define DIRECTIONAL_DRAG_AREA_H | ||
4174 | 19 | |||
4175 | 20 | #include <QtQuick/QQuickItem> | ||
4176 | 21 | #include "UbuntuGesturesQmlGlobal.h" | ||
4177 | 22 | #include "Damper.h" | ||
4178 | 23 | #include "Direction.h" | ||
4179 | 24 | |||
4180 | 25 | // lib UbuntuGestures | ||
4181 | 26 | #include <Pool.h> | ||
4182 | 27 | #include <Timer.h> | ||
4183 | 28 | |||
4184 | 29 | class TouchOwnershipEvent; | ||
4185 | 30 | class UnownedTouchEvent; | ||
4186 | 31 | class DirectionalDragAreaPrivate; | ||
4187 | 32 | |||
4188 | 33 | /* | ||
4189 | 34 | An area that detects axis-aligned single-finger drag gestures | ||
4190 | 35 | |||
4191 | 36 | If a drag deviates too much from the components' direction recognition will | ||
4192 | 37 | fail. It will also fail if the drag or flick is too short. E.g. a noisy or | ||
4193 | 38 | fidgety click | ||
4194 | 39 | |||
4195 | 40 | See doc/DirectionalDragArea.svg | ||
4196 | 41 | */ | ||
4197 | 42 | class UBUNTUGESTURESQML_EXPORT DirectionalDragArea : public QQuickItem { | ||
4198 | 43 | Q_OBJECT | ||
4199 | 44 | |||
4200 | 45 | // The direction in which the gesture should move in order to be recognized. | ||
4201 | 46 | Q_PROPERTY(Direction::Type direction READ direction WRITE setDirection NOTIFY directionChanged) | ||
4202 | 47 | |||
4203 | 48 | // The distance travelled by the finger along the axis specified by | ||
4204 | 49 | // DirectionalDragArea's direction. | ||
4205 | 50 | Q_PROPERTY(qreal distance READ distance NOTIFY distanceChanged) | ||
4206 | 51 | |||
4207 | 52 | // The distance travelled by the finger along the axis specified by | ||
4208 | 53 | // DirectionalDragArea's direction in scene coordinates | ||
4209 | 54 | Q_PROPERTY(qreal sceneDistance READ sceneDistance NOTIFY sceneDistanceChanged) | ||
4210 | 55 | |||
4211 | 56 | // Position of the touch point performing the drag relative to this item. | ||
4212 | 57 | Q_PROPERTY(qreal touchX READ touchX NOTIFY touchXChanged) | ||
4213 | 58 | Q_PROPERTY(qreal touchY READ touchY NOTIFY touchYChanged) | ||
4214 | 59 | |||
4215 | 60 | // Position of the touch point performing the drag, in scene's coordinate system | ||
4216 | 61 | Q_PROPERTY(qreal touchSceneX READ touchSceneX NOTIFY touchSceneXChanged) | ||
4217 | 62 | Q_PROPERTY(qreal touchSceneY READ touchSceneY NOTIFY touchSceneYChanged) | ||
4218 | 63 | |||
4219 | 64 | // Whether a drag gesture is taking place | ||
4220 | 65 | Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged) | ||
4221 | 66 | |||
4222 | 67 | // Whether the drag area is pressed. | ||
4223 | 68 | Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged) | ||
4224 | 69 | |||
4225 | 70 | // Whether a gesture should be Recognized as soon a touch lands on the area. | ||
4226 | 71 | // With this property enabled it will work pretty much like a MultiPointTouchArea, | ||
4227 | 72 | // just with a different API. | ||
4228 | 73 | // | ||
4229 | 74 | // It's false by default. In most cases you will not want that enabled. | ||
4230 | 75 | Q_PROPERTY(bool immediateRecognition | ||
4231 | 76 | READ immediateRecognition | ||
4232 | 77 | WRITE setImmediateRecognition | ||
4233 | 78 | NOTIFY immediateRecognitionChanged) | ||
4234 | 79 | |||
4235 | 80 | // Whether we are merely monitoring touch events (in which case, we don't | ||
4236 | 81 | // claim ownership of the touch). | ||
4237 | 82 | Q_PROPERTY(bool monitorOnly READ monitorOnly WRITE setMonitorOnly NOTIFY monitorOnlyChanged) | ||
4238 | 83 | |||
4239 | 84 | Q_ENUMS(Direction) | ||
4240 | 85 | public: | ||
4241 | 86 | DirectionalDragArea(QQuickItem *parent = 0); | ||
4242 | 87 | |||
4243 | 88 | Direction::Type direction() const; | ||
4244 | 89 | void setDirection(Direction::Type); | ||
4245 | 90 | |||
4246 | 91 | qreal distance() const; | ||
4247 | 92 | qreal sceneDistance() const; | ||
4248 | 93 | |||
4249 | 94 | qreal touchX() const; | ||
4250 | 95 | qreal touchY() const; | ||
4251 | 96 | |||
4252 | 97 | qreal touchSceneX() const; | ||
4253 | 98 | qreal touchSceneY() const; | ||
4254 | 99 | |||
4255 | 100 | bool dragging() const; | ||
4256 | 101 | |||
4257 | 102 | bool pressed() const; | ||
4258 | 103 | |||
4259 | 104 | bool immediateRecognition() const; | ||
4260 | 105 | void setImmediateRecognition(bool enabled); | ||
4261 | 106 | |||
4262 | 107 | bool monitorOnly() const; | ||
4263 | 108 | void setMonitorOnly(bool monitorOnly); | ||
4264 | 109 | |||
4265 | 110 | bool event(QEvent *e) override; | ||
4266 | 111 | |||
4267 | 112 | /* | ||
4268 | 113 | In qmltests, sequences of touch events are sent all at once, unlike in "real life". | ||
4269 | 114 | Also qmltests might run really slowly, e.g. when run from inside virtual machines. | ||
4270 | 115 | Thus to remove a variable that qmltests cannot really control, namely time, this | ||
4271 | 116 | function removes all constraints that are sensible to elapsed time. | ||
4272 | 117 | |||
4273 | 118 | This effectively makes the DirectionalDragArea easier to fool. | ||
4274 | 119 | */ | ||
4275 | 120 | Q_INVOKABLE void removeTimeConstraints(); | ||
4276 | 121 | |||
4277 | 122 | Q_SIGNALS: | ||
4278 | 123 | void directionChanged(Direction::Type direction); | ||
4279 | 124 | void draggingChanged(bool value); | ||
4280 | 125 | void pressedChanged(bool value); | ||
4281 | 126 | void distanceChanged(qreal value); | ||
4282 | 127 | void sceneDistanceChanged(qreal value); | ||
4283 | 128 | void touchXChanged(qreal value); | ||
4284 | 129 | void touchYChanged(qreal value); | ||
4285 | 130 | void touchSceneXChanged(qreal value); | ||
4286 | 131 | void touchSceneYChanged(qreal value); | ||
4287 | 132 | void immediateRecognitionChanged(bool value); | ||
4288 | 133 | void monitorOnlyChanged(bool value); | ||
4289 | 134 | |||
4290 | 135 | protected: | ||
4291 | 136 | void touchEvent(QTouchEvent *event) override; | ||
4292 | 137 | void itemChange(ItemChange change, const ItemChangeData &value) override; | ||
4293 | 138 | |||
4294 | 139 | public: // so tests can access it | ||
4295 | 140 | DirectionalDragAreaPrivate *d; | ||
4296 | 141 | }; | ||
4297 | 142 | |||
4298 | 143 | #endif // DIRECTIONAL_DRAG_AREA_H | ||
4299 | 144 | 0 | ||
4300 | === removed file 'plugins/Ubuntu/Gestures/DirectionalDragArea_p.h' | |||
4301 | --- plugins/Ubuntu/Gestures/DirectionalDragArea_p.h 2016-03-29 03:47:39 +0000 | |||
4302 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea_p.h 1970-01-01 00:00:00 +0000 | |||
4303 | @@ -1,169 +0,0 @@ | |||
4304 | 1 | /* | ||
4305 | 2 | * Copyright (C) 2015 Canonical, Ltd. | ||
4306 | 3 | * | ||
4307 | 4 | * This program is free software; you can redistribute it and/or modify | ||
4308 | 5 | * it under the terms of the GNU General Public License as published by | ||
4309 | 6 | * the Free Software Foundation; version 3. | ||
4310 | 7 | * | ||
4311 | 8 | * This program is distributed in the hope that it will be useful, | ||
4312 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
4313 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
4314 | 11 | * GNU General Public License for more details. | ||
4315 | 12 | * | ||
4316 | 13 | * You should have received a copy of the GNU General Public License | ||
4317 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
4318 | 15 | */ | ||
4319 | 16 | |||
4320 | 17 | #ifndef DIRECTIONAL_DRAG_AREA_PRIV_H | ||
4321 | 18 | #define DIRECTIONAL_DRAG_AREA_PRIV_H | ||
4322 | 19 | |||
4323 | 20 | // Information about an active touch point | ||
4324 | 21 | struct UBUNTUGESTURESQML_EXPORT ActiveTouchInfo { | ||
4325 | 22 | ActiveTouchInfo() : id(-1), startTime(-1) {} | ||
4326 | 23 | bool isValid() const { return id != -1; } | ||
4327 | 24 | void reset() { id = -1; } | ||
4328 | 25 | int id; | ||
4329 | 26 | qint64 startTime; | ||
4330 | 27 | }; | ||
4331 | 28 | class UBUNTUGESTURESQML_EXPORT ActiveTouchesInfo { | ||
4332 | 29 | public: | ||
4333 | 30 | ActiveTouchesInfo(const UbuntuGestures::SharedTimeSource &timeSource); | ||
4334 | 31 | void update(QTouchEvent *event); | ||
4335 | 32 | qint64 touchStartTime(int id); | ||
4336 | 33 | bool isEmpty() const { return m_touchInfoPool.isEmpty(); } | ||
4337 | 34 | qint64 mostRecentStartTime(); | ||
4338 | 35 | UbuntuGestures::SharedTimeSource m_timeSource; | ||
4339 | 36 | private: | ||
4340 | 37 | void addTouchPoint(int touchId); | ||
4341 | 38 | void removeTouchPoint(int touchId); | ||
4342 | 39 | #if ACTIVETOUCHESINFO_DEBUG | ||
4343 | 40 | QString toString(); | ||
4344 | 41 | #endif | ||
4345 | 42 | |||
4346 | 43 | Pool<ActiveTouchInfo> m_touchInfoPool; | ||
4347 | 44 | }; | ||
4348 | 45 | |||
4349 | 46 | class UBUNTUGESTURESQML_EXPORT DirectionalDragAreaPrivate : public QObject { | ||
4350 | 47 | Q_OBJECT | ||
4351 | 48 | |||
4352 | 49 | Q_ENUMS(Status) | ||
4353 | 50 | public: | ||
4354 | 51 | DirectionalDragAreaPrivate(DirectionalDragArea *q); | ||
4355 | 52 | |||
4356 | 53 | public Q_SLOTS: | ||
4357 | 54 | void giveUpIfDisabledOrInvisible(); | ||
4358 | 55 | void rejectGesture(); | ||
4359 | 56 | |||
4360 | 57 | public: | ||
4361 | 58 | // Describes the state of the directional drag gesture. | ||
4362 | 59 | enum Status { | ||
4363 | 60 | // Waiting for a new touch point to land on this area. No gesture is being processed | ||
4364 | 61 | // or tracked. | ||
4365 | 62 | WaitingForTouch, | ||
4366 | 63 | |||
4367 | 64 | // A touch point has landed on this area but it's not know yet whether it is | ||
4368 | 65 | // performing a drag in the correct direction. | ||
4369 | 66 | // If it's decided that the touch point is not performing a directional drag gesture, | ||
4370 | 67 | // it will be rejected/ignored and status will return to WaitingForTouch. | ||
4371 | 68 | Undecided, //Recognizing, | ||
4372 | 69 | |||
4373 | 70 | // There's a touch point in this area and it performed a drag in the correct | ||
4374 | 71 | // direction. | ||
4375 | 72 | // | ||
4376 | 73 | // Once recognized, the gesture state will move back to WaitingForTouch only once | ||
4377 | 74 | // that touch point ends. The gesture will remain in the Recognized state even if | ||
4378 | 75 | // the touch point starts moving in other directions or halts. | ||
4379 | 76 | Recognized, | ||
4380 | 77 | }; | ||
4381 | 78 | |||
4382 | 79 | void touchEvent_absent(QTouchEvent *event); | ||
4383 | 80 | void touchEvent_undecided(QTouchEvent *event); | ||
4384 | 81 | void touchEvent_recognized(QTouchEvent *event); | ||
4385 | 82 | bool movingInRightDirection() const; | ||
4386 | 83 | bool movedFarEnoughAlongGestureAxis() const; | ||
4387 | 84 | bool isPastMaxDistance() const; | ||
4388 | 85 | const QTouchEvent::TouchPoint *fetchTargetTouchPoint(QTouchEvent *event); | ||
4389 | 86 | void setStatus(Status newStatus); | ||
4390 | 87 | void setPublicPos(const QPointF point); | ||
4391 | 88 | void setPublicScenePos(const QPointF point); | ||
4392 | 89 | bool isWithinTouchCompositionWindow(); | ||
4393 | 90 | void updateSceneDirectionVector(); | ||
4394 | 91 | // returns the scalar projection between the given vector (in scene coordinates) | ||
4395 | 92 | // and m_sceneDirectionVector | ||
4396 | 93 | qreal projectOntoDirectionVector(const QPointF sceneVector) const; | ||
4397 | 94 | void touchOwnershipEvent(TouchOwnershipEvent *event); | ||
4398 | 95 | void unownedTouchEvent(UnownedTouchEvent *event); | ||
4399 | 96 | void unownedTouchEvent_undecided(UnownedTouchEvent *unownedTouchEvent); | ||
4400 | 97 | void watchPressedTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints); | ||
4401 | 98 | bool recognitionIsDisabled() const; | ||
4402 | 99 | bool sanityCheckRecognitionProperties(); | ||
4403 | 100 | void updateSceneDistance(); | ||
4404 | 101 | void setMaxTime(int value); | ||
4405 | 102 | void setDistanceThreshold(qreal value); | ||
4406 | 103 | void setPixelsPerMm(qreal pixelsPerMm); | ||
4407 | 104 | QString objectName() const { return q->objectName(); } | ||
4408 | 105 | |||
4409 | 106 | // Replaces the existing Timer with the given one. | ||
4410 | 107 | // | ||
4411 | 108 | // Useful for providing a fake timer when testing. | ||
4412 | 109 | void setRecognitionTimer(UbuntuGestures::AbstractTimer *timer); | ||
4413 | 110 | |||
4414 | 111 | // Useful for testing, where a fake time source can be supplied | ||
4415 | 112 | void setTimeSource(const UbuntuGestures::SharedTimeSource &timeSource); | ||
4416 | 113 | |||
4417 | 114 | DirectionalDragArea *q; | ||
4418 | 115 | |||
4419 | 116 | // The current status of the directional drag gesture area. | ||
4420 | 117 | Status status; | ||
4421 | 118 | |||
4422 | 119 | QPointF startPos; | ||
4423 | 120 | QPointF startScenePos; | ||
4424 | 121 | qreal sceneDistance; | ||
4425 | 122 | int touchId; | ||
4426 | 123 | |||
4427 | 124 | // The touch position exposed in the public API. | ||
4428 | 125 | // It only starts to move once the gesture gets recognized. | ||
4429 | 126 | QPointF publicPos; | ||
4430 | 127 | QPointF publicScenePos; | ||
4431 | 128 | |||
4432 | 129 | // A movement damper is used in some of the gesture recognition calculations | ||
4433 | 130 | // to get rid of noise or small oscillations in the touch position. | ||
4434 | 131 | DampedPointF dampedScenePos; | ||
4435 | 132 | QPointF previousDampedScenePos; | ||
4436 | 133 | |||
4437 | 134 | // Unit vector in scene coordinates describing the direction of the gesture recognition | ||
4438 | 135 | QPointF sceneDirectionVector; | ||
4439 | 136 | |||
4440 | 137 | Direction::Type direction; | ||
4441 | 138 | |||
4442 | 139 | // How far a touch point has to move from its initial position along the gesture axis in order | ||
4443 | 140 | // for it to be recognized as a directional drag. | ||
4444 | 141 | qreal distanceThreshold; | ||
4445 | 142 | qreal distanceThresholdSquared; // it's pow(distanceThreshold, 2) | ||
4446 | 143 | |||
4447 | 144 | // Maximum time (in milliseconds) the gesture can take to go beyond the distance threshold | ||
4448 | 145 | int maxTime; | ||
4449 | 146 | |||
4450 | 147 | // Maximum distance the gesture can go without crossing the axis-aligned distance threshold | ||
4451 | 148 | qreal maxDistance; | ||
4452 | 149 | |||
4453 | 150 | // Maximum time (in milliseconds) after the start of a given touch point where | ||
4454 | 151 | // subsequent touch starts are grouped with the first one into an N-touches gesture | ||
4455 | 152 | // (e.g. a two-fingers tap or drag). | ||
4456 | 153 | int compositionTime; | ||
4457 | 154 | |||
4458 | 155 | bool immediateRecognition; | ||
4459 | 156 | |||
4460 | 157 | UbuntuGestures::AbstractTimer *recognitionTimer; | ||
4461 | 158 | |||
4462 | 159 | UbuntuGestures::SharedTimeSource timeSource; | ||
4463 | 160 | |||
4464 | 161 | ActiveTouchesInfo activeTouches; | ||
4465 | 162 | |||
4466 | 163 | bool monitorOnly; | ||
4467 | 164 | |||
4468 | 165 | Q_SIGNALS: | ||
4469 | 166 | void statusChanged(Status value); | ||
4470 | 167 | }; | ||
4471 | 168 | |||
4472 | 169 | #endif // DIRECTIONAL_DRAG_AREA_PRIV_H | ||
4473 | 170 | 0 | ||
4474 | === modified file 'plugins/Ubuntu/Gestures/Gestures.qmltypes' | |||
4475 | --- plugins/Ubuntu/Gestures/Gestures.qmltypes 2016-03-29 03:47:39 +0000 | |||
4476 | +++ plugins/Ubuntu/Gestures/Gestures.qmltypes 2016-06-01 16:58:47 +0000 | |||
4477 | @@ -55,88 +55,6 @@ | |||
4478 | 55 | } | 55 | } |
4479 | 56 | } | 56 | } |
4480 | 57 | Component { | 57 | Component { |
4481 | 58 | name: "DirectionalDragArea" | ||
4482 | 59 | defaultProperty: "data" | ||
4483 | 60 | prototype: "QQuickItem" | ||
4484 | 61 | exports: ["Ubuntu.Gestures/DirectionalDragArea 0.1"] | ||
4485 | 62 | exportMetaObjectRevisions: [0] | ||
4486 | 63 | Property { name: "direction"; type: "Direction::Type" } | ||
4487 | 64 | Property { name: "distance"; type: "double"; isReadonly: true } | ||
4488 | 65 | Property { name: "sceneDistance"; type: "double"; isReadonly: true } | ||
4489 | 66 | Property { name: "touchX"; type: "double"; isReadonly: true } | ||
4490 | 67 | Property { name: "touchY"; type: "double"; isReadonly: true } | ||
4491 | 68 | Property { name: "touchSceneX"; type: "double"; isReadonly: true } | ||
4492 | 69 | Property { name: "touchSceneY"; type: "double"; isReadonly: true } | ||
4493 | 70 | Property { name: "dragging"; type: "bool"; isReadonly: true } | ||
4494 | 71 | Property { name: "pressed"; type: "bool"; isReadonly: true } | ||
4495 | 72 | Property { name: "immediateRecognition"; type: "bool" } | ||
4496 | 73 | Signal { | ||
4497 | 74 | name: "directionChanged" | ||
4498 | 75 | Parameter { name: "direction"; type: "Direction::Type" } | ||
4499 | 76 | } | ||
4500 | 77 | Signal { | ||
4501 | 78 | name: "draggingChanged" | ||
4502 | 79 | Parameter { name: "value"; type: "bool" } | ||
4503 | 80 | } | ||
4504 | 81 | Signal { | ||
4505 | 82 | name: "pressedChanged" | ||
4506 | 83 | Parameter { name: "value"; type: "bool" } | ||
4507 | 84 | } | ||
4508 | 85 | Signal { | ||
4509 | 86 | name: "distanceChanged" | ||
4510 | 87 | Parameter { name: "value"; type: "double" } | ||
4511 | 88 | } | ||
4512 | 89 | Signal { | ||
4513 | 90 | name: "sceneDistanceChanged" | ||
4514 | 91 | Parameter { name: "value"; type: "double" } | ||
4515 | 92 | } | ||
4516 | 93 | Signal { | ||
4517 | 94 | name: "touchXChanged" | ||
4518 | 95 | Parameter { name: "value"; type: "double" } | ||
4519 | 96 | } | ||
4520 | 97 | Signal { | ||
4521 | 98 | name: "touchYChanged" | ||
4522 | 99 | Parameter { name: "value"; type: "double" } | ||
4523 | 100 | } | ||
4524 | 101 | Signal { | ||
4525 | 102 | name: "touchSceneXChanged" | ||
4526 | 103 | Parameter { name: "value"; type: "double" } | ||
4527 | 104 | } | ||
4528 | 105 | Signal { | ||
4529 | 106 | name: "touchSceneYChanged" | ||
4530 | 107 | Parameter { name: "value"; type: "double" } | ||
4531 | 108 | } | ||
4532 | 109 | Signal { | ||
4533 | 110 | name: "immediateRecognitionChanged" | ||
4534 | 111 | Parameter { name: "value"; type: "bool" } | ||
4535 | 112 | } | ||
4536 | 113 | Method { name: "removeTimeConstraints" } | ||
4537 | 114 | } | ||
4538 | 115 | Component { | ||
4539 | 116 | name: "FloatingFlickable" | ||
4540 | 117 | defaultProperty: "data" | ||
4541 | 118 | prototype: "QQuickItem" | ||
4542 | 119 | exports: ["Ubuntu.Gestures/FloatingFlickable 0.1"] | ||
4543 | 120 | exportMetaObjectRevisions: [0] | ||
4544 | 121 | Property { name: "contentWidth"; type: "double" } | ||
4545 | 122 | Property { name: "contentHeight"; type: "double" } | ||
4546 | 123 | Property { name: "contentX"; type: "double" } | ||
4547 | 124 | Property { name: "contentY"; type: "double" } | ||
4548 | 125 | Property { name: "direction"; type: "Direction::Type" } | ||
4549 | 126 | } | ||
4550 | 127 | Component { | ||
4551 | 128 | name: "GestureTouchPoint" | ||
4552 | 129 | prototype: "QObject" | ||
4553 | 130 | exports: ["Ubuntu.Gestures/GestureTouchPoint 0.1"] | ||
4554 | 131 | isCreatable: false | ||
4555 | 132 | exportMetaObjectRevisions: [0] | ||
4556 | 133 | Property { name: "pointId"; type: "int"; isReadonly: true } | ||
4557 | 134 | Property { name: "pressed"; type: "bool"; isReadonly: true } | ||
4558 | 135 | Property { name: "x"; type: "double"; isReadonly: true } | ||
4559 | 136 | Property { name: "y"; type: "double"; isReadonly: true } | ||
4560 | 137 | Property { name: "dragging"; type: "bool"; isReadonly: true } | ||
4561 | 138 | } | ||
4562 | 139 | Component { | ||
4563 | 140 | name: "PressedOutsideNotifier" | 58 | name: "PressedOutsideNotifier" |
4564 | 141 | defaultProperty: "data" | 59 | defaultProperty: "data" |
4565 | 142 | prototype: "QQuickItem" | 60 | prototype: "QQuickItem" |
4566 | @@ -156,54 +74,4 @@ | |||
4567 | 156 | Parameter { name: "item"; type: "QQuickItem"; isPointer: true } | 74 | Parameter { name: "item"; type: "QQuickItem"; isPointer: true } |
4568 | 157 | } | 75 | } |
4569 | 158 | } | 76 | } |
4570 | 159 | Component { | ||
4571 | 160 | name: "TouchGestureArea" | ||
4572 | 161 | defaultProperty: "data" | ||
4573 | 162 | prototype: "QQuickItem" | ||
4574 | 163 | exports: ["Ubuntu.Gestures/TouchGestureArea 0.1"] | ||
4575 | 164 | exportMetaObjectRevisions: [0] | ||
4576 | 165 | Enum { | ||
4577 | 166 | name: "Status" | ||
4578 | 167 | values: { | ||
4579 | 168 | "WaitingForTouch": 0, | ||
4580 | 169 | "Undecided": 1, | ||
4581 | 170 | "Recognized": 2, | ||
4582 | 171 | "Rejected": 3 | ||
4583 | 172 | } | ||
4584 | 173 | } | ||
4585 | 174 | Property { name: "touchPoints"; type: "GestureTouchPoint"; isList: true; isReadonly: true } | ||
4586 | 175 | Property { name: "dragging"; type: "bool"; isReadonly: true } | ||
4587 | 176 | Property { name: "minimumTouchPoints"; type: "int" } | ||
4588 | 177 | Property { name: "maximumTouchPoints"; type: "int" } | ||
4589 | 178 | Signal { | ||
4590 | 179 | name: "statusChanged" | ||
4591 | 180 | Parameter { name: "status"; type: "Status" } | ||
4592 | 181 | } | ||
4593 | 182 | Signal { name: "touchPointsUpdated" } | ||
4594 | 183 | Signal { | ||
4595 | 184 | name: "draggingChanged" | ||
4596 | 185 | Parameter { name: "dragging"; type: "bool" } | ||
4597 | 186 | } | ||
4598 | 187 | Signal { | ||
4599 | 188 | name: "minimumTouchPointsChanged" | ||
4600 | 189 | Parameter { name: "value"; type: "bool" } | ||
4601 | 190 | } | ||
4602 | 191 | Signal { | ||
4603 | 192 | name: "maximumTouchPointsChanged" | ||
4604 | 193 | Parameter { name: "value"; type: "bool" } | ||
4605 | 194 | } | ||
4606 | 195 | Signal { | ||
4607 | 196 | name: "pressed" | ||
4608 | 197 | Parameter { name: "points"; type: "QList<QObject*>" } | ||
4609 | 198 | } | ||
4610 | 199 | Signal { | ||
4611 | 200 | name: "released" | ||
4612 | 201 | Parameter { name: "points"; type: "QList<QObject*>" } | ||
4613 | 202 | } | ||
4614 | 203 | Signal { | ||
4615 | 204 | name: "updated" | ||
4616 | 205 | Parameter { name: "points"; type: "QList<QObject*>" } | ||
4617 | 206 | } | ||
4618 | 207 | Signal { name: "clicked" } | ||
4619 | 208 | } | ||
4620 | 209 | } | 77 | } |
4621 | 210 | 78 | ||
4622 | === renamed file 'plugins/Ubuntu/Gestures/FloatingFlickable.cpp' => 'plugins/Ubuntu/Gestures/MouseEventGenerator.cpp' | |||
4623 | --- plugins/Ubuntu/Gestures/FloatingFlickable.cpp 2015-05-27 09:37:34 +0000 | |||
4624 | +++ plugins/Ubuntu/Gestures/MouseEventGenerator.cpp 2016-06-01 16:58:47 +0000 | |||
4625 | @@ -1,5 +1,5 @@ | |||
4626 | 1 | /* | 1 | /* |
4628 | 2 | * Copyright (C) 2015 Canonical, Ltd. | 2 | * Copyright (C) 2015-2016 Canonical, Ltd. |
4629 | 3 | * | 3 | * |
4630 | 4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
4631 | 5 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
4632 | @@ -14,137 +14,51 @@ | |||
4633 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4634 | 15 | */ | 15 | */ |
4635 | 16 | 16 | ||
4769 | 17 | #include "FloatingFlickable.h" | 17 | #include "MouseEventGenerator.h" |
4770 | 18 | 18 | ||
4771 | 19 | #include <private/qquickflickable_p.h> | 19 | #include <QCoreApplication> |
4772 | 20 | #include "DirectionalDragArea.h" | 20 | #include <QMouseEvent> |
4773 | 21 | 21 | #include <QQuickItem> | |
4774 | 22 | #include <QDebug> | 22 | |
4775 | 23 | 23 | MouseEventGenerator::MouseEventGenerator(QObject *parent) | |
4776 | 24 | FloatingFlickable::FloatingFlickable(QQuickItem *parent) | 24 | : QObject(parent) |
4777 | 25 | : QQuickItem(parent) | 25 | { |
4778 | 26 | , m_mousePressed(false) | 26 | } |
4779 | 27 | { | 27 | |
4780 | 28 | m_dragArea = new DirectionalDragArea(this); | 28 | void MouseEventGenerator::move(const QPointF position) |
4781 | 29 | m_dragArea->setWidth(width()); | 29 | { |
4782 | 30 | m_dragArea->setHeight(height()); | 30 | if (!m_mousePressed || !m_targetItem) { |
4783 | 31 | m_dragArea->setDirection(Direction::Horizontal); | 31 | return; |
4784 | 32 | connect(m_dragArea, &DirectionalDragArea::touchXChanged, | 32 | } |
4785 | 33 | this, &FloatingFlickable::onDragAreaTouchPosChanged); | 33 | |
4786 | 34 | connect(m_dragArea, &DirectionalDragArea::touchYChanged, | 34 | QMouseEvent mouseEvent(QEvent::MouseMove, |
4787 | 35 | this, &FloatingFlickable::onDragAreaTouchPosChanged); | 35 | QPointF(position.x(), position.y()), Qt::NoButton, Qt::LeftButton, Qt::NoModifier); |
4788 | 36 | connect(m_dragArea, &DirectionalDragArea::draggingChanged, | 36 | |
4789 | 37 | this, &FloatingFlickable::onDragAreaDraggingChanged); | 37 | QCoreApplication::sendEvent(m_targetItem, &mouseEvent); |
4790 | 38 | connect(m_dragArea, &DirectionalDragArea::directionChanged, this, &FloatingFlickable::directionChanged); | 38 | } |
4791 | 39 | 39 | ||
4792 | 40 | m_flickable = new QQuickFlickable(this); | 40 | void MouseEventGenerator::press(const QPointF position) |
4793 | 41 | m_flickable->setEnabled(false); | 41 | { |
4794 | 42 | m_flickable->setWidth(width()); | 42 | if (m_mousePressed || !m_targetItem) { |
4795 | 43 | m_flickable->setHeight(height()); | 43 | return; |
4796 | 44 | connect(m_flickable, &QQuickFlickable::contentWidthChanged, this, &FloatingFlickable::contentWidthChanged); | 44 | } |
4797 | 45 | connect(m_flickable, &QQuickFlickable::contentHeightChanged, this, &FloatingFlickable::contentHeightChanged); | 45 | |
4798 | 46 | connect(m_flickable, &QQuickFlickable::contentXChanged, this, &FloatingFlickable::contentXChanged); | 46 | QMouseEvent mouseEvent(QEvent::MouseButtonPress, |
4799 | 47 | connect(m_flickable, &QQuickFlickable::contentYChanged, this, &FloatingFlickable::contentYChanged); | 47 | QPointF(position.x(), position.y()), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); |
4800 | 48 | 48 | ||
4801 | 49 | connect(this, &QQuickItem::widthChanged, this, &FloatingFlickable::updateChildrenWidth); | 49 | QCoreApplication::sendEvent(m_targetItem, &mouseEvent); |
4802 | 50 | connect(this, &QQuickItem::heightChanged, this, &FloatingFlickable::updateChildrenHeight); | 50 | m_mousePressed = true; |
4803 | 51 | } | 51 | } |
4804 | 52 | 52 | ||
4805 | 53 | qreal FloatingFlickable::contentWidth() const | 53 | void MouseEventGenerator::release(const QPointF position) |
4806 | 54 | { | 54 | { |
4807 | 55 | return m_flickable->contentWidth(); | 55 | if (!m_mousePressed || !m_targetItem) { |
4808 | 56 | } | 56 | return; |
4809 | 57 | 57 | } | |
4810 | 58 | void FloatingFlickable::setContentWidth(qreal contentWidth) | 58 | |
4811 | 59 | { | 59 | QMouseEvent mouseEvent(QEvent::MouseButtonRelease, |
4812 | 60 | m_flickable->setContentWidth(contentWidth); | 60 | QPointF(position.x(), position.y()), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); |
4813 | 61 | } | 61 | |
4814 | 62 | 62 | QCoreApplication::sendEvent(m_targetItem, &mouseEvent); | |
4815 | 63 | qreal FloatingFlickable::contentHeight() const | 63 | m_mousePressed = false; |
4683 | 64 | { | ||
4684 | 65 | return m_flickable->contentHeight(); | ||
4685 | 66 | } | ||
4686 | 67 | |||
4687 | 68 | void FloatingFlickable::setContentHeight(qreal contentHeight) | ||
4688 | 69 | { | ||
4689 | 70 | m_flickable->setContentHeight(contentHeight); | ||
4690 | 71 | } | ||
4691 | 72 | |||
4692 | 73 | qreal FloatingFlickable::contentX() const | ||
4693 | 74 | { | ||
4694 | 75 | return m_flickable->contentX(); | ||
4695 | 76 | } | ||
4696 | 77 | |||
4697 | 78 | void FloatingFlickable::setContentX(qreal contentX) | ||
4698 | 79 | { | ||
4699 | 80 | m_flickable->setContentX(contentX); | ||
4700 | 81 | } | ||
4701 | 82 | |||
4702 | 83 | qreal FloatingFlickable::contentY() const | ||
4703 | 84 | { | ||
4704 | 85 | return m_flickable->contentY(); | ||
4705 | 86 | } | ||
4706 | 87 | |||
4707 | 88 | void FloatingFlickable::setContentY(qreal contentY) | ||
4708 | 89 | { | ||
4709 | 90 | m_flickable->setContentY(contentY); | ||
4710 | 91 | } | ||
4711 | 92 | |||
4712 | 93 | Direction::Type FloatingFlickable::direction() const | ||
4713 | 94 | { | ||
4714 | 95 | return m_dragArea->direction(); | ||
4715 | 96 | } | ||
4716 | 97 | |||
4717 | 98 | void FloatingFlickable::setDirection(Direction::Type direction) | ||
4718 | 99 | { | ||
4719 | 100 | m_dragArea->setDirection(direction); | ||
4720 | 101 | if (Direction::isHorizontal(direction)) { | ||
4721 | 102 | m_flickable->setFlickableDirection(QQuickFlickable::HorizontalFlick); | ||
4722 | 103 | } else { | ||
4723 | 104 | m_flickable->setFlickableDirection(QQuickFlickable::VerticalFlick); | ||
4724 | 105 | } | ||
4725 | 106 | } | ||
4726 | 107 | |||
4727 | 108 | void FloatingFlickable::updateChildrenWidth() | ||
4728 | 109 | { | ||
4729 | 110 | m_dragArea->setWidth(width()); | ||
4730 | 111 | m_flickable->setWidth(width()); | ||
4731 | 112 | } | ||
4732 | 113 | |||
4733 | 114 | void FloatingFlickable::updateChildrenHeight() | ||
4734 | 115 | { | ||
4735 | 116 | m_dragArea->setHeight(height()); | ||
4736 | 117 | m_flickable->setHeight(height()); | ||
4737 | 118 | } | ||
4738 | 119 | |||
4739 | 120 | void FloatingFlickable::onDragAreaTouchPosChanged(qreal) | ||
4740 | 121 | { | ||
4741 | 122 | if (m_mousePressed) { | ||
4742 | 123 | QMouseEvent mouseEvent(QEvent::MouseMove, | ||
4743 | 124 | QPointF(m_dragArea->touchX(),m_dragArea->touchY()), | ||
4744 | 125 | Qt::NoButton, Qt::LeftButton, Qt::NoModifier); | ||
4745 | 126 | |||
4746 | 127 | QCoreApplication::sendEvent(m_flickable, &mouseEvent); | ||
4747 | 128 | |||
4748 | 129 | } | ||
4749 | 130 | } | ||
4750 | 131 | |||
4751 | 132 | void FloatingFlickable::onDragAreaDraggingChanged(bool dragging) | ||
4752 | 133 | { | ||
4753 | 134 | if (dragging && !m_mousePressed) { | ||
4754 | 135 | QMouseEvent mouseEvent(QEvent::MouseButtonPress, | ||
4755 | 136 | QPointF(m_dragArea->touchX(),m_dragArea->touchY()), | ||
4756 | 137 | Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); | ||
4757 | 138 | |||
4758 | 139 | QCoreApplication::sendEvent(m_flickable, &mouseEvent); | ||
4759 | 140 | m_mousePressed = true; | ||
4760 | 141 | |||
4761 | 142 | } else if (!dragging && m_mousePressed) { | ||
4762 | 143 | QMouseEvent mouseEvent(QEvent::MouseButtonRelease, | ||
4763 | 144 | QPointF(m_dragArea->touchX(),m_dragArea->touchY()), | ||
4764 | 145 | Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); | ||
4765 | 146 | |||
4766 | 147 | QCoreApplication::sendEvent(m_flickable, &mouseEvent); | ||
4767 | 148 | m_mousePressed = false; | ||
4768 | 149 | } | ||
4816 | 150 | } | 64 | } |
4817 | 151 | 65 | ||
4818 | === renamed file 'plugins/Ubuntu/Gestures/FloatingFlickable.h' => 'plugins/Ubuntu/Gestures/MouseEventGenerator.h' | |||
4819 | --- plugins/Ubuntu/Gestures/FloatingFlickable.h 2015-05-27 09:37:34 +0000 | |||
4820 | +++ plugins/Ubuntu/Gestures/MouseEventGenerator.h 2016-06-01 16:58:47 +0000 | |||
4821 | @@ -1,5 +1,5 @@ | |||
4822 | 1 | /* | 1 | /* |
4824 | 2 | * Copyright (C) 2015 Canonical, Ltd. | 2 | * Copyright (C) 2015-2016 Canonical, Ltd. |
4825 | 3 | * | 3 | * |
4826 | 4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
4827 | 5 | * it under the terms of the GNU General Public License as published by | 5 | * it under the terms of the GNU General Public License as published by |
4828 | @@ -14,73 +14,35 @@ | |||
4829 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
4830 | 15 | */ | 15 | */ |
4831 | 16 | 16 | ||
4836 | 17 | #ifndef FLOATING_FLICKABLE_H | 17 | #ifndef MOUSEEVENTGENERATOR_H |
4837 | 18 | #define FLOATING_FLICKABLE_H | 18 | #define MOUSEEVENTGENERATOR_H |
4838 | 19 | 19 | ||
4839 | 20 | #include <QQuickItem> | 20 | #include <QObject> |
4840 | 21 | #include <QPointF> | ||
4841 | 22 | |||
4842 | 21 | #include "UbuntuGesturesQmlGlobal.h" | 23 | #include "UbuntuGesturesQmlGlobal.h" |
4859 | 22 | #include "Direction.h" | 24 | |
4860 | 23 | 25 | class QQuickItem; | |
4861 | 24 | class DirectionalDragArea; | 26 | |
4862 | 25 | class QQuickFlickable; | 27 | class UBUNTUGESTURESQML_EXPORT MouseEventGenerator : public QObject { |
4847 | 26 | |||
4848 | 27 | /* | ||
4849 | 28 | A Flickable that can be put in front of the item to be flicked and | ||
4850 | 29 | still have the item-to-be-flicked receive input events that are not flicks. | ||
4851 | 30 | |||
4852 | 31 | Ie, it's a Flickable that, input-wise, is transparent to non-flick gestures. | ||
4853 | 32 | |||
4854 | 33 | With a regular Flickable you would have to make the item-to-be-flicked a child | ||
4855 | 34 | of Flicakble to achieve the same result. FloatingFlickable has no such requirement | ||
4856 | 35 | or limitation. | ||
4857 | 36 | */ | ||
4858 | 37 | class UBUNTUGESTURESQML_EXPORT FloatingFlickable : public QQuickItem { | ||
4863 | 38 | Q_OBJECT | 28 | Q_OBJECT |
4871 | 39 | 29 | Q_PROPERTY(QQuickItem* targetItem MEMBER m_targetItem NOTIFY targetItemChanged) | |
4872 | 40 | Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged) | 30 | |
4873 | 41 | Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged) | 31 | public: |
4874 | 42 | Q_PROPERTY(qreal contentX READ contentX WRITE setContentX NOTIFY contentXChanged) | 32 | MouseEventGenerator(QObject *parent = nullptr); |
4875 | 43 | Q_PROPERTY(qreal contentY READ contentY WRITE setContentY NOTIFY contentYChanged) | 33 | |
4876 | 44 | 34 | Q_INVOKABLE void move(const QPointF position); | |
4877 | 45 | Q_PROPERTY(Direction::Type direction READ direction WRITE setDirection NOTIFY directionChanged) | 35 | Q_INVOKABLE void press(const QPointF position); |
4878 | 36 | Q_INVOKABLE void release(const QPointF position); | ||
4879 | 46 | 37 | ||
4880 | 47 | Q_SIGNALS: | 38 | Q_SIGNALS: |
4910 | 48 | void contentWidthChanged(); | 39 | void targetItemChanged(QQuickItem *); |
4882 | 49 | void contentHeightChanged(); | ||
4883 | 50 | void contentXChanged(); | ||
4884 | 51 | void contentYChanged(); | ||
4885 | 52 | void directionChanged(); | ||
4886 | 53 | |||
4887 | 54 | public: | ||
4888 | 55 | FloatingFlickable(QQuickItem *parent = nullptr); | ||
4889 | 56 | |||
4890 | 57 | qreal contentWidth() const; | ||
4891 | 58 | void setContentWidth(qreal contentWidth); | ||
4892 | 59 | |||
4893 | 60 | qreal contentHeight() const; | ||
4894 | 61 | void setContentHeight(qreal contentHeight); | ||
4895 | 62 | |||
4896 | 63 | qreal contentX() const; | ||
4897 | 64 | void setContentX(qreal contentX); | ||
4898 | 65 | |||
4899 | 66 | qreal contentY() const; | ||
4900 | 67 | void setContentY(qreal contentY); | ||
4901 | 68 | |||
4902 | 69 | Direction::Type direction() const; | ||
4903 | 70 | void setDirection(Direction::Type); | ||
4904 | 71 | |||
4905 | 72 | private Q_SLOTS: | ||
4906 | 73 | void updateChildrenWidth(); | ||
4907 | 74 | void updateChildrenHeight(); | ||
4908 | 75 | void onDragAreaTouchPosChanged(qreal); | ||
4909 | 76 | void onDragAreaDraggingChanged(bool value); | ||
4911 | 77 | 40 | ||
4912 | 78 | private: | 41 | private: |
4916 | 79 | DirectionalDragArea *m_dragArea; | 42 | bool m_mousePressed {false}; |
4917 | 80 | QQuickFlickable *m_flickable; | 43 | QQuickItem *m_targetItem {nullptr}; |
4915 | 81 | bool m_mousePressed; | ||
4918 | 82 | 44 | ||
4919 | 83 | friend class tst_FloatingFlickable; | 45 | friend class tst_FloatingFlickable; |
4920 | 84 | }; | 46 | }; |
4921 | 85 | 47 | ||
4923 | 86 | #endif // FLOATING_FLICKABLE_H | 48 | #endif // MOUSEEVENTGENERATOR_H |
4924 | 87 | 49 | ||
4925 | === modified file 'plugins/Ubuntu/Gestures/PressedOutsideNotifier.h' | |||
4926 | --- plugins/Ubuntu/Gestures/PressedOutsideNotifier.h 2013-11-22 13:43:40 +0000 | |||
4927 | +++ plugins/Ubuntu/Gestures/PressedOutsideNotifier.h 2016-06-01 16:58:47 +0000 | |||
4928 | @@ -23,7 +23,7 @@ | |||
4929 | 23 | #include <QPointer> | 23 | #include <QPointer> |
4930 | 24 | #include <QTimer> | 24 | #include <QTimer> |
4931 | 25 | 25 | ||
4933 | 26 | #include "UbuntuGesturesGlobal.h" | 26 | #include <ubuntugesturesglobal.h> |
4934 | 27 | 27 | ||
4935 | 28 | /* | 28 | /* |
4936 | 29 | Notifies when a point, mouse or touch, is pressed outside its area. | 29 | Notifies when a point, mouse or touch, is pressed outside its area. |
4937 | 30 | 30 | ||
4938 | === modified file 'plugins/Ubuntu/Gestures/TouchGate.cpp' | |||
4939 | --- plugins/Ubuntu/Gestures/TouchGate.cpp 2015-06-24 11:41:09 +0000 | |||
4940 | +++ plugins/Ubuntu/Gestures/TouchGate.cpp 2016-06-01 16:58:47 +0000 | |||
4941 | @@ -20,8 +20,8 @@ | |||
4942 | 20 | #include <QDebug> | 20 | #include <QDebug> |
4943 | 21 | #include <QQuickWindow> | 21 | #include <QQuickWindow> |
4944 | 22 | 22 | ||
4947 | 23 | #include <TouchOwnershipEvent.h> | 23 | #include <TouchOwnershipEvent> |
4948 | 24 | #include <TouchRegistry.h> | 24 | #include <TouchRegistry> |
4949 | 25 | 25 | ||
4950 | 26 | #if TOUCHGATE_DEBUG | 26 | #if TOUCHGATE_DEBUG |
4951 | 27 | #define ugDebug(params) qDebug().nospace() << "[TouchGate(" << (void*)this << ")] " << params | 27 | #define ugDebug(params) qDebug().nospace() << "[TouchGate(" << (void*)this << ")] " << params |
4952 | 28 | 28 | ||
4953 | === modified file 'plugins/Ubuntu/Gestures/TouchGestureArea.cpp' | |||
4954 | --- plugins/Ubuntu/Gestures/TouchGestureArea.cpp 2016-03-11 20:18:12 +0000 | |||
4955 | +++ plugins/Ubuntu/Gestures/TouchGestureArea.cpp 2016-06-01 16:58:47 +0000 | |||
4956 | @@ -16,10 +16,11 @@ | |||
4957 | 16 | 16 | ||
4958 | 17 | #include "TouchGestureArea.h" | 17 | #include "TouchGestureArea.h" |
4959 | 18 | 18 | ||
4964 | 19 | // local | 19 | #include <UbuntuGestures/TouchOwnershipEvent> |
4965 | 20 | #include "TouchOwnershipEvent.h" | 20 | #include <UbuntuGestures/TouchRegistry> |
4966 | 21 | #include "TouchRegistry.h" | 21 | #include <UbuntuGestures/UnownedTouchEvent> |
4967 | 22 | #include "UnownedTouchEvent.h" | 22 | // #include "TouchRegistry.h" |
4968 | 23 | // #include "UnownedTouchEvent.h" | ||
4969 | 23 | 24 | ||
4970 | 24 | #include <QGuiApplication> | 25 | #include <QGuiApplication> |
4971 | 25 | #include <QStyleHints> | 26 | #include <QStyleHints> |
4972 | @@ -588,13 +589,15 @@ | |||
4973 | 588 | resyncCachedTouchPoints(); | 589 | resyncCachedTouchPoints(); |
4974 | 589 | break; | 590 | break; |
4975 | 590 | case InternalStatus::WaitingForMoreTouches: | 591 | case InternalStatus::WaitingForMoreTouches: |
4977 | 591 | m_recognitionTimer->start(m_recognitionPeriod); | 592 | m_recognitionTimer->setInterval(m_recognitionPeriod); |
4978 | 593 | m_recognitionTimer->start(); | ||
4979 | 592 | break; | 594 | break; |
4980 | 593 | case InternalStatus::Recognized: | 595 | case InternalStatus::Recognized: |
4981 | 594 | resyncCachedTouchPoints(); | 596 | resyncCachedTouchPoints(); |
4982 | 595 | break; | 597 | break; |
4983 | 596 | case InternalStatus::WaitingForRejection: | 598 | case InternalStatus::WaitingForRejection: |
4985 | 597 | m_recognitionTimer->start(m_releaseRejectPeriod); | 599 | m_recognitionTimer->setInterval(m_releaseRejectPeriod); |
4986 | 600 | m_recognitionTimer->start(); | ||
4987 | 598 | break; | 601 | break; |
4988 | 599 | case InternalStatus::Rejected: | 602 | case InternalStatus::Rejected: |
4989 | 600 | resyncCachedTouchPoints(); | 603 | resyncCachedTouchPoints(); |
4990 | 601 | 604 | ||
4991 | === modified file 'plugins/Ubuntu/Gestures/TouchGestureArea.h' | |||
4992 | --- plugins/Ubuntu/Gestures/TouchGestureArea.h 2016-03-11 20:18:12 +0000 | |||
4993 | +++ plugins/Ubuntu/Gestures/TouchGestureArea.h 2016-06-01 16:58:47 +0000 | |||
4994 | @@ -21,8 +21,7 @@ | |||
4995 | 21 | 21 | ||
4996 | 22 | #include <QQuickItem> | 22 | #include <QQuickItem> |
4997 | 23 | 23 | ||
5000 | 24 | // lib UbuntuGestures | 24 | #include <UbuntuGestures/Timer> |
4999 | 25 | #include <Timer.h> |
The diff has been truncated for viewing.