Remove obsolete and non functional SizeChanged signal from actor
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / public-api / controls / scrollable / item-view / spiral-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/spiral-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_ITEMS_PER_SPIRAL_TURN = 9.5f;
32 const float DEFAULT_ITEM_SPACING_RADIANS = Math::PI*2.0f/DEFAULT_ITEMS_PER_SPIRAL_TURN;
33
34 const float DEFAULT_REVOLUTION_DISTANCE = 190.0f;
35 const float DEFAULT_ITEM_DESCENT = DEFAULT_REVOLUTION_DISTANCE / DEFAULT_ITEMS_PER_SPIRAL_TURN;
36
37 const float DEFAULT_TOP_ITEM_ALIGNMENT = -0.125f;
38
39 const float DEFAULT_SCROLL_SPEED_FACTOR = 0.01f;
40 const float DEFAULT_MAXIMUM_SWIPE_SPEED = 30.0f;
41 const float DEFAULT_ITEM_FLICK_ANIMATION_DURATION = 0.1f;
42
43 struct DefaultItemSizeFunction
44 {
45   Vector3 operator()(const Vector3& layoutSize)
46   {
47     float width = layoutSize.width * 0.25f;
48
49     // 4x3 aspect ratio
50     return Vector3(width, (width/4)*3, (width/4)*3);
51   }
52 };
53
54 struct DefaultSpiralRadiusFunction
55 {
56   float operator()(const Vector3& layoutSize)
57   {
58     return layoutSize.width*0.4f;
59   }
60 };
61
62 struct SpiralPositionConstraintUp
63 {
64   SpiralPositionConstraintUp(SpiralLayout::SpiralRadiusFunction spiralRadius, float itemSpacingRadians, float itemDescent, float topItemAlignment)
65   : mSpiralRadius(spiralRadius),
66     mItemSpacingRadians(itemSpacingRadians),
67     mItemDescent(itemDescent),
68     mTopItemAlignment(topItemAlignment)
69   {
70   }
71
72   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
73   {
74     float spiralRadius = mSpiralRadius(layoutSize);
75
76     float angle = -Math::PI*0.5f + mItemSpacingRadians * layoutPosition;
77
78     return Vector3( -spiralRadius * cosf(angle),
79                     (mItemDescent * layoutPosition) + layoutSize.height*mTopItemAlignment,
80                     -spiralRadius * sinf(angle) );
81   }
82
83   SpiralLayout::SpiralRadiusFunction mSpiralRadius;
84   float mItemSpacingRadians;
85   float mItemDescent;
86   float mTopItemAlignment;
87 };
88
89 struct SpiralPositionConstraintLeft
90 {
91   SpiralPositionConstraintLeft(SpiralLayout::SpiralRadiusFunction spiralRadius, float itemSpacingRadians, float itemDescent, float topItemAlignment)
92   : mSpiralRadius(spiralRadius),
93     mItemSpacingRadians(itemSpacingRadians),
94     mItemDescent(itemDescent),
95     mTopItemAlignment(topItemAlignment)
96   {
97   }
98
99   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
100   {
101     float spiralRadius = mSpiralRadius(layoutSize);
102
103     float angle = Math::PI*0.5f + mItemSpacingRadians * layoutPosition;
104
105     return Vector3(  (mItemDescent * layoutPosition) + layoutSize.width*mTopItemAlignment,
106                      -spiralRadius * cosf(angle),
107                       spiralRadius * sinf(angle) );
108   }
109
110   SpiralLayout::SpiralRadiusFunction mSpiralRadius;
111   float mItemSpacingRadians;
112   float mItemDescent;
113   float mTopItemAlignment;
114 };
115
116 struct SpiralPositionConstraintDown
117 {
118   SpiralPositionConstraintDown(SpiralLayout::SpiralRadiusFunction spiralRadius, float itemSpacingRadians, float itemDescent, float topItemAlignment)
119   : mSpiralRadius(spiralRadius),
120     mItemSpacingRadians(itemSpacingRadians),
121     mItemDescent(itemDescent),
122     mTopItemAlignment(topItemAlignment)
123   {
124   }
125
126   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
127   {
128     float spiralRadius = mSpiralRadius(layoutSize);
129
130     float angle = Math::PI*0.5f + mItemSpacingRadians * layoutPosition;
131
132     return Vector3(  -spiralRadius * cosf(angle),
133                     (-mItemDescent * layoutPosition) - layoutSize.height*mTopItemAlignment,
134                       spiralRadius * sinf(angle) );
135   }
136
137   SpiralLayout::SpiralRadiusFunction mSpiralRadius;
138   float mItemSpacingRadians;
139   float mItemDescent;
140   float mTopItemAlignment;
141 };
142
143 struct SpiralPositionConstraintRight
144 {
145   SpiralPositionConstraintRight(SpiralLayout::SpiralRadiusFunction spiralRadius, float itemSpacingRadians, float itemDescent, float topItemAlignment)
146   : mSpiralRadius(spiralRadius),
147     mItemSpacingRadians(itemSpacingRadians),
148     mItemDescent(itemDescent),
149     mTopItemAlignment(topItemAlignment)
150   {
151   }
152
153   Vector3 operator()(const Vector3& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
154   {
155     float spiralRadius = mSpiralRadius(layoutSize);
156
157     float angle = -Math::PI*0.5f + mItemSpacingRadians * layoutPosition;
158
159     return Vector3( (-mItemDescent * layoutPosition) - layoutSize.width*mTopItemAlignment,
160                      -spiralRadius * cosf(angle),
161                      -spiralRadius * sinf(angle) );
162   }
163
164   SpiralLayout::SpiralRadiusFunction mSpiralRadius;
165   float mItemSpacingRadians;
166   float mItemDescent;
167   float mTopItemAlignment;
168 };
169
170 struct SpiralRotationConstraintUp
171 {
172   SpiralRotationConstraintUp(float itemSpacingRadians)
173   : mItemSpacingRadians(itemSpacingRadians)
174   {
175   }
176
177   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
178   {
179     float angle = -mItemSpacingRadians * layoutPosition;
180
181     return Quaternion(angle, Vector3::YAXIS);
182   }
183
184   float mItemSpacingRadians;
185 };
186
187 struct SpiralRotationConstraintLeft
188 {
189   SpiralRotationConstraintLeft(float itemSpacingRadians)
190   : mItemSpacingRadians(itemSpacingRadians)
191   {
192   }
193
194   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
195   {
196     float angle = -mItemSpacingRadians * layoutPosition;
197
198     return Quaternion(-Math::PI*0.5f, Vector3::ZAXIS) * Quaternion(angle, Vector3::YAXIS);
199   }
200
201   float mItemSpacingRadians;
202 };
203
204 struct SpiralRotationConstraintDown
205 {
206   SpiralRotationConstraintDown(float itemSpacingRadians)
207   : mItemSpacingRadians(itemSpacingRadians)
208   {
209   }
210
211   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
212   {
213     float angle = -mItemSpacingRadians * layoutPosition;
214
215     return Quaternion(-Math::PI, Vector3::ZAXIS) * Quaternion(angle, Vector3::YAXIS);
216   }
217
218   float mItemSpacingRadians;
219 };
220
221 struct SpiralRotationConstraintRight
222 {
223   SpiralRotationConstraintRight(float itemSpacingRadians)
224   : mItemSpacingRadians(itemSpacingRadians)
225   {
226   }
227
228   Quaternion operator()(const Quaternion& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
229   {
230     float angle = -mItemSpacingRadians * layoutPosition;
231
232     return Quaternion(-Math::PI*1.5f, Vector3::ZAXIS) * Quaternion(angle, Vector3::YAXIS);
233   }
234
235   float mItemSpacingRadians;
236 };
237
238 struct SpiralColorConstraint
239 {
240   SpiralColorConstraint(float itemSpacingRadians)
241   : mItemSpacingRadians(itemSpacingRadians)
242   {
243   }
244
245   Vector4 operator()(const Vector4& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
246   {
247     Degree angle = Radian(mItemSpacingRadians * fabsf(layoutPosition));
248     angle = (float)((int)angle % 360);
249
250     float progress = angle / 360.0f;
251     progress = (progress > 0.5f) ? 2.0f*(1.0f - progress) : progress*2.0f;
252
253     float darkness(1.0f);
254     {
255       const float startMarker = 0.10f; // The progress at which darkening starts
256       const float endMarker   = 0.35f; // The progress at which darkening ends
257       const float minDarkness = 0.15f; // The darkness at end marker
258
259       if (progress > endMarker)
260       {
261         darkness = minDarkness;
262       }
263       else if (progress > startMarker)
264       {
265         darkness = 1.0f - ( (1.0f - minDarkness) * ((progress-startMarker) / (endMarker-startMarker)) );
266       }
267     }
268
269     return Vector4( darkness, darkness, darkness, current.a );
270   }
271
272   float mItemSpacingRadians;
273 };
274
275 struct SpiralVisibilityConstraintPortrait
276 {
277   SpiralVisibilityConstraintPortrait(float itemSpacingRadians, float itemDescent, float topItemAlignment)
278   : mItemSpacingRadians(itemSpacingRadians),
279     mItemDescent(itemDescent),
280     mTopItemAlignment(topItemAlignment)
281   {
282   }
283
284   bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
285   {
286     float itemsCachedBeforeTopItem = layoutSize.height*(mTopItemAlignment+0.5f) / mItemDescent;
287     return (layoutPosition >= -itemsCachedBeforeTopItem - 1.0f && layoutPosition <= (layoutSize.height / mItemDescent) + 1.0f);
288   }
289
290   float mItemSpacingRadians;
291   float mItemDescent;
292   float mTopItemAlignment;
293 };
294
295 struct SpiralVisibilityConstraintLandscape
296 {
297   SpiralVisibilityConstraintLandscape(float itemSpacingRadians, float itemDescent, float topItemAlignment)
298   : mItemSpacingRadians(itemSpacingRadians),
299     mItemDescent(itemDescent),
300     mTopItemAlignment(topItemAlignment)
301   {
302   }
303
304   bool operator()(const bool& current, const float& layoutPosition, const float& scrollSpeed, const Vector3& layoutSize)
305   {
306     float itemsCachedBeforeTopItem = layoutSize.width*(mTopItemAlignment+0.5f) / mItemDescent;
307     return (layoutPosition >= -itemsCachedBeforeTopItem - 1.0f && layoutPosition <= (layoutSize.width / mItemDescent) + 1.0f);
308   }
309
310   float mItemSpacingRadians;
311   float mItemDescent;
312   float mTopItemAlignment;
313 };
314
315 } // unnamed namespace
316
317 namespace Dali
318 {
319
320 namespace Toolkit
321 {
322
323 struct SpiralLayout::Impl
324 {
325   Impl()
326   : mItemSizeFunction(DefaultItemSizeFunction()),
327     mSpiralRadiusFunction(DefaultSpiralRadiusFunction()),
328     mItemSpacingRadians(DEFAULT_ITEM_SPACING_RADIANS),
329     mRevolutionDistance(DEFAULT_REVOLUTION_DISTANCE),
330     mItemDescent(DEFAULT_ITEM_DESCENT),
331     mTopItemAlignment(DEFAULT_TOP_ITEM_ALIGNMENT),
332     mScrollSpeedFactor(DEFAULT_SCROLL_SPEED_FACTOR),
333     mMaximumSwipeSpeed(DEFAULT_MAXIMUM_SWIPE_SPEED),
334     mItemFlickAnimationDuration(DEFAULT_ITEM_FLICK_ANIMATION_DURATION)
335   {
336   }
337
338   ItemSizeFunction     mItemSizeFunction;
339   SpiralRadiusFunction mSpiralRadiusFunction;
340
341   float mItemSpacingRadians;
342   float mRevolutionDistance;
343   float mItemDescent;
344   float mTopItemAlignment;
345   float mScrollSpeedFactor;
346   float mMaximumSwipeSpeed;
347   float mItemFlickAnimationDuration;
348 };
349
350 SpiralLayoutPtr SpiralLayout::New()
351 {
352   return SpiralLayoutPtr(new SpiralLayout());
353 }
354
355 SpiralLayout::~SpiralLayout()
356 {
357   delete mImpl;
358 }
359
360 void SpiralLayout::SetItemSizeFunction(ItemSizeFunction function)
361 {
362   mImpl->mItemSizeFunction = function;
363 }
364
365 SpiralLayout::ItemSizeFunction SpiralLayout::GetItemSizeFunction() const
366 {
367   return mImpl->mItemSizeFunction;
368 }
369
370 void SpiralLayout::SetItemSpacing(Radian itemSpacing)
371 {
372   mImpl->mItemSpacingRadians = itemSpacing;
373
374   float itemsPerSpiral = std::max(1.0f, (2.0f*(float)Math::PI) / mImpl->mItemSpacingRadians);
375   mImpl->mItemDescent = mImpl->mRevolutionDistance / itemsPerSpiral;
376 }
377
378 Radian SpiralLayout::GetItemSpacing() const
379 {
380   return Radian( mImpl->mItemSpacingRadians );
381 }
382
383 void SpiralLayout::SetRevolutionDistance(float distance)
384 {
385   mImpl->mRevolutionDistance = distance;
386
387   float itemsPerSpiral = std::max(1.0f, (2.0f*(float)Math::PI) / mImpl->mItemSpacingRadians);
388   mImpl->mItemDescent = mImpl->mRevolutionDistance / itemsPerSpiral;
389 }
390
391 float SpiralLayout::GetRevolutionDistance() const
392 {
393   return mImpl->mRevolutionDistance;
394 }
395
396 void SpiralLayout::SetSpiralRadiusFunction(SpiralRadiusFunction function)
397 {
398   mImpl->mSpiralRadiusFunction = function;
399 }
400
401 SpiralLayout::SpiralRadiusFunction SpiralLayout::GetSpiralRadiusFunction() const
402 {
403   return mImpl->mSpiralRadiusFunction;
404 }
405
406 void SpiralLayout::SetTopItemAlignment(float alignment)
407 {
408   mImpl->mTopItemAlignment = alignment;
409 }
410
411 float SpiralLayout::GetTopItemAlignment() const
412 {
413   return mImpl->mTopItemAlignment;
414 }
415
416 void SpiralLayout::SetScrollSpeedFactor(float scrollSpeed)
417 {
418   mImpl->mScrollSpeedFactor = scrollSpeed;
419 }
420
421 void SpiralLayout::SetMaximumSwipeSpeed(float speed)
422 {
423   mImpl->mMaximumSwipeSpeed = speed;
424 }
425
426 void SpiralLayout::SetItemFlickAnimationDuration(float durationSeconds)
427 {
428   mImpl->mItemFlickAnimationDuration = durationSeconds;
429 }
430
431 float SpiralLayout::GetScrollSpeedFactor() const
432 {
433   return mImpl->mScrollSpeedFactor;
434 }
435
436 float SpiralLayout::GetMaximumSwipeSpeed() const
437 {
438   return mImpl->mMaximumSwipeSpeed;
439 }
440
441 float SpiralLayout::GetItemFlickAnimationDuration() const
442 {
443   return mImpl->mItemFlickAnimationDuration;
444 }
445
446 float SpiralLayout::GetMinimumLayoutPosition(unsigned int numberOfItems, Vector3 layoutSize) const
447 {
448   return 1.0f - static_cast<float>(numberOfItems);
449 }
450
451 float SpiralLayout::GetClosestAnchorPosition(float layoutPosition) const
452 {
453   return round(layoutPosition);
454 }
455
456 float SpiralLayout::GetItemScrollToPosition(unsigned int itemId) const
457 {
458   return -(static_cast<float>(itemId));
459 }
460
461 ItemRange SpiralLayout::GetItemsWithinArea(float firstItemPosition, Vector3 layoutSize) const
462 {
463   float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
464   float itemsPerSpiral = layoutHeight / mImpl->mItemDescent;
465   float itemsCachedBeforeTopItem = layoutHeight * (mImpl->mTopItemAlignment + 0.5f) / mImpl->mItemDescent;
466   float itemsViewable = std::min(itemsPerSpiral, itemsPerSpiral - itemsCachedBeforeTopItem - firstItemPosition + 1.0f);
467
468   unsigned int firstItem = static_cast<unsigned int>(std::max(0.0f, -firstItemPosition - itemsCachedBeforeTopItem - 1.0f));
469   unsigned int lastItem  = static_cast<unsigned int>(std::max(0.0f, firstItem + itemsViewable));
470
471   return ItemRange(firstItem, lastItem+1);
472 }
473
474 unsigned int SpiralLayout::GetReserveItemCount(Vector3 layoutSize) const
475 {
476   float layoutHeight = IsHorizontal(mOrientation) ? layoutSize.width : layoutSize.height;
477   return static_cast<unsigned int>(layoutHeight / mImpl->mItemDescent);
478 }
479
480 bool SpiralLayout::GetItemSize(unsigned int itemId, Vector3 layoutSize, Vector3& itemSize) const
481 {
482   // Note: itemId is not checked, since every item has the same size
483
484   itemSize = mImpl->mItemSizeFunction(layoutSize);
485   return true;
486 }
487
488 void SpiralLayout::GetResizeAnimation(Animation& animation, Actor actor, Vector3 size, float durationSeconds) const
489 {
490   if(animation)
491   {
492     animation.Resize(actor, size);
493   }
494 }
495
496 bool SpiralLayout::GetPositionConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
497 {
498   if (mOrientation == ControlOrientation::Up)
499   {
500     constraint = SpiralPositionConstraintUp(mImpl->mSpiralRadiusFunction, mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment);
501   }
502   else if (mOrientation == ControlOrientation::Left)
503   {
504     constraint = SpiralPositionConstraintLeft(mImpl->mSpiralRadiusFunction, mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment);
505   }
506   else if (mOrientation == ControlOrientation::Down)
507   {
508     constraint = SpiralPositionConstraintDown(mImpl->mSpiralRadiusFunction, mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment);
509   }
510   else // mOrientation == ControlOrientation::Right
511   {
512     constraint = SpiralPositionConstraintRight(mImpl->mSpiralRadiusFunction, mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment);
513   }
514
515   return true;
516 }
517
518 bool SpiralLayout::GetRotationConstraint(unsigned int itemId, ItemLayout::QuaternionFunction& constraint) const
519 {
520   if (mOrientation == ControlOrientation::Up)
521   {
522     constraint = SpiralRotationConstraintUp(mImpl->mItemSpacingRadians);
523   }
524   else if (mOrientation == ControlOrientation::Left)
525   {
526     constraint = SpiralRotationConstraintLeft(mImpl->mItemSpacingRadians);
527   }
528   else if (mOrientation == ControlOrientation::Down)
529   {
530     constraint = SpiralRotationConstraintDown(mImpl->mItemSpacingRadians);
531   }
532   else // mOrientation == ControlOrientation::Right
533   {
534     constraint = SpiralRotationConstraintRight(mImpl->mItemSpacingRadians);
535   }
536
537   return true;
538 }
539
540 bool SpiralLayout::GetScaleConstraint(unsigned int itemId, ItemLayout::Vector3Function& constraint) const
541 {
542   return false; // No scaling
543 }
544
545 bool SpiralLayout::GetColorConstraint(unsigned int itemId, ItemLayout::Vector4Function& constraint) const
546 {
547   constraint = SpiralColorConstraint(mImpl->mItemSpacingRadians);
548   return true;
549 }
550
551 bool SpiralLayout::GetVisibilityConstraint(unsigned int itemId, ItemLayout::BoolFunction& constraint) const
552 {
553   if (IsVertical(mOrientation))
554   {
555     constraint = SpiralVisibilityConstraintPortrait(mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment);
556   }
557   else // horizontal
558   {
559     constraint = SpiralVisibilityConstraintLandscape(mImpl->mItemSpacingRadians, mImpl->mItemDescent, mImpl->mTopItemAlignment);
560   }
561
562   return true;
563 }
564
565 Degree SpiralLayout::GetScrollDirection() const
566 {
567   Degree scrollDirection(0);
568
569   if (mOrientation == ControlOrientation::Up)
570   {
571     scrollDirection = 0.0f - 45.0f; // Allow swiping horizontally & vertically
572   }
573   else if (mOrientation == ControlOrientation::Left)
574   {
575     scrollDirection = 90.0f - 45.0f;
576   }
577   else if (mOrientation == ControlOrientation::Down)
578   {
579     scrollDirection = 180.0f - 45.0f;
580   }
581   else // mOrientation == ControlOrientation::Right
582   {
583     scrollDirection = 270.0f - 45.0f;
584   }
585
586   return scrollDirection;
587 }
588
589 SpiralLayout::SpiralLayout()
590 : mImpl(NULL)
591 {
592   mImpl = new Impl();
593 }
594
595 float SpiralLayout::GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize)
596 {
597   return GetItemScrollToPosition(itemID);
598 }
599
600 } // namespace Toolkit
601
602 } // namespace Dali