Fix for text's highlight box.
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / decorator / text-decorator.cpp
index 74fc924..281e43d 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-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/image-view/image-view.h>
@@ -49,12 +47,10 @@ namespace
 const char* VERTEX_SHADER = MAKE_SHADER(
 attribute mediump vec2    aPosition;
 uniform   mediump mat4    uMvpMatrix;
-uniform   mediump vec3    uSize;
 
 void main()
 {
   mediump vec4 position = vec4( aPosition, 0.0, 1.0 );
-  position.xyz *= uSize;
   gl_Position = uMvpMatrix * position;
 }
 );
@@ -93,17 +89,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.
@@ -208,6 +204,7 @@ struct Decorator::Impl : public ConnectionTracker
   {
     HandleImpl()
     : position(),
+      globalPosition(),
       size(),
       lineHeight( 0.0f ),
       grabDisplacementX( 0.f ),
@@ -226,6 +223,7 @@ struct Decorator::Impl : public ConnectionTracker
     ImageView markerActor;
 
     Vector2 position;
+    Vector2 globalPosition;
     Size    size;
     float   lineHeight;              ///< Not the handle height
     float   grabDisplacementX;
@@ -277,10 +275,12 @@ 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;
     mHighlightShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
@@ -304,7 +304,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,
@@ -316,7 +319,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,
@@ -331,7 +337,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 )
       {
@@ -363,8 +372,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 )
       {
@@ -623,11 +638,18 @@ struct Decorator::Impl : public ConnectionTracker
 
   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()
@@ -695,8 +717,15 @@ struct Decorator::Impl : public ConnectionTracker
         grabHandle.actor.SetColor( mHandleColor );
 
         grabHandle.grabArea.TouchSignal().Connect( this, &Decorator::Impl::OnGrabHandleTouched );
-        mTapDetector.Attach( grabHandle.grabArea );
-        mPanGestureDetector.Attach( grabHandle.grabArea );
+
+        // 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 );
       }
@@ -755,10 +784,17 @@ struct Decorator::Impl : public ConnectionTracker
         primary.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
         primary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
 
-        mTapDetector.Attach( primary.grabArea );
-        mPanGestureDetector.Attach( primary.grabArea );
         primary.grabArea.TouchSignal().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 );
+
+        // 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 );
+
         primary.actor.Add( primary.grabArea );
 
         CreateHandleMarker( primary, mHandleImages[LEFT_SELECTION_HANDLE_MARKER][HANDLE_IMAGE_RELEASED], LEFT_SELECTION_HANDLE );
@@ -792,10 +828,17 @@ struct Decorator::Impl : public ConnectionTracker
         secondary.grabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
         secondary.grabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE );
 
-        mTapDetector.Attach( secondary.grabArea );
-        mPanGestureDetector.Attach( secondary.grabArea );
         secondary.grabArea.TouchSignal().Connect( this, &Decorator::Impl::OnHandleTwoTouched );
 
+        // 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 );
+
+        // 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  );
@@ -816,8 +859,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()
@@ -849,8 +892,8 @@ struct Decorator::Impl : public ConnectionTracker
 
     if( grabHandle.actor )
     {
-      grabHandle.actor.SetPosition( grabHandle.position.x + floor( 0.5f * mCursorWidth ),
-                                    yLocalPosition ); // TODO : Fix for multiline.
+      grabHandle.actor.SetPosition( grabHandle.position.x + floor( 0.5f * mCursorWidth ) + ( mSmoothHandlePanEnabled ? grabHandle.grabDisplacementX : 0.f ),
+                                    yLocalPosition + ( mSmoothHandlePanEnabled ? grabHandle.grabDisplacementY : 0.f ) );
     }
   }
 
@@ -875,18 +918,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 )
       {
@@ -939,8 +985,8 @@ struct Decorator::Impl : public ConnectionTracker
 
     if( handle.actor )
     {
-      handle.actor.SetPosition( handle.position.x,
-                                yLocalPosition ); // TODO : Fix for multiline.
+      handle.actor.SetPosition( handle.position.x + ( mSmoothHandlePanEnabled ? handle.grabDisplacementX : 0.f ),
+                                yLocalPosition + ( mSmoothHandlePanEnabled ? handle.grabDisplacementY : 0.f ) );
     }
   }
 
