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