Selection Handled Scrolling - Step1 94/38694/6
authorVictor Cebollada <v.cebollada@samsung.com>
Fri, 24 Apr 2015 06:33:49 +0000 (07:33 +0100)
committerVictor Cebollada <v.cebollada@samsung.com>
Fri, 24 Apr 2015 16:06:07 +0000 (17:06 +0100)
  *Decorator uses the same data structure to store the three handles.
  *Decorator uses the same code to send events to the controller for the three handles.

Change-Id: I14595b6531c55ecfffedc7a8266a2f70b927c5ce
Signed-off-by: Victor Cebollada <v.cebollada@samsung.com>
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/text/decorator/text-decorator.cpp
dali-toolkit/internal/text/decorator/text-decorator.h
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h

index 5074cdc..bb2fb04 100644 (file)
@@ -323,7 +323,7 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr
 
         if( impl.mDecorator )
         {
-          impl.mDecorator->SetGrabHandleImage( GRAB_HANDLE_IMAGE_RELEASED, image );
+          impl.mDecorator->SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED, image );
         }
         break;
       }
@@ -333,7 +333,7 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr
 
         if( impl.mDecorator )
         {
-          impl.mDecorator->SetGrabHandleImage( GRAB_HANDLE_IMAGE_PRESSED, image );
+          impl.mDecorator->SetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_PRESSED, image );
         }
         break;
       }
@@ -363,7 +363,7 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr
 
         if( impl.mDecorator )
         {
-          impl.mDecorator->SetLeftSelectionImage( SELECTION_HANDLE_RELEASED, image );
+          impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, image );
         }
         break;
       }
@@ -373,7 +373,7 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr
 
         if( impl.mDecorator )
         {
-          impl.mDecorator->SetRightSelectionImage( SELECTION_HANDLE_RELEASED, image );
+          impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED, image );
         }
         break;
       }
@@ -383,7 +383,7 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr
 
         if( impl.mDecorator )
         {
-          impl.mDecorator->SetLeftSelectionImage( SELECTION_HANDLE_PRESSED, image );
+          impl.mDecorator->SetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, image );
         }
         break;
       }
@@ -393,7 +393,7 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr
 
         if( impl.mDecorator )
         {
-          impl.mDecorator->SetLeftSelectionImage( SELECTION_HANDLE_PRESSED, image );
+          impl.mDecorator->SetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED, image );
         }
         break;
       }
