Merge "Fixes crash when fontclient is unable to supply a correct bitmap" into tizen
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scrollable / item-view / item-view-impl.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring> // for strcmp
23 #include <algorithm>
24 #include <dali/public-api/animation/constraint.h>
25 #include <dali/public-api/animation/constraints.h>
26 #include <dali/public-api/common/set-wrapper.h>
27 #include <dali/public-api/common/stage.h>
28 #include <dali/public-api/events/mouse-wheel-event.h>
29 #include <dali/public-api/events/touch-event.h>
30 #include <dali/public-api/object/type-registry.h>
31 #include <dali/public-api/object/type-registry-helper.h>
32
33 // INTERNAL INCLUDES
34 #include <dali-toolkit/public-api/controls/scrollable/item-view/item-factory.h>
35 #include <dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.h>
36 #include <dali-toolkit/internal/controls/scrollable/scroll-connector-impl.h>
37
38 using std::string;
39 using std::set;
40 using namespace Dali;
41
42 namespace // Unnamed namespace
43 {
44
45 //Type registration
46
47 DALI_TYPE_REGISTRATION_BEGIN( Toolkit::ItemView, Toolkit::Scrollable, NULL )
48 DALI_TYPE_REGISTRATION_END()
49
50 const float DEFAULT_MINIMUM_SWIPE_SPEED = 1.0f;
51 const float DEFAULT_MINIMUM_SWIPE_DISTANCE = 3.0f;
52 const float DEFAULT_MOUSE_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = 0.1f;
53
54 const float DEFAULT_MINIMUM_SWIPE_DURATION = 0.45f;
55 const float DEFAULT_MAXIMUM_SWIPE_DURATION = 2.6f;
56
57 const float DEFAULT_REFRESH_INTERVAL_LAYOUT_POSITIONS = 20.0f; // 1 updates per 20 items
58 const int MOUSE_WHEEL_EVENT_FINISHED_TIME_OUT = 500;  // 0.5 second
59
60 const float DEFAULT_ANCHORING_DURATION = 1.0f;  // 1 second
61
62 const float MILLISECONDS_PER_SECONDS = 1000.0f;
63
64 const Vector2 OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE( 720.0f, 42.0f );
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 string LAYOUT_POSITION_PROPERTY_NAME( "item-view-layout-position" );
70 const string POSITION_PROPERTY_NAME( "item-view-position" );
71 const string MINIMUM_LAYOUT_POSITION_PROPERTY_NAME( "item-view-minimum-layout-position" );
72 const string SCROLL_SPEED_PROPERTY_NAME( "item-view-scroll-speed" );
73 const string SCROLL_DIRECTION_PROPERTY_NAME( "item-view-scroll-direction" );
74 const string OVERSHOOT_PROPERTY_NAME( "item-view-overshoot" );
75
76 /**
77  * Local helper to convert pan distance (in actor coordinates) to the layout-specific scrolling direction
78  */
79 float CalculateScrollDistance(Vector2 panDistance, Toolkit::ItemLayout& layout)
80 {
81   Radian scrollDirection(layout.GetScrollDirection());
82
83   float cosTheta = cosf(scrollDirection);
84   float sinTheta = sinf(scrollDirection);
85
86   return panDistance.x * sinTheta + panDistance.y * cosTheta;
87 }
88
89 // Overshoot overlay constraints
90 void OvershootOverlaySizeConstraint( Vector3& current, const PropertyInputContainer& inputs )
91 {
92   const Vector3& parentScrollDirection = inputs[0]->GetVector3();
93   const Vector3& parentSize = inputs[1]->GetVector3();
94   const Toolkit::ControlOrientation::Type& parentOrientation = static_cast<Toolkit::ControlOrientation::Type>(parentScrollDirection.z);
95
96   if(Toolkit::IsVertical(parentOrientation))
97   {
98     current.width = fabsf(parentScrollDirection.y) > Math::MACHINE_EPSILON_1 ? parentSize.x : parentSize.y;
99   }
100   else
101   {
102     current.width = fabsf(parentScrollDirection.x) > Math::MACHINE_EPSILON_1 ? parentSize.y : parentSize.x;
103   }
104
105   current.height = ( current.width > OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD ) ? OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height : OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height*0.5f;
106 }
107
108 void OvershootOverlayRotationConstraint( Quaternion& current, const PropertyInputContainer& inputs )
109 {
110   const Vector3& parentScrollDirection = inputs[0]->GetVector3();
111   const float parentOvershoot = inputs[1]->GetFloat();
112   const Toolkit::ControlOrientation::Type& parentOrientation = static_cast<Toolkit::ControlOrientation::Type>(parentScrollDirection.z);
113
114   float multiplier = 0;
115   if(Toolkit::IsVertical(parentOrientation))
116   {
117     if(fabsf(parentScrollDirection.y) <= Math::MACHINE_EPSILON_1)
118     {
119       if( (parentOrientation == Toolkit::ControlOrientation::Up && parentOvershoot < Math::MACHINE_EPSILON_0)
120           || (parentOrientation == Toolkit::ControlOrientation::Down && parentOvershoot > Math::MACHINE_EPSILON_0) )
121       {
122         multiplier = 0.5f;
123       }
124       else
125       {
126         multiplier = 1.5f;
127       }
128     }
129     else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.y > Math::MACHINE_EPSILON_0)
130           || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.y < Math::MACHINE_EPSILON_0) )
131     {
132       multiplier = 0.0f;
133     }
134     else
135     {
136       multiplier = 1.0f;
137     }
138   }
139   else
140   {
141     if(fabsf(parentScrollDirection.x) <= Math::MACHINE_EPSILON_1)
142     {
143       if( (parentOrientation == Toolkit::ControlOrientation::Left && parentOvershoot > Math::MACHINE_EPSILON_0)
144           ||(parentOrientation == Toolkit::ControlOrientation::Right && parentOvershoot < Math::MACHINE_EPSILON_0) )
145       {
146         multiplier = 1.0f;
147       }
148       else
149       {
150         multiplier = 0.0f;
151       }
152     }
153     else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.x > Math::MACHINE_EPSILON_0)
154           || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.x < Math::MACHINE_EPSILON_0) )
155     {
156       multiplier = 1.5f;
157     }
158     else
159     {
160       multiplier = 0.5f;
161     }
162   }
163
164   current = Quaternion( Radian( multiplier * Math::PI ), Vector3::ZAXIS );
165 }
166
167 void OvershootOverlayPositionConstraint( Vector3& current, const PropertyInputContainer& inputs )
168 {
169   const Vector3& parentSize = inputs[0]->GetVector3();
170   const Vector3& parentScrollDirection = inputs[1]->GetVector3();
171   const float parentOvershoot = inputs[2]->GetFloat();
172   const Toolkit::ControlOrientation::Type& parentOrientation = static_cast<Toolkit::ControlOrientation::Type>(parentScrollDirection.z);
173
174   Vector3 relativeOffset;
175
176   if(Toolkit::IsVertical(parentOrientation))
177   {
178     if(fabsf(parentScrollDirection.y) <= Math::MACHINE_EPSILON_1)
179     {
180       if( (parentOrientation == Toolkit::ControlOrientation::Up && parentOvershoot < Math::MACHINE_EPSILON_0)
181           || (parentOrientation == Toolkit::ControlOrientation::Down && parentOvershoot > Math::MACHINE_EPSILON_0) )
182       {
183         relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
184       }
185       else
186       {
187         relativeOffset =Vector3(0.0f, 1.0f, 0.0f);
188       }
189     }
190     else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.y > Math::MACHINE_EPSILON_0)
191           || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.y < Math::MACHINE_EPSILON_0) )
192     {
193       relativeOffset = Vector3(0.0f, 0.0f, 0.0f);
194     }
195     else
196     {
197       relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
198     }
199   }
200   else
201   {
202     if(fabsf(parentScrollDirection.x) <= Math::MACHINE_EPSILON_1)
203     {
204       if( (parentOrientation == Toolkit::ControlOrientation::Left && parentOvershoot < Math::MACHINE_EPSILON_0)
205           || (parentOrientation == Toolkit::ControlOrientation::Right && parentOvershoot > Math::MACHINE_EPSILON_0) )
206       {
207         relativeOffset = Vector3(0.0f, 0.0f, 0.0f);
208       }
209       else
210       {
211         relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
212       }
213     }
214     else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.x > Math::MACHINE_EPSILON_0)
215           || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.x < Math::MACHINE_EPSILON_0) )
216     {
217       relativeOffset = Vector3(0.0f, 1.0f, 0.0f);
218     }
219     else
220     {
221       relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
222     }
223   }
224
225   current = relativeOffset * parentSize;
226 }
227
228 void OvershootOverlayVisibilityConstraint( bool& current, const PropertyInputContainer& inputs )
229 {
230   current = inputs[0]->GetBoolean();
231 }
232
233 /**
234  * Relative position Constraint
235  * Generates the relative position value of the item view based on the layout position,
236  * and it's relation to the layout domain. This is a value from 0.0f to 1.0f in each axis.
237  */
238 void RelativePositionConstraint( Vector3& current, const PropertyInputContainer& inputs )
239 {
240   const Vector3& position = Vector3(0.0f, inputs[0]->GetFloat(), 0.0f);
241   const Vector3& min = inputs[1]->GetVector3();
242   const Vector3& max = inputs[2]->GetVector3();
243
244   Vector3 domainSize = max - min;
245
246   current.x = fabsf(domainSize.x) > Math::MACHINE_EPSILON_1 ? ((min.x - position.x) / fabsf(domainSize.x)) : 0.0f;
247   current.y = fabsf(domainSize.y) > Math::MACHINE_EPSILON_1 ? ((min.y - position.y) / fabsf(domainSize.y)) : 0.0f;
248   current.z = 0.0f;
249 }
250
251 } // unnamed namespace
252
253 namespace Dali
254 {
255
256 namespace Toolkit
257 {
258
259 namespace Internal
260 {
261
262 namespace // unnamed namespace
263 {
264
265 bool FindById( const ItemContainer& items, ItemId id )
266 {
267   for( ConstItemIter iter = items.begin(); items.end() != iter; ++iter )
268   {
269     if( iter->first == id )
270     {
271       return true;
272     }
273   }
274
275   return false;
276 }
277
278 } // unnamed namespace
279
280 Dali::Toolkit::ItemView ItemView::New(ItemFactory& factory)
281 {
282   // Create the implementation
283   ItemViewPtr itemView(new ItemView(factory));
284
285   // Pass ownership to CustomActor via derived handle
286   Dali::Toolkit::ItemView handle(*itemView);
287
288   // Second-phase init of the implementation
289   // This can only be done after the CustomActor connection has been made...
290   itemView->Initialize();
291
292   return handle;
293 }
294
295 ItemView::ItemView(ItemFactory& factory)
296 : Scrollable( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | REQUIRES_MOUSE_WHEEL_EVENTS | REQUIRES_KEYBOARD_NAVIGATION_SUPPORT ) ),
297   mItemFactory(factory),
298   mActiveLayout(NULL),
299   mAnimatingOvershootOn(false),
300   mAnimateOvershootOff(false),
301   mAnchoringEnabled(true),
302   mAnchoringDuration(DEFAULT_ANCHORING_DURATION),
303   mRefreshIntervalLayoutPositions(0.0f),
304   mRefreshOrderHint(true/*Refresh item 0 first*/),
305   mMinimumSwipeSpeed(DEFAULT_MINIMUM_SWIPE_SPEED),
306   mMinimumSwipeDistance(DEFAULT_MINIMUM_SWIPE_DISTANCE),
307   mMouseWheelScrollDistanceStep(0.0f),
308   mScrollDistance(0.0f),
309   mScrollSpeed(0.0f),
310   mTotalPanDisplacement(Vector2::ZERO),
311   mScrollOvershoot(0.0f),
312   mIsFlicking(false),
313   mGestureState(Gesture::Clear),
314   mAddingItems(false),
315   mPropertyPosition(Property::INVALID_INDEX),
316   mPropertyMinimumLayoutPosition(Property::INVALID_INDEX),
317   mPropertyScrollSpeed(Property::INVALID_INDEX),
318   mRefreshEnabled(true),
319   mItemsParentOrigin( ParentOrigin::CENTER),
320   mItemsAnchorPoint( AnchorPoint::CENTER)
321 {
322 }
323
324 void ItemView::OnInitialize()
325 {
326   Actor self = Self();
327
328   mScrollConnector = Dali::Toolkit::ScrollConnector::New();
329   mScrollPositionObject = mScrollConnector.GetScrollPositionObject();
330   mScrollConnector.ScrollPositionChangedSignal().Connect( this, &ItemView::OnScrollPositionChanged );
331
332   mPropertyMinimumLayoutPosition = self.RegisterProperty(MINIMUM_LAYOUT_POSITION_PROPERTY_NAME, 0.0f);
333   mPropertyPosition = self.RegisterProperty(POSITION_PROPERTY_NAME, 0.0f);
334   mPropertyScrollSpeed = self.RegisterProperty(SCROLL_SPEED_PROPERTY_NAME, 0.0f);
335
336   EnableScrollComponent(Toolkit::Scrollable::OvershootIndicator);
337
338   Constraint constraint = Constraint::New<Vector3>( self, Toolkit::Scrollable::Property::SCROLL_RELATIVE_POSITION, RelativePositionConstraint );
339   constraint.AddSource( LocalSource( mPropertyPosition ) );
340   constraint.AddSource( LocalSource( Toolkit::Scrollable::Property::SCROLL_POSITION_MIN ) );
341   constraint.AddSource( LocalSource( Toolkit::Scrollable::Property::SCROLL_POSITION_MAX ) );
342   constraint.Apply();
343
344   Vector2 stageSize = Stage::GetCurrent().GetSize();
345   mMouseWheelScrollDistanceStep = stageSize.y * DEFAULT_MOUSE_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION;
346
347   EnableGestureDetection(Gesture::Type(Gesture::Pan));
348
349   mMouseWheelEventFinishedTimer = Timer::New( MOUSE_WHEEL_EVENT_FINISHED_TIME_OUT );
350   mMouseWheelEventFinishedTimer.TickSignal().Connect( this, &ItemView::OnMouseWheelEventFinished );
351
352   SetRefreshInterval(DEFAULT_REFRESH_INTERVAL_LAYOUT_POSITIONS);
353 }
354
355 ItemView::~ItemView()
356 {
357 }
358
359 Dali::Toolkit::ScrollConnector ItemView::GetScrollConnector() const
360 {
361   return mScrollConnector;
362 }
363
364 unsigned int ItemView::GetLayoutCount() const
365 {
366   return mLayouts.size();
367 }
368
369 void ItemView::AddLayout(ItemLayout& layout)
370 {
371   mLayouts.push_back(ItemLayoutPtr(&layout));
372 }
373
374 void ItemView::RemoveLayout(unsigned int layoutIndex)
375 {
376   DALI_ASSERT_ALWAYS(layoutIndex < mLayouts.size());
377
378   if (mActiveLayout == mLayouts[layoutIndex].Get())
379   {
380     mActiveLayout = NULL;
381   }
382
383   mLayouts.erase(mLayouts.begin() + layoutIndex);
384 }
385
386 ItemLayoutPtr ItemView::GetLayout(unsigned int layoutIndex) const
387 {
388   return mLayouts[layoutIndex];
389 }
390
391 ItemLayoutPtr ItemView::GetActiveLayout() const
392 {
393   return ItemLayoutPtr(mActiveLayout);
394 }
395
396 float ItemView::GetCurrentLayoutPosition(unsigned int itemId) const
397 {
398   return mScrollConnector.GetScrollPosition() + static_cast<float>( itemId );
399 }
400
401 void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSize, float durationSeconds)
402 {
403   DALI_ASSERT_ALWAYS(layoutIndex < mLayouts.size());
404
405   mRefreshEnabled = false;
406
407   Actor self = Self();
408
409   // The ItemView size should match the active layout size
410   self.SetSize(targetSize);
411   mActiveLayoutTargetSize = targetSize;
412
413   // Switch to the new layout
414   mActiveLayout = mLayouts[layoutIndex].Get();
415
416   // Move the items to the new layout positions...
417
418   for (ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
419   {
420     unsigned int itemId = iter->first;
421     Actor actor = iter->second;
422
423     // Remove constraints from previous layout
424     actor.RemoveConstraints();
425
426     Vector3 size;
427     if(mActiveLayout->GetItemSize(itemId, targetSize, size))
428     {
429       // resize immediately
430       actor.SetSize( size.GetVectorXY() );
431     }
432
433     mActiveLayout->ApplyConstraints(actor, itemId, durationSeconds, mScrollPositionObject, Self() );
434   }
435
436   // Refresh the new layout
437   ItemRange range = GetItemRange(*mActiveLayout, targetSize, GetCurrentLayoutPosition(0), false/* don't reserve extra*/);
438   AddActorsWithinRange( range, durationSeconds );
439
440   // Scroll to an appropriate layout position
441
442   bool scrollAnimationNeeded(false);
443   float firstItemScrollPosition(0.0f);
444
445   float current = GetCurrentLayoutPosition(0);
446   float minimum = ClampFirstItemPosition(current, targetSize, *mActiveLayout);
447   self.SetProperty(mPropertyPosition, GetScrollPosition(current, targetSize));
448
449   if (current < minimum)
450   {
451     scrollAnimationNeeded = true;
452     firstItemScrollPosition = minimum;
453   }
454   else if (mAnchoringEnabled)
455   {
456     scrollAnimationNeeded = true;
457     firstItemScrollPosition = mActiveLayout->GetClosestAnchorPosition(current);
458   }
459
460   if (scrollAnimationNeeded)
461   {
462     RemoveAnimation(mScrollAnimation);
463     mScrollAnimation = Animation::New(durationSeconds);
464     mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut );
465     mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, targetSize), AlphaFunctions::EaseOut );
466     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnLayoutActivationScrollFinished);
467     mScrollAnimation.Play();
468   }
469
470   self.SetProperty(mPropertyMinimumLayoutPosition, mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), targetSize));
471   AnimateScrollOvershoot(0.0f);
472   mScrollOvershoot = 0.0f;
473
474   Radian scrollDirection(mActiveLayout->GetScrollDirection());
475   float orientation = static_cast<float>(mActiveLayout->GetOrientation());
476   self.SetProperty(Toolkit::Scrollable::Property::SCROLL_DIRECTION, Vector3(sinf(scrollDirection), cosf(scrollDirection), orientation));
477
478   self.SetProperty(mPropertyScrollSpeed, mScrollSpeed);
479
480   CalculateDomainSize(targetSize);
481 }
482
483 void ItemView::DeactivateCurrentLayout()
484 {
485   if (mActiveLayout)
486   {
487     for (ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
488     {
489       Actor actor = iter->second;
490       actor.RemoveConstraints();
491     }
492
493     mActiveLayout = NULL;
494   }
495 }
496
497 void ItemView::OnRefreshNotification(PropertyNotification& source)
498 {
499   if(mRefreshEnabled || mScrollAnimation)
500   {
501     // Only refresh the cache during normal scrolling
502     DoRefresh(GetCurrentLayoutPosition(0), true);
503   }
504 }
505
506 void ItemView::Refresh()
507 {
508   for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter )
509   {
510     ReleaseActor( iter->first, iter->second );
511   }
512   mItemPool.clear();
513
514   DoRefresh(GetCurrentLayoutPosition(0), true);
515 }
516
517 void ItemView::DoRefresh(float currentLayoutPosition, bool cacheExtra)
518 {
519   if (mActiveLayout)
520   {
521     ItemRange range = GetItemRange(*mActiveLayout, mActiveLayoutTargetSize, currentLayoutPosition, cacheExtra/*reserve extra*/);
522     RemoveActorsOutsideRange( range );
523     AddActorsWithinRange( range, 0.0f/*immediate*/ );
524
525     mScrollUpdatedSignal.Emit( Vector3(0.0f, currentLayoutPosition, 0.0f) );
526   }
527 }
528
529 void ItemView::SetMinimumSwipeSpeed(float speed)
530 {
531   mMinimumSwipeSpeed = speed;
532 }
533
534 float ItemView::GetMinimumSwipeSpeed() const
535 {
536   return mMinimumSwipeSpeed;
537 }
538
539 void ItemView::SetMinimumSwipeDistance(float distance)
540 {
541   mMinimumSwipeDistance = distance;
542 }
543
544 float ItemView::GetMinimumSwipeDistance() const
545 {
546   return mMinimumSwipeDistance;
547 }
548
549 void ItemView::SetMouseWheelScrollDistanceStep(float step)
550 {
551   mMouseWheelScrollDistanceStep = step;
552 }
553
554 float ItemView::GetMouseWheelScrollDistanceStep() const
555 {
556   return mMouseWheelScrollDistanceStep;
557 }
558
559 void ItemView::SetAnchoring(bool enabled)
560 {
561   mAnchoringEnabled = enabled;
562 }
563
564 bool ItemView::GetAnchoring() const
565 {
566   return mAnchoringEnabled;
567 }
568
569 void ItemView::SetAnchoringDuration(float durationSeconds)
570 {
571   mAnchoringDuration = durationSeconds;
572 }
573
574 float ItemView::GetAnchoringDuration() const
575 {
576   return mAnchoringDuration;
577 }
578
579 void ItemView::SetRefreshInterval(float intervalLayoutPositions)
580 {
581   if( !Equals(mRefreshIntervalLayoutPositions, intervalLayoutPositions) )
582   {
583     mRefreshIntervalLayoutPositions = intervalLayoutPositions;
584
585     if(mRefreshNotification)
586     {
587       mScrollPositionObject.RemovePropertyNotification(mRefreshNotification);
588     }
589     mRefreshNotification = mScrollPositionObject.AddPropertyNotification( ScrollConnector::SCROLL_POSITION, StepCondition(mRefreshIntervalLayoutPositions, 0.0f) );
590     mRefreshNotification.NotifySignal().Connect( this, &ItemView::OnRefreshNotification );
591   }
592 }
593
594 float ItemView::GetRefreshInterval() const
595 {
596   return mRefreshIntervalLayoutPositions;
597 }
598
599 void ItemView::SetRefreshEnabled(bool enabled)
600 {
601   mRefreshEnabled = enabled;
602 }
603
604 Actor ItemView::GetItem(unsigned int itemId) const
605 {
606   Actor actor;
607
608   ConstItemPoolIter iter = mItemPool.find( itemId );
609   if( iter != mItemPool.end() )
610   {
611     actor = iter->second;
612   }
613
614   return actor;
615 }
616
617 unsigned int ItemView::GetItemId( Actor actor ) const
618 {
619   unsigned int itemId( 0 );
620
621   for ( ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter )
622   {
623     if( iter->second == actor )
624     {
625       itemId = iter->first;
626       break;
627     }
628   }
629
630   return itemId;
631 }
632
633 void ItemView::InsertItem( Item newItem, float durationSeconds )
634 {
635   mAddingItems = true;
636
637   Actor displacedActor;
638   ItemPoolIter afterDisplacedIter = mItemPool.end();
639
640   ItemPoolIter foundIter = mItemPool.find( newItem.first );
641   if( mItemPool.end() != foundIter )
642   {
643     SetupActor( newItem, durationSeconds );
644     Self().Add( newItem.second );
645
646     displacedActor = foundIter->second;
647     foundIter->second = newItem.second;
648
649     afterDisplacedIter = ++foundIter;
650   }
651   else
652   {
653     // Inserting before the existing item range?
654     ItemPoolIter iter = mItemPool.begin();
655     if( iter != mItemPool.end() &&
656         iter->first > newItem.first )
657     {
658       displacedActor = iter->second;
659       mItemPool.erase( iter++ ); // iter is still valid after the erase
660
661       afterDisplacedIter = iter;
662     }
663   }
664
665   if( displacedActor )
666   {
667     // Move the existing actors to make room
668     for( ItemPoolIter iter = afterDisplacedIter; mItemPool.end() != iter; ++iter )
669     {
670       Actor temp = iter->second;
671       iter->second = displacedActor;
672       displacedActor = temp;
673
674       iter->second.RemoveConstraints();
675       mActiveLayout->ApplyConstraints( iter->second, iter->first, durationSeconds, mScrollPositionObject, Self() );
676     }
677
678     // Create last item
679     ItemPool::reverse_iterator lastIter = mItemPool.rbegin();
680     if ( lastIter != mItemPool.rend() )
681     {
682       ItemId lastId = lastIter->first;
683       Item lastItem( lastId + 1, displacedActor );
684       mItemPool.insert( lastItem );
685
686       lastItem.second.RemoveConstraints();
687       mActiveLayout->ApplyConstraints( lastItem.second, lastItem.first, durationSeconds, mScrollPositionObject, Self() );
688     }
689   }
690
691   CalculateDomainSize(Self().GetCurrentSize());
692
693   mAddingItems = false;
694 }
695
696 void ItemView::InsertItems( const ItemContainer& newItems, float durationSeconds )
697 {
698   mAddingItems = true;
699
700   // Insert from lowest id to highest
701   std::set<Item> sortedItems;
702   for( ConstItemIter iter = newItems.begin(); newItems.end() != iter; ++iter )
703   {
704     sortedItems.insert( *iter );
705   }
706
707   for( std::set<Item>::iterator iter = sortedItems.begin(); sortedItems.end() != iter; ++iter )
708   {
709     Self().Add( iter->second );
710
711     ItemPoolIter foundIter = mItemPool.find( iter->first );
712     if( mItemPool.end() != foundIter )
713     {
714       Actor moveMe = foundIter->second;
715       foundIter->second = iter->second;
716
717       // Move the existing actors to make room
718       for( ItemPoolIter iter = ++foundIter; mItemPool.end() != iter; ++iter )
719       {
720         Actor temp = iter->second;
721         iter->second = moveMe;
722         moveMe = temp;
723       }
724
725       // Create last item
726       ItemId lastId = mItemPool.rbegin()->first;
727       Item lastItem( lastId + 1, moveMe );
728       mItemPool.insert( lastItem );
729     }
730     else
731     {
732       mItemPool.insert( *iter );
733     }
734   }
735
736   // Relayout everything
737   for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
738   {
739     // If newly inserted
740     if( FindById( newItems, iter->first ) )
741     {
742       SetupActor( *iter, durationSeconds );
743     }
744     else
745     {
746       iter->second.RemoveConstraints();
747       mActiveLayout->ApplyConstraints( iter->second, iter->first, durationSeconds, mScrollPositionObject, Self() );
748     }
749   }
750
751   CalculateDomainSize(Self().GetCurrentSize());
752
753   mAddingItems = false;
754 }
755
756 void ItemView::RemoveItem( unsigned int itemId, float durationSeconds )
757 {
758   bool actorsReordered = RemoveActor( itemId );
759   if( actorsReordered )
760   {
761     ReapplyAllConstraints( durationSeconds );
762
763     OnItemsRemoved();
764   }
765 }
766
767 void ItemView::RemoveItems( const ItemIdContainer& itemIds, float durationSeconds )
768 {
769   bool actorsReordered( false );
770
771   // Remove from highest id to lowest
772   set<ItemId> sortedItems;
773   for( ConstItemIdIter iter = itemIds.begin(); itemIds.end() != iter; ++iter )
774   {
775     sortedItems.insert( *iter );
776   }
777
778   for( set<ItemId>::reverse_iterator iter = sortedItems.rbegin(); sortedItems.rend() != iter; ++iter )
779   {
780     if( RemoveActor( *iter ) )
781     {
782       actorsReordered = true;
783     }
784   }
785
786   if( actorsReordered )
787   {
788     ReapplyAllConstraints( durationSeconds );
789
790     OnItemsRemoved();
791   }
792 }
793
794 bool ItemView::RemoveActor(unsigned int itemId)
795 {
796   bool reordered( false );
797
798   ItemPoolIter removeIter = mItemPool.find( itemId );
799   if( removeIter != mItemPool.end() )
800   {
801     ReleaseActor(itemId, removeIter->second);
802   }
803   else
804   {
805     // Removing before the existing item range?
806     ItemPoolIter iter = mItemPool.begin();
807     if( iter != mItemPool.end() &&
808         iter->first > itemId )
809     {
810       // In order to decrement the first visible item ID
811       mItemPool.insert( Item(iter->first - 1, Actor()) );
812
813       removeIter = mItemPool.begin();
814     }
815   }
816
817   if( removeIter != mItemPool.end() )
818   {
819     reordered = true;
820
821     // Adjust the remaining item IDs, for example if item 2 is removed:
822     //   Initial actors:     After insert:
823     //     ID 1 - ActorA       ID 1 - ActorA
824     //     ID 2 - ActorB       ID 2 - ActorC (previously ID 3)
825     //     ID 3 - ActorC       ID 3 - ActorB (previously ID 4)
826     //     ID 4 - ActorD
827     for (ItemPoolIter iter = removeIter; iter != mItemPool.end(); ++iter)
828     {
829       if( iter->first < mItemPool.rbegin()->first )
830       {
831         iter->second = mItemPool[ iter->first + 1 ];
832       }
833       else
834       {
835         mItemPool.erase( iter );
836         break;
837       }
838     }
839   }
840
841   return reordered;
842 }
843
844 void ItemView::ReplaceItem( Item replacementItem, float durationSeconds )
845 {
846   mAddingItems = true;
847
848   SetupActor( replacementItem, durationSeconds );
849   Self().Add( replacementItem.second );
850
851   const ItemPoolIter iter = mItemPool.find( replacementItem.first );
852   if( mItemPool.end() != iter )
853   {
854     ReleaseActor(iter->first, iter->second);
855     iter->second = replacementItem.second;
856   }
857   else
858   {
859     mItemPool.insert( replacementItem );
860   }
861
862   CalculateDomainSize(Self().GetCurrentSize());
863
864   mAddingItems = false;
865 }
866
867 void ItemView::ReplaceItems( const ItemContainer& replacementItems, float durationSeconds )
868 {
869   for( ConstItemIter iter = replacementItems.begin(); replacementItems.end() != iter; ++iter )
870   {
871     ReplaceItem( *iter, durationSeconds );
872   }
873 }
874
875 void ItemView::RemoveActorsOutsideRange( ItemRange range )
876 {
877   // Remove unwanted actors from the ItemView & ItemPool
878   for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); )
879   {
880     unsigned int current = iter->first;
881
882     if( ! range.Within( current ) )
883     {
884       ReleaseActor(iter->first, iter->second);
885
886       mItemPool.erase( iter++ ); // erase invalidates the return value of post-increment; iter remains valid
887     }
888     else
889     {
890       ++iter;
891     }
892   }
893 }
894
895 void ItemView::AddActorsWithinRange( ItemRange range, float durationSeconds )
896 {
897   range.end = std::min(mItemFactory.GetNumberOfItems(), range.end);
898
899   // The order of addition depends on the scroll direction.
900   if (mRefreshOrderHint)
901   {
902     for (unsigned int itemId = range.begin; itemId < range.end; ++itemId)
903     {
904       AddNewActor( itemId, durationSeconds );
905     }
906   }
907   else
908   {
909     for (unsigned int itemId = range.end; itemId > range.begin; --itemId)
910     {
911       AddNewActor( itemId-1, durationSeconds );
912     }
913   }
914
915   // Total number of items may change dynamically.
916   // Always recalculate the domain size to reflect that.
917   CalculateDomainSize(Self().GetCurrentSize());
918 }
919
920 void ItemView::AddNewActor( unsigned int itemId, float durationSeconds )
921 {
922   mAddingItems = true;
923
924   if( mItemPool.end() == mItemPool.find( itemId ) )
925   {
926     Actor actor = mItemFactory.NewItem( itemId );
927
928     if( actor )
929     {
930       Item newItem( itemId, actor );
931
932       mItemPool.insert( newItem );
933
934       SetupActor( newItem, durationSeconds );
935       Self().Add( actor );
936     }
937   }
938
939   mAddingItems = false;
940 }
941
942 void ItemView::SetupActor( Item item, float durationSeconds )
943 {
944   item.second.SetParentOrigin( mItemsParentOrigin );
945   item.second.SetAnchorPoint( mItemsAnchorPoint );
946
947   if( mActiveLayout )
948   {
949     Vector3 size;
950     if( mActiveLayout->GetItemSize( item.first, mActiveLayoutTargetSize, size ) )
951     {
952       item.second.SetSize( size.GetVectorXY() );
953     }
954
955     mActiveLayout->ApplyConstraints( item.second, item.first, durationSeconds, mScrollPositionObject, Self() );
956   }
957 }
958
959 void ItemView::ReleaseActor( ItemId item, Actor actor )
960 {
961   Self().Remove( actor );
962   mItemFactory.ItemReleased(item, actor);
963 }
964
965 ItemRange ItemView::GetItemRange(ItemLayout& layout, const Vector3& layoutSize, float layoutPosition, bool reserveExtra)
966 {
967   unsigned int itemCount = mItemFactory.GetNumberOfItems();
968
969   ItemRange available(0u, itemCount);
970
971   ItemRange range = layout.GetItemsWithinArea( layoutPosition, layoutSize );
972
973   if (reserveExtra)
974   {
975     // Add the reserve items for scrolling
976     unsigned int extra = layout.GetReserveItemCount(layoutSize);
977     range.begin = (range.begin >= extra) ? (range.begin - extra) : 0u;
978     range.end += extra;
979   }
980
981   return range.Intersection(available);
982 }
983
984 void ItemView::OnChildAdd(Actor& child)
985 {
986   if(!mAddingItems)
987   {
988     // We don't want to do this downcast check for any item added by ItemView itself.
989     Dali::Toolkit::ScrollComponent scrollComponent = Dali::Toolkit::ScrollComponent::DownCast(child);
990     if(scrollComponent)
991     {
992       // Set the scroll connector when scroll bar is being added
993       scrollComponent.SetScrollConnector(mScrollConnector);
994     }
995   }
996 }
997
998 bool ItemView::OnTouchEvent(const TouchEvent& event)
999 {
1000   // Ignore events with multiple-touch points
1001   if (event.GetPointCount() != 1)
1002   {
1003     return false;
1004   }
1005
1006   if (event.GetPoint(0).state == TouchPoint::Down)
1007   {
1008     // Cancel ongoing scrolling etc.
1009     mGestureState = Gesture::Clear;
1010
1011     mScrollDistance = 0.0f;
1012     mScrollSpeed = 0.0f;
1013     Self().SetProperty(mPropertyScrollSpeed, mScrollSpeed);
1014
1015     mScrollOvershoot = 0.0f;
1016     AnimateScrollOvershoot(0.0f);
1017
1018     if(mScrollAnimation)
1019     {
1020       mScrollCompletedSignal.Emit(GetCurrentScrollPosition());
1021     }
1022
1023     RemoveAnimation(mScrollAnimation);
1024   }
1025
1026   return true; // consume since we're potentially scrolling
1027 }
1028
1029 bool ItemView::OnMouseWheelEvent(const MouseWheelEvent& event)
1030 {
1031   // Respond the mouse wheel event to scroll
1032   if (mActiveLayout)
1033   {
1034     Actor self = Self();
1035     const Vector3 layoutSize = Self().GetCurrentSize();
1036     float layoutPositionDelta = GetCurrentLayoutPosition(0) - (event.z * mMouseWheelScrollDistanceStep * mActiveLayout->GetScrollSpeedFactor());
1037     float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout);
1038
1039     mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
1040     self.SetProperty(mPropertyPosition, GetScrollPosition(firstItemScrollPosition, layoutSize));
1041     mScrollStartedSignal.Emit(GetCurrentScrollPosition());
1042     mRefreshEnabled = true;
1043   }
1044
1045   if (mMouseWheelEventFinishedTimer.IsRunning())
1046   {
1047     mMouseWheelEventFinishedTimer.Stop();
1048   }
1049
1050   mMouseWheelEventFinishedTimer.Start();
1051
1052   return true;
1053 }
1054
1055 bool ItemView::OnMouseWheelEventFinished()
1056 {
1057   if (mActiveLayout)
1058   {
1059     RemoveAnimation(mScrollAnimation);
1060
1061     // No more mouse wheel events coming. Do the anchoring if enabled.
1062     mScrollAnimation = DoAnchoring();
1063     if (mScrollAnimation)
1064     {
1065       mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1066       mScrollAnimation.Play();
1067     }
1068     else
1069     {
1070       mScrollOvershoot = 0.0f;
1071       AnimateScrollOvershoot(0.0f);
1072
1073       mScrollCompletedSignal.Emit(GetCurrentScrollPosition());
1074     }
1075   }
1076
1077   return false;
1078 }
1079
1080 void ItemView::ReapplyAllConstraints( float durationSeconds )
1081 {
1082   for (ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
1083   {
1084     unsigned int id = iter->first;
1085     Actor actor = iter->second;
1086
1087     actor.RemoveConstraints();
1088     mActiveLayout->ApplyConstraints(actor, id, durationSeconds, mScrollPositionObject, Self());
1089   }
1090 }
1091
1092 void ItemView::OnItemsRemoved()
1093 {
1094   CalculateDomainSize(Self().GetCurrentSize());
1095
1096   // Adjust scroll-position after an item is removed
1097   if( mActiveLayout )
1098   {
1099     float firstItemScrollPosition = ClampFirstItemPosition(GetCurrentLayoutPosition(0), Self().GetCurrentSize(), *mActiveLayout);
1100
1101     mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
1102   }
1103 }
1104
1105 float ItemView::ClampFirstItemPosition(float targetPosition, const Vector3& targetSize, ItemLayout& layout)
1106 {
1107   Actor self = Self();
1108   float minLayoutPosition = layout.GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), targetSize);
1109   float clamppedPosition = std::min(0.0f, std::max(minLayoutPosition, targetPosition));
1110   mScrollOvershoot = targetPosition - clamppedPosition;
1111   self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition);
1112
1113   return clamppedPosition;
1114 }
1115
1116 void ItemView::OnPan( const PanGesture& gesture )
1117 {
1118   Actor self = Self();
1119   const Vector3 layoutSize = Self().GetCurrentSize();
1120
1121   RemoveAnimation(mScrollAnimation);
1122
1123   // Short-circuit if there is no active layout
1124   if (!mActiveLayout)
1125   {
1126     mGestureState = Gesture::Clear;
1127     return;
1128   }
1129
1130   mGestureState = gesture.state;
1131
1132   switch (mGestureState)
1133   {
1134     case Gesture::Finished:
1135     {
1136       // Swipe Detection
1137       if (fabsf(mScrollDistance) > mMinimumSwipeDistance &&
1138           mScrollSpeed > mMinimumSwipeSpeed)
1139       {
1140         float direction = (mScrollDistance < 0.0f) ? -1.0f : 1.0f;
1141
1142         mRefreshOrderHint = true;
1143
1144         float currentLayoutPosition = GetCurrentLayoutPosition(0);
1145         float firstItemScrollPosition = ClampFirstItemPosition(currentLayoutPosition + mScrollSpeed * direction,
1146                                                                layoutSize,
1147                                                                *mActiveLayout);
1148
1149         if (mAnchoringEnabled)
1150         {
1151           firstItemScrollPosition = mActiveLayout->GetClosestAnchorPosition(firstItemScrollPosition);
1152         }
1153
1154         RemoveAnimation(mScrollAnimation);
1155
1156         float flickAnimationDuration = Clamp( mActiveLayout->GetItemFlickAnimationDuration() * std::max(1.0f, fabsf(firstItemScrollPosition - GetCurrentLayoutPosition(0)))
1157                                        , DEFAULT_MINIMUM_SWIPE_DURATION, DEFAULT_MAXIMUM_SWIPE_DURATION);
1158
1159         mScrollAnimation = Animation::New(flickAnimationDuration);
1160         mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut );
1161         mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut );
1162         mScrollAnimation.AnimateTo( Property(self, mPropertyScrollSpeed), 0.0f, AlphaFunctions::EaseOut );
1163
1164         mIsFlicking = true;
1165         // Check whether it has already scrolled to the end
1166         if(fabs(currentLayoutPosition - firstItemScrollPosition) > Math::MACHINE_EPSILON_0)
1167         {
1168           AnimateScrollOvershoot(0.0f);
1169         }
1170       }
1171
1172       // Anchoring may be triggered when there was no swipe
1173       if (!mScrollAnimation)
1174       {
1175         mScrollAnimation = DoAnchoring();
1176       }
1177
1178       // Reset the overshoot if no scroll animation.
1179       if (!mScrollAnimation)
1180       {
1181         mScrollCompletedSignal.Emit(GetCurrentScrollPosition());
1182
1183         AnimateScrollOvershoot(0.0f, false);
1184       }
1185     }
1186     break;
1187
1188     case Gesture::Started: // Fall through
1189     {
1190       mTotalPanDisplacement = Vector2::ZERO;
1191       mScrollStartedSignal.Emit(GetCurrentScrollPosition());
1192       mRefreshEnabled = true;
1193     }
1194
1195     case Gesture::Continuing:
1196     {
1197       mScrollDistance = CalculateScrollDistance(gesture.displacement, *mActiveLayout);
1198       mScrollSpeed = Clamp((gesture.GetSpeed() * gesture.GetSpeed() * mActiveLayout->GetFlickSpeedFactor() * MILLISECONDS_PER_SECONDS), 0.0f, mActiveLayout->GetMaximumSwipeSpeed());
1199
1200       // Refresh order depends on the direction of the scroll; negative is towards the last item.
1201       mRefreshOrderHint = mScrollDistance < 0.0f;
1202
1203       float layoutPositionDelta = GetCurrentLayoutPosition(0) + (mScrollDistance * mActiveLayout->GetScrollSpeedFactor());
1204
1205       float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout);
1206
1207       float currentOvershoot = mScrollPositionObject.GetProperty<float>(ScrollConnector::OVERSHOOT);
1208
1209       mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
1210       self.SetProperty(mPropertyPosition, GetScrollPosition(firstItemScrollPosition, layoutSize));
1211
1212       if( (firstItemScrollPosition >= 0.0f && currentOvershoot < 1.0f) || (firstItemScrollPosition <= mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize) && currentOvershoot > -1.0f) )
1213       {
1214         mTotalPanDisplacement += gesture.displacement;
1215       }
1216
1217       mScrollOvershoot = CalculateScrollOvershoot();
1218       mScrollPositionObject.SetProperty( ScrollConnector::OVERSHOOT, mScrollOvershoot );
1219     }
1220     break;
1221
1222     case Gesture::Cancelled:
1223     {
1224       mScrollAnimation = DoAnchoring();
1225     }
1226     break;
1227
1228     default:
1229       break;
1230   }
1231
1232   if (mScrollAnimation)
1233   {
1234     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1235     mScrollAnimation.Play();
1236   }
1237 }
1238
1239 bool ItemView::OnAccessibilityPan(PanGesture gesture)
1240 {
1241   OnPan(gesture);
1242   return true;
1243 }
1244
1245 Actor ItemView::GetNextKeyboardFocusableActor(Actor actor, Toolkit::Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
1246 {
1247   Actor nextFocusActor;
1248   if(mActiveLayout)
1249   {
1250     int nextItemID = 0;
1251     if(!actor || actor == this->Self())
1252     {
1253       nextFocusActor = GetItem(nextItemID);
1254     }
1255     else if(actor && actor.GetParent() == this->Self())
1256     {
1257       int itemID = GetItemId(actor);
1258       nextItemID = mActiveLayout->GetNextFocusItemID(itemID, mItemFactory.GetNumberOfItems(), direction, loopEnabled);
1259       nextFocusActor = GetItem(nextItemID);
1260       if(nextFocusActor == actor)
1261       {
1262         // need to pass NULL actor back to focus manager
1263         nextFocusActor.Reset();
1264         return nextFocusActor;
1265       }
1266     }
1267     float layoutPosition = mActiveLayout->GetClosestAnchorPosition( GetCurrentLayoutPosition(0) );
1268     Vector3 layoutSize = Self().GetCurrentSize();
1269     if(!nextFocusActor)
1270     {
1271       // likely the current item is not buffered, so not in our item pool, probably best to get first viewable item
1272       ItemRange viewableItems = mActiveLayout->GetItemsWithinArea(layoutPosition, layoutSize);
1273       nextItemID = viewableItems.begin;
1274       nextFocusActor = GetItem(nextItemID);
1275     }
1276   }
1277   return nextFocusActor;
1278 }
1279
1280 void ItemView::OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor)
1281 {
1282   // only in this function if our chosen focus actor was actually used
1283   if(commitedFocusableActor)
1284   {
1285     int nextItemID = GetItemId(commitedFocusableActor);
1286     float layoutPosition = GetCurrentLayoutPosition(0);
1287     Vector3 layoutSize = Self().GetCurrentSize();
1288
1289     float scrollTo = mActiveLayout->GetClosestOnScreenLayoutPosition(nextItemID, layoutPosition, layoutSize);
1290     ScrollTo(Vector3(0.0f, scrollTo, 0.0f), DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION);
1291   }
1292 }
1293
1294 Animation ItemView::DoAnchoring()
1295 {
1296   Animation anchoringAnimation;
1297   Actor self = Self();
1298
1299   if (mActiveLayout && mAnchoringEnabled)
1300   {
1301     float anchorPosition = mActiveLayout->GetClosestAnchorPosition( GetCurrentLayoutPosition(0) );
1302
1303     anchoringAnimation = Animation::New(mAnchoringDuration);
1304     anchoringAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), anchorPosition, AlphaFunctions::EaseOut );
1305     anchoringAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(anchorPosition, self.GetCurrentSize()), AlphaFunctions::EaseOut );
1306     anchoringAnimation.AnimateTo( Property(self, mPropertyScrollSpeed), 0.0f, AlphaFunctions::EaseOut );
1307     if(!mIsFlicking)
1308     {
1309       AnimateScrollOvershoot(0.0f);
1310     }
1311   }
1312
1313   return anchoringAnimation;
1314 }
1315
1316 void ItemView::OnScrollFinished(Animation& source)
1317 {
1318   Actor self = Self();
1319
1320   RemoveAnimation(mScrollAnimation); // mScrollAnimation is used to query whether we're scrolling
1321
1322   mScrollCompletedSignal.Emit(GetCurrentScrollPosition());
1323
1324   if(mIsFlicking && fabsf(mScrollOvershoot) > Math::MACHINE_EPSILON_1)
1325   {
1326     AnimateScrollOvershoot( mScrollOvershoot > 0.0f ? 1.0f : -1.0f, true);
1327   }
1328   else
1329   {
1330     // Reset the overshoot
1331     AnimateScrollOvershoot( 0.0f );
1332   }
1333   mIsFlicking = false;
1334
1335   mScrollOvershoot = 0.0f;
1336 }
1337
1338 void ItemView::OnLayoutActivationScrollFinished(Animation& source)
1339 {
1340   RemoveAnimation(mScrollAnimation);
1341   mRefreshEnabled = true;
1342   DoRefresh(GetCurrentLayoutPosition(0), true);
1343 }
1344
1345 void ItemView::OnOvershootOnFinished(Animation& animation)
1346 {
1347   mAnimatingOvershootOn = false;
1348   mScrollOvershootAnimation.FinishedSignal().Disconnect(this, &ItemView::OnOvershootOnFinished);
1349   RemoveAnimation(mScrollOvershootAnimation);
1350   if(mAnimateOvershootOff)
1351   {
1352     AnimateScrollOvershoot(0.0f);
1353   }
1354 }
1355
1356 void ItemView::ScrollToItem(unsigned int itemId, float durationSeconds)
1357 {
1358   Actor self = Self();
1359   const Vector3 layoutSize = Self().GetCurrentSize();
1360   float firstItemScrollPosition = ClampFirstItemPosition(mActiveLayout->GetItemScrollToPosition(itemId), layoutSize, *mActiveLayout);
1361
1362   if(durationSeconds > 0.0f)
1363   {
1364     RemoveAnimation(mScrollAnimation);
1365     mScrollAnimation = Animation::New(durationSeconds);
1366     mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut );
1367     mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut );
1368     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1369     mScrollAnimation.Play();
1370   }
1371   else
1372   {
1373     mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
1374     AnimateScrollOvershoot(0.0f);
1375   }
1376
1377   mScrollStartedSignal.Emit(GetCurrentScrollPosition());
1378   mRefreshEnabled = true;
1379 }
1380
1381 void ItemView::RemoveAnimation(Animation& animation)
1382 {
1383   if(animation)
1384   {
1385     // Cease animating, and reset handle.
1386     animation.Clear();
1387     animation.Reset();
1388   }
1389 }
1390
1391 void ItemView::CalculateDomainSize(const Vector3& layoutSize)
1392 {
1393   Actor self = Self();
1394
1395   Vector3 firstItemPosition(Vector3::ZERO);
1396   Vector3 lastItemPosition(Vector3::ZERO);
1397
1398   if(mActiveLayout)
1399   {
1400     firstItemPosition = mActiveLayout->GetItemPosition( 0,0,layoutSize );
1401
1402     float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize);
1403     self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition);
1404     lastItemPosition = mActiveLayout->GetItemPosition( fabs(minLayoutPosition),fabs(minLayoutPosition),layoutSize );
1405
1406     float domainSize;
1407
1408     if(IsHorizontal(mActiveLayout->GetOrientation()))
1409     {
1410       self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN, Vector3(0.0f, firstItemPosition.x, 0.0f));
1411       self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, Vector3(0.0f, lastItemPosition.x, 0.0f));
1412       domainSize = fabs(firstItemPosition.x - lastItemPosition.x);
1413     }
1414     else
1415     {
1416       self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN, Vector3(0.0f, firstItemPosition.y, 0.0f));
1417       self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, Vector3(0.0f, lastItemPosition.y, 0.0f));
1418       domainSize = fabs(firstItemPosition.y - lastItemPosition.y);
1419     }
1420
1421     mScrollConnector.SetScrollDomain(minLayoutPosition, 0.0f, domainSize);
1422
1423     bool isLayoutScrollable = IsLayoutScrollable(layoutSize);
1424     self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL, isLayoutScrollable);
1425     self.SetProperty(Toolkit::Scrollable::Property::CAN_SCROLL_HORIZONTAL, false);
1426   }
1427 }
1428
1429 Vector3 ItemView::GetDomainSize() const
1430 {
1431   Actor self = Self();
1432
1433   float minScrollPosition = self.GetProperty<float>(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN);
1434   float maxScrollPosition = self.GetProperty<float>(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX);
1435
1436   return Vector3(0.0f, fabs(maxScrollPosition - minScrollPosition), 0.0f);
1437 }
1438
1439 bool ItemView::IsLayoutScrollable(const Vector3& layoutSize)
1440 {
1441   Actor self = Self();
1442
1443   float currentLayoutPosition = ClampFirstItemPosition( GetCurrentLayoutPosition(0), layoutSize, *mActiveLayout );
1444   float forwardClampedPosition = ClampFirstItemPosition(currentLayoutPosition + 1.0, layoutSize, *mActiveLayout);
1445   float backwardClampedPosition = ClampFirstItemPosition(currentLayoutPosition - 1.0, layoutSize, *mActiveLayout);
1446
1447   return (fabs(forwardClampedPosition - backwardClampedPosition) > Math::MACHINE_EPSILON_0);
1448 }
1449
1450 float ItemView::GetScrollPosition(float layoutPosition, const Vector3& layoutSize) const
1451 {
1452   Vector3 firstItemPosition( mActiveLayout->GetItemPosition(0, layoutPosition, layoutSize ) );
1453   return IsHorizontal(mActiveLayout->GetOrientation()) ? firstItemPosition.x: firstItemPosition.y;
1454 }
1455
1456 Vector3 ItemView::GetCurrentScrollPosition() const
1457 {
1458   float currentLayoutPosition = GetCurrentLayoutPosition(0);
1459   return Vector3(0.0f, GetScrollPosition(currentLayoutPosition, Self().GetCurrentSize()), 0.0f);
1460 }
1461
1462 void ItemView::AddOverlay(Actor actor)
1463 {
1464   Self().Add(actor);
1465 }
1466
1467 void ItemView::RemoveOverlay(Actor actor)
1468 {
1469   Self().Remove(actor);
1470 }
1471
1472 void ItemView::ScrollTo(const Vector3& position, float duration)
1473 {
1474   Actor self = Self();
1475   const Vector3 layoutSize = Self().GetCurrentSize();
1476
1477   float firstItemScrollPosition = ClampFirstItemPosition(position.y, layoutSize, *mActiveLayout);
1478
1479   if(duration > 0.0f)
1480   {
1481     RemoveAnimation(mScrollAnimation);
1482     mScrollAnimation = Animation::New(duration);
1483     mScrollAnimation.AnimateTo( Property( mScrollPositionObject, ScrollConnector::SCROLL_POSITION ), firstItemScrollPosition, AlphaFunctions::EaseOut );
1484     mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut );
1485     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1486     mScrollAnimation.Play();
1487   }
1488   else
1489   {
1490     mScrollPositionObject.SetProperty( ScrollConnector::SCROLL_POSITION, firstItemScrollPosition );
1491     AnimateScrollOvershoot(0.0f);
1492   }
1493
1494   mScrollStartedSignal.Emit(GetCurrentScrollPosition());
1495   mRefreshEnabled = true;
1496 }
1497
1498 void ItemView::SetOvershootEffectColor( const Vector4& color )
1499 {
1500   mOvershootEffectColor = color;
1501   if( mOvershootOverlay )
1502   {
1503     mOvershootOverlay.SetColor( color );
1504   }
1505 }
1506
1507 void ItemView::SetOvershootEnabled( bool enable )
1508 {
1509   Actor self = Self();
1510   if( enable )
1511   {
1512     Property::Index effectOvershootPropertyIndex = Property::INVALID_INDEX;
1513     mOvershootOverlay = CreateBouncingEffectActor( effectOvershootPropertyIndex );
1514     mOvershootOverlay.SetColor(mOvershootEffectColor);
1515     mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT);
1516     mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT);
1517     mOvershootOverlay.SetDrawMode(DrawMode::OVERLAY);
1518     self.Add(mOvershootOverlay);
1519
1520     Constraint constraint = Constraint::New<Vector3>( mOvershootOverlay, Actor::Property::SIZE, OvershootOverlaySizeConstraint );
1521     constraint.AddSource( ParentSource( Toolkit::Scrollable::Property::SCROLL_DIRECTION ) );
1522     constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
1523     constraint.Apply();
1524
1525     mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.width, OVERSHOOT_BOUNCE_ACTOR_DEFAULT_SIZE.height);
1526
1527     constraint = Constraint::New<Quaternion>( mOvershootOverlay, Actor::Property::ORIENTATION, OvershootOverlayRotationConstraint );
1528     constraint.AddSource( ParentSource( Toolkit::Scrollable::Property::SCROLL_DIRECTION ) );
1529     constraint.AddSource( Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ) );
1530     constraint.Apply();
1531
1532     constraint = Constraint::New<Vector3>( mOvershootOverlay, Actor::Property::POSITION, OvershootOverlayPositionConstraint );
1533     constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
1534     constraint.AddSource( ParentSource( Toolkit::Scrollable::Property::SCROLL_DIRECTION ) );
1535     constraint.AddSource( Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ) );
1536     constraint.Apply();
1537
1538     constraint = Constraint::New<bool>( mOvershootOverlay, Actor::Property::VISIBLE, OvershootOverlayVisibilityConstraint );
1539     constraint.AddSource( ParentSource( Toolkit::Scrollable::Property::CAN_SCROLL_VERTICAL ) );
1540     constraint.Apply();
1541
1542     constraint = Constraint::New<float>( mOvershootOverlay, effectOvershootPropertyIndex, EqualToConstraint() );
1543     constraint.AddSource( Source( mScrollPositionObject, ScrollConnector::OVERSHOOT ) );
1544     constraint.Apply();
1545   }
1546   else
1547   {
1548     if( mOvershootOverlay )
1549     {
1550       self.Remove(mOvershootOverlay);
1551       mOvershootOverlay.Reset();
1552     }
1553   }
1554 }
1555
1556 float ItemView::CalculateScrollOvershoot()
1557 {
1558   float overshoot = 0.0f;
1559
1560   if(mActiveLayout)
1561   {
1562     // The overshoot must be calculated from the accumulated pan gesture displacement
1563     // since the pan gesture starts.
1564     Actor self = Self();
1565     float scrollDistance = CalculateScrollDistance(mTotalPanDisplacement, *mActiveLayout) * mActiveLayout->GetScrollSpeedFactor();
1566     float positionDelta = GetCurrentLayoutPosition(0) + scrollDistance;
1567     float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), Self().GetCurrentSize());
1568     self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition);
1569     float clamppedPosition = std::min(0.0f, std::max(minLayoutPosition, positionDelta));
1570     overshoot = positionDelta - clamppedPosition;
1571   }
1572
1573   return overshoot > 0.0f ? std::min(overshoot, 1.0f) : std::max(overshoot, -1.0f);
1574 }
1575
1576 void ItemView::AnimateScrollOvershoot(float overshootAmount, bool animateBack)
1577 {
1578   bool animatingOn = fabsf(overshootAmount) > Math::MACHINE_EPSILON_1;
1579
1580   // make sure we animate back if needed
1581   mAnimateOvershootOff = animateBack || (!animatingOn && mAnimatingOvershootOn);
1582
1583   if( mAnimatingOvershootOn )
1584   {
1585     // animating on, do not allow animate off
1586     return;
1587   }
1588
1589   if(mOvershootAnimationSpeed > Math::MACHINE_EPSILON_0)
1590   {
1591     float currentOvershoot = mScrollPositionObject.GetProperty<float>(ScrollConnector::OVERSHOOT);
1592     float duration = 0.0f;
1593
1594     if (mOvershootOverlay)
1595     {
1596       duration = mOvershootOverlay.GetCurrentSize().height * (animatingOn ? (1.0f - fabsf(currentOvershoot)) : fabsf(currentOvershoot)) / mOvershootAnimationSpeed;
1597     }
1598
1599     RemoveAnimation(mScrollOvershootAnimation);
1600     mScrollOvershootAnimation = Animation::New(duration);
1601     mScrollOvershootAnimation.FinishedSignal().Connect(this, &ItemView::OnOvershootOnFinished);
1602     mScrollOvershootAnimation.AnimateTo( Property(mScrollPositionObject, ScrollConnector::OVERSHOOT), overshootAmount, TimePeriod(0.0f, duration) );
1603     mScrollOvershootAnimation.Play();
1604
1605     mAnimatingOvershootOn = animatingOn;
1606   }
1607   else
1608   {
1609     mScrollPositionObject.SetProperty( ScrollConnector::OVERSHOOT, overshootAmount );
1610   }
1611 }
1612
1613 void ItemView::SetItemsParentOrigin( const Vector3& parentOrigin )
1614 {
1615   if( parentOrigin != mItemsParentOrigin )
1616   {
1617     mItemsParentOrigin = parentOrigin;
1618     for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
1619     {
1620       iter->second.SetParentOrigin(parentOrigin);
1621     }
1622   }
1623 }
1624
1625 Vector3 ItemView::GetItemsParentOrigin() const
1626 {
1627   return mItemsParentOrigin;
1628 }
1629
1630 void ItemView::SetItemsAnchorPoint( const Vector3& anchorPoint )
1631 {
1632   if( anchorPoint != mItemsAnchorPoint )
1633   {
1634     mItemsAnchorPoint = anchorPoint;
1635     for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
1636     {
1637       iter->second.SetAnchorPoint(anchorPoint);
1638     }
1639   }
1640 }
1641
1642 Vector3 ItemView::GetItemsAnchorPoint() const
1643 {
1644   return mItemsAnchorPoint;
1645 }
1646
1647 void ItemView::GetItemsRange(ItemRange& range)
1648 {
1649   if( !mItemPool.empty() )
1650   {
1651     range.begin = mItemPool.begin()->first;
1652     range.end = mItemPool.rbegin()->first + 1;
1653   }
1654   else
1655   {
1656     range.begin = 0;
1657     range.end = 0;
1658   }
1659 }
1660
1661 void ItemView::OnScrollPositionChanged( float position )
1662 {
1663   // Cancel scroll animation to prevent any fighting of setting the scroll position property.
1664   RemoveAnimation(mScrollAnimation);
1665
1666   // Refresh the cache immediately when the scroll position is changed.
1667   DoRefresh(position, false); // No need to cache extra items.
1668 }
1669
1670 } // namespace Internal
1671
1672 } // namespace Toolkit
1673
1674 } // namespace Dali