rhodes 5.5.0.3 → 5.5.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -0
  3. data/lib/commonAPI/coreapi/ext/platform/android/src/com/rho/notification/NotificationSingleton.java +20 -8
  4. data/lib/commonAPI/coreapi/ext/platform/iphone/cpp_based_impl/SystemImpl.mm +1 -2
  5. data/lib/commonAPI/coreapi/ext/system.xml +1 -1
  6. data/platform/android/build/android.rake +1 -0
  7. data/platform/iphone/Classes/AppManager/AppManager.m +44 -3
  8. data/platform/iphone/Classes/NativeView/RhoNativeViewManager.mm +4 -3
  9. data/platform/iphone/Classes/NativeView/RhoNativeViewManagerOC.h +1 -1
  10. data/platform/iphone/Classes/RhoMainView.h +8 -2
  11. data/platform/iphone/Classes/RhoUIWebView.h +75 -0
  12. data/platform/iphone/Classes/RhoUIWebView.m +142 -0
  13. data/platform/iphone/Classes/RhoWKWebView.h +87 -0
  14. data/platform/iphone/Classes/RhoWKWebView.m +187 -0
  15. data/platform/iphone/Classes/RhoWebView.h +72 -0
  16. data/platform/iphone/Classes/RhoWebViewFabrique.h +35 -0
  17. data/platform/iphone/Classes/RhoWebViewFabrique.m +87 -0
  18. data/platform/iphone/Classes/Rhodes.m +17 -6
  19. data/platform/iphone/Classes/Signature.old/SignatureDelegate.m +11 -4
  20. data/platform/iphone/Classes/Signature/SignatureDelegate.m +3 -4
  21. data/platform/iphone/Classes/SimpleMainView.h +7 -5
  22. data/platform/iphone/Classes/SimpleMainView.m +174 -179
  23. data/platform/iphone/Classes/SplitView/RightViewController.h +2 -2
  24. data/platform/iphone/Classes/SplitView/RightViewController.m +9 -10
  25. data/platform/iphone/Classes/SplitView/SplittedMainView.h +2 -3
  26. data/platform/iphone/Classes/SplitView/SplittedMainView.m +10 -7
  27. data/platform/iphone/Classes/TabbedMainView.h +2 -1
  28. data/platform/iphone/Classes/TabbedMainView.m +13 -10
  29. data/platform/iphone/Classes/URLProtocol/CRhoURLProtocol.m +21 -5
  30. data/platform/iphone/Classes/WebView.m +1 -1
  31. data/platform/iphone/RhoAppBaseLib/RhoAppBaseLib.xcodeproj/project.pbxproj +40 -3
  32. data/platform/iphone/RhoLib/RhoLib.xcodeproj/project.pbxproj +4 -0
  33. data/platform/iphone/rbuild/iphone.rake +51 -0
  34. data/platform/shared/common/RhoNativeViewManager.h +9 -9
  35. data/platform/shared/common/RhodesApp.cpp +13 -1
  36. data/platform/shared/net/HttpServer.cpp +12 -2
  37. data/platform/shared/qt/rhodes/ExternalWebView.ui +11 -2
  38. data/platform/shared/qt/rhodes/QtMainWindow.cpp +9 -7
  39. data/platform/shared/qt/rhodes/QtMainWindow.ui +13 -4
  40. data/platform/shared/qt/rhodes/qkineticscroller.cpp +1245 -0
  41. data/platform/shared/qt/rhodes/qkineticscroller.h +165 -0
  42. data/platform/shared/qt/rhodes/qkineticscroller_p.h +168 -0
  43. data/platform/shared/qt/rhodes/qtflickgesture.cpp +696 -0
  44. data/platform/shared/qt/rhodes/qtflickgesture_p.h +107 -0
  45. data/platform/shared/qt/rhodes/qtscroller.cpp +2080 -0
  46. data/platform/shared/qt/rhodes/qtscroller.h +138 -0
  47. data/platform/shared/qt/rhodes/qtscroller_p.h +205 -0
  48. data/platform/shared/qt/rhodes/qtscrollerfilter.cpp +350 -0
  49. data/platform/shared/qt/rhodes/qtscrollerfilter_p.h +110 -0
  50. data/platform/shared/qt/rhodes/qtscrollerproperties.cpp +412 -0
  51. data/platform/shared/qt/rhodes/qtscrollerproperties.h +135 -0
  52. data/platform/shared/qt/rhodes/qtscrollerproperties_p.h +90 -0
  53. data/platform/shared/qt/rhodes/qtscrollevent.cpp +190 -0
  54. data/platform/shared/qt/rhodes/qtscrollevent.h +100 -0
  55. data/platform/shared/qt/rhodes/qtscrollevent_p.h +33 -0
  56. data/platform/shared/qt/rhodes/qwebviewkineticscroller.cpp +347 -0
  57. data/platform/shared/qt/rhodes/qwebviewkineticscroller.h +90 -0
  58. data/platform/shared/qt/rhodes/qwebviewselectionsuppressor.h +113 -0
  59. data/platform/shared/qt/rhodes/rhodes.pro +19 -0
  60. data/res/generators/rhogen.rb +307 -15
  61. data/res/generators/templates/application/app/Settings/err_sync.erb +12 -6
  62. data/res/generators/templates/application/app/Settings/home.erb +32 -17
  63. data/res/generators/templates/application/app/Settings/index.erb +55 -26
  64. data/res/generators/templates/application/app/Settings/javascript_index.html +111 -0
  65. data/res/generators/templates/application/app/Settings/javascript_login.html +65 -0
  66. data/res/generators/templates/application/app/Settings/login.erb +25 -19
  67. data/res/generators/templates/application/app/Settings/reset.erb +18 -9
  68. data/res/generators/templates/application/app/Settings/wait.erb +10 -7
  69. data/res/generators/templates/application/app/index.erb +32 -20
  70. data/res/generators/templates/application/app/javascript_index.html +66 -0
  71. data/res/generators/templates/application/app/javascript_index.js +250 -0
  72. data/res/generators/templates/application/app/layout.erb +12 -67
  73. data/res/generators/templates/application/javascript_build.yml +41 -0
  74. data/res/generators/templates/application/javascript_rhoconfig.txt +123 -0
  75. data/res/generators/templates/application/public/bootstrap-3.3.7/css/bootstrap-theme.css +587 -0
  76. data/res/generators/templates/application/public/bootstrap-3.3.7/css/bootstrap-theme.css.map +1 -0
  77. data/res/generators/templates/application/public/bootstrap-3.3.7/css/bootstrap-theme.min.css +6 -0
  78. data/res/generators/templates/application/public/bootstrap-3.3.7/css/bootstrap-theme.min.css.map +1 -0
  79. data/res/generators/templates/application/public/bootstrap-3.3.7/css/bootstrap.css +6757 -0
  80. data/res/generators/templates/application/public/bootstrap-3.3.7/css/bootstrap.css.map +1 -0
  81. data/res/generators/templates/application/public/bootstrap-3.3.7/css/bootstrap.min.css +6 -0
  82. data/res/generators/templates/application/public/bootstrap-3.3.7/css/bootstrap.min.css.map +1 -0
  83. data/res/generators/templates/application/public/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.eot +0 -0
  84. data/res/generators/templates/application/public/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.svg +288 -0
  85. data/res/generators/templates/application/public/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.ttf +0 -0
  86. data/res/generators/templates/application/public/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.woff +0 -0
  87. data/res/generators/templates/application/public/bootstrap-3.3.7/fonts/glyphicons-halflings-regular.woff2 +0 -0
  88. data/res/generators/templates/application/public/bootstrap-3.3.7/js/bootstrap.js +2377 -0
  89. data/res/generators/templates/application/public/bootstrap-3.3.7/js/bootstrap.min.js +7 -0
  90. data/res/generators/templates/application/public/bootstrap-3.3.7/js/npm.js +13 -0
  91. data/res/generators/templates/application/public/css/style.css +3 -0
  92. data/res/generators/templates/application/public/jquery/jquery-3.1.1.min.js +4 -0
  93. data/res/generators/templates/application/public/jquery/jquery-3.1.1.min.map +1 -0
  94. data/res/generators/templates/application/rhoconfig.txt +16 -0
  95. data/res/generators/templates/iphone_project/Bremen7.xcodeproj/project.pbxproj +4 -0
  96. data/res/generators/templates/model/edit.erb +22 -21
  97. data/res/generators/templates/model/index.erb +24 -22
  98. data/res/generators/templates/model/javascript_edit.html +65 -0
  99. data/res/generators/templates/model/javascript_index.html +56 -0
  100. data/res/generators/templates/model/javascript_index.js +83 -0
  101. data/res/generators/templates/model/javascript_model.js +16 -0
  102. data/res/generators/templates/model/javascript_new.html +64 -0
  103. data/res/generators/templates/model/javascript_show.html +66 -0
  104. data/res/generators/templates/model/new.erb +22 -19
  105. data/res/generators/templates/model/show.erb +22 -14
  106. data/res/prebuild_base_app/app/index.erb +31 -18
  107. data/res/prebuild_base_app/app/layout.erb +11 -56
  108. data/version +1 -1
  109. metadata +59 -24
  110. data/res/generators/templates/application/public/css/android.css +0 -418
  111. data/res/generators/templates/application/public/css/iphone.css +0 -378
  112. data/res/generators/templates/application/public/css/jqmobile-patch.css +0 -62
  113. data/res/generators/templates/application/public/css/re_webkit.css +0 -736
  114. data/res/generators/templates/application/public/css/re_webkit_flat.css +0 -753
  115. data/res/generators/templates/application/public/css/windows_mobile.css +0 -327
  116. data/res/generators/templates/application/public/jqmobile/images/ajax-loader.gif +0 -0
  117. data/res/generators/templates/application/public/jqmobile/images/icon-search-black.png +0 -0
  118. data/res/generators/templates/application/public/jqmobile/images/icons-18-black.png +0 -0
  119. data/res/generators/templates/application/public/jqmobile/images/icons-18-white.png +0 -0
  120. data/res/generators/templates/application/public/jqmobile/images/icons-36-black.png +0 -0
  121. data/res/generators/templates/application/public/jqmobile/images/icons-36-white.png +0 -0
  122. data/res/generators/templates/application/public/jqmobile/jquery.mobile-1.4.5.min.css +0 -3
  123. data/res/generators/templates/application/public/jqmobile/jquery.mobile-1.4.5.min.js +0 -10
  124. data/res/generators/templates/application/public/jqmobile/jquery.mobile-1.4.5.min.map +0 -1
  125. data/res/generators/templates/application/public/jqmobile/jquery.mobile.structure-1.4.5.min.css +0 -3
  126. data/res/generators/templates/application/public/jqmobile/jquery.mobile.theme-1.4.5.min.css +0 -3
  127. data/res/generators/templates/application/public/jquery/jquery-1.9.1.min.js +0 -5
  128. data/res/generators/templates/application/public/jquery/jquery-1.9.1.min.map +0 -1
  129. data/res/generators/templates/application/public/js/application.js +0 -1
  130. data/res/generators/templates/application/public/js/jqmobile-patch.js +0 -466
  131. data/res/generators/templates/application/public/js/syncengine.js +0 -504
