Partial fix for homescreen panning issue
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / scrollable / scroll-view / scroll-view-cube-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 // EXTERNAL INCLUDES
18 #include <boost/bind.hpp>
19
20 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
21 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-cube-effect-impl.h>
22
23 using namespace Dali;
24
25 namespace // unnamed namespace
26 {
27
28 /**
29  * ScrollCubeEffectInfo
30  *
31  * Rotate constraint: adjusts the angle of the Actors
32  * based on their parent page's position relative to the middle of the screen.
33  * When at middle of screen Angles on X and Y Axes is 0.
34  * When one screen away from the middle Angle is 90 degrees (pi/2)
35  *
36  * Color constraint: adjusts the alpha of the Actors
37  * based on their parent page's position relative to the middle of the screen.
38  * When at middle of screen Alpha is 100% opacity.
39  * When one screen away from middle Alpha is at 0% opacity (invisble).
40  *
41  * Position constraint: adjusts the position of the Actors
42  * based on their parent page's position relative to the middle of the screen.
43  * When at middle of the screen the position is not altered.
44  * When one screen away from middle the position is rotated about it's origin + mAnchor
45  */
46 class ScrollCubeEffectInfo : public Dali::RefObject
47 {
48 public:
49
50   ScrollCubeEffectInfo(const Vector3& anchor,
51                        const Vector2& angleSwing,
52                        const Vector2& positionSwing)
53   : mAnchor(anchor),
54     mAngleSwing(angleSwing),
55     mPositionSwing(positionSwing)
56   {
57   }
58
59   /**
60    * @param[in] current The current orientation of this Actor
61    * @param[in] pagePositionProperty The page's position.
62    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
63    * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
64    * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
65    * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
66    * @param[in] scrollWrap Whether scroll wrap has been enabled or not (SCROLL_WRAP_PROPERTY_NAME)
67    * @return The new orientation of this Actor.
68    */
69   Quaternion RotationConstraint(const Quaternion& current,
70                                 const PropertyInput& pagePositionProperty,
71                                 const PropertyInput& scrollPositionProperty,
72                                 const PropertyInput& scrollPositionMin,
73                                 const PropertyInput& scrollPositionMax,
74                                 const PropertyInput& pageSizeProperty,
75                                 const PropertyInput& scrollWrap)
76   {
77     const Vector3& pagePosition = pagePositionProperty.GetVector3();
78     const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
79
80     // Get position of page.
81     Vector3 position = pagePosition + scrollPosition;
82
83     // short circuit: for orthognal view.
84     if( (fabsf(position.x) < Math::MACHINE_EPSILON_1) && (fabsf(position.y) < Math::MACHINE_EPSILON_1) )
85     {
86       return current;
87     }
88
89     const Vector3& pageSize = pageSizeProperty.GetVector3();
90     bool wrap = scrollWrap.GetBoolean();
91
92     if(wrap)
93     {
94       const Vector3& min = scrollPositionMin.GetVector3();
95       const Vector3& max = scrollPositionMax.GetVector3();
96
97       if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
98       {
99         // WRAP X (based on the position of the right side)
100         position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
101       }
102
103       if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
104       {
105         // WRAP Y (based on the position of the bottom side)
106         position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
107       }
108     }
109
110     // short circuit: for pages outside of view.
111     if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
112     {
113       return current;
114     }
115
116     position.x /= pageSize.x;
117     position.y /= pageSize.y;
118
119     Vector2 angle( Clamp(position.x, -1.0f,1.0f),
120                    Clamp(position.y, -1.0f,1.0f) );
121
122     Quaternion rotation = Quaternion(angle.x * mAngleSwing.x, Vector3::YAXIS) *
123                           Quaternion(-angle.y * mAngleSwing.y, Vector3::XAXIS) *
124                           current;
125
126     return rotation;
127   }
128
129   /**
130    * @param[in] current The current color of this Actor
131    * @param[in] pagePositionProperty The page's position.
132    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
133    * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
134    * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
135    * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
136    * @param[in] scrollWrap Whether scroll wrap has been enabled or not (SCROLL_WRAP_PROPERTY_NAME)
137    * @return The new color of this Actor.
138    */
139   Vector4 ColorConstraint(const Vector4& current,
140                           const PropertyInput& pagePositionProperty,
141                           const PropertyInput& scrollPositionProperty,
142                           const PropertyInput& scrollPositionMin,
143                           const PropertyInput& scrollPositionMax,
144                           const PropertyInput& pageSizeProperty,
145                           const PropertyInput& scrollWrap)
146   {
147     const Vector3& pagePosition = pagePositionProperty.GetVector3();
148     const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
149
150     // Get position of page.
151     Vector3 position = pagePosition + scrollPosition;
152
153     // short circuit: for orthognal view.
154     if( (fabsf(position.x) < Math::MACHINE_EPSILON_1) && (fabsf(position.y) < Math::MACHINE_EPSILON_1) )
155     {
156       return current;
157     }
158
159     const Vector3& pageSize = pageSizeProperty.GetVector3();
160     bool wrap = scrollWrap.GetBoolean();
161
162     if(wrap)
163     {
164       const Vector3& min = scrollPositionMin.GetVector3();
165       const Vector3& max = scrollPositionMax.GetVector3();
166
167       if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
168       {
169         // WRAP X (based on the position of the right side)
170         position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
171       }
172
173       if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
174       {
175         // WRAP Y (based on the position of the bottom side)
176         position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
177       }
178     }
179
180     // short circuit: for pages outside of view.
181     if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
182     {
183       // note preserve color channels incase there is a shader/further constraint
184       // that wishes to do something with that information.
185       return Vector4(current.r, current.g, current.b, 0.0f);
186     }
187
188     position.x /= pageSize.x;
189     position.y /= pageSize.y;
190
191     Vector2 angle( Clamp(position.x, -1.0f,1.0f),
192                    Clamp(position.y, -1.0f,1.0f) );
193
194     float f = (1.0f - fabsf(angle.x)) * (1.0f - fabsf(angle.y));
195     f = f*f;
196
197     Vector4 color = current;
198     color.a *= f;
199
200     return color;
201   }
202
203   /**
204    * @param[in] current The current position
205    * @param[in] pagePositionProperty The page's position.
206    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
207    * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
208    * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
209    * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
210    * @param[in] scrollWrap Whether scroll wrap has been enabled or not (SCROLL_WRAP_PROPERTY_NAME)
211    * @return The new position of this Actor.
212    */
213   Vector3 PositionConstraint(const Vector3& current,
214                              const PropertyInput& pagePositionProperty,
215                              const PropertyInput& scrollPositionProperty,
216                              const PropertyInput& scrollPositionMin,
217                              const PropertyInput& scrollPositionMax,
218                              const PropertyInput& pageSizeProperty,
219                              const PropertyInput& scrollWrap)
220   {
221     const Vector3& pagePosition = pagePositionProperty.GetVector3();
222     const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
223
224     // Get position of page.
225     Vector3 relativePosition = pagePosition + scrollPosition;
226
227     // short circuit: for orthognal view.
228     if( (fabsf(relativePosition.x) < Math::MACHINE_EPSILON_1) && (fabsf(relativePosition.y) < Math::MACHINE_EPSILON_1) )
229     {
230       return current + scrollPosition;
231     }
232
233     const Vector3& pageSize = pageSizeProperty.GetVector3();
234     bool wrap = scrollWrap.GetBoolean();
235
236     if(wrap)
237     {
238       const Vector3& min = scrollPositionMin.GetVector3();
239       const Vector3& max = scrollPositionMax.GetVector3();
240
241       if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
242       {
243         // WRAP X (based on the position of the right side)
244         relativePosition.x = WrapInDomain(relativePosition.x + pageSize.x, min.x, max.x) - pageSize.x;
245       }
246
247       if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
248       {
249         // WRAP Y (based on the position of the bottom side)
250         relativePosition.y = WrapInDomain(relativePosition.y + pageSize.y, min.y, max.y) - pageSize.y;
251       }
252     }
253
254     // short circuit: for pages outside of view.
255     if( (fabsf(relativePosition.x) >= pageSize.x) || (fabsf(relativePosition.y) >= pageSize.y) )
256     {
257       // position actors at: scrollposition (Property) + pagePosition (Parent) + current (this)
258       // they will be invisible so doesn't have to be precise, just away from stage.
259       return current + scrollPosition;
260     }
261
262     relativePosition.x /= pageSize.x;
263     relativePosition.y /= pageSize.y;
264     relativePosition.z = 0.0f;
265
266     Vector3 angle( Clamp(relativePosition.x, -1.0f,1.0f) * mAngleSwing.x,
267                    Clamp(relativePosition.y, -1.0f,1.0f) * mAngleSwing.y,
268                    0.0f);
269
270     // Rotate position (current) about point.
271     Vector3 position = current - mAnchor;
272     Quaternion rotatorY(angle.x, Vector3::YAXIS);
273     position = rotatorY.Rotate(position);
274     Quaternion rotatorX(-angle.y, Vector3::XAXIS);
275     position = rotatorX.Rotate(position);
276     position += mAnchor;
277     position += relativePosition * mPositionSwing;
278
279     return position - pagePosition;
280   }
281
282   Vector3 mAnchor;                                        ///< Anchor point where Actor should rotate about.
283   Vector2 mAngleSwing;                                    ///< Maximum amount in X and Y axes to rotate.
284   Vector3 mPositionSwing;                                 ///< Maximum amount in X and Y axes to alter position.
285 };
286
287 typedef IntrusivePtr<ScrollCubeEffectInfo> ScrollCubeEffectInfoPtr;
288
289 /**
290  * Helper: Applies the 3D scroll cube constraints to the child actor
291  *
292  * @param[in] scrollView The ScrollView containing the pages.
293  * @param[in] child The child to be affected with the 3D Effect.
294  * @param[in] info The effect info for the constraints
295  */
296 void ApplyScrollCubeConstraints(Toolkit::ScrollView scrollView,
297                                 Actor child,
298                                 Actor parentPage,
299                                 ScrollCubeEffectInfoPtr info)
300 {
301   // Apply constraints to this actor //
302   Constraint constraint;
303   constraint = Constraint::New<Quaternion>( Actor::ROTATION,
304                                          Source(parentPage, Actor::POSITION),
305                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_FINAL_PROPERTY_NAME ) ),
306                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
307                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
308                                          Source(scrollView, Actor::SIZE ),
309                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_WRAP_PROPERTY_NAME ) ),
310                                          boost::bind( &ScrollCubeEffectInfo::RotationConstraint, info, _1, _2, _3, _4, _5, _6, _7) );
311
312   constraint.SetRemoveAction( Constraint::Discard );
313   child.ApplyConstraint( constraint );
314
315   constraint = Constraint::New<Vector4>( Actor::COLOR,
316                                          Source(parentPage, Actor::POSITION),
317                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_FINAL_PROPERTY_NAME ) ),
318                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
319                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
320                                          Source(scrollView, Actor::SIZE ),
321                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_WRAP_PROPERTY_NAME ) ),
322                                          boost::bind( &ScrollCubeEffectInfo::ColorConstraint, info, _1, _2, _3, _4, _5, _6, _7) );
323
324   constraint.SetRemoveAction( Constraint::Discard );
325   child.ApplyConstraint( constraint );
326
327   constraint = Constraint::New<Vector3>( Actor::POSITION,
328                                          Source(parentPage, Actor::POSITION),
329                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_FINAL_PROPERTY_NAME ) ),
330                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
331                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
332                                          Source(scrollView, Actor::SIZE ),
333                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_WRAP_PROPERTY_NAME ) ),
334                                          boost::bind( &ScrollCubeEffectInfo::PositionConstraint, info, _1, _2, _3, _4, _5, _6, _7) );
335
336   constraint.SetRemoveAction( Constraint::Discard );
337   child.ApplyConstraint( constraint );
338 }
339
340 } // unnamed namespace
341
342 namespace Dali
343 {
344
345 namespace Toolkit
346 {
347
348 namespace Internal
349 {
350
351 ScrollViewCubeEffect::ScrollViewCubeEffect()
352 {
353
354 }
355
356 ScrollViewCubeEffect::~ScrollViewCubeEffect()
357 {
358 }
359
360 void ScrollViewCubeEffect::ApplyToActor(Actor child,
361                                         const Vector3& anchor,
362                                         const Vector2& angleSwing,
363                                         const Vector2& positionSwing)
364 {
365   ScrollCubeEffectInfoPtr info(new ScrollCubeEffectInfo(anchor, angleSwing, positionSwing));
366
367   ApplyScrollCubeConstraints( GetScrollView(), child, child.GetParent(), info );
368 }
369
370 void ScrollViewCubeEffect::ApplyToActor(Actor child,
371                                         Actor parentPage,
372                                         const Vector3& anchor,
373                                         const Vector2& angleSwing,
374                                         const Vector2& positionSwing)
375 {
376   ScrollCubeEffectInfoPtr info(new ScrollCubeEffectInfo(anchor, angleSwing, positionSwing));
377
378   ApplyScrollCubeConstraints( GetScrollView(), child, parentPage, info );
379 }
380
381 void ScrollViewCubeEffect::OnAttach(Toolkit::ScrollView& scrollView)
382 {
383 }
384
385 void ScrollViewCubeEffect::OnDetach(Toolkit::ScrollView& scrollView)
386 {
387 }
388
389 } // namespace Internal
390
391 } // namespace Toolkit
392
393 } // namespace Dali