Added UIHTMLListItem to handle list items properly.

This commit is contained in:
Martín Lucas Golini
2026-04-27 01:38:37 -03:00
parent 41e979d314
commit 82a93dada4
11 changed files with 534 additions and 47 deletions

View File

@@ -148,52 +148,12 @@ ol > li {
padding-left: 2em;
}
ol > li {
background-tint: var(--font);
background-position: 0.6em 0.3em;
ul {
list-style-type: disc;
}
ol > li:nth-child(1) {
background-image: glyph("monospace", 1em, "1");
}
ol > li:nth-child(2) {
background-image: glyph("monospace", 1em, "2");
}
ol > li:nth-child(3) {
background-image: glyph("monospace", 1em, "3");
}
ol > li:nth-child(4) {
background-image: glyph("monospace", 1em, "4");
}
ol > li:nth-child(5) {
background-image: glyph("monospace", 1em, "5");
}
ol > li:nth-child(6) {
background-image: glyph("monospace", 1em, "6");
}
ol > li:nth-child(7) {
background-image: glyph("monospace", 1em, "7");
}
ol > li:nth-child(8) {
background-image: glyph("monospace", 1em, "8");
}
ol > li:nth-child(9) {
background-image: glyph("monospace", 1em, "9");
}
ul > li {
background-image: url("data:image/svg,<svg viewBox='0 0 24 24' width='12' height='12' fill='#ffffff'><path d='M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z'></path></svg>");
background-tint: var(--font);
background-position: 0.6em 0.45em;
background-size: 0.5em 0.5em;
ol {
list-style-type: decimal;
}
a {

View File

@@ -247,6 +247,9 @@ enum class PropertyId : Uint32 {
Bottom = String::hash( "bottom" ),
Left = String::hash( "left" ),
ZIndex = String::hash( "z-index" ),
ListStyleType = String::hash( "list-style-type" ),
ListStylePosition = String::hash( "list-style-position" ),
ListStyleImage = String::hash( "list-style-image" ),
DataLanguage = String::hash( "data-language" ), // Minor hack
};

View File

@@ -34,6 +34,32 @@ struct CSSPositionHelper {
static CSSPosition fromString( std::string_view val );
};
enum class CSSListStyleType {
None,
Disc,
Circle,
Square,
Decimal,
LowerAlpha,
UpperAlpha,
LowerRoman,
UpperRoman
};
struct CSSListStyleTypeHelper {
static std::string toString( CSSListStyleType type );
static CSSListStyleType fromString( std::string_view val );
};
enum class CSSListStylePosition { Outside, Inside };
struct CSSListStylePositionHelper {
static std::string toString( CSSListStylePosition pos );
static CSSListStylePosition fromString( std::string_view val );
};
}} // namespace EE::UI
#endif

View File

@@ -128,6 +128,7 @@ enum UINodeType {
UI_TYPE_BR,
UI_TYPE_HTML_HTML,
UI_TYPE_HTML_BODY,
UI_TYPE_HTML_LIST_ITEM,
UI_TYPE_MODULES = 10000,
UI_TYPE_TERMINAL = 10001,
UI_TYPE_USER = 200000,

View File

@@ -0,0 +1,51 @@
#ifndef EE_UI_UIHTMLLISTITEM_HPP
#define EE_UI_UIHTMLLISTITEM_HPP
#include <eepp/graphics/text.hpp>
#include <eepp/ui/uirichtext.hpp>
#include <memory>
namespace EE { namespace UI {
class EE_API UIHTMLListItem : public UIRichText {
public:
static UIHTMLListItem* New();
virtual Uint32 getType() const;
virtual bool isType( const Uint32& type ) const;
virtual void draw();
virtual bool applyProperty( const StyleSheetProperty& attribute );
virtual std::string getPropertyString( const PropertyDefinition* propertyDef,
const Uint32& propertyIndex = 0 ) const;
virtual std::vector<PropertyId> getPropertiesImplemented() const;
CSSListStyleType getListStyleType() const { return mListStyleType; }
void setListStyleType( CSSListStyleType type );
CSSListStylePosition getListStylePosition() const { return mListStylePosition; }
void setListStylePosition( CSSListStylePosition pos );
protected:
UIHTMLListItem();
CSSListStyleType mListStyleType{ CSSListStyleType::None };
CSSListStylePosition mListStylePosition{ CSSListStylePosition::Outside };
std::unique_ptr<Graphics::Text> mListMarkerText;
int countPrecedingLiSiblings() const;
String::View getListMarkerString() const;
void invalidateList();
};
}} // namespace EE::UI
#endif

View File

@@ -44,8 +44,6 @@ class EE_API UIRichText : public UIHTMLWidget {
static UIRichText* NewPre() { return UIRichText::NewWithTag( "pre" ); };
static UIRichText* NewListItem() { return UIRichText::NewWithTag( "li" ); };
static UIRichText* NewBlockquote() { return UIRichText::NewWithTag( "blockquote" ); };
virtual Uint32 getType() const;

View File

@@ -85,4 +85,58 @@ CSSPosition CSSPositionHelper::fromString( std::string_view val ) {
return position;
}
std::string CSSListStyleTypeHelper::toString( CSSListStyleType type ) {
switch ( type ) {
case CSSListStyleType::Disc:
return "disc";
case CSSListStyleType::Circle:
return "circle";
case CSSListStyleType::Square:
return "square";
case CSSListStyleType::Decimal:
return "decimal";
case CSSListStyleType::LowerAlpha:
return "lower-alpha";
case CSSListStyleType::UpperAlpha:
return "upper-alpha";
case CSSListStyleType::LowerRoman:
return "lower-roman";
case CSSListStyleType::UpperRoman:
return "upper-roman";
case CSSListStyleType::None:
default:
return "none";
}
}
CSSListStyleType CSSListStyleTypeHelper::fromString( std::string_view val ) {
if ( val == "disc" )
return CSSListStyleType::Disc;
if ( val == "circle" )
return CSSListStyleType::Circle;
if ( val == "square" )
return CSSListStyleType::Square;
if ( val == "decimal" )
return CSSListStyleType::Decimal;
if ( val == "lower-alpha" )
return CSSListStyleType::LowerAlpha;
if ( val == "upper-alpha" )
return CSSListStyleType::UpperAlpha;
if ( val == "lower-roman" )
return CSSListStyleType::LowerRoman;
if ( val == "upper-roman" )
return CSSListStyleType::UpperRoman;
return CSSListStyleType::None;
}
std::string CSSListStylePositionHelper::toString( CSSListStylePosition pos ) {
return pos == CSSListStylePosition::Inside ? "inside" : "outside";
}
CSSListStylePosition CSSListStylePositionHelper::fromString( std::string_view val ) {
if ( val == "inside" )
return CSSListStylePosition::Inside;
return CSSListStylePosition::Outside;
}
}} // namespace EE::UI

View File

@@ -428,6 +428,9 @@ void StyleSheetSpecification::registerDefaultProperties() {
registerProperty( "hidden", "" ).setType( PropertyType::Bool );
registerProperty( "display", "inline" ).setType( PropertyType::String );
registerProperty( "position", "static" ).setType( PropertyType::String );
registerProperty( "list-style-type", "none", true ).setType( PropertyType::String );
registerProperty( "list-style-position", "outside", true ).setType( PropertyType::String );
registerProperty( "list-style-image", "none" ).setType( PropertyType::String );
registerProperty( "top", "auto" ).setType( PropertyType::NumberLength );
registerProperty( "right", "auto" ).setType( PropertyType::NumberLength );
registerProperty( "bottom", "auto" ).setType( PropertyType::NumberLength );
@@ -516,6 +519,9 @@ void StyleSheetSpecification::registerDefaultProperties() {
registerShorthand( "border-bottom",
{ "border-bottom-width", "border-bottom-style", "border-bottom-color" },
"border-side" );
registerShorthand( "list-style",
{ "list-style-type", "list-style-position", "list-style-image" },
"list-style" );
}
void StyleSheetSpecification::registerNodeSelector( const std::string& name,
@@ -1135,6 +1141,40 @@ void StyleSheetSpecification::registerDefaultShorthandParsers() {
return properties;
};
mShorthandParsers["list-style"] = []( const ShorthandDefinition* shorthand,
std::string value ) -> std::vector<StyleSheetProperty> {
value = String::trim( value );
if ( value.empty() )
return {};
std::vector<StyleSheetProperty> properties;
const std::vector<std::string>& propNames = shorthand->getProperties();
if ( propNames.empty() )
return {};
auto tokens = String::split( value, " ", "", "(" );
int typePos = getIndexEndingWith( propNames, "-type" );
int posPos = getIndexEndingWith( propNames, "-position" );
int imagePos = getIndexEndingWith( propNames, "-image" );
for ( auto& tok : tokens ) {
String::trimInPlace( tok );
if ( tok == "inside" || tok == "outside" ) {
if ( posPos != -1 )
properties.emplace_back( StyleSheetProperty( propNames[posPos], tok ) );
} else if ( String::startsWith( tok, "url(" ) ) {
if ( imagePos != -1 )
properties.emplace_back( StyleSheetProperty( propNames[imagePos], tok ) );
} else if ( tok == "none" ) {
if ( typePos != -1 )
properties.emplace_back( StyleSheetProperty( propNames[typePos], tok ) );
if ( imagePos != -1 )
properties.emplace_back( StyleSheetProperty( propNames[imagePos], tok ) );
} else {
if ( typePos != -1 )
properties.emplace_back( StyleSheetProperty( propNames[typePos], tok ) );
}
}
return properties;
};
}
}}} // namespace EE::UI::CSS

