EventData::EventData( DecoratorPtr decorator )
: mDecorator( decorator ),
mImfManager(),
- mPlaceholderText(),
+ mPlaceholderFont( NULL ),
mPlaceholderTextActive(),
mPlaceholderTextInactive(),
- mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ),
+ mPlaceholderTextColor( 0.8f, 0.8f, 0.8f, 0.8f ), // This color has been published in the Public API (placeholder-properties.h).
mEventQueue(),
mInputStyleChangedQueue(),
mPreviousState( INACTIVE ),
mScrollAfterDelete( false ),
mAllTextSelected( false ),
mUpdateInputStyle( false ),
- mPasswordInput( false )
+ mPasswordInput( false ),
+ mIsPlaceholderPixelSize( false ),
+ mIsPlaceholderElideEnabled( false ),
+ mPlaceholderEllipsisFlag( false )
{
mImfManager = ImfManager::Get();
}
// Get the default font's description.
TextAbstraction::FontDescription defaultFontDescription;
TextAbstraction::PointSize26Dot6 defaultPointSize = TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
- if( NULL != mFontDefaults )
+
+ if( IsShowingPlaceholderText() && mEventData && ( NULL != mEventData->mPlaceholderFont ) )
+ {
+ // If the placeholder font is set specifically, only placeholder font is changed.
+ defaultFontDescription = mEventData->mPlaceholderFont->mFontDescription;
+ if( mEventData->mPlaceholderFont->sizeDefined )
+ {
+ defaultPointSize = mEventData->mPlaceholderFont->mDefaultPointSize * 64u;
+ }
+ }
+ else if( NULL != mFontDefaults )
{
+ // Set the normal font and the placeholder font.
defaultFontDescription = mFontDefaults->mFontDescription;
defaultPointSize = mFontDefaults->mDefaultPointSize * 64u;
}
void Controller::Impl::OnCursorKeyEvent( const Event& event )
{
- if( NULL == mEventData )
+ if( NULL == mEventData || !IsShowingRealText() )
{
// Nothing to do if there is no text input.
return;
}
int keyCode = event.p1.mInt;
+ bool isShiftModifier = event.p2.mBool;
+
+ CharacterIndex previousPrimaryCursorPosition = mEventData->mPrimaryCursorPosition;
if( Dali::DALI_KEY_CURSOR_LEFT == keyCode )
{
mEventData->mPrimaryCursorPosition = CalculateNewCursorIndex( mEventData->mPrimaryCursorPosition );
}
}
- else if( Dali::DALI_KEY_CURSOR_UP == keyCode )
+ else if( Dali::DALI_KEY_CURSOR_UP == keyCode && !isShiftModifier )
{
+ // Ignore Shift-Up for text selection for now.
+
// Get first the line index of the current cursor position index.
CharacterIndex characterIndex = 0u;
CharacterHitTest::TAP,
matchedCharacter );
}
- else if( Dali::DALI_KEY_CURSOR_DOWN == keyCode )
+ else if( Dali::DALI_KEY_CURSOR_DOWN == keyCode && !isShiftModifier )
{
+ // Ignore Shift-Down for text selection for now.
+
// Get first the line index of the current cursor position index.
CharacterIndex characterIndex = 0u;
}
}
- mEventData->mUpdateCursorPosition = true;
+ if ( !isShiftModifier && mEventData->mState != EventData::SELECTING )
+ {
+ // Update selection position after moving the cursor
+ mEventData->mLeftSelectionPosition = mEventData->mPrimaryCursorPosition;
+ mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
+ }
+
+ if ( isShiftModifier && IsShowingRealText() )
+ {
+ // Handle text selection
+ bool selecting = false;
+
+ if ( Dali::DALI_KEY_CURSOR_LEFT == keyCode || Dali::DALI_KEY_CURSOR_RIGHT == keyCode )
+ {
+ // Shift-Left/Right to select the text
+ int cursorPositionDelta = mEventData->mPrimaryCursorPosition - previousPrimaryCursorPosition;
+ if ( cursorPositionDelta > 0 || mEventData->mRightSelectionPosition > 0u ) // Check the boundary
+ {
+ mEventData->mRightSelectionPosition += cursorPositionDelta;
+ }
+ selecting = true;
+ }
+ else if ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition )
+ {
+ // Show no grab handles and text highlight if Shift-Up/Down pressed but no selected text
+ selecting = true;
+ }
+
+ if ( selecting )
+ {
+ // Notify the cursor position to the imf manager.
+ if( mEventData->mImfManager )
+ {
+ mEventData->mImfManager.SetCursorPosition( mEventData->mPrimaryCursorPosition );
+ mEventData->mImfManager.NotifyCursorPosition();
+ }
+
+ ChangeState( EventData::SELECTING );
+
+ mEventData->mUpdateLeftSelectionPosition = true;
+ mEventData->mUpdateRightSelectionPosition = true;
+ mEventData->mUpdateGrabHandlePosition = true;
+ mEventData->mUpdateHighlightBox = true;
+
+ // Hide the text selection popup if select the text using keyboard instead of moving grab handles
+ if( mEventData->mGrabHandlePopupEnabled )
+ {
+ mEventData->mDecorator->SetPopupActive( false );
+ }
+ }
+ }
+ else
+ {
+ // Handle normal cursor move
+ ChangeState( EventData::EDITING );
+ mEventData->mUpdateCursorPosition = true;
+ }
+
mEventData->mUpdateInputStyle = true;
mEventData->mScrollAfterUpdatePosition = true;
}
mEventData->mPrimaryCursorPosition = 0u;
}
+ // Update selection position after tapping
+ mEventData->mLeftSelectionPosition = mEventData->mPrimaryCursorPosition;
+ mEventData->mRightSelectionPosition = mEventData->mPrimaryCursorPosition;
+
mEventData->mUpdateCursorPosition = true;
mEventData->mUpdateGrabHandlePosition = true;
mEventData->mScrollAfterUpdatePosition = true;
mModel->mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
// Mark the paragraphs to be updated.
- mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
- mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ if( Layout::Engine::SINGLE_LINE_BOX == mLayoutEngine.GetLayout() )
+ {
+ mTextUpdateInfo.mCharacterIndex = 0;
+ mTextUpdateInfo.mNumberOfCharactersToRemove = mTextUpdateInfo.mPreviousNumberOfCharacters;
+ mTextUpdateInfo.mNumberOfCharactersToAdd = mTextUpdateInfo.mPreviousNumberOfCharacters - lengthOfSelectedText;
+ mTextUpdateInfo.mClearAll = true;
+ }
+ else
+ {
+ mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+ mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+ }
// Delete text between handles
Vector<Character>::Iterator first = utf32Characters.Begin() + startOfSelectedText;
const SelectionBoxInfo& firstSelectionBoxLineInfo = *( selectionBoxLinesInfo.Begin() );
highLightPosition.y = firstSelectionBoxLineInfo.lineOffset;
- mEventData->mDecorator->SetHighLightBox( highLightPosition, highLightSize );
+ mEventData->mDecorator->SetHighLightBox( highLightPosition, highLightSize, static_cast<float>( mModel->GetOutlineWidth() ) );
if( !mEventData->mDecorator->IsSmoothHandlePanEnabled() )
{
switch( mModel->mHorizontalAlignment )
{
- case Layout::HORIZONTAL_ALIGN_BEGIN:
+ case Text::HorizontalAlignment::BEGIN :
{
cursorInfo.primaryPosition.x = 0.f;
break;
}
- case Layout::HORIZONTAL_ALIGN_CENTER:
+ case Text::HorizontalAlignment::CENTER:
{
cursorInfo.primaryPosition.x = floorf( 0.5f * mModel->mVisualModel->mControlSize.width );
break;
}
- case Layout::HORIZONTAL_ALIGN_END:
+ case Text::HorizontalAlignment::END:
{
cursorInfo.primaryPosition.x = mModel->mVisualModel->mControlSize.width - mEventData->mDecorator->GetCursorWidth();
break;
return;
}
- Text::GetCursorPosition( mModel->mVisualModel,
- mModel->mLogicalModel,
- mMetrics,
- logical,
+ const bool isMultiLine = ( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() );
+ GetCursorPositionParameters parameters;
+ parameters.visualModel = mModel->mVisualModel;
+ parameters.logicalModel = mModel->mLogicalModel;
+ parameters.metrics = mMetrics;
+ parameters.logical = logical;
+ parameters.isMultiline = isMultiLine;
+
+ Text::GetCursorPosition( parameters,
cursorInfo );
- if( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
+ // Adds Outline offset.
+ const float outlineWidth = static_cast<float>( mModel->GetOutlineWidth() );
+ cursorInfo.primaryPosition.x += outlineWidth;
+ cursorInfo.primaryPosition.y += outlineWidth;
+ cursorInfo.secondaryPosition.x += outlineWidth;
+ cursorInfo.secondaryPosition.y += outlineWidth;
+
+ if( isMultiLine )
{
// If the text is editable and multi-line, the cursor position after a white space shouldn't exceed the boundaries of the text control.
const Vector2 cursorPosition = cursorInfo.primaryPosition + mModel->mScrollPosition;
+ mEventData->mDecorator->SetGlyphOffset( PRIMARY_CURSOR, cursorInfo.glyphOffset );
+
// Sets the cursor position.
mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
cursorPosition.x,
mModel->mScrollPosition.x = mModel->mVisualModel->mControlSize.width - positionEndX;
}
- if( decoratorPositionBeginY < 0.f )
- {
- mModel->mScrollPosition.y = -position.y;
- }
- else if( decoratorPositionEndY > mModel->mVisualModel->mControlSize.height )
+ if( Layout::Engine::MULTI_LINE_BOX == mLayoutEngine.GetLayout() )
{
- mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
+ if( decoratorPositionBeginY < 0.f )
+ {
+ mModel->mScrollPosition.y = -position.y;
+ }
+ else if( decoratorPositionEndY > mModel->mVisualModel->mControlSize.height )
+ {
+ mModel->mScrollPosition.y = mModel->mVisualModel->mControlSize.height - positionEndY;
+ }
}
}
// Get the current cursor position in decorator coords.
const Vector2& currentCursorPosition = mEventData->mDecorator->GetPosition( PRIMARY_CURSOR );
+ const LineIndex lineIndex = mModel->mVisualModel->GetLineOfCharacter( mEventData->mPrimaryCursorPosition );
+
+
+
// Calculate the offset to match the cursor position before the character was deleted.
mModel->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x;
- mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset;
+
+ //If text control has more than two lines and current line index is not last, calculate scrollpositionY
+ if( mModel->mVisualModel->mLines.Count() > 1u && lineIndex != mModel->mVisualModel->mLines.Count() -1u )
+ {
+ const float currentCursorGlyphOffset = mEventData->mDecorator->GetGlyphOffset( PRIMARY_CURSOR );
+ mModel->mScrollPosition.y = currentCursorPosition.y - cursorInfo.lineOffset - currentCursorGlyphOffset;
+ }
+
ClampHorizontalScroll( mModel->mVisualModel->GetLayoutSize() );
ClampVerticalScroll( mModel->mVisualModel->GetLayoutSize() );