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 <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/type-registry-helper.h>
27 #include <dali/integration-api/debug.h>
30 #include <dali-toolkit/public-api/controls/cluster/cluster-style.h>
31 #include <dali-toolkit/internal/controls/cluster/cluster-style-impl.h>
49 Toolkit::ClusterStyleStandard s = Toolkit::ClusterStyleStandard::New( Toolkit::ClusterStyleStandard::ClusterStyle1 );
50 return Toolkit::Cluster::New( s );
53 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::Cluster, Toolkit::Control, Create )
55 DALI_ACTION_REGISTRATION( Toolkit, Cluster, "expand", ACTION_EXPAND )
56 DALI_ACTION_REGISTRATION( Toolkit, Cluster, "collapse", ACTION_COLLAPSE )
57 DALI_ACTION_REGISTRATION( Toolkit, Cluster, "transform", ACTION_TRANSFORM )
59 DALI_TYPE_REGISTRATION_END()
61 const float CLUSTER_STYLE_CONSTRAINT_DURATION = 1.0f;
65 ///////////////////////////////////////////////////////////////////////////////////////////////////
67 ///////////////////////////////////////////////////////////////////////////////////////////////////
69 Dali::Toolkit::Cluster Cluster::New(Toolkit::ClusterStyle& style)
71 // Create the implementation
72 ClusterPtr cluster(new Cluster(style));
74 // Pass ownership to CustomActor via derived handle
75 Dali::Toolkit::Cluster handle(*cluster);
77 // Second-phase init of the implementation
78 // This can only be done after the CustomActor connection has been made...
79 cluster->Initialize();
84 Cluster::Cluster(Toolkit::ClusterStyle& style)
85 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS | DISABLE_SIZE_NEGOTIATION ) ),
91 void Cluster::OnInitialize()
95 void Cluster::OnControlSizeSet( const Vector3& targetSize )
97 mClusterSize = targetSize;
98 GetImpl(mClusterStyle).SetClusterSize(targetSize);
100 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
105 mClusterStyle.ApplyStyle( (*iter).mActor,
106 (*iter).mPositionIndex,
107 AlphaFunctions::EaseOut,
112 UpdateBackground(0.f);
120 void Cluster::AddChild( Actor child )
122 // automatically add child with a position at end.
123 AddChild( child, mChildren.size() );
126 void Cluster::AddChild( Actor child, unsigned int positionIndex )
128 AddChildInfo( ChildInfo(child, positionIndex) );
131 void Cluster::AddChildAt( Actor child, unsigned int index )
133 // automatically add child with a position at end.
134 AddChild( child, mChildren.size() );
137 void Cluster::AddChildAt( Actor child, unsigned int positionIndex, unsigned int index )
139 AddChildInfoAt( ChildInfo(child, positionIndex), index );
142 void Cluster::AddChildInfo( ChildInfo childInfo )
144 AddChildInfoAt(childInfo, mChildren.size());
147 void Cluster::AddChildInfoAt( ChildInfo childInfo, unsigned int index )
149 // check that the child is valid
150 DALI_ASSERT_ALWAYS( childInfo.mActor );
152 ChildInfoIter offset = index < mChildren.size() ? (mChildren.begin() + index) : mChildren.end();
153 // now perform customization on this child.
156 if(childInfo.mActor.GetParent() != Self())
158 Actor& child = childInfo.mActor;
159 const float depth = std::distance(mChildren.begin(), offset);
161 Property::Index depthProperty = child.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
162 if(depthProperty == Property::INVALID_INDEX)
164 child.RegisterProperty(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH, depth);
168 Self().Add( childInfo.mActor );
169 mChildren.insert( offset, childInfo );
171 // Use parent position plus relative position.
172 child.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
174 // remove old constraints
175 child.RemoveConstraints();
177 // apply new constraints to the child
178 mClusterStyle.ApplyStyle(child, childInfo.mPositionIndex, AlphaFunctions::EaseOut, 0.0f);
183 ChildInfoContainer mNewChildren;
184 ChildInfoIter iter = mChildren.begin();
187 for( ; iter != mChildren.end(); ++iter)
191 SetDepth(childInfo, depth);
193 // insert the new childInfo before offset.
194 mNewChildren.push_back(childInfo);
196 // copy all children except the one that we wish to move.
197 if((*iter).mActor != childInfo.mActor)
199 SetDepth(*iter, depth);
201 mNewChildren.push_back(*iter);
207 SetDepth(childInfo, depth);
208 // insert the new childInfo before offset (end).
209 mNewChildren.push_back(childInfo);
212 mChildren = mNewChildren;
214 // Todo somehow adjust their perceived depth.
218 void Cluster::SetDepth( ChildInfo& childInfo, float depth )
220 Property::Index depthProperty = childInfo.mActor.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
221 childInfo.mActor.SetProperty( depthProperty, depth );
224 ChildInfo Cluster::GetChildInfoAt( unsigned int index )
226 // check if we have this position in the cluster
227 if( index < mChildren.size() )
229 // return the child handle
230 return mChildren[ index ];
233 // return an empty handle
237 Actor Cluster::GetChildAt( unsigned int index )
239 // check if we have this position in the cluster
240 if( index < mChildren.size() )
242 // return the child handle
243 return mChildren[ index ].mActor;
246 // return an empty handle
250 Actor Cluster::RemoveChildAt( unsigned int index )
252 DALI_ASSERT_ALWAYS( index < mChildren.size() );
254 ChildInfoIter iter = mChildren.begin() + index;
255 Actor child = (*iter).mActor;
256 mChildren.erase( iter );
257 Self().Remove(child);
258 // note: constraints will automatically be removed in OnControlChildRemove
263 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
265 SetDepth(*iter, depth);
272 void Cluster::ExpandChild( unsigned int index )
274 if( index < mChildren.size() )
276 ChildInfo& childInfo = mChildren[ index ];
277 DALI_ASSERT_ALWAYS(childInfo.mActor);
279 if(!childInfo.mExpanded)
281 // expand child to a random position/angle.
282 const Vector3 clusterSize = Self().GetCurrentSize();
283 const float length = clusterSize.Length() * 0.1f;
284 const float zOffset = 50.0f;
285 const float angle = (rand()%360) * Math::PI / 180.0f;
286 Vector3 position(sin(angle) * length, -cos(angle) * length, zOffset);
287 const float scale(1.2f);
288 const Radian rotate( Degree( (rand()%30) - 15 ) );
290 position += childInfo.mActor.GetCurrentPosition();
292 TransformChild(index,
294 Vector3::ONE * scale,
295 Quaternion(rotate, Vector3::ZAXIS),
296 AlphaFunctions::EaseOut,
302 void Cluster::ExpandAllChildren()
304 for(unsigned int index = 0;index < mChildren.size(); index++)
306 ExpandChild( index );
310 void Cluster::CollapseChild( unsigned int index, bool front )
312 if( index < mChildren.size() )
315 AlphaFunctions::EaseOut,
321 void Cluster::CollapseAllChildren( bool front )
323 for(unsigned int index = 0;index < mChildren.size(); index++)
326 AlphaFunctions::EaseOut,
332 void Cluster::TransformChild( unsigned int index, const Vector3& position, const Vector3& scale, const Quaternion& rotation, AlphaFunction alpha, const TimePeriod& period )
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 = true;
345 child.RemoveConstraints();
346 Animation animation = Animation::New(period.delaySeconds + period.durationSeconds);
347 animation.AnimateTo( Property(child, Actor::Property::POSITION), position, AlphaFunctions::EaseOut, period);
348 animation.AnimateTo( Property(child, Actor::Property::SCALE), scale, AlphaFunctions::EaseOut, period);
349 animation.AnimateTo( Property(child, Actor::Property::ORIENTATION), rotation, AlphaFunctions::EaseOut, period);
355 void Cluster::RestoreChild( unsigned int index, AlphaFunction alpha, const TimePeriod& period, bool front )
357 if( index < mChildren.size() )
359 ChildInfo& childInfo = mChildren[ index ];
360 DALI_ASSERT_ALWAYS(childInfo.mActor);
362 if(childInfo.mExpanded)
364 Actor child = childInfo.mActor;
365 childInfo.mExpanded = false;
367 mClusterStyle.ApplyStyle( child, childInfo.mPositionIndex, alpha, period );
369 const unsigned int hideIndex = front ? mChildren.size() : 0;
370 AddChildInfoAt(childInfo, hideIndex); // move child info to the back or front of the pack.
375 void Cluster::SetBackgroundImage( Actor image )
377 // Replaces the background image.
378 if(mBackgroundImage && mBackgroundImage.GetParent())
380 mBackgroundImage.GetParent().Remove(mBackgroundImage);
383 mBackgroundImage = image;
384 Self().Add(mBackgroundImage);
386 mBackgroundImage.SetAnchorPoint( AnchorPoint::TOP_LEFT );
387 mBackgroundImage.SetParentOrigin( ParentOrigin::TOP_LEFT );
389 UpdateBackground(0.0f);
392 void Cluster::SetTitle( Actor text )
394 // Replaces the title actor.
395 if(mTitle && mTitle.GetParent())
397 mTitle.GetParent().Remove( mTitle );
401 Self().Add( mTitle );
403 mTitle.SetAnchorPoint( AnchorPoint::TOP_LEFT );
404 mTitle.SetParentOrigin( ParentOrigin::TOP_LEFT );
409 void Cluster::SetStyle(Toolkit::ClusterStyle style)
411 unsigned int previousChildrenNum = mChildren.size();
412 mClusterStyle = style;
413 GetImpl(mClusterStyle).SetClusterSize(mClusterSize);
414 unsigned int newChildrenNum = mClusterStyle.GetMaximumNumberOfChildren();
416 // New style supports less children (remove those that no longer belong)
417 if(newChildrenNum < previousChildrenNum)
419 ChildInfoIter removeStart = mChildren.begin() + newChildrenNum;
421 for(ChildInfoIter iter = removeStart; iter != mChildren.end(); ++iter)
423 Actor child = (*iter).mActor;
424 child.RemoveConstraints();
425 Self().Remove(child);
428 mChildren.erase( removeStart, mChildren.end() );
431 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
436 mClusterStyle.ApplyStyle( (*iter).mActor,
437 (*iter).mPositionIndex,
438 AlphaFunctions::EaseOut,
439 CLUSTER_STYLE_CONSTRAINT_DURATION );
443 UpdateBackground(CLUSTER_STYLE_CONSTRAINT_DURATION);
444 UpdateTitle(CLUSTER_STYLE_CONSTRAINT_DURATION);
447 Toolkit::ClusterStyle Cluster::GetStyle() const
449 return mClusterStyle;
452 unsigned int Cluster::GetExpandedCount() const
454 return mExpandedCount;
457 unsigned int Cluster::GetTotalCount() const
459 return mChildren.size();
462 void Cluster::UpdateBackground(float duration)
464 if (mBackgroundImage)
466 mClusterStyle.ApplyStyleToBackground(mBackgroundImage, AlphaFunctions::EaseOut, duration);
470 void Cluster::UpdateTitle(float duration)
474 mClusterStyle.ApplyStyleToTitle(mTitle, AlphaFunctions::EaseOut, duration);
478 void Cluster::DoExpandAction(const PropertyValueContainer& attributes)
480 if(attributes.size() >= 1)
482 for(PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter)
484 const Property::Value& value = *iter;
486 DALI_ASSERT_ALWAYS(value.GetType() == Property::FLOAT);
487 unsigned int index = value.Get<float>();
488 ExpandChild( index );
497 void Cluster::DoCollapseAction(const PropertyValueContainer& attributes)
499 if(attributes.size() >= 1)
501 for(PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter)
503 const Property::Value& value = *iter;
505 DALI_ASSERT_ALWAYS(value.GetType() == Property::FLOAT);
506 unsigned int index = value.Get<float>();
507 CollapseChild( index, false );
512 CollapseAllChildren( false );
516 void Cluster::DoTransformAction(const PropertyValueContainer& attributes)
518 DALI_ASSERT_ALWAYS(attributes.size() >= 2);
520 DALI_ASSERT_ALWAYS(attributes[0].GetType() == Property::FLOAT);
521 unsigned int index = attributes[0].Get<float>();
523 Vector3 scale(Vector3::ONE);
524 Quaternion rotation( Dali::ANGLE_0, Vector3::ZAXIS );
526 DALI_ASSERT_ALWAYS(attributes[1].GetType() == Property::VECTOR3);
527 attributes[1].Get(position);
529 if(attributes.size()>2)
531 attributes[2].Get(scale);
534 if(attributes.size()>3)
536 attributes[3].Get(rotation);
539 // wrap index around -1 => size - 1
540 index%= mChildren.size();
542 TransformChild(index, position, scale, rotation, AlphaFunctions::EaseOut, 0.5f);
545 void Cluster::OnControlChildRemove(Actor& child)
547 child.RemoveConstraints();
550 bool Cluster::DoAction(BaseObject* object, const std::string& actionName, const PropertyValueContainer& attributes)
554 Dali::BaseHandle handle( object );
556 Toolkit::Cluster cluster = Toolkit::Cluster::DownCast( handle );
558 DALI_ASSERT_ALWAYS( cluster );
560 if( 0 == strcmp( actionName.c_str(), ACTION_EXPAND ) )
562 GetImpl( cluster ).DoExpandAction( attributes );
565 else if( 0 == strcmp( actionName.c_str(), ACTION_COLLAPSE ) )
567 GetImpl( cluster ).DoCollapseAction( attributes );
570 else if( 0 == strcmp( actionName.c_str(), ACTION_TRANSFORM ) )
572 GetImpl( cluster ).DoTransformAction( attributes );
579 } // namespace Internal
581 } // namespace Toolkit