Add support for ItemView layout customisation through properties.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scrollable / item-view / spiral-layout.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/scrollable/item-view/spiral-layout.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23 #include <dali/public-api/animation/animation.h>
24 #include <dali/public-api/animation/constraint.h>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/public-api/controls/scrollable/item-view/item-view.h>
28 #include <dali-toolkit/devel-api/controls/scrollable/item-view/default-item-layout-property.h>
29
30 using namespace Dali;
31 using namespace Dali::Toolkit;
32
33 namespace // unnamed namespace
34 {
35
36 const float DEFAULT_ITEMS_PER_SPIRAL_TURN = 9.5f;
37 const float DEFAULT_ITEM_SPACING_RADIANS = Math::PI*2.0f/DEFAULT_ITEMS_PER_SPIRAL_TURN;
38
39 const float DEFAULT_REVOLUTION_DISTANCE = 190.0f;
40 const float DEFAULT_ITEM_DESCENT = DEFAULT_REVOLUTION_DISTANCE / DEFAULT_ITEMS_PER_SPIRAL_TURN;
41
42 const float DEFAULT_TOP_ITEM_ALIGNMENT = -0.125f;
43
44 const float DEFAULT_SCROLL_SPEED_FACTOR = 0.01f;
45 const float DEFAULT_MAXIMUM_SWIPE_SPEED = 30.0f;
46 const float DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.1f;
47
48 float GetDefaultSpiralRadiusFunction(const Vector3& layoutSize)
49 {
50   return layoutSize.width*0.4f;
51 }
52
53 struct SpiralPositionConstraint
54 {
55   SpiralPositionConstraint( unsigned int itemId, float spiralRadius, float itemSpacingRadians, float itemDescent, float topItemAlignment )
56   : mItemId( itemId ),
57     mSpiralRadius( spiralRadius ),
58     mItemSpacingRadians( itemSpacingRadians ),
59     mItemDescent( itemDescent ),
60     mTopItemAlignment( topItemAlignment )
61   {
62   }
63
64   inline void OrientationUp( Vector3& current, float layoutPosition, const Vector3& layoutSize )
65   {
66     float angle = -Math::PI * 0.5f + mItemSpacingRadians * layoutPosition;
67
68     current.x = -mSpiralRadius * cosf( angle );
69     current.y = ( mItemDescent * layoutPosition ) + layoutSize.height * mTopItemAlignment;
70     current.z = -mSpiralRadius * sinf( angle );
71   }
72
73   inline void OrientationLeft( Vector3& current, float layoutPosition, const Vector3& layoutSize )
74   {
75     float angle = Math::PI * 0.5f + mItemSpacingRadians * layoutPosition;
76
77     current.x = ( mItemDescent * layoutPosition ) + layoutSize.width * mTopItemAlignment;
78     current.y = -mSpiralRadius * cosf( angle );
79     current.z = mSpiralRadius * sinf( angle );
80   }
81
82   inline void OrientationDown( Vector3& current, float layoutPosition, const Vector3& layoutSize )
83   {
84     float angle = Math::PI * 0.5f + mItemSpacingRadians * layoutPosition;
85
86     current.x = -mSpiralRadius * cosf( angle );
87     current.y = ( -mItemDescent * layoutPosition ) - layoutSize.height * mTopItemAlignment;
88     current.z = mSpiralRadius * sinf(angle);
89   }
90
91   inline void OrientationRight( Vector3& current, float layoutPosition, const Vector3& layoutSize )
92   {
93     float angle = -Math::PI*0.5f + mItemSpacingRadians * layoutPosition;
94
95     current.x = (-mItemDescent * layoutPosition) - layoutSize.width * mTopItemAlignment;
96     current.y = -mSpiralRadius * cosf( angle );
97     current.z = -mSpiralRadius * sinf( angle );
98   }
99
100   void OrientationUp( Vector3& current, const PropertyInputContainer& inputs )
101   {
102     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
103     const Vector3& layoutSize = inputs[1]->GetVector3();
104     OrientationUp( current, layoutPosition, layoutSize );
105   }
106
107   void OrientationLeft( Vector3& current, const PropertyInputContainer& inputs )
108   {
109     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
110     const Vector3& layoutSize = inputs[1]->GetVector3();
111     OrientationLeft( current, layoutPosition, layoutSize );
112   }
113
114   void OrientationDown( Vector3& current, const PropertyInputContainer& inputs )
115   {
116     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
117     const Vector3& layoutSize = inputs[1]->GetVector3();
118     OrientationDown( current, layoutPosition, layoutSize );
119   }
120
121   void OrientationRight( Vector3& current, const PropertyInputContainer& inputs )
122   {
123     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
124     const Vector3& layoutSize = inputs[1]->GetVector3();
125     OrientationRight( current, layoutPosition, layoutSize );
126   }
127
128   unsigned int mItemId;
129   float mSpiralRadius;
130   float mItemSpacingRadians;
131   float mItemDescent;
132   float mTopItemAlignment;
133 };
134
135 struct SpiralRotationConstraint
136 {
137   SpiralRotationConstraint( unsigned int itemId, float itemSpacingRadians )
138   : mItemId( itemId ),
139     mItemSpacingRadians( itemSpacingRadians )
140   {
141   }
142
143   void OrientationUp( Quaternion& current, const PropertyInputContainer& inputs )
144   {
145     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
146     float angle = -mItemSpacingRadians * layoutPosition;
147
148     current = Quaternion( Radian( angle ), Vector3::YAXIS);
149   }
150
151   void OrientationLeft( Quaternion& current, const PropertyInputContainer& inputs )
152   {
153     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
154     float angle = -mItemSpacingRadians * layoutPosition;
155
156     current = Quaternion( Radian( -Math::PI * 0.5f ), Vector3::ZAXIS ) * Quaternion( Radian( angle ), Vector3::YAXIS );
157   }
158
159   void OrientationDown( Quaternion& current, const PropertyInputContainer& inputs )
160   {
161     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
162     float angle = -mItemSpacingRadians * layoutPosition;
163
164     current = Quaternion( Radian( -Math::PI ), Vector3::ZAXIS) * Quaternion( Radian( angle ), Vector3::YAXIS );
165   }
166
167   void OrientationRight( Quaternion& current, const PropertyInputContainer& inputs )
168   {
169     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
170     float angle = -mItemSpacingRadians * layoutPosition;
171
172     current = Quaternion( Radian( -Math::PI * 1.5f ), Vector3::ZAXIS) * Quaternion( Radian( angle ), Vector3::YAXIS );
173   }
174
175   unsigned int mItemId;
176   float mItemSpacingRadians;
177 };
178
179 struct SpiralColorConstraint
180 {
181   SpiralColorConstraint( unsigned int itemId, float itemSpacingRadians )
182   : mItemId( itemId ),
183     mItemSpacingRadians( itemSpacingRadians )
184   {
185   }
186
187   void operator()( Vector4& current, const PropertyInputContainer& inputs )
188   {
189     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
190     Radian angle( mItemSpacingRadians * fabsf( layoutPosition ) / Dali::ANGLE_360 );
191
192     float progress = angle - floorf( angle ); // take fractional bit only to get between 0.0 - 1.0
193     progress = (progress > 0.5f) ? 2.0f*(1.0f - progress) : progress*2.0f;
194
195     float darkness(1.0f);
196     {
197       const float startMarker = 0.10f; // The progress at which darkening starts
198       const float endMarker   = 0.35f; // The progress at which darkening ends
199       const float minDarkness = 0.15f; // The darkness at end marker
200
201       if (progress > endMarker)
202       {
203         darkness = minDarkness;
204       }
205       else if (progress > startMarker)
206       {
207         darkness = 1.0f - ( (1.0f - minDarkness) * ((progress-startMarker) / (endMarker-startMarker)) );
208       }
209     }
210
211     current.r = current.g = current.b = darkness;
212   }
213
214   unsigned int mItemId;
215   float mItemSpacingRadians;
216 };
217
218 struct SpiralVisibilityConstraint
219 {
220   SpiralVisibilityConstraint( unsigned int itemId, float itemSpacingRadians, float itemDescent, float topItemAlignment )
221   : mItemId( itemId ),
222     mItemSpacingRadians( itemSpacingRadians ),
223     mItemDescent( itemDescent ),
224     mTopItemAlignment( topItemAlignment )
225   {
226   }
227
228   void Portrait( bool& current, const PropertyInputContainer& inputs )
229   {
230     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
231     const Vector3& layoutSize = inputs[1]->GetVector3();
232     float itemsCachedBeforeTopItem = layoutSize.height*(mTopItemAlignment+0.5f) / mItemDescent;
233     current = ( layoutPosition >= -itemsCachedBeforeTopItem - 1.0f && layoutPosition <= ( layoutSize.height / mItemDescent ) + 1.0f );
234   }
235
236   void Landscape( bool& current, const PropertyInputContainer& inputs )
237   {
238     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
239     const Vector3& layoutSize = inputs[1]->GetVector3();
240     float itemsCachedBeforeTopItem = layoutSize.width*(mTopItemAlignment+0.5f) / mItemDescent;
241     current = ( layoutPosition >= -itemsCachedBeforeTopItem - 1.0f && layoutPosition <= ( layoutSize.width / mItemDescent ) + 1.0f );
242   }
243
244   unsigned int mItemId;
245   float mItemSpacingRadians;
246   float mItemDescent;
247   float mTopItemAlignment;
248 };
249
250 } // unnamed namespace
251
252 namespace Dali
253 {
254
255 namespace Toolkit
256 {
257
258 namespace Internal
259 {
260
261 struct SpiralLayout::Impl
262 {
263   Impl()
264   : mItemSpacingRadians(DEFAULT_ITEM_SPACING_RADIANS),
265     mRevolutionDistance(DEFAULT_REVOLUTION_DISTANCE),
266     mItemDescent(DEFAULT_ITEM_DESCENT),
267     mTopItemAlignment(DEFAULT_TOP_ITEM_ALIGNMENT),
268     mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
269     mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
270     mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION)
271   {
272   }
273
274   float mItemSpacingRadians;
275   float mRevolutionDistance;
276   float mItemDescent;
277   float mTopItemAlignment;
278   float mScrollSpeedFactor;
279   float mMaximumSwipeSpeed;
280   float mItemFlickAnimationDuration;
281 };
282
283 SpiralLayoutPtr SpiralLayout::New()
284 {
285   return SpiralLayoutPtr(new SpiralLayout());
286 }
287
288 SpiralLayout::~SpiralLayout()
289 {
290   delete mImpl;
291 }
292
293 void SpiralLayout::SetItemSpacing(Radian itemSpacing)
294 {
295   mImpl->mItemSpacingRadians = itemSpacing;
296
297   float itemsPerSpiral = std::max(1.0f, (2.0f*(float)Math::PI) / mImpl->mItemSpacingRadians);
298   mImpl->mItemDescent = mImpl->mRevolutionDistance / itemsPerSpiral;
299 }
300
301 Radian SpiralLayout::GetItemSpacing() const
302 {
303   return Radian( mImpl->mItemSpacingRadians );
304 }
305
306 void SpiralLayout::SetRevolutionDistance(float distance)
307 {
308   mImpl->mRevolutionDistance = distance;
309
310   float itemsPerSpiral = std::max(1.0f, (2.0f*(float)Math::PI) / mImpl->mItemSpacingRadians);
311   mImpl->mItemDescent = mImpl->mRevolutionDistance / itemsPerSpiral;
312 }
313
314 float SpiralLayout::GetRevolutionDistance() const
315 {
316   return mImpl->mRevolutionDistance;
317 }
318
319 void SpiralLayout::SetTopItemAlignment(float alignment)
320 {
321   mImpl->mTopItemAlignment = alignment;
322 }
323
324 float SpiralLayout::GetTopItemAlignment() const
325 {
326   return mImpl->mTopItemAlignment;
327 }
328
329 void SpiralLayout::SetScrollSpeedFactor(float scrollSpeed)
330 {
331   mImpl->mScrollSpeedFactor = scrollSpeed;
332 }
333
334 void SpiralLayout::SetMaximumSwipeSpeed(float speed)
335 {
336   mImpl->mMaximumSwipeSpeed = speed;
337 }
338
339 void SpiralLayout::SetItemFlickAnimationDuration(float durationSeconds)
340 {
341   mImpl->mItemFlickAnimationDuration = durationSeconds;
342 }
343
344 float SpiralLayout::GetScrollSpeedFactor() const
345 {
346   return mImpl->mScrollSpeedFactor;
347 }
348
349 float SpiralLayout::GetMaximumSwipeSpeed() const
350 {
351   return mImpl->mMaximumSwipeSpeed;
352 }
353
354 float SpiralLayout::GetItemFlickAnimationDuration() const
355 {
356   return mImpl->mItemFlickAnimationDuration;
357 }
358
359 float SpiralLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
360 {
361   return 1.0f - static_cast<float>(numberOfItems);
362 }
363
364 float SpiralLayout::GetClosestAnchorPosition(float layoutPosition) const
365 {
366   return round(layoutPosition);
367 }
368
369 float SpiralLayout::GetItemScrollToPosition(unsigned int itemId) const
370 {
371   return -(static_cast<float>(itemId));
372 }
373
374 ItemRange SpiralLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
375 {
376   float layoutHeight = IsHorizontal( GetOrientation() ) ? layoutSize.width : layoutSize.height;
377   float itemsPerSpiral = layoutHeight / mImpl->mItemDescent;
378   float itemsCachedBeforeTopItem = layoutHeight * (mImpl->mTopItemAlignment + 0.5f) / mImpl->mItemDescent;
379   float itemsViewable = std::min(itemsPerSpiral, itemsPerSpiral - itemsCachedBeforeTopItem - firstItemPosition + 1.0f);
380
381   unsigned int firstItem = static_cast<unsigned int>(std::max(0.0f, -firstItemPosition - itemsCachedBeforeTopItem - 1.0f));
382   unsigned int lastItem  = static_cast<unsigned int>(std::max(0.0f, firstItem + itemsViewable));
383
384   return ItemRange(firstItem, lastItem+1);
385 }
386
387 unsigned int SpiralLayout::GetReserveItemCount(Vector3 layoutSize) const
388 {
389   float layoutHeight = IsHorizontal( GetOrientation() ) ? layoutSize.width : layoutSize.height;
390   return static_cast<unsigned int>(layoutHeight / mImpl->mItemDescent);
391 }
392
393 void SpiralLayout::GetDefaultItemSize( unsigned int itemId, const Vector3& layoutSize, Vector3& itemSize ) const
394 {
395   itemSize.width = layoutSize.width * 0.25f;
396
397   // 4x3 aspect ratio
398   itemSize.height = itemSize.depth = ( itemSize.width / 4.0f ) * 3.0f;
399 }
400
401 Degree SpiralLayout::GetScrollDirection() const
402 {
403   Degree scrollDirection(0);
404   const ControlOrientation::Type orientation = GetOrientation();
405
406   if ( orientation == ControlOrientation::Up )
407   {
408     scrollDirection = Degree( -45.0f ); // Allow swiping horizontally & vertically
409   }
410   else if ( orientation == ControlOrientation::Left )
411   {
412     scrollDirection = Degree( 45.0f );
413   }
414   else if ( orientation == ControlOrientation::Down )
415   {
416     scrollDirection = Degree( 180.0f - 45.0f );
417   }
418   else // orientation == ControlOrientation::Right
419   {
420     scrollDirection = Degree( 270.0f - 45.0f );
421   }
422
423   return scrollDirection;
424 }
425
426 void SpiralLayout::ApplyConstraints( Actor& actor, const int itemId, const Vector3& layoutSize, const Actor& itemViewActor )
427 {
428
429   if(HasLayoutChanged())
430   {
431     SetSpiralLayoutProperties(GetLayoutProperties());
432   }
433   // This just implements the default behaviour of constraint application.
434   // Custom layouts can override this function to apply their custom constraints.
435   Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast( itemViewActor );
436   if( itemView )
437   {
438     const ControlOrientation::Type orientation = GetOrientation();
439
440     // Position constraint
441     SpiralPositionConstraint positionConstraint( itemId, GetDefaultSpiralRadiusFunction( layoutSize ), mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment );
442     Constraint constraint;
443     if ( orientation == ControlOrientation::Up )
444     {
445       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &SpiralPositionConstraint::OrientationUp );
446     }
447     else if ( orientation == ControlOrientation::Left )
448     {
449       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &SpiralPositionConstraint::OrientationLeft );
450     }
451     else if ( orientation == ControlOrientation::Down )
452     {
453       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &SpiralPositionConstraint::OrientationDown );
454     }
455     else // orientation == ControlOrientation::Right
456     {
457       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &SpiralPositionConstraint::OrientationRight );
458     }
459     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
460     constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
461     constraint.Apply();
462
463     // Rotation constraint
464     SpiralRotationConstraint rotationConstraint( itemId, mImpl->mItemSpacingRadians );
465     if ( orientation == ControlOrientation::Up )
466     {
467       constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, rotationConstraint, &SpiralRotationConstraint::OrientationUp );
468     }
469     else if ( orientation == ControlOrientation::Left )
470     {
471       constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, rotationConstraint, &SpiralRotationConstraint::OrientationLeft );
472     }
473     else if ( orientation == ControlOrientation::Down )
474     {
475       constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, rotationConstraint, &SpiralRotationConstraint::OrientationDown );
476     }
477     else // orientation == ControlOrientation::Right
478     {
479       constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, rotationConstraint, &SpiralRotationConstraint::OrientationRight );
480     }
481     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
482     constraint.Apply();
483
484     // Color constraint
485     constraint = Constraint::New< Vector4 >( actor, Actor::Property::COLOR, SpiralColorConstraint( itemId, mImpl->mItemSpacingRadians ) );
486     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
487     constraint.SetRemoveAction(Dali::Constraint::Discard);
488     constraint.Apply();
489
490     // Visibility constraint
491     SpiralVisibilityConstraint visibilityConstraint( itemId, mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment );
492     if (IsVertical( orientation ) )
493     {
494       constraint = Constraint::New< bool >( actor, Actor::Property::VISIBLE, visibilityConstraint, &SpiralVisibilityConstraint::Portrait );
495     }
496     else // horizontal
497     {
498       constraint = Constraint::New< bool >( actor, Actor::Property::VISIBLE, visibilityConstraint, &SpiralVisibilityConstraint::Landscape );
499     }
500     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
501     constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
502     constraint.SetRemoveAction(Dali::Constraint::Discard);
503     constraint.Apply();
504   }
505 }
506
507 void SpiralLayout::SetSpiralLayoutProperties(const Property::Map& properties)
508 {
509   // Set any properties specified for SpiralLayout.
510   for( unsigned int idx = 0, mapCount = properties.Count(); idx < mapCount; ++idx )
511   {
512     KeyValuePair propertyPair = properties.GetKeyValue( idx );
513     switch(DefaultItemLayoutProperty::Property(propertyPair.first.indexKey))
514     {
515       case DefaultItemLayoutProperty::SPIRAL_ITEM_SPACING:
516       {
517         SetItemSpacing(Radian(propertyPair.second.Get<float>()));
518         break;
519       }
520       case DefaultItemLayoutProperty::SPIRAL_MAXIMUM_SWIPE_SPEED:
521       {
522         SetMaximumSwipeSpeed(propertyPair.second.Get<float>());
523         break;
524       }
525       case DefaultItemLayoutProperty::SPIRAL_TOP_ITEM_ALIGNMENT:
526       {
527         SetTopItemAlignment(propertyPair.second.Get<float>());
528         break;
529       }
530       case DefaultItemLayoutProperty::SPIRAL_SCROLL_SPEED_FACTOR:
531       {
532         SetScrollSpeedFactor(propertyPair.second.Get<float>());
533         break;
534       }
535       case DefaultItemLayoutProperty::SPIRAL_REVOLUTION_DISTANCE:
536       {
537         SetRevolutionDistance(propertyPair.second.Get<float>());
538         break;
539       }
540       case DefaultItemLayoutProperty::SPIRAL_ITEM_FLICK_ANIMATION_DURATION:
541       {
542         SetItemFlickAnimationDuration(propertyPair.second.Get<float>());
543         break;
544       }
545       default:
546       {
547         break;
548       }
549     }
550   }
551   ResetLayoutChangedFlag();
552 }
553
554 Vector3 SpiralLayout::GetItemPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize) const
555 {
556   Vector3 itemPosition = Vector3::ZERO;
557   const ControlOrientation::Type orientation = GetOrientation();
558
559   SpiralPositionConstraint positionConstraint( itemID, GetDefaultSpiralRadiusFunction( layoutSize ), mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment );
560
561   if ( orientation == ControlOrientation::Up )
562   {
563     positionConstraint.OrientationUp( itemPosition, currentLayoutPosition + itemID, layoutSize );
564   }
565   else if ( orientation == ControlOrientation::Left )
566   {
567     positionConstraint.OrientationLeft( itemPosition, currentLayoutPosition + itemID, layoutSize );
568   }
569   else if ( orientation == ControlOrientation::Down )
570   {
571     positionConstraint.OrientationDown( itemPosition, currentLayoutPosition + itemID, layoutSize );
572   }
573   else //orientation == ControlOrientation::Right
574   {
575     positionConstraint.OrientationRight( itemPosition, currentLayoutPosition + itemID, layoutSize );
576   }
577
578   return itemPosition;
579 }
580
581 SpiralLayout::SpiralLayout()
582 : mImpl(NULL)
583 {
584   mImpl = new Impl();
585 }
586
587 float SpiralLayout::GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize)
588 {
589   return GetItemScrollToPosition(itemID);
590 }
591
592 } // namespace Internal
593
594 } // namespace Toolkit
595
596 } // namespace Dali