2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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.
17 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
18 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-depth-effect-impl.h>
22 namespace // unnamed namespace
25 // constraints ////////////////////////////////////////////////////////////////
28 * Ramp equation is a variable easing equation
29 * of the form f(x) = |x|^y * x / |x|
31 * An exponent (y) of 1 will result in a fast (linear graph)
32 * Increasing the exponent will increase the Ease In
34 * @param[in] x mantissa (value from -1.0f to 1.0f)
35 * @param[in] y exponent (+ve value)
36 * @return The signed progress value from -1.0f to 1.0f
38 inline float RampFunction(float x, float y)
42 return -powf(fabsf(x), y);
45 return powf(fabsf(x), y);
49 * ScrollDepthScaleConstraint
51 * Scale constraint adjusts the scale of the Actors
52 * based on their parent page's position relative to the middle of the screen.
53 * When at middle of the screen the scale is not altered.
54 * As the page is moved away from the middle, Actors shrink in scale but at
55 * different rates defined by the RampFunction(x, f).
56 * All Actors eventually shrink to the same amount once at their destination.
58 struct ScrollDepthScaleConstraint
61 * The scaling constraint uses the amount the actors
62 * have moved in position to determine scaling extent.
63 * So essentially very similar calculations are used here.
65 * @param[in] positionExtent Controls how much Actor's X and Y
66 * position affects their alpha function's exponent value
67 * @param[in] offsetExtent exponent offset for X and Y scrolling
69 * @param[in] positionScale Changes the amount the page as a whole
71 * @param[in] scaleExtent Scale factor to reach when page is one whole
72 * page away from screen.
74 ScrollDepthScaleConstraint( Vector2 positionExtent = Vector2(0.5f, 1.0f),
75 Vector2 offsetExtent = Vector2(1.0f, 1.0f),
76 float positionScale = 1.5f,
77 float scaleExtent = 0.5f)
78 : mPositionExtent(positionExtent),
79 mOffsetExtent(offsetExtent),
80 mMaxExtent(positionExtent.x + positionExtent.y),
81 mPositionScale(positionScale),
82 mScaleExtent(scaleExtent)
87 * @param[in] current The current scale
88 * @param[in] pagePositionProperty The page's position.
89 * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
90 * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
91 * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
92 * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
93 * @param[in] scrollWrap Whether scroll wrap has been enabled or not (SCROLL_WRAP_PROPERTY_NAME)
94 * @return The new scale of this Actor.
96 Vector3 operator()(const Vector3& currentScale,
97 const PropertyInput& currentPositionProperty,
98 const PropertyInput& pagePositionProperty,
99 const PropertyInput& scrollPositionProperty,
100 const PropertyInput& scrollPositionMin,
101 const PropertyInput& scrollPositionMax,
102 const PropertyInput& pageSizeProperty)
104 const Vector3& currentPosition = currentPositionProperty.GetVector3();
105 const Vector3& pagePosition = pagePositionProperty.GetVector3();
106 const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
108 // Get position of page.
109 Vector3 position = pagePosition + scrollPosition;
111 // short circuit: for orthognal view.
112 if( (fabsf(position.x) < Math::MACHINE_EPSILON_1) && (fabsf(position.y) < Math::MACHINE_EPSILON_1) )
117 const Vector3& pageSize = pageSizeProperty.GetVector3();
118 // Don't have enough parameters, to provide Wrap mode (need a way of having 'uniforms' instead of scrollWrap.GetBoolean())
119 const bool wrap = true;
123 const Vector3& min = scrollPositionMin.GetVector3();
124 const Vector3& max = scrollPositionMax.GetVector3();
126 if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
128 // WRAP X (based on the position of the right side)
129 position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
132 if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
134 // WRAP Y (based on the position of the bottom side)
135 position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
139 // short circuit: for pages outside of view.
140 if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
145 // Calculate scale ////////////////////////////////////////////////////////
147 position.x /= pageSize.x;
148 position.y /= pageSize.y;
150 position *= mPositionScale;
152 Vector3 relCurrentPosition = currentPosition;
153 relCurrentPosition.x = relCurrentPosition.x / pageSize.x + 0.5f;
154 relCurrentPosition.y = relCurrentPosition.y / pageSize.y + 0.5f;
156 Vector3 extent( (relCurrentPosition.x * mPositionExtent.x + relCurrentPosition.y * mPositionExtent.y) * 1.0f,
157 (relCurrentPosition.x * mPositionExtent.y + relCurrentPosition.y * mPositionExtent.x) * 1.0f,
162 extent.x = mMaxExtent - extent.x; // Flip for right.
166 extent.y = mMaxExtent - extent.y; // Flip for bottom.
169 position.x = RampFunction(position.x, mOffsetExtent.x + extent.x);
170 position.y = RampFunction(position.y, mOffsetExtent.y + extent.y);
172 float f = mScaleExtent + cos(position.x * Math::PI_2) * cos(position.y * Math::PI_2) * (1.0f - mScaleExtent);
174 return currentScale * f;
177 const Vector2 mPositionExtent; ///< Determines how much of the Actor's X and Y position affects exponent value.
178 const Vector2 mOffsetExtent; ///< Offset for exponent value.
179 const float mMaxExtent; ///< Maximum possible extent (mOffsetExtent.x + mOffsetExtent.y)
180 const float mPositionScale; ///< Position scaling factor (spreads out pages, to avoid overlap)
181 const float mScaleExtent; ///< Scale factor when page is at furthest from
185 * ScrollDepthPositionConstraint
187 * Position constraint adjusts the position of the Actors
188 * based on their parent page's position relative to the middle of the screen.
189 * When at middle of the screen the position is not altered.
190 * As the page is moved away from the middle, Actors move away but at
191 * different rates defined by the RampFunction(x, f).
192 * All Actors eventually arrive at their destination at the same time.
194 struct ScrollDepthPositionConstraint
197 * @param [in] positionExtent Controls how much Actor's X and Y
198 * position affects their alpha function's exponent value
199 * @param [in] offsetExtent exponent offset for X and Y scrolling
201 * @param [in] positionScale Changes the amount the page as a whole
204 ScrollDepthPositionConstraint( Vector2 positionExtent = Vector2(0.5f, 1.0f),
205 Vector2 offsetExtent = Vector2(1.0f, 1.0f),
206 float positionScale = 1.5f )
207 : mPositionExtent(positionExtent),
208 mOffsetExtent(offsetExtent),
209 mMaxExtent(positionExtent.x + positionExtent.y),
210 mPositionScale(positionScale)
215 * @param[in] current The current position
216 * @param[in] pagePositionProperty The page's position.
217 * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
218 * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
219 * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
220 * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
221 * @param[in] scrollWrap Whether scroll wrap has been enabled or not (SCROLL_WRAP_PROPERTY_NAME)
222 * @return The new position of this Actor.
224 Vector3 operator()(const Vector3& currentPosition,
225 const PropertyInput& pagePositionProperty,
226 const PropertyInput& scrollPositionProperty,
227 const PropertyInput& scrollPositionMin,
228 const PropertyInput& scrollPositionMax,
229 const PropertyInput& pageSizeProperty,
230 const PropertyInput& scrollWrap)
232 const Vector3& pagePosition = pagePositionProperty.GetVector3();
233 const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
235 // Get position of page.
236 Vector3 position = pagePosition + scrollPosition;
238 // short circuit: for orthognal view.
239 if( (fabsf(position.x) < Math::MACHINE_EPSILON_1) && (fabsf(position.y) < Math::MACHINE_EPSILON_1) )
241 return currentPosition + scrollPosition;
244 const Vector3& pageSize = pageSizeProperty.GetVector3();
245 bool wrap = scrollWrap.GetBoolean();
249 const Vector3& min = scrollPositionMin.GetVector3();
250 const Vector3& max = scrollPositionMax.GetVector3();
252 if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
254 // WRAP X (based on the position of the right side)
255 position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
258 if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
260 // WRAP Y (based on the position of the bottom side)
261 position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
265 // short circuit: for pages outside of view.
266 if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
268 // position actors at: scrollposition (Property) + pagePosition (Parent) + current (this)
269 // they will be invisible so doesn't have to be precise, just away from stage.
270 return currentPosition + scrollPosition;
273 // Calculate position /////////////////////////////////////////////////////
275 position.x /= pageSize.x;
276 position.y /= pageSize.y;
278 position *= mPositionScale;
280 Vector3 finalPosition(currentPosition - pagePosition);
282 Vector3 relCurrentPosition = currentPosition;
283 relCurrentPosition.x = relCurrentPosition.x / pageSize.x + 0.5f;
284 relCurrentPosition.y = relCurrentPosition.y / pageSize.y + 0.5f;
286 Vector3 extent( (relCurrentPosition.x * mPositionExtent.x + relCurrentPosition.y * mPositionExtent.y) * 1.0f,
287 (relCurrentPosition.x * mPositionExtent.y + relCurrentPosition.y * mPositionExtent.x) * 1.0f,
292 extent.x = mMaxExtent - extent.x; // Flip for right.
296 extent.y = mMaxExtent - extent.y; // Flip for bottom.
299 position.x = RampFunction(position.x, mOffsetExtent.x + extent.x);
300 position.y = RampFunction(position.y, mOffsetExtent.y + extent.y);
302 finalPosition += pageSize * position;
304 return finalPosition;
307 const Vector2 mPositionExtent; ///< Determines how much of the Actor's X and Y position affects exponent value.
308 const Vector2 mOffsetExtent; ///< Offset for exponent value.
309 const float mMaxExtent; ///< Maximum possible extent (mOffsetExtent.x + mOffsetExtent.y)
310 const float mPositionScale; ///< Position scaling factor (spreads out pages, to avoid overlap)
314 * Applies the scroll depth constraints to the child actor
316 * @param[in] scrollView The ScrollView containing the pages.
317 * @param[in] child The child to be affected with the 3D Effect.
318 * @param[in] positionExtent Controls how much Actor's X and Y
319 * position affects their alpha function's exponent value
320 * @param[in] offsetExtent exponent offset for X and Y scrolling
322 * @param[in] positionScale Changes the amount the page as a whole
324 * @param[in] scaleExtent Scale factor to reach when page is one whole
325 * page away from screen.
327 void ApplyScrollDepthConstraints(Toolkit::ScrollView scrollView,
329 const Vector2& positionExtent,
330 const Vector2& offsetExtent,
335 Constraint constraint = Constraint::New<Vector3>( Actor::SCALE,
336 LocalSource(Actor::POSITION),
337 ParentSource(Actor::POSITION),
338 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
339 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
340 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
341 Source(scrollView, Actor::SIZE ),
342 ScrollDepthScaleConstraint( positionExtent, offsetExtent, positionScale, scaleExtent ) );
343 constraint.SetRemoveAction( Constraint::Discard );
344 child.ApplyConstraint( constraint );
346 // Position Constraint (apply last as other constraints use Actor::POSITION as a function input)
347 constraint = Constraint::New<Vector3>( Actor::POSITION,
348 ParentSource(Actor::POSITION),
349 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_PROPERTY_NAME ) ),
350 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
351 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
352 Source(scrollView, Actor::SIZE ),
353 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_WRAP_PROPERTY_NAME ) ),
354 ScrollDepthPositionConstraint( positionExtent, offsetExtent, positionScale ) );
356 constraint.SetRemoveAction( Constraint::Discard );
357 child.ApplyConstraint( constraint );
360 } // unnamed namespace
371 ScrollViewDepthEffect::ScrollViewDepthEffect()
376 ScrollViewDepthEffect::~ScrollViewDepthEffect()
380 void ScrollViewDepthEffect::ApplyToActor(Actor child,
381 const Vector2& positionExtent,
382 const Vector2& offsetExtent,
386 ApplyScrollDepthConstraints( GetScrollView(), child, positionExtent, offsetExtent, positionScale, scaleExtent );
389 void ScrollViewDepthEffect::OnAttach(Toolkit::ScrollView& scrollView)
393 void ScrollViewDepthEffect::OnDetach(Toolkit::ScrollView& scrollView)
397 } // namespace Internal
399 } // namespace Toolkit