e6cdf3f1f77af33e4c5c2c1027122a6509f2ec9b
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scrollable / item-view / grid-layout.cpp
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/scrollable/item-view/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 Degree GridLayout::GetScrollDirection() const
510 {
511   Degree scrollDirection(0.0f);
512   ControlOrientation::Type orientation = GetOrientation();
513
514   if ( orientation == ControlOrientation::Up )
515   {
516     scrollDirection = Degree( 0.0f );
517   }
518   else if ( orientation == ControlOrientation::Left )
519   {
520     scrollDirection = Degree( 90.0f );
521   }
522   else if ( orientation == ControlOrientation::Down )
523   {
524     scrollDirection = Degree( 180.0f );
525   }
526   else // orientation == ControlOrientation::Right
527   {
528     scrollDirection = Degree( 270.0f );
529   }
530
531   return scrollDirection;
532 }
533
534 void GridLayout::ApplyConstraints( Actor& actor, const int itemId, const Vector3& layoutSize, const Actor& itemViewActor )
535 {
536   // This just implements the default behaviour of constraint application.
537   // Custom layouts can override this function to apply their custom constraints.
538   Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast( itemViewActor );
539   if( itemView )
540   {
541     Vector3 itemSize;
542     GetItemSize( itemId, layoutSize, itemSize );
543     const unsigned int columnIndex = itemId % mImpl->mNumberOfColumns;
544     const ControlOrientation::Type orientation = GetOrientation();
545
546     // Position constraint
547     GridPositionConstraint positionConstraint( itemId,
548                                                columnIndex,
549                                                mImpl->mNumberOfColumns,
550                                                mImpl->mRowSpacing,
551                                                mImpl->mColumnSpacing,
552                                                mImpl->mTopMargin,
553                                                mImpl->mSideMargin,
554                                                itemSize,
555                                                mImpl->mZGap );
556     Constraint constraint;
557     if ( orientation == ControlOrientation::Up )
558     {
559       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &GridPositionConstraint::Orientation0 );
560     }
561     else if ( orientation == ControlOrientation::Left )
562     {
563       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &GridPositionConstraint::Orientation90 );
564     }
565     else if ( orientation == ControlOrientation::Down )
566     {
567       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &GridPositionConstraint::Orientation180 );
568     }
569     else // orientation == ControlOrientation::Right
570     {
571       constraint = Constraint::New< Vector3 >( actor, Actor::Property::POSITION, positionConstraint, &GridPositionConstraint::Orientation270 );
572     }
573     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
574     constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
575     constraint.Apply();
576
577     // Rotation constraint
578     if ( orientation == ControlOrientation::Up )
579     {
580       constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, &GridRotationConstraint0 );
581     }
582     else if ( orientation == ControlOrientation::Left )
583     {
584       constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, &GridRotationConstraint90 );
585     }
586     else if ( orientation == ControlOrientation::Down )
587     {
588       constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, &GridRotationConstraint180 );
589     }
590     else // orientation == ControlOrientation::Right
591     {
592       constraint = Constraint::New< Quaternion >( actor, Actor::Property::ORIENTATION, &GridRotationConstraint270 );
593     }
594     constraint.Apply();
595
596     // Color constraint
597     constraint = Constraint::New< Vector4 >( actor, Actor::Property::COLOR, &GridColorConstraint );
598     constraint.SetRemoveAction( Dali::Constraint::Discard );
599     constraint.Apply();
600
601     // Visibility constraint
602     GridVisibilityConstraint visibilityConstraint( itemId,
603                                                    columnIndex,
604                                                    mImpl->mNumberOfColumns,
605                                                    mImpl->mRowSpacing,
606                                                    mImpl->mColumnSpacing,
607                                                    mImpl->mSideMargin,
608                                                    itemSize );
609     if ( IsVertical( orientation ) )
610     {
611       constraint = Constraint::New<bool>( actor, Actor::Property::VISIBLE, visibilityConstraint, &GridVisibilityConstraint::Portrait );
612     }
613     else // horizontal
614     {
615       constraint = Constraint::New<bool>( actor, Actor::Property::VISIBLE, visibilityConstraint, &GridVisibilityConstraint::Landscape );
616     }
617     constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_POSITION ) );
618     constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
619     constraint.SetRemoveAction( Dali::Constraint::Discard );
620     constraint.Apply();
621   }
622 }
623
624 Vector3 GridLayout::GetItemPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize) const
625 {
626   Vector3 itemPosition = Vector3::ZERO;
627   const unsigned int columnIndex = itemID % mImpl->mNumberOfColumns;
628   const ControlOrientation::Type orientation = GetOrientation();
629   Vector3 itemSize;
630   GetItemSize( itemID, layoutSize, itemSize );
631
632   GridPositionConstraint positionConstraintStruct( itemID,
633                                                    columnIndex,
634                                                    mImpl->mNumberOfColumns,
635                                                    mImpl->mRowSpacing,
636                                                    mImpl->mColumnSpacing,
637                                                    mImpl->mTopMargin,
638                                                    mImpl->mSideMargin,
639                                                    itemSize,
640                                                    mImpl->mZGap );
641
642   if ( orientation == ControlOrientation::Up )
643   {
644     positionConstraintStruct.Orientation0( itemPosition, currentLayoutPosition + itemID, layoutSize );
645   }
646   else if ( orientation == ControlOrientation::Left )
647   {
648     positionConstraintStruct.Orientation90( itemPosition, currentLayoutPosition + itemID, layoutSize );
649   }
650   else if ( orientation == ControlOrientation::Down )
651   {
652     positionConstraintStruct.Orientation180( itemPosition, currentLayoutPosition + itemID, layoutSize );
653   }
654   else // orientation == ControlOrientation::Right
655   {
656     positionConstraintStruct.Orientation270( itemPosition, currentLayoutPosition + itemID, layoutSize );
657   }
658
659   return itemPosition;
660 }
661
662 int GridLayout::GetNextFocusItemID(int itemID, int maxItems, Dali::Toolkit::Control::KeyboardFocus::Direction direction, bool loopEnabled)
663 {
664   switch( direction )
665   {
666     case Toolkit::Control::KeyboardFocus::LEFT:
667     {
668       itemID--;
669       if( itemID < 0 )
670       {
671         itemID = loopEnabled ? maxItems - 1 : 0;
672       }
673       break;
674     }
675     case Toolkit::Control::KeyboardFocus::UP:
676     {
677       itemID -= mImpl->mNumberOfColumns;
678       if( itemID < 0 )
679       {
680         itemID = loopEnabled ? itemID + maxItems : itemID + mImpl->mNumberOfColumns;
681       }
682       break;
683     }
684     case Toolkit::Control::KeyboardFocus::RIGHT:
685     {
686       itemID++;
687       if( itemID >= maxItems )
688       {
689         itemID = loopEnabled ? 0 : maxItems - 1;
690       }
691       break;
692     }
693     case Toolkit::Control::KeyboardFocus::DOWN:
694     {
695       itemID += mImpl->mNumberOfColumns;
696       if( itemID >= maxItems )
697       {
698         itemID = loopEnabled ? 0 : itemID - mImpl->mNumberOfColumns;
699       }
700       break;
701     }
702     default:
703     {
704       break;
705     }
706   }
707   return itemID;
708 }
709
710 GridLayout::GridLayout()
711 : mImpl(NULL)
712 {
713   mImpl = new Impl();
714 }
715
716 } // namespace Internal
717
718 } // namespace Toolkit
719
720 } // namespace Dali