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