2 * Copyright (c) 2021 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-helper-functions.h>
24 #include <dali-toolkit/internal/text/property-string-parser.h>
25 #include <dali-toolkit/public-api/text/text-enumerations.h>
26 #include <dali-toolkit/internal/text/text-enumerations-impl.h>
36 const std::string COLOR_KEY("color");
37 const std::string OFFSET_KEY("offset");
38 const std::string BLUR_RADIUS_KEY("blurRadius");
39 const std::string WIDTH_KEY("width");
40 const std::string HEIGHT_KEY("height");
41 const std::string ENABLE_KEY("enable");
42 const std::string TYPE_KEY("type");
43 const std::string DASH_WIDTH_KEY("dashWidth");
44 const std::string DASH_GAP_KEY("dashGap");
45 const std::string TRUE_TOKEN("true");
46 const std::string FALSE_TOKEN("false");
49 bool ParseShadowProperties(const Property::Map& shadowPropertiesMap,
54 bool& blurRadiusDefined,
57 const unsigned int numberOfItems = shadowPropertiesMap.Count();
59 // Parses and applies the style.
60 for(unsigned int index = 0u; index < numberOfItems; ++index)
62 const KeyValuePair& valueGet = shadowPropertiesMap.GetKeyValue(index);
64 if((DevelText::Shadow::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
69 if(valueGet.second.GetType() == Dali::Property::STRING)
71 const std::string colorStr = valueGet.second.Get<std::string>();
72 Text::ColorStringToVector4(colorStr.c_str(), colorStr.size(), color);
76 color = valueGet.second.Get<Vector4>();
79 else if((DevelText::Shadow::Property::OFFSET == valueGet.first.indexKey) || (OFFSET_KEY == valueGet.first.stringKey))
84 if(valueGet.second.GetType() == Dali::Property::STRING)
86 const std::string offsetStr = valueGet.second.Get<std::string>();
87 StringToVector2(offsetStr.c_str(), offsetStr.size(), offset);
91 offset = valueGet.second.Get<Vector2>();
94 else if((DevelText::Shadow::Property::BLUR_RADIUS == valueGet.first.indexKey) || (BLUR_RADIUS_KEY == valueGet.first.stringKey))
97 blurRadiusDefined = true;
99 if(valueGet.second.GetType() == Dali::Property::STRING)
101 const std::string blurRadiusStr = valueGet.second.Get<std::string>();
102 blurRadius = StringToFloat(blurRadiusStr.c_str());
106 blurRadius = valueGet.second.Get<float>();
111 return 0u == numberOfItems;
114 bool ParseUnderlineProperties(const Property::Map& underlinePropertiesMap,
121 Text::Underline::Type& type,
122 bool& dashWidthDefined,
124 bool& dashGapDefined,
127 const unsigned int numberOfItems = underlinePropertiesMap.Count();
129 // Parses and applies the style.
130 for(unsigned int index = 0u; index < numberOfItems; ++index)
132 const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue(index);
134 if((DevelText::Underline::Property::ENABLE == valueGet.first.indexKey) || (ENABLE_KEY == valueGet.first.stringKey))
137 if(valueGet.second.GetType() == Dali::Property::STRING)
139 const std::string enableStr = valueGet.second.Get<std::string>();
140 enabled = Text::TokenComparison(TRUE_TOKEN, enableStr.c_str(), enableStr.size());
144 enabled = valueGet.second.Get<bool>();
147 else if((DevelText::Underline::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
152 if(valueGet.second.GetType() == Dali::Property::STRING)
154 const std::string colorStr = valueGet.second.Get<std::string>();
155 Text::ColorStringToVector4(colorStr.c_str(), colorStr.size(), color);
159 color = valueGet.second.Get<Vector4>();
162 else if((DevelText::Underline::Property::HEIGHT == valueGet.first.indexKey) || (HEIGHT_KEY == valueGet.first.stringKey))
165 heightDefined = true;
167 if(valueGet.second.GetType() == Dali::Property::STRING)
169 const std::string heightStr = valueGet.second.Get<std::string>();
170 height = StringToFloat(heightStr.c_str());
174 height = valueGet.second.Get<float>();
177 else if((DevelText::Underline::Property::TYPE == valueGet.first.indexKey) || (TYPE_KEY == valueGet.first.stringKey))
179 /// Underline Type key.
182 if(valueGet.second.GetType() == Dali::Property::STRING)
184 const std::string typeStr = valueGet.second.Get<std::string>();
185 Text::UnderlineTypeStringToTypeValue(typeStr.c_str(), typeStr.size(), type);
189 type = valueGet.second.Get<Text::Underline::Type>();
192 else if((DevelText::Underline::Property::DASH_WIDTH == valueGet.first.indexKey) || (DASH_WIDTH_KEY == valueGet.first.stringKey))
194 /// Dashed Underline Width key.
195 dashWidthDefined = true;
197 if(valueGet.second.GetType() == Dali::Property::STRING)
199 const std::string dashWidthStr = valueGet.second.Get<std::string>();
200 dashWidth = StringToFloat(dashWidthStr.c_str());
204 dashWidth = valueGet.second.Get<float>();
207 else if((DevelText::Underline::Property::DASH_GAP == valueGet.first.indexKey) || (DASH_GAP_KEY == valueGet.first.stringKey))
209 /// Dashed Underline Gap key.
210 dashGapDefined = true;
212 if(valueGet.second.GetType() == Dali::Property::STRING)
214 const std::string dashGapStr = valueGet.second.Get<std::string>();
215 dashGap = StringToFloat(dashGapStr.c_str());
219 dashGap = valueGet.second.Get<float>();
224 return 0u == numberOfItems;
227 bool ParseOutlineProperties(const Property::Map& underlinePropertiesMap,
233 const unsigned int numberOfItems = underlinePropertiesMap.Count();
235 // Parses and applies the style.
236 for(unsigned int index = 0u; index < numberOfItems; ++index)
238 const KeyValuePair& valueGet = underlinePropertiesMap.GetKeyValue(index);
240 if((DevelText::Outline::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
244 color = valueGet.second.Get<Vector4>();
246 else if((DevelText::Outline::Property::WIDTH == valueGet.first.indexKey) || (WIDTH_KEY == valueGet.first.stringKey))
250 width = static_cast<uint16_t>(valueGet.second.Get<float>());
254 return 0u == numberOfItems;
257 bool ParseBackgroundProperties(const Property::Map& backgroundProperties,
262 const unsigned int numberOfItems = backgroundProperties.Count();
264 // Parses and applies the style.
265 for(unsigned int index = 0u; index < numberOfItems; ++index)
267 const KeyValuePair& valueGet = backgroundProperties.GetKeyValue(index);
269 if((DevelText::Background::Property::ENABLE == valueGet.first.indexKey) || (ENABLE_KEY == valueGet.first.stringKey))
272 enabled = valueGet.second.Get<bool>();
274 else if((DevelText::Background::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
278 color = valueGet.second.Get<Vector4>();
282 return 0u == numberOfItems;
285 bool ParseStrikethroughProperties(const Property::Map& strikethroughPropertiesMap,
292 const unsigned int numberOfItems = strikethroughPropertiesMap.Count();
294 // Parses and applies the style.
295 for(unsigned int index = 0u; index < numberOfItems; ++index)
297 const KeyValuePair& valueGet = strikethroughPropertiesMap.GetKeyValue(index);
299 if((DevelText::Strikethrough::Property::ENABLE == valueGet.first.indexKey) || (ENABLE_KEY == valueGet.first.stringKey))
302 if(valueGet.second.GetType() == Dali::Property::STRING)
304 const std::string enableStr = valueGet.second.Get<std::string>();
305 enabled = Text::TokenComparison(TRUE_TOKEN, enableStr.c_str(), enableStr.size());
309 enabled = valueGet.second.Get<bool>();
312 else if((DevelText::Strikethrough::Property::COLOR == valueGet.first.indexKey) || (COLOR_KEY == valueGet.first.stringKey))
317 if(valueGet.second.GetType() == Dali::Property::STRING)
319 const std::string colorStr = valueGet.second.Get<std::string>();
320 Text::ColorStringToVector4(colorStr.c_str(), colorStr.size(), color);
324 color = valueGet.second.Get<Vector4>();
327 else if((DevelText::Strikethrough::Property::HEIGHT == valueGet.first.indexKey) || (HEIGHT_KEY == valueGet.first.stringKey))
330 heightDefined = true;
332 if(valueGet.second.GetType() == Dali::Property::STRING)
334 const std::string heightStr = valueGet.second.Get<std::string>();
335 height = StringToFloat(heightStr.c_str());
339 height = valueGet.second.Get<float>();
343 return 0u == numberOfItems;
346 bool SetUnderlineProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
354 case EffectStyle::DEFAULT:
356 const Property::Map& propertiesMap = value.Get<Property::Map>();
358 bool enabled = false;
359 bool colorDefined = false;
361 bool heightDefined = false;
363 bool typeDefined = false;
364 Text::Underline::Type type;
365 bool dashWidthDefined = false;
366 float dashWidth = 2.0f;
367 bool dashGapDefined = false;
368 float dashGap = 1.0f;
372 if(propertiesMap.Empty())
374 // Map empty so check if a string provided
375 const std::string propertyString = value.Get<std::string>();
377 if(!propertyString.empty())
379 Property::Map parsedStringMap;
380 Text::ParsePropertyString(propertyString, parsedStringMap);
382 empty = ParseUnderlineProperties(parsedStringMap,
395 controller->UnderlineSetByString(!empty);
400 empty = ParseUnderlineProperties(propertiesMap,
413 controller->UnderlineSetByString(false);
418 if(enabled != controller->IsUnderlineEnabled())
420 controller->SetUnderlineEnabled(enabled);
424 // Sets the default underline values.
425 if(colorDefined && (controller->GetUnderlineColor() != color))
427 controller->SetUnderlineColor(color);
431 if(heightDefined && (fabsf(controller->GetUnderlineHeight() - height) > Math::MACHINE_EPSILON_1000))
433 controller->SetUnderlineHeight(height);
437 if(typeDefined && (controller->GetUnderlineType() != type))
439 controller->SetUnderlineType(type);
443 if(dashWidthDefined && (fabsf(controller->GetDashedUnderlineWidth() - dashWidth) > Math::MACHINE_EPSILON_1000))
445 controller->SetDashedUnderlineWidth(dashWidth);
449 if(dashGapDefined && (fabsf(controller->GetDashedUnderlineGap() - dashGap) > Math::MACHINE_EPSILON_1000))
451 controller->SetDashedUnderlineGap(dashGap);
457 // Disable underline.
458 if(controller->IsUnderlineEnabled())
460 controller->SetUnderlineEnabled(false);
466 case EffectStyle::INPUT:
468 const std::string& underlineProperties = value.Get<std::string>();
470 controller->SetInputUnderlineProperties(underlineProperties);
474 } // if( controller )
479 void GetUnderlineProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
485 case EffectStyle::DEFAULT:
487 const bool enabled = controller->IsUnderlineEnabled();
488 const Vector4& color = controller->GetUnderlineColor();
489 const float height = controller->GetUnderlineHeight();
490 const Text::Underline::Type type = controller->GetUnderlineType();
491 const float dashWidth = controller->GetDashedUnderlineWidth();
492 const float dashGap = controller->GetDashedUnderlineGap();
494 if(controller->IsUnderlineSetByString())
496 std::string underlineProperties = "{\"enable\":";
497 const std::string enabledStr = enabled ? "true" : "false";
498 underlineProperties += "\"" + enabledStr + "\",";
500 std::string colorStr;
501 Vector4ToColorString(color, colorStr);
502 underlineProperties += "\"color\":\"" + colorStr + "\",";
504 std::string heightStr;
505 FloatToString(height, heightStr);
506 underlineProperties += "\"height\":\"" + heightStr + "\",";
509 typeStr = GetUnderlineTypeToString(type);
510 underlineProperties += "\"type\":\"" + typeStr + "\",";
512 std::string dashWidthStr;
513 FloatToString(dashWidth, dashWidthStr);
514 underlineProperties += "\"dashWidth\":\"" + dashWidthStr + "\",";
516 std::string dashGapStr;
517 FloatToString(dashGap, dashGapStr);
518 underlineProperties += "\"dashGap\":\"" + dashGapStr + "\"}";
520 value = underlineProperties;
526 map.Insert(ENABLE_KEY, enabled);
527 map.Insert(COLOR_KEY, color);
528 map.Insert(HEIGHT_KEY, height);
529 map.Insert(TYPE_KEY, type);
530 map.Insert(DASH_WIDTH_KEY, dashWidth);
531 map.Insert(DASH_GAP_KEY, dashGap);
538 case EffectStyle::INPUT:
540 value = controller->GetInputUnderlineProperties();
547 bool SetShadowProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
555 case EffectStyle::DEFAULT:
557 const Property::Map& propertiesMap = value.Get<Property::Map>();
559 bool colorDefined = false;
561 bool offsetDefined = false;
563 bool blurRadiusDefined = false;
568 if(propertiesMap.Empty())
570 // Map empty so check if a string provided
571 const std::string propertyString = value.Get<std::string>();
573 Property::Map parsedStringMap;
574 Text::ParsePropertyString(propertyString, parsedStringMap);
576 empty = ParseShadowProperties(parsedStringMap,
584 controller->ShadowSetByString(!empty);
588 empty = ParseShadowProperties(propertiesMap,
596 controller->ShadowSetByString(false);
601 // Sets the default shadow values.
602 if(colorDefined && (controller->GetShadowColor() != color))
604 controller->SetShadowColor(color);
608 if(offsetDefined && (controller->GetShadowOffset() != offset))
610 controller->SetShadowOffset(offset);
614 if(blurRadiusDefined && (controller->GetShadowBlurRadius() != blurRadius))
616 controller->SetShadowBlurRadius(blurRadius);
623 if(Vector2::ZERO != controller->GetShadowOffset())
625 controller->SetShadowOffset(Vector2::ZERO);
630 case EffectStyle::INPUT:
632 const std::string& shadowString = value.Get<std::string>();
634 controller->SetInputShadowProperties(shadowString);
638 } // if( controller )
643 void GetShadowProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
649 case EffectStyle::DEFAULT:
651 const Vector4& color = controller->GetShadowColor();
652 const Vector2& offset = controller->GetShadowOffset();
653 const float& blurRadius = controller->GetShadowBlurRadius();
655 if(controller->IsShadowSetByString())
657 std::string shadowProperties = "{";
659 std::string colorStr;
660 Vector4ToColorString(color, colorStr);
661 shadowProperties += "\"color\":\"" + colorStr + "\",";
663 std::string offsetStr;
664 Vector2ToString(offset, offsetStr);
665 shadowProperties += "\"offset\":\"" + offsetStr + "\",";
667 std::string blurRadiusStr;
668 FloatToString(blurRadius, blurRadiusStr);
669 shadowProperties += "\"blurRadius\":\"" + blurRadiusStr + "\"}";
671 value = shadowProperties;
677 map.Insert(COLOR_KEY, color);
678 map.Insert(OFFSET_KEY, offset);
679 map.Insert(BLUR_RADIUS_KEY, blurRadius);
685 case EffectStyle::INPUT:
687 value = controller->GetInputShadowProperties();
694 bool SetEmbossProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
700 const std::string properties = value.Get<std::string>();
704 case EffectStyle::DEFAULT:
706 // Stores the default emboss's properties string to be recovered by the GetEmbossProperties() function.
707 controller->SetDefaultEmbossProperties(properties);
710 case EffectStyle::INPUT:
712 // Stores the input emboss's properties string to be recovered by the GetEmbossProperties() function.
713 controller->SetInputEmbossProperties(properties);
722 void GetEmbossProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
728 case EffectStyle::DEFAULT:
730 value = controller->GetDefaultEmbossProperties();
733 case EffectStyle::INPUT:
735 value = controller->GetInputEmbossProperties();
742 bool SetOutlineProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
750 case EffectStyle::DEFAULT:
752 const Property::Map& propertiesMap = value.Get<Property::Map>();
754 bool colorDefined = false;
756 bool widthDefined = false;
761 if(propertiesMap.Empty())
763 // Map empty so check if a string provided
764 // This is purely to maintain backward compatibility, but we don't parse the string to be a property map.
765 const std::string propertyString = value.Get<std::string>();
767 // Stores the default outline's properties string to be recovered by the GetOutlineProperties() function.
768 controller->SetDefaultOutlineProperties(propertyString);
770 controller->OutlineSetByString(true);
774 empty = ParseOutlineProperties(propertiesMap,
780 controller->OutlineSetByString(false);
785 // Sets the default outline values.
786 if(colorDefined && (controller->GetOutlineColor() != color))
788 controller->SetOutlineColor(color);
792 if(widthDefined && (controller->GetOutlineWidth() != width))
794 controller->SetOutlineWidth(width);
801 if(0u != controller->GetOutlineWidth())
803 controller->SetOutlineWidth(0u);
809 case EffectStyle::INPUT:
811 const std::string& outlineProperties = value.Get<std::string>();
813 controller->SetInputOutlineProperties(outlineProperties);
817 } // if( controller )
822 void GetOutlineProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
828 case EffectStyle::DEFAULT:
830 if(controller->IsOutlineSetByString())
832 value = controller->GetDefaultOutlineProperties();
837 const Vector4& color = controller->GetOutlineColor();
838 const uint16_t width = controller->GetOutlineWidth();
841 map.Insert(COLOR_KEY, color);
842 map.Insert(WIDTH_KEY, static_cast<int>(width));
849 case EffectStyle::INPUT:
851 value = controller->GetInputOutlineProperties();
858 bool SetBackgroundProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
866 case EffectStyle::DEFAULT:
868 const Property::Map& propertiesMap = value.Get<Property::Map>();
870 bool enabled = false;
871 bool colorDefined = false;
876 if(!propertiesMap.Empty())
878 empty = ParseBackgroundProperties(propertiesMap,
886 if(enabled != controller->IsBackgroundEnabled())
888 controller->SetBackgroundEnabled(enabled);
892 if(colorDefined && (controller->GetBackgroundColor() != color))
894 controller->SetBackgroundColor(color);
900 // Disable background.
901 if(controller->IsBackgroundEnabled())
903 controller->SetBackgroundEnabled(false);
909 case EffectStyle::INPUT:
911 // Text background is not supported while inputting yet
915 } // if( controller )
920 void GetBackgroundProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
926 case EffectStyle::DEFAULT:
928 const bool enabled = controller->IsBackgroundEnabled();
929 const Vector4& color = controller->GetBackgroundColor();
932 map.Insert(ENABLE_KEY, enabled);
933 map.Insert(COLOR_KEY, color);
939 case EffectStyle::INPUT:
941 // Text background is not supported while inputting yet
948 bool SetStrikethroughProperties(ControllerPtr controller, const Property::Value& value, EffectStyle::Type type)
956 case EffectStyle::DEFAULT:
958 const Property::Map& propertiesMap = value.Get<Property::Map>();
960 bool enabled = false;
961 bool colorDefined = false;
963 bool heightDefined = false;
968 if(propertiesMap.Empty())
970 // Map empty so check if a string provided
971 const std::string propertyString = value.Get<std::string>();
973 if(!propertyString.empty())
975 Property::Map parsedStringMap;
976 Text::ParsePropertyString(propertyString, parsedStringMap);
978 empty = ParseStrikethroughProperties(parsedStringMap,
985 controller->StrikethroughSetByString(!empty);
990 empty = ParseStrikethroughProperties(propertiesMap,
997 controller->StrikethroughSetByString(false);
1002 if(enabled != controller->IsStrikethroughEnabled())
1004 controller->SetStrikethroughEnabled(enabled);
1008 // Sets the default strikethrough values.
1009 if(colorDefined && (controller->GetStrikethroughColor() != color))
1011 controller->SetStrikethroughColor(color);
1014 if(heightDefined && (fabsf(controller->GetStrikethroughHeight() - height) > Math::MACHINE_EPSILON_1000))
1016 controller->SetStrikethroughHeight(height);
1022 // Disable strikethrough.
1023 if(controller->IsStrikethroughEnabled())
1025 controller->SetStrikethroughEnabled(false);
1031 case EffectStyle::INPUT:
1033 const std::string& strikethroughProperties = value.Get<std::string>();
1035 controller->SetInputStrikethroughProperties(strikethroughProperties);
1040 } // if( controller )
1045 void GetStrikethroughProperties(ControllerPtr controller, Property::Value& value, EffectStyle::Type type)
1051 case EffectStyle::DEFAULT:
1053 const bool enabled = controller->IsStrikethroughEnabled();
1054 const Vector4& color = controller->GetStrikethroughColor();
1055 const float height = controller->GetStrikethroughHeight();
1057 if(controller->IsStrikethroughSetByString())
1059 std::string strikethroughProperties = "{\"enable\":";
1060 const std::string enabledStr = enabled ? "true" : "false";
1061 strikethroughProperties += "\"" + enabledStr + "\",";
1063 std::string colorStr;
1064 Vector4ToColorString(color, colorStr);
1065 strikethroughProperties += "\"color\":\"" + colorStr + "\",";
1067 std::string heightStr;
1068 FloatToString(height, heightStr);
1069 strikethroughProperties += "\"height\":\"" + heightStr + "\"}";
1071 value = strikethroughProperties;
1077 map.Insert(ENABLE_KEY, enabled);
1078 map.Insert(COLOR_KEY, color);
1079 map.Insert(HEIGHT_KEY, height);
1086 case EffectStyle::INPUT:
1088 value = controller->GetInputStrikethroughProperties();
1097 } // namespace Toolkit