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