f49228033a8d256aadfbd6c6a9dc77faef0677ef
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / public-api / controls / scrollable / item-view / navigation-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/navigation-layout.h>
21 using namespace Dali;
22 using namespace Dali::Toolkit;
23 using namespace std;
24
25 namespace // unnamed namespace
26 {
27 const unsigned int DEFAULT_NUMBER_OF_COLUMNS = 3;
28 const float DEFAULT_TOP_MARGIN     =  0.3f;
29 const float DEFAULT_BOTTOM_MARGIN  =  0.3f;
30 const float DEFAULT_SIDE_MARGIN    =  0.2f;
31 const float DEFAULT_COLUMN_SPACING =  20.0f;
32 const float DEFAULT_ROW_SPACING    =  20.0f;
33 const float DEFAULT_SCROLL_SPEED_FACTOR = 0.01f;
34 const float DEFAULT_MAXIMUM_SWIPE_SPEED = 3.0f;
35 const float DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.05f;
36 const float DEFAULT_SIZE_EXTEND = 1.4f;
37 const float DEFAULT_HEIGHT_FACTOR = 0.6f;
38
39 // 4 orientations are supported
40 struct NavigationPositionConstraintUp
41 {
42   NavigationPositionConstraintUp(const unsigned int columnIndex,
43                                          const unsigned int numberOfColumns,
44                                          const float columnSpacing,
45                                          const float sizeExtend,
46                                          const float bottomMargin,
47                                          const float topMargin)
48   : mColumnIndex(columnIndex),
49     mNumberOfColumns(numberOfColumns),
50     mColumnSpacing(columnSpacing),
51     mSizeExtend(sizeExtend),
52     mBottomMargin(bottomMargin),
53     mTopMargin(topMargin)
54   {
55   }
56
57   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
58   {
59     float itemWidth = (layoutSize.width * mSizeExtend- mColumnSpacing * (mNumberOfColumns - 1))/( mNumberOfColumns );
60
61     Vector3 itemPosition;
62
63     float z = (sinf((layoutPosition + 1.0f) * Math::PI *0.5f) - 1.0f) * itemWidth * 2.0f;
64
65     itemPosition = Vector3( (layoutPosition + 1.0f) * (itemWidth + mColumnSpacing) + itemWidth * 0.5f - layoutSize.width * mSizeExtend * 0.5f,
66                              (- mBottomMargin + mTopMargin) * layoutSize.width * 0.5f ,
67                              z);
68     return itemPosition;
69   }
70
71 public:
72   unsigned int mColumnIndex;
73   unsigned int mNumberOfColumns;
74   float mColumnSpacing;
75   float mSizeExtend;
76   float mBottomMargin;
77   float mTopMargin;
78 };
79
80 struct NavigationPositionConstraintLeft
81 {
82   NavigationPositionConstraintLeft(const unsigned int columnIndex,
83                                           const unsigned int numberOfColumns,
84                                           const float columnSpacing,
85                                           const float sizeExtend,
86                                           const float bottomMargin,
87                                           const float topMargin)
88   : mColumnIndex(columnIndex),
89     mNumberOfColumns(numberOfColumns),
90     mColumnSpacing(columnSpacing),
91     mSizeExtend(sizeExtend),
92     mBottomMargin(bottomMargin),
93     mTopMargin(topMargin)
94   {
95   }
96
97   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
98   {
99     float itemWidth = (DEFAULT_HEIGHT_FACTOR * layoutSize.height * mSizeExtend- mColumnSpacing * (mNumberOfColumns - 1))/( mNumberOfColumns );
100     Vector3 itemPosition;
101     float z = (sinf((layoutPosition + 1.0f) * Math::PI *0.5f) - 1.0f) * itemWidth * 1.5f;
102     itemPosition = Vector3( (- mBottomMargin + mTopMargin) * 0.5f * layoutSize.width ,
103                             -((layoutPosition+ 1.0) * (itemWidth + mColumnSpacing) + itemWidth * 0.5f - DEFAULT_HEIGHT_FACTOR * layoutSize.height * mSizeExtend * 0.5f ),
104                             z);
105     return itemPosition;
106   }
107
108 public:
109   unsigned int mColumnIndex;
110   unsigned int mNumberOfColumns;
111   float mColumnSpacing;
112   float mSizeExtend;
113   float mBottomMargin;
114   float mTopMargin;
115 };
116
117 struct NavigationPositionConstraintDown
118 {
119   NavigationPositionConstraintDown(const unsigned int columnIndex,
120                                             const unsigned int numberOfColumns,
121                                             const float columnSpacing,
122                                             const float sizeExtend,
123                                             const float bottomMargin,
124                                             const float topMargin)
125   : mColumnIndex(columnIndex),
126     mNumberOfColumns(numberOfColumns),
127     mColumnSpacing(columnSpacing),
128     mSizeExtend(sizeExtend),
129     mBottomMargin(bottomMargin),
130     mTopMargin(topMargin)
131   {
132   }
133
134   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
135   {
136     float itemWidth = (layoutSize.width * mSizeExtend- mColumnSpacing * (mNumberOfColumns - 1))/( mNumberOfColumns );
137     Vector3 itemPosition;
138
139     float z = (sinf((layoutPosition + 1.0f ) * Math::PI *0.5f) - 1.0f) * itemWidth * 2.0f;
140     itemPosition = Vector3(  -((layoutPosition + 1.0f)  * (itemWidth + mColumnSpacing) + itemWidth * 0.5f - layoutSize.width * mSizeExtend * 0.5f),
141                              (- mBottomMargin + mTopMargin)* layoutSize.width * 0.5f,
142                              z);
143     return itemPosition;
144   }
145
146   public:
147     unsigned int mColumnIndex;
148     unsigned int mNumberOfColumns;
149     float mColumnSpacing;
150     float mSizeExtend;
151     float mBottomMargin;
152     float mTopMargin;
153 };
154
155 struct NavigationPositionConstraintRight
156 {
157   NavigationPositionConstraintRight(const unsigned int columnIndex,
158                                             const unsigned int numberOfColumns,
159                                             const float columnSpacing,
160                                             const float sizeExtend,
161                                             const float bottomMargin,
162                                             const float topMargin)
163   : mColumnIndex(columnIndex),
164     mNumberOfColumns(numberOfColumns),
165     mColumnSpacing(columnSpacing),
166     mSizeExtend(sizeExtend),
167     mBottomMargin(bottomMargin),
168     mTopMargin(topMargin)
169   {
170   }
171
172   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
173   {
174     float itemWidth = (DEFAULT_HEIGHT_FACTOR * layoutSize.height * mSizeExtend- mColumnSpacing * (mNumberOfColumns - 1))/( mNumberOfColumns );
175     Vector3 itemPosition;
176     float z = (sinf((layoutPosition + 1.0f) * Math::PI *0.5f) - 1.0f) * itemWidth * 1.5f;
177     itemPosition = Vector3(  (- mBottomMargin + mTopMargin) * layoutSize.width * 0.5f,
178                              ((layoutPosition + 1.0f) * (itemWidth + mColumnSpacing) + itemWidth * 0.5f - DEFAULT_HEIGHT_FACTOR * layoutSize.height * mSizeExtend *0.5f ),
179                              z);
180   return itemPosition;
181   }
182
183 public:
184   unsigned int mColumnIndex;
185   unsigned int mNumberOfColumns;
186   float mColumnSpacing;
187   float mSizeExtend;
188   float mBottomMargin;
189   float mTopMargin;
190 };
191
192 struct NavigationRotationConstraintUp
193 {
194   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
195   {
196     float angle = 0.0f;
197     float _layoutPosition = layoutPosition + 1.0f;
198     if(_layoutPosition >= 1.0f)
199     {
200       angle = - sinf(Math::PI * _layoutPosition) * Math::PI * 0.2f;
201     }
202     else
203     {
204       angle =  sinf(Math::PI * _layoutPosition) * Math::PI * 0.2f;
205     }
206     return Quaternion(angle, Vector3::YAXIS);
207   }
208
209 };
210
211 struct NavigationRotationConstraintLeft
212 {
213   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
214   {
215     float angle = 0.0f;
216     float _layoutPosition = layoutPosition + 1.0f;
217     if(_layoutPosition >= 1.0f)
218     {
219       angle = - sinf(Math::PI * _layoutPosition) * Math::PI * 0.2f;
220     }
221     else
222     {
223       angle =  sinf(Math::PI * _layoutPosition) * Math::PI * 0.2f;
224     }
225     return Quaternion(Math::PI * 0.5f, Vector3::ZAXIS) * Quaternion(angle, Vector3::YAXIS);
226   }
227 };
228
229 struct NavigationRotationConstraintDown
230 {
231   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
232   {
233     float angle = 0.0f;
234     float _layoutPosition = layoutPosition + 1.0f;
235     if(_layoutPosition >= 1.0f)//right side
236     {
237       //rotation angle by z axis
238       angle = - sinf(Math::PI * _layoutPosition) * Math::PI * 0.2f;
239     }
240     else // left side
241     {
242       angle =  sinf(Math::PI * _layoutPosition) * Math::PI * 0.2f;
243     }
244     return Quaternion(Math::PI, Vector3::ZAXIS) * Quaternion(angle, Vector3::YAXIS);
245   }
246 };
247
248 struct NavigationRotationConstraintRight
249 {
250   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
251   {
252     float angle = 0.0f;
253     float _layoutPosition = layoutPosition + 1.0f;
254     if(_layoutPosition >= 1.0f)
255     {
256       angle = - sinf(Math::PI * _layoutPosition) * Math::PI * 0.2f;
257     }
258     else
259     {
260       angle =  sinf(Math::PI * _layoutPosition) * Math::PI * 0.2f;
261     }
262     return Quaternion(Math::PI * 1.5f, Vector3::ZAXIS) * Quaternion(angle, Vector3::YAXIS);
263   }
264 };
265
266 struct NavigationColorConstraint
267 {
268   NavigationColorConstraint(unsigned int numberOfColumns)
269   : mNumberOfColumns(numberOfColumns)
270   {
271
272   }
273   Vector4 operator()(const Vector4& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
274   {
275     float darkness = 1.0f;
276     float alpha = 1.0f;
277
278     float pos = ( layoutPosition + 1.0f);
279     darkness = (-0.25f) * (pos + 1.0f) * (pos + 1.0f) + 1.0f * (pos + 1.0f) + 0.2f;
280
281     darkness = fabs(darkness);
282     darkness /= 1.2f;
283
284     return Vector4(darkness, darkness, darkness, current.a * alpha);
285   }
286   unsigned int mNumberOfColumns;
287
288 };
289
290 struct NavigationVisibilityConstraint
291 {
292   NavigationVisibilityConstraint(const unsigned int columnIndex,
293                                       const unsigned int numberOfColumns,
294                                       const float columnSpacing )
295   : mColumnIndex(columnIndex),
296     mNumberOfColumns(numberOfColumns),
297     mColumnSpacing(columnSpacing)
298   {
299   }
300
301   bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
302   {
303     float index = layoutPosition + 1.0f;
304     return (index >= -1.0f) && (index <= mNumberOfColumns );
305   }
306
307 public:
308   unsigned int mColumnIndex;
309   unsigned int mNumberOfColumns;
310   float mColumnSpacing;
311 };
312 }//end namespace
313
314 namespace Dali
315 {
316 namespace Toolkit
317 {
318 struct NavigationLayout::Impl
319 {
320   Impl()
321   : mNumberOfColumns(DEFAULT_NUMBER_OF_COLUMNS),
322     mColumnSpacing(DEFAULT_COLUMN_SPACING),
323     mTopMargin(DEFAULT_TOP_MARGIN),
324     mBottomMargin(DEFAULT_BOTTOM_MARGIN),
325     mSideMargin(DEFAULT_SIDE_MARGIN),
326     mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
327     mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
328     mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION),
329     mSizeExtend(DEFAULT_SIZE_EXTEND)
330     {
331       mColorConstraint = NavigationColorConstraint(mNumberOfColumns);
332       mRotationConstraint[0] = NavigationRotationConstraintUp();
333       mRotationConstraint[1] = NavigationRotationConstraintLeft();
334       mRotationConstraint[2] = NavigationRotationConstraintDown();
335       mRotationConstraint[3] = NavigationRotationConstraintRight();
336     }
337
338   unsigned int mNumberOfColumns;
339   float mColumnSpacing;
340   float mTopMargin;
341   float mBottomMargin;
342   float mSideMargin;
343   float mScrollSpeedFactor;
344   float mMaximumSwipeSpeed;
345   float mItemFlickAnimationDuration;
346   float mSizeExtend;
347
348   ItemLayout::QuaternionFunction mRotationConstraint[4];
349
350   ItemLayout::Vector4Function mColorConstraint;
351 };
352
353 NavigationLayoutPtr NavigationLayout::New()
354 {
355   return NavigationLayoutPtr(new NavigationLayout());
356 }
357
358 NavigationLayout::~NavigationLayout()
359 {
360   delete mImpl;
361 }
362
363 void NavigationLayout::SetNumberOfColumns(unsigned int columns)
364 {
365   mImpl->mNumberOfColumns = columns;
366 }
367
368 unsigned int NavigationLayout::GetNumberOfColumns() const
369 {
370   return mImpl->mNumberOfColumns;
371 }
372
373 void NavigationLayout::SetColumnSpacing(float spacing)
374 {
375   mImpl->mColumnSpacing = spacing;
376 }
377
378 float NavigationLayout::GetColumnSpacing() const
379 {
380   return mImpl->mColumnSpacing;
381 }
382
383 void NavigationLayout::SetTopMargin(float margin)
384 {
385   mImpl->mTopMargin = margin;
386 }
387
388 float NavigationLayout::GetTopMargin() const
389 {
390   return mImpl->mTopMargin;
391 }
392
393 void NavigationLayout::SetBottomMargin(float margin)
394 {
395   mImpl->mBottomMargin = margin;
396 }
397
398 float NavigationLayout::GetBottomMargin() const
399 {
400   return mImpl->mBottomMargin;
401 }
402
403 void NavigationLayout::SetSideMargin(float margin)
404 {
405   mImpl->mSideMargin = margin;
406   mImpl->mSizeExtend = (1.0f - margin) * 3.0f;
407 }
408
409 void NavigationLayout::SetScrollSpeedFactor(float scrollSpeed)
410 {
411   mImpl->mScrollSpeedFactor = scrollSpeed;
412 }
413
414 void NavigationLayout::SetMaximumSwipeSpeed(float speed)
415 {
416   mImpl->mMaximumSwipeSpeed = speed;
417 }
418
419 void NavigationLayout::SetItemFlickAnimationDuration(float durationSeconds)
420 {
421   mImpl->mItemFlickAnimationDuration = durationSeconds;
422 }
423
424 float NavigationLayout::GetScrollSpeedFactor() const
425 {
426   return mImpl->mScrollSpeedFactor;
427 }
428
429 float NavigationLayout::GetMaximumSwipeSpeed() const
430 {
431   return mImpl->mMaximumSwipeSpeed;
432 }
433
434 float NavigationLayout::GetItemFlickAnimationDuration() const
435 {
436   return mImpl->mItemFlickAnimationDuration;
437 }
438
439 float NavigationLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
440 {
441   unsigned int itemsLastRow = numberOfItems % mImpl->mNumberOfColumns;
442   if (itemsLastRow == 0)
443   {
444     itemsLastRow = mImpl->mNumberOfColumns;
445   }
446
447   float itemsLastPage =  static_cast<float>(itemsLastRow);
448   return itemsLastPage - static_cast<float>(numberOfItems) - 2.0f;
449
450 }
451
452 float NavigationLayout::GetClosestAnchorPosition(float layoutPosition) const
453 {
454   return round(layoutPosition);
455 }
456
457 float NavigationLayout::GetItemScrollToPosition(unsigned int itemId) const
458 {
459   return - static_cast<float>(itemId);
460 }
461
462 ItemRange NavigationLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
463 {
464   int itemsPerPage = mImpl->mNumberOfColumns;
465
466   int firstItemIndex = std::max(0.0f, -firstItemPosition -1.0f  );
467   int lastItemIndex = std::max(0.0f, -(firstItemPosition) + itemsPerPage );
468
469   return ItemRange(firstItemIndex , lastItemIndex );
470 }
471
472 unsigned int NavigationLayout::GetReserveItemCount(Vector3 layoutSize) const
473 {
474   float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
475   float itemWidth = (layoutWidth * mImpl->mSizeExtend - mImpl->mColumnSpacing * (mImpl->mNumberOfColumns - 1))/( mImpl->mNumberOfColumns );
476   return static_cast<unsigned int>(layoutWidth / itemWidth);
477 }
478
479 bool NavigationLayout::GetItemSize(unsigned int itemId, Vector3 layoutSize, Vector3& itemSize) const
480 {
481   float layoutWidth = IsHorizontal(mOrientation) ? (DEFAULT_HEIGHT_FACTOR * layoutSize.height) : layoutSize.width;
482   layoutWidth = layoutWidth * mImpl->mSizeExtend;
483
484   float itemWidth = (layoutWidth -  mImpl->mColumnSpacing*(mImpl->mNumberOfColumns-1)) / mImpl->mNumberOfColumns;
485   float itemHeight = layoutWidth * (1.0f - mImpl->mBottomMargin - mImpl->mTopMargin);
486   itemSize = Vector3(itemWidth, itemHeight, (itemWidth/4)*3);
487
488   return true;
489 }
490
491 void NavigationLayout::GetResizeAnimation(Animation& animation, Actor actor, Vector3 size, float durationSeconds) const
492 {
493 }
494
495 bool NavigationLayout::GetPositionConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
496 {
497   unsigned int columnIndex = itemId % mImpl->mNumberOfColumns;
498   if (mOrientation == ControlOrientation::Left)
499   {
500     constraint = NavigationPositionConstraintLeft(columnIndex, mImpl->mNumberOfColumns, mImpl->mColumnSpacing, mImpl->mSizeExtend, mImpl->mBottomMargin, mImpl->mTopMargin);
501   }
502   else if (mOrientation == ControlOrientation::Up)
503   {
504     constraint = NavigationPositionConstraintUp(columnIndex, mImpl->mNumberOfColumns, mImpl->mColumnSpacing, mImpl->mSizeExtend, mImpl->mBottomMargin, mImpl->mTopMargin);
505   }
506   else if (mOrientation == ControlOrientation::Down)
507   {
508     constraint = NavigationPositionConstraintDown(columnIndex, mImpl->mNumberOfColumns, mImpl->mColumnSpacing, mImpl->mSizeExtend, mImpl->mBottomMargin, mImpl->mTopMargin);
509   }
510   else if (mOrientation == ControlOrientation::Right)
511   {
512     constraint = NavigationPositionConstraintRight(columnIndex, mImpl->mNumberOfColumns, mImpl->mColumnSpacing, mImpl->mSizeExtend, mImpl->mBottomMargin, mImpl->mTopMargin);
513   }
514
515   return true;
516 }
517
518 bool NavigationLayout::GetScaleConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
519 {
520   return false; // No scaling
521 }
522
523 bool NavigationLayout::GetRotationConstraint(unsigned int itemId, ItemLayout::QuaternionFunction& constraint) const
524 {
525   constraint = mImpl->mRotationConstraint[mOrientation];
526   return true;
527 }
528
529 bool NavigationLayout::GetColorConstraint(unsigned int itemId, ItemLayout::Vector4Function& constraint) const
530 {
531   constraint = mImpl->mColorConstraint;
532   return true;
533 }
534
535 bool NavigationLayout::GetVisibilityConstraint(unsigned int itemId, ItemLayout::BoolFunction& constraint) const
536 {
537   unsigned int columnIndex = itemId % mImpl->mNumberOfColumns;
538   constraint = NavigationVisibilityConstraint(columnIndex, mImpl->mNumberOfColumns, mImpl->mColumnSpacing);
539   return true;
540 }
541
542 Degree NavigationLayout::GetScrollDirection() const
543 {
544   Degree scrollDirection(0);
545   if (mOrientation == ControlOrientation::Down)
546   {
547     scrollDirection = 0.0f - 45.0f;
548   }
549   else if (mOrientation == ControlOrientation::Right)
550   {
551     scrollDirection = 90.0f - 45.0f;
552   }
553   else if (mOrientation == ControlOrientation::Up)
554   {
555     scrollDirection = 180.0f - 45.0f;
556   }
557   else // mOrientation == ControlOrientation::Left
558   {
559     scrollDirection = 270.0f - 45.0f;
560   }
561
562   return scrollDirection;
563 }
564
565 NavigationLayout::NavigationLayout()
566   :mImpl(NULL)
567 {
568   mImpl = new Impl();
569 }
570
571 }
572 }