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 std::string COLOR_KEY("color");
39 const std::string OFFSET_KEY("offset");
40 const std::string BLUR_RADIUS_KEY("blurRadius");
41 const std::string WIDTH_KEY("width");
42 const std::string HEIGHT_KEY("height");
43 const std::string ENABLE_KEY("enable");
44 const std::string TYPE_KEY("type");
45 const std::string DASH_WIDTH_KEY("dashWidth");
46 const std::string DASH_GAP_KEY("dashGap");
47 const std::string TRUE_TOKEN("true");
48 const std::string FALSE_TOKEN("false");
51 bool ParseShadowProperties(const Property::Map& shadowPropertiesMap,
56 bool& blurRadiusDefined,
59 const unsigned int numberOfItems = shadowPropertiesMap.Count();
61 // Parses and applies the style.
62 for(unsigned int index = 0u; index < numberOfItems; ++index)
64 const KeyValuePair& valueGet = shadowPropertiesMap.GetKeyValue(index);
66 if((DevelText::Shadow::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
71 if(valueGet.second.GetType() == Dali::Property::STRING)
73 const std::string colorStr = valueGet.second.Get<std::string>();
74 Text::ColorStringToVector4(colorStr.c_str(), colorStr.size(), color);
78 color = valueGet.second.Get<Vector4>();
81 else if((DevelText::Shadow::Property::OFFSET == valueGet.first.indexKey) || (OFFSET_KEY == valueGet.first.stringKey))
86 if(valueGet.second.GetType() == Dali::Property::STRING)
88 const std::string offsetStr = valueGet.second.Get<std::string>();
89 StringToVector2(offsetStr.c_str(), offsetStr.size(), offset);
93 offset = valueGet.second.Get<Vector2>();
96 else if((DevelText::Shadow::Property::BLUR_RADIUS == valueGet.first.indexKey) || (BLUR_RADIUS_KEY == valueGet.first.stringKey))
99 blurRadiusDefined = true;
101 if(valueGet.second.GetType() == Dali::Property::STRING)
103 const std::string blurRadiusStr = valueGet.second.Get<std::string>();
104 blurRadius = StringToFloat(blurRadiusStr.c_str());
108 blurRadius = valueGet.second.Get<float>();
113 return 0u == numberOfItems;
116 bool ParseUnderlineProperties(const Property::Map& underlinePropertiesMap,
123 Text::Underline::Type& type,
124 bool& dashWidthDefined,
126 bool& dashGapDefined,
129 const unsigned int numberOfItems = underlinePropertiesMap.Count();
131 // Parses and applies the style.
132 for(unsigned int index = 0u; index < numberOfItems; ++index)
134 const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue(index);
136 if((DevelText::Underline::Property::ENABLE == valueGet.first.indexKey) || (ENABLE_KEY == valueGet.first.stringKey))
139 if(valueGet.second.GetType() == Dali::Property::STRING)
141 const std::string enableStr = valueGet.second.Get<std::string>();
142 enabled = Text::TokenComparison(TRUE_TOKEN, enableStr.c_str(), enableStr.size());
146 enabled = valueGet.second.Get<bool>();
149 else if((DevelText::Underline::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
154 if(valueGet.second.GetType() == Dali::Property::STRING)
156 const std::string colorStr = valueGet.second.Get<std::string>();
157 Text::ColorStringToVector4(colorStr.c_str(), colorStr.size(), color);
161 color = valueGet.second.Get<Vector4>();
164 else if((DevelText::Underline::Property::HEIGHT == valueGet.first.indexKey) || (HEIGHT_KEY == valueGet.first.stringKey))
167 heightDefined = true;
169 if(valueGet.second.GetType() == Dali::Property::STRING)
171 const std::string heightStr = valueGet.second.Get<std::string>();
172 height = StringToFloat(heightStr.c_str());
176 height = valueGet.second.Get<float>();
179 else if((DevelText::Underline::Property::TYPE == valueGet.first.indexKey) || (TYPE_KEY == valueGet.first.stringKey))
181 /// Underline Type key.
184 if(valueGet.second.GetType() == Dali::Property::STRING)
186 const std::string typeStr = valueGet.second.Get<std::string>();
187 Text::UnderlineTypeStringToTypeValue(typeStr.c_str(), typeStr.size(), type);
191 type = valueGet.second.Get<Text::Underline::Type>();
194 else if((DevelText::Underline::Property::DASH_WIDTH == valueGet.first.indexKey) || (DASH_WIDTH_KEY == valueGet.first.stringKey))
196 /// Dashed Underline Width key.
197 dashWidthDefined = true;
199 if(valueGet.second.GetType() == Dali::Property::STRING)
201 const std::string dashWidthStr = valueGet.second.Get<std::string>();
202 dashWidth = StringToFloat(dashWidthStr.c_str());
206 dashWidth = valueGet.second.Get<float>();
209 else if((DevelText::Underline::Property::DASH_GAP == valueGet.first.indexKey) || (DASH_GAP_KEY == valueGet.first.stringKey))
211 /// Dashed Underline Gap key.
212 dashGapDefined = true;
214 if(valueGet.second.GetType() == Dali::Property::STRING)
216 const std::string dashGapStr = valueGet.second.Get<std::string>();
217 dashGap = StringToFloat(dashGapStr.c_str());
221 dashGap = valueGet.second.Get<float>();
226 return 0u == numberOfItems;
229 bool ParseOutlineProperties(const Property::Map& underlinePropertiesMap,
235 const unsigned int numberOfItems = underlinePropertiesMap.Count();
237 // Parses and applies the style.
238 for(unsigned int index = 0u; index < numberOfItems; ++index)
240 const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue(index);
242 if((DevelText::Outline::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
246 color = valueGet.second.Get<Vector4>();
248 else if((DevelText::Outline::Property::WIDTH == valueGet.first.indexKey) || (WIDTH_KEY == valueGet.first.stringKey))
252 width = static_cast<uint16_t>(valueGet.second.Get<float>());
256 return 0u == numberOfItems;
259 bool ParseBackgroundProperties(const Property::Map& backgroundProperties,
264 const unsigned int numberOfItems = backgroundProperties.Count();
266 // Parses and applies the style.
267 for(unsigned int index = 0u; index < numberOfItems; ++index)
269 const KeyValuePair& valueGet = backgroundProperties.GetKeyValue(index);
271 if((DevelText::Background::Property::ENABLE == valueGet.first.indexKey) || (ENABLE_KEY == valueGet.first.stringKey))
274 enabled = valueGet.second.Get<bool>();
276 else if((DevelText::Background::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
280 color = valueGet.second.Get<Vector4>();
284 return 0u == numberOfItems;
287 bool ParseStrikethroughProperties(const Property::Map& strikethroughPropertiesMap,
294 const unsigned int numberOfItems = strikethroughPropertiesMap.Count();
296 // Parses and applies the style.
297 for(unsigned int index = 0u; index < numberOfItems; ++index)
299 const KeyValuePair& valueGet = strikethroughPropertiesMap.GetKeyValue(index);
301 if((DevelText::Strikethrough::Property::ENABLE == valueGet.first.indexKey) || (ENABLE_KEY == valueGet.first.stringKey))
304 if(valueGet.second.GetType() == Dali::Property::STRING)
306 const std::string enableStr = valueGet.second.Get<std::string>();
307 enabled = Text::TokenComparison(TRUE_TOKEN, enableStr.c_str(), enableStr.size());
311 enabled = valueGet.second.Get<bool>();
314 else if((DevelText::Strikethrough::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
319 if(valueGet.second.GetType() == Dali::Property::STRING)
321 const std::string colorStr = valueGet.second.Get<std::string>();
322 Text::ColorStringToVector4(colorStr.c_str(), colorStr.size(), color);
326 color = valueGet.second.Get<Vector4>();
329 else if((DevelText::Strikethrough::Property::HEIGHT == valueGet.first.indexKey) || (HEIGHT_KEY == valueGet.first.stringKey))
332 heightDefined = true;
334 if(valueGet.second.GetType() == Dali::Property::STRING)
336 const std::string heightStr = valueGet.second.Get<std::string>();
337 height = StringToFloat(heightStr.c_str());
341 height = valueGet.second.Get<float>();
345 return 0u == numberOfItems;
348 bool SetUnderlineProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
356 case EffectStyle::DEFAULT:
358 const Property::Map& propertiesMap = value.Get<Property::Map>();
360 bool enabled = false;
361 bool colorDefined = false;
363 bool heightDefined = false;
365 bool typeDefined = false;
366 Text::Underline::Type type;
367 bool dashWidthDefined = false;
368 float dashWidth = 2.0f;
369 bool dashGapDefined = false;
370 float dashGap = 1.0f;
374 if(propertiesMap.Empty())
376 // Map empty so check if a string provided
377 const std::string propertyString = value.Get<std::string>();
379 if(!propertyString.empty())
381 Property::Map parsedStringMap;
382 Text::ParsePropertyString(propertyString, parsedStringMap);
384 empty = ParseUnderlineProperties(parsedStringMap,
397 controller->UnderlineSetByString(!empty);
402 empty = ParseUnderlineProperties(propertiesMap,
415 controller->UnderlineSetByString(false);
420 if(enabled != controller->IsUnderlineEnabled())
422 controller->SetUnderlineEnabled(enabled);
426 // Sets the default underline values.
427 if(colorDefined && (controller->GetUnderlineColor() != color))
429 controller->SetUnderlineColor(color);
433 if(heightDefined && (fabsf(controller->GetUnderlineHeight() - height) > Math::MACHINE_EPSILON_1000))
435 controller->SetUnderlineHeight(height);
439 if(typeDefined && (controller->GetUnderlineType() != type))
441 controller->SetUnderlineType(type);
445 if(dashWidthDefined && (fabsf(controller->GetDashedUnderlineWidth() - dashWidth) > Math::MACHINE_EPSILON_1000))
447 controller->SetDashedUnderlineWidth(dashWidth);
451 if(dashGapDefined && (fabsf(controller->GetDashedUnderlineGap() - dashGap) > Math::MACHINE_EPSILON_1000))
453 controller->SetDashedUnderlineGap(dashGap);
459 // Disable underline.
460 if(controller->IsUnderlineEnabled())
462 controller->SetUnderlineEnabled(false);
468 case EffectStyle::INPUT:
470 const std::string& underlineProperties = value.Get<std::string>();
472 controller->SetInputUnderlineProperties(underlineProperties);
476 } // if( controller )
481 void GetUnderlineProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
487 case EffectStyle::DEFAULT:
489 const bool enabled = controller->IsUnderlineEnabled();
490 const Vector4& color = controller->GetUnderlineColor();
491 const float height = controller->GetUnderlineHeight();
492 const Text::Underline::Type type = controller->GetUnderlineType();
493 const float dashWidth = controller->GetDashedUnderlineWidth();
494 const float dashGap = controller->GetDashedUnderlineGap();
496 if(controller->IsUnderlineSetByString())
498 std::string underlineProperties = "{\"enable\":";
499 const std::string enabledStr = enabled ? "true" : "false";
500 underlineProperties += "\"" + enabledStr + "\",";
502 std::string colorStr;
503 Vector4ToColorString(color, colorStr);
504 underlineProperties += "\"color\":\"" + colorStr + "\",";
506 std::string heightStr;
507 FloatToString(height, heightStr);
508 underlineProperties += "\"height\":\"" + heightStr + "\",";
511 typeStr = GetUnderlineTypeToString(type);
512 underlineProperties += "\"type\":\"" + typeStr + "\",";
514 std::string dashWidthStr;
515 FloatToString(dashWidth, dashWidthStr);
516 underlineProperties += "\"dashWidth\":\"" + dashWidthStr + "\",";
518 std::string dashGapStr;
519 FloatToString(dashGap, dashGapStr);
520 underlineProperties += "\"dashGap\":\"" + dashGapStr + "\"}";
522 value = underlineProperties;
528 map.Insert(ENABLE_KEY, enabled);
529 map.Insert(COLOR_KEY, color);
530 map.Insert(HEIGHT_KEY, height);
531 map.Insert(TYPE_KEY, type);
532 map.Insert(DASH_WIDTH_KEY, dashWidth);
533 map.Insert(DASH_GAP_KEY, dashGap);
540 case EffectStyle::INPUT:
542 value = controller->GetInputUnderlineProperties();
549 bool SetShadowProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
557 case EffectStyle::DEFAULT:
559 const Property::Map& propertiesMap = value.Get<Property::Map>();
561 bool colorDefined = false;
563 bool offsetDefined = false;
565 bool blurRadiusDefined = false;
570 if(propertiesMap.Empty())
572 // Map empty so check if a string provided
573 const std::string propertyString = value.Get<std::string>();
575 Property::Map parsedStringMap;
576 Text::ParsePropertyString(propertyString, parsedStringMap);
578 empty = ParseShadowProperties(parsedStringMap,
586 controller->ShadowSetByString(!empty);
590 empty = ParseShadowProperties(propertiesMap,
598 controller->ShadowSetByString(false);
603 // Sets the default shadow values.
604 if(colorDefined && (controller->GetShadowColor() != color))
606 controller->SetShadowColor(color);
610 if(offsetDefined && (controller->GetShadowOffset() != offset))
612 controller->SetShadowOffset(offset);
616 if(blurRadiusDefined && (!Dali::Equals(controller->GetShadowBlurRadius(), blurRadius)))
618 controller->SetShadowBlurRadius(blurRadius);
625 if(Vector2::ZERO != controller->GetShadowOffset())
627 controller->SetShadowOffset(Vector2::ZERO);
632 case EffectStyle::INPUT:
634 const std::string& shadowString = value.Get<std::string>();
636 controller->SetInputShadowProperties(shadowString);
640 } // if( controller )
645 void GetShadowProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
651 case EffectStyle::DEFAULT:
653 const Vector4& color = controller->GetShadowColor();
654 const Vector2& offset = controller->GetShadowOffset();
655 const float& blurRadius = controller->GetShadowBlurRadius();
657 if(controller->IsShadowSetByString())
659 std::string shadowProperties = "{";
661 std::string colorStr;
662 Vector4ToColorString(color, colorStr);
663 shadowProperties += "\"color\":\"" + colorStr + "\",";
665 std::string offsetStr;
666 Vector2ToString(offset, offsetStr);
667 shadowProperties += "\"offset\":\"" + offsetStr + "\",";
669 std::string blurRadiusStr;
670 FloatToString(blurRadius, blurRadiusStr);
671 shadowProperties += "\"blurRadius\":\"" + blurRadiusStr + "\"}";
673 value = shadowProperties;
679 map.Insert(COLOR_KEY, color);
680 map.Insert(OFFSET_KEY, offset);
681 map.Insert(BLUR_RADIUS_KEY, blurRadius);
687 case EffectStyle::INPUT:
689 value = controller->GetInputShadowProperties();
696 bool SetEmbossProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
702 const std::string properties = value.Get<std::string>();
706 case EffectStyle::DEFAULT:
708 // Stores the default emboss's properties string to be recovered by the GetEmbossProperties() function.
709 controller->SetDefaultEmbossProperties(properties);
712 case EffectStyle::INPUT:
714 // Stores the input emboss's properties string to be recovered by the GetEmbossProperties() function.
715 controller->SetInputEmbossProperties(properties);
724 void GetEmbossProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
730 case EffectStyle::DEFAULT:
732 value = controller->GetDefaultEmbossProperties();
735 case EffectStyle::INPUT:
737 value = controller->GetInputEmbossProperties();
744 bool SetOutlineProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
752 case EffectStyle::DEFAULT:
754 const Property::Map& propertiesMap = value.Get<Property::Map>();
756 bool colorDefined = false;
758 bool widthDefined = false;
763 if(propertiesMap.Empty())
765 // Map empty so check if a string provided
766 // This is purely to maintain backward compatibility, but we don't parse the string to be a property map.
767 const std::string propertyString = value.Get<std::string>();
769 // Stores the default outline's properties string to be recovered by the GetOutlineProperties() function.
770 controller->SetDefaultOutlineProperties(propertyString);
772 controller->OutlineSetByString(true);
776 empty = ParseOutlineProperties(propertiesMap,
782 controller->OutlineSetByString(false);
787 // Sets the default outline values.
788 if(colorDefined && (controller->GetOutlineColor() != color))
790 controller->SetOutlineColor(color);
794 if(widthDefined && (controller->GetOutlineWidth() != width))
796 controller->SetOutlineWidth(width);
803 if(0u != controller->GetOutlineWidth())
805 controller->SetOutlineWidth(0u);
811 case EffectStyle::INPUT:
813 const std::string& outlineProperties = value.Get<std::string>();
815 controller->SetInputOutlineProperties(outlineProperties);
819 } // if( controller )
824 void GetOutlineProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
830 case EffectStyle::DEFAULT:
832 if(controller->IsOutlineSetByString())
834 value = controller->GetDefaultOutlineProperties();
839 const Vector4& color = controller->GetOutlineColor();
840 const uint16_t width = controller->GetOutlineWidth();
843 map.Insert(COLOR_KEY, color);
844 map.Insert(WIDTH_KEY, static_cast<int>(width));
851 case EffectStyle::INPUT:
853 value = controller->GetInputOutlineProperties();
860 bool SetBackgroundProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
868 case EffectStyle::DEFAULT:
870 const Property::Map& propertiesMap = value.Get<Property::Map>();
872 bool enabled = false;
873 bool colorDefined = false;
878 if(!propertiesMap.Empty())
880 empty = ParseBackgroundProperties(propertiesMap,
888 if(enabled != controller->IsBackgroundEnabled())
890 controller->SetBackgroundEnabled(enabled);
894 if(colorDefined && (controller->GetBackgroundColor() != color))
896 controller->SetBackgroundColor(color);
902 // Disable background.
903 if(controller->IsBackgroundEnabled())
905 controller->SetBackgroundEnabled(false);
911 case EffectStyle::INPUT:
913 // Text background is not supported while inputting yet
917 } // if( controller )
922 void GetBackgroundProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
928 case EffectStyle::DEFAULT:
930 const bool enabled = controller->IsBackgroundEnabled();
931 const Vector4& color = controller->GetBackgroundColor();
934 map.Insert(ENABLE_KEY, enabled);
935 map.Insert(COLOR_KEY, color);
941 case EffectStyle::INPUT:
943 // Text background is not supported while inputting yet
950 bool SetStrikethroughProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
958 case EffectStyle::DEFAULT:
960 const Property::Map& propertiesMap = value.Get<Property::Map>();
962 bool enabled = false;
963 bool colorDefined = false;
965 bool heightDefined = false;
970 if(propertiesMap.Empty())
972 // Map empty so check if a string provided
973 const std::string propertyString = value.Get<std::string>();
975 if(!propertyString.empty())
977 Property::Map parsedStringMap;
978 Text::ParsePropertyString(propertyString, parsedStringMap);
980 empty = ParseStrikethroughProperties(parsedStringMap,
987 controller->StrikethroughSetByString(!empty);
992 empty = ParseStrikethroughProperties(propertiesMap,
999 controller->StrikethroughSetByString(false);
1004 if(enabled != controller->IsStrikethroughEnabled())
1006 controller->SetStrikethroughEnabled(enabled);
1010 // Sets the default strikethrough values.
1011 if(colorDefined && (controller->GetStrikethroughColor() != color))
1013 controller->SetStrikethroughColor(color);
1016 if(heightDefined && (fabsf(controller->GetStrikethroughHeight() - height) > Math::MACHINE_EPSILON_1000))
1018 controller->SetStrikethroughHeight(height);
1024 // Disable strikethrough.
1025 if(controller->IsStrikethroughEnabled())
1027 controller->SetStrikethroughEnabled(false);
1033 case EffectStyle::INPUT:
1035 const std::string& strikethroughProperties = value.Get<std::string>();
1037 controller->SetInputStrikethroughProperties(strikethroughProperties);
1042 } // if( controller )
1047 void GetStrikethroughProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
1053 case EffectStyle::DEFAULT:
1055 const bool enabled = controller->IsStrikethroughEnabled();
1056 const Vector4& color = controller->GetStrikethroughColor();
1057 const float height = controller->GetStrikethroughHeight();
1059 if(controller->IsStrikethroughSetByString())
1061 std::string strikethroughProperties = "{\"enable\":";
1062 const std::string enabledStr = enabled ? "true" : "false";
1063 strikethroughProperties += "\"" + enabledStr + "\",";
1065 std::string colorStr;
1066 Vector4ToColorString(color, colorStr);
1067 strikethroughProperties += "\"color\":\"" + colorStr + "\",";
1069 std::string heightStr;
1070 FloatToString(height, heightStr);
1071 strikethroughProperties += "\"height\":\"" + heightStr + "\"}";
1073 value = strikethroughProperties;
1079 map.Insert(ENABLE_KEY, enabled);
1080 map.Insert(COLOR_KEY, color);
1081 map.Insert(HEIGHT_KEY, height);
1088 case EffectStyle::INPUT:
1090 value = controller->GetInputStrikethroughProperties();
1097 Underline::Type StringToUnderlineType(const char* const underlineTypeStr)
1099 Underline::Type underlineType = Text::Underline::SOLID;
1100 Scripting::GetEnumeration<Underline::Type>(underlineTypeStr,
1101 UNDERLINE_TYPE_STRING_TABLE,
1102 UNDERLINE_TYPE_STRING_TABLE_COUNT,
1105 return underlineType;
1110 } // namespace Toolkit