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