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