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