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