* @param[in] glyphIndex The index to the first glyph.
* @param[in] numberOfGlyphs The number of glyphs.
* @param[out] glyphMetrics Some glyph metrics (font height, advance, ascender and x bearing).
- * @param[in]
- * @param[in]
+ * @param[in] visualModel The visual model.
+ * @param[in] fontClient The font client.
*/
void GetGlyphsMetrics( GlyphIndex glyphIndex,
Length numberOfGlyphs,
mUpdateLeftSelectionPosition( false ),
mUpdateRightSelectionPosition( false ),
mScrollAfterUpdatePosition( false ),
- mScrollAfterDelete( false )
+ mScrollAfterDelete( false ),
+ mAllTextSelected( false )
{}
EventData::~EventData()
OnTapEvent( *iter );
break;
}
+ case Event::LONG_PRESS_EVENT:
+ {
+ OnLongPressEvent( *iter );
+ break;
+ }
case Event::PAN_EVENT:
{
OnPanEvent( *iter );
leftScroll = true;
}
+ SetPopupButtons();
mEventData->mDecoratorUpdated = true;
mEventData->mUpdateLeftSelectionPosition = false;
}
rightScroll = true;
}
+ SetPopupButtons();
mEventData->mDecoratorUpdated = true;
mEventData->mUpdateRightSelectionPosition = false;
}
}
}
+float Controller::Impl::GetDefaultFontLineHeight()
+{
+ FontId defaultFontId = 0u;
+ if( NULL == mFontDefaults )
+ {
+ defaultFontId = mFontClient.GetFontId( EMPTY_STRING,
+ EMPTY_STRING );
+ }
+ else
+ {
+ defaultFontId = mFontDefaults->GetFontId( mFontClient );
+ }
+
+ Text::FontMetrics fontMetrics;
+ mFontClient.GetFontMetrics( defaultFontId, fontMetrics );
+
+ return( fontMetrics.ascender - fontMetrics.descender );
+}
+
void Controller::Impl::OnCursorKeyEvent( const Event& event )
{
if( NULL == mEventData )
}
}
+void Controller::Impl::OnLongPressEvent( const Event& event )
+{
+ if ( EventData::EDITING == mEventData->mState )
+ {
+ ChangeState ( EventData::EDITING_WITH_POPUP );
+ mEventData->mDecoratorUpdated = true;
+ }
+}
+
void Controller::Impl::OnHandleEvent( const Event& event )
{
if( NULL == mEventData )
if( handleStopScrolling )
{
- mEventData->mUpdateLeftSelectionPosition = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition);
+ mEventData->mUpdateLeftSelectionPosition = ( mEventData->mRightSelectionPosition != handlePosition );
mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateLeftSelectionPosition;
if( mEventData->mUpdateLeftSelectionPosition )
if( handleStopScrolling )
{
- mEventData->mUpdateRightSelectionPosition = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
+ mEventData->mUpdateRightSelectionPosition = ( mEventData->mLeftSelectionPosition != handlePosition );
mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateRightSelectionPosition;
-
if( mEventData->mUpdateRightSelectionPosition )
{
mEventData->mRightSelectionPosition = handlePosition;
ClampHorizontalScroll( actualSize );
+ bool endOfScroll = false;
if( Vector2::ZERO == ( currentScrollPosition - mEventData->mScrollPosition ) )
{
// Notify the decorator there is no more text to scroll.
// The decorator won't send more scroll events.
mEventData->mDecorator->NotifyEndOfScroll();
+ // Still need to set the position of the handle.
+ endOfScroll = true;
}
- else
- {
- 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;
- if( Event::GRAB_HANDLE_EVENT == event.type )
- {
- ChangeState( EventData::GRAB_HANDLE_PANNING );
+ // Set the position of the handle.
+ 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;
- Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
+ if( Event::GRAB_HANDLE_EVENT == event.type )
+ {
+ ChangeState( EventData::GRAB_HANDLE_PANNING );
- // Position the grag handle close to either the left or right edge.
- position.x = scrollRightDirection ? 0.f : mControlSize.width;
+ Vector2 position = mEventData->mDecorator->GetPosition( GRAB_HANDLE );
- // 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 );
+ // Position the grag handle close to either the left or right edge.
+ position.x = scrollRightDirection ? 0.f : mControlSize.width;
- mEventData->mUpdateCursorPosition = mEventData->mPrimaryCursorPosition != handlePosition;
- mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateCursorPosition;
- mEventData->mPrimaryCursorPosition = handlePosition;
- }
- else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
- {
- // 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.
+ // 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 );
- ChangeState( EventData::SELECTION_HANDLE_PANNING );
+ mEventData->mUpdateCursorPosition = mEventData->mPrimaryCursorPosition != handlePosition;
+ mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateCursorPosition;
+ mEventData->mPrimaryCursorPosition = handlePosition;
+ }
+ else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
+ {
+ // 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.
- Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_HANDLE );
+ ChangeState( EventData::SELECTION_HANDLE_PANNING );
- // Position the selection handle close to either the left or right edge.
- position.x = scrollRightDirection ? 0.f : mControlSize.width;
+ Vector2 position = mEventData->mDecorator->GetPosition( leftSelectionHandleEvent ? Text::LEFT_SELECTION_HANDLE : Text::RIGHT_SELECTION_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 selection handle close to either the left or right edge.
+ position.x = scrollRightDirection ? 0.f : mControlSize.width;
- if( leftSelectionHandleEvent )
+ // 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 )
+ {
+ const bool differentHandles = ( mEventData->mLeftSelectionPosition != handlePosition ) && ( mEventData->mRightSelectionPosition != handlePosition );
+ mEventData->mUpdateLeftSelectionPosition = endOfScroll || differentHandles;
+ if( differentHandles )
{
- mEventData->mUpdateLeftSelectionPosition = handlePosition != mEventData->mLeftSelectionPosition;
mEventData->mLeftSelectionPosition = handlePosition;
}
- else
+ }
+ else
+ {
+ const bool differentHandles = ( mEventData->mRightSelectionPosition != handlePosition ) && ( mEventData->mLeftSelectionPosition != handlePosition );
+ mEventData->mUpdateRightSelectionPosition = endOfScroll || differentHandles;
+ if( differentHandles )
{
- mEventData->mUpdateRightSelectionPosition = handlePosition != mEventData->mRightSelectionPosition;
mEventData->mRightSelectionPosition = handlePosition;
}
+ }
- if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
- {
- RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
- mEventData->mRightSelectionPosition );
+ if( mEventData->mUpdateLeftSelectionPosition || mEventData->mUpdateRightSelectionPosition )
+ {
+ RepositionSelectionHandles( mEventData->mLeftSelectionPosition,
+ mEventData->mRightSelectionPosition );
- mEventData->mScrollAfterUpdatePosition = true;
- }
+ mEventData->mScrollAfterUpdatePosition = true;
}
- mEventData->mDecoratorUpdated = true;
}
+ mEventData->mDecoratorUpdated = true;
} // end ( HANDLE_SCROLLING == state )
}
}
}
+void Controller::Impl::ShowClipboard()
+{
+ if ( mClipboard )
+ {
+ mClipboard.ShowClipboard();
+ }
+}
+
+void Controller::Impl::HideClipboard()
+{
+ if ( mClipboard )
+ {
+ mClipboard.HideClipboard();
+ }
+}
+
bool Controller::Impl::CopyStringToClipboard( std::string& source )
{
//Send string to clipboard
std::swap( selectionStart, selectionEnd );
}
- GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
- GlyphIndex glyphEnd = *( charactersToGlyphBuffer + ( selectionEnd - 1u ) ) + *( glyphsPerCharacterBuffer + ( selectionEnd - 1u ) ) - 1u;
+ const GlyphIndex glyphStart = *( charactersToGlyphBuffer + selectionStart );
+ const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + ( selectionEnd - 1u ) );
+ const GlyphIndex glyphEnd = *( charactersToGlyphBuffer + ( selectionEnd - 1u ) ) + ( ( numberOfGlyphs > 0 ) ? numberOfGlyphs - 1u : 0u );
mEventData->mDecorator->SwapSelectionHandlesEnabled( firstLine.direction != indicesSwapped );
for( GlyphIndex index = glyphStart; index <= glyphEnd; ++index )
{
+ // TODO: Fix the LATIN ligatures. i.e ff, fi, etc...
const GlyphInfo& glyph = *( glyphsBuffer + index );
const Vector2& position = *( positionsBuffer + index );
RepositionSelectionHandles( selectionStart, selectionEnd );
}
+void Controller::Impl::SetPopupButtons()
+{
+ /**
+ * Sets the Popup buttons to be shown depending on State.
+ *
+ * If SELECTING : CUT & COPY + ( PASTE & CLIPBOARD if content available to paste )
+ *
+ * If EDITING_WITH_POPUP : SELECT & SELECT_ALL
+ */
+
+ TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::NONE;
+
+ if ( ( EventData::SELECTING == mEventData->mState ) || ( EventData::SELECTION_CHANGED == mEventData->mState ) )
+ {
+ buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::CUT | TextSelectionPopup::COPY );
+
+ if ( !IsClipboardEmpty() )
+ {
+ buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+ buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
+ }
+
+ if ( !mEventData->mAllTextSelected )
+ {
+ buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::SELECT_ALL ) );
+ }
+ }
+ else if ( EventData::EDITING_WITH_POPUP == mEventData->mState )
+ {
+ if ( mLogicalModel->mText.Count() && !IsShowingPlaceholderText())
+ {
+ buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
+ }
+
+ if ( !IsClipboardEmpty() )
+ {
+ buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
+ buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::CLIPBOARD ) );
+ }
+ }
+
+ mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
+}
+
void Controller::Impl::ChangeState( EventData::State newState )
{
if( NULL == mEventData )
mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
mEventData->mDecorator->SetPopupActive( false );
mEventData->mDecoratorUpdated = true;
+ HideClipboard();
+ }
+ else if ( EventData::INTERRUPTED == mEventData->mState)
+ {
+ 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;
+ HideClipboard();
}
else if ( EventData::SELECTING == mEventData->mState )
{
mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, true );
if( mEventData->mGrabHandlePopupEnabled )
{
- TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::CUT | TextSelectionPopup::COPY );
- if ( !IsClipboardEmpty() )
- {
- buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
- }
-
- mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
+ SetPopupButtons();
mEventData->mDecorator->SetPopupActive( true );
}
mEventData->mDecoratorUpdated = true;
{
if( mEventData->mGrabHandlePopupEnabled )
{
- TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::CUT | TextSelectionPopup::COPY );
- if ( !IsClipboardEmpty() )
- {
- buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
- }
+ SetPopupButtons();
mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
- mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
mEventData->mDecorator->SetPopupActive( true );
}
mEventData->mDecoratorUpdated = true;
mEventData->mDecorator->SetPopupActive( false );
}
mEventData->mDecoratorUpdated = true;
+ HideClipboard();
}
else if( EventData::EDITING_WITH_POPUP == mEventData->mState )
{
}
if( mEventData->mGrabHandlePopupEnabled )
{
- TextSelectionPopup::Buttons buttonsToShow = TextSelectionPopup::Buttons( TextSelectionPopup::SELECT | TextSelectionPopup::SELECT_ALL );
-
- if ( !IsClipboardEmpty() )
- {
- buttonsToShow = TextSelectionPopup::Buttons ( ( buttonsToShow | TextSelectionPopup::PASTE ) );
- }
-
- mEventData->mDecorator->SetEnabledPopupButtons( buttonsToShow );
+ SetPopupButtons();
mEventData->mDecorator->SetPopupActive( true );
}
+ HideClipboard();
+ mEventData->mDecoratorUpdated = true;
+ }
+ else if( EventData::EDITING_WITH_GRAB_HANDLE == mEventData->mState )
+ {
+ mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
+ if( mEventData->mCursorBlinkEnabled )
+ {
+ mEventData->mDecorator->StartCursorBlink();
+ }
+ // Grab handle is not shown until a tap is received whilst EDITING
+ mEventData->mDecorator->SetHandleActive( GRAB_HANDLE, true );
+ mEventData->mDecorator->SetHandleActive( LEFT_SELECTION_HANDLE, false );
+ mEventData->mDecorator->SetHandleActive( RIGHT_SELECTION_HANDLE, false );
+ if( mEventData->mGrabHandlePopupEnabled )
+ {
+ mEventData->mDecorator->SetPopupActive( false );
+ }
mEventData->mDecoratorUpdated = true;
+ HideClipboard();
}
else if ( EventData::SELECTION_HANDLE_PANNING == mEventData->mState )
{
// Get the glyphs per character table.
const Length* const glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
+ const Length* const charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
// If the vector is void, there is no right to left characters.
const bool hasRightToLeftCharacters = NULL != visualToLogicalBuffer;
// The character in logical order.
const CharacterIndex characterLogicalOrderIndex = hasRightToLeftCharacters ? *( visualToLogicalBuffer + visualIndex ) : visualIndex;
+ // Get the script of the character.
+ const Script script = mLogicalModel->GetScript( characterLogicalOrderIndex );
+
// The first glyph for that character in logical order.
const GlyphIndex glyphLogicalOrderIndex = *( charactersToGlyphBuffer + characterLogicalOrderIndex );
-
// The number of glyphs for that character
const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterLogicalOrderIndex );
const Vector2& position = *( positionsBuffer + glyphLogicalOrderIndex );
- // Find the mid-point of the area containing the glyph
- const float glyphCenter = -glyphMetrics.xBearing + position.x + 0.5f * glyphMetrics.advance;
+ // Prevents to jump the whole Latin ligatures like fi, ff, ...
+ const Length numberOfCharactersInLigature = ( TextAbstraction::LATIN == script ) ? *( charactersPerGlyphBuffer + glyphLogicalOrderIndex ) : 1u;
+ const float glyphAdvance = glyphMetrics.advance / static_cast<float>( numberOfCharactersInLigature );
+
+ for( GlyphIndex index = 0u; !matched && ( index < numberOfCharactersInLigature ); ++index )
+ {
+ // Find the mid-point of the area containing the glyph
+ const float glyphCenter = -glyphMetrics.xBearing + position.x + ( static_cast<float>( index ) + 0.5f ) * glyphAdvance;
+
+ if( visualX < glyphCenter )
+ {
+ visualIndex += index;
+ matched = true;
+ break;
+ }
+ }
- if( visualX < glyphCenter )
+ if( matched )
{
- matched = true;
break;
}
}
logicalIndex = hasRightToLeftCharacters ? *( visualToLogicalCursorBuffer + visualIndex ) : visualIndex;
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p closest visualIndex %d logicalIndex %d\n", this, visualIndex, logicalIndex );
+
return logicalIndex;
}
if( isFirstPosition && isLastPosition )
{
- // There is zero characters. Get the default font.
-
- FontId defaultFontId = 0u;
- if( NULL == mFontDefaults )
- {
- defaultFontId = mFontClient.GetFontId( EMPTY_STRING,
- EMPTY_STRING );
- }
- else
- {
- defaultFontId = mFontDefaults->GetFontId( mFontClient );
- }
-
- Text::FontMetrics fontMetrics;
- mFontClient.GetFontMetrics( defaultFontId, fontMetrics );
-
- cursorInfo.lineHeight = fontMetrics.ascender - fontMetrics.descender;
+ // There is zero characters. Get the default font's line height.
+ cursorInfo.lineHeight = GetDefaultFontLineHeight();
cursorInfo.primaryCursorHeight = cursorInfo.lineHeight;
- cursorInfo.primaryPosition.x = 0.f;
+ cursorInfo.primaryPosition.x = 1.f;
cursorInfo.primaryPosition.y = 0.f;
// Nothing else to do.
return;
}
- // Get the previous logical index.
- const CharacterIndex previousLogical = isFirstPosition ? 0u : logical - 1u;
+ // 'logical' is the logical 'cursor' index.
+ // Get the next and current logical 'character' index.
+ const CharacterIndex nextCharacterIndex = logical;
+ const CharacterIndex characterIndex = isFirstPosition ? logical : logical - 1u;
- // Decrease the logical index if it's the last one.
- if( isLastPosition )
- {
- --logical;
- }
-
- // Get the direction of the character and the previous one.
+ // Get the direction of the character and the next one.
const CharacterDirection* const modelCharacterDirectionsBuffer = ( 0u != mLogicalModel->mCharacterDirections.Count() ) ? mLogicalModel->mCharacterDirections.Begin() : NULL;
CharacterDirection isCurrentRightToLeft = false;
- CharacterDirection isPreviousRightToLeft = false;
+ CharacterDirection isNextRightToLeft = false;
if( NULL != modelCharacterDirectionsBuffer ) // If modelCharacterDirectionsBuffer is NULL, it means the whole text is left to right.
{
- isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + logical );
- isPreviousRightToLeft = *( modelCharacterDirectionsBuffer + previousLogical );
+ isCurrentRightToLeft = *( modelCharacterDirectionsBuffer + characterIndex );
+ isNextRightToLeft = *( modelCharacterDirectionsBuffer + nextCharacterIndex );
}
// Get the line where the character is laid-out.
const LineRun* modelLines = mVisualModel->mLines.Begin();
- const LineIndex lineIndex = mVisualModel->GetLineOfCharacter( logical );
+ const LineIndex lineIndex = mVisualModel->GetLineOfCharacter( characterIndex );
const LineRun& line = *( modelLines + lineIndex );
// Get the paragraph's direction.
// Check whether there is an alternative position:
- cursorInfo.isSecondaryCursor = ( isCurrentRightToLeft != isPreviousRightToLeft ) ||
- ( isLastPosition && ( isRightToLeftParagraph != isCurrentRightToLeft ) );
+ cursorInfo.isSecondaryCursor = ( !isLastPosition && ( isCurrentRightToLeft != isNextRightToLeft ) ) ||
+ ( isLastPosition && ( isRightToLeftParagraph != isCurrentRightToLeft ) );
// Set the line height.
cursorInfo.lineHeight = line.ascender + -line.descender;
- // Convert the cursor position into the glyph position.
- CharacterIndex characterIndex = logical;
- if( cursorInfo.isSecondaryCursor &&
- ( isRightToLeftParagraph != isCurrentRightToLeft ) )
+ // Calculate the primary cursor.
+
+ CharacterIndex index = characterIndex;
+ if( cursorInfo.isSecondaryCursor )
{
- characterIndex = previousLogical;
+ // If there is a secondary position, the primary cursor may be in a different place than the logical index.
+
+ if( isLastPosition )
+ {
+ // The position of the cursor after the last character needs special
+ // care depending on its direction and the direction of the paragraph.
+
+ // Need to find the first character after the last character with the paragraph's direction.
+ // i.e l0 l1 l2 r0 r1 should find r0.
+
+ // TODO: check for more than one line!
+ index = isRightToLeftParagraph ? line.characterRun.characterIndex : line.characterRun.characterIndex + line.characterRun.numberOfCharacters - 1u;
+ index = mLogicalModel->GetLogicalCharacterIndex( index );
+ }
+ else
+ {
+ index = ( isRightToLeftParagraph == isCurrentRightToLeft ) ? characterIndex : nextCharacterIndex;
+ }
}
- const GlyphIndex currentGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + characterIndex );
- const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + characterIndex );
- const Length numberOfCharacters = *( mVisualModel->mCharactersPerGlyph.Begin() +currentGlyphIndex );
+ // Convert the cursor position into the glyph position.
+ const GlyphIndex primaryGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + index );
+ const Length primaryNumberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + index );
+ const Length primaryNumberOfCharacters = *( mVisualModel->mCharactersPerGlyph.Begin() + primaryGlyphIndex );
// Get the metrics for the group of glyphs.
GlyphMetrics glyphMetrics;
- GetGlyphsMetrics( currentGlyphIndex,
- numberOfGlyphs,
+ GetGlyphsMetrics( primaryGlyphIndex,
+ primaryNumberOfGlyphs,
glyphMetrics,
mVisualModel,
mFontClient );
- float interGlyphAdvance = 0.f;
+ float glyphAdvance = 0.f;
if( !isLastPosition &&
- ( numberOfCharacters > 1u ) )
+ ( primaryNumberOfCharacters > 1u ) )
+ {
+ const CharacterIndex firstIndex = *( mVisualModel->mGlyphsToCharacters.Begin() + primaryGlyphIndex );
+ glyphAdvance = static_cast<float>( 1u + characterIndex - firstIndex ) * glyphMetrics.advance / static_cast<float>( primaryNumberOfCharacters );
+ }
+ else
{
- const CharacterIndex firstIndex = *( mVisualModel->mGlyphsToCharacters.Begin() + currentGlyphIndex );
- interGlyphAdvance = static_cast<float>( characterIndex - firstIndex ) * glyphMetrics.advance / static_cast<float>( numberOfCharacters );
+ glyphAdvance = glyphMetrics.advance;
}
// Get the glyph position and x bearing.
- const Vector2& currentPosition = *( mVisualModel->mGlyphPositions.Begin() + currentGlyphIndex );
+ const Vector2& primaryPosition = *( mVisualModel->mGlyphPositions.Begin() + primaryGlyphIndex );
- // Set the cursor's height.
- cursorInfo.primaryCursorHeight = glyphMetrics.fontHeight;
-
- // Set the position.
- cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + currentPosition.x + ( isCurrentRightToLeft ? glyphMetrics.advance : interGlyphAdvance );
- cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
+ // Set the primary cursor's height.
+ cursorInfo.primaryCursorHeight = cursorInfo.isSecondaryCursor ? 0.5f * glyphMetrics.fontHeight : glyphMetrics.fontHeight;
+ // Set the primary cursor's position.
if( isLastPosition )
{
- // The position of the cursor after the last character needs special
- // care depending on its direction and the direction of the paragraph.
-
- if( cursorInfo.isSecondaryCursor )
- {
- // Need to find the first character after the last character with the paragraph's direction.
- // i.e l0 l1 l2 r0 r1 should find r0.
-
- // TODO: check for more than one line!
- characterIndex = isRightToLeftParagraph ? line.characterRun.characterIndex : line.characterRun.characterIndex + line.characterRun.numberOfCharacters - 1u;
- characterIndex = mLogicalModel->GetLogicalCharacterIndex( characterIndex );
-
- const GlyphIndex glyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + characterIndex );
- const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + characterIndex );
-
- const Vector2& position = *( mVisualModel->mGlyphPositions.Begin() + glyphIndex );
+ cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + primaryPosition.x + ( isRightToLeftParagraph ? 0.f : glyphMetrics.advance );
+ }
+ else
+ {
+ cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + primaryPosition.x + ( ( ( isFirstPosition && !isCurrentRightToLeft ) || ( !isFirstPosition && isCurrentRightToLeft ) ) ? 0.f : glyphAdvance );
+ }
+ cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
- // Get the metrics for the group of glyphs.
- GlyphMetrics glyphMetrics;
- GetGlyphsMetrics( glyphIndex,
- numberOfGlyphs,
- glyphMetrics,
- mVisualModel,
- mFontClient );
+ // Calculate the secondary cursor.
- cursorInfo.primaryPosition.x = -glyphMetrics.xBearing + position.x + ( isRightToLeftParagraph ? 0.f : glyphMetrics.advance );
+ if( cursorInfo.isSecondaryCursor )
+ {
+ // Set the secondary cursor's height.
+ cursorInfo.secondaryCursorHeight = 0.5f * glyphMetrics.fontHeight;
- cursorInfo.primaryPosition.y = line.ascender - glyphMetrics.ascender;
- }
- else
+ CharacterIndex index = characterIndex;
+ if( !isLastPosition )
{
- if( !isCurrentRightToLeft )
- {
- cursorInfo.primaryPosition.x += glyphMetrics.advance;
- }
- else
- {
- cursorInfo.primaryPosition.x -= glyphMetrics.advance;
- }
+ index = ( isRightToLeftParagraph == isCurrentRightToLeft ) ? nextCharacterIndex : characterIndex;
}
- }
- // Set the alternative cursor position.
- if( cursorInfo.isSecondaryCursor )
- {
- // Convert the cursor position into the glyph position.
- const CharacterIndex previousCharacterIndex = ( ( isRightToLeftParagraph != isCurrentRightToLeft ) ? logical : previousLogical );
- const GlyphIndex previousGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + previousCharacterIndex );
- const Length numberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + previousCharacterIndex );
+ const GlyphIndex secondaryGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + index );
+ const Length secondaryNumberOfGlyphs = *( mVisualModel->mGlyphsPerCharacter.Begin() + index );
- // Get the glyph position.
- const Vector2& previousPosition = *( mVisualModel->mGlyphPositions.Begin() + previousGlyphIndex );
+ const Vector2& secondaryPosition = *( mVisualModel->mGlyphPositions.Begin() + index );
- // Get the metrics for the group of glyphs.
- GlyphMetrics glyphMetrics;
- GetGlyphsMetrics( previousGlyphIndex,
- numberOfGlyphs,
+ GetGlyphsMetrics( secondaryGlyphIndex,
+ secondaryNumberOfGlyphs,
glyphMetrics,
mVisualModel,
mFontClient );
- // Set the cursor position and height.
- cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + previousPosition.x + ( ( ( isLastPosition && !isCurrentRightToLeft ) ||
- ( !isLastPosition && isCurrentRightToLeft ) ) ? glyphMetrics.advance : 0.f );
-
- cursorInfo.secondaryCursorHeight = 0.5f * glyphMetrics.fontHeight;
-
+ // Set the secondary cursor's position.
+ cursorInfo.secondaryPosition.x = -glyphMetrics.xBearing + secondaryPosition.x + ( isCurrentRightToLeft ? 0.f : glyphMetrics.advance );
cursorInfo.secondaryPosition.y = cursorInfo.lineHeight - cursorInfo.secondaryCursorHeight - line.descender - ( glyphMetrics.fontHeight - glyphMetrics.ascender );
-
- // Update the primary cursor height as well.
- cursorInfo.primaryCursorHeight *= 0.5f;
}
}
cursorPosition.x,
cursorPosition.y,
cursorInfo.lineHeight );
+
+ // If selection handle at start of the text and other at end of the text then all text is selected.
+ const CharacterIndex startOfSelection = std::min( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
+ const CharacterIndex endOfSelection = std::max ( mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition );
+ mEventData->mAllTextSelected = ( startOfSelection == 0 ) && ( endOfSelection == mLogicalModel->mText.Count() );
}
void Controller::Impl::ClampHorizontalScroll( const Vector2& actualSize )
mEventData->mScrollPosition.x = currentCursorPosition.x - cursorInfo.primaryPosition.x - mAlignmentOffset.x;
ClampHorizontalScroll( mVisualModel->GetActualSize() );
- bool updateCursorPosition = true;
const Vector2 offset = mEventData->mScrollPosition + mAlignmentOffset;
const Vector2 cursorPosition = cursorInfo.primaryPosition + offset;
- if( updateCursorPosition )
- {
- // Sets the cursor position.
- mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
- cursorPosition.x,
- cursorPosition.y,
- cursorInfo.primaryCursorHeight,
- cursorInfo.lineHeight );
+ // Sets the cursor position.
+ mEventData->mDecorator->SetPosition( PRIMARY_CURSOR,
+ cursorPosition.x,
+ cursorPosition.y,
+ cursorInfo.primaryCursorHeight,
+ cursorInfo.lineHeight );
- // Sets the grab handle position.
- mEventData->mDecorator->SetPosition( GRAB_HANDLE,
- cursorPosition.x,
- cursorPosition.y,
+ // Sets the grab handle position.
+ mEventData->mDecorator->SetPosition( GRAB_HANDLE,
+ cursorPosition.x,
+ cursorPosition.y,
+ cursorInfo.lineHeight );
+
+ if( cursorInfo.isSecondaryCursor )
+ {
+ mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
+ cursorInfo.secondaryPosition.x + offset.x,
+ cursorInfo.secondaryPosition.y + offset.y,
+ cursorInfo.secondaryCursorHeight,
cursorInfo.lineHeight );
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + offset.x, cursorInfo.secondaryPosition.y + offset.y );
+ }
+ // Set which cursors are active according the state.
+ if( ( EventData::EDITING == mEventData->mState ) ||
+ ( EventData::EDITING_WITH_POPUP == mEventData->mState ) ||
+ ( EventData::GRAB_HANDLE_PANNING == mEventData->mState ) )
+ {
if( cursorInfo.isSecondaryCursor )
{
mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_BOTH );
- mEventData->mDecorator->SetPosition( SECONDARY_CURSOR,
- cursorInfo.secondaryPosition.x + offset.x,
- cursorInfo.secondaryPosition.y + offset.y,
- cursorInfo.secondaryCursorHeight,
- cursorInfo.lineHeight );
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Secondary cursor position: %f,%f\n", cursorInfo.secondaryPosition.x + offset.x, cursorInfo.secondaryPosition.y + offset.y );
}
else
{
mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_PRIMARY );
}
}
+ else
+ {
+ mEventData->mDecorator->SetActiveCursor( ACTIVE_CURSOR_NONE );
+ }
}
void Controller::Impl::RequestRelayout()