2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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
8 // http://floralicense.org/license/
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.
18 #include <dali-toolkit/internal/controls/cluster/cluster-impl.h>
22 #include <dali/integration-api/debug.h>
25 #include <dali-toolkit/public-api/controls/cluster/cluster-style.h>
30 namespace // unnamed namespace
33 const float CLUSTER_STYLE_CONSTRAINT_DURATION = 1.0f;
51 Toolkit::ClusterStyleStandard s = Toolkit::ClusterStyleStandard::New(Toolkit::ClusterStyleStandard::ClusterStyle1);
52 return Toolkit::Cluster::New( s );
55 TypeRegistration mType( typeid(Toolkit::Cluster), typeid(Toolkit::Control), Create );
57 TypeAction a1(mType, Toolkit::Cluster::ACTION_EXPAND , &Cluster::DoAction);
58 TypeAction a2(mType, Toolkit::Cluster::ACTION_COLLAPSE , &Cluster::DoAction);
59 TypeAction a3(mType, Toolkit::Cluster::ACTION_TRANSFORM, &Cluster::DoAction);
63 ///////////////////////////////////////////////////////////////////////////////////////////////////
65 ///////////////////////////////////////////////////////////////////////////////////////////////////
67 Dali::Toolkit::Cluster Cluster::New(Toolkit::ClusterStyle& style)
69 // Create the implementation
70 ClusterPtr cluster(new Cluster(style));
72 // Pass ownership to CustomActor via derived handle
73 Dali::Toolkit::Cluster handle(*cluster);
75 // Second-phase init of the implementation
76 // This can only be done after the CustomActor connection has been made...
77 cluster->Initialize();
82 Cluster::Cluster(Toolkit::ClusterStyle& style)
83 : ControlImpl(true/*requires touch*/),
89 void Cluster::OnInitialize()
97 void Cluster::AddChild( Actor child )
99 // automatically add child with a position at end.
100 AddChild( child, mChildren.size() );
103 void Cluster::AddChild( Actor child, unsigned int positionIndex )
105 AddChildInfo( ChildInfo(child, positionIndex) );
108 void Cluster::AddChildAt( Actor child, unsigned int index )
110 // automatically add child with a position at end.
111 AddChild( child, mChildren.size() );
114 void Cluster::AddChildAt( Actor child, unsigned int positionIndex, unsigned int index )
116 AddChildInfoAt( ChildInfo(child, positionIndex), index );
119 void Cluster::AddChildInfo( ChildInfo childInfo )
121 AddChildInfoAt(childInfo, mChildren.size());
124 void Cluster::AddChildInfoAt( ChildInfo childInfo, unsigned int index )
126 // check that the child is valid
127 DALI_ASSERT_ALWAYS( childInfo.mActor );
129 ChildInfoIter offset = index < mChildren.size() ? (mChildren.begin() + index) : mChildren.end();
130 // now perform customization on this child.
133 if(childInfo.mActor.GetParent() != Self())
135 Actor& child = childInfo.mActor;
136 const float depth = std::distance(mChildren.begin(), offset);
138 Property::Index depthProperty = child.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
139 if(depthProperty == Property::INVALID_INDEX)
141 depthProperty = child.RegisterProperty(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH, depth);
145 Self().Add( childInfo.mActor );
146 mChildren.insert( offset, childInfo );
148 // Use parent position plus relative position.
149 child.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
151 // remove old constraints
152 child.RemoveConstraints();
154 // apply new constraints to the child
155 mClusterStyle.ApplyStyle(child, childInfo.mPositionIndex, AlphaFunctions::EaseOut, 0.0f);
160 ChildInfoContainer mNewChildren;
161 ChildInfoIter iter = mChildren.begin();
164 for( ; iter != mChildren.end(); ++iter)
168 SetDepth(childInfo, depth);
170 // insert the new childInfo before offset.
171 mNewChildren.push_back(childInfo);
173 // copy all children except the one that we wish to move.
174 if((*iter).mActor != childInfo.mActor)
176 SetDepth(*iter, depth);
178 mNewChildren.push_back(*iter);
184 SetDepth(childInfo, depth);
185 // insert the new childInfo before offset (end).
186 mNewChildren.push_back(childInfo);
189 mChildren = mNewChildren;
191 // Todo somehow adjust their perceived depth.
195 void Cluster::SetDepth( ChildInfo& childInfo, float depth )
197 Property::Index depthProperty = childInfo.mActor.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
198 childInfo.mActor.SetProperty( depthProperty, depth );
201 ChildInfo Cluster::GetChildInfoAt( unsigned int index )
203 // check if we have this position in the cluster
204 if( index < mChildren.size() )
206 // return the child handle
207 return mChildren[ index ];
210 // return an empty handle
214 Actor Cluster::GetChildAt( unsigned int index )
216 // check if we have this position in the cluster
217 if( index < mChildren.size() )
219 // return the child handle
220 return mChildren[ index ].mActor;
223 // return an empty handle
227 Actor Cluster::RemoveChildAt( unsigned int index )
229 DALI_ASSERT_ALWAYS( index < mChildren.size() );
231 ChildInfoIter iter = mChildren.begin() + index;
232 Actor child = (*iter).mActor;
233 mChildren.erase( iter );
234 Self().Remove(child);
235 // note: constraints will automatically be removed in OnControlChildRemove
240 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
242 SetDepth(*iter, depth);
249 void Cluster::ExpandChild( unsigned int index )
251 if( index < mChildren.size() )
253 ChildInfo& childInfo = mChildren[ index ];
254 DALI_ASSERT_ALWAYS(childInfo.mActor);
256 if(!childInfo.mExpanded)
258 // expand child to a random position/angle.
259 const Vector3 clusterSize = Self().GetCurrentSize();
260 const float length = clusterSize.Length() * 0.1f;
261 const float zOffset = 50.0f;
262 const float angle = (rand()%360) * Math::PI / 180.0f;
263 Vector3 position(sin(angle) * length, -cos(angle) * length, zOffset);
264 const float scale(1.2f);
265 const float rotate = ((rand()%30) - 15) * Math::PI / 180.0f;
267 position += childInfo.mActor.GetCurrentPosition();
269 TransformChild(index,
271 Vector3::ONE * scale,
272 Quaternion(rotate, Vector3::ZAXIS),
273 AlphaFunctions::EaseOut,
279 void Cluster::ExpandAllChildren()
281 for(unsigned int index = 0;index < mChildren.size(); index++)
283 ExpandChild( index );
287 void Cluster::CollapseChild( unsigned int index, bool front )
289 if( index < mChildren.size() )
292 AlphaFunctions::EaseOut,
298 void Cluster::CollapseAllChildren( bool front )
300 for(unsigned int index = 0;index < mChildren.size(); index++)
303 AlphaFunctions::EaseOut,
309 void Cluster::TransformChild( unsigned int index, const Vector3& position, const Vector3& scale, const Quaternion& rotation, AlphaFunction alpha, const TimePeriod& period )
311 if( index < mChildren.size() )
313 ChildInfo& childInfo = mChildren[ index ];
314 DALI_ASSERT_ALWAYS(childInfo.mActor);
316 if(!childInfo.mExpanded)
318 Actor child = childInfo.mActor;
319 childInfo.mExpanded = true;
322 child.RemoveConstraints();
323 Animation animation = Animation::New(period.delaySeconds + period.durationSeconds);
324 animation.AnimateTo( Property(child, Actor::POSITION), position, AlphaFunctions::EaseOut, period);
325 animation.AnimateTo( Property(child, Actor::SCALE), scale, AlphaFunctions::EaseOut, period);
326 animation.AnimateTo( Property(child, Actor::ROTATION), rotation, AlphaFunctions::EaseOut, period);
332 void Cluster::RestoreChild( unsigned int index, AlphaFunction alpha, const TimePeriod& period, bool front )
334 if( index < mChildren.size() )
336 ChildInfo& childInfo = mChildren[ index ];
337 DALI_ASSERT_ALWAYS(childInfo.mActor);
339 if(childInfo.mExpanded)
341 Actor child = childInfo.mActor;
342 childInfo.mExpanded = false;
344 mClusterStyle.ApplyStyle( child, childInfo.mPositionIndex, alpha, period );
346 const unsigned int hideIndex = front ? mChildren.size() : 0;
347 AddChildInfoAt(childInfo, hideIndex); // move child info to the back or front of the pack.
352 void Cluster::SetBackgroundImage( Actor image )
354 // Replaces the background image.
355 if(mBackgroundImage && mBackgroundImage.GetParent())
357 mBackgroundImage.GetParent().Remove(mBackgroundImage);
360 mBackgroundImage = image;
361 Self().Add(mBackgroundImage);
363 mBackgroundImage.SetAnchorPoint( AnchorPoint::TOP_LEFT );
364 mBackgroundImage.SetParentOrigin( ParentOrigin::TOP_LEFT );
366 UpdateBackground(0.0f);
369 void Cluster::SetTitle( Actor text )
371 // Replaces the title actor.
372 if(mTitle && mTitle.GetParent())
374 mTitle.GetParent().Remove( mTitle );
378 Self().Add( mTitle );
380 mTitle.SetAnchorPoint( AnchorPoint::TOP_LEFT );
381 mTitle.SetParentOrigin( ParentOrigin::TOP_LEFT );
386 void Cluster::SetStyle(Toolkit::ClusterStyle style)
388 unsigned int previousChildrenNum = mChildren.size();
389 mClusterStyle = style;
390 unsigned int newChildrenNum = mClusterStyle.GetMaximumNumberOfChildren();
392 // New style supports less children (remove those that no longer belong)
393 if(newChildrenNum < previousChildrenNum)
395 ChildInfoIter removeStart = mChildren.begin() + newChildrenNum;
397 for(ChildInfoIter iter = removeStart; iter != mChildren.end(); ++iter)
399 Actor child = (*iter).mActor;
400 child.RemoveConstraints();
401 Self().Remove(child);
404 mChildren.erase( removeStart, mChildren.end() );
407 // Remove constraints from previous style, and apply new style's constraints.
408 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
413 (*iter).mActor.RemoveConstraints();
414 style.ApplyStyle( (*iter).mActor,
415 (*iter).mPositionIndex,
416 AlphaFunctions::EaseOut,
417 CLUSTER_STYLE_CONSTRAINT_DURATION );
421 UpdateBackground(CLUSTER_STYLE_CONSTRAINT_DURATION);
422 UpdateTitle(CLUSTER_STYLE_CONSTRAINT_DURATION);
425 Toolkit::ClusterStyle Cluster::GetStyle() const
427 return mClusterStyle;
430 unsigned int Cluster::GetExpandedCount() const
432 return mExpandedCount;
435 unsigned int Cluster::GetTotalCount() const
437 return mChildren.size();
440 void Cluster::UpdateBackground(float duration)
442 if (mBackgroundImage)
444 mBackgroundImage.RemoveConstraints();
445 mClusterStyle.ApplyStyleToBackground(mBackgroundImage, AlphaFunctions::EaseOut, duration);
449 void Cluster::UpdateTitle(float duration)
453 mTitle.RemoveConstraints();
454 mClusterStyle.ApplyStyleToTitle(mTitle, AlphaFunctions::EaseOut, duration);
458 void Cluster::DoExpandAction(const PropertyValueContainer& attributes)
460 if(attributes.size() >= 1)
462 for(PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter)
464 const Property::Value& value = *iter;
466 DALI_ASSERT_ALWAYS(value.GetType() == Property::FLOAT);
467 unsigned int index = value.Get<float>();
468 ExpandChild( index );
477 void Cluster::DoCollapseAction(const PropertyValueContainer& attributes)
479 if(attributes.size() >= 1)
481 for(PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter)
483 const Property::Value& value = *iter;
485 DALI_ASSERT_ALWAYS(value.GetType() == Property::FLOAT);
486 unsigned int index = value.Get<float>();
487 CollapseChild( index, false );
492 CollapseAllChildren( false );
496 void Cluster::DoTransformAction(const PropertyValueContainer& attributes)
498 DALI_ASSERT_ALWAYS(attributes.size() >= 2);
500 DALI_ASSERT_ALWAYS(attributes[0].GetType() == Property::FLOAT);
501 unsigned int index = attributes[0].Get<float>();
503 Vector3 scale(Vector3::ONE);
504 Quaternion rotation(0.0f, Vector3::ZAXIS);
506 DALI_ASSERT_ALWAYS(attributes[1].GetType() == Property::VECTOR3);
507 attributes[1].Get(position);
509 if(attributes.size()>2)
511 attributes[2].Get(scale);
514 if(attributes.size()>3)
516 attributes[3].Get(rotation);
519 // wrap index around -1 => size - 1
520 index%= mChildren.size();
522 TransformChild(index, position, scale, rotation, AlphaFunctions::EaseOut, 0.5f);
525 void Cluster::OnControlChildRemove(Actor& child)
527 child.RemoveConstraints();
530 bool Cluster::DoAction(BaseObject* object, const std::string& actionName, const std::vector<Property::Value>& attributes)
534 Dali::BaseHandle handle(object);
536 Toolkit::Cluster cluster = Toolkit::Cluster::DownCast(handle);
538 DALI_ASSERT_ALWAYS(cluster);
540 if(Toolkit::Cluster::ACTION_EXPAND == actionName)
542 GetImpl(cluster).DoExpandAction(attributes);
545 else if(Toolkit::Cluster::ACTION_COLLAPSE == actionName)
547 GetImpl(cluster).DoCollapseAction(attributes);
550 else if(Toolkit::Cluster::ACTION_TRANSFORM == actionName)
552 GetImpl(cluster).DoTransformAction(attributes);
559 } // namespace Internal
561 } // namespace Toolkit