+ mHighlightActor.SetParentOrigin( ParentOrigin::TOP_LEFT );
+ mHighlightActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );
+ mHighlightActor.SetColor( mHighlightColor );
+ mHighlightActor.SetColorMode( USE_OWN_COLOR );
+ }
+
+ // Add the highlight box telling the controller it needs clipping.
+ mController.AddDecoration( mHighlightActor, true );
+ }
+
+ void UpdateHighlight()
+ {
+ if ( mHighlightActor )
+ {
+ // Sets the position of the highlight actor inside the decorator.
+ mHighlightActor.SetPosition( mHighlightPosition.x + mHighlightOutlineOffset,
+ mHighlightPosition.y + mHighlightOutlineOffset );
+
+ const unsigned int numberOfQuads = mHighlightQuadList.Count();
+ if( 0u != numberOfQuads )
+ {
+ // Set the size of the highlighted text to the actor.
+ mHighlightActor.SetSize( mHighlightSize );
+
+ // Used to translate the vertices given in decorator's coords to the mHighlightActor's local coords.
+ const float offsetX = mHighlightPosition.x + 0.5f * mHighlightSize.width;
+ const float offsetY = mHighlightPosition.y + 0.5f * mHighlightSize.height;
+
+ Vector<Vector2> vertices;
+ Vector<unsigned short> indices;
+
+ vertices.Reserve( 4u * numberOfQuads );
+ indices.Reserve( 6u * numberOfQuads );
+
+ // Index to the vertex.
+ unsigned int v = 0u;
+
+ // Traverse all quads.
+ for( Vector<Vector4>::ConstIterator it = mHighlightQuadList.Begin(),
+ endIt = mHighlightQuadList.End();
+ it != endIt;
+ ++it, v += 4u )
+ {
+ const Vector4& quad = *it;
+
+ Vector2 vertex;
+
+ // top-left (v+0)
+ vertex.x = quad.x - offsetX;
+ vertex.y = quad.y - offsetY;
+ vertices.PushBack( vertex );
+
+ // top-right (v+1)
+ vertex.x = quad.z - offsetX;
+ vertex.y = quad.y - offsetY;
+ vertices.PushBack( vertex );
+
+ // bottom-left (v+2)
+ vertex.x = quad.x - offsetX;
+ vertex.y = quad.w - offsetY;
+ vertices.PushBack( vertex );
+
+ // bottom-right (v+3)
+ vertex.x = quad.z - offsetX;
+ vertex.y = quad.w - offsetY;
+ vertices.PushBack( vertex );
+
+ // triangle A (3, 1, 0)
+ indices.PushBack( v + 3 );
+ indices.PushBack( v + 1 );
+ indices.PushBack( v );
+
+ // triangle B (0, 2, 3)
+ indices.PushBack( v );
+ indices.PushBack( v + 2 );
+ indices.PushBack( v + 3 );
+ }
+
+ if( ! mQuadVertices )
+ {
+ mQuadVertices = PropertyBuffer::New( mQuadVertexFormat );
+ }
+
+ mQuadVertices.SetData( &vertices[ 0 ], vertices.Size() );
+
+ if( !mQuadGeometry )
+ {
+ mQuadGeometry = Geometry::New();
+ mQuadGeometry.AddVertexBuffer( mQuadVertices );
+ }
+ mQuadGeometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
+
+ if( !mHighlightRenderer )
+ {
+ mHighlightRenderer = Dali::Renderer::New( mQuadGeometry, mHighlightShader );
+ mHighlightActor.AddRenderer( mHighlightRenderer );
+ }
+ }
+
+ mHighlightQuadList.Clear();
+
+ if( mHighlightRenderer )
+ {
+ mHighlightRenderer.SetProperty( Renderer::Property::DEPTH_INDEX, mTextDepth - 2 ); // text is rendered at mTextDepth and text's shadow at mTextDepth -1u.
+ }
+ }
+ }
+
+ void DoPan( HandleImpl& handle, HandleType type, const PanGesture& gesture )
+ {
+ if( Gesture::Started == gesture.state )
+ {
+ handle.grabDisplacementX = handle.grabDisplacementY = 0.f;
+
+ handle.globalPosition.x = handle.position.x;
+ handle.globalPosition.y = handle.position.y;
+ }
+
+ handle.grabDisplacementX += gesture.displacement.x;
+ handle.grabDisplacementY += ( handle.verticallyFlipped ? -gesture.displacement.y : gesture.displacement.y );
+
+ const float x = handle.globalPosition.x + handle.grabDisplacementX;
+ const float y = handle.globalPosition.y + handle.grabDisplacementY + 0.5f * handle.lineHeight;
+ const float yVerticallyFlippedCorrected = y - ( handle.verticallyFlippedOnTouch ? handle.lineHeight : 0.f );
+
+ if( ( Gesture::Started == gesture.state ) ||
+ ( Gesture::Continuing == gesture.state ) )
+ {
+ Vector2 targetSize;
+ mController.GetTargetSize( targetSize );
+
+ if( mHorizontalScrollingEnabled &&
+ ( x < mScrollThreshold ) )
+ {
+ mScrollDirection = SCROLL_RIGHT;
+ mHandleScrolling = type;
+ StartScrollTimer();
+ }
+ else if( mHorizontalScrollingEnabled &&
+ ( x > targetSize.width - mScrollThreshold ) )
+ {
+ mScrollDirection = SCROLL_LEFT;
+ mHandleScrolling = type;
+ StartScrollTimer();
+ }
+ else if( mVerticalScrollingEnabled &&
+ ( yVerticallyFlippedCorrected < mScrollThreshold ) )
+ {
+ mScrollDirection = SCROLL_TOP;
+ mHandleScrolling = type;
+ StartScrollTimer();
+ }
+ else if( mVerticalScrollingEnabled &&
+ ( yVerticallyFlippedCorrected + handle.lineHeight > targetSize.height - mScrollThreshold ) )
+ {
+ mScrollDirection = SCROLL_BOTTOM;
+ mHandleScrolling = type;
+ StartScrollTimer();
+ }
+ else
+ {
+ mHandleScrolling = HANDLE_TYPE_COUNT;
+ StopScrollTimer();
+ mController.DecorationEvent( type, HANDLE_PRESSED, x, y );
+ }
+
+ mIsHandlePanning = true;
+ }
+ else if( ( Gesture::Finished == gesture.state ) ||
+ ( Gesture::Cancelled == gesture.state ) )
+ {
+ if( mScrollTimer &&
+ ( mScrollTimer.IsRunning() || mNotifyEndOfScroll ) )
+ {
+ mNotifyEndOfScroll = false;
+ mHandleScrolling = HANDLE_TYPE_COUNT;
+ StopScrollTimer();
+ mController.DecorationEvent( type, HANDLE_STOP_SCROLLING, x, y );
+ }
+ else
+ {
+ mController.DecorationEvent( type, HANDLE_RELEASED, x, y );
+ }
+
+ if( handle.actor )
+ {
+ handle.actor.SetImage( mHandleImages[type][HANDLE_IMAGE_RELEASED] );
+ }
+ handle.pressed = false;
+
+ mIsHandlePanning = false;
+ }
+ }
+
+ 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 OnGrabHandleTouched( Actor actor, const TouchData& touch )
+ {
+ HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+
+ // Switch between pressed/release grab-handle images
+ if( touch.GetPointCount() > 0 &&
+ grabHandle.actor )
+ {
+ const PointState::Type state = touch.GetState( 0 );
+
+ if( PointState::DOWN == state )
+ {
+ grabHandle.pressed = true;
+ }
+ else if( ( PointState::UP == state ) ||
+ ( PointState::INTERRUPTED == state ) )
+ {
+ grabHandle.pressed = false;
+ }
+
+ SetHandleImage( GRAB_HANDLE );
+ }
+
+ // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
+ return true;
+ }
+
+ bool OnHandleOneTouched( Actor actor, const TouchData& touch )
+ {
+ HandleImpl& primarySelectionHandle = mHandle[LEFT_SELECTION_HANDLE];
+
+ // Switch between pressed/release selection handle images
+ if( touch.GetPointCount() > 0 &&
+ primarySelectionHandle.actor )
+ {
+ const PointState::Type state = touch.GetState( 0 );
+
+ if( PointState::DOWN == state )
+ {
+ primarySelectionHandle.pressed = true;
+ primarySelectionHandle.verticallyFlippedOnTouch = primarySelectionHandle.verticallyFlipped;
+ }
+ else if( ( PointState::UP == state ) ||
+ ( PointState::INTERRUPTED == state ) )
+ {
+ primarySelectionHandle.pressed = false;
+ mIsHandlePreviouslyCrossed = mIsHandleCurrentlyCrossed;
+ mIsHandlePanning = false;
+ mHandleReleased = LEFT_SELECTION_HANDLE;
+ }
+
+ SetHandleImage( LEFT_SELECTION_HANDLE );
+ }
+
+ // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
+ return true;
+ }
+
+ bool OnHandleTwoTouched( Actor actor, const TouchData& touch )
+ {
+ HandleImpl& secondarySelectionHandle = mHandle[RIGHT_SELECTION_HANDLE];