Rendering API clean-up
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / decorator / text-decorator.cpp
index bd6a843..bb393ff 100644 (file)
@@ -33,8 +33,9 @@
 #include <dali/devel-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
@@ -220,9 +221,9 @@ struct Decorator::Impl : public ConnectionTracker
     {
     }
 
-    ImageActor actor;
+    ImageView actor;
     Actor grabArea;
-    ImageActor markerActor;
+    ImageView markerActor;
 
     Vector2 position;
     Size    size;
@@ -283,8 +284,7 @@ struct Decorator::Impl : public ConnectionTracker
   {
     mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
     mQuadIndexFormat[ "indices" ] = Property::INTEGER;
-    mHighlightMaterial = Material::New( Shader::New( VERTEX_SHADER, FRAGMENT_SHADER ) );
-
+    mHighlightShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
     SetupTouchEvents();
   }
 
@@ -294,6 +294,8 @@ struct Decorator::Impl : public ConnectionTracker
    */
   void Relayout( const Vector2& size )
   {
+    mControlSize = size;
+
     // TODO - Remove this if nothing is active
     CreateActiveLayer();
 
@@ -303,7 +305,7 @@ struct Decorator::Impl : public ConnectionTracker
     if( mPrimaryCursor )
     {
       const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
-      mPrimaryCursorVisible = ( cursor.position.x + mCursorWidth <= size.width ) && ( cursor.position.x >= 0.f );
+      mPrimaryCursorVisible = ( cursor.position.x + mCursorWidth <= mControlSize.width ) && ( cursor.position.x >= 0.f );
       if( mPrimaryCursorVisible )
       {
         mPrimaryCursor.SetPosition( cursor.position.x,
@@ -315,7 +317,7 @@ struct Decorator::Impl : public ConnectionTracker
     if( mSecondaryCursor )
     {
       const CursorImpl& cursor = mCursor[SECONDARY_CURSOR];
-      mSecondaryCursorVisible = ( cursor.position.x + mCursorWidth <= size.width ) && ( cursor.position.x >= 0.f );
+      mSecondaryCursorVisible = ( cursor.position.x + mCursorWidth <= mControlSize.width ) && ( cursor.position.x >= 0.f );
       if( mSecondaryCursorVisible )
       {
         mSecondaryCursor.SetPosition( cursor.position.x,
@@ -327,9 +329,10 @@ struct Decorator::Impl : public ConnectionTracker
 
     // Show or hide the grab handle
     HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+    bool newGrabHandlePosition = false;
     if( grabHandle.active )
     {
-      const bool isVisible = ( grabHandle.position.x + floor( 0.5f * mCursorWidth ) <= size.width ) && ( grabHandle.position.x >= 0.f );
+      const bool isVisible = ( grabHandle.position.x + floor( 0.5f * mCursorWidth ) <= mControlSize.width ) && ( grabHandle.position.x >= 0.f );
 
       if( isVisible )
       {
@@ -340,6 +343,8 @@ struct Decorator::Impl : public ConnectionTracker
 
         // Sets the grab handle image according if it's pressed, flipped, etc.
         SetHandleImage( GRAB_HANDLE );
+
+        newGrabHandlePosition = true;
       }
 
       if( grabHandle.actor )
@@ -355,10 +360,12 @@ struct Decorator::Impl : public ConnectionTracker
     // Show or hide the selection handles/highlight
     HandleImpl& primary = mHandle[ LEFT_SELECTION_HANDLE ];
     HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
+    bool newPrimaryHandlePosition = false;
+    bool newSecondaryHandlePosition = false;
     if( primary.active || secondary.active )
     {
-      const bool isPrimaryVisible = ( primary.position.x <= size.width ) && ( primary.position.x >= 0.f );
-      const bool isSecondaryVisible = ( secondary.position.x <= size.width ) && ( secondary.position.x >= 0.f );
+      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 );
 
       if( isPrimaryVisible || isSecondaryVisible )
       {
@@ -372,6 +379,8 @@ struct Decorator::Impl : public ConnectionTracker
           SetHandleImage( LEFT_SELECTION_HANDLE );
 
           SetSelectionHandleMarkerSize( primary );
+
+          newPrimaryHandlePosition = true;
         }
 
         if( isSecondaryVisible )
@@ -382,6 +391,8 @@ struct Decorator::Impl : public ConnectionTracker
           SetHandleImage( RIGHT_SELECTION_HANDLE );
 
           SetSelectionHandleMarkerSize( secondary );
+
+          newSecondaryHandlePosition = true;
         }
       }
 
@@ -413,9 +424,18 @@ struct Decorator::Impl : public ConnectionTracker
       }
     }
 
+    if( newGrabHandlePosition    ||
+        newPrimaryHandlePosition ||
+        newSecondaryHandlePosition )
+    {
+      // Setup property notifications to find whether the handles leave the boundaries of the current display.
+      SetupActiveLayerPropertyNotifications();
+    }
+
     if( mActiveCopyPastePopup )
     {
       ShowPopup();
+      mPopupSetNewPosition = true;
     }
     else
     {
@@ -503,11 +523,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 );
   }
 
@@ -615,7 +635,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 );
@@ -637,41 +656,47 @@ 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 ) )
+      if( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] )
       {
-        grabHandle.grabArea = Toolkit::CreateSolidColorActor( Vector4(0.0f, 0.0f, 0.0f, 0.0f), true, Color::RED, 1 );
-        grabHandle.grabArea.SetName( "GrabArea" );
-      }
-      else
-      {
-        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.TouchedSignal().Connect( this, &Decorator::Impl::OnGrabHandleTouched );
+        mTapDetector.Attach( grabHandle.grabArea );
+        mPanGestureDetector.Attach( grabHandle.grabArea );
 
-      mActiveLayer.Add( grabHandle.actor );
+        mActiveLayer.Add( grabHandle.actor );
+      }
     }
 
