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 Toolkit::ClusterStyleStandard s = Toolkit::ClusterStyleStandard::New(Toolkit::ClusterStyleStandard::ClusterStyle1);
55 return Toolkit::Cluster::New( s );
58 TypeRegistration mType( typeid(Toolkit::Cluster), typeid(Toolkit::Control), Create );
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);
66 ///////////////////////////////////////////////////////////////////////////////////////////////////
68 ///////////////////////////////////////////////////////////////////////////////////////////////////
70 Dali::Toolkit::Cluster Cluster::New(Toolkit::ClusterStyle& style)
72 // Create the implementation
73 ClusterPtr cluster(new Cluster(style));
75 // Pass ownership to CustomActor via derived handle
76 Dali::Toolkit::Cluster handle(*cluster);
78 // Second-phase init of the implementation
79 // This can only be done after the CustomActor connection has been made...
80 cluster->Initialize();
85 Cluster::Cluster(Toolkit::ClusterStyle& style)
86 : Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ),
92 void Cluster::OnInitialize()
96 void Cluster::OnControlSizeSet( const Vector3& targetSize )
98 mClusterSize = targetSize;
99 GetImpl(mClusterStyle).SetClusterSize(targetSize);
101 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
106 mClusterStyle.ApplyStyle( (*iter).mActor,
107 (*iter).mPositionIndex,
108 AlphaFunctions::EaseOut,
113 UpdateBackground(0.f);
121 void Cluster::AddChild( Actor child )
123 // automatically add child with a position at end.
124 AddChild( child, mChildren.size() );
127 void Cluster::AddChild( Actor child, unsigned int positionIndex )
129 AddChildInfo( ChildInfo(child, positionIndex) );
132 void Cluster::AddChildAt( Actor child, unsigned int index )
134 // automatically add child with a position at end.
135 AddChild( child, mChildren.size() );
138 void Cluster::AddChildAt( Actor child, unsigned int positionIndex, unsigned int index )
140 AddChildInfoAt( ChildInfo(child, positionIndex), index );
143 void Cluster::AddChildInfo( ChildInfo childInfo )
145 AddChildInfoAt(childInfo, mChildren.size());
148 void Cluster::AddChildInfoAt( ChildInfo childInfo, unsigned int index )
150 // check that the child is valid
151 DALI_ASSERT_ALWAYS( childInfo.mActor );
153 ChildInfoIter offset = index < mChildren.size() ? (mChildren.begin() + index) : mChildren.end();
154 // now perform customization on this child.
157 if(childInfo.mActor.GetParent() != Self())
159 Actor& child = childInfo.mActor;
160 const float depth = std::distance(mChildren.begin(), offset);
162 Property::Index depthProperty = child.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
163 if(depthProperty == Property::INVALID_INDEX)
165 child.RegisterProperty(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH, depth);
169 Self().Add( childInfo.mActor );
170 mChildren.insert( offset, childInfo );
172 // Use parent position plus relative position.
173 child.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
175 // remove old constraints
176 child.RemoveConstraints();
178 // apply new constraints to the child
179 mClusterStyle.ApplyStyle(child, childInfo.mPositionIndex, AlphaFunctions::EaseOut, 0.0f);
184 ChildInfoContainer mNewChildren;
185 ChildInfoIter iter = mChildren.begin();
188 for( ; iter != mChildren.end(); ++iter)
192 SetDepth(childInfo, depth);
194 // insert the new childInfo before offset.
195 mNewChildren.push_back(childInfo);
197 // copy all children except the one that we wish to move.
198 if((*iter).mActor != childInfo.mActor)
200 SetDepth(*iter, depth);
202 mNewChildren.push_back(*iter);
208 SetDepth(childInfo, depth);
209 // insert the new childInfo before offset (end).
210 mNewChildren.push_back(childInfo);
213 mChildren = mNewChildren;
215 // Todo somehow adjust their perceived depth.
219 void Cluster::SetDepth( ChildInfo& childInfo, float depth )
221 Property::Index depthProperty = childInfo.mActor.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
222 childInfo.mActor.SetProperty( depthProperty, depth );
225 ChildInfo Cluster::GetChildInfoAt( unsigned int index )
227 // check if we have this position in the cluster
228 if( index < mChildren.size() )
230 // return the child handle
231 return mChildren[ index ];
234 // return an empty handle
238 Actor Cluster::GetChildAt( unsigned int index )
240 // check if we have this position in the cluster
241 if( index < mChildren.size() )
243 // return the child handle
244 return mChildren[ index ].mActor;
247 // return an empty handle
251 Actor Cluster::RemoveChildAt( unsigned int index )
253 DALI_ASSERT_ALWAYS( index < mChildren.size() );
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
264 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
266 SetDepth(*iter, depth);
273 void Cluster::ExpandChild( unsigned int index )
275 if( index < mChildren.size() )
277 ChildInfo& childInfo = mChildren[ index ];
278 DALI_ASSERT_ALWAYS(childInfo.mActor);
280 if(!childInfo.mExpanded)
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;
291 position += childInfo.mActor.GetCurrentPosition();
293 TransformChild(index,
295 Vector3::ONE * scale,
296 Quaternion(rotate, Vector3::ZAXIS),
297 AlphaFunctions::EaseOut,
303 void Cluster::ExpandAllChildren()
305 for(unsigned int index = 0;index < mChildren.size(); index++)
307 ExpandChild( index );
311 void Cluster::CollapseChild( unsigned int index, bool front )
313 if( index < mChildren.size() )
316 AlphaFunctions::EaseOut,
322 void Cluster::CollapseAllChildren( bool front )
324 for(unsigned int index = 0;index < mChildren.size(); index++)
327 AlphaFunctions::EaseOut,
333 void Cluster::TransformChild( unsigned int index, const Vector3& position, const Vector3& scale, const Quaternion& rotation, AlphaFunction alpha, const TimePeriod& period )
335 if( index < mChildren.size() )
337 ChildInfo& childInfo = mChildren[ index ];
338 DALI_ASSERT_ALWAYS(childInfo.mActor);
340 if(!childInfo.mExpanded)
342 Actor child = childInfo.mActor;
343 childInfo.mExpanded = true;
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);
356 void Cluster::RestoreChild( unsigned int index, AlphaFunction alpha, const TimePeriod& period, bool front )
358 if( index < mChildren.size() )
360 ChildInfo& childInfo = mChildren[ index ];
361 DALI_ASSERT_ALWAYS(childInfo.mActor);
363 if(childInfo.mExpanded)
365 Actor child = childInfo.mActor;
366 childInfo.mExpanded = false;
368 mClusterStyle.ApplyStyle( child, childInfo.mPositionIndex, alpha, period );
370 const unsigned int hideIndex = front ? mChildren.size() : 0;
371 AddChildInfoAt(childInfo, hideIndex); // move child info to the back or front of the pack.
376 void Cluster::SetBackgroundImage( Actor image )
378 // Replaces the background image.
379 if(mBackgroundImage && mBackgroundImage.GetParent())
381 mBackgroundImage.GetParent().Remove(mBackgroundImage);
384 mBackgroundImage = image;
385 Self().Add(mBackgroundImage);
387 mBackgroundImage.SetAnchorPoint( AnchorPoint::TOP_LEFT );
388 mBackgroundImage.SetParentOrigin( ParentOrigin::TOP_LEFT );
390 UpdateBackground(0.0f);
393 void Cluster::SetTitle( Actor text )
395 // Replaces the title actor.
396 if(mTitle && mTitle.GetParent())
398 mTitle.GetParent().Remove( mTitle );
402 Self().Add( mTitle );
404 mTitle.SetAnchorPoint( AnchorPoint::TOP_LEFT );
405 mTitle.SetParentOrigin( ParentOrigin::TOP_LEFT );
410 void Cluster::SetStyle(Toolkit::ClusterStyle style)
412 unsigned int previousChildrenNum = mChildren.size();
413 mClusterStyle = style;
414 GetImpl(mClusterStyle).SetClusterSize(mClusterSize);
415 unsigned int newChildrenNum = mClusterStyle.GetMaximumNumberOfChildren();
417 // New style supports less children (remove those that no longer belong)
418 if(newChildrenNum < previousChildrenNum)
420 ChildInfoIter removeStart = mChildren.begin() + newChildrenNum;
422 for(ChildInfoIter iter = removeStart; iter != mChildren.end(); ++iter)
424 Actor child = (*iter).mActor;
425 child.RemoveConstraints();
426 Self().Remove(child);
429 mChildren.erase( removeStart, mChildren.end() );
432 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
437 mClusterStyle.ApplyStyle( (*iter).mActor,
438 (*iter).mPositionIndex,
439 AlphaFunctions::EaseOut,
440 CLUSTER_STYLE_CONSTRAINT_DURATION );
444 UpdateBackground(CLUSTER_STYLE_CONSTRAINT_DURATION);
445 UpdateTitle(CLUSTER_STYLE_CONSTRAINT_DURATION);
448 Toolkit::ClusterStyle Cluster::GetStyle() const
450 return mClusterStyle;
453 unsigned int Cluster::GetExpandedCount() const
455 return mExpandedCount;
458 unsigned int Cluster::GetTotalCount() const
460 return mChildren.size();
463 void Cluster::UpdateBackground(float duration)
465 if (mBackgroundImage)
467 mClusterStyle.ApplyStyleToBackground(mBackgroundImage, AlphaFunctions::EaseOut, duration);
471 void Cluster::UpdateTitle(float duration)
475 mClusterStyle.ApplyStyleToTitle(mTitle, AlphaFunctions::EaseOut, duration);
479 void Cluster::DoExpandAction(const PropertyValueContainer& attributes)
481 if(attributes.size() >= 1)
483 for(PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter)
485 const Property::Value& value = *iter;
487 DALI_ASSERT_ALWAYS(value.GetType() == Property::FLOAT);
488 unsigned int index = value.Get<float>();
489 ExpandChild( index );
498 void Cluster::DoCollapseAction(const PropertyValueContainer& attributes)
500 if(attributes.size() >= 1)
502 for(PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter)
504 const Property::Value& value = *iter;
506 DALI_ASSERT_ALWAYS(value.GetType() == Property::FLOAT);
507 unsigned int index = value.Get<float>();
508 CollapseChild( index, false );
513 CollapseAllChildren( false );
517 void Cluster::DoTransformAction(const PropertyValueContainer& attributes)
519 DALI_ASSERT_ALWAYS(attributes.size() >= 2);
521 DALI_ASSERT_ALWAYS(attributes[0].GetType() == Property::FLOAT);
522 unsigned int index = attributes[0].Get<float>();
524 Vector3 scale(Vector3::ONE);
525 Quaternion rotation(0.0f, Vector3::ZAXIS);
527 DALI_ASSERT_ALWAYS(attributes[1].GetType() == Property::VECTOR3);
528 attributes[1].Get(position);
530 if(attributes.size()>2)
532 attributes[2].Get(scale);
535 if(attributes.size()>3)
537 attributes[3].Get(rotation);
540 // wrap index around -1 => size - 1
541 index%= mChildren.size();
543 TransformChild(index, position, scale, rotation, AlphaFunctions::EaseOut, 0.5f);
546 void Cluster::OnControlChildRemove(Actor& child)
548 child.RemoveConstraints();
551 bool Cluster::DoAction(BaseObject* object, const std::string& actionName, const PropertyValueContainer& attributes)
555 Dali::BaseHandle handle(object);
557 Toolkit::Cluster cluster = Toolkit::Cluster::DownCast(handle);
559 DALI_ASSERT_ALWAYS(cluster);
561 if(Toolkit::Cluster::ACTION_EXPAND == actionName)
563 GetImpl(cluster).DoExpandAction(attributes);
566 else if(Toolkit::Cluster::ACTION_COLLAPSE == actionName)
568 GetImpl(cluster).DoCollapseAction(attributes);
571 else if(Toolkit::Cluster::ACTION_TRANSFORM == actionName)
573 GetImpl(cluster).DoTransformAction(attributes);
580 } // namespace Internal
582 } // namespace Toolkit