3b53bac3982ac07bdc8bb12c60210727a41fb6cc
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scrollable / item-view / depth-layout.cpp
1 /*
2  * Copyright (c) 2016 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/depth-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 unsigned int DEFAULT_NUMBER_OF_COLUMNS    = 3;
37 const float        DEFAULT_NUMBER_OF_ROWS       = 26.0f;
38 const float        DEFAULT_ROW_SPACING          = 55.0f;
39 const float        DEFAULT_BOTTOM_MARGIN_FACTOR = 0.2f;
40 const Radian       DEFAULT_TILT_ANGLE           ( Math::PI*0.15f );
41 const Radian       DEFAULT_ITEM_TILT_ANGLE      ( -Math::PI*0.025f );
42 const float        DEFAULT_SCROLL_SPEED_FACTOR  = 0.02f;
43 const float        DEFAULT_MAXIMUM_SWIPE_SPEED  = 50.0f;
44 const float        DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.03f;
45
46 inline float GetColumnPosition( unsigned int numberOfColumns, unsigned int columnNumber, const Vector3& itemSize, float layoutWidth )
47 {
48   // Share the available space between margins & column spacings
49   float availableSpace = std::max( 0.0f, ( layoutWidth - itemSize.width * numberOfColumns ) );
50
51   float leftMargin = availableSpace / numberOfColumns * 0.5f;
52
53   float columnPosition = leftMargin + itemSize.width * 0.5f + columnNumber * ( itemSize.width + availableSpace / numberOfColumns );
54
55   return columnPosition - layoutWidth * 0.5f;
56 }
57
58 struct DepthPositionConstraint
59 {
60   DepthPositionConstraint( unsigned int itemId,
61                            unsigned int numberOfColumns,
62                            unsigned int columnNumber,
63                            const Vector3& itemSize,
64                            float heightScale,
65                            float depthScale )
66   : mItemSize( itemSize ),
67     mItemId( itemId ),
68     mNumberOfColumns( numberOfColumns ),
69     mColumnNumber( columnNumber ),
70     mHeightScale( heightScale ),
71     mDepthScale( depthScale )
72   {
73   }
74
75   inline void Orientation0( Vector3& current, float layoutPosition, const Vector3& layoutSize )
76   {
77     float rowLayoutPositon = layoutPosition - static_cast< float >( mColumnNumber );
78
79     current.x = GetColumnPosition( mNumberOfColumns, mColumnNumber, mItemSize, layoutSize.width );
80     current.y = rowLayoutPositon * mHeightScale + layoutSize.height * 0.5f - DEFAULT_BOTTOM_MARGIN_FACTOR * layoutSize.height - mItemSize.height * 0.5f;
81     current.z = -rowLayoutPositon * mDepthScale;
82   }
83
84   inline void Orientation90( Vector3& current, float layoutPosition, const Vector3& layoutSize )
85   {
86     float rowLayoutPositon = layoutPosition - static_cast< float >( mColumnNumber ) + mNumberOfColumns * 0.5f;
87
88     current.x = rowLayoutPositon * mHeightScale + layoutSize.width * 0.5f - DEFAULT_BOTTOM_MARGIN_FACTOR * layoutSize.width - mItemSize.height * 0.5f;
89     current.y = -GetColumnPosition( mNumberOfColumns, mColumnNumber, mItemSize, layoutSize.height );
90     current.z = -rowLayoutPositon * mDepthScale;
91   }
92
93   inline void Orientation180( Vector3& current, float layoutPosition, const Vector3& layoutSize )
94   {
95     float rowLayoutPositon = layoutPosition - static_cast< float >( mColumnNumber );
96
97     current.x = -GetColumnPosition( mNumberOfColumns, mColumnNumber, mItemSize, layoutSize.width );
98     current.y = -( rowLayoutPositon * mHeightScale + layoutSize.height * 0.5f - DEFAULT_BOTTOM_MARGIN_FACTOR * layoutSize.height - mItemSize.height * 0.5f );
99     current.z = -rowLayoutPositon * mDepthScale;
100   }
101
102   inline void Orientation270( Vector3& current, float layoutPosition, const Vector3& layoutSize )
103   {
104     float rowLayoutPositon = layoutPosition - static_cast< float >( mColumnNumber ) + mNumberOfColumns * 0.5f;
105
106     current.x = -( rowLayoutPositon * mHeightScale + layoutSize.width * 0.5f - DEFAULT_BOTTOM_MARGIN_FACTOR * layoutSize.width - mItemSize.height * 0.5f );
107     current.y = GetColumnPosition( mNumberOfColumns, mColumnNumber, mItemSize, layoutSize.height );
108     current.z = -rowLayoutPositon * mDepthScale;
109   }
110
111   void Orientation0( Vector3& current, const PropertyInputContainer& inputs )
112   {
113     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
114     const Vector3& layoutSize = inputs[1]->GetVector3();
115     Orientation0( current, layoutPosition, layoutSize );
116   }
117
118   void Orientation90( Vector3& current, const PropertyInputContainer& inputs )
119   {
120     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
121     const Vector3& layoutSize = inputs[1]->GetVector3();
122     Orientation90( current, layoutPosition, layoutSize );
123   }
124
125   void Orientation180( Vector3& current, const PropertyInputContainer& inputs )
126   {
127     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
128     const Vector3& layoutSize = inputs[1]->GetVector3();
129     Orientation180( current, layoutPosition, layoutSize );
130   }
131
132   void Orientation270( Vector3& current, const PropertyInputContainer& inputs )
133   {
134     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
135     const Vector3& layoutSize = inputs[1]->GetVector3();
136     Orientation270( current, layoutPosition, layoutSize );
137   }
138
139   Vector3 mItemSize;
140   unsigned int mItemId;
141   unsigned int mNumberOfColumns;
142   unsigned int mColumnNumber;
143   float mHeightScale;
144   float mDepthScale;
145 };
146
147 struct DepthRotationConstraint
148 {
149   DepthRotationConstraint( Radian angleRadians, ControlOrientation::Type orientation )
150   : mTiltAngle( angleRadians ),
151     mMultiplier( 0.0f )
152   {
153     if ( orientation == ControlOrientation::Up )
154     {
155       mMultiplier = 0.0f;
156     }
157     else if ( orientation == ControlOrientation::Left )
158     {
159       mMultiplier = 1.5f;
160     }
161     else if ( orientation == ControlOrientation::Down )
162     {
163       mMultiplier = -1.0f;
164     }
165     else // orientation == ControlOrientation::Right
166     {
167       mMultiplier = 0.5f;
168     }
169   }
170
171   void operator()( Quaternion& current, const PropertyInputContainer& /* inputs */ )
172   {
173     current = Quaternion( Radian( mMultiplier * Math::PI ), Vector3::ZAXIS ) * Quaternion( mTiltAngle, Vector3::XAXIS );
174   }
175
176   Radian mTiltAngle;
177   float mMultiplier;
178 };
179
180 struct DepthColorConstraint
181 {
182   DepthColorConstraint( unsigned int itemId, unsigned int numberOfColumns, float numberOfRows, unsigned int columnNumber )
183   : mItemId( itemId ),
184     mNumberOfColumns( numberOfColumns ),
185     mNumberOfRows( numberOfRows ),
186     mColumnNumber( columnNumber )
187   {
188   }
189
190   void operator()( Vector4& current, const Dali::PropertyInputContainer& inputs )
191   {
192     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
193     float row = ( layoutPosition - static_cast<float>( mColumnNumber ) ) / mNumberOfColumns;
194
195     float darkness(1.0f);
196     float alpha(1.0f);
197
198     if (row < 0.0f)
199     {
200       darkness = alpha = std::max(0.0f, 1.0f + row);
201     }
202     else
203     {
204       if (row > mNumberOfRows)
205       {
206         darkness = 0.0f;
207       }
208       else
209       {
210         darkness = 1.0f - ( 1.0f * (row / mNumberOfRows) );
211       }
212
213       if (row > (mNumberOfRows-1.0f))
214       {
215         alpha = std::max(0.0f, 1.0f - (row-(mNumberOfRows-1.0f)));
216       }
217     }
218
219     current.r = current.g = current.b = darkness;
220     current.a *= alpha;
221   }
222
223   unsigned int mItemId;
224   unsigned int mNumberOfColumns;
225   float mNumberOfRows;
226   unsigned int mColumnNumber;
227 };
228
229 struct DepthVisibilityConstraint
230 {
231   DepthVisibilityConstraint( unsigned int itemId, unsigned int numberOfColumns, float numberOfRows, unsigned int columnNumber )
232   : mItemId( itemId ),
233     mNumberOfColumns(numberOfColumns),
234     mNumberOfRows(numberOfRows),
235     mColumnNumber(columnNumber)
236   {
237   }
238
239   void operator()( bool& current, const Dali::PropertyInputContainer& inputs )
240   {
241     float layoutPosition = inputs[0]->GetFloat() + static_cast< float >( mItemId );
242     float row = ( layoutPosition - static_cast< float >( mColumnNumber ) ) / mNumberOfColumns;
243
244     current = ( row > -1.0f ) && ( row < mNumberOfRows );
245   }
246
247   unsigned int mItemId;
248   unsigned int mNumberOfColumns;
249   float mNumberOfRows;
250   unsigned int mColumnNumber;
251 };
252
253 } // unnamed namespace
254
255 namespace Dali
256 {
257
258 namespace Toolkit
259 {
260
261 namespace Internal
262 {
263
264 struct DepthLayout::Impl
265 {
266   Impl()
267   : mNumberOfColumns(DEFAULT_NUMBER_OF_COLUMNS),
268     mNumberOfRows(DEFAULT_NUMBER_OF_ROWS),
269     mRowSpacing(DEFAULT_ROW_SPACING),
270     mTiltAngle(DEFAULT_TILT_ANGLE),
271     mItemTiltAngle(DEFAULT_ITEM_TILT_ANGLE),
272     mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
273     mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
274     mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION)
275   {
276   }
277
278   unsigned int mNumberOfColumns;
279   unsigned int mNumberOfRows;
280
281   float mRowSpacing;
282
283   Radian mTiltAngle;
284   Radian mItemTiltAngle;
285
286   float mScrollSpeedFactor;
287   float mMaximumSwipeSpeed;
288   float mItemFlickAnimationDuration;
289 };
290
291 DepthLayoutPtr DepthLayout::New()
292 {
293   return DepthLayoutPtr(new DepthLayout());
294 }
295
296 DepthLayout::~DepthLayout()
297 {
298   delete mImpl;
299 }
300
301 void DepthLayout::SetNumberOfColumns(unsigned int columns)
302 {
303   mImpl->mNumberOfColumns = columns;
304 }
305
306 unsigned int DepthLayout::GetNumberOfColumns() const
307 {
308   return mImpl->mNumberOfColumns;
309 }
310
311 void DepthLayout::SetNumberOfRows(unsigned int rows)
312 {
313   mImpl->mNumberOfRows = rows;
314 }
315
316 unsigned int DepthLayout::GetNumberOfRows() const
317 {
318   return mImpl->mNumberOfRows;
319 }
320
321 void DepthLayout::SetRowSpacing(float spacing)
322 {
323   mImpl->mRowSpacing = spacing;
324 }
325
326 float DepthLayout::GetRowSpacing() const
327 {
328   return mImpl->mRowSpacing;
329 }
330
331 void DepthLayout::SetTiltAngle(Degree angle)
332 {
333   mImpl->mTiltAngle = Degree( Clamp( angle, -45.0f, 45.0f ) );
334 }
335
336 Degree DepthLayout::GetTiltAngle() const
337 {
338   return Degree( mImpl->mTiltAngle );
339 }
340
341 void DepthLayout::SetItemTiltAngle(Degree angle)
342 {
343   mImpl->mItemTiltAngle = angle;
344 }
345
346 Degree DepthLayout::GetItemTiltAngle() const
347 {
348   return Degree( mImpl->mItemTiltAngle );
349 }
350
351 void DepthLayout::SetScrollSpeedFactor(float scrollSpeed)
352 {
353   mImpl->mScrollSpeedFactor = scrollSpeed;
354 }
355
356 void DepthLayout::SetMaximumSwipeSpeed(float speed)
357 {
358   mImpl->mMaximumSwipeSpeed = speed;
359 }
360
361 void DepthLayout::SetItemFlickAnimationDuration(float durationSeconds)
362 {
363   mImpl->mItemFlickAnimationDuration = durationSeconds;
364 }
365
366 float DepthLayout::GetScrollSpeedFactor() const
367 {
368   return mImpl->mScrollSpeedFactor;
369 }
370
371 float DepthLayout::GetMaximumSwipeSpeed() const
372 {
373   return mImpl->mMaximumSwipeSpeed;
374 }
375
376 float DepthLayout::GetItemFlickAnimationDuration() const
377 {
378   return mImpl->mItemFlickAnimationDuration;
379 }
380
381 float DepthLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
382 {
383   return static_cast<float>(mImpl->mNumberOfColumns) - static_cast<float>(numberOfItems);
384 }
385
386 float DepthLayout::GetClosestAnchorPosition(float layoutPosition) const
387 {
388   float rowIndex = static_cast<float>(round(layoutPosition / mImpl->mNumberOfColumns));
389   return rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
390 }
391
392 float DepthLayout::GetItemScrollToPosition(unsigned int itemId) const
393 {
394   float rowIndex = static_cast< float >( itemId ) / mImpl->mNumberOfColumns;
395   return -rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
396 }
397
398 ItemRange DepthLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
399 {
400   float firstRow = -(firstItemPosition/mImpl->mNumberOfColumns);
401   float lastRow = firstRow + mImpl->mNumberOfRows * 0.5f;
402
403   unsigned int firstItem = static_cast<unsigned int>(std::max(0.0f, firstRow * mImpl->mNumberOfColumns));
404   unsigned int lastItem  = static_cast<unsigned int>(std::max(0.0f, lastRow  * mImpl->mNumberOfColumns));
405
406   return ItemRange(firstItem, lastItem+1);
407 }
408
409 unsigned int DepthLayout::GetReserveItemCount(Vector3 layoutSize) const
410 {
411   float itemsWithinLayout = (layoutSize.depth * mImpl->mNumberOfColumns) / (cosf(mImpl->mTiltAngle) * mImpl->mRowSpacing);
412
413   return static_cast<unsigned int>(itemsWithinLayout);
414 }
415
416 void DepthLayout::GetDefaultItemSize( unsigned int itemId, const Vector3& layoutSize, Vector3& itemSize ) const
417 {
418   // 1x1 aspect ratio
419   itemSize.width = itemSize.height = itemSize.depth = ( IsVertical( GetOrientation() ) ? layoutSize.width : layoutSize.height ) / static_cast<float>( mImpl->mNumberOfColumns + 1 );
420 }
421
422 Degree DepthLayout::GetScrollDirection() const
423 {
424   Degree scrollDirection(0.0f);
425   ControlOrientation::Type orientation = GetOrientation();
426
427   if ( orientation == ControlOrientation::Up )
428   {
429     scrollDirection = Degree( 180.0f );
430   }
431   else if ( orientation == ControlOrientation::Left )
432   {
433     scrollDirection = Degree( 270.0f );
434   }
435   else if ( orientation == ControlOrientation::Down )
436   {
437     scrollDirection = Degree( 0.0f );
438   }
439   else // orientation == ControlOrientation::Right
440   {
441     scrollDirection = Degree( 90.0f );
442   }
443
444   return scrollDirection;
445 }
446
447 void DepthLayout::ApplyConstraints( Actor& actor, const int itemId, const Vector3& layoutSize, const Actor& itemViewActor )
448 {
449
450   if(HasLayoutChanged())
451   {
452     SetDepthLayoutProperties(GetLayoutProperties());
453   }
454   Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast( itemViewActor );
455   if( itemView )
456   {
457     Vector3 itemSize;
458     GetItemSize( itemId, layoutSize, itemSize );
459
460     ControlOrientation::Type orientation = GetOrientation();
461
462     // Position constraint
463     Constraint constraint;
464     DepthPositionConstraint depthPositionStruct( itemId,
465                                                  mImpl->mNumberOfColumns,
466                                                  itemId % mImpl->mNumberOfColumns,
467                                                  itemSize,
468                                                  -sinf( mImpl->mTiltAngle ) * mImpl->mRowSpacing,
469                                                  cosf( mImpl->mTiltAngle ) * mImpl->mRowSpacing );
470     if ( orientation == ControlOrientation::Up )
471     {
472       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, depthPositionStruct, &DepthPositionConstraint::Orientation0 );
473     }
474     else if ( orientation == ControlOrientation::Left )
475     {
476       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, depthPositionStruct, &DepthPositionConstraint::Orientation90 );
477     }
478     else if ( orientation == ControlOrientation::Down )
479     {
480       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, depthPositionStruct, &DepthPositionConstraint::Orientation180 );
481     }
482     else // orientation == ControlOrientation::Right
483     {
484       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, depthPositionStruct, &DepthPositionConstraint::Orientation270 );
485     }
486     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
487     constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
488     constraint.Apply();
489
490     // Rotation constraint
491     constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, DepthRotationConstraint( mImpl->mItemTiltAngle, orientation ) );
492     constraint.Apply();
493
494     // Color constraint
495     constraint = Constraint::New< Vector4 >( actor, Actor::Property::COLOR, DepthColorConstraint( itemId, mImpl->mNumberOfColumns, mImpl->mNumberOfRows*0.5f, itemId % mImpl->mNumberOfColumns ) );
496     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
497     constraint.SetRemoveAction( Dali::Constraint::Discard );
498     constraint.Apply();
499
500     // Visibility constraint
501     constraint = Constraint::New< bool >( actor, Actor::Property::VISIBLE, DepthVisibilityConstraint( itemId, mImpl->mNumberOfColumns, mImpl->mNumberOfRows*0.5f, itemId % mImpl->mNumberOfColumns ) );
502     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
503     constraint.SetRemoveAction( Dali::Constraint::Discard );
504     constraint.Apply();
505   }
506 }
507
508 void DepthLayout::SetDepthLayoutProperties(const Property::Map& properties)
509 {
510   // Set any properties specified for DepthLayout.
511   for( unsigned int idx = 0, mapCount = properties.Count(); idx < mapCount; ++idx )
512   {
513     KeyValuePair propertyPair = properties.GetKeyValue( idx );
514     switch(DefaultItemLayoutProperty::Property(propertyPair.first.indexKey))
515     {
516       case DefaultItemLayoutProperty::DEPTH_COLUMN_NUMBER:
517       {
518         SetNumberOfColumns(propertyPair.second.Get<int>());
519         break;
520       }
521       case DefaultItemLayoutProperty::DEPTH_ROW_NUMBER:
522       {
523         SetNumberOfRows(propertyPair.second.Get<int>());
524         break;
525       }
526       case DefaultItemLayoutProperty::DEPTH_ROW_SPACING:
527       {
528         SetRowSpacing(propertyPair.second.Get<float>());
529         break;
530       }
531       case DefaultItemLayoutProperty::DEPTH_MAXIMUM_SWIPE_SPEED:
532       {
533         SetMaximumSwipeSpeed(propertyPair.second.Get<float>());
534         break;
535       }
536       case DefaultItemLayoutProperty::DEPTH_SCROLL_SPEED_FACTOR:
537       {
538         SetScrollSpeedFactor(propertyPair.second.Get<float>());
539         break;
540       }
541       case DefaultItemLayoutProperty::DEPTH_TILT_ANGLE:
542       {
543         SetTiltAngle(Degree(Radian(propertyPair.second.Get<float>())));
544         break;
545       }
546       case DefaultItemLayoutProperty::DEPTH_ITEM_TILT_ANGLE:
547       {
548         SetItemTiltAngle(Degree(Radian(propertyPair.second.Get<float>())));
549         break;
550       }
551       case DefaultItemLayoutProperty::DEPTH_ITEM_FLICK_ANIMATION_DURATION:
552       {
553         SetItemFlickAnimationDuration(propertyPair.second.Get<float>());
554         break;
555       }
556       default:
557       {
558         break;
559       }
560     }
561   }
562   ResetLayoutChangedFlag();
563 }
564
565 Vector3 DepthLayout::GetItemPosition( int itemID, float currentLayoutPosition, const Vector3& layoutSize ) const
566 {
567   Vector3 itemPosition = Vector3::ZERO;
568
569   const float heightScale = -sinf( mImpl->mTiltAngle ) * mImpl->mRowSpacing;
570   const float depthScale  =  cosf( mImpl->mTiltAngle ) * mImpl->mRowSpacing;
571
572   Vector3 itemSize;
573   GetItemSize( itemID, layoutSize, itemSize );
574   DepthPositionConstraint positionFunctor = DepthPositionConstraint( itemID,
575                                                                      mImpl->mNumberOfColumns,
576                                                                      itemID % mImpl->mNumberOfColumns,
577                                                                      itemSize,
578                                                                      heightScale,
579                                                                      depthScale );
580   ControlOrientation::Type orientation = GetOrientation();
581   if ( orientation == ControlOrientation::Up )
582   {
583     positionFunctor.Orientation0( itemPosition, currentLayoutPosition + itemID, layoutSize );
584   }
585   else if ( orientation == ControlOrientation::Left )
586   {
587     positionFunctor.Orientation90( itemPosition, currentLayoutPosition + itemID, layoutSize );
588   }
589   else if ( orientation == ControlOrientation::Down )
590   {
591     positionFunctor.Orientation180( itemPosition, currentLayoutPosition + itemID, layoutSize );
592   }
593   else // orientation == ControlOrientation::Right
594   {
595     positionFunctor.Orientation270( itemPosition, currentLayoutPosition + itemID, layoutSize );
596   }
597
598   return itemPosition;
599 }
600
601 DepthLayout::DepthLayout()
602 : mImpl(NULL)
603 {
604   mImpl = new Impl();
605 }
606
607 float DepthLayout::GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize)
608 {
609   float scrollTo = currentLayoutPosition;
610   float row = (currentLayoutPosition + itemID - static_cast<float>(itemID % mImpl->mNumberOfColumns)) / mImpl->mNumberOfColumns;
611
612   // Check whether item is not within viewable area
613   if(row <= -1.0f)
614   {
615     scrollTo = GetItemScrollToPosition(itemID);
616   }
617   else if(row > mImpl->mNumberOfRows * 0.5f - 1.0f)
618   {
619     scrollTo = GetItemScrollToPosition(itemID) + (mImpl->mNumberOfRows - 1.0f) * 0.5f * mImpl->mNumberOfColumns;
620   }
621
622   return scrollTo;
623 }
624
625 int DepthLayout::GetNextFocusItemID(int itemID, int maxItems, Dali::Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
626 {
627   switch( direction )
628   {
629     case Toolkit::Control::KeyboardFocus::LEFT:
630     {
631       itemID--;
632       if( itemID < 0 )
633       {
634         itemID = loopEnabled ? maxItems - 1 : 0;
635       }
636       break;
637     }
638     case Toolkit::Control::KeyboardFocus::UP:
639     {
640       itemID += mImpl->mNumberOfColumns;
641       if( itemID >= maxItems )
642       {
643         itemID = loopEnabled ? 0 : itemID - mImpl->mNumberOfColumns;
644       }
645       break;
646     }
647     case Toolkit::Control::KeyboardFocus::RIGHT:
648     {
649       itemID++;
650       if( itemID >= maxItems )
651       {
652         itemID = loopEnabled ? 0 : maxItems - 1;
653       }
654       break;
655     }
656     case Toolkit::Control::KeyboardFocus::DOWN:
657     {
658       itemID -= mImpl->mNumberOfColumns;
659       if( itemID < 0 )
660       {
661         itemID = loopEnabled ? itemID + maxItems : itemID + mImpl->mNumberOfColumns;
662       }
663       break;
664     }
665     default:
666     {
667       break;
668     }
669   }
670   return itemID;
671 }
672
673 } // namespace Internal
674
675 } // namespace Toolkit
676
677 } // namespace Dali