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>
32 namespace // unnamed namespace
35 const float CLUSTER_STYLE_CONSTRAINT_DURATION = 1.0f;
53 Toolkit::ClusterStyleStandard s = Toolkit::ClusterStyleStandard::New(Toolkit::ClusterStyleStandard::ClusterStyle1);
54 return Toolkit::Cluster::New( s );
57 TypeRegistration mType( typeid(Toolkit::Cluster), typeid(Toolkit::Control), Create );
59 TypeAction a1(mType, Toolkit::Cluster::ACTION_EXPAND , &Cluster::DoAction);
60 TypeAction a2(mType, Toolkit::Cluster::ACTION_COLLAPSE , &Cluster::DoAction);
61 TypeAction a3(mType, Toolkit::Cluster::ACTION_TRANSFORM, &Cluster::DoAction);
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 ) ),
91 void Cluster::OnInitialize()
99 void Cluster::AddChild( Actor child )
101 // automatically add child with a position at end.
102 AddChild( child, mChildren.size() );
105 void Cluster::AddChild( Actor child, unsigned int positionIndex )
107 AddChildInfo( ChildInfo(child, positionIndex) );
110 void Cluster::AddChildAt( Actor child, unsigned int index )
112 // automatically add child with a position at end.
113 AddChild( child, mChildren.size() );
116 void Cluster::AddChildAt( Actor child, unsigned int positionIndex, unsigned int index )
118 AddChildInfoAt( ChildInfo(child, positionIndex), index );
121 void Cluster::AddChildInfo( ChildInfo childInfo )
123 AddChildInfoAt(childInfo, mChildren.size());
126 void Cluster::AddChildInfoAt( ChildInfo childInfo, unsigned int index )
128 // check that the child is valid
129 DALI_ASSERT_ALWAYS( childInfo.mActor );
131 ChildInfoIter offset = index < mChildren.size() ? (mChildren.begin() + index) : mChildren.end();
132 // now perform customization on this child.
135 if(childInfo.mActor.GetParent() != Self())
137 Actor& child = childInfo.mActor;
138 const float depth = std::distance(mChildren.begin(), offset);
140 Property::Index depthProperty = child.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
141 if(depthProperty == Property::INVALID_INDEX)
143 child.RegisterProperty(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH, depth);
147 Self().Add( childInfo.mActor );
148 mChildren.insert( offset, childInfo );
150 // Use parent position plus relative position.
151 child.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
153 // remove old constraints
154 child.RemoveConstraints();
156 // apply new constraints to the child
157 mClusterStyle.ApplyStyle(child, childInfo.mPositionIndex, AlphaFunctions::EaseOut, 0.0f);
162 ChildInfoContainer mNewChildren;
163 ChildInfoIter iter = mChildren.begin();
166 for( ; iter != mChildren.end(); ++iter)
170 SetDepth(childInfo, depth);
172 // insert the new childInfo before offset.
173 mNewChildren.push_back(childInfo);
175 // copy all children except the one that we wish to move.
176 if((*iter).mActor != childInfo.mActor)
178 SetDepth(*iter, depth);
180 mNewChildren.push_back(*iter);
186 SetDepth(childInfo, depth);
187 // insert the new childInfo before offset (end).
188 mNewChildren.push_back(childInfo);
191 mChildren = mNewChildren;
193 // Todo somehow adjust their perceived depth.
197 void Cluster::SetDepth( ChildInfo& childInfo, float depth )
199 Property::Index depthProperty = childInfo.mActor.GetPropertyIndex(Toolkit::Cluster::CLUSTER_ACTOR_DEPTH);
200 childInfo.mActor.SetProperty( depthProperty, depth );
203 ChildInfo Cluster::GetChildInfoAt( unsigned int index )
205 // check if we have this position in the cluster
206 if( index < mChildren.size() )
208 // return the child handle
209 return mChildren[ index ];
212 // return an empty handle
216 Actor Cluster::GetChildAt( unsigned int index )
218 // check if we have this position in the cluster
219 if( index < mChildren.size() )
221 // return the child handle
222 return mChildren[ index ].mActor;
225 // return an empty handle
229 Actor Cluster::RemoveChildAt( unsigned int index )
231 DALI_ASSERT_ALWAYS( index < mChildren.size() );
233 ChildInfoIter iter = mChildren.begin() + index;
234 Actor child = (*iter).mActor;
235 mChildren.erase( iter );
236 Self().Remove(child);
237 // note: constraints will automatically be removed in OnControlChildRemove
242 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
244 SetDepth(*iter, depth);
251 void Cluster::ExpandChild( unsigned int index )
253 if( index < mChildren.size() )
255 ChildInfo& childInfo = mChildren[ index ];
256 DALI_ASSERT_ALWAYS(childInfo.mActor);
258 if(!childInfo.mExpanded)
260 // expand child to a random position/angle.
261 const Vector3 clusterSize = Self().GetCurrentSize();
262 const float length = clusterSize.Length() * 0.1f;
263 const float zOffset = 50.0f;
264 const float angle = (rand()%360) * Math::PI / 180.0f;
265 Vector3 position(sin(angle) * length, -cos(angle) * length, zOffset);
266 const float scale(1.2f);
267 const float rotate = ((rand()%30) - 15) * Math::PI / 180.0f;
269 position += childInfo.mActor.GetCurrentPosition();
271 TransformChild(index,
273 Vector3::ONE * scale,
274 Quaternion(rotate, Vector3::ZAXIS),
275 AlphaFunctions::EaseOut,
281 void Cluster::ExpandAllChildren()
283 for(unsigned int index = 0;index < mChildren.size(); index++)
285 ExpandChild( index );
289 void Cluster::CollapseChild( unsigned int index, bool front )
291 if( index < mChildren.size() )
294 AlphaFunctions::EaseOut,
300 void Cluster::CollapseAllChildren( bool front )
302 for(unsigned int index = 0;index < mChildren.size(); index++)
305 AlphaFunctions::EaseOut,
311 void Cluster::TransformChild( unsigned int index, const Vector3& position, const Vector3& scale, const Quaternion& rotation, AlphaFunction alpha, const TimePeriod& period )
313 if( index < mChildren.size() )
315 ChildInfo& childInfo = mChildren[ index ];
316 DALI_ASSERT_ALWAYS(childInfo.mActor);
318 if(!childInfo.mExpanded)
320 Actor child = childInfo.mActor;
321 childInfo.mExpanded = true;
324 child.RemoveConstraints();
325 Animation animation = Animation::New(period.delaySeconds + period.durationSeconds);
326 animation.AnimateTo( Property(child, Actor::POSITION), position, AlphaFunctions::EaseOut, period);
327 animation.AnimateTo( Property(child, Actor::SCALE), scale, AlphaFunctions::EaseOut, period);
328 animation.AnimateTo( Property(child, Actor::ROTATION), rotation, AlphaFunctions::EaseOut, period);
334 void Cluster::RestoreChild( unsigned int index, AlphaFunction alpha, const TimePeriod& period, bool front )
336 if( index < mChildren.size() )
338 ChildInfo& childInfo = mChildren[ index ];
339 DALI_ASSERT_ALWAYS(childInfo.mActor);
341 if(childInfo.mExpanded)
343 Actor child = childInfo.mActor;
344 childInfo.mExpanded = false;
346 mClusterStyle.ApplyStyle( child, childInfo.mPositionIndex, alpha, period );
348 const unsigned int hideIndex = front ? mChildren.size() : 0;
349 AddChildInfoAt(childInfo, hideIndex); // move child info to the back or front of the pack.
354 void Cluster::SetBackgroundImage( Actor image )
356 // Replaces the background image.
357 if(mBackgroundImage && mBackgroundImage.GetParent())
359 mBackgroundImage.GetParent().Remove(mBackgroundImage);
362 mBackgroundImage = image;
363 Self().Add(mBackgroundImage);
365 mBackgroundImage.SetAnchorPoint( AnchorPoint::TOP_LEFT );
366 mBackgroundImage.SetParentOrigin( ParentOrigin::TOP_LEFT );
368 UpdateBackground(0.0f);
371 void Cluster::SetTitle( Actor text )
373 // Replaces the title actor.
374 if(mTitle && mTitle.GetParent())
376 mTitle.GetParent().Remove( mTitle );
380 Self().Add( mTitle );
382 mTitle.SetAnchorPoint( AnchorPoint::TOP_LEFT );
383 mTitle.SetParentOrigin( ParentOrigin::TOP_LEFT );
388 void Cluster::SetStyle(Toolkit::ClusterStyle style)
390 unsigned int previousChildrenNum = mChildren.size();
391 mClusterStyle = style;
392 unsigned int newChildrenNum = mClusterStyle.GetMaximumNumberOfChildren();
394 // New style supports less children (remove those that no longer belong)
395 if(newChildrenNum < previousChildrenNum)
397 ChildInfoIter removeStart = mChildren.begin() + newChildrenNum;
399 for(ChildInfoIter iter = removeStart; iter != mChildren.end(); ++iter)
401 Actor child = (*iter).mActor;
402 child.RemoveConstraints();
403 Self().Remove(child);
406 mChildren.erase( removeStart, mChildren.end() );
409 // Remove constraints from previous style, and apply new style's constraints.
410 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
415 (*iter).mActor.RemoveConstraints();
416 style.ApplyStyle( (*iter).mActor,
417 (*iter).mPositionIndex,
418 AlphaFunctions::EaseOut,
419 CLUSTER_STYLE_CONSTRAINT_DURATION );
423 UpdateBackground(CLUSTER_STYLE_CONSTRAINT_DURATION);
424 UpdateTitle(CLUSTER_STYLE_CONSTRAINT_DURATION);
427 Toolkit::ClusterStyle Cluster::GetStyle() const
429 return mClusterStyle;
432 unsigned int Cluster::GetExpandedCount() const
434 return mExpandedCount;
437 unsigned int Cluster::GetTotalCount() const
439 return mChildren.size();
442 void Cluster::UpdateBackground(float duration)
444 if (mBackgroundImage)
446 mBackgroundImage.RemoveConstraints();
447 mClusterStyle.ApplyStyleToBackground(mBackgroundImage, AlphaFunctions::EaseOut, duration);
451 void Cluster::UpdateTitle(float duration)
455 mTitle.RemoveConstraints();
456 mClusterStyle.ApplyStyleToTitle(mTitle, AlphaFunctions::EaseOut, duration);
460 void Cluster::DoExpandAction(const PropertyValueContainer& attributes)
462 if(attributes.size() >= 1)
464 for(PropertyValueConstIter iter = attributes.begin(); iter != attributes.end(); ++iter)
466 const Property::Value& value = *iter;
468 DALI_ASSERT_ALWAYS(value.GetType() == Property::FLOAT);
469 unsigned int index = value.Get<float>();
470 ExpandChild( index );
479 void Cluster::DoCollapseAction(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 CollapseChild( index, false );
494 CollapseAllChildren( false );
498 void Cluster::DoTransformAction(const PropertyValueContainer& attributes)
500 DALI_ASSERT_ALWAYS(attributes.size() >= 2);
502 DALI_ASSERT_ALWAYS(attributes[0].GetType() == Property::FLOAT);
503 unsigned int index = attributes[0].Get<float>();
505 Vector3 scale(Vector3::ONE);
506 Quaternion rotation(0.0f, Vector3::ZAXIS);
508 DALI_ASSERT_ALWAYS(attributes[1].GetType() == Property::VECTOR3);
509 attributes[1].Get(position);
511 if(attributes.size()>2)
513 attributes[2].Get(scale);
516 if(attributes.size()>3)
518 attributes[3].Get(rotation);
521 // wrap index around -1 => size - 1
522 index%= mChildren.size();
524 TransformChild(index, position, scale, rotation, AlphaFunctions::EaseOut, 0.5f);
527 void Cluster::OnControlChildRemove(Actor& child)
529 child.RemoveConstraints();
532 bool Cluster::DoAction(BaseObject* object, const std::string& actionName, const PropertyValueContainer& attributes)
536 Dali::BaseHandle handle(object);
538 Toolkit::Cluster cluster = Toolkit::Cluster::DownCast(handle);
540 DALI_ASSERT_ALWAYS(cluster);
542 if(Toolkit::Cluster::ACTION_EXPAND == actionName)
544 GetImpl(cluster).DoExpandAction(attributes);
547 else if(Toolkit::Cluster::ACTION_COLLAPSE == actionName)
549 GetImpl(cluster).DoCollapseAction(attributes);
552 else if(Toolkit::Cluster::ACTION_TRANSFORM == actionName)
554 GetImpl(cluster).DoTransformAction(attributes);
561 } // namespace Internal
563 } // namespace Toolkit