X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=base%2Fdali-toolkit%2Finternal%2Fcontrols%2Fscrollable%2Fitem-view%2Fitem-view-impl.cpp;h=03fe7b447e703c45301b86155522b710a56f02b5;hb=bc67da251f806cfa64940c3799eeafb1fc6d8c73;hp=ea5341f14bc321bc86fde771056908317e1387ca;hpb=cf229fa2e4f00e5fe727eab2d215868bf79ac524;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp b/base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp index ea5341f..03fe7b4 100644 --- a/base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp +++ b/base/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp @@ -1,18 +1,19 @@ -// -// 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 @@ -24,7 +25,7 @@ #include #include #include -#include +#include using namespace std; using namespace Dali; @@ -47,7 +48,8 @@ const float DEFAULT_COLOR_VISIBILITY_REMOVE_TIME = 0.5f; // 0.5 second const float MILLISECONDS_PER_SECONDS = 1000.0f; -const Rect OVERSHOOT_BOUNCE_IMAGE_1_PIXEL_AREA( 0, 0, 720, 58 ); +const Vector2 OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE( 720.0f, 42.0f ); +const float OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD = 180.0f; const Vector4 OVERSHOOT_OVERLAY_NINE_PATCH_BORDER(0.0f, 0.0f, 1.0f, 12.0f); const float MAXIMUM_OVERSHOOT_HEIGHT = 36.0f; // 36 pixels const float DEFAULT_OVERSHOOT_ANIMATION_DURATION = 0.5f; // 0.5 second @@ -155,7 +157,7 @@ float CalculateScrollDistance(Vector2 panDistance, Toolkit::ItemLayout& layout) struct OvershootOverlaySizeConstraint { - float operator()(const float& current, + Vector3 operator()(const Vector3& current, const PropertyInput& parentScrollDirectionProperty, const PropertyInput& parentOvershootProperty, const PropertyInput& parentSizeProperty) @@ -175,7 +177,9 @@ struct OvershootOverlaySizeConstraint overlayWidth = fabsf(parentScrollDirection.x) > Math::MACHINE_EPSILON_1 ? parentSize.y : parentSize.x; } - return overlayWidth; + float overlayHeight = (overlayWidth > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD) ? OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height : OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height*0.5f; + + return Vector3( overlayWidth, overlayHeight, current.depth ); } }; @@ -400,7 +404,7 @@ ItemView::ItemView(ItemFactory& factory) mAnimateOvershootOff(false), mAnchoringEnabled(true), mAnchoringDuration(DEFAULT_ANCHORING_DURATION), - mRefreshIntervalLayoutPositions(DEFAULT_REFRESH_INTERVAL_LAYOUT_POSITIONS), + mRefreshIntervalLayoutPositions(0.0f), mRefreshOrderHint(true/*Refresh item 0 first*/), mMinimumSwipeSpeed(DEFAULT_MINIMUM_SWIPE_SPEED), mMinimumSwipeDistance(DEFAULT_MINIMUM_SWIPE_DISTANCE), @@ -429,6 +433,7 @@ void ItemView::OnInitialize() mScrollConnector = Dali::Toolkit::ScrollConnector::New(); mScrollPositionObject = mScrollConnector.GetScrollPositionObject(); + mScrollConnector.ScrollPositionChangedSignal().Connect( this, &ItemView::OnScrollPositionChanged ); mPropertyMinimumLayoutPosition = self.RegisterProperty(MINIMUM_LAYOUT_POSITION_PROPERTY_NAME, 0.0f); mPropertyPosition = self.RegisterProperty(POSITION_PROPERTY_NAME, 0.0f); @@ -452,7 +457,7 @@ void ItemView::OnInitialize() mMouseWheelEventFinishedTimer = Timer::New( MOUSE_WHEEL_EVENT_FINISHED_TIME_OUT ); mMouseWheelEventFinishedTimer.TickSignal().Connect( this, &ItemView::OnMouseWheelEventFinished ); - SetRefreshInterval(mRefreshIntervalLayoutPositions); + SetRefreshInterval(DEFAULT_REFRESH_INTERVAL_LAYOUT_POSITIONS); } ItemView::~ItemView() @@ -498,13 +503,15 @@ ItemLayoutPtr ItemView::GetActiveLayout() const float ItemView::GetCurrentLayoutPosition(unsigned int itemId) const { - return mScrollPositionObject.GetProperty( ScrollConnector::SCROLL_POSITION ) + static_cast( itemId ); + return mScrollConnector.GetScrollPosition() + static_cast( itemId ); } void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSize, float durationSeconds) { DALI_ASSERT_ALWAYS(layoutIndex < mLayouts.size()); + mRefreshEnabled = false; + Actor self = Self(); // The ItemView size should match the active layout size @@ -558,7 +565,7 @@ void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSiz } // Refresh the new layout - ItemRange range = GetItemRange(*mActiveLayout, targetSize, GetCurrentLayoutPosition(0), true/*reserve extra*/); + ItemRange range = GetItemRange(*mActiveLayout, targetSize, GetCurrentLayoutPosition(0), false/* don't reserve extra*/); AddActorsWithinRange( range, durationSeconds ); // Scroll to an appropriate layout position @@ -584,9 +591,10 @@ void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSiz if (scrollAnimationNeeded) { RemoveAnimation(mScrollAnimation); - mScrollAnimation = Animation::New(mAnchoringDuration); + mScrollAnimation = Animation::New(durationSeconds); mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut ); mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, targetSize), AlphaFunctions::EaseOut ); + mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnLayoutActivationScrollFinished); mScrollAnimation.Play(); } @@ -629,7 +637,7 @@ AlphaFunction ItemView::GetDefaultAlphaFunction() const void ItemView::OnRefreshNotification(PropertyNotification& source) { - if(mRefreshEnabled) + if(mRefreshEnabled || mScrollAnimation) { // Only refresh the cache during normal scrolling DoRefresh(GetCurrentLayoutPosition(0), true); @@ -700,14 +708,17 @@ float ItemView::GetAnchoringDuration() const void ItemView::SetRefreshInterval(float intervalLayoutPositions) { - mRefreshIntervalLayoutPositions = intervalLayoutPositions; - - if(mRefreshNotification) + if(mRefreshIntervalLayoutPositions != intervalLayoutPositions) { - mScrollPositionObject.RemovePropertyNotification(mRefreshNotification); + mRefreshIntervalLayoutPositions = intervalLayoutPositions; + + if(mRefreshNotification) + { + mScrollPositionObject.RemovePropertyNotification(mRefreshNotification); + } + mRefreshNotification = mScrollPositionObject.AddPropertyNotification( ScrollConnector::SCROLL_POSITION, StepCondition(mRefreshIntervalLayoutPositions, 0.0f) ); + mRefreshNotification.NotifySignal().Connect( this, &ItemView::OnRefreshNotification ); } - mRefreshNotification = mScrollPositionObject.AddPropertyNotification( ScrollConnector::SCROLL_POSITION, StepCondition(mRefreshIntervalLayoutPositions, 0.0f) ); - mRefreshNotification.NotifySignal().Connect( this, &ItemView::OnRefreshNotification ); } float ItemView::GetRefreshInterval() const @@ -895,7 +906,8 @@ bool ItemView::RemoveActor(unsigned int itemId) if( removeIter != mItemPool.end() ) { - Self().Remove( removeIter->second ); + ReleaseActor(itemId, removeIter->second); + removed = true; // Adjust the remaining item IDs, for example if item 2 is removed: @@ -931,7 +943,7 @@ void ItemView::ReplaceItem( Item replacementItem, float durationSeconds ) const ItemPoolIter iter = mItemPool.find( replacementItem.first ); if( mItemPool.end() != iter ) { - Self().Remove( iter->second ); + ReleaseActor(iter->first, iter->second); iter->second = replacementItem.second; } else @@ -961,7 +973,7 @@ void ItemView::RemoveActorsOutsideRange( ItemRange range ) if( ! range.Within( current ) ) { - Self().Remove( iter->second ); + ReleaseActor(iter->first, iter->second); mItemPool.erase( iter++ ); // erase invalidates the return value of post-increment; iter remains valid } @@ -1036,6 +1048,12 @@ void ItemView::SetupActor( Item item, float durationSeconds ) } } +void ItemView::ReleaseActor( ItemId item, Actor actor ) +{ + Self().Remove( actor ); + mItemFactory.ItemReleased(item, actor); +} + ItemRange ItemView::GetItemRange(ItemLayout& layout, const Vector3& layoutSize, float layoutPosition, bool reserveExtra) { unsigned int itemCount = mItemFactory.GetNumberOfItems(); @@ -1104,12 +1122,13 @@ bool ItemView::OnMouseWheelEvent(const MouseWheelEvent& event) { Actor self = Self(); const Vector3 layoutSize = Self().GetCurrentSize(); - float layoutPositionDelta = GetCurrentLayoutPosition(0) + (event.z * mMouseWheelScrollDistanceStep * mActiveLayout->GetScrollSpeedFactor()); + float layoutPositionDelta = GetCurrentLayoutPosition(0) - (event.z * mMouseWheelScrollDistanceStep * mActiveLayout->GetScrollSpeedFactor()); float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout); mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition ); self.SetProperty(mPropertyPosition, GetScrollPosition(firstItemScrollPosition, layoutSize)); mScrollStartedSignalV2.Emit(GetCurrentScrollPosition()); + mRefreshEnabled = true; } if (mMouseWheelEventFinishedTimer.IsRunning()) @@ -1336,28 +1355,24 @@ void ItemView::OnPan(PanGesture gesture) case Gesture::Started: // Fall through { mTotalPanDisplacement = Vector2::ZERO; + mScrollStartedSignalV2.Emit(GetCurrentScrollPosition()); + mRefreshEnabled = true; } case Gesture::Continuing: { mScrollDistance = CalculateScrollDistance(gesture.displacement, *mActiveLayout); - mScrollSpeed = Clamp((gesture.GetSpeed() * mActiveLayout->GetScrollSpeedFactor() * MILLISECONDS_PER_SECONDS), 0.0f, mActiveLayout->GetMaximumSwipeSpeed()); + mScrollSpeed = Clamp((gesture.GetSpeed() * mActiveLayout->GetFlickSpeedFactor() * MILLISECONDS_PER_SECONDS), 0.0f, mActiveLayout->GetMaximumSwipeSpeed()); // Refresh order depends on the direction of the scroll; negative is towards the last item. mRefreshOrderHint = mScrollDistance < 0.0f; - RemoveAnimation(mScrollSpeedAnimation); - mScrollSpeedAnimation = Animation::New(0.3f); - mScrollSpeedAnimation.AnimateTo( Property(self, mPropertyScrollSpeed), mScrollSpeed, AlphaFunctions::Linear ); - mScrollSpeedAnimation.Play(); - float layoutPositionDelta = GetCurrentLayoutPosition(0) + (mScrollDistance * mActiveLayout->GetScrollSpeedFactor()); float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout); mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition ); self.SetProperty(mPropertyPosition, GetScrollPosition(firstItemScrollPosition, layoutSize)); - mScrollStartedSignalV2.Emit(GetCurrentScrollPosition()); mTotalPanDisplacement += gesture.displacement; mScrollOvershoot = layoutPositionDelta - firstItemScrollPosition; @@ -1498,6 +1513,12 @@ void ItemView::OnScrollFinished(Animation& source) mScrollOvershoot = 0.0f; } +void ItemView::OnLayoutActivationScrollFinished(Animation& source) +{ + mRefreshEnabled = true; + DoRefresh(GetCurrentLayoutPosition(0), true); +} + void ItemView::OnOvershootOnFinished(Animation& animation) { mAnimatingOvershootOn = false; @@ -1531,6 +1552,7 @@ void ItemView::ScrollToItem(unsigned int itemId, float durationSeconds) } mScrollStartedSignalV2.Emit(GetCurrentScrollPosition()); + mRefreshEnabled = true; } void ItemView::RemoveAnimation(Animation& animation) @@ -1662,6 +1684,16 @@ void ItemView::ScrollTo(const Vector3& position, float duration) } mScrollStartedSignalV2.Emit(GetCurrentScrollPosition()); + mRefreshEnabled = true; +} + +void ItemView::SetOvershootEffectColor( const Vector4& color ) +{ + mOvershootEffectColor = color; + if( mOvershootOverlay ) + { + mOvershootOverlay.SetColor( color ); + } } void ItemView::SetOvershootEnabled( bool enable ) @@ -1669,20 +1701,21 @@ void ItemView::SetOvershootEnabled( bool enable ) Actor self = Self(); if( enable ) { - mOvershootEffect = BouncingEffect::New(Scrollable::DEFAULT_OVERSHOOT_COLOUR); - mOvershootOverlay = CreateSolidColorActor(Vector4::ONE); + Property::Index effectOvershootPropertyIndex = Property::INVALID_INDEX; + mOvershootOverlay = CreateBouncingEffectActor( effectOvershootPropertyIndex ); + mOvershootOverlay.SetColor(mOvershootEffectColor); mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT); mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT); mOvershootOverlay.SetDrawMode(DrawMode::OVERLAY); - mOvershootOverlay.SetShaderEffect(mOvershootEffect); self.Add(mOvershootOverlay); - Constraint constraint = Constraint::New( Actor::SIZE_WIDTH, + + Constraint constraint = Constraint::New( Actor::SIZE, ParentSource( mPropertyScrollDirection ), Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ), ParentSource( Actor::SIZE ), OvershootOverlaySizeConstraint() ); mOvershootOverlay.ApplyConstraint(constraint); - mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_IMAGE_1_PIXEL_AREA.width, OVERSHOOT_BOUNCE_IMAGE_1_PIXEL_AREA.height); + mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.width, OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height); constraint = Constraint::New( Actor::ROTATION, ParentSource( mPropertyScrollDirection ), @@ -1702,12 +1735,11 @@ void ItemView::SetOvershootEnabled( bool enable ) OvershootOverlayVisibilityConstraint() ); mOvershootOverlay.ApplyConstraint(constraint); - int effectOvershootPropertyIndex = mOvershootEffect.GetPropertyIndex(mOvershootEffect.GetProgressRatePropertyName()); Actor self = Self(); constraint = Constraint::New( effectOvershootPropertyIndex, Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ), EqualToConstraint() ); - mOvershootEffect.ApplyConstraint(constraint); + mOvershootOverlay.ApplyConstraint(constraint); } else { @@ -1716,7 +1748,6 @@ void ItemView::SetOvershootEnabled( bool enable ) self.Remove(mOvershootOverlay); mOvershootOverlay.Reset(); } - mOvershootEffect.Reset(); } } @@ -1800,6 +1831,21 @@ Vector3 ItemView::GetItemsAnchorPoint() const return mItemsAnchorPoint; } +void ItemView::GetItemsRange(ItemRange& range) +{ + range.begin = mItemPool.begin()->first; + range.end = mItemPool.rbegin()->first + 1; +} + +void ItemView::OnScrollPositionChanged( float position ) +{ + // Cancel scroll animation to prevent any fighting of setting the scroll position property. + RemoveAnimation(mScrollAnimation); + + // Refresh the cache immediately when the scroll position is changed. + DoRefresh(position, false); // No need to cache extra items. +} + } // namespace Internal } // namespace Toolkit