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