-    if( !grabHandle.actor.GetParent() )
+    if( grabHandle.actor && !grabHandle.actor.GetParent() )
     {
       mActiveLayer.Add( grabHandle.actor );
     }
@@ -681,7 +706,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 );
 
@@ -705,33 +730,36 @@ 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 );
 
-      mTapDetector.Attach( primary.grabArea );
-      mPanGestureDetector.Attach( primary.grabArea );
-      primary.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnHandleOneTouched );
+        mTapDetector.Attach( primary.grabArea );
+        mPanGestureDetector.Attach( primary.grabArea );
+        primary.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnHandleOneTouched );
 
-      primary.actor.Add( primary.grabArea );
+        primary.actor.Add( primary.grabArea );
 
-      CreateHandleMarker( primary, mHandleImages[LEFT_SELECTION_HANDLE_MARKER][HANDLE_IMAGE_RELEASED], LEFT_SELECTION_HANDLE );
+        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 );
     }
@@ -739,33 +767,36 @@ 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 );
+        mTapDetector.Attach( secondary.grabArea );
+        mPanGestureDetector.Attach( secondary.grabArea );
+        secondary.grabArea.TouchedSignal().Connect( this, &Decorator::Impl::OnHandleTwoTouched );
 
-      secondary.actor.Add( secondary.grabArea );
+        secondary.actor.Add( secondary.grabArea );
 
-      CreateHandleMarker( secondary, mHandleImages[RIGHT_SELECTION_HANDLE_MARKER][HANDLE_IMAGE_RELEASED], RIGHT_SELECTION_HANDLE  );
+        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 );
     }
@@ -773,16 +804,14 @@ struct Decorator::Impl : public ConnectionTracker
 
   void CalculateHandleWorldCoordinates( HandleImpl& handle, Vector2& position )
   {
-    // Get the world position of the active layer
+    // Gets the world position of the active layer. The active layer is where the handles are added.
     const Vector3 parentWorldPosition = mActiveLayer.GetCurrentWorldPosition();
 
-    // Get the size of the UI control.
-    Vector2 targetSize;
-    mController.GetTargetSize( targetSize );
-
     // The grab handle position in world coords.
-    position.x = parentWorldPosition.x - 0.5f * targetSize.width + handle.position.x;
-    position.y = parentWorldPosition.y - 0.5f * targetSize.height + handle.position.y + handle.lineHeight;
+    // 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;
   }
 
   void SetGrabHandlePosition()
@@ -790,7 +819,12 @@ struct Decorator::Impl : public ConnectionTracker
     // Reference to the grab handle.
     HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
 
-    // The grab handle position in world coords.
+    // Transforms the handle position into world coordinates.
+    // @note This is not the same value as grabHandle.actor.GetCurrentWorldPosition()
+    // as it's transforming the handle's position set by the text-controller and not
+    // the final position set to the actor. Another difference is the GetCurrentWorldPosition()
+    // retrieves the position of the center of the actor but the handle's position set
+    // by the text controller is not the center of the actor.
     Vector2 grabHandleWorldPosition;
     CalculateHandleWorldCoordinates( grabHandle, grabHandleWorldPosition );
 
