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