+ const unsigned int numberOfQuads = mHighlightQuadList.size();
+ 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( std::vector<QuadCoordinates>::iterator it = mHighlightQuadList.begin(),
+ endIt = mHighlightQuadList.end();
+ it != endIt;
+ ++it, v += 4u )
+ {
+ QuadCoordinates& quad = *it;
+
+ Vector2 vertex;
+
+ // top-left (v+0)
+ vertex.x = quad.min.x - offsetX;
+ vertex.y = quad.min.y - offsetY;
+ vertices.PushBack( vertex );
+
+ // top-right (v+1)
+ vertex.x = quad.max.x - offsetX;
+ vertex.y = quad.min.y - offsetY;
+ vertices.PushBack( vertex );
+
+ // bottom-left (v+2)
+ vertex.x = quad.min.x - offsetX;
+ vertex.y = quad.max.y - offsetY;
+ vertices.PushBack( vertex );
+
+ // bottom-right (v+3)
+ vertex.x = quad.max.x - offsetX;
+ vertex.y = quad.max.y - 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];
+
+ // Switch between pressed/release selection handle images
+ if( touch.GetPointCount() > 0 &&
+ secondarySelectionHandle.actor )
+ {
+ const PointState::Type state = touch.GetState( 0 );
+
+ if( PointState::DOWN == state )
+ {
+ secondarySelectionHandle.pressed = true;
+ secondarySelectionHandle.verticallyFlippedOnTouch = secondarySelectionHandle.verticallyFlipped;
+ }
+ else if( ( PointState::UP == state ) ||
+ ( PointState::INTERRUPTED == state ) )
+ {
+ secondarySelectionHandle.pressed = false;
+ mIsHandlePreviouslyCrossed = mIsHandleCurrentlyCrossed;
+ mIsHandlePanning = false;
+ mHandleReleased = RIGHT_SELECTION_HANDLE;
+ }
+
+ SetHandleImage( RIGHT_SELECTION_HANDLE );
+ }
+
+ // Consume to avoid pop-ups accidentally closing, when handle is outside of pop-up area
+ return true;
+ }
+
+ void HandleResetPosition( PropertyNotification& source )
+ {
+ const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+
+ if( grabHandle.active )
+ {
+ // Sets the grab handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
+ SetGrabHandlePosition();
+
+ // Sets the grab handle image according if it's pressed, flipped, etc.
+ SetHandleImage( GRAB_HANDLE );
+ }
+ else
+ {
+ // Sets the primary selection handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
+ SetSelectionHandlePosition( LEFT_SELECTION_HANDLE );
+
+ // Sets the primary handle image according if it's pressed, flipped, etc.
+ SetHandleImage( LEFT_SELECTION_HANDLE );
+
+ // Sets the secondary selection handle position and calculates if it needs to be vertically flipped if it exceeds the boundary box.
+ SetSelectionHandlePosition( RIGHT_SELECTION_HANDLE );
+
+ // Sets the secondary handle image according if it's pressed, flipped, etc.
+ SetHandleImage( RIGHT_SELECTION_HANDLE );
+ }
+ }
+
+ void SetupActiveLayerPropertyNotifications()
+ {
+ if( !mActiveLayer )
+ {
+ return;
+ }
+
+ // Vertical notifications.
+
+ // Disconnect any previous connected callback.
+ if( mHandleVerticalLessThanNotification )
+ {
+ mHandleVerticalLessThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+ mActiveLayer.RemovePropertyNotification( mHandleVerticalLessThanNotification );
+ }
+
+ if( mHandleVerticalGreaterThanNotification )
+ {
+ mHandleVerticalGreaterThanNotification.NotifySignal().Disconnect( this, &Decorator::Impl::HandleResetPosition );
+ mActiveLayer.RemovePropertyNotification( mHandleVerticalGreaterThanNotification );
+ }
+
+ const HandleImpl& grabHandle = mHandle[GRAB_HANDLE];
+ const HandleImpl& primaryHandle = mHandle[LEFT_SELECTION_HANDLE];
+ const HandleImpl& secondaryHandle = mHandle[RIGHT_SELECTION_HANDLE];
+
+ if( grabHandle.active )
+ {
+ if( grabHandle.verticallyFlipped )
+ {
+ // The grab handle is vertically flipped. Never is going to exceed the bottom edje of the display.
+ mHandleVerticalGreaterThanNotification.Reset();
+
+ // The vertical distance from the center of the active layer to the top edje of the display.
+ const float topHeight = 0.5f * mControlSize.height - grabHandle.position.y + grabHandle.size.height;
+
+ mHandleVerticalLessThanNotification = mActiveLayer.AddPropertyNotification( Actor::Property::WORLD_POSITION_Y,
+ LessThanCondition( mBoundingBox.y + topHeight ) );
+
+ // Notifies the change from false to true and from true to false.
+ mHandleVerticalLessThanNotification.SetNotifyMode( PropertyNotification::NotifyOnChanged );
+
+ // Connects the signals with the callbacks.
+ mHandleVerticalLessThanNotification.NotifySignal().Connect( this, &Decorator::Impl::HandleResetPosition );
+ }
+ else
+ {
+ // The grab handle is not vertically flipped. Never is going to exceed the top edje of the display.
+ mHandleVerticalLessThanNotification.Reset();
+
+ // The vertical distance from the center of the active layer to the bottom edje of the display.
+ const float bottomHeight = -0.5f * mControlSize.height + grabHandle.position.y + grabHandle.lineHeight + grabHandle.size.height;