@@ -798,8 +832,8 @@ struct Decorator::Impl : public ConnectionTracker
     // At the moment only the height is checked for the grab handle.
 
     grabHandle.verticallyFlipped = ( grabHandle.verticallyFlippedPreferred &&
-                                     ( ( grabHandleWorldPosition.y - grabHandle.lineHeight - grabHandle.size.height ) > mBoundingBox.y ) ) ||
-                                   ( grabHandleWorldPosition.y + grabHandle.size.height > mBoundingBox.w );
+                                     ( ( grabHandleWorldPosition.y - grabHandle.size.height ) > mBoundingBox.y ) ) ||
+                                   ( grabHandleWorldPosition.y + grabHandle.lineHeight + grabHandle.size.height > mBoundingBox.w );
 
     // The grab handle 'y' position in local coords.
     // If the grab handle exceeds the bottom of the decoration box,
@@ -807,8 +841,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 ),
+                                    yLocalPosition ); // TODO : Fix for multiline.
+    }
   }
 
   void SetSelectionHandlePosition( HandleType type )
@@ -818,7 +855,12 @@ struct Decorator::Impl : public ConnectionTracker
     // Reference to the selection handle.
     HandleImpl& handle = mHandle[type];
 
-    // Get the world coordinates of the handle position.
+    // Transforms the handle position into world coordinates.
+    // @note This is not the same value as handle.actor.GetCurrentWorldPosition()
+    // as it's transforming the handle's position set by the text-controller and not
+    // the final position set to the actor. Another difference is the GetCurrentWorldPosition()
+    // retrieves the position of the center of the actor but the handle's position set
+    // by the text controller is not the center of the actor.
     Vector2 handleWorldPosition;
     CalculateHandleWorldCoordinates( handle, handleWorldPosition );
 
@@ -852,7 +894,6 @@ struct Decorator::Impl : public ConnectionTracker
 
     // Check if the selection handle exceeds the boundaries of the decoration box.
     const bool exceedsLeftEdge = ( isPrimaryHandle ? !flipHandle : flipHandle ) && ( handleWorldPosition.x - handle.size.width < mBoundingBox.x );
-
     const bool exceedsRightEdge = ( isPrimaryHandle ? flipHandle : !flipHandle ) && ( handleWorldPosition.x + handle.size.width > mBoundingBox.z );
 
     // Does not flip if both conditions are true (double flip)
@@ -860,7 +901,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 );
@@ -870,7 +911,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 );
@@ -881,8 +922,8 @@ struct Decorator::Impl : public ConnectionTracker
 
     // Whether to flip the handle vertically.
     handle.verticallyFlipped = ( verticallyFlippedPreferred &&
-                                 ( ( handleWorldPosition.y - handle.lineHeight - handle.size.height ) > mBoundingBox.y ) ) ||
-                               ( handleWorldPosition.y + handle.size.height > mBoundingBox.w );
+                                 ( ( handleWorldPosition.y - handle.size.height ) > mBoundingBox.y ) ) ||
+                               ( handleWorldPosition.y + handle.lineHeight + handle.size.height > mBoundingBox.w );
 
     // The primary selection handle 'y' position in local coords.
     // If the handle exceeds the bottom of the decoration box,
@@ -890,8 +931,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,
+                                yLocalPosition ); // TODO : Fix for multiline.
+    }
   }
 
   void SetHandleImage( HandleType type )
@@ -1002,26 +1046,18 @@ struct Decorator::Impl : public ConnectionTracker
           indices.PushBack( v + 3 );
         }
 
-        if( mQuadVertices )
+        if( mQuadVertices )
         {
-          mQuadVertices.SetSize( vertices.Size() );
-        }
-        else
-        {
-          mQuadVertices = PropertyBuffer::New( mQuadVertexFormat, vertices.Size() );
+          mQuadVertices = PropertyBuffer::New( mQuadVertexFormat );
         }
 
-        if( mQuadIndices )
+        if( mQuadIndices )
         {
-          mQuadIndices.SetSize( indices.Size() );
-        }
-        else
-        {
-          mQuadIndices = PropertyBuffer::New( mQuadIndexFormat, indices.Size() );
+          mQuadIndices = PropertyBuffer::New( mQuadIndexFormat );
         }
 
-        mQuadVertices.SetData( &vertices[ 0 ] );
-        mQuadIndices.SetData( &indices[ 0 ] );
+        mQuadVertices.SetData( &vertices[ 0 ], vertices.Size() );
+        mQuadIndices.SetData( &indices[ 0 ], indices.Size() );
 
         if( !mQuadGeometry )
         {
@@ -1032,7 +1068,7 @@ struct Decorator::Impl : public ConnectionTracker
 
         if( !mHighlightRenderer )
         {
-          mHighlightRenderer = Dali::Renderer::New( mQuadGeometry, mHighlightMaterial );
+          mHighlightRenderer = Dali::Renderer::New( mQuadGeometry, mHighlightShader );
           mHighlightActor.AddRenderer( mHighlightRenderer );
         }
       }
