(ItemView) Modified scroll speed and flick animation duration calculation for gallery...
[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     mScrollCompletedSignalV2.Emit(GetCurrentScrollPosition());
1115
1116     RemoveAnimation(mScrollAnimation);
1117   }
1118
1119   return true; // consume since we're potentially scrolling
1120 }
1121
1122 bool ItemView::OnMouseWheelEvent(const MouseWheelEvent& event)
1123 {
1124   // Respond the mouse wheel event to scroll
1125   if (mActiveLayout)
1126   {
1127     Actor self = Self();
1128     const Vector3 layoutSize = Self().GetCurrentSize();
1129     float layoutPositionDelta = GetCurrentLayoutPosition(0) - (event.z * mMouseWheelScrollDistanceStep * mActiveLayout->GetScrollSpeedFactor());
1130     float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout);
1131
1132     mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
1133     self.SetProperty(mPropertyPosition, GetScrollPosition(firstItemScrollPosition, layoutSize));
1134     mScrollStartedSignalV2.Emit(GetCurrentScrollPosition());
1135     mRefreshEnabled = true;
1136   }
1137
1138   if (mMouseWheelEventFinishedTimer.IsRunning())
1139   {
1140     mMouseWheelEventFinishedTimer.Stop();
1141   }
1142
1143   mMouseWheelEventFinishedTimer.Start();
1144
1145   return true;
1146 }
1147
1148 bool ItemView::OnMouseWheelEventFinished()
1149 {
1150   if (mActiveLayout)
1151   {
1152     RemoveAnimation(mScrollAnimation);
1153
1154     // No more mouse wheel events coming. Do the anchoring if enabled.
1155     mScrollAnimation = DoAnchoring();
1156     if (mScrollAnimation)
1157     {
1158       mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1159       mScrollAnimation.Play();
1160     }
1161     else
1162     {
1163       mScrollOvershoot = 0.0f;
1164       AnimateScrollOvershoot(0.0f);
1165
1166       mScrollCompletedSignalV2.Emit(GetCurrentScrollPosition());
1167     }
1168   }
1169
1170   return false;
1171 }
1172
1173 void ItemView::ApplyConstraints(Actor& actor, ItemLayout& layout, unsigned int itemId, float duration)
1174 {
1175   ItemLayout::Vector3Function positionConstraint;
1176   if (layout.GetPositionConstraint(itemId, positionConstraint))
1177   {
1178     WrappedVector3Constraint wrapped(positionConstraint, itemId);
1179
1180     Constraint constraint = Constraint::New<Vector3>( Actor::POSITION,
1181                                                       Source( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ),
1182                                                       ParentSource( mPropertyScrollSpeed ),
1183                                                       ParentSource( Actor::SIZE ),
1184                                                       wrapped );
1185     constraint.SetApplyTime(duration);
1186     constraint.SetAlphaFunction(mDefaultAlphaFunction);
1187
1188     actor.ApplyConstraint(constraint);
1189   }
1190
1191   ItemLayout::QuaternionFunction rotationConstraint;
1192   if (layout.GetRotationConstraint(itemId, rotationConstraint))
1193   {
1194     WrappedQuaternionConstraint wrapped(rotationConstraint, itemId);
1195
1196     Constraint constraint = Constraint::New<Quaternion>( Actor::ROTATION,
1197                                                          Source( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ),
1198                                                          ParentSource( mPropertyScrollSpeed ),
1199                                                          ParentSource( Actor::SIZE ),
1200                                                          wrapped );
1201     constraint.SetApplyTime(duration);
1202     constraint.SetAlphaFunction(mDefaultAlphaFunction);
1203
1204     actor.ApplyConstraint(constraint);
1205   }
1206
1207   ItemLayout::Vector3Function scaleConstraint;
1208   if (layout.GetScaleConstraint(itemId, scaleConstraint))
1209   {
1210     WrappedVector3Constraint wrapped(scaleConstraint, itemId);
1211
1212     Constraint constraint = Constraint::New<Vector3>( Actor::SCALE,
1213                                                       Source( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ),
1214                                                       ParentSource( mPropertyScrollSpeed ),
1215                                                       ParentSource( Actor::SIZE ),
1216                                                       wrapped );
1217     constraint.SetApplyTime(duration);
1218     constraint.SetAlphaFunction(mDefaultAlphaFunction);
1219
1220     actor.ApplyConstraint(constraint);
1221   }
1222
1223   ItemLayout::Vector4Function colorConstraint;
1224   if (layout.GetColorConstraint(itemId, colorConstraint))
1225   {
1226     WrappedVector4Constraint wrapped(colorConstraint, itemId);
1227
1228     Constraint constraint = Constraint::New<Vector4>( Actor::COLOR,
1229                                                       Source( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ),
1230                                                       ParentSource( mPropertyScrollSpeed ),
1231                                                       ParentSource( Actor::SIZE ),
1232                                                       wrapped );
1233     constraint.SetApplyTime(duration);
1234     constraint.SetAlphaFunction(mDefaultAlphaFunction);
1235
1236     // Release color constraints slowly; this allows ItemView to co-exist with ImageActor fade-in
1237     constraint.SetRemoveTime(DEFAULT_COLOR_VISIBILITY_REMOVE_TIME);
1238     constraint.SetRemoveAction(Dali::Constraint::Discard);
1239
1240     actor.ApplyConstraint(constraint);
1241   }
1242
1243   ItemLayout::BoolFunction visibilityConstraint;
1244   if (layout.GetVisibilityConstraint(itemId, visibilityConstraint))
1245   {
1246     WrappedBoolConstraint wrapped(visibilityConstraint, itemId);
1247
1248     Constraint constraint = Constraint::New<bool>( Actor::VISIBLE,
1249                                                    Source( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ),
1250                                                    ParentSource( mPropertyScrollSpeed ),
1251                                                    ParentSource( Actor::SIZE ),
1252                                                    wrapped );
1253     constraint.SetApplyTime(duration);
1254     constraint.SetAlphaFunction(mDefaultAlphaFunction);
1255
1256     // Release visibility constraints the same time as the color constraint
1257     constraint.SetRemoveTime(DEFAULT_COLOR_VISIBILITY_REMOVE_TIME);
1258     constraint.SetRemoveAction(Dali::Constraint::Discard);
1259
1260     actor.ApplyConstraint(constraint);
1261   }
1262 }
1263
1264 void ItemView::ReapplyAllConstraints( float durationSeconds )
1265 {
1266   for (ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
1267   {
1268     unsigned int id = iter->first;
1269     Actor actor = iter->second;
1270
1271     actor.RemoveConstraints();
1272     ApplyConstraints(actor, *mActiveLayout, id, durationSeconds);
1273   }
1274
1275   CalculateDomainSize(Self().GetCurrentSize());
1276 }
1277
1278 float ItemView::ClampFirstItemPosition(float targetPosition, const Vector3& targetSize, ItemLayout& layout)
1279 {
1280   Actor self = Self();
1281   float minLayoutPosition = layout.GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), targetSize);
1282   float clamppedPosition = min(0.0f, max(minLayoutPosition, targetPosition));
1283   mScrollOvershoot = targetPosition - clamppedPosition;
1284   self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition);
1285
1286   return clamppedPosition;
1287 }
1288
1289 void ItemView::OnPan(PanGesture gesture)
1290 {
1291   Actor self = Self();
1292   const Vector3 layoutSize = Self().GetCurrentSize();
1293
1294   RemoveAnimation(mScrollAnimation);
1295
1296   // Short-circuit if there is no active layout
1297   if (!mActiveLayout)
1298   {
1299     mGestureState = Gesture::Clear;
1300     return;
1301   }
1302
1303   mGestureState = gesture.state;
1304
1305   switch (mGestureState)
1306   {
1307     case Gesture::Finished:
1308     {
1309       // Swipe Detection
1310       if (fabsf(mScrollDistance) > mMinimumSwipeDistance &&
1311           mScrollSpeed > mMinimumSwipeSpeed)
1312       {
1313         float direction = (mScrollDistance < 0.0f) ? -1.0f : 1.0f;
1314
1315         mRefreshOrderHint = true;
1316
1317         float currentLayoutPosition = GetCurrentLayoutPosition(0);
1318         float firstItemScrollPosition = ClampFirstItemPosition(currentLayoutPosition + mScrollSpeed * direction,
1319                                                                layoutSize,
1320                                                                *mActiveLayout);
1321
1322         if (mAnchoringEnabled)
1323         {
1324           firstItemScrollPosition = mActiveLayout->GetClosestAnchorPosition(firstItemScrollPosition);
1325         }
1326
1327         RemoveAnimation(mScrollAnimation);
1328
1329         float flickAnimationDuration = Clamp( mActiveLayout->GetItemFlickAnimationDuration() * max(1.0f, fabsf(firstItemScrollPosition - GetCurrentLayoutPosition(0)))
1330                                        , DEFAULT_MINIMUM_SWIPE_DURATION, DEFAULT_MAXIMUM_SWIPE_DURATION);
1331
1332         mScrollAnimation = Animation::New(flickAnimationDuration);
1333         mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut );
1334         mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut );
1335         mScrollAnimation.AnimateTo( Property(self, mPropertyScrollSpeed), 0.0f, AlphaFunctions::EaseOut );
1336
1337         mIsFlicking = true;
1338         // Check whether it has already scrolled to the end
1339         if(fabs(currentLayoutPosition - firstItemScrollPosition) > Math::MACHINE_EPSILON_0)
1340         {
1341           AnimateScrollOvershoot(0.0f);
1342         }
1343       }
1344
1345       // Anchoring may be triggered when there was no swipe
1346       if (!mScrollAnimation)
1347       {
1348         mScrollAnimation = DoAnchoring();
1349       }
1350
1351       // Reset the overshoot if no scroll animation.
1352       if (!mScrollAnimation)
1353       {
1354         mScrollCompletedSignalV2.Emit(GetCurrentScrollPosition());
1355
1356         AnimateScrollOvershoot(0.0f, false);
1357       }
1358     }
1359     break;
1360
1361     case Gesture::Started: // Fall through
1362     {
1363       mTotalPanDisplacement = Vector2::ZERO;
1364       mScrollStartedSignalV2.Emit(GetCurrentScrollPosition());
1365       mRefreshEnabled = true;
1366     }
1367
1368     case Gesture::Continuing:
1369     {
1370       mScrollDistance = CalculateScrollDistance(gesture.displacement, *mActiveLayout);
1371       mScrollSpeed = Clamp((gesture.GetSpeed() * gesture.GetSpeed() * mActiveLayout->GetFlickSpeedFactor() * MILLISECONDS_PER_SECONDS), 0.0f, mActiveLayout->GetMaximumSwipeSpeed());
1372
1373       // Refresh order depends on the direction of the scroll; negative is towards the last item.
1374       mRefreshOrderHint = mScrollDistance < 0.0f;
1375
1376       float layoutPositionDelta = GetCurrentLayoutPosition(0) + (mScrollDistance * mActiveLayout->GetScrollSpeedFactor());
1377
1378       float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout);
1379
1380       mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
1381       self.SetProperty(mPropertyPosition, GetScrollPosition(firstItemScrollPosition, layoutSize));
1382
1383       mTotalPanDisplacement += gesture.displacement;
1384       mScrollOvershoot = layoutPositionDelta - firstItemScrollPosition;
1385       if( mScrollOvershoot > Math::MACHINE_EPSILON_1 )
1386       {
1387         AnimateScrollOvershoot(1.0f);
1388       }
1389       else if( mScrollOvershoot < -Math::MACHINE_EPSILON_1 )
1390       {
1391         AnimateScrollOvershoot(-1.0f);
1392       }
1393       else
1394       {
1395         AnimateScrollOvershoot(0.0f);
1396       }
1397     }
1398     break;
1399
1400     case Gesture::Cancelled:
1401     {
1402       mScrollAnimation = DoAnchoring();
1403     }
1404     break;
1405
1406     default:
1407       break;
1408   }
1409
1410   if (mScrollAnimation)
1411   {
1412     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1413     mScrollAnimation.Play();
1414   }
1415 }
1416
1417 bool ItemView::OnAccessibilityPan(PanGesture gesture)
1418 {
1419   OnPan(gesture);
1420   return true;
1421 }
1422
1423 Actor ItemView::GetNextKeyboardFocusableActor(Actor actor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
1424 {
1425   Actor nextFocusActor;
1426   if(mActiveLayout)
1427   {
1428     int nextItemID = 0;
1429     if(!actor || actor == this->Self())
1430     {
1431       nextFocusActor = GetItem(nextItemID);
1432     }
1433     else if(actor && actor.GetParent() == this->Self())
1434     {
1435       int itemID = GetItemId(actor);
1436       nextItemID = mActiveLayout->GetNextFocusItemID(itemID, mItemFactory.GetNumberOfItems(), direction, loopEnabled);
1437       nextFocusActor = GetItem(nextItemID);
1438       if(nextFocusActor == actor)
1439       {
1440         // need to pass NULL actor back to focus manager
1441         nextFocusActor.Reset();
1442         return nextFocusActor;
1443       }
1444     }
1445     float layoutPosition = mActiveLayout->GetClosestAnchorPosition( GetCurrentLayoutPosition(0) );
1446     Vector3 layoutSize = Self().GetCurrentSize();
1447     if(!nextFocusActor)
1448     {
1449       // likely the current item is not buffered, so not in our item pool, probably best to get first viewable item
1450       ItemRange viewableItems = mActiveLayout->GetItemsWithinArea(layoutPosition, layoutSize);
1451       nextItemID = viewableItems.begin;
1452       nextFocusActor = GetItem(nextItemID);
1453     }
1454   }
1455   return nextFocusActor;
1456 }
1457
1458 void ItemView::OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor)
1459 {
1460   // only in this function if our chosen focus actor was actually used
1461   if(commitedFocusableActor)
1462   {
1463     int nextItemID = GetItemId(commitedFocusableActor);
1464     float layoutPosition = GetCurrentLayoutPosition(0);
1465     Vector3 layoutSize = Self().GetCurrentSize();
1466     Vector3 focusItemPosition = Vector3::ZERO;
1467     ItemLayout::Vector3Function itemPositionConstraint;
1468     if (mActiveLayout->GetPositionConstraint(nextItemID, itemPositionConstraint))
1469     {
1470       focusItemPosition = itemPositionConstraint(Vector3::ZERO, layoutPosition + nextItemID, 0.0f, layoutSize);
1471     }
1472
1473     float scrollTo = mActiveLayout->GetClosestOnScreenLayoutPosition(nextItemID, layoutPosition, layoutSize);
1474     ScrollTo(Vector3(0.0f, scrollTo, 0.0f), DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION);
1475   }
1476 }
1477
1478 Animation ItemView::DoAnchoring()
1479 {
1480   Animation anchoringAnimation;
1481   Actor self = Self();
1482
1483   if (mActiveLayout && mAnchoringEnabled)
1484   {
1485     float anchorPosition = mActiveLayout->GetClosestAnchorPosition( GetCurrentLayoutPosition(0) );
1486
1487     anchoringAnimation = Animation::New(mAnchoringDuration);
1488     anchoringAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), anchorPosition, AlphaFunctions::EaseOut );
1489     anchoringAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(anchorPosition, self.GetCurrentSize()), AlphaFunctions::EaseOut );
1490     anchoringAnimation.AnimateTo( Property(self, mPropertyScrollSpeed), 0.0f, AlphaFunctions::EaseOut );
1491     if(!mIsFlicking)
1492     {
1493       AnimateScrollOvershoot(0.0f);
1494     }
1495   }
1496
1497   return anchoringAnimation;
1498 }
1499
1500 void ItemView::OnScrollFinished(Animation& source)
1501 {
1502   Actor self = Self();
1503
1504   RemoveAnimation(mScrollAnimation); // mScrollAnimation is used to query whether we're scrolling
1505
1506   mScrollCompletedSignalV2.Emit(GetCurrentScrollPosition());
1507
1508   if(mIsFlicking && fabsf(mScrollOvershoot) > Math::MACHINE_EPSILON_1)
1509   {
1510     AnimateScrollOvershoot( mScrollOvershoot > 0.0f ? 1.0f : -1.0f, true);
1511   }
1512   else
1513   {
1514     // Reset the overshoot
1515     AnimateScrollOvershoot( 0.0f );
1516   }
1517   mIsFlicking = false;
1518
1519   mScrollOvershoot = 0.0f;
1520 }
1521
1522 void ItemView::OnLayoutActivationScrollFinished(Animation& source)
1523 {
1524   mRefreshEnabled = true;
1525   DoRefresh(GetCurrentLayoutPosition(0), true);
1526 }
1527
1528 void ItemView::OnOvershootOnFinished(Animation& animation)
1529 {
1530   mAnimatingOvershootOn = false;
1531   mScrollOvershootAnimation.FinishedSignal().Disconnect(this, &ItemView::OnOvershootOnFinished);
1532   RemoveAnimation(mScrollOvershootAnimation);
1533   if(mAnimateOvershootOff)
1534   {
1535     AnimateScrollOvershoot(0.0f);
1536   }
1537 }
1538
1539 void ItemView::ScrollToItem(unsigned int itemId, float durationSeconds)
1540 {
1541   Actor self = Self();
1542   const Vector3 layoutSize = Self().GetCurrentSize();
1543   float firstItemScrollPosition = ClampFirstItemPosition(mActiveLayout->GetItemScrollToPosition(itemId), layoutSize, *mActiveLayout);
1544
1545   if(durationSeconds > 0.0f)
1546   {
1547     RemoveAnimation(mScrollAnimation);
1548     mScrollAnimation = Animation::New(durationSeconds);
1549     mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut );
1550     mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut );
1551     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1552     mScrollAnimation.Play();
1553   }
1554   else
1555   {
1556     mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
1557     AnimateScrollOvershoot(0.0f);
1558   }
1559
1560   mScrollStartedSignalV2.Emit(GetCurrentScrollPosition());
1561   mRefreshEnabled = true;
1562 }
1563
1564 void ItemView::RemoveAnimation(Animation& animation)
1565 {
1566   if(animation)
1567   {
1568     // Cease animating, and reset handle.
1569     animation.Clear();
1570     animation.Reset();
1571   }
1572 }
1573
1574 void ItemView::CalculateDomainSize(const Vector3& layoutSize)
1575 {
1576   Actor self = Self();
1577
1578   Vector3 firstItemPosition(Vector3::ZERO);
1579   Vector3 lastItemPosition(Vector3::ZERO);
1580
1581   if(mActiveLayout)
1582   {
1583     ItemLayout::Vector3Function firstItemPositionConstraint;
1584     if (mActiveLayout->GetPositionConstraint(0, firstItemPositionConstraint))
1585     {
1586       firstItemPosition = firstItemPositionConstraint(Vector3::ZERO, 0, 0.0f, layoutSize);
1587     }
1588
1589     float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize);
1590     self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition);
1591
1592     ItemLayout::Vector3Function lastItemPositionConstraint;
1593     if (mActiveLayout->GetPositionConstraint(fabs(minLayoutPosition), lastItemPositionConstraint))
1594     {
1595       lastItemPosition = lastItemPositionConstraint(Vector3::ZERO, fabs(minLayoutPosition), 0.0f, layoutSize);
1596     }
1597
1598     float domainSize;
1599
1600     if(IsHorizontal(mActiveLayout->GetOrientation()))
1601     {
1602       self.SetProperty(mPropertyPositionMin, Vector3(0.0f, firstItemPosition.x, 0.0f));
1603       self.SetProperty(mPropertyPositionMax, Vector3(0.0f, lastItemPosition.x, 0.0f));
1604       domainSize = fabs(firstItemPosition.x - lastItemPosition.x);
1605     }
1606     else
1607     {
1608       self.SetProperty(mPropertyPositionMin, Vector3(0.0f, firstItemPosition.y, 0.0f));
1609       self.SetProperty(mPropertyPositionMax, Vector3(0.0f, lastItemPosition.y, 0.0f));
1610       domainSize = fabs(firstItemPosition.y - lastItemPosition.y);
1611     }
1612
1613     mScrollConnector.SetScrollDomain(minLayoutPosition, 0.0f, domainSize);
1614
1615     bool isLayoutScrollable = IsLayoutScrollable(layoutSize);
1616     self.SetProperty(mPropertyCanScrollVertical, isLayoutScrollable);
1617     self.SetProperty(mPropertyCanScrollHorizontal, false);
1618   }
1619 }
1620
1621 Vector3 ItemView::GetDomainSize() const
1622 {
1623   Actor self = Self();
1624
1625   float minScrollPosition = self.GetProperty<float>(mPropertyPositionMin);
1626   float maxScrollPosition = self.GetProperty<float>(mPropertyPositionMax);
1627
1628   return Vector3(0.0f, fabs(maxScrollPosition - minScrollPosition), 0.0f);
1629 }
1630
1631 bool ItemView::IsLayoutScrollable(const Vector3& layoutSize)
1632 {
1633   Actor self = Self();
1634
1635   float currentLayoutPosition = ClampFirstItemPosition( GetCurrentLayoutPosition(0), layoutSize, *mActiveLayout );
1636   float forwardClampedPosition = ClampFirstItemPosition(currentLayoutPosition + 1.0, layoutSize, *mActiveLayout);
1637   float backwardClampedPosition = ClampFirstItemPosition(currentLayoutPosition - 1.0, layoutSize, *mActiveLayout);
1638
1639   return (fabs(forwardClampedPosition - backwardClampedPosition) > Math::MACHINE_EPSILON_0);
1640 }
1641
1642 float ItemView::GetScrollPosition(float layoutPosition, const Vector3& layoutSize) const
1643 {
1644   Vector3 firstItemPosition(Vector3::ZERO);
1645   ItemLayout::Vector3Function firstItemPositionConstraint;
1646   if (mActiveLayout->GetPositionConstraint(0, firstItemPositionConstraint))
1647   {
1648     firstItemPosition = firstItemPositionConstraint(Vector3::ZERO, layoutPosition, 0.0f, layoutSize);
1649   }
1650
1651   return IsHorizontal(mActiveLayout->GetOrientation()) ? firstItemPosition.x: firstItemPosition.y;
1652 }
1653
1654 Vector3 ItemView::GetCurrentScrollPosition() const
1655 {
1656   float currentLayoutPosition = GetCurrentLayoutPosition(0);
1657   return Vector3(0.0f, GetScrollPosition(currentLayoutPosition, Self().GetCurrentSize()), 0.0f);
1658 }
1659
1660 void ItemView::AddOverlay(Actor actor)
1661 {
1662   Self().Add(actor);
1663 }
1664
1665 void ItemView::RemoveOverlay(Actor actor)
1666 {
1667   Self().Remove(actor);
1668 }
1669
1670 void ItemView::ScrollTo(const Vector3& position, float duration)
1671 {
1672   Actor self = Self();
1673   const Vector3 layoutSize = Self().GetCurrentSize();
1674
1675   float firstItemScrollPosition = ClampFirstItemPosition(position.y, layoutSize, *mActiveLayout);
1676
1677   if(duration > 0.0f)
1678   {
1679     RemoveAnimation(mScrollAnimation);
1680     mScrollAnimation = Animation::New(duration);
1681     mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut );
1682     mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut );
1683     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1684     mScrollAnimation.Play();
1685   }
1686   else
1687   {
1688     mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
1689     AnimateScrollOvershoot(0.0f);
1690   }
1691
1692   mScrollStartedSignalV2.Emit(GetCurrentScrollPosition());
1693   mRefreshEnabled = true;
1694 }
1695
1696 void ItemView::SetOvershootEffectColor( const Vector4& color )
1697 {
1698   mOvershootEffectColor = color;
1699   if( mOvershootOverlay )
1700   {
1701     mOvershootOverlay.SetColor( color );
1702   }
1703 }
1704
1705 void ItemView::SetOvershootEnabled( bool enable )
1706 {
1707   Actor self = Self();
1708   if( enable )
1709   {
1710     Property::Index effectOvershootPropertyIndex = Property::INVALID_INDEX;
1711     mOvershootOverlay = CreateBouncingEffectActor( effectOvershootPropertyIndex );
1712     mOvershootOverlay.SetColor(mOvershootEffectColor);
1713     mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT);
1714     mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT);
1715     mOvershootOverlay.SetDrawMode(DrawMode::OVERLAY);
1716     self.Add(mOvershootOverlay);
1717
1718     Constraint constraint = Constraint::New<Vector3>( Actor::SIZE,
1719                                                       ParentSource( mPropertyScrollDirection ),
1720                                                       Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ),
1721                                                       ParentSource( Actor::SIZE ),
1722                                                       OvershootOverlaySizeConstraint() );
1723     mOvershootOverlay.ApplyConstraint(constraint);
1724     mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.width, OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height);
1725
1726     constraint = Constraint::New<Quaternion>( Actor::ROTATION,
1727                                               ParentSource( mPropertyScrollDirection ),
1728                                               Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ),
1729                                               OvershootOverlayRotationConstraint() );
1730     mOvershootOverlay.ApplyConstraint(constraint);
1731
1732     constraint = Constraint::New<Vector3>( Actor::POSITION,
1733                                            ParentSource( Actor::SIZE ),
1734                                            ParentSource( mPropertyScrollDirection ),
1735                                            Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ),
1736                                            OvershootOverlayPositionConstraint() );
1737     mOvershootOverlay.ApplyConstraint(constraint);
1738
1739     constraint = Constraint::New<bool>( Actor::VISIBLE,
1740                                         ParentSource( mPropertyCanScrollVertical ),
1741                                         OvershootOverlayVisibilityConstraint() );
1742     mOvershootOverlay.ApplyConstraint(constraint);
1743
1744     Actor self = Self();
1745     constraint = Constraint::New<float>( effectOvershootPropertyIndex,
1746                                          Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ),
1747                                          EqualToConstraint() );
1748     mOvershootOverlay.ApplyConstraint(constraint);
1749   }
1750   else
1751   {
1752     if( mOvershootOverlay )
1753     {
1754       self.Remove(mOvershootOverlay);
1755       mOvershootOverlay.Reset();
1756     }
1757   }
1758 }
1759
1760 float ItemView::CalculateScrollOvershoot()
1761 {
1762   float overshoot = 0.0f;
1763
1764   if(mActiveLayout)
1765   {
1766     // The overshoot must be calculated from the accumulated pan gesture displacement
1767     // since the pan gesture starts.
1768     Actor self = Self();
1769     float scrollDistance = CalculateScrollDistance(mTotalPanDisplacement, *mActiveLayout) * mActiveLayout->GetScrollSpeedFactor();
1770     float positionDelta = GetCurrentLayoutPosition(0) + scrollDistance;
1771     float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), Self().GetCurrentSize());
1772     self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition);
1773     float clamppedPosition = min(0.0f, max(minLayoutPosition, positionDelta));
1774     overshoot = positionDelta - clamppedPosition;
1775   }
1776
1777   return overshoot;
1778 }
1779
1780 void ItemView::AnimateScrollOvershoot(float overshootAmount, bool animateBack)
1781 {
1782   bool animatingOn = fabsf(overshootAmount) > Math::MACHINE_EPSILON_1;
1783
1784   // make sure we animate back if needed
1785   mAnimateOvershootOff = animateBack || (!animatingOn && mAnimatingOvershootOn);
1786
1787   if( mAnimatingOvershootOn )
1788   {
1789     // animating on, do not allow animate off
1790     return;
1791   }
1792
1793   Actor self = Self();
1794   float currentOvershoot = mScrollPositionObject.GetProperty<float>(ScrollConnector::OVERSHOOT);
1795   float duration = DEFAULT_OVERSHOOT_ANIMATION_DURATION * (animatingOn ? (1.0f - fabsf(currentOvershoot)) : fabsf(currentOvershoot));
1796
1797   RemoveAnimation(mScrollOvershootAnimation);
1798   mScrollOvershootAnimation = Animation::New(duration);
1799   mScrollOvershootAnimation.FinishedSignal().Connect(this, &ItemView::OnOvershootOnFinished);
1800   mScrollOvershootAnimation.AnimateTo( Property(mScrollPositionObject, ScrollConnector::OVERSHOOT), overshootAmount, TimePeriod(0.0f, duration) );
1801   mScrollOvershootAnimation.Play();
1802
1803   mAnimatingOvershootOn = animatingOn;
1804 }
1805
1806 void ItemView::SetItemsParentOrigin( const Vector3& parentOrigin )
1807 {
1808   if( parentOrigin != mItemsParentOrigin )
1809   {
1810     mItemsParentOrigin = parentOrigin;
1811     for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
1812     {
1813       iter->second.SetParentOrigin(parentOrigin);
1814     }
1815   }
1816 }
1817
1818 Vector3 ItemView::GetItemsParentOrigin() const
1819 {
1820   return mItemsParentOrigin;
1821 }
1822
1823 void ItemView::SetItemsAnchorPoint( const Vector3& anchorPoint )
1824 {
1825   if( anchorPoint != mItemsAnchorPoint )
1826   {
1827     mItemsAnchorPoint = anchorPoint;
1828     for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
1829     {
1830       iter->second.SetAnchorPoint(anchorPoint);
1831     }
1832   }
1833 }
1834
1835 Vector3 ItemView::GetItemsAnchorPoint() const
1836 {
1837   return mItemsAnchorPoint;
1838 }
1839
1840 void ItemView::GetItemsRange(ItemRange& range)
1841 {
1842   range.begin = mItemPool.begin()->first;
1843   range.end = mItemPool.rbegin()->first + 1;
1844 }
1845
1846 void ItemView::OnScrollPositionChanged( float position )
1847 {
1848   // Cancel scroll animation to prevent any fighting of setting the scroll position property.
1849   RemoveAnimation(mScrollAnimation);
1850
1851   // Refresh the cache immediately when the scroll position is changed.
1852   DoRefresh(position, false); // No need to cache extra items.
1853 }
1854
1855 } // namespace Internal
1856
1857 } // namespace Toolkit
1858
1859 } // namespace Dali