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