(Text Controller Impl) Moved event handling related methods into a separate struct
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-impl.cpp
old mode 100755 (executable)
new mode 100644 (file)
index 8f4de65..0cd6adb
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@
 #include <dali-toolkit/internal/text/text-controller-impl.h>
 
 // EXTERNAL INCLUDES
-#include <dali/public-api/adaptor-framework/key.h>
 #include <dali/public-api/rendering/renderer.h>
 #include <dali/integration-api/debug.h>
 #include <limits>
@@ -34,6 +33,7 @@
 #include <dali-toolkit/internal/text/segmentation.h>
 #include <dali-toolkit/internal/text/shaper.h>
 #include <dali-toolkit/internal/text/text-control-interface.h>
+#include <dali-toolkit/internal/text/text-controller-impl-event-handler.h>
 #include <dali-toolkit/internal/text/text-run-container.h>
 
 using namespace Dali;
@@ -53,7 +53,7 @@ struct SelectionBoxInfo
 };
 
 #if defined(DEBUG_ENABLED)
-  Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
 #endif
 
 const float MAX_FLOAT = std::numeric_limits<float>::max();
@@ -159,7 +159,8 @@ EventData::EventData( DecoratorPtr decorator, InputMethodContext& inputMethodCon
   mIsPlaceholderElideEnabled( false ),
   mPlaceholderEllipsisFlag( false ),
   mShiftSelectionFlag( true ),
-  mUpdateAlignment( false )
+  mUpdateAlignment( false ),
+  mEditingEnabled( true )
 {
 }
 
@@ -221,6 +222,11 @@ bool Controller::Impl::ProcessInputEvents()
           OnSelectAllEvent();
           break;
         }
+        case Event::SELECT_NONE:
+        {
+          OnSelectNoneEvent();
+          break;
+        }
       }
     }
   }
