WheelEvent class pimpling
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / scrollable / item-view / item-view-impl.cpp
index ba2000b..939ab67 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 // EXTERNAL INCLUDES
 #include <cstring> // for strcmp
 #include <algorithm>
+#include <dali/public-api/actors/layer.h>
+
 #include <dali/public-api/animation/constraint.h>
 #include <dali/public-api/animation/constraints.h>
-#include <dali/devel-api/common/set-wrapper.h>
-#include <dali/public-api/common/stage.h>
+#include <dali/devel-api/common/stage.h>
 #include <dali/public-api/events/wheel-event.h>
 #include <dali/public-api/events/touch-event.h>
 #include <dali/public-api/object/type-registry.h>
-#include <dali/devel-api/object/type-registry-helper.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/devel-api/object/property-helper-devel.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/public-api/controls/scroll-bar/scroll-bar.h>
+#include <dali-toolkit/devel-api/controls/scroll-bar/scroll-bar.h>
 #include <dali-toolkit/public-api/controls/scrollable/item-view/item-factory.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout.h>
+#include <dali-toolkit/public-api/controls/scrollable/item-view/default-item-layout-property.h>
+#include <dali-toolkit/internal/controls/scrollable/item-view/grid-layout.h>
+#include <dali-toolkit/internal/controls/scrollable/item-view/depth-layout.h>
+#include <dali-toolkit/internal/controls/scrollable/item-view/spiral-layout.h>
 #include <dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.h>
 
 using std::string;
-using std::set;
 using namespace Dali;
 
 namespace // Unnamed namespace
@@ -60,6 +66,8 @@ const float OVERSHOOT_BOUNCE_ACTOR_RESIZE_THRESHOLD = 180.0f;
 const Vector4 OVERSHOOT_OVERLAY_NINE_PATCH_BORDER(0.0f, 0.0f, 1.0f, 12.0f);
 const float DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION = 0.2f;
 
+const unsigned int OVERSHOOT_SIZE_CONSTRAINT_TAG(42);
+
 /**
  * Local helper to convert pan distance (in actor coordinates) to the layout-specific scrolling direction
  */
@@ -250,6 +258,8 @@ DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "minimumSwipeDistance",       FLO
 DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "wheelScrollDistanceStep",    FLOAT,     WHEEL_SCROLL_DISTANCE_STEP   )
 DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "snapToItemEnabled",          BOOLEAN,   SNAP_TO_ITEM_ENABLED         )
 DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "refreshInterval",            FLOAT,     REFRESH_INTERVAL             )
+DALI_PROPERTY_REGISTRATION( Toolkit, ItemView, "layout",                     ARRAY,     LAYOUT                       )
+
 
 DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "layoutPosition",      FLOAT,    LAYOUT_POSITION)
 DALI_ANIMATABLE_PROPERTY_REGISTRATION( Toolkit, ItemView, "scrollSpeed",         FLOAT,    SCROLL_SPEED)