@@ -994,8 +1040,8 @@ struct Decorator::Impl : public ConnectionTracker
 #ifdef DECORATOR_DEBUG
       mHighlightActor.SetName( "HighlightActor" );
 #endif
+      mHighlightActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
       mHighlightActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
-      mHighlightActor.SetSize( 1.0f, 1.0f );
       mHighlightActor.SetColor( mHighlightColor );
       mHighlightActor.SetColorMode( USE_OWN_COLOR );
     }
@@ -1008,37 +1054,57 @@ struct Decorator::Impl : public ConnectionTracker
   {
     if ( mHighlightActor )
     {
-      if( !mHighlightQuadList.empty() )
+      // Sets the position of the highlight actor inside the decorator.
+      mHighlightActor.SetPosition( mHighlightPosition.x,
+                                   mHighlightPosition.y );
+
+      const unsigned int numberOfQuads = mHighlightQuadList.size();
+      if( 0u != numberOfQuads )
       {
-        Vector< Vector2 > vertices;
-        Vector< unsigned short> indices;
-        Vector2 vertex;
+        // Set the size of the highlighted text to the actor.
+        mHighlightActor.SetSize( mHighlightSize );
 
-        std::vector<QuadCoordinates>::iterator iter = mHighlightQuadList.begin();
-        std::vector<QuadCoordinates>::iterator endIter = mHighlightQuadList.end();
+        // Used to translate the vertices given in decorator's coords to the mHighlightActor's local coords.
+        const float offsetX = mHighlightPosition.x + 0.5f * mHighlightSize.width;
+        const float offsetY = mHighlightPosition.y + 0.5f * mHighlightSize.height;
 
-        for( std::size_t v = 0; iter != endIter; ++iter,v+=4 )
+        Vector<Vector2> vertices;
+        Vector<unsigned short> indices;
+
+        vertices.Reserve( 4u * numberOfQuads );
+        indices.Reserve( 6u * numberOfQuads );
+
+        // Index to the vertex.
+        unsigned int v = 0u;
+
+        // Traverse all quads.
+        for( std::vector<QuadCoordinates>::iterator it = mHighlightQuadList.begin(),
+               endIt = mHighlightQuadList.end();
+             it != endIt;
+             ++it, v += 4u )
         {
-          QuadCoordinates& quad = *iter;
+          QuadCoordinates& quad = *it;
+
+          Vector2 vertex;
 
           // top-left (v+0)
-          vertex.x = quad.min.x;
-          vertex.y = quad.min.y;
+          vertex.x = quad.min.x - offsetX;
+          vertex.y = quad.min.y - offsetY;
           vertices.PushBack( vertex );
 
           // top-right (v+1)
-          vertex.x = quad.max.x;
-          vertex.y = quad.min.y;
+          vertex.x = quad.max.x - offsetX;
+          vertex.y = quad.min.y - offsetY;
           vertices.PushBack( vertex );
 
           // bottom-left (v+2)
-          vertex.x = quad.min.x;
-          vertex.y = quad.max.y;
+          vertex.x = quad.min.x - offsetX;
+          vertex.y = quad.max.y - offsetY;
           vertices.PushBack( vertex );
 
           // bottom-right (v+3)
-          vertex.x = quad.max.x;
-          vertex.y = quad.max.y;
+          vertex.x = quad.max.x - offsetX;
+          vertex.y = quad.max.y - offsetY;
           vertices.PushBack( vertex );
 
           // triangle A (3, 1, 0)
@@ -1073,9 +1139,6 @@ struct Decorator::Impl : public ConnectionTracker
         }
       }
 
-      mHighlightActor.SetPosition( mHighlightPosition.x,
-                                   mHighlightPosition.y );
-
       mHighlightQuadList.clear();
 
       if( mHighlightRenderer )
@@ -1085,45 +1148,57 @@ struct Decorator::Impl : public ConnectionTracker
     }
   }
 
-  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.f;
+
+      handle.globalPosition.x = handle.position.x;
+      handle.globalPosition.y = handle.position.y;
     }
 
     handle.grabDisplacementX += gesture.displacement.x;
     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;
