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