@@ -546,7 +546,7 @@ Property::Value TextField::GetProperty( BaseObject* object, Property::Index inde
       {
         if( impl.mDecorator )
         {
-          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetGrabHandleImage( GRAB_HANDLE_IMAGE_RELEASED ) );
+          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_RELEASED ) );
           if( image )
           {
             value = image.GetUrl();
@@ -558,7 +558,7 @@ Property::Value TextField::GetProperty( BaseObject* object, Property::Index inde
       {
         if( impl.mDecorator )
         {
-          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetGrabHandleImage( GRAB_HANDLE_IMAGE_PRESSED ) );
+          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( GRAB_HANDLE, HANDLE_IMAGE_PRESSED ) );
           if( image )
           {
             value = image.GetUrl();
@@ -586,7 +586,7 @@ Property::Value TextField::GetProperty( BaseObject* object, Property::Index inde
       {
         if( impl.mDecorator )
         {
-          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetLeftSelectionImage( SELECTION_HANDLE_RELEASED ) );
+          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED ) );
           if( image )
           {
             value = image.GetUrl();
@@ -598,7 +598,7 @@ Property::Value TextField::GetProperty( BaseObject* object, Property::Index inde
       {
         if( impl.mDecorator )
         {
-          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetRightSelectionImage( SELECTION_HANDLE_RELEASED ) );
+          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_RELEASED ) );
           if( image )
           {
             value = image.GetUrl();
@@ -610,7 +610,7 @@ Property::Value TextField::GetProperty( BaseObject* object, Property::Index inde
       {
         if( impl.mDecorator )
         {
-          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetLeftSelectionImage( SELECTION_HANDLE_PRESSED ) );
+          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( LEFT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED ) );
           if( image )
           {
             value = image.GetUrl();
@@ -622,7 +622,7 @@ Property::Value TextField::GetProperty( BaseObject* object, Property::Index inde
       {
         if( impl.mDecorator )
         {
-          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetRightSelectionImage( SELECTION_HANDLE_PRESSED ) );
+          ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetHandleImage( RIGHT_SELECTION_HANDLE, HANDLE_IMAGE_PRESSED ) );
           if( image )
           {
             value = image.GetUrl();
index 6d348cb..871b3d6 100644 (file)
@@ -76,12 +76,12 @@ const char* DEFAULT_GRAB_HANDLE_IMAGE_RELEASED( DALI_IMAGE_DIR "insertpoint-icon
 const char* DEFAULT_GRAB_HANDLE_IMAGE_PRESSED( DALI_IMAGE_DIR "insertpoint-icon-pressed.png" );
 const char* DEFAULT_SELECTION_HANDLE_ONE( DALI_IMAGE_DIR "text-input-selection-handle-left.png" );
 const char* DEFAULT_SELECTION_HANDLE_TWO( DALI_IMAGE_DIR "text-input-selection-handle-right.png" );
-//const char* DEFAULT_SELECTION_HANDLE_ONE_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-left-press.png" );
-//const char* DEFAULT_SELECTION_HANDLE_TWO_PRESSED( DALI_IMAGE_DIR "text-input-selection-handle-right-press.png" );
 
 const Dali::Vector3 DEFAULT_GRAB_HANDLE_RELATIVE_SIZE( 1.5f, 2.0f, 1.0f );
 const Dali::Vector3 DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE( 1.5f, 1.5f, 1.0f );
 
+const Dali::Vector4 LIGHT_BLUE( 0.07f, 0.41f, 0.59f, 1.0f ); // The text highlight color.
+
 const unsigned int CURSOR_BLINK_INTERVAL = 500u; // Cursor blink interval
 const float TO_MILLISECONDS = 1000.f;
 const float TO_SECONDS = 1.f / TO_MILLISECONDS;
@@ -183,11 +183,15 @@ struct Decorator::Impl : public ConnectionTracker
     float lineHeight;
   };
 
-  struct SelectionHandleImpl
+  struct HandleImpl
   {
-    SelectionHandleImpl()
+    HandleImpl()
     : position(),
       lineHeight( 0.0f ),
+      grabDisplacementX( 0.f ),
+      grabDisplacementY( 0.f ),
+      active( false ),
+      visible( false ),
       flipped( false )
     {
     }
@@ -197,25 +201,26 @@ struct Decorator::Impl : public ConnectionTracker
 
     Vector2 position;
     float lineHeight; ///< Not the handle height
-    bool flipped;
+    float grabDisplacementX;
+    float grabDisplacementY;
+    bool active  : 1;
+    bool visible : 1;
+    bool flipped : 1;
   };
 
   Impl( Dali::Toolkit::Internal::Control& parent, Observer& observer )
   : mTextControlParent( parent ),
     mObserver( observer ),
     mBoundingBox( Rect<int>() ),
-    mHighlightColor( 0.07f, 0.41f, 0.59f, 1.0f ), // light blue
+    mHighlightColor( LIGHT_BLUE ),
     mActiveCursor( ACTIVE_CURSOR_NONE ),
     mCursorBlinkInterval( CURSOR_BLINK_INTERVAL ),
     mCursorBlinkDuration( 0.0f ),
-    mGrabDisplacementX( 0.0f ),
-    mGrabDisplacementY( 0.0f ),
+    mHandleScrolling( HANDLE_TYPE_COUNT ),
     mScrollDirection( SCROLL_NONE ),
     mScrollThreshold( SCROLL_THRESHOLD ),
     mScrollSpeed( SCROLL_SPEED ),
     mScrollDistance( SCROLL_DISTANCE ),
-    mActiveGrabHandle( false ),
-    mActiveSelection( false ),
     mActiveCopyPastePopup( false ),
     mCursorBlinkStatus( true ),
     mPrimaryCursorVisible( false ),
@@ -236,31 +241,61 @@ struct Decorator::Impl : public ConnectionTracker
     CreateCursors();
     if( mPrimaryCursor )
     {
-      mPrimaryCursorVisible = ( mCursor[PRIMARY_CURSOR].position.x <= size.width ) && ( mCursor[PRIMARY_CURSOR].position.x >= 0.f );
+      const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
+      mPrimaryCursorVisible = ( cursor.position.x <= size.width ) && ( cursor.position.x >= 0.f );
       if( mPrimaryCursorVisible )
       {
-        mPrimaryCursor.SetPosition( mCursor[PRIMARY_CURSOR].position.x,
-                                    mCursor[PRIMARY_CURSOR].position.y );
-        mPrimaryCursor.SetSize( Size( 1.0f, mCursor[PRIMARY_CURSOR].cursorHeight ) );
+        Vector2 position = cursor.position;
+        if( GRAB_HANDLE == mHandleScrolling )
+        {
+          if( mScrollDirection == SCROLL_RIGHT )
+          {
+            position.x = 0.f;
+          }
+          else
+          {
+            position.x = size.width;
+          }
+        }
+
+        mPrimaryCursor.SetPosition( position.x,
+                                    position.y );
+        mPrimaryCursor.SetSize( Size( 1.0f, cursor.cursorHeight ) );
       }
       mPrimaryCursor.SetVisible( mPrimaryCursorVisible );
     }
     if( mSecondaryCursor )
     {
-      mSecondaryCursorVisible = ( mCursor[SECONDARY_CURSOR].position.x <= size.width ) && ( mCursor[SECONDARY_CURSOR].position.x >= 0.f );
+      const CursorImpl& cursor = mCursor[SECONDARY_CURSOR];
+      mSecondaryCursorVisible = ( cursor.position.x <= size.width ) && ( cursor.position.x >= 0.f );
       if( mSecondaryCursorVisible )
       {
-        mSecondaryCursor.SetPosition( mCursor[SECONDARY_CURSOR].position.x,
-                                      mCursor[SECONDARY_CURSOR].position.y );
-        mSecondaryCursor.SetSize( Size( 1.0f, mCursor[SECONDARY_CURSOR].cursorHeight ) );
+        mSecondaryCursor.SetPosition( cursor.position.x,
+                                      cursor.position.y );
+        mSecondaryCursor.SetSize( Size( 1.0f, cursor.cursorHeight ) );
       }
       mSecondaryCursor.SetVisible( mSecondaryCursorVisible );
     }
 
     // Show or hide the grab handle
-    if( mActiveGrabHandle )
+    HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+    if( grabHandle.active )
     {
-      const bool isVisible = ( mCursor[PRIMARY_CURSOR].position.x <= size.width ) && ( mCursor[PRIMARY_CURSOR].position.x >= 0.f );
+      Vector2 position = grabHandle.position;
+
+      if( GRAB_HANDLE == mHandleScrolling )
+      {
+        if( mScrollDirection == SCROLL_RIGHT )
+        {
+          position.x = 0.f;
+        }
+        else
+        {
+          position.x = size.width;
+        }
+      }
+
+      const bool isVisible = ( position.x <= size.width ) && ( position.x >= 0.f );
 
       if( isVisible )
       {
@@ -268,28 +303,28 @@ struct Decorator::Impl : public ConnectionTracker
 
         CreateGrabHandle();
 
-        mGrabHandle.SetPosition( mCursor[PRIMARY_CURSOR].position.x,
-                                 mCursor[PRIMARY_CURSOR].position.y + mCursor[PRIMARY_CURSOR].lineHeight );
+        grabHandle.actor.SetPosition( position.x,
+                                      position.y + grabHandle.lineHeight );
       }
-      mGrabHandle.SetVisible( isVisible );
+      grabHandle.actor.SetVisible( isVisible );
     }
-    else if( mGrabHandle )
+    else if( grabHandle.actor )
     {
-      UnparentAndReset( mGrabHandle );
+      UnparentAndReset( grabHandle.actor );
     }
 
     // Show or hide the selection handles/highlight
-    if( mActiveSelection )
+    HandleImpl& primary = mHandle[ LEFT_SELECTION_HANDLE ];
+    HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
+    if( primary.active || secondary.active )
     {
       SetupTouchEvents();
 
       CreateSelectionHandles();
 
-      SelectionHandleImpl& primary = mSelectionHandle[ PRIMARY_SELECTION_HANDLE ];
       primary.actor.SetPosition( primary.position.x,
                                  primary.position.y + primary.lineHeight );
 
-      SelectionHandleImpl& secondary = mSelectionHandle[ SECONDARY_SELECTION_HANDLE ];
       secondary.actor.SetPosition( secondary.position.x,
                                    secondary.position.y + secondary.lineHeight );
 
@@ -298,8 +333,8 @@ struct Decorator::Impl : public ConnectionTracker
     }
     else
     {
-      UnparentAndReset( mSelectionHandle[ PRIMARY_SELECTION_HANDLE ].actor );
-      UnparentAndReset( mSelectionHandle[ SECONDARY_SELECTION_HANDLE ].actor );
+      UnparentAndReset( primary.actor );
+      UnparentAndReset( secondary.actor );
       UnparentAndReset( mHighlightMeshActor );
     }
 
@@ -329,8 +364,9 @@ struct Decorator::Impl : public ConnectionTracker
   {
     mCursor[PRIMARY_CURSOR].position += scrollOffset;
     mCursor[SECONDARY_CURSOR].position += scrollOffset;
-    mSelectionHandle[ PRIMARY_SELECTION_HANDLE ].position += scrollOffset;
-    mSelectionHandle[ SECONDARY_SELECTION_HANDLE ].position += scrollOffset;
+    mHandle[ GRAB_HANDLE ].position += scrollOffset;
+    mHandle[ LEFT_SELECTION_HANDLE ].position += scrollOffset;
+    mHandle[ RIGHT_SELECTION_HANDLE ].position += scrollOffset;
 
     // TODO Highlight box??
   }
@@ -456,61 +492,62 @@ struct Decorator::Impl : public ConnectionTracker
 
   void CreateGrabHandle()
   {
-    if( !mGrabHandle )
+    HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+    if( !grabHandle.actor )
     {
-      if ( !mGrabHandleImageReleased )
+      if( !mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] )
       {
-        mGrabHandleImageReleased = ResourceImage::New( DEFAULT_GRAB_HANDLE_IMAGE_RELEASED );
+        mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] = ResourceImage::New( DEFAULT_GRAB_HANDLE_IMAGE_RELEASED );
       }
-      if ( !mGrabHandleImagePressed )
+      if( !mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_PRESSED] )
       {
-        mGrabHandleImagePressed = ResourceImage::New( DEFAULT_GRAB_HANDLE_IMAGE_PRESSED );
+        mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_PRESSED] = ResourceImage::New( DEFAULT_GRAB_HANDLE_IMAGE_PRESSED );
       }
 
-      mGrabHandle = ImageActor::New( mGrabHandleImageReleased );
-      mGrabHandle.SetAnchorPoint( AnchorPoint::TOP_CENTER );
-      mGrabHandle.SetDrawMode( DrawMode::OVERLAY );
+      grabHandle.actor = ImageActor::New( mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED] );
+      grabHandle.actor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+      grabHandle.actor.SetDrawMode( DrawMode::OVERLAY );
       // Area that Grab handle responds to, larger than actual handle so easier to move
 #ifdef DECORATOR_DEBUG
-      mGrabHandle.SetName( "GrabHandleActor" );
+      grabHandle.actor.SetName( "GrabHandleActor" );
       if ( Dali::Internal::gLogFilter->IsEnabledFor( Debug::Verbose ) )
       {
-        mGrabArea = Toolkit::CreateSolidColorActor( Vector4(0.0f, 0.0f, 0.0f, 0.0f), true, Color::RED, 1 );
-        mGrabArea.SetName( "GrabArea" );
+        grabHandle.grabArea = Toolkit::CreateSolidColorActor( Vector4(0.0f, 0.0f, 0.0f, 0.0f), true, Color::RED, 1 );
+        grabHandle.grabArea.SetName( "GrabArea" );
       }
       else
       {
-        mGrabArea = Actor::New();
-        mGrabArea.SetName( "GrabArea" );
+        grabHandle.grabArea = Actor::New();
+        grabHandle.grabArea.SetName( "GrabArea" );
       }
 #else
-      mGrabArea = Actor::New();
+      grabHandle.grabArea = Actor::New();
 #endif
 
-      mGrabArea.SetParentOrigin( ParentOrigin::TOP_CENTER );
-      mGrabArea.SetAnchorPoint( AnchorPoint::TOP_CENTER );
-      mGrabArea.SetResizePolicy( ResizePolicy::SIZE_RELATIVE_TO_PARENT, Dimension::ALL_DIMENSIONS );
-      mGrabArea.SetSizeModeFactor( DEFAULT_GRAB_HANDLE_RELATIVE_SIZE );
-      mGrabHandle.Add( mGrabArea );
+      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 );
 
-      mTapDetector.Attach( mGrabArea );
-      mPanGestureDetector.Attach( mGrabArea );
+      mTapDetector.Attach( grabHandle.grabArea );
+      mPanGestureDetector.Attach( grabHandle.grabArea );
 
-      mActiveLayer.Add( mGrabHandle );
+      mActiveLayer.Add( grabHandle.actor );
     }
   }
 
   void CreateSelectionHandles()
   {
-    SelectionHandleImpl& primary = mSelectionHandle[ PRIMARY_SELECTION_HANDLE ];
-    if ( !primary.actor )
+    HandleImpl& primary = mHandle[ LEFT_SELECTION_HANDLE ];
+    if( !primary.actor )
     {
-      if ( !mSelectionReleasedLeft )
+      if( !mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] )
       {
-        mSelectionReleasedLeft = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE );
+        mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE );
       }
 
-      primary.actor = ImageActor::New( mSelectionReleasedLeft );
+      primary.actor = ImageActor::New( mHandleImages[LEFT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
 #ifdef DECORATOR_DEBUG
       primary.actor.SetName("SelectionHandleOne");
 #endif
@@ -534,15 +571,15 @@ struct Decorator::Impl : public ConnectionTracker
       mActiveLayer.Add( primary.actor );
     }
 
-    SelectionHandleImpl& secondary = mSelectionHandle[ SECONDARY_SELECTION_HANDLE ];
-    if ( !secondary.actor )
+    HandleImpl& secondary = mHandle[ RIGHT_SELECTION_HANDLE ];
+    if( !secondary.actor )
     {
-      if ( !mSelectionReleasedRight )
+      if( !mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] )
       {
-        mSelectionReleasedRight = ResourceImage::New( DEFAULT_SELECTION_HANDLE_TWO );
+        mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] = ResourceImage::New( DEFAULT_SELECTION_HANDLE_TWO );
       }
 
-      secondary.actor = ImageActor::New( mSelectionReleasedRight );
+      secondary.actor = ImageActor::New( mHandleImages[RIGHT_SELECTION_HANDLE][HANDLE_IMAGE_RELEASED] );
 #ifdef DECORATOR_DEBUG
       secondary.actor.SetName("SelectionHandleTwo");
 #endif
@@ -565,8 +602,6 @@ struct Decorator::Impl : public ConnectionTracker
       secondary.actor.Add( secondary.grabArea );
       mActiveLayer.Add( secondary.actor );
     }
-
-    //SetUpHandlePropertyNotifications(); TODO
   }
 
   void CreateHighlight()
