Added shader effect to render quadratic bezier curves and bounded regions on the GPU
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / public-api / controls / scrollable / item-view / item-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/item-layout.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/animation/constraint.h>
23 #include <dali/public-api/animation/time-period.h>
24
25 // INTERNAL INCLUDES
26 #include <dali-toolkit/public-api/controls/scrollable/item-view/item-view.h>
27
28 namespace
29 {
30
31   // Functors which wrap constraint functions with stored item IDs
32   struct WrappedQuaternionConstraint
33   {
34     WrappedQuaternionConstraint(Dali::Toolkit::ItemLayout::QuaternionFunction wrapMe, unsigned int itemId)
35     :mWrapMe(wrapMe),
36      mItemId(itemId)
37     {
38     }
39
40     Dali::Quaternion operator()(const Dali::Quaternion& current, const Dali::PropertyInput& layoutPosition, const Dali::PropertyInput& scrollSpeed, const Dali::PropertyInput& layoutSize)
41     {
42       float offsetLayoutPosition = layoutPosition.GetFloat() + static_cast<float>(mItemId);
43
44       return mWrapMe(current, offsetLayoutPosition, scrollSpeed.GetFloat(), layoutSize.GetVector3());
45     }
46
47     Dali::Toolkit::ItemLayout::QuaternionFunction mWrapMe;
48     unsigned int mItemId;
49   };
50
51   struct WrappedVector3Constraint
52   {
53     WrappedVector3Constraint(Dali::Toolkit::ItemLayout::Vector3Function wrapMe, unsigned int itemId)
54     : mWrapMe(wrapMe),
55       mItemId(itemId)
56     {
57     }
58
59     Dali::Vector3 operator()(const Dali::Vector3& current, const Dali::PropertyInput& layoutPosition, const Dali::PropertyInput& scrollSpeed, const Dali::PropertyInput& layoutSize)
60     {
61       float offsetLayoutPosition = layoutPosition.GetFloat() + static_cast<float>(mItemId);
62
63       return mWrapMe(current, offsetLayoutPosition, scrollSpeed.GetFloat(), layoutSize.GetVector3());
64     }
65
66     Dali::Toolkit::ItemLayout::Vector3Function mWrapMe;
67     unsigned int mItemId;
68   };
69
70   struct WrappedVector4Constraint
71   {
72     WrappedVector4Constraint(Dali::Toolkit::ItemLayout::Vector4Function wrapMe, unsigned int itemId)
73     : mWrapMe(wrapMe),
74       mItemId(itemId)
75     {
76     }
77
78     Dali::Vector4 operator()(const Dali::Vector4& current, const Dali::PropertyInput& layoutPosition, const Dali::PropertyInput& scrollSpeed, const Dali::PropertyInput& layoutSize)
79     {
80       float offsetLayoutPosition = layoutPosition.GetFloat() + static_cast<float>(mItemId);
81
82       return mWrapMe(current, offsetLayoutPosition, scrollSpeed.GetFloat(), layoutSize.GetVector3());
83     }
84
85     Dali::Toolkit::ItemLayout::Vector4Function mWrapMe;
86     unsigned int mItemId;
87   };
88
89   struct WrappedBoolConstraint
90   {
91     WrappedBoolConstraint(Dali::Toolkit::ItemLayout::BoolFunction wrapMe, unsigned int itemId)
92     : mWrapMe(wrapMe),
93       mItemId(itemId)
94     {
95     }
96
97     bool operator()(const bool& current, const Dali::PropertyInput& layoutPosition, const Dali::PropertyInput& scrollSpeed, const Dali::PropertyInput& layoutSize)
98     {
99       float offsetLayoutPosition = layoutPosition.GetFloat() + static_cast<float>(mItemId);
100
101       return mWrapMe(current, offsetLayoutPosition, scrollSpeed.GetFloat(), layoutSize.GetVector3());
102     }
103
104     Dali::Toolkit::ItemLayout::BoolFunction mWrapMe;
105     unsigned int mItemId;
106   };
107
108 }  //Unnamed namespace
109
110 namespace Dali
111 {
112
113 namespace Toolkit
114 {
115
116 ItemLayout::ItemLayout()
117 : mOrientation(ControlOrientation::Up),
118   mAlphaFunction(Dali::Constraint::DEFAULT_ALPHA_FUNCTION)
119 {
120 }
121
122 ItemLayout::~ItemLayout()
123 {
124 }
125
126 void ItemLayout::SetOrientation(ControlOrientation::Type orientation)
127 {
128   mOrientation = orientation;
129 }
130
131 ControlOrientation::Type ItemLayout::GetOrientation() const
132 {
133   return mOrientation;
134 }
135
136 float ItemLayout::GetClosestOnScreenLayoutPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize)
137 {
138   Vector3 itemPosition = GetItemPosition( itemID, currentLayoutPosition, layoutSize );
139   Vector3 itemSize;
140   GetItemSize(itemID, layoutSize, itemSize);
141   Vector3 onScreenArea = (layoutSize - itemSize) * 0.5f;
142   if (itemPosition.x < -onScreenArea.x
143       || itemPosition.x > onScreenArea.x
144       || itemPosition.y < -onScreenArea.y
145       || itemPosition.y > onScreenArea.y)
146   {
147     // item not within viewable area
148     // safest thing to do here since we have no idea how the implementation will work is to return the scroll to position
149     return GetItemScrollToPosition(itemID);
150   }
151   return currentLayoutPosition;
152 }
153
154 void ItemLayout::GetXAxisScrollHint(Vector2& scrollHint) const
155 {
156   scrollHint = Vector2::ZERO;
157   Radian scrollAngle(GetScrollDirection());
158   Vector2 scrollDirection(sinf(scrollAngle), cosf(scrollAngle));
159   switch(mOrientation)
160   {
161     case ControlOrientation::Up:
162     {
163       if(fabsf(scrollDirection.y) < Math::MACHINE_EPSILON_1)
164       {
165         // we probably want x scrolling
166         if(scrollDirection.x > 0.0f)
167         {
168           // normal positive scrolling
169           scrollHint = Vector2::XAXIS;
170         }
171         else
172         {
173           scrollHint = -Vector2::XAXIS;
174         }
175       }
176       break;
177     }
178     case ControlOrientation::Down:
179     {
180       if(fabsf(scrollDirection.y) < Math::MACHINE_EPSILON_1)
181       {
182         // we probably want x scrolling
183         if(scrollDirection.x > 0.0f)
184         {
185           // normal positive scrolling
186           scrollHint = -Vector2::XAXIS;
187         }
188         else
189         {
190           scrollHint = Vector2::XAXIS;
191         }
192       }
193       break;
194     }
195     case ControlOrientation::Left:
196     {
197       // we probably want x scrolling
198       if(scrollDirection.x > 0.0f)
199       {
200         // normal positive scrolling
201         scrollHint = Vector2::XAXIS;
202       }
203       else
204       {
205         scrollHint = -Vector2::XAXIS;
206       }
207       break;
208     }
209     case ControlOrientation::Right:
210     {
211       // we probably want x scrolling
212       if(scrollDirection.x > 0.0f)
213       {
214         // normal positive scrolling
215         scrollHint = -Vector2::XAXIS;
216       }
217       else
218       {
219         scrollHint = Vector2::XAXIS;
220       }
221       break;
222     }
223   }
224 }
225
226 void ItemLayout::GetYAxisScrollHint(Vector2& scrollHint) const
227 {
228   scrollHint = Vector2::ZERO;
229   Radian scrollAngle(GetScrollDirection());
230   Vector2 scrollDirection(sinf(scrollAngle), cosf(scrollAngle));
231   switch(mOrientation)
232   {
233     case ControlOrientation::Up:
234     {
235       // we probably want x scrolling
236       if(scrollDirection.y > 0.0f)
237       {
238         // normal positive scrolling
239         scrollHint = Vector2::YAXIS;
240       }
241       else
242       {
243         scrollHint = -Vector2::YAXIS;
244       }
245       break;
246     }
247     case ControlOrientation::Down:
248     {
249       // we probably want x scrolling
250       if(scrollDirection.y > 0.0f)
251       {
252         // normal positive scrolling
253         scrollHint = -Vector2::YAXIS;
254       }
255       else
256       {
257         scrollHint = Vector2::YAXIS;
258       }
259       break;
260     }
261     case ControlOrientation::Left:
262     {
263       if(fabsf(scrollDirection.x) < Math::MACHINE_EPSILON_1)
264       {
265         // we probably want x scrolling
266         if(scrollDirection.y > 0.0f)
267         {
268           // normal positive scrolling
269           scrollHint = -Vector2::YAXIS;
270         }
271         else
272         {
273           scrollHint = Vector2::YAXIS;
274         }
275       }
276       break;
277     }
278     case ControlOrientation::Right:
279     {
280       if(fabsf(scrollDirection.x) < Math::MACHINE_EPSILON_1)
281       {
282         // we probably want x scrolling
283         if(scrollDirection.y > 0.0f)
284         {
285           // normal positive scrolling
286           scrollHint = Vector2::YAXIS;
287         }
288         else
289         {
290           scrollHint = -Vector2::YAXIS;
291         }
292       }
293       break;
294     }
295   }
296 }
297
298 int ItemLayout::GetNextFocusItemID(int itemID, int maxItems, Dali::Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
299 {
300   switch( direction )
301   {
302     case Control::Left:
303     case Control::Up:
304     {
305       itemID--;
306       if( itemID < 0 )
307       {
308         itemID = loopEnabled ? maxItems - 1 : 0;
309       }
310       break;
311     }
312     case Control::Right:
313     case Control::Down:
314     {
315       itemID++;
316       if( itemID >= maxItems )
317       {
318         itemID = loopEnabled ? 0 : maxItems - 1;
319       }
320       break;
321     }
322   }
323   return itemID;
324 }
325
326 float ItemLayout::GetFlickSpeedFactor() const
327 {
328   // By default, the speed factor while dragging and swiping is the same.
329   return GetScrollSpeedFactor();
330 }
331
332 void ItemLayout::ApplyConstraints( Actor& actor, const int itemId, const float durationSeconds, Constrainable scrollPositionObject, const Actor& itemViewActor )
333 {
334   // This just implements the default behaviour of constraint application.
335   // Custom layouts can override this function to apply their custom constraints.
336   Dali::Toolkit::ItemView itemView = Dali::Toolkit::ItemView::DownCast( itemViewActor );
337   if(itemView && scrollPositionObject)
338   {
339     Property::Index scrollSpeedProperty = itemView.GetPropertyIndex("item-view-scroll-speed");
340     Property::Index scrollPositionProperty = scrollPositionObject.GetPropertyIndex("scroll-position");
341
342     ItemLayout::Vector3Function positionConstraint;
343     if (GetPositionConstraint(itemId, positionConstraint))
344     {
345       WrappedVector3Constraint wrapped(positionConstraint, itemId);
346       Constraint constraint = Constraint::New<Vector3>( Actor::POSITION,
347                                                         Source( scrollPositionObject, scrollPositionProperty ),
348                                                         ParentSource( scrollSpeedProperty ),
349                                                         ParentSource( Actor::SIZE ),
350                                                         wrapped );
351       constraint.SetApplyTime(durationSeconds);
352       constraint.SetAlphaFunction(mAlphaFunction);
353       actor.ApplyConstraint(constraint);
354     }
355
356     ItemLayout::QuaternionFunction rotationConstraint;
357     if (GetRotationConstraint(itemId, rotationConstraint))
358     {
359       WrappedQuaternionConstraint wrapped(rotationConstraint, itemId);
360
361       Constraint constraint = Constraint::New<Quaternion>( Actor::ROTATION,
362                                                            Source( scrollPositionObject, scrollPositionProperty ),
363                                                            ParentSource( scrollSpeedProperty ),
364                                                            ParentSource( Actor::SIZE ),
365                                                            wrapped );
366       constraint.SetApplyTime(durationSeconds);
367       constraint.SetAlphaFunction(mAlphaFunction);
368
369       actor.ApplyConstraint(constraint);
370     }
371
372     ItemLayout::Vector3Function scaleConstraint;
373     if (GetScaleConstraint(itemId, scaleConstraint))
374     {
375       WrappedVector3Constraint wrapped(scaleConstraint, itemId);
376
377       Constraint constraint = Constraint::New<Vector3>( Actor::SCALE,
378                                                         Source( scrollPositionObject, scrollPositionProperty ),
379                                                         ParentSource( scrollSpeedProperty ),
380                                                         ParentSource( Actor::SIZE ),
381                                                         wrapped );
382       constraint.SetApplyTime(durationSeconds);
383       constraint.SetAlphaFunction(mAlphaFunction);
384
385       actor.ApplyConstraint(constraint);
386     }
387
388     ItemLayout::Vector4Function colorConstraint;
389     if (GetColorConstraint(itemId, colorConstraint))
390     {
391       WrappedVector4Constraint wrapped(colorConstraint, itemId);
392
393       Constraint constraint = Constraint::New<Vector4>( Actor::COLOR,
394                                                         Source( scrollPositionObject, scrollPositionProperty ),
395                                                         ParentSource( scrollSpeedProperty ),
396                                                         ParentSource( Actor::SIZE ),
397                                                         wrapped );
398
399       constraint.SetApplyTime(durationSeconds);
400       constraint.SetAlphaFunction(mAlphaFunction);
401       constraint.SetRemoveAction(Dali::Constraint::Discard);
402
403       actor.ApplyConstraint(constraint);
404     }
405
406     ItemLayout::BoolFunction visibilityConstraint;
407     if (GetVisibilityConstraint(itemId, visibilityConstraint))
408     {
409       WrappedBoolConstraint wrapped(visibilityConstraint, itemId);
410
411       Constraint constraint = Constraint::New<bool>( Actor::VISIBLE,
412                                                      Source( scrollPositionObject, scrollPositionProperty ),
413                                                      ParentSource( scrollSpeedProperty ),
414                                                      ParentSource( Actor::SIZE ),
415                                                      wrapped );
416
417       constraint.SetApplyTime(durationSeconds);
418       constraint.SetAlphaFunction(mAlphaFunction);
419
420       // Release visibility constraints the same time as the color constraint
421       constraint.SetRemoveAction(Dali::Constraint::Discard);
422
423       actor.ApplyConstraint(constraint);
424     }
425   }
426 }
427
428 Vector3 ItemLayout::GetItemPosition(int itemID, float currentLayoutPosition, const Vector3& layoutSize) const
429 {
430   Vector3 itemPosition = Vector3::ZERO;
431
432   ItemLayout::Vector3Function positionConstraint;
433   if (GetPositionConstraint(itemID, positionConstraint))
434   {
435     itemPosition = positionConstraint(Vector3::ZERO, currentLayoutPosition + itemID, 0.0f, layoutSize);
436   }
437
438   return itemPosition;
439 }
440
441 void ItemLayout::SetAlphaFunction(AlphaFunction func)
442 {
443   mAlphaFunction = func;
444 }
445
446 AlphaFunction ItemLayout::GetAlphaFunction() const
447 {
448   return mAlphaFunction;
449 }
450
451
452 } // namespace Toolkit
453
454 } // namespace Dali