Revert "License conversion from Flora to Apache 2.0"
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / scrollable / scroll-view / scroll-view-depth-effect-impl.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 <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
18 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-depth-effect-impl.h>
19
20 using namespace Dali;
21
22 namespace // unnamed namespace
23 {
24
25 // constraints ////////////////////////////////////////////////////////////////
26
27 /**
28  * Ramp equation is a variable easing equation
29  * of the form f(x) = |x|^y * x / |x|
30  *
31  * An exponent (y) of 1 will result in a fast (linear graph)
32  * Increasing the exponent will increase the Ease In
33  *
34  * @param[in] x mantissa (value from -1.0f to 1.0f)
35  * @param[in] y exponent (+ve value)
36  * @return The signed progress value from -1.0f to 1.0f
37  */
38 inline float RampFunction(float x, float y)
39 {
40   if(x < 0.0f)
41   {
42     return -powf(fabsf(x), y);
43   }
44
45   return powf(fabsf(x), y);
46 }
47
48 /**
49  * ScrollDepthScaleConstraint
50  *
51  * Scale constraint adjusts the scale of the Actors
52  * based on their parent page's position relative to the middle of the screen.
53  * When at middle of the screen the scale is not altered.
54  * As the page is moved away from the middle, Actors shrink in scale but at
55  * different rates defined by the RampFunction(x, f).
56  * All Actors eventually shrink to the same amount once at their destination.
57  */
58 struct ScrollDepthScaleConstraint
59 {
60   /**
61    * The scaling constraint uses the amount the actors
62    * have moved in position to determine scaling extent.
63    * So essentially very similar calculations are used here.
64    *
65    * @param[in] positionExtent Controls how much Actor's X and Y
66    * position affects their alpha function's exponent value
67    * @param[in] offsetExtent exponent offset for X and Y scrolling
68    * axes.
69    * @param[in] positionScale Changes the amount the page as a whole
70    * moves by.
71    * @param[in] scaleExtent Scale factor to reach when page is one whole
72    * page away from screen.
73    */
74   ScrollDepthScaleConstraint( Vector2 positionExtent = Vector2(0.5f, 1.0f),
75                               Vector2 offsetExtent = Vector2(1.0f, 1.0f),
76                               float positionScale = 1.5f,
77                               float scaleExtent = 0.5f)
78   : mPositionExtent(positionExtent),
79     mOffsetExtent(offsetExtent),
80     mMaxExtent(positionExtent.x + positionExtent.y),
81     mPositionScale(positionScale),
82     mScaleExtent(scaleExtent)
83   {
84   }
85
86   /**
87    * @param[in] current The current scale
88    * @param[in] pagePositionProperty The page's position.
89    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
90    * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
91    * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
92    * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
93    * @param[in] scrollWrap Whether scroll wrap has been enabled or not (SCROLL_WRAP_PROPERTY_NAME)
94    * @return The new scale of this Actor.
95    */
96   Vector3 operator()(const Vector3& currentScale,
97                      const PropertyInput& currentPositionProperty,
98                      const PropertyInput& pagePositionProperty,
99                      const PropertyInput& scrollPositionProperty,
100                      const PropertyInput& scrollPositionMin,
101                      const PropertyInput& scrollPositionMax,
102                      const PropertyInput& pageSizeProperty)
103   {
104     const Vector3& currentPosition = currentPositionProperty.GetVector3();
105     const Vector3& pagePosition = pagePositionProperty.GetVector3();
106     const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
107
108     // Get position of page.
109     Vector3 position = pagePosition + scrollPosition;
110
111     // short circuit: for orthognal view.
112     if( (fabsf(position.x) < Math::MACHINE_EPSILON_1) && (fabsf(position.y) < Math::MACHINE_EPSILON_1) )
113     {
114       return currentScale;
115     }
116
117     const Vector3& pageSize = pageSizeProperty.GetVector3();
118     // Don't have enough parameters, to provide Wrap mode (need a way of having 'uniforms' instead of scrollWrap.GetBoolean())
119     const bool wrap = true;
120
121     if(wrap)
122     {
123       const Vector3& min = scrollPositionMin.GetVector3();
124       const Vector3& max = scrollPositionMax.GetVector3();
125
126       if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
127       {
128         // WRAP X (based on the position of the right side)
129         position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
130       }
131
132       if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
133       {
134         // WRAP Y (based on the position of the bottom side)
135         position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
136       }
137     }
138
139     // short circuit: for pages outside of view.
140     if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
141     {
142       return currentScale;
143     }
144
145     // Calculate scale ////////////////////////////////////////////////////////
146
147     position.x /= pageSize.x;
148     position.y /= pageSize.y;
149
150     position *= mPositionScale;
151
152     Vector3 relCurrentPosition = currentPosition;
153     relCurrentPosition.x = relCurrentPosition.x / pageSize.x + 0.5f;
154     relCurrentPosition.y = relCurrentPosition.y / pageSize.y + 0.5f;
155
156     Vector3 extent( (relCurrentPosition.x * mPositionExtent.x + relCurrentPosition.y * mPositionExtent.y) * 1.0f,
157                     (relCurrentPosition.x * mPositionExtent.y + relCurrentPosition.y * mPositionExtent.x) * 1.0f,
158                     0.0f);
159
160     if(position.x>0.0f)
161     {
162       extent.x = mMaxExtent - extent.x; // Flip for right.
163     }
164     if(position.y>0.0f)
165     {
166       extent.y = mMaxExtent - extent.y; // Flip for bottom.
167     }
168
169     position.x = RampFunction(position.x, mOffsetExtent.x + extent.x);
170     position.y = RampFunction(position.y, mOffsetExtent.y + extent.y);
171
172     float f = mScaleExtent + cos(position.x * Math::PI_2) * cos(position.y * Math::PI_2) * (1.0f - mScaleExtent);
173
174     return currentScale * f;
175   }
176
177   const Vector2 mPositionExtent;                                ///< Determines how much of the Actor's X and Y position affects exponent value.
178   const Vector2 mOffsetExtent;                                  ///< Offset for exponent value.
179   const float mMaxExtent;                                       ///< Maximum possible extent (mOffsetExtent.x + mOffsetExtent.y)
180   const float mPositionScale;                                   ///< Position scaling factor (spreads out pages, to avoid overlap)
181   const float mScaleExtent;                                     ///< Scale factor when page is at furthest from
182 };
183
184 /**
185  * ScrollDepthPositionConstraint
186  *
187  * Position constraint adjusts the position of the Actors
188  * based on their parent page's position relative to the middle of the screen.
189  * When at middle of the screen the position is not altered.
190  * As the page is moved away from the middle, Actors move away but at
191  * different rates defined by the RampFunction(x, f).
192  * All Actors eventually arrive at their destination at the same time.
193  */
194 struct ScrollDepthPositionConstraint
195 {
196   /**
197    * @param [in] positionExtent Controls how much Actor's X and Y
198    * position affects their alpha function's exponent value
199    * @param [in] offsetExtent exponent offset for X and Y scrolling
200    * axes.
201    * @param [in] positionScale Changes the amount the page as a whole
202    * moves by.
203    */
204   ScrollDepthPositionConstraint( Vector2 positionExtent = Vector2(0.5f, 1.0f),
205                                  Vector2 offsetExtent = Vector2(1.0f, 1.0f),
206                                  float positionScale = 1.5f )
207   : mPositionExtent(positionExtent),
208     mOffsetExtent(offsetExtent),
209     mMaxExtent(positionExtent.x + positionExtent.y),
210     mPositionScale(positionScale)
211   {
212   }
213
214   /**
215    * @param[in] current The current position
216    * @param[in] pagePositionProperty The page's position.
217    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
218    * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
219    * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
220    * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
221    * @param[in] scrollWrap Whether scroll wrap has been enabled or not (SCROLL_WRAP_PROPERTY_NAME)
222    * @return The new position of this Actor.
223    */
224   Vector3 operator()(const Vector3& currentPosition,
225                      const PropertyInput& pagePositionProperty,
226                      const PropertyInput& scrollPositionProperty,
227                      const PropertyInput& scrollPositionMin,
228                      const PropertyInput& scrollPositionMax,
229                      const PropertyInput& pageSizeProperty,
230                      const PropertyInput& scrollWrap)
231   {
232     const Vector3& pagePosition = pagePositionProperty.GetVector3();
233     const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
234
235     // Get position of page.
236     Vector3 position = pagePosition + scrollPosition;
237
238     // short circuit: for orthognal view.
239     if( (fabsf(position.x) < Math::MACHINE_EPSILON_1) && (fabsf(position.y) < Math::MACHINE_EPSILON_1) )
240     {
241       return currentPosition + scrollPosition;
242     }
243
244     const Vector3& pageSize = pageSizeProperty.GetVector3();
245     bool wrap = scrollWrap.GetBoolean();
246
247     if(wrap)
248     {
249       const Vector3& min = scrollPositionMin.GetVector3();
250       const Vector3& max = scrollPositionMax.GetVector3();
251
252       if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
253       {
254         // WRAP X (based on the position of the right side)
255         position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
256       }
257
258       if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
259       {
260         // WRAP Y (based on the position of the bottom side)
261         position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
262       }
263     }
264
265     // short circuit: for pages outside of view.
266     if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
267     {
268       // position actors at: scrollposition (Property) + pagePosition (Parent) + current (this)
269       // they will be invisible so doesn't have to be precise, just away from stage.
270       return currentPosition + scrollPosition;
271     }
272
273     // Calculate position /////////////////////////////////////////////////////
274
275     position.x /= pageSize.x;
276     position.y /= pageSize.y;
277
278     position *= mPositionScale;
279
280     Vector3 finalPosition(currentPosition - pagePosition);
281
282     Vector3 relCurrentPosition = currentPosition;
283     relCurrentPosition.x = relCurrentPosition.x / pageSize.x + 0.5f;
284     relCurrentPosition.y = relCurrentPosition.y / pageSize.y + 0.5f;
285
286     Vector3 extent( (relCurrentPosition.x * mPositionExtent.x + relCurrentPosition.y * mPositionExtent.y) * 1.0f,
287                    (relCurrentPosition.x * mPositionExtent.y + relCurrentPosition.y * mPositionExtent.x) * 1.0f,
288                    0.0f);
289
290     if(position.x>0.0f)
291     {
292       extent.x = mMaxExtent - extent.x; // Flip for right.
293     }
294     if(position.y>0.0f)
295     {
296       extent.y = mMaxExtent - extent.y; // Flip for bottom.
297     }
298
299     position.x = RampFunction(position.x, mOffsetExtent.x + extent.x);
300     position.y = RampFunction(position.y, mOffsetExtent.y + extent.y);
301
302     finalPosition += pageSize * position;
303
304     return finalPosition;
305   }
306
307   const Vector2 mPositionExtent;                                ///< Determines how much of the Actor's X and Y position affects exponent value.
308   const Vector2 mOffsetExtent;                                  ///< Offset for exponent value.
309   const float mMaxExtent;                                       ///< Maximum possible extent (mOffsetExtent.x + mOffsetExtent.y)
310   const float mPositionScale;                                   ///< Position scaling factor (spreads out pages, to avoid overlap)
311 };
312
313 /**
314  * Applies the scroll depth constraints to the child actor
315  *
316  * @param[in] scrollView The ScrollView containing the pages.
317  * @param[in] child The child to be affected with the 3D Effect.
318  * @param[in] positionExtent Controls how much Actor's X and Y
319  * position affects their alpha function's exponent value
320  * @param[in] offsetExtent exponent offset for X and Y scrolling
321  * axes.
322  * @param[in] positionScale Changes the amount the page as a whole
323  * moves by.
324  * @param[in] scaleExtent Scale factor to reach when page is one whole
325  * page away from screen.
326  */
327 void ApplyScrollDepthConstraints(Toolkit::ScrollView scrollView,
328                                  Actor child,
329                                  const Vector2& positionExtent,
330                                  const Vector2& offsetExtent,
331                                  float positionScale,
332                                  float scaleExtent)
333 {
334   // Scale Constraint
335   Constraint constraint = Constraint::New<Vector3>( Actor::SCALE,
336                                          LocalSource(Actor::POSITION),
337                                          ParentSource(Actor::POSITION),
338                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
339                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
340                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
341                                          Source(scrollView, Actor::SIZE ),
342                                          ScrollDepthScaleConstraint( positionExtent, offsetExtent, positionScale, scaleExtent ) );
343   constraint.SetRemoveAction( Constraint::Discard );
344   child.ApplyConstraint( constraint );
345
346   // Position Constraint (apply last as other constraints use Actor::POSITION as a function input)
347   constraint = Constraint::New<Vector3>( Actor::POSITION,
348                                          ParentSource(Actor::POSITION),
349                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
350                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
351                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
352                                          Source(scrollView, Actor::SIZE ),
353                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_WRAP_PROPERTY_NAME ) ),
354                                          ScrollDepthPositionConstraint( positionExtent, offsetExtent, positionScale ) );
355
356   constraint.SetRemoveAction( Constraint::Discard );
357   child.ApplyConstraint( constraint );
358 }
359
360 } // unnamed namespace
361
362 namespace Dali
363 {
364
365 namespace Toolkit
366 {
367
368 namespace Internal
369 {
370
371 ScrollViewDepthEffect::ScrollViewDepthEffect()
372 {
373
374 }
375
376 ScrollViewDepthEffect::~ScrollViewDepthEffect()
377 {
378 }
379
380 void ScrollViewDepthEffect::ApplyToActor(Actor child,
381                                          const Vector2& positionExtent,
382                                          const Vector2& offsetExtent,
383                                          float positionScale,
384                                          float scaleExtent)
385 {
386   ApplyScrollDepthConstraints( GetScrollView(), child, positionExtent, offsetExtent, positionScale, scaleExtent );
387 }
388
389 void ScrollViewDepthEffect::OnAttach(Toolkit::ScrollView& scrollView)
390 {
391 }
392
393 void ScrollViewDepthEffect::OnDetach(Toolkit::ScrollView& scrollView)
394 {
395 }
396
397 } // namespace Internal
398
399 } // namespace Toolkit
400
401 } // namespace Dali