@@ -1335,683 +1341,104 @@ float Controller::Impl::GetDefaultFontLineHeight()
 
 void Controller::Impl::OnCursorKeyEvent( const Event& event )
 {
-  if( NULL == mEventData || !IsShowingRealText() )
-  {
-    // Nothing to do if there is no text input.
-    return;
-  }
-
-  int keyCode = event.p1.mInt;
-  bool isShiftModifier = event.p2.mBool;
-
-  CharacterIndex previousPrimaryCursorPosition = mEventData->mPrimaryCursorPosition;
-
-  if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
-  {
-    if( mEventData->mPrimaryCursorPosition > 0u )
-    {
-      if ( !isShiftModifier && mEventData->mDecorator->IsHighlightVisible() )
-      {
-        mEventData->mPrimaryCursorPosition = std::min(mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
-      }
-      else
-      {
-        mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition - 1u );
-      }
-    }
-  }
-  else if( Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
-  {
-    if( mModel->mLogicalModel->mText.Count() > mEventData->mPrimaryCursorPosition )
-    {
-      if ( !isShiftModifier && mEventData->mDecorator->IsHighlightVisible() )
-      {
-        mEventData->mPrimaryCursorPosition = std::max(mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition);
-      }
-      else
-      {
-        mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
-      }
-    }
-  }
-  else if( Dali::DALI_KEY_CURSOR_UP == keyCode && !isShiftModifier )
-  {
-    // Ignore Shift-Up for text selection for now.
-
-    // Get first the line index of the current cursor position index.
-    CharacterIndex characterIndex = 0u;
-
-    if( mEventData->mPrimaryCursorPosition > 0u )
-    {
-      characterIndex = mEventData->mPrimaryCursorPosition - 1u;
-    }
-
-    const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
-    const LineIndex previousLineIndex = ( lineIndex > 0 ? lineIndex - 1u : lineIndex );
-
-    // Retrieve the cursor position info.
-    CursorInfo cursorInfo;
-    GetCursorPosition( mEventData->mPrimaryCursorPosition,
-                       cursorInfo );
-
-    // Get the line above.
-    const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + previousLineIndex );
-
-    // Get the next hit 'y' point.
-    const float hitPointY = cursorInfo.lineOffset - 0.5f * ( line.ascender - line.descender );
-
-    // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
-    bool matchedCharacter = false;
-    mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
-                                                                      mModel->mLogicalModel,
-                                                                      mMetrics,
-                                                                      mEventData->mCursorHookPositionX,
-                                                                      hitPointY,
-                                                                      CharacterHitTest::TAP,
-                                                                      matchedCharacter );
-  }
-  else if( Dali::DALI_KEY_CURSOR_DOWN == keyCode && !isShiftModifier )
-  {
-    // Ignore Shift-Down for text selection for now.
-
-    // Get first the line index of the current cursor position index.
-    CharacterIndex characterIndex = 0u;
-
-    if( mEventData->mPrimaryCursorPosition > 0u )
-    {
-      characterIndex = mEventData->mPrimaryCursorPosition - 1u;
-    }
-
-    const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( characterIndex );
-
-    if( lineIndex + 1u < mModel->mVisualModel->mLines.Count() )
-    {
-      // Retrieve the cursor position info.
-      CursorInfo cursorInfo;
-      GetCursorPosition( mEventData->mPrimaryCursorPosition,
-                         cursorInfo );
-
-      // Get the line below.
-      const LineRun& line = *( mModel->mVisualModel->mLines.Begin() + lineIndex + 1u );
-
-      // Get the next hit 'y' point.
-      const float hitPointY = cursorInfo.lineOffset + cursorInfo.lineHeight + 0.5f * ( line.ascender - line.descender );
-
-      // Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
-      bool matchedCharacter = false;
-      mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
-                                                                        mModel->mLogicalModel,
-                                                                        mMetrics,
-                                                                        mEventData->mCursorHookPositionX,
-                                                                        hitPointY,
-                                                                        CharacterHitTest::TAP,
-                                                                        matchedCharacter );
-    }
-  }
-
-  if ( !isShiftModifier && mEventData->mState != EventData::SELECTING )
-  {
-    // Update selection position after moving the cursor
-    mEventData->mLeftSelectionPosition = mEventData->mPrimaryCursorPosition;
-    mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
-  }
-
-  if ( isShiftModifier && IsShowingRealText() && mEventData->mShiftSelectionFlag )
-  {
-    // Handle text selection
-    bool selecting = false;
-
-    if ( Dali::DALI_KEY_CURSOR_LEFT == keyCode || Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
-    {
-      // Shift-Left/Right to select the text
-      int cursorPositionDelta = mEventData->mPrimaryCursorPosition - previousPrimaryCursorPosition;
-      if ( cursorPositionDelta > 0 || mEventData->mRightSelectionPosition > 0u ) // Check the boundary
-      {
-        mEventData->mRightSelectionPosition += cursorPositionDelta;
-      }
-      selecting = true;
-    }
-    else if ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition )
-    {
-      // Show no grab handles and text highlight if Shift-Up/Down pressed but no selected text
-      selecting = true;
-    }
-
-    if ( selecting )
-    {
-      // Notify the cursor position to the InputMethodContext.
-      if( mEventData->mInputMethodContext )
-      {
-        mEventData->mInputMethodContext.SetCursorPosition( mEventData->mPrimaryCursorPosition );
-        mEventData->mInputMethodContext.NotifyCursorPosition();
-      }
-
-      ChangeState( EventData::SELECTING );
-
-      mEventData->mUpdateLeftSelectionPosition = true;
-      mEventData->mUpdateRightSelectionPosition = true;
-      mEventData->mUpdateGrabHandlePosition = true;
-      mEventData->mUpdateHighlightBox = true;
-
-      // Hide the text selection popup if select the text using keyboard instead of moving grab handles
-      if( mEventData->mGrabHandlePopupEnabled )
-      {
-        mEventData->mDecorator->SetPopupActive( false );
-      }
-    }
-  }
-  else
-  {
-    // Handle normal cursor move
-    ChangeState( EventData::EDITING );
-    mEventData->mUpdateCursorPosition = true;
-  }
-
-  mEventData->mUpdateInputStyle = true;
-  mEventData->mScrollAfterUpdatePosition = true;
+  ControllerImplEventHandler::OnCursorKeyEvent(*this, event);
 }
 
 void Controller::Impl::OnTapEvent( const Event& event )
 {
-  if( NULL != mEventData )
-  {
-    const unsigned int tapCount = event.p1.mUint;
-
-    if( 1u == tapCount )
-    {
-      if( IsShowingRealText() )
-      {
-        // Convert from control's coords to text's coords.
-        const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
-        const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
-
-        // Keep the tap 'x' position. Used to move the cursor.
-        mEventData->mCursorHookPositionX = xPosition;
-
-        // Whether to touch point hits on a glyph.
-        bool matchedCharacter = false;
-        mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
-                                                                          mModel->mLogicalModel,
-                                                                          mMetrics,
-                                                                          xPosition,
-                                                                          yPosition,
-                                                                          CharacterHitTest::TAP,
-                                                                          matchedCharacter );
-
-        // When the cursor position is changing, delay cursor blinking
-        mEventData->mDecorator->DelayCursorBlink();
-      }
-      else
-      {
-        mEventData->mPrimaryCursorPosition = 0u;
-      }
-
-      // Update selection position after tapping
-      mEventData->mLeftSelectionPosition = mEventData->mPrimaryCursorPosition;
-      mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
-
-      mEventData->mUpdateCursorPosition = true;
-      mEventData->mUpdateGrabHandlePosition = true;
-      mEventData->mScrollAfterUpdatePosition = true;
-      mEventData->mUpdateInputStyle = true;
-
-      // Notify the cursor position to the InputMethodContext.
-      if( mEventData->mInputMethodContext )
-      {
-        mEventData->mInputMethodContext.SetCursorPosition( mEventData->mPrimaryCursorPosition );
-        mEventData->mInputMethodContext.NotifyCursorPosition();
-      }
-    }
-    else if( 2u == tapCount )
-    {
-      if( mEventData->mSelectionEnabled )
-      {
-        // Convert from control's coords to text's coords.
-        const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
-        const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
-
-        // Calculates the logical position from the x,y coords.
-        RepositionSelectionHandles( xPosition,
-                                    yPosition,
-                                    mEventData->mDoubleTapAction );
-      }
-    }
-  }
+  ControllerImplEventHandler::OnTapEvent(*this, event);
 }
 
 void Controller::Impl::OnPanEvent( const Event& event )
 {
-  if( NULL == mEventData )
-  {
-    // Nothing to do if there is no text input.
-    return;
-  }
-
-  const bool isHorizontalScrollEnabled = mEventData->mDecorator->IsHorizontalScrollEnabled();
-  const bool isVerticalScrollEnabled = mEventData->mDecorator->IsVerticalScrollEnabled();
-
-  if( !isHorizontalScrollEnabled && !isVerticalScrollEnabled )
-  {
-    // Nothing to do if scrolling is not enabled.
-    return;
-  }
-
-  const int state = event.p1.mInt;
-
-  switch( state )
-  {
-    case Gesture::Started:
-    {
-      // Will remove the cursor, handles or text's popup, ...
-      ChangeState( EventData::TEXT_PANNING );
-      break;
-    }
-    case Gesture::Continuing:
-    {
-      const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
-      const Vector2 currentScroll = mModel->mScrollPosition;
-
-      if( isHorizontalScrollEnabled )
-      {
-        const float displacementX = event.p2.mFloat;
-        mModel->mScrollPosition.x += displacementX;
-
-        ClampHorizontalScroll( layoutSize );
-      }
-
-      if( isVerticalScrollEnabled )
-      {
-        const float displacementY = event.p3.mFloat;
-        mModel->mScrollPosition.y += displacementY;
+  ControllerImplEventHandler::OnPanEvent(*this, event);
+}
 
-        ClampVerticalScroll( layoutSize );
-      }
+void Controller::Impl::OnLongPressEvent( const Event& event )
+{
+  ControllerImplEventHandler::OnLongPressEvent(*this, event);
+}
 
-      mEventData->mDecorator->UpdatePositions( mModel->mScrollPosition - currentScroll );
-      break;
-    }
-    case Gesture::Finished:
-    case Gesture::Cancelled: // FALLTHROUGH
-    {
-      // Will go back to the previous state to show the cursor, handles, the text's popup, ...
-      ChangeState( mEventData->mPreviousState );
-      break;
-    }
-    default:
-      break;
-  }
+void Controller::Impl::OnHandleEvent( const Event& event )
+{
+  ControllerImplEventHandler::OnHandleEvent(*this, event);
 }
 
