[dali_2.3.24] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / event / events / tap-gesture / tap-gesture-detector-impl.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
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
18 // CLASS HEADER
19 #include <dali/internal/event/events/tap-gesture/tap-gesture-detector-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23
24 // INTERNAL INCLUDES
25 #include <dali/integration-api/debug.h>
26 #include <dali/integration-api/platform-abstraction.h>
27 #include <dali/internal/event/common/thread-local-storage.h>
28 #include <dali/internal/event/events/gesture-event-processor.h>
29 #include <dali/internal/event/events/tap-gesture/tap-gesture-impl.h>
30 #include <dali/public-api/events/tap-gesture.h>
31 #include <dali/public-api/object/type-registry.h>
32
33 namespace Dali
34 {
35 namespace Internal
36 {
37 namespace
38 {
39 #if defined(DEBUG_ENABLED)
40 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_TAP_GESTURE_DETECTOR");
41 #endif // defined(DEBUG_ENABLED)
42
43 constexpr uint32_t DEFAULT_TAPS_REQUIRED    = 1u;
44 constexpr uint32_t DEFAULT_TOUCHES_REQUIRED = 1u;
45 constexpr uint32_t DEFAULT_TAP_WAIT_TIME    = 330u;
46
47 // Signals
48 const char* const SIGNAL_TAP_DETECTED = "tapDetected";
49
50 BaseHandle Create()
51 {
52   return Dali::TapGestureDetector::New();
53 }
54
55 TypeRegistration mType(typeid(Dali::TapGestureDetector), typeid(Dali::GestureDetector), Create);
56
57 SignalConnectorType signalConnector1(mType, SIGNAL_TAP_DETECTED, &TapGestureDetector::DoConnectSignal);
58
59 } // namespace
60
61 TapGestureDetectorPtr TapGestureDetector::New()
62 {
63   return new TapGestureDetector(DEFAULT_TAPS_REQUIRED);
64 }
65
66 TapGestureDetectorPtr TapGestureDetector::New(uint32_t tapsRequired)
67 {
68   return new TapGestureDetector(tapsRequired);
69 }
70
71 TapGestureDetector::TapGestureDetector(uint32_t tapsRequired)
72 : GestureDetector(GestureType::TAP),
73   mMinimumTapsRequired(tapsRequired),
74   mMaximumTapsRequired(tapsRequired),
75   mTouchesRequired(DEFAULT_TOUCHES_REQUIRED),
76   mTimerId(0u),
77   mWaitTime(DEFAULT_TAP_WAIT_TIME),
78   mTappedActor(),
79   mTap(),
80   mReceiveAllTapEvents(false)
81 {
82 }
83
84 TapGestureDetector::~TapGestureDetector()
85 {
86   if(mTimerId != 0 && ThreadLocalStorage::Created())
87   {
88     Dali::Integration::PlatformAbstraction& platformAbstraction = ThreadLocalStorage::Get().GetPlatformAbstraction();
89     platformAbstraction.CancelTimer(mTimerId);
90   }
91 }
92
93 bool TapGestureDetector::CheckMinMaxTapsRequired()
94 {
95   if(mMinimumTapsRequired > mMaximumTapsRequired)
96   {
97     DALI_LOG_ERROR("Minimum taps requested is greater than the maximum requested. minimumTapsRequired(%d) maximumTapsRequired(%d)\n", mMinimumTapsRequired, mMaximumTapsRequired);
98     return false;
99   }
100   else
101   {
102     return true;
103   }
104
105 }
106
107 void TapGestureDetector::SetMinimumTapsRequired(uint32_t taps)
108 {
109   if(mMinimumTapsRequired != taps)
110   {
111     mMinimumTapsRequired = taps;
112
113     if(!mAttachedActors.empty())
114     {
115       CheckMinMaxTapsRequired();
116     }
117   }
118 }
119
120 void TapGestureDetector::SetMaximumTapsRequired(uint32_t taps)
121 {
122   if(mMaximumTapsRequired != taps)
123   {
124     mMaximumTapsRequired = taps;
125
126     if(!mAttachedActors.empty())
127     {
128       CheckMinMaxTapsRequired();
129     }
130   }
131 }
132
133 void TapGestureDetector::SetTouchesRequired(uint32_t touches)
134 {
135   if(mTouchesRequired != touches)
136   {
137     mTouchesRequired = touches;
138
139     if(!mAttachedActors.empty())
140     {
141       mGestureEventProcessor.GestureDetectorUpdated(this);
142     }
143   }
144 }
145
146 uint32_t TapGestureDetector::GetMinimumTapsRequired() const
147 {
148   return mMinimumTapsRequired;
149 }
150
151 uint32_t TapGestureDetector::GetMaximumTapsRequired() const
152 {
153   return mMaximumTapsRequired;
154 }
155
156 uint32_t TapGestureDetector::GetTouchesRequired() const
157 {
158   return mTouchesRequired;
159 }
160
161 void TapGestureDetector::ReceiveAllTapEvents(bool receive)
162 {
163   mReceiveAllTapEvents = receive;
164 }
165
166 void TapGestureDetector::EmitTapGestureSignal(Dali::Actor tappedActor, const Dali::TapGesture& tap)
167 {
168   if(!CheckMinMaxTapsRequired())
169   {
170     return;
171   }
172
173   Dali::Integration::PlatformAbstraction& platformAbstraction = ThreadLocalStorage::Get().GetPlatformAbstraction();
174   if(mTimerId != 0)
175   {
176     platformAbstraction.CancelTimer(mTimerId);
177     mTimerId = 0;
178   }
179
180   uint32_t numberOfTaps = 0u;
181   if(mMaximumTapsRequired > 0u)
182   {
183     numberOfTaps = tap.GetNumberOfTaps() % mMaximumTapsRequired;
184     numberOfTaps = numberOfTaps == 0u ? mMaximumTapsRequired : numberOfTaps;
185     if (numberOfTaps >= mMinimumTapsRequired)
186     {
187       Internal::TapGesturePtr internalTap(new Internal::TapGesture(tap.GetState()));
188       internalTap->SetTime(tap.GetTime());
189       internalTap->SetNumberOfTouches(tap.GetNumberOfTouches());
190       internalTap->SetScreenPoint(tap.GetScreenPoint());
191       internalTap->SetLocalPoint(tap.GetLocalPoint());
192       internalTap->SetSourceType(tap.GetSourceType());
193       internalTap->SetSourceData(tap.GetSourceData());
194       internalTap->SetNumberOfTaps(numberOfTaps);
195       mTap = Dali::TapGesture(internalTap.Get());
196       if(numberOfTaps == mMaximumTapsRequired || mReceiveAllTapEvents)
197       {
198         // Guard against destruction during signal emission
199         Dali::TapGestureDetector handle(this);
200         DALI_LOG_DEBUG_INFO("emitting tap gesture actor id(%d)\n", tappedActor.GetProperty<int32_t>(Dali::Actor::Property::ID));
201         mDetectedSignal.Emit(tappedActor, mTap);
202       }
203       else
204       {
205         mTappedActor = tappedActor;
206         mTimerId     = platformAbstraction.StartTimer(mWaitTime, MakeCallback(this, &TapGestureDetector::TimerCallback));
207       }
208     }
209   }
210 }
211
212 bool TapGestureDetector::TimerCallback()
213 {
214   // Guard against destruction during signal emission
215   Dali::TapGestureDetector handle(this);
216   DALI_LOG_DEBUG_INFO("emitting tap gesture actor id(%d)\n", mTappedActor.GetProperty<int32_t>(Dali::Actor::Property::ID));
217   mDetectedSignal.Emit(mTappedActor, mTap);
218
219   mTimerId = 0;
220   return false;
221 }
222
223 bool TapGestureDetector::DoConnectSignal(BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor)
224 {
225   bool                connected(true);
226   TapGestureDetector* gesture = static_cast<TapGestureDetector*>(object); // TypeRegistry guarantees that this is the correct type.
227
228   if(0 == strcmp(signalName.c_str(), SIGNAL_TAP_DETECTED))
229   {
230     gesture->DetectedSignal().Connect(tracker, functor);
231   }
232   else
233   {
234     // signalName does not match any signal
235     connected = false;
236   }
237
238   return connected;
239 }
240
241 void TapGestureDetector::OnActorAttach(Actor& actor)
242 {
243   CheckMinMaxTapsRequired();
244   mWaitTime = mGestureEventProcessor.GetTapGestureProcessor().GetMaximumAllowedTime();
245   DALI_LOG_INFO(gLogFilter, Debug::General, "TapGestureDetector attach actor(%d)\n", actor.GetId());
246 }
247
248 void TapGestureDetector::OnActorDetach(Actor& actor)
249 {
250   DALI_LOG_INFO(gLogFilter, Debug::General, "TapGestureDetector detach actor(%d)\n", actor.GetId());
251 }
252
253 void TapGestureDetector::OnActorDestroyed(Object& object)
254 {
255   // Do nothing
256 }
257
258 } // namespace Internal
259
260 } // namespace Dali