Moved Core Rendering API from devel-api to public-api
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / decorator / text-decorator.cpp
index 5d3976c..a33a9bc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 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 <dali/integration-api/debug.h>
-
-#include <dali/public-api/adaptor-framework/timer.h>
 #include <dali/public-api/actors/layer.h>
+#include <dali/public-api/adaptor-framework/timer.h>
 #include <dali/public-api/common/stage.h>
-#include <dali/public-api/events/touch-event.h>
+#include <dali/public-api/events/touch-data.h>
 #include <dali/public-api/events/pan-gesture.h>
 #include <dali/public-api/images/resource-image.h>
 #include <dali/public-api/object/property-notification.h>
-
-#include <dali/devel-api/rendering/geometry.h>
-#include <dali/devel-api/rendering/renderer.h>
+#include <dali/public-api/rendering/geometry.h>
+#include <dali/public-api/rendering/renderer.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/public-api/controls/control-depth-index-ranges.h>
-#include <dali-toolkit/public-api/controls/default-controls/solid-color-actor.h>
+#include <dali-toolkit/public-api/controls/image-view/image-view.h>
+#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
+#include <dali-toolkit/internal/controls/image-view/image-view-impl.h>
 
 #ifdef DEBUG_ENABLED
 #define DECORATOR_DEBUG
@@ -92,17 +91,17 @@ const Dali::Vector4 LIGHT_BLUE( 0.75f, 0.96f, 1.f, 1.f ); // The text highlight
 
 const Dali::Vector4 HANDLE_COLOR( 0.0f, (183.0f / 255.0f), (229.0f / 255.0f), 1.0f  );
 
-const unsigned int CURSOR_BLINK_INTERVAL = 500u; // Cursor blink interval
-const float TO_MILLISECONDS = 1000.f;
-const float TO_SECONDS = 1.f / TO_MILLISECONDS;
+const unsigned int CURSOR_BLINK_INTERVAL = 500u; ///< Cursor blink interval in milliseconds.
+const float TO_MILLISECONDS = 1000.f;            ///< Converts from seconds to milliseconds.
+const float TO_SECONDS = 1.f / TO_MILLISECONDS;  ///< Converts from milliseconds to seconds.
 
-const unsigned int SCROLL_TICK_INTERVAL = 50u;
+const unsigned int SCROLL_TICK_INTERVAL = 50u; ///< Scroll interval in milliseconds.
+const float SCROLL_THRESHOLD = 10.f;           ///< Threshold in pixels close to the edges of the decorator boundaries from where the scroll timer starts to emit signals.
+const float SCROLL_SPEED = 300.f;              ///< The scroll speed in pixels/second.
 
-const float SCROLL_THRESHOLD = 10.f;
-const float SCROLL_SPEED = 300.f;
-const float SCROLL_DISTANCE = SCROLL_SPEED * SCROLL_TICK_INTERVAL * TO_SECONDS;
+const float SCROLL_DISTANCE = SCROLL_SPEED * SCROLL_TICK_INTERVAL * TO_SECONDS; ///< Distance in pixels scrolled in one second.
 