@@ -262,19 +272,47 @@ DALI_SIGNAL_REGISTRATION(              Toolkit, ItemView, "layoutActivated",
 
 DALI_ACTION_REGISTRATION(              Toolkit, ItemView, "stopScrolling",       ACTION_STOP_SCROLLING   )
 
+DALI_ACTION_REGISTRATION(              Toolkit, ItemView, "enableRefresh",       ACTION_ENABLE_REFRESH   )
+DALI_ACTION_REGISTRATION(              Toolkit, ItemView, "disableRefresh",      ACTION_DISABLE_REFRESH  )
+
 DALI_TYPE_REGISTRATION_END()
 
-bool FindById( const ItemContainer& items, ItemId id )
+const ItemIter FindItemById( ItemContainer& items, ItemId id )
 {
-  for( ConstItemIter iter = items.begin(); items.end() != iter; ++iter )
+  for( ItemIter iter = items.begin(); items.end() != iter; ++iter )
   {
     if( iter->first == id )
     {
-      return true;
+      return iter;
     }
   }
 
-  return false;
+  return items.end();
+}
+
+void InsertToItemContainer( ItemContainer& items, Item item )
+{
+  if( items.end() == FindItemById( items, item.first ) )
+  {
+    ItemIter iterToInsert = std::lower_bound( items.begin(), items.end(), item );
+    items.insert( iterToInsert, item );
+  }
+}
+
+
+/**
+  * Helper to apply size constraint to mOvershootOverlay
+  * @param[in] overshootOverlay The overshootOverlay actor
+  * @param[in] The required height
+  */
+void ApplyOvershootSizeConstraint( Actor overshootOverlay, float height )
+{
+  Constraint constraint = Constraint::New<Vector3>( overshootOverlay, Actor::Property::SIZE, OvershootOverlaySizeConstraint( height ) );
+  constraint.AddSource( ParentSource( Dali::Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
+  constraint.AddSource( ParentSource( Dali::Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
+  constraint.AddSource( ParentSource( Dali::Actor::Property::SIZE ) );
+  constraint.SetTag( OVERSHOOT_SIZE_CONSTRAINT_TAG );
+  constraint.Apply();
 }
 
 } // unnamed namespace
@@ -295,7 +333,7 @@ Dali::Toolkit::ItemView ItemView::New(ItemFactory& factory)
 }
 
 ItemView::ItemView(ItemFactory& factory)
-: Scrollable( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | REQUIRES_WHEEL_EVENTS | REQUIRES_KEYBOARD_NAVIGATION_SUPPORT ) ),
+: Scrollable( ControlBehaviour( DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS | REQUIRES_WHEEL_EVENTS | REQUIRES_KEYBOARD_NAVIGATION_SUPPORT ) ),
   mItemFactory(factory),
   mItemsParentOrigin(ParentOrigin::CENTER),
   mItemsAnchorPoint(AnchorPoint::CENTER),
@@ -317,6 +355,7 @@ ItemView::ItemView(ItemFactory& factory)
   mIsFlicking(false),
   mAddingItems(false),
   mRefreshEnabled(true),
+  mRefreshNotificationEnabled(true),
   mInAnimation(false)
 {
 }
@@ -328,6 +367,7 @@ void ItemView::OnInitialize()
   Vector2 stageSize = Stage::GetCurrent().GetSize();
   mWheelScrollDistanceStep = stageSize.y * DEFAULT_WHEEL_SCROLL_DISTANCE_STEP_PROPORTION;
 
+  self.TouchSignal().Connect( this, &ItemView::OnTouch );
   EnableGestureDetection(Gesture::Type(Gesture::Pan));
 
   mWheelEventFinishedTimer = Timer::New( WHEEL_EVENT_FINISHED_TIME_OUT );
@@ -374,7 +414,7 @@ ItemLayoutPtr ItemView::GetActiveLayout() const
 
 float ItemView::GetCurrentLayoutPosition(unsigned int itemId) const
 {
-  return Self().GetProperty<float>( Toolkit::ItemView::Property::LAYOUT_POSITION ) + static_cast<float>( itemId );
+  return Self().GetCurrentProperty< float >( Toolkit::ItemView::Property::LAYOUT_POSITION ) + static_cast<float>( itemId );
 }
 
 void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSize, float durationSeconds)
@@ -386,7 +426,7 @@ void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSiz
   Actor self = Self();
 
   // The ItemView size should match the active layout size
-  self.SetSize(targetSize);
+  self.SetProperty( Actor::Property::SIZE, targetSize);
   mActiveLayoutTargetSize = targetSize;
 
   // Switch to the new layout
@@ -394,7 +434,7 @@ void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSiz
 
   // Move the items to the new layout positions...
 
-  for (ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
+  for (ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
   {
     unsigned int itemId = iter->first;
     Actor actor = iter->second;
@@ -402,11 +442,11 @@ void ItemView::ActivateLayout(unsigned int layoutIndex, const Vector3& targetSiz
     // Remove constraints from previous layout
     actor.RemoveConstraints();
 
+    mActiveLayout->ApplyConstraints(actor, itemId, targetSize, Self() );
+
     Vector3 size;
     mActiveLayout->GetItemSize( itemId, targetSize, size );
-    actor.SetSize( size.GetVectorXY() );
-
-    mActiveLayout->ApplyConstraints(actor, itemId, targetSize, Self() );
+    actor.SetProperty( Actor::Property::SIZE, size.GetVectorXY() );
   }
 
   // Refresh the new layout
@@ -461,7 +501,7 @@ void ItemView::DeactivateCurrentLayout()
 {
   if (mActiveLayout)
   {
-    for (ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
+    for (ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
     {
       Actor actor = iter->second;
       actor.RemoveConstraints();
@@ -473,19 +513,22 @@ void ItemView::DeactivateCurrentLayout()
 
 void ItemView::OnRefreshNotification(PropertyNotification& source)
 {
-  // Cancel scroll animation to prevent any fighting of setting the scroll position property by scroll bar during fast scroll.
-  if(!mRefreshEnabled && mScrollAnimation)
+  if( mRefreshNotificationEnabled )
   {
-    RemoveAnimation(mScrollAnimation);
-  }
+    // Cancel scroll animation to prevent any fighting of setting the scroll position property by scroll bar during fast scroll.
+    if(!mRefreshEnabled && mScrollAnimation)
+    {
+      RemoveAnimation(mScrollAnimation);
+    }
 
-  // Only cache extra items when it is not a fast scroll
-  DoRefresh(GetCurrentLayoutPosition(0), mRefreshEnabled || mScrollAnimation);
+    // Only cache extra items when it is not a fast scroll
+    DoRefresh(GetCurrentLayoutPosition(0), mRefreshEnabled || mScrollAnimation);
+  }
 }
 
 void ItemView::Refresh()
 {
-  for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter )
+  for (ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter )
   {
     ReleaseActor( iter->first, iter->second );
   }
@@ -500,7 +543,7 @@ void ItemView::DoRefresh(float currentLayoutPosition, bool cacheExtra)
   {
     ItemRange range = GetItemRange(*mActiveLayout, mActiveLayoutTargetSize, currentLayoutPosition, cacheExtra/*reserve extra*/);
     RemoveActorsOutsideRange( range );
-    AddActorsWithinRange( range, Self().GetCurrentSize() );
+    AddActorsWithinRange( range, Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ) );
 
     mScrollUpdatedSignal.Emit( Vector2(0.0f, currentLayoutPosition) );
   }
@@ -586,10 +629,13 @@ Actor ItemView::GetItem(unsigned int itemId) const
 {
   Actor actor;
 
-  ConstItemPoolIter iter = mItemPool.find( itemId );
-  if( iter != mItemPool.end() )
+  for ( ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter )
   {
-    actor = iter->second;
+    if( iter->first == itemId )
+    {
+      actor = iter->second;
+      break;
+    }
   }
 
   return actor;
@@ -599,7 +645,7 @@ unsigned int ItemView::GetItemId( Actor actor ) const
 {
   unsigned int itemId( 0 );
 
-  for ( ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter )
+  for ( ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter )
   {
     if( iter->second == actor )
     {
@@ -614,12 +660,12 @@ unsigned int ItemView::GetItemId( Actor actor ) const
 void ItemView::InsertItem( Item newItem, float durationSeconds )
 {
   mAddingItems = true;
-  Vector3 layoutSize = Self().GetCurrentSize();
+  Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
 
   Actor displacedActor;
-  ItemPoolIter afterDisplacedIter = mItemPool.end();
+  ItemIter afterDisplacedIter = mItemPool.end();
 
-  ItemPoolIter foundIter = mItemPool.find( newItem.first );
+  ItemIter foundIter = FindItemById( mItemPool, newItem.first );
   if( mItemPool.end() != foundIter )
   {
     SetupActor( newItem, layoutSize );
@@ -633,12 +679,12 @@ void ItemView::InsertItem( Item newItem, float durationSeconds )
   else
   {
     // Inserting before the existing item range?
-    ItemPoolIter iter = mItemPool.begin();
+    ItemIter iter = mItemPool.begin();
     if( iter != mItemPool.end() &&
         iter->first > newItem.first )
     {
       displacedActor = iter->second;
-      mItemPool.erase( iter++ ); // iter is still valid after the erase
+      iter = mItemPool.erase( iter ); // iter is still valid after the erase
 
       afterDisplacedIter = iter;
     }
@@ -647,7 +693,7 @@ void ItemView::InsertItem( Item newItem, float durationSeconds )
   if( displacedActor )
   {
     // Move the existing actors to make room
-    for( ItemPoolIter iter = afterDisplacedIter; mItemPool.end() != iter; ++iter )
+    for( ItemIter iter = afterDisplacedIter; mItemPool.end() != iter; ++iter )
     {
       Actor temp = iter->second;
       iter->second = displacedActor;
@@ -658,12 +704,12 @@ void ItemView::InsertItem( Item newItem, float durationSeconds )
     }
 
     // Create last item
-    ItemPool::reverse_iterator lastIter = mItemPool.rbegin();
+    ItemContainer::reverse_iterator lastIter = mItemPool.rbegin();
     if ( lastIter != mItemPool.rend() )
     {
       ItemId lastId = lastIter->first;
       Item lastItem( lastId + 1, displacedActor );
-      mItemPool.insert( lastItem );
+      InsertToItemContainer( mItemPool, lastItem );
 
       lastItem.second.RemoveConstraints();
       mActiveLayout->ApplyConstraints( lastItem.second, lastItem.first, layoutSize, Self() );
@@ -678,27 +724,24 @@ void ItemView::InsertItem( Item newItem, float durationSeconds )
 void ItemView::InsertItems( const ItemContainer& newItems, float durationSeconds )
 {
   mAddingItems = true;
-  Vector3 layoutSize = Self().GetCurrentSize();
+  Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
 
   // Insert from lowest id to highest
-  std::set<Item> sortedItems;
-  for( ConstItemIter iter = newItems.begin(); newItems.end() != iter; ++iter )
-  {
-    sortedItems.insert( *iter );
-  }
+  ItemContainer sortedItems(newItems);
+  std::sort( sortedItems.begin(), sortedItems.end() );
 
-  for( std::set<Item>::iterator iter = sortedItems.begin(); sortedItems.end() != iter; ++iter )
+  for( ItemIter iter = sortedItems.begin(); sortedItems.end() != iter; ++iter )
   {
     Self().Add( iter->second );
 
-    ItemPoolIter foundIter = mItemPool.find( iter->first );
+    ItemIter foundIter = FindItemById( mItemPool, iter->first );
     if( mItemPool.end() != foundIter )
     {
       Actor moveMe = foundIter->second;
       foundIter->second = iter->second;
 
       // Move the existing actors to make room
-      for( ItemPoolIter iter = ++foundIter; mItemPool.end() != iter; ++iter )
+      for( ItemIter iter = ++foundIter; mItemPool.end() != iter; ++iter )
       {
         Actor temp = iter->second;
         iter->second = moveMe;
@@ -708,19 +751,19 @@ void ItemView::InsertItems( const ItemContainer& newItems, float durationSeconds
       // Create last item
       ItemId lastId = mItemPool.rbegin()->first;
       Item lastItem( lastId + 1, moveMe );
-      mItemPool.insert( lastItem );
+      InsertToItemContainer( mItemPool, lastItem );
     }
     else
     {
-      mItemPool.insert( *iter );
+      InsertToItemContainer( mItemPool, *iter );
     }
   }
 
   // Relayout everything
-  for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
+  for (ItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
   {
     // If newly inserted
-    if( FindById( newItems, iter->first ) )
+    if( std::binary_search( sortedItems.begin(), sortedItems.end(), *iter ) )
     {
       SetupActor( *iter, layoutSize );
     }
@@ -752,13 +795,10 @@ void ItemView::RemoveItems( const ItemIdContainer& itemIds, float durationSecond
   bool actorsReordered( false );
 
   // Remove from highest id to lowest
-  set<ItemId> sortedItems;
-  for( ConstItemIdIter iter = itemIds.begin(); itemIds.end() != iter; ++iter )
-  {
-    sortedItems.insert( *iter );
-  }
+  ItemIdContainer sortedItems(itemIds);
+  std::sort( sortedItems.begin(), sortedItems.end() );
 
-  for( set<ItemId>::reverse_iterator iter = sortedItems.rbegin(); sortedItems.rend() != iter; ++iter )
+  for( ItemIdContainer::reverse_iterator iter = sortedItems.rbegin(); sortedItems.rend() != iter; ++iter )
   {
     if( RemoveActor( *iter ) )
     {
@@ -778,7 +818,7 @@ bool ItemView::RemoveActor(unsigned int itemId)
 {
   bool reordered( false );
 
-  ItemPoolIter removeIter = mItemPool.find( itemId );
+  ItemIter removeIter = FindItemById( mItemPool, itemId );
   if( removeIter != mItemPool.end() )
   {
     ReleaseActor(itemId, removeIter->second);
@@ -786,12 +826,12 @@ bool ItemView::RemoveActor(unsigned int itemId)
   else
   {
     // Removing before the existing item range?
-    ItemPoolIter iter = mItemPool.begin();
+    ItemIter iter = mItemPool.begin();
     if( iter != mItemPool.end() &&
         iter->first > itemId )
     {
       // In order to decrement the first visible item ID
-      mItemPool.insert( Item(iter->first - 1, Actor()) );
+      InsertToItemContainer( mItemPool, Item(iter->first - 1, Actor()) );
 
       removeIter = mItemPool.begin();
     }
@@ -807,11 +847,11 @@ bool ItemView::RemoveActor(unsigned int itemId)
     //     ID 2 - ActorB       ID 2 - ActorC (previously ID 3)
     //     ID 3 - ActorC       ID 3 - ActorB (previously ID 4)
     //     ID 4 - ActorD
-    for (ItemPoolIter iter = removeIter; iter != mItemPool.end(); ++iter)
+    for (ItemIter iter = removeIter; iter != mItemPool.end(); ++iter)
     {
       if( iter->first < mItemPool.rbegin()->first )
       {
-        iter->second = mItemPool[ iter->first + 1 ];
+        iter->second = ( iter + 1 )->second;
       }
       else
       {
@@ -827,12 +867,12 @@ bool ItemView::RemoveActor(unsigned int itemId)
 void ItemView::ReplaceItem( Item replacementItem, float durationSeconds )
 {
   mAddingItems = true;
-  Vector3 layoutSize = Self().GetCurrentSize();
+  Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
 
   SetupActor( replacementItem, layoutSize );
   Self().Add( replacementItem.second );
 
-  const ItemPoolIter iter = mItemPool.find( replacementItem.first );
+  const ItemIter iter = FindItemById( mItemPool, replacementItem.first );
   if( mItemPool.end() != iter )
   {
     ReleaseActor(iter->first, iter->second);
@@ -840,7 +880,7 @@ void ItemView::ReplaceItem( Item replacementItem, float durationSeconds )
   }
   else
   {
-    mItemPool.insert( replacementItem );
+    InsertToItemContainer( mItemPool, replacementItem );
   }
 
   CalculateDomainSize( layoutSize );
@@ -859,7 +899,7 @@ void ItemView::ReplaceItems( const ItemContainer& replacementItems, float durati
 void ItemView::RemoveActorsOutsideRange( ItemRange range )
 {
   // Remove unwanted actors from the ItemView & ItemPool
-  for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); )
+  for (ItemIter iter = mItemPool.begin(); iter != mItemPool.end(); )
   {
     unsigned int current = iter->first;
 
@@ -867,7 +907,7 @@ void ItemView::RemoveActorsOutsideRange( ItemRange range )
     {
       ReleaseActor(iter->first, iter->second);
 
-      mItemPool.erase( iter++ ); // erase invalidates the return value of post-increment; iter remains valid
+      iter = mItemPool.erase( iter ); // iter is still valid after the erase
     }
     else
     {
@@ -898,14 +938,14 @@ void ItemView::AddActorsWithinRange( ItemRange range, const Vector3& layoutSize
 
   // Total number of items may change dynamically.
   // Always recalculate the domain size to reflect that.
-  CalculateDomainSize(Self().GetCurrentSize());
+  CalculateDomainSize(Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ));
 }
 
 void ItemView::AddNewActor( unsigned int itemId, const Vector3& layoutSize )
 {
   mAddingItems = true;
 
-  if( mItemPool.end() == mItemPool.find( itemId ) )
+  if( mItemPool.end() == FindItemById( mItemPool, itemId ) )
   {
     Actor actor = mItemFactory.NewItem( itemId );
 
@@ -913,7 +953,7 @@ void ItemView::AddNewActor( unsigned int itemId, const Vector3& layoutSize )
     {
       Item newItem( itemId, actor );
 
-      mItemPool.insert( newItem );
+      InsertToItemContainer( mItemPool, newItem );
 
       SetupActor( newItem, layoutSize );
       Self().Add( actor );
@@ -925,14 +965,14 @@ void ItemView::AddNewActor( unsigned int itemId, const Vector3& layoutSize )
 
 void ItemView::SetupActor( Item item, const Vector3& layoutSize )
 {
-  item.second.SetParentOrigin( mItemsParentOrigin );
-  item.second.SetAnchorPoint( mItemsAnchorPoint );
+  item.second.SetProperty( Actor::Property::PARENT_ORIGIN, mItemsParentOrigin );
+  item.second.SetProperty( Actor::Property::ANCHOR_POINT, mItemsAnchorPoint );
 
   if( mActiveLayout )
   {
     Vector3 size;
     mActiveLayout->GetItemSize( item.first, mActiveLayoutTargetSize, size );
-    item.second.SetSize( size.GetVectorXY() );
+    item.second.SetProperty( Actor::Property::SIZE, size.GetVectorXY() );
 
     mActiveLayout->ApplyConstraints( item.second, item.first, layoutSize, Self() );
   }
@@ -978,37 +1018,8 @@ void ItemView::OnChildAdd(Actor& child)
                                         Toolkit::ItemView::Property::SCROLL_CONTENT_SIZE);
     }
   }
-}
-
-bool ItemView::OnTouchEvent(const TouchEvent& event)
-{
-  // Ignore events with multiple-touch points
-  if (event.GetPointCount() != 1)
-  {
-    return false;
-  }
 
-  if (event.GetPoint(0).state == TouchPoint::Down)
-  {
-    // Cancel ongoing scrolling etc.
-    mGestureState = Gesture::Clear;
-
-    mScrollDistance = 0.0f;
-    mScrollSpeed = 0.0f;
-    Self().SetProperty(Toolkit::ItemView::Property::SCROLL_SPEED, mScrollSpeed);
-
-    mScrollOvershoot = 0.0f;
-    AnimateScrollOvershoot(0.0f);
-
-    if(mScrollAnimation)
-    {
-      mScrollCompletedSignal.Emit(GetCurrentScrollPosition());
-    }
-
-    RemoveAnimation(mScrollAnimation);
-  }
-
-  return true; // consume since we're potentially scrolling
+  Scrollable::OnChildAdd( child );
 }
 
 bool ItemView::OnWheelEvent(const WheelEvent& event)
@@ -1017,8 +1028,8 @@ bool ItemView::OnWheelEvent(const WheelEvent& event)
   if (mActiveLayout)
   {
     Actor self = Self();
-    const Vector3 layoutSize = Self().GetCurrentSize();
-    float layoutPositionDelta = GetCurrentLayoutPosition(0) - (event.z * mWheelScrollDistanceStep * mActiveLayout->GetScrollSpeedFactor());
+    const Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
+    float layoutPositionDelta = GetCurrentLayoutPosition(0) - (event.GetDelta() * mWheelScrollDistanceStep * mActiveLayout->GetScrollSpeedFactor());
     float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout);
 
     self.SetProperty(Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition );
@@ -1064,9 +1075,9 @@ bool ItemView::OnWheelEventFinished()
 
 void ItemView::ReapplyAllConstraints()
 {
-  Vector3 layoutSize = Self().GetCurrentSize();
+  Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
 
-  for (ConstItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
+  for (ConstItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
   {
     unsigned int id = iter->first;
     Actor actor = iter->second;
@@ -1078,12 +1089,12 @@ void ItemView::ReapplyAllConstraints()
 
 void ItemView::OnItemsRemoved()
 {
-  CalculateDomainSize(Self().GetCurrentSize());
+  CalculateDomainSize(Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ));
 
   // Adjust scroll-position after an item is removed
   if( mActiveLayout )
   {
-    float firstItemScrollPosition = ClampFirstItemPosition(GetCurrentLayoutPosition(0), Self().GetCurrentSize(), *mActiveLayout);
+    float firstItemScrollPosition = ClampFirstItemPosition(GetCurrentLayoutPosition(0), Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ), *mActiveLayout);
     Self().SetProperty( Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition );
   }
 }
@@ -1103,10 +1114,41 @@ float ItemView::ClampFirstItemPosition( float targetPosition, const Vector3& tar
   return clamppedPosition;
 }
 
+bool ItemView::OnTouch( Actor actor, const TouchEvent& touch )
+{
+  // Ignore events with multiple-touch points
+  if (touch.GetPointCount() != 1)
+  {
+    return false;
+  }
+
+  if ( touch.GetState( 0 ) == PointState::DOWN )
+  {
+    // Cancel ongoing scrolling etc.
+    mGestureState = Gesture::Clear;
+
+    mScrollDistance = 0.0f;
+    mScrollSpeed = 0.0f;
+    Self().SetProperty(Toolkit::ItemView::Property::SCROLL_SPEED, mScrollSpeed);
+
+    mScrollOvershoot = 0.0f;
+    AnimateScrollOvershoot(0.0f);
+
+    if(mScrollAnimation)
+    {
+      mScrollCompletedSignal.Emit(GetCurrentScrollPosition());
+    }
+
+    RemoveAnimation(mScrollAnimation);
+  }
+
+  return false; // Do not consume as we're potentially scrolling (detecting pan gestures)
+}
+
 void ItemView::OnPan( const PanGesture& gesture )
 {
   Actor self = Self();
-  const Vector3 layoutSize = Self().GetCurrentSize();
+  const Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
 
   RemoveAnimation(mScrollAnimation);
 
@@ -1151,10 +1193,12 @@ void ItemView::OnPan( const PanGesture& gesture )
         mScrollAnimation.AnimateTo( Property(self, Toolkit::ItemView::Property::SCROLL_SPEED), 0.0f, AlphaFunction::EASE_OUT );
 
         mIsFlicking = true;
+
         // Check whether it has already scrolled to the end
-        if(fabs(currentLayoutPosition - firstItemScrollPosition) > Math::MACHINE_EPSILON_0)
+        if( fabs(currentLayoutPosition - firstItemScrollPosition) < Math::MACHINE_EPSILON_0 )
         {
-          AnimateScrollOvershoot(0.0f);
+          AnimateScrollOvershoot( 0.0f );
+          RemoveAnimation( mScrollAnimation );
         }
       }
 
@@ -1193,7 +1237,7 @@ void ItemView::OnPan( const PanGesture& gesture )
 
       float firstItemScrollPosition = ClampFirstItemPosition(layoutPositionDelta, layoutSize, *mActiveLayout);
 
-      float currentOvershoot = self.GetProperty<float>(Toolkit::ItemView::Property::OVERSHOOT);
+      float currentOvershoot = self.GetCurrentProperty< float >( Toolkit::ItemView::Property::OVERSHOOT );
 
       self.SetProperty(Toolkit::ItemView::Property::LAYOUT_POSITION, firstItemScrollPosition );
 
@@ -1279,7 +1323,7 @@ Actor ItemView::GetNextKeyboardFocusableActor(Actor actor, Toolkit::Control::Key
       }
     }
     float layoutPosition = mActiveLayout->GetClosestAnchorPosition( GetCurrentLayoutPosition(0) );
-    Vector3 layoutSize = Self().GetCurrentSize();
+    Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
     if(!nextFocusActor)
     {
       // likely the current item is not buffered, so not in our item pool, probably best to get first viewable item
@@ -1298,7 +1342,7 @@ void ItemView::OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor)
   {
     int nextItemID = GetItemId(commitedFocusableActor);
     float layoutPosition = GetCurrentLayoutPosition(0);
-    Vector3 layoutSize = Self().GetCurrentSize();
+    Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
 
     float scrollTo = mActiveLayout->GetClosestOnScreenLayoutPosition(nextItemID, layoutPosition, layoutSize);
     ScrollTo(Vector2(0.0f, scrollTo), DEFAULT_KEYBOARD_FOCUS_SCROLL_DURATION);
@@ -1373,7 +1417,7 @@ void ItemView::OnOvershootOnFinished(Animation& animation)
 void ItemView::ScrollToItem(unsigned int itemId, float durationSeconds)
 {
   Actor self = Self();
-  const Vector3 layoutSize = Self().GetCurrentSize();
+  const Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
   float firstItemScrollPosition = ClampFirstItemPosition(mActiveLayout->GetItemScrollToPosition(itemId), layoutSize, *mActiveLayout);
 
   if(durationSeconds > 0.0f)
@@ -1440,16 +1484,6 @@ void ItemView::CalculateDomainSize(const Vector3& layoutSize)
   }
 }
 
-Vector2 ItemView::GetDomainSize() const
-{
-  Actor self = Self();
-
-  float minScrollPosition = self.GetProperty<float>(Toolkit::Scrollable::Property::SCROLL_POSITION_MIN_Y);
-  float maxScrollPosition = self.GetProperty<float>(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX_Y);
-
-  return Vector2(0.0f, fabs(GetScrollPosition(minScrollPosition, self.GetCurrentSize()) - GetScrollPosition(-maxScrollPosition, self.GetCurrentSize())));
-}
-
 bool ItemView::IsLayoutScrollable(const Vector3& layoutSize)
 {
   Actor self = Self();
@@ -1469,12 +1503,12 @@ float ItemView::GetScrollPosition(float layoutPosition, const Vector3& layoutSiz
 
 Vector2 ItemView::GetCurrentScrollPosition() const
 {
-  return Vector2(0.0f, GetScrollPosition(GetCurrentLayoutPosition(0), Self().GetCurrentSize()));
+  return Vector2(0.0f, GetScrollPosition(GetCurrentLayoutPosition(0), Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE )));
 }
 
 void ItemView::AddOverlay(Actor actor)
 {
-  actor.SetDrawMode( DrawMode::OVERLAY_2D );
+  actor.SetProperty( Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D );
   Self().Add(actor);
 }
 
@@ -1486,7 +1520,7 @@ void ItemView::RemoveOverlay(Actor actor)
 void ItemView::ScrollTo(const Vector2& position, float duration)
 {
   Actor self = Self();
-  const Vector3 layoutSize = Self().GetCurrentSize();
+  const Vector3 layoutSize = Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE );
 
   float firstItemScrollPosition = ClampFirstItemPosition(position.y, layoutSize, *mActiveLayout);
 
@@ -1508,12 +1542,24 @@ void ItemView::ScrollTo(const Vector2& position, float duration)
   mRefreshEnabled = true;
 }
 
+void ItemView::SetOvershootSize( const Vector2& size )
+{
+  mOvershootSize = size;
+
+  if( mOvershootOverlay )
+  {
+    // Remove old & add new size constraint
+    mOvershootOverlay.RemoveConstraints( OVERSHOOT_SIZE_CONSTRAINT_TAG );
+    ApplyOvershootSizeConstraint( mOvershootOverlay, mOvershootSize.height );
+  }
+}
+
 void ItemView::SetOvershootEffectColor( const Vector4& color )
 {
   mOvershootEffectColor = color;
   if( mOvershootOverlay )
   {
-    mOvershootOverlay.SetColor( color );
+    mOvershootOverlay.SetProperty( Actor::Property::COLOR, color );
   }
 }
 
@@ -1526,21 +1572,15 @@ void ItemView::EnableScrollOvershoot( bool enable )
     {
       Property::Index effectOvershootPropertyIndex = Property::INVALID_INDEX;
       mOvershootOverlay = CreateBouncingEffectActor( effectOvershootPropertyIndex );
-      mOvershootOverlay.SetColor(mOvershootEffectColor);
-      mOvershootOverlay.SetParentOrigin(ParentOrigin::TOP_LEFT);
-      mOvershootOverlay.SetAnchorPoint(AnchorPoint::TOP_LEFT);
-      mOvershootOverlay.SetDrawMode( DrawMode::OVERLAY_2D );
+      mOvershootOverlay.SetProperty( Actor::Property::COLOR,mOvershootEffectColor);
+      mOvershootOverlay.SetProperty( Actor::Property::PARENT_ORIGIN,ParentOrigin::TOP_LEFT );
+      mOvershootOverlay.SetProperty( Actor::Property::ANCHOR_POINT,AnchorPoint::TOP_LEFT);
+      mOvershootOverlay.SetProperty( Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D );
       self.Add(mOvershootOverlay);
 
-      Constraint constraint = Constraint::New<Vector3>( mOvershootOverlay, Actor::Property::SIZE, OvershootOverlaySizeConstraint(mOvershootSize.height) );
-      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
-      constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
-      constraint.AddSource( ParentSource( Actor::Property::SIZE ) );
-      constraint.Apply();
-
-      mOvershootOverlay.SetSize(mOvershootSize.width, mOvershootSize.height);
+      ApplyOvershootSizeConstraint( mOvershootOverlay, mOvershootSize.height );
 
-      constraint = Constraint::New<Quaternion>( mOvershootOverlay, Actor::Property::ORIENTATION, OvershootOverlayRotationConstraint );
+      Constraint constraint = Constraint::New<Quaternion>( mOvershootOverlay, Actor::Property::ORIENTATION, OvershootOverlayRotationConstraint );
       constraint.AddSource( ParentSource( Toolkit::ItemView::Property::SCROLL_DIRECTION ) );
       constraint.AddSource( ParentSource( Toolkit::ItemView::Property::LAYOUT_ORIENTATION ) );
       constraint.AddSource( ParentSource( Toolkit::ItemView::Property::OVERSHOOT ) );
@@ -1583,7 +1623,7 @@ float ItemView::CalculateScrollOvershoot()
     Actor self = Self();
     float scrollDistance = CalculateScrollDistance(mTotalPanDisplacement, *mActiveLayout) * mActiveLayout->GetScrollSpeedFactor();
     float positionDelta = GetCurrentLayoutPosition(0) + scrollDistance;
-    float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), Self().GetCurrentSize());
+    float minLayoutPosition = mActiveLayout->GetMinimumLayoutPosition(mItemFactory.GetNumberOfItems(), Self().GetCurrentProperty< Vector3 >( Actor::Property::SIZE ));
     self.SetProperty(Toolkit::Scrollable::Property::SCROLL_POSITION_MAX, Vector2(0.0f, -minLayoutPosition));
     float clamppedPosition = std::min(0.0f, std::max(minLayoutPosition, positionDelta));
     overshoot = positionDelta - clamppedPosition;
@@ -1609,12 +1649,12 @@ void ItemView::AnimateScrollOvershoot(float overshootAmount, bool animateBack)
 
   if(mOvershootAnimationSpeed > Math::MACHINE_EPSILON_0)
   {
-    float currentOvershoot = self.GetProperty<float>(Toolkit::ItemView::Property::OVERSHOOT);
+    float currentOvershoot = self.GetCurrentProperty< float >( Toolkit::ItemView::Property::OVERSHOOT );
     float duration = 0.0f;
 
     if (mOvershootOverlay)
     {
-      duration = mOvershootOverlay.GetCurrentSize().height * (animatingOn ? (1.0f - fabsf(currentOvershoot)) : fabsf(currentOvershoot)) / mOvershootAnimationSpeed;
+      duration = mOvershootOverlay.GetCurrentProperty< Vector3 >( Actor::Property::SIZE ).height * (animatingOn ? (1.0f - fabsf(currentOvershoot)) : fabsf(currentOvershoot)) / mOvershootAnimationSpeed;
     }
 
     // Mark the animation as in progress to prevent manual property sets overwriting it.
@@ -1637,9 +1677,9 @@ void ItemView::SetItemsParentOrigin( const Vector3& parentOrigin )
   if( parentOrigin != mItemsParentOrigin )
   {
     mItemsParentOrigin = parentOrigin;
-    for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
+    for (ItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
     {
-      iter->second.SetParentOrigin(parentOrigin);
+      iter->second.SetProperty( Actor::Property::PARENT_ORIGIN,parentOrigin );
     }
   }
 }
@@ -1654,9 +1694,9 @@ void ItemView::SetItemsAnchorPoint( const Vector3& anchorPoint )
   if( anchorPoint != mItemsAnchorPoint )
   {
     mItemsAnchorPoint = anchorPoint;
-    for (ItemPoolIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
+    for (ItemIter iter = mItemPool.begin(); iter != mItemPool.end(); ++iter)
     {
-      iter->second.SetAnchorPoint(anchorPoint);
+      iter->second.SetProperty( Actor::Property::ANCHOR_POINT,anchorPoint);
     }
   }
 }
@@ -1714,26 +1754,119 @@ void ItemView::SetProperty( BaseObject* object, Property::Index index, const Pro
         itemViewImpl.SetMinimumSwipeSpeed( value.Get<float>() );
         break;
       }
+
       case Toolkit::ItemView::Property::MINIMUM_SWIPE_DISTANCE:
       {
         itemViewImpl.SetMinimumSwipeDistance( value.Get<float>() );
         break;
       }
+
       case Toolkit::ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP:
       {
         itemViewImpl.SetWheelScrollDistanceStep( value.Get<float>() );
         break;
       }
+
       case Toolkit::ItemView::Property::SNAP_TO_ITEM_ENABLED:
       {
         itemViewImpl.SetAnchoring( value.Get<bool>() );
         break;
       }
+
       case Toolkit::ItemView::Property::REFRESH_INTERVAL:
       {
         itemViewImpl.SetRefreshInterval( value.Get<float>() );
         break;
       }
+
+      case Toolkit::ItemView::Property::LAYOUT:
+      {
+        // Get a Property::Array from the property if possible.
+        Property::Array layoutArray;
+        if( value.Get( layoutArray ) )
+        {
+          itemViewImpl.SetLayoutArray( layoutArray );
+        }
+        break;
+      }
+    }
+  }
+}
+
+Property::Array ItemView::GetLayoutArray()
+{
+  return mlayoutArray;
+}
+
+void ItemView::SetLayoutArray( const Property::Array& layouts )
+{
+  mlayoutArray = layouts;
+  const int layoutCount = GetLayoutCount();
+  if( layoutCount > 0 )
+  {
+    for(int index = layoutCount - 1; index >= 0; --index)
+    {
+      RemoveLayout(index);
+      if(index == 0) break;
+    }
+  }
+
+  for( unsigned int arrayIdx = 0, arrayCount = layouts.Count(); arrayIdx < arrayCount; ++arrayIdx )
+  {
+    const Property::Value& element = layouts.GetElementAt( arrayIdx );
+
+    Property::Map* layout = element.GetMap();
+    if( layout != NULL )
+    {
+      for( unsigned int mapIdx = 0, mapCount = (*layout).Count(); mapIdx < mapCount; ++mapIdx )
+      {
+        KeyValuePair propertyPair( (*layout).GetKeyValue( mapIdx ) );
+
+        if(propertyPair.first == DefaultItemLayoutProperty::TYPE)
+        {
+          int layoutType = propertyPair.second.Get<int>();
+          if(layoutType <= DefaultItemLayout::SPIRAL && layoutType >= DefaultItemLayout::DEPTH)
+          {
+            //DEPTH, GRID, LIST, SPIRAL
+            switch(DefaultItemLayout::Type(layoutType))
+            {
+              case DefaultItemLayout::DEPTH:
+              {
+                Internal::DepthLayoutPtr depthLayout = Internal::DepthLayout::New();
+                (*depthLayout).SetLayoutProperties(*layout);
+                (*depthLayout).SetDepthLayoutProperties(*layout);
+                AddLayout(*depthLayout);
+                break;
+              }
+              case DefaultItemLayout::GRID:
+              {
+                Internal::GridLayoutPtr gridLayout = Internal::GridLayout::New();
+                (*gridLayout).SetLayoutProperties(*layout);
+                (*gridLayout).SetGridLayoutProperties(*layout);
+                AddLayout(*gridLayout);
+                break;
+              }
+              case DefaultItemLayout::LIST:
+              {
+                Internal::GridLayoutPtr listLayout = Internal::GridLayout::New();
+                listLayout->SetNumberOfColumns( 1 );
+                (*listLayout).SetLayoutProperties(*layout);
+                (*listLayout).SetGridLayoutProperties(*layout);
+                AddLayout(*listLayout);
+                break;
+              }
+              case DefaultItemLayout::SPIRAL:
+              {
+                Internal::SpiralLayoutPtr spiralLayout = Internal::SpiralLayout::New();
+                (*spiralLayout).SetLayoutProperties(*layout);
+                (*spiralLayout).SetSpiralLayoutProperties(*layout);
+                AddLayout(*spiralLayout);
+                break;
+              }
+            }
+          }
+        }
+      }
     }
   }
 }
@@ -1754,26 +1887,37 @@ Property::Value ItemView::GetProperty( BaseObject* object, Property::Index index
         value = itemViewImpl.GetMinimumSwipeSpeed();
         break;
       }
+
       case Toolkit::ItemView::Property::MINIMUM_SWIPE_DISTANCE:
       {
         value = itemViewImpl.GetMinimumSwipeDistance();
         break;
       }
+
       case Toolkit::ItemView::Property::WHEEL_SCROLL_DISTANCE_STEP:
       {
         value = itemViewImpl.GetWheelScrollDistanceStep();
         break;
       }
+
       case Toolkit::ItemView::Property::SNAP_TO_ITEM_ENABLED:
       {
         value = itemViewImpl.GetAnchoring();
         break;
       }
+
       case Toolkit::ItemView::Property::REFRESH_INTERVAL:
       {
         value = itemViewImpl.GetRefreshInterval();
         break;
       }
+
+      case Toolkit::ItemView::Property::LAYOUT:
+      {
+        Property::Array layouts= itemViewImpl.GetLayoutArray();
+        value = layouts;
+        break;
+      }
     }
   }
 
@@ -1792,6 +1936,14 @@ bool ItemView::DoAction( BaseObject* object, const std::string& actionName, cons
   {
     GetImpl( itemView ).DoStopScrolling();
   }
+  else if ( 0 == strcmp( actionName.c_str(), ACTION_ENABLE_REFRESH ) )
+  {
+    GetImpl( itemView ).SetRefreshNotificationEnabled( true );
+  }
+  else if ( 0 == strcmp( actionName.c_str(), ACTION_DISABLE_REFRESH ) )
+  {
+    GetImpl( itemView ).SetRefreshNotificationEnabled( false );
+  }
 
   return true;
 }
@@ -1805,6 +1957,11 @@ void ItemView::DoStopScrolling()
   }
 }
 
+void ItemView::SetRefreshNotificationEnabled( bool enabled )
+{
+  mRefreshNotificationEnabled = enabled;
+}
+
 } // namespace Internal
 
 } // namespace Toolkit