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