It updates the double tap and long press event on a text area with no text.
i.e. On a position clearly after the last character of the text.
* Double Tap : The cursor is placed at the beginning or at the end of the text.
* Long Press : The cursor is placed at the beginning or at the end of the text and shows the text's selection popup.
Change-Id: Iaf9ea817a515781d20c87f60991e1996d5440a62
Signed-off-by: Victor Cebollada <v.cebollada@samsung.com>
// Disable the smooth handle panning.
mController->SetSmoothHandlePanEnabled( false );
+ mController->SetNoTextDoubleTapAction( Controller::NoTextTap::NO_ACTION );
+ mController->SetNoTextLongPressAction( Controller::NoTextTap::SHOW_SELECTION_POPUP );
+
// Forward input events to controller
EnableGestureDetection( static_cast<Gesture::Type>( Gesture::Tap | Gesture::Pan | Gesture::LongPress ) );
GetTapGestureDetector().SetMaximumTapsRequired( 2 );
: textBuffer( textBuffer ),
totalNumberOfCharacters( totalNumberOfCharacters ),
hitCharacter( hitCharacter ),
- foundIndex( 0u ),
+ foundIndex( 0 ),
isWhiteSpace( isWhiteSpace ),
isNewParagraph( isNewParagraph )
{}
{
LineIndex GetClosestLine( VisualModelPtr visualModel,
- float visualY )
+ float visualY,
+ bool& matchedLine )
{
float totalHeight = 0.f;
- LineIndex lineIndex = 0u;
+ LineIndex lineIndex = 0;
+ matchedLine = false;
+
+ if( visualY < 0.f )
+ {
+ return 0;
+ }
const Vector<LineRun>& lines = visualModel->mLines;
if( visualY < totalHeight )
{
+ matchedLine = true;
return lineIndex;
}
}
- if( lineIndex == 0u )
+ if( lineIndex == 0 )
{
return 0;
}
- return lineIndex-1;
+ return lineIndex - 1u;
}
float CalculateLineOffset( const Vector<LineRun>& lines,
LogicalModelPtr logicalModel,
MetricsPtr metrics,
float visualX,
- float visualY )
+ float visualY,
+ CharacterHitTest::Mode mode,
+ bool& matchedCharacter )
{
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "GetClosestCursorIndex, closest visualX %f visualY %f\n", visualX, visualY );
- CharacterIndex logicalIndex = 0u;
+ // Whether there is a hit on a glyph.
+ matchedCharacter = false;
+
+ CharacterIndex logicalIndex = 0;
const Length totalNumberOfGlyphs = visualModel->mGlyphs.Count();
const Length totalNumberOfLines = visualModel->mLines.Count();
return logicalIndex;
}
+ // Whether there is a hit on a line.
+ bool matchedLine = false;
+
// Find which line is closest.
const LineIndex lineIndex = Text::GetClosestLine( visualModel,
- visualY );
+ visualY,
+ matchedLine );
+
+ if( !matchedLine && ( CharacterHitTest::TAP == mode ) )
+ {
+ // Return the first or the last character if the touch point doesn't hit a line.
+ return ( visualY < 0.f ) ? 0 : logicalModel->mText.Count();
+ }
// Convert from text's coords to line's coords.
const LineRun& line = *( visualModel->mLines.Begin() + lineIndex );
// The character's direction buffer.
const CharacterDirection* const directionsBuffer = bidiLineFetched ? logicalModel->mCharacterDirections.Begin() : NULL;
- // Whether there is a hit on a glyph.
- bool matched = false;
+ // Whether the touch point if before the first glyph.
+ bool isBeforeFirstGlyph = false;
// Traverses glyphs in visual order. To do that use the visual to logical conversion table.
CharacterIndex visualIndex = startCharacter;
- Length numberOfVisualCharacters = 0u;
+ Length numberOfVisualCharacters = 0;
for( ; visualIndex < endCharacter; ++visualIndex )
{
// The character in logical order.
const Length numberOfGlyphs = *( glyphsPerCharacterBuffer + characterLogicalOrderIndex );
++numberOfVisualCharacters;
- if( 0u != numberOfGlyphs )
+ if( 0 != numberOfGlyphs )
{
// Get the first character/glyph of the group of glyphs.
const CharacterIndex firstVisualCharacterIndex = 1u + visualIndex - numberOfVisualCharacters;
// Get the position of the first glyph.
const Vector2& position = *( positionsBuffer + firstLogicalGlyphIndex );
+ if( startCharacter == visualIndex )
+ {
+ const float glyphPosition = -glyphMetrics.xBearing + position.x;
+
+ if( visualX < glyphPosition )
+ {
+ isBeforeFirstGlyph = true;
+ break;
+ }
+ }
+
// Whether the glyph can be split, like Latin ligatures fi, ff or Arabic (ل + ا).
Length numberOfCharacters = *( charactersPerGlyphBuffer + firstLogicalGlyphIndex );
if( direction != LTR )
// number of glyphs in the table is found first.
// Jump the number of characters to the next glyph is needed.
- if( 0u == numberOfCharacters )
+ if( 0 == numberOfCharacters )
{
// TODO: This is a workaround to fix an issue with complex characters in the arabic
// script like i.e. رّ or الأَبْجَدِيَّة العَرَبِيَّة
// Find the number of characters.
for( GlyphIndex index = firstLogicalGlyphIndex + 1u;
- ( 0u == numberOfCharacters ) && ( index < totalNumberOfGlyphs ) ;
+ ( 0 == numberOfCharacters ) && ( index < totalNumberOfGlyphs );
++index )
{
numberOfCharacters = *( charactersPerGlyphBuffer + index );
const Length numberOfBlocks = isInterglyphIndex ? numberOfCharacters : 1u;
const float glyphAdvance = glyphMetrics.advance / static_cast<float>( numberOfBlocks );
- CharacterIndex index = 0u;
+ CharacterIndex index = 0;
for( ; index < numberOfBlocks; ++index )
{
// Find the mid-point of the area containing the glyph
if( visualX < glyphCenter )
{
- matched = true;
+ matchedCharacter = true;
break;
}
}
- if( matched )
+ if( matchedCharacter )
{
// If the glyph is shaped from more than one character, it matches the character of the glyph.
visualIndex = firstVisualCharacterIndex + index;
break;
}
- numberOfVisualCharacters = 0u;
+ numberOfVisualCharacters = 0;
}
- }
+ } // for characters in visual order.
// The number of characters of the whole text.
const Length totalNumberOfCharacters = logicalModel->mText.Count();
// Return the logical position of the cursor in characters.
- if( !matched )
+ if( !matchedCharacter )
{
- // If no character is matched, then the last character (in visual order) of the line is used.
- visualIndex = endCharacter;
+ if( isBeforeFirstGlyph )
+ {
+ // If no character is matched, then the first character (in visual order) of the line is used.
+ visualIndex = startCharacter;
+ }
+ else
+ {
+ // If no character is matched, then the last character (in visual order) of the line is used.
+ visualIndex = endCharacter;
+ }
}
// Get the paragraph direction.
isCurrentRightToLeft = *( directionsBuffer + index );
}
- Length numberOfGlyphAdvance = ( isFirstPositionOfLine ? 0u : 1u ) + characterIndex - firstIndex;
+ Length numberOfGlyphAdvance = ( isFirstPositionOfLine ? 0 : 1u ) + characterIndex - firstIndex;
if( isCurrentRightToLeft )
{
numberOfGlyphAdvance = primaryNumberOfCharacters - numberOfGlyphAdvance;
float visualX,
float visualY,
CharacterIndex& startIndex,
- CharacterIndex& endIndex )
+ CharacterIndex& endIndex,
+ CharacterIndex& noTextHitIndex )
{
-
/*
Hit character Select
|-------------------------------------------------------|------------------------------------------|
| On a new paragraph character | The word or group of white spaces before |
|-------------------------------------------------------|------------------------------------------|
*/
+ const Length totalNumberOfCharacters = logicalModel->mText.Count();
+ startIndex = 0;
+ endIndex = 0;
+ noTextHitIndex = 0;
+ if( 0 == totalNumberOfCharacters )
+ {
+ // Nothing to do if the model is empty.
+ return false;
+ }
+
+ bool matchedCharacter = false;
CharacterIndex hitCharacter = Text::GetClosestCursorIndex( visualModel,
logicalModel,
metrics,
visualX,
- visualY );
-
- const Length totalNumberOfCharacters = logicalModel->mText.Count();
-
- DALI_ASSERT_DEBUG( ( hitCharacter <= totalNumberOfCharacters ) && "GetClosestCursorIndex returned out of bounds index" );
+ visualY,
+ CharacterHitTest::TAP,
+ matchedCharacter );
- if( 0u == totalNumberOfCharacters )
+ if( !matchedCharacter )
{
- // Nothing to do if the model is empty.
- return false;
+ noTextHitIndex = hitCharacter;
}
+ DALI_ASSERT_DEBUG( ( hitCharacter <= totalNumberOfCharacters ) && "GetClosestCursorIndex returned out of bounds index" );
+
if( hitCharacter >= totalNumberOfCharacters )
{
// Closest hit character is the last character.
{
// Find the first character before the hit one which is not a new paragraph character.
- if( hitCharacter > 0u )
+ if( hitCharacter > 0 )
{
endIndex = hitCharacter - 1u;
for( ; endIndex > 0; --endIndex )
{
// Select the word before or after the white space
- if( 0u == hitCharacter )
+ if( 0 == hitCharacter )
{
data.isWhiteSpace = false;
FindEndOfWord( data );
endIndex = data.foundIndex;
}
- else if( hitCharacter > 0u )
+ else if( hitCharacter > 0 )
{
// Find the start of the word.
data.hitCharacter = hitCharacter - 1u;
}
}
- return true;
+ return matchedCharacter;
}
} // namespace Text
namespace Text
{
+struct CharacterHitTest
+{
+ /**
+ * @brief Enumeration of the types of hit test.
+ */
+ enum Mode
+ {
+ TAP, ///< Retrieves the first or last character of the line if the touch point is outside of the boundaries of the text.
+ SCROLL ///< Retrieves the character above or below to the touch point if it's outside of the boundaries of the text.
+ };
+};
+
struct CursorInfo
{
CursorInfo()
*
* @param[in] visualModel The visual model.
* @param[in] visualY The touch point 'y' in text's coords.
+ * @param[out] matchedLine Whether the touch point actually hits a line.
*
* @return A line index.
*/
LineIndex GetClosestLine( VisualModelPtr visualModel,
- float visualY );
+ float visualY,
+ bool& matchedLine );
/**
* @brief Calculates the vertical line's offset for a given line.
/**
* @brief Retrieves the cursor's logical position for a given touch point x,y
*
+ * There are two types of hit test: CharacterHitTest::TAP retrieves the first or
+ * last character of a line if the touch point is outside the boundaries of the
+ * text, CharacterHitTest::SCROLL retrieves the character above or below to the
+ * touch point if it's outside the boundaries of the text.
+ *
* @param[in] visualModel The visual model.
* @param[in] logicalModel The logical model.
* @param[in] metrics A wrapper around FontClient used to get metrics.
* @param[in] visualX The touch point 'x' in text's coords.
* @param[in] visualY The touch point 'y' in text's coords.
+ * @param[in] mode The type of hit test.
+ * @param[out] matchedCharacter Whether the touch point actually hits a character.
*
* @return The logical cursor position (in characters). 0 is just before the first character, a value equal to the number of characters is just after the last character.
*/
LogicalModelPtr logicalModel,
MetricsPtr metrics,
float visualX,
- float visualY );
-
+ float visualY,
+ CharacterHitTest::Mode mode,
+ bool& matchedCharacter );
/**
* @brief Calculates the cursor's position for a given character index in the logical order.
* @param[in] visualY The touch point 'y' in text's coords.
* @param[out] startIndex Index to the first character of the selected word.
* @param[out] endIndex Index to the last character of the selected word.
+ * @param[out] noTextHitIndex Index to the nearest character when there is no hit.
*
- * @return @e true if the indices are found.
+ * @return @e true if the touch point hits a character.
*/
bool FindSelectionIndices( VisualModelPtr visualModel,
LogicalModelPtr logicalModel,
float visualX,
float visualY,
CharacterIndex& startIndex,
- CharacterIndex& endIndex );
+ CharacterIndex& endIndex,
+ CharacterIndex& noTextHitIndex );
} // namespace Text
mPreEditStartPosition( 0u ),
mPreEditLength( 0u ),
mCursorHookPositionX( 0.f ),
+ mDoubleTapAction( Controller::NoTextTap::NO_ACTION ),
+ mLongPressAction( Controller::NoTextTap::SHOW_SELECTION_POPUP ),
mIsShowingPlaceholderText( false ),
mPreEditFlag( false ),
mDecoratorUpdated( false ),
mUpdateLeftSelectionPosition( false ),
mUpdateRightSelectionPosition( false ),
mIsLeftHandleSelected( false ),
+ mIsRightHandleSelected( false ),
mUpdateHighlightBox( false ),
mScrollAfterUpdatePosition( false ),
mScrollAfterDelete( false ),
if( mEventData->mScrollAfterUpdatePosition && ( mEventData->mIsLeftHandleSelected ? mEventData->mUpdateLeftSelectionPosition : mEventData->mUpdateRightSelectionPosition ) )
{
- CursorInfo& info = mEventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo;
+ if( mEventData->mIsLeftHandleSelected && mEventData->mIsRightHandleSelected )
+ {
+ CursorInfo& infoLeft = leftHandleInfo;
+
+ const Vector2 currentCursorPositionLeft( infoLeft.primaryPosition.x, infoLeft.lineOffset );
+ ScrollToMakePositionVisible( currentCursorPositionLeft, infoLeft.lineHeight );
+
+ CursorInfo& infoRight = rightHandleInfo;
+
+ const Vector2 currentCursorPositionRight( infoRight.primaryPosition.x, infoRight.lineOffset );
+ ScrollToMakePositionVisible( currentCursorPositionRight, infoRight.lineHeight );
+ }
+ else
+ {
+ CursorInfo& info = mEventData->mIsLeftHandleSelected ? leftHandleInfo : rightHandleInfo;
- const Vector2 currentCursorPosition( info.primaryPosition.x, info.lineOffset );
- ScrollToMakePositionVisible( currentCursorPosition, info.lineHeight );
+ const Vector2 currentCursorPosition( info.primaryPosition.x, info.lineOffset );
+ ScrollToMakePositionVisible( currentCursorPosition, info.lineHeight );
+ }
}
}
mEventData->mUpdateLeftSelectionPosition = false;
mEventData->mUpdateRightSelectionPosition = false;
mEventData->mUpdateHighlightBox = false;
+ mEventData->mIsLeftHandleSelected = false;
+ mEventData->mIsRightHandleSelected = false;
}
mEventData->mScrollAfterUpdatePosition = false;
const float hitPointY = cursorInfo.lineOffset - 0.5f * ( line.ascender - line.descender );
// Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
+ bool matchedCharacter = false;
mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mVisualModel,
mLogicalModel,
mMetrics,
mEventData->mCursorHookPositionX,
- hitPointY );
+ hitPointY,
+ CharacterHitTest::TAP,
+ matchedCharacter );
}
}
- else if( Dali::DALI_KEY_CURSOR_DOWN == keyCode )
+ else if( Dali::DALI_KEY_CURSOR_DOWN == keyCode )
{
// Get first the line index of the current cursor position index.
CharacterIndex characterIndex = 0u;
const float hitPointY = cursorInfo.lineOffset + cursorInfo.lineHeight + 0.5f * ( line.ascender - line.descender );
// Use the cursor hook position 'x' and the next hit 'y' position to calculate the new cursor index.
+ bool matchedCharacter = false;
mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mVisualModel,
mLogicalModel,
mMetrics,
mEventData->mCursorHookPositionX,
- hitPointY );
+ hitPointY,
+ CharacterHitTest::TAP,
+ matchedCharacter );
}
}
// Keep the tap 'x' position. Used to move the cursor.
mEventData->mCursorHookPositionX = xPosition;
+ // Whether to touch point hits on a glyph.
+ bool matchedCharacter = false;
mEventData->mPrimaryCursorPosition = Text::GetClosestCursorIndex( mVisualModel,
mLogicalModel,
mMetrics,
xPosition,
- yPosition );
+ yPosition,
+ CharacterHitTest::TAP,
+ matchedCharacter );
// When the cursor position is changing, delay cursor blinking
mEventData->mDecorator->DelayCursorBlink();
mEventData->mImfManager.NotifyCursorPosition();
}
}
+ else if( 2u == tapCount )
+ {
+ if( mEventData->mSelectionEnabled )
+ {
+ // Convert from control's coords to text's coords.
+ const float xPosition = event.p2.mFloat - mScrollPosition.x;
+ const float yPosition = event.p3.mFloat - mScrollPosition.y;
+
+ // Calculates the logical position from the x,y coords.
+ RepositionSelectionHandles( xPosition,
+ yPosition,
+ mEventData->mDoubleTapAction );
+ }
+ }
}
}
{
DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::OnLongPressEvent\n" );
- if( EventData::EDITING == mEventData->mState )
+ if( !IsShowingRealText() && ( EventData::EDITING == mEventData->mState ) )
{
- ChangeState ( EventData::EDITING_WITH_POPUP );
+ ChangeState( EventData::EDITING_WITH_POPUP );
mEventData->mDecoratorUpdated = true;
mEventData->mUpdateInputStyle = true;
}
+ else
+ {
+ if( mEventData->mSelectionEnabled )
+ {
+ // Convert from control's coords to text's coords.
+ const float xPosition = event.p2.mFloat - mScrollPosition.x;
+ const float yPosition = event.p3.mFloat - mScrollPosition.y;
+
+ // Calculates the logical position from the x,y coords.
+ RepositionSelectionHandles( xPosition,
+ yPosition,
+ mEventData->mLongPressAction );
+ }
+ }
}
void Controller::Impl::OnHandleEvent( const Event& event )
const float yPosition = event.p3.mFloat - mScrollPosition.y;
// Need to calculate the handle's new position.
+ bool matchedCharacter = false;
const CharacterIndex handleNewPosition = Text::GetClosestCursorIndex( mVisualModel,
mLogicalModel,
mMetrics,
xPosition,
- yPosition );
+ yPosition,
+ CharacterHitTest::SCROLL,
+ matchedCharacter );
if( Event::GRAB_HANDLE_EVENT == event.type )
{
// Will define the order to scroll the text to match the handle position.
mEventData->mIsLeftHandleSelected = true;
+ mEventData->mIsRightHandleSelected = false;
}
else if( Event::RIGHT_SELECTION_HANDLE_EVENT == event.type )
{
// Will define the order to scroll the text to match the handle position.
mEventData->mIsLeftHandleSelected = false;
+ mEventData->mIsRightHandleSelected = true;
}
} // end ( HANDLE_PRESSED == state )
else if( ( HANDLE_RELEASED == state ) ||
const float xPosition = event.p2.mFloat - mScrollPosition.x;
const float yPosition = event.p3.mFloat - mScrollPosition.y;
+ bool matchedCharacter = false;
handlePosition = Text::GetClosestCursorIndex( mVisualModel,
mLogicalModel,
mMetrics,
xPosition,
- yPosition );
+ yPosition,
+ CharacterHitTest::SCROLL,
+ matchedCharacter );
}
if( Event::GRAB_HANDLE_EVENT == event.type )
// Get the new handle position.
// The grab handle's position is in decorator's coords. Need to transforms to text's coords.
+ bool matchedCharacter = false;
const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mVisualModel,
mLogicalModel,
mMetrics,
position.x - mScrollPosition.x,
- position.y - mScrollPosition.y );
+ position.y - mScrollPosition.y,
+ CharacterHitTest::SCROLL,
+ matchedCharacter );
if( mEventData->mPrimaryCursorPosition != handlePosition )
{
// Get the new handle position.
// The selection handle's position is in decorator's coords. Need to transform to text's coords.
+ bool matchedCharacter = false;
const CharacterIndex handlePosition = Text::GetClosestCursorIndex( mVisualModel,
mLogicalModel,
mMetrics,
position.x - mScrollPosition.x,
- position.y - mScrollPosition.y );
+ position.y - mScrollPosition.y,
+ CharacterHitTest::SCROLL,
+ matchedCharacter );
if( leftSelectionHandleEvent )
{
// Calculates the logical position from the x,y coords.
RepositionSelectionHandles( xPosition,
- yPosition );
+ yPosition,
+ Controller::NoTextTap::HIGHLIGHT );
}
}
mEventData->mDecoratorUpdated = true;
}
-void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY )
+void Controller::Impl::RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action )
{
if( NULL == mEventData )
{
return;
}
- if( IsShowingPlaceholderText() )
- {
- // Nothing to do if there is the place-holder text.
- return;
- }
-
const Length numberOfGlyphs = mVisualModel->mGlyphs.Count();
const Length numberOfLines = mVisualModel->mLines.Count();
if( ( 0 == numberOfGlyphs ) ||
// Find which word was selected
CharacterIndex selectionStart( 0 );
CharacterIndex selectionEnd( 0 );
- const bool indicesFound = FindSelectionIndices( mVisualModel,
+ CharacterIndex noTextHitIndex( 0 );
+ const bool characterHit = FindSelectionIndices( mVisualModel,
mLogicalModel,
mMetrics,
visualX,
visualY,
selectionStart,
- selectionEnd );
+ selectionEnd,
+ noTextHitIndex );
DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%p selectionStart %d selectionEnd %d\n", this, selectionStart, selectionEnd );
- if( indicesFound )
+ if( characterHit || ( Controller::NoTextTap::HIGHLIGHT == action ) )
{
ChangeState( EventData::SELECTING );
mEventData->mScrollAfterUpdatePosition = ( mEventData->mLeftSelectionPosition != mEventData->mRightSelectionPosition );
}
- else
+ else if( Controller::NoTextTap::SHOW_SELECTION_POPUP == action )
{
// Nothing to select. i.e. a white space, out of bounds
- ChangeState( EventData::EDITING );
+ ChangeState( EventData::EDITING_WITH_POPUP );
+
+ mEventData->mPrimaryCursorPosition = noTextHitIndex;
- mEventData->mPrimaryCursorPosition = selectionEnd;
+ mEventData->mUpdateCursorPosition = true;
+ mEventData->mUpdateGrabHandlePosition = true;
+ mEventData->mScrollAfterUpdatePosition = true;
+ mEventData->mUpdateInputStyle = true;
+ }
+ else if( Controller::NoTextTap::NO_ACTION == action )
+ {
+ // Nothing to select. i.e. a white space, out of bounds
+ mEventData->mPrimaryCursorPosition = noTextHitIndex;
mEventData->mUpdateCursorPosition = true;
mEventData->mUpdateGrabHandlePosition = true;
float mCursorHookPositionX; ///< Used to move the cursor with the keys or when scrolling the text vertically with the handles.
+ Controller::NoTextTap::Action mDoubleTapAction; ///< Action to be done when there is a double tap on top of 'no text'
+ Controller::NoTextTap::Action mLongPressAction; ///< Action to be done when there is a long press on top of 'no text'
+
bool mIsShowingPlaceholderText : 1; ///< True if the place-holder text is being displayed.
bool mPreEditFlag : 1; ///< True if the model contains text in pre-edit state.
bool mDecoratorUpdated : 1; ///< True if the decorator was updated during event processing.
bool mUpdateLeftSelectionPosition : 1; ///< True if the visual position of the left selection handle must be recalculated.
bool mUpdateRightSelectionPosition : 1; ///< True if the visual position of the right selection handle must be recalculated.
bool mIsLeftHandleSelected : 1; ///< Whether is the left handle the one which is selected.
+ bool mIsRightHandleSelected : 1; ///< Whether is the right handle the one which is selected.
bool mUpdateHighlightBox : 1; ///< True if the text selection high light box must be updated.
bool mScrollAfterUpdatePosition : 1; ///< Whether to scroll after the cursor position is updated.
bool mScrollAfterDelete : 1; ///< Whether to scroll after delete characters.
void RequestGetTextFromClipboard();
void RepositionSelectionHandles();
- void RepositionSelectionHandles( float visualX, float visualY );
+ void RepositionSelectionHandles( float visualX, float visualY, Controller::NoTextTap::Action action );
void SetPopupButtons();
return GetDefaultOutlineProperties();
}
+void Controller::SetNoTextDoubleTapAction( NoTextTap::Action action )
+{
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mDoubleTapAction = action;
+ }
+}
+
+Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
+{
+ NoTextTap::Action action = NoTextTap::NO_ACTION;
+
+ if( NULL != mImpl->mEventData )
+ {
+ action = mImpl->mEventData->mDoubleTapAction;
+ }
+
+ return action;
+}
+
+void Controller::SetNoTextLongPressAction( NoTextTap::Action action )
+{
+ if( NULL != mImpl->mEventData )
+ {
+ mImpl->mEventData->mLongPressAction = action;
+ }
+}
+
+Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
+{
+ NoTextTap::Action action = NoTextTap::NO_ACTION;
+
+ if( NULL != mImpl->mEventData )
+ {
+ return mImpl->mEventData->mLongPressAction;
+ }
+
+ return action;
+}
+
// public : Queries & retrieves.
LayoutEngine& Controller::GetLayoutEngine()
if( mImpl->mEventData->mSelectionEnabled &&
mImpl->IsShowingRealText() )
{
- SelectEvent( x, y, false );
+ relayoutNeeded = true;
+ mImpl->mEventData->mIsLeftHandleSelected = true;
+ mImpl->mEventData->mIsRightHandleSelected = true;
}
}
+
// Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated
if( relayoutNeeded )
{
if( ( state == Gesture::Started ) &&
( NULL != mImpl->mEventData ) )
{
- if( !mImpl->IsShowingRealText() )
+ // The 1st long-press on inactive text-field is treated as tap
+ if( EventData::INACTIVE == mImpl->mEventData->mState )
+ {
+ mImpl->ChangeState( EventData::EDITING );
+
+ Event event( Event::TAP_EVENT );
+ event.p1.mUint = 1;
+ event.p2.mFloat = x;
+ event.p3.mFloat = y;
+ mImpl->mEventData->mEventQueue.push_back( event );
+
+ mImpl->RequestRelayout();
+ }
+ else if( !mImpl->IsShowingRealText() )
{
Event event( Event::LONG_PRESS_EVENT );
event.p1.mInt = state;
+ event.p2.mFloat = x;
+ event.p3.mFloat = y;
mImpl->mEventData->mEventQueue.push_back( event );
mImpl->RequestRelayout();
}
- else
+ else if( !mImpl->IsClipboardVisible() )
{
- // The 1st long-press on inactive text-field is treated as tap
- if( EventData::INACTIVE == mImpl->mEventData->mState )
- {
- mImpl->ChangeState( EventData::EDITING );
+ // Reset the imf manager to commit the pre-edit before selecting the text.
+ mImpl->ResetImfManager();
- Event event( Event::TAP_EVENT );
- event.p1.mUint = 1;
- event.p2.mFloat = x;
- event.p3.mFloat = y;
- mImpl->mEventData->mEventQueue.push_back( event );
-
- mImpl->RequestRelayout();
- }
- else
- {
- // Reset the imf manger to commit the pre-edit before selecting the text.
- mImpl->ResetImfManager();
+ Event event( Event::LONG_PRESS_EVENT );
+ event.p1.mInt = state;
+ event.p2.mFloat = x;
+ event.p3.mFloat = y;
+ mImpl->mEventData->mEventQueue.push_back( event );
+ mImpl->RequestRelayout();
- SelectEvent( x, y, false );
- }
+ mImpl->mEventData->mIsLeftHandleSelected = true;
+ mImpl->mEventData->mIsRightHandleSelected = true;
}
}
}
mImpl->mEventData->mEventQueue.push_back( event );
}
+ mImpl->mEventData->mIsLeftHandleSelected = true;
+ mImpl->mEventData->mIsRightHandleSelected = true;
mImpl->RequestRelayout();
}
}
PLACEHOLDER_TYPE_INACTIVE,
};
+ struct NoTextTap
+ {
+ enum Action
+ {
+ NO_ACTION, ///< Does no action if there is a tap on top of an area with no text.
+ HIGHLIGHT, ///< Highlights the nearest text (at the beginning or end of the text) and shows the text's selection popup.
+ SHOW_SELECTION_POPUP ///< Shows the text's selection popup.
+ };
+ };
+
public: // Constructor.
/**
*/
LayoutEngine::VerticalAlignment GetVerticalAlignment() const;
+ /**
+ * @brief Sets the action when there is a double tap event on top of a text area with no text.
+ *
+ * @param[in] action The action to do.
+ */
+ void SetNoTextDoubleTapAction( NoTextTap::Action action );
+
+ /**
+ * @brief Retrieves the action when there is a double tap event on top of a text area with no text.
+ *
+ * @return The action to do.
+ */
+ NoTextTap::Action GetNoTextDoubleTapAction() const;
+
+ /**
+ * @briefSets the action when there is a long press event on top of a text area with no text.
+ *
+ * @param[in] action The action to do.
+ */
+ void SetNoTextLongPressAction( NoTextTap::Action action );
+
+ /**
+ * @brief Retrieves the action when there is a long press event on top of a text area with no text.
+ *
+ * @return The action to do.
+ */
+ NoTextTap::Action GetNoTextLongPressAction() const;
+
public: // Update.
/**