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/active-constraint.h>
20 #include <dali/public-api/animation/constraint.h>
21 #include <dali/public-api/object/property-input.h>
24 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
25 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-depth-effect-impl.h>
29 namespace // unnamed namespace
32 // constraints ////////////////////////////////////////////////////////////////
35 * Ramp equation is a variable easing equation
36 * of the form f(x) = |x|^y * x / |x|
38 * An exponent (y) of 1 will result in a fast (linear graph)
39 * Increasing the exponent will increase the Ease In
41 * @param[in] x mantissa (value from -1.0f to 1.0f)
42 * @param[in] y exponent (+ve value)
43 * @return The signed progress value from -1.0f to 1.0f
45 inline float RampFunction(float x, float y)
49 return -powf(fabsf(x), y);
52 return powf(fabsf(x), y);
56 * ScrollDepthScaleConstraint
58 * Scale constraint adjusts the scale of the Actors
59 * based on their parent page's position relative to the middle of the screen.
60 * When at middle of the screen the scale is not altered.
61 * As the page is moved away from the middle, Actors shrink in scale but at
62 * different rates defined by the RampFunction(x, f).
63 * All Actors eventually shrink to the same amount once at their destination.
65 struct ScrollDepthScaleConstraint
68 * The scaling constraint uses the amount the actors
69 * have moved in position to determine scaling extent.
70 * So essentially very similar calculations are used here.
72 * @param[in] positionExtent Controls how much Actor's X and Y
73 * position affects their alpha function's exponent value
74 * @param[in] offsetExtent exponent offset for X and Y scrolling
76 * @param[in] positionScale Changes the amount the page as a whole
78 * @param[in] scaleExtent Scale factor to reach when page is one whole
79 * page away from screen.
81 ScrollDepthScaleConstraint( Vector2 positionExtent = Vector2(0.5f, 1.0f),
82 Vector2 offsetExtent = Vector2(1.0f, 1.0f),
83 float positionScale = 1.5f,
84 float scaleExtent = 0.5f)
85 : mPositionExtent(positionExtent),
86 mOffsetExtent(offsetExtent),
87 mMaxExtent(positionExtent.x + positionExtent.y),
88 mPositionScale(positionScale),
89 mScaleExtent(scaleExtent)
94 * @param[in] current The current scale
95 * @param[in] pagePositionProperty The page's position.
96 * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
97 * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
98 * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
99 * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
100 * @param[in] scrollWrap Whether scroll wrap has been enabled or not (SCROLL_WRAP_PROPERTY_NAME)
101 * @return The new scale of this Actor.
103 Vector3 operator()(const Vector3& currentScale,
104 const PropertyInput& currentPositionProperty,
105 const PropertyInput& pagePositionProperty,
106 const PropertyInput& scrollPositionProperty,
107 const PropertyInput& scrollPositionMin,
108 const PropertyInput& scrollPositionMax,
109 const PropertyInput& pageSizeProperty)
111 const Vector3& currentPosition = currentPositionProperty.GetVector3();
112 const Vector3& pagePosition = pagePositionProperty.GetVector3();
113 const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
115 // Get position of page.
116 Vector3 position = pagePosition + scrollPosition;
118 // short circuit: for orthognal view.
119 if( (fabsf(position.x) < Math::MACHINE_EPSILON_1) && (fabsf(position.y) < Math::MACHINE_EPSILON_1) )
124 const Vector3& pageSize = pageSizeProperty.GetVector3();
126 // Don't have enough parameters, to provide Wrap mode (need a way of having 'uniforms' instead of scrollWrap.GetBoolean())
128 const Vector3& min = scrollPositionMin.GetVector3();
129 const Vector3& max = scrollPositionMax.GetVector3();
131 if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
133 // WRAP X (based on the position of the right side)
134 position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
137 if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
139 // WRAP Y (based on the position of the bottom side)
140 position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
143 // short circuit: for pages outside of view.
144 if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
149 // Calculate scale ////////////////////////////////////////////////////////
151 position.x /= pageSize.x;
152 position.y /= pageSize.y;
154 position *= mPositionScale;
156 Vector3 relCurrentPosition = currentPosition;
157 relCurrentPosition.x = relCurrentPosition.x / pageSize.x + 0.5f;
158 relCurrentPosition.y = relCurrentPosition.y / pageSize.y + 0.5f;
160 Vector3 extent( (relCurrentPosition.x * mPositionExtent.x + relCurrentPosition.y * mPositionExtent.y) * 1.0f,
161 (relCurrentPosition.x * mPositionExtent.y + relCurrentPosition.y * mPositionExtent.x) * 1.0f,
166 extent.x = mMaxExtent - extent.x; // Flip for right.
170 extent.y = mMaxExtent - extent.y; // Flip for bottom.
173 position.x = RampFunction(position.x, mOffsetExtent.x + extent.x);
174 position.y = RampFunction(position.y, mOffsetExtent.y + extent.y);
176 float f = mScaleExtent + cos(position.x * Math::PI_2) * cos(position.y * Math::PI_2) * (1.0f - mScaleExtent);
178 return currentScale * f;
181 const Vector2 mPositionExtent; ///< Determines how much of the Actor's X and Y position affects exponent value.
182 const Vector2 mOffsetExtent; ///< Offset for exponent value.
183 const float mMaxExtent; ///< Maximum possible extent (mOffsetExtent.x + mOffsetExtent.y)
184 const float mPositionScale; ///< Position scaling factor (spreads out pages, to avoid overlap)
185 const float mScaleExtent; ///< Scale factor when page is at furthest from
189 * ScrollDepthPositionConstraint
191 * Position constraint adjusts the position of the Actors
192 * based on their parent page's position relative to the middle of the screen.
193 * When at middle of the screen the position is not altered.
194 * As the page is moved away from the middle, Actors move away but at
195 * different rates defined by the RampFunction(x, f).
196 * All Actors eventually arrive at their destination at the same time.
198 struct ScrollDepthPositionConstraint
201 * @param [in] positionExtent Controls how much Actor's X and Y
202 * position affects their alpha function's exponent value
203 * @param [in] offsetExtent exponent offset for X and Y scrolling
205 * @param [in] positionScale Changes the amount the page as a whole
208 ScrollDepthPositionConstraint( Vector2 positionExtent = Vector2(0.5f, 1.0f),
209 Vector2 offsetExtent = Vector2(1.0f, 1.0f),
210 float positionScale = 1.5f )
211 : mPositionExtent(positionExtent),
212 mOffsetExtent(offsetExtent),
213 mMaxExtent(positionExtent.x + positionExtent.y),
214 mPositionScale(positionScale)
219 * @param[in] current The current position
220 * @param[in] pagePositionProperty The page's position.
221 * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
222 * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
223 * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
224 * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
225 * @param[in] scrollWrap Whether scroll wrap has been enabled or not (SCROLL_WRAP_PROPERTY_NAME)
226 * @return The new position of this Actor.
228 Vector3 operator()(const Vector3& currentPosition,
229 const PropertyInput& pagePositionProperty,
230 const PropertyInput& scrollPositionProperty,
231 const PropertyInput& scrollPositionMin,
232 const PropertyInput& scrollPositionMax,
233 const PropertyInput& pageSizeProperty,
234 const PropertyInput& scrollWrap)
236 const Vector3& pagePosition = pagePositionProperty.GetVector3();
237 const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
239 // Get position of page.
240 Vector3 position = pagePosition + scrollPosition;
242 // short circuit: for orthognal view.
243 if( (fabsf(position.x) < Math::MACHINE_EPSILON_1) && (fabsf(position.y) < Math::MACHINE_EPSILON_1) )
245 return currentPosition + scrollPosition;
248 const Vector3& pageSize = pageSizeProperty.GetVector3();
249 bool wrap = scrollWrap.GetBoolean();
253 const Vector3& min = scrollPositionMin.GetVector3();
254 const Vector3& max = scrollPositionMax.GetVector3();
256 if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
258 // WRAP X (based on the position of the right side)
259 position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
262 if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
264 // WRAP Y (based on the position of the bottom side)
265 position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
269 // short circuit: for pages outside of view.
270 if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
272 // position actors at: scrollposition (Property) + pagePosition (Parent) + current (this)
273 // they will be invisible so doesn't have to be precise, just away from stage.
274 return currentPosition + scrollPosition;
277 // Calculate position /////////////////////////////////////////////////////
279 position.x /= pageSize.x;
280 position.y /= pageSize.y;
282 position *= mPositionScale;
284 Vector3 finalPosition(currentPosition - pagePosition);
286 Vector3 relCurrentPosition = currentPosition;
287 relCurrentPosition.x = relCurrentPosition.x / pageSize.x + 0.5f;
288 relCurrentPosition.y = relCurrentPosition.y / pageSize.y + 0.5f;
290 Vector3 extent( (relCurrentPosition.x * mPositionExtent.x + relCurrentPosition.y * mPositionExtent.y) * 1.0f,
291 (relCurrentPosition.x * mPositionExtent.y + relCurrentPosition.y * mPositionExtent.x) * 1.0f,
296 extent.x = mMaxExtent - extent.x; // Flip for right.
300 extent.y = mMaxExtent - extent.y; // Flip for bottom.
303 position.x = RampFunction(position.x, mOffsetExtent.x + extent.x);
304 position.y = RampFunction(position.y, mOffsetExtent.y + extent.y);
306 finalPosition += pageSize * position;
308 return finalPosition;
311 const Vector2 mPositionExtent; ///< Determines how much of the Actor's X and Y position affects exponent value.
312 const Vector2 mOffsetExtent; ///< Offset for exponent value.
313 const float mMaxExtent; ///< Maximum possible extent (mOffsetExtent.x + mOffsetExtent.y)
314 const float mPositionScale; ///< Position scaling factor (spreads out pages, to avoid overlap)
318 * Applies the scroll depth constraints to the child actor
320 * @param[in] scrollView The ScrollView containing the pages.
321 * @param[in] child The child to be affected with the 3D Effect.
322 * @param[in] positionExtent Controls how much Actor's X and Y
323 * position affects their alpha function's exponent value
324 * @param[in] offsetExtent exponent offset for X and Y scrolling
326 * @param[in] positionScale Changes the amount the page as a whole
328 * @param[in] scaleExtent Scale factor to reach when page is one whole
329 * page away from screen.
331 void ApplyScrollDepthConstraints(Toolkit::ScrollView scrollView,
333 const Vector2& positionExtent,
334 const Vector2& offsetExtent,
339 Constraint constraint = Constraint::New<Vector3>( Actor::SCALE,
340 LocalSource(Actor::POSITION),
341 ParentSource(Actor::POSITION),
342 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
343 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
344 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
345 Source(scrollView, Actor::SIZE ),
346 ScrollDepthScaleConstraint( positionExtent, offsetExtent, positionScale, scaleExtent ) );
347 constraint.SetRemoveAction( Constraint::Discard );
348 child.ApplyConstraint( constraint );
350 // Position Constraint (apply last as other constraints use Actor::POSITION as a function input)
351 constraint = Constraint::New<Vector3>( Actor::POSITION,
352 ParentSource(Actor::POSITION),
353 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
354 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
355 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
356 Source(scrollView, Actor::SIZE ),
357 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_WRAP_PROPERTY_NAME ) ),
358 ScrollDepthPositionConstraint( positionExtent, offsetExtent, positionScale ) );
360 constraint.SetRemoveAction( Constraint::Discard );
361 child.ApplyConstraint( constraint );
364 } // unnamed namespace
375 ScrollViewDepthEffect::ScrollViewDepthEffect()
380 ScrollViewDepthEffect::~ScrollViewDepthEffect()
384 void ScrollViewDepthEffect::ApplyToActor(Actor child,
385 const Vector2& positionExtent,
386 const Vector2& offsetExtent,
390 ApplyScrollDepthConstraints( GetScrollView(), child, positionExtent, offsetExtent, positionScale, scaleExtent );
393 void ScrollViewDepthEffect::OnAttach(Toolkit::ScrollView& scrollView)
397 void ScrollViewDepthEffect::OnDetach(Toolkit::ScrollView& scrollView)
401 } // namespace Internal
403 } // namespace Toolkit