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-placeholder-handler.h>
22 #include <dali/integration-api/debug.h>
25 #include <dali-toolkit/internal/text/character-set-conversion.h>
26 #include <dali-toolkit/internal/text/text-controller-impl.h>
27 #include <dali-toolkit/internal/text/text-font-style.h>
28 #include <dali-toolkit/public-api/controls/text-controls/placeholder-properties.h>
32 #if defined(DEBUG_ENABLED)
33 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
36 const std::string EMPTY_STRING("");
38 const char* const PLACEHOLDER_TEXT = "text";
39 const char* const PLACEHOLDER_TEXT_FOCUSED = "textFocused";
40 const char* const PLACEHOLDER_COLOR = "color";
41 const char* const PLACEHOLDER_FONT_FAMILY = "fontFamily";
42 const char* const PLACEHOLDER_FONT_STYLE = "fontStyle";
43 const char* const PLACEHOLDER_POINT_SIZE = "pointSize";
44 const char* const PLACEHOLDER_PIXEL_SIZE = "pixelSize";
45 const char* const PLACEHOLDER_ELLIPSIS = "ellipsis";
55 void Controller::PlaceholderHandler::SetPlaceholderTextElideEnabled(Controller& controller, bool enabled)
57 controller.mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
58 controller.mImpl->mEventData->mPlaceholderEllipsisFlag = true;
60 // Update placeholder if there is no text
61 if(controller.mImpl->IsShowingPlaceholderText() ||
62 (0u == controller.mImpl->mModel->mLogicalModel->mText.Count()))
64 controller.ShowPlaceholderText();
68 bool Controller::PlaceholderHandler::IsPlaceholderTextElideEnabled(const Controller& controller)
70 return controller.mImpl->mEventData->mIsPlaceholderElideEnabled;
73 void Controller::PlaceholderHandler::SetPlaceholderText(Controller& controller, PlaceholderType type, const std::string& text)
75 if(NULL != controller.mImpl->mEventData)
77 if(PLACEHOLDER_TYPE_INACTIVE == type)
79 controller.mImpl->mEventData->mPlaceholderTextInactive = text;
83 controller.mImpl->mEventData->mPlaceholderTextActive = text;
86 // Update placeholder if there is no text
87 if(controller.mImpl->IsShowingPlaceholderText() ||
88 (0u == controller.mImpl->mModel->mLogicalModel->mText.Count()))
90 controller.ShowPlaceholderText();
95 void Controller::PlaceholderHandler::GetPlaceholderText(const Controller& controller, PlaceholderType type, std::string& text)
97 if(NULL != controller.mImpl->mEventData)
99 if(PLACEHOLDER_TYPE_INACTIVE == type)
101 text = controller.mImpl->mEventData->mPlaceholderTextInactive;
105 text = controller.mImpl->mEventData->mPlaceholderTextActive;
110 void Controller::PlaceholderHandler::SetPlaceholderFontFamily(Controller& controller, const std::string& placeholderTextFontFamily)
112 if(NULL != controller.mImpl->mEventData)
114 if(NULL == controller.mImpl->mEventData->mPlaceholderFont)
116 controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults();
119 controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily;
120 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str());
121 controller.mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty();
123 controller.mImpl->RequestRelayout();
127 const std::string& Controller::PlaceholderHandler::GetPlaceholderFontFamily(const Controller& controller)
129 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
131 return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family;
137 void Controller::PlaceholderHandler::SetPlaceholderTextFontWeight(Controller& controller, FontWeight weight)
139 if(NULL != controller.mImpl->mEventData)
141 if(NULL == controller.mImpl->mEventData->mPlaceholderFont)
143 controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults();
146 controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight;
147 controller.mImpl->mEventData->mPlaceholderFont->weightDefined = true;
149 controller.mImpl->RequestRelayout();
153 bool Controller::PlaceholderHandler::IsPlaceholderTextFontWeightDefined(const Controller& controller)
155 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
157 return controller.mImpl->mEventData->mPlaceholderFont->weightDefined;
162 FontWeight Controller::PlaceholderHandler::GetPlaceholderTextFontWeight(const Controller& controller)
164 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
166 return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight;
169 return TextAbstraction::FontWeight::NORMAL;
172 void Controller::PlaceholderHandler::SetPlaceholderTextFontWidth(Controller& controller, FontWidth width)
174 if(NULL != controller.mImpl->mEventData)
176 if(NULL == controller.mImpl->mEventData->mPlaceholderFont)
178 controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults();
181 controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width;
182 controller.mImpl->mEventData->mPlaceholderFont->widthDefined = true;
184 controller.mImpl->RequestRelayout();
188 bool Controller::PlaceholderHandler::IsPlaceholderTextFontWidthDefined(const Controller& controller)
190 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
192 return controller.mImpl->mEventData->mPlaceholderFont->widthDefined;
197 FontWidth Controller::PlaceholderHandler::GetPlaceholderTextFontWidth(const Controller& controller)
199 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
201 return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width;
204 return TextAbstraction::FontWidth::NORMAL;
207 void Controller::PlaceholderHandler::SetPlaceholderTextFontSlant(Controller& controller, FontSlant slant)
209 if(NULL != controller.mImpl->mEventData)
211 if(NULL == controller.mImpl->mEventData->mPlaceholderFont)
213 controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults();
216 controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant;
217 controller.mImpl->mEventData->mPlaceholderFont->slantDefined = true;
219 controller.mImpl->RequestRelayout();
223 bool Controller::PlaceholderHandler::IsPlaceholderTextFontSlantDefined(const Controller& controller)
225 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
227 return controller.mImpl->mEventData->mPlaceholderFont->slantDefined;
232 FontSlant Controller::PlaceholderHandler::GetPlaceholderTextFontSlant(const Controller& controller)
234 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
236 return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant;
239 return TextAbstraction::FontSlant::NORMAL;
242 void Controller::PlaceholderHandler::SetPlaceholderTextFontSize(Controller& controller, float fontSize, FontSizeType type)
244 if(NULL != controller.mImpl->mEventData)
246 if(NULL == controller.mImpl->mEventData->mPlaceholderFont)
248 controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults();
255 controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize;
256 controller.mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
257 controller.mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag
262 // Point size = Pixel size * 72.f / DPI
263 unsigned int horizontalDpi = 0u;
264 unsigned int verticalDpi = 0u;
265 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
266 fontClient.GetDpi(horizontalDpi, verticalDpi);
268 controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = (fontSize * 72.f) / static_cast<float>(horizontalDpi);
269 controller.mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
270 controller.mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag
275 controller.mImpl->RequestRelayout();
279 float Controller::PlaceholderHandler::GetPlaceholderTextFontSize(const Controller& controller, FontSizeType type)
282 if(NULL != controller.mImpl->mEventData)
288 if(NULL != controller.mImpl->mEventData->mPlaceholderFont)
290 value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize;
294 // If the placeholder text font size is not set, then return the default font size.
295 value = controller.GetDefaultFontSize(POINT_SIZE);
301 if(NULL != controller.mImpl->mEventData->mPlaceholderFont)
303 // Pixel size = Point size * DPI / 72.f
304 unsigned int horizontalDpi = 0u;
305 unsigned int verticalDpi = 0u;
306 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
307 fontClient.GetDpi(horizontalDpi, verticalDpi);
309 value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast<float>(horizontalDpi) / 72.f;
313 // If the placeholder text font size is not set, then return the default font size.
314 value = controller.GetDefaultFontSize(PIXEL_SIZE);
325 void Controller::PlaceholderHandler::SetPlaceholderTextColor(Controller& controller, const Vector4& textColor)
327 if(NULL != controller.mImpl->mEventData)
329 controller.mImpl->mEventData->mPlaceholderTextColor = textColor;
332 if(controller.mImpl->IsShowingPlaceholderText())
334 controller.mImpl->mModel->mVisualModel->SetTextColor(textColor);
335 controller.mImpl->RequestRelayout();
339 const Vector4& Controller::PlaceholderHandler::GetPlaceholderTextColor(const Controller& controller)
341 if(NULL != controller.mImpl->mEventData)
343 return controller.mImpl->mEventData->mPlaceholderTextColor;
349 void Controller::PlaceholderHandler::SetPlaceholderProperty(Controller& controller, const Property::Map& map)
351 const Property::Map::SizeType count = map.Count();
353 for(Property::Map::SizeType position = 0; position < count; ++position)
355 KeyValuePair keyValue = map.GetKeyValue(position);
356 Property::Key& key = keyValue.first;
357 Property::Value& value = keyValue.second;
359 if(key == Toolkit::Text::PlaceHolder::Property::TEXT || key == PLACEHOLDER_TEXT)
361 std::string text = "";
363 SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_INACTIVE, text);
365 else if(key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED)
367 std::string text = "";
369 SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_ACTIVE, text);
371 else if(key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR)
374 value.Get(textColor);
375 if(GetPlaceholderTextColor(controller) != textColor)
377 SetPlaceholderTextColor(controller, textColor);
380 else if(key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY)
382 std::string fontFamily = "";
383 value.Get(fontFamily);
384 SetPlaceholderFontFamily(controller, fontFamily);
386 else if(key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE)
388 SetFontStyleProperty(&controller, value, Text::FontStyle::PLACEHOLDER);
390 else if(key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE)
393 value.Get(pointSize);
394 if(!Equals(GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE), pointSize))
396 SetPlaceholderTextFontSize(controller, pointSize, Text::Controller::POINT_SIZE);
399 else if(key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE)
402 value.Get(pixelSize);
403 if(!Equals(GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE), pixelSize))
405 SetPlaceholderTextFontSize(controller, pixelSize, Text::Controller::PIXEL_SIZE);
408 else if(key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS)
412 SetPlaceholderTextElideEnabled(controller, ellipsis);
417 void Controller::PlaceholderHandler::GetPlaceholderProperty(Controller& controller, Property::Map& map)
419 if(NULL != controller.mImpl->mEventData)
421 if(!controller.mImpl->mEventData->mPlaceholderTextActive.empty())
423 map[Text::PlaceHolder::Property::TEXT_FOCUSED] = controller.mImpl->mEventData->mPlaceholderTextActive;
425 if(!controller.mImpl->mEventData->mPlaceholderTextInactive.empty())
427 map[Text::PlaceHolder::Property::TEXT] = controller.mImpl->mEventData->mPlaceholderTextInactive;
430 map[Text::PlaceHolder::Property::COLOR] = controller.mImpl->mEventData->mPlaceholderTextColor;
431 map[Text::PlaceHolder::Property::FONT_FAMILY] = GetPlaceholderFontFamily(controller);
433 Property::Value fontStyleMapGet;
434 GetFontStyleProperty(&controller, fontStyleMapGet, Text::FontStyle::PLACEHOLDER);
435 map[Text::PlaceHolder::Property::FONT_STYLE] = fontStyleMapGet;
437 // Choose font size : POINT_SIZE or PIXEL_SIZE
438 if(!controller.mImpl->mEventData->mIsPlaceholderPixelSize)
440 map[Text::PlaceHolder::Property::POINT_SIZE] = GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE);
444 map[Text::PlaceHolder::Property::PIXEL_SIZE] = GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE);
447 if(controller.mImpl->mEventData->mPlaceholderEllipsisFlag)
449 map[Text::PlaceHolder::Property::ELLIPSIS] = IsPlaceholderTextElideEnabled(controller);
454 void Controller::PlaceholderHandler::ShowPlaceholderText(Controller& controller)
456 Controller::Impl& impl = *controller.mImpl;
458 if(impl.IsPlaceholderAvailable())
460 EventData*& eventData = impl.mEventData;
461 DALI_ASSERT_DEBUG(eventData && "No placeholder text available");
463 if(NULL == eventData)
468 eventData->mIsShowingPlaceholderText = true;
470 // Disable handles when showing place-holder text
471 DecoratorPtr& decorator = eventData->mDecorator;
472 decorator->SetHandleActive(GRAB_HANDLE, false);
473 decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
474 decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
476 const char* text(NULL);
479 // TODO - Switch Placeholder text when changing state
480 std::string& placeholderTextActive = eventData->mPlaceholderTextActive;
481 if((EventData::INACTIVE != eventData->mState) &&
482 (0u != placeholderTextActive.c_str()))
484 text = placeholderTextActive.c_str();
485 size = placeholderTextActive.size();
489 std::string& placeholderTextInactive = eventData->mPlaceholderTextInactive;
490 text = placeholderTextInactive.c_str();
491 size = placeholderTextInactive.size();
494 TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
495 textUpdateInfo.mCharacterIndex = 0u;
496 textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters;
498 // Reset model for showing placeholder.
499 ModelPtr& model = impl.mModel;
500 LogicalModelPtr& logicalModel = model->mLogicalModel;
501 logicalModel->mText.Clear();
502 model->mVisualModel->SetTextColor(eventData->mPlaceholderTextColor);
504 // Convert text into UTF-32
505 Vector<Character>& utf32Characters = logicalModel->mText;
506 utf32Characters.Resize(size);
508 // This is a bit horrible but std::string returns a (signed) char*
509 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text);
511 // Transform a text array encoded in utf8 into an array encoded in utf32.
512 // It returns the actual number of characters.
513 const Length characterCount = Utf8ToUtf32(utf8, size, utf32Characters.Begin());
514 utf32Characters.Resize(characterCount);
516 // The characters to be added.
517 textUpdateInfo.mNumberOfCharactersToAdd = characterCount;
519 // Reset the cursor position
520 eventData->mPrimaryCursorPosition = 0;
522 // The natural size needs to be re-calculated.
523 impl.mRecalculateNaturalSize = true;
525 // The text direction needs to be updated.
526 impl.mUpdateTextDirection = true;
528 // Apply modifications to the model
529 impl.mOperationsPending = ALL_OPERATIONS;
531 // Update the rest of the model during size negotiation
532 impl.QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
538 } // namespace Toolkit