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