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