Merge base & optional
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scrollable / scroll-view / scroll-view-page-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 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-page-cube-effect-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <boost/bind.hpp>
23
24 // INTERNAL INCLUDES
25 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-helper-functions.h>
26
27 namespace Dali
28 {
29
30 namespace Toolkit
31 {
32
33 namespace Internal
34 {
35
36 namespace // unnamed namespace
37 {
38
39 using namespace ScrollViewHelperFunctions;
40
41 /**
42  * ScrollPageCubeEffectInfo
43  *
44  * Rotate constraint: adjusts the angle of the page based on its position relative to the middle of
45  * the screen.
46  * When at middle of screen Angles on X and Y Axes is 0.
47  * When one screen away from the middle Angle is 90 degrees (pi/2)
48  *
49  * Color constraint: adjusts the alpha of the page based on their parent page's position relative
50  * to the middle of the screen.
51  * When at middle of screen Alpha is 100% opacity.
52  * When outside the viewable area, the opacity is 0%.
53  *
54  * Position constraint: adjusts the position of the page based on their parent page's position
55  * relative to the middle of the screen.
56  * When at middle of the screen the position is not altered.
57  * When one screen away from middle the position is rotated as per expected in a 3D inner cube.
58  */
59 class ScrollPageCubeEffectInfo
60 {
61 public:
62
63   ScrollPageCubeEffectInfo( const Vector2& angleSwing )
64   : mAngleSwing(angleSwing)
65   {
66   }
67
68   /**
69    * @param[in] current The current orientation of this Actor
70    * @param[in] pagePositionProperty The page's position.
71    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
72    * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
73    * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
74    * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
75    * @param[in] scrollWrap Whether scroll wrap has been enabled or not (SCROLL_WRAP_PROPERTY_NAME)
76    * @return The new orientation of this Actor.
77    */
78   Quaternion RotationConstraint(const Quaternion& current,
79                                 const PropertyInput& pagePositionProperty,
80                                 const PropertyInput& scrollPositionProperty,
81                                 const PropertyInput& scrollPositionMin,
82                                 const PropertyInput& scrollPositionMax,
83                                 const PropertyInput& pageSizeProperty,
84                                 const PropertyInput& scrollWrap)
85   {
86     const Vector3& pagePosition = pagePositionProperty.GetVector3();
87     const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
88
89     // Get position of page.
90     Vector3 position = pagePosition + scrollPosition;
91
92     // short circuit: if we're looking straight on at the page.
93     if( IsStraightOnView( position ) )
94     {
95       return current;
96     }
97
98     const Vector3& pageSize = pageSizeProperty.GetVector3();
99
100     if( scrollWrap.GetBoolean() )
101     {
102       WrapPositionWithinDomain( position, pageSize, scrollPositionMin.GetVector3(), scrollPositionMax.GetVector3() );
103     }
104
105     // short circuit: for pages outside of view.
106     if( IsOutsideView( position, pageSize ) )
107     {
108       return current;
109     }
110
111     // Our target is a 90 degree (PI/2) rotation per page, so calculate the angle we should be rotate
112     // our page by calculating the amount we've moved as a fraction of the total size of the page.
113     Vector2 angle( position / pageSize * Dali::Math::PI_2 );
114
115     Quaternion rotation = Quaternion( -angle.x * mAngleSwing.x, Vector3::YAXIS ) *
116                           Quaternion(  angle.y * mAngleSwing.y, Vector3::XAXIS ) *
117                           current;
118
119     return rotation;
120   }
121
122   /**
123    * @param[in] current The current color of this Actor
124    * @param[in] pagePositionProperty The page's position.
125    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
126    * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
127    * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
128    * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
129    * @param[in] scrollWrap Whether scroll wrap has been enabled or not (SCROLL_WRAP_PROPERTY_NAME)
130    * @return The new color of this Actor.
131    */
132   Vector4 ColorConstraint(const Vector4& current,
133                           const PropertyInput& pagePositionProperty,
134                           const PropertyInput& scrollPositionProperty,
135                           const PropertyInput& scrollPositionMin,
136                           const PropertyInput& scrollPositionMax,
137                           const PropertyInput& pageSizeProperty,
138                           const PropertyInput& scrollWrap)
139   {
140     const Vector3& pagePosition = pagePositionProperty.GetVector3();
141     const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
142
143     // Get position of page.
144     Vector3 position = pagePosition + scrollPosition;
145
146     // short circuit: if we're looking straight on at the page.
147     if( IsStraightOnView( position ) )
148     {
149       return current;
150     }
151
152     const Vector3& pageSize = pageSizeProperty.GetVector3();
153
154     if( scrollWrap.GetBoolean() )
155     {
156       WrapPositionWithinDomain( position, pageSize, scrollPositionMin.GetVector3(), scrollPositionMax.GetVector3() );
157     }
158
159     // short circuit: for pages outside of view.
160     if( IsOutsideView( position, pageSize ) )
161     {
162       // note preserve color channels incase there is a shader/further constraint
163       // that wishes to do something with that information.
164       return Vector4(current.r, current.g, current.b, 0.0f);
165     }
166
167     // Calculate the distance of this page from our view and ensure it falls within the appropriate
168     // visual bounds.
169     // If it does not, then the opacity is set to 0.0f.
170     position.x /= pageSize.width;
171     position.y /= pageSize.height;
172     float distanceFactor = sqrt( position.x * position.x + position.y * position.y );
173
174     if ( distanceFactor > 1.0f )
175     {
176       return Vector4(current.r, current.g, current.b, 0.0f);
177     }
178
179     return current;
180   }
181
182   /**
183    * @param[in] current The current position
184    * @param[in] pagePositionProperty The page's position.
185    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
186    * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
187    * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
188    * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
189    * @param[in] scrollWrap Whether scroll wrap has been enabled or not (SCROLL_WRAP_PROPERTY_NAME)
190    * @return The new position of this Actor.
191    */
192   Vector3 PositionConstraint(const Vector3& current,
193                              const PropertyInput& pagePositionProperty,
194                              const PropertyInput& scrollPositionProperty,
195                              const PropertyInput& scrollPositionMin,
196                              const PropertyInput& scrollPositionMax,
197                              const PropertyInput& pageSizeProperty,
198                              const PropertyInput& scrollWrap)
199   {
200     const Vector3& pagePosition = pagePositionProperty.GetVector3();
201     const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
202
203     // Get position of page.
204     Vector3 position = pagePosition + scrollPosition;
205
206     // short circuit: if we're looking straight on at the page.
207     if( IsStraightOnView( position ) )
208     {
209       return current + scrollPosition;
210     }
211
212     const Vector3& pageSize = pageSizeProperty.GetVector3();
213
214     if( scrollWrap.GetBoolean() )
215     {
216       WrapPositionWithinDomain( position, pageSize, scrollPositionMin.GetVector3(), scrollPositionMax.GetVector3() );
217     }
218
219     // short circuit: for pages outside of view.
220     if( IsOutsideView( position, pageSize ) )
221     {
222       // position actors at: scrollposition (Property) + pagePosition (Parent) + current (this)
223       // they will be invisible so doesn't have to be precise, just away from stage.
224       return current + scrollPosition;
225     }
226
227     // Our target when scrolling is moving from the origin to the following points around a curve:
228     //  Right To Left: (-pageWidth, 0, pageWidth)
229     //  Left To Right: ( pageWidth, 0, pageWidth)
230     //  Down To Up:    ( 0, -pageHeight, pageWidth)
231     //  Up To Down:    ( 0,  pageHeight, pageWidth)
232
233     Vector2 angle( position / pageSize * Dali::Math::PI_2 );
234     Vector2 radius( pageSize * 0.5 );
235
236     position.x = radius.x * sin( angle.x );
237     position.y = radius.y * sin( angle.y );
238     position.z = ( radius.x - ( radius.x * cos( angle.x ) ) ) + ( radius.y - ( radius.y * cos( angle.y ) ) );
239
240     return position;
241   }
242
243   Vector2 mAngleSwing;                                    ///< Maximum amount in X and Y axes to rotate.
244 };
245
246 /**
247  * Helper: Applies the 3D scroll cube constraints to the child actor
248  *
249  * @param[in] scrollView The ScrollView containing the pages.
250  * @param[in] child The child to be affected with the 3D Effect.
251  * @param[in] info The effect info for the constraints
252  */
253 void ApplyScrollCubeConstraints(Toolkit::ScrollView scrollView,
254                                 Actor child,
255                                 ScrollPageCubeEffectInfo& info)
256 {
257   // Apply constraints to this actor //
258   Constraint constraint;
259   constraint = Constraint::New<Quaternion>( Actor::ROTATION,
260                                             LocalSource(Actor::POSITION),
261                                             Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_FINAL_PROPERTY_NAME ) ),
262                                             Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
263                                             Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
264                                             Source(scrollView, Actor::SIZE ),
265                                             Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_WRAP_PROPERTY_NAME ) ),
266                                             boost::bind( &ScrollPageCubeEffectInfo::RotationConstraint, info, _1, _2, _3, _4, _5, _6, _7) );
267
268   constraint.SetRemoveAction( Constraint::Discard );
269   child.ApplyConstraint( constraint );
270
271   constraint = Constraint::New<Vector4>( Actor::COLOR,
272                                          LocalSource(Actor::POSITION),
273                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_FINAL_PROPERTY_NAME ) ),
274                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
275                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
276                                          Source(scrollView, Actor::SIZE ),
277                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_WRAP_PROPERTY_NAME ) ),
278                                          boost::bind( &ScrollPageCubeEffectInfo::ColorConstraint, info, _1, _2, _3, _4, _5, _6, _7) );
279
280   constraint.SetRemoveAction( Constraint::Discard );
281   child.ApplyConstraint( constraint );
282
283   constraint = Constraint::New<Vector3>( Actor::POSITION,
284                                          LocalSource(Actor::POSITION),
285                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_FINAL_PROPERTY_NAME ) ),
286                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
287                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
288                                          Source(scrollView, Actor::SIZE ),
289                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_WRAP_PROPERTY_NAME ) ),
290                                          boost::bind( &ScrollPageCubeEffectInfo::PositionConstraint, info, _1, _2, _3, _4, _5, _6, _7) );
291
292   constraint.SetRemoveAction( Constraint::Discard );
293   child.ApplyConstraint( constraint );
294 }
295
296 } // unnamed namespace
297
298 ScrollViewPageCubeEffect::ScrollViewPageCubeEffect()
299 {
300
301 }
302
303 ScrollViewPageCubeEffect::~ScrollViewPageCubeEffect()
304 {
305 }
306
307 void ScrollViewPageCubeEffect::ApplyToPage( Actor page, const Vector2& angleSwing )
308 {
309   ScrollPageCubeEffectInfo info( angleSwing );
310
311   ApplyScrollCubeConstraints( GetScrollView(), page, info );
312 }
313
314 void ScrollViewPageCubeEffect::OnAttach(Toolkit::ScrollView& scrollView)
315 {
316 }
317
318 void ScrollViewPageCubeEffect::OnDetach(Toolkit::ScrollView& scrollView)
319 {
320 }
321
322 } // namespace Internal
323
324 } // namespace Toolkit
325
326 } // namespace Dali