mScrollPosition(),
mState( INACTIVE ),
mPrimaryCursorPosition( 0u ),
- mSecondaryCursorPosition( 0u ),
+ mLeftSelectionPosition( 0u ),
+ mRightSelectionPosition( 0u ),
mDecoratorUpdated( false ),
mCursorBlinkEnabled( true ),
mGrabHandleEnabled( true ),
- mGrabHandlePopupEnabled( true ),
- mSelectionEnabled( true ),
+ mGrabHandlePopupEnabled( false ),
+ mSelectionEnabled( false ),
mHorizontalScrollingEnabled( true ),
mVerticalScrollingEnabled( false ),
- mUpdateCursorPosition( false )
+ mUpdateCursorPosition( false ),
+ mUpdateLeftSelectionPosition( false ),
+ mUpdateRightSelectionPosition( false ),
+ mScrollAfterUpdateCursorPosition( false )
{}
EventData::~EventData()
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;
}
}
// The cursor must also be repositioned after inserts into the model
if( mEventData->mUpdateCursorPosition )
{
+ // Updates the cursor position and scrolls the text to make it visible.
+
UpdateCursorPosition();
+
+ if( mEventData->mScrollAfterUpdateCursorPosition )
+ {
+ ScrollToMakeCursorVisible();
+ 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();
// TODO
}
- UpdateCursorPosition();
+ mEventData->mUpdateCursorPosition = true;
+ mEventData->mScrollAfterUpdateCursorPosition = true;
}
void Controller::Impl::HandleCursorKey( int keyCode )
{
ChangeState( EventData::EDITING );
- const float xPosition = event.p2.mFloat - mAlignmentOffset.x;
- const float yPosition = event.p3.mFloat - mAlignmentOffset.y;
+ 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 );
- UpdateCursorPosition();
+ mEventData->mUpdateCursorPosition = true;
+ mEventData->mScrollAfterUpdateCursorPosition = true;
}
else if( mEventData->mSelectionEnabled &&
( 2u == tapCount ) )
Gesture::Continuing == state )
{
const Vector2& actualSize = mVisualModel->GetActualSize();
+ const Vector2 currentScroll = mEventData->mScrollPosition;
if( mEventData->mHorizontalScrollingEnabled )
{
const float displacementX = event.p2.mFloat;
mEventData->mScrollPosition.x += displacementX;
- // Clamp between -space & 0 (and the text alignment).
- if( actualSize.width > mControlSize.width )
- {
- const float space = ( actualSize.width - mControlSize.width ) + mAlignmentOffset.x;
- mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x < -space ) ? -space : mEventData->mScrollPosition.x;
- mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x > -mAlignmentOffset.x ) ? -mAlignmentOffset.x : mEventData->mScrollPosition.x;
-
- mEventData->mDecoratorUpdated = true;
- }
- else
- {
- mEventData->mScrollPosition.x = 0.f;
- }
+ ClampHorizontalScroll( actualSize );
}
if( mEventData->mVerticalScrollingEnabled )
const float displacementY = event.p3.mFloat;
mEventData->mScrollPosition.y += displacementY;
- // Clamp between -space & 0 (and the text alignment).
- if( actualSize.height > mControlSize.height )
- {
- const float space = ( actualSize.height - mControlSize.height ) + mAlignmentOffset.y;
- mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y < -space ) ? -space : mEventData->mScrollPosition.y;
- mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y > -mAlignmentOffset.y ) ? -mAlignmentOffset.y : mEventData->mScrollPosition.y;
+ ClampVerticalScroll( actualSize );
+ }
- mEventData->mDecoratorUpdated = true;
- }
- else
- {
- mEventData->mScrollPosition.y = 0.f;
- }
+ if( mEventData->mDecorator )
+ {
+ mEventData->mDecorator->UpdatePositions( mEventData->mScrollPosition - currentScroll );
}
}
}
-void Controller::Impl::OnGrabHandleEvent( const Event& event )
+void Controller::Impl::OnHandleEvent( const Event& event )
{
if( NULL == mEventData )
{
return;
}
- unsigned int state = event.p1.mUint;
+ const unsigned int state = event.p1.mUint;
- if( GRAB_HANDLE_PRESSED == state )
+ if( HANDLE_PRESSED == state )
{
- float xPosition = event.p2.mFloat + mEventData->mScrollPosition.x;
- float yPosition = event.p3.mFloat + mEventData->mScrollPosition.y;
+ // 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 );
+ const CharacterIndex handleNewPosition = GetClosestCursorIndex( xPosition, yPosition );
- UpdateCursorPosition();
+ if( Event::GRAB_HANDLE_EVENT == event.type )
+ {
+ ChangeState ( EventData::EDITING );
- //mDecorator->HidePopup();
- ChangeState ( EventData::EDITING );
+ if( handleNewPosition != mEventData->mPrimaryCursorPosition )
+ {
+ mEventData->mPrimaryCursorPosition = handleNewPosition;
+ mEventData->mUpdateCursorPosition = true;
+ }
+ }
+ else if( Event::LEFT_SELECTION_HANDLE_EVENT == event.type )
+ {
+ 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 ) )
+ else if( ( HANDLE_RELEASED == state ) ||
+ ( HANDLE_STOP_SCROLLING == state ) )
{
- //mDecorator->ShowPopup();
- ChangeState ( EventData::EDITING_WITH_POPUP );
+ if( mEventData->mGrabHandlePopupEnabled )
+ {
+ ChangeState( EventData::EDITING_WITH_POPUP );
+ }
+ if( Event::GRAB_HANDLE_EVENT == event.type )
+ {
+ 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->mScrollAfterUpdateCursorPosition = true;
+ }
+ }
mEventData->mDecoratorUpdated = true;
}
+ else if( HANDLE_SCROLLING == state )
+ {
+ const float xSpeed = event.p2.mFloat;
+ const Vector2& actualSize = mVisualModel->GetActualSize();
+
+ mEventData->mScrollPosition.x += xSpeed;
+
+ ClampHorizontalScroll( actualSize );
+
+ mEventData->mDecoratorUpdated = true;
+ }
}
void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY )
if( count )
{
- float primaryX = positions[0].x;
- float secondaryX = positions[count-1].x + glyphs[count-1].width;
+ float primaryX = positions[0].x + mEventData->mScrollPosition.x;
+ float secondaryX = positions[count-1].x + glyphs[count-1].width + mEventData->mScrollPosition.x;
// TODO - multi-line selection
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, 0.0f, height );
- mEventData->mDecorator->SetPosition( SECONDARY_SELECTION_HANDLE, secondaryX, 0.0f, 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, 0.0f, secondaryX, height );
+ mEventData->mDecorator->AddHighlight( primaryX, mEventData->mScrollPosition.y, secondaryX, height + mEventData->mScrollPosition.y );
}
}
{
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;
}
{
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 )
}
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 )
}
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;
}
}
return logicalIndex;
}
- // Transform to visual model coords
- visualX -= mEventData->mScrollPosition.x;
- visualY -= mEventData->mScrollPosition.y;
-
// Find which line is closest
const LineIndex lineIndex = GetClosestLine( visualY );
const LineRun& line = mVisualModel->mLines[lineIndex];
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,
- cursorInfo.primaryPosition.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,
- cursorInfo.secondaryPosition.y,
+ cursorInfo.secondaryPosition.x + offset.x,
+ cursorInfo.secondaryPosition.y + offset.y,
cursorInfo.secondaryCursorHeight,
cursorInfo.lineHeight );
}
{
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;
+
+ 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 )
+{
+ // Clamp between -space & 0 (and the text alignment).
+ if( actualSize.width > mControlSize.width )
+ {
+ const float space = ( actualSize.width - mControlSize.width ) + mAlignmentOffset.x;
+ mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x < -space ) ? -space : mEventData->mScrollPosition.x;
+ mEventData->mScrollPosition.x = ( mEventData->mScrollPosition.x > -mAlignmentOffset.x ) ? -mAlignmentOffset.x : mEventData->mScrollPosition.x;
+
+ mEventData->mDecoratorUpdated = true;
+ }
+ else
+ {
+ mEventData->mScrollPosition.x = 0.f;
+ }
+}
+
+void Controller::Impl::ClampVerticalScroll( const Vector2& actualSize )
+{
+ // Clamp between -space & 0 (and the text alignment).
+ if( actualSize.height > mControlSize.height )
+ {
+ const float space = ( actualSize.height - mControlSize.height ) + mAlignmentOffset.y;
+ mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y < -space ) ? -space : mEventData->mScrollPosition.y;
+ mEventData->mScrollPosition.y = ( mEventData->mScrollPosition.y > -mAlignmentOffset.y ) ? -mAlignmentOffset.y : mEventData->mScrollPosition.y;
+
+ mEventData->mDecoratorUpdated = true;
+ }
+ else
+ {
+ mEventData->mScrollPosition.y = 0.f;
+ }
+}
+
+void Controller::Impl::ScrollToMakeCursorVisible()
+{
+ if( NULL == mEventData )
+ {
+ // Nothing to do if there is no text input.
+ return;
+ }
+
+ const Vector2& primaryCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
+
+ Vector2 offset;
+ bool updateDecorator = false;
+ if( primaryCursorPosition.x < 0.f )
+ {
+ offset.x = -primaryCursorPosition.x;
+ mEventData->mScrollPosition.x += offset.x;
+ updateDecorator = true;
+ }
+ else if( primaryCursorPosition.x > mControlSize.width )
+ {
+ offset.x = mControlSize.width - primaryCursorPosition.x;
+ mEventData->mScrollPosition.x += offset.x;
+ updateDecorator = true;
+ }
+
+ if( updateDecorator && mEventData->mDecorator )
+ {
+ mEventData->mDecorator->UpdatePositions( offset );
+ }
- mEventData->mUpdateCursorPosition = false;
- mEventData->mDecoratorUpdated = true;
+ // TODO : calculate the vertical scroll.
}
void Controller::Impl::RequestRelayout()