-const float CURSOR_WIDTH = 1.f;
+const float CURSOR_WIDTH = 1.f; ///< The cursor's width in pixels.
 
 /**
  * structure to hold coordinates of each quad, which will make up the mesh.
@@ -207,6 +206,7 @@ struct Decorator::Impl : public ConnectionTracker
   {
     HandleImpl()
     : position(),
+      globalPosition(),
       size(),
       lineHeight( 0.0f ),
       grabDisplacementX( 0.f ),
@@ -220,11 +220,12 @@ struct Decorator::Impl : public ConnectionTracker
     {
     }
 
-    ImageActor actor;
+    ImageView actor;
     Actor grabArea;
-    ImageActor markerActor;
+    ImageView markerActor;
 
     Vector2 position;
+    Vector2 globalPosition;
     Size    size;
     float   lineHeight;              ///< Not the handle height
     float   grabDisplacementX;
@@ -276,16 +277,16 @@ struct Decorator::Impl : public ConnectionTracker
     mFlipSelectionHandlesOnCross( false ),
     mFlipLeftSelectionHandleDirection( false ),
     mFlipRightSelectionHandleDirection( false ),
-    mHandlePanning( false ),
-    mHandleCurrentCrossed( false ),
-    mHandlePreviousCrossed( false ),
-    mNotifyEndOfScroll( false )
+    mIsHandlePanning( false ),
+    mIsHandleCurrentlyCrossed( false ),
+    mIsHandlePreviouslyCrossed( false ),
+    mNotifyEndOfScroll( false ),
+    mHorizontalScrollingEnabled( false ),
+    mVerticalScrollingEnabled( false )
   {
     mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
-    mQuadIndexFormat[ "indices" ] = Property::INTEGER;
-    mHighlightMaterial = Material::New( Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ) );
-
-    SetupTouchEvents();
+    mHighlightShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
+    SetupGestures();
   }
 
   /**
@@ -305,7 +306,10 @@ struct Decorator::Impl : public ConnectionTracker
     if( mPrimaryCursor )
     {
       const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
-      mPrimaryCursorVisible = ( cursor.position.x + mCursorWidth <= mControlSize.width ) && ( cursor.position.x >= 0.f );
+      mPrimaryCursorVisible = ( ( cursor.position.x + mCursorWidth <= mControlSize.width ) &&
+                                ( cursor.position.x >= 0.f ) &&
+                                ( cursor.position.y + cursor.cursorHeight <= mControlSize.height ) &&
+                                ( cursor.position.y >= 0.f ) );
       if( mPrimaryCursorVisible )
       {
         mPrimaryCursor.SetPosition( cursor.position.x,
@@ -317,7 +321,10 @@ struct Decorator::Impl : public ConnectionTracker
     if( mSecondaryCursor )
     {
       const CursorImpl& cursor = mCursor[SECONDARY_CURSOR];
-      mSecondaryCursorVisible = ( cursor.position.x + mCursorWidth <= mControlSize.width ) && ( cursor.position.x >= 0.f );
+      mSecondaryCursorVisible = ( ( cursor.position.x + mCursorWidth <= mControlSize.width ) &&
+                                  ( cursor.position.x >= 0.f ) &&
+                                  ( cursor.position.y + cursor.cursorHeight <= mControlSize.height ) &&
+                                  ( cursor.position.y >= 0.f ) );
       if( mSecondaryCursorVisible )
       {
         mSecondaryCursor.SetPosition( cursor.position.x,
@@ -332,7 +339,10 @@ struct Decorator::Impl : public ConnectionTracker
     bool newGrabHandlePosition = false;
     if( grabHandle.active )
     {
-      const bool isVisible = ( grabHandle.position.x + floor( 0.5f * mCursorWidth ) <= mControlSize.width ) && ( grabHandle.position.x >= 0.f );
+      const bool isVisible = ( ( grabHandle.position.x + floor( 0.5f * mCursorWidth ) <= mControlSize.width ) &&
+                               ( grabHandle.position.x >= 0.f ) &&
+                               ( grabHandle.position.y <= mControlSize.height - grabHandle.lineHeight ) &&
+                               ( grabHandle.position.y >= 0.f ) );
 
       if( isVisible )
       {
@@ -364,8 +374,14 @@ struct Decorator::Impl : public ConnectionTracker
     bool newSecondaryHandlePosition = false;
     if( primary.active || secondary.active )
     {
-      const bool isPrimaryVisible = ( primary.position.x <= mControlSize.width ) && ( primary.position.x >= 0.f );
-      const bool isSecondaryVisible = ( secondary.position.x <= mControlSize.width ) && ( secondary.position.x >= 0.f );
+      const bool isPrimaryVisible = ( ( primary.position.x <= mControlSize.width ) &&
+                                      ( primary.position.x >= 0.f ) &&
+                                      ( primary.position.y <= mControlSize.height - primary.lineHeight ) &&
+                                      ( primary.position.y >= 0.f ) );
+      const bool isSecondaryVisible = ( ( secondary.position.x <= mControlSize.width ) &&
+                                        ( secondary.position.x >= 0.f ) &&
+                                        ( secondary.position.y <= mControlSize.height - secondary.lineHeight ) &&
+                                        ( secondary.position.y >= 0.f ) );
 
       if( isPrimaryVisible || isSecondaryVisible )
       {
@@ -435,6 +451,7 @@ struct Decorator::Impl : public ConnectionTracker
     if( mActiveCopyPastePopup )
     {
       ShowPopup();
+      mPopupSetNewPosition = true;
     }
     else
     {
@@ -486,7 +503,6 @@ struct Decorator::Impl : public ConnectionTracker
     {
       const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
       const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
-      const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
       const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
 
       if( primaryHandle.active || secondaryHandle.active )
@@ -502,7 +518,15 @@ struct Decorator::Impl : public ConnectionTracker
       else
       {
         // Calculates the popup's position if the grab handle is active.
-        mCopyPastePopup.position = Vector3( cursor.position.x, -0.5f * popupSize.height - grabHandle.size.height + cursor.position.y, 0.0f );
+        const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+        if( grabHandle.verticallyFlipped )
+        {
+          mCopyPastePopup.position = Vector3( cursor.position.x, -0.5f * popupSize.height - grabHandle.size.height + cursor.position.y, 0.0f );
+        }
+        else
+        {
+          mCopyPastePopup.position = Vector3( cursor.position.x, -0.5f * popupSize.height + cursor.position.y, 0.0f );
+        }
       }
     }
 
@@ -522,11 +546,11 @@ struct Decorator::Impl : public ConnectionTracker
     DeterminePositionPopup();
   }
 
-  void CreateCursor( ImageActor& cursor, const Vector4& color )
+  void CreateCursor( Control& cursor, const Vector4& color )
   {
-    cursor = CreateSolidColorActor( color );
-    cursor.SetSortModifier( DECORATION_DEPTH_INDEX );
-    cursor.SetParentOrigin( ParentOrigin::TOP_LEFT ); // Need to set the default parent origin as CreateSolidColorActor() sets a different one.
+    cursor = Control::New();
+    cursor.SetBackgroundColor( color );
+    cursor.SetParentOrigin( ParentOrigin::TOP_LEFT );
     cursor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
   }
 
@@ -614,13 +638,20 @@ struct Decorator::Impl : public ConnectionTracker
     return true;
   }
 
-  void SetupTouchEvents()
+  void SetupGestures()
   {
+    // Will consume tap gestures on handles.
     mTapDetector = TapGestureDetector::New();
-    mTapDetector.DetectedSignal().Connect( this, &Decorator::Impl::OnTap );
 
-    mPanGestureDetector = PanGestureDetector::New();
-    mPanGestureDetector.DetectedSignal().Connect( this, &Decorator::Impl::OnPan );
+    // Will consume double tap gestures on handles.
+    mTapDetector.SetMaximumTapsRequired( 2u );
+
+    // Will consume long press gestures on handles.
+    mLongPressDetector = LongPressGestureDetector::New();
+
+    // Detects pan gestures on handles.
+    mPanDetector = PanGestureDetector::New();
+    mPanDetector.DetectedSignal().Connect( this, &Decorator::Impl::OnPan );
   }
 
   void CreateActiveLayer()
@@ -634,7 +665,6 @@ struct Decorator::Impl : public ConnectionTracker
 
       mActiveLayer.SetParentOrigin( ParentOrigin::CENTER );
       mActiveLayer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
-      mActiveLayer.SetPositionInheritanceMode( USE_PARENT_POSITION );
 
       // Add the active layer telling the controller it doesn't need clipping.
       mController.AddDecoration( mActiveLayer, false );
@@ -656,41 +686,54 @@ struct Decorator::Impl : public ConnectionTracker
     HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
     if( !grabHandle.actor )
     {
-      grabHandle.actor = ImageActor::New( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] );
-      grabHandle.actor.SetSortModifier( DECORATION_DEPTH_INDEX );
-      grabHandle.actor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
-      // Area that Grab handle responds to, larger than actual handle so easier to move
-#ifdef DECORATOR_DEBUG
-      grabHandle.actor.SetName( "GrabHandleActor" );
-      if ( Dali::Internal::gLogFilter->IsEnabledFor( Debug::Verbose ) )
-      {
-        grabHandle.grabArea = Toolkit::CreateSolidColorActor( Vector4(0.0f, 0.0f, 0.0f, 0.0f), true, Color::RED, 1 );
-        grabHandle.grabArea.SetName( "GrabArea" );
-      }
-      else
+      if( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] )
       {
-        grabHandle.grabArea = Actor::New();
-        grabHandle.grabArea.SetName( "GrabArea" );
-      }
+        grabHandle.actor = ImageView::New( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] );
+        GetImpl( grabHandle.actor).SetDepthIndex( DepthIndex::DECORATION );
+        grabHandle.actor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+
+        // Area that Grab handle responds to, larger than actual handle so easier to move
+#ifdef DECORATOR_DEBUG
+        grabHandle.actor.SetName( "GrabHandleActor" );
+        if ( Dali::Internal::gLogFilter->IsEnabledFor( Debug::Verbose ) )
+        {
+          grabHandle.grabArea = Control::New();
+          Toolkit::Control control = Toolkit::Control::DownCast( grabHandle.grabArea );
+          control.SetBackgroundColor( Vector4( 1.0f, 1.0f, 1.0f, 0.5f ) );
+          grabHandle.grabArea.SetName( "GrabArea" );
+        }
+        else
+        {
+          grabHandle.grabArea = Actor::New();
+          grabHandle.grabArea.SetName( "GrabArea" );
+        }
 #else
-      grabHandle.grabArea = Actor::New();
+        grabHandle.grabArea = Actor::New();
 #endif
 
-      grabHandle.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
-      grabHandle.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
-      grabHandle.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
-      grabHandle.grabArea.SetSizeModeFactor( DEFAULT_GRAB_HANDLE_RELATIVE_SIZE );
-      grabHandle.actor.Add( grabHandle.grabArea );
-      grabHandle.actor.SetColor( mHandleColor );
+        grabHandle.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
+        grabHandle.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+        grabHandle.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
+        grabHandle.grabArea.SetSizeModeFactor( DEFAULT_GRAB_HANDLE_RELATIVE_SIZE );
+        grabHandle.actor.Add( grabHandle.grabArea );
+        grabHandle.actor.SetColor( mHandleColor );
 
-      grabHandle.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnGrabHandleTouched );
-      mTapDetector.Attach( grabHandle.grabArea );
-      mPanGestureDetector.Attach( grabHandle.grabArea );
+        grabHandle.grabArea.TouchSignal().Connect( this, &Decorator::Impl::OnGrabHandleTouched );
 
-      mActiveLayer.Add( grabHandle.actor );
+        // The grab handle's actor is attached to the tap and long press detectors in order to consume these events.
+        // Note that no callbacks are connected to any signal emitted by the tap and long press detectors.
+        mTapDetector.Attach( grabHandle.actor );
+        mLongPressDetector.Attach( grabHandle.actor );
+
+        // The grab handle's area is attached to the pan detector.
+        // The OnPan() method is connected to the signals emitted by the pan detector.
+        mPanDetector.Attach( grabHandle.grabArea );
+
+        mActiveLayer.Add( grabHandle.actor );
+      }
     }
 
-    if( !grabHandle.actor.GetParent() )
+    if( grabHandle.actor && !grabHandle.actor.GetParent() )
     {
       mActiveLayer.Add( grabHandle.actor );
     }
@@ -700,7 +743,7 @@ struct Decorator::Impl : public ConnectionTracker
   {
     if( image )
     {
-      handle.markerActor = ImageActor::New( image );
+      handle.markerActor = ImageView::New( image );
       handle.markerActor.SetColor( mHandleColor );
       handle.actor.Add( handle.markerActor );
 
@@ -724,33 +767,43 @@ struct Decorator::Impl : public ConnectionTracker
     HandleImpl& primary = mHandle[ LEFT_SELECTION_HANDLE ];
     if( !primary.actor )
     {
-      primary.actor = ImageActor::New( mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
+      if( mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] )
+      {
+        primary.actor = ImageView::New( mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
 #ifdef DECORATOR_DEBUG
-      primary.actor.SetName("SelectionHandleOne");
+        primary.actor.SetName("SelectionHandleOne");
 #endif
-      primary.actor.SetAnchorPoint( AnchorPoint::TOP_RIGHT ); // Change to BOTTOM_RIGHT if Look'n'Feel requires handle above text.
-      primary.actor.SetSortModifier( DECORATION_DEPTH_INDEX );
-      primary.actor.SetColor( mHandleColor );
+        primary.actor.SetAnchorPoint( AnchorPoint::TOP_RIGHT ); // Change to BOTTOM_RIGHT if Look'n'Feel requires handle above text.
+        GetImpl( primary.actor ).SetDepthIndex( DepthIndex::DECORATION );
+        primary.actor.SetColor( mHandleColor );
 
-      primary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
+        primary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
 #ifdef DECORATOR_DEBUG
-      primary.grabArea.SetName("SelectionHandleOneGrabArea");
+        primary.grabArea.SetName("SelectionHandleOneGrabArea");
 #endif
-      primary.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
-      primary.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
-      primary.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
-      primary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
+        primary.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
+        primary.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
+        primary.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+        primary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
+
+        primary.grabArea.TouchSignal().Connect( this, &Decorator::Impl::OnHandleOneTouched );
 
-      mTapDetector.Attach( primary.grabArea );
-      mPanGestureDetector.Attach( primary.grabArea );
-      primary.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnHandleOneTouched );
+        // The handle's actor is attached to the tap and long press detectors in order to consume these events.
+        // Note that no callbacks are connected to any signal emitted by the tap and long press detectors.
+        mTapDetector.Attach( primary.actor );
+        mLongPressDetector.Attach( primary.actor );
 
-      primary.actor.Add( primary.grabArea );
+        // The handle's area is attached to the pan detector.
+        // The OnPan() method is connected to the signals emitted by the pan detector.
+        mPanDetector.Attach( primary.grabArea );
 
-      CreateHandleMarker( primary, mHandleImages[LEFT_SELECTION_HANDLE_MARKER][HANDLE_IMAGE_RELEASED], LEFT_SELECTION_HANDLE );
+        primary.actor.Add( primary.grabArea );
+
+        CreateHandleMarker( primary, mHandleImages[LEFT_SELECTION_HANDLE_MARKER][HANDLE_IMAGE_RELEASED], LEFT_SELECTION_HANDLE );
+      }
     }
 
-    if( !primary.actor.GetParent() )
+    if( primary.actor && !primary.actor.GetParent() )
     {
       mActiveLayer.Add( primary.actor );
     }
@@ -758,33 +811,43 @@ struct Decorator::Impl : public ConnectionTracker
     HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
     if( !secondary.actor )
     {
-      secondary.actor = ImageActor::New( mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
+      if( mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] )
+      {
+        secondary.actor = ImageView::New( mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
 #ifdef DECORATOR_DEBUG
-      secondary.actor.SetName("SelectionHandleTwo");
+        secondary.actor.SetName("SelectionHandleTwo");
 #endif
-      secondary.actor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); // Change to BOTTOM_LEFT if Look'n'Feel requires handle above text.
-      secondary.actor.SetSortModifier( DECORATION_DEPTH_INDEX );
-      secondary.actor.SetColor( mHandleColor );
+        secondary.actor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); // Change to BOTTOM_LEFT if Look'n'Feel requires handle above text.
+        GetImpl( secondary.actor ).SetDepthIndex( DepthIndex::DECORATION );
+        secondary.actor.SetColor( mHandleColor );
 
-      secondary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
+        secondary.grabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move
 #ifdef DECORATOR_DEBUG
-      secondary.grabArea.SetName("SelectionHandleTwoGrabArea");
+        secondary.grabArea.SetName("SelectionHandleTwoGrabArea");
 #endif
-      secondary.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
-      secondary.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
-      secondary.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
-      secondary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
+        secondary.grabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
+        secondary.grabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
+        secondary.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+        secondary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
 
-      mTapDetector.Attach( secondary.grabArea );
-      mPanGestureDetector.Attach( secondary.grabArea );
-      secondary.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnHandleTwoTouched );
+        secondary.grabArea.TouchSignal().Connect( this, &Decorator::Impl::OnHandleTwoTouched );
 
-      secondary.actor.Add( secondary.grabArea );
+        // The handle's actor is attached to the tap and long press detectors in order to consume these events.
+        // Note that no callbacks are connected to any signal emitted by the tap and long press detectors.
+        mTapDetector.Attach( secondary.actor );
+        mLongPressDetector.Attach( secondary.actor );
 
-      CreateHandleMarker( secondary, mHandleImages[RIGHT_SELECTION_HANDLE_MARKER][HANDLE_IMAGE_RELEASED], RIGHT_SELECTION_HANDLE  );
+        // The handle's area is attached to the pan detector.
+        // The OnPan() method is connected to the signals emitted by the pan detector.
+        mPanDetector.Attach( secondary.grabArea );
+
+        secondary.actor.Add( secondary.grabArea );
+
+        CreateHandleMarker( secondary, mHandleImages[RIGHT_SELECTION_HANDLE_MARKER][HANDLE_IMAGE_RELEASED], RIGHT_SELECTION_HANDLE  );
+      }
     }
 
-    if( !secondary.actor.GetParent() )
+    if( secondary.actor && !secondary.actor.GetParent() )
     {
       mActiveLayer.Add( secondary.actor );
     }
@@ -798,8 +861,8 @@ struct Decorator::Impl : public ConnectionTracker
     // The grab handle position in world coords.
     // The active layer's world position is the center of the active layer. The origin of the
     // coord system of the handles is the top left of the active layer.
-    position.x = parentWorldPosition.x - 0.5f * mControlSize.width + handle.position.x;
-    position.y = parentWorldPosition.y - 0.5f * mControlSize.height + handle.position.y;
+    position.x = parentWorldPosition.x - 0.5f * mControlSize.width + handle.position.x + ( mSmoothHandlePanEnabled ? handle.grabDisplacementX : 0.f );
+    position.y = parentWorldPosition.y - 0.5f * mControlSize.height + handle.position.y + ( mSmoothHandlePanEnabled ? handle.grabDisplacementY : 0.f );
   }
 
   void SetGrabHandlePosition()
@@ -829,8 +892,11 @@ struct Decorator::Impl : public ConnectionTracker
     // The SetGrabHandleImage() method will change the orientation.
     const float yLocalPosition = grabHandle.verticallyFlipped ? grabHandle.position.y : grabHandle.position.y + grabHandle.lineHeight;
 
-    grabHandle.actor.SetPosition( grabHandle.position.x + floor( 0.5f * mCursorWidth ),
-                                  yLocalPosition ); // TODO : Fix for multiline.
+    if( grabHandle.actor )
+    {
+      grabHandle.actor.SetPosition( grabHandle.position.x + floor( 0.5f * mCursorWidth ) + ( mSmoothHandlePanEnabled ? grabHandle.grabDisplacementX : 0.f ),
+                                    yLocalPosition + ( mSmoothHandlePanEnabled ? grabHandle.grabDisplacementY : 0.f ) );
+    }
   }
 
   void SetSelectionHandlePosition( HandleType type )
@@ -854,18 +920,21 @@ struct Decorator::Impl : public ConnectionTracker
 
     // Whether to flip the handles if they are crossed.
     bool crossFlip = false;
-    if( mFlipSelectionHandlesOnCross || !mHandlePanning )
+    if( mFlipSelectionHandlesOnCross || !mIsHandlePanning )
     {
-      crossFlip = mHandleCurrentCrossed;
+      crossFlip = mIsHandleCurrentlyCrossed;
     }
 
+    // Whether the handle was crossed before start the panning.
+    const bool isHandlePreviouslyCrossed = mFlipSelectionHandlesOnCross ? false : mIsHandlePreviouslyCrossed;
+
     // Does not flip if both conditions are true (double flip)
-    flipHandle = flipHandle != ( crossFlip || mHandlePreviousCrossed );
+    flipHandle = flipHandle != ( crossFlip || isHandlePreviouslyCrossed );
 
     // Will flip the handles vertically if the user prefers it.
     bool verticallyFlippedPreferred = handle.verticallyFlippedPreferred;
 
-    if( crossFlip || mHandlePreviousCrossed )
+    if( crossFlip || isHandlePreviouslyCrossed )
     {
       if( isPrimaryHandle )
       {
@@ -886,7 +955,7 @@ struct Decorator::Impl : public ConnectionTracker
 
     if( flipHandle )
     {
-      if( !handle.horizontallyFlipped )
+      if( handle.actor && !handle.horizontallyFlipped )
       {
         // Change the anchor point to flip the image.
         handle.actor.SetAnchorPoint( isPrimaryHandle ? AnchorPoint::TOP_LEFT : AnchorPoint::TOP_RIGHT );
@@ -896,7 +965,7 @@ struct Decorator::Impl : public ConnectionTracker
     }
     else
     {
-      if( handle.horizontallyFlipped )
+      if( handle.actor && handle.horizontallyFlipped )
       {
         // Reset the anchor point.
         handle.actor.SetAnchorPoint( isPrimaryHandle ? AnchorPoint::TOP_RIGHT : AnchorPoint::TOP_LEFT );
@@ -916,8 +985,11 @@ struct Decorator::Impl : public ConnectionTracker
     // The SetHandleImage() method will change the orientation.
     const float yLocalPosition = handle.verticallyFlipped ? handle.position.y : handle.position.y + handle.lineHeight;
 
-    handle.actor.SetPosition( handle.position.x,
-                              yLocalPosition ); // TODO : Fix for multiline.
+    if( handle.actor )
+    {
+      handle.actor.SetPosition( handle.position.x + ( mSmoothHandlePanEnabled ? handle.grabDisplacementX : 0.f ),
+                                yLocalPosition + ( mSmoothHandlePanEnabled ? handle.grabDisplacementY : 0.f ) );
+    }
   }
 
   void SetHandleImage( HandleType type )
@@ -987,7 +1059,7 @@ struct Decorator::Impl : public ConnectionTracker
       if( !mHighlightQuadList.empty() )
       {
         Vector< Vector2 > vertices;
-        Vector< unsigned int> indices;
+        Vector< unsigned short> indices;
         Vector2 vertex;
 
         std::vector<QuadCoordinates>::iterator iter = mHighlightQuadList.begin();
@@ -1028,37 +1100,23 @@ struct Decorator::Impl : public ConnectionTracker
           indices.PushBack( v + 3 );
         }
 
-        if( mQuadVertices )
-        {
-          mQuadVertices.SetSize( vertices.Size() );
-        }
-        else
-        {
-          mQuadVertices = PropertyBuffer::New( mQuadVertexFormat, vertices.Size() );
-        }
-
-        if( mQuadIndices )
-        {
-          mQuadIndices.SetSize( indices.Size() );
-        }
-        else
+        if( ! mQuadVertices )
         {
-          mQuadIndices = PropertyBuffer::New( mQuadIndexFormat, indices.Size() );
+          mQuadVertices = PropertyBuffer::New( mQuadVertexFormat );
         }
 
-        mQuadVertices.SetData( &vertices[ 0 ] );
-        mQuadIndices.SetData( &indices[ 0 ] );
+        mQuadVertices.SetData( &vertices[ 0 ], vertices.Size() );
 
         if( !mQuadGeometry )
         {
           mQuadGeometry = Geometry::New();
           mQuadGeometry.AddVertexBuffer( mQuadVertices );
         }
-        mQuadGeometry.SetIndexBuffer( mQuadIndices );
+        mQuadGeometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
 
         if( !mHighlightRenderer )
         {
-          mHighlightRenderer = Dali::Renderer::New( mQuadGeometry, mHighlightMaterial );
+          mHighlightRenderer = Dali::Renderer::New( mQuadGeometry, mHighlightShader );
           mHighlightActor.AddRenderer( mHighlightRenderer );
         }
       }
@@ -1070,50 +1128,62 @@ struct Decorator::Impl : public ConnectionTracker
 
       if( mHighlightRenderer )
       {
-        mHighlightRenderer.SetDepthIndex( mTextDepth - 2u ); // text is rendered at mTextDepth and text's shadow at mTextDepth -1u.
+        mHighlightRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mTextDepth - 2 ); // text is rendered at mTextDepth and text's shadow at mTextDepth -1u.
       }
     }
   }
 
-  void OnTap( Actor actor, const TapGesture& tap )
-  {
-    if( actor == mHandle[GRAB_HANDLE].actor )
-    {
-      // TODO
-    }
-  }
-
   void DoPan( HandleImpl& handle, HandleType type, const PanGesture& gesture )
   {
     if( Gesture::Started == gesture.state )
     {
-      handle.grabDisplacementX = handle.grabDisplacementY = 0;
+      handle.grabDisplacementX = handle.grabDisplacementY = 0.f;
+
+      handle.globalPosition.x = handle.position.x;
+      handle.globalPosition.y = handle.position.y;
     }
 
     handle.grabDisplacementX += gesture.displacement.x;
-    handle.grabDisplacementY += gesture.displacement.y;
+    handle.grabDisplacementY += ( handle.verticallyFlipped ? -gesture.displacement.y : gesture.displacement.y );
 
-    const float x = handle.position.x + handle.grabDisplacementX;
-    const float y = handle.position.y + handle.lineHeight*0.5f + handle.grabDisplacementY;
+    const float x = handle.globalPosition.x + handle.grabDisplacementX;
+    const float y = handle.globalPosition.y + handle.grabDisplacementY + 0.5f * handle.lineHeight;
+    const float yVerticallyFlippedCorrected = y - ( handle.verticallyFlipped ? handle.lineHeight : 0.f );
 
-    if( Gesture::Started    == gesture.state ||
-        Gesture::Continuing == gesture.state )
+    if( ( Gesture::Started    == gesture.state ) ||
+        ( Gesture::Continuing == gesture.state ) )
     {
       Vector2 targetSize;
       mController.GetTargetSize( targetSize );
 
-      if( x < mScrollThreshold )
+      if( mHorizontalScrollingEnabled &&
+          ( x < mScrollThreshold ) )
       {
         mScrollDirection = SCROLL_RIGHT;
         mHandleScrolling = type;
         StartScrollTimer();
       }
-      else if( x > targetSize.width - mScrollThreshold )
+      else if( mHorizontalScrollingEnabled &&
+               ( x > targetSize.width - mScrollThreshold ) )
       {
         mScrollDirection = SCROLL_LEFT;
         mHandleScrolling = type;
         StartScrollTimer();
       }
+      else if( mVerticalScrollingEnabled &&
+               ( yVerticallyFlippedCorrected < mScrollThreshold ) )
+      {
+        mScrollDirection = SCROLL_TOP;
+        mHandleScrolling = type;
+        StartScrollTimer();
+      }
+      else if( mVerticalScrollingEnabled &&
+               ( yVerticallyFlippedCorrected + handle.lineHeight > targetSize.height - mScrollThreshold ) )
+      {
+        mScrollDirection = SCROLL_BOTTOM;
+        mHandleScrolling = type;
+        StartScrollTimer();
+      }
       else
       {
         mHandleScrolling = HANDLE_TYPE_COUNT;
@@ -1121,10 +1191,10 @@ struct Decorator::Impl : public ConnectionTracker
         mController.DecorationEvent( type, HANDLE_PRESSED, x, y );
       }
 
-      mHandlePanning = true;
+      mIsHandlePanning = true;
     }
-    else if( Gesture::Finished  == gesture.state ||
-             Gesture::Cancelled == gesture.state )
+    else if( ( Gesture::Finished  == gesture.state ) ||
+             ( Gesture::Cancelled == gesture.state ) )
     {
       if( mScrollTimer &&
           ( mScrollTimer.IsRunning() || mNotifyEndOfScroll ) )
@@ -1139,10 +1209,13 @@ struct Decorator::Impl : public ConnectionTracker
         mController.DecorationEvent( type, HANDLE_RELEASED, x, y );
       }
 
-      handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_RELEASED] );
+      if( handle.actor )
+      {
+        handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_RELEASED] );
+      }
       handle.pressed = false;
 
-      mHandlePanning = false;
+      mIsHandlePanning = false;
     }
   }
 
@@ -1166,22 +1239,24 @@ struct Decorator::Impl : public ConnectionTracker
     }
   }
 
-  bool OnGrabHandleTouched( Actor actor, const TouchEvent& event )
+  bool OnGrabHandleTouched( Actor actor, const TouchData& touch )
   {
+    HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+
     // Switch between pressed/release grab-handle images
-    if( event.GetPointCount() > 0 &&
-        mHandle[GRAB_HANDLE].actor )
+    if( touch.GetPointCount() > 0 &&
+        grabHandle.actor )
     {
-      const TouchPoint& point = event.GetPoint(0);
+      const PointState::Type state = touch.GetState( 0 );
 
-      if( TouchPoint::Down == point.state )
+      if( PointState::DOWN == state )
       {
-        mHandle[GRAB_HANDLE].pressed = true;
+        grabHandle.pressed = true;
       }
-      else if( ( TouchPoint::Up == point.state ) ||
-               ( TouchPoint::Interrupted == point.state ) )
+      else if( ( PointState::UP == state ) ||
+               ( PointState::INTERRUPTED == state ) )
       {
-        mHandle[GRAB_HANDLE].pressed = false;
+        grabHandle.pressed = false;
       }
 
       SetHandleImage( GRAB_HANDLE );
@@ -1191,24 +1266,26 @@ struct Decorator::Impl : public ConnectionTracker
     return true;
   }
 
-  bool OnHandleOneTouched( Actor actor, const TouchEvent& event )
+  bool OnHandleOneTouched( Actor actor, const TouchData& touch )
   {
+    HandleImpl& primarySelectionHandle = mHandle[LEFT_SELECTION_HANDLE];
+
     // Switch between pressed/release selection handle images
-    if( event.GetPointCount() > 0 &&
-        mHandle[LEFT_SELECTION_HANDLE].actor )
+    if( touch.GetPointCount() > 0 &&
+        primarySelectionHandle.actor )
     {
-      const TouchPoint& point = event.GetPoint(0);
+      const PointState::Type state = touch.GetState( 0 );
 
-      if( TouchPoint::Down == point.state )
+      if( PointState::DOWN == state )
       {
-        mHandle[LEFT_SELECTION_HANDLE].pressed = true;
+        primarySelectionHandle.pressed = true;
       }
-      else if( ( TouchPoint::Up == point.state ) ||
-               ( TouchPoint::Interrupted == point.state ) )
+      else if( ( PointState::UP == state ) ||
+               ( PointState::INTERRUPTED == state ) )
       {
-        mHandle[LEFT_SELECTION_HANDLE].pressed = false;
-        mHandlePreviousCrossed = mHandleCurrentCrossed;
-        mHandlePanning = false;
+        primarySelectionHandle.pressed = false;
+        mIsHandlePreviouslyCrossed = mIsHandleCurrentlyCrossed;
+        mIsHandlePanning = false;
       }
 
       SetHandleImage( LEFT_SELECTION_HANDLE );
@@ -1218,24 +1295,26 @@ struct Decorator::Impl : public ConnectionTracker
     return true;
   }
 
-  bool OnHandleTwoTouched( Actor actor, const TouchEvent& event )
+  bool OnHandleTwoTouched( Actor actor, const TouchData& touch )
   {
+    HandleImpl& secondarySelectionHandle = mHandle[RIGHT_SELECTION_HANDLE];
+
     // Switch between pressed/release selection handle images
-    if( event.GetPointCount() > 0 &&
-        mHandle[RIGHT_SELECTION_HANDLE].actor )
+    if( touch.GetPointCount() > 0 &&
+        secondarySelectionHandle.actor )
     {
-      const TouchPoint& point = event.GetPoint(0);
+      const PointState::Type state = touch.GetState( 0 );
 
-      if( TouchPoint::Down == point.state )
+      if( PointState::DOWN == state )
       {
-        mHandle[RIGHT_SELECTION_HANDLE].pressed = true;
+        secondarySelectionHandle.pressed = true;
       }
-      else if( ( TouchPoint::Up == point.state ) ||
-               ( TouchPoint::Interrupted == point.state ) )
+      else if( ( PointState::UP == state ) ||
+               ( PointState::INTERRUPTED == state ) )
       {
-        mHandle[RIGHT_SELECTION_HANDLE].pressed = false;
-        mHandlePreviousCrossed = mHandleCurrentCrossed;
-        mHandlePanning = false;
+        secondarySelectionHandle.pressed = false;
+        mIsHandlePreviouslyCrossed = mIsHandleCurrentlyCrossed;
+        mIsHandlePanning = false;
       }
 
       SetHandleImage( RIGHT_SELECTION_HANDLE );
@@ -1613,10 +1692,39 @@ struct Decorator::Impl : public ConnectionTracker
   {
     if( HANDLE_TYPE_COUNT != mHandleScrolling )
     {
+      float x = 0.f;
+      float y = 0.f;
+
+      switch( mScrollDirection )
+      {
+        case SCROLL_RIGHT:
+        {
+          x = mScrollDistance;
+          break;
+        }
+        case SCROLL_LEFT:
+        {
+          x = -mScrollDistance;
+          break;
+        }
+        case SCROLL_TOP:
+        {
+          y = mScrollDistance;
+          break;
+        }
+        case SCROLL_BOTTOM:
+        {
+          y = -mScrollDistance;
+          break;
+        }
+        default:
+          break;
+      }
+
       mController.DecorationEvent( mHandleScrolling,
                                    HANDLE_SCROLLING,
-                                   mScrollDirection == SCROLL_RIGHT ? mScrollDistance : -mScrollDistance,
-                                   0.f );
+                                   x,
+                                   y );
     }
 
     return true;
@@ -1624,8 +1732,10 @@ struct Decorator::Impl : public ConnectionTracker
 
   ControllerInterface& mController;
 
-  TapGestureDetector  mTapDetector;
-  PanGestureDetector  mPanGestureDetector;
+  TapGestureDetector       mTapDetector;
+  PanGestureDetector       mPanDetector;
+  LongPressGestureDetector mLongPressDetector;
+
   Timer               mCursorBlinkTimer;          ///< Timer to signal cursor to blink
   Timer               mScrollTimer;               ///< Timer used to scroll the text when the grab handle is moved close to the edges.
 
@@ -1634,14 +1744,13 @@ struct Decorator::Impl : public ConnectionTracker
   PropertyNotification mVerticalGreaterThanNotification;   ///< Notifies when the 'y' coord of the active layer is grater than a given value.
   PropertyNotification mHorizontalLessThanNotification;    ///< Notifies when the 'x' coord of the active layer is less than a given value.
   PropertyNotification mHorizontalGreaterThanNotification; ///< Notifies when the 'x' coord of the active layer is grater than a given value.
-  ImageActor           mPrimaryCursor;
-  ImageActor           mSecondaryCursor;
+  Control              mPrimaryCursor;
+  Control              mSecondaryCursor;
 
   Actor               mHighlightActor;            ///< Actor to display highlight
   Renderer            mHighlightRenderer;
-  Material            mHighlightMaterial;         ///< Material used for highlight
+  Shader              mHighlightShader;           ///< Shader used for highlight
   Property::Map       mQuadVertexFormat;
-  Property::Map       mQuadIndexFormat;
   PopupImpl           mCopyPastePopup;
   TextSelectionPopup::Buttons mEnabledPopupButtons; /// Bit mask of currently enabled Popup buttons
   TextSelectionPopupCallbackInterface& mTextSelectionPopupCallbackInterface;
@@ -1653,7 +1762,6 @@ struct Decorator::Impl : public ConnectionTracker
   HandleImpl          mHandle[HANDLE_TYPE_COUNT];
 
   PropertyBuffer      mQuadVertices;
-  PropertyBuffer      mQuadIndices;
   Geometry            mQuadGeometry;
   QuadContainer       mHighlightQuadList;         ///< Sub-selections that combine to create the complete selection highlight
 
@@ -1682,10 +1790,13 @@ struct Decorator::Impl : public ConnectionTracker
   bool                mFlipSelectionHandlesOnCross       : 1; ///< Whether to flip the selection handles as soon as they cross.
   bool                mFlipLeftSelectionHandleDirection  : 1; ///< Whether to flip the left selection handle image because of the character's direction.
   bool                mFlipRightSelectionHandleDirection : 1; ///< Whether to flip the right selection handle image because of the character's direction.
-  bool                mHandlePanning                     : 1; ///< Whether any of the handles is moving.
-  bool                mHandleCurrentCrossed              : 1; ///< Whether the handles are crossed.
-  bool                mHandlePreviousCrossed             : 1; ///< Whether the handles where crossed at the last handle touch up.
+  bool                mIsHandlePanning                   : 1; ///< Whether any of the handles is moving.
+  bool                mIsHandleCurrentlyCrossed          : 1; ///< Whether the handles are crossed.
+  bool                mIsHandlePreviouslyCrossed         : 1; ///< Whether the handles where crossed at the last handle touch up.
   bool                mNotifyEndOfScroll                 : 1; ///< Whether to notify the end of the scroll.
+  bool                mHorizontalScrollingEnabled        : 1; ///< Whether the horizontal scrolling is enabled.
+  bool                mVerticalScrollingEnabled          : 1; ///< Whether the vertical scrolling is enabled.
+  bool                mSmoothHandlePanEnabled            : 1; ///< Whether to pan smoothly the handles.
 };
 
 DecoratorPtr Decorator::New( ControllerInterface& controller,
@@ -1729,18 +1840,22 @@ unsigned int Decorator::GetActiveCursor() const
 
 void Decorator::SetPosition( Cursor cursor, float x, float y, float cursorHeight, float lineHeight )
 {
-  mImpl->mCursor[cursor].position.x = x;
-  mImpl->mCursor[cursor].position.y = y;
-  mImpl->mCursor[cursor].cursorHeight = cursorHeight;
-  mImpl->mCursor[cursor].lineHeight = lineHeight;
+  Impl::CursorImpl& cursorImpl = mImpl->mCursor[cursor];
+
+  cursorImpl.position.x = x;
+  cursorImpl.position.y = y;
+  cursorImpl.cursorHeight = cursorHeight;
+  cursorImpl.lineHeight = lineHeight;
 }
 
 void Decorator::GetPosition( Cursor cursor, float& x, float& y, float& cursorHeight, float& lineHeight ) const
 {
-  x = mImpl->mCursor[cursor].position.x;
-  y = mImpl->mCursor[cursor].position.y;
-  cursorHeight = mImpl->mCursor[cursor].cursorHeight;
-  lineHeight = mImpl->mCursor[cursor].lineHeight;
+  const Impl::CursorImpl& cursorImpl = mImpl->mCursor[cursor];
+
+  x = cursorImpl.position.x;
+  y = cursorImpl.position.y;
+  cursorHeight = cursorImpl.cursorHeight;
+  lineHeight = cursorImpl.lineHeight;
 }
 
 const Vector2& Decorator::GetPosition( Cursor cursor ) const
@@ -1828,7 +1943,7 @@ void Decorator::SetHandleActive( HandleType handleType, bool active )
   {
     if( ( LEFT_SELECTION_HANDLE == handleType ) || ( RIGHT_SELECTION_HANDLE == handleType ) )
     {
-      mImpl->mHandlePreviousCrossed = false;
+      mImpl->mIsHandlePreviouslyCrossed = false;
     }
 
     // TODO: this is a work-around.
@@ -1836,10 +1951,10 @@ void Decorator::SetHandleActive( HandleType handleType, bool active )
     // state when the power button is pressed and the application goes to background.
     mImpl->mHandle[handleType].pressed = false;
     Image imageReleased = mImpl->mHandleImages[handleType][HANDLE_IMAGE_RELEASED];
-    ImageActor imageActor = mImpl->mHandle[handleType].actor;
-    if( imageReleased && imageActor )
+    ImageView imageView = mImpl->mHandle[handleType].actor;
+    if( imageReleased && imageView )
     {
-       imageActor.SetImage( imageReleased );
+      imageView.SetImage( imageReleased );
     }
   }
 
@@ -1872,15 +1987,18 @@ const Vector4& Decorator::GetHandleColor() const
 
 void Decorator::SetPosition( HandleType handleType, float x, float y, float height )
 {
-  // Adjust grab handle displacement
+  // Adjust handle's displacement
   Impl::HandleImpl& handle = mImpl->mHandle[handleType];
 
-  handle.grabDisplacementX -= x - handle.position.x;
-  handle.grabDisplacementY -= y - handle.position.y;
-
   handle.position.x = x;
   handle.position.y = y;
   handle.lineHeight = height;
+
+  if( mImpl->mSmoothHandlePanEnabled )
+  {
+    handle.grabDisplacementX = 0.f;
+    handle.grabDisplacementY = 0.f;
+  }
 }
 
 void Decorator::GetPosition( HandleType handleType, float& x, float& y, float& height ) const
@@ -1914,7 +2032,7 @@ void Decorator::FlipSelectionHandlesOnCrossEnabled( bool enable )
 
 void Decorator::SetSelectionHandleFlipState( bool indicesSwapped, bool left, bool right )
 {
-  mImpl->mHandleCurrentCrossed = indicesSwapped;
+  mImpl->mIsHandleCurrentlyCrossed = indicesSwapped;
   mImpl->mFlipLeftSelectionHandleDirection = left;
   mImpl->mFlipRightSelectionHandleDirection = right;
 }
@@ -2004,6 +2122,36 @@ void Decorator::NotifyEndOfScroll()
   mImpl->NotifyEndOfScroll();
 }
 
+void Decorator::SetHorizontalScrollEnabled( bool enable )
+{
+  mImpl->mHorizontalScrollingEnabled = enable;
+}
+
+bool Decorator::IsHorizontalScrollEnabled() const
+{
+  return mImpl->mHorizontalScrollingEnabled;
+}
+
+void Decorator::SetVerticalScrollEnabled( bool enable )
+{
+  mImpl->mVerticalScrollingEnabled = enable;
+}
+
+bool Decorator::IsVerticalScrollEnabled() const
+{
+  return mImpl->mVerticalScrollingEnabled;
+}
+
+void Decorator::SetSmoothHandlePanEnabled( bool enable )
+{
+  mImpl->mSmoothHandlePanEnabled = enable;
+}
+
+bool Decorator::IsSmoothHandlePanEnabled() const
+{
+  return mImpl->mSmoothHandlePanEnabled;
+}
+
 Decorator::~Decorator()
 {
   delete mImpl;