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