X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fcontrols%2Ftext-input%2Ftext-input-impl.cpp;h=84f8fc2e6150add3a4517caaac37b28788e7c07f;hp=69daef19bd8fa3d5b3961e120a3a9c2773153b92;hb=ee3bdc95f623f41feb37be10f21bef1d9da1e805;hpb=e2e777d22421d671e2bc7bf81148f7b89a44e807 diff --git a/dali-toolkit/internal/controls/text-input/text-input-impl.cpp b/dali-toolkit/internal/controls/text-input/text-input-impl.cpp index 69daef1..84f8fc2 100644 --- a/dali-toolkit/internal/controls/text-input/text-input-impl.cpp +++ b/dali-toolkit/internal/controls/text-input/text-input-impl.cpp @@ -1,36 +1,43 @@ -// -// Copyright (c) 2014 Samsung Electronics Co., Ltd. -// -// Licensed under the Flora License, Version 1.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://floralicense.org/license/ -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an AS IS BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#include +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +// CLASS HEADER #include -#include -#include -#include - -#include +// EXTERNAL INCLUDES #include #include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#define GET_LOCALE_TEXT(string) dgettext("sys_string", string) +// INTERNAL INCLUDES +#include +#include +#include +#include -using namespace std; using namespace Dali; // Local Data @@ -46,44 +53,28 @@ const std::size_t DEFAULT_NUMBER_OF_LINES_LIMIT( std::numeric_limitsInitialize(); - return handle; } TextInput::TextInput() -:ControlImpl( true ), +:Control( ControlBehaviour( REQUIRES_TOUCH_EVENTS | REQUIRES_STYLE_CHANGE_SIGNALS ) ), mState( StateEdit ), mStyledText(), mInputStyle(), @@ -295,6 +301,7 @@ TextInput::TextInput() mTouchStartTime( 0 ), mTextLayoutInfo(), mCurrentCopySelecton(), + mPopupPanel(), mScrollTimer(), mScrollDisplacement(), mCurrentHandlePosition(), @@ -304,6 +311,8 @@ TextInput::TextInput() mSelectionHandleFlipMargin( 0.0f, 0.0f, 0.0f, 0.0f ), mBoundingRectangleWorldCoordinates( 0.0f, 0.0f, 0.0f, 0.0f ), mClipboard(), + mMaterialColor( LIGHTBLUE ), + mPopupOffsetFromText ( Vector4( 0.0f, TOP_HANDLE_TOP_OFFSET, 0.0f, BOTTOM_HANDLE_BOTTOM_OFFSET ) ), mOverrideAutomaticAlignment( false ), mCursorRTLEnabled( false ), mClosestCursorPositionEOL ( false ), @@ -362,16 +371,20 @@ std::string TextInput::GetMarkupText() const return markupString; } +void TextInput::ShowPlaceholderText( const MarkupProcessor::StyledTextArray& stylePlaceHolderText ) +{ + mDisplayedTextView.SetText( stylePlaceHolderText ); + mPlaceHolderSet = true; + mDisplayedTextView.SetScrollPosition( Vector2( 0.0f,0.0f ) ); +} + void TextInput::SetPlaceholderText( const std::string& placeHolderText ) { // Get the placeholder styled text array from the markup string. MarkupProcessor::GetStyledTextArray( placeHolderText, mStyledPlaceHolderText, IsMarkupProcessingEnabled() ); - if( mStyledText.empty() ) { - // Set the placeholder text only if the styled text is empty. - mDisplayedTextView.SetText( mStyledPlaceHolderText ); - mPlaceHolderSet = true; + ShowPlaceholderText( mStyledPlaceHolderText ); } } @@ -411,9 +424,7 @@ void TextInput::SetText(const std::string& initialText) if( mStyledText.empty() ) { - // If the initial text is empty, set the placeholder text. - mDisplayedTextView.SetText( mStyledPlaceHolderText ); - mPlaceHolderSet = true; + ShowPlaceholderText( mStyledPlaceHolderText ); } else { @@ -443,6 +454,8 @@ void TextInput::SetText(const std::string& initialText) RemoveHighlight(); DrawCursor(); + + EmitTextModified(); } void TextInput::SetText( const MarkupProcessor::StyledTextArray& styleText ) @@ -488,6 +501,8 @@ void TextInput::SetText( const MarkupProcessor::StyledTextArray& styleText ) Toolkit::Alignment::VerticalTop ) ); mDisplayedTextView.SetLineJustification( leftToRight ? Toolkit::TextView::Left : Toolkit::TextView::Right); } + + EmitTextModified(); } void TextInput::SetMaxCharacterLength(std::size_t maxChars) @@ -515,34 +530,57 @@ std::size_t TextInput::GetNumberOfCharacters() const return mStyledText.size(); } -Toolkit::TextInput::InputSignalV2& TextInput::InputStartedSignal() +// Styling +void TextInput::SetMaterialDiffuseColor( const Vector4& color ) +{ + mMaterialColor = color; + if ( mCustomMaterial ) + { + mCustomMaterial.SetDiffuseColor( mMaterialColor ); + mMeshData.SetMaterial( mCustomMaterial ); + } +} + +const Vector4& TextInput::GetMaterialDiffuseColor() const +{ + return mMaterialColor; +} + +// Signals + +Toolkit::TextInput::InputSignalType& TextInput::InputStartedSignal() +{ + return mInputStartedSignal; +} + +Toolkit::TextInput::InputSignalType& TextInput::InputFinishedSignal() { - return mInputStartedSignalV2; + return mInputFinishedSignal; } -Toolkit::TextInput::InputSignalV2& TextInput::InputFinishedSignal() +Toolkit::TextInput::InputSignalType& TextInput::CutAndPasteToolBarDisplayedSignal() { - return mInputFinishedSignalV2; + return mCutAndPasteToolBarDisplayed; } -Toolkit::TextInput::InputSignalV2& TextInput::CutAndPasteToolBarDisplayedSignal() +Toolkit::TextInput::StyleChangedSignalType& TextInput::StyleChangedSignal() { - return mCutAndPasteToolBarDisplayedV2; + return mStyleChangedSignal; } -Toolkit::TextInput::StyleChangedSignalV2& TextInput::StyleChangedSignal() +Toolkit::TextInput::TextModifiedSignalType& TextInput::TextModifiedSignal() { - return mStyleChangedSignalV2; + return mTextModifiedSignal; } -Toolkit::TextInput::MaxInputCharactersReachedSignalV2& TextInput::MaxInputCharactersReachedSignal() +Toolkit::TextInput::MaxInputCharactersReachedSignalType& TextInput::MaxInputCharactersReachedSignal() { - return mMaxInputCharactersReachedSignalV2; + return mMaxInputCharactersReachedSignal; } -Toolkit::TextInput::InputTextExceedBoundariesSignalV2& TextInput::InputTextExceedBoundariesSignal() +Toolkit::TextInput::InputTextExceedBoundariesSignalType& TextInput::InputTextExceedBoundariesSignal() { - return mInputTextExceedBoundariesSignalV2; + return mInputTextExceedBoundariesSignal; } bool TextInput::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ) @@ -550,25 +588,29 @@ bool TextInput::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* Dali::BaseHandle handle( object ); bool connected( true ); - Toolkit::TextInput textInput = Toolkit::TextInput::DownCast(handle); + Toolkit::TextInput textInput = Toolkit::TextInput::DownCast( handle ); - if( Toolkit::TextInput::SIGNAL_START_INPUT == signalName ) + if( 0 == strcmp( signalName.c_str(), SIGNAL_START_INPUT ) ) { textInput.InputStartedSignal().Connect( tracker, functor ); } - else if( Toolkit::TextInput::SIGNAL_END_INPUT == signalName ) + else if( 0 == strcmp( signalName.c_str(), SIGNAL_END_INPUT ) ) { textInput.InputFinishedSignal().Connect( tracker, functor ); } - else if( Toolkit::TextInput::SIGNAL_STYLE_CHANGED == signalName ) + else if( 0 == strcmp( signalName.c_str(), SIGNAL_STYLE_CHANGED ) ) { textInput.StyleChangedSignal().Connect( tracker, functor ); } - else if( Toolkit::TextInput::SIGNAL_MAX_INPUT_CHARACTERS_REACHED == signalName ) + else if( 0 == strcmp( signalName.c_str(), SIGNAL_MAX_INPUT_CHARACTERS_REACHED ) ) { textInput.MaxInputCharactersReachedSignal().Connect( tracker, functor ); } - else if( Toolkit::TextInput::SIGNAL_TEXT_EXCEED_BOUNDARIES == signalName ) + else if( 0 == strcmp( signalName.c_str(), SIGNAL_TOOLBAR_DISPLAYED ) ) + { + textInput.CutAndPasteToolBarDisplayedSignal().Connect( tracker, functor ); + } + else if( 0 == strcmp( signalName.c_str(), SIGNAL_TEXT_EXCEED_BOUNDARIES ) ) { textInput.InputTextExceedBoundariesSignal().Connect( tracker, functor ); } @@ -846,7 +888,6 @@ TextStyle TextInput::GetStyleAtCursor() const if ( !mStyledText.empty() && ( mCursorPosition > 0 ) ) { DALI_ASSERT_DEBUG( ( 0 <= mCursorPosition-1 ) && ( mCursorPosition-1 < mStyledText.size() ) ); - style = mStyledText.at( mCursorPosition-1 ).mStyle; } else // No text. @@ -1003,7 +1044,7 @@ void TextInput::OnKeyInputFocusGained() StartCursorBlinkTimer(); Toolkit::TextInput handle( GetOwner() ); - mInputStartedSignalV2.Emit( handle ); + mInputStartedSignal.Emit( handle ); ImfManager imfManager = ImfManager::Get(); @@ -1015,7 +1056,7 @@ void TextInput::OnKeyInputFocusGained() imfManager.Activate(); // When window gain lost focus, the imf manager is deactivated. Thus when window gain focus again, the imf manager must be activated. - imfManager.SetRestoreAferFocusLost( true ); + imfManager.SetRestoreAfterFocusLost( true ); imfManager.SetCursorPosition( mCursorPosition ); imfManager.NotifyCursorPosition(); @@ -1024,13 +1065,10 @@ void TextInput::OnKeyInputFocusGained() mClipboard = Clipboard::Get(); // Store handle to clipboard // Now in edit mode we can accept string to paste from clipboard - if( Adaptor::IsAvailable() ) + ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() ); + if ( notifier ) { - ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() ); - if ( notifier ) - { - notifier.ContentSelectedSignal().Connect( this, &TextInput::OnClipboardTextSelected ); - } + notifier.ContentSelectedSignal().Connect( this, &TextInput::OnClipboardTextSelected ); } } @@ -1045,13 +1083,14 @@ void TextInput::OnKeyInputFocusLost() RemovePreEditStyle(); const std::size_t numberOfCharactersDeleted = DeletePreEdit(); InsertAt( mPreEditString, mPreEditStartPosition, numberOfCharactersDeleted ); + EmitTextModified(); } ImfManager imfManager = ImfManager::Get(); if ( imfManager ) { // The text editing is finished. Therefore the imf manager don't have restore activation. - imfManager.SetRestoreAferFocusLost( false ); + imfManager.SetRestoreAfterFocusLost( false ); // Notify that the text editing finish. imfManager.Deactivate(); @@ -1062,7 +1101,7 @@ void TextInput::OnKeyInputFocusLost() VirtualKeyboard::LanguageChangedSignal().Disconnect( this, &TextInput::SetTextDirection ); Toolkit::TextInput handle( GetOwner() ); - mInputFinishedSignalV2.Emit( handle ); + mInputFinishedSignal.Emit( handle ); mEditModeActive = false; mPreEditFlag = false; RemoveHighlight(); @@ -1073,19 +1112,16 @@ void TextInput::OnKeyInputFocusLost() mClipboard.Reset(); // No longer in edit mode so do not want to receive string from clipboard - if( Adaptor::IsAvailable() ) + ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() ); + if ( notifier ) { - ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() ); - if ( notifier ) - { - notifier.ContentSelectedSignal().Disconnect( this, &TextInput::OnClipboardTextSelected ); - } - Clipboard clipboard = Clipboard::Get(); + notifier.ContentSelectedSignal().Disconnect( this, &TextInput::OnClipboardTextSelected ); + } - if ( clipboard ) - { - clipboard.HideClipboard(); - } + Clipboard clipboard = Clipboard::Get(); + if ( clipboard ) + { + clipboard.HideClipboard(); } } @@ -1103,6 +1139,7 @@ void TextInput::CreateActiveLayer() { Actor self = Self(); mActiveLayer = Layer::New(); + mActiveLayer.SetName ( "ActiveLayerActor" ); mActiveLayer.SetAnchorPoint( AnchorPoint::CENTER); mActiveLayer.SetParentOrigin( ParentOrigin::CENTER); @@ -1120,9 +1157,8 @@ void TextInput::OnInitialize() // Create 2 cursors (standard LTR and RTL cursor for when text can be added at // different positions depending on language) - Image mCursorImage = Image::New( DEFAULT_CURSOR ); - mCursor = CreateCursor( mCursorImage, DEFAULT_CURSOR_IMAGE_9_BORDER ); - mCursorRTL = CreateCursor( mCursorImage, DEFAULT_CURSOR_IMAGE_9_BORDER ); + mCursor = CreateCursor(DEFAULT_CURSOR_COLOR); + mCursorRTL = CreateCursor(DEFAULT_CURSOR_COLOR); Actor self = Self(); self.Add( mCursor ); @@ -1144,9 +1180,11 @@ void TextInput::OnControlSizeSet(const Vector3& targetSize) mActiveLayer.SetSize(targetSize); } -void TextInput::OnRelaidOut( Vector2 size, ActorSizeContainer& container ) +void TextInput::OnRelayout( const Vector2& size, ActorSizeContainer& container ) { Relayout( mDisplayedTextView, size, container ); + Relayout( mPopupPanel.GetRootActor(), size, container ); + GetTextLayoutInfo(); DrawCursor(); @@ -1182,7 +1220,7 @@ float TextInput::GetHeightForWidth( float width ) // Private Internal methods -void TextInput::OnHandlePan(Actor actor, PanGesture gesture) +void TextInput::OnHandlePan(Actor actor, const PanGesture& gesture) { switch (gesture.state) { @@ -1229,7 +1267,7 @@ void TextInput::OnHandlePan(Actor actor, PanGesture gesture) { mActualGrabHandlePosition = MoveGrabHandle( gesture.displacement ); SetCursorVisibility( true ); - SetUpPopUpSelection(); + SetUpPopupSelection(); ShowPopup(); } if (actor == mHandleOneGrabArea) @@ -1307,7 +1345,7 @@ bool TextInput::OnHandleTwoTouched(Dali::Actor actor, const TouchEvent& touch) return false; } -void TextInput::OnDoubleTap(Dali::Actor actor, Dali::TapGesture tap) +void TextInput::OnDoubleTap(Dali::Actor actor, const Dali::TapGesture& tap) { // If text exists then select nearest word. if ( !mStyledText.empty()) @@ -1337,6 +1375,12 @@ void TextInput::OnDoubleTap(Dali::Actor actor, Dali::TapGesture tap) mTextLayoutInfo.mScrollOffset = mDisplayedTextView.GetScrollPosition(); ReturnClosestIndex( tap.localPoint, mCursorPosition ); + std::size_t start = 0; + std::size_t end = 0; + Dali::Toolkit::Internal::TextProcessor::FindNearestWord( mStyledText, mCursorPosition, start, end ); + + mCursorPosition = end; // Ensure cursor is positioned at end of selected word + ImfManager imfManager = ImfManager::Get(); if ( imfManager ) { @@ -1344,14 +1388,20 @@ void TextInput::OnDoubleTap(Dali::Actor actor, Dali::TapGesture tap) imfManager.NotifyCursorPosition(); } - std::size_t start = 0; - std::size_t end = 0; - Dali::Toolkit::Internal::TextProcessor::FindNearestWord( mStyledText, mCursorPosition, start, end ); - - SelectText( start, end ); + if ( !mStyledText.at(end-1).mText[0].IsWhiteSpace() ) + { + SelectText( start, end ); + ShowPopupCutCopyPaste(); + } + else + { + RemoveHighlight( false ); // Remove highlight but do not auto hide popup + HidePopup( false ); // Hide popup with setting to do auto show. + SetUpPopupSelection( false ); // Set to false so if nearest word is whitespace it will not show cut button. + ShowPopup(); + } } - // if no text but clipboard has content then show paste option - if ( mClipboard.NumberOfItems() || !mStyledText.empty() ) + else if ( mClipboard && mClipboard.NumberOfItems() ) { ShowPopupCutCopyPaste(); } @@ -1360,7 +1410,7 @@ void TextInput::OnDoubleTap(Dali::Actor actor, Dali::TapGesture tap) } // TODO: Change the function name to be more general. -void TextInput::OnTextTap(Dali::Actor actor, Dali::TapGesture tap) +void TextInput::OnTextTap(Dali::Actor actor, const Dali::TapGesture& tap) { DALI_LOG_INFO( gLogFilter, Debug::General, "OnTap mPreEditFlag[%s] mEditOnTouch[%s] mEditModeActive[%s] ", (mPreEditFlag)?"true":"false" , (mEditOnTouch)?"true":"false" @@ -1373,9 +1423,9 @@ void TextInput::OnTextTap(Dali::Actor actor, Dali::TapGesture tap) if( mGrabArea == actor ) { - if( mPopUpPanel.GetState() == TextInputPopup::StateHidden || mPopUpPanel.GetState() == TextInputPopup::StateHiding ) + if( mPopupPanel.GetState() == TextInputPopup::StateHidden || mPopupPanel.GetState() == TextInputPopup::StateHiding ) { - SetUpPopUpSelection(); + SetUpPopupSelection(); ShowPopup(); } @@ -1400,26 +1450,6 @@ void TextInput::OnTextTap(Dali::Actor actor, Dali::TapGesture tap) { // Set the initial cursor position in the tap point. ReturnClosestIndex(tap.localPoint, mCursorPosition ); - - // Create the grab handle. - // TODO Make this a re-usable function. - if ( IsGrabHandleEnabled() ) - { - const Vector3 cursorPosition = GetActualPositionFromCharacterPosition(mCursorPosition); - - CreateGrabHandle(); - - mActualGrabHandlePosition.x = cursorPosition.x; // Set grab handle to be at the cursor position - mActualGrabHandlePosition.y = cursorPosition.y; // Set grab handle to be at the cursor position - mGrabHandle.SetPosition( mActualGrabHandlePosition + UI_OFFSET ); - ShowGrabHandleAndSetVisibility( mIsGrabHandleInScrollArea ); - - } - - // Edit mode started after grab handle created to ensure the signal InputStarted is sent last. - // This is used to ensure if selecting text hides the grab handle then this code is run after grab handle is created, - // otherwise the Grab handle will be shown when selecting. - StartEditMode(); } } @@ -1473,9 +1503,24 @@ void TextInput::OnTextTap(Dali::Actor actor, Dali::TapGesture tap) } } + // Edit mode started after grab handle created to ensure the signal InputStarted is sent last. + // This is used to ensure if selecting text hides the grab handle then this code is run after grab handle is created, + // otherwise the Grab handle will be shown when selecting. if ( createGrabHandle && IsGrabHandleEnabled() ) { - const Vector3 cursorPosition = GetActualPositionFromCharacterPosition(mCursorPosition); + Vector3 altPosition; // Alternate (i.e. opposite direction) cursor position. + bool altPositionValid; // Alternate cursor validity flag. + bool directionRTL; // Need to know direction of primary cursor (in case we have 2 cursors and need to show them differently) + Vector3 cursorPosition = GetActualPositionFromCharacterPosition( mCursorPosition, directionRTL, altPosition, altPositionValid ); + + if( altPositionValid ) + { + // Check which of the positions is the closest. + if( fabsf( altPosition.x - tap.localPoint.x ) < fabsf( cursorPosition.x - tap.localPoint.x ) ) + { + cursorPosition = altPosition; + } + } CreateGrabHandle(); @@ -1487,10 +1532,16 @@ void TextInput::OnTextTap(Dali::Actor actor, Dali::TapGesture tap) } } -void TextInput::OnLongPress(Dali::Actor actor, Dali::LongPressGesture longPress) +void TextInput::OnLongPress(Dali::Actor actor, const Dali::LongPressGesture& longPress) { DALI_LOG_INFO( gLogFilter, Debug::General, "OnLongPress\n" ); + // Ignore longpress if in selection mode already + if( mHighlightMeshActor ) + { + return; + } + if(longPress.state == Dali::Gesture::Started) { // Start edit mode on long press @@ -1527,21 +1578,24 @@ void TextInput::OnLongPress(Dali::Actor actor, Dali::LongPressGesture longPress) mTextLayoutInfo.mScrollOffset = mDisplayedTextView.GetScrollPosition(); ReturnClosestIndex( longPress.localPoint, mCursorPosition ); + std::size_t start = 0; + std::size_t end = 0; + Dali::Toolkit::Internal::TextProcessor::FindNearestWord( mStyledText, mCursorPosition, start, end ); + + mCursorPosition = end; // Ensure cursor is positioned at end of selected word + ImfManager imfManager = ImfManager::Get(); if ( imfManager ) { imfManager.SetCursorPosition ( mCursorPosition ); imfManager.NotifyCursorPosition(); } - std::size_t start = 0; - std::size_t end = 0; - Dali::Toolkit::Internal::TextProcessor::FindNearestWord( mStyledText, mCursorPosition, start, end ); SelectText( start, end ); } // if no text but clipboard has content then show paste option, if no text and clipboard empty then do nothing - if ( mClipboard.NumberOfItems() || !mStyledText.empty() ) + if ( ( mClipboard && mClipboard.NumberOfItems() ) || !mStyledText.empty() ) { ShowPopupCutCopyPaste(); } @@ -1564,11 +1618,11 @@ void TextInput::OnClipboardTextSelected( ClipboardEventNotifier& notifier ) bool TextInput::OnPopupButtonPressed( Toolkit::Button button ) { - mPopUpPanel.PressedSignal().Disconnect( this, &TextInput::OnPopupButtonPressed ); + mPopupPanel.PressedSignal().Disconnect( this, &TextInput::OnPopupButtonPressed ); const std::string& name = button.GetName(); - if(name == OPTION_SELECT_WORD) + if(name == TextInputPopup::OPTION_SELECT_WORD) { std::size_t start = 0; std::size_t end = 0; @@ -1576,7 +1630,7 @@ bool TextInput::OnPopupButtonPressed( Toolkit::Button button ) SelectText( start, end ); } - else if(name == OPTION_SELECT_ALL) + else if(name == TextInputPopup::OPTION_SELECT_ALL) { SetCursorVisibility(false); StopCursorBlinkTimer(); @@ -1586,7 +1640,7 @@ bool TextInput::OnPopupButtonPressed( Toolkit::Button button ) SelectText( start, end ); } - else if(name == OPTION_CUT) + else if(name == TextInputPopup::OPTION_CUT) { bool ret = CopySelectedTextToClipboard(); @@ -1601,7 +1655,7 @@ bool TextInput::OnPopupButtonPressed( Toolkit::Button button ) HidePopup(); } - else if(name == OPTION_COPY) + else if(name == TextInputPopup::OPTION_COPY) { CopySelectedTextToClipboard(); @@ -1612,7 +1666,7 @@ bool TextInput::OnPopupButtonPressed( Toolkit::Button button ) HidePopup(); } - else if(name == OPTION_PASTE) + else if(name == TextInputPopup::OPTION_PASTE) { const Text retrievedString( mClipboard.GetItem( 0 ) ); // currently can only get first item in clip board, index 0; @@ -1623,10 +1677,9 @@ bool TextInput::OnPopupButtonPressed( Toolkit::Button button ) ShowGrabHandleAndSetVisibility( false ); - HidePopup(); } - else if(name == OPTION_CLIPBOARD) + else if(name == TextInputPopup::OPTION_CLIPBOARD) { // In the case of clipboard being shown we do not want to show updated pop-up after hide animation completes // Hence pass the false parameter for signalFinished. @@ -1695,11 +1748,9 @@ bool TextInput::OnKeyDownEvent(const KeyEvent& event) { bool preEditFlagPreviouslySet( mPreEditFlag ); - if (mHighlightMeshActor) - { - // replaces highlighted text with new line - DeleteHighlightedText( false ); - } + // replaces highlighted text with new line + DeleteHighlightedText( false ); + mCursorPosition = mCursorPosition + InsertAt( Text( NEWLINE ), mCursorPosition, 0 ); // If we are in pre-edit mode then pressing enter will cause a commit. But the commit string does not include the @@ -1715,7 +1766,7 @@ bool TextInput::OnKeyDownEvent(const KeyEvent& event) mPreEditFlag = true; mIgnoreCommitFlag = false; } - + EmitTextModified(); update = true; } else @@ -1729,7 +1780,6 @@ bool TextInput::OnKeyDownEvent(const KeyEvent& event) { // Some text is selected so erase it before adding space. DeleteHighlightedText( true ); - update = true; } mCursorPosition = mCursorPosition + InsertAt(Text(keyString), mCursorPosition, 0); @@ -1740,7 +1790,7 @@ bool TextInput::OnKeyDownEvent(const KeyEvent& event) { mCommitByKeyInput = true; } - + EmitTextModified(); update = true; } // space else if (keyName == "BackSpace") @@ -1759,6 +1809,7 @@ bool TextInput::OnKeyDownEvent(const KeyEvent& event) update = true; } } + EmitTextModified(); } // BackSpace else if (keyName == "Right") { @@ -1775,16 +1826,13 @@ bool TextInput::OnKeyDownEvent(const KeyEvent& event) // Some text may be selected, hiding keyboard causes an empty keystring to be sent, we don't want to delete highlight in this case if ( !keyString.empty() ) { - if ( mHighlightMeshActor ) - { - // replaces highlighted text with new character - DeleteHighlightedText( false ); - } - + // replaces highlighted text with new character + DeleteHighlightedText( false ); // Received key String - mCursorPosition = mCursorPosition + InsertAt( Text( keyString ), mCursorPosition, 0 ); + mCursorPosition += InsertAt( Text( keyString ), mCursorPosition, 0 ); update = true; + EmitTextModified(); } } @@ -1826,6 +1874,64 @@ bool TextInput::OnKeyUpEvent(const KeyEvent& event) return false; } +void TextInput::ChooseRtlSelectionHandlePosition( const Vector3& cursorPositionOne, + const Vector3& cursorPositionTwo, + bool altPositionValidOne, + bool altPositionValidTwo, + const Vector3& altPositionOne, + const Vector3& altPositionTwo ) +{ + // TODO VCC Valid for one line. + // Try to place the selection handles. TODO think in something better. Probably need to know the direction of the paragraph. + if( cursorPositionOne != cursorPositionTwo ) + { + if( cursorPositionOne.x < cursorPositionTwo.x ) + { + mSelectionHandleOneActualPosition = cursorPositionOne; + mSelectionHandleTwoActualPosition = cursorPositionTwo; + } + else + { + mSelectionHandleOneActualPosition = cursorPositionTwo; + mSelectionHandleTwoActualPosition = cursorPositionOne; + } + } + else + { + mSelectionHandleOneActualPosition = cursorPositionOne; + if( altPositionValidOne ) + { + if( altPositionOne.x < mSelectionHandleOneActualPosition.x ) + { + mSelectionHandleOneActualPosition = altPositionOne; + } + } + if( altPositionValidTwo ) + { + if( altPositionTwo.x < mSelectionHandleOneActualPosition.x ) + { + mSelectionHandleOneActualPosition = altPositionTwo; + } + } + + mSelectionHandleTwoActualPosition = cursorPositionTwo; + if( altPositionValidTwo ) + { + if( altPositionTwo.x > mSelectionHandleTwoActualPosition.x ) + { + mSelectionHandleTwoActualPosition = altPositionTwo; + } + } + if( altPositionValidOne ) + { + if( altPositionOne.x > mSelectionHandleTwoActualPosition.x ) + { + mSelectionHandleTwoActualPosition = altPositionOne; + } + } + } +} + void TextInput::OnTextViewScrolled( Toolkit::TextView textView, Vector2 scrollPosition ) { // Updates the stored scroll position. @@ -1837,8 +1943,21 @@ void TextInput::OnTextViewScrolled( Toolkit::TextView textView, Vector2 scrollPo // Updates the cursor and grab handle position and visibility. if( mGrabHandle || mCursor ) { - cursorSize.height = GetRowRectFromCharacterPosition( GetVisualPosition( mCursorPosition ) ).height; - const Vector3 cursorPosition = GetActualPositionFromCharacterPosition(mCursorPosition); + cursorSize.height = GetRowRectFromCharacterPosition( mCursorPosition ).height; + + Vector3 altPosition; // Alternate (i.e. opposite direction) cursor position. + bool altPositionValid; // Alternate cursor validity flag. + bool directionRTL; // Need to know direction of primary cursor (in case we have 2 cursors and need to show them differently) + Vector3 cursorPosition = GetActualPositionFromCharacterPosition( mCursorPosition, directionRTL, altPosition, altPositionValid ); + + if( altPositionValid ) + { + // Check which of the positions is the closest. + if( fabsf( altPosition.x - mActualGrabHandlePosition.x ) < fabsf( cursorPosition.x - mActualGrabHandlePosition.x ) ) + { + cursorPosition = altPosition; + } + } mIsCursorInScrollArea = mIsGrabHandleInScrollArea = IsPositionInsideBoundaries( cursorPosition, cursorSize, controlSize ); @@ -1860,16 +1979,29 @@ void TextInput::OnTextViewScrolled( Toolkit::TextView textView, Vector2 scrollPo // Updates the selection handles and highlighted text position and visibility. if( mSelectionHandleOne && mSelectionHandleTwo ) { - const Vector3 cursorPositionOne = GetActualPositionFromCharacterPosition(mSelectionHandleOnePosition); - const Vector3 cursorPositionTwo = GetActualPositionFromCharacterPosition(mSelectionHandleTwoPosition); + Vector3 altPositionOne; // Alternate (i.e. opposite direction) cursor position. + bool altPositionValidOne; // Alternate cursor validity flag. + bool directionRTLOne; // Need to know direction of primary cursor (in case we have 2 cursors and need to show them differently) + Vector3 cursorPositionOne = GetActualPositionFromCharacterPosition( mSelectionHandleOnePosition, directionRTLOne, altPositionOne, altPositionValidOne ); + + Vector3 altPositionTwo; // Alternate (i.e. opposite direction) cursor position. + bool altPositionValidTwo; // Alternate cursor validity flag. + bool directionRTLTwo; // Need to know direction of primary cursor (in case we have 2 cursors and need to show them differently) + Vector3 cursorPositionTwo = GetActualPositionFromCharacterPosition( mSelectionHandleTwoPosition, directionRTLTwo, altPositionTwo, altPositionValidTwo ); + + // VCC TODO: This method is a hack for one line. + ChooseRtlSelectionHandlePosition( cursorPositionOne, + cursorPositionTwo, + altPositionValidOne, + altPositionValidTwo, + altPositionOne, + altPositionTwo ); + cursorSize.height = ( *( mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + mSelectionHandleOnePosition ) ).mSize.height; const bool isSelectionHandleOneVisible = IsPositionInsideBoundaries( cursorPositionOne, cursorSize, controlSize ); cursorSize.height = ( *( mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + mSelectionHandleTwoPosition ) ).mSize.height; const bool isSelectionHandleTwoVisible = IsPositionInsideBoundaries( cursorPositionTwo, cursorSize, controlSize ); - mSelectionHandleOneActualPosition = cursorPositionOne.GetVectorXY(); - mSelectionHandleTwoActualPosition = cursorPositionTwo.GetVectorXY(); - mSelectionHandleOne.SetVisible( isSelectionHandleOneVisible ); mSelectionHandleTwo.SetVisible( isSelectionHandleTwoVisible ); mSelectionHandleOne.SetPosition( mSelectionHandleOneActualPosition + UI_OFFSET + mSelectionHandleOneOffset ); @@ -1887,7 +2019,7 @@ void TextInput::ScrollTextViewToMakeCursorVisible( const Vector3& cursorPosition { // Scroll the text to make the cursor visible. const Size cursorSize( CURSOR_THICKNESS, - GetRowRectFromCharacterPosition( GetVisualPosition( mCursorPosition ) ).height ); + GetRowRectFromCharacterPosition( mCursorPosition ).height ); // Need to scroll the text to make the cursor visible and to cover the whole text-input area. @@ -1900,11 +2032,7 @@ void TextInput::ScrollTextViewToMakeCursorVisible( const Vector3& cursorPosition scrollOffset.x += cursorPosition.x; } - if( cursorPosition.y - cursorSize.height < 0.f ) - { - scrollOffset.y += ( cursorPosition.y - cursorSize.height ); - } - else if( cursorPosition.y > controlSize.height ) + if( cursorPosition.y - cursorSize.height < 0.f || cursorPosition.y > controlSize.height ) { scrollOffset.y += cursorPosition.y; } @@ -2029,6 +2157,8 @@ void TextInput::SetUpTouchEvents() void TextInput::CreateTextViewActor() { mDisplayedTextView = Toolkit::TextView::New(); + mDisplayedTextView.SetName( "DisplayedTextView "); + mDisplayedTextView.SetMarkupProcessingEnabled( mMarkUpEnabled ); mDisplayedTextView.SetParentOrigin(ParentOrigin::TOP_LEFT); mDisplayedTextView.SetAnchorPoint(AnchorPoint::TOP_LEFT); mDisplayedTextView.SetMultilinePolicy(Toolkit::TextView::SplitByWord); @@ -2037,7 +2167,7 @@ void TextInput::CreateTextViewActor() mDisplayedTextView.SetLineJustification( Toolkit::TextView::Left ); mDisplayedTextView.SetTextAlignment( static_cast( Toolkit::Alignment::HorizontalLeft | Toolkit::Alignment::VerticalTop ) ); mDisplayedTextView.SetPosition( Vector3( 0.0f, 0.0f, DISPLAYED_TEXT_VIEW_Z_OFFSET ) ); - mDisplayedTextView.SetSizePolicy( Control::Fixed, Control::Fixed ); + mDisplayedTextView.SetSizePolicy( Toolkit::Control::Fixed, Toolkit::Control::Fixed ); mDisplayedTextView.ScrolledSignal().Connect( this, &TextInput::OnTextViewScrolled ); @@ -2099,7 +2229,7 @@ void TextInput::ApplyPreEditStyle( std::size_t preEditStartPosition, std::size_t { if ( mPreEditFlag && ( preEditStringLength > 0 ) ) { - mUnderlinedPriorToPreEdit = mInputStyle.GetUnderline(); + mUnderlinedPriorToPreEdit = mInputStyle.IsUnderlineEnabled(); TextStyle style; style.SetUnderline( true ); ApplyStyleToRange( style, TextStyle::UNDERLINE , preEditStartPosition, preEditStartPosition + preEditStringLength -1 ); @@ -2215,7 +2345,7 @@ ImfManager::ImfCallbackData TextInput::ImfEventReceived( Dali::ImfManager& imfMa } else { - if( std::abs( imfEvent.cursorOffset ) < mCursorPosition ) + if( static_cast(std::abs( imfEvent.cursorOffset )) < mCursorPosition ) { toDelete = mCursorPosition + imfEvent.cursorOffset; } @@ -2234,6 +2364,8 @@ ImfManager::ImfCallbackData TextInput::ImfEventReceived( Dali::ImfManager& imfMa mCursorPosition = toDelete; mNumberOfSurroundingCharactersDeleted = numberOfCharacters; + EmitTextModified(); + DALI_LOG_INFO( gLogFilter, Debug::General, "ImfEventReceived - deleteSurrounding post-delete range mCursorPosition[%u] \n", mCursorPosition); break; } @@ -2257,9 +2389,7 @@ ImfManager::ImfCallbackData TextInput::ImfEventReceived( Dali::ImfManager& imfMa if( mStyledText.empty() ) { - // Styled text is empty, so set the placeholder text. - mDisplayedTextView.SetText( mStyledPlaceHolderText ); - mPlaceHolderSet = true; + ShowPlaceholderText( mStyledPlaceHolderText ); } } break; @@ -2316,15 +2446,15 @@ bool TextInput::PreEditReceived(const std::string& keyString, std::size_t cursor if( mStyledText.empty() ) { - // Styled text is empty, so set the placeholder text. - mDisplayedTextView.SetText( mStyledPlaceHolderText ); - mPlaceHolderSet = true; + ShowPlaceholderText( mStyledPlaceHolderText ); } else { mDisplayedTextView.RemoveTextFrom( mPreEditStartPosition, numberOfCharactersToReplace ); } + GetTextLayoutInfo(); + EmitTextModified(); } else { @@ -2334,6 +2464,7 @@ bool TextInput::PreEditReceived(const std::string& keyString, std::size_t cursor mCursorPosition = mPreEditStartPosition + std::min( cursorOffset, mPreEditLength ); ApplyPreEditStyle( mPreEditStartPosition, mPreEditLength ); DALI_LOG_INFO(gLogFilter, Debug::General, "PreEditReceived mCursorPosition[%u] \n", mCursorPosition); + EmitTextModified(); } // cursor update to keyboard is not done here as the keyboard knows the cursor position and provides the 'cursorOffset'. DrawCursor(); @@ -2353,9 +2484,9 @@ bool TextInput::PreEditReceived(const std::string& keyString, std::size_t cursor mCursorPosition = mPreEditStartPosition + std::min( cursorOffset, mPreEditLength ); ApplyPreEditStyle( mPreEditStartPosition, mPreEditLength ); DALI_LOG_INFO(gLogFilter, Debug::General, "PreEditReceived mCursorPosition[%u] mPreEditStartPosition[%u]\n", mCursorPosition, mPreEditStartPosition); - // cursor update to keyboard is not done here as the keyboard knows the cursor position and provides the 'cursorOffset'. DrawCursor(); + EmitTextModified(); } else { @@ -2416,6 +2547,8 @@ bool TextInput::CommitReceived(const std::string& keyString ) } } + EmitTextModified(); + if ( mSelectTextOnCommit ) { SelectText(mRequestedSelection.mStartOfSelection, mRequestedSelection.mEndOfSelection ); @@ -2437,6 +2570,7 @@ bool TextInput::CommitReceived(const std::string& keyString ) mCursorPosition = mCursorPosition + InsertAt( Text( keyString ), mCursorPosition, mNumberOfSurroundingCharactersDeleted ); update = true; mNumberOfSurroundingCharactersDeleted = 0; + EmitTextModified(); } else { @@ -2524,7 +2658,7 @@ void TextInput::DeleteHighlightedText( bool inheritStyle ) { DALI_LOG_INFO( gLogFilter, Debug::General, "DeleteHighlightedText handlePosOne[%u] handlePosTwo[%u]\n", mSelectionHandleOnePosition, mSelectionHandleTwoPosition); - if(mHighlightMeshActor) + if( mHighlightMeshActor ) { mCursorPosition = std::min( mSelectionHandleOnePosition, mSelectionHandleTwoPosition ); @@ -2539,13 +2673,12 @@ void TextInput::DeleteHighlightedText( bool inheritStyle ) mStyledText.erase( start, end ); // erase range of characters - // Remove text from TextView. + // Remove text from TextView and update place holder text if required + // Set the placeholder text only if the styled text is empty. if( mStyledText.empty() ) { - // Styled text is empty, so set the placeholder text. - mDisplayedTextView.SetText( mStyledPlaceHolderText ); - mPlaceHolderSet = true; + ShowPlaceholderText( mStyledPlaceHolderText ); } else { @@ -2580,6 +2713,8 @@ void TextInput::DeleteHighlightedText( bool inheritStyle ) RemoveHighlight(); + EmitTextModified(); + if( inheritStyle ) { const TextStyle oldInputStyle( mInputStyle ); @@ -2670,9 +2805,7 @@ void TextInput::DeleteCharacter( std::size_t positionToDelete ) if( mStyledText.empty() ) { - // Styled text is empty, so set the placeholder text. - mDisplayedTextView.SetText( mStyledPlaceHolderText ); - mPlaceHolderSet = true; + ShowPlaceholderText( mStyledPlaceHolderText ); } else { @@ -2765,24 +2898,14 @@ std::size_t TextInput::InsertAt( const Text& newText, const std::size_t insertio return insertedStringLength; } -ImageActor TextInput::CreateCursor( Image cursorImage, const Vector4& border ) +ImageActor TextInput::CreateCursor( const Vector4& color) { ImageActor cursor; - - if ( cursorImage ) - { - cursor = ImageActor::New( cursorImage ); - } - else - { - cursor = ImageActor::New( Image::New( DEFAULT_CURSOR ) ); - } - - cursor.SetStyle(ImageActor::STYLE_NINE_PATCH); - cursor.SetNinePatchBorder( border ); + cursor = CreateSolidColorActor(color); + cursor.SetName( "Cursor" ); cursor.SetParentOrigin(ParentOrigin::TOP_LEFT); - cursor.SetAnchorPoint(AnchorPoint::BOTTOM_CENTER); + cursor.SetAnchorPoint(AnchorPoint::BOTTOM_LEFT); cursor.SetVisible(false); return cursor; @@ -2837,13 +2960,15 @@ void TextInput::AdvanceCursor(bool reverse, std::size_t places) } } -void TextInput::DrawCursor(const std::size_t nthChar) +void TextInput::DrawCursor() { + const Size rowRect = GetRowRectFromCharacterPosition( mCursorPosition ); + // Get height of cursor and set its size Size size( CURSOR_THICKNESS, 0.0f ); - if (!mTextLayoutInfo.mCharacterLayoutInfoTable.empty()) + if( !mTextLayoutInfo.mCharacterLayoutInfoTable.empty() ) { - size.height = GetRowRectFromCharacterPosition( GetVisualPosition( mCursorPosition ) ).height; + size.height = rowRect.height; } else { @@ -2854,11 +2979,11 @@ void TextInput::DrawCursor(const std::size_t nthChar) mCursor.SetSize(size); // If the character is italic then the cursor also tilts. - mCursor.SetRotation( mInputStyle.GetItalics() ? Degree( mInputStyle.GetItalicsAngle() - CURSOR_ANGLE_OFFSET ) : Degree( 0.f ), Vector3::ZAXIS ); + mCursor.SetRotation( mInputStyle.IsItalicsEnabled() ? Degree( mInputStyle.GetItalicsAngle() - CURSOR_ANGLE_OFFSET ) : Degree( 0.f ), Vector3::ZAXIS ); DALI_ASSERT_DEBUG( mCursorPosition <= mTextLayoutInfo.mCharacterLayoutInfoTable.size() ); - if ( ( mCursorPosition <= mTextLayoutInfo.mCharacterLayoutInfoTable.size() ) ) + if( ( mCursorPosition <= mTextLayoutInfo.mCharacterLayoutInfoTable.size() ) ) { Vector3 altPosition; // Alternate (i.e. opposite direction) cursor position. bool altPositionValid; // Alternate cursor validity flag. @@ -2867,7 +2992,7 @@ void TextInput::DrawCursor(const std::size_t nthChar) SetAltCursorEnabled( altPositionValid ); - if(!altPositionValid) + if( !altPositionValid ) { mCursor.SetPosition( position + UI_OFFSET ); } @@ -2875,13 +3000,12 @@ void TextInput::DrawCursor(const std::size_t nthChar) { size.height *= 0.5f; mCursor.SetSize(size); - mCursor.SetPosition( position + UI_OFFSET - Vector3(0.0f, directionRTL ? 0.0f : size.height, 0.0f) ); + mCursor.SetPosition( position + UI_OFFSET - Vector3( 0.0f, directionRTL ? 0.0f : size.height, 0.0f ) ); // TODO: change this cursor pos, to be the one where the cursor is sourced from. - Size rowSize = GetRowRectFromCharacterPosition( GetVisualPosition( mCursorPosition ) ); - size.height = rowSize.height * 0.5f; + size.height = rowRect.height * 0.5f; mCursorRTL.SetSize(size); - mCursorRTL.SetPosition( altPosition + UI_OFFSET - Vector3(0.0f, directionRTL ? size.height : 0.0f, 0.0f) ); + mCursorRTL.SetPosition( altPosition + UI_OFFSET - Vector3( 0.0f, directionRTL ? size.height : 0.0f, 0.0f ) ); } if( IsScrollEnabled() ) @@ -2911,7 +3035,7 @@ void TextInput::CreateGrabHandle( Dali::Image image ) { if ( !image ) { - mGrabHandleImage = Image::New(DEFAULT_GRAB_HANDLE); + mGrabHandleImage = ResourceImage::New(DEFAULT_GRAB_HANDLE); } else { @@ -2935,11 +3059,14 @@ void TextInput::CreateGrabHandle( Dali::Image image ) void TextInput::CreateGrabArea( Actor& parent ) { mGrabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move + mGrabArea.SetName( "GrabArea" ); mGrabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION ); - mGrabArea.ApplyConstraint( Constraint::New( Actor::SIZE, ParentSource( Actor::SIZE ), RelativeToConstraint( DEFAULT_GRAB_HANDLE_RELATIVE_SIZE ) ) ); // grab area to be larger than text actor + mGrabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT ); + mGrabArea.SetSizeModeFactor( DEFAULT_GRAB_HANDLE_RELATIVE_SIZE ); mGrabArea.TouchedSignal().Connect(this,&TextInput::OnPressDown); mTapDetector.Attach( mGrabArea ); mPanGestureDetector.Attach( mGrabArea ); + mLongPressDetector.Attach( mGrabArea ); parent.Add(mGrabArea); } @@ -2957,14 +3084,26 @@ Vector3 TextInput::MoveGrabHandle( const Vector2& displacement ) std::size_t newCursorPosition = 0; ReturnClosestIndex( mActualGrabHandlePosition.GetVectorXY(), newCursorPosition ); - actualHandlePosition = GetActualPositionFromCharacterPosition( newCursorPosition ); + Vector3 altPosition; // Alternate (i.e. opposite direction) cursor position. + bool altPositionValid; // Alternate cursor validity flag. + bool directionRTL; // Need to know direction of primary cursor (in case we have 2 cursors and need to show them differently) + actualHandlePosition = GetActualPositionFromCharacterPosition( newCursorPosition, directionRTL, altPosition, altPositionValid ); + + if( altPositionValid ) + { + // Check which of the positions is the closest. + if( fabsf( altPosition.x - mActualGrabHandlePosition.x ) < fabsf( actualHandlePosition.x - mActualGrabHandlePosition.x ) ) + { + actualHandlePosition = altPosition; + } + } bool handleVisible = true; if( IsScrollEnabled() ) { const Vector3 controlSize = GetControlSize(); - const Size cursorSize = GetRowRectFromCharacterPosition( GetVisualPosition( newCursorPosition ) ); + const Size cursorSize = GetRowRectFromCharacterPosition( newCursorPosition ); // Scrolls the text if the handle is not in a visible position handleVisible = IsPositionInsideBoundaries( actualHandlePosition, cursorSize, @@ -3146,8 +3285,8 @@ void TextInput::CreateSelectionHandles( std::size_t start, std::size_t end, Dali if ( !mSelectionHandleOne ) { // create normal and pressed images - mSelectionHandleOneImage = Image::New( DEFAULT_SELECTION_HANDLE_ONE ); - mSelectionHandleOneImagePressed = Image::New( DEFAULT_SELECTION_HANDLE_ONE_PRESSED ); + mSelectionHandleOneImage = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE ); + mSelectionHandleOneImagePressed = ResourceImage::New( DEFAULT_SELECTION_HANDLE_ONE_PRESSED ); mSelectionHandleOne = ImageActor::New( mSelectionHandleOneImage ); mSelectionHandleOne.SetName("SelectionHandleOne"); @@ -3159,7 +3298,8 @@ void TextInput::CreateSelectionHandles( std::size_t start, std::size_t end, Dali mHandleOneGrabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move mHandleOneGrabArea.SetName("SelectionHandleOneGrabArea"); - mHandleOneGrabArea.ApplyConstraint( Constraint::New( Actor::SIZE, ParentSource( Actor::SIZE ), RelativeToConstraint( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE ) ) ); // grab area to be larger than text actor + mHandleOneGrabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT ); + mHandleOneGrabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE ); mHandleOneGrabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION ); mTapDetector.Attach( mHandleOneGrabArea ); @@ -3174,8 +3314,8 @@ void TextInput::CreateSelectionHandles( std::size_t start, std::size_t end, Dali if ( !mSelectionHandleTwo ) { // create normal and pressed images - mSelectionHandleTwoImage = Image::New( DEFAULT_SELECTION_HANDLE_TWO ); - mSelectionHandleTwoImagePressed = Image::New( DEFAULT_SELECTION_HANDLE_TWO_PRESSED ); + mSelectionHandleTwoImage = ResourceImage::New( DEFAULT_SELECTION_HANDLE_TWO ); + mSelectionHandleTwoImagePressed = ResourceImage::New( DEFAULT_SELECTION_HANDLE_TWO_PRESSED ); mSelectionHandleTwo = ImageActor::New( mSelectionHandleTwoImage ); mSelectionHandleTwo.SetName("SelectionHandleTwo"); @@ -3186,7 +3326,8 @@ void TextInput::CreateSelectionHandles( std::size_t start, std::size_t end, Dali mHandleTwoGrabArea = Actor::New(); // Area that Grab handle responds to, larger than actual handle so easier to move mHandleTwoGrabArea.SetName("SelectionHandleTwoGrabArea"); - mHandleTwoGrabArea.ApplyConstraint( Constraint::New( Actor::SIZE, ParentSource( Actor::SIZE ), RelativeToConstraint( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE ) ) ); // grab area to be larger than text actor + mHandleTwoGrabArea.SetSizeMode( SIZE_RELATIVE_TO_PARENT ); + mHandleTwoGrabArea.SetSizeModeFactor( DEFAULT_SELECTION_HANDLE_RELATIVE_SIZE ); mHandleTwoGrabArea.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION ); mTapDetector.Attach( mHandleTwoGrabArea ); @@ -3204,8 +3345,23 @@ void TextInput::CreateSelectionHandles( std::size_t start, std::size_t end, Dali // update table as text may have changed. GetTextLayoutInfo(); - mSelectionHandleOneActualPosition = GetActualPositionFromCharacterPosition( mSelectionHandleOnePosition ); - mSelectionHandleTwoActualPosition = GetActualPositionFromCharacterPosition( mSelectionHandleTwoPosition ); + Vector3 altPositionOne; // Alternate (i.e. opposite direction) cursor position. + bool altPositionValidOne; // Alternate cursor validity flag. + bool directionRTLOne; // Need to know direction of primary cursor (in case we have 2 cursors and need to show them differently) + Vector3 cursorPositionOne = GetActualPositionFromCharacterPosition( mSelectionHandleOnePosition, directionRTLOne, altPositionOne, altPositionValidOne ); + + Vector3 altPositionTwo; // Alternate (i.e. opposite direction) cursor position. + bool altPositionValidTwo; // Alternate cursor validity flag. + bool directionRTLTwo; // Need to know direction of primary cursor (in case we have 2 cursors and need to show them differently) + Vector3 cursorPositionTwo = GetActualPositionFromCharacterPosition( mSelectionHandleTwoPosition, directionRTLTwo, altPositionTwo, altPositionValidTwo ); + + // VCC TODO: This method is a hack for one line. + ChooseRtlSelectionHandlePosition( cursorPositionOne, + cursorPositionTwo, + altPositionValidOne, + altPositionValidTwo, + altPositionOne, + altPositionTwo ); mSelectionHandleOne.SetPosition( mSelectionHandleOneActualPosition + UI_OFFSET + mSelectionHandleOneOffset ); mSelectionHandleTwo.SetPosition( mSelectionHandleTwoActualPosition + UI_OFFSET + mSelectionHandleTwoOffset ); @@ -3249,7 +3405,18 @@ Vector3 TextInput::MoveSelectionHandle( SelectionHandleId handleId, const Vector std::size_t newHandlePosition = 0; ReturnClosestIndex( actualSelectionHandlePosition.GetVectorXY(), newHandlePosition ); - actualHandlePosition = GetActualPositionFromCharacterPosition( newHandlePosition ); + Vector3 altPosition; // Alternate (i.e. opposite direction) cursor position. + bool altPositionValid; // Alternate cursor validity flag. + bool directionRTL; // Need to know direction of primary cursor (in case we have 2 cursors and need to show them differently) + actualHandlePosition = GetActualPositionFromCharacterPosition( newHandlePosition, directionRTL, altPosition, altPositionValid ); + if( altPositionValid ) + { + // Check which of the positions is the closest. + if( fabsf( altPosition.x - actualSelectionHandlePosition.x ) < fabsf( actualHandlePosition.x - actualSelectionHandlePosition.x ) ) + { + actualHandlePosition = altPosition; + } + } bool handleVisible = true; @@ -3257,7 +3424,7 @@ Vector3 TextInput::MoveSelectionHandle( SelectionHandleId handleId, const Vector { mCurrentSelectionId = handleId; - cursorSize.height = GetRowRectFromCharacterPosition( GetVisualPosition( newHandlePosition ) ).height; + cursorSize.height = GetRowRectFromCharacterPosition( newHandlePosition ).height; // Restricts the movement of the grab handle inside the boundaries of the text-input. handleVisible = IsPositionInsideBoundaries( actualHandlePosition, cursorSize, @@ -3328,7 +3495,6 @@ Vector3 TextInput::MoveSelectionHandle( SelectionHandleId handleId, const Vector void TextInput::SetSelectionHandlePosition(SelectionHandleId handleId) { - const std::size_t selectionHandlePosition = ( handleId == HandleOne ) ? mSelectionHandleOnePosition : mSelectionHandleTwoPosition; ImageActor selectionHandleActor = ( handleId == HandleOne ) ? mSelectionHandleOne : mSelectionHandleTwo; @@ -3341,7 +3507,7 @@ void TextInput::SetSelectionHandlePosition(SelectionHandleId handleId) if( IsScrollEnabled() ) { const Size cursorSize( CURSOR_THICKNESS, - GetRowRectFromCharacterPosition( GetVisualPosition( selectionHandlePosition ) ).height ); + GetRowRectFromCharacterPosition( selectionHandlePosition ).height ); selectionHandleActor.SetVisible( IsPositionInsideBoundaries( actualHandlePosition, cursorSize, GetControlSize() ) ); @@ -3349,50 +3515,34 @@ void TextInput::SetSelectionHandlePosition(SelectionHandleId handleId) } } -std::size_t TextInput::GetVisualPosition(std::size_t logicalPosition) const -{ - // Note: we're allowing caller to request a logical position of size (i.e. end of string) - // For now the visual position of end of logical string will be end of visual string. - DALI_ASSERT_DEBUG( logicalPosition <= mTextLayoutInfo.mCharacterLogicalToVisualMap.size() ); - - return logicalPosition != mTextLayoutInfo.mCharacterLogicalToVisualMap.size() ? mTextLayoutInfo.mCharacterLogicalToVisualMap[logicalPosition] : mTextLayoutInfo.mCharacterLogicalToVisualMap.size(); -} - -void TextInput::GetVisualTextSelection(std::vector& selectedVisualText, std::size_t startSelection, std::size_t endSelection) +void TextInput::GetVisualTextSelection( std::vector& selectedVisualText, std::size_t startSelection, std::size_t endSelection ) { - std::vector::iterator it = mTextLayoutInfo.mCharacterLogicalToVisualMap.begin(); - std::vector::iterator startSelectionIt = mTextLayoutInfo.mCharacterLogicalToVisualMap.begin() + std::min(startSelection, endSelection); - std::vector::iterator endSelectionIt = mTextLayoutInfo.mCharacterLogicalToVisualMap.begin() + std::max(startSelection, endSelection); - std::vector::iterator end = mTextLayoutInfo.mCharacterLogicalToVisualMap.end(); - - selectedVisualText.resize( mTextLayoutInfo.mCharacterLogicalToVisualMap.size() ); + selectedVisualText.resize( mTextLayoutInfo.mCharacterLogicalToVisualMap.size(), false ); - // Deselect text prior to startSelectionIt - for(;it!=startSelectionIt;++it) - { - selectedVisualText[*it] = false; - } + // VCC Set true/false in logical order. TODO : It needs to be checked. - // Select text from startSelectionIt -> endSelectionIt - for(;it!=endSelectionIt;++it) + if( startSelection > endSelection ) { - selectedVisualText[*it] = true; + std::swap( startSelection, endSelection ); } - - // Deselect text after endSelection - for(;it!=end;++it) + std::size_t index = 0u; + for( std::vector::iterator it = selectedVisualText.begin(), endIt = selectedVisualText.end(); it != endIt; ++it, ++index ) { - selectedVisualText[*it] = false; + if( ( index < startSelection ) || ( endSelection <= index ) ) + { + *it = false; + } + else + { + *it = true; + } } - - selectedVisualText.resize( mTextLayoutInfo.mCharacterLogicalToVisualMap.size(), false ); } // Calculate the dimensions of the quads they will make the highlight mesh TextInput::HighlightInfo TextInput::CalculateHighlightInfo() { // At the moment there is no public API to modify the block alignment option. - const bool blockAlignEnabled = true; mNewHighlightInfo.mQuadList.clear(); // clear last quad information. @@ -3403,9 +3553,9 @@ TextInput::HighlightInfo TextInput::CalculateHighlightInfo() // Get vector of flags representing characters that are selected (true) vs unselected (false). std::vector selectedVisualText; - GetVisualTextSelection(selectedVisualText, mSelectionHandleOnePosition, mSelectionHandleTwoPosition); - std::vector::iterator selectedIt(selectedVisualText.begin()); - std::vector::iterator selectedEndIt(selectedVisualText.end()); + GetVisualTextSelection( selectedVisualText, mSelectionHandleOnePosition, mSelectionHandleTwoPosition ); + std::vector::iterator selectedIt = selectedVisualText.begin(); + std::vector::iterator selectedEndIt = selectedVisualText.end(); SelectionState selectionState = SelectionNone; ///< Current selection status of cursor over entire text. float rowLeft = 0.0f; @@ -3422,34 +3572,34 @@ TextInput::HighlightInfo TextInput::CalculateHighlightInfo() // selectionState: None when not in selection, Started when in selection, and Ended when reached end of selection. Toolkit::TextView::CharacterLayoutInfo& charInfo(*it); - bool charSelected( false ); + bool charSelected = false; if( selectedIt != selectedEndIt ) { charSelected = *selectedIt++; } - if(selectionState == SelectionNone) + if( selectionState == SelectionNone ) { - if(charSelected) + if( charSelected ) { selectionState = SelectionStarted; rowLeft = charInfo.mPosition.x - mTextLayoutInfo.mScrollOffset.x; rowRight = rowLeft + charInfo.mSize.width; } } - else if(selectionState == SelectionStarted) + else if( selectionState == SelectionStarted ) { // break selection on: // 1. new line causing selection break. (\n or wordwrap) // 2. character not selected. - if(charInfo.mPosition.y - lastIt->mPosition.y > CHARACTER_THRESHOLD || - !charSelected) + if( !charSelected || + ( charInfo.mPosition.y - lastIt->mPosition.y > CHARACTER_THRESHOLD ) ) { // finished selection. // TODO: TextView should have a table of visual rows, and each character a reference to the row // that it resides on. That way this enumeration is not necessary. Vector2 min, max; - if(lastIt->mIsNewLineChar) + if(lastIt->mIsNewParagraphChar) { // If the last character is a new line, then to get the row rect, we need to scan from the character before the new line. lastIt = std::max( mTextLayoutInfo.mCharacterLayoutInfoTable.begin(), lastIt - 1 ); @@ -3461,7 +3611,7 @@ TextInput::HighlightInfo TextInput::CalculateHighlightInfo() float rowTop = rowBottom - rowSize.height; // Still selected, and block-align mode then set rowRight to max, so it can be clamped afterwards - if(charSelected && blockAlignEnabled) + if(charSelected) { rowRight = std::numeric_limits::max(); } @@ -3473,7 +3623,7 @@ TextInput::HighlightInfo TextInput::CalculateHighlightInfo() if( charSelected ) { // if block-align mode then set rowLeft to min, so it can be clamped afterwards - rowLeft = blockAlignEnabled ? 0.0f : charInfo.mPosition.x - mTextLayoutInfo.mScrollOffset.x; + rowLeft = 0.0f; rowRight = ( charInfo.mPosition.x - mTextLayoutInfo.mScrollOffset.x ) + charInfo.mSize.width; selectionState = SelectionStarted; } @@ -3496,7 +3646,7 @@ TextInput::HighlightInfo TextInput::CalculateHighlightInfo() { // finished selection. Vector2 min, max; - if(lastIt->mIsNewLineChar) + if(lastIt->mIsNewParagraphChar) { lastIt = std::max( mTextLayoutInfo.mCharacterLayoutInfoTable.begin(), lastIt - 1 ); } @@ -3518,8 +3668,6 @@ TextInput::HighlightInfo TextInput::CalculateHighlightInfo() mNewHighlightInfo.Clamp2D( topLeft, bottomRight ); // For block-align align Further Clamp quads to max left and right extents - if(blockAlignEnabled) - { // BlockAlign: Will adjust highlight to block: // i.e. // H[ello] (top row right = max of all rows right) @@ -3534,9 +3682,7 @@ TextInput::HighlightInfo TextInput::CalculateHighlightInfo() // [is some] // [text] // (common in regular text editors/web browser selection) - mNewHighlightInfo.Clamp2D( Vector2(maxRowLeft, topLeft.y), Vector2(maxRowRight, bottomRight.y ) ); - } // Finally clamp quads again so they don't exceed the boundry of the control. const Vector3& controlSize = GetControlSize(); @@ -3546,37 +3692,97 @@ TextInput::HighlightInfo TextInput::CalculateHighlightInfo() return mNewHighlightInfo; } -void TextInput::UpdateHighlight() +// VCC TODO: two methods are not needed. this one is a quick hack to fix PLMs. Should implement one which support both directions. +// This method creates one quad per character so different selection boxes for a mix of LTR and RTL languages are created. +TextInput::HighlightInfo TextInput::CalculateHighlightInfoRtl() { -// Construct a Mesh with a texture to be used as the highlight 'box' for selected text -// -// Example scenarios where mesh is made from 3, 1, 2, 2 ,3 or 3 quads. -// -// [ TOP ] [ TOP ] [TOP ] [ TOP ] [ TOP ] [ TOP ] -// [ MIDDLE ] [BOTTOM] [BOTTOM] [ MIDDLE ] [ MIDDLE ] -// [ BOTTOM] [ MIDDLE ] [ MIDDLE ] -// [BOTTOM] [ MIDDLE ] -// [BOTTOM] -// -// Each quad is created as 2 triangles. -// Middle is just 1 quad regardless of its size. -// -// (0,0) (0,0) -// 0* *2 0* *2 -// TOP TOP -// 3* *1 3* *1 -// 4* *1 4* *6 -// MIDDLE BOTTOM -// 6* *5 7* *5 -// 6* *8 -// BOTTOM -// 9* *7 + // At the moment there is no public API to modify the block alignment option. + + mNewHighlightInfo.mQuadList.clear(); // clear last quad information. + + if ( !mTextLayoutInfo.mCharacterLayoutInfoTable.empty() && !mTextLayoutInfo.mCharacterLogicalToVisualMap.empty() ) + { + Toolkit::TextView::CharacterLayoutInfoContainer::iterator it = mTextLayoutInfo.mCharacterLayoutInfoTable.begin(); + Toolkit::TextView::CharacterLayoutInfoContainer::iterator end = mTextLayoutInfo.mCharacterLayoutInfoTable.end(); + + // Get vector of flags representing characters that are selected (true) vs unselected (false). + std::vector selectedVisualText; + GetVisualTextSelection( selectedVisualText, mSelectionHandleOnePosition, mSelectionHandleTwoPosition ); + std::vector::iterator selectedIt = selectedVisualText.begin(); + std::vector::iterator selectedEndIt = selectedVisualText.end(); + + // SelectionState selectionState = SelectionNone; ///< Current selection status of cursor over entire text. + float rowLeft = 0.0f; + float rowRight = 0.0f; + + // VCC TODO this is valid for one line. + Vector2 min, max; + const Size rowSize = GetRowRectFromCharacterPosition( 0, min, max ); + + // Scan through entire text. + while(it != end) + { + // selectionState: None when not in selection, Started when in selection, and Ended when reached end of selection. + + Toolkit::TextView::CharacterLayoutInfo& charInfo(*it); + bool charSelected = false; + if( selectedIt != selectedEndIt ) + { + charSelected = *selectedIt++; + } + + if( charSelected ) + { + rowLeft = charInfo.mPosition.x - mTextLayoutInfo.mScrollOffset.x; + rowRight = rowLeft + charInfo.mSize.width; + + float rowBottom = charInfo.mPosition.y - mTextLayoutInfo.mScrollOffset.y; + float rowTop = rowBottom - rowSize.height; + mNewHighlightInfo.AddQuad( rowLeft, rowTop, rowRight, rowBottom ); + } + + ++it; + } + + // Finally clamp quads again so they don't exceed the boundry of the control. + const Vector3& controlSize = GetControlSize(); + mNewHighlightInfo.Clamp2D( Vector2::ZERO, Vector2(controlSize.x, controlSize.y) ); + } // end if + + return mNewHighlightInfo; +} + +void TextInput::UpdateHighlight() +{ +// Construct a Mesh with a texture to be used as the highlight 'box' for selected text +// +// Example scenarios where mesh is made from 3, 1, 2, 2 ,3 or 3 quads. +// +// [ TOP ] [ TOP ] [TOP ] [ TOP ] [ TOP ] [ TOP ] +// [ MIDDLE ] [BOTTOM] [BOTTOM] [ MIDDLE ] [ MIDDLE ] +// [ BOTTOM] [ MIDDLE ] [ MIDDLE ] +// [BOTTOM] [ MIDDLE ] +// [BOTTOM] +// +// Each quad is created as 2 triangles. +// Middle is just 1 quad regardless of its size. +// +// (0,0) (0,0) +// 0* *2 0* *2 +// TOP TOP +// 3* *1 3* *1 +// 4* *1 4* *6 +// MIDDLE BOTTOM +// 6* *5 7* *5 +// 6* *8 +// BOTTOM +// 9* *7 // if ( mHighlightMeshActor ) { // vertex and triangle buffers should always be present if MeshActor is alive. - HighlightInfo newHighlightInfo = CalculateHighlightInfo(); + HighlightInfo newHighlightInfo = CalculateHighlightInfoRtl(); MeshData::VertexContainer vertices; Dali::MeshData::FaceIndices faceIndices; @@ -3645,144 +3851,177 @@ void TextInput::UpdateHighlight() void TextInput::ClearPopup() { - mPopUpPanel.Clear(); + mPopupPanel.Clear(); } -void TextInput::AddPopupOption(const std::string& name, const std::string& caption, const Image icon, bool finalOption) +void TextInput::AddPopupOptions() { - mPopUpPanel.AddOption(name, caption, icon, finalOption); + mPopupPanel.AddPopupOptions(); } -void TextInput::SetPopupPosition(const Vector3& position) +void TextInput::SetPopupPosition( const Vector3& position, const Vector2& alternativePosition ) { - mPopUpPanel.Self().SetPosition( position ); + const Vector3& visiblePopUpSize = mPopupPanel.GetVisibileSize(); + + Vector3 clampedPosition ( position ); + Vector3 tailOffsetPosition ( position ); + + float xOffSet( 0.0f ); + + Actor self = Self(); + const Vector3 textViewTopLeftWorldPosition = self.GetCurrentWorldPosition() - self.GetCurrentSize()*0.5f; + + const float popUpLeft = textViewTopLeftWorldPosition.x + position.x - visiblePopUpSize.width*0.5f; + const float popUpTop = textViewTopLeftWorldPosition.y + position.y - visiblePopUpSize.height; + + // Clamp to left or right or of boundary + if( popUpLeft < mBoundingRectangleWorldCoordinates.x ) + { + xOffSet = mBoundingRectangleWorldCoordinates.x - popUpLeft ; + } + else if ( popUpLeft + visiblePopUpSize.width > mBoundingRectangleWorldCoordinates.z ) + { + xOffSet = mBoundingRectangleWorldCoordinates.z - ( popUpLeft + visiblePopUpSize.width ); + } + + clampedPosition.x = position.x + xOffSet; + tailOffsetPosition.x = -xOffSet; + + // Check if top left of PopUp outside of top bounding rectangle, if so then flip to lower position. + bool flipTail( false ); + + if ( popUpTop < mBoundingRectangleWorldCoordinates.y ) + { + clampedPosition.y = alternativePosition.y + visiblePopUpSize.height; + flipTail = true; + } + + mPopupPanel.GetRootActor().SetPosition( clampedPosition ); + mPopupPanel.SetTailPosition( tailOffsetPosition, flipTail ); } void TextInput::HidePopup(bool animate, bool signalFinished ) { - if ( ( mPopUpPanel.GetState() == TextInputPopup::StateShowing ) || ( mPopUpPanel.GetState() == TextInputPopup::StateShown ) ) + if ( ( mPopupPanel.GetState() == TextInputPopup::StateShowing ) || ( mPopupPanel.GetState() == TextInputPopup::StateShown ) ) { - mPopUpPanel.Hide( animate ); + mPopupPanel.Hide( animate ); if( animate && signalFinished ) { - mPopUpPanel.HideFinishedSignal().Connect( this, &TextInput::OnPopupHideFinished ); + mPopupPanel.HideFinishedSignal().Connect( this, &TextInput::OnPopupHideFinished ); } } } -void TextInput::ShowPopup(bool animate) +void TextInput::ShowPopup( bool animate ) { Vector3 position; + Vector2 alternativePopupPosition; if(mHighlightMeshActor && mState == StateEdit) { Vector3 topHandle; + Vector3 bottomHandle; // referring to the bottom most point of the handle or the bottom line of selection. Size rowSize; // When text is selected, show popup above top handle (and text), or below bottom handle. // topHandle: referring to the top most point of the handle or the top line of selection. if ( mSelectionHandleTwoActualPosition.y > mSelectionHandleOneActualPosition.y ) { topHandle = mSelectionHandleOneActualPosition; + bottomHandle = mSelectionHandleTwoActualPosition; rowSize= GetRowRectFromCharacterPosition( mSelectionHandleOnePosition ); } else { topHandle = mSelectionHandleTwoActualPosition; + bottomHandle = mSelectionHandleOneActualPosition; rowSize = GetRowRectFromCharacterPosition( mSelectionHandleTwoPosition ); } - topHandle.y += TOP_HANDLE_TOP_OFFSET - rowSize.height; + topHandle.y += -mPopupOffsetFromText.y - rowSize.height; position = Vector3(topHandle.x, topHandle.y, 0.0f); - // bottomHandle: referring to the bottom most point of the handle or the bottom line of selection. - Vector3 bottomHandle; - bottomHandle.y = std::max ( mSelectionHandleTwoActualPosition.y , mSelectionHandleOneActualPosition.y ); - bottomHandle.y += GetSelectionHandleSize().y + BOTTOM_HANDLE_BOTTOM_OFFSET; - mPopUpPanel.SetAlternativeOffset(Vector2(0.0f, bottomHandle.y - topHandle.y)); + float xPosition = ( fabsf( topHandle.x - bottomHandle.x ) )*0.5f + std::min( mSelectionHandleOneActualPosition.x , mSelectionHandleTwoActualPosition.x ); + + position.x = xPosition; + + // Alternative position if no upper space + bottomHandle.y += GetSelectionHandleSize().y + mPopupOffsetFromText.w; + alternativePopupPosition = Vector2 ( position.x, bottomHandle.y ); } else { // When no text is selected, show popup at world position of grab handle or cursor position = GetActualPositionFromCharacterPosition( mCursorPosition ); const Size rowSize = GetRowRectFromCharacterPosition( mCursorPosition ); - position.y -= rowSize.height; + position.y -= ( mPopupOffsetFromText.y + rowSize.height ); // if can't be positioned above, then position below row. - Vector2 alternativePopUpPosition( 0.0f, position.y ); // default if no grab handle + alternativePopupPosition = Vector2( position.x, position.y ); // default if no grab handle if ( mGrabHandle ) { - alternativePopUpPosition.y = rowSize.height + ( mGrabHandle.GetCurrentSize().height * DEFAULT_GRAB_HANDLE_RELATIVE_SIZE.y ) ; // If grab handle enabled then position pop-up below the grab handle. + alternativePopupPosition.y = rowSize.height + mGrabHandle.GetCurrentSize().height + mPopupOffsetFromText.w +50.0f; } - mPopUpPanel.SetAlternativeOffset( alternativePopUpPosition ); } - // reposition popup above the desired cursor posiiton. - Vector3 textViewSize = mDisplayedTextView.GetCurrentSize(); - textViewSize.z = 0.0f; - // World position = world position of ParentOrigin of cursor (i.e. top-left corner of TextView) + cursor position; - Vector3 worldPosition = mDisplayedTextView.GetCurrentWorldPosition() - (textViewSize * 0.5f) + position; - - SetPopupPosition( worldPosition ); + SetPopupPosition( position, alternativePopupPosition ); // Show popup - mPopUpPanel.Show(animate); + mPopupPanel.Show( Self(), animate ); StartMonitoringStageForTouch(); - mPopUpPanel.PressedSignal().Connect( this, &TextInput::OnPopupButtonPressed ); + mPopupPanel.PressedSignal().Connect( this, &TextInput::OnPopupButtonPressed ); } void TextInput::ShowPopupCutCopyPaste() { ClearPopup(); + + mPopupPanel.CreateOrderedListOfOptions(); // todo Move this so only run when order has changed // Check the selected text is whole text or not. if( IsTextSelected() && ( mStyledText.size() != GetSelectedText().size() ) ) { - Image selectAllIcon = Image::New( DEFAULT_ICON_SELECT_ALL ); - AddPopupOption( OPTION_SELECT_ALL, GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL"), selectAllIcon ); + mPopupPanel.TogglePopupButtonOnOff( TextInputPopup::ButtonsSelectAll, true ); } - if ( !mStyledText.empty() ) + if ( !mStyledText.empty() && IsTextSelected() ) { - Image cutIcon = Image::New( DEFAULT_ICON_CUT ); - Image copyIcon = Image::New( DEFAULT_ICON_COPY ); - AddPopupOption( OPTION_CUT, GET_LOCALE_TEXT("IDS_COM_BODY_CUT"), cutIcon ); - AddPopupOption( OPTION_COPY, GET_LOCALE_TEXT("IDS_COM_BODY_COPY"), copyIcon, true ); + mPopupPanel.TogglePopupButtonOnOff( TextInputPopup::ButtonsCopy, true ); + mPopupPanel.TogglePopupButtonOnOff( TextInputPopup::ButtonsCut, true ); } - if(mClipboard.NumberOfItems()) + if( mClipboard && mClipboard.NumberOfItems() ) { - Image pasteIcon = Image::New( DEFAULT_ICON_PASTE ); - Image clipboardIcon = Image::New( DEFAULT_ICON_CLIPBOARD ); - AddPopupOption( OPTION_PASTE, GET_LOCALE_TEXT("IDS_COM_BODY_PASTE"), pasteIcon ); - AddPopupOption( OPTION_CLIPBOARD, GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD"), clipboardIcon, true ); + mPopupPanel.TogglePopupButtonOnOff( TextInputPopup::ButtonsPaste, true ); + mPopupPanel.TogglePopupButtonOnOff( TextInputPopup::ButtonsClipboard, true ); } - mPopUpPanel.Hide(false); + AddPopupOptions(); + + mPopupPanel.Hide(false); ShowPopup(); } -void TextInput::SetUpPopUpSelection() +void TextInput::SetUpPopupSelection( bool showCutButton ) { ClearPopup(); - + mPopupPanel.CreateOrderedListOfOptions(); // todo Move this so only run when order has changed // If no text exists then don't offer to select if ( !mStyledText.empty() ) { - Image selectIcon = Image::New( DEFAULT_ICON_SELECT ); - Image selectAllIcon = Image::New( DEFAULT_ICON_SELECT_ALL ); - AddPopupOption( OPTION_SELECT_WORD, GET_LOCALE_TEXT("IDS_COM_SK_SELECT"), selectIcon ); - AddPopupOption( OPTION_SELECT_ALL, GET_LOCALE_TEXT("IDS_COM_BODY_SELECT_ALL"), selectAllIcon ); + mPopupPanel.TogglePopupButtonOnOff( TextInputPopup::ButtonsSelectAll, true ); + mPopupPanel.TogglePopupButtonOnOff( TextInputPopup::ButtonsSelect, true ); + mPopupPanel.TogglePopupButtonOnOff( TextInputPopup::ButtonsCut, ( showCutButton && IsTextSelected() ) ); } // if clipboard has valid contents then offer paste option - if( mClipboard.NumberOfItems() ) + if( mClipboard && mClipboard.NumberOfItems() ) { - Image pasteIcon = Image::New( DEFAULT_ICON_PASTE ); - Image clipboardIcon = Image::New( DEFAULT_ICON_CLIPBOARD ); - AddPopupOption( OPTION_PASTE, GET_LOCALE_TEXT("IDS_COM_BODY_PASTE"), pasteIcon, true ); - AddPopupOption( OPTION_CLIPBOARD, GET_LOCALE_TEXT("IDS_COM_BODY_CLIPBOARD"), clipboardIcon, true ); + mPopupPanel.TogglePopupButtonOnOff( TextInputPopup::ButtonsPaste, true ); + mPopupPanel.TogglePopupButtonOnOff( TextInputPopup::ButtonsClipboard, true ); } - mPopUpPanel.Hide(false); + AddPopupOptions(); + + mPopupPanel.Hide(false); } bool TextInput::ReturnClosestIndex(const Vector2& source, std::size_t& closestIndex ) @@ -3829,7 +4068,7 @@ bool TextInput::ReturnClosestIndex(const Vector2& source, std::size_t& closestIn if( fabsf( closestYdifference - currentYdifference ) < CHARACTER_THRESHOLD ) { // ignore new line character. - if( !info.mIsNewLineChar ) + if( !info.mIsNewParagraphChar ) { matchedCharacters.push_back( info ); numberOfMatchedCharacters++; @@ -3843,21 +4082,22 @@ bool TextInput::ReturnClosestIndex(const Vector2& source, std::size_t& closestIn // and check if user is touching below previous line. const Toolkit::TextView::CharacterLayoutInfo& lastInfo( mTextLayoutInfo.mCharacterLayoutInfoTable[mTextLayoutInfo.mCharacterLayoutInfoTable.size() - 1] ); - if( ( lastInfo.mIsVisible ) && ( lastInfo.mIsNewLineChar ) && ( sourceScrollOffset.y > lastInfo.mPosition.y ) ) + if( ( lastInfo.mIsVisible ) && ( lastInfo.mIsNewParagraphChar ) && ( sourceScrollOffset.y > lastInfo.mPosition.y ) ) { closestIndex = mTextLayoutInfo.mCharacterLayoutInfoTable.size(); } else { - std::vector::const_iterator it = matchedCharacters.begin(); - std::vector::const_iterator endIt = matchedCharacters.end(); + // 2 Iterate through matching list of y positions and find closest matching X position. bool matched( false ); - // 2 Iterate through matching list of y positions and find closest matching X position. - for( ; it != endIt; ++it ) + // Traverse the characters in the visual order. VCC TODO: check for more than one line. + std::size_t visualIndex = 0u; + const std::size_t matchedCharactersSize = matchedCharacters.size(); + for( ; visualIndex < matchedCharactersSize; ++visualIndex ) { - const Toolkit::TextView::CharacterLayoutInfo& info( *it ); + const Toolkit::TextView::CharacterLayoutInfo& info( *( matchedCharacters.begin() + mTextLayoutInfo.mCharacterVisualToLogicalMap[visualIndex] ) ); if( info.mIsVisible ) { @@ -3878,16 +4118,15 @@ bool TextInput::ReturnClosestIndex(const Vector2& source, std::size_t& closestIn } } - if( it == endIt ) + if( visualIndex == matchedCharactersSize ) { rightToLeftChar = lastRightToLeftChar; } - std::size_t matchCharacterIndex = it - matchedCharacters.begin(); - closestIndex = lineOffset + matchCharacterIndex; + closestIndex = lineOffset + visualIndex; mClosestCursorPositionEOL = false; // reset - if ( it == endIt && !matched ) + if( ( visualIndex == matchedCharactersSize ) && !matched ) { mClosestCursorPositionEOL = true; // Reached end of matched characters in closest line but no match so cursor should be after last character. } @@ -3954,7 +4193,7 @@ bool TextInput::ReturnClosestIndex(const Vector2& source, std::size_t& closestIn ++closestIndex; } } - else if( closestIndex == numeric_limits::max() ) // -1 RTL (after last arabic character on line) + else if( closestIndex == std::numeric_limits::max() ) // -1 RTL (after last arabic character on line) { closestIndex = mTextLayoutInfo.mCharacterVisualToLogicalMap.size(); } @@ -4026,104 +4265,132 @@ Vector3 TextInput::PositionCursorAfterWordWrap( std::size_t characterPosition ) /* Word wrap occurs automatically in TextView when the exceed policy moves a word to the next line when not enough space on current. A newline character is not inserted in this case */ - DALI_ASSERT_DEBUG( !(characterPosition <= 0 )); - Vector3 cursorPosition; - Toolkit::TextView::CharacterLayoutInfo currentCharInfo; + Toolkit::TextView::CharacterLayoutInfo currentCharInfo = mTextLayoutInfo.mCharacterLayoutInfoTable[ characterPosition ]; - if ( characterPosition == mTextLayoutInfo.mCharacterLayoutInfoTable.size() ) - { - // end character so use - currentCharInfo = mTextLayoutInfo.mCharacterLayoutInfoTable[ characterPosition - 1 ]; - cursorPosition = Vector3(currentCharInfo.mPosition.x + currentCharInfo.mSize.width, currentCharInfo.mPosition.y, currentCharInfo.mPosition.z) ; - } - else - { - currentCharInfo = mTextLayoutInfo.mCharacterLayoutInfoTable[ characterPosition ]; - } + bool noWrap = true; - Toolkit::TextView::CharacterLayoutInfo previousCharInfo = mTextLayoutInfo.mCharacterLayoutInfoTable[ characterPosition - 1]; - - // If previous character on a different line then use current characters position - if ( fabsf( (currentCharInfo.mPosition.y - currentCharInfo.mDescender ) - ( previousCharInfo.mPosition.y - previousCharInfo.mDescender) ) > Math::MACHINE_EPSILON_1000 ) + if( characterPosition > 0u ) { - if ( mClosestCursorPositionEOL ) - { - cursorPosition = Vector3(previousCharInfo.mPosition.x + previousCharInfo.mSize.width, previousCharInfo.mPosition.y, previousCharInfo.mPosition.z) ; - } - else + Toolkit::TextView::CharacterLayoutInfo previousCharInfo = mTextLayoutInfo.mCharacterLayoutInfoTable[ characterPosition - 1u ]; + + // If previous character on a different line then use current characters position + if( fabsf( (currentCharInfo.mPosition.y - currentCharInfo.mDescender ) - ( previousCharInfo.mPosition.y - previousCharInfo.mDescender) ) > Math::MACHINE_EPSILON_1000 ) { - cursorPosition = Vector3(currentCharInfo.mPosition); + // VCC TODO: PositionCursorAfterWordWrap currently doesn't work for multiline. Need to check this branch. + if ( mClosestCursorPositionEOL ) + { + cursorPosition = Vector3( previousCharInfo.mPosition.x + previousCharInfo.mSize.width, previousCharInfo.mPosition.y, previousCharInfo.mPosition.z ) ; + } + else + { + cursorPosition = Vector3( currentCharInfo.mPosition ); + } + + noWrap = false; } } - else + + if( noWrap ) { - // Previous character is on same line so use position of previous character plus it's width. - cursorPosition = Vector3(previousCharInfo.mPosition.x + previousCharInfo.mSize.width, previousCharInfo.mPosition.y, previousCharInfo.mPosition.z) ; + // If the character is left to right, the position is the character's position plus its width. + const float ltrOffset = !currentCharInfo.mIsRightToLeftCharacter ? currentCharInfo.mSize.width : 0.f; + + cursorPosition.x = currentCharInfo.mPosition.x + ltrOffset; + cursorPosition.y = currentCharInfo.mPosition.y; } return cursorPosition; } -Vector3 TextInput::GetActualPositionFromCharacterPosition(std::size_t characterPosition) const +Vector3 TextInput::GetActualPositionFromCharacterPosition( std::size_t characterPosition ) const { - bool direction(false); + bool direction = false; Vector3 alternatePosition; - bool alternatePositionValid(false); + bool alternatePositionValid = false; return GetActualPositionFromCharacterPosition( characterPosition, direction, alternatePosition, alternatePositionValid ); } -Vector3 TextInput::GetActualPositionFromCharacterPosition(std::size_t characterPosition, bool& directionRTL, Vector3& alternatePosition, bool& alternatePositionValid ) const +Vector3 TextInput::GetActualPositionFromCharacterPosition( std::size_t characterPosition, bool& directionRTL, Vector3& alternatePosition, bool& alternatePositionValid ) const { + DALI_ASSERT_DEBUG( ( mTextLayoutInfo.mCharacterLayoutInfoTable.size() == mTextLayoutInfo.mCharacterLogicalToVisualMap.size() ) && + ( mTextLayoutInfo.mCharacterLayoutInfoTable.size() == mTextLayoutInfo.mCharacterVisualToLogicalMap.size() ) && + "TextInput::GetActualPositionFromCharacterPosition. All layout tables must have the same size." ); + Vector3 cursorPosition( 0.f, 0.f, 0.f ); alternatePositionValid = false; directionRTL = false; - if( !mTextLayoutInfo.mCharacterLayoutInfoTable.empty() && !mTextLayoutInfo.mCharacterLogicalToVisualMap.empty() ) + if( !mTextLayoutInfo.mCharacterLayoutInfoTable.empty() ) { - std::size_t visualCharacterPosition; + if( characterPosition == 0u ) + { + // When the cursor position is at the beginning, it should be at the start of the current character. + // If the current character is LTR, then the start is on the right side of the glyph. + // If the current character is RTL, then the start is on the left side of the glyph. + + if( !( *( mTextLayoutInfo.mCharacterLayoutInfoTable.begin() ) ).mIsVisible ) + { + characterPosition = FindVisibleCharacter( Right, 0u ); + } + + const Toolkit::TextView::CharacterLayoutInfo& info = mTextLayoutInfo.mCharacterLayoutInfoTable[ characterPosition ]; + const float rtlOffset = info.mIsRightToLeftCharacter ? info.mSize.width : 0.0f; - // When cursor is not at beginning, consider possibility of - // showing 2 cursors. (whereas at beginning we only ever show one cursor) - if(characterPosition > 0) + cursorPosition.x = info.mPosition.x + rtlOffset; + cursorPosition.y = info.mPosition.y; + directionRTL = info.mIsRightToLeftCharacter; + } + else if( characterPosition > 0u ) { + // Get the direction of the paragraph. + const std::size_t startCharacterPosition = GetRowStartFromCharacterPosition( characterPosition ); + const bool isParagraphRightToLeft = ( *( mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + startCharacterPosition ) ).mIsRightToLeftCharacter; + + // When cursor is not at beginning, consider possibility of + // showing 2 cursors. (whereas at beginning we only ever show one cursor) + // Cursor position should be the end of the last character. // If the last character is LTR, then the end is on the right side of the glyph. // If the last character is RTL, then the end is on the left side of the glyph. - visualCharacterPosition = mTextLayoutInfo.mCharacterLogicalToVisualMap[ characterPosition - 1 ]; - if( !( *( mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + visualCharacterPosition ) ).mIsVisible ) + --characterPosition; + + if( !( *( mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + characterPosition ) ).mIsVisible ) { - visualCharacterPosition = FindVisibleCharacter( Left, visualCharacterPosition ); + characterPosition = FindVisibleCharacter( Left, characterPosition ); } - Toolkit::TextView::CharacterLayoutInfo info = mTextLayoutInfo.mCharacterLayoutInfoTable[ visualCharacterPosition ]; - if( ( visualCharacterPosition > 0 ) && info.mIsNewLineChar && !IsScrollEnabled() ) + Toolkit::TextView::CharacterLayoutInfo info = mTextLayoutInfo.mCharacterLayoutInfoTable[ characterPosition ]; + if( ( characterPosition > 0u ) && info.mIsNewParagraphChar && !IsScrollEnabled() ) { + // VCC TODO : check for a new paragraph character. + // Prevents the cursor to exceed the boundary if the last visible character is a 'new line character' and the scroll is not enabled. const Vector3& size = GetControlSize(); if( info.mPosition.y + info.mSize.height - mDisplayedTextView.GetLineHeightOffset() > size.height ) { - --visualCharacterPosition; + --characterPosition; } - info = mTextLayoutInfo.mCharacterLayoutInfoTable[ visualCharacterPosition ]; + info = mTextLayoutInfo.mCharacterLayoutInfoTable[ characterPosition ]; } - if(!info.mIsNewLineChar) + if( !info.mIsNewParagraphChar ) { cursorPosition = PositionCursorAfterWordWrap( characterPosition ); // Get position of cursor/handles taking in account auto word wrap. } else { + // VCC TODO : check for a new paragraph character. + // When cursor points to first character on new line, position cursor at the start of this glyph. - if(characterPosition < mTextLayoutInfo.mCharacterLogicalToVisualMap.size()) + if( characterPosition < mTextLayoutInfo.mCharacterLayoutInfoTable.size() ) { - std::size_t visualCharacterNextPosition = mTextLayoutInfo.mCharacterLogicalToVisualMap[ characterPosition ]; - const Toolkit::TextView::CharacterLayoutInfo& infoNext = mTextLayoutInfo.mCharacterLayoutInfoTable[ visualCharacterNextPosition ]; + const Toolkit::TextView::CharacterLayoutInfo& infoNext = mTextLayoutInfo.mCharacterLayoutInfoTable[ characterPosition ]; const float start( infoNext.mIsRightToLeftCharacter ? infoNext.mSize.width : 0.0f ); cursorPosition.x = infoNext.mPosition.x + start; @@ -4135,12 +4402,12 @@ Vector3 TextInput::GetActualPositionFromCharacterPosition(std::size_t characterP // cursor where the new line starts based on the line-justification position. cursorPosition.x = GetLineJustificationPosition(); - if(characterPosition == mTextLayoutInfo.mCharacterLogicalToVisualMap.size()) + if( characterPosition == mTextLayoutInfo.mCharacterLogicalToVisualMap.size() ) { // If this is after the last character, then we can assume that the new cursor // should be exactly one row below the current row. - const Size rowRect(GetRowRectFromCharacterPosition(characterPosition - 1)); + const Size rowRect = GetRowRectFromCharacterPosition( characterPosition - 1u ); cursorPosition.y = info.mPosition.y + rowRect.height; } else @@ -4148,7 +4415,7 @@ Vector3 TextInput::GetActualPositionFromCharacterPosition(std::size_t characterP // If this is not after last character, then we can use this row's height. // should be exactly one row below the current row. - const Size rowRect(GetRowRectFromCharacterPosition(characterPosition)); + const Size rowRect = GetRowRectFromCharacterPosition( characterPosition ); cursorPosition.y = info.mPosition.y + rowRect.height; } } @@ -4156,104 +4423,87 @@ Vector3 TextInput::GetActualPositionFromCharacterPosition(std::size_t characterP directionRTL = info.mIsRightToLeftCharacter; - // 1. When the cursor is neither at the beginning or the end, - // we can show multiple cursors under situations when the cursor is - // between RTL and LTR text... - if(characterPosition != mTextLayoutInfo.mCharacterLogicalToVisualMap.size()) + if( 1u < mTextLayoutInfo.mCharacterLayoutInfoTable.size() ) { - std::size_t visualCharacterAltPosition = mTextLayoutInfo.mCharacterLogicalToVisualMap[characterPosition] - 1; + // 1. When the cursor is neither at the beginning or the end, + // we can show multiple cursors under situations when the cursor is + // between RTL and LTR text... + if( characterPosition + 1u < mTextLayoutInfo.mCharacterLayoutInfoTable.size() ) + { + std::size_t characterAltPosition = characterPosition + 1u; - DALI_ASSERT_ALWAYS(visualCharacterAltPosition < mTextLayoutInfo.mCharacterLayoutInfoTable.size()); - const Toolkit::TextView::CharacterLayoutInfo& infoAlt = mTextLayoutInfo.mCharacterLayoutInfoTable[ visualCharacterAltPosition ]; + const Toolkit::TextView::CharacterLayoutInfo& infoAlt = mTextLayoutInfo.mCharacterLayoutInfoTable[ characterAltPosition ]; - if(!info.mIsRightToLeftCharacter && infoAlt.mIsRightToLeftCharacter) - { - // Stuation occurs when cursor is at the end of English text (LTR) and beginning of Arabic (RTL) - // Text: [...LTR...]|[...RTL...] - // Cursor pos: ^ - // Alternate cursor pos: ^ - // In which case we need to display an alternate cursor for the RTL text. - - alternatePosition.x = infoAlt.mPosition.x + infoAlt.mSize.width; - alternatePosition.y = infoAlt.mPosition.y; - alternatePositionValid = true; + if(!info.mIsRightToLeftCharacter && infoAlt.mIsRightToLeftCharacter) + { + // Stuation occurs when cursor is at the end of English text (LTR) and beginning of Arabic (RTL) + // Text: [...LTR...]|[...RTL...] + // Cursor pos: ^ + // Alternate cursor pos: ^ + // In which case we need to display an alternate cursor for the RTL text. + + alternatePosition.x = infoAlt.mPosition.x + infoAlt.mSize.width; + alternatePosition.y = infoAlt.mPosition.y; + alternatePositionValid = true; + } + else if(info.mIsRightToLeftCharacter && !infoAlt.mIsRightToLeftCharacter) + { + // Situation occurs when cursor is at end of the Arabic text (LTR) and beginning of English (RTL) + // Text: |[...RTL...] [...LTR....] + // Cursor pos: ^ + // Alternate cursor pos: ^ + // In which case we need to display an alternate cursor for the RTL text. + + alternatePosition.x = infoAlt.mPosition.x; + alternatePosition.y = infoAlt.mPosition.y; + alternatePositionValid = true; + } } - else if(info.mIsRightToLeftCharacter && !infoAlt.mIsRightToLeftCharacter) + else { - // Situation occurs when cursor is at end of the Arabic text (LTR) and beginning of English (RTL) - // Text: |[...RTL...] [...LTR....] - // Cursor pos: ^ - // Alternate cursor pos: ^ - // In which case we need to display an alternate cursor for the RTL text. - - alternatePosition.x = infoAlt.mPosition.x; - alternatePosition.y = infoAlt.mPosition.y; - alternatePositionValid = true; - } - } - else - { - // 2. When the cursor is at the end of the text, - // and we have multi-directional text, - // we can also consider showing mulitple cursors. - // The rule here is: - // If first and last characters on row are different - // Directions, then two cursors need to be displayed. - - // Get first logical glyph on row - std::size_t startCharacterPosition = GetRowStartFromCharacterPosition( characterPosition - 1 ); + // 2. When the cursor is at the end of the text, + // and we have multi-directional text, + // we can also consider showing mulitple cursors. + // The rule here is: + // If first and last characters on row are different + // Directions, then two cursors need to be displayed. + + if( info.mIsRightToLeftCharacter != isParagraphRightToLeft ) + { + // The last character's direction is differernt than the first one of current paragraph. - std::size_t visualCharacterStartPosition = mTextLayoutInfo.mCharacterLogicalToVisualMap[ startCharacterPosition ]; - const Toolkit::TextView::CharacterLayoutInfo& infoStart= mTextLayoutInfo.mCharacterLayoutInfoTable[ visualCharacterStartPosition ]; + // Get first + const Toolkit::TextView::CharacterLayoutInfo& infoStart= mTextLayoutInfo.mCharacterLayoutInfoTable[ GetFirstCharacterWithSameDirection( characterPosition ) ]; - if(info.mIsRightToLeftCharacter && !infoStart.mIsRightToLeftCharacter) - { - // For text Starting as LTR and ending as RTL. End cursor position is as follows: - // Text: [...LTR...]|[...RTL...] - // Cursor pos: ^ - // Alternate cursor pos: ^ - // In which case we need to display an alternate cursor for the RTL text, this cursor - // should be at the end of the given line. - - const Toolkit::TextView::CharacterLayoutInfo& infoAlt = mTextLayoutInfo.mCharacterLayoutInfoTable[ mTextLayoutInfo.mCharacterLayoutInfoTable.size() - 1 ]; - alternatePosition.x = infoAlt.mPosition.x + infoAlt.mSize.width; - alternatePosition.y = infoAlt.mPosition.y; - alternatePositionValid = true; - } - else if(!info.mIsRightToLeftCharacter && infoStart.mIsRightToLeftCharacter) // starting RTL - { - // For text Starting as RTL and ending as LTR. End cursor position is as follows: - // Text: |[...RTL...] [...LTR....] - // Cursor pos: ^ - // Alternate cursor pos: ^ - // In which case we need to display an alternate cursor for the RTL text. - - const Toolkit::TextView::CharacterLayoutInfo& infoAlt = mTextLayoutInfo.mCharacterLayoutInfoTable[ startCharacterPosition ]; - alternatePosition.x = infoAlt.mPosition.x; - alternatePosition.y = infoAlt.mPosition.y; - alternatePositionValid = true; + if(info.mIsRightToLeftCharacter) + { + // For text Starting as LTR and ending as RTL. End cursor position is as follows: + // Text: [...LTR...]|[...RTL...] + // Cursor pos: ^ + // Alternate cursor pos: ^ + // In which case we need to display an alternate cursor for the RTL text, this cursor + // should be at the end of the given line. + + alternatePosition.x = infoStart.mPosition.x + infoStart.mSize.width; + alternatePosition.y = infoStart.mPosition.y; + alternatePositionValid = true; + } + else if(!info.mIsRightToLeftCharacter) // starting RTL + { + // For text Starting as RTL and ending as LTR. End cursor position is as follows: + // Text: |[...RTL...] [...LTR....] + // Cursor pos: ^ + // Alternate cursor pos: ^ + // In which case we need to display an alternate cursor for the RTL text. + + alternatePosition.x = infoStart.mPosition.x; + alternatePosition.y = infoStart.mPosition.y; + alternatePositionValid = true; + } + } } } } // characterPosition > 0 - else if(characterPosition == 0) - { - // When the cursor position is at the beginning, it should be at the start of the current character. - // If the current character is LTR, then the start is on the right side of the glyph. - // If the current character is RTL, then the start is on the left side of the glyph. - visualCharacterPosition = mTextLayoutInfo.mCharacterLogicalToVisualMap[ characterPosition ]; - - if( !( *( mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + visualCharacterPosition ) ).mIsVisible ) - { - visualCharacterPosition = FindVisibleCharacter( Right, visualCharacterPosition ); - } - - const Toolkit::TextView::CharacterLayoutInfo& info = mTextLayoutInfo.mCharacterLayoutInfoTable[ visualCharacterPosition ]; - const float start(info.mIsRightToLeftCharacter ? info.mSize.width : 0.0f); - - cursorPosition.x = info.mPosition.x + start; - cursorPosition.y = info.mPosition.y; - directionRTL = info.mIsRightToLeftCharacter; - } } else { @@ -4297,6 +4547,7 @@ Vector3 TextInput::GetActualPositionFromCharacterPosition(std::size_t characterP cursorPosition.x -= mTextLayoutInfo.mScrollOffset.x; cursorPosition.y -= mTextLayoutInfo.mScrollOffset.y; + if( alternatePositionValid ) { alternatePosition.x -= mTextLayoutInfo.mScrollOffset.x; @@ -4306,14 +4557,30 @@ Vector3 TextInput::GetActualPositionFromCharacterPosition(std::size_t characterP return cursorPosition; } -std::size_t TextInput::GetRowStartFromCharacterPosition(std::size_t logicalPosition) const +std::size_t TextInput::GetRowStartFromCharacterPosition( std::size_t logicalPosition ) const { // scan string from current position to beginning of current line to note direction of line - while(logicalPosition) + while( logicalPosition ) { logicalPosition--; - std::size_t visualPosition = GetVisualPosition(logicalPosition); - if(mTextLayoutInfo.mCharacterLayoutInfoTable[visualPosition].mIsNewLineChar) + if( mTextLayoutInfo.mCharacterLayoutInfoTable[logicalPosition].mIsNewParagraphChar ) + { + logicalPosition++; + break; + } + } + + return logicalPosition; +} + +std::size_t TextInput::GetFirstCharacterWithSameDirection( std::size_t logicalPosition ) const +{ + const bool isRightToLeft = mTextLayoutInfo.mCharacterLayoutInfoTable[logicalPosition].mIsRightToLeftCharacter; + + while( logicalPosition ) + { + logicalPosition--; + if( isRightToLeft != mTextLayoutInfo.mCharacterLayoutInfoTable[logicalPosition].mIsRightToLeftCharacter ) { logicalPosition++; break; @@ -4330,7 +4597,7 @@ Size TextInput::GetRowRectFromCharacterPosition(std::size_t characterPosition) c return GetRowRectFromCharacterPosition( characterPosition, min, max ); } -Size TextInput::GetRowRectFromCharacterPosition(std::size_t characterPosition, Vector2& min, Vector2& max) const +Size TextInput::GetRowRectFromCharacterPosition( std::size_t characterPosition, Vector2& min, Vector2& max ) const { // if we have no text content, then return position 0,0 with width 0, and height the same as cursor height. if( mTextLayoutInfo.mCharacterLayoutInfoTable.empty() ) @@ -4340,85 +4607,55 @@ Size TextInput::GetRowRectFromCharacterPosition(std::size_t characterPosition, V return max; } - // TODO: This info should be readily available from text-view, we should not have to search hard for it. - Toolkit::TextView::CharacterLayoutInfoContainer::const_iterator begin = mTextLayoutInfo.mCharacterLayoutInfoTable.begin(); - Toolkit::TextView::CharacterLayoutInfoContainer::const_iterator end = mTextLayoutInfo.mCharacterLayoutInfoTable.end(); + DALI_ASSERT_DEBUG( characterPosition <= mTextLayoutInfo.mCharacterLayoutInfoTable.size() ); - // If cursor is pointing to end of line, then start from last character. - characterPosition = std::min( characterPosition, static_cast(mTextLayoutInfo.mCharacterLayoutInfoTable.size() - 1) ); + // Initializes the min and max position. + const std::size_t initialPosition = ( characterPosition == mTextLayoutInfo.mCharacterLayoutInfoTable.size() ) ? characterPosition - 1u : characterPosition; + min = ( *( mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + initialPosition ) ).mPosition.GetVectorXY(); + max = min; - Toolkit::TextView::CharacterLayoutInfoContainer::const_iterator it = mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + characterPosition; - - // 0. Find first a visible character. Draw a cursor beyound text-input bounds is not wanted. - if( !it->mIsVisible ) + bool found = false; + // 1) Find the line where the character is laid-out. + for( Toolkit::TextView::LineLayoutInfoContainer::const_iterator lineIt = mTextLayoutInfo.mLines.begin(), lineEndIt = mTextLayoutInfo.mLines.end(); + !found && ( lineIt != mTextLayoutInfo.mLines.end() ); + ++lineIt ) { - characterPosition = FindVisibleCharacter( Left, characterPosition ); - it = mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + characterPosition; - } + const Toolkit::TextView::LineLayoutInfo& lineInfo( *lineIt ); - // Scan characters left and right of cursor, stopping when end of line/string reached or - // y position greater than threshold of reference line. + // Index within the whole text to the last character of the current line. + std::size_t lastCharacterOfLine = 0u; - // 1. scan left until we reach the beginning or a different line. - Toolkit::TextView::CharacterLayoutInfoContainer::const_iterator validCharIt = it; - float referenceLine = it->mPosition.y - CHARACTER_THRESHOLD; - // min-x position is the left-most char's left (x) - // max-x position is the right-most char's right (x) - // min-y position is the minimum of all character's top (y) - // max-y position is the maximum of all character's bottom (y+height) - min.y = validCharIt->mPosition.y; - max.y = validCharIt->mPosition.y + validCharIt->mSize.y; - - while(true) - { - validCharIt = it; - min.y = std::min(min.y, validCharIt->mPosition.y); - max.y = std::max(max.y, validCharIt->mPosition.y + validCharIt->mSize.y); - - if(it == begin) + Toolkit::TextView::LineLayoutInfoContainer::const_iterator lineNextIt = lineIt + 1u; + if( lineNextIt != lineEndIt ) { - break; + lastCharacterOfLine = (*lineNextIt).mCharacterGlobalIndex - 1u; } - - --it; - - if( (it->mPosition.y < referenceLine) || - (it->mIsNewLineChar) || - (!it->mIsVisible) ) + else { - break; + lastCharacterOfLine = mTextLayoutInfo.mCharacterLayoutInfoTable.size() - 1u; } - } - - // info refers to the first character on this line. - min.x = validCharIt->mPosition.x; - - // 2. scan right until we reach end or a different line - it = mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + characterPosition; - referenceLine = it->mPosition.y + CHARACTER_THRESHOLD; - while(it != end) - { - if( (it->mPosition.y > referenceLine) || - (it->mIsNewLineChar) || - (!it->mIsVisible) ) + // Check if the given chracter position is within the line. + if( ( lineInfo.mCharacterGlobalIndex <= initialPosition ) && ( initialPosition <= lastCharacterOfLine ) ) { - break; - } + // 2) Get the row rect of all laid-out characters on the line. - validCharIt = it; - min.y = std::min(min.y, validCharIt->mPosition.y); - max.y = std::max(max.y, validCharIt->mPosition.y + validCharIt->mSize.y); - - ++it; - } + // Need to scan all characters of the line because they are in the logical position. + for( Toolkit::TextView::CharacterLayoutInfoContainer::const_iterator it = mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + lineInfo.mCharacterGlobalIndex, + endIt = mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + lastCharacterOfLine + 1u; + it != endIt; + ++it ) + { + const Toolkit::TextView::CharacterLayoutInfo& characterInfo( *it ); - DALI_ASSERT_DEBUG ( validCharIt != end && "validCharIt invalid") + min.x = std::min( min.x, characterInfo.mPosition.x ); + min.y = std::min( min.y, characterInfo.mPosition.y ); + max.x = std::max( max.x, characterInfo.mPosition.x + characterInfo.mSize.width ); + max.y = std::max( max.y, characterInfo.mPosition.y + characterInfo.mSize.height ); + } - if ( validCharIt != end ) - { - // info refers to the last character on this line. - max.x = validCharIt->mPosition.x + validCharIt->mSize.x; + found = true; + } } return Size( max.x - min.x, max.y - min.y ); @@ -4426,7 +4663,7 @@ Size TextInput::GetRowRectFromCharacterPosition(std::size_t characterPosition, V bool TextInput::WasTouchedCheck( const Actor& touchedActor ) const { - Actor popUpPanel = mPopUpPanel.GetRootActor(); + Actor popUpPanel = mPopupPanel.GetRootActor(); if ( ( touchedActor == Self() ) || ( touchedActor == popUpPanel ) ) { @@ -4467,7 +4704,7 @@ void TextInput::OnStageTouched(const TouchEvent& event) bool popUpShown( false ); - if ( ( mPopUpPanel.GetState() == TextInputPopup::StateShowing ) || ( mPopUpPanel.GetState() == TextInputPopup::StateShown ) ) + if ( ( mPopupPanel.GetState() == TextInputPopup::StateShowing ) || ( mPopupPanel.GetState() == TextInputPopup::StateShown ) ) { popUpShown = true; } @@ -4504,16 +4741,7 @@ void TextInput::SelectText(std::size_t start, std::size_t end) // When replacing highlighted text keyboard should ignore current word at cursor hence notify keyboard that the cursor is at the start of the highlight. mSelectingText = true; - mCursorPosition = std::min( start, end ); // Set cursor position to start of highlighted text. - - ImfManager imfManager = ImfManager::Get(); - if ( imfManager ) - { - imfManager.SetCursorPosition ( mCursorPosition ); - imfManager.SetSurroundingText( GetText() ); - imfManager.NotifyCursorPosition(); - } - // As the imfManager has been notified of the new cursor position we do not need to reset the pre-edit as it will be updated instead. + std::size_t selectionStartPosition = std::min( start, end ); // Hide grab handle when selecting. ShowGrabHandleAndSetVisibility( false ); @@ -4527,7 +4755,7 @@ void TextInput::SelectText(std::size_t start, std::size_t end) UpdateHighlight(); const TextStyle oldInputStyle( mInputStyle ); - mInputStyle = GetStyleAt( mCursorPosition ); // Inherit style from selected position. + mInputStyle = GetStyleAt( selectionStartPosition ); // Inherit style from selected position. if( oldInputStyle != mInputStyle ) { @@ -4602,12 +4830,12 @@ void TextInput::KeyboardStatusChanged(bool keyboardShown) ShowGrabHandleAndSetVisibility( false ); // If the keyboard is not now being shown, then hide the popup panel - mPopUpPanel.Hide( true ); + mPopupPanel.Hide( true ); } } // Removes highlight and resumes edit mode state -void TextInput::RemoveHighlight() +void TextInput::RemoveHighlight( bool hidePopup ) { DALI_LOG_INFO(gLogFilter, Debug::General, "RemoveHighlight\n"); @@ -4637,7 +4865,10 @@ void TextInput::RemoveHighlight() // NOTE: We cannot dereference mHighlightMesh, due // to a bug in how the scene-graph MeshRenderer uses the Mesh data incorrectly. - HidePopup(); + if ( hidePopup ) + { + HidePopup(); + } } mSelectionHandleOnePosition = 0; @@ -4652,7 +4883,7 @@ void TextInput::CreateHighlight() mMeshData.SetHasNormals( true ); mCustomMaterial = Material::New("CustomMaterial"); - mCustomMaterial.SetDiffuseColor( LIGHTBLUE ); + mCustomMaterial.SetDiffuseColor( mMaterialColor ); mMeshData.SetMaterial( mCustomMaterial ); @@ -4660,7 +4891,6 @@ void TextInput::CreateHighlight() mHighlightMeshActor = MeshActor::New( mHighlightMesh ); mHighlightMeshActor.SetName( "HighlightMeshActor" ); - mHighlightMeshActor.SetInheritShaderEffect( false ); mHighlightMeshActor.SetParentOrigin( ParentOrigin::TOP_LEFT ); mHighlightMeshActor.SetAnchorPoint( AnchorPoint::TOP_LEFT ); mHighlightMeshActor.SetPosition( 0.0f, 0.0f, DISPLAYED_HIGHLIGHT_Z_OFFSET ); @@ -4684,6 +4914,7 @@ bool TextInput::CopySelectedTextToClipboard() */ MarkupProcessor::StyledTextArray selectedText(mCurrentCopySelecton.begin(),mCurrentCopySelecton.end()); MarkupProcessor::GetPlainString( selectedText, stringToStore ); + bool success = mClipboard.SetItem( stringToStore ); return success; } @@ -4726,6 +4957,7 @@ void TextInput::PasteText( const Text& text ) if( update ) { CursorUpdate(); + EmitTextModified(); } if( insertedStringLength < text.GetLength() ) @@ -4791,9 +5023,10 @@ void TextInput::UpdateLineHeight() } } -std::size_t TextInput::FindVisibleCharacter( const FindVisibleCharacterDirection direction , const std::size_t cursorPosition ) const +std::size_t TextInput::FindVisibleCharacter( FindVisibleCharacterDirection direction , std::size_t cursorPosition ) const { - std::size_t position = 0; + // VCC check if we need do this in the visual order ... + std::size_t position = 0u; const std::size_t tableSize = mTextLayoutInfo.mCharacterLayoutInfoTable.size(); @@ -4803,7 +5036,7 @@ std::size_t TextInput::FindVisibleCharacter( const FindVisibleCharacterDirection { position = FindVisibleCharacterLeft( cursorPosition, mTextLayoutInfo.mCharacterLayoutInfoTable ); - if( !( *( mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + ( tableSize == position ? position - 1 : position ) ) ).mIsVisible ) + if( !( *( mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + ( tableSize == position ? position - 1u : position ) ) ).mIsVisible ) { position = FindVisibleCharacterRight( cursorPosition, mTextLayoutInfo.mCharacterLayoutInfoTable ); } @@ -4812,7 +5045,7 @@ std::size_t TextInput::FindVisibleCharacter( const FindVisibleCharacterDirection case Right: { position = FindVisibleCharacterRight( cursorPosition, mTextLayoutInfo.mCharacterLayoutInfoTable ); - if( !( *( mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + ( tableSize == position ? position - 1 : position ) ) ).mIsVisible ) + if( !( *( mTextLayoutInfo.mCharacterLayoutInfoTable.begin() + ( tableSize == position ? position - 1u : position ) ) ).mIsVisible ) { position = FindVisibleCharacterLeft( cursorPosition, mTextLayoutInfo.mCharacterLayoutInfoTable ); } @@ -4820,7 +5053,7 @@ std::size_t TextInput::FindVisibleCharacter( const FindVisibleCharacterDirection } case ByEnd: { - position = FindVisibleCharacterLeft( 0, mTextLayoutInfo.mCharacterLayoutInfoTable ); + position = FindVisibleCharacterLeft( 0u, mTextLayoutInfo.mCharacterLayoutInfoTable ); break; } default: @@ -5054,9 +5287,8 @@ std::size_t TextInput::DoInsertAt( const Text& text, const std::size_t position, if( textToInsert.empty() && emptyTextView ) { // No character has been added and the text-view was empty. - // Set the placeholder text. - mDisplayedTextView.SetText( mStyledPlaceHolderText ); - mPlaceHolderSet = true; + // Show the placeholder text. + ShowPlaceholderText( mStyledPlaceHolderText ); } else { @@ -5089,21 +5321,227 @@ void TextInput::GetTextLayoutInfo() } } +void TextInput::SetOffsetFromText( const Vector4& offset ) +{ + mPopupOffsetFromText = offset; +} + +const Vector4& TextInput::GetOffsetFromText() const +{ + return mPopupOffsetFromText; +} + +void TextInput::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value ) +{ + Toolkit::TextInput textInput = Toolkit::TextInput::DownCast( Dali::BaseHandle( object ) ); + + if ( textInput ) + { + TextInput& textInputImpl( GetImpl( textInput ) ); + + switch ( propertyIndex ) + { + case Toolkit::TextInput::HIGHLIGHT_COLOR_PROPERTY: + { + textInputImpl.SetMaterialDiffuseColor( value.Get< Vector4 >() ); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_COLOR_PROPERTY: + { + textInputImpl.mPopupPanel.SetCutPastePopupColor( value.Get< Vector4 >() ); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_PRESSED_COLOR_PROPERTY: + { + textInputImpl.mPopupPanel.SetCutPastePopupPressedColor( value.Get< Vector4 >() ); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_BORDER_COLOR_PROPERTY: + { + textInputImpl.mPopupPanel.SetCutPastePopupBorderColor( value.Get< Vector4 >() ); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_ICON_COLOR_PROPERTY: + { + textInputImpl.mPopupPanel.SetCutPastePopupIconColor( value.Get< Vector4 >() ); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_ICON_PRESSED_COLOR_PROPERTY: + { + textInputImpl.mPopupPanel.SetCutPastePopupIconPressedColor( value.Get< Vector4 >() ); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_TEXT_COLOR_PROPERTY: + { + textInputImpl.mPopupPanel.SetCutPastePopupTextColor( value.Get< Vector4 >() ); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_TEXT_PRESSED_COLOR_PROPERTY: + { + textInputImpl.mPopupPanel.SetCutPastePopupTextPressedColor( value.Get< Vector4 >() ); + break; + } + case Toolkit::TextInput::CUT_BUTTON_POSITION_PRIORITY_PROPERTY: + { + textInputImpl.mPopupPanel.SetButtonPriorityPosition( TextInputPopup::ButtonsCut, value.Get() ); + break; + } + case Toolkit::TextInput::COPY_BUTTON_POSITION_PRIORITY_PROPERTY: + { + textInputImpl.mPopupPanel.SetButtonPriorityPosition( TextInputPopup::ButtonsCopy, value.Get() ); + break; + } + case Toolkit::TextInput::PASTE_BUTTON_POSITION_PRIORITY_PROPERTY: + { + textInputImpl.mPopupPanel.SetButtonPriorityPosition( TextInputPopup::ButtonsPaste, value.Get() ); + break; + } + case Toolkit::TextInput::SELECT_BUTTON_POSITION_PRIORITY_PROPERTY: + { + textInputImpl.mPopupPanel.SetButtonPriorityPosition( TextInputPopup::ButtonsSelect, value.Get() ); + break; + } + case Toolkit::TextInput::SELECT_ALL_BUTTON_POSITION_PRIORITY_PROPERTY: + { + textInputImpl.mPopupPanel.SetButtonPriorityPosition( TextInputPopup::ButtonsSelectAll, value.Get() ); + break; + } + case Toolkit::TextInput::CLIPBOARD_BUTTON_POSITION_PRIORITY_PROPERTY: + { + textInputImpl.mPopupPanel.SetButtonPriorityPosition( TextInputPopup::ButtonsClipboard, value.Get() ); + break; + } + case Toolkit::TextInput::POP_UP_OFFSET_FROM_TEXT_PROPERTY: + { + textInputImpl.SetOffsetFromText( value.Get< Vector4 >() ); + break; + } + case Toolkit::TextInput::CURSOR_COLOR_PROPERTY: + { + textInputImpl.mCursor.SetColor( value.Get< Vector4 >() ); + } + } + } +} + +Property::Value TextInput::GetProperty( BaseObject* object, Property::Index propertyIndex ) +{ + Property::Value value; + + Toolkit::TextInput textInput = Toolkit::TextInput::DownCast( Dali::BaseHandle( object ) ); + + if ( textInput ) + { + TextInput& textInputImpl( GetImpl( textInput ) ); + + switch ( propertyIndex ) + { + case Toolkit::TextInput::HIGHLIGHT_COLOR_PROPERTY: + { + value = textInputImpl.GetMaterialDiffuseColor(); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_COLOR_PROPERTY: + { + value = textInputImpl.mPopupPanel.GetCutPastePopupColor(); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_PRESSED_COLOR_PROPERTY: + { + value = textInputImpl.mPopupPanel.GetCutPastePopupPressedColor(); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_BORDER_COLOR_PROPERTY : + { + value = textInputImpl.mPopupPanel.GetCutPastePopupBorderColor(); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_ICON_COLOR_PROPERTY: + { + value = textInputImpl.mPopupPanel.GetCutPastePopupIconColor(); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_ICON_PRESSED_COLOR_PROPERTY: + { + value = textInputImpl.mPopupPanel.GetCutPastePopupIconPressedColor(); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_TEXT_COLOR_PROPERTY: + { + value = textInputImpl.mPopupPanel.GetCutPastePopupTextColor(); + break; + } + case Toolkit::TextInput::CUT_AND_PASTE_TEXT_PRESSED_COLOR_PROPERTY: + { + value = textInputImpl.mPopupPanel.GetCutPastePopupTextPressedColor(); + break; + } + case Toolkit::TextInput::CUT_BUTTON_POSITION_PRIORITY_PROPERTY: + { + value = textInputImpl.mPopupPanel.GetButtonPriorityPosition( TextInputPopup::ButtonsCut ); + break; + } + case Toolkit::TextInput::COPY_BUTTON_POSITION_PRIORITY_PROPERTY: + { + value = textInputImpl.mPopupPanel.GetButtonPriorityPosition( TextInputPopup::ButtonsCopy ); + break; + } + case Toolkit::TextInput::PASTE_BUTTON_POSITION_PRIORITY_PROPERTY: + { + value = textInputImpl.mPopupPanel.GetButtonPriorityPosition( TextInputPopup::ButtonsPaste ); + break; + } + case Toolkit::TextInput::SELECT_BUTTON_POSITION_PRIORITY_PROPERTY: + { + value = textInputImpl.mPopupPanel.GetButtonPriorityPosition( TextInputPopup::ButtonsSelect ); + break; + } + case Toolkit::TextInput::SELECT_ALL_BUTTON_POSITION_PRIORITY_PROPERTY: + { + value = textInputImpl.mPopupPanel.GetButtonPriorityPosition( TextInputPopup::ButtonsSelectAll ); + break; + } + case Toolkit::TextInput::CLIPBOARD_BUTTON_POSITION_PRIORITY_PROPERTY: + { + value = textInputImpl.mPopupPanel.GetButtonPriorityPosition( TextInputPopup::ButtonsClipboard ); + break; + } + case Toolkit::TextInput::POP_UP_OFFSET_FROM_TEXT_PROPERTY: + { + value = textInputImpl.GetOffsetFromText(); + break; + } + case Toolkit::TextInput::CURSOR_COLOR_PROPERTY: + { + value = textInputImpl.mCursor.GetCurrentColor(); + } + } + } + return value; +} + void TextInput::EmitStyleChangedSignal() { // emit signal if input style changes. + Toolkit::TextInput handle( GetOwner() ); + mStyleChangedSignal.Emit( handle, mInputStyle ); +} +void TextInput::EmitTextModified() +{ + // emit signal when text changes. Toolkit::TextInput handle( GetOwner() ); - mStyleChangedSignalV2.Emit( handle, mInputStyle ); + mTextModifiedSignal.Emit( handle ); } + void TextInput::EmitMaxInputCharactersReachedSignal() { // emit signal if max characters is reached during text input. DALI_LOG_INFO(gLogFilter, Debug::General, "EmitMaxInputCharactersReachedSignal \n"); Toolkit::TextInput handle( GetOwner() ); - mMaxInputCharactersReachedSignalV2.Emit( handle ); + mMaxInputCharactersReachedSignal.Emit( handle ); } void TextInput::EmitInputTextExceedsBoundariesSignal() @@ -5111,7 +5549,7 @@ void TextInput::EmitInputTextExceedsBoundariesSignal() // Emit a signal when the input text exceeds the boundaries of the text input. Toolkit::TextInput handle( GetOwner() ); - mInputTextExceedBoundariesSignalV2.Emit( handle ); + mInputTextExceedBoundariesSignal.Emit( handle ); } } // namespace Internal