[SRUK] Initial copy from Tizen 2.2 version
[platform/core/uifw/dali-core.git] / dali / integration-api / events / touch-event-combiner.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 // CLASS HEADER
18 #include <dali/integration-api/events/touch-event-combiner.h>
19
20 // EXTERNAL INCLUDES
21 #include <algorithm>
22
23 // INTERNAL INCLUDES
24 #include <dali/integration-api/events/touch-event-integ.h>
25 #include <dali/public-api/common/dali-common.h>
26
27 namespace Dali
28 {
29
30 namespace Integration
31 {
32
33 namespace
34 {
35 const unsigned long DEFAULT_MINIMUM_MOTION_TIME( 1u );
36 const Vector2 DEFAULT_MINIMUM_MOTION_DISTANCE( 1.0f, 1.0f );
37 } // unnamed namespace
38
39 struct TouchEventCombiner::PointInfo
40 {
41   // Construction
42
43   /**
44    * Constructor
45    * @param[in]  touchPoint  The point to add.
46    * @param[in]  pointTime   The time of the point event.
47    */
48   PointInfo( const TouchPoint& touchPoint, unsigned long pointTime )
49   : point( touchPoint ),
50     time( pointTime )
51   {
52   }
53
54   // Data
55
56   TouchPoint point;   ///< The point.
57   unsigned long time; ///< The time the point event took place.
58 };
59
60 TouchEventCombiner::TouchEventCombiner()
61 : mMinMotionTime( DEFAULT_MINIMUM_MOTION_TIME ),
62   mMinMotionDistance( DEFAULT_MINIMUM_MOTION_DISTANCE )
63 {
64 }
65
66 TouchEventCombiner::TouchEventCombiner( unsigned long minMotionTime, float minMotionXDistance, float minMotionYDistance )
67 : mMinMotionTime( minMotionTime ),
68   mMinMotionDistance( minMotionXDistance, minMotionYDistance )
69 {
70   DALI_ASSERT_ALWAYS( minMotionXDistance >= 0.0f && minMotionYDistance >= 0.0f && "Negative values not allowed\n" );
71 }
72
73 TouchEventCombiner::TouchEventCombiner( unsigned long minMotionTime, Vector2 minMotionDistance )
74 : mMinMotionTime( minMotionTime ),
75   mMinMotionDistance( minMotionDistance )
76 {
77   DALI_ASSERT_ALWAYS( minMotionDistance.x >= 0.0f && minMotionDistance.y >= 0.0f && "Negative values not allowed\n" );
78 }
79
80 TouchEventCombiner::~TouchEventCombiner()
81 {
82 }
83
84 bool TouchEventCombiner::GetNextTouchEvent( const TouchPoint& point, unsigned long time, TouchEvent& touchEvent )
85 {
86   bool dispatchEvent( false );
87
88   switch ( point.state )
89   {
90     case TouchPoint::Down:
91     {
92       touchEvent.time = time;
93       bool addToContainer( true );
94
95       // Iterate through already stored touch points and add to TouchEvent
96       for ( PointInfoContainer::iterator iter = mPressedPoints.begin(), endIter = mPressedPoints.end(); iter != endIter; ++iter )
97       {
98         if ( iter->point.deviceId != point.deviceId )
99         {
100           iter->point.state = TouchPoint::Stationary;
101         }
102         else
103         {
104           // System has sent us two down points for the same point ID, update our stored data to latest.
105           // We do not want to emit another down event for this Point Device ID.
106
107           addToContainer = false;
108           iter->point = point;
109           iter->time = time;
110         }
111         touchEvent.AddPoint( iter->point );
112       }
113
114       // Add new touch point to the list and to the TouchEvent
115       if (addToContainer)
116       {
117         mPressedPoints.push_back( PointInfo( point, time ) );
118         touchEvent.AddPoint( point );
119         dispatchEvent = true; // Only dispatch event if just added to container
120       }
121
122       break;
123     }
124
125     case TouchPoint::Up:
126     {
127       touchEvent.time = time;
128
129       // Find pressed touch point in local list (while also adding the stored points to the touchEvent)
130       PointInfoContainer::iterator match( mPressedPoints.end() );
131       for ( PointInfoContainer::iterator iter = mPressedPoints.begin(), endIter = mPressedPoints.end(); iter != endIter; ++iter )
132       {
133         if ( point.deviceId == iter->point.deviceId )
134         {
135           match = iter;
136
137           // Add new point to the TouchEvent
138           touchEvent.AddPoint( point );
139         }
140         else
141         {
142           iter->point.state = TouchPoint::Stationary;
143           touchEvent.AddPoint( iter->point );
144         }
145       }
146
147       if ( match != mPressedPoints.end() )
148       {
149         mPressedPoints.erase( match );
150         dispatchEvent = true; // We should only dispatch events if the point was actually pressed in this window
151       }
152       break;
153     }
154
155     case TouchPoint::Motion:
156     {
157       if ( !mPressedPoints.empty() )
158       {
159         touchEvent.time = time;
160
161         PointInfoContainer::iterator match = mPressedPoints.end();
162         for ( PointInfoContainer::iterator iter = mPressedPoints.begin(), endIter = mPressedPoints.end(); iter != endIter; ++iter )
163         {
164           if ( point.deviceId == iter->point.deviceId )
165           {
166             unsigned long timeDiff( time - iter->time );
167
168             if ( timeDiff < mMinMotionTime )
169             {
170               // Motion event sent too soon after previous event so ignore
171               break;
172             }
173
174             if ( ( abs( point.screen.x - iter->point.screen.x ) < mMinMotionDistance.x ) &&
175                  ( abs( point.screen.y - iter->point.screen.y ) < mMinMotionDistance.y ) )
176             {
177               // Not enough positional change from last event so ignore
178               break;
179             }
180
181             match = iter;
182
183             // Add new touch point to the TouchEvent
184             touchEvent.AddPoint( point );
185           }
186           else
187           {
188             iter->point.state = TouchPoint::Stationary;
189             touchEvent.AddPoint( iter->point );
190           }
191         }
192
193         if ( match != mPressedPoints.end() )
194         {
195           PointInfo matchedPoint( point, time );
196           std::swap( *match, matchedPoint );
197
198           dispatchEvent = true;
199         }
200       }
201       break;
202     }
203
204     case TouchPoint::Interrupted:
205     {
206       Reset();
207
208       // We should still tell core about the interruption.
209       touchEvent.AddPoint( point );
210       dispatchEvent = true;
211       break;
212     }
213
214     default:
215       break;
216   }
217
218   return dispatchEvent;
219 }
220
221 void TouchEventCombiner::SetMinimumMotionTimeThreshold( unsigned long minTime )
222 {
223   mMinMotionTime = minTime;
224 }
225
226 void TouchEventCombiner::SetMinimumMotionDistanceThreshold( float minDistance )
227 {
228   DALI_ASSERT_ALWAYS( minDistance >= 0.0f && "Negative values not allowed\n" );
229
230   mMinMotionDistance.x = mMinMotionDistance.y = minDistance;
231 }
232
233 void TouchEventCombiner::SetMinimumMotionDistanceThreshold( float minXDistance, float minYDistance )
234 {
235   DALI_ASSERT_ALWAYS( minXDistance >= 0.0f && minYDistance >= 0.0f && "Negative values not allowed\n" );
236
237   mMinMotionDistance.x = minXDistance;
238   mMinMotionDistance.y = minYDistance;
239 }
240
241 void TouchEventCombiner::SetMinimumMotionDistanceThreshold( Vector2 minDistance )
242 {
243   DALI_ASSERT_ALWAYS( minDistance.x >= 0.0f && minDistance.y >= 0.0f && "Negative values not allowed\n" );
244
245   mMinMotionDistance = minDistance;
246 }
247
248 unsigned long TouchEventCombiner::GetMinimumMotionTimeThreshold() const
249 {
250   return mMinMotionTime;
251 }
252
253 Vector2 TouchEventCombiner::GetMinimumMotionDistanceThreshold() const
254 {
255   return mMinMotionDistance;
256 }
257
258 void TouchEventCombiner::Reset()
259 {
260   mPressedPoints.clear();
261 }
262
263 } // namespace Integration
264
265 } // namespace Dali