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-toolkit/devel-api/controls/text-controls/text-style-properties-devel.h>
23 #include <dali-toolkit/internal/text/markup-processor/markup-processor-helper-functions.h>
24 #include <dali-toolkit/internal/text/property-string-parser.h>
25 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
35 const std::string COLOR_KEY("color");
36 const std::string OFFSET_KEY("offset");
37 const std::string BLUR_RADIUS_KEY("blurRadius");
38 const std::string WIDTH_KEY("width");
39 const std::string HEIGHT_KEY("height");
40 const std::string ENABLE_KEY("enable");
41 const std::string TYPE_KEY("type");
42 const std::string DASH_WIDTH_KEY("dashWidth");
43 const std::string DASH_GAP_KEY("dashGap");
44 const std::string TRUE_TOKEN("true");
45 const std::string FALSE_TOKEN("false");
48 bool ParseShadowProperties(const Property::Map& shadowPropertiesMap,
53 bool& blurRadiusDefined,
56 const unsigned int numberOfItems = shadowPropertiesMap.Count();
58 // Parses and applies the style.
59 for(unsigned int index = 0u; index < numberOfItems; ++index)
61 const KeyValuePair& valueGet = shadowPropertiesMap.GetKeyValue(index);
63 if((DevelText::Shadow::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
68 if(valueGet.second.GetType() == Dali::Property::STRING)
70 const std::string colorStr = valueGet.second.Get<std::string>();
71 Text::ColorStringToVector4(colorStr.c_str(), colorStr.size(), color);
75 color = valueGet.second.Get<Vector4>();
78 else if((DevelText::Shadow::Property::OFFSET == valueGet.first.indexKey) || (OFFSET_KEY == valueGet.first.stringKey))
83 if(valueGet.second.GetType() == Dali::Property::STRING)
85 const std::string offsetStr = valueGet.second.Get<std::string>();
86 StringToVector2(offsetStr.c_str(), offsetStr.size(), offset);
90 offset = valueGet.second.Get<Vector2>();
93 else if((DevelText::Shadow::Property::BLUR_RADIUS == valueGet.first.indexKey) || (BLUR_RADIUS_KEY == valueGet.first.stringKey))
96 blurRadiusDefined = true;
98 if(valueGet.second.GetType() == Dali::Property::STRING)
100 const std::string blurRadiusStr = valueGet.second.Get<std::string>();
101 blurRadius = StringToFloat(blurRadiusStr.c_str());
105 blurRadius = valueGet.second.Get<float>();
110 return 0u == numberOfItems;
113 bool ParseUnderlineProperties(const Property::Map& underlinePropertiesMap,
120 Text::Underline::Type& type,
121 bool& dashWidthDefined,
123 bool& dashGapDefined,
126 const unsigned int numberOfItems = underlinePropertiesMap.Count();
128 // Parses and applies the style.
129 for(unsigned int index = 0u; index < numberOfItems; ++index)
131 const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue(index);
133 if((DevelText::Underline::Property::ENABLE == valueGet.first.indexKey) || (ENABLE_KEY == valueGet.first.stringKey))
136 if(valueGet.second.GetType() == Dali::Property::STRING)
138 const std::string enableStr = valueGet.second.Get<std::string>();
139 enabled = Text::TokenComparison(TRUE_TOKEN, enableStr.c_str(), enableStr.size());
143 enabled = valueGet.second.Get<bool>();
146 else if((DevelText::Underline::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
151 if(valueGet.second.GetType() == Dali::Property::STRING)
153 const std::string colorStr = valueGet.second.Get<std::string>();
154 Text::ColorStringToVector4(colorStr.c_str(), colorStr.size(), color);
158 color = valueGet.second.Get<Vector4>();
161 else if((DevelText::Underline::Property::HEIGHT == valueGet.first.indexKey) || (HEIGHT_KEY == valueGet.first.stringKey))
164 heightDefined = true;
166 if(valueGet.second.GetType() == Dali::Property::STRING)
168 const std::string heightStr = valueGet.second.Get<std::string>();
169 height = StringToFloat(heightStr.c_str());
173 height = valueGet.second.Get<float>();
176 else if((DevelText::Underline::Property::TYPE == valueGet.first.indexKey) || (TYPE_KEY == valueGet.first.stringKey))
178 /// Underline Type key.
181 if(valueGet.second.GetType() == Dali::Property::STRING)
183 const std::string typeStr = valueGet.second.Get<std::string>();
184 Text::UnderlineTypeStringToTypeValue(typeStr.c_str(), typeStr.size(), type);
188 type = valueGet.second.Get<Text::Underline::Type>();
191 else if((DevelText::Underline::Property::DASH_WIDTH == valueGet.first.indexKey) || (DASH_WIDTH_KEY == valueGet.first.stringKey))
193 /// Dashed Underline Width key.
194 dashWidthDefined = true;
196 if(valueGet.second.GetType() == Dali::Property::STRING)
198 const std::string dashWidthStr = valueGet.second.Get<std::string>();
199 dashWidth = StringToFloat(dashWidthStr.c_str());
203 dashWidth = valueGet.second.Get<float>();
206 else if((DevelText::Underline::Property::DASH_GAP == valueGet.first.indexKey) || (DASH_GAP_KEY == valueGet.first.stringKey))
208 /// Dashed Underline Gap key.
209 dashGapDefined = true;
211 if(valueGet.second.GetType() == Dali::Property::STRING)
213 const std::string dashGapStr = valueGet.second.Get<std::string>();
214 dashGap = StringToFloat(dashGapStr.c_str());
218 dashGap = valueGet.second.Get<float>();
223 return 0u == numberOfItems;
226 bool ParseOutlineProperties(const Property::Map& underlinePropertiesMap,
232 const unsigned int numberOfItems = underlinePropertiesMap.Count();
234 // Parses and applies the style.
235 for(unsigned int index = 0u; index < numberOfItems; ++index)
237 const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue(index);
239 if((DevelText::Outline::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
243 color = valueGet.second.Get<Vector4>();
245 else if((DevelText::Outline::Property::WIDTH == valueGet.first.indexKey) || (WIDTH_KEY == valueGet.first.stringKey))
249 width = static_cast<uint16_t>(valueGet.second.Get<float>());
253 return 0u == numberOfItems;
256 bool ParseBackgroundProperties(const Property::Map& backgroundProperties,
261 const unsigned int numberOfItems = backgroundProperties.Count();
263 // Parses and applies the style.
264 for(unsigned int index = 0u; index < numberOfItems; ++index)
266 const KeyValuePair& valueGet = backgroundProperties.GetKeyValue(index);
268 if((DevelText::Background::Property::ENABLE == valueGet.first.indexKey) || (ENABLE_KEY == valueGet.first.stringKey))
271 enabled = valueGet.second.Get<bool>();
273 else if((DevelText::Background::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
277 color = valueGet.second.Get<Vector4>();
281 return 0u == numberOfItems;
284 bool ParseStrikethroughProperties(const Property::Map& strikethroughPropertiesMap,
291 const unsigned int numberOfItems = strikethroughPropertiesMap.Count();
293 // Parses and applies the style.
294 for(unsigned int index = 0u; index < numberOfItems; ++index)
296 const KeyValuePair& valueGet = strikethroughPropertiesMap.GetKeyValue(index);
298 if((DevelText::Strikethrough::Property::ENABLE == valueGet.first.indexKey) || (ENABLE_KEY == valueGet.first.stringKey))
301 if(valueGet.second.GetType() == Dali::Property::STRING)
303 const std::string enableStr = valueGet.second.Get<std::string>();
304 enabled = Text::TokenComparison(TRUE_TOKEN, enableStr.c_str(), enableStr.size());
308 enabled = valueGet.second.Get<bool>();
311 else if((DevelText::Strikethrough::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
316 if(valueGet.second.GetType() == Dali::Property::STRING)
318 const std::string colorStr = valueGet.second.Get<std::string>();
319 Text::ColorStringToVector4(colorStr.c_str(), colorStr.size(), color);
323 color = valueGet.second.Get<Vector4>();
326 else if((DevelText::Strikethrough::Property::HEIGHT == valueGet.first.indexKey) || (HEIGHT_KEY == valueGet.first.stringKey))
329 heightDefined = true;
331 if(valueGet.second.GetType() == Dali::Property::STRING)
333 const std::string heightStr = valueGet.second.Get<std::string>();
334 height = StringToFloat(heightStr.c_str());
338 height = valueGet.second.Get<float>();
342 return 0u == numberOfItems;
345 bool SetUnderlineProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
353 case EffectStyle::DEFAULT:
355 const Property::Map& propertiesMap = value.Get<Property::Map>();
357 bool enabled = false;
358 bool colorDefined = false;
360 bool heightDefined = false;
362 bool typeDefined = false;
363 Text::Underline::Type type;
364 bool dashWidthDefined = false;
365 float dashWidth = 2.0f;
366 bool dashGapDefined = false;
367 float dashGap = 1.0f;
371 if(propertiesMap.Empty())
373 // Map empty so check if a string provided
374 const std::string propertyString = value.Get<std::string>();
376 if(!propertyString.empty())
378 Property::Map parsedStringMap;
379 Text::ParsePropertyString(propertyString, parsedStringMap);
381 empty = ParseUnderlineProperties(parsedStringMap,
394 controller->UnderlineSetByString(!empty);
399 empty = ParseUnderlineProperties(propertiesMap,
412 controller->UnderlineSetByString(false);
417 if(enabled != controller->IsUnderlineEnabled())
419 controller->SetUnderlineEnabled(enabled);
423 // Sets the default underline values.
424 if(colorDefined && (controller->GetUnderlineColor() != color))
426 controller->SetUnderlineColor(color);
430 if(heightDefined && (fabsf(controller->GetUnderlineHeight() - height) > Math::MACHINE_EPSILON_1000))
432 controller->SetUnderlineHeight(height);
436 if(typeDefined && (controller->GetUnderlineType() != type))
438 controller->SetUnderlineType(type);
442 if(dashWidthDefined && (fabsf(controller->GetDashedUnderlineWidth() - dashWidth) > Math::MACHINE_EPSILON_1000))
444 controller->SetDashedUnderlineWidth(dashWidth);
448 if(dashGapDefined && (fabsf(controller->GetDashedUnderlineGap() - dashGap) > Math::MACHINE_EPSILON_1000))
450 controller->SetDashedUnderlineGap(dashGap);
456 // Disable underline.
457 if(controller->IsUnderlineEnabled())
459 controller->SetUnderlineEnabled(false);
465 case EffectStyle::INPUT:
467 const std::string& underlineProperties = value.Get<std::string>();
469 controller->SetInputUnderlineProperties(underlineProperties);
473 } // if( controller )
478 void GetUnderlineProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
484 case EffectStyle::DEFAULT:
486 const bool enabled = controller->IsUnderlineEnabled();
487 const Vector4& color = controller->GetUnderlineColor();
488 const float height = controller->GetUnderlineHeight();
489 const Text::Underline::Type type = controller->GetUnderlineType();
490 const float dashWidth = controller->GetDashedUnderlineWidth();
491 const float dashGap = controller->GetDashedUnderlineGap();
493 if(controller->IsUnderlineSetByString())
495 std::string underlineProperties = "{\"enable\":";
496 const std::string enabledStr = enabled ? "true" : "false";
497 underlineProperties += "\"" + enabledStr + "\",";
499 std::string colorStr;
500 Vector4ToColorString(color, colorStr);
501 underlineProperties += "\"color\":\"" + colorStr + "\",";
503 std::string heightStr;
504 FloatToString(height, heightStr);
505 underlineProperties += "\"height\":\"" + heightStr + "\",";
508 typeStr = GetUnderlineTypeToString(type);
509 underlineProperties += "\"type\":\"" + typeStr + "\",";
511 std::string dashWidthStr;
512 FloatToString(dashWidth, dashWidthStr);
513 underlineProperties += "\"dashWidth\":\"" + dashWidthStr + "\",";
515 std::string dashGapStr;
516 FloatToString(dashGap, dashGapStr);
517 underlineProperties += "\"dashGap\":\"" + dashGapStr + "\"}";
519 value = underlineProperties;
525 map.Insert(ENABLE_KEY, enabled);
526 map.Insert(COLOR_KEY, color);
527 map.Insert(HEIGHT_KEY, height);
528 map.Insert(TYPE_KEY, type);
529 map.Insert(DASH_WIDTH_KEY, dashWidth);
530 map.Insert(DASH_GAP_KEY, dashGap);
537 case EffectStyle::INPUT:
539 value = controller->GetInputUnderlineProperties();
546 bool SetShadowProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
554 case EffectStyle::DEFAULT:
556 const Property::Map& propertiesMap = value.Get<Property::Map>();
558 bool colorDefined = false;
560 bool offsetDefined = false;
562 bool blurRadiusDefined = false;
567 if(propertiesMap.Empty())
569 // Map empty so check if a string provided
570 const std::string propertyString = value.Get<std::string>();
572 Property::Map parsedStringMap;
573 Text::ParsePropertyString(propertyString, parsedStringMap);
575 empty = ParseShadowProperties(parsedStringMap,
583 controller->ShadowSetByString(!empty);
587 empty = ParseShadowProperties(propertiesMap,
595 controller->ShadowSetByString(false);
600 // Sets the default shadow values.
601 if(colorDefined && (controller->GetShadowColor() != color))
603 controller->SetShadowColor(color);
607 if(offsetDefined && (controller->GetShadowOffset() != offset))
609 controller->SetShadowOffset(offset);
613 if(blurRadiusDefined && (controller->GetShadowBlurRadius() != blurRadius))
615 controller->SetShadowBlurRadius(blurRadius);
622 if(Vector2::ZERO != controller->GetShadowOffset())
624 controller->SetShadowOffset(Vector2::ZERO);
629 case EffectStyle::INPUT:
631 const std::string& shadowString = value.Get<std::string>();
633 controller->SetInputShadowProperties(shadowString);
637 } // if( controller )
642 void GetShadowProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
648 case EffectStyle::DEFAULT:
650 const Vector4& color = controller->GetShadowColor();
651 const Vector2& offset = controller->GetShadowOffset();
652 const float& blurRadius = controller->GetShadowBlurRadius();
654 if(controller->IsShadowSetByString())
656 std::string shadowProperties = "{";
658 std::string colorStr;
659 Vector4ToColorString(color, colorStr);
660 shadowProperties += "\"color\":\"" + colorStr + "\",";
662 std::string offsetStr;
663 Vector2ToString(offset, offsetStr);
664 shadowProperties += "\"offset\":\"" + offsetStr + "\",";
666 std::string blurRadiusStr;
667 FloatToString(blurRadius, blurRadiusStr);
668 shadowProperties += "\"blurRadius\":\"" + blurRadiusStr + "\"}";
670 value = shadowProperties;
676 map.Insert(COLOR_KEY, color);
677 map.Insert(OFFSET_KEY, offset);
678 map.Insert(BLUR_RADIUS_KEY, blurRadius);
684 case EffectStyle::INPUT:
686 value = controller->GetInputShadowProperties();
693 bool SetEmbossProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
699 const std::string properties = value.Get<std::string>();
703 case EffectStyle::DEFAULT:
705 // Stores the default emboss's properties string to be recovered by the GetEmbossProperties() function.
706 controller->SetDefaultEmbossProperties(properties);
709 case EffectStyle::INPUT:
711 // Stores the input emboss's properties string to be recovered by the GetEmbossProperties() function.
712 controller->SetInputEmbossProperties(properties);
721 void GetEmbossProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
727 case EffectStyle::DEFAULT:
729 value = controller->GetDefaultEmbossProperties();
732 case EffectStyle::INPUT:
734 value = controller->GetInputEmbossProperties();
741 bool SetOutlineProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
749 case EffectStyle::DEFAULT:
751 const Property::Map& propertiesMap = value.Get<Property::Map>();
753 bool colorDefined = false;
755 bool widthDefined = false;
760 if(propertiesMap.Empty())
762 // Map empty so check if a string provided
763 // This is purely to maintain backward compatibility, but we don't parse the string to be a property map.
764 const std::string propertyString = value.Get<std::string>();
766 // Stores the default outline's properties string to be recovered by the GetOutlineProperties() function.
767 controller->SetDefaultOutlineProperties(propertyString);
769 controller->OutlineSetByString(true);
773 empty = ParseOutlineProperties(propertiesMap,
779 controller->OutlineSetByString(false);
784 // Sets the default outline values.
785 if(colorDefined && (controller->GetOutlineColor() != color))
787 controller->SetOutlineColor(color);
791 if(widthDefined && (controller->GetOutlineWidth() != width))
793 controller->SetOutlineWidth(width);
800 if(0u != controller->GetOutlineWidth())
802 controller->SetOutlineWidth(0u);
808 case EffectStyle::INPUT:
810 const std::string& outlineProperties = value.Get<std::string>();
812 controller->SetInputOutlineProperties(outlineProperties);
816 } // if( controller )
821 void GetOutlineProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
827 case EffectStyle::DEFAULT:
829 if(controller->IsOutlineSetByString())
831 value = controller->GetDefaultOutlineProperties();
836 const Vector4& color = controller->GetOutlineColor();
837 const uint16_t width = controller->GetOutlineWidth();
840 map.Insert(COLOR_KEY, color);
841 map.Insert(WIDTH_KEY, static_cast<int>(width));
848 case EffectStyle::INPUT:
850 value = controller->GetInputOutlineProperties();
857 bool SetBackgroundProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
865 case EffectStyle::DEFAULT:
867 const Property::Map& propertiesMap = value.Get<Property::Map>();
869 bool enabled = false;
870 bool colorDefined = false;
875 if(!propertiesMap.Empty())
877 empty = ParseBackgroundProperties(propertiesMap,
885 if(enabled != controller->IsBackgroundEnabled())
887 controller->SetBackgroundEnabled(enabled);
891 if(colorDefined && (controller->GetBackgroundColor() != color))
893 controller->SetBackgroundColor(color);
899 // Disable background.
900 if(controller->IsBackgroundEnabled())
902 controller->SetBackgroundEnabled(false);
908 case EffectStyle::INPUT:
910 // Text background is not supported while inputting yet
914 } // if( controller )
919 void GetBackgroundProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
925 case EffectStyle::DEFAULT:
927 const bool enabled = controller->IsBackgroundEnabled();
928 const Vector4& color = controller->GetBackgroundColor();
931 map.Insert(ENABLE_KEY, enabled);
932 map.Insert(COLOR_KEY, color);
938 case EffectStyle::INPUT:
940 // Text background is not supported while inputting yet
947 bool SetStrikethroughProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
955 case EffectStyle::DEFAULT:
957 const Property::Map& propertiesMap = value.Get<Property::Map>();
959 bool enabled = false;
960 bool colorDefined = false;
962 bool heightDefined = false;
967 if(propertiesMap.Empty())
969 // Map empty so check if a string provided
970 const std::string propertyString = value.Get<std::string>();
972 if(!propertyString.empty())
974 Property::Map parsedStringMap;
975 Text::ParsePropertyString(propertyString, parsedStringMap);
977 empty = ParseStrikethroughProperties(parsedStringMap,
984 controller->StrikethroughSetByString(!empty);
989 empty = ParseStrikethroughProperties(propertiesMap,
996 controller->StrikethroughSetByString(false);
1001 if(enabled != controller->IsStrikethroughEnabled())
1003 controller->SetStrikethroughEnabled(enabled);
1007 // Sets the default strikethrough values.
1008 if(colorDefined && (controller->GetStrikethroughColor() != color))
1010 controller->SetStrikethroughColor(color);
1013 if(heightDefined && (fabsf(controller->GetStrikethroughHeight() - height) > Math::MACHINE_EPSILON_1000))
1015 controller->SetStrikethroughHeight(height);
1021 // Disable strikethrough.
1022 if(controller->IsStrikethroughEnabled())
1024 controller->SetStrikethroughEnabled(false);
1030 case EffectStyle::INPUT:
1032 const std::string& strikethroughProperties = value.Get<std::string>();
1034 controller->SetInputStrikethroughProperties(strikethroughProperties);
1039 } // if( controller )
1044 void GetStrikethroughProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
1050 case EffectStyle::DEFAULT:
1052 const bool enabled = controller->IsStrikethroughEnabled();
1053 const Vector4& color = controller->GetStrikethroughColor();
1054 const float height = controller->GetStrikethroughHeight();
1056 if(controller->IsStrikethroughSetByString())
1058 std::string strikethroughProperties = "{\"enable\":";
1059 const std::string enabledStr = enabled ? "true" : "false";
1060 strikethroughProperties += "\"" + enabledStr + "\",";
1062 std::string colorStr;
1063 Vector4ToColorString(color, colorStr);
1064 strikethroughProperties += "\"color\":\"" + colorStr + "\",";
1066 std::string heightStr;
1067 FloatToString(height, heightStr);
1068 strikethroughProperties += "\"height\":\"" + heightStr + "\"}";
1070 value = strikethroughProperties;
1076 map.Insert(ENABLE_KEY, enabled);
1077 map.Insert(COLOR_KEY, color);
1078 map.Insert(HEIGHT_KEY, height);
1085 case EffectStyle::INPUT:
1087 value = controller->GetInputStrikethroughProperties();
1094 Underline::Type StringToUnderlineType(const char* const underlineTypeStr)
1096 Underline::Type underlineType = Text::Underline::SOLID;
1097 Scripting::GetEnumeration<Underline::Type>(underlineTypeStr,
1098 UNDERLINE_TYPE_STRING_TABLE,
1099 UNDERLINE_TYPE_STRING_TABLE_COUNT,
1102 return underlineType;
1107 } // namespace Toolkit