Scrollable: Klocwork issues fix
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / public-api / controls / scrollable / item-view / grid-layout.cpp
1 /*
2  * Copyright (c) 2014 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/public-api/controls/scrollable/item-view/grid-layout.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23 #include <dali/public-api/animation/animation.h>
24
25 using namespace Dali;
26 using namespace Dali::Toolkit;
27 using namespace std;
28
29 namespace // unnamed namespace
30 {
31
32 const unsigned int DEFAULT_NUMBER_OF_COLUMNS = 4;
33 const float DEFAULT_TOP_MARGIN     =  95.0f;
34 const float DEFAULT_BOTTOM_MARGIN  =  20.0f;
35 const float DEFAULT_SIDE_MARGIN    =  20.0f;
36 const float DEFAULT_COLUMN_SPACING =  20.0f;
37 const float DEFAULT_ROW_SPACING    =  20.0f;
38 const float DEFAULT_SCROLL_SPEED_FACTOR = 0.03f;
39 const float DEFAULT_MAXIMUM_SWIPE_SPEED = 100.0f;
40 const float DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.015f;
41
42 // 4 orientations are supported
43 static const unsigned int ORIENTATION_COUNT = 4;
44
45 static Vector3 GetItemSizeDefaultFunction(unsigned int numberOfColumns, float layoutWidth, float sideMargin, float columnSpacing)
46 {
47   float width = (layoutWidth - sideMargin * 2.0f - columnSpacing * static_cast<float>(numberOfColumns - 1)) / static_cast<float>(numberOfColumns);
48
49   // 4x3 aspect ratio
50   return Vector3(width, width * 0.75f, width * 0.75f);
51 }
52
53 struct GridPositionConstraint0
54 {
55   GridPositionConstraint0(const unsigned int columnIndex, const unsigned int numberOfColumns, const float rowSpacing, const float columnSpacing, const float topMargin, const float sideMargin, GridLayout::ItemSizeFunction itemSizeFunction, const float gap)
56   : mColumnIndex(columnIndex),
57     mNumberOfColumns(numberOfColumns),
58     mRowSpacing(rowSpacing),
59     mColumnSpacing(columnSpacing),
60     mTopMargin(topMargin),
61     mSideMargin(sideMargin),
62     mItemSizeFunction(itemSizeFunction),
63     mZGap(gap)
64   {
65   }
66
67   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
68   {
69     Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.width, mSideMargin, mColumnSpacing);
70
71     return Vector3(mSideMargin + (mColumnIndex * (itemSize.x + mColumnSpacing)) + itemSize.x * 0.5f - layoutSize.x * 0.5f,
72                    ((itemSize.y + mRowSpacing) * (layoutPosition - mColumnIndex)) / mNumberOfColumns - layoutSize.height * 0.5f + itemSize.y * 0.5f + mTopMargin,
73                    mColumnIndex * mZGap);
74   }
75
76 public:
77
78   unsigned int mColumnIndex;
79   unsigned int mNumberOfColumns;
80   float mRowSpacing;
81   float mColumnSpacing;
82   float mTopMargin;
83   float mSideMargin;
84   GridLayout::ItemSizeFunction mItemSizeFunction;
85   float mZGap;
86 };
87
88 struct GridPositionConstraint90
89 {
90   GridPositionConstraint90(const unsigned int columnIndex, const unsigned int numberOfColumns, const float rowSpacing, const float columnSpacing, const float topMargin, const float sideMargin, GridLayout::ItemSizeFunction itemSizeFunction, const float gap)
91   : mColumnIndex(columnIndex),
92     mNumberOfColumns(numberOfColumns),
93     mRowSpacing(rowSpacing),
94     mColumnSpacing(columnSpacing),
95     mTopMargin(topMargin),
96     mSideMargin(sideMargin),
97     mItemSizeFunction(itemSizeFunction),
98     mZGap(gap)
99   {
100   }
101
102   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
103   {
104     Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.height, mSideMargin, mColumnSpacing);
105
106     return Vector3(((itemSize.y + mRowSpacing) * (layoutPosition - mColumnIndex)) / mNumberOfColumns - layoutSize.width * 0.5f + itemSize.y * 0.5f + mTopMargin,
107                    -(mSideMargin + (mColumnIndex * (itemSize.x + mColumnSpacing)) + itemSize.x * 0.5f - layoutSize.y*0.5f),
108                    mColumnIndex * mZGap);
109   }
110
111 public:
112
113   unsigned int mColumnIndex;
114   unsigned int mNumberOfColumns;
115   float mRowSpacing;
116   float mColumnSpacing;
117   float mTopMargin;
118   float mSideMargin;
119   GridLayout::ItemSizeFunction mItemSizeFunction;
120   float mZGap;
121 };
122
123 struct GridPositionConstraint180
124 {
125   GridPositionConstraint180(const unsigned int columnIndex, const unsigned int numberOfColumns, const float rowSpacing, const float columnSpacing, const float topMargin, const float sideMargin, GridLayout::ItemSizeFunction itemSizeFunction, const float gap)
126   : mColumnIndex(columnIndex),
127     mNumberOfColumns(numberOfColumns),
128     mRowSpacing(rowSpacing),
129     mColumnSpacing(columnSpacing),
130     mTopMargin(topMargin),
131     mSideMargin(sideMargin),
132     mItemSizeFunction(itemSizeFunction),
133     mZGap(gap)
134   {
135   }
136
137   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
138   {
139     Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.width, mSideMargin, mColumnSpacing);
140
141     return Vector3(-(mSideMargin + (mColumnIndex * (itemSize.x + mColumnSpacing)) + itemSize.x * 0.5f - layoutSize.x * 0.5f),
142                    -(((itemSize.y + mRowSpacing) * (layoutPosition - mColumnIndex)) / mNumberOfColumns - layoutSize.height * 0.5f + itemSize.y * 0.5f + mTopMargin),
143                    mColumnIndex * mZGap);
144   }
145
146 public:
147
148   unsigned int mColumnIndex;
149   unsigned int mNumberOfColumns;
150   float mRowSpacing;
151   float mColumnSpacing;
152   float mTopMargin;
153   float mSideMargin;
154   GridLayout::ItemSizeFunction mItemSizeFunction;
155   float mZGap;
156 };
157
158 struct GridPositionConstraint270
159 {
160   GridPositionConstraint270(const unsigned int columnIndex, const unsigned int numberOfColumns, const float rowSpacing, const float columnSpacing, const float topMargin, const float sideMargin, GridLayout::ItemSizeFunction itemSizeFunction, const float gap)
161   : mColumnIndex(columnIndex),
162     mNumberOfColumns(numberOfColumns),
163     mRowSpacing(rowSpacing),
164     mColumnSpacing(columnSpacing),
165     mTopMargin(topMargin),
166     mSideMargin(sideMargin),
167     mItemSizeFunction(itemSizeFunction),
168     mZGap(gap)
169   {
170   }
171
172   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
173   {
174     Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.height, mSideMargin, mColumnSpacing);
175
176     return Vector3(-(((itemSize.y + mRowSpacing) * (layoutPosition - mColumnIndex)) / mNumberOfColumns - layoutSize.width * 0.5f + itemSize.y * 0.5f + mTopMargin),
177                    mSideMargin + (mColumnIndex * (itemSize.x + mColumnSpacing)) + itemSize.x * 0.5f - layoutSize.y * 0.5f,
178                    mColumnIndex * mZGap);
179   }
180
181 public:
182
183   unsigned int mColumnIndex;
184   unsigned int mNumberOfColumns;
185   float mRowSpacing;
186   float mColumnSpacing;
187   float mTopMargin;
188   float mSideMargin;
189   GridLayout::ItemSizeFunction mItemSizeFunction;
190   float mZGap;
191 };
192
193 struct GridRotationConstraint0
194 {
195   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
196   {
197     return Quaternion(0.0f, Vector3::ZAXIS);
198   }
199 };
200
201 struct GridRotationConstraint90
202 {
203   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
204   {
205     return Quaternion(1.5f * Math::PI, Vector3::ZAXIS);
206   }
207 };
208
209 struct GridRotationConstraint180
210 {
211   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
212   {
213     return Quaternion(Math::PI, Vector3::ZAXIS);
214   }
215 };
216
217 struct GridRotationConstraint270
218 {
219   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
220   {
221     return Quaternion(0.5f * Math::PI, Vector3::ZAXIS);
222   }
223 };
224
225 struct GridColorConstraint
226 {
227   Vector4 operator()(const Vector4& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
228   {
229     return Vector4( 1.0f, 1.0f, 1.0f, current.a );
230   }
231 };
232
233 struct GridVisibilityConstraintPortrait
234 {
235   GridVisibilityConstraintPortrait(const unsigned int columnIndex, const unsigned int numberOfColumns, const float rowSpacing, const float columnSpacing, const float sideMargin, GridLayout::ItemSizeFunction itemSizeFunction)
236   : mColumnIndex(columnIndex),
237     mNumberOfColumns(numberOfColumns),
238     mRowSpacing(rowSpacing),
239     mColumnSpacing(columnSpacing),
240     mSideMargin(sideMargin),
241     mItemSizeFunction(itemSizeFunction)
242   {
243   }
244
245   bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
246   {
247     Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.width, mSideMargin, mColumnSpacing);
248
249     float row = (layoutPosition - static_cast<float>(mColumnIndex)) / mNumberOfColumns;
250     int rowsPerPage = ceil(layoutSize.height / (itemSize.y + mRowSpacing));
251
252     return (row > -2.0f) && (row < rowsPerPage);
253   }
254
255 public:
256
257   unsigned int mColumnIndex;
258   unsigned int mNumberOfColumns;
259   float mRowSpacing;
260   float mColumnSpacing;
261   float mSideMargin;
262   GridLayout::ItemSizeFunction mItemSizeFunction;
263 };
264
265 struct GridVisibilityConstraintLandscape
266 {
267   GridVisibilityConstraintLandscape(const unsigned int columnIndex, const unsigned int numberOfColumns, const float rowSpacing, const float columnSpacing, const float sideMargin, GridLayout::ItemSizeFunction itemSizeFunction)
268   : mColumnIndex(columnIndex),
269     mNumberOfColumns(numberOfColumns),
270     mRowSpacing(rowSpacing),
271     mColumnSpacing(columnSpacing),
272     mSideMargin(sideMargin),
273     mItemSizeFunction(itemSizeFunction)
274   {
275   }
276
277   bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
278   {
279     Vector3 itemSize = mItemSizeFunction(mNumberOfColumns, layoutSize.height, mSideMargin, mColumnSpacing);
280
281     float row = (layoutPosition - static_cast<float>(mColumnIndex)) / mNumberOfColumns;
282     int rowsPerPage = ceil(layoutSize.width / (itemSize.y + mRowSpacing));
283
284     return (row > -2.0f) && (row < rowsPerPage);
285   }
286
287 public:
288
289   unsigned int mColumnIndex;
290   unsigned int mNumberOfColumns;
291   float mRowSpacing;
292   float mColumnSpacing;
293   float mSideMargin;
294   GridLayout::ItemSizeFunction mItemSizeFunction;
295 };
296
297 } // unnamed namespace
298
299 namespace Dali
300 {
301
302 namespace Toolkit
303 {
304
305 struct GridLayout::Impl
306 {
307   Impl()
308   : mNumberOfColumns(DEFAULT_NUMBER_OF_COLUMNS),
309     mRowSpacing(DEFAULT_ROW_SPACING),
310     mColumnSpacing(DEFAULT_COLUMN_SPACING),
311     mTopMargin(DEFAULT_TOP_MARGIN),
312     mBottomMargin(DEFAULT_BOTTOM_MARGIN),
313     mSideMargin(DEFAULT_SIDE_MARGIN),
314     mZGap(0.f),
315     mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
316     mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
317     mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION),
318     mItemSizeFunction(GetItemSizeDefaultFunction)
319   {
320     mColorConstraint = GridColorConstraint();
321
322     mRotationConstraint[0] = GridRotationConstraint0();
323     mRotationConstraint[1] = GridRotationConstraint90();
324     mRotationConstraint[2] = GridRotationConstraint180();
325     mRotationConstraint[3] = GridRotationConstraint270();
326   }
327
328   unsigned int mNumberOfColumns;
329   float mRowSpacing;
330   float mColumnSpacing;
331   float mTopMargin;
332   float mBottomMargin;
333   float mSideMargin;
334   float mZGap;
335
336   float mScrollSpeedFactor;
337   float mMaximumSwipeSpeed;
338   float mItemFlickAnimationDuration;
339
340   ItemLayout::QuaternionFunction mRotationConstraint[ORIENTATION_COUNT];
341   ItemLayout::Vector4Function mColorConstraint;
342
343   ItemSizeFunction mItemSizeFunction;
344 };
345
346 GridLayoutPtr GridLayout::New()
347 {
348   return GridLayoutPtr(new GridLayout());
349 }
350
351 GridLayout::~GridLayout()
352 {
353   delete mImpl;
354 }
355
356 void GridLayout::SetNumberOfColumns(unsigned int columns)
357 {
358   mImpl->mNumberOfColumns = columns;
359 }
360
361 unsigned int GridLayout::GetNumberOfColumns() const
362 {
363   return mImpl->mNumberOfColumns;
364 }
365
366 void GridLayout::SetRowSpacing(float spacing)
367 {
368   mImpl->mRowSpacing = spacing;
369 }
370
371 float GridLayout::GetRowSpacing() const
372 {
373   return mImpl->mRowSpacing;
374 }
375
376 void GridLayout::SetColumnSpacing(float spacing)
377 {
378   mImpl->mColumnSpacing = spacing;
379 }
380
381 float GridLayout::GetColumnSpacing() const
382 {
383   return mImpl->mColumnSpacing;
384 }
385
386 void GridLayout::SetTopMargin(float margin)
387 {
388   mImpl->mTopMargin = margin;
389 }
390
391 float GridLayout::GetTopMargin() const
392 {
393   return mImpl->mTopMargin;
394 }
395
396 void GridLayout::SetBottomMargin(float margin)
397 {
398   mImpl->mBottomMargin = margin;
399 }
400
401 float GridLayout::GetBottomMargin() const
402 {
403   return mImpl->mBottomMargin;
404 }
405
406 void GridLayout::SetSideMargin(float margin)
407 {
408   mImpl->mSideMargin = margin;
409 }
410
411 float GridLayout::GetSideMargin() const
412 {
413   return mImpl->mSideMargin;
414 }
415
416 void GridLayout::SetZGap(float gap)
417 {
418   mImpl->mZGap = gap;
419 }
420
421 float GridLayout::GetZGap() const
422 {
423   return mImpl->mZGap;
424 }
425
426 void GridLayout::SetItemSizeFunction(ItemSizeFunction function)
427 {
428   mImpl->mItemSizeFunction = function;
429 }
430
431 GridLayout::ItemSizeFunction GridLayout::GetItemSizeFunction() const
432 {
433   return mImpl->mItemSizeFunction;
434 }
435
436 void GridLayout::SetScrollSpeedFactor(float scrollSpeed)
437 {
438   mImpl->mScrollSpeedFactor = scrollSpeed;
439 }
440
441 void GridLayout::SetMaximumSwipeSpeed(float speed)
442 {
443   mImpl->mMaximumSwipeSpeed = speed;
444 }
445
446 void GridLayout::SetItemFlickAnimationDuration(float durationSeconds)
447 {
448   mImpl->mItemFlickAnimationDuration = durationSeconds;
449 }
450
451 float GridLayout::GetScrollSpeedFactor() const
452 {
453   return mImpl->mScrollSpeedFactor;
454 }
455
456 float GridLayout::GetMaximumSwipeSpeed() const
457 {
458   return mImpl->mMaximumSwipeSpeed;
459 }
460
461 float GridLayout::GetItemFlickAnimationDuration() const
462 {
463   return mImpl->mItemFlickAnimationDuration;
464 }
465
466 float GridLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
467 {
468   float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
469   float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
470
471   Vector3 itemSize = mImpl->mItemSizeFunction( mImpl->mNumberOfColumns, layoutWidth, mImpl->mSideMargin, mImpl->mColumnSpacing);
472
473   unsigned int itemsLastRow = numberOfItems % mImpl->mNumberOfColumns;
474   if (itemsLastRow == 0)
475   {
476     itemsLastRow = mImpl->mNumberOfColumns;
477   }
478
479   float rowsLastPage = (layoutHeight - mImpl->mBottomMargin - mImpl->mTopMargin + mImpl->mRowSpacing) / (itemSize.y + mImpl->mRowSpacing);
480   float itemsLastPage = (rowsLastPage - 1.0f) * static_cast<float>(mImpl->mNumberOfColumns) + static_cast<float>(itemsLastRow);
481
482   return itemsLastPage - static_cast<float>(numberOfItems);
483 }
484
485 float GridLayout::GetClosestAnchorPosition(float layoutPosition) const
486 {
487   float rowIndex = static_cast<float>(round(layoutPosition / mImpl->mNumberOfColumns));
488   return rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
489 }
490
491 float GridLayout::GetItemScrollToPosition(unsigned int itemId) const
492 {
493   float rowIndex = static_cast<float>(itemId / mImpl->mNumberOfColumns);
494   return -rowIndex * static_cast<float>(mImpl->mNumberOfColumns);
495 }
496
497 ItemRange GridLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
498 {
499   float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
500   float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
501
502   Vector3 itemSize = mImpl->mItemSizeFunction( mImpl->mNumberOfColumns, layoutWidth, mImpl->mSideMargin, mImpl->mColumnSpacing);
503
504   int itemsPerPage = mImpl->mNumberOfColumns * ceil(layoutHeight / (itemSize.y + mImpl->mRowSpacing));
505   int firstVisibleItem = -(static_cast<int>(firstItemPosition / mImpl->mNumberOfColumns)) * mImpl->mNumberOfColumns;
506
507   int firstItemIndex = std::max(0, firstVisibleItem - static_cast<int>(mImpl->mNumberOfColumns));
508   int lastItemIndex  = std::max(0, firstVisibleItem + itemsPerPage);
509
510   return ItemRange(firstItemIndex, lastItemIndex);
511 }
512
513 float GridLayout::GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize)
514 {
515   ItemLayout::Vector3Function positionConstraint;
516   Vector3 itemPosition = Vector3::ZERO;
517   if (GetPositionConstraint(itemID, positionConstraint))
518   {
519     itemPosition = positionConstraint(Vector3::ZERO, currentLayoutPosition + itemID, 0.0f, layoutSize);
520   }
521   Vector3 itemSize;
522   GetItemSize(itemID, layoutSize, itemSize);
523   Vector3 onScreenArea = (layoutSize - (IsVertical(mOrientation) ? itemSize : Vector3(itemSize.y, itemSize.x, itemSize.z))) * 0.5f;
524   if (itemPosition.x < -onScreenArea.x
525       || itemPosition.x > onScreenArea.x
526       || itemPosition.y < -onScreenArea.y
527       || itemPosition.y > onScreenArea.y)
528   {
529     // item not within viewable area
530     float rowHeight = itemSize.y + mImpl->mRowSpacing;
531     ItemLayout::Vector3Function firstItemPositionConstraint;
532     Vector3 firstItemPosition = Vector3::ZERO;
533     float offset = 0.0f;
534     if (GetPositionConstraint(0, firstItemPositionConstraint))
535     {
536       firstItemPosition = firstItemPositionConstraint(Vector3::ZERO, 0.0f, 0.0f, layoutSize);
537     }
538     switch( mOrientation )
539     {
540       case ControlOrientation::Up:
541       {
542         if(itemPosition.y > onScreenArea.y)
543         {
544           offset = ((layoutSize.y - rowHeight) * 0.5f) - firstItemPosition.y;
545         }
546         else
547         {
548           offset = ((-layoutSize.y + rowHeight) * 0.5f) - firstItemPosition.y;
549         }
550         break;
551       }
552       case ControlOrientation::Down:
553       {
554         if(itemPosition.y < -onScreenArea.y)
555         {
556           offset = ((layoutSize.y - rowHeight) * 0.5f) - firstItemPosition.y;
557         }
558         else
559         {
560           offset = ((-layoutSize.y + rowHeight) * 0.5f) - firstItemPosition.y;
561         }
562         break;
563       }
564       case ControlOrientation::Left:
565       {
566         if(itemPosition.x > onScreenArea.x)
567         {
568           offset = ((layoutSize.x - rowHeight) * 0.5f) - firstItemPosition.x;
569         }
570         else
571         {
572           offset = ((-layoutSize.x + rowHeight) * 0.5f) - firstItemPosition.x;
573         }
574         break;
575       }
576       case ControlOrientation::Right:
577       {
578         if(itemPosition.x < -onScreenArea.x)
579         {
580           offset = ((layoutSize.x - rowHeight) * 0.5f) - firstItemPosition.x;
581         }
582         else
583         {
584           offset = ((-layoutSize.x + rowHeight) * 0.5f) - firstItemPosition.x;
585         }
586         break;
587       }
588     }
589     // work out number of rows from first item position to an item aligned to bottom of screen
590     float rowDiff = offset / rowHeight;
591     float layoutPositionOffset = rowDiff * mImpl->mNumberOfColumns;
592     float scrollTo = GetItemScrollToPosition(itemID) + layoutPositionOffset;
593     return scrollTo;
594   }
595   return currentLayoutPosition;
596 }
597
598 unsigned int GridLayout::GetReserveItemCount(Vector3 layoutSize) const
599 {
600   float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
601   float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
602
603   Vector3 itemSize = mImpl->mItemSizeFunction( mImpl->mNumberOfColumns, layoutWidth, mImpl->mSideMargin, mImpl->mColumnSpacing);
604   int itemsPerPage = mImpl->mNumberOfColumns * ceil(layoutHeight / (itemSize.y + mImpl->mRowSpacing));
605   return itemsPerPage;
606 }
607
608 bool GridLayout::GetItemSize(unsigned int itemId, Vector3 layoutSize, Vector3& itemSize) const
609 {
610   // Note: itemId is not checked, since every item has the same size
611
612   itemSize = mImpl->mItemSizeFunction( mImpl->mNumberOfColumns, (IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width), mImpl->mSideMargin, mImpl->mColumnSpacing);
613   return true;
614 }
615
616 void GridLayout::GetResizeAnimation(Animation& animation, Actor actor, Vector3 size, float durationSeconds) const
617 {
618   if(animation)
619   {
620     Vector3 currentSize( actor.GetCurrentSize() );
621     Vector3 shrink( currentSize );
622
623     shrink.width = min(size.width, currentSize.width);
624     shrink.height = min(size.height, currentSize.height);
625
626     // Do a nonlinear size animation to shrink the actor first when the actor size changes,
627     // so that we can avoid the actors overlapping during orientation change.
628     animation.Resize( actor, shrink, AlphaFunctions::EaseOut, 0.0f, durationSeconds * 0.5f );
629     animation.Resize( actor, size, AlphaFunctions::EaseIn, 0.0f, durationSeconds );
630   }
631 }
632
633 bool GridLayout::GetPositionConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
634 {
635   unsigned int columnIndex = itemId % mImpl->mNumberOfColumns;
636
637   if (mOrientation == ControlOrientation::Up)
638   {
639     constraint = GridPositionConstraint0(columnIndex, mImpl->mNumberOfColumns, mImpl->mRowSpacing, mImpl->mColumnSpacing, mImpl->mTopMargin, mImpl->mSideMargin, mImpl->mItemSizeFunction, mImpl->mZGap);
640   }
641   else if (mOrientation == ControlOrientation::Left)
642   {
643     constraint = GridPositionConstraint90(columnIndex, mImpl->mNumberOfColumns, mImpl->mRowSpacing, mImpl->mColumnSpacing, mImpl->mTopMargin, mImpl->mSideMargin, mImpl->mItemSizeFunction, mImpl->mZGap);
644   }
645   else if (mOrientation == ControlOrientation::Down)
646   {
647     constraint = GridPositionConstraint180(columnIndex, mImpl->mNumberOfColumns, mImpl->mRowSpacing, mImpl->mColumnSpacing, mImpl->mTopMargin, mImpl->mSideMargin, mImpl->mItemSizeFunction, mImpl->mZGap);
648   }
649   else // mOrientation == ControlOrientation::Right
650   {
651     constraint = GridPositionConstraint270(columnIndex, mImpl->mNumberOfColumns, mImpl->mRowSpacing, mImpl->mColumnSpacing, mImpl->mTopMargin, mImpl->mSideMargin, mImpl->mItemSizeFunction, mImpl->mZGap);
652   }
653
654   return true;
655 }
656
657 bool GridLayout::GetRotationConstraint(unsigned int itemId, ItemLayout::QuaternionFunction& constraint) const
658 {
659   constraint = mImpl->mRotationConstraint[mOrientation];
660   return true;
661 }
662
663 bool GridLayout::GetScaleConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
664 {
665   return false; // No scaling
666 }
667
668 bool GridLayout::GetColorConstraint(unsigned int itemId, ItemLayout::Vector4Function& constraint) const
669 {
670   constraint = mImpl->mColorConstraint;
671   return true;
672 }
673
674 bool GridLayout::GetVisibilityConstraint(unsigned int itemId, ItemLayout::BoolFunction& constraint) const
675 {
676   unsigned int columnIndex = itemId % mImpl->mNumberOfColumns;
677
678   if (IsVertical(mOrientation))
679   {
680     constraint = GridVisibilityConstraintPortrait(columnIndex, mImpl->mNumberOfColumns, mImpl->mRowSpacing, mImpl->mColumnSpacing, mImpl->mSideMargin, mImpl->mItemSizeFunction);
681   }
682   else // horizontal
683   {
684     constraint = GridVisibilityConstraintLandscape(columnIndex, mImpl->mNumberOfColumns, mImpl->mRowSpacing, mImpl->mColumnSpacing, mImpl->mSideMargin, mImpl->mItemSizeFunction);
685   }
686
687   return true;
688 }
689
690 Degree GridLayout::GetScrollDirection() const
691 {
692   Degree scrollDirection(0.0f);
693
694   if (mOrientation == ControlOrientation::Up)
695   {
696     scrollDirection = 0.0f;
697   }
698   else if (mOrientation == ControlOrientation::Left)
699   {
700     scrollDirection = 90.0f;
701   }
702   else if (mOrientation == ControlOrientation::Down)
703   {
704     scrollDirection = 180.0f;
705   }
706   else // mOrientation == ControlOrientation::Right
707   {
708     scrollDirection = 270.0f;
709   }
710
711   return scrollDirection;
712 }
713
714 int GridLayout::GetNextFocusItemID(int itemID, int maxItems, Dali::Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
715 {
716   switch( direction )
717   {
718     case Control::Left:
719     {
720       itemID--;
721       if( itemID < 0 )
722       {
723         itemID = loopEnabled ? maxItems - 1 : 0;
724       }
725       break;
726     }
727     case Control::Up:
728     {
729       itemID -= mImpl->mNumberOfColumns;
730       if( itemID < 0 )
731       {
732         itemID = loopEnabled ? itemID + maxItems : itemID + mImpl->mNumberOfColumns;
733       }
734       break;
735     }
736     case Control::Right:
737     {
738       itemID++;
739       if( itemID >= maxItems )
740       {
741         itemID = loopEnabled ? 0 : maxItems - 1;
742       }
743       break;
744     }
745     case Control::Down:
746     {
747       itemID += mImpl->mNumberOfColumns;
748       if( itemID >= maxItems )
749       {
750         itemID = loopEnabled ? 0 : itemID - mImpl->mNumberOfColumns;
751       }
752       break;
753     }
754   }
755   return itemID;
756 }
757
758 GridLayout::GridLayout()
759 : mImpl(NULL)
760 {
761   mImpl = new Impl();
762 }
763
764 } // namespace Toolkit
765
766 } // namespace Dali