View File

@@ -0,0 +1,198 @@
#include <eepp/graphics/primitives.hpp>
#include <eepp/ui/css/propertydefinition.hpp>
#include <eepp/ui/uihtmllistitem.hpp>
#include <eepp/ui/uilayouter.hpp>
namespace EE { namespace UI {
UIHTMLListItem* UIHTMLListItem::New() {
return eeNew( UIHTMLListItem, () );
}
UIHTMLListItem::UIHTMLListItem() : UIRichText( "li" ) {}
void UIHTMLListItem::setListStyleType( CSSListStyleType type ) {
if ( mListStyleType != type ) {
mListStyleType = type;
invalidateList();
}
}
void UIHTMLListItem::setListStylePosition( CSSListStylePosition pos ) {
if ( mListStylePosition != pos ) {
mListStylePosition = pos;
invalidateList();
}
}
Uint32 UIHTMLListItem::getType() const {
return UI_TYPE_HTML_LIST_ITEM;
}
bool UIHTMLListItem::isType( const Uint32& type ) const {
return UIHTMLListItem::getType() == type ? true : UIRichText::isType( type );
}
void UIHTMLListItem::draw() {
UIRichText::draw();
if ( mVisible && 0.f != mAlpha ) {
const FontStyleConfig& style = mRichText.getFontStyleConfig();
Float fontSize = style.CharacterSize;
Float offset = 0.25f * fontSize;
Float lineHeight =
style.Font ? style.Font->getLineSpacing( (unsigned int)fontSize ) : fontSize;
Float lineTop = mScreenPos.y + mPaddingPx.Top;
if ( mListStyleType == CSSListStyleType::Disc ) {
Float radius = fontSize * 0.22f;
Float markerX = std::floor( mScreenPos.x + mPaddingPx.Left - radius * 2.f - offset );
Float markerY = std::floor( lineTop + ( lineHeight - radius * 2.f ) * 0.5f + radius );
Primitives p;
p.setColor( style.FontColor );
p.setFillMode( PrimitiveFillMode::DRAW_FILL );
p.drawCircle( { markerX, markerY }, radius );
} else if ( mListStyleType == CSSListStyleType::Circle ) {
Float radius = fontSize * 0.2f;
Float lineWidth = fontSize * 0.04f;
Float markerX = std::floor( mScreenPos.x + mPaddingPx.Left - radius * 2.f - offset );
Float markerY = std::floor( lineTop + ( lineHeight - radius * 2.f ) * 0.5f + radius );
Primitives p;
p.setColor( style.FontColor );
p.setFillMode( PrimitiveFillMode::DRAW_LINE );
p.setLineWidth( lineWidth );
p.drawCircle( { markerX, markerY }, radius );
} else if ( mListStyleType == CSSListStyleType::Square ) {
Float size = fontSize * 0.38f;
Float markerX = std::floor( mScreenPos.x + mPaddingPx.Left - size - fontSize * 0.5 );
Float markerY = std::floor( lineTop + ( lineHeight - size ) * 0.5f );
Primitives p;
p.setColor( style.FontColor );
p.setFillMode( PrimitiveFillMode::DRAW_FILL );
p.drawRectangle( Rectf( markerX, markerY, markerX + size, markerY + size ) );
} else if ( mListMarkerText && !mListMarkerText->getString().empty() ) {
Float markerX =
mScreenPos.x + mPaddingPx.Left - mListMarkerText->getTextWidth() - offset;
mListMarkerText->draw( markerX, lineTop, Vector2f::One, 0.f, getBlendMode() );
}
}
}
bool UIHTMLListItem::applyProperty( const StyleSheetProperty& attribute ) {
if ( !checkPropertyDefinition( attribute ) )
return false;
switch ( attribute.getPropertyDefinition()->getPropertyId() ) {
case PropertyId::ListStyleType:
setListStyleType( CSSListStyleTypeHelper::fromString( attribute.value() ) );
return true;
case PropertyId::ListStylePosition:
setListStylePosition( CSSListStylePositionHelper::fromString( attribute.value() ) );
return true;
default:
return UIRichText::applyProperty( attribute );
}
}
std::string UIHTMLListItem::getPropertyString( const PropertyDefinition* propertyDef,
const Uint32& propertyIndex ) const {
if ( NULL == propertyDef )
return "";
switch ( propertyDef->getPropertyId() ) {
case PropertyId::ListStyleType:
return CSSListStyleTypeHelper::toString( mListStyleType );
case PropertyId::ListStylePosition:
return CSSListStylePositionHelper::toString( mListStylePosition );
default:
return UIRichText::getPropertyString( propertyDef, propertyIndex );
}
}
std::vector<PropertyId> UIHTMLListItem::getPropertiesImplemented() const {
auto props = UIRichText::getPropertiesImplemented();
props.push_back( PropertyId::ListStyleType );
props.push_back( PropertyId::ListStylePosition );
return props;
}
void UIHTMLListItem::invalidateList() {
if ( mListStyleType == CSSListStyleType::None || mListStyleType == CSSListStyleType::Disc ||
mListStyleType == CSSListStyleType::Circle ||
mListStyleType == CSSListStyleType::Square ) {
mListMarkerText.reset();
} else {
String::View markerStr = getListMarkerString();
if ( !markerStr.empty() ) {
if ( !mListMarkerText )
mListMarkerText = std::make_unique<Text>();
mListMarkerText->setString( markerStr );
mListMarkerText->setStyleConfig( mRichText.getFontStyleConfig() );
} else {
mListMarkerText.reset();
}
}
invalidateDraw();
}
int UIHTMLListItem::countPrecedingLiSiblings() const {
int count = 0;
Node* prev = getPrevNode();
while ( prev ) {
if ( prev->isWidget() && prev->asType<UIWidget>()->getElementTag() == "li" )
count++;
prev = prev->getPrevNode();
}
return count;
}
String::View UIHTMLListItem::getListMarkerString() const {
static String sBuf;
switch ( mListStyleType ) {
case CSSListStyleType::None:
case CSSListStyleType::Disc:
case CSSListStyleType::Circle:
case CSSListStyleType::Square:
return {};
case CSSListStyleType::Decimal: {
int idx = countPrecedingLiSiblings() + 1;
sBuf = String( String::toString( idx ) + ". " );
return sBuf.view();
}
case CSSListStyleType::LowerAlpha: {
int idx = countPrecedingLiSiblings();
char c = 'a' + ( idx % 26 );
sBuf = String( 1, (String::StringBaseType)c ) + ". ";
return sBuf.view();
}
case CSSListStyleType::UpperAlpha: {
int idx = countPrecedingLiSiblings();
char c = 'A' + ( idx % 26 );
sBuf = String( 1, (String::StringBaseType)c ) + ". ";
return sBuf.view();
}
case CSSListStyleType::LowerRoman: {
static const char* numerals[] = { "i", "ii", "iii", "iv", "v", "vi",
"vii", "viii", "ix", "x", "xi", "xii" };
int idx = countPrecedingLiSiblings();
if ( idx < 12 )
sBuf = String( numerals[idx] ) + ". ";
else
sBuf = String( String::toString( idx + 1 ) + ". " );
return sBuf.view();
}
case CSSListStyleType::UpperRoman: {
static const char* numerals[] = { "I", "II", "III", "IV", "V", "VI",
"VII", "VIII", "IX", "X", "XI", "XII" };
int idx = countPrecedingLiSiblings();
if ( idx < 12 )
sBuf = String( numerals[idx] ) + ". ";
else
sBuf = String( String::toString( idx + 1 ) + ". " );
return sBuf.view();
}
}
return {};
}
}} // namespace EE::UI