@@ -687,67 +722,86 @@ struct Decorator::Impl : public ConnectionTracker
 
   void OnTap( Actor actor, const TapGesture& tap )
   {
-    if( actor == mGrabHandle )
+    if( actor == mHandle[GRAB_HANDLE].actor )
     {
       // TODO
     }
   }
 
-  void OnPan( Actor actor, const PanGesture& gesture )
+  void DoPan( HandleImpl& handle, HandleType type, const PanGesture& gesture )
   {
-    if( actor == mGrabArea )
+    if( Gesture::Started == gesture.state )
     {
-      if( Gesture::Started == gesture.state )
+      handle.grabDisplacementX = handle.grabDisplacementY = 0;
+      if( mHandleImages[type][HANDLE_IMAGE_PRESSED] )
       {
-        mGrabDisplacementX = mGrabDisplacementY = 0;
-        mGrabHandle.SetImage( mGrabHandleImagePressed );
+        handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_PRESSED] );
       }
+    }
 
-      mGrabDisplacementX += gesture.displacement.x;
-      mGrabDisplacementY += gesture.displacement.y;
+    handle.grabDisplacementX += gesture.displacement.x;
+    handle.grabDisplacementY += gesture.displacement.y;
 
-      const float x = mCursor[PRIMARY_CURSOR].position.x + mGrabDisplacementX;
-      const float y = mCursor[PRIMARY_CURSOR].position.y + mCursor[PRIMARY_CURSOR].lineHeight*0.5f + mGrabDisplacementY;
+    const float x = handle.position.x + handle.grabDisplacementX;
+    const float y = handle.position.y + handle.lineHeight*0.5f + handle.grabDisplacementY;
 
-      if( Gesture::Started    == gesture.state ||
-          Gesture::Continuing == gesture.state )
+    if( Gesture::Started    == gesture.state ||
+        Gesture::Continuing == gesture.state )
+    {
+      if( x < mScrollThreshold )
       {
-        if( x < mScrollThreshold )
-        {
-          mScrollDirection = SCROLL_RIGHT;
-          mGrabDisplacementX -= x;
-          mCursor[PRIMARY_CURSOR].position.x = 0.f;
-          StartScrollTimer();
-        }
-        else if( x > mTextControlParent.GetControlSize().width - mScrollThreshold )
-        {
-          mScrollDirection = SCROLL_LEFT;
-          mGrabDisplacementX += ( mTextControlParent.GetControlSize().width - x );
-          mCursor[PRIMARY_CURSOR].position.x = mTextControlParent.GetControlSize().width;
-          StartScrollTimer();
-        }
-        else
-        {
-          StopScrollTimer();
-          mObserver.GrabHandleEvent( GRAB_HANDLE_PRESSED, x, y );
-        }
+        mScrollDirection = SCROLL_RIGHT;
+        mHandleScrolling = type;
+        StartScrollTimer();
       }
-      else if( Gesture::Finished  == gesture.state ||
-               Gesture::Cancelled == gesture.state )
+      else if( x > mTextControlParent.GetControlSize().width - mScrollThreshold )
       {
-        if( mScrollTimer && mScrollTimer.IsRunning() )
-        {
-          StopScrollTimer();
-          mObserver.GrabHandleEvent( GRAB_HANDLE_STOP_SCROLLING, x, y );
-        }
-        else
-        {
-          mObserver.GrabHandleEvent( GRAB_HANDLE_RELEASED, x, y );
-        }
-
-        mGrabHandle.SetImage( mGrabHandleImageReleased );
+        mScrollDirection = SCROLL_LEFT;
+        mHandleScrolling = type;
+        StartScrollTimer();
+      }
+      else
+      {
+        mHandleScrolling = HANDLE_TYPE_COUNT;
+        StopScrollTimer();
+        mObserver.HandleEvent( type, HANDLE_PRESSED, x, y );
       }
     }
