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