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