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/public-api/object/type-registry-helper.h>
26 #include <dali/integration-api/debug.h>
29 #include <dali-toolkit/public-api/controls/cluster/cluster-style.h>
30 #include <dali-toolkit/internal/controls/cluster/cluster-style-impl.h>
48 Toolkit::ClusterStyleStandard s = Toolkit::ClusterStyleStandard::New( Toolkit::ClusterStyleStandard::ClusterStyle1 );
49 return Toolkit::Cluster::New( s );
52 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Cluster, Toolkit::Control, Create )
54 DALI_ACTION_REGISTRATION( Cluster, "expand", ACTION_EXPAND )
55 DALI_ACTION_REGISTRATION( Cluster, "collapse", ACTION_COLLAPSE )
56 DALI_ACTION_REGISTRATION( Cluster, "transform", ACTION_TRANSFORM )
58 DALI_TYPE_REGISTRATION_END()
60 const float CLUSTER_STYLE_CONSTRAINT_DURATION = 1.0f;
64 ///////////////////////////////////////////////////////////////////////////////////////////////////
66 ///////////////////////////////////////////////////////////////////////////////////////////////////
68 Dali::Toolkit::Cluster Cluster::New(Toolkit::ClusterStyle& style)
70 // Create the implementation
71 ClusterPtr cluster(new Cluster(style));
73 // Pass ownership to CustomActor via derived handle
74 Dali::Toolkit::Cluster handle(*cluster);
76 // Second-phase init of the implementation
77 // This can only be done after the CustomActor connection has been made...
78 cluster->Initialize();
83 Cluster::Cluster(Toolkit::ClusterStyle& style)
84 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
90 void Cluster::OnInitialize()
94 void Cluster::OnControlSizeSet( const Vector3& targetSize )
96 mClusterSize = targetSize;
97 GetImpl(mClusterStyle).SetClusterSize(targetSize);
99 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
104 mClusterStyle.ApplyStyle( (*iter).mActor,
105 (*iter).mPositionIndex,
106 AlphaFunctions::EaseOut,
111 UpdateBackground(0.f);
119 void Cluster::AddChild( Actor child )
121 // automatically add child with a position at end.
122 AddChild( child, mChildren.size() );
125 void Cluster::AddChild( Actor child, unsigned int positionIndex )
127 AddChildInfo( ChildInfo(child, positionIndex) );
130 void Cluster::AddChildAt( Actor child, unsigned int index )
132 // automatically add child with a position at end.
133 AddChild( child, mChildren.size() );
136 void Cluster::AddChildAt( Actor child, unsigned int positionIndex, unsigned int index )
138 AddChildInfoAt( ChildInfo(child, positionIndex), index );
141 void Cluster::AddChildInfo( ChildInfo childInfo )
143 AddChildInfoAt(childInfo, mChildren.size());
146 void Cluster::AddChildInfoAt( ChildInfo childInfo, unsigned int index )
148 // check that the child is valid
149 DALI_ASSERT_ALWAYS( childInfo.mActor );
151 ChildInfoIter offset = index < mChildren.size() ? (mChildren.begin() + index) : mChildren.end();
152 // now perform customization on this child.
155 if(childInfo.mActor.GetParent() != Self())
157 Actor& child = childInfo.mActor;
158 const float depth = std::distance(mChildren.begin(), offset);
160 Property::Index depthProperty = child.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
161 if(depthProperty == Property::INVALID_INDEX)
163 child.RegisterProperty(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH, depth);
167 Self().Add( childInfo.mActor );
168 mChildren.insert( offset, childInfo );
170 // Use parent position plus relative position.
171 child.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
173 // remove old constraints
174 child.RemoveConstraints();
176 // apply new constraints to the child
177 mClusterStyle.ApplyStyle(child, childInfo.mPositionIndex, AlphaFunctions::EaseOut, 0.0f);
182 ChildInfoContainer mNewChildren;
183 ChildInfoIter iter = mChildren.begin();
186 for( ; iter != mChildren.end(); ++iter)
190 SetDepth(childInfo, depth);
192 // insert the new childInfo before offset.
193 mNewChildren.push_back(childInfo);
195 // copy all children except the one that we wish to move.
196 if((*iter).mActor != childInfo.mActor)
198 SetDepth(*iter, depth);
200 mNewChildren.push_back(*iter);
206 SetDepth(childInfo, depth);
207 // insert the new childInfo before offset (end).
208 mNewChildren.push_back(childInfo);
211 mChildren = mNewChildren;
213 // Todo somehow adjust their perceived depth.
217 void Cluster::SetDepth( ChildInfo& childInfo, float depth )
219 Property::Index depthProperty = childInfo.mActor.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
220 childInfo.mActor.SetProperty( depthProperty, depth );
223 ChildInfo Cluster::GetChildInfoAt( unsigned int index )
225 // check if we have this position in the cluster
226 if( index < mChildren.size() )
228 // return the child handle
229 return mChildren[ index ];
232 // return an empty handle
236 Actor Cluster::GetChildAt( unsigned int index )
238 // check if we have this position in the cluster
239 if( index < mChildren.size() )
241 // return the child handle
242 return mChildren[ index ].mActor;
245 // return an empty handle
249 Actor Cluster::RemoveChildAt( unsigned int index )
251 DALI_ASSERT_ALWAYS( index < mChildren.size() );
253 ChildInfoIter iter = mChildren.begin() + index;
254 Actor child = (*iter).mActor;
255 mChildren.erase( iter );
256 Self().Remove(child);
257 // note: constraints will automatically be removed in OnControlChildRemove
262 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
264 SetDepth(*iter, depth);
271 void Cluster::ExpandChild( unsigned int index )
273 if( index < mChildren.size() )
275 ChildInfo& childInfo = mChildren[ index ];
276 DALI_ASSERT_ALWAYS(childInfo.mActor);
278 if(!childInfo.mExpanded)
280 // expand child to a random position/angle.
281 const Vector3 clusterSize = Self().GetCurrentSize();
282 const float length = clusterSize.Length() * 0.1f;
283 const float zOffset = 50.0f;
284 const float angle = (rand()%360) * Math::PI / 180.0f;
285 Vector3 position(sin(angle) * length, -cos(angle) * length, zOffset);
286 const float scale(1.2f);
287 const float rotate = ((rand()%30) - 15) * Math::PI / 180.0f;
289 position += childInfo.mActor.GetCurrentPosition();
291 TransformChild(index,
293 Vector3::ONE * scale,
294 Quaternion(rotate, Vector3::ZAXIS),
295 AlphaFunctions::EaseOut,
301 void Cluster::ExpandAllChildren()
303 for(unsigned int index = 0;index < mChildren.size(); index++)
305 ExpandChild( index );
309 void Cluster::CollapseChild( unsigned int index, bool front )
311 if( index < mChildren.size() )
314 AlphaFunctions::EaseOut,
320 void Cluster::CollapseAllChildren( bool front )
322 for(unsigned int index = 0;index < mChildren.size(); index++)
325 AlphaFunctions::EaseOut,
331 void Cluster::TransformChild( unsigned int index, const Vector3& position, const Vector3& scale, const Quaternion& rotation, AlphaFunction alpha, const TimePeriod& period )
333 if( index < mChildren.size() )
335 ChildInfo& childInfo = mChildren[ index ];
336 DALI_ASSERT_ALWAYS(childInfo.mActor);
338 if(!childInfo.mExpanded)
340 Actor child = childInfo.mActor;
341 childInfo.mExpanded = true;
344 child.RemoveConstraints();
345 Animation animation = Animation::New(period.delaySeconds + period.durationSeconds);
346 animation.AnimateTo( Property(child, Actor::Property::POSITION), position, AlphaFunctions::EaseOut, period);
347 animation.AnimateTo( Property(child, Actor::Property::SCALE), scale, AlphaFunctions::EaseOut, period);
348 animation.AnimateTo( Property(child, Actor::Property::ROTATION), rotation, AlphaFunctions::EaseOut, period);
354 void Cluster::RestoreChild( unsigned int index, AlphaFunction alpha, const TimePeriod& period, bool front )
356 if( index < mChildren.size() )
358 ChildInfo& childInfo = mChildren[ index ];
359 DALI_ASSERT_ALWAYS(childInfo.mActor);
361 if(childInfo.mExpanded)
363 Actor child = childInfo.mActor;
364 childInfo.mExpanded = false;
366 mClusterStyle.ApplyStyle( child, childInfo.mPositionIndex, alpha, period );
368 const unsigned int hideIndex = front ? mChildren.size() : 0;
369 AddChildInfoAt(childInfo, hideIndex); // move child info to the back or front of the pack.
374 void Cluster::SetBackgroundImage( Actor image )
376 // Replaces the background image.
377 if(mBackgroundImage && mBackgroundImage.GetParent())
379 mBackgroundImage.GetParent().Remove(mBackgroundImage);
382 mBackgroundImage = image;
383 Self().Add(mBackgroundImage);
385 mBackgroundImage.SetAnchorPoint( AnchorPoint::TOP_LEFT );
386 mBackgroundImage.SetParentOrigin( ParentOrigin::TOP_LEFT );
388 UpdateBackground(0.0f);
391 void Cluster::SetTitle( Actor text )
393 // Replaces the title actor.
394 if(mTitle && mTitle.GetParent())
396 mTitle.GetParent().Remove( mTitle );
400 Self().Add( mTitle );
402 mTitle.SetAnchorPoint( AnchorPoint::TOP_LEFT );
403 mTitle.SetParentOrigin( ParentOrigin::TOP_LEFT );
408 void Cluster::SetStyle(Toolkit::ClusterStyle style)
410 unsigned int previousChildrenNum = mChildren.size();
411 mClusterStyle = style;
412 GetImpl(mClusterStyle).SetClusterSize(mClusterSize);
413 unsigned int newChildrenNum = mClusterStyle.GetMaximumNumberOfChildren();
415 // New style supports less children (remove those that no longer belong)
416 if(newChildrenNum < previousChildrenNum)
418 ChildInfoIter removeStart = mChildren.begin() + newChildrenNum;
420 for(ChildInfoIter iter = removeStart; iter != mChildren.end(); ++iter)
422 Actor child = (*iter).mActor;
423 child.RemoveConstraints();
424 Self().Remove(child);
427 mChildren.erase( removeStart, mChildren.end() );
430 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
435 mClusterStyle.ApplyStyle( (*iter).mActor,
436 (*iter).mPositionIndex,
437 AlphaFunctions::EaseOut,
438 CLUSTER_STYLE_CONSTRAINT_DURATION );
442 UpdateBackground(CLUSTER_STYLE_CONSTRAINT_DURATION);
443 UpdateTitle(CLUSTER_STYLE_CONSTRAINT_DURATION);
446 Toolkit::ClusterStyle Cluster::GetStyle() const
448 return mClusterStyle;
451 unsigned int Cluster::GetExpandedCount() const
453 return mExpandedCount;
456 unsigned int Cluster::GetTotalCount() const
458 return mChildren.size();
461 void Cluster::UpdateBackground(float duration)
463 if (mBackgroundImage)
465 mClusterStyle.ApplyStyleToBackground(mBackgroundImage, AlphaFunctions::EaseOut, duration);
469 void Cluster::UpdateTitle(float duration)
473 mClusterStyle.ApplyStyleToTitle(mTitle, AlphaFunctions::EaseOut, duration);
477 void Cluster::DoExpandAction(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 ExpandChild( index );
496 void Cluster::DoCollapseAction(const PropertyValueContainer& attributes)
498 if(attributes.size() >= 1)
500 for(PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter)
502 const Property::Value& value = *iter;
504 DALI_ASSERT_ALWAYS(value.GetType() == Property::FLOAT);
505 unsigned int index = value.Get<float>();
506 CollapseChild( index, false );
511 CollapseAllChildren( false );
515 void Cluster::DoTransformAction(const PropertyValueContainer& attributes)
517 DALI_ASSERT_ALWAYS(attributes.size() >= 2);
519 DALI_ASSERT_ALWAYS(attributes[0].GetType() == Property::FLOAT);
520 unsigned int index = attributes[0].Get<float>();
522 Vector3 scale(Vector3::ONE);
523 Quaternion rotation(0.0f, Vector3::ZAXIS);
525 DALI_ASSERT_ALWAYS(attributes[1].GetType() == Property::VECTOR3);
526 attributes[1].Get(position);
528 if(attributes.size()>2)
530 attributes[2].Get(scale);
533 if(attributes.size()>3)
535 attributes[3].Get(rotation);
538 // wrap index around -1 => size - 1
539 index%= mChildren.size();
541 TransformChild(index, position, scale, rotation, AlphaFunctions::EaseOut, 0.5f);
544 void Cluster::OnControlChildRemove(Actor& child)
546 child.RemoveConstraints();
549 bool Cluster::DoAction(BaseObject* object, const std::string& actionName, const PropertyValueContainer& attributes)
553 Dali::BaseHandle handle( object );
555 Toolkit::Cluster cluster = Toolkit::Cluster::DownCast( handle );
557 DALI_ASSERT_ALWAYS( cluster );
559 if( 0 == strcmp( actionName.c_str(), ACTION_EXPAND ) )
561 GetImpl( cluster ).DoExpandAction( attributes );
564 else if( 0 == strcmp( actionName.c_str(), ACTION_COLLAPSE ) )
566 GetImpl( cluster ).DoCollapseAction( attributes );
569 else if( 0 == strcmp( actionName.c_str(), ACTION_TRANSFORM ) )
571 GetImpl( cluster ).DoTransformAction( attributes );
578 } // namespace Internal
580 } // namespace Toolkit