-void Controller::Impl::OnLongPressEvent( const Event& event )
+void Controller::Impl::OnSelectEvent( const Event& event )
 {
-  DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" );
+  ControllerImplEventHandler::OnSelectEvent(*this, event);
+}
 
-  if( !IsShowingRealText() && ( EventData::EDITING == mEventData->mState ) )
-  {
-    ChangeState( EventData::EDITING_WITH_POPUP );
-    mEventData->mDecoratorUpdated = true;
-    mEventData->mUpdateInputStyle = true;
-  }
-  else
-  {
-    if( mEventData->mSelectionEnabled )
-    {
-      // Convert from control's coords to text's coords.
-      const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
-      const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
+void Controller::Impl::OnSelectAllEvent()
+{
+  ControllerImplEventHandler::OnSelectAllEvent(*this);
+}
 
-      // Calculates the logical position from the x,y coords.
-      RepositionSelectionHandles( xPosition,
-                                  yPosition,
-                                  mEventData->mLongPressAction );
-    }
-  }
+void Controller::Impl::OnSelectNoneEvent()
+{
+  ControllerImplEventHandler::OnSelectNoneEvent(*this);
 }
 
-void Controller::Impl::OnHandleEvent( const Event& event )
+void Controller::Impl::SetTextSelectionRange(const uint32_t *pStart, const uint32_t *pEnd)
 {
-  if( NULL == mEventData )
+  if( nullptr == mEventData )
   {
-    // Nothing to do if there is no text input.
+    // Nothing to do if there is no text.
     return;
   }
 
-  const unsigned int state = event.p1.mUint;
-  const bool handleStopScrolling = ( HANDLE_STOP_SCROLLING == state );
-  const bool isSmoothHandlePanEnabled = mEventData->mDecorator->IsSmoothHandlePanEnabled();
-
-  if( HANDLE_PRESSED == state )
+  if( mEventData->mSelectionEnabled && (pStart || pEnd))
   {
-    // Convert from decorator's coords to text's coords.
-    const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
-    const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
-
-    // Need to calculate the handle's new position.
-    bool matchedCharacter = false;
-    const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
-                                                                          mModel->mLogicalModel,
-                                                                          mMetrics,
-                                                                          xPosition,
-                                                                          yPosition,
-                                                                          CharacterHitTest::SCROLL,
-                                                                          matchedCharacter );
-
-    if( Event::GRAB_HANDLE_EVENT == event.type )
-    {
-      ChangeState ( EventData::GRAB_HANDLE_PANNING );
-
-      if( handleNewPosition != mEventData->mPrimaryCursorPosition )
-      {
-        // Updates the cursor position if the handle's new position is different than the current one.
-        mEventData->mUpdateCursorPosition = true;
-        // Does not update the grab handle position if the smooth panning is enabled. (The decorator does it smooth).
-        mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
-        mEventData->mPrimaryCursorPosition = handleNewPosition;
-      }
-
-      // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
-      mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
-    }
-    else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
-    {
-      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
-
-      if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
-          ( handleNewPosition != mEventData->mRightSelectionPosition ) )
-      {
-        // Updates the highlight box if the handle's new position is different than the current one.
-        mEventData->mUpdateHighlightBox = true;
-        // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
-        mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
-        mEventData->mLeftSelectionPosition = handleNewPosition;
-      }
-
-      // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
-      mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
+    uint32_t length = static_cast<uint32_t>(mModel->mLogicalModel->mText.Count());
 
-      // Will define the order to scroll the text to match the handle position.
-      mEventData->mIsLeftHandleSelected = true;
-      mEventData->mIsRightHandleSelected = false;
-    }
-    else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
+    if (pStart)
     {
-      ChangeState ( EventData::SELECTION_HANDLE_PANNING );
-
-      if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
-          ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
-      {
-        // Updates the highlight box if the handle's new position is different than the current one.
-        mEventData->mUpdateHighlightBox = true;
-        // Does not update the selection handle position if the smooth panning is enabled. (The decorator does it smooth).
-        mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
-        mEventData->mRightSelectionPosition = handleNewPosition;
-      }
-
-      // Updates the decorator if the soft handle panning is enabled. It triggers a relayout in the decorator and the new position of the handle is set.
-      mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
-
-      // Will define the order to scroll the text to match the handle position.
-      mEventData->mIsLeftHandleSelected = false;
-      mEventData->mIsRightHandleSelected = true;
+      mEventData->mLeftSelectionPosition = std::min(*pStart, length);
     }
