From dfd3018cbcc4e2a9c61b3cd165a0bd9b538b9d0c Mon Sep 17 00:00:00 2001 From: Adeel Kazmi Date: Wed, 2 Dec 2020 18:34:33 +0000 Subject: [PATCH] (TextController) Refactored out Text updating methods & moved another method to the Relayouter Change-Id: I9a3e48c86f593a05fceda2bd29f9d9d72e1c4dc4 --- dali-toolkit/internal/file.list | 1 + .../internal/text/text-controller-relayouter.cpp | 58 ++ .../internal/text/text-controller-relayouter.h | 8 + .../internal/text/text-controller-text-updater.cpp | 632 +++++++++++++++++++++ .../internal/text/text-controller-text-updater.h | 73 +++ dali-toolkit/internal/text/text-controller.cpp | 578 +------------------ dali-toolkit/internal/text/text-controller.h | 1 + 7 files changed, 781 insertions(+), 570 deletions(-) create mode 100644 dali-toolkit/internal/text/text-controller-text-updater.cpp create mode 100644 dali-toolkit/internal/text/text-controller-text-updater.h diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index b57fd97..0081833 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -146,6 +146,7 @@ SET( toolkit_src_files ${toolkit_src_dir}/text/text-controller-input-font-handler.cpp ${toolkit_src_dir}/text/text-controller-placeholder-handler.cpp ${toolkit_src_dir}/text/text-controller-relayouter.cpp + ${toolkit_src_dir}/text/text-controller-text-updater.cpp ${toolkit_src_dir}/text/text-effects-style.cpp ${toolkit_src_dir}/text/text-font-style.cpp ${toolkit_src_dir}/text/text-io.cpp diff --git a/dali-toolkit/internal/text/text-controller-relayouter.cpp b/dali-toolkit/internal/text/text-controller-relayouter.cpp index 63aa2ad..fa71759 100644 --- a/dali-toolkit/internal/text/text-controller-relayouter.cpp +++ b/dali-toolkit/internal/text/text-controller-relayouter.cpp @@ -174,6 +174,64 @@ bool Controller::Relayouter::CheckForTextFit(Controller& controller, float point return true; } +void Controller::Relayouter::FitPointSizeforLayout(Controller& controller, const Size& layoutSize) +{ + Controller::Impl& impl = *controller.mImpl; + + const OperationsMask operations = impl.mOperationsPending; + if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) || impl.mTextFitContentSize != layoutSize ) + { + ModelPtr& model = impl.mModel; + + bool actualellipsis = model->mElideEnabled; + float minPointSize = impl.mTextFitMinSize; + float maxPointSize = impl.mTextFitMaxSize; + float pointInterval = impl.mTextFitStepSize; + + model->mElideEnabled = false; + Vector pointSizeArray; + + // check zero value + if( pointInterval < 1.f ) + { + impl.mTextFitStepSize = pointInterval = 1.0f; + } + + pointSizeArray.Reserve( static_cast< unsigned int >( ceil( ( maxPointSize - minPointSize ) / pointInterval ) ) ); + + for( float i = minPointSize; i < maxPointSize; i += pointInterval ) + { + pointSizeArray.PushBack( i ); + } + + pointSizeArray.PushBack( maxPointSize ); + + int bestSizeIndex = 0; + int min = bestSizeIndex + 1; + int max = pointSizeArray.Size() - 1; + while( min <= max ) + { + int destI = ( min + max ) / 2; + + if( CheckForTextFit( controller, pointSizeArray[destI], layoutSize ) ) + { + bestSizeIndex = min; + min = destI + 1; + } + else + { + max = destI - 1; + bestSizeIndex = max; + } + } + + model->mElideEnabled = actualellipsis; + impl.mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex]; + impl.mFontDefaults->sizeDefined = true; + controller.ClearFontData(); + } +} + float Controller::Relayouter::GetHeightForWidth(Controller& controller, float width) { DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", &controller, width ); diff --git a/dali-toolkit/internal/text/text-controller-relayouter.h b/dali-toolkit/internal/text/text-controller-relayouter.h index cfb7e83..4c62d89 100644 --- a/dali-toolkit/internal/text/text-controller-relayouter.h +++ b/dali-toolkit/internal/text/text-controller-relayouter.h @@ -59,6 +59,14 @@ struct Controller::Relayouter static bool CheckForTextFit(Controller& controller, float pointSize, const Size& layoutSize); /** + * @brief Calculates the point size for text for given layout() + * + * @param[in] controller A reference to the controller class + * @param[in] layoutSize The layout size + */ + static void FitPointSizeforLayout(Controller& controller, const Size& layoutSize); + + /** * @brief Called by the Controller to get the height for a particular width. * * @param[in] controller A reference to the controller class diff --git a/dali-toolkit/internal/text/text-controller-text-updater.cpp b/dali-toolkit/internal/text/text-controller-text-updater.cpp new file mode 100644 index 0000000..cd3f755 --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-text-updater.cpp @@ -0,0 +1,632 @@ +/* + * Copyright (c) 2020 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 + +// EXTERNAL INCLUDES +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include +#include + +namespace +{ + +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); +#endif + +} // namespace + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +void Controller::TextUpdater::SetText(Controller& controller, const std::string& text) +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" ); + + Controller::Impl& impl = *controller.mImpl; + + // Reset keyboard as text changed + impl.ResetInputMethodContext(); + + // Remove the previously set text and style. + ResetText(controller); + + // Remove the style. + controller.ClearStyleData(); + + CharacterIndex lastCursorIndex = 0u; + + EventData*& eventData = impl.mEventData; + + if( nullptr != eventData ) + { + // If popup shown then hide it by switching to Editing state + if( ( EventData::SELECTING == eventData->mState ) || + ( EventData::EDITING_WITH_POPUP == eventData->mState ) || + ( EventData::EDITING_WITH_GRAB_HANDLE == eventData->mState ) || + ( EventData::EDITING_WITH_PASTE_POPUP == eventData->mState ) ) + { + impl.ChangeState( EventData::EDITING ); + } + } + + if( !text.empty() ) + { + ModelPtr& model = impl.mModel; + LogicalModelPtr& logicalModel = model->mLogicalModel; + model->mVisualModel->SetTextColor( impl.mTextColor ); + + MarkupProcessData markupProcessData( logicalModel->mColorRuns, + logicalModel->mFontDescriptionRuns, + logicalModel->mEmbeddedItems ); + + Length textSize = 0u; + const uint8_t* utf8 = NULL; + if( impl.mMarkupProcessorEnabled ) + { + ProcessMarkupString( text, markupProcessData ); + textSize = markupProcessData.markupProcessedText.size(); + + // This is a bit horrible but std::string returns a (signed) char* + utf8 = reinterpret_cast( markupProcessData.markupProcessedText.c_str() ); + } + else + { + textSize = text.size(); + + // This is a bit horrible but std::string returns a (signed) char* + utf8 = reinterpret_cast( text.c_str() ); + } + + // Convert text into UTF-32 + Vector& utf32Characters = logicalModel->mText; + utf32Characters.Resize( textSize ); + + // Transform a text array encoded in utf8 into an array encoded in utf32. + // It returns the actual number of characters. + Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() ); + utf32Characters.Resize( characterCount ); + + DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", &controller, textSize, logicalModel->mText.Count() ); + + // The characters to be added. + impl.mTextUpdateInfo.mNumberOfCharactersToAdd = logicalModel->mText.Count(); + + // To reset the cursor position + lastCursorIndex = characterCount; + + // Update the rest of the model during size negotiation + impl.QueueModifyEvent( ModifyEvent::TEXT_REPLACED ); + + // The natural size needs to be re-calculated. + impl.mRecalculateNaturalSize = true; + + // The text direction needs to be updated. + impl.mUpdateTextDirection = true; + + // Apply modifications to the model + impl.mOperationsPending = ALL_OPERATIONS; + } + else + { + controller.ShowPlaceholderText(); + } + + // Resets the cursor position. + controller.ResetCursorPosition( lastCursorIndex ); + + // Scrolls the text to make the cursor visible. + controller.ResetScrollPosition(); + + impl.RequestRelayout(); + + if( nullptr != eventData ) + { + // Cancel previously queued events + eventData->mEventQueue.clear(); + } + + // Do this last since it provides callbacks into application code. + if( NULL != impl.mEditableControlInterface ) + { + impl.mEditableControlInterface->TextChanged(); + } +} + +void Controller::TextUpdater::InsertText(Controller& controller, const std::string& text, Controller::InsertType type) +{ + Controller::Impl& impl = *controller.mImpl; + EventData*& eventData = impl.mEventData; + + DALI_ASSERT_DEBUG( nullptr != eventData && "Unexpected InsertText" ) + + if( NULL == eventData ) + { + return; + } + + bool removedPrevious = false; + bool removedSelected = false; + bool maxLengthReached = false; + + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n", + &controller, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"), + eventData->mPrimaryCursorPosition, eventData->mPreEditFlag, eventData->mPreEditStartPosition, eventData->mPreEditLength ); + + ModelPtr& model = impl.mModel; + LogicalModelPtr& logicalModel = model->mLogicalModel; + + // TODO: At the moment the underline runs are only for pre-edit. + model->mVisualModel->mUnderlineRuns.Clear(); + + // Remove the previous InputMethodContext pre-edit. + if( eventData->mPreEditFlag && ( 0u != eventData->mPreEditLength ) ) + { + removedPrevious = RemoveText( controller, + -static_cast( eventData->mPrimaryCursorPosition - eventData->mPreEditStartPosition ), + eventData->mPreEditLength, + DONT_UPDATE_INPUT_STYLE ); + + eventData->mPrimaryCursorPosition = eventData->mPreEditStartPosition; + eventData->mPreEditLength = 0u; + } + else + { + // Remove the previous Selection. + removedSelected = RemoveSelectedText(controller); + + } + + Vector utf32Characters; + Length characterCount = 0u; + + if( !text.empty() ) + { + // Convert text into UTF-32 + utf32Characters.Resize( text.size() ); + + // This is a bit horrible but std::string returns a (signed) char* + const uint8_t* utf8 = reinterpret_cast( text.c_str() ); + + // Transform a text array encoded in utf8 into an array encoded in utf32. + // It returns the actual number of characters. + characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() ); + utf32Characters.Resize( characterCount ); + + DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" ); + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() ); + } + + if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded + { + // The placeholder text is no longer needed + if( impl.IsShowingPlaceholderText() ) + { + ResetText(controller); + } + + impl.ChangeState( EventData::EDITING ); + + // Handle the InputMethodContext (predicitive text) state changes + if( COMMIT == type ) + { + // InputMethodContext is no longer handling key-events + impl.ClearPreEditFlag(); + } + else // PRE_EDIT + { + if( !eventData->mPreEditFlag ) + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" ); + + // Record the start of the pre-edit text + eventData->mPreEditStartPosition = eventData->mPrimaryCursorPosition; + } + + eventData->mPreEditLength = utf32Characters.Count(); + eventData->mPreEditFlag = true; + + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", eventData->mPreEditStartPosition, eventData->mPreEditLength ); + } + + const Length numberOfCharactersInModel = logicalModel->mText.Count(); + + // Restrict new text to fit within Maximum characters setting. + Length maxSizeOfNewText = std::min( ( impl.mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount ); + maxLengthReached = ( characterCount > maxSizeOfNewText ); + + // The cursor position. + CharacterIndex& cursorIndex = eventData->mPrimaryCursorPosition; + + // Update the text's style. + + // Updates the text style runs by adding characters. + logicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText ); + + // Get the character index from the cursor index. + const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u; + + // Retrieve the text's style for the given index. + InputStyle style; + impl.RetrieveDefaultInputStyle( style ); + logicalModel->RetrieveStyle( styleIndex, style ); + + InputStyle& inputStyle = eventData->mInputStyle; + + // Whether to add a new text color run. + const bool addColorRun = ( style.textColor != inputStyle.textColor ) && !inputStyle.isDefaultColor; + + // Whether to add a new font run. + const bool addFontNameRun = ( style.familyName != inputStyle.familyName ) && inputStyle.isFamilyDefined; + const bool addFontWeightRun = ( style.weight != inputStyle.weight ) && inputStyle.isWeightDefined; + const bool addFontWidthRun = ( style.width != inputStyle.width ) && inputStyle.isWidthDefined; + const bool addFontSlantRun = ( style.slant != inputStyle.slant ) && inputStyle.isSlantDefined; + const bool addFontSizeRun = ( style.size != inputStyle.size ) && inputStyle.isSizeDefined ; + + // Add style runs. + if( addColorRun ) + { + const VectorBase::SizeType numberOfRuns = logicalModel->mColorRuns.Count(); + logicalModel->mColorRuns.Resize( numberOfRuns + 1u ); + + ColorRun& colorRun = *( logicalModel->mColorRuns.Begin() + numberOfRuns ); + colorRun.color = inputStyle.textColor; + colorRun.characterRun.characterIndex = cursorIndex; + colorRun.characterRun.numberOfCharacters = maxSizeOfNewText; + } + + if( addFontNameRun || + addFontWeightRun || + addFontWidthRun || + addFontSlantRun || + addFontSizeRun ) + { + const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count(); + logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u ); + + FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns ); + + if( addFontNameRun ) + { + fontDescriptionRun.familyLength = inputStyle.familyName.size(); + fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength]; + memcpy( fontDescriptionRun.familyName, inputStyle.familyName.c_str(), fontDescriptionRun.familyLength ); + fontDescriptionRun.familyDefined = true; + + // The memory allocated for the font family name is freed when the font description is removed from the logical model. + } + + if( addFontWeightRun ) + { + fontDescriptionRun.weight = inputStyle.weight; + fontDescriptionRun.weightDefined = true; + } + + if( addFontWidthRun ) + { + fontDescriptionRun.width = inputStyle.width; + fontDescriptionRun.widthDefined = true; + } + + if( addFontSlantRun ) + { + fontDescriptionRun.slant = inputStyle.slant; + fontDescriptionRun.slantDefined = true; + } + + if( addFontSizeRun ) + { + fontDescriptionRun.size = static_cast( inputStyle.size * impl.mFontSizeScale * 64.f ); + fontDescriptionRun.sizeDefined = true; + } + + fontDescriptionRun.characterRun.characterIndex = cursorIndex; + fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText; + } + + // Insert at current cursor position. + Vector& modifyText = logicalModel->mText; + + auto pos = modifyText.End(); + if( cursorIndex < numberOfCharactersInModel ) + { + pos = modifyText.Begin() + cursorIndex; + } + unsigned int realPos = pos - modifyText.Begin(); + modifyText.Insert( pos, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText ); + + if( NULL != impl.mEditableControlInterface ) + { + impl.mEditableControlInterface->TextInserted( realPos, maxSizeOfNewText, text ); + } + + TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo; + + // Mark the first paragraph to be updated. + if( Layout::Engine::SINGLE_LINE_BOX == impl.mLayoutEngine.GetLayout() ) + { + textUpdateInfo.mCharacterIndex = 0; + textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters; + textUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText; + textUpdateInfo.mClearAll = true; + } + else + { + textUpdateInfo.mCharacterIndex = std::min( cursorIndex, textUpdateInfo.mCharacterIndex ); + textUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText; + } + + // Update the cursor index. + cursorIndex += maxSizeOfNewText; + + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, logicalModel->mText.Count(), eventData->mPrimaryCursorPosition ); + } + + if( ( 0u == logicalModel->mText.Count() ) && + impl.IsPlaceholderAvailable() ) + { + // Show place-holder if empty after removing the pre-edit text + controller.ShowPlaceholderText(); + eventData->mUpdateCursorPosition = true; + impl.ClearPreEditFlag(); + } + else if( removedPrevious || + removedSelected || + ( 0 != utf32Characters.Count() ) ) + { + // Queue an inserted event + impl.QueueModifyEvent( ModifyEvent::TEXT_INSERTED ); + + eventData->mUpdateCursorPosition = true; + if( removedSelected ) + { + eventData->mScrollAfterDelete = true; + } + else + { + eventData->mScrollAfterUpdatePosition = true; + } + } + + if( maxLengthReached ) + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", logicalModel->mText.Count() ); + + impl.ResetInputMethodContext(); + + if( NULL != impl.mEditableControlInterface ) + { + // Do this last since it provides callbacks into application code + impl.mEditableControlInterface->MaxLengthReached(); + } + } +} + +void Controller::TextUpdater::PasteText(Controller& controller, const std::string& stringToPaste) +{ + InsertText( controller, stringToPaste, Text::Controller::COMMIT ); + Controller::Impl& impl = *controller.mImpl; + impl.ChangeState( EventData::EDITING ); + impl.RequestRelayout(); + + if( NULL != impl.mEditableControlInterface ) + { + // Do this last since it provides callbacks into application code + impl.mEditableControlInterface->TextChanged(); + } +} + +bool Controller::TextUpdater::RemoveText( + Controller& controller, + int cursorOffset, + int numberOfCharacters, + UpdateInputStyleType type ) +{ + bool removed = false; + + Controller::Impl& impl = *controller.mImpl; + EventData*& eventData = impl.mEventData; + + if( nullptr == eventData ) + { + return removed; + } + + ModelPtr& model = impl.mModel; + LogicalModelPtr& logicalModel = model->mLogicalModel; + + DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n", + &controller, logicalModel->mText.Count(), eventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters ); + + if( !impl.IsShowingPlaceholderText() ) + { + // Delete at current cursor position + Vector& currentText = logicalModel->mText; + CharacterIndex& oldCursorIndex = eventData->mPrimaryCursorPosition; + + CharacterIndex cursorIndex = 0; + + // Validate the cursor position & number of characters + if( ( static_cast< int >( eventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 ) + { + cursorIndex = eventData->mPrimaryCursorPosition + cursorOffset; + } + + if( ( cursorIndex + numberOfCharacters ) > currentText.Count() ) + { + numberOfCharacters = currentText.Count() - cursorIndex; + } + + TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo; + + if( eventData->mPreEditFlag || // If the preedit flag is enabled, it means two (or more) of them came together i.e. when two keys have been pressed at the same time. + ( ( cursorIndex + numberOfCharacters ) <= textUpdateInfo.mPreviousNumberOfCharacters ) ) + { + // Mark the paragraphs to be updated. + if( Layout::Engine::SINGLE_LINE_BOX == impl.mLayoutEngine.GetLayout() ) + { + textUpdateInfo.mCharacterIndex = 0; + textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters; + textUpdateInfo.mNumberOfCharactersToAdd = textUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters; + textUpdateInfo.mClearAll = true; + } + else + { + textUpdateInfo.mCharacterIndex = std::min( cursorIndex, textUpdateInfo.mCharacterIndex ); + textUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters; + } + + // Update the input style and remove the text's style before removing the text. + + if( UPDATE_INPUT_STYLE == type ) + { + InputStyle& eventDataInputStyle = eventData->mInputStyle; + + // Keep a copy of the current input style. + InputStyle currentInputStyle; + currentInputStyle.Copy( eventDataInputStyle ); + + // Set first the default input style. + impl.RetrieveDefaultInputStyle( eventDataInputStyle ); + + // Update the input style. + logicalModel->RetrieveStyle( cursorIndex, eventDataInputStyle ); + + // Compare if the input style has changed. + const bool hasInputStyleChanged = !currentInputStyle.Equal( eventDataInputStyle ); + + if( hasInputStyleChanged ) + { + const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( eventDataInputStyle ); + // Queue the input style changed signal. + eventData->mInputStyleChangedQueue.PushBack( styleChangedMask ); + } + } + + // If the number of current text and the number of characters to be deleted are same, + // it means all texts should be removed and all Preedit variables should be initialized. + if( ( currentText.Count() - numberOfCharacters == 0 ) && ( cursorIndex == 0 ) ) + { + impl.ClearPreEditFlag(); + textUpdateInfo.mNumberOfCharactersToAdd = 0; + } + + // Updates the text style runs by removing characters. Runs with no characters are removed. + logicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters ); + + // Remove the characters. + Vector::Iterator first = currentText.Begin() + cursorIndex; + Vector::Iterator last = first + numberOfCharacters; + + if( NULL != impl.mEditableControlInterface ) + { + std::string utf8; + Utf32ToUtf8( first, numberOfCharacters, utf8 ); + impl.mEditableControlInterface->TextDeleted( cursorIndex, numberOfCharacters, utf8 ); + } + + currentText.Erase( first, last ); + + // Cursor position retreat + oldCursorIndex = cursorIndex; + + eventData->mScrollAfterDelete = true; + + if( EventData::INACTIVE == eventData->mState ) + { + impl.ChangeState( EventData::EDITING ); + } + + DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", &controller, numberOfCharacters ); + removed = true; + } + } + + return removed; +} + +bool Controller::TextUpdater::RemoveSelectedText(Controller& controller) +{ + bool textRemoved( false ); + + Controller::Impl& impl = *controller.mImpl; + + if( EventData::SELECTING == impl.mEventData->mState ) + { + std::string removedString; + impl.RetrieveSelection( removedString, true ); + + if( !removedString.empty() ) + { + textRemoved = true; + impl.ChangeState( EventData::EDITING ); + } + } + + return textRemoved; +} + +void Controller::TextUpdater::ResetText(Controller& controller) +{ + Controller::Impl& impl = *controller.mImpl; + LogicalModelPtr& logicalModel = impl.mModel->mLogicalModel; + + // Reset buffers. + logicalModel->mText.Clear(); + + // Reset the embedded images buffer. + logicalModel->ClearEmbeddedImages(); + + // We have cleared everything including the placeholder-text + impl.PlaceholderCleared(); + + impl.mTextUpdateInfo.mCharacterIndex = 0u; + impl.mTextUpdateInfo.mNumberOfCharactersToRemove = impl.mTextUpdateInfo.mPreviousNumberOfCharacters; + impl.mTextUpdateInfo.mNumberOfCharactersToAdd = 0u; + + // Clear any previous text. + impl.mTextUpdateInfo.mClearAll = true; + + // The natural size needs to be re-calculated. + impl.mRecalculateNaturalSize = true; + + // The text direction needs to be updated. + impl.mUpdateTextDirection = true; + + // Apply modifications to the model + impl.mOperationsPending = ALL_OPERATIONS; +} + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/text/text-controller-text-updater.h b/dali-toolkit/internal/text/text-controller-text-updater.h new file mode 100644 index 0000000..147ccb9 --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-text-updater.h @@ -0,0 +1,73 @@ +#ifndef DALI_TOOLKIT_TEXT_UPDATER_H +#define DALI_TOOLKIT_TEXT_UPDATER_H + +/* + * Copyright (c) 2020 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. + * + */ + + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +/** + * @brief Methods that update the text + */ +struct Controller::TextUpdater +{ + /// @copydoc Text::Contoller::SetText + /// @param[in] controller The controller + static void SetText(Controller& controller, const std::string& text); + + /// @copydoc Text::Contoller::InsertText + /// @param[in] controller The controller + static void InsertText(Controller& controller, const std::string& text, Controller::InsertType type); + + /// @copydoc Text::Contoller::PasteText + /// @param[in] controller The controller + static void PasteText(Controller& controller, const std::string& stringToPaste); + + /// @copydoc Text::Contoller::RemoveText + /// @param[in] controller The controller + static bool RemoveText(Controller& controller, int cursorOffset, int numberOfCharacters, UpdateInputStyleType type); + + /// @copydoc Text::Contoller::RemoveSelectedText + /// @param[in] controller The controller + static bool RemoveSelectedText(Controller& controller); + + /// @copydoc Text::Contoller::ResetText + /// @param[in] controller The controller + static void ResetText(Controller& controller); +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_UPDATER_H diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 0fd084c..bcff10f 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -25,13 +25,12 @@ #include // INTERNAL INCLUDES -#include -#include #include #include #include #include #include +#include #include namespace @@ -582,111 +581,7 @@ bool Controller::IsGrabHandlePopupEnabled() const void Controller::SetText( const std::string& text ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText\n" ); - - // Reset keyboard as text changed - mImpl->ResetInputMethodContext(); - - // Remove the previously set text and style. - ResetText(); - - // Remove the style. - ClearStyleData(); - - CharacterIndex lastCursorIndex = 0u; - - if( NULL != mImpl->mEventData ) - { - // If popup shown then hide it by switching to Editing state - if( ( EventData::SELECTING == mImpl->mEventData->mState ) || - ( EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState ) || - ( EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState ) || - ( EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState ) ) - { - mImpl->ChangeState( EventData::EDITING ); - } - } - - if( !text.empty() ) - { - mImpl->mModel->mVisualModel->SetTextColor( mImpl->mTextColor ); - - MarkupProcessData markupProcessData( mImpl->mModel->mLogicalModel->mColorRuns, - mImpl->mModel->mLogicalModel->mFontDescriptionRuns, - mImpl->mModel->mLogicalModel->mEmbeddedItems ); - - Length textSize = 0u; - const uint8_t* utf8 = NULL; - if( mImpl->mMarkupProcessorEnabled ) - { - ProcessMarkupString( text, markupProcessData ); - textSize = markupProcessData.markupProcessedText.size(); - - // This is a bit horrible but std::string returns a (signed) char* - utf8 = reinterpret_cast( markupProcessData.markupProcessedText.c_str() ); - } - else - { - textSize = text.size(); - - // This is a bit horrible but std::string returns a (signed) char* - utf8 = reinterpret_cast( text.c_str() ); - } - - // Convert text into UTF-32 - Vector& utf32Characters = mImpl->mModel->mLogicalModel->mText; - utf32Characters.Resize( textSize ); - - // Transform a text array encoded in utf8 into an array encoded in utf32. - // It returns the actual number of characters. - Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() ); - utf32Characters.Resize( characterCount ); - - DALI_ASSERT_DEBUG( textSize >= characterCount && "Invalid UTF32 conversion length" ); - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mModel->mLogicalModel->mText.Count() ); - - // The characters to be added. - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - - // To reset the cursor position - lastCursorIndex = characterCount; - - // Update the rest of the model during size negotiation - mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED ); - - // The natural size needs to be re-calculated. - mImpl->mRecalculateNaturalSize = true; - - // The text direction needs to be updated. - mImpl->mUpdateTextDirection = true; - - // Apply modifications to the model - mImpl->mOperationsPending = ALL_OPERATIONS; - } - else - { - ShowPlaceholderText(); - } - - // Resets the cursor position. - ResetCursorPosition( lastCursorIndex ); - - // Scrolls the text to make the cursor visible. - ResetScrollPosition(); - - mImpl->RequestRelayout(); - - if( NULL != mImpl->mEventData ) - { - // Cancel previously queued events - mImpl->mEventData->mEventQueue.clear(); - } - - // Do this last since it provides callbacks into application code. - if( NULL != mImpl->mEditableControlInterface ) - { - mImpl->mEditableControlInterface->TextChanged(); - } + TextUpdater::SetText(*this, text); } void Controller::GetText( std::string& text ) const @@ -1648,56 +1543,7 @@ bool Controller::CheckForTextFit( float pointSize, Size& layoutSize ) void Controller::FitPointSizeforLayout( Size layoutSize ) { - const OperationsMask operations = mImpl->mOperationsPending; - if( NO_OPERATION != ( UPDATE_LAYOUT_SIZE & operations ) || mImpl->mTextFitContentSize != layoutSize ) - { - bool actualellipsis = mImpl->mModel->mElideEnabled; - float minPointSize = mImpl->mTextFitMinSize; - float maxPointSize = mImpl->mTextFitMaxSize; - float pointInterval = mImpl->mTextFitStepSize; - - mImpl->mModel->mElideEnabled = false; - Vector pointSizeArray; - - // check zero value - if( pointInterval < 1.f ) - { - mImpl->mTextFitStepSize = pointInterval = 1.0f; - } - - pointSizeArray.Reserve( static_cast< unsigned int >( ceil( ( maxPointSize - minPointSize ) / pointInterval ) ) ); - - for( float i = minPointSize; i < maxPointSize; i += pointInterval ) - { - pointSizeArray.PushBack( i ); - } - - pointSizeArray.PushBack( maxPointSize ); - - int bestSizeIndex = 0; - int min = bestSizeIndex + 1; - int max = pointSizeArray.Size() - 1; - while( min <= max ) - { - int destI = ( min + max ) / 2; - - if( CheckForTextFit( pointSizeArray[destI], layoutSize ) ) - { - bestSizeIndex = min; - min = destI + 1; - } - else - { - max = destI - 1; - bestSizeIndex = max; - } - } - - mImpl->mModel->mElideEnabled = actualellipsis; - mImpl->mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex]; - mImpl->mFontDefaults->sizeDefined = true; - ClearFontData(); - } + Relayouter::FitPointSizeforLayout(*this, layoutSize); } float Controller::GetHeightForWidth( float width ) @@ -2077,409 +1923,24 @@ void Controller::DisplayTimeExpired() void Controller::InsertText( const std::string& text, Controller::InsertType type ) { - bool removedPrevious = false; - bool removedSelected = false; - bool maxLengthReached = false; - - DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected InsertText" ) - - if( NULL == mImpl->mEventData ) - { - return; - } - - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::InsertText %p %s (%s) mPrimaryCursorPosition %d mPreEditFlag %d mPreEditStartPosition %d mPreEditLength %d\n", - this, text.c_str(), (COMMIT == type ? "COMMIT" : "PRE_EDIT"), - mImpl->mEventData->mPrimaryCursorPosition, mImpl->mEventData->mPreEditFlag, mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength ); - - // TODO: At the moment the underline runs are only for pre-edit. - mImpl->mModel->mVisualModel->mUnderlineRuns.Clear(); - - // Remove the previous InputMethodContext pre-edit. - if( mImpl->mEventData->mPreEditFlag && ( 0u != mImpl->mEventData->mPreEditLength ) ) - { - removedPrevious = RemoveText( -static_cast( mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition ), - mImpl->mEventData->mPreEditLength, - DONT_UPDATE_INPUT_STYLE ); - - mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition; - mImpl->mEventData->mPreEditLength = 0u; - } - else - { - // Remove the previous Selection. - removedSelected = RemoveSelectedText(); - - } - - Vector utf32Characters; - Length characterCount = 0u; - - if( !text.empty() ) - { - // Convert text into UTF-32 - utf32Characters.Resize( text.size() ); - - // This is a bit horrible but std::string returns a (signed) char* - const uint8_t* utf8 = reinterpret_cast( text.c_str() ); - - // Transform a text array encoded in utf8 into an array encoded in utf32. - // It returns the actual number of characters. - characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() ); - utf32Characters.Resize( characterCount ); - - DALI_ASSERT_DEBUG( text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length" ); - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count() ); - } - - if( 0u != utf32Characters.Count() ) // Check if Utf8ToUtf32 conversion succeeded - { - // The placeholder text is no longer needed - if( mImpl->IsShowingPlaceholderText() ) - { - ResetText(); - } - - mImpl->ChangeState( EventData::EDITING ); - - // Handle the InputMethodContext (predicitive text) state changes - if( COMMIT == type ) - { - // InputMethodContext is no longer handling key-events - mImpl->ClearPreEditFlag(); - } - else // PRE_EDIT - { - if( !mImpl->mEventData->mPreEditFlag ) - { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Entered PreEdit state\n" ); - - // Record the start of the pre-edit text - mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition; - } - - mImpl->mEventData->mPreEditLength = utf32Characters.Count(); - mImpl->mEventData->mPreEditFlag = true; - - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength ); - } - - const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count(); - - // Restrict new text to fit within Maximum characters setting. - Length maxSizeOfNewText = std::min( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount ); - maxLengthReached = ( characterCount > maxSizeOfNewText ); - - // The cursor position. - CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition; - - // Update the text's style. - - // Updates the text style runs by adding characters. - mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText ); - - // Get the character index from the cursor index. - const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u; - - // Retrieve the text's style for the given index. - InputStyle style; - mImpl->RetrieveDefaultInputStyle( style ); - mImpl->mModel->mLogicalModel->RetrieveStyle( styleIndex, style ); - - // Whether to add a new text color run. - const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor ) && !mImpl->mEventData->mInputStyle.isDefaultColor; - - // Whether to add a new font run. - const bool addFontNameRun = ( style.familyName != mImpl->mEventData->mInputStyle.familyName ) && mImpl->mEventData->mInputStyle.isFamilyDefined; - const bool addFontWeightRun = ( style.weight != mImpl->mEventData->mInputStyle.weight ) && mImpl->mEventData->mInputStyle.isWeightDefined; - const bool addFontWidthRun = ( style.width != mImpl->mEventData->mInputStyle.width ) && mImpl->mEventData->mInputStyle.isWidthDefined; - const bool addFontSlantRun = ( style.slant != mImpl->mEventData->mInputStyle.slant ) && mImpl->mEventData->mInputStyle.isSlantDefined; - const bool addFontSizeRun = ( style.size != mImpl->mEventData->mInputStyle.size ) && mImpl->mEventData->mInputStyle.isSizeDefined ; - - // Add style runs. - if( addColorRun ) - { - const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count(); - mImpl->mModel->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u ); - - ColorRun& colorRun = *( mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns ); - colorRun.color = mImpl->mEventData->mInputStyle.textColor; - colorRun.characterRun.characterIndex = cursorIndex; - colorRun.characterRun.numberOfCharacters = maxSizeOfNewText; - } - - if( addFontNameRun || - addFontWeightRun || - addFontWidthRun || - addFontSlantRun || - addFontSizeRun ) - { - const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count(); - mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u ); - - FontDescriptionRun& fontDescriptionRun = *( mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns ); - - if( addFontNameRun ) - { - fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size(); - fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength]; - memcpy( fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength ); - fontDescriptionRun.familyDefined = true; - - // The memory allocated for the font family name is freed when the font description is removed from the logical model. - } - - if( addFontWeightRun ) - { - fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight; - fontDescriptionRun.weightDefined = true; - } - - if( addFontWidthRun ) - { - fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width; - fontDescriptionRun.widthDefined = true; - } - - if( addFontSlantRun ) - { - fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant; - fontDescriptionRun.slantDefined = true; - } - - if( addFontSizeRun ) - { - fontDescriptionRun.size = static_cast( mImpl->mEventData->mInputStyle.size * mImpl->mFontSizeScale * 64.f ); - fontDescriptionRun.sizeDefined = true; - } - - fontDescriptionRun.characterRun.characterIndex = cursorIndex; - fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText; - } - - // Insert at current cursor position. - Vector& modifyText = mImpl->mModel->mLogicalModel->mText; - - auto pos = modifyText.End(); - if( cursorIndex < numberOfCharactersInModel ) - { - pos = modifyText.Begin() + cursorIndex; - } - unsigned int realPos = pos - modifyText.Begin(); - modifyText.Insert( pos, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText ); - - if( NULL != mImpl->mEditableControlInterface ) - { - mImpl->mEditableControlInterface->TextInserted( realPos, maxSizeOfNewText, text ); - } - - // Mark the first paragraph to be updated. - if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() ) - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText; - mImpl->mTextUpdateInfo.mClearAll = true; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex ); - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText; - } - - // Update the cursor index. - cursorIndex += maxSizeOfNewText; - - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Inserted %d characters, new size %d new cursor %d\n", maxSizeOfNewText, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition ); - } - - if( ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) && - mImpl->IsPlaceholderAvailable() ) - { - // Show place-holder if empty after removing the pre-edit text - ShowPlaceholderText(); - mImpl->mEventData->mUpdateCursorPosition = true; - mImpl->ClearPreEditFlag(); - } - else if( removedPrevious || - removedSelected || - ( 0 != utf32Characters.Count() ) ) - { - // Queue an inserted event - mImpl->QueueModifyEvent( ModifyEvent::TEXT_INSERTED ); - - mImpl->mEventData->mUpdateCursorPosition = true; - if( removedSelected ) - { - mImpl->mEventData->mScrollAfterDelete = true; - } - else - { - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } - - if( maxLengthReached ) - { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count() ); - - mImpl->ResetInputMethodContext(); - - if( NULL != mImpl->mEditableControlInterface ) - { - // Do this last since it provides callbacks into application code - mImpl->mEditableControlInterface->MaxLengthReached(); - } - } + TextUpdater::InsertText(*this, text, type); } void Controller::PasteText( const std::string& stringToPaste ) { - InsertText( stringToPaste, Text::Controller::COMMIT ); - mImpl->ChangeState( EventData::EDITING ); - mImpl->RequestRelayout(); - - if( NULL != mImpl->mEditableControlInterface ) - { - // Do this last since it provides callbacks into application code - mImpl->mEditableControlInterface->TextChanged(); - } + TextUpdater::PasteText(*this, stringToPaste); } bool Controller::RemoveText( int cursorOffset, int numberOfCharacters, UpdateInputStyleType type ) { - bool removed = false; - - if( NULL == mImpl->mEventData ) - { - return removed; - } - - DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p mText.Count() %d cursor %d cursorOffset %d numberOfCharacters %d\n", - this, mImpl->mModel->mLogicalModel->mText.Count(), mImpl->mEventData->mPrimaryCursorPosition, cursorOffset, numberOfCharacters ); - - if( !mImpl->IsShowingPlaceholderText() ) - { - // Delete at current cursor position - Vector& currentText = mImpl->mModel->mLogicalModel->mText; - CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition; - - CharacterIndex cursorIndex = 0; - - // Validate the cursor position & number of characters - if( ( static_cast< int >( mImpl->mEventData->mPrimaryCursorPosition ) + cursorOffset ) >= 0 ) - { - cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset; - } - - if( ( cursorIndex + numberOfCharacters ) > currentText.Count() ) - { - numberOfCharacters = currentText.Count() - cursorIndex; - } - - if( mImpl->mEventData->mPreEditFlag || // If the preedit flag is enabled, it means two (or more) of them came together i.e. when two keys have been pressed at the same time. - ( ( cursorIndex + numberOfCharacters ) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) ) - { - // Mark the paragraphs to be updated. - if( Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout() ) - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters; - mImpl->mTextUpdateInfo.mClearAll = true; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = std::min( cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex ); - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters; - } - - // Update the input style and remove the text's style before removing the text. - - if( UPDATE_INPUT_STYLE == type ) - { - // Keep a copy of the current input style. - InputStyle currentInputStyle; - currentInputStyle.Copy( mImpl->mEventData->mInputStyle ); - - // Set first the default input style. - mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle ); - - // Update the input style. - mImpl->mModel->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle ); - - // Compare if the input style has changed. - const bool hasInputStyleChanged = !currentInputStyle.Equal( mImpl->mEventData->mInputStyle ); - - if( hasInputStyleChanged ) - { - const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask( mImpl->mEventData->mInputStyle ); - // Queue the input style changed signal. - mImpl->mEventData->mInputStyleChangedQueue.PushBack( styleChangedMask ); - } - } - - // If the number of current text and the number of characters to be deleted are same, - // it means all texts should be removed and all Preedit variables should be initialized. - if( ( currentText.Count() - numberOfCharacters == 0 ) && ( cursorIndex == 0 ) ) - { - mImpl->ClearPreEditFlag(); - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0; - } - - // Updates the text style runs by removing characters. Runs with no characters are removed. - mImpl->mModel->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters ); - - // Remove the characters. - Vector::Iterator first = currentText.Begin() + cursorIndex; - Vector::Iterator last = first + numberOfCharacters; - - if( NULL != mImpl->mEditableControlInterface ) - { - std::string utf8; - Utf32ToUtf8( first, numberOfCharacters, utf8 ); - mImpl->mEditableControlInterface->TextDeleted( cursorIndex, numberOfCharacters, utf8 ); - } - - currentText.Erase( first, last ); - - // Cursor position retreat - oldCursorIndex = cursorIndex; - - mImpl->mEventData->mScrollAfterDelete = true; - - if( EventData::INACTIVE == mImpl->mEventData->mState ) - { - mImpl->ChangeState( EventData::EDITING ); - } - - DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters ); - removed = true; - } - } - - return removed; + return TextUpdater::RemoveText(*this, cursorOffset, numberOfCharacters, type); } bool Controller::RemoveSelectedText() { - bool textRemoved( false ); - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - std::string removedString; - mImpl->RetrieveSelection( removedString, true ); - - if( !removedString.empty() ) - { - textRemoved = true; - mImpl->ChangeState( EventData::EDITING ); - } - } - - return textRemoved; + return TextUpdater::RemoveSelectedText(*this); } // private : Relayout. @@ -2527,30 +1988,7 @@ bool Controller::DeleteEvent( int keyCode ) void Controller::ResetText() { - // Reset buffers. - mImpl->mModel->mLogicalModel->mText.Clear(); - - // Reset the embedded images buffer. - mImpl->mModel->mLogicalModel->ClearEmbeddedImages(); - - // We have cleared everything including the placeholder-text - mImpl->PlaceholderCleared(); - - mImpl->mTextUpdateInfo.mCharacterIndex = 0u; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u; - - // Clear any previous text. - mImpl->mTextUpdateInfo.mClearAll = true; - - // The natural size needs to be re-calculated. - mImpl->mRecalculateNaturalSize = true; - - // The text direction needs to be updated. - mImpl->mUpdateTextDirection = true; - - // Apply modifications to the model - mImpl->mOperationsPending = ALL_OPERATIONS; + TextUpdater::ResetText(*this); } void Controller::ShowPlaceholderText() diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index b9fb7ae..5d8c021 100644 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -1837,6 +1837,7 @@ private: struct InputFontHandler; struct PlaceholderHandler; struct Relayouter; + struct TextUpdater; Impl* mImpl; }; -- 2.7.4