Revert "License conversion from Flora to Apache 2.0"
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / public-api / controls / scrollable / item-view / roll-layout.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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 #include <algorithm>
18
19 #include <dali-toolkit/public-api/controls/scrollable/item-view/roll-layout.h>
20
21 using namespace Dali;
22 using namespace Dali::Toolkit;
23 using namespace std;
24
25 namespace // unnamed namespace
26 {
27
28 const float DEFAULT_ROW_SPACING = 20.0f;
29 const float DEFAULT_SCROLL_SPEED_FACTOR = 0.0015f;
30 const float DEFAULT_MAXIMUM_SWIPE_SPEED = 8.0f;
31 const float DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.4f;
32
33 // 4 orientations are supported
34 static const unsigned int ORIENTATION_COUNT = 4;
35
36 static Vector3 GetItemSizeDefaultFunction(float layoutWidth, float layoutHeight, float rowSpacing)
37 {
38   float height = (layoutHeight - rowSpacing) * 0.5f;
39   return Vector3(layoutWidth, height, height);
40 }
41
42 struct RollPositionConstraint0
43 {
44   RollPositionConstraint0(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
45   : mRowSpacing(rowSpacing),
46     mItemSizeFunction(itemSizeFunction)
47   {
48   }
49
50   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
51   {
52     Vector3 itemSize = mItemSizeFunction(layoutSize.width, layoutSize.height, mRowSpacing);
53
54     float adjustedLayoutPosition = layoutPosition;
55     float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed * scrollSpeed;
56     float y = 0.0f;
57
58     float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
59
60     if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
61     {
62       float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
63       adjustedLayoutPosition = adjustment * 2.0f;
64       y = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.height * 0.5f + itemSize.y * 0.5f;
65     }
66     else
67     {
68       float yStep = max(50.0f, min(itemSize.y, scrollSpeedFactor));
69       y = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * yStep : (layoutSize.height * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * yStep;
70       y += itemSize.y * 0.5f - layoutSize.height * 0.5f;
71     }
72
73     float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
74     z -= min(3000.0f, scrollSpeedFactor * 2.0f);
75
76     return Vector3(itemSize.x * 0.5f - layoutSize.x * 0.5f, y, z);
77   }
78
79 public:
80
81   float mRowSpacing;
82   RollLayout::ItemSizeFunction mItemSizeFunction;
83 };
84
85 struct RollPositionConstraint90
86 {
87   RollPositionConstraint90(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
88   : mRowSpacing(rowSpacing),
89     mItemSizeFunction(itemSizeFunction)
90   {
91   }
92
93   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
94   {
95     Vector3 itemSize = mItemSizeFunction(layoutSize.height, layoutSize.width, mRowSpacing);
96
97     float adjustedLayoutPosition = layoutPosition;
98     float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed;
99     float x = 0.0f;
100
101     float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
102
103     if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
104     {
105       float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
106       adjustedLayoutPosition = adjustment * 2.0f;
107       x = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.width * 0.5f + itemSize.y * 0.5f;
108     }
109     else
110     {
111       float xStep = max(50.0f, min(itemSize.y, scrollSpeedFactor));
112       x = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * xStep : (layoutSize.width * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * xStep;
113       x += itemSize.y * 0.5f - layoutSize.width * 0.5f;
114     }
115
116     float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
117     z -= min(3000.0f, scrollSpeedFactor * 2.0f);
118
119     return Vector3(x, itemSize.x * 0.5f - layoutSize.y * 0.5f, z);
120   }
121
122 public:
123
124   float mRowSpacing;
125   RollLayout::ItemSizeFunction mItemSizeFunction;
126 };
127
128 struct RollPositionConstraint180
129 {
130   RollPositionConstraint180(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
131   : mRowSpacing(rowSpacing),
132     mItemSizeFunction(itemSizeFunction)
133   {
134   }
135
136   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
137   {
138     Vector3 itemSize = mItemSizeFunction(layoutSize.width, layoutSize.height, mRowSpacing);
139
140     float adjustedLayoutPosition = layoutPosition;
141     float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed;
142     float y = 0.0f;
143
144     float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
145
146     if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
147     {
148       float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
149       adjustedLayoutPosition = adjustment * 2.0f;
150       y = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.height * 0.5f + itemSize.y * 0.5f;
151     }
152     else
153     {
154       float yStep = max(50.0f, min(itemSize.y, scrollSpeedFactor));
155       y = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * yStep : (layoutSize.height * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * yStep;
156       y += itemSize.y * 0.5f - layoutSize.height * 0.5f;
157     }
158
159     float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
160     z -= min(3000.0f, scrollSpeedFactor * 2.0f);
161
162
163     return Vector3(-(itemSize.x * 0.5f - layoutSize.x * 0.5f),
164                    -y,
165                    z);
166   }
167
168 public:
169
170   float mRowSpacing;
171   RollLayout::ItemSizeFunction mItemSizeFunction;
172 };
173
174 struct RollPositionConstraint270
175 {
176   RollPositionConstraint270(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
177   : mRowSpacing(rowSpacing),
178     mItemSizeFunction(itemSizeFunction)
179   {
180   }
181
182   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
183   {
184     Vector3 itemSize = mItemSizeFunction(layoutSize.height, layoutSize.width, mRowSpacing);
185
186     float adjustedLayoutPosition = layoutPosition;
187     float scrollSpeedFactor = scrollSpeed * scrollSpeed * scrollSpeed;
188     float x = 0.0f;
189
190     float adjustedRowSpacing = mRowSpacing + scrollSpeedFactor;
191
192     if(adjustedLayoutPosition > Math::MACHINE_EPSILON_0 && adjustedLayoutPosition -2.0f < Math::MACHINE_EPSILON_0)
193     {
194       float adjustment = 1.0f - Dali::AlphaFunctions::EaseInOutSine60((2.0f - adjustedLayoutPosition) * 0.5f);
195       adjustedLayoutPosition = adjustment * 2.0f;
196       x = ((itemSize.y + adjustedRowSpacing ) * adjustedLayoutPosition) - layoutSize.width * 0.5f + itemSize.y * 0.5f;
197     }
198     else
199     {
200       float xStep = max(50.0f, min(itemSize.y, scrollSpeedFactor));
201       x = adjustedLayoutPosition < Math::MACHINE_EPSILON_0 ? adjustedLayoutPosition * xStep : (layoutSize.width * 0.5f + adjustedRowSpacing) + (adjustedLayoutPosition - 1.0f) * xStep;
202       x += itemSize.y * 0.5f - layoutSize.width * 0.5f;
203     }
204
205     float z = adjustedLayoutPosition * (10.0f + scrollSpeedFactor);
206     z -= min(3000.0f, scrollSpeedFactor * 2.0f);
207
208     return Vector3(-x,
209                    itemSize.x * 0.5f - layoutSize.y * 0.5f,
210                    z);
211   }
212
213 public:
214
215   float mRowSpacing;
216   RollLayout::ItemSizeFunction mItemSizeFunction;
217 };
218
219 struct RollRotationConstraint0
220 {
221   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
222   {
223     return Quaternion(0.0f, Vector3::ZAXIS);
224   }
225 };
226
227 struct RollRotationConstraint90
228 {
229   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
230   {
231     return Quaternion(1.5f * Math::PI, Vector3::ZAXIS);
232   }
233 };
234
235 struct RollRotationConstraint180
236 {
237   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
238   {
239     return Quaternion(Math::PI, Vector3::ZAXIS);
240   }
241 };
242
243 struct RollRotationConstraint270
244 {
245   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
246   {
247     return Quaternion(0.5f * Math::PI, Vector3::ZAXIS);
248   }
249 };
250
251 struct RollScaleConstraint
252 {
253   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
254   {
255     float adjustedLayoutPosition = layoutPosition;
256     float factor = 0.0f;
257     if(adjustedLayoutPosition < Math::MACHINE_EPSILON_0)
258     {
259       factor = fabsf(adjustedLayoutPosition);
260     }
261     if(adjustedLayoutPosition - 1.0f > Math::MACHINE_EPSILON_0)
262     {
263       factor = adjustedLayoutPosition - 1.0f;
264     }
265
266     float scale = min(1.0f, max(0.1f, 1.0f - 0.1f * factor));
267     if(scrollSpeed > 0.0f)
268     {
269       scale *= min(1.0f, max(0.1f, 1.0f / (scrollSpeed * 0.05f)));
270     }
271
272     return Vector3(scale, scale, scale);
273   }
274 };
275
276 struct RollColorConstraint
277 {
278   Vector4 operator()(const Vector4& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
279   {
280     float adjustedLayoutPosition = layoutPosition;
281
282     float factor = 0.0f;
283     if(adjustedLayoutPosition < Math::MACHINE_EPSILON_0)
284     {
285       factor = fabsf(adjustedLayoutPosition);
286     }
287     if(adjustedLayoutPosition - 1.0f > Math::MACHINE_EPSILON_0)
288     {
289       factor = adjustedLayoutPosition - 1.0f;
290     }
291
292     float darkness = min(1.0f, max(0.5f, 1.0f - 0.5f * factor));
293     float alpha = min(1.0f, max(0.0f, 1.0f - 0.9f * factor));
294     return Vector4(darkness, darkness, darkness, alpha);
295   }
296 };
297
298 struct RollVisibilityConstraintPortrait
299 {
300   RollVisibilityConstraintPortrait(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
301   : mRowSpacing(rowSpacing),
302     mItemSizeFunction(itemSizeFunction)
303   {
304   }
305
306   bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
307   {
308     Vector3 itemSize = mItemSizeFunction(layoutSize.width, layoutSize.height, mRowSpacing);
309     int rowsPerPage = ceil(layoutSize.height / (itemSize.y + mRowSpacing));
310     return (layoutPosition > -rowsPerPage) && (layoutPosition < rowsPerPage);
311   }
312
313 public:
314
315   float mRowSpacing;
316   RollLayout::ItemSizeFunction mItemSizeFunction;
317 };
318
319 struct RollVisibilityConstraintLandscape
320 {
321   RollVisibilityConstraintLandscape(const float rowSpacing, RollLayout::ItemSizeFunction itemSizeFunction)
322   : mRowSpacing(rowSpacing),
323     mItemSizeFunction(itemSizeFunction)
324   {
325   }
326
327   bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
328   {
329     Vector3 itemSize = mItemSizeFunction(layoutSize.height, layoutSize.width, mRowSpacing);
330     int rowsPerPage = ceil(layoutSize.width / (itemSize.y + mRowSpacing));
331     return (layoutPosition + 2.0f > Math::MACHINE_EPSILON_0) && (layoutPosition < rowsPerPage);
332   }
333
334 public:
335
336   float mRowSpacing;
337   RollLayout::ItemSizeFunction mItemSizeFunction;
338 };
339
340 } // unnamed namespace
341
342 namespace Dali
343 {
344
345 namespace Toolkit
346 {
347
348 struct RollLayout::Impl
349 {
350   Impl()
351   : mRowSpacing(DEFAULT_ROW_SPACING),
352     mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
353     mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
354     mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION),
355     mItemSizeFunction(GetItemSizeDefaultFunction)
356   {
357     mScaleConstraint = RollScaleConstraint();
358     mColorConstraint = RollColorConstraint();
359
360     mRotationConstraint[0] = RollRotationConstraint0();
361     mRotationConstraint[1] = RollRotationConstraint90();
362     mRotationConstraint[2] = RollRotationConstraint180();
363     mRotationConstraint[3] = RollRotationConstraint270();
364   }
365
366   float mRowSpacing;
367
368   float mScrollSpeedFactor;
369   float mMaximumSwipeSpeed;
370   float mItemFlickAnimationDuration;
371
372   ItemLayout::QuaternionFunction mRotationConstraint[ORIENTATION_COUNT];
373   ItemLayout::Vector3Function mScaleConstraint;
374   ItemLayout::Vector4Function mColorConstraint;
375
376   ItemSizeFunction mItemSizeFunction;
377 };
378
379 RollLayoutPtr RollLayout::New()
380 {
381   return RollLayoutPtr(new RollLayout());
382 }
383
384 RollLayout::~RollLayout()
385 {
386   delete mImpl;
387 }
388
389 void RollLayout::SetRowSpacing(float spacing)
390 {
391   mImpl->mRowSpacing = spacing;
392 }
393
394 float RollLayout::GetRowSpacing() const
395 {
396   return mImpl->mRowSpacing;
397 }
398
399 void RollLayout::SetItemSizeFunction(ItemSizeFunction function)
400 {
401   mImpl->mItemSizeFunction = function;
402 }
403
404 RollLayout::ItemSizeFunction RollLayout::GetItemSizeFunction() const
405 {
406   return mImpl->mItemSizeFunction;
407 }
408
409 void RollLayout::SetScrollSpeedFactor(float scrollSpeed)
410 {
411   mImpl->mScrollSpeedFactor = scrollSpeed;
412 }
413
414 void RollLayout::SetMaximumSwipeSpeed(float speed)
415 {
416   mImpl->mMaximumSwipeSpeed = speed;
417 }
418
419 void RollLayout::SetItemFlickAnimationDuration(float durationSeconds)
420 {
421   mImpl->mItemFlickAnimationDuration = durationSeconds;
422 }
423
424 float RollLayout::GetScrollSpeedFactor() const
425 {
426   return mImpl->mScrollSpeedFactor;
427 }
428
429 float RollLayout::GetMaximumSwipeSpeed() const
430 {
431   return mImpl->mMaximumSwipeSpeed;
432 }
433
434 float RollLayout::GetItemFlickAnimationDuration() const
435 {
436   return mImpl->mItemFlickAnimationDuration;
437 }
438
439 float RollLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
440 {
441   return 2.0f - static_cast<float>(numberOfItems);
442 }
443
444 float RollLayout::GetClosestAnchorPosition(float layoutPosition) const
445 {
446   return static_cast<float>(round(layoutPosition));
447 }
448
449 float RollLayout::GetItemScrollToPosition(unsigned int itemId) const
450 {
451   return 0.0f - static_cast<float>(itemId);
452 }
453
454 ItemRange RollLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
455 {
456   float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
457   float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
458
459   Vector3 itemSize = mImpl->mItemSizeFunction( layoutWidth,layoutHeight, mImpl->mRowSpacing);
460
461   float itemsPerPage = (layoutHeight / (itemSize.y + mImpl->mRowSpacing));
462   if(firstItemPosition + 0.001f >= Math::MACHINE_EPSILON_0)
463   {
464     itemsPerPage = std::max(0.0f, itemsPerPage - 1.0f);
465   }
466   int firstVisibleItem = -(static_cast<int>(firstItemPosition));
467
468   int firstItemIndex = std::max(0, firstVisibleItem);
469   int lastItemIndex  = std::max(0, static_cast<int>(ceil(firstVisibleItem + itemsPerPage - 1)));
470   return ItemRange(firstItemIndex, lastItemIndex);
471 }
472
473 unsigned int RollLayout::GetReserveItemCount(Vector3 layoutSize) const
474 {
475   float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
476   float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
477
478   Vector3 itemSize = mImpl->mItemSizeFunction(layoutWidth, layoutHeight, mImpl->mRowSpacing);
479   int itemsPerPage = ceil(layoutHeight / (itemSize.y + mImpl->mRowSpacing));
480   return itemsPerPage * 5;
481 }
482
483 bool RollLayout::GetItemSize(unsigned int itemId, Vector3 layoutSize, Vector3& itemSize) const
484 {
485   // Note: itemId is not checked, since every item has the same size
486   float layoutWidth = IsHorizontal(mOrientation) ? layoutSize.height : layoutSize.width;
487   float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
488
489   itemSize = mImpl->mItemSizeFunction(layoutWidth, layoutHeight, mImpl->mRowSpacing);
490
491   return true;
492 }
493
494 void RollLayout::GetResizeAnimation(Animation& animation, Actor actor, Vector3 size, float durationSeconds) const
495 {
496   if(animation)
497   {
498     animation.Resize(actor, size);
499   }
500 }
501
502 bool RollLayout::GetPositionConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
503 {
504   if (mOrientation == ControlOrientation::Up)
505   {
506     constraint = RollPositionConstraint0(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
507   }
508   else if (mOrientation == ControlOrientation::Left)
509   {
510     constraint = RollPositionConstraint90(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
511   }
512   else if (mOrientation == ControlOrientation::Down)
513   {
514     constraint = RollPositionConstraint180(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
515   }
516   else // mOrientation == ControlOrientation::Right
517   {
518     constraint = RollPositionConstraint270(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
519   }
520
521   return true;
522 }
523
524 bool RollLayout::GetRotationConstraint(unsigned int itemId, ItemLayout::QuaternionFunction& constraint) const
525 {
526   constraint = mImpl->mRotationConstraint[mOrientation];
527   return true;
528 }
529
530 bool RollLayout::GetScaleConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
531 {
532   constraint = mImpl->mScaleConstraint;
533   return true;
534 }
535
536 bool RollLayout::GetColorConstraint(unsigned int itemId, ItemLayout::Vector4Function& constraint) const
537 {
538   constraint = mImpl->mColorConstraint;
539   return true;
540 }
541
542 bool RollLayout::GetVisibilityConstraint(unsigned int itemId, ItemLayout::BoolFunction& constraint) const
543 {
544   if (IsVertical(mOrientation))
545   {
546     constraint = RollVisibilityConstraintPortrait(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
547   }
548   else // horizontal
549   {
550     constraint = RollVisibilityConstraintLandscape(mImpl->mRowSpacing, mImpl->mItemSizeFunction);
551   }
552
553   return true;
554 }
555
556 Degree RollLayout::GetScrollDirection() const
557 {
558   Degree scrollDirection(0.0f);
559
560   if (mOrientation == ControlOrientation::Up)
561   {
562     scrollDirection = 0.0f;
563   }
564   else if (mOrientation == ControlOrientation::Left)
565   {
566     scrollDirection = 90.0f;
567   }
568   else if (mOrientation == ControlOrientation::Down)
569   {
570     scrollDirection = 180.0f;
571   }
572   else // mOrientation == ControlOrientation::Right
573   {
574     scrollDirection = 270.0f;
575   }
576
577   return scrollDirection;
578 }
579
580 RollLayout::RollLayout()
581 : mImpl(NULL)
582 {
583   mImpl = new Impl();
584 }
585
586 } // namespace Toolkit
587
588 } // namespace Dali