Fixed shader test cases to match code changes.
[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 Flora License, Version 1.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://floralicense.org/license/
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 // CLASS HEADER
18 #include <dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h>
19
20 // EXTERNAL INCLUDES
21 #include <algorithm>
22
23 // INTERNAL INCLUDES
24 #include <dali/public-api/events/mouse-wheel-event.h>
25 #include <dali-toolkit/public-api/controls/scrollable/item-view/item-factory.h>
26
27 using namespace std;
28 using namespace Dali;
29
30 namespace // unnamed namespace
31 {
32
33 //Type registration
34 TypeRegistration mType( typeid(Toolkit::ItemView), typeid(Toolkit::Scrollable), NULL );
35
36 const float DEFAULT_MINIMUM_SWIPE_SPEED = 1.0f;
37 const float DEFAULT_MINIMUM_SWIPE_DISTANCE = 3.0f;
38 const float DEFAULT_MOUSE_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION = 0.1f;
39
40 const int DEFAULT_REFRESH_INTERVAL_MILLISECONDS = 50; // 20 updates per second
41 const int MOUSE_WHEEL_EVENT_FINISHED_TIME_OUT = 500;  // 0.5 second
42
43 const float DEFAULT_ANCHORING_DURATION = 1.0f;  // 1 second
44 const float DEFAULT_COLOR_VISIBILITY_REMOVE_TIME = 0.5f; // 0.5 second
45
46 const float MILLISECONDS_PER_SECONDS = 1000.0f;
47
48 const char* OVERSHOOT_OVERLAY_RIPPLE_IMAGE_PATH = DALI_IMAGE_DIR "overshoot_ripple.png";
49 const Rect<int> OVERSHOOT_BOUNCE_IMAGE_1_PIXEL_AREA( 0, 0, 720, 58 );
50 const Vector4 OVERSHOOT_OVERLAY_NINE_PATCH_BORDER(0.0f, 0.0f, 1.0f, 12.0f);
51 const float MAXIMUM_OVERSHOOT_HEIGHT = 36.0f;  // 36 pixels
52 const float DEFAULT_OVERSHOOT_ANIMATION_DURATION = 0.5f;  // 0.5 second
53 const float DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION = 0.2f;
54
55 const string LAYOUT_POSITION_PROPERTY_NAME( "item-view-layout-position" );
56 const string POSITION_PROPERTY_NAME( "item-view-position" );
57 const string MINIMUM_LAYOUT_POSITION_PROPERTY_NAME( "item-view-minimum-layout-position" );
58 const string SCROLL_SPEED_PROPERTY_NAME( "item-view-scroll-speed" );
59 const string SCROLL_DIRECTION_PROPERTY_NAME( "item-view-scroll-direction" );
60 const string OVERSHOOT_PROPERTY_NAME( "item-view-overshoot" );
61
62 // Functors which wrap constraint functions with stored item IDs
63
64 struct WrappedVector3Constraint
65 {
66   WrappedVector3Constraint(Toolkit::ItemLayout::Vector3Function wrapMe, unsigned int itemId)
67   : mWrapMe(wrapMe),
68     mItemId(itemId)
69   {
70   }
71
72   Vector3 operator()(const Vector3& current, const PropertyInput& layoutPosition, const PropertyInput& scrollSpeed, const PropertyInput& layoutSize)
73   {
74     float offsetLayoutPosition = layoutPosition.GetFloat() + static_cast<float>(mItemId);
75
76     return mWrapMe(current, offsetLayoutPosition, scrollSpeed.GetFloat(), layoutSize.GetVector3());
77   }
78
79   Toolkit::ItemLayout::Vector3Function mWrapMe;
80   unsigned int mItemId;
81 };
82
83 struct WrappedQuaternionConstraint
84 {
85   WrappedQuaternionConstraint(Toolkit::ItemLayout::QuaternionFunction wrapMe, unsigned int itemId)
86   : mWrapMe(wrapMe),
87     mItemId(itemId)
88   {
89   }
90
91   Quaternion operator()(const Quaternion& current, const PropertyInput& layoutPosition, const PropertyInput& scrollSpeed, const PropertyInput& layoutSize)
92   {
93     float offsetLayoutPosition = layoutPosition.GetFloat() + static_cast<float>(mItemId);
94
95     return mWrapMe(current, offsetLayoutPosition, scrollSpeed.GetFloat(), layoutSize.GetVector3());
96   }
97
98   Toolkit::ItemLayout::QuaternionFunction mWrapMe;
99   unsigned int mItemId;
100 };
101
102 struct WrappedVector4Constraint
103 {
104   WrappedVector4Constraint(Toolkit::ItemLayout::Vector4Function wrapMe, unsigned int itemId)
105   : mWrapMe(wrapMe),
106     mItemId(itemId)
107   {
108   }
109
110   Vector4 operator()(const Vector4& current, const PropertyInput& layoutPosition, const PropertyInput& scrollSpeed, const PropertyInput& layoutSize)
111   {
112     float offsetLayoutPosition = layoutPosition.GetFloat() + static_cast<float>(mItemId);
113
114     return mWrapMe(current, offsetLayoutPosition, scrollSpeed.GetFloat(), layoutSize.GetVector3());
115   }
116
117   Toolkit::ItemLayout::Vector4Function mWrapMe;
118   unsigned int mItemId;
119 };
120
121 struct WrappedBoolConstraint
122 {
123   WrappedBoolConstraint(Toolkit::ItemLayout::BoolFunction wrapMe, unsigned int itemId)
124   : mWrapMe(wrapMe),
125     mItemId(itemId)
126   {
127   }
128
129   bool operator()(const bool& current, const PropertyInput& layoutPosition, const PropertyInput& scrollSpeed, const PropertyInput& layoutSize)
130   {
131     float offsetLayoutPosition = layoutPosition.GetFloat() + static_cast<float>(mItemId);
132
133     return mWrapMe(current, offsetLayoutPosition, scrollSpeed.GetFloat(), layoutSize.GetVector3());
134   }
135
136   Toolkit::ItemLayout::BoolFunction mWrapMe;
137   unsigned int mItemId;
138 };
139
140 /**
141  * Local helper to convert pan distance (in actor coordinates) to the layout-specific scrolling direction
142  */
143 float CalculateScrollDistance(Vector2 panDistance, Toolkit::ItemLayout& layout)
144 {
145   Radian scrollDirection(layout.GetScrollDirection());
146
147   float cosTheta = cosf(scrollDirection);
148   float sinTheta = sinf(scrollDirection);
149
150   return panDistance.x * sinTheta + panDistance.y * cosTheta;
151 }
152
153 // Overshoot overlay constraints
154
155 struct OvershootOverlaySizeConstraint
156 {
157   float operator()(const float& current,
158                      const PropertyInput& parentScrollDirectionProperty,
159                      const PropertyInput& parentOvershootProperty,
160                      const PropertyInput& parentSizeProperty)
161   {
162     const Vector3 parentScrollDirection = parentScrollDirectionProperty.GetVector3();
163     const Vector3 parentSize = parentSizeProperty.GetVector3();
164     const Toolkit::ControlOrientation::Type& parentOrientation = static_cast<Toolkit::ControlOrientation::Type>(parentScrollDirection.z);
165
166     float overlayWidth;
167
168     if(Toolkit::IsVertical(parentOrientation))
169     {
170       overlayWidth = fabsf(parentScrollDirection.y) > Math::MACHINE_EPSILON_1 ? parentSize.x : parentSize.y;
171     }
172     else
173     {
174       overlayWidth = fabsf(parentScrollDirection.x) > Math::MACHINE_EPSILON_1 ? parentSize.y : parentSize.x;
175     }
176
177     return overlayWidth;
178   }
179 };
180
181 struct OvershootOverlayRotationConstraint
182 {
183   Quaternion operator()(const Quaternion& current,
184                         const PropertyInput& parentScrollDirectionProperty,
185                         const PropertyInput& parentOvershootProperty)
186   {
187     const Vector3 parentScrollDirection = parentScrollDirectionProperty.GetVector3();
188     const float parentOvershoot = parentOvershootProperty.GetFloat();
189     const Toolkit::ControlOrientation::Type& parentOrientation = static_cast<Toolkit::ControlOrientation::Type>(parentScrollDirection.z);
190
191     Quaternion rotation;
192
193     if(Toolkit::IsVertical(parentOrientation))
194     {
195       if(fabsf(parentScrollDirection.y) <= Math::MACHINE_EPSILON_1)
196       {
197         if( (parentOrientation == Toolkit::ControlOrientation::Up && parentOvershoot < Math::MACHINE_EPSILON_0)
198             || (parentOrientation == Toolkit::ControlOrientation::Down && parentOvershoot > Math::MACHINE_EPSILON_0) )
199         {
200           rotation = Quaternion(0.5f * Math::PI, Vector3::ZAXIS);
201         }
202         else
203         {
204           rotation = Quaternion(1.5f * Math::PI, Vector3::ZAXIS);
205         }
206       }
207       else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.y > Math::MACHINE_EPSILON_0)
208             || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.y < Math::MACHINE_EPSILON_0) )
209       {
210         rotation = Quaternion(0.0f, Vector3::ZAXIS);
211       }
212       else
213       {
214         rotation = Quaternion(Math::PI, Vector3::ZAXIS);
215       }
216     }
217     else
218     {
219       if(fabsf(parentScrollDirection.x) <= Math::MACHINE_EPSILON_1)
220       {
221         if( (parentOrientation == Toolkit::ControlOrientation::Left && parentOvershoot > Math::MACHINE_EPSILON_0)
222             ||(parentOrientation == Toolkit::ControlOrientation::Right && parentOvershoot < Math::MACHINE_EPSILON_0) )
223         {
224           rotation = Quaternion(Math::PI, Vector3::ZAXIS);
225         }
226         else
227         {
228           rotation = Quaternion(0.0f, Vector3::ZAXIS);
229         }
230       }
231       else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.x > Math::MACHINE_EPSILON_0)
232             || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.x < Math::MACHINE_EPSILON_0) )
233       {
234         rotation = Quaternion(1.5f * Math::PI, Vector3::ZAXIS);
235       }
236       else
237       {
238         rotation = Quaternion(0.5f * Math::PI, Vector3::ZAXIS);
239       }
240     }
241
242     return rotation;
243   }
244 };
245
246 struct OvershootOverlayPositionConstraint
247 {
248   Vector3 operator()(const Vector3&    current,
249                      const PropertyInput& parentSizeProperty,
250                      const PropertyInput& parentScrollDirectionProperty,
251                      const PropertyInput& parentOvershootProperty)
252   {
253     const Vector3 parentScrollDirection = parentScrollDirectionProperty.GetVector3();
254     const float parentOvershoot = parentOvershootProperty.GetFloat();
255     const Vector3 parentSize = parentSizeProperty.GetVector3();
256     const Toolkit::ControlOrientation::Type& parentOrientation = static_cast<Toolkit::ControlOrientation::Type>(parentScrollDirection.z);
257
258     Vector3 relativeOffset;
259
260     if(Toolkit::IsVertical(parentOrientation))
261     {
262       if(fabsf(parentScrollDirection.y) <= Math::MACHINE_EPSILON_1)
263       {
264         if( (parentOrientation == Toolkit::ControlOrientation::Up && parentOvershoot < Math::MACHINE_EPSILON_0)
265             || (parentOrientation == Toolkit::ControlOrientation::Down && parentOvershoot > Math::MACHINE_EPSILON_0) )
266         {
267           relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
268         }
269         else
270         {
271           relativeOffset =Vector3(0.0f, 1.0f, 0.0f);
272         }
273       }
274       else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.y > Math::MACHINE_EPSILON_0)
275             || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.y < Math::MACHINE_EPSILON_0) )
276       {
277         relativeOffset = Vector3(0.0f, 0.0f, 0.0f);
278       }
279       else
280       {
281         relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
282       }
283     }
284     else
285     {
286       if(fabsf(parentScrollDirection.x) <= Math::MACHINE_EPSILON_1)
287       {
288         if( (parentOrientation == Toolkit::ControlOrientation::Left && parentOvershoot < Math::MACHINE_EPSILON_0)
289             || (parentOrientation == Toolkit::ControlOrientation::Right && parentOvershoot > Math::MACHINE_EPSILON_0) )
290         {
291           relativeOffset = Vector3(0.0f, 0.0f, 0.0f);
292         }
293         else
294         {
295           relativeOffset = Vector3(1.0f, 1.0f, 0.0f);
296         }
297       }
298       else if( (parentOvershoot > Math::MACHINE_EPSILON_0 && parentScrollDirection.x > Math::MACHINE_EPSILON_0)
299             || (parentOvershoot < Math::MACHINE_EPSILON_0 && parentScrollDirection.x < Math::MACHINE_EPSILON_0) )
300       {
301         relativeOffset = Vector3(0.0f, 1.0f, 0.0f);
302       }
303       else
304       {
305         relativeOffset = Vector3(1.0f, 0.0f, 0.0f);
306       }
307     }
308
309     return relativeOffset * parentSize;
310
311   }
312 };
313
314 struct OvershootOverlayVisibilityConstraint
315 {
316   bool operator()(const bool& current,
317                   const PropertyInput& parentLayoutScrollableProperty)
318   {
319     const bool parentLayoutScrollable = parentLayoutScrollableProperty.GetBoolean();
320
321     return parentLayoutScrollable;
322   }
323 };
324
325 /**
326  * Relative position Constraint
327  * Generates the relative position value of the item view based on the layout position,
328  * and it's relation to the layout domain. This is a value from 0.0f to 1.0f in each axis.
329  */
330 Vector3 RelativePositionConstraint(const Vector3& current,
331                                    const PropertyInput& scrollPositionProperty,
332                                    const PropertyInput& scrollMinProperty,
333                                    const PropertyInput& scrollMaxProperty,
334                                    const PropertyInput& layoutSizeProperty)
335 {
336   const Vector3& position = Vector3(0.0f, scrollPositionProperty.GetFloat(), 0.0f);
337   const Vector3& min = scrollMinProperty.GetVector3();
338   const Vector3& max = scrollMaxProperty.GetVector3();
339
340   Vector3 relativePosition;
341   Vector3 domainSize = max - min;
342
343   relativePosition.x = fabsf(domainSize.x) > Math::MACHINE_EPSILON_1 ? ((min.x - position.x) / fabsf(domainSize.x)) : 0.0f;
344   relativePosition.y = fabsf(domainSize.y) > Math::MACHINE_EPSILON_1 ? ((min.y - position.y) / fabsf(domainSize.y)) : 0.0f;
345
346   return relativePosition;
347 }
348
349 } // unnamed namespace
350
351 namespace Dali
352 {
353
354 namespace Toolkit
355 {
356
357 namespace Internal
358 {
359
360 ///////////////////////////////////////////////////////////////////////////////////////////////////
361 // ItemPool
362 ///////////////////////////////////////////////////////////////////////////////////////////////////
363
364 void ItemPool::AddItems(bool scrollingTowardsLast, ItemRange range, const Vector3& targetSize)
365 {
366   // Add new actors to the ItemPool.
367   // The order of addition depends on the scroll direction.
368   if (scrollingTowardsLast)
369   {
370     for (unsigned int itemId = range.begin; itemId < range.end; ++itemId)
371     {
372       AddItem(itemId, targetSize);
373     }
374   }
375   else
376   {
377     for (unsigned int itemId = range.end; itemId > range.begin; --itemId)
378     {
379       AddItem(itemId-1, targetSize);
380     }
381   }
382 }
383
384 void ItemPool::RemoveItems(ItemRange range)
385 {
386   // Remove unwanted actors from the ItemView & ItemPool
387   for (IDKeyIter iter = mIdKeyContainer.begin(); iter != mIdKeyContainer.end(); )
388   {
389     unsigned int current = iter->first;
390
391     if (!range.Within(current))
392     {
393       mItemView.ActorRemovedFromItemPool(iter->second, iter->first);
394
395       mActorKeyContainer.erase(iter->second);
396       mIdKeyContainer.erase(iter++); // erase invalidates the current iter; the post-increment is important here
397     }
398     else
399     {
400       ++iter;
401     }
402   }
403 }
404
405 void ItemPool::AddItem(unsigned int itemId, const Vector3& targetSize)
406 {
407   if (mIdKeyContainer.find(itemId) == mIdKeyContainer.end())
408   {
409     Actor actor = mItemView.CreateActor(itemId);
410
411     if (actor)
412     {
413       mIdKeyContainer.insert(IDKeyPair(itemId, actor));
414       mActorKeyContainer.insert(ActorKeyPair(actor, itemId));
415
416       mItemView.ActorAddedToItemPool(actor, itemId, targetSize);
417     }
418   }
419 }
420
421 bool ItemPool::RemoveItem(unsigned int itemId)
422 {
423   bool found = false;
424
425   IDKeyIter iter = mIdKeyContainer.find(itemId);
426   if (iter != mIdKeyContainer.end())
427   {
428     mItemView.ActorRemovedFromItemPool(iter->second, iter->first);
429
430     mActorKeyContainer.erase(iter->second);
431     for (ActorKeyIter iterActorKey = mActorKeyContainer.begin(); iterActorKey != mActorKeyContainer.end(); ++iterActorKey)
432     {
433       if(iterActorKey->second > itemId)
434       {
435         iterActorKey->second--;
436       }
437     }
438
439     for (IDKeyIter iterIDKey = iter; iterIDKey != mIdKeyContainer.end(); ++iterIDKey)
440     {
441       if(iterIDKey->first < mIdKeyContainer.rbegin()->first)
442       {
443         iterIDKey->second = mIdKeyContainer[iterIDKey->first + 1];
444       }
445       else
446       {
447         mIdKeyContainer.erase(iterIDKey);
448         break;
449       }
450     }
451
452     found = true;
453   }
454
455   return found;
456 }
457
458 ///////////////////////////////////////////////////////////////////////////////////////////////////
459 // ItemView
460 ///////////////////////////////////////////////////////////////////////////////////////////////////
461
462 Dali::Toolkit::ItemView ItemView::New(ItemFactory& factory)
463 {
464   // Create the implementation
465   ItemViewPtr itemView(new ItemView(factory));
466
467   // Pass ownership to CustomActor via derived handle
468   Dali::Toolkit::ItemView handle(*itemView);
469
470   // Second-phase init of the implementation
471   // This can only be done after the CustomActor connection has been made...
472   itemView->Initialize();
473
474   return handle;
475 }
476
477 ItemView::ItemView(ItemFactory& factory)
478 : Scrollable(),
479   mItemFactory(factory),
480   mItemPool(*this),
481   mActiveLayout(NULL),
482   mAnimatingOvershootOn(false),
483   mAnimateOvershootOff(false),
484   mAnchoringEnabled(true),
485   mAnchoringDuration(DEFAULT_ANCHORING_DURATION),
486   mRefreshIntervalMilliseconds(DEFAULT_REFRESH_INTERVAL_MILLISECONDS),
487   mRefreshOrderHint(true/*Refresh item 0 first*/),
488   mMinimumSwipeSpeed(DEFAULT_MINIMUM_SWIPE_SPEED),
489   mMinimumSwipeDistance(DEFAULT_MINIMUM_SWIPE_DISTANCE),
490   mScrollDistance(0.0f),
491   mScrollSpeed(0.0f),
492   mTotalPanDisplacement(Vector2::ZERO),
493   mScrollOvershoot(0.0f),
494   mIsFlicking(false),
495   mGestureState(Gesture::Clear)
496 {
497   SetRequiresMouseWheelEvents(true);
498   SetKeyboardNavigationSupport(true);
499 }
500
501 void ItemView::OnInitialize()
502 {
503   SetSizePolicy( Toolkit::Control::Fixed, Toolkit::Control::Fixed );
504
505   RegisterCommonProperties();
506
507   Actor self = Self();
508
509   mOvershootEffect = OvershootRippleEffect::New();
510   Image overshootImage = Image::New( OVERSHOOT_OVERLAY_RIPPLE_IMAGE_PATH );
511   mOvershootOverlay = ImageActor::New( overshootImage );
512   mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT);
513   mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT);
514   mOvershootOverlay.SetDrawMode(DrawMode::OVERLAY);
515   mOvershootOverlay.SetShaderEffect(mOvershootEffect);
516   mOvershootOverlay.SetPixelArea(OVERSHOOT_BOUNCE_IMAGE_1_PIXEL_AREA);
517   self.Add(mOvershootOverlay);
518
519   mPropertyLayoutPosition = self.RegisterProperty(LAYOUT_POSITION_PROPERTY_NAME, 0.0f);
520   mPropertyMinimumLayoutPosition = self.RegisterProperty(MINIMUM_LAYOUT_POSITION_PROPERTY_NAME, 0.0f);
521   mPropertyPosition = self.RegisterProperty(POSITION_PROPERTY_NAME, 0.0f);
522   mPropertyScrollSpeed = self.RegisterProperty(SCROLL_SPEED_PROPERTY_NAME, 0.0f);
523   mPropertyOvershoot = self.RegisterProperty(OVERSHOOT_PROPERTY_NAME, 0.0f);
524
525   ApplyOvershootOverlayConstraints();
526
527   Constraint constraint = Constraint::New<Vector3>(mPropertyRelativePosition,
528                                                    LocalSource(mPropertyPosition),
529                                                    LocalSource(mPropertyPositionMin),
530                                                    LocalSource(mPropertyPositionMax),
531                                                    LocalSource(Actor::SIZE),
532                                                    RelativePositionConstraint);
533   self.ApplyConstraint(constraint);
534
535   Vector2 stageSize = Stage::GetCurrent().GetSize();
536   mMouseWheelScrollDistanceStep = stageSize.y * DEFAULT_MOUSE_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION;
537
538   EnableGestureDetection(Gesture::Type(Gesture::Pan));
539
540   mMouseWheelEventFinishedTimer = Timer::New( MOUSE_WHEEL_EVENT_FINISHED_TIME_OUT );
541   mMouseWheelEventFinishedTimer.TickSignal().Connect( this, &ItemView::OnMouseWheelEventFinished );
542 }
543
544 ItemView::~ItemView()
545 {
546 }
547
548 unsigned int ItemView::GetLayoutCount() const
549 {
550   return mLayouts.size();
551 }
552
553 void ItemView::AddLayout(ItemLayout& layout)
554 {
555   mLayouts.push_back(ItemLayoutPtr(&layout));
556 }
557
558 void ItemView::RemoveLayout(unsigned int layoutIndex)
559 {
560   DALI_ASSERT_ALWAYS(layoutIndex < mLayouts.size());
561
562   if (mActiveLayout == mLayouts[layoutIndex].Get())
563   {
564     mActiveLayout = NULL;
565   }
566
567   mLayouts.erase(mLayouts.begin() + layoutIndex);
568 }
569
570 ItemLayoutPtr ItemView::GetLayout(unsigned int layoutIndex) const
571 {
572   return mLayouts[layoutIndex];
573 }
574
575 ItemLayoutPtr ItemView::GetActiveLayout() const
576 {
577   return ItemLayoutPtr(mActiveLayout);
578 }
579
580 float ItemView::GetCurrentLayoutPosition(unsigned int itemId) const
581 {
582   return Self().GetProperty<float>(mPropertyLayoutPosition) + static_cast<float>(itemId);
583 }
584
585 void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSize, float durationSeconds)
586 {
587   DALI_ASSERT_ALWAYS(layoutIndex < mLayouts.size());
588
589   Actor self = Self();
590
591   // The ItemView size should match the active layout size
592   self.SetSize(targetSize);
593
594   // Switch to the new layout
595   ItemLayout* previousLayout = mActiveLayout;
596   mActiveLayout = mLayouts[layoutIndex].Get();
597
598   // Calculate which items are within either layout
599   ItemRange oldRange = previousLayout ? GetItemRange(*previousLayout, targetSize, false/*don't reserve extra*/) : ItemRange(0u, 0u);
600   ItemRange newRange = GetItemRange(*mActiveLayout, targetSize, false/*don't reserve extra*/);
601
602   // Move the items to the new layout positions...
603
604   bool resizeAnimationNeeded(false);
605
606   const ItemPool::IDKeyContainer& itemPool = mItemPool.GetIDKeyContainer();
607   for (ItemPool::IDKeyConstIter iter = itemPool.begin(); iter != itemPool.end(); ++iter)
608   {
609     unsigned int itemId = iter->first;
610     Actor actor = iter->second;
611
612     // Immediately relayout items that aren't within either layout
613     bool immediate = !oldRange.Within(itemId) &&
614                      !newRange.Within(itemId);
615
616     // Remove constraints from previous layout
617     actor.RemoveConstraints();
618
619     Vector3 size;
620     if(mActiveLayout->GetItemSize(itemId, targetSize, size))
621     {
622       if (!immediate &&
623           durationSeconds > 0.0f)
624       {
625         // Use a size animation
626         if (!resizeAnimationNeeded)
627         {
628           resizeAnimationNeeded = true;
629           RemoveAnimation(mResizeAnimation);
630           mResizeAnimation = Animation::New(durationSeconds);
631         }
632
633         // The layout provides its own resize animation
634         mActiveLayout->GetResizeAnimation(mResizeAnimation, actor, size, durationSeconds);
635       }
636       else
637       {
638         // resize immediately
639         actor.SetSize(size);
640       }
641     }
642
643     ApplyConstraints(actor, *mActiveLayout, itemId, immediate ? 0.0f : durationSeconds);
644   }
645
646   if (resizeAnimationNeeded)
647   {
648     mResizeAnimation.Play();
649   }
650
651   // Refresh the new layout
652   ItemRange range = GetItemRange(*mActiveLayout, targetSize, true/*reserve extra*/);
653   AddItems(*mActiveLayout, targetSize, range);
654
655   // Scroll to an appropriate layout position
656
657   bool scrollAnimationNeeded(false);
658   float firstItemScrollPosition(0.0f);
659
660   float current = self.GetProperty<float>(mPropertyLayoutPosition);
661   float minimum = ClampFirstItemPosition(current, targetSize, *mActiveLayout);
662   self.SetProperty(mPropertyPosition, GetScrollPosition(current, targetSize));
663
664   if (current < minimum)
665   {
666     scrollAnimationNeeded = true;
667     firstItemScrollPosition = minimum;
668   }
669   else if (mAnchoringEnabled)
670   {
671     scrollAnimationNeeded = true;
672     firstItemScrollPosition = mActiveLayout->GetClosestAnchorPosition(current);
673   }
674
675   if (scrollAnimationNeeded)
676   {
677     RemoveAnimation(mScrollAnimation);
678     mScrollAnimation = Animation::New(mAnchoringDuration);
679     mScrollAnimation.AnimateTo( Property(self, mPropertyLayoutPosition), firstItemScrollPosition, AlphaFunctions::EaseOut );
680     mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, targetSize), AlphaFunctions::EaseOut );
681     mScrollAnimation.Play();
682   }
683
684   self.SetProperty(mPropertyMinimumLayoutPosition, mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), targetSize));
685   AnimateScrollOvershoot(0.0f);
686   mScrollOvershoot = 0.0f;
687
688   Radian scrollDirection(mActiveLayout->GetScrollDirection());
689   float orientation = static_cast<float>(mActiveLayout->GetOrientation());
690   self.SetProperty(mPropertyScrollDirection, Vector3(sinf(scrollDirection), cosf(scrollDirection), orientation));
691
692   self.SetProperty(mPropertyScrollSpeed, mScrollSpeed);
693
694   CalculateDomainSize(targetSize);
695 }
696
697 void ItemView::DeactivateCurrentLayout()
698 {
699   if (mActiveLayout)
700   {
701     const ItemPool::IDKeyContainer& itemPool = mItemPool.GetIDKeyContainer();
702     for (ItemPool::IDKeyConstIter iter = itemPool.begin(); iter != itemPool.end(); ++iter)
703     {
704       Actor actor = iter->second;
705       actor.RemoveConstraints();
706     }
707
708     mActiveLayout = NULL;
709   }
710
711   CancelRefreshTimer();
712 }
713
714 bool ItemView::OnRefreshTick()
715 {
716   // Short-circuit if there is no active layout
717   if (!mActiveLayout)
718   {
719     return false;
720   }
721
722   const Vector3 layoutSize = Self().GetCurrentSize();
723
724   ItemRange range = GetItemRange(*mActiveLayout, layoutSize, true/*reserve extra*/);
725
726   RemoveItems(range);
727   AddItems(*mActiveLayout, layoutSize, range);
728
729   // Keep refreshing whilst the layout is moving
730   return mScrollAnimation || (mGestureState == Gesture::Started || mGestureState == Gesture::Continuing);
731 }
732
733 void ItemView::SetMinimumSwipeSpeed(float speed)
734 {
735   mMinimumSwipeSpeed = speed;
736 }
737
738 float ItemView::GetMinimumSwipeSpeed() const
739 {
740   return mMinimumSwipeSpeed;
741 }
742
743 void ItemView::SetMinimumSwipeDistance(float distance)
744 {
745   mMinimumSwipeDistance = distance;
746 }
747
748 float ItemView::GetMinimumSwipeDistance() const
749 {
750   return mMinimumSwipeDistance;
751 }
752
753 void ItemView::SetMouseWheelScrollDistanceStep(float step)
754 {
755   mMouseWheelScrollDistanceStep = step;
756 }
757
758 float ItemView::GetMouseWheelScrollDistanceStep() const
759 {
760   return mMouseWheelScrollDistanceStep;
761 }
762
763 void ItemView::SetAnchoring(bool enabled)
764 {
765   mAnchoringEnabled = enabled;
766 }
767
768 bool ItemView::GetAnchoring() const
769 {
770   return mAnchoringEnabled;
771 }
772
773 void ItemView::SetAnchoringDuration(float durationSeconds)
774 {
775   mAnchoringDuration = durationSeconds;
776 }
777
778 float ItemView::GetAnchoringDuration() const
779 {
780   return mAnchoringDuration;
781 }
782
783 void ItemView::SetRefreshInterval(unsigned int intervalMilliseconds)
784 {
785   mRefreshIntervalMilliseconds = intervalMilliseconds;
786 }
787
788 unsigned int ItemView::GetRefreshInterval() const
789 {
790   return mRefreshIntervalMilliseconds;
791 }
792
793 Actor ItemView::GetItem(unsigned int itemId) const
794 {
795   Actor actor;
796
797   ItemPool::IDKeyConstIter found = mItemPool.GetIDKeyContainer().find(itemId);
798   if (found != mItemPool.GetIDKeyContainer().end())
799   {
800     actor = found->second;
801   }
802
803   return actor;
804 }
805
806 unsigned int ItemView::GetItemId(Actor actor) const
807 {
808   unsigned int itemId(0);
809
810   ItemPool::ActorKeyConstIter found = mItemPool.GetActorKeyContainer().find(actor);
811   if (found != mItemPool.GetActorKeyContainer().end())
812   {
813     itemId = found->second;
814   }
815
816   return itemId;
817 }
818
819 void ItemView::RemoveItem(unsigned int itemId, float durationSeconds)
820 {
821   if (mItemPool.RemoveItem(itemId))
822   {
823     const ItemPool::IDKeyContainer& itemPool = mItemPool.GetIDKeyContainer();
824     for (ItemPool::IDKeyConstIter iter = itemPool.begin(); iter != itemPool.end(); ++iter)
825     {
826       unsigned int id = iter->first;
827       Actor actor = iter->second;
828
829       // Reposition the items if necessary
830       actor.RemoveConstraints();
831       ApplyConstraints(actor, *mActiveLayout, id, durationSeconds);
832     }
833
834     CalculateDomainSize(Self().GetCurrentSize());
835   }
836 }
837
838 Actor ItemView::CreateActor(unsigned int itemId)
839 {
840   return mItemFactory.NewItem(itemId);
841 }
842
843 void ItemView::ActorAddedToItemPool(Actor actor, unsigned int itemId, const Vector3& targetSize)
844 {
845   Actor self = Self();
846
847   actor.SetParentOrigin(ParentOrigin::CENTER);
848   actor.SetAnchorPoint(AnchorPoint::CENTER);
849
850   if (mActiveLayout)
851   {
852     Vector3 size;
853     if(mActiveLayout->GetItemSize(itemId, targetSize, size))
854     {
855       actor.SetSize(size);
856     }
857
858     ApplyConstraints(actor, *mActiveLayout, itemId, 0.0f/*immediate*/);
859   }
860
861   self.Add(actor);
862 }
863
864 void ItemView::ActorRemovedFromItemPool(Actor actor, unsigned int itemId)
865 {
866   Self().Remove(actor);
867 }
868
869 void ItemView::RemoveItems(ItemRange range)
870 {
871   mItemPool.RemoveItems(range);
872 }
873
874 void ItemView::AddItems(ItemLayout& layout, const Vector3& layoutSize, ItemRange range)
875 {
876   range.end = min(mItemFactory.GetNumberOfItems(), range.end);
877
878   mItemPool.AddItems(mRefreshOrderHint, range, layoutSize);
879 }
880
881 ItemRange ItemView::GetItemRange(ItemLayout& layout, const Vector3& layoutSize, bool reserveExtra)
882 {
883   unsigned int itemCount = mItemFactory.GetNumberOfItems();
884
885   ItemRange available(0u, itemCount);
886
887   ItemRange range = layout.GetItemsWithinArea(Self().GetProperty<float>(mPropertyLayoutPosition), layoutSize);
888
889   if (reserveExtra)
890   {
891     // Add the reserve items for scrolling
892     unsigned int extra = layout.GetReserveItemCount(layoutSize);
893     range.begin = (range.begin >= extra) ? (range.begin - extra) : 0u;
894     range.end += extra;
895   }
896
897   return range.Intersection(available);
898 }
899
900 bool ItemView::OnTouchEvent(const TouchEvent& event)
901 {
902   // Ignore events with multiple-touch points
903   if (event.GetPointCount() != 1)
904   {
905     return false;
906   }
907
908   if (event.GetPoint(0).state == TouchPoint::Down)
909   {
910     // Cancel ongoing scrolling etc.
911     mGestureState = Gesture::Clear;
912
913     mScrollDistance = 0.0f;
914     mScrollSpeed = 0.0f;
915     Self().SetProperty(mPropertyScrollSpeed, mScrollSpeed);
916
917     mScrollOvershoot = 0.0f;
918     AnimateScrollOvershoot(0.0f);
919
920     mScrollCompletedSignalV2.Emit(GetCurrentScrollPosition());
921
922     RemoveAnimation(mScrollAnimation);
923   }
924
925   return true; // consume since we're potentially scrolling
926 }
927
928 bool ItemView::OnMouseWheelEvent(const MouseWheelEvent& event)
929 {
930   // Respond the mouse wheel event to scroll
931   if (mActiveLayout)
932   {
933     Actor self = Self();
934     const Vector3 layoutSize = Self().GetCurrentSize();
935     float layoutPositionDelta = self.GetProperty<float>(mPropertyLayoutPosition) + (event.z * mMouseWheelScrollDistanceStep * mActiveLayout->GetScrollSpeedFactor());
936     float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout);
937     self.SetProperty(mPropertyLayoutPosition, firstItemScrollPosition);
938     self.SetProperty(mPropertyPosition, GetScrollPosition(firstItemScrollPosition, layoutSize));
939     mScrollStartedSignalV2.Emit(GetCurrentScrollPosition());
940     StartRefreshTimer();
941   }
942
943   if (mMouseWheelEventFinishedTimer.IsRunning())
944   {
945     mMouseWheelEventFinishedTimer.Stop();
946   }
947
948   mMouseWheelEventFinishedTimer.Start();
949
950   return true;
951 }
952
953 bool ItemView::OnMouseWheelEventFinished()
954 {
955   if (mActiveLayout)
956   {
957     RemoveAnimation(mScrollAnimation);
958
959     // No more mouse wheel events coming. Do the anchoring if enabled.
960     mScrollAnimation = DoAnchoring();
961     if (mScrollAnimation)
962     {
963       StartRefreshTimer();
964
965       mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
966       mScrollAnimation.Play();
967     }
968     else
969     {
970       mScrollOvershoot = 0.0f;
971       AnimateScrollOvershoot(0.0f);
972
973       mScrollCompletedSignalV2.Emit(GetCurrentScrollPosition());
974     }
975   }
976
977   return false;
978 }
979
980 void ItemView::ApplyConstraints(Actor& actor, ItemLayout& layout, unsigned int itemId, float duration)
981 {
982   ItemLayout::Vector3Function positionConstraint;
983   if (layout.GetPositionConstraint(itemId, positionConstraint))
984   {
985     WrappedVector3Constraint wrapped(positionConstraint, itemId);
986
987     Constraint constraint = Constraint::New<Vector3>( Actor::POSITION,
988                                                       ParentSource( mPropertyLayoutPosition ),
989                                                       ParentSource( mPropertyScrollSpeed ),
990                                                       ParentSource( Actor::SIZE ),
991                                                       wrapped );
992     constraint.SetApplyTime(duration);
993
994     actor.ApplyConstraint(constraint);
995   }
996
997   ItemLayout::QuaternionFunction rotationConstraint;
998   if (layout.GetRotationConstraint(itemId, rotationConstraint))
999   {
1000     WrappedQuaternionConstraint wrapped(rotationConstraint, itemId);
1001
1002     Constraint constraint = Constraint::New<Quaternion>( Actor::ROTATION,
1003                                                          ParentSource( mPropertyLayoutPosition ),
1004                                                          ParentSource( mPropertyScrollSpeed ),
1005                                                          ParentSource( Actor::SIZE ),
1006                                                          wrapped );
1007     constraint.SetApplyTime(duration);
1008
1009     actor.ApplyConstraint(constraint);
1010   }
1011
1012   ItemLayout::Vector3Function scaleConstraint;
1013   if (layout.GetScaleConstraint(itemId, scaleConstraint))
1014   {
1015     WrappedVector3Constraint wrapped(scaleConstraint, itemId);
1016
1017     Constraint constraint = Constraint::New<Vector3>( Actor::SCALE,
1018                                                       ParentSource( mPropertyLayoutPosition ),
1019                                                       ParentSource( mPropertyScrollSpeed ),
1020                                                       ParentSource( Actor::SIZE ),
1021                                                       wrapped );
1022     constraint.SetApplyTime(duration);
1023
1024     actor.ApplyConstraint(constraint);
1025   }
1026
1027   ItemLayout::Vector4Function colorConstraint;
1028   if (layout.GetColorConstraint(itemId, colorConstraint))
1029   {
1030     WrappedVector4Constraint wrapped(colorConstraint, itemId);
1031
1032     Constraint constraint = Constraint::New<Vector4>( Actor::COLOR,
1033                                                       ParentSource( mPropertyLayoutPosition ),
1034                                                       ParentSource( mPropertyScrollSpeed ),
1035                                                       ParentSource( Actor::SIZE ),
1036                                                       wrapped );
1037     constraint.SetApplyTime(duration);
1038
1039     // Release color constraints slowly; this allows ItemView to co-exist with ImageActor fade-in
1040     constraint.SetRemoveTime(DEFAULT_COLOR_VISIBILITY_REMOVE_TIME);
1041     constraint.SetRemoveAction(Dali::Constraint::Discard);
1042
1043     actor.ApplyConstraint(constraint);
1044   }
1045
1046   ItemLayout::BoolFunction visibilityConstraint;
1047   if (layout.GetVisibilityConstraint(itemId, visibilityConstraint))
1048   {
1049     WrappedBoolConstraint wrapped(visibilityConstraint, itemId);
1050
1051     Constraint constraint = Constraint::New<bool>( Actor::VISIBLE,
1052                                                    ParentSource( mPropertyLayoutPosition ),
1053                                                    ParentSource( mPropertyScrollSpeed ),
1054                                                    ParentSource( Actor::SIZE ),
1055                                                    wrapped );
1056     constraint.SetApplyTime(duration);
1057
1058     // Release visibility constraints the same time as the color constraint
1059     constraint.SetRemoveTime(DEFAULT_COLOR_VISIBILITY_REMOVE_TIME);
1060     constraint.SetRemoveAction(Dali::Constraint::Discard);
1061
1062     actor.ApplyConstraint(constraint);
1063   }
1064 }
1065
1066 float ItemView::ClampFirstItemPosition(float targetPosition, const Vector3& targetSize, ItemLayout& layout)
1067 {
1068   Actor self = Self();
1069   float minLayoutPosition = layout.GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), targetSize);
1070   float clamppedPosition = min(0.0f, max(minLayoutPosition, targetPosition));
1071   mScrollOvershoot = targetPosition - clamppedPosition;
1072   self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition);
1073
1074   return clamppedPosition;
1075 }
1076
1077 void ItemView::OnPan(PanGesture gesture)
1078 {
1079   Actor self = Self();
1080   const Vector3 layoutSize = Self().GetCurrentSize();
1081
1082   RemoveAnimation(mScrollAnimation);
1083
1084   // Short-circuit if there is no active layout
1085   if (!mActiveLayout)
1086   {
1087     mGestureState = Gesture::Clear;
1088     return;
1089   }
1090
1091   mGestureState = gesture.state;
1092
1093   switch (mGestureState)
1094   {
1095     case Gesture::Finished:
1096     {
1097       // Swipe Detection
1098       if (fabsf(mScrollDistance) > mMinimumSwipeDistance &&
1099           mScrollSpeed > mMinimumSwipeSpeed)
1100       {
1101         float direction = (mScrollDistance < 0.0f) ? -1.0f : 1.0f;
1102
1103         mRefreshOrderHint = true;
1104
1105         float currentLayoutPosition = self.GetProperty<float>(mPropertyLayoutPosition);
1106         float firstItemScrollPosition = ClampFirstItemPosition(currentLayoutPosition + mScrollSpeed * direction,
1107                                                                layoutSize,
1108                                                                *mActiveLayout);
1109
1110         if (mAnchoringEnabled)
1111         {
1112           firstItemScrollPosition = mActiveLayout->GetClosestAnchorPosition(firstItemScrollPosition);
1113         }
1114
1115         RemoveAnimation(mScrollAnimation);
1116
1117         float flickAnimationDuration = mActiveLayout->GetItemFlickAnimationDuration() * max(1.0f, fabsf(firstItemScrollPosition - GetCurrentLayoutPosition(0)));
1118         mScrollAnimation = Animation::New(flickAnimationDuration);
1119         mScrollAnimation.AnimateTo( Property(self, mPropertyLayoutPosition), firstItemScrollPosition, AlphaFunctions::EaseOut );
1120         mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut );
1121         mScrollAnimation.AnimateTo( Property(self, mPropertyScrollSpeed), 0.0f, AlphaFunctions::EaseOut );
1122
1123         mIsFlicking = true;
1124         // Check whether it has already scrolled to the end
1125         if(fabs(currentLayoutPosition - firstItemScrollPosition) > Math::MACHINE_EPSILON_0)
1126         {
1127           AnimateScrollOvershoot(0.0f);
1128         }
1129       }
1130
1131       // Anchoring may be triggered when there was no swipe
1132       if (!mScrollAnimation)
1133       {
1134         mScrollAnimation = DoAnchoring();
1135       }
1136
1137       // Reset the overshoot if no scroll animation.
1138       if (!mScrollAnimation)
1139       {
1140         mScrollCompletedSignalV2.Emit(GetCurrentScrollPosition());
1141
1142         AnimateScrollOvershoot(0.0f, false);
1143       }
1144     }
1145     break;
1146
1147     case Gesture::Started: // Fall through
1148     {
1149       mTotalPanDisplacement = Vector2::ZERO;
1150     }
1151
1152     case Gesture::Continuing:
1153     {
1154       mScrollDistance = CalculateScrollDistance(gesture.displacement, *mActiveLayout);
1155       mScrollSpeed = Clamp((gesture.GetSpeed() * mActiveLayout->GetScrollSpeedFactor() * MILLISECONDS_PER_SECONDS), 0.0f, mActiveLayout->GetMaximumSwipeSpeed());
1156
1157       // Refresh order depends on the direction of the scroll; negative is towards the last item.
1158       mRefreshOrderHint = mScrollDistance < 0.0f;
1159
1160       RemoveAnimation(mScrollSpeedAnimation);
1161       mScrollSpeedAnimation = Animation::New(0.3f);
1162       mScrollSpeedAnimation.AnimateTo( Property(self, mPropertyScrollSpeed), mScrollSpeed, AlphaFunctions::Linear );
1163       mScrollSpeedAnimation.Play();
1164
1165       float layoutPositionDelta = self.GetProperty<float>(mPropertyLayoutPosition) + (mScrollDistance * mActiveLayout->GetScrollSpeedFactor());
1166
1167       float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout);
1168
1169       self.SetProperty(mPropertyLayoutPosition, firstItemScrollPosition);
1170       self.SetProperty(mPropertyPosition, GetScrollPosition(firstItemScrollPosition, layoutSize));
1171       mScrollStartedSignalV2.Emit(GetCurrentScrollPosition());
1172
1173       mTotalPanDisplacement += gesture.displacement;
1174       mScrollOvershoot = layoutPositionDelta - firstItemScrollPosition;
1175       if( mScrollOvershoot > Math::MACHINE_EPSILON_1 )
1176       {
1177         AnimateScrollOvershoot(1.0f);
1178       }
1179       else if( mScrollOvershoot < -Math::MACHINE_EPSILON_1 )
1180       {
1181         AnimateScrollOvershoot(-1.0f);
1182       }
1183       else
1184       {
1185         AnimateScrollOvershoot(0.0f);
1186       }
1187
1188       StartRefreshTimer();
1189     }
1190     break;
1191
1192     case Gesture::Cancelled:
1193     {
1194       mScrollAnimation = DoAnchoring();
1195     }
1196     break;
1197
1198     default:
1199       break;
1200   }
1201
1202   if (mScrollAnimation)
1203   {
1204     StartRefreshTimer();
1205
1206     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1207     mScrollAnimation.Play();
1208   }
1209 }
1210
1211 bool ItemView::OnAccessibilityPan(PanGesture gesture)
1212 {
1213   OnPan(gesture);
1214   return true;
1215 }
1216
1217 Actor ItemView::GetNextKeyboardFocusableActor(Actor actor, Control::KeyboardFocusNavigationDirection direction, bool loopEnabled)
1218 {
1219   Actor nextFocusActor;
1220   if(mActiveLayout)
1221   {
1222     int nextItemID = 0;
1223     if(!actor || actor == this->Self())
1224     {
1225       nextFocusActor = GetItem(nextItemID);
1226     }
1227     else if(actor && actor.GetParent() == this->Self())
1228     {
1229       int itemID = GetItemId(actor);
1230       nextItemID = mActiveLayout->GetNextFocusItemID(itemID, mItemFactory.GetNumberOfItems(), direction, loopEnabled);
1231       nextFocusActor = GetItem(nextItemID);
1232       if(nextFocusActor == actor)
1233       {
1234         // need to pass NULL actor back to focus manager
1235         nextFocusActor.Reset();
1236         return nextFocusActor;
1237       }
1238     }
1239     float layoutPosition = mActiveLayout->GetClosestAnchorPosition(Self().GetProperty<float>(mPropertyLayoutPosition));
1240     Vector3 layoutSize = Self().GetCurrentSize();
1241     if(!nextFocusActor)
1242     {
1243       // likely the current item is not buffered, so not in our item pool, probably best to get first viewable item
1244       ItemRange viewableItems = mActiveLayout->GetItemsWithinArea(layoutPosition, layoutSize);
1245       nextItemID = viewableItems.begin;
1246       nextFocusActor = GetItem(nextItemID);
1247     }
1248   }
1249   return nextFocusActor;
1250 }
1251
1252 void ItemView::OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor)
1253 {
1254   // only in this function if our chosen focus actor was actually used
1255   if(commitedFocusableActor)
1256   {
1257     int nextItemID = GetItemId(commitedFocusableActor);
1258     float layoutPosition = Self().GetProperty<float>(mPropertyLayoutPosition);
1259     Vector3 layoutSize = Self().GetCurrentSize();
1260     Vector3 focusItemPosition = Vector3::ZERO;
1261     ItemLayout::Vector3Function itemPositionConstraint;
1262     if (mActiveLayout->GetPositionConstraint(nextItemID, itemPositionConstraint))
1263     {
1264       focusItemPosition = itemPositionConstraint(Vector3::ZERO, layoutPosition + nextItemID, 0.0f, layoutSize);
1265     }
1266
1267     float scrollTo = mActiveLayout->GetClosestOnScreenLayoutPosition(nextItemID, layoutPosition, layoutSize);
1268     ScrollTo(Vector3(0.0f, scrollTo, 0.0f), DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION);
1269   }
1270 }
1271
1272 Animation ItemView::DoAnchoring()
1273 {
1274   Animation anchoringAnimation;
1275   Actor self = Self();
1276
1277   if (mActiveLayout && mAnchoringEnabled)
1278   {
1279     float anchorPosition = mActiveLayout->GetClosestAnchorPosition(Self().GetProperty<float>(mPropertyLayoutPosition));
1280
1281     anchoringAnimation = Animation::New(mAnchoringDuration);
1282     anchoringAnimation.AnimateTo( Property(self, mPropertyLayoutPosition), anchorPosition, AlphaFunctions::EaseOut );
1283     anchoringAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(anchorPosition, self.GetCurrentSize()), AlphaFunctions::EaseOut );
1284     anchoringAnimation.AnimateTo( Property(self, mPropertyScrollSpeed), 0.0f, AlphaFunctions::EaseOut );
1285     if(!mIsFlicking)
1286     {
1287       AnimateScrollOvershoot(0.0f);
1288     }
1289   }
1290
1291   return anchoringAnimation;
1292 }
1293
1294 void ItemView::OnScrollFinished(Animation& source)
1295 {
1296   Actor self = Self();
1297
1298   RemoveAnimation(mScrollAnimation); // mScrollAnimation is used to query whether we're scrolling
1299
1300   mScrollCompletedSignalV2.Emit(GetCurrentScrollPosition());
1301
1302   if(mIsFlicking && fabsf(mScrollOvershoot) > Math::MACHINE_EPSILON_1)
1303   {
1304     AnimateScrollOvershoot( mScrollOvershoot > 0.0f ? 1.0f : -1.0f, true);
1305   }
1306   else
1307   {
1308     // Reset the overshoot
1309     AnimateScrollOvershoot( 0.0f );
1310   }
1311   mIsFlicking = false;
1312
1313   mScrollOvershoot = 0.0f;
1314 }
1315
1316 void ItemView::OnOvershootOnFinished(Animation& animation)
1317 {
1318   mAnimatingOvershootOn = false;
1319   mScrollOvershootAnimation.FinishedSignal().Disconnect(this, &ItemView::OnOvershootOnFinished);
1320   RemoveAnimation(mScrollOvershootAnimation);
1321   if(mAnimateOvershootOff)
1322   {
1323     AnimateScrollOvershoot(0.0f);
1324   }
1325 }
1326
1327 void ItemView::StartRefreshTimer()
1328 {
1329   if (!mRefreshTimer)
1330   {
1331     mRefreshTimer = Timer::New( mRefreshIntervalMilliseconds );
1332     mRefreshTimer.TickSignal().Connect( this, &ItemView::OnRefreshTick );
1333   }
1334
1335   if (!mRefreshTimer.IsRunning())
1336   {
1337     mRefreshTimer.Start();
1338   }
1339 }
1340
1341 void ItemView::CancelRefreshTimer()
1342 {
1343   if (mRefreshTimer)
1344   {
1345     mRefreshTimer.Stop();
1346   }
1347 }
1348
1349 void ItemView::ScrollToItem(unsigned int itemId, float durationSeconds)
1350 {
1351   Actor self = Self();
1352   const Vector3 layoutSize = Self().GetCurrentSize();
1353   float firstItemScrollPosition = ClampFirstItemPosition(mActiveLayout->GetItemScrollToPosition(itemId), layoutSize, *mActiveLayout);
1354
1355   StartRefreshTimer();
1356
1357   if(durationSeconds > 0.0f)
1358   {
1359     RemoveAnimation(mScrollAnimation);
1360     mScrollAnimation = Animation::New(durationSeconds);
1361     mScrollAnimation.AnimateTo( Property(self, mPropertyLayoutPosition), firstItemScrollPosition, AlphaFunctions::EaseOut );
1362     mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut );
1363     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1364     mScrollAnimation.Play();
1365   }
1366   else
1367   {
1368     self.SetProperty(mPropertyLayoutPosition, firstItemScrollPosition);
1369     AnimateScrollOvershoot(0.0f);
1370   }
1371
1372   mScrollStartedSignalV2.Emit(GetCurrentScrollPosition());
1373 }
1374
1375 void ItemView::RemoveAnimation(Animation& animation)
1376 {
1377   if(animation)
1378   {
1379     // Cease animating, and reset handle.
1380     animation.Clear();
1381     animation.Reset();
1382   }
1383 }
1384
1385 void ItemView::CalculateDomainSize(const Vector3& layoutSize)
1386 {
1387   Actor self = Self();
1388
1389   Vector3 firstItemPosition(Vector3::ZERO);
1390   Vector3 lastItemPosition(Vector3::ZERO);
1391
1392   if(mActiveLayout)
1393   {
1394     ItemLayout::Vector3Function firstItemPositionConstraint;
1395     if (mActiveLayout->GetPositionConstraint(0, firstItemPositionConstraint))
1396     {
1397       firstItemPosition = firstItemPositionConstraint(Vector3::ZERO, 0, 0.0f, layoutSize);
1398     }
1399
1400     float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), layoutSize);
1401     ItemLayout::Vector3Function lastItemPositionConstraint;
1402     if (mActiveLayout->GetPositionConstraint(fabs(minLayoutPosition), lastItemPositionConstraint))
1403     {
1404       lastItemPosition = lastItemPositionConstraint(Vector3::ZERO, fabs(minLayoutPosition), 0.0f, layoutSize);
1405     }
1406
1407     if(IsHorizontal(mActiveLayout->GetOrientation()))
1408     {
1409       self.SetProperty(mPropertyPositionMin, Vector3(0.0f, firstItemPosition.x, 0.0f));
1410       self.SetProperty(mPropertyPositionMax, Vector3(0.0f, lastItemPosition.x, 0.0f));
1411     }
1412     else
1413     {
1414       self.SetProperty(mPropertyPositionMin, Vector3(0.0f, firstItemPosition.y, 0.0f));
1415       self.SetProperty(mPropertyPositionMax, Vector3(0.0f, lastItemPosition.y, 0.0f));
1416     }
1417
1418     bool isLayoutScrollable = IsLayoutScrollable(layoutSize);
1419     self.SetProperty(mPropertyCanScrollVertical, isLayoutScrollable);
1420     self.SetProperty(mPropertyCanScrollHorizontal, false);
1421   }
1422 }
1423
1424 Vector3 ItemView::GetDomainSize() const
1425 {
1426   Actor self = Self();
1427
1428   float minScrollPosition = self.GetProperty<float>(mPropertyPositionMin);
1429   float maxScrollPosition = self.GetProperty<float>(mPropertyPositionMax);
1430
1431   return Vector3(0.0f, fabs(maxScrollPosition - minScrollPosition), 0.0f);
1432 }
1433
1434 bool ItemView::IsLayoutScrollable(const Vector3& layoutSize)
1435 {
1436   Actor self = Self();
1437
1438   float currentLayoutPosition = ClampFirstItemPosition(self.GetProperty<float>(mPropertyLayoutPosition), layoutSize, *mActiveLayout);
1439   float forwardClampedPosition = ClampFirstItemPosition(currentLayoutPosition + 1.0, layoutSize, *mActiveLayout);
1440   float backwardClampedPosition = ClampFirstItemPosition(currentLayoutPosition - 1.0, layoutSize, *mActiveLayout);
1441
1442   return (fabs(forwardClampedPosition - backwardClampedPosition) > Math::MACHINE_EPSILON_0);
1443 }
1444
1445 float ItemView::GetScrollPosition(float layoutPosition, const Vector3& layoutSize) const
1446 {
1447   Vector3 firstItemPosition(Vector3::ZERO);
1448   ItemLayout::Vector3Function firstItemPositionConstraint;
1449   if (mActiveLayout->GetPositionConstraint(0, firstItemPositionConstraint))
1450   {
1451     firstItemPosition = firstItemPositionConstraint(Vector3::ZERO, layoutPosition, 0.0f, layoutSize);
1452   }
1453
1454   return IsHorizontal(mActiveLayout->GetOrientation()) ? firstItemPosition.x: firstItemPosition.y;
1455 }
1456
1457 Vector3 ItemView::GetCurrentScrollPosition() const
1458 {
1459   float currentLayoutPosition = Self().GetProperty<float>(mPropertyLayoutPosition);
1460   return Vector3(0.0f, GetScrollPosition(currentLayoutPosition, Self().GetCurrentSize()), 0.0f);
1461 }
1462
1463 void ItemView::AddOverlay(Actor actor)
1464 {
1465   Self().Add(actor);
1466 }
1467
1468 void ItemView::RemoveOverlay(Actor actor)
1469 {
1470   Self().Remove(actor);
1471 }
1472
1473 void ItemView::ScrollTo(const Vector3& position, float duration)
1474 {
1475   Actor self = Self();
1476   const Vector3 layoutSize = Self().GetCurrentSize();
1477
1478   float firstItemScrollPosition = ClampFirstItemPosition(position.y, layoutSize, *mActiveLayout);
1479
1480   StartRefreshTimer();
1481
1482   if(duration > 0.0f)
1483   {
1484     RemoveAnimation(mScrollAnimation);
1485     mScrollAnimation = Animation::New(duration);
1486     mScrollAnimation.AnimateTo( Property(self, mPropertyLayoutPosition), firstItemScrollPosition, AlphaFunctions::EaseOut );
1487     mScrollAnimation.AnimateTo( Property(self, mPropertyPosition), GetScrollPosition(firstItemScrollPosition, layoutSize), AlphaFunctions::EaseOut );
1488     mScrollAnimation.FinishedSignal().Connect(this, &ItemView::OnScrollFinished);
1489     mScrollAnimation.Play();
1490   }
1491   else
1492   {
1493     self.SetProperty(mPropertyLayoutPosition, firstItemScrollPosition);
1494     AnimateScrollOvershoot(0.0f);
1495   }
1496
1497   mScrollStartedSignalV2.Emit(GetCurrentScrollPosition());
1498 }
1499
1500 void ItemView::ApplyOvershootOverlayConstraints()
1501 {
1502   Constraint constraint = Constraint::New<float>( Actor::SIZE_WIDTH,
1503                                                     ParentSource( mPropertyScrollDirection ),
1504                                                     ParentSource( mPropertyOvershoot ),
1505                                                     ParentSource( Actor::SIZE ),
1506                                                     OvershootOverlaySizeConstraint() );
1507   mOvershootOverlay.ApplyConstraint(constraint);
1508   mOvershootOverlay.SetSize(OVERSHOOT_BOUNCE_IMAGE_1_PIXEL_AREA.width, OVERSHOOT_BOUNCE_IMAGE_1_PIXEL_AREA.height);
1509
1510   constraint = Constraint::New<Quaternion>( Actor::ROTATION,
1511                                             ParentSource( mPropertyScrollDirection ),
1512                                             ParentSource( mPropertyOvershoot ),
1513                                             OvershootOverlayRotationConstraint() );
1514   mOvershootOverlay.ApplyConstraint(constraint);
1515
1516   constraint = Constraint::New<Vector3>( Actor::POSITION,
1517                                          ParentSource( Actor::SIZE ),
1518                                          ParentSource( mPropertyScrollDirection ),
1519                                          ParentSource( mPropertyOvershoot ),
1520                                          OvershootOverlayPositionConstraint() );
1521   mOvershootOverlay.ApplyConstraint(constraint);
1522
1523   constraint = Constraint::New<bool>( Actor::VISIBLE,
1524                                       ParentSource( mPropertyCanScrollVertical ),
1525                                       OvershootOverlayVisibilityConstraint() );
1526   mOvershootOverlay.ApplyConstraint(constraint);
1527
1528   int effectOvershootPropertyIndex = mOvershootEffect.GetPropertyIndex(mOvershootEffect.GetOvershootPropertyName());
1529   Actor self = Self();
1530   constraint = Constraint::New<float>( effectOvershootPropertyIndex,
1531                                        Source( self, mPropertyOvershoot ),
1532                                        EqualToConstraint() );
1533   mOvershootEffect.ApplyConstraint(constraint);
1534 }
1535
1536 float ItemView::CalculateScrollOvershoot()
1537 {
1538   float overshoot = 0.0f;
1539
1540   if(mActiveLayout)
1541   {
1542     // The overshoot must be calculated from the accumulated pan gesture displacement
1543     // since the pan gesture starts.
1544     Actor self = Self();
1545     float scrollDistance = CalculateScrollDistance(mTotalPanDisplacement, *mActiveLayout) * mActiveLayout->GetScrollSpeedFactor();
1546     float positionDelta = self.GetProperty<float>(mPropertyLayoutPosition) + scrollDistance;
1547     float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), Self().GetCurrentSize());
1548     self.SetProperty(mPropertyMinimumLayoutPosition, minLayoutPosition);
1549     float clamppedPosition = min(0.0f, max(minLayoutPosition, positionDelta));
1550     overshoot = positionDelta - clamppedPosition;
1551   }
1552
1553   return overshoot;
1554 }
1555
1556 void ItemView::AnimateScrollOvershoot(float overshootAmount, bool animateBack)
1557 {
1558   bool animatingOn = fabsf(overshootAmount) > Math::MACHINE_EPSILON_1;
1559
1560   // make sure we animate back if needed
1561   mAnimateOvershootOff = animateBack || (!animatingOn && mAnimatingOvershootOn);
1562
1563   if( mAnimatingOvershootOn )
1564   {
1565     // animating on, do not allow animate off
1566     return;
1567   }
1568
1569   Actor self = Self();
1570   float currentOvershoot = self.GetProperty<float>(mPropertyOvershoot);
1571   float duration = DEFAULT_OVERSHOOT_ANIMATION_DURATION * (animatingOn ? (1.0f - fabsf(currentOvershoot)) : fabsf(currentOvershoot));
1572
1573   RemoveAnimation(mScrollOvershootAnimation);
1574   mScrollOvershootAnimation = Animation::New(duration);
1575   mScrollOvershootAnimation.FinishedSignal().Connect(this, &ItemView::OnOvershootOnFinished);
1576   mScrollOvershootAnimation.AnimateTo( Property(self, mPropertyOvershoot), overshootAmount, TimePeriod(0.0f, duration) );
1577   mScrollOvershootAnimation.Play();
1578
1579   mAnimatingOvershootOn = animatingOn;
1580 }
1581
1582 } // namespace Internal
1583
1584 } // namespace Toolkit
1585
1586 } // namespace Dali