X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;ds=sidebyside;f=base%2Fdali-toolkit%2Finternal%2Fcontrols%2Fscrollable%2Fscroll-view%2Fscroll-overshoot-indicator-impl.cpp;h=e6876dc61c6c8be6e02dbae4517fafb368fea6e1;hb=b54d9cd65c353af149eb2bafa60ae02a825fd9c1;hp=4df873cc5f9303d1bd049a341b41edc30650a981;hpb=e58fa784d19a558e35f458ecf6d262a2344beb4f;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/base/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.cpp b/base/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.cpp index 4df873c..e6876dc 100644 --- a/base/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.cpp +++ b/base/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-overshoot-indicator-impl.cpp @@ -1,29 +1,52 @@ -// -// Copyright (c) 2014 Samsung Electronics Co., Ltd. -// -// Licensed under the Flora License, Version 1.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://floralicense.org/license/ -// -// 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. -// - +/* + * 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. + * + */ + +// CLASS HEADER #include // EXTERNAL INCLUDES #include +// INTERNAL INCLUDES #include +#include #include using namespace Dali; +namespace +{ +const float DEFAULT_MAX_OVERSHOOT_HEIGHT = 36.0f; // 36 pixels +const Vector2 OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE( 720.0f, 42.0f ); +const float OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD = 180.0f; + +// local helper function to resize the height of the bounce actor +float GetBounceActorHeight( float width ) +{ + return (width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD) ? OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height : OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height * 0.5f; +} + +const float DEFAULT_OVERSHOOT_ANIMATION_DURATION = 0.35f; // time in seconds +const float MAX_OVERSHOOT_NOTIFY_AMOUNT = 0.9f; // maximum amount to set notification for increased overshoot, beyond this we just wait for it to reduce again +const float MIN_OVERSHOOT_NOTIFY_AMOUNT = Math::MACHINE_EPSILON_1; // minimum amount to set notification for reduced overshoot, beyond this we just wait for it to increase again +const float OVERSHOOT_NOTIFY_STEP = 0.1f; // amount to set notifications beyond current overshoot value + +} + namespace Dali { @@ -33,14 +56,7 @@ namespace Toolkit namespace Internal { -const char* OVERSHOOT_OVERLAY_IMAGE_PATH = DALI_IMAGE_DIR "scroll_overshoot.png"; -const char* OVERSHOOT_OVERLAY_RIPPLE_IMAGE_PATH = DALI_IMAGE_DIR "overshoot_ripple.png"; -const float DEFAULT_MAX_OVERSHOOT_HEIGHT = 36.0f; // 36 pixels -const Rect OVERSHOOT_RIPPLE_IMAGE_1_PIXEL_AREA( 0, 0, 720, 58 ); -const float DEFAULT_OVERSHOOT_ANIMATION_DURATION = 0.35f; // time in seconds - -ScrollOvershootIndicator::ScrollOvershootIndicator(Scrollable& scrollable) : - mScrollable(scrollable), +ScrollOvershootIndicator::ScrollOvershootIndicator() : mEffectX(NULL), mEffectY(NULL) { @@ -51,575 +67,340 @@ ScrollOvershootIndicator::~ScrollOvershootIndicator() } -ScrollOvershootIndicator* ScrollOvershootIndicator::New(Scrollable& scrollable) +ScrollOvershootIndicator* ScrollOvershootIndicator::New() { - ScrollOvershootIndicator* scrollOvershootPtr = new ScrollOvershootIndicator(scrollable); + ScrollOvershootIndicator* scrollOvershootPtr = new ScrollOvershootIndicator(); return scrollOvershootPtr; } -void ScrollOvershootIndicator::Enable(bool enable) +void ScrollOvershootIndicator::AttachToScrollable(Scrollable& scrollable) { - if(enable) + if(!mEffectX) { - Actor scrollableActor = mScrollable.Self(); - if(!mEffectX) - { - mEffectX = ScrollOvershootEffectRipple::New(false); - } - mEffectX->Apply(mScrollable); - if(!mEffectY) - { - mEffectY = ScrollOvershootEffectRipple::New(true); - } - mEffectY->Apply(mScrollable); - mEffectY->SetPropertyNotifications(scrollableActor); + mEffectX = ScrollOvershootEffectRipple::New(false, scrollable); } - else + mEffectX->Apply(); + if(!mEffectY) { - if(mEffectX) - { - mEffectX->Remove(mScrollable); - } - if(mEffectY) - { - mEffectY->Remove(mScrollable); - } + mEffectY = ScrollOvershootEffectRipple::New(true, scrollable); } + mEffectY->Apply(); } -void ScrollOvershootIndicator::Reset() +void ScrollOvershootIndicator::DetachFromScrollable(Scrollable& scrollable) { - mEffectX->Reset(); - mEffectY->Reset(); -} - -ScrollOvershootEffect::ScrollOvershootEffect(bool vertical) : - mVertical(vertical) -{ - -} - -ScrollOvershootEffectGradient::ScrollOvershootEffectGradient(bool vertical) : - ScrollOvershootEffect(vertical), - mMaxOvershootImageSize(DEFAULT_MAX_OVERSHOOT_HEIGHT) -{ - Image overshootImage = Image::New( OVERSHOOT_OVERLAY_IMAGE_PATH ); - mOvershootImage = ImageActor::New( overshootImage ); - mOvershootImage.SetParentOrigin(ParentOrigin::TOP_LEFT); - mOvershootImage.SetAnchorPoint(AnchorPoint::TOP_LEFT); - mOvershootImage.SetDrawMode(DrawMode::OVERLAY); -} - -void ScrollOvershootEffectGradient::Apply(Scrollable& scrollable) -{ - Actor scrollableActor = scrollable.Self(); - int overshootXPropertyIndex = scrollableActor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_X_PROPERTY_NAME); - int overshootYPropertyIndex = scrollableActor.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_Y_PROPERTY_NAME); - - Constraint constraint = Constraint::New( Actor::SIZE, - Source( scrollableActor, overshootXPropertyIndex ), - Source( scrollableActor, overshootYPropertyIndex ), - Source( scrollableActor, Actor::SIZE ), - boost::bind( &ScrollOvershootEffectGradient::SizeConstraint, this, _1, _2, _3, _4) ); - mSizeConstraint = mOvershootImage.ApplyConstraint(constraint); - - constraint = Constraint::New( Actor::ROTATION, - Source( scrollableActor, overshootXPropertyIndex ), - Source( scrollableActor, overshootYPropertyIndex ), - boost::bind( &ScrollOvershootEffectGradient::RotationConstraint, this, _1, _2, _3) ); - mRotationConstraint = mOvershootImage.ApplyConstraint(constraint); - - constraint = Constraint::New( Actor::POSITION, - Source( scrollableActor, Actor::SIZE ), - Source( scrollableActor, overshootXPropertyIndex ), - Source( scrollableActor, overshootYPropertyIndex ), - boost::bind( &ScrollOvershootEffectGradient::PositionConstraint, this, _1, _2, _3, _4) ); - mPositionConstraint = mOvershootImage.ApplyConstraint(constraint); - - constraint = Constraint::New( Actor::VISIBLE, - Source( scrollableActor, IsVertical() ? scrollableActor.GetPropertyIndex(Scrollable::SCROLLABLE_CAN_SCROLL_VERTICAL) : scrollableActor.GetPropertyIndex(Scrollable::SCROLLABLE_CAN_SCROLL_HORIZONTAL)), - boost::bind( &ScrollOvershootEffectGradient::VisibilityConstraint, this, _1, _2) ); - mVisibilityConstraint = mOvershootImage.ApplyConstraint(constraint); - scrollable.AddOverlay(mOvershootImage); - SetPropertyNotifications(scrollableActor); -} - -void ScrollOvershootEffectGradient::Remove(Scrollable& scrollable) -{ - if(mOvershootImage) + if(mEffectX) { - if(mSizeConstraint) - { - mOvershootImage.RemoveConstraint(mSizeConstraint); - mSizeConstraint = NULL; - } - if(mRotationConstraint) - { - mOvershootImage.RemoveConstraint(mRotationConstraint); - mRotationConstraint = NULL; - } - if(mPositionConstraint) - { - mOvershootImage.RemoveConstraint(mPositionConstraint); - mPositionConstraint = NULL; - } - if(mVisibilityConstraint) - { - mOvershootImage.RemoveConstraint(mVisibilityConstraint); - mVisibilityConstraint = NULL; - } - scrollable.RemoveOverlay(mOvershootImage); + mEffectX->Remove(scrollable); + } + if(mEffectY) + { + mEffectY->Remove(scrollable); } } -Vector3 ScrollOvershootEffectGradient::SizeConstraint(const Vector3& current, - const PropertyInput& overshootPropertyX, const PropertyInput& overshootPropertyY, - const PropertyInput& parentSizeProperty) +void ScrollOvershootIndicator::Reset() { - float overshootx = overshootPropertyX.GetFloat(); - float overshooty = overshootPropertyY.GetFloat(); - const Vector3 parentSize = parentSizeProperty.GetVector3(); - - float overlayWidth = IsVertical() ? parentSize.x : parentSize.y; - float overlayHeight = mMaxOvershootImageSize * fabsf(IsVertical() ? overshooty : overshootx); - - return Vector3(overlayWidth, overlayHeight, current.z); + mEffectX->Reset(); + mEffectY->Reset(); } -Quaternion ScrollOvershootEffectGradient::RotationConstraint(const Quaternion& current, - const PropertyInput& overshootPropertyX, const PropertyInput& overshootPropertyY) +void ScrollOvershootIndicator::SetOvershootEffectColor( const Vector4& color ) { - float overshootx = overshootPropertyX.GetFloat(); - float overshooty = overshootPropertyY.GetFloat(); - - Quaternion rotation; - - if(IsVertical()) + if(mEffectX) { - if(overshooty < -Math::MACHINE_EPSILON_0) - { - rotation = Quaternion(Math::PI, Vector3::ZAXIS); - } - else if(overshooty > Math::MACHINE_EPSILON_0) - { - rotation = Quaternion(0.0f, Vector3::ZAXIS); - } + mEffectX->SetOvershootEffectColor(color); } - else + if(mEffectY) { - if(overshootx < -Math::MACHINE_EPSILON_0) - { - rotation = Quaternion(0.5f * Math::PI, Vector3::ZAXIS); - } - else if(overshootx > Math::MACHINE_EPSILON_0) - { - rotation = Quaternion(1.5f * Math::PI, Vector3::ZAXIS); - } + mEffectY->SetOvershootEffectColor(color); } - - return rotation; } -Vector3 ScrollOvershootEffectGradient::PositionConstraint(const Vector3& current, - const PropertyInput& parentSizeProperty, - const PropertyInput& overshootPropertyX, const PropertyInput& overshootPropertyY) +void ScrollOvershootIndicator::ClearOvershoot() { - float overshootx = overshootPropertyX.GetFloat(); - float overshooty = overshootPropertyY.GetFloat(); - const Vector3 parentSize = parentSizeProperty.GetVector3(); - - Vector3 relativeOffset = Vector3::ZERO; - - if(IsVertical()) + if(mEffectX) { - if(overshooty > Math::MACHINE_EPSILON_0) - { - relativeOffset = Vector3(0.0f, 0.0f, 0.0f); - } - else if (overshooty < -Math::MACHINE_EPSILON_0) - { - relativeOffset = Vector3(1.0f, 1.0f, 0.0f); - } + mEffectX->SetOvershoot(0.0f); } - else + if(mEffectY) { - if(overshootx > Math::MACHINE_EPSILON_0) - { - relativeOffset = Vector3(0.0f, 1.0f, 0.0f); - } - else if (overshootx < -Math::MACHINE_EPSILON_0) - { - relativeOffset = Vector3(1.0f, 0.0f, 0.0f); - } + mEffectY->SetOvershoot(0.0f); } - - return relativeOffset * parentSize; -} - -bool ScrollOvershootEffectGradient::VisibilityConstraint(const bool& current, - const PropertyInput& canScrollProperty) -{ - return canScrollProperty.GetBoolean(); } -ScrollOvershootEffectGradientPtr ScrollOvershootEffectGradient::New(bool vertical) -{ - return new ScrollOvershootEffectGradient(vertical); -} - -namespace -{ - -const std::string OVERSHOOT_PROPERTY_NAME( "uOvershoot" ); -const std::string OVERSHOOT_IMAGE_COUNT_PROPERTY_NAME( "uOvershootImageCount" ); - -} // namespace - -OvershootRippleEffect::OvershootRippleEffect() -{ -} - -//Call the Parent copy constructor to add reference to the implementation for this object -OvershootRippleEffect::OvershootRippleEffect(ShaderEffect handle) -:ShaderEffect(handle) -{ -} - -OvershootRippleEffect::~OvershootRippleEffect() -{ -} - -OvershootRippleEffect OvershootRippleEffect::New() -{ - std::string vertextShader( - "precision mediump float; \n" - "uniform float uOvershoot; \n" - "uniform float uOvershootImageCount; \n" - "void main() \n" - "{ \n" - " gl_Position = uProjection * uModelView * vec4(aPosition, 1.0); \n" - " vTexCoord = aTexCoord; \n" - " vTexCoord.y += (1.0 / uOvershootImageCount) * min(floor((abs(uOvershoot) * (uOvershootImageCount - 1.0)) + 0.5), (uOvershootImageCount - 1.0)); \n" - "} \n" ); - - std::string fragmentShader( - "void main() \n" - "{ \n" - " gl_FragColor = texture2D(sTexture, vTexCoord); \n" - "} \n" ); - - // Create the implementation, temporarily owned on stack, - Dali::ShaderEffect shaderEffectCustom = Dali::ShaderEffect::New( - vertextShader, - fragmentShader); - - /* Pass ownership to OvershootRippleEffect through overloaded constructor, So that it now has access to the - Dali::ShaderEffect implementation */ - OvershootRippleEffect handle( shaderEffectCustom ); - handle.SetUniform(OVERSHOOT_PROPERTY_NAME, 0.0f); - handle.SetUniform(OVERSHOOT_IMAGE_COUNT_PROPERTY_NAME, 10.0f); - return handle; -} - -void OvershootRippleEffect::SetOvershoot( float overshoot ) +ScrollOvershootEffect::ScrollOvershootEffect( bool vertical ) : + mVertical(vertical) { - SetUniform( OVERSHOOT_PROPERTY_NAME, overshoot ); -} -void OvershootRippleEffect::SetOvershootImageCount( float imageCount ) -{ - SetUniform( OVERSHOOT_IMAGE_COUNT_PROPERTY_NAME, imageCount ); } -const std::string& OvershootRippleEffect::GetOvershootPropertyName() const +bool ScrollOvershootEffect::IsVertical() const { - return OVERSHOOT_PROPERTY_NAME; + return mVertical; } -const std::string& OvershootRippleEffect::GetOvershootImageCountPropertyName() const +ScrollOvershootEffectRipple::ScrollOvershootEffectRipple( bool vertical, Scrollable& scrollable ) : + ScrollOvershootEffect( vertical ), + mAttachedScrollView(scrollable), + mCanScrollPropertyIndex(Property::INVALID_INDEX), + mOvershootProperty(Property::INVALID_INDEX), + mEffectOvershootProperty(Property::INVALID_INDEX), + mMaxOvershootImageSize(DEFAULT_MAX_OVERSHOOT_HEIGHT), + mOvershootAnimationDuration(DEFAULT_OVERSHOOT_ANIMATION_DURATION), + mOvershoot(0.0f), + mAnimationStateFlags(0) { - return OVERSHOOT_IMAGE_COUNT_PROPERTY_NAME; -} + mOvershootOverlay = CreateBouncingEffectActor(mEffectOvershootProperty); + mOvershootOverlay.SetColor(mAttachedScrollView.GetOvershootEffectColor()); + mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT); + mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT); + mOvershootOverlay.SetDrawMode(DrawMode::OVERLAY); + mOvershootOverlay.SetVisible(false); -ScrollOvershootEffectRipple::ScrollOvershootEffectRipple(bool vertical) : - ScrollOvershootEffect(vertical), - mMaxOvershootImageSize(DEFAULT_MAX_OVERSHOOT_HEIGHT) -{ - mRippleEffect = OvershootRippleEffect::New(); - Image overshootImage = Image::New( OVERSHOOT_OVERLAY_RIPPLE_IMAGE_PATH ); - mOvershootImage = ImageActor::New( overshootImage ); - mOvershootImage.SetParentOrigin(ParentOrigin::TOP_LEFT); - mOvershootImage.SetAnchorPoint(AnchorPoint::TOP_LEFT); - mOvershootImage.SetDrawMode(DrawMode::OVERLAY); - mOvershootImage.SetShaderEffect(mRippleEffect); - mOvershootImage.SetPixelArea(OVERSHOOT_RIPPLE_IMAGE_1_PIXEL_AREA); - mOvershootImage.SetVisible(false); - mAnimatingOvershootOn = false; - mAnimateOvershootOff = false; } -void ScrollOvershootEffectRipple::Apply(Scrollable& scrollable) +void ScrollOvershootEffectRipple::Apply() { - Actor scrollableActor = scrollable.Self(); + Actor self = mAttachedScrollView.Self(); + mOvershootProperty = self.GetPropertyIndex(IsVertical() ? Toolkit::ScrollView::SCROLL_OVERSHOOT_Y_PROPERTY_NAME : Toolkit::ScrollView::SCROLL_OVERSHOOT_X_PROPERTY_NAME); + mCanScrollPropertyIndex = self.GetPropertyIndex(IsVertical() ? Scrollable::SCROLLABLE_CAN_SCROLL_VERTICAL : Scrollable::SCROLLABLE_CAN_SCROLL_HORIZONTAL); // make sure height is set, since we only create a constraint for image width - mOvershootImage.SetSize(OVERSHOOT_RIPPLE_IMAGE_1_PIXEL_AREA.width, OVERSHOOT_RIPPLE_IMAGE_1_PIXEL_AREA.height); + mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.width, OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height); - UpdateConstraints(scrollableActor); - scrollable.AddOverlay(mOvershootImage); + mAttachedScrollView.AddOverlay(mOvershootOverlay); - SetPropertyNotifications(scrollableActor); + UpdatePropertyNotifications(); } -void ScrollOvershootEffectRipple::Remove(Scrollable& scrollable) +void ScrollOvershootEffectRipple::Remove( Scrollable& scrollable ) { - if(mOvershootImage) + if(mOvershootOverlay) { - if(mSizeConstraint) + if(mOvershootIncreaseNotification) { - mOvershootImage.RemoveConstraint(mSizeConstraint); - mSizeConstraint = NULL; + scrollable.Self().RemovePropertyNotification(mOvershootIncreaseNotification); + mOvershootIncreaseNotification.Reset(); } - if(mPositionConstraint) + if(mOvershootDecreaseNotification) { - mOvershootImage.RemoveConstraint(mPositionConstraint); - mPositionConstraint = NULL; + scrollable.Self().RemovePropertyNotification(mOvershootDecreaseNotification); + mOvershootDecreaseNotification.Reset(); } - scrollable.RemoveOverlay(mOvershootImage); + scrollable.RemoveOverlay(mOvershootOverlay); } } void ScrollOvershootEffectRipple::Reset() { - mAnimatingOvershootOn = false; - mAnimateOvershootOff = false; - mOvershootImage.SetVisible(false); - mRippleEffect.SetUniform(mRippleEffect.GetOvershootPropertyName(), 0.0f); - if(mScrollOvershootAnimation) - { - mScrollOvershootAnimation.Clear(); - mScrollOvershootAnimation.Reset(); - } + mOvershootOverlay.SetVisible(false); + mOvershootOverlay.SetProperty( mEffectOvershootProperty, 0.f); } -void ScrollOvershootEffectRipple::UpdateConstraints(Actor& scrollable) +void ScrollOvershootEffectRipple::UpdatePropertyNotifications() { - int overshootPropertyIndex = mRippleEffect.GetPropertyIndex(mRippleEffect.GetOvershootPropertyName()); - Constraint constraint; - if(!mSizeConstraint) - { - constraint = Constraint::New( Actor::SIZE_WIDTH, - Source( scrollable, IsVertical() ? Actor::SIZE_WIDTH : Actor::SIZE_HEIGHT), - EqualToConstraint() ); - mSizeConstraint = mOvershootImage.ApplyConstraint(constraint); - } + float absOvershoot = fabsf(mOvershoot); - if(!mPositionConstraint) + Actor self = mAttachedScrollView.Self(); + // update overshoot increase notify + if( mOvershootIncreaseNotification ) { - constraint = Constraint::New( Actor::POSITION, - Source( scrollable, Actor::SIZE ), - Source( mRippleEffect, overshootPropertyIndex ), - boost::bind( &ScrollOvershootEffectRipple::PositionConstraint, this, _1, _2, _3) ); - mPositionConstraint = mOvershootImage.ApplyConstraint(constraint); + self.RemovePropertyNotification( mOvershootIncreaseNotification ); + mOvershootIncreaseNotification.Reset(); } -} - -void ScrollOvershootEffectRipple::SetPropertyNotifications(Actor& scrollable) -{ - int overshootXPropertyIndex = scrollable.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_X_PROPERTY_NAME); - int overshootYPropertyIndex = scrollable.GetPropertyIndex(Toolkit::ScrollView::SCROLL_OVERSHOOT_Y_PROPERTY_NAME); - mCanScrollPropertyIndex = scrollable.GetPropertyIndex(IsVertical() ? Scrollable::SCROLLABLE_CAN_SCROLL_VERTICAL : Scrollable::SCROLLABLE_CAN_SCROLL_HORIZONTAL); - if(scrollable.OnStage()) + if( absOvershoot < MAX_OVERSHOOT_NOTIFY_AMOUNT ) { - if(!mOvershootNegativeNotification) + float increaseStep = absOvershoot + OVERSHOOT_NOTIFY_STEP; + if( increaseStep > MAX_OVERSHOOT_NOTIFY_AMOUNT ) { - mOvershootNegativeNotification = scrollable.AddPropertyNotification(IsVertical() ? overshootYPropertyIndex : overshootXPropertyIndex, LessThanCondition(-Math::MACHINE_EPSILON_1)); - mOvershootNegativeNotification.SetNotifyMode(PropertyNotification::NotifyOnChanged); - mOvershootNegativeNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnNegativeOvershootNotification); - } - - if(!mOvershootPositiveNotification) - { - mOvershootPositiveNotification = scrollable.AddPropertyNotification(IsVertical() ? overshootYPropertyIndex : overshootXPropertyIndex, GreaterThanCondition(Math::MACHINE_EPSILON_1)); - mOvershootPositiveNotification.SetNotifyMode(PropertyNotification::NotifyOnChanged); - mOvershootPositiveNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnPositiveOvershootNotification); + increaseStep = MAX_OVERSHOOT_NOTIFY_AMOUNT; } + mOvershootIncreaseNotification = self.AddPropertyNotification( mOvershootProperty, OutsideCondition(-increaseStep, increaseStep) ); + mOvershootIncreaseNotification.SetNotifyMode(PropertyNotification::NotifyOnTrue); + mOvershootIncreaseNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnOvershootNotification); } -} - -Vector3 ScrollOvershootEffectRipple::PositionConstraint(const Vector3& current, - const PropertyInput& parentSizeProperty, const PropertyInput& overshootProperty) -{ - float overshoot = overshootProperty.GetFloat(); - const Vector3 parentSize = parentSizeProperty.GetVector3(); - - Vector3 relativeOffset = Vector3::ZERO; - if(IsVertical()) + // update overshoot decrease notify + if( mOvershootDecreaseNotification ) { - if(overshoot > Math::MACHINE_EPSILON_0) - { - relativeOffset = Vector3(0.0f, 0.0f, 0.0f); - } - else if (overshoot < -Math::MACHINE_EPSILON_0) - { - relativeOffset = Vector3(1.0f, 1.0f, 0.0f); - } + self.RemovePropertyNotification( mOvershootDecreaseNotification ); + mOvershootDecreaseNotification.Reset(); } - else + if( absOvershoot > MIN_OVERSHOOT_NOTIFY_AMOUNT ) { - if(overshoot > Math::MACHINE_EPSILON_0) - { - relativeOffset = Vector3(0.0f, 1.0f, 0.0f); - } - else if (overshoot < -Math::MACHINE_EPSILON_0) + float reduceStep = absOvershoot - OVERSHOOT_NOTIFY_STEP; + if( reduceStep < MIN_OVERSHOOT_NOTIFY_AMOUNT ) { - relativeOffset = Vector3(1.0f, 0.0f, 0.0f); + reduceStep = MIN_OVERSHOOT_NOTIFY_AMOUNT; } + mOvershootDecreaseNotification = self.AddPropertyNotification( mOvershootProperty, InsideCondition(-reduceStep, reduceStep) ); + mOvershootDecreaseNotification.SetNotifyMode(PropertyNotification::NotifyOnTrue); + mOvershootDecreaseNotification.NotifySignal().Connect(this, &ScrollOvershootEffectRipple::OnOvershootNotification); } - - return relativeOffset * parentSize; } -void ScrollOvershootEffectRipple::OnPositiveOvershootNotification(PropertyNotification& source) +void ScrollOvershootEffectRipple::SetOvershootEffectColor( const Vector4& color ) { - Actor delegate = Actor::DownCast(source.GetTarget()); - float overshoot = delegate.GetProperty(source.GetTargetProperty()); - bool canScroll = delegate.GetProperty(mCanScrollPropertyIndex); - if(!canScroll) + if(mOvershootOverlay) { - mOvershootImage.SetVisible(false); - return; + mOvershootOverlay.SetColor(color); } - mOvershootImage.SetVisible(true); +} - if (fabsf(overshoot) < Math::MACHINE_EPSILON_1) - { - AnimateScrollOvershoot(0.0f); - return; - } - if(overshoot > 0.0f) +void ScrollOvershootEffectRipple::UpdateVisibility( bool visible ) +{ + mOvershootOverlay.SetVisible(visible); + // make sure overshoot image is correctly placed + if( visible ) { - const Vector3 imageSize = mOvershootImage.GetCurrentSize(); - Vector3 relativeOffset = Vector3::ZERO; - const Vector3 parentSize = delegate.GetCurrentSize(); - AnimateScrollOvershoot(1.0f); - if(IsVertical()) + Actor self = mAttachedScrollView.Self(); + if(mOvershoot > 0.0f) { - mOvershootImage.SetRotation(Quaternion(0.0f, Vector3::ZAXIS)); - mOvershootImage.SetSize(parentSize.width, imageSize.height, imageSize.depth); - relativeOffset = Vector3(0.0f, 0.0f, 0.0f); + // positive overshoot + const Vector3 size = mOvershootOverlay.GetCurrentSize(); + Vector3 relativeOffset; + const Vector3 parentSize = self.GetCurrentSize(); + if(IsVertical()) + { + mOvershootOverlay.SetRotation(Quaternion(0.0f, Vector3::ZAXIS)); + mOvershootOverlay.SetSize(parentSize.width, GetBounceActorHeight(parentSize.width), size.depth); + } + else + { + mOvershootOverlay.SetRotation(Quaternion(1.5f * Math::PI, Vector3::ZAXIS)); + mOvershootOverlay.SetSize(parentSize.height, GetBounceActorHeight(parentSize.height), size.depth); + relativeOffset = Vector3(0.0f, 1.0f, 0.0f); + } + mOvershootOverlay.SetPosition(relativeOffset * parentSize); } else { - mOvershootImage.SetRotation(Quaternion(1.5f * Math::PI, Vector3::ZAXIS)); - mOvershootImage.SetSize(parentSize.height, imageSize.height, imageSize.depth); - relativeOffset = Vector3(0.0f, 1.0f, 0.0f); + // negative overshoot + const Vector3 size = mOvershootOverlay.GetCurrentSize(); + Vector3 relativeOffset; + const Vector3 parentSize = self.GetCurrentSize(); + if(IsVertical()) + { + mOvershootOverlay.SetRotation(Quaternion(Math::PI, Vector3::ZAXIS)); + mOvershootOverlay.SetSize(parentSize.width, GetBounceActorHeight(parentSize.width), size.depth); + relativeOffset = Vector3(1.0f, 1.0f, 0.0f); + } + else + { + mOvershootOverlay.SetRotation(Quaternion(0.5f * Math::PI, Vector3::ZAXIS)); + mOvershootOverlay.SetSize(parentSize.height, GetBounceActorHeight(parentSize.height), size.depth); + relativeOffset = Vector3(1.0f, 0.0f, 0.0f); + } + mOvershootOverlay.SetPosition(relativeOffset * parentSize); } - mOvershootImage.SetPosition(relativeOffset * parentSize); } } -void ScrollOvershootEffectRipple::OnNegativeOvershootNotification(PropertyNotification& source) +void ScrollOvershootEffectRipple::OnOvershootNotification(PropertyNotification& source) { - Actor delegate = Actor::DownCast(source.GetTarget()); - float overshoot = delegate.GetProperty(source.GetTargetProperty()); - bool canScroll = delegate.GetProperty(mCanScrollPropertyIndex); - if(!canScroll) + Actor self = mAttachedScrollView.Self(); + mOvershoot = self.GetProperty(mOvershootProperty); + if( source == mOvershootIncreaseNotification ) { - mOvershootImage.SetVisible(false); - return; - } - mOvershootImage.SetVisible(true); - - if (fabsf(overshoot) < Math::MACHINE_EPSILON_1) - { - AnimateScrollOvershoot(0.0f); - return; - } - - if(overshoot < 0.0f) - { - const Vector3 imageSize = mOvershootImage.GetCurrentSize(); - Vector3 relativeOffset = Vector3::ZERO; - const Vector3 parentSize = delegate.GetCurrentSize(); - AnimateScrollOvershoot(-1.0f); - if(IsVertical()) + if( mOvershoot > Math::MACHINE_EPSILON_0 ) { - mOvershootImage.SetRotation(Quaternion(Math::PI, Vector3::ZAXIS)); - mOvershootImage.SetSize(parentSize.width, imageSize.height, imageSize.depth); - relativeOffset = Vector3(1.0f, 1.0f, 0.0f); + SetOvershoot(1.0f); } - else + else if ( mOvershoot < -Math::MACHINE_EPSILON_0 ) { - mOvershootImage.SetRotation(Quaternion(0.5f * Math::PI, Vector3::ZAXIS)); - mOvershootImage.SetSize(parentSize.height, imageSize.height, imageSize.depth); - relativeOffset = Vector3(1.0f, 0.0f, 0.0f); + SetOvershoot(-1.0f); } - mOvershootImage.SetPosition(relativeOffset * parentSize); } + else if( source == mOvershootDecreaseNotification ) + { + SetOvershoot(0.0f); + // overshoot reducing + } + UpdatePropertyNotifications(); } -void ScrollOvershootEffectRipple::AnimateScrollOvershoot(float overshootAmount) +void ScrollOvershootEffectRipple::SetOvershoot(float amount, bool animate) { - bool animatingOn = fabsf(overshootAmount) > Math::MACHINE_EPSILON_1; - - // make sure we animate back if needed - mAnimateOvershootOff = (!animatingOn && mAnimatingOvershootOn); - - int overShootProperty = mRippleEffect.GetPropertyIndex(mRippleEffect.GetOvershootPropertyName()); - float currentOvershoot = mRippleEffect.GetProperty(overShootProperty); - if(((currentOvershoot < 0.0f && overshootAmount > 0.0f) - || (currentOvershoot > 0.0f && overshootAmount < 0.0f))) + float absAmount = fabsf(amount); + bool animatingOn = absAmount > Math::MACHINE_EPSILON_0; + if( (animatingOn && (mAnimationStateFlags & AnimatingIn)) ) { - // cancel current animation - mAnimatingOvershootOn = false; - // reset currentOvershoot to 0.0f - mRippleEffect.SetProperty(overShootProperty, 0.0f); - currentOvershoot = 0.0f; + // trying to do what we are already doing + if( mAnimationStateFlags & AnimateBack ) + { + mAnimationStateFlags &= ~AnimateBack; + } + return; } - if( mAnimatingOvershootOn ) + if( (!animatingOn && (mAnimationStateFlags & AnimatingOut)) ) { - // animating on in same direction, do not allow animate off + // trying to do what we are already doing return; } - float duration = DEFAULT_OVERSHOOT_ANIMATION_DURATION * (animatingOn ? (1.0f - fabsf(currentOvershoot)) : fabsf(currentOvershoot)); - - if(mScrollOvershootAnimation) + if( !animatingOn && (mAnimationStateFlags & AnimatingIn) ) { - mScrollOvershootAnimation.Clear(); - mScrollOvershootAnimation.Reset(); + // dont interrupt while animating on + mAnimationStateFlags |= AnimateBack; + return; } - mScrollOvershootAnimation = Animation::New(duration); - mScrollOvershootAnimation.FinishedSignal().Connect(this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished); - mScrollOvershootAnimation.AnimateTo( Property(mRippleEffect, overShootProperty), overshootAmount, TimePeriod(0.0f, duration) ); - mScrollOvershootAnimation.Play(); - - mOvershootImage.SetVisible(true); + // When we need to animate overshoot to 0 + if( mOvershootAnimationDuration > Math::MACHINE_EPSILON_1 ) + { + // setup the new overshoot to 0 animation + float currentOvershoot = fabsf( mOvershootOverlay.GetProperty( mEffectOvershootProperty ).Get() ); + float duration = mOvershootAnimationDuration * (animatingOn ? (1.0f - currentOvershoot) : currentOvershoot); - mAnimatingOvershootOn = animatingOn; + if( duration > Math::MACHINE_EPSILON_0 ) + { + if(mScrollOvershootAnimation) + { + mScrollOvershootAnimation.FinishedSignal().Disconnect( this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished ); + mScrollOvershootAnimation.Stop(); + mScrollOvershootAnimation.Reset(); + } + mScrollOvershootAnimation = Animation::New(duration); + mScrollOvershootAnimation.FinishedSignal().Connect( this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished ); + mScrollOvershootAnimation.AnimateTo( Property(mOvershootOverlay, mEffectOvershootProperty), amount, TimePeriod(duration) ); + mScrollOvershootAnimation.Play(); + mAnimationStateFlags = animatingOn ? AnimatingIn : AnimatingOut; + } + } + else + { + mOvershootOverlay.SetProperty( mEffectOvershootProperty, amount); + } + if( absAmount > Math::MACHINE_EPSILON_1 ) + { + UpdateVisibility(true); + } } void ScrollOvershootEffectRipple::OnOvershootAnimFinished(Animation& animation) { - if(!mAnimatingOvershootOn && !mAnimateOvershootOff) + bool animateOff = false; + if( mAnimationStateFlags & AnimatingOut ) + { + // should now be offscreen + mOvershootOverlay.SetVisible(false); + } + if( (mAnimationStateFlags & AnimateBack) ) { - // just finished animating overshoot to 0 - mOvershootImage.SetVisible(false); + animateOff = true; } - mAnimatingOvershootOn = false; - mScrollOvershootAnimation.FinishedSignal().Disconnect(this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished); - mScrollOvershootAnimation.Clear(); + mScrollOvershootAnimation.FinishedSignal().Disconnect( this, &ScrollOvershootEffectRipple::OnOvershootAnimFinished ); + mScrollOvershootAnimation.Stop(); mScrollOvershootAnimation.Reset(); - if(mAnimateOvershootOff) + mAnimationStateFlags = 0; + if( animateOff ) { - AnimateScrollOvershoot(0.0f); + SetOvershoot(0.0f, true); } } -ScrollOvershootEffectRipplePtr ScrollOvershootEffectRipple::New(bool vertical) +ScrollOvershootEffectRipplePtr ScrollOvershootEffectRipple::New( bool vertical, Scrollable& scrollable ) { - return new ScrollOvershootEffectRipple(vertical); + return new ScrollOvershootEffectRipple(vertical, scrollable); } } // namespace Internal