[dali_2.3.20] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / drag-drop-detector / drag-and-drop-detector-impl.cpp
1 /*
2  * Copyright (c) 2021 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-toolkit/internal/drag-drop-detector/drag-and-drop-detector-impl.h>
20
21 #include <dali/public-api/events/point-state.h>
22 #include <dali/public-api/events/touch-event.h>
23
24 namespace Dali
25 {
26 namespace Toolkit
27 {
28 namespace Internal
29 {
30 Dali::Toolkit::DragAndDropDetector DragAndDropDetector::New()
31 {
32   Dali::Toolkit::DragAndDropDetector detector = Dali::Toolkit::DragAndDropDetector(new DragAndDropDetector());
33
34   return detector;
35 }
36
37 void DragAndDropDetector::Attach(Dali::Toolkit::Control& control)
38 {
39   if(control)
40   {
41     if(!mControls.empty())
42     {
43       auto match = std::find(mControls.begin(), mControls.end(), control);
44       if(match != mControls.end())
45       {
46         return;
47       }
48     }
49     mControls.push_back(control);
50     control.TouchedSignal().Connect(this, &DragAndDropDetector::OnDrag);
51     mFirstEnter.push_back(control.GetProperty<int>(Actor::Property::ID));
52     mPanGestureDetector.Attach(control);
53     mPanGestureDetector.DetectedSignal().Connect(this, &DragAndDropDetector::OnPan);
54   }
55 }
56
57 void DragAndDropDetector::Detach(Dali::Toolkit::Control& control)
58 {
59   if(!mControls.empty())
60   {
61     if(!control)
62     {
63       return;
64     }
65
66     auto match = std::find(mControls.begin(), mControls.end(), control);
67
68     if(match != mControls.end())
69     {
70       match->TouchedSignal().Disconnect(this, &DragAndDropDetector::OnDrag);
71       mPanGestureDetector.Detach(*match);
72       mFirstEnter.erase(std::find(mFirstEnter.begin(), mFirstEnter.end(), control.GetProperty<int>(Actor::Property::ID)));
73       mControls.erase(match);
74     }
75   }
76 }
77
78 void DragAndDropDetector::DetachAll()
79 {
80   if(!mControls.empty())
81   {
82     auto iter = mControls.begin();
83     for(; iter != mControls.end();)
84     {
85       iter->TouchedSignal().Disconnect(this, &DragAndDropDetector::OnDrag);
86       mPanGestureDetector.Detach(*iter);
87       iter = mControls.erase(iter);
88     }
89   }
90
91   if(!mFirstEnter.empty())
92   {
93     auto iter = mFirstEnter.begin();
94     for(; iter != mFirstEnter.end();)
95     {
96       iter = mFirstEnter.erase(iter);
97     }
98   }
99 }
100
101 uint32_t DragAndDropDetector::GetAttachedControlCount() const
102 {
103   return mControls.size();
104 }
105
106 Dali::Toolkit::Control DragAndDropDetector::GetAttachedControl(uint32_t index) const
107 {
108   Dali::Toolkit::Control control;
109
110   if(index < mControls.size())
111   {
112     control = mControls[index];
113   }
114
115   return control;
116 }
117
118 void DragAndDropDetector::OnPan(Dali::Actor actor, const PanGesture& gesture)
119 {
120   Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
121
122   GestureState state = gesture.GetState();
123
124   if(state == GestureState::STARTED)
125   {
126     mDragLocalPosition = gesture.GetPosition();
127     mPointDown         = true;
128     mDragControl       = control;
129     mFirstEnter.clear();
130     for(auto&& control : mControls)
131     {
132       mFirstEnter.push_back(control.GetProperty<int>(Actor::Property::ID));
133     }
134     float   width    = control.GetProperty<float>(Dali::Actor::Property::SIZE_WIDTH);
135     float   height   = control.GetProperty<float>(Dali::Actor::Property::SIZE_HEIGHT);
136     Vector3 actorPos = control.GetProperty<Vector3>(Dali::Actor::Property::POSITION);
137
138     mShadowControl = Dali::Toolkit::Control::New();
139     mShadowControl.SetProperty(Actor::Property::POSITION, actorPos);
140     mShadowControl.SetProperty(Actor::Property::SIZE, Vector2(width, height));
141     mShadowControl.SetBackgroundColor(Vector4(0.3f, 0.3f, 0.3f, 0.7f));
142     mShadowControl.SetProperty(Actor::Property::PARENT_ORIGIN, control.GetCurrentProperty<Vector3>(Actor::Property::PARENT_ORIGIN));
143     mShadowControl.SetProperty(Actor::Property::ANCHOR_POINT, control.GetCurrentProperty<Vector3>(Actor::Property::ANCHOR_POINT));
144     control.GetParent().Add(mShadowControl);
145     SetPosition(gesture.GetScreenPosition());
146     EmitStartedSignal(control);
147   }
148   if(state == GestureState::CONTINUING)
149   {
150     Vector2 screenPosition = gesture.GetScreenPosition();
151     control.GetParent().ScreenToLocal(mLocalPosition.x, mLocalPosition.y, screenPosition.x, screenPosition.y);
152     mShadowControl.SetProperty(Actor::Property::POSITION, Vector2(mLocalPosition.x - mDragLocalPosition.x, mLocalPosition.y - mDragLocalPosition.y));
153   }
154   if(state == GestureState::FINISHED)
155   {
156     mDragControl.GetParent().Remove(mShadowControl);
157     EmitEndedSignal(control);
158   }
159 }
160
161 bool DragAndDropDetector::OnDrag(Dali::Actor actor, const Dali::TouchEvent& data)
162 {
163   Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
164   PointState::Type       type    = data.GetState(0);
165
166   if(type == PointState::MOTION)
167   {
168     if(mDragControl != control && mPointDown)
169     {
170       auto found = std::find(mFirstEnter.begin(), mFirstEnter.end(), control.GetProperty<int>(Actor::Property::ID));
171       if(mFirstEnter.end() != found)
172       {
173         SetPosition(data.GetScreenPosition(0));
174         mFirstEnter.erase(found);
175         EmitEnteredSignal(control);
176       }
177       else
178       {
179         SetPosition(data.GetScreenPosition(0));
180         EmitMovedSignal(control);
181       }
182     }
183   }
184
185   if(type == PointState::LEAVE)
186   {
187     if(mDragControl != control && mPointDown)
188     {
189       mFirstEnter.push_back(control.GetProperty<int>(Actor::Property::ID));
190       EmitExitedSignal(control);
191     }
192   }
193
194   if(type == PointState::UP)
195   {
196     if(mDragControl != control && mPointDown)
197     {
198       SetPosition(data.GetScreenPosition(0));
199       ClearContent();
200       SetContent(mDragControl.GetProperty<std::string>(Dali::Actor::Property::NAME));
201       EmitDroppedSignal(control);
202     }
203
204     if(mShadowControl)
205     {
206       control.GetParent().Remove(mShadowControl);
207     }
208     mPointDown = false;
209   }
210   return false;
211 }
212
213 const std::string& DragAndDropDetector::GetContent() const
214 {
215   return mContent;
216 }
217
218 const Vector2& DragAndDropDetector::GetCurrentScreenPosition() const
219 {
220   return mScreenPosition;
221 }
222
223 void DragAndDropDetector::SetContent(const std::string& content)
224 {
225   mContent = content;
226 }
227
228 void DragAndDropDetector::ClearContent()
229 {
230   mContent.clear();
231 }
232
233 void DragAndDropDetector::SetPosition(const Vector2& screenPosition)
234 {
235   mScreenPosition = screenPosition;
236 }
237
238 void DragAndDropDetector::EmitStartedSignal(Dali::Toolkit::Control& control)
239 {
240   if(!mStartedSignal.Empty())
241   {
242     Dali::Toolkit::DragAndDropDetector handle(this);
243     mStartedSignal.Emit(control, handle);
244   }
245 }
246 void DragAndDropDetector::EmitEnteredSignal(Dali::Toolkit::Control& control)
247 {
248   if(!mEnteredSignal.Empty())
249   {
250     Dali::Toolkit::DragAndDropDetector handle(this);
251     mEnteredSignal.Emit(control, handle);
252   }
253 }
254
255 void DragAndDropDetector::EmitExitedSignal(Dali::Toolkit::Control& control)
256 {
257   if(!mExitedSignal.Empty())
258   {
259     Dali::Toolkit::DragAndDropDetector handle(this);
260     mExitedSignal.Emit(control, handle);
261   }
262 }
263
264 void DragAndDropDetector::EmitMovedSignal(Dali::Toolkit::Control& control)
265 {
266   if(!mMovedSignal.Empty())
267   {
268     Dali::Toolkit::DragAndDropDetector handle(this);
269     mMovedSignal.Emit(control, handle);
270   }
271 }
272
273 void DragAndDropDetector::EmitDroppedSignal(Dali::Toolkit::Control& control)
274 {
275   if(!mDroppedSignal.Empty())
276   {
277     Dali::Toolkit::DragAndDropDetector handle(this);
278     mDroppedSignal.Emit(control, handle);
279   }
280 }
281
282 void DragAndDropDetector::EmitEndedSignal(Dali::Toolkit::Control& control)
283 {
284   if(!mEndedSignal.Empty())
285   {
286     Dali::Toolkit::DragAndDropDetector handle(this);
287     mEndedSignal.Emit(control, handle);
288   }
289 }
290
291 DragAndDropDetector::DragAndDropDetector()
292 : mContent(),
293   mScreenPosition()
294 {
295   mPanGestureDetector = Dali::PanGestureDetector::New();
296   mPointDown          = false;
297 }
298
299 DragAndDropDetector::~DragAndDropDetector()
300 {
301 }
302
303 } // namespace Internal
304
305 } //namespace Toolkit
306
307 } // namespace Dali