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