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