-  } // end ( HANDLE_PRESSED == state )
-  else if( ( HANDLE_RELEASED == state ) ||
-           handleStopScrolling )
-  {
-    CharacterIndex handlePosition = 0u;
-    if( handleStopScrolling || isSmoothHandlePanEnabled )
+    if (pEnd)
     {
-      // Convert from decorator's coords to text's coords.
-      const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
-      const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
-
-      bool matchedCharacter = false;
-      handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
-                                                    mModel->mLogicalModel,
-                                                    mMetrics,
-                                                    xPosition,
-                                                    yPosition,
-                                                    CharacterHitTest::SCROLL,
-                                                    matchedCharacter );
+      mEventData->mRightSelectionPosition = std::min(*pEnd, length);
     }
 
-    if( Event::GRAB_HANDLE_EVENT == event.type )
+    if (mEventData->mLeftSelectionPosition == mEventData->mRightSelectionPosition)
     {
+      ChangeState( EventData::EDITING );
+      mEventData->mPrimaryCursorPosition = mEventData->mLeftSelectionPosition = mEventData->mRightSelectionPosition;
       mEventData->mUpdateCursorPosition = true;
-      mEventData->mUpdateGrabHandlePosition = true;
-      mEventData->mUpdateInputStyle = true;
-
-      if( !IsClipboardEmpty() )
-      {
-        ChangeState( EventData::EDITING_WITH_PASTE_POPUP ); // Moving grabhandle will show Paste Popup
-      }
-
-      if( handleStopScrolling || isSmoothHandlePanEnabled )
-      {
-        mEventData->mScrollAfterUpdatePosition = true;
-        mEventData->mPrimaryCursorPosition = handlePosition;
-      }
     }
