Merge "Changes after TouchedSignal changes" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scrollable / item-view / item-view-impl.cpp
1 /*
2  * Copyright (c) 2020 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/devel-api/common/stage.h>
29 #include <dali/public-api/events/wheel-event.h>
30 #include <dali/public-api/events/touch-event.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/devel-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.TouchedSignal().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.SetProperty( Actor::Property::SIZE, 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.SetProperty( Actor::Property::SIZE, 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.SetProperty( Actor::Property::SIZE, 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.GetDelta() * 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 TouchEvent& 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 false; // Do not consume as we're potentially scrolling (detecting pan gestures)
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.GetState();
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       const Vector2& displacement = gesture.GetDisplacement();
1231       mScrollDistance = CalculateScrollDistance(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 += 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().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
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().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
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().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
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().GetCurrentProperty< Vector3 >( Actor::Property::SIZE )));
1508 }
1509
1510 void ItemView::AddOverlay(Actor actor)
1511 {
1512   actor.SetProperty( Actor::Property::DRAW_MODE, 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().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
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.SetProperty( Actor::Property::COLOR, 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.SetProperty( Actor::Property::COLOR,mOvershootEffectColor);
1577       mOvershootOverlay.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::TOP_LEFT );
1578       mOvershootOverlay.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::TOP_LEFT);
1579       mOvershootOverlay.SetProperty( Actor::Property::DRAW_MODE, 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().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ));
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.GetCurrentProperty< Vector3 >( Actor::Property::SIZE ).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.SetProperty( Actor::Property::PARENT_ORIGIN,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.SetProperty( Actor::Property::ANCHOR_POINT,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
1759       case Toolkit::ItemView::Property::MINIMUM_SWIPE_DISTANCE:
1760       {
1761         itemViewImpl.SetMinimumSwipeDistance( value.Get<float>() );
1762         break;
1763       }
1764
1765       case Toolkit::ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP:
1766       {
1767         itemViewImpl.SetWheelScrollDistanceStep( value.Get<float>() );
1768         break;
1769       }
1770
1771       case Toolkit::ItemView::Property::SNAP_TO_ITEM_ENABLED:
1772       {
1773         itemViewImpl.SetAnchoring( value.Get<bool>() );
1774         break;
1775       }
1776
1777       case Toolkit::ItemView::Property::REFRESH_INTERVAL:
1778       {
1779         itemViewImpl.SetRefreshInterval( value.Get<float>() );
1780         break;
1781       }
1782
1783       case Toolkit::ItemView::Property::LAYOUT:
1784       {
1785         // Get a Property::Array from the property if possible.
1786         Property::Array layoutArray;
1787         if( value.Get( layoutArray ) )
1788         {
1789           itemViewImpl.SetLayoutArray( layoutArray );
1790         }
1791         break;
1792       }
1793     }
1794   }
1795 }
1796
1797 Property::Array ItemView::GetLayoutArray()
1798 {
1799   return mlayoutArray;
1800 }
1801
1802 void ItemView::SetLayoutArray( const Property::Array& layouts )
1803 {
1804   mlayoutArray = layouts;
1805   const int layoutCount = GetLayoutCount();
1806   if( layoutCount > 0 )
1807   {
1808     for(int index = layoutCount - 1; index >= 0; --index)
1809     {
1810       RemoveLayout(index);
1811       if(index == 0) break;
1812     }
1813   }
1814
1815   for( unsigned int arrayIdx = 0, arrayCount = layouts.Count(); arrayIdx < arrayCount; ++arrayIdx )
1816   {
1817     const Property::Value& element = layouts.GetElementAt( arrayIdx );
1818
1819     Property::Map* layout = element.GetMap();
1820     if( layout != NULL )
1821     {
1822       for( unsigned int mapIdx = 0, mapCount = (*layout).Count(); mapIdx < mapCount; ++mapIdx )
1823       {
1824         KeyValuePair propertyPair( (*layout).GetKeyValue( mapIdx ) );
1825
1826         if(propertyPair.first == DefaultItemLayoutProperty::TYPE)
1827         {
1828           int layoutType = propertyPair.second.Get<int>();
1829           if(layoutType <= DefaultItemLayout::SPIRAL && layoutType >= DefaultItemLayout::DEPTH)
1830           {
1831             //DEPTH, GRID, LIST, SPIRAL
1832             switch(DefaultItemLayout::Type(layoutType))
1833             {
1834               case DefaultItemLayout::DEPTH:
1835               {
1836                 Internal::DepthLayoutPtr depthLayout = Internal::DepthLayout::New();
1837                 (*depthLayout).SetLayoutProperties(*layout);
1838                 (*depthLayout).SetDepthLayoutProperties(*layout);
1839                 AddLayout(*depthLayout);
1840                 break;
1841               }
1842               case DefaultItemLayout::GRID:
1843               {
1844                 Internal::GridLayoutPtr gridLayout = Internal::GridLayout::New();
1845                 (*gridLayout).SetLayoutProperties(*layout);
1846                 (*gridLayout).SetGridLayoutProperties(*layout);
1847                 AddLayout(*gridLayout);
1848                 break;
1849               }
1850               case DefaultItemLayout::LIST:
1851               {
1852                 Internal::GridLayoutPtr listLayout = Internal::GridLayout::New();
1853                 listLayout->SetNumberOfColumns( 1 );
1854                 (*listLayout).SetLayoutProperties(*layout);
1855                 (*listLayout).SetGridLayoutProperties(*layout);
1856                 AddLayout(*listLayout);
1857                 break;
1858               }
1859               case DefaultItemLayout::SPIRAL:
1860               {
1861                 Internal::SpiralLayoutPtr spiralLayout = Internal::SpiralLayout::New();
1862                 (*spiralLayout).SetLayoutProperties(*layout);
1863                 (*spiralLayout).SetSpiralLayoutProperties(*layout);
1864                 AddLayout(*spiralLayout);
1865                 break;
1866               }
1867             }
1868           }
1869         }
1870       }
1871     }
1872   }
1873 }
1874
1875 Property::Value ItemView::GetProperty( BaseObject* object, Property::Index index )
1876 {
1877   Property::Value value;
1878
1879   Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( Dali::BaseHandle( object ) );
1880
1881   if( itemView )
1882   {
1883     ItemView& itemViewImpl( GetImpl( itemView ) );
1884     switch( index )
1885     {
1886       case Toolkit::ItemView::Property::MINIMUM_SWIPE_SPEED:
1887       {
1888         value = itemViewImpl.GetMinimumSwipeSpeed();
1889         break;
1890       }
1891
1892       case Toolkit::ItemView::Property::MINIMUM_SWIPE_DISTANCE:
1893       {
1894         value = itemViewImpl.GetMinimumSwipeDistance();
1895         break;
1896       }
1897
1898       case Toolkit::ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP:
1899       {
1900         value = itemViewImpl.GetWheelScrollDistanceStep();
1901         break;
1902       }
1903
1904       case Toolkit::ItemView::Property::SNAP_TO_ITEM_ENABLED:
1905       {
1906         value = itemViewImpl.GetAnchoring();
1907         break;
1908       }
1909
1910       case Toolkit::ItemView::Property::REFRESH_INTERVAL:
1911       {
1912         value = itemViewImpl.GetRefreshInterval();
1913         break;
1914       }
1915
1916       case Toolkit::ItemView::Property::LAYOUT:
1917       {
1918         Property::Array layouts= itemViewImpl.GetLayoutArray();
1919         value = layouts;
1920         break;
1921       }
1922     }
1923   }
1924
1925   return value;
1926 }
1927
1928 bool ItemView::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
1929 {
1930   Dali::BaseHandle handle( object );
1931
1932   Toolkit::ItemView itemView = Toolkit::ItemView::DownCast( handle );
1933
1934   DALI_ASSERT_ALWAYS( itemView );
1935
1936   if( 0 == strcmp( actionName.c_str(), ACTION_STOP_SCROLLING ) )
1937   {
1938     GetImpl( itemView ).DoStopScrolling();
1939   }
1940   else if ( 0 == strcmp( actionName.c_str(), ACTION_ENABLE_REFRESH ) )
1941   {
1942     GetImpl( itemView ).SetRefreshNotificationEnabled( true );
1943   }
1944   else if ( 0 == strcmp( actionName.c_str(), ACTION_DISABLE_REFRESH ) )
1945   {
1946     GetImpl( itemView ).SetRefreshNotificationEnabled( false );
1947   }
1948
1949   return true;
1950 }
1951
1952 void ItemView::DoStopScrolling()
1953 {
1954   if( mScrollAnimation )
1955   {
1956     mScrollAnimation.Stop();
1957     mScrollAnimation.Reset();
1958   }
1959 }
1960
1961 void ItemView::SetRefreshNotificationEnabled( bool enabled )
1962 {
1963   mRefreshNotificationEnabled = enabled;
1964 }
1965
1966 } // namespace Internal
1967
1968 } // namespace Toolkit
1969
1970 } // namespace Dali