@@ -1131,10 +1206,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 ) )
@@ -1155,7 +1230,7 @@ struct Decorator::Impl : public ConnectionTracker
       }
       handle.pressed = false;
 
-      mHandlePanning = false;
+      mIsHandlePanning = false;
     }
   }
 
@@ -1181,20 +1256,22 @@ struct Decorator::Impl : public ConnectionTracker
 
   bool OnGrabHandleTouched( Actor actor, const TouchData& touch )
   {
+    HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+
     // Switch between pressed/release grab-handle images
     if( touch.GetPointCount() > 0 &&
-        mHandle[GRAB_HANDLE].actor )
+        grabHandle.actor )
     {
       const PointState::Type state = touch.GetState( 0 );
 
       if( PointState::DOWN == state )
       {
-        mHandle[GRAB_HANDLE].pressed = true;
+        grabHandle.pressed = true;
       }
       else if( ( PointState::UP == state ) ||
                ( PointState::INTERRUPTED == state ) )
       {
-        mHandle[GRAB_HANDLE].pressed = false;
+        grabHandle.pressed = false;
       }
 
       SetHandleImage( GRAB_HANDLE );
@@ -1206,22 +1283,24 @@ struct Decorator::Impl : public ConnectionTracker
 
   bool OnHandleOneTouched( Actor actor, const TouchData& touch )
   {
+    HandleImpl& primarySelectionHandle = mHandle[LEFT_SELECTION_HANDLE];
+
     // Switch between pressed/release selection handle images
     if( touch.GetPointCount() > 0 &&
-        mHandle[LEFT_SELECTION_HANDLE].actor )
+        primarySelectionHandle.actor )
     {
       const PointState::Type state = touch.GetState( 0 );
 
       if( PointState::DOWN == state )
       {
-        mHandle[LEFT_SELECTION_HANDLE].pressed = true;
+        primarySelectionHandle.pressed = true;
       }
       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 );
@@ -1233,22 +1312,24 @@ struct Decorator::Impl : public ConnectionTracker
 
   bool OnHandleTwoTouched( Actor actor, const TouchData& touch )
   {
+    HandleImpl& secondarySelectionHandle = mHandle[RIGHT_SELECTION_HANDLE];
+
     // Switch between pressed/release selection handle images
     if( touch.GetPointCount() > 0 &&
-        mHandle[RIGHT_SELECTION_HANDLE].actor )
+        secondarySelectionHandle.actor )
     {
       const PointState::Type state = touch.GetState( 0 );
 
       if( PointState::DOWN == state )
       {
-        mHandle[RIGHT_SELECTION_HANDLE].pressed = true;
+        secondarySelectionHandle.pressed = true;
       }
       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 );
@@ -1626,10 +1707,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;
@@ -1637,8 +1747,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.
 
@@ -1671,7 +1783,8 @@ struct Decorator::Impl : public ConnectionTracker
   Vector4             mBoundingBox;               ///< The bounding box in world coords.
   Vector4             mHighlightColor;            ///< Color of the highlight
   Vector2             mHighlightPosition;         ///< The position of the highlight actor.
-  Vector2             mControlSize;               ///< The control's size. Set by the Relayout.
+  Size                mHighlightSize;             ///< The size of the highlighted text.
+  Size                mControlSize;               ///< The control's size. Set by the Relayout.
 
   unsigned int        mActiveCursor;
   unsigned int        mCursorBlinkInterval;
@@ -1693,10 +1806,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,
@@ -1740,18 +1856,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
@@ -1839,7 +1959,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.
@@ -1886,12 +2006,15 @@ void Decorator::SetPosition( HandleType handleType, float x, float y, float heig
   // 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
@@ -1925,7 +2048,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;
 }
@@ -1935,6 +2058,12 @@ void Decorator::AddHighlight( float x1, float y1, float x2, float y2 )
   mImpl->mHighlightQuadList.push_back( QuadCoordinates(x1, y1, x2, y2) );
 }
 
+void Decorator::SetHighLightBox( const Vector2& position, const Size& size )
+{
+  mImpl->mHighlightPosition = position;
+  mImpl->mHighlightSize = size;
+}
+
 void Decorator::ClearHighlights()
 {
   mImpl->mHighlightQuadList.clear();
@@ -2015,6 +2144,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;