+    else if( Gesture::Finished  == gesture.state ||
+             Gesture::Cancelled == gesture.state )
+    {
+      if( mScrollTimer && mScrollTimer.IsRunning() )
+      {
+        mHandleScrolling = HANDLE_TYPE_COUNT;
+        StopScrollTimer();
+        mObserver.HandleEvent( type, HANDLE_STOP_SCROLLING, x, y );
+      }
+      else
+      {
+        mObserver.HandleEvent( type, HANDLE_RELEASED, x, y );
+      }
+      handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_RELEASED] );
+    }
+  }
+
+  void OnPan( Actor actor, const PanGesture& gesture )
+  {
+    HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+    HandleImpl& primarySelectionHandle = mHandle[LEFT_SELECTION_HANDLE];
+    HandleImpl& secondarySelectionHandle = mHandle[RIGHT_SELECTION_HANDLE];
+
+    if( actor == grabHandle.grabArea )
+    {
+      DoPan( grabHandle, GRAB_HANDLE, gesture );
+    }
+    else if( actor == primarySelectionHandle.grabArea )
+    {
+      DoPan( primarySelectionHandle, LEFT_SELECTION_HANDLE, gesture );
+    }
+    else if( actor == secondarySelectionHandle.grabArea )
+    {
+      DoPan( secondarySelectionHandle, RIGHT_SELECTION_HANDLE, gesture );
+    }
   }
 
   bool OnHandleOneTouched( Actor actor, const TouchEvent& touch )
@@ -776,7 +830,7 @@ struct Decorator::Impl : public ConnectionTracker
 
     const float popupHeight = 120.0f; // todo Set as a MaxSize Property in Control or retrieve from CopyPastePopup class.
 
