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