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