@@ -75,8 +75,8 @@ public:
75
75
  // UIView* for iPhone
76
76
  // jobject for Android - jobect must be android.view.View class type
77
77
  // HWND for Windows Mobile
78
- // this function executed when we make native view by Ruby NativeViewManager (not by URL prefix)
79
- virtual void* createView(VALUE params) {return getView();}
78
+ // this function executed when we make native view by Ruby NativeViewManager (not by URL prefix)
79
+ virtual void* createView(VALUE params) {return getView();}
80
80
  };
81
81
 
82
82
  class NativeViewFactory {
@@ -95,21 +95,21 @@ public:
95
95
  static void unregisterViewType(const char* viewType);
96
96
 
97
97
  // that function return native object used for display Web content :
98
- // UIWebView* for iPhone
98
+ // UIView* for iPhone - ATTENTION !!! Now method return CONTAINER VIEW for WebView. For UIWebView is [UIWebView scrollView]. For WkWebView is [WKWebView scrollView] !!!
99
99
  // jobject for Android - jobect is android.webkit.WebView class type
100
100
  // HWND for Windows Mobile
101
101
  static void* getWebViewObject(int tab_index);
102
102
 
103
103
 
104
- // destroy native view (opened with URL prefix or in separated full-screen window)
105
- // this function can executed from your native code (from NativeView code, for example)
106
- // instead of this function you can execute destroy() for Ruby NativeView object
107
- static void destroyNativeView(NativeView* nativeView);
104
+ // destroy native view (opened with URL prefix or in separated full-screen window)
105
+ // this function can executed from your native code (from NativeView code, for example)
106
+ // instead of this function you can execute destroy() for Ruby NativeView object
107
+ static void destroyNativeView(NativeView* nativeView);
108
108
 
109
109
 
110
- static int openNativeView(const char* viewType, int tab_index, VALUE params);
110
+ static int openNativeView(const char* viewType, int tab_index, VALUE params);
111
111
 
112
- static void closeNativeView(int v_id);
112
+ static void closeNativeView(int v_id);
113
113
 
114
114
  };
115
115
 
@@ -1718,7 +1718,19 @@ void CRhodesApp::initAppUrls()
1718
1718
  m_isJSFSApp = false; //We need local server for out of process webkit, it use sockets to call common API
1719
1719
  #endif
1720
1720
 
1721
- m_strHomeUrl = "http://127.0.0.1:";
1721
+ boolean force_https = false;
1722
+ #ifdef OS_MACOSX
1723
+ if (rho_conf_is_property_exists("ios_https_local_server")!=0) {
1724
+ force_https = rho_conf_getBool("ios_https_local_server")!=0;
1725
+ }
1726
+ #endif
1727
+ if (force_https) {
1728
+ m_strHomeUrl = "https://127.0.0.1:";
1729
+ }
1730
+ else {
1731
+ m_strHomeUrl = "http://127.0.0.1:";
1732
+ }
1733
+
1722
1734
  m_strHomeUrl += getFreeListeningPort();
1723
1735
 
1724
1736
  #ifndef RHODES_EMULATOR
@@ -1540,8 +1540,18 @@ bool CDirectHttpRequestQueue::run( )
1540
1540
 
1541
1541
  do
