(ItemView) Make default layout properties public
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scrollable / item-view / spiral-layout.cpp
1 /*
2  * Copyright (c) 2017 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/public-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   // This just implements the default behaviour of constraint application.
430   // Custom layouts can override this function to apply their custom constraints.
431   Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast( itemViewActor );
432   if( itemView )
433   {
434     const ControlOrientation::Type orientation = GetOrientation();
435
436     // Position constraint
437     SpiralPositionConstraint positionConstraint( itemId, GetDefaultSpiralRadiusFunction( layoutSize ), mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment );
438     Constraint constraint;
439     if ( orientation == ControlOrientation::Up )
440     {
441       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &SpiralPositionConstraint::OrientationUp );
442     }
443     else if ( orientation == ControlOrientation::Left )
444     {
445       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &SpiralPositionConstraint::OrientationLeft );
446     }
447     else if ( orientation == ControlOrientation::Down )
448     {
449       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &SpiralPositionConstraint::OrientationDown );
450     }
451     else // orientation == ControlOrientation::Right
452     {
453       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &SpiralPositionConstraint::OrientationRight );
454     }
455     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
456     constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
457     constraint.Apply();
458
459     // Rotation constraint
460     SpiralRotationConstraint rotationConstraint( itemId, mImpl->mItemSpacingRadians );
461     if ( orientation == ControlOrientation::Up )
462     {
463       constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, rotationConstraint, &SpiralRotationConstraint::OrientationUp );
464     }
465     else if ( orientation == ControlOrientation::Left )
466     {
467       constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, rotationConstraint, &SpiralRotationConstraint::OrientationLeft );
468     }
469     else if ( orientation == ControlOrientation::Down )
470     {
471       constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, rotationConstraint, &SpiralRotationConstraint::OrientationDown );
472     }
473     else // orientation == ControlOrientation::Right
474     {
475       constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, rotationConstraint, &SpiralRotationConstraint::OrientationRight );
476     }
477     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
478     constraint.Apply();
479
480     // Color constraint
481     constraint = Constraint::New< Vector4 >( actor, Actor::Property::COLOR, SpiralColorConstraint( itemId, mImpl->mItemSpacingRadians ) );
482     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
483     constraint.SetRemoveAction(Dali::Constraint::Discard);
484     constraint.Apply();
485
486     // Visibility constraint
487     SpiralVisibilityConstraint visibilityConstraint( itemId, mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment );
488     if (IsVertical( orientation ) )
489     {
490       constraint = Constraint::New< bool >( actor, Actor::Property::VISIBLE, visibilityConstraint, &SpiralVisibilityConstraint::Portrait );
491     }
492     else // horizontal
493     {
494       constraint = Constraint::New< bool >( actor, Actor::Property::VISIBLE, visibilityConstraint, &SpiralVisibilityConstraint::Landscape );
495     }
496     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
497     constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
498     constraint.SetRemoveAction(Dali::Constraint::Discard);
499     constraint.Apply();
500   }
501 }
502
503 void SpiralLayout::SetSpiralLayoutProperties(const Property::Map& properties)
504 {
505   // Set any properties specified for SpiralLayout.
506   for( unsigned int idx = 0, mapCount = properties.Count(); idx < mapCount; ++idx )
507   {
508     KeyValuePair propertyPair = properties.GetKeyValue( idx );
509     switch(DefaultItemLayoutProperty::Property(propertyPair.first.indexKey))
510     {
511       case DefaultItemLayoutProperty::SPIRAL_ITEM_SPACING:
512       {
513         SetItemSpacing(Radian(propertyPair.second.Get<float>()));
514         break;
515       }
516       case DefaultItemLayoutProperty::SPIRAL_MAXIMUM_SWIPE_SPEED:
517       {
518         SetMaximumSwipeSpeed(propertyPair.second.Get<float>());
519         break;
520       }
521       case DefaultItemLayoutProperty::SPIRAL_TOP_ITEM_ALIGNMENT:
522       {
523         SetTopItemAlignment(propertyPair.second.Get<float>());
524         break;
525       }
526       case DefaultItemLayoutProperty::SPIRAL_SCROLL_SPEED_FACTOR:
527       {
528         SetScrollSpeedFactor(propertyPair.second.Get<float>());
529         break;
530       }
531       case DefaultItemLayoutProperty::SPIRAL_REVOLUTION_DISTANCE:
532       {
533         SetRevolutionDistance(propertyPair.second.Get<float>());
534         break;
535       }
536       case DefaultItemLayoutProperty::SPIRAL_ITEM_FLICK_ANIMATION_DURATION:
537       {
538         SetItemFlickAnimationDuration(propertyPair.second.Get<float>());
539         break;
540       }
541       default:
542       {
543         break;
544       }
545     }
546   }
547 }
548
549 Vector3 SpiralLayout::GetItemPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize) const
550 {
551   Vector3 itemPosition = Vector3::ZERO;
552   const ControlOrientation::Type orientation = GetOrientation();
553
554   SpiralPositionConstraint positionConstraint( itemID, GetDefaultSpiralRadiusFunction( layoutSize ), mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment );
555
556   if ( orientation == ControlOrientation::Up )
557   {
558     positionConstraint.OrientationUp( itemPosition, currentLayoutPosition + itemID, layoutSize );
559   }
560   else if ( orientation == ControlOrientation::Left )
561   {
562     positionConstraint.OrientationLeft( itemPosition, currentLayoutPosition + itemID, layoutSize );
563   }
564   else if ( orientation == ControlOrientation::Down )
565   {
566     positionConstraint.OrientationDown( itemPosition, currentLayoutPosition + itemID, layoutSize );
567   }
568   else //orientation == ControlOrientation::Right
569   {
570     positionConstraint.OrientationRight( itemPosition, currentLayoutPosition + itemID, layoutSize );
571   }
572
573   return itemPosition;
574 }
575
576 SpiralLayout::SpiralLayout()
577 : mImpl(NULL)
578 {
579   mImpl = new Impl();
580 }
581
582 float SpiralLayout::GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize)
583 {
584   return GetItemScrollToPosition(itemID);
585 }
586
587 } // namespace Internal
588
589 } // namespace Toolkit
590
591 } // namespace Dali