-    if( mActiveGrabHandle )
+    if( mHandle[GRAB_HANDLE].active )
     {
       // If grab handle enabled then position pop-up below the grab handle.
       const Vector2 grabHandleSize( 59.0f, 56.0f ); // todo
@@ -794,16 +848,10 @@ struct Decorator::Impl : public ConnectionTracker
   void PopUpLeavesVerticalBoundary( PropertyNotification& source )
   {
     float alternativeYPosition=0.0f;
-  // todo
-  //  if( mHighlightMeshActor ) // Text Selection mode
-  //  {
-  //    alternativePosition = AlternatePopUpPositionRelativeToSelectionHandles();
-  //  }
-  //  else // Not in Text Selection mode
-  //  {
+    // todo use AlternatePopUpPositionRelativeToSelectionHandles() if text is highlighted
     // if can't be positioned above, then position below row.
     alternativeYPosition = AlternatePopUpPositionRelativeToCursor();
-   // }
+
     mCopyPastePopup.SetY( alternativeYPosition );
   }
 
@@ -918,9 +966,14 @@ struct Decorator::Impl : public ConnectionTracker
    */
   bool OnScrollTimerTick()
   {
-    mObserver.GrabHandleEvent( GRAB_HANDLE_SCROLLING,
-                               mScrollDirection == SCROLL_RIGHT ? mScrollDistance : -mScrollDistance,
-                               0.f );
+    if( HANDLE_TYPE_COUNT != mHandleScrolling )
+    {
+      mObserver.HandleEvent( mHandleScrolling,
+                             HANDLE_SCROLLING,
+                             mScrollDirection == SCROLL_RIGHT ? mScrollDistance : -mScrollDistance,
+                             0.f );
+    }
+
     return true;
   }
 
@@ -935,44 +988,32 @@ struct Decorator::Impl : public ConnectionTracker
   Layer               mActiveLayer;               ///< Layer for active handles and alike that ensures they are above all else.
   ImageActor          mPrimaryCursor;
   ImageActor          mSecondaryCursor;
-  ImageActor          mGrabHandle;
-  Actor               mGrabArea;
   MeshActor           mHighlightMeshActor;        ///< Mesh Actor to display highlight
   TextSelectionPopup  mCopyPastePopup;
 
+  Image               mHandleImages[HANDLE_TYPE_COUNT][HANDLE_IMAGE_TYPE_COUNT];
   Image               mCursorImage;
-  Image               mGrabHandleImageReleased;
-  Image               mGrabHandleImagePressed;
   Mesh                mHighlightMesh;             ///< Mesh for highlight
   MeshData            mHighlightMeshData;         ///< Mesh Data for highlight
   Material            mHighlightMaterial;         ///< Material used for highlight
 
   CursorImpl          mCursor[CURSOR_COUNT];
-  SelectionHandleImpl mSelectionHandle[SELECTION_HANDLE_COUNT];
-
+  HandleImpl          mHandle[HANDLE_TYPE_COUNT];
   QuadContainer       mHighlightQuadList;         ///< Sub-selections that combine to create the complete selection highlight
 
-  Image               mSelectionReleasedLeft;     ///< Selection handle images
-  Image               mSelectionReleasedRight;
-  Image               mSelectionPressedLeft;
-  Image               mSelectionPressedRight;
-
   Rect<int>           mBoundingBox;
   Vector4             mHighlightColor;            ///< Color of the highlight
 
   unsigned int        mActiveCursor;
   unsigned int        mCursorBlinkInterval;
   float               mCursorBlinkDuration;
-  float               mGrabDisplacementX;
-  float               mGrabDisplacementY;
+  HandleType          mHandleScrolling;         ///< The handle which is scrolling.
   ScrollDirection     mScrollDirection;         ///< The direction of the scroll.
   float               mScrollThreshold;         ///< Defines a square area inside the control, close to the edge. A cursor entering this area will trigger scroll events.
   float               mScrollSpeed;             ///< The scroll speed in pixels per second.
   float               mScrollDistance;          ///< Distance the text scrolls during a scroll interval.
   unsigned int        mScrollInterval;          ///< Time in milliseconds of a scroll interval.
 
-  bool                mActiveGrabHandle       : 1;
-  bool                mActiveSelection        : 1;
   bool                mActiveCopyPastePopup   : 1;
   bool                mCursorBlinkStatus      : 1; ///< Flag to switch between blink on and blink off.
   bool                mPrimaryCursorVisible   : 1; ///< Whether the primary cursor is visible.
@@ -1018,13 +1059,6 @@ unsigned int Decorator::GetActiveCursor() const
 
 void Decorator::SetPosition( Cursor cursor, float x, float y, float cursorHeight, float lineHeight )
 {
-  // Adjust grab handle displacement
-  if( PRIMARY_CURSOR == cursor )
-  {
-    mImpl->mGrabDisplacementX -= x - mImpl->mCursor[cursor].position.x;
-    mImpl->mGrabDisplacementY -= y - mImpl->mCursor[cursor].position.y;
-  }
-
   mImpl->mCursor[cursor].position.x = x;
   mImpl->mCursor[cursor].position.y = y;
   mImpl->mCursor[cursor].cursorHeight = cursorHeight;
@@ -1096,108 +1130,48 @@ float Decorator::GetCursorBlinkDuration() const
   return mImpl->mCursorBlinkDuration;
 }
 
-/** GrabHandle **/
+/** Handles **/
 
-void Decorator::SetGrabHandleActive( bool active )
+void Decorator::SetHandleActive( HandleType handleType, bool active )
 {
-  mImpl->mActiveGrabHandle = active;
+  mImpl->mHandle[handleType].active = active;
 }
 
-bool Decorator::IsGrabHandleActive() const
+bool Decorator::IsHandleActive( HandleType handleType ) const
 {
-  return mImpl->mActiveGrabHandle;
+  return mImpl->mHandle[handleType].active ;
 }
 
-void Decorator::SetGrabHandleImage( GrabHandleImageType type, Dali::Image image )
-{
-  if( GRAB_HANDLE_IMAGE_PRESSED == type )
-  {
-    mImpl->mGrabHandleImagePressed = image;
-  }
-  else
-  {
-    mImpl->mGrabHandleImageReleased = image;
-  }
-}
-
-Dali::Image Decorator::GetGrabHandleImage( GrabHandleImageType type ) const
-{
-  if( GRAB_HANDLE_IMAGE_PRESSED == type )
-  {
-    return mImpl->mGrabHandleImagePressed;
-  }
-
-  return mImpl->mGrabHandleImageReleased;
-}
-
-/** Selection **/
-
-void Decorator::SetSelectionActive( bool active )
+void Decorator::SetHandleImage( HandleType handleType, HandleImageType handleImageType, Dali::Image image )
 {
-  mImpl->mActiveSelection = active;
+  mImpl->mHandleImages[handleType][handleImageType] = image;
 }
 
-bool Decorator::IsSelectionActive() const
+Dali::Image Decorator::GetHandleImage( HandleType handleType, HandleImageType handleImageType ) const
 {
-  return mImpl->mActiveSelection;
+  return mImpl->mHandleImages[handleType][handleImageType];
 }
 
-void Decorator::SetPosition( SelectionHandle handle, float x, float y, float height )
+void Decorator::SetPosition( HandleType handleType, float x, float y, float height )
 {
-  mImpl->mSelectionHandle[handle].position.x = x;
-  mImpl->mSelectionHandle[handle].position.y = y;
-  mImpl->mSelectionHandle[handle].lineHeight = height;
-}
-
-void Decorator::GetPosition( SelectionHandle handle, float& x, float& y, float& height ) const
-{
-  x = mImpl->mSelectionHandle[handle].position.x;
-  y = mImpl->mSelectionHandle[handle].position.y;
-  height = mImpl->mSelectionHandle[handle].lineHeight;
-}
-
-void Decorator::SetLeftSelectionImage( SelectionHandleState state, Dali::Image image )
-{
-  if( SELECTION_HANDLE_PRESSED == state )
-  {
-    mImpl->mSelectionPressedLeft = image;
-  }
-  else
-  {
-    mImpl->mSelectionReleasedLeft = image;
-  }
-}
-
-Dali::Image Decorator::GetLeftSelectionImage( SelectionHandleState state ) const
-{
-  if( SELECTION_HANDLE_PRESSED == state )
-  {
-    return mImpl->mSelectionPressedLeft;
-  }
+  // Adjust grab handle displacement
+  Impl::HandleImpl& handle = mImpl->mHandle[handleType];
 
-  return mImpl->mSelectionReleasedLeft;
-}
+  handle.grabDisplacementX -= x - handle.position.x;
+  handle.grabDisplacementY -= y - handle.position.y;
 
-void Decorator::SetRightSelectionImage( SelectionHandleState state, Dali::Image image )
-{
-  if( SELECTION_HANDLE_PRESSED == state )
-  {
-    mImpl->mSelectionPressedRight = image;
-  }
-  else
-  {
-    mImpl->mSelectionReleasedRight = image;
-  }
+  handle.position.x = x;
+  handle.position.y = y;
+  handle.lineHeight = height;
 }
 
-Dali::Image Decorator::GetRightSelectionImage( SelectionHandleState state ) const
+void Decorator::GetPosition( HandleType handleType, float& x, float& y, float& height ) const
 {
-  if( SELECTION_HANDLE_PRESSED == state )
-  {
-    return mImpl->mSelectionPressedRight;
-  }
+  Impl::HandleImpl& handle = mImpl->mHandle[handleType];
 
-  return mImpl->mSelectionReleasedRight;
+  x = handle.position.x;
+  y = handle.position.y;
+  height = handle.lineHeight;
 }
 
 void Decorator::AddHighlight( float x1, float y1, float x2, float y2 )
index e8bc5cf..e341e2b 100644 (file)
@@ -61,35 +61,31 @@ enum ActiveCursor
   ACTIVE_CURSOR_BOTH     ///< Both primary and secondary cursor are active
 };
 
-// The state information for grab handle events
-enum GrabHandleState
+// The state information for handle events.
+enum HandleState
 {
-  GRAB_HANDLE_TAPPED,
-  GRAB_HANDLE_PRESSED,
-  GRAB_HANDLE_RELEASED,
-  GRAB_HANDLE_SCROLLING,
-  GRAB_HANDLE_STOP_SCROLLING
+  HANDLE_TAPPED,
+  HANDLE_PRESSED,
+  HANDLE_RELEASED,
+  HANDLE_SCROLLING,
+  HANDLE_STOP_SCROLLING
 };
 
-// Used to set different grab handle images
-enum GrabHandleImageType
+// Used to set different handle images
+enum HandleImageType
 {
-  GRAB_HANDLE_IMAGE_PRESSED,
-  GRAB_HANDLE_IMAGE_RELEASED
+  HANDLE_IMAGE_PRESSED,
+  HANDLE_IMAGE_RELEASED,
+  HANDLE_IMAGE_TYPE_COUNT
 };
 
-// The set the selection-handle positions etc.
-enum SelectionHandle
+// Types of handles.
+enum HandleType
 {
-  PRIMARY_SELECTION_HANDLE,
-  SECONDARY_SELECTION_HANDLE,
-  SELECTION_HANDLE_COUNT
-};
-
-enum SelectionHandleState
-{
-  SELECTION_HANDLE_PRESSED,
-  SELECTION_HANDLE_RELEASED
+  GRAB_HANDLE,
+  LEFT_SELECTION_HANDLE,
+  RIGHT_SELECTION_HANDLE,
+  HANDLE_TYPE_COUNT
 };
 
 /**
@@ -124,13 +120,14 @@ public:
     virtual ~Observer() {};
 
     /**
-     * @brief An input event from the grab handle.
+     * @brief An input event from one of the handles.
      *
-     * @param[in] state The grab handle state.
+     * @param[in] handleType The handle's type.
+     * @param[in] state The handle's state.
      * @param[in] x The x position relative to the top-left of the parent control.
      * @param[in] y The y position relative to the top-left of the parent control.
      */
