fix incorrect calculaion of natural size in text
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / text-controller-placeholder-handler.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/text/text-controller-placeholder-handler.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23
24 // INTERNAL INCLUDES
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>
29
30 namespace
31 {
32 #if defined(DEBUG_ENABLED)
33 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
34 #endif
35
36 const std::string EMPTY_STRING("");
37
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";
46
47 } // namespace
48
49 namespace Dali
50 {
51 namespace Toolkit
52 {
53 namespace Text
54 {
55 void Controller::PlaceholderHandler::SetPlaceholderTextElideEnabled(Controller& controller, bool enabled)
56 {
57   controller.mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
58   controller.mImpl->mEventData->mPlaceholderEllipsisFlag   = true;
59
60   // Update placeholder if there is no text
61   if(controller.mImpl->IsShowingPlaceholderText() ||
62      (0u == controller.mImpl->mModel->mLogicalModel->mText.Count()))
63   {
64     ShowPlaceholderText(*controller.mImpl);
65   }
66 }
67
68 bool Controller::PlaceholderHandler::IsPlaceholderTextElideEnabled(const Controller& controller)
69 {
70   return controller.mImpl->mEventData->mIsPlaceholderElideEnabled;
71 }
72
73 void Controller::PlaceholderHandler::SetPlaceholderText(Controller& controller, PlaceholderType type, const std::string& text)
74 {
75   if(NULL != controller.mImpl->mEventData)
76   {
77     if(PLACEHOLDER_TYPE_INACTIVE == type)
78     {
79       controller.mImpl->mEventData->mPlaceholderTextInactive = text;
80     }
81     else
82     {
83       controller.mImpl->mEventData->mPlaceholderTextActive = text;
84     }
85
86     // Update placeholder if there is no text
87     if(controller.mImpl->IsShowingPlaceholderText() ||
88        (0u == controller.mImpl->mModel->mLogicalModel->mText.Count()))
89     {
90       ShowPlaceholderText(*controller.mImpl);
91     }
92   }
93 }
94
95 void Controller::PlaceholderHandler::GetPlaceholderText(const Controller& controller, PlaceholderType type, std::string& text)
96 {
97   if(NULL != controller.mImpl->mEventData)
98   {
99     if(PLACEHOLDER_TYPE_INACTIVE == type)
100     {
101       text = controller.mImpl->mEventData->mPlaceholderTextInactive;
102     }
103     else
104     {
105       text = controller.mImpl->mEventData->mPlaceholderTextActive;
106     }
107   }
108 }
109
110 void Controller::PlaceholderHandler::SetPlaceholderFontFamily(Controller& controller, const std::string& placeholderTextFontFamily)
111 {
112   if(NULL != controller.mImpl->mEventData)
113   {
114     // if mPlaceholderFont is null, create an instance.
115     CreatePlaceholderFont(controller);
116
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();
120
121     controller.mImpl->RequestRelayout();
122   }
123 }
124
125 const std::string& Controller::PlaceholderHandler::GetPlaceholderFontFamily(const Controller& controller)
126 {
127   if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
128   {
129     return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family;
130   }
131
132   return EMPTY_STRING;
133 }
134
135 void Controller::PlaceholderHandler::SetPlaceholderTextFontWeight(Controller& controller, FontWeight weight)
136 {
137   if(NULL != controller.mImpl->mEventData)
138   {
139     // if mPlaceholderFont is null, create an instance.
140     CreatePlaceholderFont(controller);
141
142     controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight;
143     controller.mImpl->mEventData->mPlaceholderFont->weightDefined           = true;
144
145     controller.mImpl->RequestRelayout();
146   }
147 }
148
149 bool Controller::PlaceholderHandler::IsPlaceholderTextFontWeightDefined(const Controller& controller)
150 {
151   if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
152   {
153     return controller.mImpl->mEventData->mPlaceholderFont->weightDefined;
154   }
155   return false;
156 }
157
158 FontWeight Controller::PlaceholderHandler::GetPlaceholderTextFontWeight(const Controller& controller)
159 {
160   if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
161   {
162     return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight;
163   }
164
165   return TextAbstraction::FontWeight::NORMAL;
166 }
167
168 void Controller::PlaceholderHandler::SetPlaceholderTextFontWidth(Controller& controller, FontWidth width)
169 {
170   if(NULL != controller.mImpl->mEventData)
171   {
172     // if mPlaceholderFont is null, create an instance.
173     CreatePlaceholderFont(controller);
174
175     controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width;
176     controller.mImpl->mEventData->mPlaceholderFont->widthDefined           = true;
177
178     controller.mImpl->RequestRelayout();
179   }
180 }
181
182 bool Controller::PlaceholderHandler::IsPlaceholderTextFontWidthDefined(const Controller& controller)
183 {
184   if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
185   {
186     return controller.mImpl->mEventData->mPlaceholderFont->widthDefined;
187   }
188   return false;
189 }
190
191 FontWidth Controller::PlaceholderHandler::GetPlaceholderTextFontWidth(const Controller& controller)
192 {
193   if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
194   {
195     return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width;
196   }
197
198   return TextAbstraction::FontWidth::NORMAL;
199 }
200
201 void Controller::PlaceholderHandler::SetPlaceholderTextFontSlant(Controller& controller, FontSlant slant)
202 {
203   if(NULL != controller.mImpl->mEventData)
204   {
205     // if mPlaceholderFont is null, create an instance.
206     CreatePlaceholderFont(controller);
207
208     controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant;
209     controller.mImpl->mEventData->mPlaceholderFont->slantDefined           = true;
210
211     controller.mImpl->RequestRelayout();
212   }
213 }
214
215 bool Controller::PlaceholderHandler::IsPlaceholderTextFontSlantDefined(const Controller& controller)
216 {
217   if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
218   {
219     return controller.mImpl->mEventData->mPlaceholderFont->slantDefined;
220   }
221   return false;
222 }
223
224 FontSlant Controller::PlaceholderHandler::GetPlaceholderTextFontSlant(const Controller& controller)
225 {
226   if((NULL != controller.mImpl->mEventData) && (NULL != controller.mImpl->mEventData->mPlaceholderFont))
227   {
228     return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant;
229   }
230
231   return TextAbstraction::FontSlant::NORMAL;
232 }
233
234 void Controller::PlaceholderHandler::SetPlaceholderTextFontSize(Controller& controller, float fontSize, FontSizeType type)
235 {
236   if(NULL != controller.mImpl->mEventData)
237   {
238     // if mPlaceholderFont is null, create an instance.
239     CreatePlaceholderFont(controller);
240
241     switch(type)
242     {
243       case POINT_SIZE:
244       {
245         controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize;
246         controller.mImpl->mEventData->mPlaceholderFont->sizeDefined       = true;
247         controller.mImpl->mEventData->mIsPlaceholderPixelSize             = false; // Font size flag
248         break;
249       }
250       case PIXEL_SIZE:
251       {
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);
257
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
261         break;
262       }
263     }
264
265     controller.mImpl->RequestRelayout();
266   }
267 }
268
269 float Controller::PlaceholderHandler::GetPlaceholderTextFontSize(const Controller& controller, FontSizeType type)
270 {
271   float value = 0.0f;
272   if(NULL != controller.mImpl->mEventData)
273   {
274     switch(type)
275     {
276       case POINT_SIZE:
277       {
278         if(NULL != controller.mImpl->mEventData->mPlaceholderFont)
279         {
280           value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize;
281         }
282         else
283         {
284           // If the placeholder text font size is not set, then return the default font size.
285           value = controller.GetDefaultFontSize(POINT_SIZE);
286         }
287         break;
288       }
289       case PIXEL_SIZE:
290       {
291         if(NULL != controller.mImpl->mEventData->mPlaceholderFont)
292         {
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);
298
299           value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast<float>(horizontalDpi) / 72.f;
300         }
301         else
302         {
303           // If the placeholder text font size is not set, then return the default font size.
304           value = controller.GetDefaultFontSize(PIXEL_SIZE);
305         }
306         break;
307       }
308     }
309     return value;
310   }
311
312   return value;
313 }
314
315 void Controller::PlaceholderHandler::SetPlaceholderTextColor(Controller& controller, const Vector4& textColor)
316 {
317   if(NULL != controller.mImpl->mEventData)
318   {
319     controller.mImpl->mEventData->mPlaceholderTextColor = textColor;
320   }
321
322   if(controller.mImpl->IsShowingPlaceholderText())
323   {
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();
328   }
329 }
330
331 const Vector4& Controller::PlaceholderHandler::GetPlaceholderTextColor(const Controller& controller)
332 {
333   if(NULL != controller.mImpl->mEventData)
334   {
335     return controller.mImpl->mEventData->mPlaceholderTextColor;
336   }
337
338   return Color::BLACK;
339 }
340
341 void Controller::PlaceholderHandler::SetPlaceholderProperty(Controller& controller, const Property::Map& map)
342 {
343   const Property::Map::SizeType count = map.Count();
344
345   for(Property::Map::SizeType position = 0; position < count; ++position)
346   {
347     KeyValuePair     keyValue = map.GetKeyValue(position);
348     Property::Key&   key      = keyValue.first;
349     Property::Value& value    = keyValue.second;
350
351     if(key == Toolkit::Text::PlaceHolder::Property::TEXT || key == PLACEHOLDER_TEXT)
352     {
353       std::string text = "";
354       value.Get(text);
355       SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_INACTIVE, text);
356     }
357     else if(key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED)
358     {
359       std::string text = "";
360       value.Get(text);
361       SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_ACTIVE, text);
362     }
363     else if(key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR)
364     {
365       Vector4 textColor;
366       value.Get(textColor);
367       if(GetPlaceholderTextColor(controller) != textColor)
368       {
369         SetPlaceholderTextColor(controller, textColor);
370       }
371     }
372     else if(key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY)
373     {
374       std::string fontFamily = "";
375       value.Get(fontFamily);
376       SetPlaceholderFontFamily(controller, fontFamily);
377     }
378     else if(key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE)
379     {
380       SetFontStyleProperty(&controller, value, Text::FontStyle::PLACEHOLDER);
381     }
382     else if(key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE)
383     {
384       float pointSize;
385       value.Get(pointSize);
386       if(!Equals(GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE), pointSize))
387       {
388         SetPlaceholderTextFontSize(controller, pointSize, Text::Controller::POINT_SIZE);
389       }
390     }
391     else if(key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE)
392     {
393       float pixelSize;
394       value.Get(pixelSize);
395       if(!Equals(GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE), pixelSize))
396       {
397         SetPlaceholderTextFontSize(controller, pixelSize, Text::Controller::PIXEL_SIZE);
398       }
399     }
400     else if(key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS)
401     {
402       bool ellipsis;
403       value.Get(ellipsis);
404       SetPlaceholderTextElideEnabled(controller, ellipsis);
405     }
406   }
407 }
408
409 void Controller::PlaceholderHandler::GetPlaceholderProperty(Controller& controller, Property::Map& map)
410 {
411   if(NULL != controller.mImpl->mEventData)
412   {
413     if(!controller.mImpl->mEventData->mPlaceholderTextActive.empty())
414     {
415       map[Text::PlaceHolder::Property::TEXT_FOCUSED] = controller.mImpl->mEventData->mPlaceholderTextActive;
416     }
417     if(!controller.mImpl->mEventData->mPlaceholderTextInactive.empty())
418     {
419       map[Text::PlaceHolder::Property::TEXT] = controller.mImpl->mEventData->mPlaceholderTextInactive;
420     }
421
422     map[Text::PlaceHolder::Property::COLOR]       = controller.mImpl->mEventData->mPlaceholderTextColor;
423     map[Text::PlaceHolder::Property::FONT_FAMILY] = GetPlaceholderFontFamily(controller);
424
425     Property::Value fontStyleMapGet;
426     GetFontStyleProperty(&controller, fontStyleMapGet, Text::FontStyle::PLACEHOLDER);
427     map[Text::PlaceHolder::Property::FONT_STYLE] = fontStyleMapGet;
428
429     // Choose font size : POINT_SIZE or PIXEL_SIZE
430     if(!controller.mImpl->mEventData->mIsPlaceholderPixelSize)
431     {
432       map[Text::PlaceHolder::Property::POINT_SIZE] = GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE);
433     }
434     else
435     {
436       map[Text::PlaceHolder::Property::PIXEL_SIZE] = GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE);
437     }
438
439     if(controller.mImpl->mEventData->mPlaceholderEllipsisFlag)
440     {
441       map[Text::PlaceHolder::Property::ELLIPSIS] = IsPlaceholderTextElideEnabled(controller);
442     }
443   }
444 }
445
446 void Controller::PlaceholderHandler::ShowPlaceholderText(Controller::Impl& impl)
447 {
448   if(impl.IsPlaceholderAvailable())
449   {
450     EventData*& eventData = impl.mEventData;
451     DALI_ASSERT_DEBUG(eventData && "No placeholder text available");
452
453     if(NULL == eventData)
454     {
455       return;
456     }
457
458     eventData->mIsShowingPlaceholderText = true;
459
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);
465
466     const char* text(NULL);
467     size_t      size(0);
468
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()))
473     {
474       text = placeholderTextActive.c_str();
475       size = placeholderTextActive.size();
476     }
477     else
478     {
479       std::string& placeholderTextInactive = eventData->mPlaceholderTextInactive;
480       text                                 = placeholderTextInactive.c_str();
481       size                                 = placeholderTextInactive.size();
482     }
483
484     TextUpdateInfo& textUpdateInfo             = impl.mTextUpdateInfo;
485     textUpdateInfo.mCharacterIndex             = 0u;
486     textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters;
487
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);
493
494     // Convert text into UTF-32
495     Vector<Character>& utf32Characters = logicalModel->mText;
496     utf32Characters.Resize(size);
497
498     // This is a bit horrible but std::string returns a (signed) char*
499     const uint8_t* utf8 = reinterpret_cast<const uint8_t*>(text);
500
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);
505
506     // The characters to be added.
507     textUpdateInfo.mNumberOfCharactersToAdd = characterCount;
508
509     // Reset the cursor position
510     eventData->mPrimaryCursorPosition = 0;
511
512     // The natural size needs to be re-calculated.
513     impl.mRecalculateNaturalSize = true;
514
515     // The text direction needs to be updated.
516     impl.mUpdateTextDirection = true;
517
518     // Apply modifications to the model
519     impl.mOperationsPending = ALL_OPERATIONS;
520
521     // Update the rest of the model during size negotiation
522     impl.QueueModifyEvent(ModifyEvent::TEXT_REPLACED);
523   }
524 }
525
526 void Controller::PlaceholderHandler::CreatePlaceholderFont(Controller& controller)
527 {
528   if(nullptr == controller.mImpl->mEventData->mPlaceholderFont)
529   {
530     controller.mImpl->mEventData->mPlaceholderFont = std::unique_ptr<FontDefaults>(new FontDefaults());
531   }
532 }
533
534 } // namespace Text
535
536 } // namespace Toolkit
537
538 } // namespace Dali