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 "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/property-array.h>
27 #include <dali/devel-api/object/type-registry-helper.h>
28 #include <dali/devel-api/scripting/scripting.h>
29 #include <dali/integration-api/debug.h>
32 #include "cluster-style.h"
33 #include "cluster-style-impl.h"
51 Demo::ClusterStyleStandard s = Demo::ClusterStyleStandard::New( Demo::ClusterStyleStandard::ClusterStyle1 );
52 return Demo::Cluster::New( s );
55 DALI_TYPE_REGISTRATION_BEGIN( Demo::Cluster, Toolkit::Control, Create )
57 DALI_ACTION_REGISTRATION( Demo, Cluster, "expand", ACTION_EXPAND )
58 DALI_ACTION_REGISTRATION( Demo, Cluster, "collapse", ACTION_COLLAPSE )
59 DALI_ACTION_REGISTRATION( Demo, Cluster, "transform", ACTION_TRANSFORM )
61 DALI_TYPE_REGISTRATION_END()
63 const float CLUSTER_STYLE_CONSTRAINT_DURATION = 1.0f;
67 ///////////////////////////////////////////////////////////////////////////////////////////////////
69 ///////////////////////////////////////////////////////////////////////////////////////////////////
71 Dali::Demo::Cluster Cluster::New(Demo::ClusterStyle& style)
73 // Create the implementation
74 ClusterPtr cluster(new Cluster(style));
76 // Pass ownership to CustomActor via derived handle
77 Dali::Demo::Cluster handle(*cluster);
79 // Second-phase init of the implementation
80 // This can only be done after the CustomActor connection has been made...
81 cluster->Initialize();
86 Cluster::Cluster(Demo::ClusterStyle& style)
87 : Toolkit::Internal::Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS | DISABLE_SIZE_NEGOTIATION ) ),
93 void Cluster::OnInitialize()
97 void Cluster::OnSizeSet( const Vector3& targetSize )
99 mClusterSize = targetSize;
100 GetImpl(mClusterStyle).SetClusterSize(targetSize);
102 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
107 mClusterStyle.ApplyStyle( (*iter).mActor,
108 (*iter).mPositionIndex,
109 AlphaFunction::EASE_OUT,
114 UpdateBackground(0.f);
122 void Cluster::AddChild( Actor child )
124 // automatically add child with a position at end.
125 AddChild( child, mChildren.size() );
128 void Cluster::AddChild( Actor child, unsigned int positionIndex )
130 AddChildInfo( ChildInfo(child, positionIndex) );
133 void Cluster::AddChildAt( Actor child, unsigned int index )
135 // automatically add child with a position at end.
136 AddChild( child, mChildren.size() );
139 void Cluster::AddChildAt( Actor child, unsigned int positionIndex, unsigned int index )
141 AddChildInfoAt( ChildInfo(child, positionIndex), index );
144 void Cluster::AddChildInfo( ChildInfo childInfo )
146 AddChildInfoAt(childInfo, mChildren.size());
149 void Cluster::AddChildInfoAt( ChildInfo childInfo, unsigned int index )
151 // check that the child is valid
152 DALI_ASSERT_ALWAYS( childInfo.mActor );
154 ChildInfoIter offset = index < mChildren.size() ? (mChildren.begin() + index) : mChildren.end();
155 // now perform customization on this child.
158 if(childInfo.mActor.GetParent() != Self())
160 Actor& child = childInfo.mActor;
161 const float depth = std::distance(mChildren.begin(), offset);
163 Property::Index depthProperty = child.GetPropertyIndex(Demo::Cluster::CLUSTER_ACTOR_DEPTH);
164 if(depthProperty == Property::INVALID_INDEX)
166 child.RegisterProperty(Demo::Cluster::CLUSTER_ACTOR_DEPTH, depth);
170 Self().Add( childInfo.mActor );
171 mChildren.insert( offset, childInfo );
173 // Use parent position plus relative position.
174 child.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
176 // remove old constraints
177 child.RemoveConstraints();
179 // apply new constraints to the child
180 mClusterStyle.ApplyStyle(child, childInfo.mPositionIndex, AlphaFunction::EASE_OUT, TimePeriod(0.0f));
185 ChildInfoContainer mNewChildren;
186 ChildInfoIter iter = mChildren.begin();
189 for( ; iter != mChildren.end(); ++iter)
193 SetDepth(childInfo, depth);
195 // insert the new childInfo before offset.
196 mNewChildren.push_back(childInfo);
198 // copy all children except the one that we wish to move.
199 if((*iter).mActor != childInfo.mActor)
201 SetDepth(*iter, depth);
203 mNewChildren.push_back(*iter);
209 SetDepth(childInfo, depth);
210 // insert the new childInfo before offset (end).
211 mNewChildren.push_back(childInfo);
214 mChildren = mNewChildren;
216 // Todo somehow adjust their perceived depth.
220 void Cluster::SetDepth( ChildInfo& childInfo, float depth )
222 Property::Index depthProperty = childInfo.mActor.GetPropertyIndex(Demo::Cluster::CLUSTER_ACTOR_DEPTH);
223 childInfo.mActor.SetProperty( depthProperty, depth );
226 ChildInfo Cluster::GetChildInfoAt( unsigned int index )
228 // check if we have this position in the cluster
229 if( index < mChildren.size() )
231 // return the child handle
232 return mChildren[ index ];
235 // return an empty handle
239 Actor Cluster::GetChildAt( unsigned int index )
241 // check if we have this position in the cluster
242 if( index < mChildren.size() )
244 // return the child handle
245 return mChildren[ index ].mActor;
248 // return an empty handle
252 Actor Cluster::RemoveChildAt( unsigned int index )
254 DALI_ASSERT_ALWAYS( index < mChildren.size() );
256 ChildInfoIter iter = mChildren.begin() + index;
257 Actor child = (*iter).mActor;
258 mChildren.erase( iter );
259 Self().Remove(child);
260 // note: constraints will automatically be removed in OnControlChildRemove
265 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
267 SetDepth(*iter, depth);
274 void Cluster::ExpandChild( unsigned int index )
276 if( index < mChildren.size() )
278 ChildInfo& childInfo = mChildren[ index ];
279 DALI_ASSERT_ALWAYS(childInfo.mActor);
281 if(!childInfo.mExpanded)
283 // expand child to a random position/angle.
284 const Vector3 clusterSize = Self().GetCurrentSize();
285 const float length = clusterSize.Length() * 0.1f;
286 const float zOffset = 50.0f;
287 const float angle = (rand()%360) * Math::PI / 180.0f;
288 Vector3 position(sin(angle) * length, -cos(angle) * length, zOffset);
289 const float scale(1.2f);
290 const Radian rotate( Degree( (rand()%30) - 15 ) );
292 position += childInfo.mActor.GetCurrentPosition();
294 TransformChild(index,
296 Vector3::ONE * scale,
297 Quaternion(rotate, Vector3::ZAXIS),
298 AlphaFunction::EASE_OUT,
304 void Cluster::ExpandAllChildren()
306 for(unsigned int index = 0;index < mChildren.size(); index++)
308 ExpandChild( index );
312 void Cluster::CollapseChild( unsigned int index, bool front )
314 if( index < mChildren.size() )
317 AlphaFunction::EASE_OUT,
323 void Cluster::CollapseAllChildren( bool front )
325 for(unsigned int index = 0;index < mChildren.size(); index++)
328 AlphaFunction::EASE_OUT,
334 void Cluster::TransformChild( unsigned int index, const Vector3& position, const Vector3& scale, const Quaternion& rotation, AlphaFunction alpha, const TimePeriod& period )
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 = true;
347 child.RemoveConstraints();
348 Animation animation = Animation::New(period.delaySeconds + period.durationSeconds);
349 animation.AnimateTo( Property(child, Actor::Property::POSITION), position, AlphaFunction::EASE_OUT, period);
350 animation.AnimateTo( Property(child, Actor::Property::SCALE), scale, AlphaFunction::EASE_OUT, period);
351 animation.AnimateTo( Property(child, Actor::Property::ORIENTATION), rotation, AlphaFunction::EASE_OUT, period);
357 void Cluster::RestoreChild( unsigned int index, AlphaFunction alpha, const TimePeriod& period, bool front )
359 if( index < mChildren.size() )
361 ChildInfo& childInfo = mChildren[ index ];
362 DALI_ASSERT_ALWAYS(childInfo.mActor);
364 if(childInfo.mExpanded)
366 Actor child = childInfo.mActor;
367 childInfo.mExpanded = false;
369 mClusterStyle.ApplyStyle( child, childInfo.mPositionIndex, alpha, period );
371 const unsigned int hideIndex = front ? mChildren.size() : 0;
372 AddChildInfoAt(childInfo, hideIndex); // move child info to the back or front of the pack.
377 void Cluster::SetTitle( Actor text )
379 // Replaces the title actor.
380 if(mTitle && mTitle.GetParent())
382 mTitle.GetParent().Remove( mTitle );
386 Self().Add( mTitle );
388 mTitle.SetAnchorPoint( AnchorPoint::TOP_LEFT );
389 mTitle.SetParentOrigin( ParentOrigin::TOP_LEFT );
394 void Cluster::SetStyle(Demo::ClusterStyle style)
396 unsigned int previousChildrenNum = mChildren.size();
397 mClusterStyle = style;
398 GetImpl(mClusterStyle).SetClusterSize(mClusterSize);
399 unsigned int newChildrenNum = mClusterStyle.GetMaximumNumberOfChildren();
401 // New style supports less children (remove those that no longer belong)
402 if(newChildrenNum < previousChildrenNum)
404 ChildInfoIter removeStart = mChildren.begin() + newChildrenNum;
406 for(ChildInfoIter iter = removeStart; iter != mChildren.end(); ++iter)
408 Actor child = (*iter).mActor;
409 child.RemoveConstraints();
410 Self().Remove(child);
413 mChildren.erase( removeStart, mChildren.end() );
416 for(ChildInfoIter iter = mChildren.begin(); iter != mChildren.end(); ++iter)
421 mClusterStyle.ApplyStyle( (*iter).mActor,
422 (*iter).mPositionIndex,
423 AlphaFunction::EASE_OUT,
424 TimePeriod(CLUSTER_STYLE_CONSTRAINT_DURATION) );
428 UpdateBackground(CLUSTER_STYLE_CONSTRAINT_DURATION);
429 UpdateTitle(CLUSTER_STYLE_CONSTRAINT_DURATION);
432 Demo::ClusterStyle Cluster::GetStyle() const
434 return mClusterStyle;
437 unsigned int Cluster::GetExpandedCount() const
439 return mExpandedCount;
442 unsigned int Cluster::GetTotalCount() const
444 return mChildren.size();
447 void Cluster::UpdateBackground(float duration)
449 if (mBackgroundImage)
451 mClusterStyle.ApplyStyleToBackground(mBackgroundImage, AlphaFunction::EASE_OUT, TimePeriod(duration));
455 void Cluster::UpdateTitle(float duration)
459 mClusterStyle.ApplyStyleToTitle(mTitle, AlphaFunction::EASE_OUT, TimePeriod(duration));
463 void Cluster::DoExpandAction(const Property::Map& attributes)
465 Property::Value* value = attributes.Find( "indices" );
469 if( value->GetType() == Property::ARRAY )
471 Property::Array array = value->Get<Property::Array>();
472 for( size_t i = 0; i < array.Size(); i++ )
474 Property::Value& item = array[i];
475 DALI_ASSERT_ALWAYS(item.GetType() == Property::INTEGER);
476 ExpandChild( item.Get<int>() );
486 void Cluster::DoCollapseAction(const Property::Map& attributes)
488 Property::Value* value = attributes.Find( "indices" );
492 if( value->GetType() == Property::ARRAY )
494 Property::Array array = value->Get<Property::Array>();
495 for( size_t i = 0; i < array.Size(); i++ )
497 Property::Value& item = array[i];
498 DALI_ASSERT_ALWAYS(item.GetType() == Property::INTEGER);
499 CollapseChild( item.Get<int>(), false );
505 CollapseAllChildren( false );
510 void Cluster::DoTransformAction(const Property::Map& attributes)
512 typedef Dali::StringValuePair StringValuePair;
516 Vector3 scale(Vector3::ONE);
517 Quaternion rotation( Dali::ANGLE_0, Vector3::ZAXIS );
519 for(size_t i = 0; i < attributes.Count(); i++)
521 StringValuePair& stringValue = attributes.GetPair(i);
522 Property::Type type = stringValue.second.GetType();
524 if( Property::VECTOR3 == type && "position" == stringValue.first )
526 stringValue.second.Get( position );
528 else if( Property::VECTOR3 == type && "scale" == stringValue.first )
530 stringValue.second.Get( scale );
532 else if( "rotation" == stringValue.first )
534 stringValue.second.Get( rotation );
538 // wrap index around -1 => size - 1
539 index%= mChildren.size();
541 TransformChild(index, position, scale, rotation, AlphaFunction::EASE_OUT, TimePeriod(0.5f));
544 void Cluster::OnControlChildRemove(Actor& child)
546 child.RemoveConstraints();
549 bool Cluster::DoAction(BaseObject* object, const std::string& actionName, const Property::Map& attributes)
553 Dali::BaseHandle handle( object );
555 Demo::Cluster cluster = Demo::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