-    else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
+    else
     {
       ChangeState( EventData::SELECTING );
-
       mEventData->mUpdateHighlightBox = true;
       mEventData->mUpdateLeftSelectionPosition = true;
       mEventData->mUpdateRightSelectionPosition = true;
-
-      if( handleStopScrolling || isSmoothHandlePanEnabled )
-      {
-        mEventData->mScrollAfterUpdatePosition = true;
-
-        if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
-            ( handlePosition != mEventData->mLeftSelectionPosition ) )
-        {
-          mEventData->mLeftSelectionPosition = handlePosition;
-        }
-      }
-    }
-    else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
-    {
-      ChangeState( EventData::SELECTING );
-
-      mEventData->mUpdateHighlightBox = true;
-      mEventData->mUpdateRightSelectionPosition = true;
-      mEventData->mUpdateLeftSelectionPosition = true;
-
-      if( handleStopScrolling || isSmoothHandlePanEnabled )
-      {
-        mEventData->mScrollAfterUpdatePosition = true;
-        if( ( handlePosition != mEventData->mRightSelectionPosition ) &&
-            ( handlePosition != mEventData->mLeftSelectionPosition ) )
-        {
-          mEventData->mRightSelectionPosition = handlePosition;
-        }
-      }
     }
-
-    mEventData->mDecoratorUpdated = true;
-  } // end ( ( HANDLE_RELEASED == state ) || ( HANDLE_STOP_SCROLLING == state ) )
-  else if( HANDLE_SCROLLING == state )
-  {
-    const float xSpeed = event.p2.mFloat;
-    const float ySpeed = event.p3.mFloat;
-    const Vector2& layoutSize = mModel->mVisualModel->GetLayoutSize();
-    const Vector2 currentScrollPosition = mModel->mScrollPosition;
-
-    mModel->mScrollPosition.x += xSpeed;
-    mModel->mScrollPosition.y += ySpeed;
-
-    ClampHorizontalScroll( layoutSize );
-    ClampVerticalScroll( layoutSize );
-
-    bool endOfScroll = false;
-    if( Vector2::ZERO == ( currentScrollPosition - mModel->mScrollPosition ) )
-    {
-      // Notify the decorator there is no more text to scroll.
-      // The decorator won't send more scroll events.
-      mEventData->mDecorator->NotifyEndOfScroll();
-      // Still need to set the position of the handle.
-      endOfScroll = true;
-    }
-
-    // Set the position of the handle.
-    const bool scrollRightDirection = xSpeed > 0.f;
-    const bool scrollBottomDirection = ySpeed > 0.f;
-    const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
-    const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
-
-    if( Event::GRAB_HANDLE_EVENT == event.type )
-    {
-      ChangeState( EventData::GRAB_HANDLE_PANNING );
-
-      // Get the grab handle position in decorator coords.
-      Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
-
-      if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
-      {
-        // Position the grag handle close to either the left or right edge.
-        position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
-      }
-
-      if( mEventData->mDecorator->IsVerticalScrollEnabled() )
-      {
-        position.x = mEventData->mCursorHookPositionX;
-
-        // Position the grag handle close to either the top or bottom edge.
-        position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
-      }
-
-      // Get the new handle position.
-      // The grab handle's position is in decorator's coords. Need to transforms to text's coords.
-      bool matchedCharacter = false;
-      const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
-                                                                         mModel->mLogicalModel,
-                                                                         mMetrics,
-                                                                         position.x - mModel->mScrollPosition.x,
-                                                                         position.y - mModel->mScrollPosition.y,
-                                                                         CharacterHitTest::SCROLL,
-                                                                         matchedCharacter );
-
-      if( mEventData->mPrimaryCursorPosition != handlePosition )
-      {
-        mEventData->mUpdateCursorPosition = true;
-        mEventData->mUpdateGrabHandlePosition = !isSmoothHandlePanEnabled;
-        mEventData->mScrollAfterUpdatePosition = true;
-        mEventData->mPrimaryCursorPosition = handlePosition;
-      }
-      mEventData->mUpdateInputStyle = mEventData->mUpdateCursorPosition;
-
-      // Updates the decorator if the soft handle panning is enabled.
-      mEventData->mDecoratorUpdated = isSmoothHandlePanEnabled;
-    }
-    else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
-    {
-      ChangeState( EventData::SELECTION_HANDLE_PANNING );
-
-      // Get the selection handle position in decorator coords.
-      Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
-
-      if( mEventData->mDecorator->IsHorizontalScrollEnabled() )
-      {
-        // Position the selection handle close to either the left or right edge.
-        position.x = scrollRightDirection ? 0.f : mModel->mVisualModel->mControlSize.width;
-      }
-
-      if( mEventData->mDecorator->IsVerticalScrollEnabled() )
-      {
-        position.x = mEventData->mCursorHookPositionX;
-
-        // Position the grag handle close to either the top or bottom edge.
-        position.y = scrollBottomDirection ? 0.f : mModel->mVisualModel->mControlSize.height;
-      }
-
-      // Get the new handle position.
-      // The selection handle's position is in decorator's coords. Need to transform to text's coords.
-      bool matchedCharacter = false;
-      const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mModel->mVisualModel,
-                                                                         mModel->mLogicalModel,
-                                                                         mMetrics,
-                                                                         position.x - mModel->mScrollPosition.x,
-                                                                         position.y - mModel->mScrollPosition.y,
-                                                                         CharacterHitTest::SCROLL,
-                                                                         matchedCharacter );
-
-      if( leftSelectionHandleEvent )
-      {
-        const bool differentHandles = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition );
-
-        if( differentHandles || endOfScroll )
-        {
-          mEventData->mUpdateHighlightBox = true;
-          mEventData->mUpdateLeftSelectionPosition = !isSmoothHandlePanEnabled;
-          mEventData->mUpdateRightSelectionPosition = isSmoothHandlePanEnabled;
-          mEventData->mLeftSelectionPosition = handlePosition;
-        }
-      }
-      else
-      {
-        const bool differentHandles = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
-        if( differentHandles || endOfScroll )
-        {
-          mEventData->mUpdateHighlightBox = true;
-          mEventData->mUpdateRightSelectionPosition = !isSmoothHandlePanEnabled;
-          mEventData->mUpdateLeftSelectionPosition = isSmoothHandlePanEnabled;
-          mEventData->mRightSelectionPosition = handlePosition;
-        }
-      }
-
-      if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
-      {
-        RepositionSelectionHandles();
-
-        mEventData->mScrollAfterUpdatePosition = !isSmoothHandlePanEnabled;
-      }
-    }
-    mEventData->mDecoratorUpdated = true;
-  } // end ( HANDLE_SCROLLING == state )
+  }
 }
 
