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.
18 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-page-spiral-effect-impl.h>
21 #include <boost/bind.hpp>
24 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-helper-functions.h>
25 #include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h>
36 namespace // unnamed namespace
39 const float PAGE_EPSILON_FACTOR( 0.25f );
41 const float PAGE_SIZE_RELATIVE_ANGLE_FACTOR( 0.75f );
42 const float NON_SCROLL_PAGE_SPIRAL_ANGLE_FACTOR( 1.5f );
44 const float SCROLL_PAGE_OPAQUE_BEFORE( 0.4f );
45 const float SCROLL_PAGE_FULLY_TRANSPARENT_AFTER( 0.9f );
46 const float NON_SCROLL_PAGE_OPAQUE_BEFORE( 0.8f );
47 const float NON_SCROLL_PAGE_FULLY_TRANSPARENT_AFTER( 1.0f );
49 const float RADIUS_FACTOR( 0.95f );
50 const float SCROLL_PAGE_Z_POSITION_FACTOR( -2.0f );
51 const float NON_SCROLL_PAGE_Z_POSITION_FACTOR( -0.75f );
53 using namespace ScrollViewHelperFunctions;
56 * ScrollPageSpiralEffectInfo
58 * Rotate constraint: adjusts the angle of the page based on its position relative to the middle of
60 * When at middle of screen Angles on X and Y Axes is 0.
62 * Color constraint: adjusts the alpha of the page based on their parent page's position relative
63 * to the middle of the screen.
64 * When at middle of screen Alpha is 100% opacity.
65 * When outside the viewable area, the opacity is 0%.
67 * Position constraint: adjusts the position of the page based on their parent page's position
68 * relative to the middle of the screen.
69 * When at middle of the screen the position is not altered.
71 class ScrollPageSpiralEffectInfo : public Dali::RefObject
75 ScrollPageSpiralEffectInfo( const Vector2& spiralAngle, bool scrollWrap )
76 : mSpiralAngle( spiralAngle ),
77 mScrollWrap( scrollWrap )
82 * @param[in] current The current orientation of this Actor
83 * @param[in] pagePositionProperty The page's position.
84 * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
85 * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
86 * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
87 * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
88 * @param[in] scrollPageStartPositionProperty The position of the page where scrolling started. (SCROLL_START_PAGE_POSITION_PROPERTY_NAME)
89 * @return The new orientation of this Actor.
91 Quaternion RotationConstraint(const Quaternion& current,
92 const PropertyInput& pagePositionProperty,
93 const PropertyInput& scrollPositionProperty,
94 const PropertyInput& scrollPositionMin,
95 const PropertyInput& scrollPositionMax,
96 const PropertyInput& pageSizeProperty,
97 const PropertyInput& scrollStartPagePositionProperty)
99 const Vector3& pagePosition = pagePositionProperty.GetVector3();
100 const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
101 const Vector3& scrollStartPagePosition = scrollStartPagePositionProperty.GetVector3();
103 // Get position of page.
104 Vector3 position = pagePosition + scrollPosition;
106 // short circuit: if we're looking straight on at the page.
107 if( IsStraightOnView( position ) )
112 const Vector3& pageSize = pageSizeProperty.GetVector3();
113 const Vector3& minScrollPosition( scrollPositionMin.GetVector3() );
114 const Vector3& maxScrollPosition( scrollPositionMax.GetVector3() );
118 WrapPositionWithinDomain( position, pageSize, minScrollPosition, maxScrollPosition );
121 // short circuit: for pages outside of view.
122 if( IsOutsideView( position, pageSize ) )
127 Vector2 angle( position / ( pageSize * PAGE_SIZE_RELATIVE_ANGLE_FACTOR ) * Vector3( mSpiralAngle ) );
128 const Vector2 epsilon( pageSize * PAGE_EPSILON_FACTOR );
129 Vector2 distanceFromScrollPage;
130 distanceFromScrollPage.x = ShortestDistanceInDomain( scrollStartPagePosition.x, pagePosition.x, minScrollPosition.x, maxScrollPosition.x );
131 distanceFromScrollPage.y = ShortestDistanceInDomain( scrollStartPagePosition.y, pagePosition.y, minScrollPosition.y, maxScrollPosition.y );
133 Vector2 angleMaxMin( mSpiralAngle );
136 if ( fabsf( distanceFromScrollPage.x ) <= epsilon.x ) // Did scroll start on this page?
138 angle.x = -angle.x * 0.9f;
142 // If not then multiply by angle factor.
143 angleMaxMin.x *= NON_SCROLL_PAGE_SPIRAL_ANGLE_FACTOR;
145 ClampInPlace( angle.x, -angleMaxMin.x, angleMaxMin.x );
148 if ( fabsf( distanceFromScrollPage.y ) > epsilon.y ) // If not on the scroll page then multiply by angle factor.
150 angleMaxMin.y *= NON_SCROLL_PAGE_SPIRAL_ANGLE_FACTOR;
153 ClampInPlace( angle.y, -angleMaxMin.y, angleMaxMin.y );
155 Quaternion rotation = Quaternion( angle.x, Vector3::YAXIS ) *
156 Quaternion( angle.y, Vector3::XAXIS ) *
163 * @param[in] current The current color of this Actor
164 * @param[in] pagePositionProperty The page's position.
165 * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
166 * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
167 * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
168 * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
169 * @param[in] scrollPageStartPositionProperty The position of the page where scrolling started. (SCROLL_START_PAGE_POSITION_PROPERTY_NAME)
170 * @return The new color of this Actor.
172 Vector4 ColorConstraint(const Vector4& current,
173 const PropertyInput& pagePositionProperty,
174 const PropertyInput& scrollPositionProperty,
175 const PropertyInput& scrollPositionMin,
176 const PropertyInput& scrollPositionMax,
177 const PropertyInput& pageSizeProperty,
178 const PropertyInput& scrollStartPagePositionProperty)
180 const Vector3& pagePosition = pagePositionProperty.GetVector3();
181 const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
182 const Vector3& scrollStartPagePosition = scrollStartPagePositionProperty.GetVector3();
184 // Get position of page.
185 Vector3 position = pagePosition + scrollPosition;
187 // short circuit: if we're looking straight on at the page.
188 if( IsStraightOnView( position ) )
193 const Vector3& pageSize = pageSizeProperty.GetVector3();
194 const Vector3& minScrollPosition( scrollPositionMin.GetVector3() );
195 const Vector3& maxScrollPosition( scrollPositionMax.GetVector3() );
199 WrapPositionWithinDomain( position, pageSize, minScrollPosition, maxScrollPosition );
202 // short circuit: for pages outside of view.
203 if( IsOutsideView( position, pageSize ) )
205 // note preserve color channels incase there is a shader/further constraint
206 // that wishes to do something with that information.
207 return Vector4(current.r, current.g, current.b, 0.0f);
210 Vector4 color( current );
211 Vector2 distance( position / pageSize );
212 float distanceLength( distance.Length() );
213 const Vector2 epsilon( pageSize * PAGE_EPSILON_FACTOR );
214 Vector2 distanceFromScrollPage;
215 distanceFromScrollPage.x = ShortestDistanceInDomain( scrollStartPagePosition.x, pagePosition.x, minScrollPosition.x, maxScrollPosition.x );
216 distanceFromScrollPage.y = ShortestDistanceInDomain( scrollStartPagePosition.y, pagePosition.y, minScrollPosition.y, maxScrollPosition.y );
218 float fullyOpaqueBefore( 0.0f );
219 float fullyTransparentAfter( 1.0f );
221 if ( ( fabsf( distanceFromScrollPage.x ) <= epsilon.x ) && ( fabsf( distanceFromScrollPage.y ) <= epsilon.y )) // Did scroll start on this page?
223 fullyOpaqueBefore = SCROLL_PAGE_OPAQUE_BEFORE;
224 fullyTransparentAfter = SCROLL_PAGE_FULLY_TRANSPARENT_AFTER;
228 fullyOpaqueBefore = NON_SCROLL_PAGE_OPAQUE_BEFORE;
229 fullyTransparentAfter = NON_SCROLL_PAGE_FULLY_TRANSPARENT_AFTER;
232 if ( distanceLength <= fullyOpaqueBefore )
236 else if ( distanceLength <= fullyTransparentAfter )
238 float opacity( distanceLength - fullyOpaqueBefore );
239 opacity /= fullyTransparentAfter - fullyOpaqueBefore;
240 color.a = Clamp( 1.0f - opacity, 0.0f, 1.0f );
251 * @param[in] current The current position
252 * @param[in] pagePositionProperty The page's position.
253 * @param[in] scrollPositionProperty The scroll-view's position property (SCROLL_POSITION_PROPERTY_NAME)
254 * @param[in] scrollPositionMin The minimum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
255 * @param[in] scrollPositionMax The maximum extent of this scroll domain. (SCROLL_POSITION_MIN_PROPERTY_NAME)
256 * @param[in] pageSizeProperty The size of the page. (scrollView SIZE)
257 * @param[in] scrollPageStartPositionProperty The position of the page where scrolling started. (SCROLL_START_PAGE_POSITION_PROPERTY_NAME)
258 * @return The new position of this Actor.
260 Vector3 PositionConstraint(const Vector3& current,
261 const PropertyInput& pagePositionProperty,
262 const PropertyInput& scrollPositionProperty,
263 const PropertyInput& scrollPositionMin,
264 const PropertyInput& scrollPositionMax,
265 const PropertyInput& pageSizeProperty,
266 const PropertyInput& scrollStartPagePositionProperty)
268 const Vector3& pagePosition = pagePositionProperty.GetVector3();
269 const Vector3& scrollPosition = scrollPositionProperty.GetVector3();
270 const Vector3& scrollStartPagePosition = scrollStartPagePositionProperty.GetVector3();
272 // Get position of page.
273 Vector3 position = pagePosition + scrollPosition;
275 // short circuit: if we're looking straight on at the page.
276 if( IsStraightOnView( position ) )
278 return current + scrollPosition;
281 const Vector3& pageSize = pageSizeProperty.GetVector3();
282 const Vector3& minScrollPosition( scrollPositionMin.GetVector3() );
283 const Vector3& maxScrollPosition( scrollPositionMax.GetVector3() );
287 WrapPositionWithinDomain( position, pageSize, minScrollPosition, maxScrollPosition );
290 // short circuit: for pages outside of view.
291 if( IsOutsideView( position, pageSize ) )
293 // position actors at: scrollposition (Property) + pagePosition (Parent) + current (this)
294 // they will be invisible so doesn't have to be precise, just away from stage.
295 return current + scrollPosition;
298 const Vector2 angle( position / pageSize * ( Dali::Math::PI_4 ) );
299 const Vector2 radius( pageSize * RADIUS_FACTOR );
300 const Vector2 epsilon( pageSize * PAGE_EPSILON_FACTOR );
301 Vector2 distanceFromScrollPage;
302 distanceFromScrollPage.x = ShortestDistanceInDomain( scrollStartPagePosition.x, pagePosition.x, minScrollPosition.x, maxScrollPosition.x );
303 distanceFromScrollPage.y = ShortestDistanceInDomain( scrollStartPagePosition.y, pagePosition.y, minScrollPosition.y, maxScrollPosition.y );
305 // X position and relative Z position
306 if ( fabsf( distanceFromScrollPage.x ) <= epsilon.x ) // Did scroll start on this page?
308 position.x = radius.x * sin( angle.x ) * 0.77f;
309 position.z = fabsf( position.x ) * SCROLL_PAGE_Z_POSITION_FACTOR;
313 position.x = radius.x * ( sinf( angle.x * Math::PI * 0.4f ) );
315 position.z = fabsf( position.x ) * NON_SCROLL_PAGE_Z_POSITION_FACTOR;
318 // Y position and relative Z position
319 if ( fabsf( distanceFromScrollPage.y ) <= epsilon.y ) // Did scroll start on this page?
321 position.y = radius.y * sin( angle.y ) * 0.77f;
322 position.z += fabsf( position.y ) * SCROLL_PAGE_Z_POSITION_FACTOR;
326 position.y = radius.y * ( sinf( angle.y * Math::PI * 0.4f ) );
328 position.z += fabsf( position.y ) * NON_SCROLL_PAGE_Z_POSITION_FACTOR;
334 Vector2 mSpiralAngle; ///< The angle of the spirald page
335 bool mScrollWrap; ///< Whether the scroll view wraps or not.
338 typedef IntrusivePtr<ScrollPageSpiralEffectInfo> ScrollPageSpiralEffectInfoPtr;
341 * Helper: Applies the 3D scroll cube constraints to the child actor
343 * @param[in] scrollView The ScrollView containing the pages.
344 * @param[in] child The child to be affected with the 3D Effect.
345 * @param[in] info The effect info for the constraints
347 void ApplyScrollCubeConstraints(Toolkit::ScrollView scrollView,
349 ScrollPageSpiralEffectInfoPtr info)
351 // Apply constraints to this actor //
352 Constraint constraint;
353 constraint = Constraint::New<Quaternion>( Actor::ROTATION,
354 LocalSource(Actor::POSITION),
355 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_FINAL_PROPERTY_NAME ) ),
356 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
357 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
358 Source(scrollView, Actor::SIZE ),
359 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_START_PAGE_POSITION_PROPERTY_NAME ) ),
360 boost::bind( &ScrollPageSpiralEffectInfo::RotationConstraint, info, _1, _2, _3, _4, _5, _6, _7) );
362 constraint.SetRemoveAction( Constraint::Discard );
363 child.ApplyConstraint( constraint );
365 constraint = Constraint::New<Vector4>( Actor::COLOR,
366 LocalSource(Actor::POSITION),
367 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_FINAL_PROPERTY_NAME ) ),
368 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
369 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
370 Source(scrollView, Actor::SIZE ),
371 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_START_PAGE_POSITION_PROPERTY_NAME ) ),
372 boost::bind( &ScrollPageSpiralEffectInfo::ColorConstraint, info, _1, _2, _3, _4, _5, _6, _7) );
374 constraint.SetRemoveAction( Constraint::Discard );
375 child.ApplyConstraint( constraint );
377 constraint = Constraint::New<Vector3>( Actor::POSITION,
378 LocalSource(Actor::POSITION),
379 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_FINAL_PROPERTY_NAME ) ),
380 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MIN_PROPERTY_NAME ) ),
381 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_POSITION_MAX_PROPERTY_NAME ) ),
382 Source(scrollView, Actor::SIZE ),
383 Source(scrollView, scrollView.GetPropertyIndex( Toolkit::ScrollView::SCROLL_START_PAGE_POSITION_PROPERTY_NAME ) ),
384 boost::bind( &ScrollPageSpiralEffectInfo::PositionConstraint, info, _1, _2, _3, _4, _5, _6, _7) );
386 constraint.SetRemoveAction( Constraint::Discard );
387 child.ApplyConstraint( constraint );
390 } // unnamed namespace
392 ScrollViewPageSpiralEffect::ScrollViewPageSpiralEffect()
397 ScrollViewPageSpiralEffect::~ScrollViewPageSpiralEffect()
401 void ScrollViewPageSpiralEffect::ApplyToPage( Actor page, const Vector2& spiralAngle )
403 Toolkit::ScrollView scrollView( GetScrollView() );
407 ScrollPageSpiralEffectInfoPtr info(new ScrollPageSpiralEffectInfo( spiralAngle, GetImpl( scrollView ).GetWrapMode() ));
408 ApplyScrollCubeConstraints( scrollView, page, info );
412 void ScrollViewPageSpiralEffect::OnAttach(Toolkit::ScrollView& scrollView)
416 void ScrollViewPageSpiralEffect::OnDetach(Toolkit::ScrollView& scrollView)
420 } // namespace Internal
422 } // namespace Toolkit