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 ShowPlaceholderText(*controller.mImpl);
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 ShowPlaceholderText(*controller.mImpl);
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 mPlaceholderFont is null, create an instance.
115 CreatePlaceholderFont(controller);
117 controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily;
118 DALI_LOG_INFO(gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str());
119 controller.mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty();
121 controller.mImpl->RequestRelayout();
125 const std::string& Controller::PlaceholderHandler::GetPlaceholderFontFamily(const Controller& controller)
127 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
129 return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family;
135 void Controller::PlaceholderHandler::SetPlaceholderTextFontWeight(Controller& controller, FontWeight weight)
137 if(NULL != controller.mImpl->mEventData)
139 // if mPlaceholderFont is null, create an instance.
140 CreatePlaceholderFont(controller);
142 controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight;
143 controller.mImpl->mEventData->mPlaceholderFont->weightDefined = true;
145 controller.mImpl->RequestRelayout();
149 bool Controller::PlaceholderHandler::IsPlaceholderTextFontWeightDefined(const Controller& controller)
151 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
153 return controller.mImpl->mEventData->mPlaceholderFont->weightDefined;
158 FontWeight Controller::PlaceholderHandler::GetPlaceholderTextFontWeight(const Controller& controller)
160 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
162 return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight;
165 return TextAbstraction::FontWeight::NORMAL;
168 void Controller::PlaceholderHandler::SetPlaceholderTextFontWidth(Controller& controller, FontWidth width)
170 if(NULL != controller.mImpl->mEventData)
172 // if mPlaceholderFont is null, create an instance.
173 CreatePlaceholderFont(controller);
175 controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width;
176 controller.mImpl->mEventData->mPlaceholderFont->widthDefined = true;
178 controller.mImpl->RequestRelayout();
182 bool Controller::PlaceholderHandler::IsPlaceholderTextFontWidthDefined(const Controller& controller)
184 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
186 return controller.mImpl->mEventData->mPlaceholderFont->widthDefined;
191 FontWidth Controller::PlaceholderHandler::GetPlaceholderTextFontWidth(const Controller& controller)
193 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
195 return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width;
198 return TextAbstraction::FontWidth::NORMAL;
201 void Controller::PlaceholderHandler::SetPlaceholderTextFontSlant(Controller& controller, FontSlant slant)
203 if(NULL != controller.mImpl->mEventData)
205 // if mPlaceholderFont is null, create an instance.
206 CreatePlaceholderFont(controller);
208 controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant;
209 controller.mImpl->mEventData->mPlaceholderFont->slantDefined = true;
211 controller.mImpl->RequestRelayout();
215 bool Controller::PlaceholderHandler::IsPlaceholderTextFontSlantDefined(const Controller& controller)
217 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
219 return controller.mImpl->mEventData->mPlaceholderFont->slantDefined;
224 FontSlant Controller::PlaceholderHandler::GetPlaceholderTextFontSlant(const Controller& controller)
226 if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
228 return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant;
231 return TextAbstraction::FontSlant::NORMAL;
234 void Controller::PlaceholderHandler::SetPlaceholderTextFontSize(Controller& controller, float fontSize, FontSizeType type)
236 if(NULL != controller.mImpl->mEventData)
238 // if mPlaceholderFont is null, create an instance.
239 CreatePlaceholderFont(controller);
245 controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize;
246 controller.mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
247 controller.mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag
252 // Point size = Pixel size * 72.f / DPI
253 unsigned int horizontalDpi = 0u;
254 unsigned int verticalDpi = 0u;
255 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
256 fontClient.GetDpi(horizontalDpi, verticalDpi);
258 controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = (fontSize * 72.f) / static_cast<float>(horizontalDpi);
259 controller.mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
260 controller.mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag
265 controller.mImpl->RequestRelayout();
269 float Controller::PlaceholderHandler::GetPlaceholderTextFontSize(const Controller& controller, FontSizeType type)
272 if(NULL != controller.mImpl->mEventData)
278 if(NULL != controller.mImpl->mEventData->mPlaceholderFont)
280 value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize;
284 // If the placeholder text font size is not set, then return the default font size.
285 value = controller.GetDefaultFontSize(POINT_SIZE);
291 if(NULL != controller.mImpl->mEventData->mPlaceholderFont)
293 // Pixel size = Point size * DPI / 72.f
294 unsigned int horizontalDpi = 0u;
295 unsigned int verticalDpi = 0u;
296 TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
297 fontClient.GetDpi(horizontalDpi, verticalDpi);
299 value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast<float>(horizontalDpi) / 72.f;
303 // If the placeholder text font size is not set, then return the default font size.
304 value = controller.GetDefaultFontSize(PIXEL_SIZE);
315 void Controller::PlaceholderHandler::SetPlaceholderTextColor(Controller& controller, const Vector4& textColor)
317 if(NULL != controller.mImpl->mEventData)
319 controller.mImpl->mEventData->mPlaceholderTextColor = textColor;
322 if(controller.mImpl->IsShowingPlaceholderText())
324 controller.mImpl->mModel->mVisualModel->SetTextColor(textColor);
325 controller.mImpl->mModel->mLogicalModel->mColorRuns.Clear();
326 controller.mImpl->mOperationsPending = static_cast<OperationsMask>(controller.mImpl->mOperationsPending | COLOR);
327 controller.mImpl->RequestRelayout();
331 const Vector4& Controller::PlaceholderHandler::GetPlaceholderTextColor(const Controller& controller)
333 if(NULL != controller.mImpl->mEventData)
335 return controller.mImpl->mEventData->mPlaceholderTextColor;
341 void Controller::PlaceholderHandler::SetPlaceholderProperty(Controller& controller, const Property::Map& map)
343 const Property::Map::SizeType count = map.Count();
345 for(Property::Map::SizeType position = 0; position < count; ++position)
347 KeyValuePair keyValue = map.GetKeyValue(position);
348 Property::Key& key = keyValue.first;
349 Property::Value& value = keyValue.second;
351 if(key == Toolkit::Text::PlaceHolder::Property::TEXT || key == PLACEHOLDER_TEXT)
353 std::string text = "";
355 SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_INACTIVE, text);
357 else if(key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED)
359 std::string text = "";
361 SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_ACTIVE, text);
363 else if(key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR)
366 value.Get(textColor);
367 if(GetPlaceholderTextColor(controller) != textColor)
369 SetPlaceholderTextColor(controller, textColor);
372 else if(key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY)
374 std::string fontFamily = "";
375 value.Get(fontFamily);
376 SetPlaceholderFontFamily(controller, fontFamily);
378 else if(key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE)
380 SetFontStyleProperty(&controller, value, Text::FontStyle::PLACEHOLDER);
382 else if(key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE)
385 value.Get(pointSize);
386 if(!Equals(GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE), pointSize))
388 SetPlaceholderTextFontSize(controller, pointSize, Text::Controller::POINT_SIZE);
391 else if(key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE)
394 value.Get(pixelSize);
395 if(!Equals(GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE), pixelSize))
397 SetPlaceholderTextFontSize(controller, pixelSize, Text::Controller::PIXEL_SIZE);
400 else if(key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS)
404 SetPlaceholderTextElideEnabled(controller, ellipsis);
409 void Controller::PlaceholderHandler::GetPlaceholderProperty(Controller& controller, Property::Map& map)
411 if(NULL != controller.mImpl->mEventData)
413 if(!controller.mImpl->mEventData->mPlaceholderTextActive.empty())
415 map[Text::PlaceHolder::Property::TEXT_FOCUSED] = controller.mImpl->mEventData->mPlaceholderTextActive;
417 if(!controller.mImpl->mEventData->mPlaceholderTextInactive.empty())
419 map[Text::PlaceHolder::Property::TEXT] = controller.mImpl->mEventData->mPlaceholderTextInactive;
422 map[Text::PlaceHolder::Property::COLOR] = controller.mImpl->mEventData->mPlaceholderTextColor;
423 map[Text::PlaceHolder::Property::FONT_FAMILY] = GetPlaceholderFontFamily(controller);
425 Property::Value fontStyleMapGet;
426 GetFontStyleProperty(&controller, fontStyleMapGet, Text::FontStyle::PLACEHOLDER);
427 map[Text::PlaceHolder::Property::FONT_STYLE] = fontStyleMapGet;
429 // Choose font size : POINT_SIZE or PIXEL_SIZE
430 if(!controller.mImpl->mEventData->mIsPlaceholderPixelSize)
432 map[Text::PlaceHolder::Property::POINT_SIZE] = GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE);
436 map[Text::PlaceHolder::Property::PIXEL_SIZE] = GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE);
439 if(controller.mImpl->mEventData->mPlaceholderEllipsisFlag)
441 map[Text::PlaceHolder::Property::ELLIPSIS] = IsPlaceholderTextElideEnabled(controller);
446 void Controller::PlaceholderHandler::ShowPlaceholderText(Controller::Impl& impl)
448 if(impl.IsPlaceholderAvailable())
450 EventData*& eventData = impl.mEventData;
451 DALI_ASSERT_DEBUG(eventData && "No placeholder text available");
453 if(NULL == eventData)
458 eventData->mIsShowingPlaceholderText = true;
460 // Disable handles when showing place-holder text
461 DecoratorPtr& decorator = eventData->mDecorator;
462 decorator->SetHandleActive(GRAB_HANDLE, false);
463 decorator->SetHandleActive(LEFT_SELECTION_HANDLE, false);
464 decorator->SetHandleActive(RIGHT_SELECTION_HANDLE, false);
466 const char* text(NULL);
469 // TODO - Switch Placeholder text when changing state
470 std::string& placeholderTextActive = eventData->mPlaceholderTextActive;
471 if((EventData::INACTIVE != eventData->mState) &&
472 (0u != placeholderTextActive.c_str()))
474 text = placeholderTextActive.c_str();
475 size = placeholderTextActive.size();
479 std::string& placeholderTextInactive = eventData->mPlaceholderTextInactive;
480 text = placeholderTextInactive.c_str();
481 size = placeholderTextInactive.size();
484 TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
485 textUpdateInfo.mCharacterIndex = 0u;
486 textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters;
488 // Reset model for showing placeholder.
489 ModelPtr& model = impl.mModel;
490 LogicalModelPtr& logicalModel = model->mLogicalModel;
491 logicalModel->mText.Clear();
492 model->mVisualModel->SetTextColor(eventData->mPlaceholderTextColor);
494 // Convert text into UTF-32
495 Vector<Character>& utf32Characters = logicalModel->mText;
496 utf32Characters.Resize(size);
498 // This is a bit horrible but std::string returns a (signed) char*
499 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text);
501 // Transform a text array encoded in utf8 into an array encoded in utf32.
502 // It returns the actual number of characters.
503 const Length characterCount = Utf8ToUtf32(utf8, size, utf32Characters.Begin());
504 utf32Characters.Resize(characterCount);
506 // The characters to be added.
507 textUpdateInfo.mNumberOfCharactersToAdd = characterCount;
509 // Reset the cursor position
510 eventData->mPrimaryCursorPosition = 0;
512 // The natural size needs to be re-calculated.
513 impl.mRecalculateNaturalSize = true;
515 // The text direction needs to be updated.
516 impl.mUpdateTextDirection = true;
518 // Apply modifications to the model
519 impl.mOperationsPending = ALL_OPERATIONS;
521 // Update the rest of the model during size negotiation
522 impl.QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
526 void Controller::PlaceholderHandler::CreatePlaceholderFont(Controller& controller)
528 if(nullptr == controller.mImpl->mEventData->mPlaceholderFont)
530 controller.mImpl->mEventData->mPlaceholderFont = std::unique_ptr<FontDefaults>(new FontDefaults());
536 } // namespace Toolkit