-void Controller::Impl::OnSelectEvent( const Event& event )
+Uint32Pair Controller::Impl::GetTextSelectionRange() const
 {
-  if( NULL == mEventData )
-  {
-    // Nothing to do if there is no text.
-    return;
-  }
+  Uint32Pair range;
 
-  if( mEventData->mSelectionEnabled )
+  if( mEventData )
   {
-    // Convert from control's coords to text's coords.
-    const float xPosition = event.p2.mFloat - mModel->mScrollPosition.x;
-    const float yPosition = event.p3.mFloat - mModel->mScrollPosition.y;
-
-    // Calculates the logical position from the x,y coords.
-    RepositionSelectionHandles( xPosition,
-                                yPosition,
-                                Controller::NoTextTap::HIGHLIGHT );
+    range.first = mEventData->mLeftSelectionPosition;
+    range.second = mEventData->mRightSelectionPosition;
   }
+
+  return range;
 }
 
-void Controller::Impl::OnSelectAllEvent()
+bool Controller::Impl::IsEditable() const
 {
-  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "OnSelectAllEvent mEventData->mSelectionEnabled%s \n", mEventData->mSelectionEnabled?"true":"false");
-
-  if( NULL == mEventData )
-  {
-    // Nothing to do if there is no text.
-    return;
-  }
+  return mEventData && mEventData->mEditingEnabled;
+}
 
