f5b079a3d592d9a35650b757cf77f72b2f168d3a
[platform/core/uifw/dali-toolkit.git] / optional / dali-toolkit / internal / controls / cluster / cluster-impl.cpp
1 /*
2  * Copyright (c) 2014 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/controls/cluster/cluster-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23 #include <dali/integration-api/debug.h>
24
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/public-api/controls/cluster/cluster-style.h>
27
28 using namespace std;
29 using namespace Dali;
30
31 namespace // unnamed namespace
32 {
33
34 const float CLUSTER_STYLE_CONSTRAINT_DURATION = 1.0f;
35
36 }
37
38 namespace Dali
39 {
40
41 namespace Toolkit
42 {
43
44 namespace Internal
45 {
46
47 namespace
48 {
49
50 BaseHandle Create()
51 {
52   Toolkit::ClusterStyleStandard s = Toolkit::ClusterStyleStandard::New(Toolkit::ClusterStyleStandard::ClusterStyle1);
53   return Toolkit::Cluster::New( s );
54 }
55
56 TypeRegistration mType( typeid(Toolkit::Cluster), typeid(Toolkit::Control), Create );
57
58 TypeAction a1(mType, Toolkit::Cluster::ACTION_EXPAND   , &Cluster::DoAction);
59 TypeAction a2(mType, Toolkit::Cluster::ACTION_COLLAPSE , &Cluster::DoAction);
60 TypeAction a3(mType, Toolkit::Cluster::ACTION_TRANSFORM, &Cluster::DoAction);
61
62 }
63
64 ///////////////////////////////////////////////////////////////////////////////////////////////////
65 // Cluster
66 ///////////////////////////////////////////////////////////////////////////////////////////////////
67
68 Dali::Toolkit::Cluster Cluster::New(Toolkit::ClusterStyle& style)
69 {
70   // Create the implementation
71   ClusterPtr cluster(new Cluster(style));
72
73   // Pass ownership to CustomActor via derived handle
74   Dali::Toolkit::Cluster handle(*cluster);
75
76   // Second-phase init of the implementation
77   // This can only be done after the CustomActor connection has been made...
78   cluster->Initialize();
79
80   return handle;
81 }
82
83 Cluster::Cluster(Toolkit::ClusterStyle& style)
84 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
85   mClusterStyle(style),
86   mExpandedCount(0)
87 {
88 }
89
90 void Cluster::OnInitialize()
91 {
92 }
93
94 Cluster::~Cluster()
95 {
96 }
97
98 void Cluster::AddChild( Actor child )
99 {
100   // automatically add child with a position at end.
101   AddChild( child, mChildren.size() );
102 }
103
104 void Cluster::AddChild( Actor child, unsigned int positionIndex )
105 {
106   AddChildInfo( ChildInfo(child, positionIndex) );
107 }
108
109 void Cluster::AddChildAt( Actor child, unsigned int index )
110 {
111   // automatically add child with a position at end.
112   AddChild( child, mChildren.size() );
113 }
114
115 void Cluster::AddChildAt( Actor child, unsigned int positionIndex, unsigned int index )
116 {
117   AddChildInfoAt( ChildInfo(child, positionIndex), index );
118 }
119
120 void Cluster::AddChildInfo( ChildInfo childInfo )
121 {
122   AddChildInfoAt(childInfo, mChildren.size());
123 }
124
125 void Cluster::AddChildInfoAt( ChildInfo childInfo, unsigned int index )
126 {
127   // check that the child is valid
128   DALI_ASSERT_ALWAYS( childInfo.mActor );
129
130   ChildInfoIter offset = index < mChildren.size() ? (mChildren.begin() + index) : mChildren.end();
131   // now perform customization on this child.
132
133   // adopt the child
134   if(childInfo.mActor.GetParent() != Self())
135   {
136     Actor& child = childInfo.mActor;
137     const float depth = std::distance(mChildren.begin(), offset);
138
139     Property::Index depthProperty = child.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
140     if(depthProperty == Property::INVALID_INDEX)
141     {
142       depthProperty = child.RegisterProperty(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH, depth);
143     }
144
145     // not added prior
146     Self().Add( childInfo.mActor );
147     mChildren.insert( offset, childInfo );
148
149     // Use parent position plus relative position.
150     child.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
151
152     // remove old constraints
153     child.RemoveConstraints();
154
155     // apply new constraints to the child
156     mClusterStyle.ApplyStyle(child, childInfo.mPositionIndex, AlphaFunctions::EaseOut, 0.0f);
157   }
158   else
159   {
160     // already added.
161     ChildInfoContainer mNewChildren;
162     ChildInfoIter iter = mChildren.begin();
163     float depth = 0.0f;
164
165     for( ; iter != mChildren.end(); ++iter)
166     {
167       if(iter == offset)
168       {
169         SetDepth(childInfo, depth);
170         depth++;
171         // insert the new childInfo before offset.
172         mNewChildren.push_back(childInfo);
173       }
174       // copy all children except the one that we wish to move.
175       if((*iter).mActor != childInfo.mActor)
176       {
177         SetDepth(*iter, depth);
178         depth++;
179         mNewChildren.push_back(*iter);
180       }
181     } // end for.
182
183     if(iter == offset)
184     {
185       SetDepth(childInfo, depth);
186       // insert the new childInfo before offset (end).
187       mNewChildren.push_back(childInfo);
188     }
189
190     mChildren = mNewChildren;
191
192     // Todo somehow adjust their perceived depth.
193   }
194 }
195
196 void Cluster::SetDepth( ChildInfo& childInfo, float depth )
197 {
198   Property::Index depthProperty = childInfo.mActor.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
199   childInfo.mActor.SetProperty( depthProperty, depth );
200 }
201
202 ChildInfo Cluster::GetChildInfoAt( unsigned int index )
203 {
204   // check if we have this position in the cluster
205   if( index < mChildren.size() )
206   {
207     // return the child handle
208     return mChildren[ index ];
209   }
210
211   // return an empty handle
212   return ChildInfo();
213 }
214
215 Actor Cluster::GetChildAt( unsigned int index )
216 {
217   // check if we have this position in the cluster
218   if( index < mChildren.size() )
219   {
220     // return the child handle
221     return mChildren[ index ].mActor;
222   }
223
224   // return an empty handle
225   return Actor();
226 }
227
228 Actor Cluster::RemoveChildAt( unsigned int index )
229 {
230   DALI_ASSERT_ALWAYS( index < mChildren.size() );
231
232   ChildInfoIter iter = mChildren.begin() + index;
233   Actor child = (*iter).mActor;
234   mChildren.erase( iter );
235   Self().Remove(child);
236   // note: constraints will automatically be removed in OnControlChildRemove
237
238   // update depths.
239   float depth = 0.0f;
240
241   for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
242   {
243     SetDepth(*iter, depth);
244     depth++;
245   } // end for.
246
247   return child;
248 }
249
250 void Cluster::ExpandChild( unsigned int index )
251 {
252   if( index < mChildren.size() )
253   {
254     ChildInfo& childInfo = mChildren[ index ];
255     DALI_ASSERT_ALWAYS(childInfo.mActor);
256
257     if(!childInfo.mExpanded)
258     {
259       // expand child to a random position/angle.
260       const Vector3 clusterSize = Self().GetCurrentSize();
261       const float length = clusterSize.Length() * 0.1f;
262       const float zOffset = 50.0f;
263       const float angle = (rand()%360) * Math::PI / 180.0f;
264       Vector3 position(sin(angle) * length, -cos(angle) * length, zOffset);
265       const float scale(1.2f);
266       const float rotate = ((rand()%30) - 15) * Math::PI / 180.0f;
267
268       position += childInfo.mActor.GetCurrentPosition();
269
270       TransformChild(index,
271                      position,
272                      Vector3::ONE * scale,
273                      Quaternion(rotate, Vector3::ZAXIS),
274                      AlphaFunctions::EaseOut,
275                      0.5f);
276     }
277   }
278 }
279
280 void Cluster::ExpandAllChildren()
281 {
282   for(unsigned int index = 0;index < mChildren.size(); index++)
283   {
284     ExpandChild( index );
285   }
286 }
287
288 void Cluster::CollapseChild( unsigned int index, bool front )
289 {
290   if( index < mChildren.size() )
291   {
292     RestoreChild(index,
293                  AlphaFunctions::EaseOut,
294                  0.25f,
295                  front);
296   }
297 }
298
299 void Cluster::CollapseAllChildren( bool front )
300 {
301   for(unsigned int index = 0;index < mChildren.size(); index++)
302   {
303     RestoreChild(index,
304                  AlphaFunctions::EaseOut,
305                  0.25f,
306                  front);
307   }
308 }
309
310 void Cluster::TransformChild( unsigned int index, const Vector3& position, const Vector3& scale, const Quaternion& rotation, AlphaFunction alpha, const TimePeriod& period )
311 {
312   if( index < mChildren.size() )
313   {
314     ChildInfo& childInfo = mChildren[ index ];
315     DALI_ASSERT_ALWAYS(childInfo.mActor);
316
317     if(!childInfo.mExpanded)
318     {
319       Actor child = childInfo.mActor;
320       childInfo.mExpanded = true;
321       mExpandedCount++;
322
323       child.RemoveConstraints();
324       Animation animation = Animation::New(period.delaySeconds + period.durationSeconds);
325       animation.AnimateTo( Property(child, Actor::POSITION), position, AlphaFunctions::EaseOut, period);
326       animation.AnimateTo( Property(child, Actor::SCALE), scale, AlphaFunctions::EaseOut, period);
327       animation.AnimateTo( Property(child, Actor::ROTATION), rotation, AlphaFunctions::EaseOut, period);
328       animation.Play();
329     }
330   }
331 }
332
333 void Cluster::RestoreChild( unsigned int index, AlphaFunction alpha, const TimePeriod& period, bool front )
334 {
335   if( index < mChildren.size() )
336   {
337     ChildInfo& childInfo = mChildren[ index ];
338     DALI_ASSERT_ALWAYS(childInfo.mActor);
339
340     if(childInfo.mExpanded)
341     {
342       Actor child = childInfo.mActor;
343       childInfo.mExpanded = false;
344       mExpandedCount--;
345       mClusterStyle.ApplyStyle( child, childInfo.mPositionIndex, alpha, period );
346
347       const unsigned int hideIndex = front ? mChildren.size() : 0;
348       AddChildInfoAt(childInfo, hideIndex); // move child info to the back or front of the pack.
349     }
350   }
351 }
352
353 void Cluster::SetBackgroundImage( Actor image )
354 {
355   // Replaces the background image.
356   if(mBackgroundImage && mBackgroundImage.GetParent())
357   {
358     mBackgroundImage.GetParent().Remove(mBackgroundImage);
359   }
360
361   mBackgroundImage = image;
362   Self().Add(mBackgroundImage);
363
364   mBackgroundImage.SetAnchorPoint( AnchorPoint::TOP_LEFT );
365   mBackgroundImage.SetParentOrigin( ParentOrigin::TOP_LEFT );
366
367   UpdateBackground(0.0f);
368 }
369
370 void Cluster::SetTitle( Actor text )
371 {
372   // Replaces the title actor.
373   if(mTitle && mTitle.GetParent())
374   {
375     mTitle.GetParent().Remove( mTitle );
376   }
377
378   mTitle = text;
379   Self().Add( mTitle );
380
381   mTitle.SetAnchorPoint( AnchorPoint::TOP_LEFT );
382   mTitle.SetParentOrigin( ParentOrigin::TOP_LEFT );
383
384   UpdateTitle(0.0f);
385 }
386
387 void Cluster::SetStyle(Toolkit::ClusterStyle style)
388 {
389   unsigned int previousChildrenNum = mChildren.size();
390   mClusterStyle = style;
391   unsigned int newChildrenNum = mClusterStyle.GetMaximumNumberOfChildren();
392
393   // New style supports less children (remove those that no longer belong)
394   if(newChildrenNum < previousChildrenNum)
395   {
396     ChildInfoIter removeStart = mChildren.begin() + newChildrenNum;
397
398     for(ChildInfoIter iter = removeStart; iter != mChildren.end(); ++iter)
399     {
400       Actor child = (*iter).mActor;
401       child.RemoveConstraints();
402       Self().Remove(child);
403     }
404
405     mChildren.erase( removeStart, mChildren.end() );
406   }
407
408   // Remove constraints from previous style, and apply new style's constraints.
409   for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
410   {
411
412     if((*iter).mActor)
413     {
414       (*iter).mActor.RemoveConstraints();
415       style.ApplyStyle( (*iter).mActor,
416                         (*iter).mPositionIndex,
417                         AlphaFunctions::EaseOut,
418                         CLUSTER_STYLE_CONSTRAINT_DURATION );
419     }
420   }
421
422   UpdateBackground(CLUSTER_STYLE_CONSTRAINT_DURATION);
423   UpdateTitle(CLUSTER_STYLE_CONSTRAINT_DURATION);
424 }
425
426 Toolkit::ClusterStyle Cluster::GetStyle() const
427 {
428   return mClusterStyle;
429 }
430
431 unsigned int Cluster::GetExpandedCount() const
432 {
433   return mExpandedCount;
434 }
435
436 unsigned int Cluster::GetTotalCount() const
437 {
438   return mChildren.size();
439 }
440
441 void Cluster::UpdateBackground(float duration)
442 {
443   if (mBackgroundImage)
444   {
445     mBackgroundImage.RemoveConstraints();
446     mClusterStyle.ApplyStyleToBackground(mBackgroundImage, AlphaFunctions::EaseOut, duration);
447   }
448 }
449
450 void Cluster::UpdateTitle(float duration)
451 {
452   if (mTitle)
453   {
454     mTitle.RemoveConstraints();
455     mClusterStyle.ApplyStyleToTitle(mTitle, AlphaFunctions::EaseOut, duration);
456   }
457 }
458
459 void Cluster::DoExpandAction(const PropertyValueContainer& attributes)
460 {
461   if(attributes.size() >= 1)
462   {
463     for(PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter)
464     {
465       const Property::Value& value = *iter;
466
467       DALI_ASSERT_ALWAYS(value.GetType() == Property::FLOAT);
468       unsigned int index = value.Get<float>();
469       ExpandChild( index );
470     }
471   }
472   else
473   {
474     ExpandAllChildren();
475   }
476 }
477
478 void Cluster::DoCollapseAction(const PropertyValueContainer& attributes)
479 {
480   if(attributes.size() >= 1)
481   {
482     for(PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter)
483     {
484       const Property::Value& value = *iter;
485
486       DALI_ASSERT_ALWAYS(value.GetType() == Property::FLOAT);
487       unsigned int index = value.Get<float>();
488       CollapseChild( index, false );
489     }
490   }
491   else
492   {
493     CollapseAllChildren( false );
494   }
495 }
496
497 void Cluster::DoTransformAction(const PropertyValueContainer& attributes)
498 {
499   DALI_ASSERT_ALWAYS(attributes.size() >= 2);
500
501   DALI_ASSERT_ALWAYS(attributes[0].GetType() == Property::FLOAT);
502   unsigned int index = attributes[0].Get<float>();
503   Vector3 position;
504   Vector3 scale(Vector3::ONE);
505   Quaternion rotation(0.0f, Vector3::ZAXIS);
506
507   DALI_ASSERT_ALWAYS(attributes[1].GetType() == Property::VECTOR3);
508   attributes[1].Get(position);
509
510   if(attributes.size()>2)
511   {
512     attributes[2].Get(scale);
513   }
514
515   if(attributes.size()>3)
516   {
517     attributes[3].Get(rotation);
518   }
519
520   // wrap index around -1 => size - 1
521   index%= mChildren.size();
522
523   TransformChild(index, position, scale, rotation, AlphaFunctions::EaseOut, 0.5f);
524 }
525
526 void Cluster::OnControlChildRemove(Actor& child)
527 {
528   child.RemoveConstraints();
529 }
530
531 bool Cluster::DoAction(BaseObject* object, const std::string& actionName, const std::vector<Property::Value>& attributes)
532 {
533   bool ret = false;
534
535   Dali::BaseHandle handle(object);
536
537   Toolkit::Cluster cluster = Toolkit::Cluster::DownCast(handle);
538
539   DALI_ASSERT_ALWAYS(cluster);
540
541   if(Toolkit::Cluster::ACTION_EXPAND == actionName)
542   {
543     GetImpl(cluster).DoExpandAction(attributes);
544     ret = true;
545   }
546   else if(Toolkit::Cluster::ACTION_COLLAPSE == actionName)
547   {
548     GetImpl(cluster).DoCollapseAction(attributes);
549     ret = true;
550   }
551   else if(Toolkit::Cluster::ACTION_TRANSFORM == actionName)
552   {
553     GetImpl(cluster).DoTransformAction(attributes);
554     ret = true;
555   }
556
557   return ret;
558 }
559
560 } // namespace Internal
561
562 } // namespace Toolkit
563
564 } // namespace Dali