2 * Copyright (c) 2020 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/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>
33 #if defined(DEBUG_ENABLED)
34 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS");
37 const std::string EMPTY_STRING("");
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";
59 void Controller::PlaceholderHandler::SetPlaceholderTextElideEnabled(Controller& controller, bool enabled)
61 controller.mImpl->mEventData->mIsPlaceholderElideEnabled = enabled;
62 controller.mImpl->mEventData->mPlaceholderEllipsisFlag = true;
64 // Update placeholder if there is no text
65 if( controller.mImpl->IsShowingPlaceholderText() ||
66 ( 0u == controller.mImpl->mModel->mLogicalModel->mText.Count() ) )
68 controller.ShowPlaceholderText();
72 bool Controller::PlaceholderHandler::IsPlaceholderTextElideEnabled(const Controller& controller)
74 return controller.mImpl->mEventData->mIsPlaceholderElideEnabled;
77 void Controller::PlaceholderHandler::SetPlaceholderText(Controller& controller, PlaceholderType type, const std::string& text)
79 if( NULL != controller.mImpl->mEventData )
81 if( PLACEHOLDER_TYPE_INACTIVE == type )
83 controller.mImpl->mEventData->mPlaceholderTextInactive = text;
87 controller.mImpl->mEventData->mPlaceholderTextActive = text;
90 // Update placeholder if there is no text
91 if( controller.mImpl->IsShowingPlaceholderText() ||
92 ( 0u == controller.mImpl->mModel->mLogicalModel->mText.Count() ) )
94 controller.ShowPlaceholderText();
99 void Controller::PlaceholderHandler::GetPlaceholderText(const Controller& controller, PlaceholderType type, std::string& text)
101 if( NULL != controller.mImpl->mEventData )
103 if( PLACEHOLDER_TYPE_INACTIVE == type )
105 text = controller.mImpl->mEventData->mPlaceholderTextInactive;
109 text = controller.mImpl->mEventData->mPlaceholderTextActive;
114 void Controller::PlaceholderHandler::SetPlaceholderFontFamily(Controller& controller, const std::string& placeholderTextFontFamily)
116 if( NULL != controller.mImpl->mEventData )
118 if( NULL == controller.mImpl->mEventData->mPlaceholderFont )
120 controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults();
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();
127 controller.mImpl->RequestRelayout();
131 const std::string& Controller::PlaceholderHandler::GetPlaceholderFontFamily(const Controller& controller)
133 if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) )
135 return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family;
141 void Controller::PlaceholderHandler::SetPlaceholderTextFontWeight(Controller& controller, FontWeight weight)
143 if( NULL != controller.mImpl->mEventData )
145 if( NULL == controller.mImpl->mEventData->mPlaceholderFont )
147 controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults();
150 controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight;
151 controller.mImpl->mEventData->mPlaceholderFont->weightDefined = true;
153 controller.mImpl->RequestRelayout();
157 bool Controller::PlaceholderHandler::IsPlaceholderTextFontWeightDefined(const Controller& controller)
159 if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) )
161 return controller.mImpl->mEventData->mPlaceholderFont->weightDefined;
166 FontWeight Controller::PlaceholderHandler::GetPlaceholderTextFontWeight(const Controller& controller)
168 if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) )
170 return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight;
173 return TextAbstraction::FontWeight::NORMAL;
176 void Controller::PlaceholderHandler::SetPlaceholderTextFontWidth(Controller& controller, FontWidth width)
178 if( NULL != controller.mImpl->mEventData )
180 if( NULL == controller.mImpl->mEventData->mPlaceholderFont )
182 controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults();
185 controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width;
186 controller.mImpl->mEventData->mPlaceholderFont->widthDefined = true;
188 controller.mImpl->RequestRelayout();
192 bool Controller::PlaceholderHandler::IsPlaceholderTextFontWidthDefined(const Controller& controller)
194 if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) )
196 return controller.mImpl->mEventData->mPlaceholderFont->widthDefined;
201 FontWidth Controller::PlaceholderHandler::GetPlaceholderTextFontWidth(const Controller& controller)
203 if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) )
205 return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width;
208 return TextAbstraction::FontWidth::NORMAL;
211 void Controller::PlaceholderHandler::SetPlaceholderTextFontSlant(Controller& controller, FontSlant slant)
213 if( NULL != controller.mImpl->mEventData )
215 if( NULL == controller.mImpl->mEventData->mPlaceholderFont )
217 controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults();
220 controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant;
221 controller.mImpl->mEventData->mPlaceholderFont->slantDefined = true;
223 controller.mImpl->RequestRelayout();
227 bool Controller::PlaceholderHandler::IsPlaceholderTextFontSlantDefined(const Controller& controller)
229 if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) )
231 return controller.mImpl->mEventData->mPlaceholderFont->slantDefined;
236 FontSlant Controller::PlaceholderHandler::GetPlaceholderTextFontSlant(const Controller& controller)
238 if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) )
240 return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant;
243 return TextAbstraction::FontSlant::NORMAL;
246 void Controller::PlaceholderHandler::SetPlaceholderTextFontSize(Controller& controller, float fontSize, FontSizeType type)
248 if( NULL != controller.mImpl->mEventData )
250 if( NULL == controller.mImpl->mEventData->mPlaceholderFont )
252 controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults();
259 controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize;
260 controller.mImpl->mEventData->mPlaceholderFont->sizeDefined = true;
261 controller.mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag
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 );
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
279 controller.mImpl->RequestRelayout();
283 float Controller::PlaceholderHandler::GetPlaceholderTextFontSize(const Controller& controller, FontSizeType type )
286 if( NULL != controller.mImpl->mEventData )
292 if( NULL != controller.mImpl->mEventData->mPlaceholderFont )
294 value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize;
298 // If the placeholder text font size is not set, then return the default font size.
299 value = controller.GetDefaultFontSize( POINT_SIZE );
305 if( NULL != controller.mImpl->mEventData->mPlaceholderFont )
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 );
313 value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f;
317 // If the placeholder text font size is not set, then return the default font size.
318 value = controller.GetDefaultFontSize( PIXEL_SIZE );
329 void Controller::PlaceholderHandler::SetPlaceholderTextColor(Controller& controller, const Vector4& textColor )
331 if( NULL != controller.mImpl->mEventData )
333 controller.mImpl->mEventData->mPlaceholderTextColor = textColor;
336 if( controller.mImpl->IsShowingPlaceholderText() )
338 controller.mImpl->mModel->mVisualModel->SetTextColor( textColor );
339 controller.mImpl->RequestRelayout();
343 const Vector4& Controller::PlaceholderHandler::GetPlaceholderTextColor(const Controller& controller)
345 if( NULL != controller.mImpl->mEventData )
347 return controller.mImpl->mEventData->mPlaceholderTextColor;
353 void Controller::PlaceholderHandler::SetPlaceholderProperty(Controller& controller, const Property::Map& map )
355 const Property::Map::SizeType count = map.Count();
357 for( Property::Map::SizeType position = 0; position < count; ++position )
359 KeyValuePair keyValue = map.GetKeyValue( position );
360 Property::Key& key = keyValue.first;
361 Property::Value& value = keyValue.second;
363 if( key == Toolkit::Text::PlaceHolder::Property::TEXT || key == PLACEHOLDER_TEXT )
365 std::string text = "";
367 SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_INACTIVE, text);
369 else if( key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED )
371 std::string text = "";
373 SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_ACTIVE, text);
375 else if( key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR )
378 value.Get( textColor );
379 if( GetPlaceholderTextColor(controller) != textColor )
381 SetPlaceholderTextColor(controller, textColor);
384 else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY )
386 std::string fontFamily = "";
387 value.Get( fontFamily );
388 SetPlaceholderFontFamily(controller, fontFamily);
390 else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE )
392 SetFontStyleProperty( &controller, value, Text::FontStyle::PLACEHOLDER );
394 else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE )
397 value.Get( pointSize );
398 if( !Equals(GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE), pointSize) )
400 SetPlaceholderTextFontSize(controller, pointSize, Text::Controller::POINT_SIZE);
403 else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE )
406 value.Get( pixelSize );
407 if( !Equals(GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE), pixelSize) )
409 SetPlaceholderTextFontSize(controller, pixelSize, Text::Controller::PIXEL_SIZE);
412 else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS )
415 value.Get( ellipsis );
416 SetPlaceholderTextElideEnabled(controller, ellipsis);
421 void Controller::PlaceholderHandler::GetPlaceholderProperty(Controller& controller, Property::Map& map)
423 if( NULL != controller.mImpl->mEventData )
425 if( !controller.mImpl->mEventData->mPlaceholderTextActive.empty() )
427 map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = controller.mImpl->mEventData->mPlaceholderTextActive;
429 if( !controller.mImpl->mEventData->mPlaceholderTextInactive.empty() )
431 map[ Text::PlaceHolder::Property::TEXT ] = controller.mImpl->mEventData->mPlaceholderTextInactive;
434 map[ Text::PlaceHolder::Property::COLOR ] = controller.mImpl->mEventData->mPlaceholderTextColor;
435 map[ Text::PlaceHolder::Property::FONT_FAMILY ] = GetPlaceholderFontFamily(controller);
437 Property::Value fontStyleMapGet;
438 GetFontStyleProperty( &controller, fontStyleMapGet, Text::FontStyle::PLACEHOLDER );
439 map[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet;
441 // Choose font size : POINT_SIZE or PIXEL_SIZE
442 if( !controller.mImpl->mEventData->mIsPlaceholderPixelSize )
444 map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE);
448 map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE);
451 if( controller.mImpl->mEventData->mPlaceholderEllipsisFlag )
453 map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled(controller);
458 void Controller::PlaceholderHandler::ShowPlaceholderText(Controller& controller)
460 Controller::Impl& impl = *controller.mImpl;
462 if( impl.IsPlaceholderAvailable() )
464 EventData*& eventData = impl.mEventData;
465 DALI_ASSERT_DEBUG( eventData && "No placeholder text available" );
467 if( NULL == eventData )
472 eventData->mIsShowingPlaceholderText = true;
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 );
480 const char* text( NULL );
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() ) )
488 text = placeholderTextActive.c_str();
489 size = placeholderTextActive.size();
493 std::string& placeholderTextInactive = eventData->mPlaceholderTextInactive;
494 text = placeholderTextInactive.c_str();
495 size = placeholderTextInactive.size();
498 TextUpdateInfo& textUpdateInfo = impl.mTextUpdateInfo;
499 textUpdateInfo.mCharacterIndex = 0u;
500 textUpdateInfo.mNumberOfCharactersToRemove = textUpdateInfo.mPreviousNumberOfCharacters;
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 );
508 // Convert text into UTF-32
509 Vector<Character>& utf32Characters = logicalModel->mText;
510 utf32Characters.Resize( size );
512 // This is a bit horrible but std::string returns a (signed) char*
513 const uint8_t* utf8 = reinterpret_cast<const uint8_t*>( text );
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 );
520 // The characters to be added.
521 textUpdateInfo.mNumberOfCharactersToAdd = characterCount;
523 // Reset the cursor position
524 eventData->mPrimaryCursorPosition = 0;
526 // The natural size needs to be re-calculated.
527 impl.mRecalculateNaturalSize = true;
529 // The text direction needs to be updated.
530 impl.mUpdateTextDirection = true;
532 // Apply modifications to the model
533 impl.mOperationsPending = ALL_OPERATIONS;
535 // Update the rest of the model during size negotiation
536 impl.QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
543 } // namespace Toolkit