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