1542
1542
  {
1543
- m_thread.wait(-1);
1544
-
1543
+
1544
+ if (rho_ruby_is_started() ) {
1545
+ rho_ruby_start_threadidle();
1546
+ }
1547
+
1548
+ m_thread.wait(-1);
1549
+
1550
+
1551
+ if (rho_ruby_is_started() ) {
1552
+ rho_ruby_stop_threadidle();
1553
+ }
1554
+
1545
1555
  m_response = "";
1546
1556
 
1547
1557
  if ( m_request != 0 )
@@ -20,7 +20,16 @@
20
20
  <property name="spacing">
21
21
  <number>0</number>
22
22
  </property>
23
- <property name="margin">
23
+ <property name="leftMargin">
24
+ <number>0</number>
25
+ </property>
26
+ <property name="topMargin">
27
+ <number>0</number>
28
+ </property>
29
+ <property name="rightMargin">
30
+ <number>0</number>
31
+ </property>
32
+ <property name="bottomMargin">
24
33
  <number>0</number>
25
34
  </property>
26
35
  <item>
@@ -38,7 +47,7 @@
38
47
  <customwidget>
39
48
  <class>QWebView</class>
40
49
  <extends>QWidget</extends>
41
- <header>QtWebKit/QWebView</header>
50
+ <header>QtWebKitWidgets/QWebView</header>
42
51
  </customwidget>
43
52
  </customwidgets>
44
53
  <resources/>
@@ -63,16 +63,16 @@
63
63
  #include <QFileDialog>
64
64
  #include <QDesktopServices>
65
65
  #include <QDesktopWidget>
66
+ #include <QScroller>
67
+ #include <QScrollArea>
66
68
 
67
69
  #if defined(OS_MACOSX) || defined(OS_LINUX)
68
70
  #define stricmp strcasecmp
69
71
  #define strnicmp strncasecmp
70
72
  #endif
71
73
 
72
- #ifdef OS_SYMBIAN
73
74
  #include "qwebviewselectionsuppressor.h"
74
75
  #include "qwebviewkineticscroller.h"
75
- #endif
76
76
 
77
77
  IMPLEMENT_LOGCLASS(QtMainWindow,"QtMainWindow");
78
78
 
@@ -167,11 +167,13 @@ QtMainWindow::QtMainWindow(QWidget *parent) :
167
167
  main_webInspector->setPage(ui->webView->page());
168
168
  #endif
169
169
 
170
- #ifdef OS_SYMBIAN
171
- QWebViewKineticScroller *newScroller = new QWebViewKineticScroller();
172
- newScroller->setWidget(this->ui->webView);
173
- QWebViewSelectionSuppressor* suppressor = new QWebViewSelectionSuppressor(this->ui->webView);
174
- #endif
170
+ if (RHOCONF().isExist("use_kinetic_scroll_on_windows") && RHOCONF().getBool("use_kinetic_scroll_on_windows"))
171
+ {
172
+ QWebViewKineticScroller *newScroller = new QWebViewKineticScroller();
173
+ newScroller->setWidget(this->ui->webView);
174
+ QWebViewSelectionSuppressor* suppressor = new QWebViewSelectionSuppressor(this->ui->webView);
175
+ }
176
+
175
177
 
176
178
  #if defined(RHODES_EMULATOR)
177
179
  webInspectorWindow->show();
@@ -21,11 +21,20 @@
21
21
  <property name="spacing">
22
22
  <number>0</number>
23
23
  </property>
24
- <property name="margin">
24
+ <property name="leftMargin">
25
+ <number>0</number>
26
+ </property>
27
+ <property name="topMargin">
28
+ <number>0</number>
29
+ </property>
30
+ <property name="rightMargin">
31
+ <number>0</number>
32
+ </property>
33
+ <property name="bottomMargin">
25
34
  <number>0</number>
26
35
  </property>
27
36
  <item>
28
- <widget class="QtNativeTabBar" name="tabBar">
37
+ <widget class="QtNativeTabBar" name="tabBar" native="true">
29
38
  <property name="visible">
30
39
  <bool>false</bool>
31
40
  </property>
@@ -158,11 +167,11 @@
158
167
  <customwidget>
159
168
  <class>QWebView</class>
160
169
  <extends>QWidget</extends>
161
- <header>QtWebKit/QWebView</header>
170
+ <header>QtWebKitWidgets/QWebView</header>
162
171
  </customwidget>
163
172
  <customwidget>
164
173
  <class>QtNativeTabBar</class>
165
- <extends>QTabBar</extends>
174
+ <extends>QWidget</extends>
166
175
  <header>QtNativeTabBar.h</header>
167
176
  </customwidget>
168
177
  </customwidgets>
@@ -0,0 +1,1245 @@
1
+ /****************************************************************************
2
+ **
3
+ ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4
+ ** All rights reserved.
5
+ ** Contact: Nokia Corporation (qt-info@nokia.com)
6
+ **
7
+ ** This file is part of the QtGui module of the Qt Toolkit.
8
+ **
9
+ ** $QT_BEGIN_LICENSE:LGPL$
10
+ ** No Commercial Usage
11
+ ** This file contains pre-release code and may not be distributed.
12
+ ** You may use this file in accordance with the terms and conditions
13
+ ** contained in the Technology Preview License Agreement accompanying
14
+ ** this package.
15
+ **
16
+ ** GNU Lesser General Public License Usage
17
+ ** Alternatively, this file may be used under the terms of the GNU Lesser
18
+ ** General Public License version 2.1 as published by the Free Software
19
+ ** Foundation and appearing in the file LICENSE.LGPL included in the
20
+ ** packaging of this file. Please review the following information to
21
+ ** ensure the GNU Lesser General Public License version 2.1 requirements
22
+ ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23
+ **
24
+ ** In addition, as a special exception, Nokia gives you certain additional
25
+ ** rights. These rights are described in the Nokia Qt LGPL Exception
26
+ ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27
+ **
28
+ ** If you have questions regarding the use of this file, please contact
29
+ ** Nokia at qt-info@nokia.com.
30
+ **
31
+ **
32
+ **
33
+ **
34
+ **
35
+ **
36
+ **
37
+ **
38
+ ** $QT_END_LICENSE$
39
+ **
40
+ ****************************************************************************/
41
+ #include <qkineticscroller.h>
42
+ #include <qkineticscroller_p.h>
43
+ #include <QMap>
44
+ #include <QApplication>
45
+ #include <QDesktopWidget>
46
+ #include <QtCore/qmath.h>
47
+
48
+ #include <QtDebug>
49
+
50
+ QT_BEGIN_NAMESPACE
51
+
52
+ #define KINETIC_SCROLLER_DEBUG
53
+
54
+ #ifdef KINETIC_SCROLLER_DEBUG
55
+ # define qKSDebug qDebug
56
+ #else
57
+ # define qKSDebug while (false) qDebug
58
+ #endif
59
+
60
+
61
+ inline bool operator<=(const QPointF &p, qreal f)
62
+ {
63
+ return (qAbs(p.x()) <= f) && (qAbs(p.y()) <= f);
64
+ }
65
+ inline bool operator<(const QPointF &p, qreal f)
66
+ {
67
+ return (qAbs(p.x()) < f) && (qAbs(p.y()) < f);
68
+ }
69
+
70
+ inline bool operator>=(const QPointF &p, qreal f)
71
+ {
72
+ return (qAbs(p.x()) >= f) || (qAbs(p.y()) >= f);
73
+ }
74
+ inline bool operator>(const QPointF &p, qreal f)
75
+ {
76
+ return (qAbs(p.x()) > f) || (qAbs(p.y()) > f);
77
+ }
78
+
79
+ inline QPointF qAbs(const QPointF &p)
80
+ {
81
+ return QPointF(qAbs(p.x()), qAbs(p.y()));
82
+ }
83
+
84
+ inline int qSign(qreal r)
85
+ {
86
+ return (r < 0) ? -1 : ((r > 0) ? 1 : 0);
87
+ }
88
+
89
+
90
+ /*!
91
+ \class QKineticScroller
92
+ \brief The QKineticScroller class enables kinetic scrolling for any scrolling widget or graphics item.
93
+ \ingroup qtmaemo5
94
+ \since 4.6
95
+ \preliminary
96
+
97
+ With kinetic scrolling, the user can push the widget in a given
98
+ direction and it will continue to scroll in this direction until it is
99
+ stopped either by the user or by friction. Aspects of inertia, friction
100
+ and other physical concepts can be changed in order to fine-tune an
101
+ intuitive user experience.
102
+
103
+ To enable kinetic scrolling for a widget or graphics item, you need to
104
+ derive from this class and implement at least all the pure-virtual
105
+ functions.
106
+
107
+ Qt for Maemo 5 already comes with two implementations for
108
+ QScrollArea and QWebView, and those kinetic scrollers are
109
+ automatically instantiated and attached to these widgets on creation.
110
+ In the QScrollArea case, the kinetic scroller is initially
111
+ disabled. However, for QItemView and QScrollArea derived classes
112
+ it is enabled by default. You can obtain these automatically created
113
+ objects via a dynamic property:
114
+
115
+ \code
116
+ // disable the kinetic scroller on scrollArea
117
+ QKineticScroller *scroller = scrollArea->property("kineticScroller")
118
+ .value<QKineticScroller *>();
119
+ if (scroller)
120
+ scroller->setEnabled(false);
121
+ \endcode
122
+
123
+ In addition there is also an example on how you would add kinetic
124
+ scrolling to a QGraphicsView based application in \c maemobrowser
125
+ examples in the \c maemo5 examples directory.
126
+
127
+ The kinetic scroller installs an event filter on the widget to handle mouse
128
+ presses and moves on the widget \mdash presses and moves on a device's touch screen
129
+ are also handled by this mechanism. These events will be interpreted as scroll actions
130
+ depending on the current state() of the scroller.
131
+
132
+ Even though this kinetic scroller has a huge number of settings, we
133
+ recommend that you leave them all at their default values. In case you
134
+ really want to change them you can try out the \c kineticscroller
135
+ example in the \c maemo5 examples directory.
136
+
137
+ \sa QWidget
138
+ */
139
+
140
+
141
+ /*!
142
+ Constructs a new kinetic scroller.
143
+ */
144
+ QKineticScroller::QKineticScroller()
145
+ : d_ptr(new QKineticScrollerPrivate())
146
+ {
147
+ Q_D(QKineticScroller);
148
+ d->q_ptr = this;
149
+ d->init();
150
+ }
151
+
152
+ /*! \internal
153
+ */
154
+ QKineticScroller::QKineticScroller(QKineticScrollerPrivate &dd)
155
+ : d_ptr(&dd)
156
+ {
157
+ Q_D(QKineticScroller);
158
+ d->q_ptr = this;
159
+ d->init();
160
+ }
161
+
162
+ /*!
163
+ Destroys the scroller.
164
+ */
165
+ QKineticScroller::~QKineticScroller()
166
+ {
167
+ }
168
+
169
+ /*!
170
+ \enum QKineticScroller::State
171
+
172
+ This enum describes the possible states the kinetic scroller can be in.
173
+
174
+ \value Inactive The scroller is inactive. It may also have been disabled.
175
+ \value Pressed The user has pressed the mouse button (or pressed the
176
+ the touch screen).
177
+ \value Dragging The user is dragging the mouse cursor (or other input
178
+ point) over the scroll area.
179
+ \value Scrolling Scrolling is occurring without direct user input.
180
+ */
181
+
182
+ QKineticScrollerPrivate::QKineticScrollerPrivate()
183
+ : enabled(true)
184
+ , state(QKineticScroller::StateInactive)
185
+ , hOvershootPolicy(QKineticScroller::OvershootWhenScrollable)
186
+ , vOvershootPolicy(QKineticScroller::OvershootWhenScrollable)
187
+ , pressTimestamp(0)
188
+ , lastTimestamp(0)
189
+ , scrollToX(false)
190
+ , scrollToY(false)
191
+ , overshootX(false)
192
+ , overshootY(false)
193
+ , cancelPress(false)
194
+ , debugHook(0)
195
+ , debugHookUser(0)
196
+ { }
197
+
198
+ QKineticScrollerPrivate::~QKineticScrollerPrivate()
199
+ { }
200
+
201
+ void QKineticScrollerPrivate::init()
202
+ {
203
+ Q_Q(QKineticScroller);
204
+ q->setDpiFromWidget(0);
205
+ q->resetScrollMetrics();
206
+ }
207
+
208
+ void QKineticScroller::registerDebugHook(void (*callback)(void *user, const QPointF &releaseVelocity, const QPointF &position, const QPointF &overshootPosition), void *user)
209
+ {
210
+ Q_D(QKineticScroller);
211
+ d->debugHook = callback;
212
+ d->debugHookUser = user;
213
+ }
214
+
215
+ void QKineticScroller::resetScrollMetrics()
216
+ {
217
+ static QMap<ScrollMetric, QVariant> metrics;
218
+
219
+ #ifdef Q_WS_MAEMO_5
220
+ metrics.insert(DragVelocitySmoothingFactor, qreal(0.15));
221
+ metrics.insert(ExponentialDecelerationBase, qreal(0.38)); // 0.85^20
222
+ metrics.insert(LinearDecelerationFactor, qreal(0));
223
+ metrics.insert(OvershootSpringConstant, qreal(80.56));
224
+ metrics.insert(OvershootDragResistanceFactor, qreal(1));
225
+ metrics.insert(OvershootMaximumDistance, QPointF(qreal(15.0 / 1000), qreal(15.0 / 1000)));
226
+ metrics.insert(DragStartDistance, qreal(2.5 / 1000));
227
+ metrics.insert(DragStartDirectionErrorMargin, qreal(1.0 / 1000));
228
+ metrics.insert(MaximumVelocity, qreal(6.84));
229
+ metrics.insert(MinimumVelocity, qreal(0.0195));
230
+ metrics.insert(MaximumNonAcceleratedVelocity, qreal(5.6));
231
+ metrics.insert(MaximumClickThroughVelocity, qreal(0.0684));
232
+ metrics.insert(AxisLockThreshold, qreal(0));
233
+ metrics.insert(FastSwipeBaseVelocity, qreal(5.6 * 27));
234
+ metrics.insert(FastSwipeMinimumVelocity, qreal(0.078));
235
+ metrics.insert(FastSwipeMaximumTime, qreal(0.125));
236
+ metrics.insert(FramesPerSecond, qreal(20));
237
+ #else
238
+ metrics.insert(DragVelocitySmoothingFactor, qreal(0.02));
239
+ metrics.insert(ExponentialDecelerationBase, qreal(1));
240
+ metrics.insert(LinearDecelerationFactor, qreal(0.38));
241
+ metrics.insert(OvershootSpringConstant, qreal(15.0));
242
+ metrics.insert(OvershootDragResistanceFactor, qreal(0.5));
243
+ metrics.insert(OvershootMaximumDistance, QPointF(0,0)); // QPointF(qreal(14.25 / 1000), qreal(14.25 / 1000)));
244
+ metrics.insert(DragStartDistance, qreal(2.5 / 1000));
245
+ metrics.insert(DragStartDirectionErrorMargin, qreal(1.0 / 1000));
246
+ metrics.insert(MaximumVelocity, qreal(6650.0 / 1000));
247
+ metrics.insert(MinimumVelocity, qreal(30.0 / 1000));
248
+ metrics.insert(MaximumNonAcceleratedVelocity, qreal(532.0 / 1000));
249
+ metrics.insert(MaximumClickThroughVelocity, qreal(66.5 / 1000));
250
+ metrics.insert(AxisLockThreshold, qreal(0));
251
+ metrics.insert(FastSwipeBaseVelocity, qreal(51.3 / 1000));
252
+ metrics.insert(FastSwipeMinimumVelocity, qreal(76.0 / 1000));
253
+ metrics.insert(FastSwipeMaximumTime, qreal(0.125));
254
+ metrics.insert(FramesPerSecond, qreal(60));
255
+ #endif
256
+
257
+ if (!metrics.isEmpty()) {
258
+ for (QMap<ScrollMetric, QVariant>::const_iterator it = metrics.constBegin(); it != metrics.constEnd(); ++it)
259
+ setScrollMetric(it.key(), it.value());
260
+ if (metrics.count() != ScrollMetricCount)
261
+ qWarning("QKineticScroller::resetAllMetrics(): scroll metrics parameter set did not contain all metrics.");
262
+ } else {
263
+ qWarning("QKineticScroller::resetAllMetrics(): no platform default parameter set available.");
264
+ }
265
+ }
266
+
267
+
268
+ const char *QKineticScrollerPrivate::stateName(QKineticScroller::State state)
269
+ {
270
+ switch (state) {
271
+ case QKineticScroller::StateInactive: return "inactive";
272
+ case QKineticScroller::StatePressed: return "pressed";
273
+ case QKineticScroller::StateDragging: return "dragging";
274
+ case QKineticScroller::StateScrolling: return "scrolling";
275
+ default: return "(invalid)";
276
+ }
277
+ }
278
+
279
+ const char *QKineticScrollerPrivate::inputName(QKineticScroller::Input input)
280
+ {
281
+ switch (input) {
282
+ case QKineticScroller::InputPress: return "press";
283
+ case QKineticScroller::InputMove: return "move";
284
+ case QKineticScroller::InputRelease: return "release";
285
+ default: return "(invalid)";
286
+ }
287
+ }
288
+
289
+
290
+
291
+
292
+ void QKineticScrollerPrivate::timerEvent(QTimerEvent *e)
293
+ {
294
+ if (e->timerId() != timerId) {
295
+ QObject::timerEvent(e);
296
+ return;
297
+ }
298
+
299
+ struct timerevent {
300
+ QKineticScroller::State state;
301
+ typedef void (QKineticScrollerPrivate::*timerhandler_t)();
302
+ timerhandler_t handler;
303
+ };
304
+
305
+ timerevent timerevents[] = {
306
+ { QKineticScroller::StateDragging, &QKineticScrollerPrivate::timerEventWhileDragging },
307
+ { QKineticScroller::StateScrolling, &QKineticScrollerPrivate::timerEventWhileScrolling },
308
+ };
309
+
310
+ for (int i = 0; i < int(sizeof(timerevents) / sizeof(*timerevents)); ++i) {
311
+ timerevent *te = timerevents + i;
312
+
313
+ if (state == te->state) {
314
+ (this->*te->handler)();
315
+ return;
316
+ }
317
+ }
318
+
319
+ if (timerId) {
320
+ qWarning() << "Unhandled timer event, while in state " << stateName(state);
321
+ killTimer(timerId);
322
+ timerId = 0;
323
+ }
324
+ // otherwise this is a timer event that was already queued when the
325
+ // timer was killed, so just ignore it
326
+ }
327
+
328
+ bool QKineticScroller::handleInput(Input input, const QPointF &position, qint64 timestamp)
329
+ {
330
+ Q_D(QKineticScroller);
331
+
332
+
333
+ qKSDebug() << "QKS::handleInput(" << input << ", " << position << ", " << timestamp << ")";
334
+ struct statechange {
335
+ State state;
336
+ Input input;
337
+ typedef bool (QKineticScrollerPrivate::*inputhandler_t)(Input input, const QPointF &position, qint64 timestamp);
338
+ inputhandler_t handler;
339
+ };
340
+
341
+ statechange statechanges[] = {
342
+ { StateInactive, InputPress, &QKineticScrollerPrivate::pressWhileInactive },
343
+ { StatePressed, InputMove, &QKineticScrollerPrivate::moveWhilePressed },
344
+ { StatePressed, InputRelease, &QKineticScrollerPrivate::releaseWhilePressed },
345
+ { StateDragging, InputMove, &QKineticScrollerPrivate::moveWhileDragging },
346
+ { StateDragging, InputRelease, &QKineticScrollerPrivate::releaseWhileDragging },
347
+ { StateScrolling, InputPress, &QKineticScrollerPrivate::pressWhileScrolling }
348
+ };
349
+
350
+ for (int i = 0; i < int(sizeof(statechanges) / sizeof(*statechanges)); ++i) {
351
+ statechange *sc = statechanges + i;
352
+
353
+ if (d->state == sc->state && input == sc->input)
354
+ return (d->*sc->handler)(input, position, timestamp);
355
+ }
356
+
357
+ qWarning() << "Unhandled input: got input " << d->inputName(input) << " while in state " << d->stateName(d->state);
358
+ return false;
359
+ }
360
+
361
+ bool QKineticScroller::isEnabled() const
362
+ {
363
+ Q_D(const QKineticScroller);
364
+ return d->enabled;
365
+ }
366
+
367
+ void QKineticScroller::setEnabled(bool b)
368
+ {
369
+ Q_D(QKineticScroller);
370
+ d->enabled = b;
371
+ }
372
+
373
+ QKineticScroller::State QKineticScroller::state() const
374
+ {
375
+ Q_D(const QKineticScroller);
376
+ return d->state;
377
+ }
378
+
379
+ /*!
380
+ Resets the internal state of the kinetic scroller. This function is not
381
+ needed for normal use. This function only needs to be called if the
382
+ kinetic scroller is being re-attached to a different widget.
383
+ */
384
+ void QKineticScroller::reset()
385
+ {
386
+ Q_D(QKineticScroller);
387
+
388
+ d->setState(StateInactive);
389
+ }
390
+
391
+ QKineticScroller::OvershootPolicy QKineticScroller::horizontalOvershootPolicy() const
392
+ {
393
+ Q_D(const QKineticScroller);
394
+ return d->hOvershootPolicy;
395
+ }
396
+
397
+ void QKineticScroller::setHorizontalOvershootPolicy(QKineticScroller::OvershootPolicy policy)
398
+ {
399
+ Q_D(QKineticScroller);
400
+ d->hOvershootPolicy = policy;
401
+ }
402
+
403
+ QKineticScroller::OvershootPolicy QKineticScroller::verticalOvershootPolicy() const
404
+ {
405
+ Q_D(const QKineticScroller);
406
+ return d->vOvershootPolicy;
407
+ }
408
+
409
+ void QKineticScroller::setVerticalOvershootPolicy(QKineticScroller::OvershootPolicy policy)
410
+ {
411
+ Q_D(QKineticScroller);
412
+ d->vOvershootPolicy = policy;
413
+ }
414
+
415
+ QVariant QKineticScroller::scrollMetric(ScrollMetric metric) const
416
+ {
417
+ Q_D(const QKineticScroller);
418
+
419
+ switch (metric) {
420
+ case DragVelocitySmoothingFactor: return d->dragVelocitySmoothingFactor;
421
+ case LinearDecelerationFactor: return d->linearDecelerationFactor;
422
+ case ExponentialDecelerationBase: return d->exponentialDecelerationBase;
423
+ case OvershootSpringConstant: return d->overshootSpringConstantRoot * d->overshootSpringConstantRoot;
424
+ case OvershootDragResistanceFactor: return d->overshootDragResistanceFactor;
425
+ case OvershootMaximumDistance: return d->overshootMaximumDistance;
426
+ case DragStartDistance: return d->dragStartDistance;
427
+ case DragStartDirectionErrorMargin: return d->dragStartDirectionErrorMargin;
428
+ case MinimumVelocity: return d->minimumVelocity;
429
+ case MaximumVelocity: return d->maximumVelocity;
430
+ case MaximumNonAcceleratedVelocity: return d->maximumNonAcceleratedVelocity;
431
+ case MaximumClickThroughVelocity: return d->maximumClickThroughVelocity;
432
+ case AxisLockThreshold: return d->axisLockThreshold;
433
+ case FramesPerSecond: return d->framesPerSecond;
434
+ case FastSwipeMaximumTime: return d->fastSwipeMaximumTime;
435
+ case FastSwipeMinimumVelocity: return d->fastSwipeMinimumVelocity;
436
+ case FastSwipeBaseVelocity: return d->fastSwipeBaseVelocity;
437
+ case ScrollMetricCount: break;
438
+ }
439
+ return QVariant();
440
+ }
441
+
442
+
443
+ void QKineticScroller::setScrollMetric(ScrollMetric metric, const QVariant &value)
444
+ {
445
+ Q_D(QKineticScroller);
446
+
447
+ switch (metric) {
448
+ case DragVelocitySmoothingFactor: d->dragVelocitySmoothingFactor = qBound(qreal(0), value.toReal(), qreal(1)); break;
449
+ case LinearDecelerationFactor: d->linearDecelerationFactor = qBound(qreal(0), value.toReal(), qreal(1)); break;
450
+ case ExponentialDecelerationBase: d->exponentialDecelerationBase = qBound(qreal(0), value.toReal(), qreal(1)); break;
451
+ case OvershootSpringConstant: d->overshootSpringConstantRoot = qSqrt(value.toReal()); break;
452
+ case OvershootDragResistanceFactor: d->overshootDragResistanceFactor = value.toReal(); break;
453
+ case OvershootMaximumDistance: d->overshootMaximumDistance = value.toPointF(); break;
454
+ case DragStartDistance: d->dragStartDistance = value.toReal(); break;
455
+ case DragStartDirectionErrorMargin: d->dragStartDirectionErrorMargin = value.toReal(); break;
456
+ case MinimumVelocity: d->minimumVelocity = value.toReal(); break;
457
+ case MaximumVelocity: d->maximumVelocity = value.toReal(); break;
458
+ case MaximumNonAcceleratedVelocity: d->maximumNonAcceleratedVelocity = value.toReal(); break;
459
+ case MaximumClickThroughVelocity: d->maximumClickThroughVelocity = value.toReal(); break;
460
+ case AxisLockThreshold: d->axisLockThreshold = qBound(qreal(0), value.toReal(), qreal(1)); break;
461
+ case FramesPerSecond: d->framesPerSecond = qBound(1, value.toInt(), 100); break;
462
+ case FastSwipeMaximumTime: d->fastSwipeMaximumTime = value.toReal(); break;
463
+ case FastSwipeMinimumVelocity: d->fastSwipeMinimumVelocity = value.toReal(); break;
464
+ case FastSwipeBaseVelocity: d->fastSwipeBaseVelocity = value.toReal(); break;
465
+ case ScrollMetricCount: break;
466
+ }
467
+ }
468
+
469
+ qreal QKineticScroller::dpi() const
470
+ {
471
+ Q_D(const QKineticScroller);
472
+ return d->pixelPerMeter / qreal(39.3700787);
473
+ }
474
+
475
+
476
+ void QKineticScroller::setDpi(qreal dpi)
477
+ {
478
+ Q_D(QKineticScroller);
479
+ d->pixelPerMeter = dpi * qreal(39.3700787);
480
+ }
481
+
482
+ void QKineticScroller::setDpiFromWidget(QWidget *widget)
483
+ {
484
+ Q_D(QKineticScroller);
485
+
486
+ QDesktopWidget *dw = QApplication::desktop();
487
+ QPointF dpi = d->realDpi(widget ? dw->screenNumber(widget) : dw->primaryScreen());
488
+ setDpi((dpi.x() + dpi.y()) / qreal(2));
489
+ }
490
+
491
+ #if !defined(Q_WS_MAEMO_5) && !defined(Q_WS_MAC)
492
+
493
+ QPointF QKineticScrollerPrivate::realDpi(int screen)
494
+ {
495
+ QWidget *w = QApplication::desktop()->screen(screen);
496
+ return QPointF(w->physicalDpiX(), w->physicalDpiY());
497
+ }
498
+
499
+ #endif
500
+
501
+
502
+ void QKineticScrollerPrivate::updateVelocity(const QPointF &deltaPixelRaw, qint64 deltaTime)
503
+ {
504
+ qKSDebug() << "QKS::updateVelocity(" << deltaPixelRaw << " [delta pix], " << deltaTime << " [delta ms])";
505
+
506
+ QPointF deltaPixel = deltaPixelRaw;
507
+
508
+ // faster than 2.5mm/ms seems bogus (that would be a screen height in ~20 ms)
509
+ if (((deltaPixelRaw / qreal(deltaTime)).manhattanLength() / pixelPerMeter * 1000) > qreal(2.5))
510
+ deltaPixel = deltaPixelRaw * qreal(2.5) * pixelPerMeter / 1000 / (deltaPixelRaw / qreal(deltaTime)).manhattanLength();
511
+
512
+ qreal inversSmoothingFactor = ((qreal(1) - dragVelocitySmoothingFactor) * qreal(deltaTime) / qreal(1000));
513
+ QPointF newv = -deltaPixel / qreal(deltaTime) * qreal(1000) / pixelPerMeter;
514
+ newv = newv * (qreal(1) - inversSmoothingFactor) + releaseVelocity * inversSmoothingFactor;
515
+
516
+ // newv = newv * dragVelocitySmoothingFactor + velocity * (qreal(1) - dragVelocitySmoothingFactor);
517
+
518
+ if (deltaPixel.x())
519
+ releaseVelocity.setX(qBound(-maximumVelocity, newv.x(), maximumVelocity));
520
+ if (deltaPixel.y())
521
+ releaseVelocity.setY(qBound(-maximumVelocity, newv.y(), maximumVelocity));
522
+
523
+ qKSDebug() << " --> new velocity:" << releaseVelocity;
524
+ }
525
+
526
+ qreal QKineticScrollerPrivate::decelerate(qreal v, qreal t)
527
+ {
528
+ qreal result = v * qPow(exponentialDecelerationBase, t);
529
+ qreal linear = linearDecelerationFactor * t;
530
+ if (qAbs(result) > linear)
531
+ return result + (result < 0 ? linear : -linear);
532
+ else
533
+ return 0;
534
+ }
535
+
536
+ /*! Calculates the current velocity during scrolling
537
+ */
538
+ QPointF QKineticScrollerPrivate::calculateVelocity(qreal time)
539
+ {
540
+ QPointF velocity;
541
+
542
+ // -- x coordinate
543
+ if (overshootX) {
544
+ if (overshootSpringConstantRoot * (time-overshootStartTimeX) < M_PI) // prevent swinging around
545
+ velocity.setX(overshootVelocity.x() * qCos(overshootSpringConstantRoot * (time - overshootStartTimeX)));
546
+ else
547
+ velocity.setX(-overshootVelocity.x());
548
+
549
+ } else {
550
+ qreal newVelocity = decelerate(releaseVelocity.x(), time);
551
+
552
+ if (scrollToX) {
553
+ if (qAbs(newVelocity) < qreal(30.0 / 1000) /* 30mm/s */)
554
+ newVelocity = qreal(30.0 / 1000) * qSign(releaseVelocity.x());
555
+
556
+ } else {
557
+ if (qAbs(newVelocity) < qreal(0.5) * qreal(framesPerSecond) / pixelPerMeter /* 0.5 [pix/frame] */)
558
+ newVelocity = 0;
559
+ }
560
+
561
+ velocity.setX(newVelocity);
562
+ }
563
+
564
+ // -- y coordinate
565
+ if (overshootY) {
566
+ if (overshootSpringConstantRoot * (time-overshootStartTimeY) < M_PI) // prevent swinging around
567
+ velocity.setY(overshootVelocity.y() * qCos(overshootSpringConstantRoot * (time - overshootStartTimeY)));
568
+ else
569
+ velocity.setY(-overshootVelocity.y());
570
+
571
+ } else {
572
+ qreal newVelocity = decelerate(releaseVelocity.y(), time);
573
+
574
+ if (scrollToY) {
575
+ if (qAbs(newVelocity) < qreal(30.0 / 1000) /* 30mm/s */)
576
+ newVelocity = qreal(30.0 / 1000) * qSign(releaseVelocity.y());
577
+
578
+ } else {
579
+ if (qAbs(newVelocity) < qreal(0.5) * qreal(framesPerSecond) / pixelPerMeter /* 0.5 [pix/frame] */)
580
+ newVelocity = 0;
581
+ }
582
+
583
+ velocity.setY(newVelocity);
584
+ }
585
+
586
+ return velocity;
587
+ }
588
+
589
+
590
+ void QKineticScrollerPrivate::handleDrag(const QPointF &position, qint64 timestamp)
591
+ {
592
+ Q_Q(QKineticScroller);
593
+
594
+ QPointF deltaPixel = position - lastPosition;
595
+ qint64 deltaTime = timestamp - lastTimestamp;
596
+
597
+ if (axisLockThreshold) {
598
+ int dx = qAbs(deltaPixel.x());
599
+ int dy = qAbs(deltaPixel.y());
600
+ if (dx || dy) {
601
+ bool vertical = (dy > dx);
602
+ qreal alpha = qreal(vertical ? dx : dy) / qreal(vertical ? dy : dx);
603
+ //qKSDebug() << "QKS::handleDrag() -- axis lock:" << alpha << " / " << axisLockThreshold << "- isvertical:" << vertical << "- dx:" << dx << "- dy:" << dy;
604
+ if (alpha <= axisLockThreshold) {
605
+ if (vertical)
606
+ deltaPixel.setX(0);
607
+ else
608
+ deltaPixel.setY(0);
609
+ }
610
+ }
611
+ }
612
+
613
+ // calculate velocity (if the user would release the mouse NOW)
614
+ updateVelocity(deltaPixel, deltaTime);
615
+
616
+ // restrict velocity, if content is not scrollable
617
+ QPointF maxPos = q->maximumContentPosition();
618
+ bool canScrollX = maxPos.x() || (hOvershootPolicy == QKineticScroller::OvershootAlwaysOn);
619
+ bool canScrollY = maxPos.y() || (vOvershootPolicy == QKineticScroller::OvershootAlwaysOn);
620
+
621
+ if (!canScrollX) {
622
+ deltaPixel.setX(0);
623
+ releaseVelocity.setX(0);
624
+ }
625
+ if (!canScrollY) {
626
+ deltaPixel.setY(0);
627
+ releaseVelocity.setY(0);
628
+ }
629
+
630
+ // if (firstDrag) {
631
+ // // Do not delay the first drag
632
+ // setContentPositionHelper(q->contentPosition() - overshootDistance - deltaPixel);
633
+ // dragDistance = QPointF(0, 0);
634
+ // } else {
635
+ dragDistance += deltaPixel;
636
+ // }
637
+
638
+ if (canScrollX)
639
+ lastPosition.setX(position.x());
640
+ if (canScrollY)
641
+ lastPosition.setY(position.y());
642
+ lastTimestamp = timestamp;
643
+ }
644
+
645
+
646
+
647
+ bool QKineticScrollerPrivate::pressWhileInactive(QKineticScroller::Input, const QPointF &position, qint64 timestamp)
648
+ {
649
+ Q_Q(QKineticScroller);
650
+
651
+ if ((q->maximumContentPosition() > qreal(0)) ||
652
+ (hOvershootPolicy == QKineticScroller::OvershootAlwaysOn) ||
653
+ (vOvershootPolicy == QKineticScroller::OvershootAlwaysOn)) {
654
+ if (q->canStartScrollingAt(position)) {
655
+ lastPosition = pressPosition = position;
656
+ lastTimestamp = pressTimestamp = timestamp;
657
+ cancelPress = true;
658
+ setState(QKineticScroller::StatePressed);
659
+ }
660
+ }
661
+ return false;
662
+ }
663
+
664
+ bool QKineticScrollerPrivate::releaseWhilePressed(QKineticScroller::Input, const QPointF &, qint64)
665
+ {
666
+ if (overshootX || overshootY)
667
+ setState(QKineticScroller::StateScrolling);
668
+ else
669
+ setState(QKineticScroller::StateInactive);
670
+ return false;
671
+ }
672
+
673
+ bool QKineticScrollerPrivate::moveWhilePressed(QKineticScroller::Input, const QPointF &position, qint64 timestamp)
674
+ {
675
+ Q_Q(QKineticScroller);
676
+
677
+ QPointF deltaPixel = position - pressPosition;
678
+
679
+ bool moveStarted = ((deltaPixel.manhattanLength() / pixelPerMeter) > dragStartDistance);
680
+
681
+ if (moveStarted) {
682
+ qreal deltaXtoY = qAbs(pressPosition.x() - position.x()) - qAbs(pressPosition.y() - position.y());
683
+ deltaXtoY /= pixelPerMeter;
684
+
685
+ QPointF maxPos = q->maximumContentPosition();
686
+ bool canScrollX = (maxPos.x() > 0);
687
+ bool canScrollY = (maxPos.y() > 0);
688
+
689
+ if (hOvershootPolicy == QKineticScroller::OvershootAlwaysOn)
690
+ canScrollX = true;
691
+ if (vOvershootPolicy == QKineticScroller::OvershootAlwaysOn)
692
+ canScrollY = true;
693
+
694
+ if (deltaXtoY < 0) {
695
+ if (!canScrollY && (!canScrollX || (-deltaXtoY >= dragStartDirectionErrorMargin)))
696
+ moveStarted = false;
697
+ } else {
698
+ if (!canScrollX && (!canScrollY || (deltaXtoY >= dragStartDirectionErrorMargin)))
699
+ moveStarted = false;
700
+ }
701
+ }
702
+
703
+ if (moveStarted) {
704
+ if (cancelPress)
705
+ q->cancelPress(pressPosition);
706
+ setState(QKineticScroller::StateDragging);
707
+
708
+ // subtract the dragStartDistance
709
+ deltaPixel = deltaPixel - deltaPixel * (dragStartDistance / deltaPixel.manhattanLength());
710
+
711
+ if (!deltaPixel.isNull()) {
712
+ // handleDrag updates lastPosition, lastTimestamp and velocity
713
+ handleDrag(pressPosition + deltaPixel, timestamp);
714
+ }
715
+ }
716
+ return moveStarted;
717
+ }
718
+
719
+ bool QKineticScrollerPrivate::moveWhileDragging(QKineticScroller::Input, const QPointF &position, qint64 timestamp)
720
+ {
721
+ // handleDrag updates lastPosition, lastTimestamp and velocity
722
+ handleDrag(position, timestamp);
723
+ return true;
724
+ }
725
+
726
+ void QKineticScrollerPrivate::timerEventWhileDragging()
727
+ {
728
+ if (!dragDistance.isNull()) {
729
+ qKSDebug() << "QKS::timerEventWhileDragging() -- dragDistance:" << dragDistance;
730
+
731
+ setContentPositionHelper(-dragDistance);
732
+ dragDistance = QPointF(0, 0);
733
+ }
734
+ }
735
+
736
+ bool QKineticScrollerPrivate::releaseWhileDragging(QKineticScroller::Input, const QPointF &, qint64 timestamp)
737
+ {
738
+ Q_Q(QKineticScroller);
739
+
740
+ // calculate the fastSwipe velocity
741
+ QPointF maxPos = q->maximumContentPosition();
742
+ QPointF fastSwipeVelocity = QPoint(0, 0);
743
+ QSizeF size = q->viewportSize();
744
+ if (size.width())
745
+ fastSwipeVelocity.setX(qMin(maximumVelocity, maxPos.x() / size.width() * fastSwipeBaseVelocity));
746
+ if (size.height())
747
+ fastSwipeVelocity.setY(qMin(maximumVelocity, maxPos.y() / size.height() * fastSwipeBaseVelocity));
748
+
749
+ if (fastSwipeMaximumTime &&
750
+ ((timestamp - pressTimestamp) < qint64(fastSwipeMaximumTime * 1000)) &&
751
+ (oldVelocity > fastSwipeMinimumVelocity)) {
752
+
753
+ // more than one fast swipe in a row: add fastSwipeVelocity
754
+ int signX = 0, signY = 0;
755
+ if (releaseVelocity.x())
756
+ signX = (releaseVelocity.x() > 0) == (oldVelocity.x() > 0) ? 1 : -1;
757
+ if (releaseVelocity.y())
758
+ signY = (releaseVelocity.y() > 0) == (oldVelocity.y() > 0) ? 1 : -1;
759
+
760
+ releaseVelocity.setX(signX * (oldVelocity.x() + (oldVelocity.x() > 0 ? fastSwipeVelocity.x() : -fastSwipeVelocity.x())));
761
+ releaseVelocity.setY(signY * (oldVelocity.y() + (oldVelocity.y() > 0 ? fastSwipeVelocity.y() : -fastSwipeVelocity.y())));
762
+
763
+ } else if (releaseVelocity >= minimumVelocity) {
764
+
765
+ // if we have a fast swipe, accelerate it to the fastSwipe velocity
766
+ if ((qAbs(releaseVelocity.x()) > maximumNonAcceleratedVelocity) &&
767
+ (fastSwipeVelocity.x() > maximumNonAcceleratedVelocity)) {
768
+ releaseVelocity.setX(releaseVelocity.x() > 0 ? fastSwipeVelocity.x() : -fastSwipeVelocity.x());
769
+ }
770
+ if ((qAbs(releaseVelocity.y()) > maximumNonAcceleratedVelocity) &&
771
+ (fastSwipeVelocity.y() > maximumNonAcceleratedVelocity)) {
772
+ releaseVelocity.setY(releaseVelocity.y() > 0 ? fastSwipeVelocity.y() : -fastSwipeVelocity.y());
773
+ }
774
+
775
+ }
776
+
777
+ qKSDebug() << "QKS::releaseWhileDragging() -- velocity:" << releaseVelocity << "-- minimum velocity:" << minimumVelocity;
778
+ if (overshootX || overshootY)
779
+ setState(QKineticScroller::StateScrolling);
780
+ else if (releaseVelocity >= minimumVelocity)
781
+ setState(QKineticScroller::StateScrolling);
782
+ else
783
+ setState(QKineticScroller::StateInactive);
784
+
785
+ return true;
786
+ }
787
+
788
+ void QKineticScrollerPrivate::timerEventWhileScrolling()
789
+ {
790
+ qreal deltaTime = qreal(scrollRelativeTimer.restart()) / 1000;
791
+ qreal time = qreal(scrollAbsoluteTimer.elapsed()) / 1000;
792
+
793
+ // calculate the velocity for the passed interval deltatime.
794
+ // using the midpoint of the interval gives a better precision than using just time.
795
+ QPointF newVelocity = calculateVelocity(time - deltaTime / 2);
796
+ QPointF deltaPos = newVelocity * deltaTime * pixelPerMeter;
797
+
798
+ // -- move (convert from [m/s] to [pix/frame]
799
+ if (!deltaPos.isNull())
800
+ setContentPositionHelper(deltaPos);
801
+
802
+ qKSDebug() << "QKS::timerEventWhileScrolling() -- DeltaPos:" << deltaPos << "- NewVel:" << newVelocity << "- Time:" << time;
803
+
804
+ if (newVelocity.isNull() ||
805
+ (releaseVelocity.isNull() && !scrollToX && !scrollToY && !overshootX && !overshootY))
806
+ // if (newVelocity.isNull())
807
+ setState(QKineticScroller::StateInactive);
808
+ }
809
+
810
+ bool QKineticScrollerPrivate::pressWhileScrolling(QKineticScroller::Input, const QPointF &position, qint64 timestamp)
811
+ {
812
+ lastPosition = pressPosition = position;
813
+ lastTimestamp = pressTimestamp = timestamp;
814
+ cancelPress = false;
815
+ setState(QKineticScroller::StatePressed);
816
+ return true;
817
+ }
818
+
819
+ void QKineticScrollerPrivate::setState(QKineticScroller::State newstate)
820
+ {
821
+ Q_Q(QKineticScroller);
822
+
823
+ if (state == newstate)
824
+ return;
825
+
826
+ qKSDebug() << "QKS::setState(" << stateName(newstate) << ")";
827
+
828
+ switch (newstate) {
829
+ case QKineticScroller::StateInactive:
830
+ if (state == QKineticScroller::StateScrolling) {
831
+ if (timerId) {
832
+ killTimer(timerId);
833
+ timerId = 0;
834
+ } else {
835
+ qKSDebug() << " --> state change from " << stateName(state) << " to " << stateName(newstate) << ", but timer is not active.";
836
+ }
837
+ }
838
+ releaseVelocity = QPointF(0, 0);
839
+ break;
840
+
841
+ case QKineticScroller::StatePressed:
842
+ if (timerId) {
843
+ killTimer(timerId);
844
+ timerId = 0;
845
+ }
846
+ scrollToX = false;
847
+ scrollToY = false;
848
+ oldVelocity = releaseVelocity;
849
+ // releaseVelocity = QPointF(0, 0);
850
+ break;
851
+
852
+ case QKineticScroller::StateDragging:
853
+
854
+ dragDistance = QPointF(0, 0);
855
+ if (state == QKineticScroller::StatePressed) {
856
+ if (!timerId) {
857
+ timerId = startTimer(1000 / framesPerSecond);
858
+ } else {
859
+ qKSDebug() << " --> state change from " << stateName(state) << " to " << stateName(newstate) << ", but timer is already active.";
860
+ }
861
+ }
862
+
863
+ break;
864
+
865
+ case QKineticScroller::StateScrolling:
866
+ if (!timerId) {
867
+ timerId = startTimer(1000 / framesPerSecond);
868
+ }
869
+ scrollRelativeTimer.start();
870
+ scrollAbsoluteTimer.start();
871
+
872
+ if (state == QKineticScroller::StateDragging) {
873
+ // TODO: better calculate StartTime using the current releaseVelocity
874
+ overshootStartTimeX = overshootStartTimeY = qreal(scrollAbsoluteTimer.elapsed()) / 1000 - M_PI / (overshootSpringConstantRoot * 2);
875
+ overshootVelocity = overshootPosition / pixelPerMeter * overshootSpringConstantRoot;
876
+ }
877
+
878
+ break;
879
+ }
880
+
881
+ qSwap(state, newstate);
882
+ q->stateChanged(newstate);
883
+ }
884
+
885
+ /*!
886
+ Starts scrolling the widget so that the point \a pos is visible inside
887
+ the viewport.
888
+
889
+ If the specified point cannot be reached, the contents are scrolled to the
890
+ nearest valid position (in this case the scroller might or might not overshoot).
891
+
892
+ The scrolling speed will be calculated so that the given position will
893
+ be reached after a platform-defined time span (1 second for Maemo 5).
894
+ The final speed at the end position is not guaranteed to be zero.
895
+
896
+ \sa ensureVisible(), maximumContentPosition()
897
+ */
898
+ void QKineticScroller::scrollTo(const QPointF &pos, int scrollTime)
899
+ {
900
+ Q_D(QKineticScroller);
901
+
902
+ if (scrollTime <= 0)
903
+ scrollTime = 1;
904
+
905
+ qKSDebug() << "QKS::scrollTo(" << pos << " [pix], " << scrollTime << " [ms])";
906
+
907
+ qreal time = qreal(scrollTime) / 1000;
908
+
909
+ if ((pos == contentPosition()) ||
910
+ (d->state == QKineticScroller::StatePressed) ||
911
+ (d->state == QKineticScroller::StateDragging)) {
912
+ return;
913
+ }
914
+
915
+ // estimate the minimal start velocity
916
+ // if the start velocity is below that then the scrolling would stop before scrollTime.
917
+ //qreal vMin = d->linearDecelerationFactor * time / qPow(d->exponentialDecelerationBase, time);
918
+
919
+ /*
920
+ // estimate of the distance passed within the vMin time during scrollTime
921
+ qreal distMin = qreal(scrollTime) * vMin / 2.0;
922
+
923
+ QPointF v = QPointF((pos.x()-contentPosition().x()) / distMin * vMin,
924
+ (pos.y()-contentPosition().y()) / distMin * vMin);
925
+
926
+ */
927
+
928
+ // v(t) = vstart * exponentialDecelerationBase ^ t - linearDecelerationFactor * t
929
+ // pos(t) = integrate(v(t) * dt)
930
+ // pos(t) = vstart * (eDB ^ t / ln(eDB) + C) - lDF / 2 * t ^ 2
931
+ //
932
+ // pos(time) = pos - contentsPos()
933
+ // vstart = ((lDF / 2) * time ^ 2 + (pos - contentPos())) / (eDB ^ time / ln(eDB) + C)
934
+ // (for C = -1/ln(eDB) )
935
+
936
+ QPointF scrollDir(qSign(pos.x() - contentPosition().x()),
937
+ qSign(pos.y() - contentPosition().y()));
938
+
939
+ QPointF v = (scrollDir * (d->linearDecelerationFactor / qreal(2)) * qreal(time) * qreal(time) + (pos - contentPosition()) / d->pixelPerMeter);
940
+ if (d->exponentialDecelerationBase != qreal(1))
941
+ v /= (qPow(d->exponentialDecelerationBase, time) - 1) / qLn(d->exponentialDecelerationBase);
942
+ else
943
+ v /= time;
944
+
945
+ d->scrollToPosition = pos;
946
+ d->scrollToX = true;
947
+ d->scrollToY = true;
948
+ d->releaseVelocity = v;
949
+ d->scrollRelativeTimer.restart();
950
+ d->scrollAbsoluteTimer.restart();
951
+ d->setState(QKineticScroller::StateScrolling);
952
+ }
953
+
954
+ /*!
955
+ Starts scrolling the widget so that the point \a pos is visible inside the
956
+ viewport with margins specified in pixels by \a xmargin and \a ymargin.
957
+
958
+ If the specified point cannot be reached, the contents are scrolled to the
959
+ nearest valid position. The default value for both margins is 50 pixels.
960
+
961
+ This function performs the actual scrolling by calling scrollTo().
962
+
963
+ \sa maximumContentPosition()
964
+ */
965
+ void QKineticScroller::ensureVisible(const QPointF &pos, int xmargin, int ymargin, int scrollTime)
966
+ {
967
+ QSizeF visible = viewportSize();
968
+ QPointF currentPos = contentPosition();
969
+
970
+ qKSDebug() << "QKS::ensureVisible(" << pos << " [pix], " << xmargin << " [pix], " << ymargin << " [pix], " << scrollTime << "[ms])";
971
+ qKSDebug() << " --> content position:" << contentPosition();
972
+
973
+ QRectF posRect(pos.x() - xmargin, pos.y() - ymargin, 2 * xmargin, 2 * ymargin);
974
+ QRectF visibleRect(currentPos, visible);
975
+
976
+ if (visibleRect.contains(posRect))
977
+ return;
978
+
979
+ QPointF newPos = currentPos;
980
+ if (posRect.top() < visibleRect.top())
981
+ newPos.setY(posRect.top());
982
+ else if (posRect.bottom() > visibleRect.bottom())
983
+ newPos.setY(posRect.bottom() - visible.height());
984
+ if (posRect.left() < visibleRect.left())
985
+ newPos.setX(posRect.left());
986
+ else if (posRect.right() > visibleRect.right())
987
+ newPos.setY(posRect.right() - visible.width());
988
+
989
+ scrollTo(newPos, scrollTime);
990
+ }
991
+
992
+
993
+ /*! \internal
994
+ Helps when setting the content position.
995
+ It will try to move the content by the requested delta but stop in case
996
+ when we are coming back from an overshoot or a scrollTo.
997
+ It will also indicate a new overshooting condition by the overshootX and oversthootY flags.
998
+
999
+ In this cases it will reset the velocity variables and other flags.
1000
+
1001
+ Also keeps track of the current over-shooting value in overshootPosition.
1002
+
1003
+ \deltaPos is the amout of pixels the current content position should be moved
1004
+ */
1005
+ void QKineticScrollerPrivate::setContentPositionHelper(const QPointF &deltaPos)
1006
+ {
1007
+ Q_Q(QKineticScroller);
1008
+
1009
+ if (state == QKineticScroller::StateDragging && overshootDragResistanceFactor)
1010
+ overshootPosition /= overshootDragResistanceFactor;
1011
+
1012
+ QPointF oldPos = q->contentPosition() + overshootPosition;
1013
+ QPointF newPos = oldPos + deltaPos;
1014
+ QPointF maxPos = q->maximumContentPosition();
1015
+
1016
+ QPointF oldScrollToDist = scrollToPosition - oldPos;
1017
+ QPointF newScrollToDist = scrollToPosition - newPos;
1018
+
1019
+ qKSDebug() << "QKS::setContentPositionHelper(" << deltaPos << " [pix])";
1020
+ qKSDebug() << " --> overshoot:" << overshootPosition << "- old pos:" << oldPos << "- new pos:" << newPos;
1021
+
1022
+ QPointF oldClampedPos;
1023
+ oldClampedPos.setX(qBound(qreal(0), oldPos.x(), maxPos.x()));
1024
+ oldClampedPos.setY(qBound(qreal(0), oldPos.y(), maxPos.y()));
1025
+
1026
+ QPointF newClampedPos;
1027
+ newClampedPos.setX(qBound(qreal(0), newPos.x(), maxPos.x()));
1028
+ newClampedPos.setY(qBound(qreal(0), newPos.y(), maxPos.y()));
1029
+
1030
+ // --- handle overshooting and stop if the coordinate is going back inside the normal area
1031
+ bool alwaysOvershootX = (hOvershootPolicy == QKineticScroller::OvershootAlwaysOn);
1032
+ bool alwaysOvershootY = (vOvershootPolicy == QKineticScroller::OvershootAlwaysOn);
1033
+ bool noOvershootX = (hOvershootPolicy == QKineticScroller::OvershootAlwaysOff) ||
1034
+ ((state == QKineticScroller::StateDragging) && !overshootDragResistanceFactor);
1035
+ bool noOvershootY = (vOvershootPolicy == QKineticScroller::OvershootAlwaysOff) ||
1036
+ ((state == QKineticScroller::StateDragging) && !overshootDragResistanceFactor);
1037
+ bool canOvershootX = !noOvershootX && (alwaysOvershootX || maxPos.x());
1038
+ bool canOvershootY = !noOvershootY && (alwaysOvershootY || maxPos.y());
1039
+
1040
+ qreal oldOvershootX = (canOvershootX) ? oldPos.x() - oldClampedPos.x() : 0;
1041
+ qreal oldOvershootY = (canOvershootY) ? oldPos.y() - oldClampedPos.y() : 0;
1042
+
1043
+ qreal newOvershootX = (canOvershootX) ? newPos.x() - newClampedPos.x() : 0;
1044
+ qreal newOvershootY = (canOvershootY) ? newPos.y() - newClampedPos.y() : 0;
1045
+
1046
+ if (state == QKineticScroller::StateDragging && overshootDragResistanceFactor) {
1047
+ oldOvershootX *= overshootDragResistanceFactor;
1048
+ oldOvershootY *= overshootDragResistanceFactor;
1049
+ newOvershootX *= overshootDragResistanceFactor;
1050
+ newOvershootY *= overshootDragResistanceFactor;
1051
+ }
1052
+
1053
+ // -- stop at the maximum overshoot distance (if set)
1054
+ if (!overshootMaximumDistance.isNull()) {
1055
+ newOvershootX = qBound(-overshootMaximumDistance.x() * pixelPerMeter, newOvershootX, overshootMaximumDistance.x() * pixelPerMeter);
1056
+
1057
+ newOvershootY = qBound(-overshootMaximumDistance.y() * pixelPerMeter, newOvershootY, overshootMaximumDistance.y() * pixelPerMeter);
1058
+ }
1059
+
1060
+ // --- sanity check for scrollTo in case we can't even scroll that direction
1061
+ if (!(maxPos.x() || alwaysOvershootX))
1062
+ scrollToX = false;
1063
+ if (!(maxPos.y() || alwaysOvershootY))
1064
+ scrollToY = false;
1065
+
1066
+ // --- handle crossing over borders (scrollTo and overshoot)
1067
+ qKSDebug() << " --> old overshoot Y:" << oldOvershootY << "- new overshoot Y:" << newOvershootY;
1068
+ // -- x axis
1069
+ if (scrollToX && qSign(oldScrollToDist.x()) != qSign(newScrollToDist.x())) {
1070
+ newClampedPos.setX(scrollToPosition.x());
1071
+ newOvershootX = 0;
1072
+ releaseVelocity.setX(0);
1073
+ scrollToX = false;
1074
+
1075
+ } else if (oldOvershootX && (qSign(oldOvershootX) != qSign(newOvershootX))) {
1076
+ newClampedPos.setX((oldOvershootX < 0) ? 0 : maxPos.x());
1077
+ newOvershootX = 0;
1078
+ releaseVelocity.setX(0);
1079
+ overshootVelocity.setX(0);
1080
+ overshootX = false;
1081
+
1082
+ } else if (!oldOvershootX && newOvershootX) {
1083
+ overshootStartTimeX = qreal(scrollAbsoluteTimer.elapsed()) / 1000;
1084
+ overshootVelocity.setX(calculateVelocity(overshootStartTimeX).x());
1085
+
1086
+ // restrict the overshoot to overshootMaximumDistance
1087
+ qreal maxOvershootVelocity = overshootMaximumDistance.x() * overshootSpringConstantRoot;
1088
+ if (overshootMaximumDistance.x() && qAbs(overshootVelocity.x()) > maxOvershootVelocity)
1089
+ overshootVelocity.setX(maxOvershootVelocity * qSign(newOvershootX));
1090
+
1091
+ // -- prevent going into overshoot too far
1092
+ if (state != QKineticScroller::StateDragging)
1093
+ newOvershootX = qSign(newOvershootX) * qreal(0.0001);
1094
+
1095
+ scrollToX = false;
1096
+ overshootX = true;
1097
+ }
1098
+
1099
+ // -- y axis
1100
+ if (scrollToY && qSign(oldScrollToDist.y()) != qSign(newScrollToDist.y())) {
1101
+ newClampedPos.setY(scrollToPosition.y());
1102
+ newOvershootY = 0;
1103
+ releaseVelocity.setY(0);
1104
+ scrollToY = false;
1105
+
1106
+ } else if (oldOvershootY && (qSign(oldOvershootY) != qSign(newOvershootY))) {
1107
+ newClampedPos.setY((oldOvershootY < 0) ? 0 : maxPos.y());
1108
+ newOvershootY = 0;
1109
+ releaseVelocity.setY(0);
1110
+ overshootVelocity.setY(0);
1111
+ overshootY = false;
1112
+
1113
+ } else if (!oldOvershootY && newOvershootY) {
1114
+ overshootStartTimeY = qreal(scrollAbsoluteTimer.elapsed()) / 1000;
1115
+ overshootVelocity.setY(calculateVelocity(overshootStartTimeY).y());
1116
+
1117
+ // -- restrict the overshoot to overshootMaximumDistance
1118
+ qreal maxOvershootVelocity = overshootMaximumDistance.y() * overshootSpringConstantRoot;
1119
+ if (overshootMaximumDistance.y() && (qAbs(overshootVelocity.y()) > maxOvershootVelocity))
1120
+ overshootVelocity.setY(maxOvershootVelocity * qSign(newOvershootY));
1121
+
1122
+ // -- prevent going into overshoot too far
1123
+ if (state != QKineticScroller::StateDragging)
1124
+ newOvershootY = qSign(newOvershootY) * qreal(0.0001);
1125
+
1126
+ scrollToY = false;
1127
+ overshootY = true;
1128
+ }
1129
+
1130
+ overshootPosition.setX(newOvershootX);
1131
+ overshootPosition.setY(newOvershootY);
1132
+
1133
+ q->setContentPosition(newClampedPos, overshootPosition);
1134
+
1135
+ if (debugHook)
1136
+ debugHook(debugHookUser, calculateVelocity(qreal(scrollAbsoluteTimer.elapsed()) / 1000), newClampedPos, overshootPosition);
1137
+
1138
+ qKSDebug() << " --> new position:" << newClampedPos << "- new overshoot:" << overshootPosition <<
1139
+ "- overshoot x/y?:" << overshootX << "/" << overshootY << "- scrollto x/y?:" << scrollToX << "/" << scrollToY;
1140
+ }
1141
+
1142
+
1143
+ /*!
1144
+ \enum QKineticScroller::OvershootPolicy
1145
+
1146
+ This enum describes the various modes of overshooting.
1147
+
1148
+ \value OvershootWhenScrollable Overshooting is when the content is scrollable. This is the default.
1149
+
1150
+ \value OvershootAlwaysOff Overshooting is never enabled (even when the content is scrollable).
1151
+
1152
+ \value OvershootAlwaysOn Overshooting is always enabled (even when the content is not scrollable).
1153
+ */
1154
+
1155
+
1156
+ /*!
1157
+ If kinetic scrolling can be started at the given content's \a position,
1158
+ this function needs to return true; otherwise it needs to return false.
1159
+
1160
+ The default value is true, regardless of \a position.
1161
+ */
1162
+ bool QKineticScroller::canStartScrollingAt(const QPointF &position) const
1163
+ {
1164
+ Q_UNUSED(position);
1165
+ return true;
1166
+ }
1167
+
1168
+ /*!
1169
+ Since a mouse press is always delivered normally when the scroller is in
1170
+ the StateInactive state, we may need to cancel it as soon as the user
1171
+ has moved the mouse far enough to actually start a kinetic scroll
1172
+ operation.
1173
+
1174
+ The \a pressPosition parameter can be used to find out which widget (or
1175
+ graphics item) received the mouse press in the first place.
1176
+
1177
+ Subclasses may choose to simulate a fake mouse release event for that
1178
+ widget (or graphics item), preferably \bold not within its boundaries.
1179
+ The default implementation does nothing.
1180
+ */
1181
+ void QKineticScroller::cancelPress(const QPointF &pressPosition)
1182
+ {
1183
+ Q_UNUSED(pressPosition);
1184
+ }
1185
+
1186
+
1187
+ /*!
1188
+ This function get called whenever the state of the kinetic scroller changes.
1189
+ The old state is supplied as \a oldState, while the new state is returned by
1190
+ calling state().
1191
+
1192
+ The default implementation does nothing.
1193
+
1194
+ \sa state()
1195
+ */
1196
+ void QKineticScroller::stateChanged(State oldState)
1197
+ {
1198
+ Q_UNUSED(oldState);
1199
+ }
1200
+
1201
+ /*!
1202
+ \fn QPointF QKineticScroller::maximumContentPosition() const
1203
+
1204
+ Returns the maximum valid content position. The minimum is always \c
1205
+ (0,0).
1206
+
1207
+ \sa scrollTo()
1208
+ */
1209
+
1210
+ /*!
1211
+ \fn QSizeF QKineticScroller::viewportSize() const
1212
+
1213
+ Returns the size of the currently visible content positions. In the
1214
+ case where an QAbstractScrollArea is used, this is equivalent to the
1215
+ viewport() size.
1216
+
1217
+ \sa scrollTo()
1218
+ */
1219
+
1220
+ /*!
1221
+ \fn QPointF QKineticScroller::contentPosition() const
1222
+
1223
+ \brief Returns the current position of the content.
1224
+
1225
+ Note that overshooting is not considered to be "real" scrolling so the
1226
+ position might be (0,0) even if the user is currently dragging the
1227
+ widget outside the "normal" maximumContentPosition().
1228
+
1229
+ \sa maximumContentPosition()
1230
+ */
1231
+
1232
+
1233
+ /*!
1234
+ \fn void QKineticScroller::setContentPosition(const QPointF &position, const QPointF &overshoot)
1235
+
1236
+ Set the content's \a position. This parameter will always be in the
1237
+ valid range QPointF(0, 0) and maximumContentPosition().
1238
+
1239
+ In the case where overshooting is required, the \a overshoot parameter
1240
+ will give the direction and the absolute distance to overshoot.
1241
+
1242
+ \sa maximumContentPosition()
1243
+ */
1244
+
1245
+ QT_END_NAMESPACE