2 * Copyright (c) 2022 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-effects-style.h>
22 #include <dali/public-api/math/math-utils.h>
25 #include <dali-toolkit/devel-api/controls/text-controls/text-style-properties-devel.h>
26 #include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
27 #include <dali-toolkit/internal/text/property-string-parser.h>
28 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
38 const char* COLOR_KEY = "color";
39 const char* OFFSET_KEY = "offset";
40 const char* BLUR_RADIUS_KEY = "blurRadius";
41 const char* WIDTH_KEY = "width";
42 const char* HEIGHT_KEY = "height";
43 const char* ENABLE_KEY = "enable";
44 const char* TYPE_KEY = "type";
45 const char* DASH_WIDTH_KEY = "dashWidth";
46 const char* DASH_GAP_KEY = "dashGap";
47 const char* TRUE_TOKEN = "true";
50 bool ParseShadowProperties(const Property::Map& shadowPropertiesMap,
55 bool& blurRadiusDefined,
58 const unsigned int numberOfItems = shadowPropertiesMap.Count();
60 // Parses and applies the style.
61 for(unsigned int index = 0u; index < numberOfItems; ++index)
63 const KeyValuePair& valueGet = shadowPropertiesMap.GetKeyValue(index);
65 if((DevelText::Shadow::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
70 if(valueGet.second.GetType() == Dali::Property::STRING)
72 const std::string colorStr = valueGet.second.Get<std::string>();
73 Text::ColorStringToVector4(colorStr.c_str(), colorStr.size(), color);
77 color = valueGet.second.Get<Vector4>();
80 else if((DevelText::Shadow::Property::OFFSET == valueGet.first.indexKey) || (OFFSET_KEY == valueGet.first.stringKey))
85 if(valueGet.second.GetType() == Dali::Property::STRING)
87 const std::string offsetStr = valueGet.second.Get<std::string>();
88 StringToVector2(offsetStr.c_str(), offsetStr.size(), offset);
92 offset = valueGet.second.Get<Vector2>();
95 else if((DevelText::Shadow::Property::BLUR_RADIUS == valueGet.first.indexKey) || (BLUR_RADIUS_KEY == valueGet.first.stringKey))
98 blurRadiusDefined = true;
100 if(valueGet.second.GetType() == Dali::Property::STRING)
102 const std::string blurRadiusStr = valueGet.second.Get<std::string>();
103 blurRadius = StringToFloat(blurRadiusStr.c_str());
107 blurRadius = valueGet.second.Get<float>();
112 return 0u == numberOfItems;
115 bool ParseUnderlineProperties(const Property::Map& underlinePropertiesMap,
122 Text::Underline::Type& type,
123 bool& dashWidthDefined,
125 bool& dashGapDefined,
128 const unsigned int numberOfItems = underlinePropertiesMap.Count();
130 // Parses and applies the style.
131 for(unsigned int index = 0u; index < numberOfItems; ++index)
133 const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue(index);
135 if((DevelText::Underline::Property::ENABLE == valueGet.first.indexKey) || (ENABLE_KEY == valueGet.first.stringKey))
138 if(valueGet.second.GetType() == Dali::Property::STRING)
140 const std::string enableStr = valueGet.second.Get<std::string>();
141 enabled = Text::TokenComparison(TRUE_TOKEN, enableStr.c_str(), enableStr.size());
145 enabled = valueGet.second.Get<bool>();
148 else if((DevelText::Underline::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
153 if(valueGet.second.GetType() == Dali::Property::STRING)
155 const std::string colorStr = valueGet.second.Get<std::string>();
156 Text::ColorStringToVector4(colorStr.c_str(), colorStr.size(), color);
160 color = valueGet.second.Get<Vector4>();
163 else if((DevelText::Underline::Property::HEIGHT == valueGet.first.indexKey) || (HEIGHT_KEY == valueGet.first.stringKey))
166 heightDefined = true;
168 if(valueGet.second.GetType() == Dali::Property::STRING)
170 const std::string heightStr = valueGet.second.Get<std::string>();
171 height = StringToFloat(heightStr.c_str());
175 height = valueGet.second.Get<float>();
178 else if((DevelText::Underline::Property::TYPE == valueGet.first.indexKey) || (TYPE_KEY == valueGet.first.stringKey))
180 /// Underline Type key.
183 if(valueGet.second.GetType() == Dali::Property::STRING)
185 const std::string typeStr = valueGet.second.Get<std::string>();
186 Text::UnderlineTypeStringToTypeValue(typeStr.c_str(), typeStr.size(), type);
190 type = valueGet.second.Get<Text::Underline::Type>();
193 else if((DevelText::Underline::Property::DASH_WIDTH == valueGet.first.indexKey) || (DASH_WIDTH_KEY == valueGet.first.stringKey))
195 /// Dashed Underline Width key.
196 dashWidthDefined = true;
198 if(valueGet.second.GetType() == Dali::Property::STRING)
200 const std::string dashWidthStr = valueGet.second.Get<std::string>();
201 dashWidth = StringToFloat(dashWidthStr.c_str());
205 dashWidth = valueGet.second.Get<float>();
208 else if((DevelText::Underline::Property::DASH_GAP == valueGet.first.indexKey) || (DASH_GAP_KEY == valueGet.first.stringKey))
210 /// Dashed Underline Gap key.
211 dashGapDefined = true;
213 if(valueGet.second.GetType() == Dali::Property::STRING)
215 const std::string dashGapStr = valueGet.second.Get<std::string>();
216 dashGap = StringToFloat(dashGapStr.c_str());
220 dashGap = valueGet.second.Get<float>();
225 return 0u == numberOfItems;
228 bool ParseOutlineProperties(const Property::Map& underlinePropertiesMap,
234 const unsigned int numberOfItems = underlinePropertiesMap.Count();
236 // Parses and applies the style.
237 for(unsigned int index = 0u; index < numberOfItems; ++index)
239 const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue(index);
241 if((DevelText::Outline::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
245 color = valueGet.second.Get<Vector4>();
247 else if((DevelText::Outline::Property::WIDTH == valueGet.first.indexKey) || (WIDTH_KEY == valueGet.first.stringKey))
251 width = static_cast<uint16_t>(valueGet.second.Get<float>());
255 return 0u == numberOfItems;
258 bool ParseBackgroundProperties(const Property::Map& backgroundProperties,
263 const unsigned int numberOfItems = backgroundProperties.Count();
265 // Parses and applies the style.
266 for(unsigned int index = 0u; index < numberOfItems; ++index)
268 const KeyValuePair& valueGet = backgroundProperties.GetKeyValue(index);
270 if((DevelText::Background::Property::ENABLE == valueGet.first.indexKey) || (ENABLE_KEY == valueGet.first.stringKey))
273 enabled = valueGet.second.Get<bool>();
275 else if((DevelText::Background::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
279 color = valueGet.second.Get<Vector4>();
283 return 0u == numberOfItems;
286 bool ParseStrikethroughProperties(const Property::Map& strikethroughPropertiesMap,
293 const unsigned int numberOfItems = strikethroughPropertiesMap.Count();
295 // Parses and applies the style.
296 for(unsigned int index = 0u; index < numberOfItems; ++index)
298 const KeyValuePair& valueGet = strikethroughPropertiesMap.GetKeyValue(index);
300 if((DevelText::Strikethrough::Property::ENABLE == valueGet.first.indexKey) || (ENABLE_KEY == valueGet.first.stringKey))
303 if(valueGet.second.GetType() == Dali::Property::STRING)
305 const std::string enableStr = valueGet.second.Get<std::string>();
306 enabled = Text::TokenComparison(TRUE_TOKEN, enableStr.c_str(), enableStr.size());
310 enabled = valueGet.second.Get<bool>();
313 else if((DevelText::Strikethrough::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
318 if(valueGet.second.GetType() == Dali::Property::STRING)
320 const std::string colorStr = valueGet.second.Get<std::string>();
321 Text::ColorStringToVector4(colorStr.c_str(), colorStr.size(), color);
325 color = valueGet.second.Get<Vector4>();
328 else if((DevelText::Strikethrough::Property::HEIGHT == valueGet.first.indexKey) || (HEIGHT_KEY == valueGet.first.stringKey))
331 heightDefined = true;
333 if(valueGet.second.GetType() == Dali::Property::STRING)
335 const std::string heightStr = valueGet.second.Get<std::string>();
336 height = StringToFloat(heightStr.c_str());
340 height = valueGet.second.Get<float>();
344 return 0u == numberOfItems;
347 bool SetUnderlineProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
355 case EffectStyle::DEFAULT:
357 const Property::Map& propertiesMap = value.Get<Property::Map>();
359 bool enabled = false;
360 bool colorDefined = false;
362 bool heightDefined = false;
364 bool typeDefined = false;
365 Text::Underline::Type type;
366 bool dashWidthDefined = false;
367 float dashWidth = 2.0f;
368 bool dashGapDefined = false;
369 float dashGap = 1.0f;
373 if(propertiesMap.Empty())
375 // Map empty so check if a string provided
376 const std::string propertyString = value.Get<std::string>();
378 if(!propertyString.empty())
380 Property::Map parsedStringMap;
381 Text::ParsePropertyString(propertyString, parsedStringMap);
383 empty = ParseUnderlineProperties(parsedStringMap,
396 controller->UnderlineSetByString(!empty);
401 empty = ParseUnderlineProperties(propertiesMap,
414 controller->UnderlineSetByString(false);
419 if(enabled != controller->IsUnderlineEnabled())
421 controller->SetUnderlineEnabled(enabled);
425 // Sets the default underline values.
426 if(colorDefined && (controller->GetUnderlineColor() != color))
428 controller->SetUnderlineColor(color);
432 if(heightDefined && (fabsf(controller->GetUnderlineHeight() - height) > Math::MACHINE_EPSILON_1000))
434 controller->SetUnderlineHeight(height);
438 if(typeDefined && (controller->GetUnderlineType() != type))
440 controller->SetUnderlineType(type);
444 if(dashWidthDefined && (fabsf(controller->GetDashedUnderlineWidth() - dashWidth) > Math::MACHINE_EPSILON_1000))
446 controller->SetDashedUnderlineWidth(dashWidth);
450 if(dashGapDefined && (fabsf(controller->GetDashedUnderlineGap() - dashGap) > Math::MACHINE_EPSILON_1000))
452 controller->SetDashedUnderlineGap(dashGap);
458 // Disable underline.
459 if(controller->IsUnderlineEnabled())
461 controller->SetUnderlineEnabled(false);
467 case EffectStyle::INPUT:
469 const std::string& underlineProperties = value.Get<std::string>();
471 controller->SetInputUnderlineProperties(underlineProperties);
475 } // if( controller )
480 void GetUnderlineProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
486 case EffectStyle::DEFAULT:
488 const bool enabled = controller->IsUnderlineEnabled();
489 const Vector4& color = controller->GetUnderlineColor();
490 const float height = controller->GetUnderlineHeight();
491 const Text::Underline::Type type = controller->GetUnderlineType();
492 const float dashWidth = controller->GetDashedUnderlineWidth();
493 const float dashGap = controller->GetDashedUnderlineGap();
495 if(controller->IsUnderlineSetByString())
497 std::string underlineProperties = "{\"enable\":";
498 const std::string enabledStr = enabled ? "true" : "false";
499 underlineProperties += "\"" + enabledStr + "\",";
501 std::string colorStr;
502 Vector4ToColorString(color, colorStr);
503 underlineProperties += "\"color\":\"" + colorStr + "\",";
505 std::string heightStr;
506 FloatToString(height, heightStr);
507 underlineProperties += "\"height\":\"" + heightStr + "\",";
510 typeStr = GetUnderlineTypeToString(type);
511 underlineProperties += "\"type\":\"" + typeStr + "\",";
513 std::string dashWidthStr;
514 FloatToString(dashWidth, dashWidthStr);
515 underlineProperties += "\"dashWidth\":\"" + dashWidthStr + "\",";
517 std::string dashGapStr;
518 FloatToString(dashGap, dashGapStr);
519 underlineProperties += "\"dashGap\":\"" + dashGapStr + "\"}";
521 value = underlineProperties;
527 map.Insert(ENABLE_KEY, enabled);
528 map.Insert(COLOR_KEY, color);
529 map.Insert(HEIGHT_KEY, height);
530 map.Insert(TYPE_KEY, type);
531 map.Insert(DASH_WIDTH_KEY, dashWidth);
532 map.Insert(DASH_GAP_KEY, dashGap);
539 case EffectStyle::INPUT:
541 value = controller->GetInputUnderlineProperties();
548 bool SetShadowProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
556 case EffectStyle::DEFAULT:
558 const Property::Map& propertiesMap = value.Get<Property::Map>();
560 bool colorDefined = false;
562 bool offsetDefined = false;
564 bool blurRadiusDefined = false;
569 if(propertiesMap.Empty())
571 // Map empty so check if a string provided
572 const std::string propertyString = value.Get<std::string>();
574 Property::Map parsedStringMap;
575 Text::ParsePropertyString(propertyString, parsedStringMap);
577 empty = ParseShadowProperties(parsedStringMap,
585 controller->ShadowSetByString(!empty);
589 empty = ParseShadowProperties(propertiesMap,
597 controller->ShadowSetByString(false);
602 // Sets the default shadow values.
603 if(colorDefined && (controller->GetShadowColor() != color))
605 controller->SetShadowColor(color);
609 if(offsetDefined && (controller->GetShadowOffset() != offset))
611 controller->SetShadowOffset(offset);
615 if(blurRadiusDefined && (!Dali::Equals(controller->GetShadowBlurRadius(), blurRadius)))
617 controller->SetShadowBlurRadius(blurRadius);
624 if(Vector2::ZERO != controller->GetShadowOffset())
626 controller->SetShadowOffset(Vector2::ZERO);
631 case EffectStyle::INPUT:
633 const std::string& shadowString = value.Get<std::string>();
635 controller->SetInputShadowProperties(shadowString);
639 } // if( controller )
644 void GetShadowProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
650 case EffectStyle::DEFAULT:
652 const Vector4& color = controller->GetShadowColor();
653 const Vector2& offset = controller->GetShadowOffset();
654 const float& blurRadius = controller->GetShadowBlurRadius();
656 if(controller->IsShadowSetByString())
658 std::string shadowProperties = "{";
660 std::string colorStr;
661 Vector4ToColorString(color, colorStr);
662 shadowProperties += "\"color\":\"" + colorStr + "\",";
664 std::string offsetStr;
665 Vector2ToString(offset, offsetStr);
666 shadowProperties += "\"offset\":\"" + offsetStr + "\",";
668 std::string blurRadiusStr;
669 FloatToString(blurRadius, blurRadiusStr);
670 shadowProperties += "\"blurRadius\":\"" + blurRadiusStr + "\"}";
672 value = shadowProperties;
678 map.Insert(COLOR_KEY, color);
679 map.Insert(OFFSET_KEY, offset);
680 map.Insert(BLUR_RADIUS_KEY, blurRadius);
686 case EffectStyle::INPUT:
688 value = controller->GetInputShadowProperties();
695 bool SetEmbossProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
701 const std::string properties = value.Get<std::string>();
705 case EffectStyle::DEFAULT:
707 // Stores the default emboss's properties string to be recovered by the GetEmbossProperties() function.
708 controller->SetDefaultEmbossProperties(properties);
711 case EffectStyle::INPUT:
713 // Stores the input emboss's properties string to be recovered by the GetEmbossProperties() function.
714 controller->SetInputEmbossProperties(properties);
723 void GetEmbossProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
729 case EffectStyle::DEFAULT:
731 value = controller->GetDefaultEmbossProperties();
734 case EffectStyle::INPUT:
736 value = controller->GetInputEmbossProperties();
743 bool SetOutlineProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
751 case EffectStyle::DEFAULT:
753 const Property::Map& propertiesMap = value.Get<Property::Map>();
755 bool colorDefined = false;
757 bool widthDefined = false;
762 if(propertiesMap.Empty())
764 // Map empty so check if a string provided
765 // This is purely to maintain backward compatibility, but we don't parse the string to be a property map.
766 const std::string propertyString = value.Get<std::string>();
768 // Stores the default outline's properties string to be recovered by the GetOutlineProperties() function.
769 controller->SetDefaultOutlineProperties(propertyString);
771 controller->OutlineSetByString(true);
775 empty = ParseOutlineProperties(propertiesMap,
781 controller->OutlineSetByString(false);
786 // Sets the default outline values.
787 if(colorDefined && (controller->GetOutlineColor() != color))
789 controller->SetOutlineColor(color);
793 if(widthDefined && (controller->GetOutlineWidth() != width))
795 controller->SetOutlineWidth(width);
802 if(0u != controller->GetOutlineWidth())
804 controller->SetOutlineWidth(0u);
810 case EffectStyle::INPUT:
812 const std::string& outlineProperties = value.Get<std::string>();
814 controller->SetInputOutlineProperties(outlineProperties);
818 } // if( controller )
823 void GetOutlineProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
829 case EffectStyle::DEFAULT:
831 if(controller->IsOutlineSetByString())
833 value = controller->GetDefaultOutlineProperties();
838 const Vector4& color = controller->GetOutlineColor();
839 const uint16_t width = controller->GetOutlineWidth();
842 map.Insert(COLOR_KEY, color);
843 map.Insert(WIDTH_KEY, static_cast<int>(width));
850 case EffectStyle::INPUT:
852 value = controller->GetInputOutlineProperties();
859 bool SetBackgroundProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
867 case EffectStyle::DEFAULT:
869 const Property::Map& propertiesMap = value.Get<Property::Map>();
871 bool enabled = false;
872 bool colorDefined = false;
877 if(!propertiesMap.Empty())
879 empty = ParseBackgroundProperties(propertiesMap,
887 if(enabled != controller->IsBackgroundEnabled())
889 controller->SetBackgroundEnabled(enabled);
893 if(colorDefined && (controller->GetBackgroundColor() != color))
895 controller->SetBackgroundColor(color);
901 // Disable background.
902 if(controller->IsBackgroundEnabled())
904 controller->SetBackgroundEnabled(false);
910 case EffectStyle::INPUT:
912 // Text background is not supported while inputting yet
916 } // if( controller )
921 void GetBackgroundProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
927 case EffectStyle::DEFAULT:
929 const bool enabled = controller->IsBackgroundEnabled();
930 const Vector4& color = controller->GetBackgroundColor();
933 map.Insert(ENABLE_KEY, enabled);
934 map.Insert(COLOR_KEY, color);
940 case EffectStyle::INPUT:
942 // Text background is not supported while inputting yet
949 bool SetStrikethroughProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
957 case EffectStyle::DEFAULT:
959 const Property::Map& propertiesMap = value.Get<Property::Map>();
961 bool enabled = false;
962 bool colorDefined = false;
964 bool heightDefined = false;
969 if(propertiesMap.Empty())
971 // Map empty so check if a string provided
972 const std::string propertyString = value.Get<std::string>();
974 if(!propertyString.empty())
976 Property::Map parsedStringMap;
977 Text::ParsePropertyString(propertyString, parsedStringMap);
979 empty = ParseStrikethroughProperties(parsedStringMap,
986 controller->StrikethroughSetByString(!empty);
991 empty = ParseStrikethroughProperties(propertiesMap,
998 controller->StrikethroughSetByString(false);
1003 if(enabled != controller->IsStrikethroughEnabled())
1005 controller->SetStrikethroughEnabled(enabled);
1009 // Sets the default strikethrough values.
1010 if(colorDefined && (controller->GetStrikethroughColor() != color))
1012 controller->SetStrikethroughColor(color);
1015 if(heightDefined && (fabsf(controller->GetStrikethroughHeight() - height) > Math::MACHINE_EPSILON_1000))
1017 controller->SetStrikethroughHeight(height);
1023 // Disable strikethrough.
1024 if(controller->IsStrikethroughEnabled())
1026 controller->SetStrikethroughEnabled(false);
1032 case EffectStyle::INPUT:
1034 const std::string& strikethroughProperties = value.Get<std::string>();
1036 controller->SetInputStrikethroughProperties(strikethroughProperties);
1041 } // if( controller )
1046 void GetStrikethroughProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
1052 case EffectStyle::DEFAULT:
1054 const bool enabled = controller->IsStrikethroughEnabled();
1055 const Vector4& color = controller->GetStrikethroughColor();
1056 const float height = controller->GetStrikethroughHeight();
1058 if(controller->IsStrikethroughSetByString())
1060 std::string strikethroughProperties = "{\"enable\":";
1061 const std::string enabledStr = enabled ? "true" : "false";
1062 strikethroughProperties += "\"" + enabledStr + "\",";
1064 std::string colorStr;
1065 Vector4ToColorString(color, colorStr);
1066 strikethroughProperties += "\"color\":\"" + colorStr + "\",";
1068 std::string heightStr;
1069 FloatToString(height, heightStr);
1070 strikethroughProperties += "\"height\":\"" + heightStr + "\"}";
1072 value = strikethroughProperties;
1078 map.Insert(ENABLE_KEY, enabled);
1079 map.Insert(COLOR_KEY, color);
1080 map.Insert(HEIGHT_KEY, height);
1087 case EffectStyle::INPUT:
1089 value = controller->GetInputStrikethroughProperties();
1096 Underline::Type StringToUnderlineType(const char* const underlineTypeStr)
1098 Underline::Type underlineType = Text::Underline::SOLID;
1099 Scripting::GetEnumeration<Underline::Type>(underlineTypeStr,
1100 UNDERLINE_TYPE_STRING_TABLE,
1101 UNDERLINE_TYPE_STRING_TABLE_COUNT,
1104 return underlineType;
1109 } // namespace Toolkit