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