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