2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/internal/text/text-controller.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/adaptor-framework/tts-player.h>
29 #include <dali-toolkit/internal/text/character-set-conversion.h>
30 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
31 #include <dali-toolkit/internal/text/markup-processor.h>
32 #include <dali-toolkit/internal/text/text-controller-event-handler.h>
33 #include <dali-toolkit/internal/text/text-controller-impl.h>
34 #include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
35 #include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
36 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
40 #if defined(DEBUG_ENABLED)
41 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
44 const float MAX_FLOAT = std::numeric_limits<float>::max();
46 const std::string EMPTY_STRING("");
48 float ConvertToEven(float value)
50 int intValue(static_cast<int>(value));
51 return static_cast<float>(intValue + (intValue & 1));
54 int ConvertPixelToPint(float pixel)
56 unsigned int horizontalDpi = 0u;
57 unsigned int verticalDpi = 0u;
58 Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
59 fontClient.GetDpi(horizontalDpi, verticalDpi);
61 return (pixel * 72.f) / static_cast<float>(horizontalDpi);
72 // public : Constructor.
74 ControllerPtr Controller::New()
76 return ControllerPtr(new Controller());
79 ControllerPtr Controller::New(ControlInterface* controlInterface)
81 return ControllerPtr(new Controller(controlInterface));
84 ControllerPtr Controller::New(ControlInterface* controlInterface,
85 EditableControlInterface* editableControlInterface,
86 SelectableControlInterface* selectableControlInterface)
88 return ControllerPtr(new Controller(controlInterface,
89 editableControlInterface,
90 selectableControlInterface));
93 // public : Configure the text controller.
95 void Controller::EnableTextInput(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
99 delete mImpl->mEventData;
100 mImpl->mEventData = NULL;
102 // Nothing else to do.
106 if(NULL == mImpl->mEventData)
108 mImpl->mEventData = new EventData(decorator, inputMethodContext);
112 void Controller::SetGlyphType(TextAbstraction::GlyphType glyphType)
114 // Metrics for bitmap & vector based glyphs are different
115 mImpl->mMetrics->SetGlyphType(glyphType);
117 // Clear the font-specific data
120 mImpl->RequestRelayout();
123 void Controller::SetMarkupProcessorEnabled(bool enable)
125 if(enable != mImpl->mMarkupProcessorEnabled)
127 //If Text was already set, call the SetText again for enabling or disabling markup
128 mImpl->mMarkupProcessorEnabled = enable;
135 bool Controller::IsMarkupProcessorEnabled() const
137 return mImpl->mMarkupProcessorEnabled;
140 void Controller::SetAutoScrollEnabled(bool enable)
142 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled[%s] SingleBox[%s]-> [%p]\n", (enable) ? "true" : "false", (mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX) ? "true" : "false", this);
144 if(mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)
148 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n");
149 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
158 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
159 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
166 mImpl->mIsAutoScrollEnabled = enable;
167 mImpl->RequestRelayout();
171 DALI_LOG_WARNING("Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n");
172 mImpl->mIsAutoScrollEnabled = false;
176 bool Controller::IsAutoScrollEnabled() const
178 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled ? "true" : "false");
180 return mImpl->mIsAutoScrollEnabled;
183 CharacterDirection Controller::GetAutoScrollDirection() const
185 return mImpl->mIsTextDirectionRTL;
188 float Controller::GetAutoScrollLineAlignment() const
192 if(mImpl->mModel->mVisualModel &&
193 (0u != mImpl->mModel->mVisualModel->mLines.Count()))
195 offset = (*mImpl->mModel->mVisualModel->mLines.Begin()).alignmentOffset;
201 void Controller::SetHorizontalScrollEnabled(bool enable)
203 if((NULL != mImpl->mEventData) &&
204 mImpl->mEventData->mDecorator)
206 mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled(enable);
209 bool Controller::IsHorizontalScrollEnabled() const
211 if((NULL != mImpl->mEventData) &&
212 mImpl->mEventData->mDecorator)
214 return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
220 void Controller::SetVerticalScrollEnabled(bool enable)
222 if((NULL != mImpl->mEventData) &&
223 mImpl->mEventData->mDecorator)
225 if(mImpl->mEventData->mDecorator)
227 mImpl->mEventData->mDecorator->SetVerticalScrollEnabled(enable);
232 bool Controller::IsVerticalScrollEnabled() const
234 if((NULL != mImpl->mEventData) &&
235 mImpl->mEventData->mDecorator)
237 return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
243 void Controller::SetSmoothHandlePanEnabled(bool enable)
245 if((NULL != mImpl->mEventData) &&
246 mImpl->mEventData->mDecorator)
248 mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled(enable);
252 bool Controller::IsSmoothHandlePanEnabled() const
254 if((NULL != mImpl->mEventData) &&
255 mImpl->mEventData->mDecorator)
257 return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
263 void Controller::SetMaximumNumberOfCharacters(Length maxCharacters)
265 mImpl->mMaximumNumberOfCharacters = maxCharacters;
268 int Controller::GetMaximumNumberOfCharacters()
270 return mImpl->mMaximumNumberOfCharacters;
273 void Controller::SetEnableCursorBlink(bool enable)
275 DALI_ASSERT_DEBUG(NULL != mImpl->mEventData && "TextInput disabled");
277 if(NULL != mImpl->mEventData)
279 mImpl->mEventData->mCursorBlinkEnabled = enable;
282 mImpl->mEventData->mDecorator)
284 mImpl->mEventData->mDecorator->StopCursorBlink();
289 bool Controller::GetEnableCursorBlink() const
291 if(NULL != mImpl->mEventData)
293 return mImpl->mEventData->mCursorBlinkEnabled;
299 void Controller::SetMultiLineEnabled(bool enable)
301 const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
303 if(layout != mImpl->mLayoutEngine.GetLayout())
305 // Set the layout type.
306 mImpl->mLayoutEngine.SetLayout(layout);
308 // Set the flags to redo the layout operations
309 const OperationsMask layoutOperations = static_cast<OperationsMask>(LAYOUT |
314 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
315 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | layoutOperations);
317 // Need to recalculate natural size
318 mImpl->mRecalculateNaturalSize = true;
320 mImpl->RequestRelayout();
324 bool Controller::IsMultiLineEnabled() const
326 return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
329 void Controller::SetHorizontalAlignment(Text::HorizontalAlignment::Type alignment)
331 if(alignment != mImpl->mModel->mHorizontalAlignment)
333 // Set the alignment.
334 mImpl->mModel->mHorizontalAlignment = alignment;
336 // Set the flag to redo the alignment operation.
337 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | ALIGN);
339 if(mImpl->mEventData)
341 mImpl->mEventData->mUpdateAlignment = true;
343 // Update the cursor if it's in editing mode
344 if(EventData::IsEditingState(mImpl->mEventData->mState))
346 mImpl->ChangeState(EventData::EDITING);
347 mImpl->mEventData->mUpdateCursorPosition = true;
351 mImpl->RequestRelayout();
355 Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
357 return mImpl->mModel->mHorizontalAlignment;
360 void Controller::SetVerticalAlignment(VerticalAlignment::Type alignment)
362 if(alignment != mImpl->mModel->mVerticalAlignment)
364 // Set the alignment.
365 mImpl->mModel->mVerticalAlignment = alignment;
367 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | ALIGN);
369 mImpl->RequestRelayout();
373 VerticalAlignment::Type Controller::GetVerticalAlignment() const
375 return mImpl->mModel->mVerticalAlignment;
378 bool Controller::IsIgnoreSpacesAfterText() const
380 return mImpl->mModel->mIgnoreSpacesAfterText;
383 void Controller::SetIgnoreSpacesAfterText(bool ignore)
385 mImpl->mModel->mIgnoreSpacesAfterText = ignore;
388 bool Controller::IsMatchSystemLanguageDirection() const
390 return mImpl->mModel->mMatchSystemLanguageDirection;
393 void Controller::SetMatchSystemLanguageDirection(bool match)
395 mImpl->mModel->mMatchSystemLanguageDirection = match;
398 void Controller::SetLayoutDirection(Dali::LayoutDirection::Type layoutDirection)
400 mImpl->mLayoutDirection = layoutDirection;
403 bool Controller::IsShowingRealText() const
405 return mImpl->IsShowingRealText();
408 void Controller::SetLineWrapMode(Text::LineWrap::Mode lineWrapMode)
410 if(lineWrapMode != mImpl->mModel->mLineWrapMode)
412 // Set the text wrap mode.
413 mImpl->mModel->mLineWrapMode = lineWrapMode;
415 // Update Text layout for applying wrap mode
416 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
421 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
422 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
423 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
426 mImpl->RequestRelayout();
430 Text::LineWrap::Mode Controller::GetLineWrapMode() const
432 return mImpl->mModel->mLineWrapMode;
435 void Controller::SetTextElideEnabled(bool enabled)
437 mImpl->mModel->mElideEnabled = enabled;
440 bool Controller::IsTextElideEnabled() const
442 return mImpl->mModel->mElideEnabled;
445 void Controller::SetTextFitEnabled(bool enabled)
447 mImpl->mTextFitEnabled = enabled;
450 bool Controller::IsTextFitEnabled() const
452 return mImpl->mTextFitEnabled;
455 void Controller::SetTextFitMinSize(float minSize, FontSizeType type)
461 mImpl->mTextFitMinSize = minSize;
466 mImpl->mTextFitMinSize = ConvertPixelToPint(minSize);
472 float Controller::GetTextFitMinSize() const
474 return mImpl->mTextFitMinSize;
477 void Controller::SetTextFitMaxSize(float maxSize, FontSizeType type)
483 mImpl->mTextFitMaxSize = maxSize;
488 mImpl->mTextFitMaxSize = ConvertPixelToPint(maxSize);
494 float Controller::GetTextFitMaxSize() const
496 return mImpl->mTextFitMaxSize;
499 void Controller::SetTextFitStepSize(float step, FontSizeType type)
505 mImpl->mTextFitStepSize = step;
510 mImpl->mTextFitStepSize = ConvertPixelToPint(step);
516 float Controller::GetTextFitStepSize() const
518 return mImpl->mTextFitStepSize;
521 void Controller::SetTextFitContentSize(Vector2 size)
523 mImpl->mTextFitContentSize = size;
526 Vector2 Controller::GetTextFitContentSize() const
528 return mImpl->mTextFitContentSize;
531 void Controller::SetPlaceholderTextElideEnabled(bool enabled)
533 PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled);
536 bool Controller::IsPlaceholderTextElideEnabled() const
538 return PlaceholderHandler::IsPlaceholderTextElideEnabled(*this);
541 void Controller::SetSelectionEnabled(bool enabled)
543 mImpl->mEventData->mSelectionEnabled = enabled;
546 bool Controller::IsSelectionEnabled() const
548 return mImpl->mEventData->mSelectionEnabled;
551 void Controller::SetShiftSelectionEnabled(bool enabled)
553 mImpl->mEventData->mShiftSelectionFlag = enabled;
556 bool Controller::IsShiftSelectionEnabled() const
558 return mImpl->mEventData->mShiftSelectionFlag;
561 void Controller::SetGrabHandleEnabled(bool enabled)
563 mImpl->mEventData->mGrabHandleEnabled = enabled;
566 bool Controller::IsGrabHandleEnabled() const
568 return mImpl->mEventData->mGrabHandleEnabled;
571 void Controller::SetGrabHandlePopupEnabled(bool enabled)
573 mImpl->mEventData->mGrabHandlePopupEnabled = enabled;
576 bool Controller::IsGrabHandlePopupEnabled() const
578 return mImpl->mEventData->mGrabHandlePopupEnabled;
583 void Controller::SetText(const std::string& text)
585 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SetText\n");
587 // Reset keyboard as text changed
588 mImpl->ResetInputMethodContext();
590 // Remove the previously set text and style.
596 CharacterIndex lastCursorIndex = 0u;
598 if(NULL != mImpl->mEventData)
600 // If popup shown then hide it by switching to Editing state
601 if((EventData::SELECTING == mImpl->mEventData->mState) ||
602 (EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState) ||
603 (EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState) ||
604 (EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState))
606 mImpl->ChangeState(EventData::EDITING);
612 mImpl->mModel->mVisualModel->SetTextColor(mImpl->mTextColor);
614 MarkupProcessData markupProcessData(mImpl->mModel->mLogicalModel->mColorRuns,
615 mImpl->mModel->mLogicalModel->mFontDescriptionRuns,
616 mImpl->mModel->mLogicalModel->mEmbeddedItems);
618 Length textSize = 0u;
619 const uint8_t* utf8 = NULL;
620 if(mImpl->mMarkupProcessorEnabled)
622 ProcessMarkupString(text, markupProcessData);
623 textSize = markupProcessData.markupProcessedText.size();
625 // This is a bit horrible but std::string returns a (signed) char*
626 utf8 = reinterpret_cast<const uint8_t*>(markupProcessData.markupProcessedText.c_str());
630 textSize = text.size();
632 // This is a bit horrible but std::string returns a (signed) char*
633 utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
636 // Convert text into UTF-32
637 Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
638 utf32Characters.Resize(textSize);
640 // Transform a text array encoded in utf8 into an array encoded in utf32.
641 // It returns the actual number of characters.
642 Length characterCount = Utf8ToUtf32(utf8, textSize, utf32Characters.Begin());
643 utf32Characters.Resize(characterCount);
645 DALI_ASSERT_DEBUG(textSize >= characterCount && "Invalid UTF32 conversion length");
646 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mModel->mLogicalModel->mText.Count());
648 // The characters to be added.
649 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
651 // To reset the cursor position
652 lastCursorIndex = characterCount;
654 // Update the rest of the model during size negotiation
655 mImpl->QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
657 // The natural size needs to be re-calculated.
658 mImpl->mRecalculateNaturalSize = true;
660 // The text direction needs to be updated.
661 mImpl->mUpdateTextDirection = true;
663 // Apply modifications to the model
664 mImpl->mOperationsPending = ALL_OPERATIONS;
668 ShowPlaceholderText();
671 // Resets the cursor position.
672 ResetCursorPosition(lastCursorIndex);
674 // Scrolls the text to make the cursor visible.
675 ResetScrollPosition();
677 mImpl->RequestRelayout();
679 if(NULL != mImpl->mEventData)
681 // Cancel previously queued events
682 mImpl->mEventData->mEventQueue.clear();
685 // Do this last since it provides callbacks into application code.
686 if(NULL != mImpl->mEditableControlInterface)
688 mImpl->mEditableControlInterface->TextChanged(true);
692 void Controller::GetText(std::string& text) const
694 if(!mImpl->IsShowingPlaceholderText())
696 // Retrieves the text string.
697 mImpl->GetText(0u, text);
701 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this);
705 void Controller::SetPlaceholderText(PlaceholderType type, const std::string& text)
707 PlaceholderHandler::SetPlaceholderText(*this, type, text);
710 void Controller::GetPlaceholderText(PlaceholderType type, std::string& text) const
712 PlaceholderHandler::GetPlaceholderText(*this, type, text);
715 void Controller::UpdateAfterFontChange(const std::string& newDefaultFont)
717 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
719 if(!mImpl->mFontDefaults->familyDefined) // If user defined font then should not update when system font changes
721 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str());
722 mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
726 mImpl->RequestRelayout();
730 // public : Default style & Input style
732 void Controller::SetDefaultFontFamily(const std::string& defaultFontFamily)
734 if(NULL == mImpl->mFontDefaults)
736 mImpl->mFontDefaults = new FontDefaults();
739 mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
740 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
741 mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
743 if(mImpl->mEventData)
745 // Update the cursor position if it's in editing mode
746 if(EventData::IsEditingState(mImpl->mEventData->mState))
748 mImpl->mEventData->mDecoratorUpdated = true;
749 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font family is updated.
753 // Clear the font-specific data
756 mImpl->RequestRelayout();
759 const std::string& Controller::GetDefaultFontFamily() const
761 if(NULL != mImpl->mFontDefaults)
763 return mImpl->mFontDefaults->mFontDescription.family;
769 void Controller::SetPlaceholderFontFamily(const std::string& placeholderTextFontFamily)
771 PlaceholderHandler::SetPlaceholderFontFamily(*this, placeholderTextFontFamily);
774 const std::string& Controller::GetPlaceholderFontFamily() const
776 return PlaceholderHandler::GetPlaceholderFontFamily(*this);
779 void Controller::SetDefaultFontWeight(FontWeight weight)
781 if(NULL == mImpl->mFontDefaults)
783 mImpl->mFontDefaults = new FontDefaults();
786 mImpl->mFontDefaults->mFontDescription.weight = weight;
787 mImpl->mFontDefaults->weightDefined = true;
789 if(mImpl->mEventData)
791 // Update the cursor position if it's in editing mode
792 if(EventData::IsEditingState(mImpl->mEventData->mState))
794 mImpl->mEventData->mDecoratorUpdated = true;
795 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font weight is updated.
799 // Clear the font-specific data
802 mImpl->RequestRelayout();
805 bool Controller::IsDefaultFontWeightDefined() const
807 if(NULL != mImpl->mFontDefaults)
809 return mImpl->mFontDefaults->weightDefined;
815 FontWeight Controller::GetDefaultFontWeight() const
817 if(NULL != mImpl->mFontDefaults)
819 return mImpl->mFontDefaults->mFontDescription.weight;
822 return TextAbstraction::FontWeight::NORMAL;
825 void Controller::SetPlaceholderTextFontWeight(FontWeight weight)
827 PlaceholderHandler::SetPlaceholderTextFontWeight(*this, weight);
830 bool Controller::IsPlaceholderTextFontWeightDefined() const
832 return PlaceholderHandler::IsPlaceholderTextFontWeightDefined(*this);
836 FontWeight Controller::GetPlaceholderTextFontWeight() const
838 return PlaceholderHandler::GetPlaceholderTextFontWeight(*this);
841 void Controller::SetDefaultFontWidth(FontWidth width)
843 if(NULL == mImpl->mFontDefaults)
845 mImpl->mFontDefaults = new FontDefaults();
848 mImpl->mFontDefaults->mFontDescription.width = width;
849 mImpl->mFontDefaults->widthDefined = true;
851 if(mImpl->mEventData)
853 // Update the cursor position if it's in editing mode
854 if(EventData::IsEditingState(mImpl->mEventData->mState))
856 mImpl->mEventData->mDecoratorUpdated = true;
857 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font width is updated.
861 // Clear the font-specific data
864 mImpl->RequestRelayout();
867 bool Controller::IsDefaultFontWidthDefined() const
869 if(NULL != mImpl->mFontDefaults)
871 return mImpl->mFontDefaults->widthDefined;
877 FontWidth Controller::GetDefaultFontWidth() const
879 if(NULL != mImpl->mFontDefaults)
881 return mImpl->mFontDefaults->mFontDescription.width;
884 return TextAbstraction::FontWidth::NORMAL;
887 void Controller::SetPlaceholderTextFontWidth(FontWidth width)
889 PlaceholderHandler::SetPlaceholderTextFontWidth(*this, width);
892 bool Controller::IsPlaceholderTextFontWidthDefined() const
894 return PlaceholderHandler::IsPlaceholderTextFontWidthDefined(*this);
897 FontWidth Controller::GetPlaceholderTextFontWidth() const
899 return PlaceholderHandler::GetPlaceholderTextFontWidth(*this);
902 void Controller::SetDefaultFontSlant(FontSlant slant)
904 if(NULL == mImpl->mFontDefaults)
906 mImpl->mFontDefaults = new FontDefaults();
909 mImpl->mFontDefaults->mFontDescription.slant = slant;
910 mImpl->mFontDefaults->slantDefined = true;
912 if(mImpl->mEventData)
914 // Update the cursor position if it's in editing mode
915 if(EventData::IsEditingState(mImpl->mEventData->mState))
917 mImpl->mEventData->mDecoratorUpdated = true;
918 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font slant is updated.
922 // Clear the font-specific data
925 mImpl->RequestRelayout();
928 bool Controller::IsDefaultFontSlantDefined() const
930 if(NULL != mImpl->mFontDefaults)
932 return mImpl->mFontDefaults->slantDefined;
937 FontSlant Controller::GetDefaultFontSlant() const
939 if(NULL != mImpl->mFontDefaults)
941 return mImpl->mFontDefaults->mFontDescription.slant;
944 return TextAbstraction::FontSlant::NORMAL;
947 void Controller::SetPlaceholderTextFontSlant(FontSlant slant)
949 PlaceholderHandler::SetPlaceholderTextFontSlant(*this, slant);
952 bool Controller::IsPlaceholderTextFontSlantDefined() const
954 return PlaceholderHandler::IsPlaceholderTextFontSlantDefined(*this);
957 FontSlant Controller::GetPlaceholderTextFontSlant() const
959 return PlaceholderHandler::GetPlaceholderTextFontSlant(*this);
962 void Controller::SetDefaultFontSize(float fontSize, FontSizeType type)
964 if(NULL == mImpl->mFontDefaults)
966 mImpl->mFontDefaults = new FontDefaults();
973 mImpl->mFontDefaults->mDefaultPointSize = fontSize;
974 mImpl->mFontDefaults->sizeDefined = true;
979 // Point size = Pixel size * 72.f / DPI
980 unsigned int horizontalDpi = 0u;
981 unsigned int verticalDpi = 0u;
982 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
983 fontClient.GetDpi(horizontalDpi, verticalDpi);
985 mImpl->mFontDefaults->mDefaultPointSize = (fontSize * 72.f) / static_cast<float>(horizontalDpi);
986 mImpl->mFontDefaults->sizeDefined = true;
991 if(mImpl->mEventData)
993 // Update the cursor position if it's in editing mode
994 if(EventData::IsEditingState(mImpl->mEventData->mState))
996 mImpl->mEventData->mDecoratorUpdated = true;
997 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font size is updated.
1001 // Clear the font-specific data
1004 mImpl->RequestRelayout();
1007 float Controller::GetDefaultFontSize(FontSizeType type) const
1010 if(NULL != mImpl->mFontDefaults)
1016 value = mImpl->mFontDefaults->mDefaultPointSize;
1021 // Pixel size = Point size * DPI / 72.f
1022 unsigned int horizontalDpi = 0u;
1023 unsigned int verticalDpi = 0u;
1024 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1025 fontClient.GetDpi(horizontalDpi, verticalDpi);
1027 value = mImpl->mFontDefaults->mDefaultPointSize * static_cast<float>(horizontalDpi) / 72.f;
1037 void Controller::SetPlaceholderTextFontSize(float fontSize, FontSizeType type)
1039 PlaceholderHandler::SetPlaceholderTextFontSize(*this, fontSize, type);
1042 float Controller::GetPlaceholderTextFontSize(FontSizeType type) const
1044 return PlaceholderHandler::GetPlaceholderTextFontSize(*this, type);
1047 void Controller::SetDefaultColor(const Vector4& color)
1049 mImpl->mTextColor = color;
1051 if(!mImpl->IsShowingPlaceholderText())
1053 mImpl->mModel->mVisualModel->SetTextColor(color);
1055 mImpl->mModel->mLogicalModel->mColorRuns.Clear();
1057 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | COLOR);
1059 mImpl->RequestRelayout();
1063 const Vector4& Controller::GetDefaultColor() const
1065 return mImpl->mTextColor;
1068 void Controller::SetPlaceholderTextColor(const Vector4& textColor)
1070 PlaceholderHandler::SetPlaceholderTextColor(*this, textColor);
1073 const Vector4& Controller::GetPlaceholderTextColor() const
1075 return PlaceholderHandler::GetPlaceholderTextColor(*this);
1078 void Controller::SetShadowOffset(const Vector2& shadowOffset)
1080 mImpl->mModel->mVisualModel->SetShadowOffset(shadowOffset);
1082 mImpl->RequestRelayout();
1085 const Vector2& Controller::GetShadowOffset() const
1087 return mImpl->mModel->mVisualModel->GetShadowOffset();
1090 void Controller::SetShadowColor(const Vector4& shadowColor)
1092 mImpl->mModel->mVisualModel->SetShadowColor(shadowColor);
1094 mImpl->RequestRelayout();
1097 const Vector4& Controller::GetShadowColor() const
1099 return mImpl->mModel->mVisualModel->GetShadowColor();
1102 void Controller::SetShadowBlurRadius(const float& shadowBlurRadius)
1104 if(fabsf(GetShadowBlurRadius() - shadowBlurRadius) > Math::MACHINE_EPSILON_1)
1106 mImpl->mModel->mVisualModel->SetShadowBlurRadius(shadowBlurRadius);
1108 mImpl->RequestRelayout();
1112 const float& Controller::GetShadowBlurRadius() const
1114 return mImpl->mModel->mVisualModel->GetShadowBlurRadius();
1117 void Controller::SetUnderlineColor(const Vector4& color)
1119 mImpl->mModel->mVisualModel->SetUnderlineColor(color);
1121 mImpl->RequestRelayout();
1124 const Vector4& Controller::GetUnderlineColor() const
1126 return mImpl->mModel->mVisualModel->GetUnderlineColor();
1129 void Controller::SetUnderlineEnabled(bool enabled)
1131 mImpl->mModel->mVisualModel->SetUnderlineEnabled(enabled);
1133 mImpl->RequestRelayout();
1136 bool Controller::IsUnderlineEnabled() const
1138 return mImpl->mModel->mVisualModel->IsUnderlineEnabled();
1141 void Controller::SetUnderlineHeight(float height)
1143 mImpl->mModel->mVisualModel->SetUnderlineHeight(height);
1145 mImpl->RequestRelayout();
1148 float Controller::GetUnderlineHeight() const
1150 return mImpl->mModel->mVisualModel->GetUnderlineHeight();
1153 void Controller::SetOutlineColor(const Vector4& color)
1155 mImpl->mModel->mVisualModel->SetOutlineColor(color);
1157 mImpl->RequestRelayout();
1160 const Vector4& Controller::GetOutlineColor() const
1162 return mImpl->mModel->mVisualModel->GetOutlineColor();
1165 void Controller::SetOutlineWidth(uint16_t width)
1167 mImpl->mModel->mVisualModel->SetOutlineWidth(width);
1169 mImpl->RequestRelayout();
1172 uint16_t Controller::GetOutlineWidth() const
1174 return mImpl->mModel->mVisualModel->GetOutlineWidth();
1177 void Controller::SetBackgroundColor(const Vector4& color)
1179 mImpl->mModel->mVisualModel->SetBackgroundColor(color);
1181 mImpl->RequestRelayout();
1184 const Vector4& Controller::GetBackgroundColor() const
1186 return mImpl->mModel->mVisualModel->GetBackgroundColor();
1189 void Controller::SetBackgroundEnabled(bool enabled)
1191 mImpl->mModel->mVisualModel->SetBackgroundEnabled(enabled);
1193 mImpl->RequestRelayout();
1196 bool Controller::IsBackgroundEnabled() const
1198 return mImpl->mModel->mVisualModel->IsBackgroundEnabled();
1201 void Controller::SetDefaultEmbossProperties(const std::string& embossProperties)
1203 if(NULL == mImpl->mEmbossDefaults)
1205 mImpl->mEmbossDefaults = new EmbossDefaults();
1208 mImpl->mEmbossDefaults->properties = embossProperties;
1211 const std::string& Controller::GetDefaultEmbossProperties() const
1213 if(NULL != mImpl->mEmbossDefaults)
1215 return mImpl->mEmbossDefaults->properties;
1218 return EMPTY_STRING;
1221 void Controller::SetDefaultOutlineProperties(const std::string& outlineProperties)
1223 if(NULL == mImpl->mOutlineDefaults)
1225 mImpl->mOutlineDefaults = new OutlineDefaults();
1228 mImpl->mOutlineDefaults->properties = outlineProperties;
1231 const std::string& Controller::GetDefaultOutlineProperties() const
1233 if(NULL != mImpl->mOutlineDefaults)
1235 return mImpl->mOutlineDefaults->properties;
1238 return EMPTY_STRING;
1241 bool Controller::SetDefaultLineSpacing(float lineSpacing)
1243 if(std::fabs(lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000)
1245 mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
1246 mImpl->mRecalculateNaturalSize = true;
1252 float Controller::GetDefaultLineSpacing() const
1254 return mImpl->mLayoutEngine.GetDefaultLineSpacing();
1257 bool Controller::SetDefaultLineSize(float lineSize)
1259 if(std::fabs(lineSize - mImpl->mLayoutEngine.GetDefaultLineSize()) > Math::MACHINE_EPSILON_1000)
1261 mImpl->mLayoutEngine.SetDefaultLineSize(lineSize);
1262 mImpl->mRecalculateNaturalSize = true;
1268 float Controller::GetDefaultLineSize() const
1270 return mImpl->mLayoutEngine.GetDefaultLineSize();
1273 void Controller::SetInputColor(const Vector4& color)
1275 if(NULL != mImpl->mEventData)
1277 mImpl->mEventData->mInputStyle.textColor = color;
1278 mImpl->mEventData->mInputStyle.isDefaultColor = false;
1280 if(EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState)
1282 if(EventData::SELECTING == mImpl->mEventData->mState)
1284 const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
1286 // Get start and end position of selection
1287 const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
1288 const Length lengthOfSelectedText = (handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition) - startOfSelectedText;
1290 // Add the color run.
1291 const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
1292 mImpl->mModel->mLogicalModel->mColorRuns.Resize(numberOfRuns + 1u);
1294 ColorRun& colorRun = *(mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns);
1295 colorRun.color = color;
1296 colorRun.characterRun.characterIndex = startOfSelectedText;
1297 colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
1299 mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1300 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1301 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1305 mImpl->mTextUpdateInfo.mCharacterIndex = 0;
1306 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
1307 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
1310 // Request to relayout.
1311 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | COLOR);
1312 mImpl->RequestRelayout();
1317 const Vector4& Controller::GetInputColor() const
1319 if(NULL != mImpl->mEventData)
1321 return mImpl->mEventData->mInputStyle.textColor;
1324 // Return the default text's color if there is no EventData.
1325 return mImpl->mTextColor;
1328 void Controller::SetInputFontFamily(const std::string& fontFamily)
1330 InputFontHandler::SetInputFontFamily(*this, fontFamily);
1333 const std::string& Controller::GetInputFontFamily() const
1335 return InputFontHandler::GetInputFontFamily(*this);
1338 void Controller::SetInputFontWeight(FontWeight weight)
1340 InputFontHandler::SetInputFontWeight(*this, weight);
1343 bool Controller::IsInputFontWeightDefined() const
1345 return InputFontHandler::IsInputFontWeightDefined(*this);
1348 FontWeight Controller::GetInputFontWeight() const
1350 return InputFontHandler::GetInputFontWeight(*this);
1353 void Controller::SetInputFontWidth(FontWidth width)
1355 InputFontHandler::SetInputFontWidth(*this, width);
1358 bool Controller::IsInputFontWidthDefined() const
1360 return InputFontHandler::IsInputFontWidthDefined(*this);
1363 FontWidth Controller::GetInputFontWidth() const
1365 return InputFontHandler::GetInputFontWidth(*this);
1368 void Controller::SetInputFontSlant(FontSlant slant)
1370 InputFontHandler::SetInputFontSlant(*this, slant);
1373 bool Controller::IsInputFontSlantDefined() const
1375 return InputFontHandler::IsInputFontSlantDefined(*this);
1378 FontSlant Controller::GetInputFontSlant() const
1380 return InputFontHandler::GetInputFontSlant(*this);
1383 void Controller::SetInputFontPointSize(float size)
1385 InputFontHandler::SetInputFontPointSize(*this, size);
1388 float Controller::GetInputFontPointSize() const
1390 return InputFontHandler::GetInputFontPointSize(*this);
1393 void Controller::SetInputLineSpacing(float lineSpacing)
1395 if(NULL != mImpl->mEventData)
1397 mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1398 mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1402 float Controller::GetInputLineSpacing() const
1404 if(NULL != mImpl->mEventData)
1406 return mImpl->mEventData->mInputStyle.lineSpacing;
1412 void Controller::SetInputShadowProperties(const std::string& shadowProperties)
1414 if(NULL != mImpl->mEventData)
1416 mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1420 const std::string& Controller::GetInputShadowProperties() const
1422 if(NULL != mImpl->mEventData)
1424 return mImpl->mEventData->mInputStyle.shadowProperties;
1427 return EMPTY_STRING;
1430 void Controller::SetInputUnderlineProperties(const std::string& underlineProperties)
1432 if(NULL != mImpl->mEventData)
1434 mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1438 const std::string& Controller::GetInputUnderlineProperties() const
1440 if(NULL != mImpl->mEventData)
1442 return mImpl->mEventData->mInputStyle.underlineProperties;
1445 return EMPTY_STRING;
1448 void Controller::SetInputEmbossProperties(const std::string& embossProperties)
1450 if(NULL != mImpl->mEventData)
1452 mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1456 const std::string& Controller::GetInputEmbossProperties() const
1458 if(NULL != mImpl->mEventData)
1460 return mImpl->mEventData->mInputStyle.embossProperties;
1463 return GetDefaultEmbossProperties();
1466 void Controller::SetInputOutlineProperties(const std::string& outlineProperties)
1468 if(NULL != mImpl->mEventData)
1470 mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1474 const std::string& Controller::GetInputOutlineProperties() const
1476 if(NULL != mImpl->mEventData)
1478 return mImpl->mEventData->mInputStyle.outlineProperties;
1481 return GetDefaultOutlineProperties();
1484 void Controller::SetInputModePassword(bool passwordInput)
1486 if(NULL != mImpl->mEventData)
1488 mImpl->mEventData->mPasswordInput = passwordInput;
1492 bool Controller::IsInputModePassword()
1494 if(NULL != mImpl->mEventData)
1496 return mImpl->mEventData->mPasswordInput;
1501 void Controller::SetNoTextDoubleTapAction(NoTextTap::Action action)
1503 if(NULL != mImpl->mEventData)
1505 mImpl->mEventData->mDoubleTapAction = action;
1509 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
1511 NoTextTap::Action action = NoTextTap::NO_ACTION;
1513 if(NULL != mImpl->mEventData)
1515 action = mImpl->mEventData->mDoubleTapAction;
1521 void Controller::SetNoTextLongPressAction(NoTextTap::Action action)
1523 if(NULL != mImpl->mEventData)
1525 mImpl->mEventData->mLongPressAction = action;
1529 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
1531 NoTextTap::Action action = NoTextTap::NO_ACTION;
1533 if(NULL != mImpl->mEventData)
1535 action = mImpl->mEventData->mLongPressAction;
1541 bool Controller::IsUnderlineSetByString()
1543 return mImpl->mUnderlineSetByString;
1546 void Controller::UnderlineSetByString(bool setByString)
1548 mImpl->mUnderlineSetByString = setByString;
1551 bool Controller::IsShadowSetByString()
1553 return mImpl->mShadowSetByString;
1556 void Controller::ShadowSetByString(bool setByString)
1558 mImpl->mShadowSetByString = setByString;
1561 bool Controller::IsOutlineSetByString()
1563 return mImpl->mOutlineSetByString;
1566 void Controller::OutlineSetByString(bool setByString)
1568 mImpl->mOutlineSetByString = setByString;
1571 bool Controller::IsFontStyleSetByString()
1573 return mImpl->mFontStyleSetByString;
1576 void Controller::FontStyleSetByString(bool setByString)
1578 mImpl->mFontStyleSetByString = setByString;
1581 // public : Queries & retrieves.
1583 Layout::Engine& Controller::GetLayoutEngine()
1585 return mImpl->mLayoutEngine;
1588 View& Controller::GetView()
1590 return mImpl->mView;
1593 Vector3 Controller::GetNaturalSize()
1595 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n");
1596 Vector3 naturalSize;
1598 // Make sure the model is up-to-date before layouting
1599 ProcessModifyEvents();
1601 if(mImpl->mRecalculateNaturalSize)
1603 // Operations that can be done only once until the text changes.
1604 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1612 // Set the update info to relayout the whole text.
1613 mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1614 mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1616 // Make sure the model is up-to-date before layouting
1617 mImpl->UpdateModel(onlyOnceOperations);
1619 // Layout the text for the new width.
1620 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | LAYOUT | REORDER);
1622 // Store the actual control's size to restore later.
1623 const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
1625 DoRelayout(Size(MAX_FLOAT, MAX_FLOAT),
1626 static_cast<OperationsMask>(onlyOnceOperations |
1628 naturalSize.GetVectorXY());
1630 // Do not do again the only once operations.
1631 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
1633 // Do the size related operations again.
1634 const OperationsMask sizeOperations = static_cast<OperationsMask>(LAYOUT |
1637 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | sizeOperations);
1639 // Stores the natural size to avoid recalculate it again
1640 // unless the text/style changes.
1641 mImpl->mModel->mVisualModel->SetNaturalSize(naturalSize.GetVectorXY());
1643 mImpl->mRecalculateNaturalSize = false;
1645 // Clear the update info. This info will be set the next time the text is updated.
1646 mImpl->mTextUpdateInfo.Clear();
1647 mImpl->mTextUpdateInfo.mClearAll = true;
1649 // Restore the actual control's size.
1650 mImpl->mModel->mVisualModel->mControlSize = actualControlSize;
1652 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z);
1656 naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize();
1658 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z);
1661 naturalSize.x = ConvertToEven(naturalSize.x);
1662 naturalSize.y = ConvertToEven(naturalSize.y);
1667 bool Controller::CheckForTextFit(float pointSize, Size& layoutSize)
1670 mImpl->mFontDefaults->mFitPointSize = pointSize;
1671 mImpl->mFontDefaults->sizeDefined = true;
1674 // Operations that can be done only once until the text changes.
1675 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1683 mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1684 mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1686 // Make sure the model is up-to-date before layouting
1687 mImpl->UpdateModel(onlyOnceOperations);
1689 DoRelayout(Size(layoutSize.width, MAX_FLOAT),
1690 static_cast<OperationsMask>(onlyOnceOperations | LAYOUT),
1693 // Clear the update info. This info will be set the next time the text is updated.
1694 mImpl->mTextUpdateInfo.Clear();
1695 mImpl->mTextUpdateInfo.mClearAll = true;
1697 if(textSize.width > layoutSize.width || textSize.height > layoutSize.height)
1704 void Controller::FitPointSizeforLayout(Size layoutSize)
1706 const OperationsMask operations = mImpl->mOperationsPending;
1707 if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations) || mImpl->mTextFitContentSize != layoutSize)
1709 bool actualellipsis = mImpl->mModel->mElideEnabled;
1710 float minPointSize = mImpl->mTextFitMinSize;
1711 float maxPointSize = mImpl->mTextFitMaxSize;
1712 float pointInterval = mImpl->mTextFitStepSize;
1714 mImpl->mModel->mElideEnabled = false;
1715 Vector<float> pointSizeArray;
1718 if(pointInterval < 1.f)
1720 mImpl->mTextFitStepSize = pointInterval = 1.0f;
1723 pointSizeArray.Reserve(static_cast<unsigned int>(ceil((maxPointSize - minPointSize) / pointInterval)));
1725 for(float i = minPointSize; i < maxPointSize; i += pointInterval)
1727 pointSizeArray.PushBack(i);
1730 pointSizeArray.PushBack(maxPointSize);
1732 int bestSizeIndex = 0;
1733 int min = bestSizeIndex + 1;
1734 int max = pointSizeArray.Size() - 1;
1737 int destI = (min + max) / 2;
1739 if(CheckForTextFit(pointSizeArray[destI], layoutSize))
1741 bestSizeIndex = min;
1747 bestSizeIndex = max;
1751 mImpl->mModel->mElideEnabled = actualellipsis;
1752 mImpl->mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
1753 mImpl->mFontDefaults->sizeDefined = true;
1758 float Controller::GetHeightForWidth(float width)
1760 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width);
1761 // Make sure the model is up-to-date before layouting
1762 ProcessModifyEvents();
1765 if(fabsf(width - mImpl->mModel->mVisualModel->mControlSize.width) > Math::MACHINE_EPSILON_1000 ||
1766 mImpl->mTextUpdateInfo.mFullRelayoutNeeded ||
1767 mImpl->mTextUpdateInfo.mClearAll)
1769 // Operations that can be done only once until the text changes.
1770 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1778 // Set the update info to relayout the whole text.
1779 mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1780 mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1782 // Make sure the model is up-to-date before layouting
1783 mImpl->UpdateModel(onlyOnceOperations);
1785 // Layout the text for the new width.
1786 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | LAYOUT);
1788 // Store the actual control's width.
1789 const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
1791 DoRelayout(Size(width, MAX_FLOAT),
1792 static_cast<OperationsMask>(onlyOnceOperations |
1796 // Do not do again the only once operations.
1797 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
1799 // Do the size related operations again.
1800 const OperationsMask sizeOperations = static_cast<OperationsMask>(LAYOUT |
1804 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | sizeOperations);
1806 // Clear the update info. This info will be set the next time the text is updated.
1807 mImpl->mTextUpdateInfo.Clear();
1808 mImpl->mTextUpdateInfo.mClearAll = true;
1810 // Restore the actual control's width.
1811 mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
1813 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height);
1817 layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
1818 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height);
1821 return layoutSize.height;
1824 int Controller::GetLineCount(float width)
1826 GetHeightForWidth(width);
1827 int numberofLines = mImpl->mModel->GetNumberOfLines();
1828 return numberofLines;
1831 const ModelInterface* const Controller::GetTextModel() const
1833 return mImpl->mModel.Get();
1836 float Controller::GetScrollAmountByUserInput()
1838 float scrollAmount = 0.0f;
1840 if(NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1842 scrollAmount = mImpl->mModel->mScrollPosition.y - mImpl->mModel->mScrollPositionLast.y;
1843 mImpl->mEventData->mCheckScrollAmount = false;
1845 return scrollAmount;
1848 bool Controller::GetTextScrollInfo(float& scrollPosition, float& controlHeight, float& layoutHeight)
1850 const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1853 controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
1854 layoutHeight = layout.height;
1855 scrollPosition = mImpl->mModel->mScrollPosition.y;
1856 isScrolled = !Equals(mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1);
1860 void Controller::SetHiddenInputOption(const Property::Map& options)
1862 if(NULL == mImpl->mHiddenInput)
1864 mImpl->mHiddenInput = new HiddenText(this);
1866 mImpl->mHiddenInput->SetProperties(options);
1869 void Controller::GetHiddenInputOption(Property::Map& options)
1871 if(NULL != mImpl->mHiddenInput)
1873 mImpl->mHiddenInput->GetProperties(options);
1877 void Controller::SetPlaceholderProperty(const Property::Map& map)
1879 PlaceholderHandler::SetPlaceholderProperty(*this, map);
1882 void Controller::GetPlaceholderProperty(Property::Map& map)
1884 PlaceholderHandler::GetPlaceholderProperty(*this, map);
1887 Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
1889 // Make sure the model is up-to-date before layouting
1890 ProcessModifyEvents();
1892 if(mImpl->mUpdateTextDirection)
1894 // Operations that can be done only once until the text changes.
1895 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1903 // Set the update info to relayout the whole text.
1904 mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1905 mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1907 // Make sure the model is up-to-date before layouting
1908 mImpl->UpdateModel(onlyOnceOperations);
1910 Vector3 naturalSize;
1911 DoRelayout(Size(MAX_FLOAT, MAX_FLOAT),
1912 static_cast<OperationsMask>(onlyOnceOperations |
1913 LAYOUT | REORDER | UPDATE_DIRECTION),
1914 naturalSize.GetVectorXY());
1916 // Do not do again the only once operations.
1917 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
1919 // Clear the update info. This info will be set the next time the text is updated.
1920 mImpl->mTextUpdateInfo.Clear();
1922 // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
1923 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1925 mImpl->mUpdateTextDirection = false;
1928 return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
1931 Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
1933 return mImpl->mModel->GetVerticalLineAlignment();
1936 void Controller::SetVerticalLineAlignment(Toolkit::DevelText::VerticalLineAlignment::Type alignment)
1938 mImpl->mModel->mVerticalLineAlignment = alignment;
1941 // public : Relayout.
1943 Controller::UpdateTextType Controller::Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection)
1945 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ? "true" : "false");
1947 UpdateTextType updateTextType = NONE_UPDATED;
1949 if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
1951 if(0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count())
1953 mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
1954 updateTextType = MODEL_UPDATED;
1957 // Clear the update info. This info will be set the next time the text is updated.
1958 mImpl->mTextUpdateInfo.Clear();
1960 // Not worth to relayout if width or height is equal to zero.
1961 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n");
1963 return updateTextType;
1966 // Whether a new size has been set.
1967 const bool newSize = (size != mImpl->mModel->mVisualModel->mControlSize);
1971 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height);
1973 if((0 == mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd) &&
1974 (0 == mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters) &&
1975 ((mImpl->mModel->mVisualModel->mControlSize.width < Math::MACHINE_EPSILON_1000) || (mImpl->mModel->mVisualModel->mControlSize.height < Math::MACHINE_EPSILON_1000)))
1977 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
1980 // Layout operations that need to be done if the size changes.
1981 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
1984 UPDATE_LAYOUT_SIZE |
1986 // Set the update info to relayout the whole text.
1987 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1988 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
1990 // Store the size used to layout the text.
1991 mImpl->mModel->mVisualModel->mControlSize = size;
1994 // Whether there are modify events.
1995 if(0u != mImpl->mModifyEvents.Count())
1997 // Style operations that need to be done if the text is modified.
1998 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
2002 // Set the update info to elide the text.
2003 if(mImpl->mModel->mElideEnabled ||
2004 ((NULL != mImpl->mEventData) && mImpl->mEventData->mIsPlaceholderElideEnabled))
2006 // Update Text layout for applying elided
2007 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
2010 UPDATE_LAYOUT_SIZE |
2012 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2013 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2016 if(mImpl->mModel->mMatchSystemLanguageDirection && mImpl->mLayoutDirection != layoutDirection)
2018 // Clear the update info. This info will be set the next time the text is updated.
2019 mImpl->mTextUpdateInfo.mClearAll = true;
2020 // Apply modifications to the model
2021 // Shape the text again is needed because characters like '()[]{}' have to be mirrored and the glyphs generated again.
2022 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
2029 mImpl->mLayoutDirection = layoutDirection;
2032 // Make sure the model is up-to-date before layouting.
2033 ProcessModifyEvents();
2034 bool updated = mImpl->UpdateModel(mImpl->mOperationsPending);
2038 updated = DoRelayout(size,
2039 mImpl->mOperationsPending,
2045 updateTextType = MODEL_UPDATED;
2048 // Do not re-do any operation until something changes.
2049 mImpl->mOperationsPending = NO_OPERATION;
2050 mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2052 // Whether the text control is editable
2053 const bool isEditable = NULL != mImpl->mEventData;
2055 // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2057 if(newSize && isEditable)
2059 offset = mImpl->mModel->mScrollPosition;
2062 if(!isEditable || !IsMultiLineEnabled())
2064 // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2065 CalculateVerticalOffset(size);
2072 // If there is a new size, the scroll position needs to be clamped.
2073 mImpl->ClampHorizontalScroll(layoutSize);
2075 // Update the decorator's positions is needed if there is a new size.
2076 mImpl->mEventData->mDecorator->UpdatePositions(mImpl->mModel->mScrollPosition - offset);
2079 // Move the cursor, grab handle etc.
2080 if(mImpl->ProcessInputEvents())
2082 updateTextType = static_cast<UpdateTextType>(updateTextType | DECORATOR_UPDATED);
2086 // Clear the update info. This info will be set the next time the text is updated.
2087 mImpl->mTextUpdateInfo.Clear();
2088 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayout\n");
2090 return updateTextType;
2093 void Controller::RequestRelayout()
2095 mImpl->RequestRelayout();
2098 // public : Input style change signals.
2100 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2102 return (NULL == mImpl->mEventData) || (0u == mImpl->mEventData->mInputStyleChangedQueue.Count());
2105 void Controller::ProcessInputStyleChangedSignals()
2107 if(NULL == mImpl->mEventData)
2113 for(Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2114 endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2118 const InputStyle::Mask mask = *it;
2120 if(NULL != mImpl->mEditableControlInterface)
2122 // Emit the input style changed signal.
2123 mImpl->mEditableControlInterface->InputStyleChanged(mask);
2127 mImpl->mEventData->mInputStyleChangedQueue.Clear();
2130 // public : Text-input Event Queuing.
2132 void Controller::KeyboardFocusGainEvent()
2134 EventHandler::KeyboardFocusGainEvent(*this);
2137 void Controller::KeyboardFocusLostEvent()
2139 EventHandler::KeyboardFocusLostEvent(*this);
2142 bool Controller::KeyEvent(const Dali::KeyEvent& keyEvent)
2144 return EventHandler::KeyEvent(*this, keyEvent);
2147 void Controller::TapEvent(unsigned int tapCount, float x, float y)
2149 EventHandler::TapEvent(*this, tapCount, x, y);
2152 void Controller::PanEvent(GestureState state, const Vector2& displacement)
2154 EventHandler::PanEvent(*this, state, displacement);
2157 void Controller::LongPressEvent(GestureState state, float x, float y)
2159 EventHandler::LongPressEvent(*this, state, x, y);
2162 void Controller::SelectEvent(float x, float y, SelectionType selectType)
2164 EventHandler::SelectEvent(*this, x, y, selectType);
2167 void Controller::SetTextSelectionRange(const uint32_t* start, const uint32_t* end)
2169 if(mImpl->mEventData)
2171 mImpl->mEventData->mCheckScrollAmount = true;
2172 mImpl->mEventData->mIsLeftHandleSelected = true;
2173 mImpl->mEventData->mIsRightHandleSelected = true;
2174 mImpl->SetTextSelectionRange(start, end);
2175 mImpl->RequestRelayout();
2176 KeyboardFocusGainEvent();
2180 Uint32Pair Controller::GetTextSelectionRange() const
2182 return mImpl->GetTextSelectionRange();
2185 void Controller::SelectWholeText()
2187 SelectEvent(0.f, 0.f, SelectionType::ALL);
2190 void Controller::SelectNone()
2192 SelectEvent(0.f, 0.f, SelectionType::NONE);
2195 string Controller::GetSelectedText() const
2198 if(EventData::SELECTING == mImpl->mEventData->mState)
2200 mImpl->RetrieveSelection(text, false);
2205 InputMethodContext::CallbackData Controller::OnInputMethodContextEvent(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
2207 return EventHandler::OnInputMethodContextEvent(*this, inputMethodContext, inputMethodContextEvent);
2210 void Controller::PasteClipboardItemEvent()
2212 EventHandler::PasteClipboardItemEvent(*this);
2215 // protected : Inherit from Text::Decorator::ControllerInterface.
2217 void Controller::GetTargetSize(Vector2& targetSize)
2219 targetSize = mImpl->mModel->mVisualModel->mControlSize;
2222 void Controller::AddDecoration(Actor& actor, bool needsClipping)
2224 if(NULL != mImpl->mEditableControlInterface)
2226 mImpl->mEditableControlInterface->AddDecoration(actor, needsClipping);
2230 bool Controller::IsEditable() const
2232 return mImpl->IsEditable();
2235 void Controller::SetEditable(bool editable)
2237 mImpl->SetEditable(editable);
2238 if(mImpl->mEventData && mImpl->mEventData->mDecorator)
2240 mImpl->mEventData->mDecorator->SetEditable(editable);
2244 void Controller::DecorationEvent(HandleType handleType, HandleState state, float x, float y)
2246 EventHandler::DecorationEvent(*this, handleType, state, x, y);
2249 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2251 void Controller::TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::Buttons button)
2253 EventHandler::TextPopupButtonTouched(*this, button);
2256 void Controller::DisplayTimeExpired()
2258 mImpl->mEventData->mUpdateCursorPosition = true;
2259 // Apply modifications to the model
2260 mImpl->mOperationsPending = ALL_OPERATIONS;
2262 mImpl->RequestRelayout();
2265 // private : Update.
2267 void Controller::InsertText(const std::string& text, Controller::InsertType type)
2269 bool removedPrevious = false;
2270 bool removedSelected = false;
2271 bool maxLengthReached = false;
2273 DALI_ASSERT_DEBUG(NULL != mImpl->mEventData && "Unexpected InsertText")
2275 if(NULL == mImpl->mEventData)
2280 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);
2282 // TODO: At the moment the underline runs are only for pre-edit.
2283 mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
2285 // Remove the previous InputMethodContext pre-edit.
2286 if(mImpl->mEventData->mPreEditFlag && (0u != mImpl->mEventData->mPreEditLength))
2288 removedPrevious = RemoveText(-static_cast<int>(mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition),
2289 mImpl->mEventData->mPreEditLength,
2290 DONT_UPDATE_INPUT_STYLE);
2292 mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2293 mImpl->mEventData->mPreEditLength = 0u;
2297 // Remove the previous Selection.
2298 removedSelected = RemoveSelectedText();
2301 Vector<Character> utf32Characters;
2302 Length characterCount = 0u;
2306 // Convert text into UTF-32
2307 utf32Characters.Resize(text.size());
2309 // This is a bit horrible but std::string returns a (signed) char*
2310 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
2312 // Transform a text array encoded in utf8 into an array encoded in utf32.
2313 // It returns the actual number of characters.
2314 characterCount = Utf8ToUtf32(utf8, text.size(), utf32Characters.Begin());
2315 utf32Characters.Resize(characterCount);
2317 DALI_ASSERT_DEBUG(text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length");
2318 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count());
2320 // Play the input text with the TTS player.
2321 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
2324 if(type == COMMIT && mImpl->mEventData->mPreEditToCommitFlag)
2326 if(characterCount > 1u)
2328 std::string ttsText = text;
2329 if(text.length() > mImpl->mEventData->mPreEditTextLength)
2331 ttsText = text.substr(mImpl->mEventData->mPreEditTextLength);
2333 player.Play(ttsText);
2343 // PRE_EDIT type empty text is inserted before the preedit input is converted to commit.
2344 if(text.empty() && type == PRE_EDIT)
2346 mImpl->mEventData->mPreEditToCommitFlag = true;
2349 if(0u != utf32Characters.Count()) // Check if Utf8ToUtf32 conversion succeeded
2351 // The placeholder text is no longer needed
2352 if(mImpl->IsShowingPlaceholderText())
2357 mImpl->ChangeState(EventData::EDITING);
2358 mImpl->mEventData->mPreEditToCommitFlag = false;
2360 // Handle the InputMethodContext (predicitive text) state changes
2363 // InputMethodContext is no longer handling key-events
2364 mImpl->ClearPreEditFlag();
2368 if(!mImpl->mEventData->mPreEditFlag)
2370 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Entered PreEdit state\n");
2372 // Record the start of the pre-edit text
2373 mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2376 mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2377 mImpl->mEventData->mPreEditTextLength = text.length();
2378 mImpl->mEventData->mPreEditFlag = true;
2380 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength);
2383 const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
2385 // Restrict new text to fit within Maximum characters setting.
2386 Length maxSizeOfNewText = std::min((mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel), characterCount);
2387 maxLengthReached = (characterCount > maxSizeOfNewText);
2389 // The cursor position.
2390 CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2392 // Update the text's style.
2394 // Updates the text style runs by adding characters.
2395 mImpl->mModel->mLogicalModel->UpdateTextStyleRuns(cursorIndex, maxSizeOfNewText);
2397 // Get the character index from the cursor index.
2398 const CharacterIndex styleIndex = (cursorIndex > 0u) ? cursorIndex - 1u : 0u;
2400 // Retrieve the text's style for the given index.
2402 mImpl->RetrieveDefaultInputStyle(style);
2403 mImpl->mModel->mLogicalModel->RetrieveStyle(styleIndex, style);
2405 // Whether to add a new text color run.
2406 const bool addColorRun = (style.textColor != mImpl->mEventData->mInputStyle.textColor) && !mImpl->mEventData->mInputStyle.isDefaultColor;
2408 // Whether to add a new font run.
2409 const bool addFontNameRun = (style.familyName != mImpl->mEventData->mInputStyle.familyName) && mImpl->mEventData->mInputStyle.isFamilyDefined;
2410 const bool addFontWeightRun = (style.weight != mImpl->mEventData->mInputStyle.weight) && mImpl->mEventData->mInputStyle.isWeightDefined;
2411 const bool addFontWidthRun = (style.width != mImpl->mEventData->mInputStyle.width) && mImpl->mEventData->mInputStyle.isWidthDefined;
2412 const bool addFontSlantRun = (style.slant != mImpl->mEventData->mInputStyle.slant) && mImpl->mEventData->mInputStyle.isSlantDefined;
2413 const bool addFontSizeRun = (style.size != mImpl->mEventData->mInputStyle.size) && mImpl->mEventData->mInputStyle.isSizeDefined;
2418 const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
2419 mImpl->mModel->mLogicalModel->mColorRuns.Resize(numberOfRuns + 1u);
2421 ColorRun& colorRun = *(mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns);
2422 colorRun.color = mImpl->mEventData->mInputStyle.textColor;
2423 colorRun.characterRun.characterIndex = cursorIndex;
2424 colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2427 if(addFontNameRun ||
2433 const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
2434 mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize(numberOfRuns + 1u);
2436 FontDescriptionRun& fontDescriptionRun = *(mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns);
2440 fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
2441 fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
2442 memcpy(fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength);
2443 fontDescriptionRun.familyDefined = true;
2445 // The memory allocated for the font family name is freed when the font description is removed from the logical model.
2448 if(addFontWeightRun)
2450 fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
2451 fontDescriptionRun.weightDefined = true;
2456 fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
2457 fontDescriptionRun.widthDefined = true;
2462 fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
2463 fontDescriptionRun.slantDefined = true;
2468 fontDescriptionRun.size = static_cast<PointSize26Dot6>(mImpl->mEventData->mInputStyle.size * 64.f);
2469 fontDescriptionRun.sizeDefined = true;
2472 fontDescriptionRun.characterRun.characterIndex = cursorIndex;
2473 fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2476 // Insert at current cursor position.
2477 Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
2479 if(cursorIndex < numberOfCharactersInModel)
2481 modifyText.Insert(modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText);
2485 modifyText.Insert(modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText);
2488 // Mark the first paragraph to be updated.
2489 if(Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout())
2491 mImpl->mTextUpdateInfo.mCharacterIndex = 0;
2492 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2493 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
2494 mImpl->mTextUpdateInfo.mClearAll = true;
2498 mImpl->mTextUpdateInfo.mCharacterIndex = std::min(cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex);
2499 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
2502 // Update the cursor index.
2503 cursorIndex += maxSizeOfNewText;
2505 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);
2508 if((0u == mImpl->mModel->mLogicalModel->mText.Count()) &&
2509 mImpl->IsPlaceholderAvailable())
2511 // Show place-holder if empty after removing the pre-edit text
2512 ShowPlaceholderText();
2513 mImpl->mEventData->mUpdateCursorPosition = true;
2514 mImpl->ClearPreEditFlag();
2516 else if(removedPrevious ||
2518 (0 != utf32Characters.Count()))
2520 // Queue an inserted event
2521 mImpl->QueueModifyEvent(ModifyEvent::TEXT_INSERTED);
2523 mImpl->mEventData->mUpdateCursorPosition = true;
2526 mImpl->mEventData->mScrollAfterDelete = true;
2530 mImpl->mEventData->mScrollAfterUpdatePosition = true;
2534 if(maxLengthReached)
2536 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count());
2538 mImpl->ResetInputMethodContext();
2540 if(NULL != mImpl->mEditableControlInterface)
2542 // Do this last since it provides callbacks into application code
2543 mImpl->mEditableControlInterface->MaxLengthReached();
2548 void Controller::PasteText(const std::string& stringToPaste)
2550 InsertText(stringToPaste, Text::Controller::COMMIT);
2551 mImpl->ChangeState(EventData::EDITING);
2552 mImpl->RequestRelayout();
2554 if(NULL != mImpl->mEditableControlInterface)
2556 // Do this last since it provides callbacks into application code
2557 mImpl->mEditableControlInterface->TextChanged(true);
2561 bool Controller::RemoveText(int cursorOffset,
2562 int numberOfCharacters,
2563 UpdateInputStyleType type)
2565 bool removed = false;
2566 bool removeAll = false;
2568 if(NULL == mImpl->mEventData)
2573 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);
2575 if(!mImpl->IsShowingPlaceholderText())
2577 // Delete at current cursor position
2578 Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
2579 CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2581 CharacterIndex cursorIndex = 0;
2583 // Validate the cursor position & number of characters
2584 if((static_cast<int>(mImpl->mEventData->mPrimaryCursorPosition) + cursorOffset) >= 0)
2586 cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
2589 if((cursorIndex + numberOfCharacters) > currentText.Count())
2591 numberOfCharacters = currentText.Count() - cursorIndex;
2594 if((cursorIndex == 0) && (currentText.Count() - numberOfCharacters == 0))
2599 if(mImpl->mEventData->mPreEditFlag || removeAll || // 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.
2600 ((cursorIndex + numberOfCharacters) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters))
2602 // Mark the paragraphs to be updated.
2603 if(Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout())
2605 mImpl->mTextUpdateInfo.mCharacterIndex = 0;
2606 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2607 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
2608 mImpl->mTextUpdateInfo.mClearAll = true;
2612 mImpl->mTextUpdateInfo.mCharacterIndex = std::min(cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex);
2613 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
2616 // Update the input style and remove the text's style before removing the text.
2618 if(UPDATE_INPUT_STYLE == type)
2620 // Keep a copy of the current input style.
2621 InputStyle currentInputStyle;
2622 currentInputStyle.Copy(mImpl->mEventData->mInputStyle);
2624 // Set first the default input style.
2625 mImpl->RetrieveDefaultInputStyle(mImpl->mEventData->mInputStyle);
2627 // Update the input style.
2628 mImpl->mModel->mLogicalModel->RetrieveStyle(cursorIndex, mImpl->mEventData->mInputStyle);
2630 // Compare if the input style has changed.
2631 const bool hasInputStyleChanged = !currentInputStyle.Equal(mImpl->mEventData->mInputStyle);
2633 if(hasInputStyleChanged)
2635 const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(mImpl->mEventData->mInputStyle);
2636 // Queue the input style changed signal.
2637 mImpl->mEventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
2641 // If the number of current text and the number of characters to be deleted are same,
2642 // it means all texts should be removed and all Preedit variables should be initialized.
2645 mImpl->ClearPreEditFlag();
2646 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0;
2649 // Updates the text style runs by removing characters. Runs with no characters are removed.
2650 mImpl->mModel->mLogicalModel->UpdateTextStyleRuns(cursorIndex, -numberOfCharacters);
2652 // Remove the characters.
2653 Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
2654 Vector<Character>::Iterator last = first + numberOfCharacters;
2656 currentText.Erase(first, last);
2658 // Cursor position retreat
2659 oldCursorIndex = cursorIndex;
2661 mImpl->mEventData->mScrollAfterDelete = true;
2663 if(EventData::INACTIVE == mImpl->mEventData->mState)
2665 mImpl->ChangeState(EventData::EDITING);
2668 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters);
2677 bool Controller::RemoveSelectedText()
2679 bool textRemoved(false);
2681 if(EventData::SELECTING == mImpl->mEventData->mState)
2683 std::string removedString;
2684 mImpl->RetrieveSelection(removedString, true);
2686 if(!removedString.empty())
2689 mImpl->ChangeState(EventData::EDITING);
2696 // private : Relayout.
2698 bool Controller::DoRelayout(const Size& size,
2699 OperationsMask operationsRequired,
2702 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height);
2703 bool viewUpdated(false);
2705 // Calculate the operations to be done.
2706 const OperationsMask operations = static_cast<OperationsMask>(mImpl->mOperationsPending & operationsRequired);
2708 const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
2709 const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
2711 // Get the current layout size.
2712 layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2714 if(NO_OPERATION != (LAYOUT & operations))
2716 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
2718 // Some vectors with data needed to layout and reorder may be void
2719 // after the first time the text has been laid out.
2720 // Fill the vectors again.
2722 // Calculate the number of glyphs to layout.
2723 const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
2724 const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
2725 const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
2726 const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
2728 const CharacterIndex lastIndex = startIndex + ((requestedNumberOfCharacters > 0u) ? requestedNumberOfCharacters - 1u : 0u);
2729 const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
2731 // Make sure the index is not out of bound
2732 if(charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
2733 requestedNumberOfCharacters > charactersToGlyph.Count() ||
2734 (lastIndex > charactersToGlyph.Count() && charactersToGlyph.Count() > 0u))
2736 std::string currentText;
2737 GetText(currentText);
2739 DALI_LOG_ERROR("Controller::DoRelayout: Attempting to access invalid buffer\n");
2740 DALI_LOG_ERROR("Current text is: %s\n", currentText.c_str());
2741 DALI_LOG_ERROR("startIndex: %u, lastIndex: %u, requestedNumberOfCharacters: %u, charactersToGlyph.Count = %lu, glyphsPerCharacter.Count = %lu\n", startIndex, lastIndex, requestedNumberOfCharacters, charactersToGlyph.Count(), glyphsPerCharacter.Count());
2746 const Length numberOfGlyphs = (requestedNumberOfCharacters > 0u) ? *(charactersToGlyphBuffer + lastIndex) + *(glyphsPerCharacterBuffer + lastIndex) - startGlyphIndex : 0u;
2747 const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
2749 if(0u == totalNumberOfGlyphs)
2751 if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations))
2753 mImpl->mModel->mVisualModel->SetLayoutSize(Size::ZERO);
2756 // Nothing else to do if there is no glyphs.
2757 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n");
2761 // Set the layout parameters.
2762 Layout::Parameters layoutParameters(size,
2765 // Resize the vector of positions to have the same size than the vector of glyphs.
2766 Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
2767 glyphPositions.Resize(totalNumberOfGlyphs);
2769 // Whether the last character is a new paragraph character.
2770 const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
2771 mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph = TextAbstraction::IsNewParagraph(*(textBuffer + (mImpl->mModel->mLogicalModel->mText.Count() - 1u)));
2772 layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
2774 // The initial glyph and the number of glyphs to layout.
2775 layoutParameters.startGlyphIndex = startGlyphIndex;
2776 layoutParameters.numberOfGlyphs = numberOfGlyphs;
2777 layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
2778 layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
2780 // Update the ellipsis
2781 bool elideTextEnabled = mImpl->mModel->mElideEnabled;
2783 if(NULL != mImpl->mEventData)
2785 if(mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText())
2787 elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
2789 else if(EventData::INACTIVE != mImpl->mEventData->mState)
2791 // Disable ellipsis when editing
2792 elideTextEnabled = false;
2795 // Reset the scroll position in inactive state
2796 if(elideTextEnabled && (mImpl->mEventData->mState == EventData::INACTIVE))
2798 ResetScrollPosition();
2802 // Update the visual model.
2803 bool isAutoScrollEnabled = mImpl->mIsAutoScrollEnabled;
2805 viewUpdated = mImpl->mLayoutEngine.LayoutText(layoutParameters,
2808 isAutoScrollEnabled);
2809 mImpl->mIsAutoScrollEnabled = isAutoScrollEnabled;
2811 viewUpdated = viewUpdated || (newLayoutSize != layoutSize);
2815 layoutSize = newLayoutSize;
2817 if(NO_OPERATION != (UPDATE_DIRECTION & operations))
2819 mImpl->mIsTextDirectionRTL = false;
2822 if((NO_OPERATION != (UPDATE_DIRECTION & operations)) && !mImpl->mModel->mVisualModel->mLines.Empty())
2824 mImpl->mIsTextDirectionRTL = mImpl->mModel->mVisualModel->mLines[0u].direction;
2827 // Sets the layout size.
2828 if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations))
2830 mImpl->mModel->mVisualModel->SetLayoutSize(layoutSize);
2835 if(NO_OPERATION != (ALIGN & operations))
2837 // The laid-out lines.
2838 Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
2840 CharacterIndex alignStartIndex = startIndex;
2841 Length alignRequestedNumberOfCharacters = requestedNumberOfCharacters;
2843 // the whole text needs to be full aligned.
2844 // If you do not do a full aligned, only the last line of the multiline input is aligned.
2845 if(mImpl->mEventData && mImpl->mEventData->mUpdateAlignment)
2847 alignStartIndex = 0u;
2848 alignRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
2849 mImpl->mEventData->mUpdateAlignment = false;
2852 // Need to align with the control's size as the text may contain lines
2853 // starting either with left to right text or right to left.
2854 mImpl->mLayoutEngine.Align(size,
2856 alignRequestedNumberOfCharacters,
2857 mImpl->mModel->mHorizontalAlignment,
2859 mImpl->mModel->mAlignmentOffset,
2860 mImpl->mLayoutDirection,
2861 mImpl->mModel->mMatchSystemLanguageDirection);
2865 #if defined(DEBUG_ENABLED)
2866 std::string currentText;
2867 GetText(currentText);
2868 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", this, (mImpl->mIsTextDirectionRTL) ? "true" : "false", currentText.c_str());
2870 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", (viewUpdated ? "true" : "false"));
2874 void Controller::CalculateVerticalOffset(const Size& controlSize)
2876 ModelPtr& model = mImpl->mModel;
2877 VisualModelPtr& visualModel = model->mVisualModel;
2878 Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2879 Size oldLayoutSize = layoutSize;
2880 float offsetY = 0.f;
2881 bool needRecalc = false;
2882 float defaultFontLineHeight = mImpl->GetDefaultFontLineHeight();
2884 if(fabsf(layoutSize.height) < Math::MACHINE_EPSILON_1000)
2886 // Get the line height of the default font.
2887 layoutSize.height = defaultFontLineHeight;
2890 // Whether the text control is editable
2891 const bool isEditable = NULL != mImpl->mEventData;
2892 if(isEditable && layoutSize.height != defaultFontLineHeight)
2894 // This code prevents the wrong positioning of cursor when the layout size is bigger/smaller than defaultFontLineHeight.
2895 // This situation occurs when the size of placeholder text is different from the default text.
2896 layoutSize.height = defaultFontLineHeight;
2900 switch(mImpl->mModel->mVerticalAlignment)
2902 case VerticalAlignment::TOP:
2904 mImpl->mModel->mScrollPosition.y = 0.f;
2908 case VerticalAlignment::CENTER:
2910 mImpl->mModel->mScrollPosition.y = floorf(0.5f * (controlSize.height - layoutSize.height)); // try to avoid pixel alignment.
2911 if(needRecalc) offsetY = floorf(0.5f * (layoutSize.height - oldLayoutSize.height));
2914 case VerticalAlignment::BOTTOM:
2916 mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
2917 if(needRecalc) offsetY = layoutSize.height - oldLayoutSize.height;
2924 // Update glyphPositions according to recalculation.
2925 const Length positionCount = visualModel->mGlyphPositions.Count();
2926 Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
2927 for(Length index = 0u; index < positionCount; index++)
2929 glyphPositions[index].y += offsetY;
2934 // private : Events.
2936 void Controller::ProcessModifyEvents()
2938 EventHandler::ProcessModifyEvents(*this);
2941 void Controller::TextReplacedEvent()
2943 EventHandler::TextReplacedEvent(*this);
2946 void Controller::TextInsertedEvent()
2948 EventHandler::TextInsertedEvent(*this);
2951 void Controller::TextDeletedEvent()
2953 EventHandler::TextDeletedEvent(*this);
2956 bool Controller::DeleteEvent(int keyCode)
2958 return EventHandler::DeleteEvent(*this, keyCode);
2961 // private : Helpers.
2963 void Controller::ResetText()
2966 mImpl->mModel->mLogicalModel->mText.Clear();
2968 // Reset the embedded images buffer.
2969 mImpl->mModel->mLogicalModel->ClearEmbeddedImages();
2971 // We have cleared everything including the placeholder-text
2972 mImpl->PlaceholderCleared();
2974 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2975 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2976 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
2978 // Clear any previous text.
2979 mImpl->mTextUpdateInfo.mClearAll = true;
2981 // The natural size needs to be re-calculated.
2982 mImpl->mRecalculateNaturalSize = true;
2984 // The text direction needs to be updated.
2985 mImpl->mUpdateTextDirection = true;
2987 // Apply modifications to the model
2988 mImpl->mOperationsPending = ALL_OPERATIONS;
2991 void Controller::ShowPlaceholderText()
2993 if(mImpl->IsPlaceholderAvailable())
2995 DALI_ASSERT_DEBUG(mImpl->mEventData && "No placeholder text available");
2997 if(NULL == mImpl->mEventData)
3002 mImpl->mEventData->mIsShowingPlaceholderText = true;
3004 // Disable handles when showing place-holder text
3005 mImpl->mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
3006 mImpl->mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
3007 mImpl->mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
3009 const char* text(NULL);
3012 // TODO - Switch Placeholder text when changing state
3013 if((EventData::INACTIVE != mImpl->mEventData->mState) &&
3014 (0u != mImpl->mEventData->mPlaceholderTextActive.c_str()))
3016 text = mImpl->mEventData->mPlaceholderTextActive.c_str();
3017 size = mImpl->mEventData->mPlaceholderTextActive.size();
3021 text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
3022 size = mImpl->mEventData->mPlaceholderTextInactive.size();
3025 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3026 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3028 // Reset model for showing placeholder.
3029 mImpl->mModel->mLogicalModel->mText.Clear();
3030 mImpl->mModel->mVisualModel->SetTextColor(mImpl->mEventData->mPlaceholderTextColor);
3032 // Convert text into UTF-32
3033 Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
3034 utf32Characters.Resize(size);
3036 // This is a bit horrible but std::string returns a (signed) char*
3037 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text);
3039 // Transform a text array encoded in utf8 into an array encoded in utf32.
3040 // It returns the actual number of characters.
3041 const Length characterCount = Utf8ToUtf32(utf8, size, utf32Characters.Begin());
3042 utf32Characters.Resize(characterCount);
3044 // The characters to be added.
3045 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
3047 // Reset the cursor position
3048 mImpl->mEventData->mPrimaryCursorPosition = 0;
3050 // The natural size needs to be re-calculated.
3051 mImpl->mRecalculateNaturalSize = true;
3053 // The text direction needs to be updated.
3054 mImpl->mUpdateTextDirection = true;
3056 // Apply modifications to the model
3057 mImpl->mOperationsPending = ALL_OPERATIONS;
3059 // Update the rest of the model during size negotiation
3060 mImpl->QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
3064 void Controller::ClearFontData()
3066 if(mImpl->mFontDefaults)
3068 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
3071 // Set flags to update the model.
3072 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3073 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3074 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
3076 mImpl->mTextUpdateInfo.mClearAll = true;
3077 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
3078 mImpl->mRecalculateNaturalSize = true;
3080 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
3086 UPDATE_LAYOUT_SIZE |
3091 void Controller::ClearStyleData()
3093 mImpl->mModel->mLogicalModel->mColorRuns.Clear();
3094 mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
3097 void Controller::ResetCursorPosition(CharacterIndex cursorIndex)
3099 // Reset the cursor position
3100 if(NULL != mImpl->mEventData)
3102 mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
3104 // Update the cursor if it's in editing mode.
3105 if(EventData::IsEditingState(mImpl->mEventData->mState))
3107 mImpl->mEventData->mUpdateCursorPosition = true;
3112 void Controller::ResetScrollPosition()
3114 if(NULL != mImpl->mEventData)
3116 // Reset the scroll position.
3117 mImpl->mModel->mScrollPosition = Vector2::ZERO;
3118 mImpl->mEventData->mScrollAfterUpdatePosition = true;
3122 void Controller::SetControlInterface(ControlInterface* controlInterface)
3124 mImpl->mControlInterface = controlInterface;
3127 bool Controller::ShouldClearFocusOnEscape() const
3129 return mImpl->mShouldClearFocusOnEscape;
3132 Actor Controller::CreateBackgroundActor()
3134 return mImpl->CreateBackgroundActor();
3137 // private : Private contructors & copy operator.
3139 Controller::Controller()
3140 : Controller(nullptr, nullptr, nullptr)
3144 Controller::Controller(ControlInterface* controlInterface)
3145 : Controller(controlInterface, nullptr, nullptr)
3149 Controller::Controller(ControlInterface* controlInterface,
3150 EditableControlInterface* editableControlInterface,
3151 SelectableControlInterface* selectableControlInterface)
3152 : mImpl(new Controller::Impl(controlInterface, editableControlInterface, selectableControlInterface))
3156 // The copy constructor and operator are left unimplemented.
3158 // protected : Destructor.
3160 Controller::~Controller()
3167 } // namespace Toolkit