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