rhodes 5.5.0.3 → 5.5.0.7

Sign up to get free protection for your applications and to get access to all the features.
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