2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/internal/controls/cluster/cluster-impl.h>
23 #include <dali/public-api/animation/animation.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/integration-api/debug.h>
28 #include <dali-toolkit/public-api/controls/cluster/cluster-style.h>
29 #include <dali-toolkit/internal/controls/cluster/cluster-style-impl.h>
33 namespace // unnamed namespace
36 const float CLUSTER_STYLE_CONSTRAINT_DURATION = 1.0f;
54 const char* const ACTION_EXPAND = "expand";
55 const char* const ACTION_COLLAPSE = "collapse";
56 const char* const ACTION_TRANSFORM = "transform";
60 Toolkit::ClusterStyleStandard s = Toolkit::ClusterStyleStandard::New( Toolkit::ClusterStyleStandard::ClusterStyle1 );
61 return Toolkit::Cluster::New( s );
64 TypeRegistration mType( typeid( Toolkit::Cluster ), typeid( Toolkit::Control ), Create );
66 TypeAction a1( mType, ACTION_EXPAND, &Cluster::DoAction );
67 TypeAction a2( mType, ACTION_COLLAPSE, &Cluster::DoAction );
68 TypeAction a3( mType, ACTION_TRANSFORM, &Cluster::DoAction );
72 ///////////////////////////////////////////////////////////////////////////////////////////////////
74 ///////////////////////////////////////////////////////////////////////////////////////////////////
76 Dali::Toolkit::Cluster Cluster::New(Toolkit::ClusterStyle& style)
78 // Create the implementation
79 ClusterPtr cluster(new Cluster(style));
81 // Pass ownership to CustomActor via derived handle
82 Dali::Toolkit::Cluster handle(*cluster);
84 // Second-phase init of the implementation
85 // This can only be done after the CustomActor connection has been made...
86 cluster->Initialize();
91 Cluster::Cluster(Toolkit::ClusterStyle& style)
92 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
98 void Cluster::OnInitialize()
102 void Cluster::OnControlSizeSet( const Vector3& targetSize )
104 mClusterSize = targetSize;
105 GetImpl(mClusterStyle).SetClusterSize(targetSize);
107 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
112 mClusterStyle.ApplyStyle( (*iter).mActor,
113 (*iter).mPositionIndex,
114 AlphaFunctions::EaseOut,
119 UpdateBackground(0.f);
127 void Cluster::AddChild( Actor child )
129 // automatically add child with a position at end.
130 AddChild( child, mChildren.size() );
133 void Cluster::AddChild( Actor child, unsigned int positionIndex )
135 AddChildInfo( ChildInfo(child, positionIndex) );
138 void Cluster::AddChildAt( Actor child, unsigned int index )
140 // automatically add child with a position at end.
141 AddChild( child, mChildren.size() );
144 void Cluster::AddChildAt( Actor child, unsigned int positionIndex, unsigned int index )
146 AddChildInfoAt( ChildInfo(child, positionIndex), index );
149 void Cluster::AddChildInfo( ChildInfo childInfo )
151 AddChildInfoAt(childInfo, mChildren.size());
154 void Cluster::AddChildInfoAt( ChildInfo childInfo, unsigned int index )
156 // check that the child is valid
157 DALI_ASSERT_ALWAYS( childInfo.mActor );
159 ChildInfoIter offset = index < mChildren.size() ? (mChildren.begin() + index) : mChildren.end();
160 // now perform customization on this child.
163 if(childInfo.mActor.GetParent() != Self())
165 Actor& child = childInfo.mActor;
166 const float depth = std::distance(mChildren.begin(), offset);
168 Property::Index depthProperty = child.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
169 if(depthProperty == Property::INVALID_INDEX)
171 child.RegisterProperty(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH, depth);
175 Self().Add( childInfo.mActor );
176 mChildren.insert( offset, childInfo );
178 // Use parent position plus relative position.
179 child.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
181 // remove old constraints
182 child.RemoveConstraints();
184 // apply new constraints to the child
185 mClusterStyle.ApplyStyle(child, childInfo.mPositionIndex, AlphaFunctions::EaseOut, 0.0f);
190 ChildInfoContainer mNewChildren;
191 ChildInfoIter iter = mChildren.begin();
194 for( ; iter != mChildren.end(); ++iter)
198 SetDepth(childInfo, depth);
200 // insert the new childInfo before offset.
201 mNewChildren.push_back(childInfo);
203 // copy all children except the one that we wish to move.
204 if((*iter).mActor != childInfo.mActor)
206 SetDepth(*iter, depth);
208 mNewChildren.push_back(*iter);
214 SetDepth(childInfo, depth);
215 // insert the new childInfo before offset (end).
216 mNewChildren.push_back(childInfo);
219 mChildren = mNewChildren;
221 // Todo somehow adjust their perceived depth.
225 void Cluster::SetDepth( ChildInfo& childInfo, float depth )
227 Property::Index depthProperty = childInfo.mActor.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
228 childInfo.mActor.SetProperty( depthProperty, depth );
231 ChildInfo Cluster::GetChildInfoAt( unsigned int index )
233 // check if we have this position in the cluster
234 if( index < mChildren.size() )
236 // return the child handle
237 return mChildren[ index ];
240 // return an empty handle
244 Actor Cluster::GetChildAt( unsigned int index )
246 // check if we have this position in the cluster
247 if( index < mChildren.size() )
249 // return the child handle
250 return mChildren[ index ].mActor;
253 // return an empty handle
257 Actor Cluster::RemoveChildAt( unsigned int index )
259 DALI_ASSERT_ALWAYS( index < mChildren.size() );
261 ChildInfoIter iter = mChildren.begin() + index;
262 Actor child = (*iter).mActor;
263 mChildren.erase( iter );
264 Self().Remove(child);
265 // note: constraints will automatically be removed in OnControlChildRemove
270 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
272 SetDepth(*iter, depth);
279 void Cluster::ExpandChild( unsigned int index )
281 if( index < mChildren.size() )
283 ChildInfo& childInfo = mChildren[ index ];
284 DALI_ASSERT_ALWAYS(childInfo.mActor);
286 if(!childInfo.mExpanded)
288 // expand child to a random position/angle.
289 const Vector3 clusterSize = Self().GetCurrentSize();
290 const float length = clusterSize.Length() * 0.1f;
291 const float zOffset = 50.0f;
292 const float angle = (rand()%360) * Math::PI / 180.0f;
293 Vector3 position(sin(angle) * length, -cos(angle) * length, zOffset);
294 const float scale(1.2f);
295 const float rotate = ((rand()%30) - 15) * Math::PI / 180.0f;
297 position += childInfo.mActor.GetCurrentPosition();
299 TransformChild(index,
301 Vector3::ONE * scale,
302 Quaternion(rotate, Vector3::ZAXIS),
303 AlphaFunctions::EaseOut,
309 void Cluster::ExpandAllChildren()
311 for(unsigned int index = 0;index < mChildren.size(); index++)
313 ExpandChild( index );
317 void Cluster::CollapseChild( unsigned int index, bool front )
319 if( index < mChildren.size() )
322 AlphaFunctions::EaseOut,
328 void Cluster::CollapseAllChildren( bool front )
330 for(unsigned int index = 0;index < mChildren.size(); index++)
333 AlphaFunctions::EaseOut,
339 void Cluster::TransformChild( unsigned int index, const Vector3& position, const Vector3& scale, const Quaternion& rotation, AlphaFunction alpha, const TimePeriod& period )
341 if( index < mChildren.size() )
343 ChildInfo& childInfo = mChildren[ index ];
344 DALI_ASSERT_ALWAYS(childInfo.mActor);
346 if(!childInfo.mExpanded)
348 Actor child = childInfo.mActor;
349 childInfo.mExpanded = true;
352 child.RemoveConstraints();
353 Animation animation = Animation::New(period.delaySeconds + period.durationSeconds);
354 animation.AnimateTo( Property(child, Actor::POSITION), position, AlphaFunctions::EaseOut, period);
355 animation.AnimateTo( Property(child, Actor::SCALE), scale, AlphaFunctions::EaseOut, period);
356 animation.AnimateTo( Property(child, Actor::ROTATION), rotation, AlphaFunctions::EaseOut, period);
362 void Cluster::RestoreChild( unsigned int index, AlphaFunction alpha, const TimePeriod& period, bool front )
364 if( index < mChildren.size() )
366 ChildInfo& childInfo = mChildren[ index ];
367 DALI_ASSERT_ALWAYS(childInfo.mActor);
369 if(childInfo.mExpanded)
371 Actor child = childInfo.mActor;
372 childInfo.mExpanded = false;
374 mClusterStyle.ApplyStyle( child, childInfo.mPositionIndex, alpha, period );
376 const unsigned int hideIndex = front ? mChildren.size() : 0;
377 AddChildInfoAt(childInfo, hideIndex); // move child info to the back or front of the pack.
382 void Cluster::SetBackgroundImage( Actor image )
384 // Replaces the background image.
385 if(mBackgroundImage && mBackgroundImage.GetParent())
387 mBackgroundImage.GetParent().Remove(mBackgroundImage);
390 mBackgroundImage = image;
391 Self().Add(mBackgroundImage);
393 mBackgroundImage.SetAnchorPoint( AnchorPoint::TOP_LEFT );
394 mBackgroundImage.SetParentOrigin( ParentOrigin::TOP_LEFT );
396 UpdateBackground(0.0f);
399 void Cluster::SetTitle( Actor text )
401 // Replaces the title actor.
402 if(mTitle && mTitle.GetParent())
404 mTitle.GetParent().Remove( mTitle );
408 Self().Add( mTitle );
410 mTitle.SetAnchorPoint( AnchorPoint::TOP_LEFT );
411 mTitle.SetParentOrigin( ParentOrigin::TOP_LEFT );
416 void Cluster::SetStyle(Toolkit::ClusterStyle style)
418 unsigned int previousChildrenNum = mChildren.size();
419 mClusterStyle = style;
420 GetImpl(mClusterStyle).SetClusterSize(mClusterSize);
421 unsigned int newChildrenNum = mClusterStyle.GetMaximumNumberOfChildren();
423 // New style supports less children (remove those that no longer belong)
424 if(newChildrenNum < previousChildrenNum)
426 ChildInfoIter removeStart = mChildren.begin() + newChildrenNum;
428 for(ChildInfoIter iter = removeStart; iter != mChildren.end(); ++iter)
430 Actor child = (*iter).mActor;
431 child.RemoveConstraints();
432 Self().Remove(child);
435 mChildren.erase( removeStart, mChildren.end() );
438 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
443 mClusterStyle.ApplyStyle( (*iter).mActor,
444 (*iter).mPositionIndex,
445 AlphaFunctions::EaseOut,
446 CLUSTER_STYLE_CONSTRAINT_DURATION );
450 UpdateBackground(CLUSTER_STYLE_CONSTRAINT_DURATION);
451 UpdateTitle(CLUSTER_STYLE_CONSTRAINT_DURATION);
454 Toolkit::ClusterStyle Cluster::GetStyle() const
456 return mClusterStyle;
459 unsigned int Cluster::GetExpandedCount() const
461 return mExpandedCount;
464 unsigned int Cluster::GetTotalCount() const
466 return mChildren.size();
469 void Cluster::UpdateBackground(float duration)
471 if (mBackgroundImage)
473 mClusterStyle.ApplyStyleToBackground(mBackgroundImage, AlphaFunctions::EaseOut, duration);
477 void Cluster::UpdateTitle(float duration)
481 mClusterStyle.ApplyStyleToTitle(mTitle, AlphaFunctions::EaseOut, duration);
485 void Cluster::DoExpandAction(const PropertyValueContainer& attributes)
487 if(attributes.size() >= 1)
489 for(PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter)
491 const Property::Value& value = *iter;
493 DALI_ASSERT_ALWAYS(value.GetType() == Property::FLOAT);
494 unsigned int index = value.Get<float>();
495 ExpandChild( index );
504 void Cluster::DoCollapseAction(const PropertyValueContainer& attributes)
506 if(attributes.size() >= 1)
508 for(PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter)
510 const Property::Value& value = *iter;
512 DALI_ASSERT_ALWAYS(value.GetType() == Property::FLOAT);
513 unsigned int index = value.Get<float>();
514 CollapseChild( index, false );
519 CollapseAllChildren( false );
523 void Cluster::DoTransformAction(const PropertyValueContainer& attributes)
525 DALI_ASSERT_ALWAYS(attributes.size() >= 2);
527 DALI_ASSERT_ALWAYS(attributes[0].GetType() == Property::FLOAT);
528 unsigned int index = attributes[0].Get<float>();
530 Vector3 scale(Vector3::ONE);
531 Quaternion rotation(0.0f, Vector3::ZAXIS);
533 DALI_ASSERT_ALWAYS(attributes[1].GetType() == Property::VECTOR3);
534 attributes[1].Get(position);
536 if(attributes.size()>2)
538 attributes[2].Get(scale);
541 if(attributes.size()>3)
543 attributes[3].Get(rotation);
546 // wrap index around -1 => size - 1
547 index%= mChildren.size();
549 TransformChild(index, position, scale, rotation, AlphaFunctions::EaseOut, 0.5f);
552 void Cluster::OnControlChildRemove(Actor& child)
554 child.RemoveConstraints();
557 bool Cluster::DoAction(BaseObject* object, const std::string& actionName, const PropertyValueContainer& attributes)
561 Dali::BaseHandle handle( object );
563 Toolkit::Cluster cluster = Toolkit::Cluster::DownCast( handle );
565 DALI_ASSERT_ALWAYS( cluster );
567 if( 0 == strcmp( actionName.c_str(), ACTION_EXPAND ) )
569 GetImpl( cluster ).DoExpandAction( attributes );
572 else if( 0 == strcmp( actionName.c_str(), ACTION_COLLAPSE ) )
574 GetImpl( cluster ).DoCollapseAction( attributes );
577 else if( 0 == strcmp( actionName.c_str(), ACTION_TRANSFORM ) )
579 GetImpl( cluster ).DoTransformAction( attributes );
586 } // namespace Internal
588 } // namespace Toolkit