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/integration-api/debug.h>
26 #include <dali-toolkit/public-api/controls/cluster/cluster-style.h>
31 namespace // unnamed namespace
34 const float CLUSTER_STYLE_CONSTRAINT_DURATION = 1.0f;
52 Toolkit::ClusterStyleStandard s = Toolkit::ClusterStyleStandard::New(Toolkit::ClusterStyleStandard::ClusterStyle1);
53 return Toolkit::Cluster::New( s );
56 TypeRegistration mType( typeid(Toolkit::Cluster), typeid(Toolkit::Control), Create );
58 TypeAction a1(mType, Toolkit::Cluster::ACTION_EXPAND , &Cluster::DoAction);
59 TypeAction a2(mType, Toolkit::Cluster::ACTION_COLLAPSE , &Cluster::DoAction);
60 TypeAction a3(mType, Toolkit::Cluster::ACTION_TRANSFORM, &Cluster::DoAction);
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()
98 void Cluster::AddChild( Actor child )
100 // automatically add child with a position at end.
101 AddChild( child, mChildren.size() );
104 void Cluster::AddChild( Actor child, unsigned int positionIndex )
106 AddChildInfo( ChildInfo(child, positionIndex) );
109 void Cluster::AddChildAt( Actor child, unsigned int index )
111 // automatically add child with a position at end.
112 AddChild( child, mChildren.size() );
115 void Cluster::AddChildAt( Actor child, unsigned int positionIndex, unsigned int index )
117 AddChildInfoAt( ChildInfo(child, positionIndex), index );
120 void Cluster::AddChildInfo( ChildInfo childInfo )
122 AddChildInfoAt(childInfo, mChildren.size());
125 void Cluster::AddChildInfoAt( ChildInfo childInfo, unsigned int index )
127 // check that the child is valid
128 DALI_ASSERT_ALWAYS( childInfo.mActor );
130 ChildInfoIter offset = index < mChildren.size() ? (mChildren.begin() + index) : mChildren.end();
131 // now perform customization on this child.
134 if(childInfo.mActor.GetParent() != Self())
136 Actor& child = childInfo.mActor;
137 const float depth = std::distance(mChildren.begin(), offset);
139 Property::Index depthProperty = child.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
140 if(depthProperty == Property::INVALID_INDEX)
142 depthProperty = child.RegisterProperty(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH, depth);
146 Self().Add( childInfo.mActor );
147 mChildren.insert( offset, childInfo );
149 // Use parent position plus relative position.
150 child.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
152 // remove old constraints
153 child.RemoveConstraints();
155 // apply new constraints to the child
156 mClusterStyle.ApplyStyle(child, childInfo.mPositionIndex, AlphaFunctions::EaseOut, 0.0f);
161 ChildInfoContainer mNewChildren;
162 ChildInfoIter iter = mChildren.begin();
165 for( ; iter != mChildren.end(); ++iter)
169 SetDepth(childInfo, depth);
171 // insert the new childInfo before offset.
172 mNewChildren.push_back(childInfo);
174 // copy all children except the one that we wish to move.
175 if((*iter).mActor != childInfo.mActor)
177 SetDepth(*iter, depth);
179 mNewChildren.push_back(*iter);
185 SetDepth(childInfo, depth);
186 // insert the new childInfo before offset (end).
187 mNewChildren.push_back(childInfo);
190 mChildren = mNewChildren;
192 // Todo somehow adjust their perceived depth.
196 void Cluster::SetDepth( ChildInfo& childInfo, float depth )
198 Property::Index depthProperty = childInfo.mActor.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
199 childInfo.mActor.SetProperty( depthProperty, depth );
202 ChildInfo Cluster::GetChildInfoAt( unsigned int index )
204 // check if we have this position in the cluster
205 if( index < mChildren.size() )
207 // return the child handle
208 return mChildren[ index ];
211 // return an empty handle
215 Actor Cluster::GetChildAt( unsigned int index )
217 // check if we have this position in the cluster
218 if( index < mChildren.size() )
220 // return the child handle
221 return mChildren[ index ].mActor;
224 // return an empty handle
228 Actor Cluster::RemoveChildAt( unsigned int index )
230 DALI_ASSERT_ALWAYS( index < mChildren.size() );
232 ChildInfoIter iter = mChildren.begin() + index;
233 Actor child = (*iter).mActor;
234 mChildren.erase( iter );
235 Self().Remove(child);
236 // note: constraints will automatically be removed in OnControlChildRemove
241 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
243 SetDepth(*iter, depth);
250 void Cluster::ExpandChild( unsigned int index )
252 if( index < mChildren.size() )
254 ChildInfo& childInfo = mChildren[ index ];
255 DALI_ASSERT_ALWAYS(childInfo.mActor);
257 if(!childInfo.mExpanded)
259 // expand child to a random position/angle.
260 const Vector3 clusterSize = Self().GetCurrentSize();
261 const float length = clusterSize.Length() * 0.1f;
262 const float zOffset = 50.0f;
263 const float angle = (rand()%360) * Math::PI / 180.0f;
264 Vector3 position(sin(angle) * length, -cos(angle) * length, zOffset);
265 const float scale(1.2f);
266 const float rotate = ((rand()%30) - 15) * Math::PI / 180.0f;
268 position += childInfo.mActor.GetCurrentPosition();
270 TransformChild(index,
272 Vector3::ONE * scale,
273 Quaternion(rotate, Vector3::ZAXIS),
274 AlphaFunctions::EaseOut,
280 void Cluster::ExpandAllChildren()
282 for(unsigned int index = 0;index < mChildren.size(); index++)
284 ExpandChild( index );
288 void Cluster::CollapseChild( unsigned int index, bool front )
290 if( index < mChildren.size() )
293 AlphaFunctions::EaseOut,
299 void Cluster::CollapseAllChildren( bool front )
301 for(unsigned int index = 0;index < mChildren.size(); index++)
304 AlphaFunctions::EaseOut,
310 void Cluster::TransformChild( unsigned int index, const Vector3& position, const Vector3& scale, const Quaternion& rotation, AlphaFunction alpha, const TimePeriod& period )
312 if( index < mChildren.size() )
314 ChildInfo& childInfo = mChildren[ index ];
315 DALI_ASSERT_ALWAYS(childInfo.mActor);
317 if(!childInfo.mExpanded)
319 Actor child = childInfo.mActor;
320 childInfo.mExpanded = true;
323 child.RemoveConstraints();
324 Animation animation = Animation::New(period.delaySeconds + period.durationSeconds);
325 animation.AnimateTo( Property(child, Actor::POSITION), position, AlphaFunctions::EaseOut, period);
326 animation.AnimateTo( Property(child, Actor::SCALE), scale, AlphaFunctions::EaseOut, period);
327 animation.AnimateTo( Property(child, Actor::ROTATION), rotation, AlphaFunctions::EaseOut, period);
333 void Cluster::RestoreChild( unsigned int index, AlphaFunction alpha, const TimePeriod& period, bool front )
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 = false;
345 mClusterStyle.ApplyStyle( child, childInfo.mPositionIndex, alpha, period );
347 const unsigned int hideIndex = front ? mChildren.size() : 0;
348 AddChildInfoAt(childInfo, hideIndex); // move child info to the back or front of the pack.
353 void Cluster::SetBackgroundImage( Actor image )
355 // Replaces the background image.
356 if(mBackgroundImage && mBackgroundImage.GetParent())
358 mBackgroundImage.GetParent().Remove(mBackgroundImage);
361 mBackgroundImage = image;
362 Self().Add(mBackgroundImage);
364 mBackgroundImage.SetAnchorPoint( AnchorPoint::TOP_LEFT );
365 mBackgroundImage.SetParentOrigin( ParentOrigin::TOP_LEFT );
367 UpdateBackground(0.0f);
370 void Cluster::SetTitle( Actor text )
372 // Replaces the title actor.
373 if(mTitle && mTitle.GetParent())
375 mTitle.GetParent().Remove( mTitle );
379 Self().Add( mTitle );
381 mTitle.SetAnchorPoint( AnchorPoint::TOP_LEFT );
382 mTitle.SetParentOrigin( ParentOrigin::TOP_LEFT );
387 void Cluster::SetStyle(Toolkit::ClusterStyle style)
389 unsigned int previousChildrenNum = mChildren.size();
390 mClusterStyle = style;
391 unsigned int newChildrenNum = mClusterStyle.GetMaximumNumberOfChildren();
393 // New style supports less children (remove those that no longer belong)
394 if(newChildrenNum < previousChildrenNum)
396 ChildInfoIter removeStart = mChildren.begin() + newChildrenNum;
398 for(ChildInfoIter iter = removeStart; iter != mChildren.end(); ++iter)
400 Actor child = (*iter).mActor;
401 child.RemoveConstraints();
402 Self().Remove(child);
405 mChildren.erase( removeStart, mChildren.end() );
408 // Remove constraints from previous style, and apply new style's constraints.
409 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
414 (*iter).mActor.RemoveConstraints();
415 style.ApplyStyle( (*iter).mActor,
416 (*iter).mPositionIndex,
417 AlphaFunctions::EaseOut,
418 CLUSTER_STYLE_CONSTRAINT_DURATION );
422 UpdateBackground(CLUSTER_STYLE_CONSTRAINT_DURATION);
423 UpdateTitle(CLUSTER_STYLE_CONSTRAINT_DURATION);
426 Toolkit::ClusterStyle Cluster::GetStyle() const
428 return mClusterStyle;
431 unsigned int Cluster::GetExpandedCount() const
433 return mExpandedCount;
436 unsigned int Cluster::GetTotalCount() const
438 return mChildren.size();
441 void Cluster::UpdateBackground(float duration)
443 if (mBackgroundImage)
445 mBackgroundImage.RemoveConstraints();
446 mClusterStyle.ApplyStyleToBackground(mBackgroundImage, AlphaFunctions::EaseOut, duration);
450 void Cluster::UpdateTitle(float duration)
454 mTitle.RemoveConstraints();
455 mClusterStyle.ApplyStyleToTitle(mTitle, AlphaFunctions::EaseOut, duration);
459 void Cluster::DoExpandAction(const PropertyValueContainer& attributes)
461 if(attributes.size() >= 1)
463 for(PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter)
465 const Property::Value& value = *iter;
467 DALI_ASSERT_ALWAYS(value.GetType() == Property::FLOAT);
468 unsigned int index = value.Get<float>();
469 ExpandChild( index );
478 void Cluster::DoCollapseAction(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 CollapseChild( index, false );
493 CollapseAllChildren( false );
497 void Cluster::DoTransformAction(const PropertyValueContainer& attributes)
499 DALI_ASSERT_ALWAYS(attributes.size() >= 2);
501 DALI_ASSERT_ALWAYS(attributes[0].GetType() == Property::FLOAT);
502 unsigned int index = attributes[0].Get<float>();
504 Vector3 scale(Vector3::ONE);
505 Quaternion rotation(0.0f, Vector3::ZAXIS);
507 DALI_ASSERT_ALWAYS(attributes[1].GetType() == Property::VECTOR3);
508 attributes[1].Get(position);
510 if(attributes.size()>2)
512 attributes[2].Get(scale);
515 if(attributes.size()>3)
517 attributes[3].Get(rotation);
520 // wrap index around -1 => size - 1
521 index%= mChildren.size();
523 TransformChild(index, position, scale, rotation, AlphaFunctions::EaseOut, 0.5f);
526 void Cluster::OnControlChildRemove(Actor& child)
528 child.RemoveConstraints();
531 bool Cluster::DoAction(BaseObject* object, const std::string& actionName, const std::vector<Property::Value>& attributes)
535 Dali::BaseHandle handle(object);
537 Toolkit::Cluster cluster = Toolkit::Cluster::DownCast(handle);
539 DALI_ASSERT_ALWAYS(cluster);
541 if(Toolkit::Cluster::ACTION_EXPAND == actionName)
543 GetImpl(cluster).DoExpandAction(attributes);
546 else if(Toolkit::Cluster::ACTION_COLLAPSE == actionName)
548 GetImpl(cluster).DoCollapseAction(attributes);
551 else if(Toolkit::Cluster::ACTION_TRANSFORM == actionName)
553 GetImpl(cluster).DoTransformAction(attributes);
560 } // namespace Internal
562 } // namespace Toolkit