f3966455bd32f0ac33f45804fd9e69c0a61aaa6e
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scrollable / scroll-view / scroll-view-carousel-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
21 // INTERNAL INCLUDES
22 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
23 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-carousel-effect-impl.h>
24
25 using namespace Dali;
26
27 namespace // unnamed namespace
28 {
29
30 /**
31  * Gets a property index. If the property doesn't already exist, then
32  * it will create the property.
33  * @param[in] handle The handle that owns or will own the property
34  * @param[in] name The name for this property
35  * @param[in] propertyValue The initial value for this property
36  * @return The property index for this property is returned.
37  */
38 Property::Index SafeRegisterProperty( Handle& handle, const std::string& name, Property::Value propertyValue )
39 {
40   Property::Index index = handle.GetPropertyIndex( name );
41
42   if(index == Property::INVALID_INDEX)
43   {
44     index = handle.RegisterProperty( name, propertyValue );
45   }
46
47   return index;
48 }
49
50 /**
51  * ScrollCarouselEffectInfo
52  *
53  * Visibility constraint: switches off the visibility when Actor
54  * is outside of bounds, for performance reasons.
55  *
56  * Rotate constraint: adjusts the angle of the Actors
57  * based on their position relative to the edges of the screen.
58  * When in the middle portion of the screen Angle does not change.
59  * When leaving the edge of the screen screen rotation changes.
60  *
61  * Position constraint: adjusts the position of the Actors
62  * based on their parent page's position relative to the edges of the screen.
63  * The position constraint compensates for the rotation which would otherwise
64  * move the Actor's edge visually away from the neighboring actor, as they rotate
65  * around their default anchor point.
66  */
67 class ScrollCarouselEffectInfo
68 {
69 public:
70
71   ScrollCarouselEffectInfo(const Vector2& angleSwing)
72   : mAngleSwing(angleSwing),
73     mCanvasMargin( 0.0f, 0.0f ),
74     mVisibilityThreshold( 1.0f, 1.0f )
75   {
76   }
77
78   /**
79    * @param[in] current The current visibility of this Actor
80    * @param[in] positionProperty The Actor's Position.
81    * @param[in] scaleProperty The Actor's Scale.
82    * @param[in] sizeProperty The Actor's Size
83    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
84    * @param[in] scrollSizeProperty The size of the scroll-view (scrollView SIZE)
85    * @return The new visibility of this Actor.
86    */
87   bool VisibilityConstraint(const bool& current,
88                                   const PropertyInput& positionProperty,
89                                   const PropertyInput& scaleProperty,
90                                   const PropertyInput& sizeProperty,
91                                   const PropertyInput& scrollPositionProperty,
92                                   const PropertyInput& scrollSizeProperty)
93   {
94     const Vector2& anchor(AnchorPoint::CENTER.GetVectorXY());
95     Vector2 position(positionProperty.GetVector3() + scrollPositionProperty.GetVector3());
96     Vector2 scaledSize(sizeProperty.GetVector3() * scaleProperty.GetVector3());
97
98     Vector2 domain(scrollSizeProperty.GetVector3());
99
100     position -= (anchor - mVisibilityThreshold) * scaledSize;
101     domain -= (Vector2::ONE - mVisibilityThreshold * 2.0f) * scaledSize;
102
103     return ( position.x >= 0 &&
104              position.x <= domain.x &&
105              position.y >= 0 &&
106              position.y <= domain.y );
107   }
108
109   /**
110    * @param[in] current The current orientation of this Actor
111    * @param[in] positionProperty The Actor's Position.
112    * @param[in] scaleProperty The Actor's Scale.
113    * @param[in] sizeProperty The Actor's Size
114    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
115    * @param[in] scrollSizeProperty The size of the scroll-view (scrollView SIZE)
116    * @param[in] activateProperty Activation value (0 - normal, 1.0 - full effect)
117    * @return The new orientation of this Actor.
118    */
119   Quaternion RotationConstraint(const Quaternion& current,
120                                 const PropertyInput& positionProperty,
121                                 const PropertyInput& scaleProperty,
122                                 const PropertyInput& sizeProperty,
123                                 const PropertyInput& scrollPositionProperty,
124                                 const PropertyInput& scrollSizeProperty,
125                                 const PropertyInput& activateProperty)
126   {
127     const float activate(activateProperty.GetFloat());
128
129     if(activate <= Math::MACHINE_EPSILON_0)
130     {
131       return current;
132     }
133
134     const Vector2& anchor(AnchorPoint::CENTER.GetVectorXY());
135     Vector2 position(positionProperty.GetVector3() + scrollPositionProperty.GetVector3());
136     Vector2 scaledSize(sizeProperty.GetVector3() * scaleProperty.GetVector3());
137     Vector2 domain(scrollSizeProperty.GetVector3());
138
139     position -= (anchor - mCanvasMargin) * scaledSize;
140     domain -= (Vector2::ONE - mCanvasMargin * 2.0f) * scaledSize;
141
142     Vector2 angle;
143
144     if( position.y < 0 )
145     {
146       angle.y = (-position.y / scaledSize.height) * mAngleSwing.y;
147     }
148     else if( position.y > domain.y )
149     {
150       angle.y = ((domain.y - position.y) / scaledSize.height) * mAngleSwing.y;
151     }
152
153     angle *= activate;
154
155     return Quaternion(-angle.x, Vector3::YAXIS) *
156            Quaternion(angle.y, Vector3::XAXIS) *
157            current;
158   }
159
160   /**
161    * @param[in] current The current position of this Actor
162    * @param[in] scaleProperty The Actor's Scale.
163    * @param[in] sizeProperty The Actor's Size
164    * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
165    * @param[in] scrollSizeProperty The size of the scroll-view (scrollView SIZE)
166    * @param[in] activateProperty Activation value (0 - normal, 1.0 - full effect)
167    * @return The new position of this Actor.
168    */
169   Vector3 PositionConstraint(const Vector3& current,
170                              const PropertyInput& scaleProperty,
171                              const PropertyInput& sizeProperty,
172                              const PropertyInput& scrollPositionProperty,
173                              const PropertyInput& scrollSizeProperty,
174                              const PropertyInput& activateProperty)
175   {
176     const float activate(activateProperty.GetFloat());
177     Vector3 position(current + scrollPositionProperty.GetVector3());
178
179     if(activate <= Math::MACHINE_EPSILON_0)
180     {
181       return position;
182     }
183
184     const Vector2& anchor(AnchorPoint::CENTER.GetVectorXY());
185     Vector2 scaledSize(sizeProperty.GetVector3() * scaleProperty.GetVector3());
186     Vector2 domain(scrollSizeProperty.GetVector3());
187
188     position.GetVectorXY() -= (anchor - mCanvasMargin) * scaledSize;
189     domain -= (Vector2::ONE - mCanvasMargin * 2.0f) * scaledSize;
190
191     Vector2 angle;
192
193     if(position.y < 0)
194     {
195       angle.y = (-position.y / scaledSize.height) * mAngleSwing.y * activate;
196       position.y += (1.0f - cosf(angle.y)) * scaledSize.height * 0.5f;
197       position.z -= sinf(angle.y) * scaledSize.height * 0.5f;
198     }
199     else if(position.y > domain.y)
200     {
201       angle.y = ((domain.y - position.y) / scaledSize.height) * mAngleSwing.y * activate;
202       position.y -= (1.0f - cosf(angle.y)) * scaledSize.height * 0.5f;
203       position.z -= sinf(-angle.y) * scaledSize.height * 0.5f;
204     }
205
206     position.GetVectorXY() += (anchor - mCanvasMargin) * scaledSize;
207
208     return position;
209   }
210
211   Vector2 mAngleSwing;                                    ///< Maximum amount in X and Y axes to rotate.
212   Vector2 mCanvasMargin;                                  ///< Margin around the canvas for when to start rotating
213   Vector2 mVisibilityThreshold;                           ///< Threshold for when to to switch off visibility of Actor (for performance)
214 };
215
216 /**
217  * Helper: Applies the 3D scroll carousel constraints to the child actor
218  *
219  * @param[in] scrollView The ScrollView containing the pages.
220  * @param[in] child The child to be affected with the 3D Effect.
221  * @param[in] info The effect info for the constraints
222  */
223 void ApplyScrollCarouselConstraints(Toolkit::ScrollView scrollView,
224                                     Actor child,
225                                     ScrollCarouselEffectInfo& info)
226 {
227   // Apply constraints to this actor //
228   Constraint constraint;
229
230   constraint = Constraint::New<bool>( Actor::VISIBLE,
231                                       LocalSource( Actor::POSITION ),
232                                       LocalSource( Actor::SCALE ),
233                                       LocalSource( Actor::SIZE ),
234                                       Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
235                                       Source(scrollView, Actor::SIZE ),
236                                       Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollViewCarouselEffect::EFFECT_ACTIVATE ) ),
237                                       boost::bind( &ScrollCarouselEffectInfo::VisibilityConstraint, info, _1, _2, _3, _4, _5, _6) );
238   constraint.SetRemoveAction( Constraint::Discard );
239   child.ApplyConstraint( constraint );
240
241   constraint = Constraint::New<Quaternion>( Actor::ROTATION,
242                                             LocalSource( Actor::POSITION ),
243                                             LocalSource( Actor::SCALE ),
244                                             LocalSource( Actor::SIZE ),
245                                             Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
246                                             Source(scrollView, Actor::SIZE ),
247                                             Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollViewCarouselEffect::EFFECT_ACTIVATE ) ),
248                                             boost::bind( &ScrollCarouselEffectInfo::RotationConstraint, info, _1, _2, _3, _4, _5, _6, _7) );
249   constraint.SetRemoveAction( Constraint::Discard );
250   child.ApplyConstraint( constraint );
251
252   constraint = Constraint::New<Vector3>( Actor::POSITION,
253                                          LocalSource( Actor::SCALE ),
254                                          LocalSource( Actor::SIZE ),
255                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
256                                          Source(scrollView, Actor::SIZE ),
257                                          Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollViewCarouselEffect::EFFECT_ACTIVATE ) ),
258                                          boost::bind( &ScrollCarouselEffectInfo::PositionConstraint, info, _1, _2, _3, _4, _5, _6) );
259
260   constraint.SetRemoveAction( Constraint::Discard );
261   child.ApplyConstraint( constraint );
262 }
263
264 } // unnamed namespace
265
266 namespace Dali
267 {
268
269 namespace Toolkit
270 {
271
272 namespace Internal
273 {
274
275 ScrollViewCarouselEffect::ScrollViewCarouselEffect()
276 : mPropertyActivate(Property::INVALID_INDEX)
277 {
278 }
279
280 ScrollViewCarouselEffect::~ScrollViewCarouselEffect()
281 {
282 }
283
284 void ScrollViewCarouselEffect::ApplyToActor(Actor child, const Vector2& angleSwing)
285 {
286   ScrollCarouselEffectInfo info( angleSwing );
287
288   ApplyScrollCarouselConstraints( GetScrollView(), child, info );
289 }
290
291 void ScrollViewCarouselEffect::OnAttach(Toolkit::ScrollView& scrollView)
292 {
293   if(mPropertyActivate == Property::INVALID_INDEX)
294   {
295     mPropertyActivate = SafeRegisterProperty( scrollView, Toolkit::ScrollViewCarouselEffect::EFFECT_ACTIVATE, 1.0f );
296   }
297 }
298
299 void ScrollViewCarouselEffect::OnDetach(Toolkit::ScrollView& scrollView)
300 {
301 }
302
303 } // namespace Internal
304
305 } // namespace Toolkit
306
307 } // namespace Dali