-    virtual void GrabHandleEvent( GrabHandleState state, float x, float y ) = 0;
+    virtual void HandleEvent( HandleType handleType, HandleState state, float x, float y ) = 0;
   };
 
   /**
@@ -287,101 +284,61 @@ public:
   float GetCursorBlinkDuration() const;
 
   /**
-   * @brief Sets whether the grab handle is active.
+   * @brief Sets whether a handle is active.
    *
-   * @note The grab handle follows the cursor position set with SetPosition(Cursor, ...)
-   * @param[in] active True if the grab handle should be active.
+   * @param[in] handleType One of the handles.
+   * @param[in] active True if the handle should be active.
    */
-  void SetGrabHandleActive( bool active );
+  void SetHandleActive( HandleType handleType,
+                        bool active );
 
   /**
-   * @brief Query whether the grab handle is active.
+   * @brief Query whether a handle is active.
    *
-   * @return True if the grab handle should be active.
+   * @param[in] handleType One of the handles.
+   *
+   * @return True if the handle is active.
    */
-  bool IsGrabHandleActive() const;
+  bool IsHandleActive( HandleType handleType ) const;
 
   /**
-   * @brief Sets the image for the grab handle.
+   * @brief Sets the image for one of the handles.
    *
-   * @param[in] type A different image can be set for the pressed/released states.
+   * @param[in] handleType One of the handles.
+   * @param[in] handleImageType A different image can be set for the pressed/released states.
    * @param[in] image The image to use.
    */
-  void SetGrabHandleImage( GrabHandleImageType type, Dali::Image image );
+  void SetHandleImage( HandleType handleType, HandleImageType handleImageType, Dali::Image image );
 
   /**
-   * @brief Retrieves the image for the grab handle.
+   * @brief Retrieves the image for one of the handles.
    *
-   * @param[in] type A different image can be set for the pressed/released states.
-   * @return The grab handle image.
-   */
-  Dali::Image GetGrabHandleImage( GrabHandleImageType type ) const;
-
-  /**
-   * @brief Sets whether the selection handles and highlight are active.
+   * @param[in] handleType One of the handles.
+   * @param[in] handleImageType A different image can be set for the pressed/released states.
    *
-   * @param[in] active True if the selection handles and highlight are active.
-   */
-  void SetSelectionActive( bool active );
-
-  /**
-   * @brief Query whether the selection handles and highlight are active.
-   *
-   * @return True if the selection handles and highlight are active.
+   * @return The grab handle image.
    */
-  bool IsSelectionActive() const;
+  Dali::Image GetHandleImage( HandleType handleType, HandleImageType handleImageType ) const;
 
   /**
    * @brief Sets the position of a selection handle.
    *
-   * @param[in] handle The handle to set.
+   * @param[in] handleType The handle to set.
    * @param[in] x The x position relative to the top-left of the parent control.
    * @param[in] y The y position relative to the top-left of the parent control.
    * @param[in] lineHeight The logical line height at this position.
    */
-  void SetPosition( SelectionHandle handle, float x, float y, float lineHeight );
+  void SetPosition( HandleType handleType, float x, float y, float lineHeight );
 
   /**
    * @brief Retrieves the position of a selection handle.
    *
-   * @param[in] handle The handle to get.
+   * @param[in] handleType The handle to get.
    * @param[out] x The x position relative to the top-left of the parent control.
    * @param[out] y The y position relative to the top-left of the parent control.
-   * @param[out] cursorHeight The logical cursor height at this position.
-   */
-  void GetPosition( SelectionHandle handle, float& x, float& y, float& cursorHeight ) const;
-
-  /**
-   * @brief Sets the image for one of the selection handles.
-   *
-   * @param[in] state A different image can be set for the pressed/released states.
-   * @param[in] image The image to use.
-   */
-  void SetLeftSelectionImage( SelectionHandleState state, Dali::Image image );
-
-  /**
-   * @brief Retrieves the image for a selection handle.
-   *
-   * @param[in] state A different image can be set for the pressed/released states.
-   * @return The image.
-   */
-  Dali::Image GetLeftSelectionImage( SelectionHandleState state ) const;
-
-  /**
-   * @brief Sets the image for one of the selection handles.
-   *
-   * @param[in] state A different image can be set for the pressed/released states.
-   * @param[in] image The image to use.
-   */
-  void SetRightSelectionImage( SelectionHandleState state, Dali::Image image );
-
-  /**
-   * @brief Retrieves the image for a selection handle.
-   *
-   * @param[in] state A different image can be set for the pressed/released states.
-   * @return The image.
+   * @param[out] lineHeight The logical line height at this position.
    */