-  if( mEventData->mSelectionEnabled )
+void Controller::Impl::SetEditable( bool editable )
+{
+  if( mEventData)
   {
-    // Calculates the logical position from the start.
-    RepositionSelectionHandles( 0.f - mModel->mScrollPosition.x,
-                                0.f - mModel->mScrollPosition.y,
-                                Controller::NoTextTap::HIGHLIGHT );
-
-    mEventData->mLeftSelectionPosition = 0u;
-    mEventData->mRightSelectionPosition = mModel->mLogicalModel->mText.Count();
+    mEventData->mEditingEnabled = editable;
   }
 }
 
@@ -2620,15 +2047,23 @@ void Controller::Impl::SetPopupButtons()
    *  If EDITING_WITH_POPUP : SELECT & SELECT_ALL
    */
 
+  bool isEditable = IsEditable();
   TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
 
   if( EventData::SELECTING == mEventData->mState )
   {
-    buttonsToShow = TextSelectionPopup::Buttons(  TextSelectionPopup::CUT | TextSelectionPopup::COPY );
+    buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::COPY );
+    if(isEditable)
+    {
+      buttonsToShow = TextSelectionPopup::Buttons( buttonsToShow | TextSelectionPopup::CUT );
+    }
 
     if( !IsClipboardEmpty() )
     {
-      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      if(isEditable)
+      {
+        buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      }
       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
     }
 
@@ -2646,7 +2081,10 @@ void Controller::Impl::SetPopupButtons()
 
     if( !IsClipboardEmpty() )
     {
-      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      if(isEditable)
+      {
+        buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      }
       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
     }
   }
@@ -2654,7 +2092,10 @@ void Controller::Impl::SetPopupButtons()
   {
     if ( !IsClipboardEmpty() )
     {
-      buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      if(isEditable)
+      {
+        buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+      }
       buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
     }
   }
@@ -3359,7 +2800,7 @@ Actor Controller::Impl::CreateBackgroundActor()
       quadVertexFormat[ "aPosition" ] = Property::VECTOR2;
       quadVertexFormat[ "aColor" ] = Property::VECTOR4;
 
-      PropertyBuffer quadVertices = PropertyBuffer::New( quadVertexFormat );
+      VertexBuffer quadVertices = VertexBuffer::New( quadVertexFormat );
       quadVertices.SetData( &mesh.mVertices[ 0 ], mesh.mVertices.Size() );
 
       Geometry quadGeometry = Geometry::New();
@@ -3376,11 +2817,11 @@ Actor Controller::Impl::CreateBackgroundActor()
       renderer.SetProperty( Dali::Renderer::Property::DEPTH_INDEX, DepthIndex::CONTENT );
 
       actor = Actor::New();
-      actor.SetName( "TextBackgroundColorActor" );
-      actor.SetParentOrigin( ParentOrigin::TOP_LEFT );
-      actor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
-      actor.SetSize( textSize );
-      actor.SetColorMode( USE_OWN_MULTIPLY_PARENT_COLOR );
+      actor.SetProperty( Dali::Actor::Property::NAME, "TextBackgroundColorActor" );
+      actor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT );
+      actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT );
+      actor.SetProperty( Actor::Property::SIZE, textSize );
+      actor.SetProperty( Actor::Property::COLOR_MODE, USE_OWN_MULTIPLY_PARENT_COLOR );
       actor.AddRenderer( renderer );
     }
   }