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