Merge base & optional
[platform/core/uifw/dali-toolkit.git] / 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
120     // Don't have enough parameters, to provide Wrap mode (need a way of having 'uniforms' instead of scrollWrap.GetBoolean())
121
122     const Vector3& min = scrollPositionMin.GetVector3();
123     const Vector3& max = scrollPositionMax.GetVector3();
124
125     if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
126     {
127       // WRAP X (based on the position of the right side)
128       position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
129     }
130
131     if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
132     {
133       // WRAP Y (based on the position of the bottom side)
134       position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
135     }
136
137     // short circuit: for pages outside of view.
138     if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
139     {
140       return currentScale;
141     }
142
143     // Calculate scale ////////////////////////////////////////////////////////
144
145     position.x /= pageSize.x;
146     position.y /= pageSize.y;
147
148     position *= mPositionScale;
149
150     Vector3 relCurrentPosition = currentPosition;
151     relCurrentPosition.x = relCurrentPosition.x / pageSize.x + 0.5f;
152     relCurrentPosition.y = relCurrentPosition.y / pageSize.y + 0.5f;
153
154     Vector3 extent( (relCurrentPosition.x * mPositionExtent.x + relCurrentPosition.y * mPositionExtent.y) * 1.0f,
155                     (relCurrentPosition.x * mPositionExtent.y + relCurrentPosition.y * mPositionExtent.x) * 1.0f,
156                     0.0f);
157
158     if(position.x>0.0f)
159     {
160       extent.x = mMaxExtent - extent.x; // Flip for right.
161     }
162     if(position.y>0.0f)
163     {
164       extent.y = mMaxExtent - extent.y; // Flip for bottom.
165     }
166
167     position.x = RampFunction(position.x, mOffsetExtent.x + extent.x);
168     position.y = RampFunction(position.y, mOffsetExtent.y + extent.y);
169
170     float f = mScaleExtent + cos(position.x * Math::PI_2) * cos(position.y * Math::PI_2) * (1.0f - mScaleExtent);
171
172     return currentScale * f;
173   }
174
175   const Vector2 mPositionExtent;                                ///< Determines how much of the Actor's X and Y position affects exponent value.
176   const Vector2 mOffsetExtent;                                  ///< Offset for exponent value.
177   const float mMaxExtent;                                       ///< Maximum possible extent (mOffsetExtent.x + mOffsetExtent.y)
178   const float mPositionScale;                                   ///< Position scaling factor (spreads out pages, to avoid overlap)
179   const float mScaleExtent;                                     ///< Scale factor when page is at furthest from
180 };
181
182 /**
183  * ScrollDepthPositionConstraint
184  *
185  * Position constraint adjusts the position of the Actors
186  * based on their parent page's position relative to the middle of the screen.
187  * When at middle of the screen the position is not altered.
188  * As the page is moved away from the middle, Actors move away but at
189  * different rates defined by the RampFunction(x, f).
190  * All Actors eventually arrive at their destination at the same time.
191  */
192 struct ScrollDepthPositionConstraint
193 {
194   /**
195    * @param [in] positionExtent Controls how much Actor's X and Y
196    * position affects their alpha function's exponent value
197    * @param [in] offsetExtent exponent offset for X and Y scrolling
198    * axes.
199    * @param [in] positionScale Changes the amount the page as a whole
200    * moves by.
201    */
202   ScrollDepthPositionConstraint( Vector2 positionExtent = Vector2(0.5f, 1.0f),
203                                  Vector2 offsetExtent = Vector2(1.0f, 1.0f),
204                                  float positionScale = 1.5f )
205   : mPositionExtent(positionExtent),
206     mOffsetExtent(offsetExtent),
207     mMaxExtent(positionExtent.x + positionExtent.y),
208     mPositionScale(positionScale)
209   {
210   }
211
212   /**
213    * @param[in] current The current position
214    * @param[in] pagePositionProperty The page's position.
215    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
216    * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
217    * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
218    * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
219    * @param[in] scrollWrap Whether scroll wrap has been enabled or not (SCROLL_WRAP_PROPERTY_NAME)
220    * @return The new position of this Actor.
221    */
222   Vector3 operator()(const Vector3& currentPosition,
223                      const PropertyInput& pagePositionProperty,
224                      const PropertyInput& scrollPositionProperty,
225                      const PropertyInput& scrollPositionMin,
226                      const PropertyInput& scrollPositionMax,
227                      const PropertyInput& pageSizeProperty,
228                      const PropertyInput& scrollWrap)
229   {
230     const Vector3& pagePosition = pagePositionProperty.GetVector3();
231     const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
232
233     // Get position of page.
234     Vector3 position = pagePosition + scrollPosition;
235
236     // short circuit: for orthognal view.
237     if( (fabsf(position.x) < Math::MACHINE_EPSILON_1) && (fabsf(position.y) < Math::MACHINE_EPSILON_1) )
238     {
239       return currentPosition + scrollPosition;
240     }
241
242     const Vector3& pageSize = pageSizeProperty.GetVector3();
243     bool wrap = scrollWrap.GetBoolean();
244
245     if(wrap)
246     {
247       const Vector3& min = scrollPositionMin.GetVector3();
248       const Vector3& max = scrollPositionMax.GetVector3();
249
250       if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
251       {
252         // WRAP X (based on the position of the right side)
253         position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
254       }
255
256       if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
257       {
258         // WRAP Y (based on the position of the bottom side)
259         position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
260       }
261     }
262
263     // short circuit: for pages outside of view.
264     if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
265     {
266       // position actors at: scrollposition (Property) + pagePosition (Parent) + current (this)
267       // they will be invisible so doesn't have to be precise, just away from stage.
268       return currentPosition + scrollPosition;
269     }
270
271     // Calculate position /////////////////////////////////////////////////////
272
273     position.x /= pageSize.x;
274     position.y /= pageSize.y;
275
276     position *= mPositionScale;
277
278     Vector3 finalPosition(currentPosition - pagePosition);
279
280     Vector3 relCurrentPosition = currentPosition;
281     relCurrentPosition.x = relCurrentPosition.x / pageSize.x + 0.5f;
282     relCurrentPosition.y = relCurrentPosition.y / pageSize.y + 0.5f;
283
284     Vector3 extent( (relCurrentPosition.x * mPositionExtent.x + relCurrentPosition.y * mPositionExtent.y) * 1.0f,
285                    (relCurrentPosition.x * mPositionExtent.y + relCurrentPosition.y * mPositionExtent.x) * 1.0f,
286                    0.0f);
287
288     if(position.x>0.0f)
289     {
290       extent.x = mMaxExtent - extent.x; // Flip for right.
291     }
292     if(position.y>0.0f)
293     {
294       extent.y = mMaxExtent - extent.y; // Flip for bottom.
295     }
296
297     position.x = RampFunction(position.x, mOffsetExtent.x + extent.x);
298     position.y = RampFunction(position.y, mOffsetExtent.y + extent.y);
299
300     finalPosition += pageSize * position;
301
302     return finalPosition;
303   }
304
305   const Vector2 mPositionExtent;                                ///< Determines how much of the Actor's X and Y position affects exponent value.
306   const Vector2 mOffsetExtent;                                  ///< Offset for exponent value.
307   const float mMaxExtent;                                       ///< Maximum possible extent (mOffsetExtent.x + mOffsetExtent.y)
308   const float mPositionScale;                                   ///< Position scaling factor (spreads out pages, to avoid overlap)
309 };
310
311 /**
312  * Applies the scroll depth constraints to the child actor
313  *
314  * @param[in] scrollView The ScrollView containing the pages.
315  * @param[in] child The child to be affected with the 3D Effect.
316  * @param[in] positionExtent Controls how much Actor's X and Y
317  * position affects their alpha function's exponent value
318  * @param[in] offsetExtent exponent offset for X and Y scrolling
319  * axes.
320  * @param[in] positionScale Changes the amount the page as a whole
321  * moves by.
322  * @param[in] scaleExtent Scale factor to reach when page is one whole
323  * page away from screen.
324  */
325 void ApplyScrollDepthConstraints(Toolkit::ScrollView scrollView,
326                                  Actor child,
327                                  const Vector2& positionExtent,
328                                  const Vector2& offsetExtent,
329                                  float positionScale,
330                                  float scaleExtent)
331 {
332   // Scale Constraint
333   Constraint constraint = Constraint::New<Vector3>( Actor::SCALE,
334                                          LocalSource(Actor::POSITION),
335                                          ParentSource(Actor::POSITION),
336                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
337                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
338                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
339                                          Source(scrollView, Actor::SIZE ),
340                                          ScrollDepthScaleConstraint( positionExtent, offsetExtent, positionScale, scaleExtent ) );
341   constraint.SetRemoveAction( Constraint::Discard );
342   child.ApplyConstraint( constraint );
343
344   // Position Constraint (apply last as other constraints use Actor::POSITION as a function input)
345   constraint = Constraint::New<Vector3>( Actor::POSITION,
346                                          ParentSource(Actor::POSITION),
347                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
348                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
349                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
350                                          Source(scrollView, Actor::SIZE ),
351                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_WRAP_PROPERTY_NAME ) ),
352                                          ScrollDepthPositionConstraint( positionExtent, offsetExtent, positionScale ) );
353
354   constraint.SetRemoveAction( Constraint::Discard );
355   child.ApplyConstraint( constraint );
356 }
357
358 } // unnamed namespace
359
360 namespace Dali
361 {
362
363 namespace Toolkit
364 {
365
366 namespace Internal
367 {
368
369 ScrollViewDepthEffect::ScrollViewDepthEffect()
370 {
371
372 }
373
374 ScrollViewDepthEffect::~ScrollViewDepthEffect()
375 {
376 }
377
378 void ScrollViewDepthEffect::ApplyToActor(Actor child,
379                                          const Vector2& positionExtent,
380                                          const Vector2& offsetExtent,
381                                          float positionScale,
382                                          float scaleExtent)
383 {
384   ApplyScrollDepthConstraints( GetScrollView(), child, positionExtent, offsetExtent, positionScale, scaleExtent );
385 }
386
387 void ScrollViewDepthEffect::OnAttach(Toolkit::ScrollView& scrollView)
388 {
389 }
390
391 void ScrollViewDepthEffect::OnDetach(Toolkit::ScrollView& scrollView)
392 {
393 }
394
395 } // namespace Internal
396
397 } // namespace Toolkit
398
399 } // namespace Dali