-  Dali::Image GetRightSelectionImage( SelectionHandleState state ) const;
+  void GetPosition( HandleType handleType, float& x, float& y, float& lineHeight ) const;
 
   /**
    * @brief Adds a quad to the existing selection highlights.
index 6baf19e..f7f1739 100644 (file)
@@ -101,7 +101,8 @@ EventData::EventData( DecoratorPtr decorator )
   mScrollPosition(),
   mState( INACTIVE ),
   mPrimaryCursorPosition( 0u ),
-  mSecondaryCursorPosition( 0u ),
+  mLeftSelectionPosition( 0u ),
+  mRightSelectionPosition( 0u ),
   mDecoratorUpdated( false ),
   mCursorBlinkEnabled( true ),
   mGrabHandleEnabled( true ),
@@ -110,6 +111,8 @@ EventData::EventData( DecoratorPtr decorator )
   mHorizontalScrollingEnabled( true ),
   mVerticalScrollingEnabled( false ),
   mUpdateCursorPosition( false ),
+  mUpdateLeftSelectionPosition( false ),
+  mUpdateRightSelectionPosition( false ),
   mScrollAfterUpdateCursorPosition( false )
 {}
 
@@ -160,8 +163,10 @@ bool Controller::Impl::ProcessInputEvents()
         break;
       }
       case Event::GRAB_HANDLE_EVENT:
+      case Event::LEFT_SELECTION_HANDLE_EVENT:
+      case Event::RIGHT_SELECTION_HANDLE_EVENT: // Fall through
       {
-        OnGrabHandleEvent( *iter );
+        OnHandleEvent( *iter );
         break;
       }
       }
@@ -181,8 +186,35 @@ bool Controller::Impl::ProcessInputEvents()
       mEventData->mScrollAfterUpdateCursorPosition = false;
     }
 
+    mEventData->mDecoratorUpdated = true;
     mEventData->mUpdateCursorPosition = false;
   }
+  else if( mEventData->mUpdateLeftSelectionPosition )
+  {
+    UpdateSelectionHandle( LEFT_SELECTION_HANDLE );
+
+    if( mEventData->mScrollAfterUpdateCursorPosition )
+    {
+      ScrollToMakeCursorVisible();
+      mEventData->mScrollAfterUpdateCursorPosition = false;
+    }
+
+    mEventData->mDecoratorUpdated = true;
+    mEventData->mUpdateLeftSelectionPosition = false;
+  }
+  else if( mEventData->mUpdateRightSelectionPosition )
+  {
+    UpdateSelectionHandle( RIGHT_SELECTION_HANDLE );
+
+    if( mEventData->mScrollAfterUpdateCursorPosition )
+    {
+      ScrollToMakeCursorVisible();
+      mEventData->mScrollAfterUpdateCursorPosition = false;
+    }
+
+    mEventData->mDecoratorUpdated = true;
+    mEventData->mUpdateRightSelectionPosition = false;
+  }
 
   mEventData->mEventQueue.clear();
 
@@ -325,7 +357,7 @@ void Controller::Impl::OnPanEvent( const Event& event )
   }
 }
 
-void Controller::Impl::OnGrabHandleEvent( const Event& event )
+void Controller::Impl::OnHandleEvent( const Event& event )
 {
   if( NULL == mEventData )
   {
@@ -333,46 +365,68 @@ void Controller::Impl::OnGrabHandleEvent( const Event& event )
     return;
   }
 
-  unsigned int state = event.p1.mUint;
+  const unsigned int state = event.p1.mUint;
 
-  if( GRAB_HANDLE_PRESSED == state )
+  if( HANDLE_PRESSED == state )
   {
     // The event.p2 and event.p3 are in decorator coords. Need to transforms to text coords.
     const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
     const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
 
-    //mDecorator->HidePopup();
-    ChangeState ( EventData::EDITING );
+    const CharacterIndex handleNewPosition = GetClosestCursorIndex( xPosition, yPosition );
 
-    const CharacterIndex newCursorPosition = GetClosestCursorIndex( xPosition, yPosition );
+    if( Event::GRAB_HANDLE_EVENT == event.type )
+    {
+      ChangeState ( EventData::EDITING );
 
-    if( newCursorPosition != mEventData->mPrimaryCursorPosition )
+      if( handleNewPosition != mEventData->mPrimaryCursorPosition )
+      {
+        mEventData->mPrimaryCursorPosition = handleNewPosition;
+        mEventData->mUpdateCursorPosition = true;
+      }
+    }
+    else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
     {
-      mEventData->mPrimaryCursorPosition = newCursorPosition;
-      mEventData->mUpdateCursorPosition = true;
+      if( handleNewPosition != mEventData->mLeftSelectionPosition )
+      {
+        mEventData->mLeftSelectionPosition = handleNewPosition;
+        mEventData->mUpdateLeftSelectionPosition = true;
+      }
+    }
+    else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
+    {
+      if( handleNewPosition != mEventData->mRightSelectionPosition )
+      {
+        mEventData->mRightSelectionPosition = handleNewPosition;
+        mEventData->mUpdateRightSelectionPosition = true;
+      }
     }
   }
-  else if( mEventData->mGrabHandlePopupEnabled &&
-           ( ( GRAB_HANDLE_RELEASED == state ) ||
-             ( GRAB_HANDLE_STOP_SCROLLING == state ) ) )
+  else if( ( HANDLE_RELEASED == state ) ||
+           ( HANDLE_STOP_SCROLLING == state ) )
   {
-    //mDecorator->ShowPopup();
-    ChangeState ( EventData::EDITING_WITH_POPUP );
-    mEventData->mUpdateCursorPosition = true;
-    mEventData->mDecoratorUpdated = true;
-
-    if( GRAB_HANDLE_STOP_SCROLLING == state )
+    if( mEventData->mGrabHandlePopupEnabled )
+    {
+      ChangeState( EventData::EDITING_WITH_POPUP );
+    }
+    if( Event::GRAB_HANDLE_EVENT == event.type )
     {
-      // The event.p2 and event.p3 are in decorator coords. Need to transforms to text coords.
-      const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
-      const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
+      mEventData->mUpdateCursorPosition = true;
+
+      if( HANDLE_STOP_SCROLLING == state )
+      {
+        // The event.p2 and event.p3 are in decorator coords. Need to transforms to text coords.
+        const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
+        const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
 
-      mEventData->mPrimaryCursorPosition = GetClosestCursorIndex( xPosition, yPosition );
+        mEventData->mPrimaryCursorPosition = GetClosestCursorIndex( xPosition, yPosition );
 
-      mEventData->mScrollAfterUpdateCursorPosition = true;
+        mEventData->mScrollAfterUpdateCursorPosition = true;
+      }
     }
+    mEventData->mDecoratorUpdated = true;
   }
-  else if( GRAB_HANDLE_SCROLLING == state )
+  else if( HANDLE_SCROLLING == state )
   {
     const float xSpeed = event.p2.mFloat;
     const Vector2& actualSize = mVisualModel->GetActualSize();
@@ -380,6 +434,8 @@ void Controller::Impl::OnGrabHandleEvent( const Event& event )
     mEventData->mScrollPosition.x += xSpeed;
 
     ClampHorizontalScroll( actualSize );
+
+   mEventData->mDecoratorUpdated = true;
   }
 }
 
@@ -411,8 +467,8 @@ void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY
     const Vector<LineRun>& lines = mVisualModel->mLines;
     float height = lines.Count() ? lines[0].ascender + -lines[0].descender : 0.0f;
 
-    mEventData->mDecorator->SetPosition( PRIMARY_SELECTION_HANDLE,     primaryX, mEventData->mScrollPosition.y, height );
-    mEventData->mDecorator->SetPosition( SECONDARY_SELECTION_HANDLE, secondaryX, mEventData->mScrollPosition.y, height );
+    mEventData->mDecorator->SetPosition( LEFT_SELECTION_HANDLE,     primaryX, mEventData->mScrollPosition.y, height );
+    mEventData->mDecorator->SetPosition( RIGHT_SELECTION_HANDLE, secondaryX, mEventData->mScrollPosition.y, height );
 
     mEventData->mDecorator->ClearHighlights();
     mEventData->mDecorator->AddHighlight( primaryX, mEventData->mScrollPosition.y, secondaryX, height + mEventData->mScrollPosition.y );
@@ -435,8 +491,9 @@ void Controller::Impl::ChangeState( EventData::State newState )
     {
       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
       mEventData->mDecorator->StopCursorBlink();
-      mEventData->mDecorator->SetGrabHandleActive( false );
-      mEventData->mDecorator->SetSelectionActive( false );
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
       mEventData->mDecorator->SetPopupActive( false );
       mEventData->mDecoratorUpdated = true;
     }
@@ -444,8 +501,9 @@ void Controller::Impl::ChangeState( EventData::State newState )
     {
       mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
       mEventData->mDecorator->StopCursorBlink();
-      mEventData->mDecorator->SetGrabHandleActive( false );
-      mEventData->mDecorator->SetSelectionActive( true );
+      mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
       mEventData->mDecoratorUpdated = true;
     }
     else if( EventData::EDITING == mEventData->mState )
@@ -457,13 +515,14 @@ void Controller::Impl::ChangeState( EventData::State newState )
       }
       if( mEventData->mGrabHandleEnabled )
       {
-        mEventData->mDecorator->SetGrabHandleActive( true );
+        mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
       }
       if( mEventData->mGrabHandlePopupEnabled )
       {
         mEventData->mDecorator->SetPopupActive( false );
       }
-      mEventData->mDecorator->SetSelectionActive( false );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
       mEventData->mDecoratorUpdated = true;
     }
     else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
@@ -475,13 +534,15 @@ void Controller::Impl::ChangeState( EventData::State newState )
       }
       if( mEventData->mGrabHandleEnabled )
       {
-        mEventData->mDecorator->SetGrabHandleActive( true );
+        mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, true );
+        mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
       }
       if( mEventData->mGrabHandlePopupEnabled )
       {
         mEventData->mDecorator->SetPopupActive( true );
       }
-      mEventData->mDecorator->SetSelectionActive( false );
+      mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+      mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
       mEventData->mDecoratorUpdated = true;
     }
   }
@@ -841,18 +902,28 @@ void Controller::Impl::UpdateCursorPosition()
   GetCursorPosition( mEventData->mPrimaryCursorPosition,
                      cursorInfo );
 
+  const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
+  const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
+
+  // Sets the cursor position.
   mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
-                                       cursorInfo.primaryPosition.x + mEventData->mScrollPosition.x + mAlignmentOffset.x,
-                                       cursorInfo.primaryPosition.y + mEventData->mScrollPosition.y + mAlignmentOffset.y,
+                                       cursorPosition.x,
+                                       cursorPosition.y,
                                        cursorInfo.primaryCursorHeight,
                                        cursorInfo.lineHeight );
 
+  // Sets the grab handle position.
+  mEventData->mDecorator->SetPosition( GRAB_HANDLE,
+                                       cursorPosition.x,
+                                       cursorPosition.y,
+                                       cursorInfo.lineHeight );
+
   if( cursorInfo.isSecondaryCursor )
   {
     mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
     mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
-                                         cursorInfo.secondaryPosition.x + mEventData->mScrollPosition.x + mAlignmentOffset.x,
-                                         cursorInfo.secondaryPosition.y + mEventData->mScrollPosition.y + mAlignmentOffset.y,
+                                         cursorInfo.secondaryPosition.x + offset.x,
+                                         cursorInfo.secondaryPosition.y + offset.y,
                                          cursorInfo.secondaryCursorHeight,
                                          cursorInfo.lineHeight );
   }
@@ -860,9 +931,31 @@ void Controller::Impl::UpdateCursorPosition()
   {
     mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
   }
+}
+
+void Controller::Impl::UpdateSelectionHandle( HandleType handleType )
+{
+  if( ( LEFT_SELECTION_HANDLE != handleType ) &&
+      ( RIGHT_SELECTION_HANDLE != handleType ) )
+  {
+    return;
+  }
+
+  const bool leftSelectionHandle = LEFT_SELECTION_HANDLE == handleType;
+  const CharacterIndex index = leftSelectionHandle ? mEventData->mLeftSelectionPosition : mEventData->mRightSelectionPosition;
 
-  mEventData->mUpdateCursorPosition = false;
-  mEventData->mDecoratorUpdated = true;
+  CursorInfo cursorInfo;
+  GetCursorPosition( index,
+                     cursorInfo );
+
+  const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
+  const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
+
+  // Sets the grab handle position.
+  mEventData->mDecorator->SetPosition( handleType,
+                                       cursorPosition.x,
+                                       cursorPosition.y,
+                                       cursorInfo.lineHeight );
 }
 
 void Controller::Impl::ClampHorizontalScroll( const Vector2& actualSize )
index 34ea828..103013a 100644 (file)
@@ -46,7 +46,9 @@ struct Event
     CURSOR_KEY_EVENT,
     TAP_EVENT,
     PAN_EVENT,
-    GRAB_HANDLE_EVENT
+    GRAB_HANDLE_EVENT,
+    LEFT_SELECTION_HANDLE_EVENT,
+    RIGHT_SELECTION_HANDLE_EVENT
   };
 
   union Param
@@ -61,6 +63,7 @@ struct Event
   {
     p1.mInt = 0;
     p2.mInt = 0;
+    p3.mInt = 0;
   }
 
   Type type;
@@ -123,7 +126,8 @@ struct EventData
   State              mState;                   ///< Selection mode, edit mode etc.
 
   CharacterIndex     mPrimaryCursorPosition;   ///< Index into logical model for primary cursor.
-  CharacterIndex     mSecondaryCursorPosition; ///< Index into logical model for secondary cursor.
+  CharacterIndex     mLeftSelectionPosition;   ///< Index into logical model for left selection handle.
+  CharacterIndex     mRightSelectionPosition;  ///< Index into logical model for right selection handle.
 
   bool mDecoratorUpdated                : 1;   ///< True if the decorator was updated during event processing.
   bool mCursorBlinkEnabled              : 1;   ///< True if cursor should blink when active.
@@ -133,6 +137,8 @@ struct EventData
   bool mHorizontalScrollingEnabled      : 1;   ///< True if horizontal scrolling is enabled.
   bool mVerticalScrollingEnabled        : 1;   ///< True if vertical scrolling is enabled.
   bool mUpdateCursorPosition            : 1;   ///< True if the visual position of the cursor must be recalculated.
+  bool mUpdateLeftSelectionPosition     : 1;   ///< True if the visual position of the left selection handle must be recalculated.
+  bool mUpdateRightSelectionPosition    : 1;   ///< True if the visual position of the right selection handle must be recalculated.
   bool mScrollAfterUpdateCursorPosition : 1;   ///< Whether to scroll after the cursor position is updated.
 };
 
@@ -232,7 +238,7 @@ struct Controller::Impl
 
   void OnPanEvent( const Event& event );
 
-  void OnGrabHandleEvent( const Event& event );
+  void OnHandleEvent( const Event& event );
 
   void RepositionSelectionHandles( float visualX, float visualY );
 
@@ -285,6 +291,13 @@ struct Controller::Impl
   void UpdateCursorPosition();
 
   /**
+   * @brief Updates the position of the given selection handle.
+   *
+   * @param[in] handleType One of the selection handles.
+   */
+  void UpdateSelectionHandle( HandleType handleType );
+
+  /**
    * @biref Clamps the horizontal scrolling to get the control always filled with text.
    *
    * @param[in] actualSize The size of the laid out text.
index abbc2e7..da7da29 100644 (file)
@@ -1146,18 +1146,49 @@ void Controller::PanEvent( Gesture::State state, const Vector2& displacement )
   }
 }
 
-void Controller::GrabHandleEvent( GrabHandleState state, float x, float y )
+void Controller::HandleEvent( HandleType handleType, HandleState state, float x, float y )
 {
-  DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected GrabHandleEvent" );
+  DALI_ASSERT_DEBUG( mImpl->mEventData && "Controller::HandleEvent. Unexpected HandleEvent" );
 
   if( mImpl->mEventData )
   {
-    Event event( Event::GRAB_HANDLE_EVENT );
-    event.p1.mUint  = state;
-    event.p2.mFloat = x;
-    event.p3.mFloat = y;
-    
-    mImpl->mEventData->mEventQueue.push_back( event );
+    switch( handleType )
+    {
+      case GRAB_HANDLE:
+      {
+        Event event( Event::GRAB_HANDLE_EVENT );
+        event.p1.mUint  = state;
+        event.p2.mFloat = x;
+        event.p3.mFloat = y;
+
+        mImpl->mEventData->mEventQueue.push_back( event );
+        break;
+      }
+      case LEFT_SELECTION_HANDLE:
+      {
+        Event event( Event::LEFT_SELECTION_HANDLE_EVENT );
+        event.p1.mUint  = state;
+        event.p2.mFloat = x;
+        event.p3.mFloat = y;
+
+        mImpl->mEventData->mEventQueue.push_back( event );
+        break;
+      }
+      case RIGHT_SELECTION_HANDLE:
+      {
+        Event event( Event::RIGHT_SELECTION_HANDLE_EVENT );
+        event.p1.mUint  = state;
+        event.p2.mFloat = x;
+        event.p3.mFloat = y;
+
+        mImpl->mEventData->mEventQueue.push_back( event );
+        break;
+      }
+      case HANDLE_TYPE_COUNT:
+      {
+        DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" );
+      }
+    }
 
     mImpl->RequestRelayout();
   }
index d37efab..bb44698 100644 (file)
@@ -413,9 +413,9 @@ public:
   void PanEvent( Gesture::State state, const Vector2& displacement );
 
   /**
-   * @copydoc Dali::Toolkit::Text::Decorator::Observer::GrabHandleEvent()
+   * @copydoc Dali::Toolkit::Text::Decorator::Observer::HandleEvent()
    */
-  virtual void GrabHandleEvent( GrabHandleState state, float x, float y );
+  virtual void HandleEvent( HandleType handle, HandleState state, float x, float y );
 
 protected: