2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/public-api/animation/constraint.h>
20 #include <dali/public-api/object/property-input.h>
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-depth-effect-impl.h>
28 namespace // unnamed namespace
31 // constraints ////////////////////////////////////////////////////////////////
34 * Ramp equation is a variable easing equation
35 * of the form f(x) = |x|^y * x / |x|
37 * An exponent (y) of 1 will result in a fast (linear graph)
38 * Increasing the exponent will increase the Ease In
40 * @param[in] x mantissa (value from -1.0f to 1.0f)
41 * @param[in] y exponent (+ve value)
42 * @return The signed progress value from -1.0f to 1.0f
44 inline float RampFunction(float x, float y)
48 return -powf(fabsf(x), y);
51 return powf(fabsf(x), y);
55 * ScrollDepthScaleConstraint
57 * Scale constraint adjusts the scale of the Actors
58 * based on their parent page's position relative to the middle of the screen.
59 * When at middle of the screen the scale is not altered.
60 * As the page is moved away from the middle, Actors shrink in scale but at
61 * different rates defined by the RampFunction(x, f).
62 * All Actors eventually shrink to the same amount once at their destination.
64 struct ScrollDepthScaleConstraint
67 * The scaling constraint uses the amount the actors
68 * have moved in position to determine scaling extent.
69 * So essentially very similar calculations are used here.
71 * @param[in] positionExtent Controls how much Actor's X and Y
72 * position affects their alpha function's exponent value
73 * @param[in] offsetExtent exponent offset for X and Y scrolling
75 * @param[in] positionScale Changes the amount the page as a whole
77 * @param[in] scaleExtent Scale factor to reach when page is one whole
78 * page away from screen.
80 ScrollDepthScaleConstraint( Vector2 positionExtent = Vector2(0.5f, 1.0f),
81 Vector2 offsetExtent = Vector2(1.0f, 1.0f),
82 float positionScale = 1.5f,
83 float scaleExtent = 0.5f)
84 : mPositionExtent(positionExtent),
85 mOffsetExtent(offsetExtent),
86 mMaxExtent(positionExtent.x + positionExtent.y),
87 mPositionScale(positionScale),
88 mScaleExtent(scaleExtent)
93 * @param[in,out] current The current scale
94 * @param[in] inputs Contains:
95 * The page's position.
96 * The scroll-view's position property (SCROLL_POSITION)
97 * The minimum extent of this scroll domain. (SCROLL_POSITION_MIN)
98 * The maximum extent of this scroll domain. (SCROLL_POSITION_MIN)
99 * The size of the page. (scrollView SIZE)
100 * Whether scroll wrap has been enabled or not (SCROLL_WRAP)
101 * @return The new scale of this Actor.
103 void operator()( Vector3& currentScale, const PropertyInputContainer& inputs )
105 const Vector3& currentPosition = inputs[0]->GetVector3();
106 const Vector3& pagePosition = inputs[1]->GetVector3();
107 const Vector2& scrollPosition = inputs[2]->GetVector2();
109 // Get position of page.
110 Vector2 position = pagePosition.GetVectorXY() + scrollPosition;
112 // short circuit: for orthognal view.
113 if( (fabsf(position.x) < Math::MACHINE_EPSILON_1) && (fabsf(position.y) < Math::MACHINE_EPSILON_1) )
118 const Vector3& pageSize = inputs[5]->GetVector3();
120 // Don't have enough parameters, to provide Wrap mode (need a way of having 'uniforms' instead of scrollWrap.GetBoolean())
122 const Vector2& min = inputs[3]->GetVector2();
123 const Vector2& max = inputs[4]->GetVector2();
125 if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
127 // WRAP X (based on the position of the right side)
128 position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
131 if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
133 // WRAP Y (based on the position of the bottom side)
134 position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
137 // short circuit: for pages outside of view.
138 if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
143 // Calculate scale ////////////////////////////////////////////////////////
145 position.x /= pageSize.x;
146 position.y /= pageSize.y;
148 position *= mPositionScale;
150 Vector3 relCurrentPosition = currentPosition;
151 relCurrentPosition.x = relCurrentPosition.x / pageSize.x + 0.5f;
152 relCurrentPosition.y = relCurrentPosition.y / pageSize.y + 0.5f;
154 Vector3 extent( (relCurrentPosition.x * mPositionExtent.x + relCurrentPosition.y * mPositionExtent.y) * 1.0f,
155 (relCurrentPosition.x * mPositionExtent.y + relCurrentPosition.y * mPositionExtent.x) * 1.0f,
160 extent.x = mMaxExtent - extent.x; // Flip for right.
164 extent.y = mMaxExtent - extent.y; // Flip for bottom.
167 position.x = RampFunction(position.x, mOffsetExtent.x + extent.x);
168 position.y = RampFunction(position.y, mOffsetExtent.y + extent.y);
170 float f = mScaleExtent + cos(position.x * Math::PI_2) * cos(position.y * Math::PI_2) * (1.0f - mScaleExtent);
175 const Vector2 mPositionExtent; ///< Determines how much of the Actor's X and Y position affects exponent value.
176 const Vector2 mOffsetExtent; ///< Offset for exponent value.
177 const float mMaxExtent; ///< Maximum possible extent (mOffsetExtent.x + mOffsetExtent.y)
178 const float mPositionScale; ///< Position scaling factor (spreads out pages, to avoid overlap)
179 const float mScaleExtent; ///< Scale factor when page is at furthest from
183 * ScrollDepthPositionConstraint
185 * Position constraint adjusts the position of the Actors
186 * based on their parent page's position relative to the middle of the screen.
187 * When at middle of the screen the position is not altered.
188 * As the page is moved away from the middle, Actors move away but at
189 * different rates defined by the RampFunction(x, f).
190 * All Actors eventually arrive at their destination at the same time.
192 struct ScrollDepthPositionConstraint
195 * @param [in] positionExtent Controls how much Actor's X and Y
196 * position affects their alpha function's exponent value
197 * @param [in] offsetExtent exponent offset for X and Y scrolling
199 * @param [in] positionScale Changes the amount the page as a whole
202 ScrollDepthPositionConstraint( Vector2 positionExtent = Vector2(0.5f, 1.0f),
203 Vector2 offsetExtent = Vector2(1.0f, 1.0f),
204 float positionScale = 1.5f )
205 : mPositionExtent(positionExtent),
206 mOffsetExtent(offsetExtent),
207 mMaxExtent(positionExtent.x + positionExtent.y),
208 mPositionScale(positionScale)
213 * @param[in,out] current The current position
214 * @param[in] inputs Contains:
215 * The page's position.
216 * The scroll-view's position property (SCROLL_POSITION)
217 * The minimum extent of this scroll domain. (SCROLL_POSITION_MIN)
218 * The maximum extent of this scroll domain. (SCROLL_POSITION_MIN)
219 * The size of the page. (scrollView SIZE)
220 * Whether scroll wrap has been enabled or not (SCROLL_WRAP)
221 * @return The new position of this Actor.
223 void operator()( Vector3& currentPosition, const PropertyInputContainer& inputs )
225 const Vector3& pagePosition = inputs[0]->GetVector3();
226 const Vector2& scrollPosition = inputs[1]->GetVector2();
228 // Get position of page.
229 Vector2 position = pagePosition.GetVectorXY() + scrollPosition;
231 // short circuit: for orthognal view.
232 if( (fabsf(position.x) < Math::MACHINE_EPSILON_1) && (fabsf(position.y) < Math::MACHINE_EPSILON_1) )
234 currentPosition.GetVectorXY() += scrollPosition;
238 const Vector3& pageSize = inputs[4]->GetVector3();
239 bool wrap = inputs[5]->GetBoolean();
243 const Vector2& min = inputs[2]->GetVector2();
244 const Vector2& max = inputs[3]->GetVector2();
246 if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
248 // WRAP X (based on the position of the right side)
249 position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
252 if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
254 // WRAP Y (based on the position of the bottom side)
255 position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
259 // short circuit: for pages outside of view.
260 if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
262 // position actors at: scrollposition (Property) + pagePosition (Parent) + current (this)
263 // they will be invisible so doesn't have to be precise, just away from stage.
264 currentPosition.GetVectorXY() += scrollPosition;
268 // Calculate position /////////////////////////////////////////////////////
270 position.x /= pageSize.x;
271 position.y /= pageSize.y;
273 position *= mPositionScale;
275 Vector3 relCurrentPosition = currentPosition;
276 relCurrentPosition.x = relCurrentPosition.x / pageSize.x + 0.5f;
277 relCurrentPosition.y = relCurrentPosition.y / pageSize.y + 0.5f;
279 Vector3 extent( (relCurrentPosition.x * mPositionExtent.x + relCurrentPosition.y * mPositionExtent.y) * 1.0f,
280 (relCurrentPosition.x * mPositionExtent.y + relCurrentPosition.y * mPositionExtent.x) * 1.0f,
285 extent.x = mMaxExtent - extent.x; // Flip for right.
289 extent.y = mMaxExtent - extent.y; // Flip for bottom.
292 position.x = RampFunction(position.x, mOffsetExtent.x + extent.x);
293 position.y = RampFunction(position.y, mOffsetExtent.y + extent.y);
295 currentPosition -= pagePosition;
296 currentPosition += pageSize * Vector3(position);
299 const Vector2 mPositionExtent; ///< Determines how much of the Actor's X and Y position affects exponent value.
300 const Vector2 mOffsetExtent; ///< Offset for exponent value.
301 const float mMaxExtent; ///< Maximum possible extent (mOffsetExtent.x + mOffsetExtent.y)
302 const float mPositionScale; ///< Position scaling factor (spreads out pages, to avoid overlap)
306 * Applies the scroll depth constraints to the child actor
308 * @param[in] scrollView The ScrollView containing the pages.
309 * @param[in] child The child to be affected with the 3D Effect.
310 * @param[in] positionExtent Controls how much Actor's X and Y
311 * position affects their alpha function's exponent value
312 * @param[in] offsetExtent exponent offset for X and Y scrolling
314 * @param[in] positionScale Changes the amount the page as a whole
316 * @param[in] scaleExtent Scale factor to reach when page is one whole
317 * page away from screen.
319 void ApplyScrollDepthConstraints(Toolkit::ScrollView scrollView,
321 const Vector2& positionExtent,
322 const Vector2& offsetExtent,
327 Constraint constraint = Constraint::New<Vector3>( child, Actor::Property::SCALE, ScrollDepthScaleConstraint( positionExtent, offsetExtent, positionScale, scaleExtent ) );
328 constraint.AddSource( LocalSource( Actor::Property::POSITION ) );
329 constraint.AddSource( ParentSource( Actor::Property::POSITION ) );
330 constraint.AddSource( Source( scrollView, Toolkit::ScrollView::Property::SCROLL_POSITION ) );
331 constraint.AddSource( Source( scrollView, Toolkit::Scrollable::Property::SCROLL_POSITION_MIN ) );
332 constraint.AddSource( Source( scrollView, Toolkit::Scrollable::Property::SCROLL_POSITION_MAX ) );
333 constraint.AddSource( Source( scrollView, Actor::Property::SIZE ) );
334 constraint.SetRemoveAction( Constraint::Discard );
337 // Position Constraint (apply last as other constraints use Actor::POSITION as a function input)
338 constraint = Constraint::New<Vector3>( child, Actor::Property::POSITION, ScrollDepthPositionConstraint( positionExtent, offsetExtent, positionScale ) );
339 constraint.AddSource( ParentSource(Actor::Property::POSITION) );
340 constraint.AddSource( Source(scrollView, Toolkit::ScrollView::Property::SCROLL_POSITION ) );
341 constraint.AddSource( Source(scrollView, Toolkit::Scrollable::Property::SCROLL_POSITION_MIN ) );
342 constraint.AddSource( Source(scrollView, Toolkit::Scrollable::Property::SCROLL_POSITION_MAX ) );
343 constraint.AddSource( Source(scrollView, Actor::Property::SIZE ) );
344 constraint.AddSource( Source(scrollView, Toolkit::ScrollView::Property::WRAP ) );
345 constraint.SetRemoveAction( Constraint::Discard );
349 } // unnamed namespace
360 ScrollViewDepthEffect::ScrollViewDepthEffect()
365 ScrollViewDepthEffect::~ScrollViewDepthEffect()
369 void ScrollViewDepthEffect::ApplyToActor(Actor child,
370 const Vector2& positionExtent,
371 const Vector2& offsetExtent,
375 ApplyScrollDepthConstraints( GetScrollView(), child, positionExtent, offsetExtent, positionScale, scaleExtent );
378 void ScrollViewDepthEffect::OnAttach(Toolkit::ScrollView& scrollView)
382 void ScrollViewDepthEffect::OnDetach(Toolkit::ScrollView& scrollView)
386 } // namespace Internal
388 } // namespace Toolkit