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