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