@@ -1044,7 +1080,7 @@ 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.
       }
     }
   }
@@ -1113,7 +1149,10 @@ 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;
@@ -1219,6 +1258,213 @@ struct Decorator::Impl : public ConnectionTracker
     return true;
   }
 
+  void HandleResetPosition( PropertyNotification& source )
+  {
+    const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+
+    if( grabHandle.active )
+    {
+      // Sets the grab handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
+      SetGrabHandlePosition();
+
+      // Sets the grab handle image according if it's pressed, flipped, etc.
+      SetHandleImage( GRAB_HANDLE );
+    }
+    else
+    {
+      // Sets the primary selection handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
+      SetSelectionHandlePosition( LEFT_SELECTION_HANDLE );
+
+      // Sets the primary handle image according if it's pressed, flipped, etc.
+      SetHandleImage( LEFT_SELECTION_HANDLE );
+
+      // Sets the secondary selection handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
+      SetSelectionHandlePosition( RIGHT_SELECTION_HANDLE );
+
+      // Sets the secondary handle image according if it's pressed, flipped, etc.
+      SetHandleImage( RIGHT_SELECTION_HANDLE );
+    }
+  }
+
+  void SetupActiveLayerPropertyNotifications()
+  {
+    if( !mActiveLayer )
+    {
+      return;
+    }
+
+    // Vertical notifications.
+
+    // Disconnect any previous connected callback.
+    if( mVerticalLessThanNotification )
+    {
+      mVerticalLessThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+      mActiveLayer.RemovePropertyNotification( mVerticalLessThanNotification );
+    }
+
+    if( mVerticalGreaterThanNotification )
+    {
+      mVerticalGreaterThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+      mActiveLayer.RemovePropertyNotification( mVerticalGreaterThanNotification );
+    }
+
+    const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+    const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
+    const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
+
+    if( grabHandle.active )
+    {
+      if( grabHandle.verticallyFlipped )
+      {
+        // The grab handle is vertically flipped. Never is going to exceed the bottom edje of the display.
+        mVerticalGreaterThanNotification.Reset();
+
+        // The vertical distance from the center of the active layer to the top edje of the display.
+        const float topHeight = 0.5f * mControlSize.height - grabHandle.position.y + grabHandle.size.height;
+
+        mVerticalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                              LessThanCondition( mBoundingBox.y + topHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mVerticalLessThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mVerticalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+      else
+      {
+        // The grab handle is not vertically flipped. Never is going to exceed the top edje of the display.
+        mVerticalLessThanNotification.Reset();
+
+        // The vertical distance from the center of the active layer to the bottom edje of the display.
+        const float bottomHeight = -0.5f * mControlSize.height + grabHandle.position.y + grabHandle.lineHeight + grabHandle.size.height;
+
+        mVerticalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                 GreaterThanCondition( mBoundingBox.w - bottomHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mVerticalGreaterThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mVerticalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+    }
+    else // The selection handles are active
+    {
+      if( primaryHandle.verticallyFlipped && secondaryHandle.verticallyFlipped )
+      {
+        // Both selection handles are vertically flipped. Never are going to exceed the bottom edje of the display.
+        mVerticalGreaterThanNotification.Reset();
+
+        // The vertical distance from the center of the active layer to the top edje of the display.
+        const float topHeight = 0.5f * mControlSize.height + std::max( -primaryHandle.position.y + primaryHandle.size.height, -secondaryHandle.position.y + secondaryHandle.size.height );
+
+        mVerticalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                              LessThanCondition( mBoundingBox.y + topHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mVerticalLessThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mVerticalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+      else if( !primaryHandle.verticallyFlipped && !secondaryHandle.verticallyFlipped )
+      {
+        // Both selection handles aren't vertically flipped. Never are going to exceed the top edje of the display.
+        mVerticalLessThanNotification.Reset();
+
+        // The vertical distance from the center of the active layer to the bottom edje of the display.
+        const float bottomHeight = -0.5f * mControlSize.height + std::max( primaryHandle.position.y + primaryHandle.lineHeight + primaryHandle.size.height,
+                                                                           secondaryHandle.position.y + secondaryHandle.lineHeight + secondaryHandle.size.height );
+
+        mVerticalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                 GreaterThanCondition( mBoundingBox.w - bottomHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mVerticalGreaterThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mVerticalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+      else
+      {
+        // Only one of the selection handles is vertically flipped. Both vertical notifications are needed.
+
+        // The vertical distance from the center of the active layer to the top edje of the display.
+        const float topHeight = 0.5f * mControlSize.height + ( primaryHandle.verticallyFlipped                              ?
+                                                               -primaryHandle.position.y + primaryHandle.size.height        :
+                                                               -secondaryHandle.position.y + secondaryHandle.size.height );
+
+        mVerticalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                              LessThanCondition( mBoundingBox.y + topHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mVerticalLessThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mVerticalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+
+        // The vertical distance from the center of the active layer to the bottom edje of the display.
+        const float bottomHeight = -0.5f * mControlSize.height + ( primaryHandle.verticallyFlipped                                                       ?
+                                                                   secondaryHandle.position.y + secondaryHandle.lineHeight + secondaryHandle.size.height :
+                                                                   primaryHandle.position.y + primaryHandle.lineHeight + primaryHandle.size.height );
+
+        mVerticalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+                                                                                 GreaterThanCondition( mBoundingBox.w - bottomHeight ) );
+
+        // Notifies the change from false to true and from true to false.
+        mVerticalGreaterThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+        // Connects the signals with the callbacks.
+        mVerticalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+      }
+    }
+
+    // Horizontal notifications.
+
+    // Disconnect any previous connected callback.
+    if( mHorizontalLessThanNotification )
+    {
+      mHorizontalLessThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+      mActiveLayer.RemovePropertyNotification( mHorizontalLessThanNotification );
+    }
+
+    if( mHorizontalGreaterThanNotification )
+    {
+      mHorizontalGreaterThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+      mActiveLayer.RemovePropertyNotification( mHorizontalGreaterThanNotification );
+    }
+
+    if( primaryHandle.active || secondaryHandle.active )
+    {
+      // The horizontal distance from the center of the active layer to the left edje of the display.
+      const float leftWidth = 0.5f * mControlSize.width + std::max( -primaryHandle.position.x + primaryHandle.size.width,
+                                                                    -secondaryHandle.position.x + secondaryHandle.size.width );
+
+      mHorizontalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_X,
+                                                                              LessThanCondition( mBoundingBox.x + leftWidth ) );
+
+      // Notifies the change from false to true and from true to false.
+      mHorizontalLessThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+      // Connects the signals with the callbacks.
+      mHorizontalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+
+      // The horizontal distance from the center of the active layer to the right edje of the display.
+      const float rightWidth = -0.5f * mControlSize.width + std::max( primaryHandle.position.x + primaryHandle.size.width,
+                                                                      secondaryHandle.position.x + secondaryHandle.size.width );
+
+      mHorizontalGreaterThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_X,
+                                                                                 GreaterThanCondition( mBoundingBox.z - rightWidth ) );
+
+      // Notifies the change from false to true and from true to false.
+      mHorizontalGreaterThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+      // Connects the signals with the callbacks.
+      mHorizontalGreaterThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+    }
+  }
+
   // Popup
 
   float AlternatePopUpPositionRelativeToCursor()
@@ -1255,7 +1501,7 @@ struct Decorator::Impl : public ConnectionTracker
     mCopyPastePopup.actor.SetY( alternativeYPosition );
   }
 
-  void SetUpPopupPositionNotifications( )
+  void SetUpPopupPositionNotifications()
   {
     // Note Property notifications ignore any set anchor point so conditions must allow for this.  Default is Top Left.
 
@@ -1396,13 +1642,17 @@ struct Decorator::Impl : public ConnectionTracker
   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.
 
-  Layer               mActiveLayer;               ///< Layer for active handles and alike that ensures they are above all else.
-  ImageActor          mPrimaryCursor;
-  ImageActor          mSecondaryCursor;
+  Layer                mActiveLayer;                       ///< Layer for active handles and alike that ensures they are above all else.
+  PropertyNotification mVerticalLessThanNotification;      ///< Notifies when the 'y' coord of the active layer is less than a given value.
+  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.
+  Control              mPrimaryCursor;
+  Control              mSecondaryCursor;
 
-  Actor               mHighlightActor;        ///< Actor to display highlight
+  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;
@@ -1423,6 +1673,7 @@ 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.
 
   unsigned int        mActiveCursor;
   unsigned int        mCursorBlinkInterval;
@@ -1598,10 +1849,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 );
     }
   }
 
@@ -1634,7 +1885,7 @@ 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;