-/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/animation/constraint.h>
-#include <dali/public-api/object/property-input.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-effect-impl.h>
-#include <dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-depth-effect-impl.h>
-
-using namespace Dali;
-
-namespace // unnamed namespace
-{
-
-// constraints ////////////////////////////////////////////////////////////////
-
-/**
- * Ramp equation is a variable easing equation
- * of the form f(x) = |x|^y * x / |x|
- *
- * An exponent (y) of 1 will result in a fast (linear graph)
- * Increasing the exponent will increase the Ease In
- *
- * @param[in] x mantissa (value from -1.0f to 1.0f)
- * @param[in] y exponent (+ve value)
- * @return The signed progress value from -1.0f to 1.0f
- */
-inline float RampFunction(float x, float y)
-{
- if(x < 0.0f)
- {
- return -powf(fabsf(x), y);
- }
-
- return powf(fabsf(x), y);
-}
-
-/**
- * ScrollDepthScaleConstraint
- *
- * Scale constraint adjusts the scale of the Actors
- * based on their parent page's position relative to the middle of the screen.
- * When at middle of the screen the scale is not altered.
- * As the page is moved away from the middle, Actors shrink in scale but at
- * different rates defined by the RampFunction(x, f).
- * All Actors eventually shrink to the same amount once at their destination.
- */
-struct ScrollDepthScaleConstraint
-{
- /**
- * The scaling constraint uses the amount the actors
- * have moved in position to determine scaling extent.
- * So essentially very similar calculations are used here.
- *
- * @param[in] positionExtent Controls how much Actor's X and Y
- * position affects their alpha function's exponent value
- * @param[in] offsetExtent exponent offset for X and Y scrolling
- * axes.
- * @param[in] positionScale Changes the amount the page as a whole
- * moves by.
- * @param[in] scaleExtent Scale factor to reach when page is one whole
- * page away from screen.
- */
- ScrollDepthScaleConstraint( Vector2 positionExtent = Vector2(0.5f, 1.0f),
- Vector2 offsetExtent = Vector2(1.0f, 1.0f),
- float positionScale = 1.5f,
- float scaleExtent = 0.5f)
- : mPositionExtent(positionExtent),
- mOffsetExtent(offsetExtent),
- mMaxExtent(positionExtent.x + positionExtent.y),
- mPositionScale(positionScale),
- mScaleExtent(scaleExtent)
- {
- }
-
- /**
- * @param[in,out] current The current scale
- * @param[in] inputs Contains:
- * The page's position.
- * The scroll-view's position property (SCROLL_POSITION)
- * The minimum extent of this scroll domain. (SCROLL_POSITION_MIN)
- * The maximum extent of this scroll domain. (SCROLL_POSITION_MIN)
- * The size of the page. (scrollView SIZE)
- * Whether scroll wrap has been enabled or not (SCROLL_WRAP)
- * @return The new scale of this Actor.
- */
- void operator()( Vector3& currentScale, const PropertyInputContainer& inputs )
- {
- const Vector3& currentPosition = inputs[0]->GetVector3();
- const Vector3& pagePosition = inputs[1]->GetVector3();
- const Vector2& scrollPosition = inputs[2]->GetVector2();
-
- // Get position of page.
- Vector2 position = pagePosition.GetVectorXY() + scrollPosition;
-
- // short circuit: for orthognal view.
- if( (fabsf(position.x) < Math::MACHINE_EPSILON_1) && (fabsf(position.y) < Math::MACHINE_EPSILON_1) )
- {
- return;
- }
-
- const Vector3& pageSize = inputs[5]->GetVector3();
-
- // Don't have enough parameters, to provide Wrap mode (need a way of having 'uniforms' instead of scrollWrap.GetBoolean())
-
- const Vector2& min = inputs[3]->GetVector2();
- const Vector2& max = inputs[4]->GetVector2();
-
- if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
- {
- // WRAP X (based on the position of the right side)
- position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
- }
-
- if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
- {
- // WRAP Y (based on the position of the bottom side)
- position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
- }
-
- // short circuit: for pages outside of view.
- if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
- {
- return;
- }
-
- // Calculate scale ////////////////////////////////////////////////////////
-
- position.x /= pageSize.x;
- position.y /= pageSize.y;
-
- position *= mPositionScale;
-
- Vector3 relCurrentPosition = currentPosition;
- relCurrentPosition.x = relCurrentPosition.x / pageSize.x + 0.5f;
- relCurrentPosition.y = relCurrentPosition.y / pageSize.y + 0.5f;
-
- Vector3 extent( (relCurrentPosition.x * mPositionExtent.x + relCurrentPosition.y * mPositionExtent.y) * 1.0f,
- (relCurrentPosition.x * mPositionExtent.y + relCurrentPosition.y * mPositionExtent.x) * 1.0f,
- 0.0f);
-
- if(position.x>0.0f)
- {
- extent.x = mMaxExtent - extent.x; // Flip for right.
- }
- if(position.y>0.0f)
- {
- extent.y = mMaxExtent - extent.y; // Flip for bottom.
- }
-
- position.x = RampFunction(position.x, mOffsetExtent.x + extent.x);
- position.y = RampFunction(position.y, mOffsetExtent.y + extent.y);
-
- float f = mScaleExtent + cos(position.x * Math::PI_2) * cos(position.y * Math::PI_2) * (1.0f - mScaleExtent);
-
- currentScale *= f;
- }
-
- const Vector2 mPositionExtent; ///< Determines how much of the Actor's X and Y position affects exponent value.
- const Vector2 mOffsetExtent; ///< Offset for exponent value.
- const float mMaxExtent; ///< Maximum possible extent (mOffsetExtent.x + mOffsetExtent.y)
- const float mPositionScale; ///< Position scaling factor (spreads out pages, to avoid overlap)
- const float mScaleExtent; ///< Scale factor when page is at furthest from
-};
-
-/**
- * ScrollDepthPositionConstraint
- *
- * Position constraint adjusts the position of the Actors
- * based on their parent page's position relative to the middle of the screen.
- * When at middle of the screen the position is not altered.
- * As the page is moved away from the middle, Actors move away but at
- * different rates defined by the RampFunction(x, f).
- * All Actors eventually arrive at their destination at the same time.
- */
-struct ScrollDepthPositionConstraint
-{
- /**
- * @param [in] positionExtent Controls how much Actor's X and Y
- * position affects their alpha function's exponent value
- * @param [in] offsetExtent exponent offset for X and Y scrolling
- * axes.
- * @param [in] positionScale Changes the amount the page as a whole
- * moves by.
- */
- ScrollDepthPositionConstraint( Vector2 positionExtent = Vector2(0.5f, 1.0f),
- Vector2 offsetExtent = Vector2(1.0f, 1.0f),
- float positionScale = 1.5f )
- : mPositionExtent(positionExtent),
- mOffsetExtent(offsetExtent),
- mMaxExtent(positionExtent.x + positionExtent.y),
- mPositionScale(positionScale)
- {
- }
-
- /**
- * @param[in,out] current The current position
- * @param[in] inputs Contains:
- * The page's position.
- * The scroll-view's position property (SCROLL_POSITION)
- * The minimum extent of this scroll domain. (SCROLL_POSITION_MIN)
- * The maximum extent of this scroll domain. (SCROLL_POSITION_MIN)
- * The size of the page. (scrollView SIZE)
- * Whether scroll wrap has been enabled or not (SCROLL_WRAP)
- * @return The new position of this Actor.
- */
- void operator()( Vector3& currentPosition, const PropertyInputContainer& inputs )
- {
- const Vector3& pagePosition = inputs[0]->GetVector3();
- const Vector2& scrollPosition = inputs[1]->GetVector2();
-
- // Get position of page.
- Vector2 position = pagePosition.GetVectorXY() + scrollPosition;
-
- // short circuit: for orthognal view.
- if( (fabsf(position.x) < Math::MACHINE_EPSILON_1) && (fabsf(position.y) < Math::MACHINE_EPSILON_1) )
- {
- currentPosition.GetVectorXY() += scrollPosition;
- return;
- }
-
- const Vector3& pageSize = inputs[4]->GetVector3();
- bool wrap = inputs[5]->GetBoolean();
-
- if(wrap)
- {
- const Vector2& min = inputs[2]->GetVector2();
- const Vector2& max = inputs[3]->GetVector2();
-
- if(fabsf(min.x - max.x) > Math::MACHINE_EPSILON_1)
- {
- // WRAP X (based on the position of the right side)
- position.x = WrapInDomain(position.x + pageSize.x, min.x, max.x) - pageSize.x;
- }
-
- if(fabsf(min.y - max.y) > Math::MACHINE_EPSILON_1)
- {
- // WRAP Y (based on the position of the bottom side)
- position.y = WrapInDomain(position.y + pageSize.y, min.y, max.y) - pageSize.y;
- }
- }
-
- // short circuit: for pages outside of view.
- if( (fabsf(position.x) >= pageSize.x) || (fabsf(position.y) >= pageSize.y) )
- {
- // position actors at: scrollposition (Property) + pagePosition (Parent) + current (this)
- // they will be invisible so doesn't have to be precise, just away from stage.
- currentPosition.GetVectorXY() += scrollPosition;
- return;
- }
-
- // Calculate position /////////////////////////////////////////////////////
-
- position.x /= pageSize.x;
- position.y /= pageSize.y;
-
- position *= mPositionScale;
-
- Vector3 relCurrentPosition = currentPosition;
- relCurrentPosition.x = relCurrentPosition.x / pageSize.x + 0.5f;
- relCurrentPosition.y = relCurrentPosition.y / pageSize.y + 0.5f;
-
- Vector3 extent( (relCurrentPosition.x * mPositionExtent.x + relCurrentPosition.y * mPositionExtent.y) * 1.0f,
- (relCurrentPosition.x * mPositionExtent.y + relCurrentPosition.y * mPositionExtent.x) * 1.0f,
- 0.0f);
-
- if(position.x>0.0f)
- {
- extent.x = mMaxExtent - extent.x; // Flip for right.
- }
- if(position.y>0.0f)
- {
- extent.y = mMaxExtent - extent.y; // Flip for bottom.
- }
-
- position.x = RampFunction(position.x, mOffsetExtent.x + extent.x);
- position.y = RampFunction(position.y, mOffsetExtent.y + extent.y);
-
- currentPosition -= pagePosition;
- currentPosition += pageSize * Vector3(position);
- }
-
- const Vector2 mPositionExtent; ///< Determines how much of the Actor's X and Y position affects exponent value.
- const Vector2 mOffsetExtent; ///< Offset for exponent value.
- const float mMaxExtent; ///< Maximum possible extent (mOffsetExtent.x + mOffsetExtent.y)
- const float mPositionScale; ///< Position scaling factor (spreads out pages, to avoid overlap)
-};
-
-/**
- * Applies the scroll depth constraints to the child actor
- *
- * @param[in] scrollView The ScrollView containing the pages.
- * @param[in] child The child to be affected with the 3D Effect.
- * @param[in] positionExtent Controls how much Actor's X and Y
- * position affects their alpha function's exponent value
- * @param[in] offsetExtent exponent offset for X and Y scrolling
- * axes.
- * @param[in] positionScale Changes the amount the page as a whole
- * moves by.
- * @param[in] scaleExtent Scale factor to reach when page is one whole
- * page away from screen.
- */
-void ApplyScrollDepthConstraints(Toolkit::ScrollView scrollView,
- Actor child,
- const Vector2& positionExtent,
- const Vector2& offsetExtent,
- float positionScale,
- float scaleExtent)
-{
- // Scale Constraint
- Constraint constraint = Constraint::New<Vector3>( child, Actor::Property::SCALE, ScrollDepthScaleConstraint( positionExtent, offsetExtent, positionScale, scaleExtent ) );
- constraint.AddSource( LocalSource( Actor::Property::POSITION ) );
- constraint.AddSource( ParentSource( Actor::Property::POSITION ) );
- constraint.AddSource( Source( scrollView, Toolkit::ScrollView::Property::SCROLL_POSITION ) );
- constraint.AddSource( Source( scrollView, Toolkit::Scrollable::Property::SCROLL_POSITION_MIN ) );
- constraint.AddSource( Source( scrollView, Toolkit::Scrollable::Property::SCROLL_POSITION_MAX ) );
- constraint.AddSource( Source( scrollView, Actor::Property::SIZE ) );
- constraint.SetRemoveAction( Constraint::Discard );
- constraint.Apply();
-
- // Position Constraint (apply last as other constraints use Actor::POSITION as a function input)
- constraint = Constraint::New<Vector3>( child, Actor::Property::POSITION, ScrollDepthPositionConstraint( positionExtent, offsetExtent, positionScale ) );
- constraint.AddSource( ParentSource(Actor::Property::POSITION) );
- constraint.AddSource( Source(scrollView, Toolkit::ScrollView::Property::SCROLL_POSITION ) );
- constraint.AddSource( Source(scrollView, Toolkit::Scrollable::Property::SCROLL_POSITION_MIN ) );
- constraint.AddSource( Source(scrollView, Toolkit::Scrollable::Property::SCROLL_POSITION_MAX ) );
- constraint.AddSource( Source(scrollView, Actor::Property::SIZE ) );
- constraint.AddSource( Source(scrollView, Toolkit::ScrollView::Property::WRAP ) );
- constraint.SetRemoveAction( Constraint::Discard );
- constraint.Apply();
-}
-
-} // unnamed namespace
-
-namespace Dali
-{
-
-namespace Toolkit
-{
-
-namespace Internal
-{
-
-ScrollViewDepthEffect::ScrollViewDepthEffect()
-{
-
-}
-
-ScrollViewDepthEffect::~ScrollViewDepthEffect()
-{
-}
-
-void ScrollViewDepthEffect::ApplyToActor(Actor child,
- const Vector2& positionExtent,
- const Vector2& offsetExtent,
- float positionScale,
- float scaleExtent)
-{
- ApplyScrollDepthConstraints( GetScrollView(), child, positionExtent, offsetExtent, positionScale, scaleExtent );
-}
-
-void ScrollViewDepthEffect::OnAttach(Toolkit::ScrollView& scrollView)
-{
-}
-
-void ScrollViewDepthEffect::OnDetach(Toolkit::ScrollView& scrollView)
-{
-}
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali