mTextSelectionPopupCallbackInterface( callbackInterface ),
mBoundingBox( Rect<int>() ),
mHighlightColor( LIGHT_BLUE ),
+ mHighlightPosition( Vector2::ZERO ),
mActiveCursor( ACTIVE_CURSOR_NONE ),
mCursorBlinkInterval( CURSOR_BLINK_INTERVAL ),
mCursorBlinkDuration( 0.0f ),
mCursorBlinkStatus( true ),
mPrimaryCursorVisible( false ),
mSecondaryCursorVisible( false ),
- mSwapSelectionHandles( false )
+ mSwapSelectionHandles( false ),
+ mNotifyEndOfScroll( false )
{
}
if( mPrimaryCursorVisible )
{
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 );
{
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 )
Vector2 primaryPosition = primary.position;
Vector2 secondaryPosition = secondary.position;
- if( LEFT_SELECTION_HANDLE == mHandleScrolling )
- {
- if( mScrollDirection == SCROLL_RIGHT )
- {
- primaryPosition.x = 0.f;
- }
- else
- {
- primaryPosition.x = size.width;
- }
- }
- else if( RIGHT_SELECTION_HANDLE == mHandleScrolling )
- {
- if( mScrollDirection == SCROLL_RIGHT )
- {
- secondaryPosition.x = 0.f;
- }
- else
- {
- secondaryPosition.x = size.width;
- }
- }
-
const bool isPrimaryVisible = ( primaryPosition.x <= size.width ) && ( primaryPosition.x >= 0.f );
const bool isSecondaryVisible = ( secondaryPosition.x <= size.width ) && ( secondaryPosition.x >= 0.f );
else if( Gesture::Finished == gesture.state ||
Gesture::Cancelled == gesture.state )
{
- if( mScrollTimer && mScrollTimer.IsRunning() )
+ if( mScrollTimer &&
+ ( mScrollTimer.IsRunning() || mNotifyEndOfScroll ) )
{
+ mNotifyEndOfScroll = false;
mHandleScrolling = HANDLE_TYPE_COUNT;
StopScrollTimer();
mController.DecorationEvent( type, HANDLE_STOP_SCROLLING, x, y );
return mScrollSpeed;
}
+ void NotifyEndOfScroll()
+ {
+ StopScrollTimer();
+
+ if( mScrollTimer )
+ {
+ mNotifyEndOfScroll = true;
+ }
+ }
+
/**
* Creates and starts a timer to scroll the text when handles are close to the edges of the text.
*
CursorImpl mCursor[CURSOR_COUNT];
HandleImpl mHandle[HANDLE_TYPE_COUNT];
QuadContainer mHighlightQuadList; ///< Sub-selections that combine to create the complete selection highlight
- Vector2 mHighlightPosition; ///< The position of the highlight actor.
Rect<int> mBoundingBox;
Vector4 mHighlightColor; ///< Color of the highlight
+ Vector2 mHighlightPosition; ///< The position of the highlight actor.
unsigned int mActiveCursor;
unsigned int mCursorBlinkInterval;
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 mActiveCopyPastePopup : 1;
bool mCursorBlinkStatus : 1; ///< Flag to switch between blink on and blink off.
bool mPrimaryCursorVisible : 1; ///< Whether the primary cursor is visible.
bool mSecondaryCursorVisible : 1; ///< Whether the secondary cursor is visible.
bool mSwapSelectionHandles : 1; ///< Whether to swap the selection handle images.
+ bool mNotifyEndOfScroll : 1; ///< Whether to notify the end of the scroll.
};
DecoratorPtr Decorator::New( ControllerInterface& controller,
return mImpl->GetScrollSpeed();
}
+void Decorator::NotifyEndOfScroll()
+{
+ mImpl->NotifyEndOfScroll();
+}
+
Decorator::~Decorator()
{
delete mImpl;
{
ChangeState ( EventData::SELECTION_HANDLE_PANNING );
- if( handleNewPosition != mEventData->mLeftSelectionPosition )
+ if( ( handleNewPosition != mEventData->mLeftSelectionPosition ) &&
+ ( handleNewPosition != mEventData->mRightSelectionPosition ) )
{
mEventData->mLeftSelectionPosition = handleNewPosition;
{
ChangeState ( EventData::SELECTION_HANDLE_PANNING );
- if( handleNewPosition != mEventData->mRightSelectionPosition )
+ if( ( handleNewPosition != mEventData->mRightSelectionPosition ) &&
+ ( handleNewPosition != mEventData->mLeftSelectionPosition ) )
{
mEventData->mRightSelectionPosition = handleNewPosition;
if( handleStopScrolling )
{
- mEventData->mUpdateLeftSelectionPosition = mEventData->mLeftSelectionPosition != handlePosition;
+ mEventData->mUpdateLeftSelectionPosition = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition);
mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateLeftSelectionPosition;
- mEventData->mLeftSelectionPosition = handlePosition;
if( mEventData->mUpdateLeftSelectionPosition )
{
+ mEventData->mLeftSelectionPosition = handlePosition;
+
RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
mEventData->mRightSelectionPosition );
}
if( handleStopScrolling )
{
- mEventData->mUpdateRightSelectionPosition = mEventData->mRightSelectionPosition != handlePosition;
+ mEventData->mUpdateRightSelectionPosition = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateRightSelectionPosition;
- mEventData->mRightSelectionPosition = handlePosition;
if( mEventData->mUpdateRightSelectionPosition )
{
+ mEventData->mRightSelectionPosition = handlePosition;
RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
mEventData->mRightSelectionPosition );
}
{
const float xSpeed = event.p2.mFloat;
const Vector2& actualSize = mVisualModel->GetActualSize();
+ const Vector2 currentScrollPosition = mEventData->mScrollPosition;
mEventData->mScrollPosition.x += xSpeed;
ClampHorizontalScroll( actualSize );
- 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 )
+ if( Vector2::ZERO == ( currentScrollPosition - mEventData->mScrollPosition ) )
{
- ChangeState( EventData::GRAB_HANDLE_PANNING );
+ // Notify the decorator there is no more text to scroll.
+ // The decorator won't send more scroll events.
+ mEventData->mDecorator->NotifyEndOfScroll();
}
- else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
+ else
{
- // TODO: This is recalculating the selection box every time the text is scrolled with the selection handles.
- // Think if something can be done to save power.
+ const bool scrollRightDirection = xSpeed > 0.f;
+ const bool leftSelectionHandleEvent = Event::LEFT_SELECTION_HANDLE_EVENT == event.type;
+ const bool rightSelectionHandleEvent = Event::RIGHT_SELECTION_HANDLE_EVENT == event.type;
- ChangeState( EventData::SELECTION_HANDLE_PANNING );
+ if( Event::GRAB_HANDLE_EVENT == event.type )
+ {
+ ChangeState( EventData::GRAB_HANDLE_PANNING );
- const Vector2& position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
+ Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
- // Get the new handle position.
- // The selection handle's position is in decorator coords. Need to transforms to text coords.
- const CharacterIndex handlePosition = GetClosestCursorIndex( position.x - mEventData->mScrollPosition.x - mAlignmentOffset.x,
- position.y - mEventData->mScrollPosition.y - mAlignmentOffset.y );
+ // Position the grag handle close to either the left or right edge.
+ position.x = scrollRightDirection ? 0.f : mControlSize.width;
- if( leftSelectionHandleEvent )
- {
- mEventData->mUpdateLeftSelectionPosition = handlePosition != mEventData->mLeftSelectionPosition;
- mEventData->mLeftSelectionPosition = handlePosition;
+ // Get the new handle position.
+ // The grab handle's position is in decorator coords. Need to transforms to text coords.
+ const CharacterIndex handlePosition = GetClosestCursorIndex( position.x - mEventData->mScrollPosition.x - mAlignmentOffset.x,
+ position.y - mEventData->mScrollPosition.y - mAlignmentOffset.y );
+
+ mEventData->mUpdateCursorPosition = mEventData->mPrimaryCursorPosition != handlePosition;
+ mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateCursorPosition;
+ mEventData->mPrimaryCursorPosition = handlePosition;
}
- else
+ else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
{
- mEventData->mUpdateRightSelectionPosition = handlePosition != mEventData->mRightSelectionPosition;
- mEventData->mRightSelectionPosition = handlePosition;
- }
+ // TODO: This is recalculating the selection box every time the text is scrolled with the selection handles.
+ // Think if something can be done to save power.
- if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
- {
- RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
- mEventData->mRightSelectionPosition );
+ ChangeState( EventData::SELECTION_HANDLE_PANNING );
+
+ Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
+
+ // Position the selection handle close to either the left or right edge.
+ position.x = scrollRightDirection ? 0.f : mControlSize.width;
+
+ // Get the new handle position.
+ // The selection handle's position is in decorator coords. Need to transforms to text coords.
+ const CharacterIndex handlePosition = GetClosestCursorIndex( position.x - mEventData->mScrollPosition.x - mAlignmentOffset.x,
+ position.y - mEventData->mScrollPosition.y - mAlignmentOffset.y );
+
+ if( leftSelectionHandleEvent )
+ {
+ mEventData->mUpdateLeftSelectionPosition = handlePosition != mEventData->mLeftSelectionPosition;
+ mEventData->mLeftSelectionPosition = handlePosition;
+ }
+ else
+ {
+ mEventData->mUpdateRightSelectionPosition = handlePosition != mEventData->mRightSelectionPosition;
+ mEventData->mRightSelectionPosition = handlePosition;
+ }
+
+ if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
+ {
+ RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
+ mEventData->mRightSelectionPosition );
+
+ mEventData->mScrollAfterUpdatePosition = true;
+ }
}
+ mEventData->mDecoratorUpdated = true;
}
- mEventData->mDecoratorUpdated = true;
} // end ( HANDLE_SCROLLING == state )
}
const float xPosition = event.p2.mFloat - mEventData->mScrollPosition.x - mAlignmentOffset.x;
const float yPosition = event.p3.mFloat - mEventData->mScrollPosition.y - mAlignmentOffset.y;
+ const CharacterIndex leftPosition = mEventData->mLeftSelectionPosition;
+ const CharacterIndex rightPosition = mEventData->mRightSelectionPosition;
+
RepositionSelectionHandles( xPosition,
yPosition );
- mEventData->mScrollAfterUpdatePosition = true;
- mEventData->mUpdateLeftSelectionPosition = true;
- mEventData->mUpdateRightSelectionPosition = true;
+ mEventData->mUpdateLeftSelectionPosition = leftPosition != mEventData->mLeftSelectionPosition;
+ mEventData->mUpdateRightSelectionPosition = rightPosition != mEventData->mRightSelectionPosition;
+
+ mEventData->mScrollAfterUpdatePosition = ( ( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition ) &&
+ ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition ) );
}
}