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>
28 #include <dali-toolkit/internal/text/character-set-conversion.h>
29 #include <dali-toolkit/internal/text/layouts/layout-parameters.h>
30 #include <dali-toolkit/internal/text/markup-processor.h>
31 #include <dali-toolkit/internal/text/text-controller-event-handler.h>
32 #include <dali-toolkit/internal/text/text-controller-impl.h>
33 #include <dali-toolkit/internal/text/text-controller-input-font-handler.h>
34 #include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
35 #include <dali-toolkit/internal/text/text-editable-control-interface.h>
39 #if defined(DEBUG_ENABLED)
40 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
43 const float MAX_FLOAT = std::numeric_limits<float>::max();
45 const std::string EMPTY_STRING("");
47 float ConvertToEven(float value)
49 int intValue(static_cast<int>(value));
50 return static_cast<float>(intValue + (intValue & 1));
53 int ConvertPixelToPint(float pixel)
55 unsigned int horizontalDpi = 0u;
56 unsigned int verticalDpi = 0u;
57 Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
58 fontClient.GetDpi(horizontalDpi, verticalDpi);
60 return (pixel * 72.f) / static_cast<float>(horizontalDpi);
71 // public : Constructor.
73 ControllerPtr Controller::New()
75 return ControllerPtr(new Controller());
78 ControllerPtr Controller::New(ControlInterface* controlInterface)
80 return ControllerPtr(new Controller(controlInterface));
83 ControllerPtr Controller::New(ControlInterface* controlInterface,
84 EditableControlInterface* editableControlInterface,
85 SelectableControlInterface* selectableControlInterface)
87 return ControllerPtr(new Controller(controlInterface,
88 editableControlInterface,
89 selectableControlInterface));
92 // public : Configure the text controller.
94 void Controller::EnableTextInput(DecoratorPtr decorator, InputMethodContext& inputMethodContext)
98 delete mImpl->mEventData;
99 mImpl->mEventData = NULL;
101 // Nothing else to do.
105 if(NULL == mImpl->mEventData)
107 mImpl->mEventData = new EventData(decorator, inputMethodContext);
111 void Controller::SetGlyphType(TextAbstraction::GlyphType glyphType)
113 // Metrics for bitmap & vector based glyphs are different
114 mImpl->mMetrics->SetGlyphType(glyphType);
116 // Clear the font-specific data
119 mImpl->RequestRelayout();
122 void Controller::SetMarkupProcessorEnabled(bool enable)
124 if(enable != mImpl->mMarkupProcessorEnabled)
126 //If Text was already set, call the SetText again for enabling or disabling markup
127 mImpl->mMarkupProcessorEnabled = enable;
134 bool Controller::IsMarkupProcessorEnabled() const
136 return mImpl->mMarkupProcessorEnabled;
139 void Controller::SetAutoScrollEnabled(bool enable)
141 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);
143 if(mImpl->mLayoutEngine.GetLayout() == Layout::Engine::SINGLE_LINE_BOX)
147 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled for SINGLE_LINE_BOX\n");
148 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
157 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetAutoScrollEnabled Disabling autoscroll\n");
158 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
165 mImpl->mIsAutoScrollEnabled = enable;
166 mImpl->RequestRelayout();
170 DALI_LOG_WARNING("Attempted AutoScrolling on a non SINGLE_LINE_BOX, request ignored\n");
171 mImpl->mIsAutoScrollEnabled = false;
175 bool Controller::IsAutoScrollEnabled() const
177 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::IsAutoScrollEnabled[%s]\n", mImpl->mIsAutoScrollEnabled ? "true" : "false");
179 return mImpl->mIsAutoScrollEnabled;
182 CharacterDirection Controller::GetAutoScrollDirection() const
184 return mImpl->mIsTextDirectionRTL;
187 float Controller::GetAutoScrollLineAlignment() const
191 if(mImpl->mModel->mVisualModel &&
192 (0u != mImpl->mModel->mVisualModel->mLines.Count()))
194 offset = (*mImpl->mModel->mVisualModel->mLines.Begin()).alignmentOffset;
200 void Controller::SetHorizontalScrollEnabled(bool enable)
202 if((NULL != mImpl->mEventData) &&
203 mImpl->mEventData->mDecorator)
205 mImpl->mEventData->mDecorator->SetHorizontalScrollEnabled(enable);
208 bool Controller::IsHorizontalScrollEnabled() const
210 if((NULL != mImpl->mEventData) &&
211 mImpl->mEventData->mDecorator)
213 return mImpl->mEventData->mDecorator->IsHorizontalScrollEnabled();
219 void Controller::SetVerticalScrollEnabled(bool enable)
221 if((NULL != mImpl->mEventData) &&
222 mImpl->mEventData->mDecorator)
224 if(mImpl->mEventData->mDecorator)
226 mImpl->mEventData->mDecorator->SetVerticalScrollEnabled(enable);
231 bool Controller::IsVerticalScrollEnabled() const
233 if((NULL != mImpl->mEventData) &&
234 mImpl->mEventData->mDecorator)
236 return mImpl->mEventData->mDecorator->IsVerticalScrollEnabled();
242 void Controller::SetSmoothHandlePanEnabled(bool enable)
244 if((NULL != mImpl->mEventData) &&
245 mImpl->mEventData->mDecorator)
247 mImpl->mEventData->mDecorator->SetSmoothHandlePanEnabled(enable);
251 bool Controller::IsSmoothHandlePanEnabled() const
253 if((NULL != mImpl->mEventData) &&
254 mImpl->mEventData->mDecorator)
256 return mImpl->mEventData->mDecorator->IsSmoothHandlePanEnabled();
262 void Controller::SetMaximumNumberOfCharacters(Length maxCharacters)
264 mImpl->mMaximumNumberOfCharacters = maxCharacters;
267 int Controller::GetMaximumNumberOfCharacters()
269 return mImpl->mMaximumNumberOfCharacters;
272 void Controller::SetEnableCursorBlink(bool enable)
274 DALI_ASSERT_DEBUG(NULL != mImpl->mEventData && "TextInput disabled");
276 if(NULL != mImpl->mEventData)
278 mImpl->mEventData->mCursorBlinkEnabled = enable;
281 mImpl->mEventData->mDecorator)
283 mImpl->mEventData->mDecorator->StopCursorBlink();
288 bool Controller::GetEnableCursorBlink() const
290 if(NULL != mImpl->mEventData)
292 return mImpl->mEventData->mCursorBlinkEnabled;
298 void Controller::SetMultiLineEnabled(bool enable)
300 const Layout::Engine::Type layout = enable ? Layout::Engine::MULTI_LINE_BOX : Layout::Engine::SINGLE_LINE_BOX;
302 if(layout != mImpl->mLayoutEngine.GetLayout())
304 // Set the layout type.
305 mImpl->mLayoutEngine.SetLayout(layout);
307 // Set the flags to redo the layout operations
308 const OperationsMask layoutOperations = static_cast<OperationsMask>(LAYOUT |
313 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
314 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | layoutOperations);
316 // Need to recalculate natural size
317 mImpl->mRecalculateNaturalSize = true;
319 mImpl->RequestRelayout();
323 bool Controller::IsMultiLineEnabled() const
325 return Layout::Engine::MULTI_LINE_BOX == mImpl->mLayoutEngine.GetLayout();
328 void Controller::SetHorizontalAlignment(Text::HorizontalAlignment::Type alignment)
330 if(alignment != mImpl->mModel->mHorizontalAlignment)
332 // Set the alignment.
333 mImpl->mModel->mHorizontalAlignment = alignment;
335 // Set the flag to redo the alignment operation.
336 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | ALIGN);
338 if(mImpl->mEventData)
340 mImpl->mEventData->mUpdateAlignment = true;
342 // Update the cursor if it's in editing mode
343 if(EventData::IsEditingState(mImpl->mEventData->mState))
345 mImpl->ChangeState(EventData::EDITING);
346 mImpl->mEventData->mUpdateCursorPosition = true;
350 mImpl->RequestRelayout();
354 Text::HorizontalAlignment::Type Controller::GetHorizontalAlignment() const
356 return mImpl->mModel->mHorizontalAlignment;
359 void Controller::SetVerticalAlignment(VerticalAlignment::Type alignment)
361 if(alignment != mImpl->mModel->mVerticalAlignment)
363 // Set the alignment.
364 mImpl->mModel->mVerticalAlignment = alignment;
366 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | ALIGN);
368 mImpl->RequestRelayout();
372 VerticalAlignment::Type Controller::GetVerticalAlignment() const
374 return mImpl->mModel->mVerticalAlignment;
377 bool Controller::IsIgnoreSpacesAfterText() const
379 return mImpl->mModel->mIgnoreSpacesAfterText;
382 void Controller::SetIgnoreSpacesAfterText(bool ignore)
384 mImpl->mModel->mIgnoreSpacesAfterText = ignore;
387 bool Controller::IsMatchSystemLanguageDirection() const
389 return mImpl->mModel->mMatchSystemLanguageDirection;
392 void Controller::SetMatchSystemLanguageDirection(bool match)
394 mImpl->mModel->mMatchSystemLanguageDirection = match;
397 void Controller::SetLayoutDirection(Dali::LayoutDirection::Type layoutDirection)
399 mImpl->mLayoutDirection = layoutDirection;
402 bool Controller::IsShowingRealText() const
404 return mImpl->IsShowingRealText();
407 void Controller::SetLineWrapMode(Text::LineWrap::Mode lineWrapMode)
409 if(lineWrapMode != mImpl->mModel->mLineWrapMode)
411 // Set the text wrap mode.
412 mImpl->mModel->mLineWrapMode = lineWrapMode;
414 // Update Text layout for applying wrap mode
415 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
420 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
421 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
422 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
425 mImpl->RequestRelayout();
429 Text::LineWrap::Mode Controller::GetLineWrapMode() const
431 return mImpl->mModel->mLineWrapMode;
434 void Controller::SetTextElideEnabled(bool enabled)
436 mImpl->mModel->mElideEnabled = enabled;
439 bool Controller::IsTextElideEnabled() const
441 return mImpl->mModel->mElideEnabled;
444 void Controller::SetTextFitEnabled(bool enabled)
446 mImpl->mTextFitEnabled = enabled;
449 bool Controller::IsTextFitEnabled() const
451 return mImpl->mTextFitEnabled;
454 void Controller::SetTextFitMinSize(float minSize, FontSizeType type)
460 mImpl->mTextFitMinSize = minSize;
465 mImpl->mTextFitMinSize = ConvertPixelToPint(minSize);
471 float Controller::GetTextFitMinSize() const
473 return mImpl->mTextFitMinSize;
476 void Controller::SetTextFitMaxSize(float maxSize, FontSizeType type)
482 mImpl->mTextFitMaxSize = maxSize;
487 mImpl->mTextFitMaxSize = ConvertPixelToPint(maxSize);
493 float Controller::GetTextFitMaxSize() const
495 return mImpl->mTextFitMaxSize;
498 void Controller::SetTextFitStepSize(float step, FontSizeType type)
504 mImpl->mTextFitStepSize = step;
509 mImpl->mTextFitStepSize = ConvertPixelToPint(step);
515 float Controller::GetTextFitStepSize() const
517 return mImpl->mTextFitStepSize;
520 void Controller::SetTextFitContentSize(Vector2 size)
522 mImpl->mTextFitContentSize = size;
525 Vector2 Controller::GetTextFitContentSize() const
527 return mImpl->mTextFitContentSize;
530 void Controller::SetPlaceholderTextElideEnabled(bool enabled)
532 PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled);
535 bool Controller::IsPlaceholderTextElideEnabled() const
537 return PlaceholderHandler::IsPlaceholderTextElideEnabled(*this);
540 void Controller::SetSelectionEnabled(bool enabled)
542 mImpl->mEventData->mSelectionEnabled = enabled;
545 bool Controller::IsSelectionEnabled() const
547 return mImpl->mEventData->mSelectionEnabled;
550 void Controller::SetShiftSelectionEnabled(bool enabled)
552 mImpl->mEventData->mShiftSelectionFlag = enabled;
555 bool Controller::IsShiftSelectionEnabled() const
557 return mImpl->mEventData->mShiftSelectionFlag;
560 void Controller::SetGrabHandleEnabled(bool enabled)
562 mImpl->mEventData->mGrabHandleEnabled = enabled;
565 bool Controller::IsGrabHandleEnabled() const
567 return mImpl->mEventData->mGrabHandleEnabled;
570 void Controller::SetGrabHandlePopupEnabled(bool enabled)
572 mImpl->mEventData->mGrabHandlePopupEnabled = enabled;
575 bool Controller::IsGrabHandlePopupEnabled() const
577 return mImpl->mEventData->mGrabHandlePopupEnabled;
582 void Controller::SetText(const std::string& text)
584 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SetText\n");
586 // Reset keyboard as text changed
587 mImpl->ResetInputMethodContext();
589 // Remove the previously set text and style.
595 CharacterIndex lastCursorIndex = 0u;
597 if(NULL != mImpl->mEventData)
599 // If popup shown then hide it by switching to Editing state
600 if((EventData::SELECTING == mImpl->mEventData->mState) ||
601 (EventData::EDITING_WITH_POPUP == mImpl->mEventData->mState) ||
602 (EventData::EDITING_WITH_GRAB_HANDLE == mImpl->mEventData->mState) ||
603 (EventData::EDITING_WITH_PASTE_POPUP == mImpl->mEventData->mState))
605 mImpl->ChangeState(EventData::EDITING);
611 mImpl->mModel->mVisualModel->SetTextColor(mImpl->mTextColor);
613 MarkupProcessData markupProcessData(mImpl->mModel->mLogicalModel->mColorRuns,
614 mImpl->mModel->mLogicalModel->mFontDescriptionRuns,
615 mImpl->mModel->mLogicalModel->mEmbeddedItems);
617 Length textSize = 0u;
618 const uint8_t* utf8 = NULL;
619 if(mImpl->mMarkupProcessorEnabled)
621 ProcessMarkupString(text, markupProcessData);
622 textSize = markupProcessData.markupProcessedText.size();
624 // This is a bit horrible but std::string returns a (signed) char*
625 utf8 = reinterpret_cast<const uint8_t*>(markupProcessData.markupProcessedText.c_str());
629 textSize = text.size();
631 // This is a bit horrible but std::string returns a (signed) char*
632 utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
635 // Convert text into UTF-32
636 Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
637 utf32Characters.Resize(textSize);
639 // Transform a text array encoded in utf8 into an array encoded in utf32.
640 // It returns the actual number of characters.
641 Length characterCount = Utf8ToUtf32(utf8, textSize, utf32Characters.Begin());
642 utf32Characters.Resize(characterCount);
644 DALI_ASSERT_DEBUG(textSize >= characterCount && "Invalid UTF32 conversion length");
645 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::SetText %p UTF8 size %d, UTF32 size %d\n", this, textSize, mImpl->mModel->mLogicalModel->mText.Count());
647 // The characters to be added.
648 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
650 // To reset the cursor position
651 lastCursorIndex = characterCount;
653 // Update the rest of the model during size negotiation
654 mImpl->QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
656 // The natural size needs to be re-calculated.
657 mImpl->mRecalculateNaturalSize = true;
659 // The text direction needs to be updated.
660 mImpl->mUpdateTextDirection = true;
662 // Apply modifications to the model
663 mImpl->mOperationsPending = ALL_OPERATIONS;
667 ShowPlaceholderText();
670 // Resets the cursor position.
671 ResetCursorPosition(lastCursorIndex);
673 // Scrolls the text to make the cursor visible.
674 ResetScrollPosition();
676 mImpl->RequestRelayout();
678 if(NULL != mImpl->mEventData)
680 // Cancel previously queued events
681 mImpl->mEventData->mEventQueue.clear();
684 // Do this last since it provides callbacks into application code.
685 if(NULL != mImpl->mEditableControlInterface)
687 mImpl->mEditableControlInterface->TextChanged(true);
691 void Controller::GetText(std::string& text) const
693 if(!mImpl->IsShowingPlaceholderText())
695 // Retrieves the text string.
696 mImpl->GetText(0u, text);
700 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::GetText %p empty (but showing placeholder)\n", this);
704 void Controller::SetPlaceholderText(PlaceholderType type, const std::string& text)
706 PlaceholderHandler::SetPlaceholderText(*this, type, text);
709 void Controller::GetPlaceholderText(PlaceholderType type, std::string& text) const
711 PlaceholderHandler::GetPlaceholderText(*this, type, text);
714 void Controller::UpdateAfterFontChange(const std::string& newDefaultFont)
716 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Controller::UpdateAfterFontChange\n");
718 if(!mImpl->mFontDefaults->familyDefined) // If user defined font then should not update when system font changes
720 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str());
721 mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
725 mImpl->RequestRelayout();
729 // public : Default style & Input style
731 void Controller::SetDefaultFontFamily(const std::string& defaultFontFamily)
733 if(NULL == mImpl->mFontDefaults)
735 mImpl->mFontDefaults = new FontDefaults();
738 mImpl->mFontDefaults->mFontDescription.family = defaultFontFamily;
739 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetDefaultFontFamily %s\n", defaultFontFamily.c_str());
740 mImpl->mFontDefaults->familyDefined = !defaultFontFamily.empty();
742 if(mImpl->mEventData)
744 // Update the cursor position if it's in editing mode
745 if(EventData::IsEditingState(mImpl->mEventData->mState))
747 mImpl->mEventData->mDecoratorUpdated = true;
748 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font family is updated.
752 // Clear the font-specific data
755 mImpl->RequestRelayout();
758 const std::string& Controller::GetDefaultFontFamily() const
760 if(NULL != mImpl->mFontDefaults)
762 return mImpl->mFontDefaults->mFontDescription.family;
768 void Controller::SetPlaceholderFontFamily(const std::string& placeholderTextFontFamily)
770 PlaceholderHandler::SetPlaceholderFontFamily(*this, placeholderTextFontFamily);
773 const std::string& Controller::GetPlaceholderFontFamily() const
775 return PlaceholderHandler::GetPlaceholderFontFamily(*this);
778 void Controller::SetDefaultFontWeight(FontWeight weight)
780 if(NULL == mImpl->mFontDefaults)
782 mImpl->mFontDefaults = new FontDefaults();
785 mImpl->mFontDefaults->mFontDescription.weight = weight;
786 mImpl->mFontDefaults->weightDefined = true;
788 if(mImpl->mEventData)
790 // Update the cursor position if it's in editing mode
791 if(EventData::IsEditingState(mImpl->mEventData->mState))
793 mImpl->mEventData->mDecoratorUpdated = true;
794 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font weight is updated.
798 // Clear the font-specific data
801 mImpl->RequestRelayout();
804 bool Controller::IsDefaultFontWeightDefined() const
806 if(NULL != mImpl->mFontDefaults)
808 return mImpl->mFontDefaults->weightDefined;
814 FontWeight Controller::GetDefaultFontWeight() const
816 if(NULL != mImpl->mFontDefaults)
818 return mImpl->mFontDefaults->mFontDescription.weight;
821 return TextAbstraction::FontWeight::NORMAL;
824 void Controller::SetPlaceholderTextFontWeight(FontWeight weight)
826 PlaceholderHandler::SetPlaceholderTextFontWeight(*this, weight);
829 bool Controller::IsPlaceholderTextFontWeightDefined() const
831 return PlaceholderHandler::IsPlaceholderTextFontWeightDefined(*this);
835 FontWeight Controller::GetPlaceholderTextFontWeight() const
837 return PlaceholderHandler::GetPlaceholderTextFontWeight(*this);
840 void Controller::SetDefaultFontWidth(FontWidth width)
842 if(NULL == mImpl->mFontDefaults)
844 mImpl->mFontDefaults = new FontDefaults();
847 mImpl->mFontDefaults->mFontDescription.width = width;
848 mImpl->mFontDefaults->widthDefined = true;
850 if(mImpl->mEventData)
852 // Update the cursor position if it's in editing mode
853 if(EventData::IsEditingState(mImpl->mEventData->mState))
855 mImpl->mEventData->mDecoratorUpdated = true;
856 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font width is updated.
860 // Clear the font-specific data
863 mImpl->RequestRelayout();
866 bool Controller::IsDefaultFontWidthDefined() const
868 if(NULL != mImpl->mFontDefaults)
870 return mImpl->mFontDefaults->widthDefined;
876 FontWidth Controller::GetDefaultFontWidth() const
878 if(NULL != mImpl->mFontDefaults)
880 return mImpl->mFontDefaults->mFontDescription.width;
883 return TextAbstraction::FontWidth::NORMAL;
886 void Controller::SetPlaceholderTextFontWidth(FontWidth width)
888 PlaceholderHandler::SetPlaceholderTextFontWidth(*this, width);
891 bool Controller::IsPlaceholderTextFontWidthDefined() const
893 return PlaceholderHandler::IsPlaceholderTextFontWidthDefined(*this);
896 FontWidth Controller::GetPlaceholderTextFontWidth() const
898 return PlaceholderHandler::GetPlaceholderTextFontWidth(*this);
901 void Controller::SetDefaultFontSlant(FontSlant slant)
903 if(NULL == mImpl->mFontDefaults)
905 mImpl->mFontDefaults = new FontDefaults();
908 mImpl->mFontDefaults->mFontDescription.slant = slant;
909 mImpl->mFontDefaults->slantDefined = true;
911 if(mImpl->mEventData)
913 // Update the cursor position if it's in editing mode
914 if(EventData::IsEditingState(mImpl->mEventData->mState))
916 mImpl->mEventData->mDecoratorUpdated = true;
917 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font slant is updated.
921 // Clear the font-specific data
924 mImpl->RequestRelayout();
927 bool Controller::IsDefaultFontSlantDefined() const
929 if(NULL != mImpl->mFontDefaults)
931 return mImpl->mFontDefaults->slantDefined;
936 FontSlant Controller::GetDefaultFontSlant() const
938 if(NULL != mImpl->mFontDefaults)
940 return mImpl->mFontDefaults->mFontDescription.slant;
943 return TextAbstraction::FontSlant::NORMAL;
946 void Controller::SetPlaceholderTextFontSlant(FontSlant slant)
948 PlaceholderHandler::SetPlaceholderTextFontSlant(*this, slant);
951 bool Controller::IsPlaceholderTextFontSlantDefined() const
953 return PlaceholderHandler::IsPlaceholderTextFontSlantDefined(*this);
956 FontSlant Controller::GetPlaceholderTextFontSlant() const
958 return PlaceholderHandler::GetPlaceholderTextFontSlant(*this);
961 void Controller::SetDefaultFontSize(float fontSize, FontSizeType type)
963 if(NULL == mImpl->mFontDefaults)
965 mImpl->mFontDefaults = new FontDefaults();
972 mImpl->mFontDefaults->mDefaultPointSize = fontSize;
973 mImpl->mFontDefaults->sizeDefined = true;
978 // Point size = Pixel size * 72.f / DPI
979 unsigned int horizontalDpi = 0u;
980 unsigned int verticalDpi = 0u;
981 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
982 fontClient.GetDpi(horizontalDpi, verticalDpi);
984 mImpl->mFontDefaults->mDefaultPointSize = (fontSize * 72.f) / static_cast<float>(horizontalDpi);
985 mImpl->mFontDefaults->sizeDefined = true;
990 if(mImpl->mEventData)
992 // Update the cursor position if it's in editing mode
993 if(EventData::IsEditingState(mImpl->mEventData->mState))
995 mImpl->mEventData->mDecoratorUpdated = true;
996 mImpl->mEventData->mUpdateCursorPosition = true; // Cursor position should be updated when the font size is updated.
1000 // Clear the font-specific data
1003 mImpl->RequestRelayout();
1006 float Controller::GetDefaultFontSize(FontSizeType type) const
1009 if(NULL != mImpl->mFontDefaults)
1015 value = mImpl->mFontDefaults->mDefaultPointSize;
1020 // Pixel size = Point size * DPI / 72.f
1021 unsigned int horizontalDpi = 0u;
1022 unsigned int verticalDpi = 0u;
1023 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
1024 fontClient.GetDpi(horizontalDpi, verticalDpi);
1026 value = mImpl->mFontDefaults->mDefaultPointSize * static_cast<float>(horizontalDpi) / 72.f;
1036 void Controller::SetPlaceholderTextFontSize(float fontSize, FontSizeType type)
1038 PlaceholderHandler::SetPlaceholderTextFontSize(*this, fontSize, type);
1041 float Controller::GetPlaceholderTextFontSize(FontSizeType type) const
1043 return PlaceholderHandler::GetPlaceholderTextFontSize(*this, type);
1046 void Controller::SetDefaultColor(const Vector4& color)
1048 mImpl->mTextColor = color;
1050 if(!mImpl->IsShowingPlaceholderText())
1052 mImpl->mModel->mVisualModel->SetTextColor(color);
1054 mImpl->mModel->mLogicalModel->mColorRuns.Clear();
1056 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | COLOR);
1058 mImpl->RequestRelayout();
1062 const Vector4& Controller::GetDefaultColor() const
1064 return mImpl->mTextColor;
1067 void Controller::SetPlaceholderTextColor(const Vector4& textColor)
1069 PlaceholderHandler::SetPlaceholderTextColor(*this, textColor);
1072 const Vector4& Controller::GetPlaceholderTextColor() const
1074 return PlaceholderHandler::GetPlaceholderTextColor(*this);
1077 void Controller::SetShadowOffset(const Vector2& shadowOffset)
1079 mImpl->mModel->mVisualModel->SetShadowOffset(shadowOffset);
1081 mImpl->RequestRelayout();
1084 const Vector2& Controller::GetShadowOffset() const
1086 return mImpl->mModel->mVisualModel->GetShadowOffset();
1089 void Controller::SetShadowColor(const Vector4& shadowColor)
1091 mImpl->mModel->mVisualModel->SetShadowColor(shadowColor);
1093 mImpl->RequestRelayout();
1096 const Vector4& Controller::GetShadowColor() const
1098 return mImpl->mModel->mVisualModel->GetShadowColor();
1101 void Controller::SetShadowBlurRadius(const float& shadowBlurRadius)
1103 if(fabsf(GetShadowBlurRadius() - shadowBlurRadius) > Math::MACHINE_EPSILON_1)
1105 mImpl->mModel->mVisualModel->SetShadowBlurRadius(shadowBlurRadius);
1107 mImpl->RequestRelayout();
1111 const float& Controller::GetShadowBlurRadius() const
1113 return mImpl->mModel->mVisualModel->GetShadowBlurRadius();
1116 void Controller::SetUnderlineColor(const Vector4& color)
1118 mImpl->mModel->mVisualModel->SetUnderlineColor(color);
1120 mImpl->RequestRelayout();
1123 const Vector4& Controller::GetUnderlineColor() const
1125 return mImpl->mModel->mVisualModel->GetUnderlineColor();
1128 void Controller::SetUnderlineEnabled(bool enabled)
1130 mImpl->mModel->mVisualModel->SetUnderlineEnabled(enabled);
1132 mImpl->RequestRelayout();
1135 bool Controller::IsUnderlineEnabled() const
1137 return mImpl->mModel->mVisualModel->IsUnderlineEnabled();
1140 void Controller::SetUnderlineHeight(float height)
1142 mImpl->mModel->mVisualModel->SetUnderlineHeight(height);
1144 mImpl->RequestRelayout();
1147 float Controller::GetUnderlineHeight() const
1149 return mImpl->mModel->mVisualModel->GetUnderlineHeight();
1152 void Controller::SetOutlineColor(const Vector4& color)
1154 mImpl->mModel->mVisualModel->SetOutlineColor(color);
1156 mImpl->RequestRelayout();
1159 const Vector4& Controller::GetOutlineColor() const
1161 return mImpl->mModel->mVisualModel->GetOutlineColor();
1164 void Controller::SetOutlineWidth(uint16_t width)
1166 mImpl->mModel->mVisualModel->SetOutlineWidth(width);
1168 mImpl->RequestRelayout();
1171 uint16_t Controller::GetOutlineWidth() const
1173 return mImpl->mModel->mVisualModel->GetOutlineWidth();
1176 void Controller::SetBackgroundColor(const Vector4& color)
1178 mImpl->mModel->mVisualModel->SetBackgroundColor(color);
1180 mImpl->RequestRelayout();
1183 const Vector4& Controller::GetBackgroundColor() const
1185 return mImpl->mModel->mVisualModel->GetBackgroundColor();
1188 void Controller::SetBackgroundEnabled(bool enabled)
1190 mImpl->mModel->mVisualModel->SetBackgroundEnabled(enabled);
1192 mImpl->RequestRelayout();
1195 bool Controller::IsBackgroundEnabled() const
1197 return mImpl->mModel->mVisualModel->IsBackgroundEnabled();
1200 void Controller::SetDefaultEmbossProperties(const std::string& embossProperties)
1202 if(NULL == mImpl->mEmbossDefaults)
1204 mImpl->mEmbossDefaults = new EmbossDefaults();
1207 mImpl->mEmbossDefaults->properties = embossProperties;
1210 const std::string& Controller::GetDefaultEmbossProperties() const
1212 if(NULL != mImpl->mEmbossDefaults)
1214 return mImpl->mEmbossDefaults->properties;
1217 return EMPTY_STRING;
1220 void Controller::SetDefaultOutlineProperties(const std::string& outlineProperties)
1222 if(NULL == mImpl->mOutlineDefaults)
1224 mImpl->mOutlineDefaults = new OutlineDefaults();
1227 mImpl->mOutlineDefaults->properties = outlineProperties;
1230 const std::string& Controller::GetDefaultOutlineProperties() const
1232 if(NULL != mImpl->mOutlineDefaults)
1234 return mImpl->mOutlineDefaults->properties;
1237 return EMPTY_STRING;
1240 bool Controller::SetDefaultLineSpacing(float lineSpacing)
1242 if(std::fabs(lineSpacing - mImpl->mLayoutEngine.GetDefaultLineSpacing()) > Math::MACHINE_EPSILON_1000)
1244 mImpl->mLayoutEngine.SetDefaultLineSpacing(lineSpacing);
1245 mImpl->mRecalculateNaturalSize = true;
1251 float Controller::GetDefaultLineSpacing() const
1253 return mImpl->mLayoutEngine.GetDefaultLineSpacing();
1256 bool Controller::SetDefaultLineSize(float lineSize)
1258 if(std::fabs(lineSize - mImpl->mLayoutEngine.GetDefaultLineSize()) > Math::MACHINE_EPSILON_1000)
1260 mImpl->mLayoutEngine.SetDefaultLineSize(lineSize);
1261 mImpl->mRecalculateNaturalSize = true;
1267 float Controller::GetDefaultLineSize() const
1269 return mImpl->mLayoutEngine.GetDefaultLineSize();
1272 void Controller::SetInputColor(const Vector4& color)
1274 if(NULL != mImpl->mEventData)
1276 mImpl->mEventData->mInputStyle.textColor = color;
1277 mImpl->mEventData->mInputStyle.isDefaultColor = false;
1279 if(EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState)
1281 const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
1283 // Get start and end position of selection
1284 const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
1285 const Length lengthOfSelectedText = (handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition) - startOfSelectedText;
1287 // Add the color run.
1288 const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
1289 mImpl->mModel->mLogicalModel->mColorRuns.Resize(numberOfRuns + 1u);
1291 ColorRun& colorRun = *(mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns);
1292 colorRun.color = color;
1293 colorRun.characterRun.characterIndex = startOfSelectedText;
1294 colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
1296 // Request to relayout.
1297 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | COLOR);
1298 mImpl->RequestRelayout();
1300 mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1301 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1302 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1307 const Vector4& Controller::GetInputColor() const
1309 if(NULL != mImpl->mEventData)
1311 return mImpl->mEventData->mInputStyle.textColor;
1314 // Return the default text's color if there is no EventData.
1315 return mImpl->mTextColor;
1318 void Controller::SetInputFontFamily(const std::string& fontFamily)
1320 InputFontHandler::SetInputFontFamily(*this, fontFamily);
1323 const std::string& Controller::GetInputFontFamily() const
1325 return InputFontHandler::GetInputFontFamily(*this);
1328 void Controller::SetInputFontWeight(FontWeight weight)
1330 InputFontHandler::SetInputFontWeight(*this, weight);
1333 bool Controller::IsInputFontWeightDefined() const
1335 return InputFontHandler::IsInputFontWeightDefined(*this);
1338 FontWeight Controller::GetInputFontWeight() const
1340 return InputFontHandler::GetInputFontWeight(*this);
1343 void Controller::SetInputFontWidth(FontWidth width)
1345 InputFontHandler::SetInputFontWidth(*this, width);
1348 bool Controller::IsInputFontWidthDefined() const
1350 return InputFontHandler::IsInputFontWidthDefined(*this);
1353 FontWidth Controller::GetInputFontWidth() const
1355 return InputFontHandler::GetInputFontWidth(*this);
1358 void Controller::SetInputFontSlant(FontSlant slant)
1360 InputFontHandler::SetInputFontSlant(*this, slant);
1363 bool Controller::IsInputFontSlantDefined() const
1365 return InputFontHandler::IsInputFontSlantDefined(*this);
1368 FontSlant Controller::GetInputFontSlant() const
1370 return InputFontHandler::GetInputFontSlant(*this);
1373 void Controller::SetInputFontPointSize(float size)
1375 InputFontHandler::SetInputFontPointSize(*this, size);
1378 float Controller::GetInputFontPointSize() const
1380 return InputFontHandler::GetInputFontPointSize(*this);
1383 void Controller::SetInputLineSpacing(float lineSpacing)
1385 if(NULL != mImpl->mEventData)
1387 mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1388 mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1392 float Controller::GetInputLineSpacing() const
1394 if(NULL != mImpl->mEventData)
1396 return mImpl->mEventData->mInputStyle.lineSpacing;
1402 void Controller::SetInputShadowProperties(const std::string& shadowProperties)
1404 if(NULL != mImpl->mEventData)
1406 mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1410 const std::string& Controller::GetInputShadowProperties() const
1412 if(NULL != mImpl->mEventData)
1414 return mImpl->mEventData->mInputStyle.shadowProperties;
1417 return EMPTY_STRING;
1420 void Controller::SetInputUnderlineProperties(const std::string& underlineProperties)
1422 if(NULL != mImpl->mEventData)
1424 mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1428 const std::string& Controller::GetInputUnderlineProperties() const
1430 if(NULL != mImpl->mEventData)
1432 return mImpl->mEventData->mInputStyle.underlineProperties;
1435 return EMPTY_STRING;
1438 void Controller::SetInputEmbossProperties(const std::string& embossProperties)
1440 if(NULL != mImpl->mEventData)
1442 mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1446 const std::string& Controller::GetInputEmbossProperties() const
1448 if(NULL != mImpl->mEventData)
1450 return mImpl->mEventData->mInputStyle.embossProperties;
1453 return GetDefaultEmbossProperties();
1456 void Controller::SetInputOutlineProperties(const std::string& outlineProperties)
1458 if(NULL != mImpl->mEventData)
1460 mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1464 const std::string& Controller::GetInputOutlineProperties() const
1466 if(NULL != mImpl->mEventData)
1468 return mImpl->mEventData->mInputStyle.outlineProperties;
1471 return GetDefaultOutlineProperties();
1474 void Controller::SetInputModePassword(bool passwordInput)
1476 if(NULL != mImpl->mEventData)
1478 mImpl->mEventData->mPasswordInput = passwordInput;
1482 bool Controller::IsInputModePassword()
1484 if(NULL != mImpl->mEventData)
1486 return mImpl->mEventData->mPasswordInput;
1491 void Controller::SetNoTextDoubleTapAction(NoTextTap::Action action)
1493 if(NULL != mImpl->mEventData)
1495 mImpl->mEventData->mDoubleTapAction = action;
1499 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
1501 NoTextTap::Action action = NoTextTap::NO_ACTION;
1503 if(NULL != mImpl->mEventData)
1505 action = mImpl->mEventData->mDoubleTapAction;
1511 void Controller::SetNoTextLongPressAction(NoTextTap::Action action)
1513 if(NULL != mImpl->mEventData)
1515 mImpl->mEventData->mLongPressAction = action;
1519 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
1521 NoTextTap::Action action = NoTextTap::NO_ACTION;
1523 if(NULL != mImpl->mEventData)
1525 action = mImpl->mEventData->mLongPressAction;
1531 bool Controller::IsUnderlineSetByString()
1533 return mImpl->mUnderlineSetByString;
1536 void Controller::UnderlineSetByString(bool setByString)
1538 mImpl->mUnderlineSetByString = setByString;
1541 bool Controller::IsShadowSetByString()
1543 return mImpl->mShadowSetByString;
1546 void Controller::ShadowSetByString(bool setByString)
1548 mImpl->mShadowSetByString = setByString;
1551 bool Controller::IsOutlineSetByString()
1553 return mImpl->mOutlineSetByString;
1556 void Controller::OutlineSetByString(bool setByString)
1558 mImpl->mOutlineSetByString = setByString;
1561 bool Controller::IsFontStyleSetByString()
1563 return mImpl->mFontStyleSetByString;
1566 void Controller::FontStyleSetByString(bool setByString)
1568 mImpl->mFontStyleSetByString = setByString;
1571 // public : Queries & retrieves.
1573 Layout::Engine& Controller::GetLayoutEngine()
1575 return mImpl->mLayoutEngine;
1578 View& Controller::GetView()
1580 return mImpl->mView;
1583 Vector3 Controller::GetNaturalSize()
1585 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n");
1586 Vector3 naturalSize;
1588 // Make sure the model is up-to-date before layouting
1589 ProcessModifyEvents();
1591 if(mImpl->mRecalculateNaturalSize)
1593 // Operations that can be done only once until the text changes.
1594 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1602 // Set the update info to relayout the whole text.
1603 mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1604 mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1606 // Make sure the model is up-to-date before layouting
1607 mImpl->UpdateModel(onlyOnceOperations);
1609 // Layout the text for the new width.
1610 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | LAYOUT | REORDER);
1612 // Store the actual control's size to restore later.
1613 const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
1615 DoRelayout(Size(MAX_FLOAT, MAX_FLOAT),
1616 static_cast<OperationsMask>(onlyOnceOperations |
1618 naturalSize.GetVectorXY());
1620 // Do not do again the only once operations.
1621 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
1623 // Do the size related operations again.
1624 const OperationsMask sizeOperations = static_cast<OperationsMask>(LAYOUT |
1627 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | sizeOperations);
1629 // Stores the natural size to avoid recalculate it again
1630 // unless the text/style changes.
1631 mImpl->mModel->mVisualModel->SetNaturalSize(naturalSize.GetVectorXY());
1633 mImpl->mRecalculateNaturalSize = false;
1635 // Clear the update info. This info will be set the next time the text is updated.
1636 mImpl->mTextUpdateInfo.Clear();
1637 mImpl->mTextUpdateInfo.mClearAll = true;
1639 // Restore the actual control's size.
1640 mImpl->mModel->mVisualModel->mControlSize = actualControlSize;
1642 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z);
1646 naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize();
1648 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z);
1651 naturalSize.x = ConvertToEven(naturalSize.x);
1652 naturalSize.y = ConvertToEven(naturalSize.y);
1657 bool Controller::CheckForTextFit(float pointSize, Size& layoutSize)
1660 mImpl->mFontDefaults->mFitPointSize = pointSize;
1661 mImpl->mFontDefaults->sizeDefined = true;
1664 // Operations that can be done only once until the text changes.
1665 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1673 mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1674 mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1676 // Make sure the model is up-to-date before layouting
1677 mImpl->UpdateModel(onlyOnceOperations);
1679 DoRelayout(Size(layoutSize.width, MAX_FLOAT),
1680 static_cast<OperationsMask>(onlyOnceOperations | LAYOUT),
1683 // Clear the update info. This info will be set the next time the text is updated.
1684 mImpl->mTextUpdateInfo.Clear();
1685 mImpl->mTextUpdateInfo.mClearAll = true;
1687 if(textSize.width > layoutSize.width || textSize.height > layoutSize.height)
1694 void Controller::FitPointSizeforLayout(Size layoutSize)
1696 const OperationsMask operations = mImpl->mOperationsPending;
1697 if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations) || mImpl->mTextFitContentSize != layoutSize)
1699 bool actualellipsis = mImpl->mModel->mElideEnabled;
1700 float minPointSize = mImpl->mTextFitMinSize;
1701 float maxPointSize = mImpl->mTextFitMaxSize;
1702 float pointInterval = mImpl->mTextFitStepSize;
1704 mImpl->mModel->mElideEnabled = false;
1705 Vector<float> pointSizeArray;
1708 if(pointInterval < 1.f)
1710 mImpl->mTextFitStepSize = pointInterval = 1.0f;
1713 pointSizeArray.Reserve(static_cast<unsigned int>(ceil((maxPointSize - minPointSize) / pointInterval)));
1715 for(float i = minPointSize; i < maxPointSize; i += pointInterval)
1717 pointSizeArray.PushBack(i);
1720 pointSizeArray.PushBack(maxPointSize);
1722 int bestSizeIndex = 0;
1723 int min = bestSizeIndex + 1;
1724 int max = pointSizeArray.Size() - 1;
1727 int destI = (min + max) / 2;
1729 if(CheckForTextFit(pointSizeArray[destI], layoutSize))
1731 bestSizeIndex = min;
1737 bestSizeIndex = max;
1741 mImpl->mModel->mElideEnabled = actualellipsis;
1742 mImpl->mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
1743 mImpl->mFontDefaults->sizeDefined = true;
1748 float Controller::GetHeightForWidth(float width)
1750 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width);
1751 // Make sure the model is up-to-date before layouting
1752 ProcessModifyEvents();
1755 if(fabsf(width - mImpl->mModel->mVisualModel->mControlSize.width) > Math::MACHINE_EPSILON_1000 ||
1756 mImpl->mTextUpdateInfo.mFullRelayoutNeeded ||
1757 mImpl->mTextUpdateInfo.mClearAll)
1759 // Operations that can be done only once until the text changes.
1760 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1768 // Set the update info to relayout the whole text.
1769 mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1770 mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1772 // Make sure the model is up-to-date before layouting
1773 mImpl->UpdateModel(onlyOnceOperations);
1775 // Layout the text for the new width.
1776 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | LAYOUT);
1778 // Store the actual control's width.
1779 const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
1781 DoRelayout(Size(width, MAX_FLOAT),
1782 static_cast<OperationsMask>(onlyOnceOperations |
1786 // Do not do again the only once operations.
1787 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
1789 // Do the size related operations again.
1790 const OperationsMask sizeOperations = static_cast<OperationsMask>(LAYOUT |
1794 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | sizeOperations);
1796 // Clear the update info. This info will be set the next time the text is updated.
1797 mImpl->mTextUpdateInfo.Clear();
1798 mImpl->mTextUpdateInfo.mClearAll = true;
1800 // Restore the actual control's width.
1801 mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
1803 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height);
1807 layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
1808 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height);
1811 return layoutSize.height;
1814 int Controller::GetLineCount(float width)
1816 GetHeightForWidth(width);
1817 int numberofLines = mImpl->mModel->GetNumberOfLines();
1818 return numberofLines;
1821 const ModelInterface* const Controller::GetTextModel() const
1823 return mImpl->mModel.Get();
1826 float Controller::GetScrollAmountByUserInput()
1828 float scrollAmount = 0.0f;
1830 if(NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1832 scrollAmount = mImpl->mModel->mScrollPosition.y - mImpl->mModel->mScrollPositionLast.y;
1833 mImpl->mEventData->mCheckScrollAmount = false;
1835 return scrollAmount;
1838 bool Controller::GetTextScrollInfo(float& scrollPosition, float& controlHeight, float& layoutHeight)
1840 const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1843 controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
1844 layoutHeight = layout.height;
1845 scrollPosition = mImpl->mModel->mScrollPosition.y;
1846 isScrolled = !Equals(mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1);
1850 void Controller::SetHiddenInputOption(const Property::Map& options)
1852 if(NULL == mImpl->mHiddenInput)
1854 mImpl->mHiddenInput = new HiddenText(this);
1856 mImpl->mHiddenInput->SetProperties(options);
1859 void Controller::GetHiddenInputOption(Property::Map& options)
1861 if(NULL != mImpl->mHiddenInput)
1863 mImpl->mHiddenInput->GetProperties(options);
1867 void Controller::SetPlaceholderProperty(const Property::Map& map)
1869 PlaceholderHandler::SetPlaceholderProperty(*this, map);
1872 void Controller::GetPlaceholderProperty(Property::Map& map)
1874 PlaceholderHandler::GetPlaceholderProperty(*this, map);
1877 Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
1879 // Make sure the model is up-to-date before layouting
1880 ProcessModifyEvents();
1882 if(mImpl->mUpdateTextDirection)
1884 // Operations that can be done only once until the text changes.
1885 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1893 // Set the update info to relayout the whole text.
1894 mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1895 mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1897 // Make sure the model is up-to-date before layouting
1898 mImpl->UpdateModel(onlyOnceOperations);
1900 Vector3 naturalSize;
1901 DoRelayout(Size(MAX_FLOAT, MAX_FLOAT),
1902 static_cast<OperationsMask>(onlyOnceOperations |
1903 LAYOUT | REORDER | UPDATE_DIRECTION),
1904 naturalSize.GetVectorXY());
1906 // Do not do again the only once operations.
1907 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
1909 // Clear the update info. This info will be set the next time the text is updated.
1910 mImpl->mTextUpdateInfo.Clear();
1912 // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
1913 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1915 mImpl->mUpdateTextDirection = false;
1918 return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
1921 Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
1923 return mImpl->mModel->GetVerticalLineAlignment();
1926 void Controller::SetVerticalLineAlignment(Toolkit::DevelText::VerticalLineAlignment::Type alignment)
1928 mImpl->mModel->mVerticalLineAlignment = alignment;
1931 // public : Relayout.
1933 Controller::UpdateTextType Controller::Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection)
1935 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ? "true" : "false");
1937 UpdateTextType updateTextType = NONE_UPDATED;
1939 if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
1941 if(0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count())
1943 mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
1944 updateTextType = MODEL_UPDATED;
1947 // Clear the update info. This info will be set the next time the text is updated.
1948 mImpl->mTextUpdateInfo.Clear();
1950 // Not worth to relayout if width or height is equal to zero.
1951 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n");
1953 return updateTextType;
1956 // Whether a new size has been set.
1957 const bool newSize = (size != mImpl->mModel->mVisualModel->mControlSize);
1961 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height);
1963 if((0 == mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd) &&
1964 (0 == mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters) &&
1965 ((mImpl->mModel->mVisualModel->mControlSize.width < Math::MACHINE_EPSILON_1000) || (mImpl->mModel->mVisualModel->mControlSize.height < Math::MACHINE_EPSILON_1000)))
1967 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
1970 // Layout operations that need to be done if the size changes.
1971 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
1974 UPDATE_LAYOUT_SIZE |
1976 // Set the update info to relayout the whole text.
1977 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1978 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
1980 // Store the size used to layout the text.
1981 mImpl->mModel->mVisualModel->mControlSize = size;
1984 // Whether there are modify events.
1985 if(0u != mImpl->mModifyEvents.Count())
1987 // Style operations that need to be done if the text is modified.
1988 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
1992 // Set the update info to elide the text.
1993 if(mImpl->mModel->mElideEnabled ||
1994 ((NULL != mImpl->mEventData) && mImpl->mEventData->mIsPlaceholderElideEnabled))
1996 // Update Text layout for applying elided
1997 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
2000 UPDATE_LAYOUT_SIZE |
2002 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2003 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2006 if(mImpl->mModel->mMatchSystemLanguageDirection && mImpl->mLayoutDirection != layoutDirection)
2008 // Clear the update info. This info will be set the next time the text is updated.
2009 mImpl->mTextUpdateInfo.mClearAll = true;
2010 // Apply modifications to the model
2011 // Shape the text again is needed because characters like '()[]{}' have to be mirrored and the glyphs generated again.
2012 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
2019 mImpl->mLayoutDirection = layoutDirection;
2022 // Make sure the model is up-to-date before layouting.
2023 ProcessModifyEvents();
2024 bool updated = mImpl->UpdateModel(mImpl->mOperationsPending);
2028 updated = DoRelayout(size,
2029 mImpl->mOperationsPending,
2035 updateTextType = MODEL_UPDATED;
2038 // Do not re-do any operation until something changes.
2039 mImpl->mOperationsPending = NO_OPERATION;
2040 mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2042 // Whether the text control is editable
2043 const bool isEditable = NULL != mImpl->mEventData;
2045 // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2047 if(newSize && isEditable)
2049 offset = mImpl->mModel->mScrollPosition;
2052 if(!isEditable || !IsMultiLineEnabled())
2054 // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2055 CalculateVerticalOffset(size);
2062 // If there is a new size, the scroll position needs to be clamped.
2063 mImpl->ClampHorizontalScroll(layoutSize);
2065 // Update the decorator's positions is needed if there is a new size.
2066 mImpl->mEventData->mDecorator->UpdatePositions(mImpl->mModel->mScrollPosition - offset);
2069 // Move the cursor, grab handle etc.
2070 if(mImpl->ProcessInputEvents())
2072 updateTextType = static_cast<UpdateTextType>(updateTextType | DECORATOR_UPDATED);
2076 // Clear the update info. This info will be set the next time the text is updated.
2077 mImpl->mTextUpdateInfo.Clear();
2078 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayout\n");
2080 return updateTextType;
2083 void Controller::RequestRelayout()
2085 mImpl->RequestRelayout();
2088 // public : Input style change signals.
2090 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2092 return (NULL == mImpl->mEventData) || (0u == mImpl->mEventData->mInputStyleChangedQueue.Count());
2095 void Controller::ProcessInputStyleChangedSignals()
2097 if(NULL == mImpl->mEventData)
2103 for(Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2104 endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2108 const InputStyle::Mask mask = *it;
2110 if(NULL != mImpl->mEditableControlInterface)
2112 // Emit the input style changed signal.
2113 mImpl->mEditableControlInterface->InputStyleChanged(mask);
2117 mImpl->mEventData->mInputStyleChangedQueue.Clear();
2120 // public : Text-input Event Queuing.
2122 void Controller::KeyboardFocusGainEvent()
2124 EventHandler::KeyboardFocusGainEvent(*this);
2127 void Controller::KeyboardFocusLostEvent()
2129 EventHandler::KeyboardFocusLostEvent(*this);
2132 bool Controller::KeyEvent(const Dali::KeyEvent& keyEvent)
2134 return EventHandler::KeyEvent(*this, keyEvent);
2137 void Controller::TapEvent(unsigned int tapCount, float x, float y)
2139 EventHandler::TapEvent(*this, tapCount, x, y);
2142 void Controller::PanEvent(GestureState state, const Vector2& displacement)
2144 EventHandler::PanEvent(*this, state, displacement);
2147 void Controller::LongPressEvent(GestureState state, float x, float y)
2149 EventHandler::LongPressEvent(*this, state, x, y);
2152 void Controller::SelectEvent(float x, float y, SelectionType selectType)
2154 EventHandler::SelectEvent(*this, x, y, selectType);
2157 void Controller::SetTextSelectionRange(const uint32_t* start, const uint32_t* end)
2159 if(mImpl->mEventData)
2161 mImpl->mEventData->mCheckScrollAmount = true;
2162 mImpl->mEventData->mIsLeftHandleSelected = true;
2163 mImpl->mEventData->mIsRightHandleSelected = true;
2164 mImpl->SetTextSelectionRange(start, end);
2165 mImpl->RequestRelayout();
2166 KeyboardFocusGainEvent();
2170 Uint32Pair Controller::GetTextSelectionRange() const
2172 return mImpl->GetTextSelectionRange();
2175 void Controller::SelectWholeText()
2177 SelectEvent(0.f, 0.f, SelectionType::ALL);
2180 void Controller::SelectNone()
2182 SelectEvent(0.f, 0.f, SelectionType::NONE);
2185 string Controller::GetSelectedText() const
2188 if(EventData::SELECTING == mImpl->mEventData->mState)
2190 mImpl->RetrieveSelection(text, false);
2195 InputMethodContext::CallbackData Controller::OnInputMethodContextEvent(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
2197 return EventHandler::OnInputMethodContextEvent(*this, inputMethodContext, inputMethodContextEvent);
2200 void Controller::PasteClipboardItemEvent()
2202 EventHandler::PasteClipboardItemEvent(*this);
2205 // protected : Inherit from Text::Decorator::ControllerInterface.
2207 void Controller::GetTargetSize(Vector2& targetSize)
2209 targetSize = mImpl->mModel->mVisualModel->mControlSize;
2212 void Controller::AddDecoration(Actor& actor, bool needsClipping)
2214 if(NULL != mImpl->mEditableControlInterface)
2216 mImpl->mEditableControlInterface->AddDecoration(actor, needsClipping);
2220 bool Controller::IsEditable() const
2222 return mImpl->IsEditable();
2225 void Controller::SetEditable(bool editable)
2227 mImpl->SetEditable(editable);
2228 if(mImpl->mEventData && mImpl->mEventData->mDecorator)
2230 mImpl->mEventData->mDecorator->SetEditable(editable);
2234 void Controller::DecorationEvent(HandleType handleType, HandleState state, float x, float y)
2236 EventHandler::DecorationEvent(*this, handleType, state, x, y);
2239 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2241 void Controller::TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::Buttons button)
2243 EventHandler::TextPopupButtonTouched(*this, button);
2246 void Controller::DisplayTimeExpired()
2248 mImpl->mEventData->mUpdateCursorPosition = true;
2249 // Apply modifications to the model
2250 mImpl->mOperationsPending = ALL_OPERATIONS;
2252 mImpl->RequestRelayout();
2255 // private : Update.
2257 void Controller::InsertText(const std::string& text, Controller::InsertType type)
2259 bool removedPrevious = false;
2260 bool removedSelected = false;
2261 bool maxLengthReached = false;
2263 DALI_ASSERT_DEBUG(NULL != mImpl->mEventData && "Unexpected InsertText")
2265 if(NULL == mImpl->mEventData)
2270 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);
2272 // TODO: At the moment the underline runs are only for pre-edit.
2273 mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
2275 // Remove the previous InputMethodContext pre-edit.
2276 if(mImpl->mEventData->mPreEditFlag && (0u != mImpl->mEventData->mPreEditLength))
2278 removedPrevious = RemoveText(-static_cast<int>(mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition),
2279 mImpl->mEventData->mPreEditLength,
2280 DONT_UPDATE_INPUT_STYLE);
2282 mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2283 mImpl->mEventData->mPreEditLength = 0u;
2287 // Remove the previous Selection.
2288 removedSelected = RemoveSelectedText();
2291 Vector<Character> utf32Characters;
2292 Length characterCount = 0u;
2296 // Convert text into UTF-32
2297 utf32Characters.Resize(text.size());
2299 // This is a bit horrible but std::string returns a (signed) char*
2300 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
2302 // Transform a text array encoded in utf8 into an array encoded in utf32.
2303 // It returns the actual number of characters.
2304 characterCount = Utf8ToUtf32(utf8, text.size(), utf32Characters.Begin());
2305 utf32Characters.Resize(characterCount);
2307 DALI_ASSERT_DEBUG(text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length");
2308 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count());
2311 if(0u != utf32Characters.Count()) // Check if Utf8ToUtf32 conversion succeeded
2313 // The placeholder text is no longer needed
2314 if(mImpl->IsShowingPlaceholderText())
2319 mImpl->ChangeState(EventData::EDITING);
2321 // Handle the InputMethodContext (predicitive text) state changes
2324 // InputMethodContext is no longer handling key-events
2325 mImpl->ClearPreEditFlag();
2329 if(!mImpl->mEventData->mPreEditFlag)
2331 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Entered PreEdit state\n");
2333 // Record the start of the pre-edit text
2334 mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2337 mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2338 mImpl->mEventData->mPreEditFlag = true;
2340 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength);
2343 const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
2345 // Restrict new text to fit within Maximum characters setting.
2346 Length maxSizeOfNewText = std::min((mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel), characterCount);
2347 maxLengthReached = (characterCount > maxSizeOfNewText);
2349 // The cursor position.
2350 CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2352 // Update the text's style.
2354 // Updates the text style runs by adding characters.
2355 mImpl->mModel->mLogicalModel->UpdateTextStyleRuns(cursorIndex, maxSizeOfNewText);
2357 // Get the character index from the cursor index.
2358 const CharacterIndex styleIndex = (cursorIndex > 0u) ? cursorIndex - 1u : 0u;
2360 // Retrieve the text's style for the given index.
2362 mImpl->RetrieveDefaultInputStyle(style);
2363 mImpl->mModel->mLogicalModel->RetrieveStyle(styleIndex, style);
2365 // Whether to add a new text color run.
2366 const bool addColorRun = (style.textColor != mImpl->mEventData->mInputStyle.textColor) && !mImpl->mEventData->mInputStyle.isDefaultColor;
2368 // Whether to add a new font run.
2369 const bool addFontNameRun = (style.familyName != mImpl->mEventData->mInputStyle.familyName) && mImpl->mEventData->mInputStyle.isFamilyDefined;
2370 const bool addFontWeightRun = (style.weight != mImpl->mEventData->mInputStyle.weight) && mImpl->mEventData->mInputStyle.isWeightDefined;
2371 const bool addFontWidthRun = (style.width != mImpl->mEventData->mInputStyle.width) && mImpl->mEventData->mInputStyle.isWidthDefined;
2372 const bool addFontSlantRun = (style.slant != mImpl->mEventData->mInputStyle.slant) && mImpl->mEventData->mInputStyle.isSlantDefined;
2373 const bool addFontSizeRun = (style.size != mImpl->mEventData->mInputStyle.size) && mImpl->mEventData->mInputStyle.isSizeDefined;
2378 const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
2379 mImpl->mModel->mLogicalModel->mColorRuns.Resize(numberOfRuns + 1u);
2381 ColorRun& colorRun = *(mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns);
2382 colorRun.color = mImpl->mEventData->mInputStyle.textColor;
2383 colorRun.characterRun.characterIndex = cursorIndex;
2384 colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2387 if(addFontNameRun ||
2393 const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
2394 mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize(numberOfRuns + 1u);
2396 FontDescriptionRun& fontDescriptionRun = *(mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns);
2400 fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
2401 fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
2402 memcpy(fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength);
2403 fontDescriptionRun.familyDefined = true;
2405 // The memory allocated for the font family name is freed when the font description is removed from the logical model.
2408 if(addFontWeightRun)
2410 fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
2411 fontDescriptionRun.weightDefined = true;
2416 fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
2417 fontDescriptionRun.widthDefined = true;
2422 fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
2423 fontDescriptionRun.slantDefined = true;
2428 fontDescriptionRun.size = static_cast<PointSize26Dot6>(mImpl->mEventData->mInputStyle.size * 64.f);
2429 fontDescriptionRun.sizeDefined = true;
2432 fontDescriptionRun.characterRun.characterIndex = cursorIndex;
2433 fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2436 // Insert at current cursor position.
2437 Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
2439 if(cursorIndex < numberOfCharactersInModel)
2441 modifyText.Insert(modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText);
2445 modifyText.Insert(modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText);
2448 // Mark the first paragraph to be updated.
2449 if(Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout())
2451 mImpl->mTextUpdateInfo.mCharacterIndex = 0;
2452 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2453 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
2454 mImpl->mTextUpdateInfo.mClearAll = true;
2458 mImpl->mTextUpdateInfo.mCharacterIndex = std::min(cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex);
2459 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
2462 // Update the cursor index.
2463 cursorIndex += maxSizeOfNewText;
2465 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);
2468 if((0u == mImpl->mModel->mLogicalModel->mText.Count()) &&
2469 mImpl->IsPlaceholderAvailable())
2471 // Show place-holder if empty after removing the pre-edit text
2472 ShowPlaceholderText();
2473 mImpl->mEventData->mUpdateCursorPosition = true;
2474 mImpl->ClearPreEditFlag();
2476 else if(removedPrevious ||
2478 (0 != utf32Characters.Count()))
2480 // Queue an inserted event
2481 mImpl->QueueModifyEvent(ModifyEvent::TEXT_INSERTED);
2483 mImpl->mEventData->mUpdateCursorPosition = true;
2486 mImpl->mEventData->mScrollAfterDelete = true;
2490 mImpl->mEventData->mScrollAfterUpdatePosition = true;
2494 if(maxLengthReached)
2496 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count());
2498 mImpl->ResetInputMethodContext();
2500 if(NULL != mImpl->mEditableControlInterface)
2502 // Do this last since it provides callbacks into application code
2503 mImpl->mEditableControlInterface->MaxLengthReached();
2508 void Controller::PasteText(const std::string& stringToPaste)
2510 InsertText(stringToPaste, Text::Controller::COMMIT);
2511 mImpl->ChangeState(EventData::EDITING);
2512 mImpl->RequestRelayout();
2514 if(NULL != mImpl->mEditableControlInterface)
2516 // Do this last since it provides callbacks into application code
2517 mImpl->mEditableControlInterface->TextChanged(true);
2521 bool Controller::RemoveText(int cursorOffset,
2522 int numberOfCharacters,
2523 UpdateInputStyleType type)
2525 bool removed = false;
2527 if(NULL == mImpl->mEventData)
2532 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);
2534 if(!mImpl->IsShowingPlaceholderText())
2536 // Delete at current cursor position
2537 Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
2538 CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2540 CharacterIndex cursorIndex = 0;
2542 // Validate the cursor position & number of characters
2543 if((static_cast<int>(mImpl->mEventData->mPrimaryCursorPosition) + cursorOffset) >= 0)
2545 cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
2548 if((cursorIndex + numberOfCharacters) > currentText.Count())
2550 numberOfCharacters = currentText.Count() - cursorIndex;
2553 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.
2554 ((cursorIndex + numberOfCharacters) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters))
2556 // Mark the paragraphs to be updated.
2557 if(Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout())
2559 mImpl->mTextUpdateInfo.mCharacterIndex = 0;
2560 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2561 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
2562 mImpl->mTextUpdateInfo.mClearAll = true;
2566 mImpl->mTextUpdateInfo.mCharacterIndex = std::min(cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex);
2567 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
2570 // Update the input style and remove the text's style before removing the text.
2572 if(UPDATE_INPUT_STYLE == type)
2574 // Keep a copy of the current input style.
2575 InputStyle currentInputStyle;
2576 currentInputStyle.Copy(mImpl->mEventData->mInputStyle);
2578 // Set first the default input style.
2579 mImpl->RetrieveDefaultInputStyle(mImpl->mEventData->mInputStyle);
2581 // Update the input style.
2582 mImpl->mModel->mLogicalModel->RetrieveStyle(cursorIndex, mImpl->mEventData->mInputStyle);
2584 // Compare if the input style has changed.
2585 const bool hasInputStyleChanged = !currentInputStyle.Equal(mImpl->mEventData->mInputStyle);
2587 if(hasInputStyleChanged)
2589 const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(mImpl->mEventData->mInputStyle);
2590 // Queue the input style changed signal.
2591 mImpl->mEventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
2595 // If the number of current text and the number of characters to be deleted are same,
2596 // it means all texts should be removed and all Preedit variables should be initialized.
2597 if((currentText.Count() - numberOfCharacters == 0) && (cursorIndex == 0))
2599 mImpl->ClearPreEditFlag();
2600 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0;
2603 // Updates the text style runs by removing characters. Runs with no characters are removed.
2604 mImpl->mModel->mLogicalModel->UpdateTextStyleRuns(cursorIndex, -numberOfCharacters);
2606 // Remove the characters.
2607 Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
2608 Vector<Character>::Iterator last = first + numberOfCharacters;
2610 currentText.Erase(first, last);
2612 // Cursor position retreat
2613 oldCursorIndex = cursorIndex;
2615 mImpl->mEventData->mScrollAfterDelete = true;
2617 if(EventData::INACTIVE == mImpl->mEventData->mState)
2619 mImpl->ChangeState(EventData::EDITING);
2622 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters);
2630 bool Controller::RemoveSelectedText()
2632 bool textRemoved(false);
2634 if(EventData::SELECTING == mImpl->mEventData->mState)
2636 std::string removedString;
2637 mImpl->RetrieveSelection(removedString, true);
2639 if(!removedString.empty())
2642 mImpl->ChangeState(EventData::EDITING);
2649 // private : Relayout.
2651 bool Controller::DoRelayout(const Size& size,
2652 OperationsMask operationsRequired,
2655 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height);
2656 bool viewUpdated(false);
2658 // Calculate the operations to be done.
2659 const OperationsMask operations = static_cast<OperationsMask>(mImpl->mOperationsPending & operationsRequired);
2661 const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
2662 const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
2664 // Get the current layout size.
2665 layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2667 if(NO_OPERATION != (LAYOUT & operations))
2669 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
2671 // Some vectors with data needed to layout and reorder may be void
2672 // after the first time the text has been laid out.
2673 // Fill the vectors again.
2675 // Calculate the number of glyphs to layout.
2676 const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
2677 const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
2678 const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
2679 const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
2681 const CharacterIndex lastIndex = startIndex + ((requestedNumberOfCharacters > 0u) ? requestedNumberOfCharacters - 1u : 0u);
2682 const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
2684 // Make sure the index is not out of bound
2685 if(charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
2686 requestedNumberOfCharacters > charactersToGlyph.Count() ||
2687 (lastIndex > charactersToGlyph.Count() && charactersToGlyph.Count() > 0u))
2689 std::string currentText;
2690 GetText(currentText);
2692 DALI_LOG_ERROR("Controller::DoRelayout: Attempting to access invalid buffer\n");
2693 DALI_LOG_ERROR("Current text is: %s\n", currentText.c_str());
2694 DALI_LOG_ERROR("startIndex: %u, lastIndex: %u, requestedNumberOfCharacters: %u, charactersToGlyph.Count = %lu, glyphsPerCharacter.Count = %lu\n", startIndex, lastIndex, requestedNumberOfCharacters, charactersToGlyph.Count(), glyphsPerCharacter.Count());
2699 const Length numberOfGlyphs = (requestedNumberOfCharacters > 0u) ? *(charactersToGlyphBuffer + lastIndex) + *(glyphsPerCharacterBuffer + lastIndex) - startGlyphIndex : 0u;
2700 const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
2702 if(0u == totalNumberOfGlyphs)
2704 if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations))
2706 mImpl->mModel->mVisualModel->SetLayoutSize(Size::ZERO);
2709 // Nothing else to do if there is no glyphs.
2710 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n");
2714 // Set the layout parameters.
2715 Layout::Parameters layoutParameters(size,
2718 // Resize the vector of positions to have the same size than the vector of glyphs.
2719 Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
2720 glyphPositions.Resize(totalNumberOfGlyphs);
2722 // Whether the last character is a new paragraph character.
2723 const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
2724 mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph = TextAbstraction::IsNewParagraph(*(textBuffer + (mImpl->mModel->mLogicalModel->mText.Count() - 1u)));
2725 layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
2727 // The initial glyph and the number of glyphs to layout.
2728 layoutParameters.startGlyphIndex = startGlyphIndex;
2729 layoutParameters.numberOfGlyphs = numberOfGlyphs;
2730 layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
2731 layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
2733 // Update the ellipsis
2734 bool elideTextEnabled = mImpl->mModel->mElideEnabled;
2736 if(NULL != mImpl->mEventData)
2738 if(mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText())
2740 elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
2742 else if(EventData::INACTIVE != mImpl->mEventData->mState)
2744 // Disable ellipsis when editing
2745 elideTextEnabled = false;
2748 // Reset the scroll position in inactive state
2749 if(elideTextEnabled && (mImpl->mEventData->mState == EventData::INACTIVE))
2751 ResetScrollPosition();
2755 // Update the visual model.
2756 bool isAutoScrollEnabled = mImpl->mIsAutoScrollEnabled;
2758 viewUpdated = mImpl->mLayoutEngine.LayoutText(layoutParameters,
2761 isAutoScrollEnabled);
2762 mImpl->mIsAutoScrollEnabled = isAutoScrollEnabled;
2764 viewUpdated = viewUpdated || (newLayoutSize != layoutSize);
2768 layoutSize = newLayoutSize;
2770 if(NO_OPERATION != (UPDATE_DIRECTION & operations))
2772 mImpl->mIsTextDirectionRTL = false;
2775 if((NO_OPERATION != (UPDATE_DIRECTION & operations)) && !mImpl->mModel->mVisualModel->mLines.Empty())
2777 mImpl->mIsTextDirectionRTL = mImpl->mModel->mVisualModel->mLines[0u].direction;
2780 // Sets the layout size.
2781 if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations))
2783 mImpl->mModel->mVisualModel->SetLayoutSize(layoutSize);
2788 if(NO_OPERATION != (ALIGN & operations))
2790 // The laid-out lines.
2791 Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
2793 CharacterIndex alignStartIndex = startIndex;
2794 Length alignRequestedNumberOfCharacters = requestedNumberOfCharacters;
2796 // the whole text needs to be full aligned.
2797 // If you do not do a full aligned, only the last line of the multiline input is aligned.
2798 if(mImpl->mEventData && mImpl->mEventData->mUpdateAlignment)
2800 alignStartIndex = 0u;
2801 alignRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
2802 mImpl->mEventData->mUpdateAlignment = false;
2805 // Need to align with the control's size as the text may contain lines
2806 // starting either with left to right text or right to left.
2807 mImpl->mLayoutEngine.Align(size,
2809 alignRequestedNumberOfCharacters,
2810 mImpl->mModel->mHorizontalAlignment,
2812 mImpl->mModel->mAlignmentOffset,
2813 mImpl->mLayoutDirection,
2814 mImpl->mModel->mMatchSystemLanguageDirection);
2818 #if defined(DEBUG_ENABLED)
2819 std::string currentText;
2820 GetText(currentText);
2821 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", this, (mImpl->mIsTextDirectionRTL) ? "true" : "false", currentText.c_str());
2823 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", (viewUpdated ? "true" : "false"));
2827 void Controller::CalculateVerticalOffset(const Size& controlSize)
2829 ModelPtr& model = mImpl->mModel;
2830 VisualModelPtr& visualModel = model->mVisualModel;
2831 Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2832 Size oldLayoutSize = layoutSize;
2833 float offsetY = 0.f;
2834 bool needRecalc = false;
2835 float defaultFontLineHeight = mImpl->GetDefaultFontLineHeight();
2837 if(fabsf(layoutSize.height) < Math::MACHINE_EPSILON_1000)
2839 // Get the line height of the default font.
2840 layoutSize.height = defaultFontLineHeight;
2843 // Whether the text control is editable
2844 const bool isEditable = NULL != mImpl->mEventData;
2845 if(isEditable && layoutSize.height != defaultFontLineHeight)
2847 // This code prevents the wrong positioning of cursor when the layout size is bigger/smaller than defaultFontLineHeight.
2848 // This situation occurs when the size of placeholder text is different from the default text.
2849 layoutSize.height = defaultFontLineHeight;
2853 switch(mImpl->mModel->mVerticalAlignment)
2855 case VerticalAlignment::TOP:
2857 mImpl->mModel->mScrollPosition.y = 0.f;
2861 case VerticalAlignment::CENTER:
2863 mImpl->mModel->mScrollPosition.y = floorf(0.5f * (controlSize.height - layoutSize.height)); // try to avoid pixel alignment.
2864 if(needRecalc) offsetY = floorf(0.5f * (layoutSize.height - oldLayoutSize.height));
2867 case VerticalAlignment::BOTTOM:
2869 mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
2870 if(needRecalc) offsetY = layoutSize.height - oldLayoutSize.height;
2877 // Update glyphPositions according to recalculation.
2878 const Length positionCount = visualModel->mGlyphPositions.Count();
2879 Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
2880 for(Length index = 0u; index < positionCount; index++)
2882 glyphPositions[index].y += offsetY;
2887 // private : Events.
2889 void Controller::ProcessModifyEvents()
2891 EventHandler::ProcessModifyEvents(*this);
2894 void Controller::TextReplacedEvent()
2896 EventHandler::TextReplacedEvent(*this);
2899 void Controller::TextInsertedEvent()
2901 EventHandler::TextInsertedEvent(*this);
2904 void Controller::TextDeletedEvent()
2906 EventHandler::TextDeletedEvent(*this);
2909 bool Controller::DeleteEvent(int keyCode)
2911 return EventHandler::DeleteEvent(*this, keyCode);
2914 // private : Helpers.
2916 void Controller::ResetText()
2919 mImpl->mModel->mLogicalModel->mText.Clear();
2921 // Reset the embedded images buffer.
2922 mImpl->mModel->mLogicalModel->ClearEmbeddedImages();
2924 // We have cleared everything including the placeholder-text
2925 mImpl->PlaceholderCleared();
2927 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2928 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2929 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
2931 // Clear any previous text.
2932 mImpl->mTextUpdateInfo.mClearAll = true;
2934 // The natural size needs to be re-calculated.
2935 mImpl->mRecalculateNaturalSize = true;
2937 // The text direction needs to be updated.
2938 mImpl->mUpdateTextDirection = true;
2940 // Apply modifications to the model
2941 mImpl->mOperationsPending = ALL_OPERATIONS;
2944 void Controller::ShowPlaceholderText()
2946 if(mImpl->IsPlaceholderAvailable())
2948 DALI_ASSERT_DEBUG(mImpl->mEventData && "No placeholder text available");
2950 if(NULL == mImpl->mEventData)
2955 mImpl->mEventData->mIsShowingPlaceholderText = true;
2957 // Disable handles when showing place-holder text
2958 mImpl->mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
2959 mImpl->mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
2960 mImpl->mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
2962 const char* text(NULL);
2965 // TODO - Switch Placeholder text when changing state
2966 if((EventData::INACTIVE != mImpl->mEventData->mState) &&
2967 (0u != mImpl->mEventData->mPlaceholderTextActive.c_str()))
2969 text = mImpl->mEventData->mPlaceholderTextActive.c_str();
2970 size = mImpl->mEventData->mPlaceholderTextActive.size();
2974 text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
2975 size = mImpl->mEventData->mPlaceholderTextInactive.size();
2978 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2979 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2981 // Reset model for showing placeholder.
2982 mImpl->mModel->mLogicalModel->mText.Clear();
2983 mImpl->mModel->mVisualModel->SetTextColor(mImpl->mEventData->mPlaceholderTextColor);
2985 // Convert text into UTF-32
2986 Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
2987 utf32Characters.Resize(size);
2989 // This is a bit horrible but std::string returns a (signed) char*
2990 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text);
2992 // Transform a text array encoded in utf8 into an array encoded in utf32.
2993 // It returns the actual number of characters.
2994 const Length characterCount = Utf8ToUtf32(utf8, size, utf32Characters.Begin());
2995 utf32Characters.Resize(characterCount);
2997 // The characters to be added.
2998 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
3000 // Reset the cursor position
3001 mImpl->mEventData->mPrimaryCursorPosition = 0;
3003 // The natural size needs to be re-calculated.
3004 mImpl->mRecalculateNaturalSize = true;
3006 // The text direction needs to be updated.
3007 mImpl->mUpdateTextDirection = true;
3009 // Apply modifications to the model
3010 mImpl->mOperationsPending = ALL_OPERATIONS;
3012 // Update the rest of the model during size negotiation
3013 mImpl->QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
3017 void Controller::ClearFontData()
3019 if(mImpl->mFontDefaults)
3021 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
3024 // Set flags to update the model.
3025 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3026 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3027 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
3029 mImpl->mTextUpdateInfo.mClearAll = true;
3030 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
3031 mImpl->mRecalculateNaturalSize = true;
3033 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
3039 UPDATE_LAYOUT_SIZE |
3044 void Controller::ClearStyleData()
3046 mImpl->mModel->mLogicalModel->mColorRuns.Clear();
3047 mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
3050 void Controller::ResetCursorPosition(CharacterIndex cursorIndex)
3052 // Reset the cursor position
3053 if(NULL != mImpl->mEventData)
3055 mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
3057 // Update the cursor if it's in editing mode.
3058 if(EventData::IsEditingState(mImpl->mEventData->mState))
3060 mImpl->mEventData->mUpdateCursorPosition = true;
3065 void Controller::ResetScrollPosition()
3067 if(NULL != mImpl->mEventData)
3069 // Reset the scroll position.
3070 mImpl->mModel->mScrollPosition = Vector2::ZERO;
3071 mImpl->mEventData->mScrollAfterUpdatePosition = true;
3075 void Controller::SetControlInterface(ControlInterface* controlInterface)
3077 mImpl->mControlInterface = controlInterface;
3080 bool Controller::ShouldClearFocusOnEscape() const
3082 return mImpl->mShouldClearFocusOnEscape;
3085 Actor Controller::CreateBackgroundActor()
3087 return mImpl->CreateBackgroundActor();
3090 // private : Private contructors & copy operator.
3092 Controller::Controller()
3093 : Controller(nullptr, nullptr, nullptr)
3097 Controller::Controller(ControlInterface* controlInterface)
3098 : Controller(controlInterface, nullptr, nullptr)
3102 Controller::Controller(ControlInterface* controlInterface,
3103 EditableControlInterface* editableControlInterface,
3104 SelectableControlInterface* selectableControlInterface)
3105 : mImpl(new Controller::Impl(controlInterface, editableControlInterface, selectableControlInterface))
3109 // The copy constructor and operator are left unimplemented.
3111 // protected : Destructor.
3113 Controller::~Controller()
3120 } // namespace Toolkit