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 if(EventData::SELECTING == mImpl->mEventData->mState)
1283 const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
1285 // Get start and end position of selection
1286 const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
1287 const Length lengthOfSelectedText = (handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition) - startOfSelectedText;
1289 // Add the color run.
1290 const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
1291 mImpl->mModel->mLogicalModel->mColorRuns.Resize(numberOfRuns + 1u);
1293 ColorRun& colorRun = *(mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns);
1294 colorRun.color = color;
1295 colorRun.characterRun.characterIndex = startOfSelectedText;
1296 colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
1298 mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
1299 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
1300 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
1304 mImpl->mTextUpdateInfo.mCharacterIndex = 0;
1305 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
1306 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
1309 // Request to relayout.
1310 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | COLOR);
1311 mImpl->RequestRelayout();
1316 const Vector4& Controller::GetInputColor() const
1318 if(NULL != mImpl->mEventData)
1320 return mImpl->mEventData->mInputStyle.textColor;
1323 // Return the default text's color if there is no EventData.
1324 return mImpl->mTextColor;
1327 void Controller::SetInputFontFamily(const std::string& fontFamily)
1329 InputFontHandler::SetInputFontFamily(*this, fontFamily);
1332 const std::string& Controller::GetInputFontFamily() const
1334 return InputFontHandler::GetInputFontFamily(*this);
1337 void Controller::SetInputFontWeight(FontWeight weight)
1339 InputFontHandler::SetInputFontWeight(*this, weight);
1342 bool Controller::IsInputFontWeightDefined() const
1344 return InputFontHandler::IsInputFontWeightDefined(*this);
1347 FontWeight Controller::GetInputFontWeight() const
1349 return InputFontHandler::GetInputFontWeight(*this);
1352 void Controller::SetInputFontWidth(FontWidth width)
1354 InputFontHandler::SetInputFontWidth(*this, width);
1357 bool Controller::IsInputFontWidthDefined() const
1359 return InputFontHandler::IsInputFontWidthDefined(*this);
1362 FontWidth Controller::GetInputFontWidth() const
1364 return InputFontHandler::GetInputFontWidth(*this);
1367 void Controller::SetInputFontSlant(FontSlant slant)
1369 InputFontHandler::SetInputFontSlant(*this, slant);
1372 bool Controller::IsInputFontSlantDefined() const
1374 return InputFontHandler::IsInputFontSlantDefined(*this);
1377 FontSlant Controller::GetInputFontSlant() const
1379 return InputFontHandler::GetInputFontSlant(*this);
1382 void Controller::SetInputFontPointSize(float size)
1384 InputFontHandler::SetInputFontPointSize(*this, size);
1387 float Controller::GetInputFontPointSize() const
1389 return InputFontHandler::GetInputFontPointSize(*this);
1392 void Controller::SetInputLineSpacing(float lineSpacing)
1394 if(NULL != mImpl->mEventData)
1396 mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing;
1397 mImpl->mEventData->mInputStyle.isLineSpacingDefined = true;
1401 float Controller::GetInputLineSpacing() const
1403 if(NULL != mImpl->mEventData)
1405 return mImpl->mEventData->mInputStyle.lineSpacing;
1411 void Controller::SetInputShadowProperties(const std::string& shadowProperties)
1413 if(NULL != mImpl->mEventData)
1415 mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties;
1419 const std::string& Controller::GetInputShadowProperties() const
1421 if(NULL != mImpl->mEventData)
1423 return mImpl->mEventData->mInputStyle.shadowProperties;
1426 return EMPTY_STRING;
1429 void Controller::SetInputUnderlineProperties(const std::string& underlineProperties)
1431 if(NULL != mImpl->mEventData)
1433 mImpl->mEventData->mInputStyle.underlineProperties = underlineProperties;
1437 const std::string& Controller::GetInputUnderlineProperties() const
1439 if(NULL != mImpl->mEventData)
1441 return mImpl->mEventData->mInputStyle.underlineProperties;
1444 return EMPTY_STRING;
1447 void Controller::SetInputEmbossProperties(const std::string& embossProperties)
1449 if(NULL != mImpl->mEventData)
1451 mImpl->mEventData->mInputStyle.embossProperties = embossProperties;
1455 const std::string& Controller::GetInputEmbossProperties() const
1457 if(NULL != mImpl->mEventData)
1459 return mImpl->mEventData->mInputStyle.embossProperties;
1462 return GetDefaultEmbossProperties();
1465 void Controller::SetInputOutlineProperties(const std::string& outlineProperties)
1467 if(NULL != mImpl->mEventData)
1469 mImpl->mEventData->mInputStyle.outlineProperties = outlineProperties;
1473 const std::string& Controller::GetInputOutlineProperties() const
1475 if(NULL != mImpl->mEventData)
1477 return mImpl->mEventData->mInputStyle.outlineProperties;
1480 return GetDefaultOutlineProperties();
1483 void Controller::SetInputModePassword(bool passwordInput)
1485 if(NULL != mImpl->mEventData)
1487 mImpl->mEventData->mPasswordInput = passwordInput;
1491 bool Controller::IsInputModePassword()
1493 if(NULL != mImpl->mEventData)
1495 return mImpl->mEventData->mPasswordInput;
1500 void Controller::SetNoTextDoubleTapAction(NoTextTap::Action action)
1502 if(NULL != mImpl->mEventData)
1504 mImpl->mEventData->mDoubleTapAction = action;
1508 Controller::NoTextTap::Action Controller::GetNoTextDoubleTapAction() const
1510 NoTextTap::Action action = NoTextTap::NO_ACTION;
1512 if(NULL != mImpl->mEventData)
1514 action = mImpl->mEventData->mDoubleTapAction;
1520 void Controller::SetNoTextLongPressAction(NoTextTap::Action action)
1522 if(NULL != mImpl->mEventData)
1524 mImpl->mEventData->mLongPressAction = action;
1528 Controller::NoTextTap::Action Controller::GetNoTextLongPressAction() const
1530 NoTextTap::Action action = NoTextTap::NO_ACTION;
1532 if(NULL != mImpl->mEventData)
1534 action = mImpl->mEventData->mLongPressAction;
1540 bool Controller::IsUnderlineSetByString()
1542 return mImpl->mUnderlineSetByString;
1545 void Controller::UnderlineSetByString(bool setByString)
1547 mImpl->mUnderlineSetByString = setByString;
1550 bool Controller::IsShadowSetByString()
1552 return mImpl->mShadowSetByString;
1555 void Controller::ShadowSetByString(bool setByString)
1557 mImpl->mShadowSetByString = setByString;
1560 bool Controller::IsOutlineSetByString()
1562 return mImpl->mOutlineSetByString;
1565 void Controller::OutlineSetByString(bool setByString)
1567 mImpl->mOutlineSetByString = setByString;
1570 bool Controller::IsFontStyleSetByString()
1572 return mImpl->mFontStyleSetByString;
1575 void Controller::FontStyleSetByString(bool setByString)
1577 mImpl->mFontStyleSetByString = setByString;
1580 // public : Queries & retrieves.
1582 Layout::Engine& Controller::GetLayoutEngine()
1584 return mImpl->mLayoutEngine;
1587 View& Controller::GetView()
1589 return mImpl->mView;
1592 Vector3 Controller::GetNaturalSize()
1594 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetNaturalSize\n");
1595 Vector3 naturalSize;
1597 // Make sure the model is up-to-date before layouting
1598 ProcessModifyEvents();
1600 if(mImpl->mRecalculateNaturalSize)
1602 // Operations that can be done only once until the text changes.
1603 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1611 // Set the update info to relayout the whole text.
1612 mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1613 mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1615 // Make sure the model is up-to-date before layouting
1616 mImpl->UpdateModel(onlyOnceOperations);
1618 // Layout the text for the new width.
1619 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | LAYOUT | REORDER);
1621 // Store the actual control's size to restore later.
1622 const Size actualControlSize = mImpl->mModel->mVisualModel->mControlSize;
1624 DoRelayout(Size(MAX_FLOAT, MAX_FLOAT),
1625 static_cast<OperationsMask>(onlyOnceOperations |
1627 naturalSize.GetVectorXY());
1629 // Do not do again the only once operations.
1630 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
1632 // Do the size related operations again.
1633 const OperationsMask sizeOperations = static_cast<OperationsMask>(LAYOUT |
1636 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | sizeOperations);
1638 // Stores the natural size to avoid recalculate it again
1639 // unless the text/style changes.
1640 mImpl->mModel->mVisualModel->SetNaturalSize(naturalSize.GetVectorXY());
1642 mImpl->mRecalculateNaturalSize = false;
1644 // Clear the update info. This info will be set the next time the text is updated.
1645 mImpl->mTextUpdateInfo.Clear();
1646 mImpl->mTextUpdateInfo.mClearAll = true;
1648 // Restore the actual control's size.
1649 mImpl->mModel->mVisualModel->mControlSize = actualControlSize;
1651 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize calculated %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z);
1655 naturalSize = mImpl->mModel->mVisualModel->GetNaturalSize();
1657 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetNaturalSize cached %f,%f,%f\n", naturalSize.x, naturalSize.y, naturalSize.z);
1660 naturalSize.x = ConvertToEven(naturalSize.x);
1661 naturalSize.y = ConvertToEven(naturalSize.y);
1666 bool Controller::CheckForTextFit(float pointSize, Size& layoutSize)
1669 mImpl->mFontDefaults->mFitPointSize = pointSize;
1670 mImpl->mFontDefaults->sizeDefined = true;
1673 // Operations that can be done only once until the text changes.
1674 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1682 mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1683 mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1685 // Make sure the model is up-to-date before layouting
1686 mImpl->UpdateModel(onlyOnceOperations);
1688 DoRelayout(Size(layoutSize.width, MAX_FLOAT),
1689 static_cast<OperationsMask>(onlyOnceOperations | LAYOUT),
1692 // Clear the update info. This info will be set the next time the text is updated.
1693 mImpl->mTextUpdateInfo.Clear();
1694 mImpl->mTextUpdateInfo.mClearAll = true;
1696 if(textSize.width > layoutSize.width || textSize.height > layoutSize.height)
1703 void Controller::FitPointSizeforLayout(Size layoutSize)
1705 const OperationsMask operations = mImpl->mOperationsPending;
1706 if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations) || mImpl->mTextFitContentSize != layoutSize)
1708 bool actualellipsis = mImpl->mModel->mElideEnabled;
1709 float minPointSize = mImpl->mTextFitMinSize;
1710 float maxPointSize = mImpl->mTextFitMaxSize;
1711 float pointInterval = mImpl->mTextFitStepSize;
1713 mImpl->mModel->mElideEnabled = false;
1714 Vector<float> pointSizeArray;
1717 if(pointInterval < 1.f)
1719 mImpl->mTextFitStepSize = pointInterval = 1.0f;
1722 pointSizeArray.Reserve(static_cast<unsigned int>(ceil((maxPointSize - minPointSize) / pointInterval)));
1724 for(float i = minPointSize; i < maxPointSize; i += pointInterval)
1726 pointSizeArray.PushBack(i);
1729 pointSizeArray.PushBack(maxPointSize);
1731 int bestSizeIndex = 0;
1732 int min = bestSizeIndex + 1;
1733 int max = pointSizeArray.Size() - 1;
1736 int destI = (min + max) / 2;
1738 if(CheckForTextFit(pointSizeArray[destI], layoutSize))
1740 bestSizeIndex = min;
1746 bestSizeIndex = max;
1750 mImpl->mModel->mElideEnabled = actualellipsis;
1751 mImpl->mFontDefaults->mFitPointSize = pointSizeArray[bestSizeIndex];
1752 mImpl->mFontDefaults->sizeDefined = true;
1757 float Controller::GetHeightForWidth(float width)
1759 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::GetHeightForWidth %p width %f\n", this, width);
1760 // Make sure the model is up-to-date before layouting
1761 ProcessModifyEvents();
1764 if(fabsf(width - mImpl->mModel->mVisualModel->mControlSize.width) > Math::MACHINE_EPSILON_1000 ||
1765 mImpl->mTextUpdateInfo.mFullRelayoutNeeded ||
1766 mImpl->mTextUpdateInfo.mClearAll)
1768 // Operations that can be done only once until the text changes.
1769 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1777 // Set the update info to relayout the whole text.
1778 mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1779 mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1781 // Make sure the model is up-to-date before layouting
1782 mImpl->UpdateModel(onlyOnceOperations);
1784 // Layout the text for the new width.
1785 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | LAYOUT);
1787 // Store the actual control's width.
1788 const float actualControlWidth = mImpl->mModel->mVisualModel->mControlSize.width;
1790 DoRelayout(Size(width, MAX_FLOAT),
1791 static_cast<OperationsMask>(onlyOnceOperations |
1795 // Do not do again the only once operations.
1796 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
1798 // Do the size related operations again.
1799 const OperationsMask sizeOperations = static_cast<OperationsMask>(LAYOUT |
1803 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending | sizeOperations);
1805 // Clear the update info. This info will be set the next time the text is updated.
1806 mImpl->mTextUpdateInfo.Clear();
1807 mImpl->mTextUpdateInfo.mClearAll = true;
1809 // Restore the actual control's width.
1810 mImpl->mModel->mVisualModel->mControlSize.width = actualControlWidth;
1812 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth calculated %f\n", layoutSize.height);
1816 layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
1817 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::GetHeightForWidth cached %f\n", layoutSize.height);
1820 return layoutSize.height;
1823 int Controller::GetLineCount(float width)
1825 GetHeightForWidth(width);
1826 int numberofLines = mImpl->mModel->GetNumberOfLines();
1827 return numberofLines;
1830 const ModelInterface* const Controller::GetTextModel() const
1832 return mImpl->mModel.Get();
1835 float Controller::GetScrollAmountByUserInput()
1837 float scrollAmount = 0.0f;
1839 if(NULL != mImpl->mEventData && mImpl->mEventData->mCheckScrollAmount)
1841 scrollAmount = mImpl->mModel->mScrollPosition.y - mImpl->mModel->mScrollPositionLast.y;
1842 mImpl->mEventData->mCheckScrollAmount = false;
1844 return scrollAmount;
1847 bool Controller::GetTextScrollInfo(float& scrollPosition, float& controlHeight, float& layoutHeight)
1849 const Vector2& layout = mImpl->mModel->mVisualModel->GetLayoutSize();
1852 controlHeight = mImpl->mModel->mVisualModel->mControlSize.height;
1853 layoutHeight = layout.height;
1854 scrollPosition = mImpl->mModel->mScrollPosition.y;
1855 isScrolled = !Equals(mImpl->mModel->mScrollPosition.y, mImpl->mModel->mScrollPositionLast.y, Math::MACHINE_EPSILON_1);
1859 void Controller::SetHiddenInputOption(const Property::Map& options)
1861 if(NULL == mImpl->mHiddenInput)
1863 mImpl->mHiddenInput = new HiddenText(this);
1865 mImpl->mHiddenInput->SetProperties(options);
1868 void Controller::GetHiddenInputOption(Property::Map& options)
1870 if(NULL != mImpl->mHiddenInput)
1872 mImpl->mHiddenInput->GetProperties(options);
1876 void Controller::SetPlaceholderProperty(const Property::Map& map)
1878 PlaceholderHandler::SetPlaceholderProperty(*this, map);
1881 void Controller::GetPlaceholderProperty(Property::Map& map)
1883 PlaceholderHandler::GetPlaceholderProperty(*this, map);
1886 Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection()
1888 // Make sure the model is up-to-date before layouting
1889 ProcessModifyEvents();
1891 if(mImpl->mUpdateTextDirection)
1893 // Operations that can be done only once until the text changes.
1894 const OperationsMask onlyOnceOperations = static_cast<OperationsMask>(CONVERT_TO_UTF32 |
1902 // Set the update info to relayout the whole text.
1903 mImpl->mTextUpdateInfo.mParagraphCharacterIndex = 0u;
1904 mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
1906 // Make sure the model is up-to-date before layouting
1907 mImpl->UpdateModel(onlyOnceOperations);
1909 Vector3 naturalSize;
1910 DoRelayout(Size(MAX_FLOAT, MAX_FLOAT),
1911 static_cast<OperationsMask>(onlyOnceOperations |
1912 LAYOUT | REORDER | UPDATE_DIRECTION),
1913 naturalSize.GetVectorXY());
1915 // Do not do again the only once operations.
1916 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending & ~onlyOnceOperations);
1918 // Clear the update info. This info will be set the next time the text is updated.
1919 mImpl->mTextUpdateInfo.Clear();
1921 // FullRelayoutNeeded should be true because DoRelayout is MAX_FLOAT, MAX_FLOAT.
1922 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1924 mImpl->mUpdateTextDirection = false;
1927 return mImpl->mIsTextDirectionRTL ? Toolkit::DevelText::TextDirection::RIGHT_TO_LEFT : Toolkit::DevelText::TextDirection::LEFT_TO_RIGHT;
1930 Toolkit::DevelText::VerticalLineAlignment::Type Controller::GetVerticalLineAlignment() const
1932 return mImpl->mModel->GetVerticalLineAlignment();
1935 void Controller::SetVerticalLineAlignment(Toolkit::DevelText::VerticalLineAlignment::Type alignment)
1937 mImpl->mModel->mVerticalLineAlignment = alignment;
1940 // public : Relayout.
1942 Controller::UpdateTextType Controller::Relayout(const Size& size, Dali::LayoutDirection::Type layoutDirection)
1944 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::Relayout %p size %f,%f, autoScroll[%s]\n", this, size.width, size.height, mImpl->mIsAutoScrollEnabled ? "true" : "false");
1946 UpdateTextType updateTextType = NONE_UPDATED;
1948 if((size.width < Math::MACHINE_EPSILON_1000) || (size.height < Math::MACHINE_EPSILON_1000))
1950 if(0u != mImpl->mModel->mVisualModel->mGlyphPositions.Count())
1952 mImpl->mModel->mVisualModel->mGlyphPositions.Clear();
1953 updateTextType = MODEL_UPDATED;
1956 // Clear the update info. This info will be set the next time the text is updated.
1957 mImpl->mTextUpdateInfo.Clear();
1959 // Not worth to relayout if width or height is equal to zero.
1960 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n");
1962 return updateTextType;
1965 // Whether a new size has been set.
1966 const bool newSize = (size != mImpl->mModel->mVisualModel->mControlSize);
1970 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mModel->mVisualModel->mControlSize.width, mImpl->mModel->mVisualModel->mControlSize.height);
1972 if((0 == mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd) &&
1973 (0 == mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters) &&
1974 ((mImpl->mModel->mVisualModel->mControlSize.width < Math::MACHINE_EPSILON_1000) || (mImpl->mModel->mVisualModel->mControlSize.height < Math::MACHINE_EPSILON_1000)))
1976 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
1979 // Layout operations that need to be done if the size changes.
1980 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
1983 UPDATE_LAYOUT_SIZE |
1985 // Set the update info to relayout the whole text.
1986 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
1987 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
1989 // Store the size used to layout the text.
1990 mImpl->mModel->mVisualModel->mControlSize = size;
1993 // Whether there are modify events.
1994 if(0u != mImpl->mModifyEvents.Count())
1996 // Style operations that need to be done if the text is modified.
1997 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
2001 // Set the update info to elide the text.
2002 if(mImpl->mModel->mElideEnabled ||
2003 ((NULL != mImpl->mEventData) && mImpl->mEventData->mIsPlaceholderElideEnabled))
2005 // Update Text layout for applying elided
2006 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
2009 UPDATE_LAYOUT_SIZE |
2011 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
2012 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2015 if(mImpl->mModel->mMatchSystemLanguageDirection && mImpl->mLayoutDirection != layoutDirection)
2017 // Clear the update info. This info will be set the next time the text is updated.
2018 mImpl->mTextUpdateInfo.mClearAll = true;
2019 // Apply modifications to the model
2020 // Shape the text again is needed because characters like '()[]{}' have to be mirrored and the glyphs generated again.
2021 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
2028 mImpl->mLayoutDirection = layoutDirection;
2031 // Make sure the model is up-to-date before layouting.
2032 ProcessModifyEvents();
2033 bool updated = mImpl->UpdateModel(mImpl->mOperationsPending);
2037 updated = DoRelayout(size,
2038 mImpl->mOperationsPending,
2044 updateTextType = MODEL_UPDATED;
2047 // Do not re-do any operation until something changes.
2048 mImpl->mOperationsPending = NO_OPERATION;
2049 mImpl->mModel->mScrollPositionLast = mImpl->mModel->mScrollPosition;
2051 // Whether the text control is editable
2052 const bool isEditable = NULL != mImpl->mEventData;
2054 // Keep the current offset as it will be used to update the decorator's positions (if the size changes).
2056 if(newSize && isEditable)
2058 offset = mImpl->mModel->mScrollPosition;
2061 if(!isEditable || !IsMultiLineEnabled())
2063 // After doing the text layout, the vertical offset to place the actor in the desired position can be calculated.
2064 CalculateVerticalOffset(size);
2071 // If there is a new size, the scroll position needs to be clamped.
2072 mImpl->ClampHorizontalScroll(layoutSize);
2074 // Update the decorator's positions is needed if there is a new size.
2075 mImpl->mEventData->mDecorator->UpdatePositions(mImpl->mModel->mScrollPosition - offset);
2078 // Move the cursor, grab handle etc.
2079 if(mImpl->ProcessInputEvents())
2081 updateTextType = static_cast<UpdateTextType>(updateTextType | DECORATOR_UPDATED);
2085 // Clear the update info. This info will be set the next time the text is updated.
2086 mImpl->mTextUpdateInfo.Clear();
2087 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::Relayout\n");
2089 return updateTextType;
2092 void Controller::RequestRelayout()
2094 mImpl->RequestRelayout();
2097 // public : Input style change signals.
2099 bool Controller::IsInputStyleChangedSignalsQueueEmpty()
2101 return (NULL == mImpl->mEventData) || (0u == mImpl->mEventData->mInputStyleChangedQueue.Count());
2104 void Controller::ProcessInputStyleChangedSignals()
2106 if(NULL == mImpl->mEventData)
2112 for(Vector<InputStyle::Mask>::ConstIterator it = mImpl->mEventData->mInputStyleChangedQueue.Begin(),
2113 endIt = mImpl->mEventData->mInputStyleChangedQueue.End();
2117 const InputStyle::Mask mask = *it;
2119 if(NULL != mImpl->mEditableControlInterface)
2121 // Emit the input style changed signal.
2122 mImpl->mEditableControlInterface->InputStyleChanged(mask);
2126 mImpl->mEventData->mInputStyleChangedQueue.Clear();
2129 // public : Text-input Event Queuing.
2131 void Controller::KeyboardFocusGainEvent()
2133 EventHandler::KeyboardFocusGainEvent(*this);
2136 void Controller::KeyboardFocusLostEvent()
2138 EventHandler::KeyboardFocusLostEvent(*this);
2141 bool Controller::KeyEvent(const Dali::KeyEvent& keyEvent)
2143 return EventHandler::KeyEvent(*this, keyEvent);
2146 void Controller::TapEvent(unsigned int tapCount, float x, float y)
2148 EventHandler::TapEvent(*this, tapCount, x, y);
2151 void Controller::PanEvent(GestureState state, const Vector2& displacement)
2153 EventHandler::PanEvent(*this, state, displacement);
2156 void Controller::LongPressEvent(GestureState state, float x, float y)
2158 EventHandler::LongPressEvent(*this, state, x, y);
2161 void Controller::SelectEvent(float x, float y, SelectionType selectType)
2163 EventHandler::SelectEvent(*this, x, y, selectType);
2166 void Controller::SetTextSelectionRange(const uint32_t* start, const uint32_t* end)
2168 if(mImpl->mEventData)
2170 mImpl->mEventData->mCheckScrollAmount = true;
2171 mImpl->mEventData->mIsLeftHandleSelected = true;
2172 mImpl->mEventData->mIsRightHandleSelected = true;
2173 mImpl->SetTextSelectionRange(start, end);
2174 mImpl->RequestRelayout();
2175 KeyboardFocusGainEvent();
2179 Uint32Pair Controller::GetTextSelectionRange() const
2181 return mImpl->GetTextSelectionRange();
2184 void Controller::SelectWholeText()
2186 SelectEvent(0.f, 0.f, SelectionType::ALL);
2189 void Controller::SelectNone()
2191 SelectEvent(0.f, 0.f, SelectionType::NONE);
2194 string Controller::GetSelectedText() const
2197 if(EventData::SELECTING == mImpl->mEventData->mState)
2199 mImpl->RetrieveSelection(text, false);
2204 InputMethodContext::CallbackData Controller::OnInputMethodContextEvent(InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent)
2206 return EventHandler::OnInputMethodContextEvent(*this, inputMethodContext, inputMethodContextEvent);
2209 void Controller::PasteClipboardItemEvent()
2211 EventHandler::PasteClipboardItemEvent(*this);
2214 // protected : Inherit from Text::Decorator::ControllerInterface.
2216 void Controller::GetTargetSize(Vector2& targetSize)
2218 targetSize = mImpl->mModel->mVisualModel->mControlSize;
2221 void Controller::AddDecoration(Actor& actor, bool needsClipping)
2223 if(NULL != mImpl->mEditableControlInterface)
2225 mImpl->mEditableControlInterface->AddDecoration(actor, needsClipping);
2229 bool Controller::IsEditable() const
2231 return mImpl->IsEditable();
2234 void Controller::SetEditable(bool editable)
2236 mImpl->SetEditable(editable);
2237 if(mImpl->mEventData && mImpl->mEventData->mDecorator)
2239 mImpl->mEventData->mDecorator->SetEditable(editable);
2243 void Controller::DecorationEvent(HandleType handleType, HandleState state, float x, float y)
2245 EventHandler::DecorationEvent(*this, handleType, state, x, y);
2248 // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface.
2250 void Controller::TextPopupButtonTouched(Dali::Toolkit::TextSelectionPopup::Buttons button)
2252 EventHandler::TextPopupButtonTouched(*this, button);
2255 void Controller::DisplayTimeExpired()
2257 mImpl->mEventData->mUpdateCursorPosition = true;
2258 // Apply modifications to the model
2259 mImpl->mOperationsPending = ALL_OPERATIONS;
2261 mImpl->RequestRelayout();
2264 // private : Update.
2266 void Controller::InsertText(const std::string& text, Controller::InsertType type)
2268 bool removedPrevious = false;
2269 bool removedSelected = false;
2270 bool maxLengthReached = false;
2272 DALI_ASSERT_DEBUG(NULL != mImpl->mEventData && "Unexpected InsertText")
2274 if(NULL == mImpl->mEventData)
2279 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);
2281 // TODO: At the moment the underline runs are only for pre-edit.
2282 mImpl->mModel->mVisualModel->mUnderlineRuns.Clear();
2284 // Remove the previous InputMethodContext pre-edit.
2285 if(mImpl->mEventData->mPreEditFlag && (0u != mImpl->mEventData->mPreEditLength))
2287 removedPrevious = RemoveText(-static_cast<int>(mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition),
2288 mImpl->mEventData->mPreEditLength,
2289 DONT_UPDATE_INPUT_STYLE);
2291 mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
2292 mImpl->mEventData->mPreEditLength = 0u;
2296 // Remove the previous Selection.
2297 removedSelected = RemoveSelectedText();
2300 Vector<Character> utf32Characters;
2301 Length characterCount = 0u;
2305 // Convert text into UTF-32
2306 utf32Characters.Resize(text.size());
2308 // This is a bit horrible but std::string returns a (signed) char*
2309 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text.c_str());
2311 // Transform a text array encoded in utf8 into an array encoded in utf32.
2312 // It returns the actual number of characters.
2313 characterCount = Utf8ToUtf32(utf8, text.size(), utf32Characters.Begin());
2314 utf32Characters.Resize(characterCount);
2316 DALI_ASSERT_DEBUG(text.size() >= utf32Characters.Count() && "Invalid UTF32 conversion length");
2317 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "UTF8 size %d, UTF32 size %d\n", text.size(), utf32Characters.Count());
2320 if(0u != utf32Characters.Count()) // Check if Utf8ToUtf32 conversion succeeded
2322 // The placeholder text is no longer needed
2323 if(mImpl->IsShowingPlaceholderText())
2328 mImpl->ChangeState(EventData::EDITING);
2330 // Handle the InputMethodContext (predicitive text) state changes
2333 // InputMethodContext is no longer handling key-events
2334 mImpl->ClearPreEditFlag();
2338 if(!mImpl->mEventData->mPreEditFlag)
2340 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Entered PreEdit state\n");
2342 // Record the start of the pre-edit text
2343 mImpl->mEventData->mPreEditStartPosition = mImpl->mEventData->mPrimaryCursorPosition;
2346 mImpl->mEventData->mPreEditLength = utf32Characters.Count();
2347 mImpl->mEventData->mPreEditFlag = true;
2349 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "mPreEditStartPosition %d mPreEditLength %d\n", mImpl->mEventData->mPreEditStartPosition, mImpl->mEventData->mPreEditLength);
2352 const Length numberOfCharactersInModel = mImpl->mModel->mLogicalModel->mText.Count();
2354 // Restrict new text to fit within Maximum characters setting.
2355 Length maxSizeOfNewText = std::min((mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel), characterCount);
2356 maxLengthReached = (characterCount > maxSizeOfNewText);
2358 // The cursor position.
2359 CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2361 // Update the text's style.
2363 // Updates the text style runs by adding characters.
2364 mImpl->mModel->mLogicalModel->UpdateTextStyleRuns(cursorIndex, maxSizeOfNewText);
2366 // Get the character index from the cursor index.
2367 const CharacterIndex styleIndex = (cursorIndex > 0u) ? cursorIndex - 1u : 0u;
2369 // Retrieve the text's style for the given index.
2371 mImpl->RetrieveDefaultInputStyle(style);
2372 mImpl->mModel->mLogicalModel->RetrieveStyle(styleIndex, style);
2374 // Whether to add a new text color run.
2375 const bool addColorRun = (style.textColor != mImpl->mEventData->mInputStyle.textColor) && !mImpl->mEventData->mInputStyle.isDefaultColor;
2377 // Whether to add a new font run.
2378 const bool addFontNameRun = (style.familyName != mImpl->mEventData->mInputStyle.familyName) && mImpl->mEventData->mInputStyle.isFamilyDefined;
2379 const bool addFontWeightRun = (style.weight != mImpl->mEventData->mInputStyle.weight) && mImpl->mEventData->mInputStyle.isWeightDefined;
2380 const bool addFontWidthRun = (style.width != mImpl->mEventData->mInputStyle.width) && mImpl->mEventData->mInputStyle.isWidthDefined;
2381 const bool addFontSlantRun = (style.slant != mImpl->mEventData->mInputStyle.slant) && mImpl->mEventData->mInputStyle.isSlantDefined;
2382 const bool addFontSizeRun = (style.size != mImpl->mEventData->mInputStyle.size) && mImpl->mEventData->mInputStyle.isSizeDefined;
2387 const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mColorRuns.Count();
2388 mImpl->mModel->mLogicalModel->mColorRuns.Resize(numberOfRuns + 1u);
2390 ColorRun& colorRun = *(mImpl->mModel->mLogicalModel->mColorRuns.Begin() + numberOfRuns);
2391 colorRun.color = mImpl->mEventData->mInputStyle.textColor;
2392 colorRun.characterRun.characterIndex = cursorIndex;
2393 colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2396 if(addFontNameRun ||
2402 const VectorBase::SizeType numberOfRuns = mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Count();
2403 mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Resize(numberOfRuns + 1u);
2405 FontDescriptionRun& fontDescriptionRun = *(mImpl->mModel->mLogicalModel->mFontDescriptionRuns.Begin() + numberOfRuns);
2409 fontDescriptionRun.familyLength = mImpl->mEventData->mInputStyle.familyName.size();
2410 fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
2411 memcpy(fontDescriptionRun.familyName, mImpl->mEventData->mInputStyle.familyName.c_str(), fontDescriptionRun.familyLength);
2412 fontDescriptionRun.familyDefined = true;
2414 // The memory allocated for the font family name is freed when the font description is removed from the logical model.
2417 if(addFontWeightRun)
2419 fontDescriptionRun.weight = mImpl->mEventData->mInputStyle.weight;
2420 fontDescriptionRun.weightDefined = true;
2425 fontDescriptionRun.width = mImpl->mEventData->mInputStyle.width;
2426 fontDescriptionRun.widthDefined = true;
2431 fontDescriptionRun.slant = mImpl->mEventData->mInputStyle.slant;
2432 fontDescriptionRun.slantDefined = true;
2437 fontDescriptionRun.size = static_cast<PointSize26Dot6>(mImpl->mEventData->mInputStyle.size * 64.f);
2438 fontDescriptionRun.sizeDefined = true;
2441 fontDescriptionRun.characterRun.characterIndex = cursorIndex;
2442 fontDescriptionRun.characterRun.numberOfCharacters = maxSizeOfNewText;
2445 // Insert at current cursor position.
2446 Vector<Character>& modifyText = mImpl->mModel->mLogicalModel->mText;
2448 if(cursorIndex < numberOfCharactersInModel)
2450 modifyText.Insert(modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText);
2454 modifyText.Insert(modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText);
2457 // Mark the first paragraph to be updated.
2458 if(Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout())
2460 mImpl->mTextUpdateInfo.mCharacterIndex = 0;
2461 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2462 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = numberOfCharactersInModel + maxSizeOfNewText;
2463 mImpl->mTextUpdateInfo.mClearAll = true;
2467 mImpl->mTextUpdateInfo.mCharacterIndex = std::min(cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex);
2468 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd += maxSizeOfNewText;
2471 // Update the cursor index.
2472 cursorIndex += maxSizeOfNewText;
2474 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);
2477 if((0u == mImpl->mModel->mLogicalModel->mText.Count()) &&
2478 mImpl->IsPlaceholderAvailable())
2480 // Show place-holder if empty after removing the pre-edit text
2481 ShowPlaceholderText();
2482 mImpl->mEventData->mUpdateCursorPosition = true;
2483 mImpl->ClearPreEditFlag();
2485 else if(removedPrevious ||
2487 (0 != utf32Characters.Count()))
2489 // Queue an inserted event
2490 mImpl->QueueModifyEvent(ModifyEvent::TEXT_INSERTED);
2492 mImpl->mEventData->mUpdateCursorPosition = true;
2495 mImpl->mEventData->mScrollAfterDelete = true;
2499 mImpl->mEventData->mScrollAfterUpdatePosition = true;
2503 if(maxLengthReached)
2505 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "MaxLengthReached (%d)\n", mImpl->mModel->mLogicalModel->mText.Count());
2507 mImpl->ResetInputMethodContext();
2509 if(NULL != mImpl->mEditableControlInterface)
2511 // Do this last since it provides callbacks into application code
2512 mImpl->mEditableControlInterface->MaxLengthReached();
2517 void Controller::PasteText(const std::string& stringToPaste)
2519 InsertText(stringToPaste, Text::Controller::COMMIT);
2520 mImpl->ChangeState(EventData::EDITING);
2521 mImpl->RequestRelayout();
2523 if(NULL != mImpl->mEditableControlInterface)
2525 // Do this last since it provides callbacks into application code
2526 mImpl->mEditableControlInterface->TextChanged(true);
2530 bool Controller::RemoveText(int cursorOffset,
2531 int numberOfCharacters,
2532 UpdateInputStyleType type)
2534 bool removed = false;
2535 bool removeAll = false;
2537 if(NULL == mImpl->mEventData)
2542 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);
2544 if(!mImpl->IsShowingPlaceholderText())
2546 // Delete at current cursor position
2547 Vector<Character>& currentText = mImpl->mModel->mLogicalModel->mText;
2548 CharacterIndex& oldCursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
2550 CharacterIndex cursorIndex = 0;
2552 // Validate the cursor position & number of characters
2553 if((static_cast<int>(mImpl->mEventData->mPrimaryCursorPosition) + cursorOffset) >= 0)
2555 cursorIndex = mImpl->mEventData->mPrimaryCursorPosition + cursorOffset;
2558 if((cursorIndex + numberOfCharacters) > currentText.Count())
2560 numberOfCharacters = currentText.Count() - cursorIndex;
2563 if((cursorIndex == 0) && (currentText.Count() - numberOfCharacters == 0))
2568 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.
2569 ((cursorIndex + numberOfCharacters) <= mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters))
2571 // Mark the paragraphs to be updated.
2572 if(Layout::Engine::SINGLE_LINE_BOX == mImpl->mLayoutEngine.GetLayout())
2574 mImpl->mTextUpdateInfo.mCharacterIndex = 0;
2575 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2576 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters - numberOfCharacters;
2577 mImpl->mTextUpdateInfo.mClearAll = true;
2581 mImpl->mTextUpdateInfo.mCharacterIndex = std::min(cursorIndex, mImpl->mTextUpdateInfo.mCharacterIndex);
2582 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove += numberOfCharacters;
2585 // Update the input style and remove the text's style before removing the text.
2587 if(UPDATE_INPUT_STYLE == type)
2589 // Keep a copy of the current input style.
2590 InputStyle currentInputStyle;
2591 currentInputStyle.Copy(mImpl->mEventData->mInputStyle);
2593 // Set first the default input style.
2594 mImpl->RetrieveDefaultInputStyle(mImpl->mEventData->mInputStyle);
2596 // Update the input style.
2597 mImpl->mModel->mLogicalModel->RetrieveStyle(cursorIndex, mImpl->mEventData->mInputStyle);
2599 // Compare if the input style has changed.
2600 const bool hasInputStyleChanged = !currentInputStyle.Equal(mImpl->mEventData->mInputStyle);
2602 if(hasInputStyleChanged)
2604 const InputStyle::Mask styleChangedMask = currentInputStyle.GetInputStyleChangeMask(mImpl->mEventData->mInputStyle);
2605 // Queue the input style changed signal.
2606 mImpl->mEventData->mInputStyleChangedQueue.PushBack(styleChangedMask);
2610 // If the number of current text and the number of characters to be deleted are same,
2611 // it means all texts should be removed and all Preedit variables should be initialized.
2614 mImpl->ClearPreEditFlag();
2615 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0;
2618 // Updates the text style runs by removing characters. Runs with no characters are removed.
2619 mImpl->mModel->mLogicalModel->UpdateTextStyleRuns(cursorIndex, -numberOfCharacters);
2621 // Remove the characters.
2622 Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
2623 Vector<Character>::Iterator last = first + numberOfCharacters;
2625 currentText.Erase(first, last);
2627 // Cursor position retreat
2628 oldCursorIndex = cursorIndex;
2630 mImpl->mEventData->mScrollAfterDelete = true;
2632 if(EventData::INACTIVE == mImpl->mEventData->mState)
2634 mImpl->ChangeState(EventData::EDITING);
2637 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::RemoveText %p removed %d\n", this, numberOfCharacters);
2646 bool Controller::RemoveSelectedText()
2648 bool textRemoved(false);
2650 if(EventData::SELECTING == mImpl->mEventData->mState)
2652 std::string removedString;
2653 mImpl->RetrieveSelection(removedString, true);
2655 if(!removedString.empty())
2658 mImpl->ChangeState(EventData::EDITING);
2665 // private : Relayout.
2667 bool Controller::DoRelayout(const Size& size,
2668 OperationsMask operationsRequired,
2671 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::DoRelayout %p size %f,%f\n", this, size.width, size.height);
2672 bool viewUpdated(false);
2674 // Calculate the operations to be done.
2675 const OperationsMask operations = static_cast<OperationsMask>(mImpl->mOperationsPending & operationsRequired);
2677 const CharacterIndex startIndex = mImpl->mTextUpdateInfo.mParagraphCharacterIndex;
2678 const Length requestedNumberOfCharacters = mImpl->mTextUpdateInfo.mRequestedNumberOfCharacters;
2680 // Get the current layout size.
2681 layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2683 if(NO_OPERATION != (LAYOUT & operations))
2685 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->Controller::DoRelayout LAYOUT & operations\n");
2687 // Some vectors with data needed to layout and reorder may be void
2688 // after the first time the text has been laid out.
2689 // Fill the vectors again.
2691 // Calculate the number of glyphs to layout.
2692 const Vector<GlyphIndex>& charactersToGlyph = mImpl->mModel->mVisualModel->mCharactersToGlyph;
2693 const Vector<Length>& glyphsPerCharacter = mImpl->mModel->mVisualModel->mGlyphsPerCharacter;
2694 const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
2695 const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
2697 const CharacterIndex lastIndex = startIndex + ((requestedNumberOfCharacters > 0u) ? requestedNumberOfCharacters - 1u : 0u);
2698 const GlyphIndex startGlyphIndex = mImpl->mTextUpdateInfo.mStartGlyphIndex;
2700 // Make sure the index is not out of bound
2701 if(charactersToGlyph.Count() != glyphsPerCharacter.Count() ||
2702 requestedNumberOfCharacters > charactersToGlyph.Count() ||
2703 (lastIndex > charactersToGlyph.Count() && charactersToGlyph.Count() > 0u))
2705 std::string currentText;
2706 GetText(currentText);
2708 DALI_LOG_ERROR("Controller::DoRelayout: Attempting to access invalid buffer\n");
2709 DALI_LOG_ERROR("Current text is: %s\n", currentText.c_str());
2710 DALI_LOG_ERROR("startIndex: %u, lastIndex: %u, requestedNumberOfCharacters: %u, charactersToGlyph.Count = %lu, glyphsPerCharacter.Count = %lu\n", startIndex, lastIndex, requestedNumberOfCharacters, charactersToGlyph.Count(), glyphsPerCharacter.Count());
2715 const Length numberOfGlyphs = (requestedNumberOfCharacters > 0u) ? *(charactersToGlyphBuffer + lastIndex) + *(glyphsPerCharacterBuffer + lastIndex) - startGlyphIndex : 0u;
2716 const Length totalNumberOfGlyphs = mImpl->mModel->mVisualModel->mGlyphs.Count();
2718 if(0u == totalNumberOfGlyphs)
2720 if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations))
2722 mImpl->mModel->mVisualModel->SetLayoutSize(Size::ZERO);
2725 // Nothing else to do if there is no glyphs.
2726 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::DoRelayout no glyphs, view updated true\n");
2730 // Set the layout parameters.
2731 Layout::Parameters layoutParameters(size,
2734 // Resize the vector of positions to have the same size than the vector of glyphs.
2735 Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
2736 glyphPositions.Resize(totalNumberOfGlyphs);
2738 // Whether the last character is a new paragraph character.
2739 const Character* const textBuffer = mImpl->mModel->mLogicalModel->mText.Begin();
2740 mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph = TextAbstraction::IsNewParagraph(*(textBuffer + (mImpl->mModel->mLogicalModel->mText.Count() - 1u)));
2741 layoutParameters.isLastNewParagraph = mImpl->mTextUpdateInfo.mIsLastCharacterNewParagraph;
2743 // The initial glyph and the number of glyphs to layout.
2744 layoutParameters.startGlyphIndex = startGlyphIndex;
2745 layoutParameters.numberOfGlyphs = numberOfGlyphs;
2746 layoutParameters.startLineIndex = mImpl->mTextUpdateInfo.mStartLineIndex;
2747 layoutParameters.estimatedNumberOfLines = mImpl->mTextUpdateInfo.mEstimatedNumberOfLines;
2749 // Update the ellipsis
2750 bool elideTextEnabled = mImpl->mModel->mElideEnabled;
2752 if(NULL != mImpl->mEventData)
2754 if(mImpl->mEventData->mPlaceholderEllipsisFlag && mImpl->IsShowingPlaceholderText())
2756 elideTextEnabled = mImpl->mEventData->mIsPlaceholderElideEnabled;
2758 else if(EventData::INACTIVE != mImpl->mEventData->mState)
2760 // Disable ellipsis when editing
2761 elideTextEnabled = false;
2764 // Reset the scroll position in inactive state
2765 if(elideTextEnabled && (mImpl->mEventData->mState == EventData::INACTIVE))
2767 ResetScrollPosition();
2771 // Update the visual model.
2772 bool isAutoScrollEnabled = mImpl->mIsAutoScrollEnabled;
2774 viewUpdated = mImpl->mLayoutEngine.LayoutText(layoutParameters,
2777 isAutoScrollEnabled);
2778 mImpl->mIsAutoScrollEnabled = isAutoScrollEnabled;
2780 viewUpdated = viewUpdated || (newLayoutSize != layoutSize);
2784 layoutSize = newLayoutSize;
2786 if(NO_OPERATION != (UPDATE_DIRECTION & operations))
2788 mImpl->mIsTextDirectionRTL = false;
2791 if((NO_OPERATION != (UPDATE_DIRECTION & operations)) && !mImpl->mModel->mVisualModel->mLines.Empty())
2793 mImpl->mIsTextDirectionRTL = mImpl->mModel->mVisualModel->mLines[0u].direction;
2796 // Sets the layout size.
2797 if(NO_OPERATION != (UPDATE_LAYOUT_SIZE & operations))
2799 mImpl->mModel->mVisualModel->SetLayoutSize(layoutSize);
2804 if(NO_OPERATION != (ALIGN & operations))
2806 // The laid-out lines.
2807 Vector<LineRun>& lines = mImpl->mModel->mVisualModel->mLines;
2809 CharacterIndex alignStartIndex = startIndex;
2810 Length alignRequestedNumberOfCharacters = requestedNumberOfCharacters;
2812 // the whole text needs to be full aligned.
2813 // If you do not do a full aligned, only the last line of the multiline input is aligned.
2814 if(mImpl->mEventData && mImpl->mEventData->mUpdateAlignment)
2816 alignStartIndex = 0u;
2817 alignRequestedNumberOfCharacters = mImpl->mModel->mLogicalModel->mText.Count();
2818 mImpl->mEventData->mUpdateAlignment = false;
2821 // Need to align with the control's size as the text may contain lines
2822 // starting either with left to right text or right to left.
2823 mImpl->mLayoutEngine.Align(size,
2825 alignRequestedNumberOfCharacters,
2826 mImpl->mModel->mHorizontalAlignment,
2828 mImpl->mModel->mAlignmentOffset,
2829 mImpl->mLayoutDirection,
2830 mImpl->mModel->mMatchSystemLanguageDirection);
2834 #if defined(DEBUG_ENABLED)
2835 std::string currentText;
2836 GetText(currentText);
2837 DALI_LOG_INFO(gLogFilter, Debug::Concise, "Controller::DoRelayout [%p] mImpl->mIsTextDirectionRTL[%s] [%s]\n", this, (mImpl->mIsTextDirectionRTL) ? "true" : "false", currentText.c_str());
2839 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "<--Controller::DoRelayout, view updated %s\n", (viewUpdated ? "true" : "false"));
2843 void Controller::CalculateVerticalOffset(const Size& controlSize)
2845 ModelPtr& model = mImpl->mModel;
2846 VisualModelPtr& visualModel = model->mVisualModel;
2847 Size layoutSize = mImpl->mModel->mVisualModel->GetLayoutSize();
2848 Size oldLayoutSize = layoutSize;
2849 float offsetY = 0.f;
2850 bool needRecalc = false;
2851 float defaultFontLineHeight = mImpl->GetDefaultFontLineHeight();
2853 if(fabsf(layoutSize.height) < Math::MACHINE_EPSILON_1000)
2855 // Get the line height of the default font.
2856 layoutSize.height = defaultFontLineHeight;
2859 // Whether the text control is editable
2860 const bool isEditable = NULL != mImpl->mEventData;
2861 if(isEditable && layoutSize.height != defaultFontLineHeight)
2863 // This code prevents the wrong positioning of cursor when the layout size is bigger/smaller than defaultFontLineHeight.
2864 // This situation occurs when the size of placeholder text is different from the default text.
2865 layoutSize.height = defaultFontLineHeight;
2869 switch(mImpl->mModel->mVerticalAlignment)
2871 case VerticalAlignment::TOP:
2873 mImpl->mModel->mScrollPosition.y = 0.f;
2877 case VerticalAlignment::CENTER:
2879 mImpl->mModel->mScrollPosition.y = floorf(0.5f * (controlSize.height - layoutSize.height)); // try to avoid pixel alignment.
2880 if(needRecalc) offsetY = floorf(0.5f * (layoutSize.height - oldLayoutSize.height));
2883 case VerticalAlignment::BOTTOM:
2885 mImpl->mModel->mScrollPosition.y = controlSize.height - layoutSize.height;
2886 if(needRecalc) offsetY = layoutSize.height - oldLayoutSize.height;
2893 // Update glyphPositions according to recalculation.
2894 const Length positionCount = visualModel->mGlyphPositions.Count();
2895 Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
2896 for(Length index = 0u; index < positionCount; index++)
2898 glyphPositions[index].y += offsetY;
2903 // private : Events.
2905 void Controller::ProcessModifyEvents()
2907 EventHandler::ProcessModifyEvents(*this);
2910 void Controller::TextReplacedEvent()
2912 EventHandler::TextReplacedEvent(*this);
2915 void Controller::TextInsertedEvent()
2917 EventHandler::TextInsertedEvent(*this);
2920 void Controller::TextDeletedEvent()
2922 EventHandler::TextDeletedEvent(*this);
2925 bool Controller::DeleteEvent(int keyCode)
2927 return EventHandler::DeleteEvent(*this, keyCode);
2930 // private : Helpers.
2932 void Controller::ResetText()
2935 mImpl->mModel->mLogicalModel->mText.Clear();
2937 // Reset the embedded images buffer.
2938 mImpl->mModel->mLogicalModel->ClearEmbeddedImages();
2940 // We have cleared everything including the placeholder-text
2941 mImpl->PlaceholderCleared();
2943 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2944 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2945 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = 0u;
2947 // Clear any previous text.
2948 mImpl->mTextUpdateInfo.mClearAll = true;
2950 // The natural size needs to be re-calculated.
2951 mImpl->mRecalculateNaturalSize = true;
2953 // The text direction needs to be updated.
2954 mImpl->mUpdateTextDirection = true;
2956 // Apply modifications to the model
2957 mImpl->mOperationsPending = ALL_OPERATIONS;
2960 void Controller::ShowPlaceholderText()
2962 if(mImpl->IsPlaceholderAvailable())
2964 DALI_ASSERT_DEBUG(mImpl->mEventData && "No placeholder text available");
2966 if(NULL == mImpl->mEventData)
2971 mImpl->mEventData->mIsShowingPlaceholderText = true;
2973 // Disable handles when showing place-holder text
2974 mImpl->mEventData->mDecorator->SetHandleActive(GRAB_HANDLE, false);
2975 mImpl->mEventData->mDecorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
2976 mImpl->mEventData->mDecorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
2978 const char* text(NULL);
2981 // TODO - Switch Placeholder text when changing state
2982 if((EventData::INACTIVE != mImpl->mEventData->mState) &&
2983 (0u != mImpl->mEventData->mPlaceholderTextActive.c_str()))
2985 text = mImpl->mEventData->mPlaceholderTextActive.c_str();
2986 size = mImpl->mEventData->mPlaceholderTextActive.size();
2990 text = mImpl->mEventData->mPlaceholderTextInactive.c_str();
2991 size = mImpl->mEventData->mPlaceholderTextInactive.size();
2994 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
2995 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
2997 // Reset model for showing placeholder.
2998 mImpl->mModel->mLogicalModel->mText.Clear();
2999 mImpl->mModel->mVisualModel->SetTextColor(mImpl->mEventData->mPlaceholderTextColor);
3001 // Convert text into UTF-32
3002 Vector<Character>& utf32Characters = mImpl->mModel->mLogicalModel->mText;
3003 utf32Characters.Resize(size);
3005 // This is a bit horrible but std::string returns a (signed) char*
3006 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text);
3008 // Transform a text array encoded in utf8 into an array encoded in utf32.
3009 // It returns the actual number of characters.
3010 const Length characterCount = Utf8ToUtf32(utf8, size, utf32Characters.Begin());
3011 utf32Characters.Resize(characterCount);
3013 // The characters to be added.
3014 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = characterCount;
3016 // Reset the cursor position
3017 mImpl->mEventData->mPrimaryCursorPosition = 0;
3019 // The natural size needs to be re-calculated.
3020 mImpl->mRecalculateNaturalSize = true;
3022 // The text direction needs to be updated.
3023 mImpl->mUpdateTextDirection = true;
3025 // Apply modifications to the model
3026 mImpl->mOperationsPending = ALL_OPERATIONS;
3028 // Update the rest of the model during size negotiation
3029 mImpl->QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
3033 void Controller::ClearFontData()
3035 if(mImpl->mFontDefaults)
3037 mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
3040 // Set flags to update the model.
3041 mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
3042 mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
3043 mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count();
3045 mImpl->mTextUpdateInfo.mClearAll = true;
3046 mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
3047 mImpl->mRecalculateNaturalSize = true;
3049 mImpl->mOperationsPending = static_cast<OperationsMask>(mImpl->mOperationsPending |
3055 UPDATE_LAYOUT_SIZE |
3060 void Controller::ClearStyleData()
3062 mImpl->mModel->mLogicalModel->mColorRuns.Clear();
3063 mImpl->mModel->mLogicalModel->ClearFontDescriptionRuns();
3066 void Controller::ResetCursorPosition(CharacterIndex cursorIndex)
3068 // Reset the cursor position
3069 if(NULL != mImpl->mEventData)
3071 mImpl->mEventData->mPrimaryCursorPosition = cursorIndex;
3073 // Update the cursor if it's in editing mode.
3074 if(EventData::IsEditingState(mImpl->mEventData->mState))
3076 mImpl->mEventData->mUpdateCursorPosition = true;
3081 void Controller::ResetScrollPosition()
3083 if(NULL != mImpl->mEventData)
3085 // Reset the scroll position.
3086 mImpl->mModel->mScrollPosition = Vector2::ZERO;
3087 mImpl->mEventData->mScrollAfterUpdatePosition = true;
3091 void Controller::SetControlInterface(ControlInterface* controlInterface)
3093 mImpl->mControlInterface = controlInterface;
3096 bool Controller::ShouldClearFocusOnEscape() const
3098 return mImpl->mShouldClearFocusOnEscape;
3101 Actor Controller::CreateBackgroundActor()
3103 return mImpl->CreateBackgroundActor();
3106 // private : Private contructors & copy operator.
3108 Controller::Controller()
3109 : Controller(nullptr, nullptr, nullptr)
3113 Controller::Controller(ControlInterface* controlInterface)
3114 : Controller(controlInterface, nullptr, nullptr)
3118 Controller::Controller(ControlInterface* controlInterface,
3119 EditableControlInterface* editableControlInterface,
3120 SelectableControlInterface* selectableControlInterface)
3121 : mImpl(new Controller::Impl(controlInterface, editableControlInterface, selectableControlInterface))
3125 // The copy constructor and operator are left unimplemented.
3127 // protected : Destructor.
3129 Controller::~Controller()
3136 } // namespace Toolkit