View File

@@ -10,6 +10,7 @@
#include <eepp/ui/uidropdownlist.hpp>
#include <eepp/ui/uidropdownmodellist.hpp>
#include <eepp/ui/uigridlayout.hpp>
#include <eepp/ui/uihtmllistitem.hpp>
#include <eepp/ui/uihtmltable.hpp>
#include <eepp/ui/uiimage.hpp>
#include <eepp/ui/uilinearlayout.hpp>
@@ -158,7 +159,7 @@ void UIWidgetCreator::createBaseWidgetList() {
registeredWidget["hr"] = UIRichText::NewHr;
registeredWidget["ul"] = [] { return UILinearLayout::NewVerticalWidthMatchParent( "ul" ); };
registeredWidget["ol"] = [] { return UILinearLayout::NewVerticalWidthMatchParent( "ol" ); };
registeredWidget["li"] = UIRichText::NewListItem;
registeredWidget["li"] = UIHTMLListItem::New;
registeredWidget["pre"] = UIRichText::NewPre;
registeredWidget["img"] = [] {
auto img = UIImage::NewWithTag( "img" );

View File

@@ -8,6 +8,7 @@
#include <eepp/system/filesystem.hpp>
#include <eepp/system/sys.hpp>
#include <eepp/ui/css/stylesheetparser.hpp>
#include <eepp/ui/css/stylesheetspecification.hpp>
#include <eepp/ui/htmlinput.hpp>
#include <eepp/ui/htmltextarea.hpp>
#include <eepp/ui/htmltextinput.hpp>
@@ -570,3 +571,157 @@ UTEST( UILayout, marginAuto ) {
Engine::destroySingleton();
}
UTEST( UILayout, listStyleTypeDecimal ) {
init_ui_test();
auto* sceneNode = SceneManager::instance()->getUISceneNode();
sceneNode->loadLayoutFromString( R"html(
<html>
<ol>
<li id="li1" style="list-style-type: decimal;">First item</li>
<li id="li2" style="list-style-type: decimal;">Second item</li>
<li id="li3" style="list-style-type: decimal;">Third item</li>
</ol>
</html>
)html" );
sceneNode->updateDirtyLayouts();
const auto* propDef =
StyleSheetSpecification::instance()->getProperty( "list-style-type" );
ASSERT_TRUE( propDef != nullptr );
auto* li1 = sceneNode->getRoot()->find( "li1" )->asType<UIRichText>();
auto* li2 = sceneNode->getRoot()->find( "li2" )->asType<UIRichText>();
auto* li3 = sceneNode->getRoot()->find( "li3" )->asType<UIRichText>();
ASSERT_TRUE( li1 != nullptr );
ASSERT_TRUE( li2 != nullptr );
ASSERT_TRUE( li3 != nullptr );
EXPECT_TRUE( li1->getPropertyString( propDef ) == "decimal" );
EXPECT_TRUE( li2->getPropertyString( propDef ) == "decimal" );
EXPECT_TRUE( li3->getPropertyString( propDef ) == "decimal" );
Engine::destroySingleton();
}
UTEST( UILayout, listStyleTypeDisc ) {
init_ui_test();
auto* sceneNode = SceneManager::instance()->getUISceneNode();
sceneNode->loadLayoutFromString( R"html(
<html>
<ul>
<li id="li1" style="list-style-type: disc;">Bullet item</li>
</ul>
</html>
)html" );
sceneNode->updateDirtyLayouts();
const auto* propDef =
StyleSheetSpecification::instance()->getProperty( "list-style-type" );
ASSERT_TRUE( propDef != nullptr );
auto* li1 = sceneNode->getRoot()->find( "li1" )->asType<UIRichText>();
ASSERT_TRUE( li1 != nullptr );
EXPECT_TRUE( li1->getPropertyString( propDef ) == "disc" );
Engine::destroySingleton();
}
UTEST( UILayout, listStyleShorthand ) {
init_ui_test();
auto* sceneNode = SceneManager::instance()->getUISceneNode();
sceneNode->loadLayoutFromString( R"html(
<html>
<ol>
<li id="li1" style="list-style: decimal outside;">First</li>
<li id="li2" style="list-style: lower-alpha inside;">Second</li>
<li id="li3" style="list-style: none;">Third</li>
</ol>
<ul>
<li id="li4" style="list-style: disc;">Bullet</li>
<li id="li5" style="list-style: square outside;">Square</li>
<li id="li6" style="list-style: circle;">Circle</li>
</ul>
</html>
)html" );
sceneNode->updateDirtyLayouts();
const auto* typeDef =
StyleSheetSpecification::instance()->getProperty( "list-style-type" );
const auto* posDef =
StyleSheetSpecification::instance()->getProperty( "list-style-position" );
for ( const char* id : { "li1", "li2", "li3", "li4", "li5", "li6" } ) {
auto* li = sceneNode->getRoot()->find( id )->asType<UIWidget>();
ASSERT_TRUE( li != nullptr );
EXPECT_TRUE( li->isType( UI_TYPE_HTML_LIST_ITEM ) );
}
EXPECT_TRUE( sceneNode->getRoot()->find( "li1" )->asType<UIRichText>()->getPropertyString( typeDef ) == "decimal" );
EXPECT_TRUE( sceneNode->getRoot()->find( "li1" )->asType<UIRichText>()->getPropertyString( posDef ) == "outside" );
EXPECT_TRUE( sceneNode->getRoot()->find( "li2" )->asType<UIRichText>()->getPropertyString( typeDef ) == "lower-alpha" );
EXPECT_TRUE( sceneNode->getRoot()->find( "li2" )->asType<UIRichText>()->getPropertyString( posDef ) == "inside" );
EXPECT_TRUE( sceneNode->getRoot()->find( "li3" )->asType<UIRichText>()->getPropertyString( typeDef ) == "none" );
EXPECT_TRUE( sceneNode->getRoot()->find( "li4" )->asType<UIRichText>()->getPropertyString( typeDef ) == "disc" );
EXPECT_TRUE( sceneNode->getRoot()->find( "li5" )->asType<UIRichText>()->getPropertyString( typeDef ) == "square" );
EXPECT_TRUE( sceneNode->getRoot()->find( "li5" )->asType<UIRichText>()->getPropertyString( posDef ) == "outside" );
EXPECT_TRUE( sceneNode->getRoot()->find( "li6" )->asType<UIRichText>()->getPropertyString( typeDef ) == "circle" );
Engine::destroySingleton();
}
UTEST( UILayout, listStyleInheritanceFromUl ) {
init_ui_test();
auto* sceneNode = SceneManager::instance()->getUISceneNode();
sceneNode->loadLayoutFromString( R"html(
<html>
<head>
<style>
ul.a { list-style-type: circle; }
ul.b { list-style-type: disc; }
ul.c { list-style-type: square; }
ol.d { list-style-type: decimal; }
ol.h { list-style-type: upper-roman; }
</style>
</head>
<body>
<ol class="h">
<li id="h1">Coffee</li>
</ol>
<ul class="a">
<li id="a1">Coffee</li>
</ul>
<ul class="b">
<li id="b1">Coffee</li>
</ul>
<ul class="c">
<li id="c1">Coffee</li>
</ul>
<ol class="d">
<li id="d1">Coffee</li>
</ol>
</body>
</html>
)html" );
sceneNode->updateDirtyLayouts();
const auto* typeDef =
StyleSheetSpecification::instance()->getProperty( "list-style-type" );
EXPECT_TRUE( sceneNode->getRoot()->find( "h1" )->asType<UIRichText>()->getPropertyString( typeDef ) == "upper-roman" );
EXPECT_TRUE( sceneNode->getRoot()->find( "a1" )->asType<UIRichText>()->getPropertyString( typeDef ) == "circle" );
EXPECT_TRUE( sceneNode->getRoot()->find( "b1" )->asType<UIRichText>()->getPropertyString( typeDef ) == "disc" );
EXPECT_TRUE( sceneNode->getRoot()->find( "c1" )->asType<UIRichText>()->getPropertyString( typeDef ) == "square" );
EXPECT_TRUE( sceneNode->getRoot()->find( "d1" )->asType<UIRichText>()->getPropertyString( typeDef ) == "decimal" );
Engine::destroySingleton();
}