Notify ItemFactory when an item is removed from ItemView
[platform/core/uifw/dali-toolkit.git] / base / dali-toolkit / internal / controls / scrollable / item-view / item-view-impl.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <algorithm>
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/events/mouse-wheel-event.h>
26 #include <dali-toolkit/public-api/controls/scrollable/item-view/item-factory.h>
27 #include <dali-toolkit/internal/controls/scrollable/scroll-connector-impl.h>
28 #include <dali-toolkit/public-api/controls/default-controls/solid-color-actor.h>
29
30 using namespace std;
31 using namespace Dali;
32
33 namespace // unnamed namespace
34 {
35
36 //Type registration
37 TypeRegistration mType( typeid(Toolkit::ItemView), typeid(Toolkit::Scrollable), NULL );
38
39 const float DEFAULT_MINIMUM_SWIPE_SPEED = 1.0f;
40 const float DEFAULT_MINIMUM_SWIPE_DISTANCE = 3.0f;
41 const float DEFAULT_MOUSE_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = 0.1f;
42
43 const float DEFAULT_REFRESH_INTERVAL_LAYOUT_POSITIONS = 20.0f; // 1 updates per 20 items
44 const int MOUSE_WHEEL_EVENT_FINISHED_TIME_OUT = 500;  // 0.5 second
45
46 const float DEFAULT_ANCHORING_DURATION = 1.0f;  // 1 second
47 const float DEFAULT_COLOR_VISIBILITY_REMOVE_TIME = 0.5f; // 0.5 second
48
49 const float MILLISECONDS_PER_SECONDS = 1000.0f;
50
51 const Rect<int> OVERSHOOT_BOUNCE_IMAGE_1_PIXEL_AREA( 0, 0, 720, 58 );
52 const Vector4 OVERSHOOT_OVERLAY_NINE_PATCH_BORDER(0.0f, 0.0f, 1.0f, 12.0f);
53 const float MAXIMUM_OVERSHOOT_HEIGHT = 36.0f;  // 36 pixels
54 const float DEFAULT_OVERSHOOT_ANIMATION_DURATION = 0.5f;  // 0.5 second
55 const float DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION = 0.2f;
56
57 const string LAYOUT_POSITION_PROPERTY_NAME( "item-view-layout-position" );
58 const string POSITION_PROPERTY_NAME( "item-view-position" );
59 const string MINIMUM_LAYOUT_POSITION_PROPERTY_NAME( "item-view-minimum-layout-position" );
60 const string SCROLL_SPEED_PROPERTY_NAME( "item-view-scroll-speed" );
61 const string SCROLL_DIRECTION_PROPERTY_NAME( "item-view-scroll-direction" );
62 const string OVERSHOOT_PROPERTY_NAME( "item-view-overshoot" );
63
64 // Functors which wrap constraint functions with stored item IDs
65
66 struct WrappedVector3Constraint
67 {
68   WrappedVector3Constraint(Toolkit::ItemLayout::Vector3Function wrapMe, unsigned int itemId)
69   : mWrapMe(wrapMe),
70     mItemId(itemId)
71   {
72   }
73
74   Vector3 operator()(const Vector3& current, const PropertyInput& layoutPosition, const PropertyInput& scrollSpeed, const PropertyInput& layoutSize)
75   {
76     float offsetLayoutPosition = layoutPosition.GetFloat() + static_cast<float>(mItemId);
77
78     return mWrapMe(current, offsetLayoutPosition, scrollSpeed.GetFloat(), layoutSize.GetVector3());
79   }
80
81   Toolkit::ItemLayout::Vector3Function mWrapMe;
82   unsigned int mItemId;
83 };
84
85 struct WrappedQuaternionConstraint
86 {
87   WrappedQuaternionConstraint(Toolkit::ItemLayout::QuaternionFunction wrapMe, unsigned int itemId)
88   : mWrapMe(wrapMe),
89     mItemId(itemId)
90   {
91   }
92
93   Quaternion operator()(const Quaternion& current, const PropertyInput& layoutPosition, const PropertyInput& scrollSpeed, const PropertyInput& layoutSize)
94   {
95     float offsetLayoutPosition = layoutPosition.GetFloat() + static_cast<float>(mItemId);
96
97     return mWrapMe(current, offsetLayoutPosition, scrollSpeed.GetFloat(), layoutSize.GetVector3());
98   }
99
100   Toolkit::ItemLayout::QuaternionFunction mWrapMe;
101   unsigned int mItemId;
102 };
103
104 struct WrappedVector4Constraint
105 {
106   WrappedVector4Constraint(Toolkit::ItemLayout::Vector4Function wrapMe, unsigned int itemId)
107   : mWrapMe(wrapMe),
108     mItemId(itemId)
109   {
110   }
111
112   Vector4 operator()(const Vector4& current, const PropertyInput& layoutPosition, const PropertyInput& scrollSpeed, const PropertyInput& layoutSize)
113   {
114     float offsetLayoutPosition = layoutPosition.GetFloat() + static_cast<float>(mItemId);
115
116     return mWrapMe(current, offsetLayoutPosition, scrollSpeed.GetFloat(), layoutSize.GetVector3());
117   }
118
119   Toolkit::ItemLayout::Vector4Function mWrapMe;
120   unsigned int mItemId;
121 };
122
123 struct WrappedBoolConstraint
124 {
125   WrappedBoolConstraint(Toolkit::ItemLayout::BoolFunction wrapMe, unsigned int itemId)
126   : mWrapMe(wrapMe),
127     mItemId(itemId)
128   {
129   }
130
131   bool operator()(const bool& current, const PropertyInput& layoutPosition, const PropertyInput& scrollSpeed, const PropertyInput& layoutSize)
132   {
133     float offsetLayoutPosition = layoutPosition.GetFloat() + static_cast<float>(mItemId);
134
135     return mWrapMe(current, offsetLayoutPosition, scrollSpeed.GetFloat(), layoutSize.GetVector3());
136   }
137
138   Toolkit::ItemLayout::BoolFunction mWrapMe;
139   unsigned int mItemId;
140 };
141
142 /**
143  * Local helper to convert pan distance (in actor coordinates) to the layout-specific scrolling direction
144  */
145 float CalculateScrollDistance(Vector2 panDistance, Toolkit::ItemLayout& layout)
146 {
147   Radian scrollDirection(layout.GetScrollDirection());
148
149   float cosTheta = cosf(scrollDirection);
150   float sinTheta = sinf(scrollDirection);
151
152   return panDistance.x * sinTheta + panDistance.y * cosTheta;
153 }
154
155 // Overshoot overlay constraints
156
157 struct OvershootOverlaySizeConstraint
158 {
159   float operator()(const float& current,
160                      const PropertyInput& parentScrollDirectionProperty,
161                      const PropertyInput& parentOvershootProperty,
162                      const PropertyInput& parentSizeProperty)
163   {
164     const Vector3 parentScrollDirection = parentScrollDirectionProperty.GetVector3();
165     const Vector3 parentSize = parentSizeProperty.GetVector3();
166     const Toolkit::ControlOrientation::Type& parentOrientation = static_cast<Toolkit::ControlOrientation::Type>(parentScrollDirection.z);
167
168     float overlayWidth;
169
170     if(Toolkit::IsVertical(parentOrientation))
171     {
172       overlayWidth = fabsf(parentScrollDirection.y) > Math::MACHINE_EPSILON_1 ? parentSize.x : parentSize.y;
173     }
174     else
175     {
176       overlayWidth = fabsf(parentScrollDirection.x) > Math::MACHINE_EPSILON_1 ? parentSize.y : parentSize.x;
177     }
178
179     return overlayWidth;
180   }
181 };
182
183 struct OvershootOverlayRotationConstraint
184 {
185   Quaternion operator()(const Quaternion& current,
186                         const PropertyInput& parentScrollDirectionProperty,
187                         const PropertyInput& parentOvershootProperty)
188   {
189     const Vector3 parentScrollDirection = parentScrollDirectionProperty.GetVector3();
190     const float parentOvershoot = parentOvershootProperty.GetFloat();
191     const Toolkit::ControlOrientation::Type& parentOrientation = static_cast<Toolkit::ControlOrientation::Type>(parentScrollDirection.z);
192
193     Quaternion rotation;
194
195     if(Toolkit::IsVertical(parentOrientation))
196     {
197       if(fabsf(parentScrollDirection.y) <= Math::MACHINE_EPSILON_1)
198       {
199         if( (parentOrientation == Toolkit::ControlOrientation::Up && parentOvershoot < Math::MACHINE_EPSILON_0)
200             || (parentOrientation == Toolkit::ControlOrientation::Down && parentOvershoot > Math::MACHINE_EPSILON_0) )
201         {
202           rotation = Quaternion(0.5f * Math::PI, Vector3::ZAXIS);
203         }
204         else
205         {
206           rotation = Quaternion(1.5f * Math::PI, Vector3::ZAXIS);
207         }
208       }
209       else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.y > Math::MACHINE_EPSILON_0)
210             || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.y < Math::MACHINE_EPSILON_0) )
211       {
212         rotation = Quaternion(0.0f, Vector3::ZAXIS);
213       }
214       else
215       {
216         rotation = Quaternion(Math::PI, Vector3::ZAXIS);
217       }
218     }
219     else
220     {
221       if(fabsf(parentScrollDirection.x) <= Math::MACHINE_EPSILON_1)
222       {
223         if( (parentOrientation == Toolkit::ControlOrientation::Left && parentOvershoot > Math::MACHINE_EPSILON_0)
224             ||(parentOrientation == Toolkit::ControlOrientation::Right && parentOvershoot < Math::MACHINE_EPSILON_0) )
225         {
226           rotation = Quaternion(Math::PI, Vector3::ZAXIS);
227         }
228         else
229         {
230           rotation = Quaternion(0.0f, Vector3::ZAXIS);
231         }
232       }
233       else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.x > Math::MACHINE_EPSILON_0)
234             || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.x < Math::MACHINE_EPSILON_0) )
235       {
236         rotation = Quaternion(1.5f * Math::PI, Vector3::ZAXIS);
237       }
238       else
239       {
240         rotation = Quaternion(0.5f * Math::PI, Vector3::ZAXIS);
241       }
242     }
243
244     return rotation;
245   }
246 };
247
248 struct OvershootOverlayPositionConstraint
249 {
250   Vector3 operator()(const Vector3&    current,
251                      const PropertyInput& parentSizeProperty,
252                      const PropertyInput& parentScrollDirectionProperty,
253                      const PropertyInput& parentOvershootProperty)
254   {
255     const Vector3 parentScrollDirection = parentScrollDirectionProperty.GetVector3();
256     const float parentOvershoot = parentOvershootProperty.GetFloat();
257     const Vector3 parentSize = parentSizeProperty.GetVector3();
258     const Toolkit::ControlOrientation::Type& parentOrientation = static_cast<Toolkit::ControlOrientation::Type>(parentScrollDirection.z);
259
260     Vector3 relativeOffset;
261
262     if(Toolkit::IsVertical(parentOrientation))
263     {
264       if(fabsf(parentScrollDirection.y) <= Math::MACHINE_EPSILON_1)
265       {
266         if( (parentOrientation == Toolkit::ControlOrientation::Up && parentOvershoot < Math::MACHINE_EPSILON_0)
267             || (parentOrientation == Toolkit::ControlOrientation::Down && parentOvershoot > Math::MACHINE_EPSILON_0) )
268         {
269           relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
270         }
271         else
272         {
273           relativeOffset =Vector3(0.0f, 1.0f, 0.0f);
274         }
275       }
276       else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.y > Math::MACHINE_EPSILON_0)
277             || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.y < Math::MACHINE_EPSILON_0) )
278       {
279         relativeOffset = Vector3(0.0f, 0.0f, 0.0f);
280       }
281       else
282       {
283         relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
284       }
285     }
286     else
287     {
288       if(fabsf(parentScrollDirection.x) <= Math::MACHINE_EPSILON_1)
289       {
290         if( (parentOrientation == Toolkit::ControlOrientation::Left && parentOvershoot < Math::MACHINE_EPSILON_0)
291             || (parentOrientation == Toolkit::ControlOrientation::Right && parentOvershoot > Math::MACHINE_EPSILON_0) )
292         {
293           relativeOffset = Vector3(0.0f, 0.0f, 0.0f);
294         }
295         else
296         {
297           relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
298         }
299       }
300       else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.x > Math::MACHINE_EPSILON_0)
301             || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.x < Math::MACHINE_EPSILON_0) )
302       {
303         relativeOffset = Vector3(0.0f, 1.0f, 0.0f);
304       }
305       else
306       {
307         relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
308       }
309     }
310
311     return relativeOffset * parentSize;
312
313   }
314 };
315
316 struct OvershootOverlayVisibilityConstraint
317 {
318   bool operator()(const bool& current,
319                   const PropertyInput& parentLayoutScrollableProperty)
320   {
321     const bool parentLayoutScrollable = parentLayoutScrollableProperty.GetBoolean();
322
323     return parentLayoutScrollable;
324   }
325 };
326
327 /**
328  * Relative position Constraint
329  * Generates the relative position value of the item view based on the layout position,
330  * and it's relation to the layout domain. This is a value from 0.0f to 1.0f in each axis.
331  */
332 Vector3 RelativePositionConstraint(const Vector3& current,
333                                    const PropertyInput& scrollPositionProperty,
334                                    const PropertyInput& scrollMinProperty,
335                                    const PropertyInput& scrollMaxProperty,
336                                    const PropertyInput& layoutSizeProperty)
337 {
338   const Vector3& position = Vector3(0.0f, scrollPositionProperty.GetFloat(), 0.0f);
339   const Vector3& min = scrollMinProperty.GetVector3();
340   const Vector3& max = scrollMaxProperty.GetVector3();
341
342   Vector3 relativePosition;
343   Vector3 domainSize = max - min;
344
345   relativePosition.x = fabsf(domainSize.x) > Math::MACHINE_EPSILON_1 ? ((min.x - position.x) / fabsf(domainSize.x)) : 0.0f;
346   relativePosition.y = fabsf(domainSize.y) > Math::MACHINE_EPSILON_1 ? ((min.y - position.y) / fabsf(domainSize.y)) : 0.0f;
347
348   return relativePosition;
349 }
350
351 } // unnamed namespace
352
353 namespace Dali
354 {
355
356 namespace Toolkit
357 {
358
359 namespace Internal
360 {
361
362 namespace // unnamed namespace
363 {
364
365 bool FindById( const ItemContainer& items, ItemId id )
366 {
367   for( ConstItemIter iter = items.begin(); items.end() != iter; ++iter )
368   {
369     if( iter->first == id )
370     {
371       return true;
372     }
373   }
374
375   return false;
376 }
377
378 } // unnamed namespace
379
380 Dali::Toolkit::ItemView ItemView::New(ItemFactory& factory)
381 {
382   // Create the implementation
383   ItemViewPtr itemView(new ItemView(factory));
384
385   // Pass ownership to CustomActor via derived handle
386   Dali::Toolkit::ItemView handle(*itemView);
387
388   // Second-phase init of the implementation
389   // This can only be done after the CustomActor connection has been made...
390   itemView->Initialize();
391
392   return handle;
393 }
394
395 ItemView::ItemView(ItemFactory& factory)
396 : Scrollable(),
397   mItemFactory(factory),
398   mActiveLayout(NULL),
399   mDefaultAlphaFunction(Dali::Constraint::DEFAULT_ALPHA_FUNCTION),
400   mAnimatingOvershootOn(false),
401   mAnimateOvershootOff(false),
402   mAnchoringEnabled(true),
403   mAnchoringDuration(DEFAULT_ANCHORING_DURATION),
404   mRefreshIntervalLayoutPositions(DEFAULT_REFRESH_INTERVAL_LAYOUT_POSITIONS),
405   mRefreshOrderHint(true/*Refresh item 0 first*/),
406   mMinimumSwipeSpeed(DEFAULT_MINIMUM_SWIPE_SPEED),
407   mMinimumSwipeDistance(DEFAULT_MINIMUM_SWIPE_DISTANCE),
408   mScrollDistance(0.0f),
409   mScrollSpeed(0.0f),
410   mTotalPanDisplacement(Vector2::ZERO),
411   mScrollOvershoot(0.0f),
412   mIsFlicking(false),
413   mGestureState(Gesture::Clear),
414   mAddingItems(false),
415   mRefreshEnabled(true),
416   mItemsParentOrigin( ParentOrigin::CENTER),
417   mItemsAnchorPoint( AnchorPoint::CENTER)
418 {
419   SetRequiresMouseWheelEvents(true);
420   SetKeyboardNavigationSupport(true);
421 }
422
423 void ItemView::OnInitialize()
424 {
425   SetSizePolicy( Toolkit::Control::Fixed, Toolkit::Control::Fixed );
426
427   RegisterCommonProperties();
428
429   Actor self = Self();
430
431   mScrollConnector = Dali::Toolkit::ScrollConnector::New();
432   mScrollPositionObject = mScrollConnector.GetScrollPositionObject();
433
434   mPropertyMinimumLayoutPosition = self.RegisterProperty(MINIMUM_LAYOUT_POSITION_PROPERTY_NAME, 0.0f);
435   mPropertyPosition = self.RegisterProperty(POSITION_PROPERTY_NAME, 0.0f);
436   mPropertyScrollSpeed = self.RegisterProperty(SCROLL_SPEED_PROPERTY_NAME, 0.0f);
437
438   EnableScrollComponent(Toolkit::Scrollable::OvershootIndicator);
439
440   Constraint constraint = Constraint::New<Vector3>(mPropertyRelativePosition,
441                                                    LocalSource(mPropertyPosition),
442                                                    LocalSource(mPropertyPositionMin),
443                                                    LocalSource(mPropertyPositionMax),
444                                                    LocalSource(Actor::SIZE),
445                                                    RelativePositionConstraint);
446   self.ApplyConstraint(constraint);
447
448   Vector2 stageSize = Stage::GetCurrent().GetSize();
449   mMouseWheelScrollDistanceStep = stageSize.y * DEFAULT_MOUSE_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION;
450
451   EnableGestureDetection(Gesture::Type(Gesture::Pan));
452
453   mMouseWheelEventFinishedTimer = Timer::New( MOUSE_WHEEL_EVENT_FINISHED_TIME_OUT );
454   mMouseWheelEventFinishedTimer.TickSignal().Connect( this, &ItemView::OnMouseWheelEventFinished );
455
456   SetRefreshInterval(mRefreshIntervalLayoutPositions);
457 }
458
459 ItemView::~ItemView()
460 {
461 }
462
463 Dali::Toolkit::ScrollConnector ItemView::GetScrollConnector() const
464 {
465   return mScrollConnector;
466 }
467
468 unsigned int ItemView::GetLayoutCount() const
469 {
470   return mLayouts.size();
471 }
472
473 void ItemView::AddLayout(ItemLayout& layout)
474 {
475   mLayouts.push_back(ItemLayoutPtr(&layout));
476 }
477
478 void ItemView::RemoveLayout(unsigned int layoutIndex)
479 {
480   DALI_ASSERT_ALWAYS(layoutIndex < mLayouts.size());
481
482   if (mActiveLayout == mLayouts[layoutIndex].Get())
483   {
484     mActiveLayout = NULL;
485   }
486
487   mLayouts.erase(mLayouts.begin() + layoutIndex);
488 }
489
490 ItemLayoutPtr ItemView::GetLayout(unsigned int layoutIndex) const
491 {
492   return mLayouts[layoutIndex];
493 }
494
495 ItemLayoutPtr ItemView::GetActiveLayout() const
496 {
497   return ItemLayoutPtr(mActiveLayout);
498 }
499
500 float ItemView::GetCurrentLayoutPosition(unsigned int itemId) const
501 {
502   return mScrollPositionObject.GetProperty<float>( ScrollConnector::SCROLL_POSITION ) + static_cast<float>( itemId );
503 }
504
505 void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSize, float durationSeconds)
506 {
507   DALI_ASSERT_ALWAYS(layoutIndex < mLayouts.size());
508
509   Actor self = Self();
510
511   // The ItemView size should match the active layout size
512   self.SetSize(targetSize);
513   mActiveLayoutTargetSize = targetSize;
514
515   // Switch to the new layout
516   mActiveLayout = mLayouts[layoutIndex].Get();
517
518   // Move the items to the new layout positions...
519
520   bool resizeAnimationNeeded(false);
521
522   for (ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
523   {
524     unsigned int itemId = iter->first;
525     Actor actor = iter->second;
526
527     // Remove constraints from previous layout
528     actor.RemoveConstraints();
529
530     Vector3 size;
531     if(mActiveLayout->GetItemSize(itemId, targetSize, size))
532     {
533       if( durationSeconds > 0.0f )
534       {
535         // Use a size animation
536         if (!resizeAnimationNeeded)
537         {
538           resizeAnimationNeeded = true;
539           RemoveAnimation(mResizeAnimation);
540           mResizeAnimation = Animation::New(durationSeconds);
541         }
542
543         // The layout provides its own resize animation
544         mActiveLayout->GetResizeAnimation(mResizeAnimation, actor, size, durationSeconds);
545       }
546       else
547       {
548         // resize immediately
549         actor.SetSize(size);
550       }
551     }
552
553     ApplyConstraints(actor, *mActiveLayout, itemId, durationSeconds);
554   }
555
556   if (resizeAnimationNeeded)
557   {
558     mResizeAnimation.Play();
559   }
560
561   // Refresh the new layout
562   ItemRange range = GetItemRange(*mActiveLayout, targetSize, GetCurrentLayoutPosition(0), true/*reserve extra*/);
563   AddActorsWithinRange( range, durationSeconds );
564
565   // Scroll to an appropriate layout position
566
567   bool scrollAnimationNeeded(false);
568   float firstItemScrollPosition(0.0f);
569
570   float current = GetCurrentLayoutPosition(0);
571   float minimum = ClampFirstItemPosition(current, targetSize, *mActiveLayout);
572   self.SetProperty(mPropertyPosition, GetScrollPosition(current, targetSize));
573
574   if (current < minimum)
575   {
576     scrollAnimationNeeded = true;
577     firstItemScrollPosition = minimum;
578   }
579   else if (mAnchoringEnabled)
580   {
581     scrollAnimationNeeded = true;
582     firstItemScrollPosition = mActiveLayout->GetClosestAnchorPosition(current);
583   }
584
585   if (scrollAnimationNeeded)
586   {
587     RemoveAnimation(mScrollAnimation);
588     mScrollAnimation = Animation::New(durationSeconds);
589     mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut );
590     mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, targetSize), AlphaFunctions::EaseOut );
591     mScrollAnimation.Play();
592   }
593
594   self.SetProperty(mPropertyMinimumLayoutPosition, mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), targetSize));
595   AnimateScrollOvershoot(0.0f);
596   mScrollOvershoot = 0.0f;
597
598   Radian scrollDirection(mActiveLayout->GetScrollDirection());
599   float orientation = static_cast<float>(mActiveLayout->GetOrientation());
600   self.SetProperty(mPropertyScrollDirection, Vector3(sinf(scrollDirection), cosf(scrollDirection), orientation));
601
602   self.SetProperty(mPropertyScrollSpeed, mScrollSpeed);
603
604   CalculateDomainSize(targetSize);
605 }
606
607 void ItemView::DeactivateCurrentLayout()
608 {
609   if (mActiveLayout)
610   {
611     for (ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
612     {
613       Actor actor = iter->second;
614       actor.RemoveConstraints();
615     }
616
617     mActiveLayout = NULL;
618   }
619 }
620
621 void ItemView::SetDefaultAlphaFunction(AlphaFunction func)
622 {
623   mDefaultAlphaFunction = func;
624 }
625
626 AlphaFunction ItemView::GetDefaultAlphaFunction() const
627 {
628   return mDefaultAlphaFunction;
629 }
630
631 void ItemView::OnRefreshNotification(PropertyNotification& source)
632 {
633   if(mRefreshEnabled)
634   {
635     // Only refresh the cache during normal scrolling
636     DoRefresh(GetCurrentLayoutPosition(0), true);
637   }
638 }
639
640 void ItemView::DoRefresh(float currentLayoutPosition, bool cacheExtra)
641 {
642   if (mActiveLayout)
643   {
644     ItemRange range = GetItemRange(*mActiveLayout, mActiveLayoutTargetSize, currentLayoutPosition, cacheExtra/*reserve extra*/);
645     RemoveActorsOutsideRange( range );
646     AddActorsWithinRange( range, 0.0f/*immediate*/ );
647
648     mScrollUpdatedSignalV2.Emit( Vector3(0.0f, currentLayoutPosition, 0.0f) );
649   }
650 }
651
652 void ItemView::SetMinimumSwipeSpeed(float speed)
653 {
654   mMinimumSwipeSpeed = speed;
655 }
656
657 float ItemView::GetMinimumSwipeSpeed() const
658 {
659   return mMinimumSwipeSpeed;
660 }
661
662 void ItemView::SetMinimumSwipeDistance(float distance)
663 {
664   mMinimumSwipeDistance = distance;
665 }
666
667 float ItemView::GetMinimumSwipeDistance() const
668 {
669   return mMinimumSwipeDistance;
670 }
671
672 void ItemView::SetMouseWheelScrollDistanceStep(float step)
673 {
674   mMouseWheelScrollDistanceStep = step;
675 }
676
677 float ItemView::GetMouseWheelScrollDistanceStep() const
678 {
679   return mMouseWheelScrollDistanceStep;
680 }
681
682 void ItemView::SetAnchoring(bool enabled)
683 {
684   mAnchoringEnabled = enabled;
685 }
686
687 bool ItemView::GetAnchoring() const
688 {
689   return mAnchoringEnabled;
690 }
691
692 void ItemView::SetAnchoringDuration(float durationSeconds)
693 {
694   mAnchoringDuration = durationSeconds;
695 }
696
697 float ItemView::GetAnchoringDuration() const
698 {
699   return mAnchoringDuration;
700 }
701
702 void ItemView::SetRefreshInterval(float intervalLayoutPositions)
703 {
704   mRefreshIntervalLayoutPositions = intervalLayoutPositions;
705
706   if(mRefreshNotification)
707   {
708     mScrollPositionObject.RemovePropertyNotification(mRefreshNotification);
709   }
710   mRefreshNotification = mScrollPositionObject.AddPropertyNotification( ScrollConnector::SCROLL_POSITION, StepCondition(mRefreshIntervalLayoutPositions, 0.0f) );
711   mRefreshNotification.NotifySignal().Connect( this, &ItemView::OnRefreshNotification );
712 }
713
714 float ItemView::GetRefreshInterval() const
715 {
716   return mRefreshIntervalLayoutPositions;
717 }
718
719 void ItemView::SetRefreshEnabled(bool enabled)
720 {
721   mRefreshEnabled = enabled;
722 }
723
724 Actor ItemView::GetItem(unsigned int itemId) const
725 {
726   Actor actor;
727
728   ConstItemPoolIter iter = mItemPool.find( itemId );
729   if( iter != mItemPool.end() )
730   {
731     actor = iter->second;
732   }
733
734   return actor;
735 }
736
737 unsigned int ItemView::GetItemId( Actor actor ) const
738 {
739   unsigned int itemId( 0 );
740
741   for ( ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter )
742   {
743     if( iter->second == actor )
744     {
745       itemId = iter->first;
746       break;
747     }
748   }
749
750   return itemId;
751 }
752
753 void ItemView::InsertItem( Item newItem, float durationSeconds )
754 {
755   mAddingItems = true;
756
757   SetupActor( newItem, durationSeconds );
758   Self().Add( newItem.second );
759
760   ItemPoolIter foundIter = mItemPool.find( newItem.first );
761   if( mItemPool.end() != foundIter )
762   {
763     Actor moveMe = foundIter->second;
764     foundIter->second = newItem.second;
765
766     // Move the existing actors to make room
767     for( ItemPoolIter iter = ++foundIter; mItemPool.end() != iter; ++iter )
768     {
769       Actor temp = iter->second;
770       iter->second = moveMe;
771       moveMe = temp;
772
773       iter->second.RemoveConstraints();
774       ApplyConstraints( iter->second, *mActiveLayout, iter->first, durationSeconds );
775     }
776
777     // Create last item
778     ItemId lastId = mItemPool.rbegin()->first;
779     Item lastItem( lastId + 1, moveMe );
780     mItemPool.insert( lastItem );
781
782     lastItem.second.RemoveConstraints();
783     ApplyConstraints( lastItem.second, *mActiveLayout, lastItem.first, durationSeconds );
784   }
785   else
786   {
787     mItemPool.insert( newItem );
788   }
789
790   CalculateDomainSize(Self().GetCurrentSize());
791
792   mAddingItems = false;
793 }
794
795 void ItemView::InsertItems( const ItemContainer& newItems, float durationSeconds )
796 {
797   mAddingItems = true;
798
799   // Insert from lowest id to highest
800   set<Item> sortedItems;
801   for( ConstItemIter iter = newItems.begin(); newItems.end() != iter; ++iter )
802   {
803     sortedItems.insert( *iter );
804   }
805
806   for( set<Item>::iterator iter = sortedItems.begin(); sortedItems.end() != iter; ++iter )
807   {
808     Self().Add( iter->second );
809
810     cout << "inserting item: " << iter->first << endl;
811
812     ItemPoolIter foundIter = mItemPool.find( iter->first );
813     if( mItemPool.end() != foundIter )
814     {
815       Actor moveMe = foundIter->second;
816       foundIter->second = iter->second;
817
818       // Move the existing actors to make room
819       for( ItemPoolIter iter = ++foundIter; mItemPool.end() != iter; ++iter )
820       {
821         Actor temp = iter->second;
822         iter->second = moveMe;
823         moveMe = temp;
824       }
825
826       // Create last item
827       ItemId lastId = mItemPool.rbegin()->first;
828       Item lastItem( lastId + 1, moveMe );
829       mItemPool.insert( lastItem );
830     }
831     else
832     {
833       mItemPool.insert( *iter );
834     }
835   }
836
837   // Relayout everything
838   for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
839   {
840     // If newly inserted
841     if( FindById( newItems, iter->first ) )
842     {
843       SetupActor( *iter, durationSeconds );
844     }
845     else
846     {
847       iter->second.RemoveConstraints();
848       ApplyConstraints( iter->second, *mActiveLayout, iter->first, durationSeconds );
849     }
850   }
851
852   CalculateDomainSize(Self().GetCurrentSize());
853
854   mAddingItems = false;
855 }
856
857 void ItemView::RemoveItem( unsigned int itemId, float durationSeconds )
858 {
859   bool actorRemoved = RemoveActor( itemId );
860   if( actorRemoved )
861   {
862     ReapplyAllConstraints( durationSeconds );
863   }
864 }
865
866 void ItemView::RemoveItems( const ItemIdContainer& itemIds, float durationSeconds )
867 {
868   bool actorRemoved( false );
869
870   // Remove from highest id to lowest
871   set<ItemId> sortedItems;
872   for( ConstItemIdIter iter = itemIds.begin(); itemIds.end() != iter; ++iter )
873   {
874     sortedItems.insert( *iter );
875   }
876
877   for( set<ItemId>::reverse_iterator iter = sortedItems.rbegin(); sortedItems.rend() != iter; ++iter )
878   {
879     if( RemoveActor( *iter ) )
880     {
881       actorRemoved = true;
882     }
883   }
884
885   if( actorRemoved )
886   {
887     ReapplyAllConstraints( durationSeconds );
888   }
889 }
890
891 bool ItemView::RemoveActor(unsigned int itemId)
892 {
893   bool removed( false );
894
895   const ItemPoolIter removeIter = mItemPool.find( itemId );
896
897   if( removeIter != mItemPool.end() )
898   {
899     ReleaseActor(itemId, removeIter->second);
900
901     removed = true;
902
903     // Adjust the remaining item IDs, for example if item 2 is removed:
904     //   Initial actors:     After insert:
905     //     ID 1 - ActorA       ID 1 - ActorA
906     //     ID 2 - ActorB       ID 2 - ActorC (previously ID 3)
907     //     ID 3 - ActorC       ID 3 - ActorB (previously ID 4)
908     //     ID 4 - ActorD
909     for (ItemPoolIter iter = removeIter; iter != mItemPool.end(); ++iter)
910     {
911       if( iter->first < mItemPool.rbegin()->first )
912       {
913         iter->second = mItemPool[ iter->first + 1 ];
914       }
915       else
916       {
917         mItemPool.erase( iter );
918         break;
919       }
920     }
921   }
922
923   return removed;
924 }
925
926 void ItemView::ReplaceItem( Item replacementItem, float durationSeconds )
927 {
928   mAddingItems = true;
929
930   SetupActor( replacementItem, durationSeconds );
931   Self().Add( replacementItem.second );
932
933   const ItemPoolIter iter = mItemPool.find( replacementItem.first );
934   if( mItemPool.end() != iter )
935   {
936     ReleaseActor(iter->first, iter->second);
937     iter->second = replacementItem.second;
938   }
939   else
940   {
941     mItemPool.insert( replacementItem );
942   }
943
944   CalculateDomainSize(Self().GetCurrentSize());
945
946   mAddingItems = false;
947 }
948
949 void ItemView::ReplaceItems( const ItemContainer& replacementItems, float durationSeconds )
950 {
951   for( ConstItemIter iter = replacementItems.begin(); replacementItems.end() != iter; ++iter )
952   {
953     ReplaceItem( *iter, durationSeconds );
954   }
955 }
956
957 void ItemView::RemoveActorsOutsideRange( ItemRange range )
958 {
959   // Remove unwanted actors from the ItemView & ItemPool
960   for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); )
961   {
962     unsigned int current = iter->first;
963
964     if( ! range.Within( current ) )
965     {
966       ReleaseActor(iter->first, iter->second);
967
968       mItemPool.erase( iter++ ); // erase invalidates the return value of post-increment; iter remains valid
969     }
970     else
971     {
972       ++iter;
973     }
974   }
975 }
976
977 void ItemView::AddActorsWithinRange( ItemRange range, float durationSeconds )
978 {
979   range.end = min(mItemFactory.GetNumberOfItems(), range.end);
980
981   // The order of addition depends on the scroll direction.
982   if (mRefreshOrderHint)
983   {
984     for (unsigned int itemId = range.begin; itemId < range.end; ++itemId)
985     {
986       AddNewActor( itemId, durationSeconds );
987     }
988   }
989   else
990   {
991     for (unsigned int itemId = range.end; itemId > range.begin; --itemId)
992     {
993       AddNewActor( itemId-1, durationSeconds );
994     }
995   }
996
997   // Total number of items may change dynamically.
998   // Always recalculate the domain size to reflect that.
999   CalculateDomainSize(Self().GetCurrentSize());
1000 }
1001
1002 void ItemView::AddNewActor( unsigned int itemId, float durationSeconds )
1003 {
1004   mAddingItems = true;
1005
1006   if( mItemPool.end() == mItemPool.find( itemId ) )
1007   {
1008     Actor actor = mItemFactory.NewItem( itemId );
1009
1010     if( actor )
1011     {
1012       Item newItem( itemId, actor );
1013
1014       mItemPool.insert( newItem );
1015
1016       SetupActor( newItem, durationSeconds );
1017       Self().Add( actor );
1018     }
1019   }
1020
1021   mAddingItems = false;
1022 }
1023
1024 void ItemView::SetupActor( Item item, float durationSeconds )
1025 {
1026   item.second.SetParentOrigin( mItemsParentOrigin );
1027   item.second.SetAnchorPoint( mItemsAnchorPoint );
1028
1029   if( mActiveLayout )
1030   {
1031     Vector3 size;
1032     if( mActiveLayout->GetItemSize( item.first, mActiveLayoutTargetSize, size ) )
1033     {
1034       item.second.SetSize( size );
1035     }
1036
1037     ApplyConstraints( item.second, *mActiveLayout, item.first, durationSeconds );
1038   }
1039 }
1040
1041 void ItemView::ReleaseActor( ItemId item, Actor actor )
1042 {
1043   Self().Remove( actor );
1044   mItemFactory.ItemReleased(item, actor);
1045 }
1046
1047 ItemRange ItemView::GetItemRange(ItemLayout& layout, const Vector3& layoutSize, float layoutPosition, bool reserveExtra)
1048 {
1049   unsigned int itemCount = mItemFactory.GetNumberOfItems();
1050
1051   ItemRange available(0u, itemCount);
1052
1053   ItemRange range = layout.GetItemsWithinArea( layoutPosition, layoutSize );
1054
1055   if (reserveExtra)
1056   {
1057     // Add the reserve items for scrolling
1058     unsigned int extra = layout.GetReserveItemCount(layoutSize);
1059     range.begin = (range.begin >= extra) ? (range.begin - extra) : 0u;
1060     range.end += extra;
1061   }
1062
1063   return range.Intersection(available);
1064 }
1065
1066 void ItemView::OnChildAdd(Actor& child)
1067 {
1068   if(!mAddingItems)
1069   {
1070     // We don't want to do this downcast check for any item added by ItemView itself.
1071     Dali::Toolkit::ScrollComponent scrollComponent = Dali::Toolkit::ScrollComponent::DownCast(child);
1072     if(scrollComponent)
1073     {
1074       // Set the scroll connector when scroll bar is being added
1075       scrollComponent.SetScrollConnector(mScrollConnector);
1076     }
1077   }
1078 }
1079
1080 bool ItemView::OnTouchEvent(const TouchEvent& event)
1081 {
1082   // Ignore events with multiple-touch points
1083   if (event.GetPointCount() != 1)
1084   {
1085     return false;
1086   }
1087
1088   if (event.GetPoint(0).state == TouchPoint::Down)
1089   {
1090     // Cancel ongoing scrolling etc.
1091     mGestureState = Gesture::Clear;
1092
1093     mScrollDistance = 0.0f;
1094     mScrollSpeed = 0.0f;
1095     Self().SetProperty(mPropertyScrollSpeed, mScrollSpeed);
1096
1097     mScrollOvershoot = 0.0f;
1098     AnimateScrollOvershoot(0.0f);
1099
1100     mScrollCompletedSignalV2.Emit(GetCurrentScrollPosition());
1101
1102     RemoveAnimation(mScrollAnimation);
1103   }
1104
1105   return true; // consume since we're potentially scrolling
1106 }
1107
1108 bool ItemView::OnMouseWheelEvent(const MouseWheelEvent& event)
1109 {
1110   // Respond the mouse wheel event to scroll
1111   if (mActiveLayout)
1112   {
1113     Actor self = Self();
1114     const Vector3 layoutSize = Self().GetCurrentSize();
1115     float layoutPositionDelta = GetCurrentLayoutPosition(0) - (event.z * mMouseWheelScrollDistanceStep * mActiveLayout->GetScrollSpeedFactor());
1116     float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout);
1117
1118     mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
1119     self.SetProperty(mPropertyPosition, GetScrollPosition(firstItemScrollPosition, layoutSize));
1120     mScrollStartedSignalV2.Emit(GetCurrentScrollPosition());
1121   }
1122
1123   if (mMouseWheelEventFinishedTimer.IsRunning())
1124   {
1125     mMouseWheelEventFinishedTimer.Stop();
1126   }
1127
1128   mMouseWheelEventFinishedTimer.Start();
1129
1130   return true;
1131 }
1132
1133 bool ItemView::OnMouseWheelEventFinished()
1134 {
1135   if (mActiveLayout)
1136   {
1137     RemoveAnimation(mScrollAnimation);
1138
1139     // No more mouse wheel events coming. Do the anchoring if enabled.
1140     mScrollAnimation = DoAnchoring();
1141     if (mScrollAnimation)
1142     {
1143       mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1144       mScrollAnimation.Play();
1145     }
1146     else
1147     {
1148       mScrollOvershoot = 0.0f;
1149       AnimateScrollOvershoot(0.0f);
1150
1151       mScrollCompletedSignalV2.Emit(GetCurrentScrollPosition());
1152     }
1153   }
1154
1155   return false;
1156 }
1157
1158 void ItemView::ApplyConstraints(Actor& actor, ItemLayout& layout, unsigned int itemId, float duration)
1159 {
1160   ItemLayout::Vector3Function positionConstraint;
1161   if (layout.GetPositionConstraint(itemId, positionConstraint))
1162   {
1163     WrappedVector3Constraint wrapped(positionConstraint, itemId);
1164
1165     Constraint constraint = Constraint::New<Vector3>( Actor::POSITION,
1166                                                       Source( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ),
1167                                                       ParentSource( mPropertyScrollSpeed ),
1168                                                       ParentSource( Actor::SIZE ),
1169                                                       wrapped );
1170     constraint.SetApplyTime(duration);
1171     constraint.SetAlphaFunction(mDefaultAlphaFunction);
1172
1173     actor.ApplyConstraint(constraint);
1174   }
1175
1176   ItemLayout::QuaternionFunction rotationConstraint;
1177   if (layout.GetRotationConstraint(itemId, rotationConstraint))
1178   {
1179     WrappedQuaternionConstraint wrapped(rotationConstraint, itemId);
1180
1181     Constraint constraint = Constraint::New<Quaternion>( Actor::ROTATION,
1182                                                          Source( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ),
1183                                                          ParentSource( mPropertyScrollSpeed ),
1184                                                          ParentSource( Actor::SIZE ),
1185                                                          wrapped );
1186     constraint.SetApplyTime(duration);
1187     constraint.SetAlphaFunction(mDefaultAlphaFunction);
1188
1189     actor.ApplyConstraint(constraint);
1190   }
1191
1192   ItemLayout::Vector3Function scaleConstraint;
1193   if (layout.GetScaleConstraint(itemId, scaleConstraint))
1194   {
1195     WrappedVector3Constraint wrapped(scaleConstraint, itemId);
1196
1197     Constraint constraint = Constraint::New<Vector3>( Actor::SCALE,
1198                                                       Source( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ),
1199                                                       ParentSource( mPropertyScrollSpeed ),
1200                                                       ParentSource( Actor::SIZE ),
1201                                                       wrapped );
1202     constraint.SetApplyTime(duration);
1203     constraint.SetAlphaFunction(mDefaultAlphaFunction);
1204
1205     actor.ApplyConstraint(constraint);
1206   }
1207
1208   ItemLayout::Vector4Function colorConstraint;
1209   if (layout.GetColorConstraint(itemId, colorConstraint))
1210   {
1211     WrappedVector4Constraint wrapped(colorConstraint, itemId);
1212
1213     Constraint constraint = Constraint::New<Vector4>( Actor::COLOR,
1214                                                       Source( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ),
1215                                                       ParentSource( mPropertyScrollSpeed ),
1216                                                       ParentSource( Actor::SIZE ),
1217                                                       wrapped );
1218     constraint.SetApplyTime(duration);
1219     constraint.SetAlphaFunction(mDefaultAlphaFunction);
1220
1221     // Release color constraints slowly; this allows ItemView to co-exist with ImageActor fade-in
1222     constraint.SetRemoveTime(DEFAULT_COLOR_VISIBILITY_REMOVE_TIME);
1223     constraint.SetRemoveAction(Dali::Constraint::Discard);
1224
1225     actor.ApplyConstraint(constraint);
1226   }
1227
1228   ItemLayout::BoolFunction visibilityConstraint;
1229   if (layout.GetVisibilityConstraint(itemId, visibilityConstraint))
1230   {
1231     WrappedBoolConstraint wrapped(visibilityConstraint, itemId);
1232
1233     Constraint constraint = Constraint::New<bool>( Actor::VISIBLE,
1234                                                    Source( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ),
1235                                                    ParentSource( mPropertyScrollSpeed ),
1236                                                    ParentSource( Actor::SIZE ),
1237                                                    wrapped );
1238     constraint.SetApplyTime(duration);
1239     constraint.SetAlphaFunction(mDefaultAlphaFunction);
1240
1241     // Release visibility constraints the same time as the color constraint
1242     constraint.SetRemoveTime(DEFAULT_COLOR_VISIBILITY_REMOVE_TIME);
1243     constraint.SetRemoveAction(Dali::Constraint::Discard);
1244
1245     actor.ApplyConstraint(constraint);
1246   }
1247 }
1248
1249 void ItemView::ReapplyAllConstraints( float durationSeconds )
1250 {
1251   for (ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
1252   {
1253     unsigned int id = iter->first;
1254     Actor actor = iter->second;
1255
1256     actor.RemoveConstraints();
1257     ApplyConstraints(actor, *mActiveLayout, id, durationSeconds);
1258   }
1259
1260   CalculateDomainSize(Self().GetCurrentSize());
1261 }
1262
1263 float ItemView::ClampFirstItemPosition(float targetPosition, const Vector3& targetSize, ItemLayout& layout)
1264 {
1265   Actor self = Self();
1266   float minLayoutPosition = layout.GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), targetSize);
1267   float clamppedPosition = min(0.0f, max(minLayoutPosition, targetPosition));
1268   mScrollOvershoot = targetPosition - clamppedPosition;
1269   self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition);
1270
1271   return clamppedPosition;
1272 }
1273
1274 void ItemView::OnPan(PanGesture gesture)
1275 {
1276   Actor self = Self();
1277   const Vector3 layoutSize = Self().GetCurrentSize();
1278
1279   RemoveAnimation(mScrollAnimation);
1280
1281   // Short-circuit if there is no active layout
1282   if (!mActiveLayout)
1283   {
1284     mGestureState = Gesture::Clear;
1285     return;
1286   }
1287
1288   mGestureState = gesture.state;
1289
1290   switch (mGestureState)
1291   {
1292     case Gesture::Finished:
1293     {
1294       // Swipe Detection
1295       if (fabsf(mScrollDistance) > mMinimumSwipeDistance &&
1296           mScrollSpeed > mMinimumSwipeSpeed)
1297       {
1298         float direction = (mScrollDistance < 0.0f) ? -1.0f : 1.0f;
1299
1300         mRefreshOrderHint = true;
1301
1302         float currentLayoutPosition = GetCurrentLayoutPosition(0);
1303         float firstItemScrollPosition = ClampFirstItemPosition(currentLayoutPosition + mScrollSpeed * direction,
1304                                                                layoutSize,
1305                                                                *mActiveLayout);
1306
1307         if (mAnchoringEnabled)
1308         {
1309           firstItemScrollPosition = mActiveLayout->GetClosestAnchorPosition(firstItemScrollPosition);
1310         }
1311
1312         RemoveAnimation(mScrollAnimation);
1313
1314         float flickAnimationDuration = mActiveLayout->GetItemFlickAnimationDuration() * max(1.0f, fabsf(firstItemScrollPosition - GetCurrentLayoutPosition(0)));
1315         mScrollAnimation = Animation::New(flickAnimationDuration);
1316         mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut );
1317         mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut );
1318         mScrollAnimation.AnimateTo( Property(self, mPropertyScrollSpeed), 0.0f, AlphaFunctions::EaseOut );
1319
1320         mIsFlicking = true;
1321         // Check whether it has already scrolled to the end
1322         if(fabs(currentLayoutPosition - firstItemScrollPosition) > Math::MACHINE_EPSILON_0)
1323         {
1324           AnimateScrollOvershoot(0.0f);
1325         }
1326       }
1327
1328       // Anchoring may be triggered when there was no swipe
1329       if (!mScrollAnimation)
1330       {
1331         mScrollAnimation = DoAnchoring();
1332       }
1333
1334       // Reset the overshoot if no scroll animation.
1335       if (!mScrollAnimation)
1336       {
1337         mScrollCompletedSignalV2.Emit(GetCurrentScrollPosition());
1338
1339         AnimateScrollOvershoot(0.0f, false);
1340       }
1341     }
1342     break;
1343
1344     case Gesture::Started: // Fall through
1345     {
1346       mTotalPanDisplacement = Vector2::ZERO;
1347     }
1348
1349     case Gesture::Continuing:
1350     {
1351       mScrollDistance = CalculateScrollDistance(gesture.displacement, *mActiveLayout);
1352       mScrollSpeed = Clamp((gesture.GetSpeed() * mActiveLayout->GetScrollSpeedFactor() * MILLISECONDS_PER_SECONDS), 0.0f, mActiveLayout->GetMaximumSwipeSpeed());
1353
1354       // Refresh order depends on the direction of the scroll; negative is towards the last item.
1355       mRefreshOrderHint = mScrollDistance < 0.0f;
1356
1357       float layoutPositionDelta = GetCurrentLayoutPosition(0) + (mScrollDistance * mActiveLayout->GetScrollSpeedFactor());
1358
1359       float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout);
1360
1361       mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
1362       self.SetProperty(mPropertyPosition, GetScrollPosition(firstItemScrollPosition, layoutSize));
1363       mScrollStartedSignalV2.Emit(GetCurrentScrollPosition());
1364
1365       mTotalPanDisplacement += gesture.displacement;
1366       mScrollOvershoot = layoutPositionDelta - firstItemScrollPosition;
1367       if( mScrollOvershoot > Math::MACHINE_EPSILON_1 )
1368       {
1369         AnimateScrollOvershoot(1.0f);
1370       }
1371       else if( mScrollOvershoot < -Math::MACHINE_EPSILON_1 )
1372       {
1373         AnimateScrollOvershoot(-1.0f);
1374       }
1375       else
1376       {
1377         AnimateScrollOvershoot(0.0f);
1378       }
1379     }
1380     break;
1381
1382     case Gesture::Cancelled:
1383     {
1384       mScrollAnimation = DoAnchoring();
1385     }
1386     break;
1387
1388     default:
1389       break;
1390   }
1391
1392   if (mScrollAnimation)
1393   {
1394     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1395     mScrollAnimation.Play();
1396   }
1397 }
1398
1399 bool ItemView::OnAccessibilityPan(PanGesture gesture)
1400 {
1401   OnPan(gesture);
1402   return true;
1403 }
1404
1405 Actor ItemView::GetNextKeyboardFocusableActor(Actor actor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
1406 {
1407   Actor nextFocusActor;
1408   if(mActiveLayout)
1409   {
1410     int nextItemID = 0;
1411     if(!actor || actor == this->Self())
1412     {
1413       nextFocusActor = GetItem(nextItemID);
1414     }
1415     else if(actor && actor.GetParent() == this->Self())
1416     {
1417       int itemID = GetItemId(actor);
1418       nextItemID = mActiveLayout->GetNextFocusItemID(itemID, mItemFactory.GetNumberOfItems(), direction, loopEnabled);
1419       nextFocusActor = GetItem(nextItemID);
1420       if(nextFocusActor == actor)
1421       {
1422         // need to pass NULL actor back to focus manager
1423         nextFocusActor.Reset();
1424         return nextFocusActor;
1425       }
1426     }
1427     float layoutPosition = mActiveLayout->GetClosestAnchorPosition( GetCurrentLayoutPosition(0) );
1428     Vector3 layoutSize = Self().GetCurrentSize();
1429     if(!nextFocusActor)
1430     {
1431       // likely the current item is not buffered, so not in our item pool, probably best to get first viewable item
1432       ItemRange viewableItems = mActiveLayout->GetItemsWithinArea(layoutPosition, layoutSize);
1433       nextItemID = viewableItems.begin;
1434       nextFocusActor = GetItem(nextItemID);
1435     }
1436   }
1437   return nextFocusActor;
1438 }
1439
1440 void ItemView::OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor)
1441 {
1442   // only in this function if our chosen focus actor was actually used
1443   if(commitedFocusableActor)
1444   {
1445     int nextItemID = GetItemId(commitedFocusableActor);
1446     float layoutPosition = GetCurrentLayoutPosition(0);
1447     Vector3 layoutSize = Self().GetCurrentSize();
1448     Vector3 focusItemPosition = Vector3::ZERO;
1449     ItemLayout::Vector3Function itemPositionConstraint;
1450     if (mActiveLayout->GetPositionConstraint(nextItemID, itemPositionConstraint))
1451     {
1452       focusItemPosition = itemPositionConstraint(Vector3::ZERO, layoutPosition + nextItemID, 0.0f, layoutSize);
1453     }
1454
1455     float scrollTo = mActiveLayout->GetClosestOnScreenLayoutPosition(nextItemID, layoutPosition, layoutSize);
1456     ScrollTo(Vector3(0.0f, scrollTo, 0.0f), DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION);
1457   }
1458 }
1459
1460 Animation ItemView::DoAnchoring()
1461 {
1462   Animation anchoringAnimation;
1463   Actor self = Self();
1464
1465   if (mActiveLayout && mAnchoringEnabled)
1466   {
1467     float anchorPosition = mActiveLayout->GetClosestAnchorPosition( GetCurrentLayoutPosition(0) );
1468
1469     anchoringAnimation = Animation::New(mAnchoringDuration);
1470     anchoringAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), anchorPosition, AlphaFunctions::EaseOut );
1471     anchoringAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(anchorPosition, self.GetCurrentSize()), AlphaFunctions::EaseOut );
1472     anchoringAnimation.AnimateTo( Property(self, mPropertyScrollSpeed), 0.0f, AlphaFunctions::EaseOut );
1473     if(!mIsFlicking)
1474     {
1475       AnimateScrollOvershoot(0.0f);
1476     }
1477   }
1478
1479   return anchoringAnimation;
1480 }
1481
1482 void ItemView::OnScrollFinished(Animation& source)
1483 {
1484   Actor self = Self();
1485
1486   RemoveAnimation(mScrollAnimation); // mScrollAnimation is used to query whether we're scrolling
1487
1488   mScrollCompletedSignalV2.Emit(GetCurrentScrollPosition());
1489
1490   if(mIsFlicking && fabsf(mScrollOvershoot) > Math::MACHINE_EPSILON_1)
1491   {
1492     AnimateScrollOvershoot( mScrollOvershoot > 0.0f ? 1.0f : -1.0f, true);
1493   }
1494   else
1495   {
1496     // Reset the overshoot
1497     AnimateScrollOvershoot( 0.0f );
1498   }
1499   mIsFlicking = false;
1500
1501   mScrollOvershoot = 0.0f;
1502 }
1503
1504 void ItemView::OnOvershootOnFinished(Animation& animation)
1505 {
1506   mAnimatingOvershootOn = false;
1507   mScrollOvershootAnimation.FinishedSignal().Disconnect(this, &ItemView::OnOvershootOnFinished);
1508   RemoveAnimation(mScrollOvershootAnimation);
1509   if(mAnimateOvershootOff)
1510   {
1511     AnimateScrollOvershoot(0.0f);
1512   }
1513 }
1514
1515 void ItemView::ScrollToItem(unsigned int itemId, float durationSeconds)
1516 {
1517   Actor self = Self();
1518   const Vector3 layoutSize = Self().GetCurrentSize();
1519   float firstItemScrollPosition = ClampFirstItemPosition(mActiveLayout->GetItemScrollToPosition(itemId), layoutSize, *mActiveLayout);
1520
1521   if(durationSeconds > 0.0f)
1522   {
1523     RemoveAnimation(mScrollAnimation);
1524     mScrollAnimation = Animation::New(durationSeconds);
1525     mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut );
1526     mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut );
1527     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1528     mScrollAnimation.Play();
1529   }
1530   else
1531   {
1532     mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
1533     AnimateScrollOvershoot(0.0f);
1534   }
1535
1536   mScrollStartedSignalV2.Emit(GetCurrentScrollPosition());
1537 }
1538
1539 void ItemView::RemoveAnimation(Animation& animation)
1540 {
1541   if(animation)
1542   {
1543     // Cease animating, and reset handle.
1544     animation.Clear();
1545     animation.Reset();
1546   }
1547 }
1548
1549 void ItemView::CalculateDomainSize(const Vector3& layoutSize)
1550 {
1551   Actor self = Self();
1552
1553   Vector3 firstItemPosition(Vector3::ZERO);
1554   Vector3 lastItemPosition(Vector3::ZERO);
1555
1556   if(mActiveLayout)
1557   {
1558     ItemLayout::Vector3Function firstItemPositionConstraint;
1559     if (mActiveLayout->GetPositionConstraint(0, firstItemPositionConstraint))
1560     {
1561       firstItemPosition = firstItemPositionConstraint(Vector3::ZERO, 0, 0.0f, layoutSize);
1562     }
1563
1564     float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize);
1565     self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition);
1566
1567     ItemLayout::Vector3Function lastItemPositionConstraint;
1568     if (mActiveLayout->GetPositionConstraint(fabs(minLayoutPosition), lastItemPositionConstraint))
1569     {
1570       lastItemPosition = lastItemPositionConstraint(Vector3::ZERO, fabs(minLayoutPosition), 0.0f, layoutSize);
1571     }
1572
1573     float domainSize;
1574
1575     if(IsHorizontal(mActiveLayout->GetOrientation()))
1576     {
1577       self.SetProperty(mPropertyPositionMin, Vector3(0.0f, firstItemPosition.x, 0.0f));
1578       self.SetProperty(mPropertyPositionMax, Vector3(0.0f, lastItemPosition.x, 0.0f));
1579       domainSize = fabs(firstItemPosition.x - lastItemPosition.x);
1580     }
1581     else
1582     {
1583       self.SetProperty(mPropertyPositionMin, Vector3(0.0f, firstItemPosition.y, 0.0f));
1584       self.SetProperty(mPropertyPositionMax, Vector3(0.0f, lastItemPosition.y, 0.0f));
1585       domainSize = fabs(firstItemPosition.y - lastItemPosition.y);
1586     }
1587
1588     mScrollConnector.SetScrollDomain(minLayoutPosition, 0.0f, domainSize);
1589
1590     bool isLayoutScrollable = IsLayoutScrollable(layoutSize);
1591     self.SetProperty(mPropertyCanScrollVertical, isLayoutScrollable);
1592     self.SetProperty(mPropertyCanScrollHorizontal, false);
1593   }
1594 }
1595
1596 Vector3 ItemView::GetDomainSize() const
1597 {
1598   Actor self = Self();
1599
1600   float minScrollPosition = self.GetProperty<float>(mPropertyPositionMin);
1601   float maxScrollPosition = self.GetProperty<float>(mPropertyPositionMax);
1602
1603   return Vector3(0.0f, fabs(maxScrollPosition - minScrollPosition), 0.0f);
1604 }
1605
1606 bool ItemView::IsLayoutScrollable(const Vector3& layoutSize)
1607 {
1608   Actor self = Self();
1609
1610   float currentLayoutPosition = ClampFirstItemPosition( GetCurrentLayoutPosition(0), layoutSize, *mActiveLayout );
1611   float forwardClampedPosition = ClampFirstItemPosition(currentLayoutPosition + 1.0, layoutSize, *mActiveLayout);
1612   float backwardClampedPosition = ClampFirstItemPosition(currentLayoutPosition - 1.0, layoutSize, *mActiveLayout);
1613
1614   return (fabs(forwardClampedPosition - backwardClampedPosition) > Math::MACHINE_EPSILON_0);
1615 }
1616
1617 float ItemView::GetScrollPosition(float layoutPosition, const Vector3& layoutSize) const
1618 {
1619   Vector3 firstItemPosition(Vector3::ZERO);
1620   ItemLayout::Vector3Function firstItemPositionConstraint;
1621   if (mActiveLayout->GetPositionConstraint(0, firstItemPositionConstraint))
1622   {
1623     firstItemPosition = firstItemPositionConstraint(Vector3::ZERO, layoutPosition, 0.0f, layoutSize);
1624   }
1625
1626   return IsHorizontal(mActiveLayout->GetOrientation()) ? firstItemPosition.x: firstItemPosition.y;
1627 }
1628
1629 Vector3 ItemView::GetCurrentScrollPosition() const
1630 {
1631   float currentLayoutPosition = GetCurrentLayoutPosition(0);
1632   return Vector3(0.0f, GetScrollPosition(currentLayoutPosition, Self().GetCurrentSize()), 0.0f);
1633 }
1634
1635 void ItemView::AddOverlay(Actor actor)
1636 {
1637   Self().Add(actor);
1638 }
1639
1640 void ItemView::RemoveOverlay(Actor actor)
1641 {
1642   Self().Remove(actor);
1643 }
1644
1645 void ItemView::ScrollTo(const Vector3& position, float duration)
1646 {
1647   Actor self = Self();
1648   const Vector3 layoutSize = Self().GetCurrentSize();
1649
1650   float firstItemScrollPosition = ClampFirstItemPosition(position.y, layoutSize, *mActiveLayout);
1651
1652   if(duration > 0.0f)
1653   {
1654     RemoveAnimation(mScrollAnimation);
1655     mScrollAnimation = Animation::New(duration);
1656     mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut );
1657     mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut );
1658     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1659     mScrollAnimation.Play();
1660   }
1661   else
1662   {
1663     mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
1664     AnimateScrollOvershoot(0.0f);
1665   }
1666
1667   mScrollStartedSignalV2.Emit(GetCurrentScrollPosition());
1668 }
1669
1670 void ItemView::SetOvershootEnabled( bool enable )
1671 {
1672   Actor self = Self();
1673   if( enable )
1674   {
1675     mOvershootEffect = BouncingEffect::New(Scrollable::DEFAULT_OVERSHOOT_COLOUR);
1676     mOvershootOverlay = CreateSolidColorActor(Vector4::ONE);
1677     mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT);
1678     mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT);
1679     mOvershootOverlay.SetDrawMode(DrawMode::OVERLAY);
1680     mOvershootOverlay.SetShaderEffect(mOvershootEffect);
1681     self.Add(mOvershootOverlay);
1682     Constraint constraint = Constraint::New<float>( Actor::SIZE_WIDTH,
1683                                                       ParentSource( mPropertyScrollDirection ),
1684                                                       Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ),
1685                                                       ParentSource( Actor::SIZE ),
1686                                                       OvershootOverlaySizeConstraint() );
1687     mOvershootOverlay.ApplyConstraint(constraint);
1688     mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_IMAGE_1_PIXEL_AREA.width, OVERSHOOT_BOUNCE_IMAGE_1_PIXEL_AREA.height);
1689
1690     constraint = Constraint::New<Quaternion>( Actor::ROTATION,
1691                                               ParentSource( mPropertyScrollDirection ),
1692                                               Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ),
1693                                               OvershootOverlayRotationConstraint() );
1694     mOvershootOverlay.ApplyConstraint(constraint);
1695
1696     constraint = Constraint::New<Vector3>( Actor::POSITION,
1697                                            ParentSource( Actor::SIZE ),
1698                                            ParentSource( mPropertyScrollDirection ),
1699                                            Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ),
1700                                            OvershootOverlayPositionConstraint() );
1701     mOvershootOverlay.ApplyConstraint(constraint);
1702
1703     constraint = Constraint::New<bool>( Actor::VISIBLE,
1704                                         ParentSource( mPropertyCanScrollVertical ),
1705                                         OvershootOverlayVisibilityConstraint() );
1706     mOvershootOverlay.ApplyConstraint(constraint);
1707
1708     int effectOvershootPropertyIndex = mOvershootEffect.GetPropertyIndex(mOvershootEffect.GetProgressRatePropertyName());
1709     Actor self = Self();
1710     constraint = Constraint::New<float>( effectOvershootPropertyIndex,
1711                                          Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ),
1712                                          EqualToConstraint() );
1713     mOvershootEffect.ApplyConstraint(constraint);
1714   }
1715   else
1716   {
1717     if( mOvershootOverlay )
1718     {
1719       self.Remove(mOvershootOverlay);
1720       mOvershootOverlay.Reset();
1721     }
1722     mOvershootEffect.Reset();
1723   }
1724 }
1725
1726 float ItemView::CalculateScrollOvershoot()
1727 {
1728   float overshoot = 0.0f;
1729
1730   if(mActiveLayout)
1731   {
1732     // The overshoot must be calculated from the accumulated pan gesture displacement
1733     // since the pan gesture starts.
1734     Actor self = Self();
1735     float scrollDistance = CalculateScrollDistance(mTotalPanDisplacement, *mActiveLayout) * mActiveLayout->GetScrollSpeedFactor();
1736     float positionDelta = GetCurrentLayoutPosition(0) + scrollDistance;
1737     float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), Self().GetCurrentSize());
1738     self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition);
1739     float clamppedPosition = min(0.0f, max(minLayoutPosition, positionDelta));
1740     overshoot = positionDelta - clamppedPosition;
1741   }
1742
1743   return overshoot;
1744 }
1745
1746 void ItemView::AnimateScrollOvershoot(float overshootAmount, bool animateBack)
1747 {
1748   bool animatingOn = fabsf(overshootAmount) > Math::MACHINE_EPSILON_1;
1749
1750   // make sure we animate back if needed
1751   mAnimateOvershootOff = animateBack || (!animatingOn && mAnimatingOvershootOn);
1752
1753   if( mAnimatingOvershootOn )
1754   {
1755     // animating on, do not allow animate off
1756     return;
1757   }
1758
1759   Actor self = Self();
1760   float currentOvershoot = mScrollPositionObject.GetProperty<float>(ScrollConnector::OVERSHOOT);
1761   float duration = DEFAULT_OVERSHOOT_ANIMATION_DURATION * (animatingOn ? (1.0f - fabsf(currentOvershoot)) : fabsf(currentOvershoot));
1762
1763   RemoveAnimation(mScrollOvershootAnimation);
1764   mScrollOvershootAnimation = Animation::New(duration);
1765   mScrollOvershootAnimation.FinishedSignal().Connect(this, &ItemView::OnOvershootOnFinished);
1766   mScrollOvershootAnimation.AnimateTo( Property(mScrollPositionObject, ScrollConnector::OVERSHOOT), overshootAmount, TimePeriod(0.0f, duration) );
1767   mScrollOvershootAnimation.Play();
1768
1769   mAnimatingOvershootOn = animatingOn;
1770 }
1771
1772 void ItemView::SetItemsParentOrigin( const Vector3& parentOrigin )
1773 {
1774   if( parentOrigin != mItemsParentOrigin )
1775   {
1776     mItemsParentOrigin = parentOrigin;
1777     for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
1778     {
1779       iter->second.SetParentOrigin(parentOrigin);
1780     }
1781   }
1782 }
1783
1784 Vector3 ItemView::GetItemsParentOrigin() const
1785 {
1786   return mItemsParentOrigin;
1787 }
1788
1789 void ItemView::SetItemsAnchorPoint( const Vector3& anchorPoint )
1790 {
1791   if( anchorPoint != mItemsAnchorPoint )
1792   {
1793     mItemsAnchorPoint = anchorPoint;
1794     for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
1795     {
1796       iter->second.SetAnchorPoint(anchorPoint);
1797     }
1798   }
1799 }
1800
1801 Vector3 ItemView::GetItemsAnchorPoint() const
1802 {
1803   return mItemsAnchorPoint;
1804 }
1805
1806 void ItemView::GetItemsRange(ItemRange& range)
1807 {
1808   range.begin = mItemPool.begin()->first;
1809   range.end = mItemPool.rbegin()->first + 1;
1810 }
1811
1812 } // namespace Internal
1813
1814 } // namespace Toolkit
1815
1816 } // namespace Dali