Adds xml support in UIRichText

Supported tags:
- <small>: makes the font 20% smaller
- <big>: makes the font 25% bigger
- <img src="" />: to add an image
- <font face="path to font" size="size" color="#00ffaa">: font
  attributes
- <i>: italics
- <b>: bold
- <u>: underline
- <del> strike-through
- </br>: new line

Also adds support for strikethrough, italics, bold and underlie to
`Label`

Contains tests for UIRichText and Label

Squashed commit of the following:

commit a0d6ae0513d40dbf414930210ab032a49d8984a0
Author: Ricardo Quesada <ricardoquesada@gmail.com>
Date:   Tue Jan 19 20:39:21 2016 -0800

    cleanup LabelTestNew

commit 0cf423af85d88a42fc1317207feeb3d05da7f8ab
Author: Ricardo Quesada <ricardoquesada@gmail.com>
Date:   Tue Jan 19 20:34:53 2016 -0800

    adds maaaany tests

    ...and fixes width and height in <img src="">

commit e8ba6acd5d79bbc766d7aa02ef166e166c801d01
Author: Ricardo Quesada <ricardoquesada@gmail.com>
Date:   Fri Jan 15 19:41:37 2016 -0800

    Label + URL working Ok

commit 36689e29ee3d77310e92264a09084cc06e30664c
Author: Ricardo Quesada <ricardoquesada@gmail.com>
Date:   Fri Jan 15 18:24:44 2016 -0800

    adding this code just in case...

    ... should use a listener component instead

commit af03708950e74483b875d0baad593aa6ed242a04
Author: Ricardo Quesada <ricardoquesada@gmail.com>
Date:   Thu Jan 14 20:23:36 2016 -0800

    URL node

    plus <de><u> and <a img

commit e3a4930b012c0b3756752dac6ffb5ad43d24ae99
Author: Ricardo Quesada <ricardoquesada@gmail.com>
Date:   Wed Jan 13 18:42:18 2016 -0800

    strikethrough and underline implemented

    they support multiline and horizontal alignment as well
    includes test
    however vertical alignment might not work

commit 640ccf39f56e153db46785a61be7000e898174c7
Author: Ricardo Quesada <ricardoquesada@gmail.com>
Date:   Tue Jan 12 18:14:57 2016 -0800

    bug fixes

commit 5e41fb76e91c571639585a609a255eb41797a302
Author: Ricardo Quesada <ricardoquesada@gmail.com>
Date:   Tue Jan 12 16:47:20 2016 -0800

    adds italics and bold "disable test"

commit 202c5a45bb9c8ea160b9f6880ef858874e07814b
Author: Ricardo Quesada <ricardoquesada@gmail.com>
Date:   Tue Jan 12 14:40:13 2016 -0800

    adds italics test

commit d1a8b421445053cc36860fc376f52692a3672dfe
Author: Ricardo Quesada <ricardoquesada@gmail.com>
Date:   Mon Jan 11 20:53:23 2016 -0800

    italics is working ok

commit fdd02087fce920c27c2409301ec88685fe68085b
Author: Ricardo Quesada <ricardoquesada@gmail.com>
Date:   Fri Jan 8 17:18:56 2016 -0800

    color, size and face working

commit c01bdef6b1d49f8805b69d4c162b74cd00c8f5b3
Author: Ricardo Quesada <ricardoquesada@gmail.com>
Date:   Thu Jan 7 19:02:16 2016 -0800

    initial commit
This commit is contained in:
Ricardo Quesada 2016-01-19 20:41:31 -08:00
parent 39ab445f7d
commit 27c8e5227d
10 changed files with 1862 additions and 105 deletions

View File

@ -141,7 +141,10 @@ bool FontFreeType::createFontObject(const std::string &fontName, float fontSize)
if (FT_New_Memory_Face(getFTLibrary(), s_cacheFontData[fontName].data.getBytes(), s_cacheFontData[fontName].data.getSize(), 0, &face ))
return false;
face->underline_position = 0;
face->underline_thickness = 3;
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE))
{
int foundIndex = -1;

View File

@ -24,6 +24,9 @@
****************************************************************************/
#include "2d/CCLabel.h"
#include <algorithm>
#include "2d/CCFont.h"
#include "2d/CCFontAtlasCache.h"
#include "2d/CCFontAtlas.h"
@ -43,6 +46,7 @@
NS_CC_BEGIN
static const int UNDERLINE_NODE_TAG = 0xaabbccdd;
/**
* LabelLetter used to update the quad in texture atlas without SpriteBatchNode.
*/
@ -207,7 +211,6 @@ Label* Label::createWithSystemFont(const std::string& text, const std::string& f
return ret;
}
delete ret;
return nullptr;
}
@ -381,6 +384,9 @@ Label::Label(TextHAlignment hAlignment /* = TextHAlignment::LEFT */,
, _fontAtlas(nullptr)
, _reusedLetter(nullptr)
, _horizontalKernings(nullptr)
, _boldEnabled(false)
, _underlineNode(nullptr)
, _strikethroughEnabled(false)
{
setAnchorPoint(Vec2::ANCHOR_MIDDLE);
reset();
@ -510,7 +516,14 @@ void Label::reset()
_bmfontScale = 1.0f;
_overflow = Overflow::NONE;
_originalFontSize = 0.0f;
_boldEnabled = false;
if (_underlineNode)
{
removeChild(_underlineNode);
_underlineNode = nullptr;
}
_strikethroughEnabled = false;
setRotationSkewX(0); // reverse italics
}
void Label::updateShaderProgram()
@ -956,6 +969,16 @@ bool Label::setTTFConfigInternal(const TTFConfig& ttfConfig)
_currLabelEffect = LabelEffect::NORMAL;
updateShaderProgram();
}
if (_fontConfig.italics)
this->enableItalics();
if (_fontConfig.bold)
this->enableBold();
if (_fontConfig.underline)
this->enableUnderline();
if (_fontConfig.strikethrough)
this->enableStrikethrough();
return true;
}
@ -1096,55 +1119,112 @@ void Label::enableShadow(const Color4B& shadowColor /* = Color4B::BLACK */,const
}
}
void Label::enableItalics()
{
setRotationSkewX(12);
}
void Label::enableBold()
{
if (!_boldEnabled)
{
// bold is implemented with outline
enableShadow(Color4B::WHITE, Size(0.9,0), 0);
// add one to kerning
setAdditionalKerning(_additionalKerning+1);
_boldEnabled = true;
}
}
void Label::enableUnderline()
{
// remove it, just in case to prevent adding two or more
if (!_underlineNode)
{
_underlineNode = DrawNode::create();
addChild(_underlineNode, 100000);
_contentDirty = true;
}
}
void Label::enableStrikethrough()
{
if (!_strikethroughEnabled)
{
enableUnderline();
_strikethroughEnabled = true;
}
}
void Label::disableEffect()
{
disableEffect(LabelEffect::GLOW);
disableEffect(LabelEffect::OUTLINE);
disableEffect(LabelEffect::SHADOW);
disableEffect(LabelEffect::ALL);
}
void Label::disableEffect(LabelEffect effect)
{
switch (effect)
{
case cocos2d::LabelEffect::NORMAL:
break;
case cocos2d::LabelEffect::OUTLINE:
if (_currLabelEffect == LabelEffect::OUTLINE)
{
if (_currentLabelType == LabelType::TTF)
case cocos2d::LabelEffect::NORMAL:
break;
case cocos2d::LabelEffect::OUTLINE:
if (_currLabelEffect == LabelEffect::OUTLINE)
{
_fontConfig.outlineSize = 0;
setTTFConfig(_fontConfig);
if (_currentLabelType == LabelType::TTF)
{
_fontConfig.outlineSize = 0;
setTTFConfig(_fontConfig);
}
_currLabelEffect = LabelEffect::NORMAL;
_contentDirty = true;
}
_currLabelEffect = LabelEffect::NORMAL;
_contentDirty = true;
}
break;
case cocos2d::LabelEffect::SHADOW:
if (_shadowEnabled)
{
_shadowEnabled = false;
CC_SAFE_RELEASE_NULL(_shadowNode);
}
break;
case cocos2d::LabelEffect::GLOW:
if (_currLabelEffect == LabelEffect::GLOW)
{
_currLabelEffect = LabelEffect::NORMAL;
updateShaderProgram();
}
break;
case LabelEffect::ALL:
break;
case cocos2d::LabelEffect::SHADOW:
if (_shadowEnabled)
{
_shadowEnabled = false;
CC_SAFE_RELEASE_NULL(_shadowNode);
}
break;
case cocos2d::LabelEffect::GLOW:
if (_currLabelEffect == LabelEffect::GLOW)
{
_currLabelEffect = LabelEffect::NORMAL;
updateShaderProgram();
}
break;
case cocos2d::LabelEffect::ITALICS:
setRotationSkewX(0);
break;
case cocos2d::LabelEffect::BOLD:
_boldEnabled = false;
_additionalKerning -= 1;
disableEffect(LabelEffect::SHADOW);
break;
case cocos2d::LabelEffect::UNDERLINE:
if (_underlineNode) {
removeChild(_underlineNode);
_underlineNode = nullptr;
}
break;
case cocos2d::LabelEffect::STRIKETHROUGH:
_strikethroughEnabled = false;
// since it is based on underline, disable it as well
disableEffect(LabelEffect::UNDERLINE);
break;
case LabelEffect::ALL:
{
disableEffect(LabelEffect::SHADOW);
disableEffect(LabelEffect::GLOW);
disableEffect(LabelEffect::OUTLINE);
disableEffect(LabelEffect::ITALICS);
disableEffect(LabelEffect::BOLD);
disableEffect(LabelEffect::UNDERLINE);
disableEffect(LabelEffect::STRIKETHROUGH);
}
break;
default:
break;
break;
default:
break;
}
}
@ -1299,6 +1379,25 @@ void Label::updateContent()
createShadowSpriteForSystemFont(fontDef);
}
}
if (_underlineNode)
{
const float charheight = (_textDesiredHeight / _numberOfLines);
_underlineNode->clear();
_underlineNode->setLineWidth(charheight/6);
for (int i=0; i<_numberOfLines; ++i)
{
float offsety = 0;
if (_strikethroughEnabled)
offsety += charheight / 2;
// FIXME: Might not work with different vertical alignments
float y = (_numberOfLines - i - 1) * charheight + offsety;
_underlineNode->drawLine(Vec2(_linesOffsetX[i],y), Vec2(_linesWidth[i] + _linesOffsetX[i],y), _textColorF);
}
}
if(updateFinished){
_contentDirty = false;
}
@ -1327,16 +1426,16 @@ float Label::getBMFontSize()const
return _bmFontSize;
}
void Label::onDrawShadow(GLProgram* glProgram)
void Label::onDrawShadow(GLProgram* glProgram, const Color4F& shadowColor)
{
if (_currentLabelType == LabelType::TTF)
{
glProgram->setUniformLocationWith4f(_uniformTextColor,
_shadowColor4F.r, _shadowColor4F.g, _shadowColor4F.b, _shadowColor4F.a);
shadowColor.r, shadowColor.g, shadowColor.b, shadowColor.a);
if (_currLabelEffect == LabelEffect::OUTLINE || _currLabelEffect == LabelEffect::GLOW)
{
glProgram->setUniformLocationWith4f(_uniformEffectColor,
_shadowColor4F.r, _shadowColor4F.g, _shadowColor4F.b, _shadowColor4F.a);
shadowColor.r, shadowColor.g, shadowColor.b, shadowColor.a);
}
glProgram->setUniformsForBuiltins(_shadowTransform);
@ -1353,8 +1452,8 @@ void Label::onDrawShadow(GLProgram* glProgram)
{
Color3B oldColor = _realColor;
GLubyte oldOPacity = _displayedOpacity;
_displayedOpacity = _shadowOpacity;
setColor(_shadowColor3B);
_displayedOpacity = shadowColor.a * 255;
setColor(Color3B(shadowColor));
glProgram->setUniformsForBuiltins(_shadowTransform);
for (auto&& it : _letters)
@ -1379,7 +1478,10 @@ void Label::onDraw(const Mat4& transform, bool transformUpdated)
if (_shadowEnabled)
{
onDrawShadow(glprogram);
if (_boldEnabled)
onDrawShadow(glprogram, _textColorF);
else
onDrawShadow(glprogram, _shadowColor4F);
}
glprogram->setUniformsForBuiltins(transform);
@ -1672,18 +1774,21 @@ float Label::getLineSpacing() const
void Label::setAdditionalKerning(float space)
{
CCASSERT(_currentLabelType != LabelType::STRING_TEXTURE, "Not supported system font!");
if (_additionalKerning != space)
if (_currentLabelType != LabelType::STRING_TEXTURE)
{
_additionalKerning = space;
_contentDirty = true;
if (_additionalKerning != space)
{
_additionalKerning = space;
_contentDirty = true;
}
}
else
CCLOG("Label::setAdditionalKerning not supported on LabelType::STRING_TEXTURE");
}
float Label::getAdditionalKerning() const
{
CCASSERT(_currentLabelType != LabelType::STRING_TEXTURE, "Not supported system font!");
return _additionalKerning;
}

View File

@ -55,14 +55,24 @@ typedef struct _ttfConfig
bool distanceFieldEnabled;
int outlineSize;
bool italics;
bool bold;
bool underline;
bool strikethrough;
_ttfConfig(const std::string& filePath = "",float size = 12, const GlyphCollection& glyphCollection = GlyphCollection::DYNAMIC,
const char *customGlyphCollection = nullptr, bool useDistanceField = false, int outline = 0)
const char *customGlyphCollection = nullptr, bool useDistanceField = false, int outline = 0,
bool useItalics = false, bool useBold = false, bool useUnderline = false, bool useStrikethrough = false)
: fontFilePath(filePath)
, fontSize(size)
, glyphs(glyphCollection)
, customGlyphs(customGlyphCollection)
, distanceFieldEnabled(useDistanceField)
, outlineSize(outline)
, italics(useItalics)
, bold(useBold)
, underline(useUnderline)
, strikethrough(useStrikethrough)
{
if(outline > 0)
{
@ -336,6 +346,27 @@ public:
*/
virtual void enableGlow(const Color4B& glowColor);
/**
* Enable italics rendering
*/
void enableItalics();
/**
* Enable bold rendering
*/
void enableBold();
/**
* Enable underline
*/
void enableUnderline();
/**
* Enables strikethrough.
* Underline and Strikethrough cannot be enabled at the same time.
* Strikethough is like an underline but at the middle of the glyph
*/
void enableStrikethrough();
/**
* Disable all effect to Label.
* @warning Please use disableEffect(LabelEffect::ALL) instead of this API.
@ -605,7 +636,7 @@ protected:
void computeStringNumLines();
void onDraw(const Mat4& transform, bool transformUpdated);
void onDrawShadow(GLProgram* glProgram);
void onDrawShadow(GLProgram* glProgram, const Color4F& shadowColor);
void drawSelf(bool visibleByCamera, Renderer* renderer, uint32_t flags);
bool multilineTextWrapByChar();
@ -735,6 +766,11 @@ protected:
float _bmfontScale;
Overflow _overflow;
float _originalFontSize;
bool _boldEnabled;
DrawNode* _underlineNode;
bool _strikethroughEnabled;
private:
CC_DISALLOW_COPY_AND_ASSIGN(Label);
};

View File

@ -570,14 +570,19 @@ public:
};
/**
* @brief Possible LabelEffect used by Label.
* @brief Effects used by `Label`
*
*/
enum class LabelEffect {
// FIXME: Covert them to bitwise. More than one effect should be supported
NORMAL,
OUTLINE,
SHADOW,
GLOW,
ITALICS,
BOLD,
UNDERLINE,
STRIKETHROUGH,
ALL
};

View File

@ -23,7 +23,15 @@
****************************************************************************/
#include "UIRichText.h"
#include <vector>
#include "tinyxml2/tinyxml2.h"
#include "platform/CCFileUtils.h"
#include "platform/CCApplication.h"
#include "base/CCEventListenerTouch.h"
#include "base/CCEventDispatcher.h"
#include "base/CCDirector.h"
#include "2d/CCLabel.h"
#include "2d/CCSprite.h"
#include "base/ccUTF8.h"
@ -32,8 +40,52 @@
NS_CC_BEGIN
namespace ui {
class ListenerComponent : public Component
{
public:
static ListenerComponent* create(Label* parent, const std::string& url)
{
auto component = new (std::nothrow) ListenerComponent(parent, url);
component->autorelease();
return component;
}
explicit ListenerComponent(Label* parent, const std::string& url)
: _parent(parent)
, _url(url)
{
_touchListener = cocos2d::EventListenerTouchAllAtOnce::create();
_touchListener->onTouchesEnded = CC_CALLBACK_2(ListenerComponent::onTouchesEnded, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(_touchListener, _parent);
_touchListener->retain();
}
virtual ~ListenerComponent()
{
Director::getInstance()->getEventDispatcher()->removeEventListener(_touchListener);
_touchListener->release();
}
void onTouchesEnded(const std::vector<Touch*>& touches, Event *event)
{
for (const auto& touch: touches)
{
// FIXME: Node::getBoundBox() doesn't return it in local coordinates... so create one manually.
Rect localRect = Rect(Vec2::ZERO, _parent->getContentSize());
if (localRect.containsPoint(_parent->convertTouchToNodeSpace(touch)))
Application::getInstance()->openURL(_url);
}
}
private:
Label* _parent; // weak ref.
std::string _url;
EventDispatcher* _eventDispatcher; // weak ref.
EventListenerTouchAllAtOnce* _touchListener; // strong ref.
};
bool RichElement::init(int tag, const Color3B &color, GLubyte opacity)
{
_tag = tag;
@ -43,10 +95,10 @@ bool RichElement::init(int tag, const Color3B &color, GLubyte opacity)
}
RichElementText* RichElementText::create(int tag, const Color3B &color, GLubyte opacity, const std::string& text, const std::string& fontName, float fontSize)
RichElementText* RichElementText::create(int tag, const Color3B &color, GLubyte opacity, const std::string& text, const std::string& fontName, float fontSize, uint32_t flags, const std::string& url)
{
RichElementText* element = new (std::nothrow) RichElementText();
if (element && element->init(tag, color, opacity, text, fontName, fontSize))
if (element && element->init(tag, color, opacity, text, fontName, fontSize, flags, url))
{
element->autorelease();
return element;
@ -55,13 +107,15 @@ RichElementText* RichElementText::create(int tag, const Color3B &color, GLubyte
return nullptr;
}
bool RichElementText::init(int tag, const Color3B &color, GLubyte opacity, const std::string& text, const std::string& fontName, float fontSize)
bool RichElementText::init(int tag, const Color3B &color, GLubyte opacity, const std::string& text, const std::string& fontName, float fontSize, uint32_t flags, const std::string& url)
{
if (RichElement::init(tag, color, opacity))
{
_text = text;
_fontName = fontName;
_fontSize = fontSize;
_flags = flags;
_url = url;
return true;
}
return false;
@ -84,10 +138,21 @@ bool RichElementImage::init(int tag, const Color3B &color, GLubyte opacity, cons
if (RichElement::init(tag, color, opacity))
{
_filePath = filePath;
_width = -1;
_height = -1;
return true;
}
return false;
}
void RichElementImage::setWidth(int width)
{
_width = width;
}
void RichElementImage::setHeight(int height)
{
_height = height;
}
RichElementCustomNode* RichElementCustomNode::create(int tag, const Color3B &color, GLubyte opacity, cocos2d::Node *customNode)
{
@ -148,6 +213,18 @@ RichText* RichText::create()
CC_SAFE_DELETE(widget);
return nullptr;
}
RichText* RichText::createWithXML(const std::string& xml)
{
RichText* widget = new (std::nothrow) RichText();
if (widget && widget->initWithXML(xml))
{
widget->autorelease();
return widget;
}
CC_SAFE_DELETE(widget);
return nullptr;
}
bool RichText::init()
{
@ -157,6 +234,307 @@ bool RichText::init()
}
return false;
}
class MyXMLVisitor: public tinyxml2::XMLVisitor
{
struct Attributes
{
std::string face;
std::string url;
float fontSize;
Color3B color;
bool hasColor;
bool bold;
bool italics;
bool underline;
bool strikethrough;
void setColor(const Color3B& acolor)
{
color = acolor;
hasColor = true;
}
Attributes()
: bold(false)
, italics(false)
, underline(false)
, strikethrough(false)
, hasColor(false)
, fontSize(-1)
{
}
};
std::vector<Attributes> _fontElements;
RichText* _richText;
Color3B getColor() const
{
for (auto i = _fontElements.rbegin(); i != _fontElements.rend(); ++i)
{
if (i->hasColor)
return i->color;
}
return Color3B::WHITE;
}
float getFontSize() const
{
for (auto i = _fontElements.rbegin(); i != _fontElements.rend(); ++i)
{
if (i->fontSize != -1)
return i->fontSize;
}
return 12;
}
std::string getFace() const
{
for (auto i = _fontElements.rbegin(); i != _fontElements.rend(); ++i)
{
if (i->face.size() != 0)
return i->face;
}
return "fonts/Marker Felt.ttf";
}
std::string getURL() const
{
for (auto i = _fontElements.rbegin(); i != _fontElements.rend(); ++i)
{
if (i->url.size() != 0)
return i->url;
}
return "";
}
bool getBold() const
{
for (auto i = _fontElements.rbegin(); i != _fontElements.rend(); ++i)
{
if (i->bold)
return true;
}
return false;
}
bool getItalics() const
{
for (auto i = _fontElements.rbegin(); i != _fontElements.rend(); ++i)
{
if (i->italics)
return true;
}
return false;
}
bool getUnderline() const
{
for (auto i = _fontElements.rbegin(); i != _fontElements.rend(); ++i)
{
if (i->underline)
return true;
}
return false;
}
bool getStrikethrough() const
{
for (auto i = _fontElements.rbegin(); i != _fontElements.rend(); ++i)
{
if (i->strikethrough)
return true;
}
return false;
}
public:
explicit MyXMLVisitor(RichText* richText)
: _richText(richText)
, _fontElements(20)
{}
virtual ~MyXMLVisitor() {}
/// Visit an element.
virtual bool VisitEnter( const tinyxml2::XMLElement& element, const tinyxml2::XMLAttribute* firstAttribute )
{
auto elementName = element.Value();
if (strcmp(elementName, "font") == 0)
{
// supported attributes:
// size, color, align, face
auto size = element.Attribute("size");
auto color = element.Attribute("color");
auto face = element.Attribute("face");
Attributes attribs;
if (size)
attribs.fontSize = atof(size);
if (color)
{
if (strlen(color) == 7)
{
int r,g,b;
sscanf(color, "%*c%2x%2x%2x", &r, &g, &b);
attribs.setColor(Color3B(r,g,b));
}
else
attribs.setColor(Color3B::WHITE);
}
if (face)
attribs.face = face;
_fontElements.push_back(attribs);
}
else if (strcmp(elementName, "b") == 0)
{
// no supported attributes
Attributes attribs;
attribs.bold = 1;
_fontElements.push_back(attribs);
}
else if (strcmp(elementName, "i") == 0)
{
// no supported attributes
Attributes attribs;
attribs.italics = 1;
_fontElements.push_back(attribs);
}
else if (strcmp(elementName, "del") == 0)
{
// no supported attributes
Attributes attribs;
attribs.strikethrough = true;
_fontElements.push_back(attribs);
}
else if (strcmp(elementName, "u") == 0)
{
// no supported attributes
Attributes attribs;
attribs.underline = true;
_fontElements.push_back(attribs);
}
else if (strcmp(elementName, "small") == 0)
{
Attributes attribs;
attribs.fontSize = getFontSize() * 0.8;
_fontElements.push_back(attribs);
}
else if (strcmp(elementName, "big") == 0)
{
Attributes attribs;
attribs.fontSize = getFontSize() * 1.25;
_fontElements.push_back(attribs);
}
else if (strcmp(elementName, "img") == 0)
{
// supported attributes:
// src, height, width
auto src = element.Attribute("src");
auto height = element.Attribute("height");
auto width = element.Attribute("width");
if (src) {
auto elementNL = RichElementImage::create(0, getColor(), 255, src);
if (height)
elementNL->setHeight(atoi(height));
if (width)
elementNL->setWidth(atoi(width));
_richText->pushBackElement(elementNL);
}
}
else if (strcmp(elementName, "a") == 0)
{
// supported attributes:
Attributes attribs;
auto href = element.Attribute("href");
attribs.setColor(Color3B::BLUE);
attribs.underline = true;
attribs.url = href;
_fontElements.push_back(attribs);
}
else if (strcmp(elementName, "br") == 0)
{
auto color = getColor();
auto elementNL = RichElementNewLine::create(0, color, 255);
_richText->pushBackElement(elementNL);
}
return true;
}
/// Visit an element.
virtual bool VisitExit( const tinyxml2::XMLElement& element )
{
auto elementName = element.Value();
if ((strcmp(elementName, "font") == 0) ||
(strcmp(elementName, "i") == 0) ||
(strcmp(elementName, "b") == 0) ||
(strcmp(elementName, "del") == 0) ||
(strcmp(elementName, "u") == 0) ||
(strcmp(elementName, "small") == 0) ||
(strcmp(elementName, "big") == 0) ||
(strcmp(elementName, "a") == 0))
{
_fontElements.pop_back();
}
return true;
}
/// Visit a text node.
virtual bool Visit(const tinyxml2::XMLText& text)
{
auto color = getColor();
auto face = getFace();
auto fontSize = getFontSize();
auto italics = getItalics();
auto underline = getUnderline();
auto strikethrough = getStrikethrough();
auto bold = getBold();
auto url = getURL();
uint32_t flags = 0;
if (italics)
flags |= RichElementText::ITALICS_FLAG;
if (bold)
flags |= RichElementText::BOLD_FLAG;
if (underline)
flags |= RichElementText::UNDERLINE_FLAG;
if (strikethrough)
flags |= RichElementText::STRIKETHROUGH_FLAG;
if (url.size() > 0)
flags |= RichElementText::URL_FLAG;
auto element = RichElementText::create(0, color, 255, text.Value(), face, fontSize, flags, url);
_richText->pushBackElement(element);
return true;
}
};
bool RichText::initWithXML(const std::string& origxml)
{
if (Widget::init())
{
tinyxml2::XMLDocument document;
// solves to issues:
// - creates defaults values
// - makes sure that the xml well formed and starts with an element
auto xml = "<font face=\"Verdana\" size=\"12\" color=\"#ffffff\">" + origxml + "</font>";
if (document.Parse(xml.c_str(), xml.length()) == tinyxml2::XML_SUCCESS)
{
MyXMLVisitor visitor(this);
document.Accept(&visitor);
return true;
}
}
return false;
}
void RichText::initRenderer()
{
@ -204,20 +582,42 @@ void RichText::formatText()
case RichElement::Type::TEXT:
{
RichElementText* elmtText = static_cast<RichElementText*>(element);
Label* label;
if (FileUtils::getInstance()->isFileExist(elmtText->_fontName))
{
elementRenderer = Label::createWithTTF(elmtText->_text.c_str(), elmtText->_fontName, elmtText->_fontSize);
label = Label::createWithTTF(elmtText->_text, elmtText->_fontName, elmtText->_fontSize);
}
else
{
elementRenderer = Label::createWithSystemFont(elmtText->_text.c_str(), elmtText->_fontName, elmtText->_fontSize);
label = Label::createWithSystemFont(elmtText->_text, elmtText->_fontName, elmtText->_fontSize);
}
if (elmtText->_flags & RichElementText::ITALICS_FLAG)
label->enableItalics();
if (elmtText->_flags & RichElementText::BOLD_FLAG)
label->enableBold();
if (elmtText->_flags & RichElementText::UNDERLINE_FLAG)
label->enableUnderline();
if (elmtText->_flags & RichElementText::STRIKETHROUGH_FLAG)
label->enableStrikethrough();
if (elmtText->_flags & RichElementText::URL_FLAG)
label->addComponent(ListenerComponent::create(label, elmtText->_url));
elementRenderer = label;
break;
}
case RichElement::Type::IMAGE:
{
RichElementImage* elmtImage = static_cast<RichElementImage*>(element);
elementRenderer = Sprite::create(elmtImage->_filePath.c_str());
elementRenderer = Sprite::create(elmtImage->_filePath);
if (elementRenderer && (elmtImage->_height != -1 || elmtImage->_width != -1))
{
auto currentSize = elementRenderer->getContentSize();
if (elmtImage->_width != -1)
elementRenderer->setScaleX(elmtImage->_width / currentSize.width);
if (elmtImage->_height != -1)
elementRenderer->setScaleY(elmtImage->_height / currentSize.height);
elementRenderer->setContentSize(Size(currentSize.width * elementRenderer->getScaleX(),
currentSize.height * elementRenderer->getScaleY()));
}
break;
}
case RichElement::Type::CUSTOM:
@ -234,9 +634,13 @@ void RichText::formatText()
default:
break;
}
elementRenderer->setColor(element->_color);
elementRenderer->setOpacity(element->_opacity);
pushToContainer(elementRenderer);
if (elementRenderer)
{
elementRenderer->setColor(element->_color);
elementRenderer->setOpacity(element->_opacity);
pushToContainer(elementRenderer);
}
}
}
else
@ -244,20 +648,19 @@ void RichText::formatText()
addNewLine();
for (ssize_t i=0; i<_richElements.size(); i++)
{
RichElement* element = static_cast<RichElement*>(_richElements.at(i));
switch (element->_type)
{
case RichElement::Type::TEXT:
{
RichElementText* elmtText = static_cast<RichElementText*>(element);
handleTextRenderer(elmtText->_text.c_str(), elmtText->_fontName.c_str(), elmtText->_fontSize, elmtText->_color, elmtText->_opacity);
handleTextRenderer(elmtText->_text, elmtText->_fontName, elmtText->_fontSize, elmtText->_color, elmtText->_opacity, elmtText->_flags, elmtText->_url);
break;
}
case RichElement::Type::IMAGE:
{
RichElementImage* elmtImage = static_cast<RichElementImage*>(element);
handleImageRenderer(elmtImage->_filePath.c_str(), elmtImage->_color, elmtImage->_opacity);
handleImageRenderer(elmtImage->_filePath, elmtImage->_color, elmtImage->_opacity, elmtImage->_width, elmtImage->_height);
break;
}
case RichElement::Type::CUSTOM:
@ -280,8 +683,8 @@ void RichText::formatText()
_formatTextDirty = false;
}
}
void RichText::handleTextRenderer(const std::string& text, const std::string& fontName, float fontSize, const Color3B &color, GLubyte opacity)
void RichText::handleTextRenderer(const std::string& text, const std::string& fontName, float fontSize, const Color3B &color, GLubyte opacity, uint32_t flags, const std::string& url)
{
auto fileExist = FileUtils::getInstance()->isFileExist(fontName);
Label* textRenderer = nullptr;
@ -293,6 +696,17 @@ void RichText::handleTextRenderer(const std::string& text, const std::string& fo
{
textRenderer = Label::createWithSystemFont(text, fontName, fontSize);
}
if (flags & RichElementText::ITALICS_FLAG)
textRenderer->enableItalics();
if (flags & RichElementText::BOLD_FLAG)
textRenderer->enableBold();
if (flags & RichElementText::UNDERLINE_FLAG)
textRenderer->enableUnderline();
if (flags & RichElementText::STRIKETHROUGH_FLAG)
textRenderer->enableStrikethrough();
if (flags & RichElementText::URL_FLAG)
textRenderer->addComponent(ListenerComponent::create(textRenderer, url));
float textRendererWidth = textRenderer->getContentSize().width;
_leftSpaceWidth -= textRendererWidth;
if (_leftSpaceWidth < 0.0f)
@ -359,11 +773,23 @@ void RichText::handleTextRenderer(const std::string& text, const std::string& fo
leftRenderer->setColor(color);
leftRenderer->setOpacity(opacity);
pushToContainer(leftRenderer);
if (flags & RichElementText::ITALICS_FLAG)
leftRenderer->enableItalics();
if (flags & RichElementText::BOLD_FLAG)
leftRenderer->enableBold();
if (flags & RichElementText::UNDERLINE_FLAG)
leftRenderer->enableUnderline();
if (flags & RichElementText::STRIKETHROUGH_FLAG)
leftRenderer->enableStrikethrough();
if (flags & RichElementText::URL_FLAG)
leftRenderer->addComponent(ListenerComponent::create(leftRenderer, url));
}
}
addNewLine();
handleTextRenderer(cutWords.c_str(), fontName, fontSize, color, opacity);
handleTextRenderer(cutWords, fontName, fontSize, color, opacity, flags, url);
}
else
{
@ -373,12 +799,23 @@ void RichText::handleTextRenderer(const std::string& text, const std::string& fo
}
}
void RichText::handleImageRenderer(const std::string& fileParh, const Color3B &color, GLubyte opacity)
void RichText::handleImageRenderer(const std::string& filePath, const Color3B &color, GLubyte opacity, int width, int height)
{
Sprite* imageRenderer = Sprite::create(fileParh);
Sprite* imageRenderer = Sprite::create(filePath);
if (imageRenderer)
{
auto currentSize = imageRenderer->getContentSize();
if (width != -1)
imageRenderer->setScaleX(width / currentSize.width);
if (height != -1)
imageRenderer->setScaleY(height / currentSize.height);
imageRenderer->setContentSize(Size(currentSize.width * imageRenderer->getScaleX(),
currentSize.height * imageRenderer->getScaleY()));
}
handleCustomRenderer(imageRenderer);
}
void RichText::handleCustomRenderer(cocos2d::Node *renderer)
{
Size imgSize = renderer->getContentSize();
@ -406,22 +843,26 @@ void RichText::formarRenderers()
if (_ignoreSize)
{
float newContentSizeWidth = 0.0f;
float newContentSizeHeight = 0.0f;
Vector<Node*>* row = (_elementRenders[0]);
float nextPosX = 0.0f;
for (ssize_t j=0; j<row->size(); j++)
float nextPosY = 0.0f;
for (auto& element: _elementRenders)
{
Node* l = row->at(j);
l->setAnchorPoint(Vec2::ZERO);
l->setPosition(nextPosX, 0.0f);
this->addProtectedChild(l, 1);
Size iSize = l->getContentSize();
newContentSizeWidth += iSize.width;
newContentSizeHeight = MAX(newContentSizeHeight, iSize.height);
nextPosX += iSize.width;
Vector<Node*>* row = element;
float nextPosX = 0.0f;
float maxY = 0.0f;
for (ssize_t j=0; j<row->size(); j++)
{
Node* l = row->at(j);
l->setAnchorPoint(Vec2::ZERO);
l->setPosition(nextPosX, nextPosY);
this->addProtectedChild(l, 1);
Size iSize = l->getContentSize();
newContentSizeWidth += iSize.width;
nextPosX += iSize.width;
maxY = MAX(maxY, iSize.height);
}
nextPosY -= maxY;
}
this->setContentSize(Size(newContentSizeWidth, newContentSizeHeight));
this->setContentSize(Size(newContentSizeWidth, -nextPosY));
}
else
{

View File

@ -98,8 +98,16 @@ public:
* @js ctor
* @lua new
*/
RichElementText(){_type = Type::TEXT;};
RichElementText()
{_type = Type::TEXT;};
enum {
ITALICS_FLAG = 1 << 0,
BOLD_FLAG = 1 << 1,
UNDERLINE_FLAG = 1 << 2,
STRIKETHROUGH_FLAG = 1 << 3,
URL_FLAG = 1 << 4
};
/**
*@brief Default destructor.
@ -117,9 +125,10 @@ public:
* @param text Content string.
* @param fontName Content font name.
* @param fontSize Content font size.
* @param flags: italics, bold, underline or strikethrough
* @return True if initialize success, false otherwise.
*/
bool init(int tag, const Color3B& color, GLubyte opacity, const std::string& text, const std::string& fontName, float fontSize);
bool init(int tag, const Color3B& color, GLubyte opacity, const std::string& text, const std::string& fontName, float fontSize, uint32_t flags, const std::string& url);
/**
@ -131,13 +140,17 @@ public:
* @param text Content string.
* @param fontName Content font name.
* @param fontSize Content font size.
* @param flags: italics, bold, underline or strikethrough
* @return RichElementText instance.
*/
static RichElementText* create(int tag, const Color3B& color, GLubyte opacity, const std::string& text, const std::string& fontName, float fontSize);
static RichElementText* create(int tag, const Color3B& color, GLubyte opacity, const std::string& text,
const std::string& fontName, float fontSize, uint32_t flags=0, const std::string& url="");
protected:
std::string _text;
std::string _fontName;
float _fontSize;
uint32_t _flags;
std::string _url;
friend class RichText;
};
@ -188,11 +201,16 @@ public:
* @return A RichElementImage instance.
*/
static RichElementImage* create(int tag, const Color3B& color, GLubyte opacity, const std::string& filePath);
void setWidth(int width);
void setHeight(int height);
protected:
std::string _filePath;
Rect _textureRect;
int _textureType;
friend class RichText;
int _width;
int _height;
};
/**
@ -307,7 +325,14 @@ public:
* @return RichText instance.
*/
static RichText* create();
/**
* @brief Create a RichText from an XML
*
* @return RichText instance.
*/
static RichText* createWithXML(const std::string& xml);
/**
* @brief Insert a RichElement at a given index.
*
@ -356,14 +381,16 @@ public:
CC_CONSTRUCTOR_ACCESS:
virtual bool init() override;
bool initWithXML(const std::string& xml);
protected:
virtual void adaptRenderers() override;
virtual void initRenderer() override;
void pushToContainer(Node* renderer);
void handleTextRenderer(const std::string& text, const std::string& fontName, float fontSize, const Color3B& color, GLubyte opacity);
void handleImageRenderer(const std::string& fileParh, const Color3B& color, GLubyte opacity);
void handleTextRenderer(const std::string& text, const std::string& fontName, float fontSize, const Color3B& color, GLubyte opacity, uint32_t flags, const std::string& url="");
void handleImageRenderer(const std::string& fileParh, const Color3B& color, GLubyte opacity, int width, int height);
void handleCustomRenderer(Node* renderer);
void formarRenderers();
void addNewLine();

View File

@ -98,6 +98,13 @@ NewLabelTests::NewLabelTests()
ADD_TEST_CASE(LabelSystemFontTest);
ADD_TEST_CASE(LabelCharMapFontTest);
ADD_TEST_CASE(LabelIssue13846Test);
ADD_TEST_CASE(LabelRichText);
ADD_TEST_CASE(LabelStrikethrough);
ADD_TEST_CASE(LabelUnderline);
ADD_TEST_CASE(LabelUnderlineMultiline);
ADD_TEST_CASE(LabelItalics);
ADD_TEST_CASE(LabelBold);
};
LabelFNTColorAndOpacity::LabelFNTColorAndOpacity()
@ -2781,3 +2788,268 @@ std::string LabelIssue13846Test::subtitle() const
{
return "Test hide label's letter,the label should display 12 45 as expected";
}
//
//
LabelRichText::LabelRichText()
{
auto center = VisibleRect::center();
auto richText2 = RichText::createWithXML("Mixing <b>UIRichText</b> with non <i>UIWidget</i> code. For more samples, see the UIRichTextTest.cpp file");
if (richText2)
{
richText2->ignoreContentAdaptWithSize(false);
richText2->setContentSize(Size(400, 400));
addChild(richText2);
richText2->setPosition(Vec2(200,0));
}
}
std::string LabelRichText::title() const
{
return "RichText";
}
std::string LabelRichText::subtitle() const
{
return "Testing RichText";
}
LabelItalics::LabelItalics()
{
auto s = Director::getInstance()->getWinSize();
// LabelBMFont
auto label1 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "hello non-italics", TextHAlignment::CENTER, s.width);
addChild(label1, 0, kTagBitmapAtlas1);
label1->setPosition(Vec2(s.width/2, s.height*4/6));
// you can enable italics by calling this method
_label1a = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "hello italics", TextHAlignment::CENTER, s.width);
addChild(_label1a, 0, kTagBitmapAtlas1);
_label1a->setPosition(Vec2(s.width/2, s.height*3/6));
// you can enable italics by calling this method
_label1a->enableItalics();
// LabelTTF
TTFConfig ttfConfig("fonts/arial.ttf",24);
auto label2 = Label::createWithTTF(ttfConfig, "hello non-italics", TextHAlignment::CENTER,s.width);
addChild(label2, 0, kTagBitmapAtlas2);
label2->setPosition(Vec2(s.width/2, s.height*2/6));
// or by setting the italics parameter on TTFConfig
ttfConfig.italics = true;
_label2a = Label::createWithTTF(ttfConfig, "hello italics", TextHAlignment::CENTER,s.width);
addChild(_label2a, 0, kTagBitmapAtlas2);
_label2a->setPosition(Vec2(s.width/2, s.height*1/6));
auto menuItem = MenuItemFont::create("disable italics", [&](cocos2d::Ref* sender) {
_label2a->disableEffect(LabelEffect::ITALICS);
_label1a->disableEffect(LabelEffect::ITALICS);
});
menuItem->setFontSizeObj(12);
auto menu = Menu::createWithItem(menuItem);
addChild(menu);
auto winSize = Director::getInstance()->getWinSize();
menu->setPosition(winSize.width * 0.9, winSize.height * 0.25f);
}
std::string LabelItalics::title() const
{
return "Testing Italics";
}
std::string LabelItalics::subtitle() const
{
return "italics on TTF and BMfont";
}
///
LabelBold::LabelBold()
{
auto s = Director::getInstance()->getWinSize();
// LabelBMFont
auto label1 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "hello non-bold", TextHAlignment::CENTER, s.width);
addChild(label1, 0, kTagBitmapAtlas1);
label1->setPosition(Vec2(s.width/2, s.height*4/6));
// you can enable italics by calling this method
_label1a = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "hello bold", TextHAlignment::CENTER, s.width);
addChild(_label1a, 0, kTagBitmapAtlas1);
_label1a->setPosition(Vec2(s.width/2, s.height*3/6));
// you can enable italics by calling this method
_label1a->enableBold();
// LabelTTF
TTFConfig ttfConfig("fonts/arial.ttf",24);
auto label2 = Label::createWithTTF(ttfConfig, "hello non-bold", TextHAlignment::CENTER,s.width);
addChild(label2, 0, kTagBitmapAtlas2);
label2->setPosition(Vec2(s.width/2, s.height*2/6));
// or by setting the italics parameter on TTFConfig
ttfConfig.bold = true;
_label2a = Label::createWithTTF(ttfConfig, "hello bold", TextHAlignment::CENTER,s.width);
addChild(_label2a, 0, kTagBitmapAtlas2);
_label2a->setPosition(Vec2(s.width/2, s.height*1/6));
auto menuItem = MenuItemFont::create("disable bold", [&](cocos2d::Ref* sender) {
_label2a->disableEffect(LabelEffect::BOLD);
_label1a->disableEffect(LabelEffect::BOLD);
});
menuItem->setFontSizeObj(12);
auto menu = Menu::createWithItem(menuItem);
addChild(menu);
auto winSize = Director::getInstance()->getWinSize();
menu->setPosition(winSize.width * 0.9, winSize.height * 0.25f);
}
std::string LabelBold::title() const
{
return "Testing Bold";
}
std::string LabelBold::subtitle() const
{
return "Bold on TTF and BMfont";
}
///
LabelUnderline::LabelUnderline()
{
auto s = Director::getInstance()->getWinSize();
// LabelBMFont
auto label1 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "hello non-underline", TextHAlignment::CENTER, s.width);
addChild(label1, 0, kTagBitmapAtlas1);
label1->setPosition(Vec2(s.width/2, s.height*4/6));
// you can enable italics by calling this method
_label1a = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "hello underline", TextHAlignment::CENTER, s.width);
addChild(_label1a, 0, kTagBitmapAtlas1);
_label1a->setPosition(Vec2(s.width/2, s.height*3/6));
// you can enable underline by calling this method
_label1a->enableUnderline();
// LabelTTF
TTFConfig ttfConfig("fonts/arial.ttf",24);
auto label2 = Label::createWithTTF(ttfConfig, "hello non-underline", TextHAlignment::CENTER,s.width);
addChild(label2, 0, kTagBitmapAtlas2);
label2->setPosition(Vec2(s.width/2, s.height*2/6));
// or by setting the italics parameter on TTFConfig
ttfConfig.underline = true;
_label2a = Label::createWithTTF(ttfConfig, "hello underline", TextHAlignment::CENTER,s.width);
addChild(_label2a, 0, kTagBitmapAtlas2);
_label2a->setPosition(Vec2(s.width/2, s.height*1/6));
auto menuItem = MenuItemFont::create("disable underline", [&](cocos2d::Ref* sender) {
_label2a->disableEffect(LabelEffect::UNDERLINE);
_label1a->disableEffect(LabelEffect::UNDERLINE);
});
menuItem->setFontSizeObj(12);
auto menu = Menu::createWithItem(menuItem);
addChild(menu);
auto winSize = Director::getInstance()->getWinSize();
menu->setPosition(winSize.width * 0.9, winSize.height * 0.25f);
}
std::string LabelUnderline::title() const
{
return "Testing Underline";
}
std::string LabelUnderline::subtitle() const
{
return "Underline on TTF and BMfont";
}
///
LabelUnderlineMultiline::LabelUnderlineMultiline()
{
auto s = Director::getInstance()->getWinSize();
// bmfont
_label1a = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "hello underline\nand multiline", TextHAlignment::CENTER, s.width);
addChild(_label1a, 0, kTagBitmapAtlas1);
_label1a->setPosition(Vec2(s.width/2, s.height*2/3));
// you can enable underline by calling this method
_label1a->enableUnderline();
// ttf
TTFConfig ttfConfig("fonts/arial.ttf",24);
ttfConfig.underline = true;
_label2a = Label::createWithTTF(ttfConfig, "hello\nunderline\nwith multiline", TextHAlignment::LEFT, s.width);
addChild(_label2a, 0, kTagBitmapAtlas2);
_label2a->setPosition(Vec2(s.width/2, s.height*1/3));
auto menuItem = MenuItemFont::create("disable underline", [&](cocos2d::Ref* sender) {
_label2a->disableEffect(LabelEffect::UNDERLINE);
_label1a->disableEffect(LabelEffect::UNDERLINE);
});
menuItem->setFontSizeObj(12);
auto menu = Menu::createWithItem(menuItem);
addChild(menu);
auto winSize = Director::getInstance()->getWinSize();
menu->setPosition(winSize.width * 0.9, winSize.height * 0.25f);
}
std::string LabelUnderlineMultiline::title() const
{
return "Testing Underline + multiline";
}
std::string LabelUnderlineMultiline::subtitle() const
{
return "Underline on TTF and BMfont with multiline";
}
///
LabelStrikethrough::LabelStrikethrough()
{
auto s = Director::getInstance()->getWinSize();
// bmfont
_label1a = Label::createWithBMFont("fonts/bitmapFontTest4.fnt", "hello strikethrough\nand multiline", TextHAlignment::LEFT, s.width);
addChild(_label1a, 0, kTagBitmapAtlas1);
_label1a->setPosition(Vec2(s.width/2, s.height*2/3));
// you can enable underline by calling this method
_label1a->enableStrikethrough();
// ttf
TTFConfig ttfConfig("fonts/arial.ttf",24);
ttfConfig.strikethrough = true;
_label2a = Label::createWithTTF(ttfConfig, "hello\nstrikethrough\nwith multiline", TextHAlignment::RIGHT, s.width);
addChild(_label2a, 0, kTagBitmapAtlas2);
_label2a->setPosition(Vec2(s.width/2, s.height*1/3));
auto menuItem = MenuItemFont::create("disable underline", [&](cocos2d::Ref* sender) {
_label2a->disableEffect(LabelEffect::STRIKETHROUGH);
_label1a->disableEffect(LabelEffect::STRIKETHROUGH);
});
menuItem->setFontSizeObj(12);
auto menu = Menu::createWithItem(menuItem);
addChild(menu);
auto winSize = Director::getInstance()->getWinSize();
menu->setPosition(winSize.width * 0.9, winSize.height * 0.25f);
}
std::string LabelStrikethrough::title() const
{
return "Testing Strikethrough + multiline";
}
std::string LabelStrikethrough::subtitle() const
{
return "Strikethrough on TTF and BMfont with multiline";
}

View File

@ -767,4 +767,79 @@ public:
virtual std::string subtitle() const override;
};
class LabelRichText : public AtlasDemoNew
{
public:
CREATE_FUNC(LabelRichText);
LabelRichText();
virtual std::string title() const override;
virtual std::string subtitle() const override;
};
class LabelItalics : public AtlasDemoNew
{
public:
CREATE_FUNC(LabelItalics);
LabelItalics();
virtual std::string title() const override;
virtual std::string subtitle() const override;
cocos2d::Label* _label1a;
cocos2d::Label* _label2a;
};
class LabelBold : public AtlasDemoNew
{
public:
CREATE_FUNC(LabelBold);
LabelBold();
virtual std::string title() const override;
virtual std::string subtitle() const override;
cocos2d::Label* _label1a;
cocos2d::Label* _label2a;
};
class LabelUnderline : public AtlasDemoNew
{
public:
CREATE_FUNC(LabelUnderline);
LabelUnderline();
virtual std::string title() const override;
virtual std::string subtitle() const override;
cocos2d::Label* _label1a;
cocos2d::Label* _label2a;
};
class LabelUnderlineMultiline : public AtlasDemoNew
{
public:
CREATE_FUNC(LabelUnderlineMultiline);
LabelUnderlineMultiline();
virtual std::string title() const override;
virtual std::string subtitle() const override;
cocos2d::Label* _label1a;
cocos2d::Label* _label2a;
};
class LabelStrikethrough : public AtlasDemoNew
{
public:
CREATE_FUNC(LabelStrikethrough);
LabelStrikethrough();
virtual std::string title() const override;
virtual std::string subtitle() const override;
cocos2d::Label* _label1a;
cocos2d::Label* _label2a;
};
#endif

View File

@ -8,18 +8,22 @@ using namespace cocos2d::ui;
UIRichTextTests::UIRichTextTests()
{
ADD_TEST_CASE(UIRichTextTest);
ADD_TEST_CASE(UIRichTextXMLBasic);
ADD_TEST_CASE(UIRichTextXMLSmallBig);
ADD_TEST_CASE(UIRichTextXMLColor);
ADD_TEST_CASE(UIRichTextXMLSUIB);
ADD_TEST_CASE(UIRichTextXMLSUIB2);
ADD_TEST_CASE(UIRichTextXMLSUIB3);
ADD_TEST_CASE(UIRichTextXMLImg);
ADD_TEST_CASE(UIRichTextXMLUrl);
ADD_TEST_CASE(UIRichTextXMLFace);
ADD_TEST_CASE(UIRichTextXMLBR);
}
UIRichTextTest::UIRichTextTest()
{
}
UIRichTextTest::~UIRichTextTest()
{
}
//
// UIRichTextTest
//
bool UIRichTextTest::init()
{
if (UIScene::init())
@ -123,3 +127,673 @@ void UIRichTextTest::touchEvent(Ref *pSender, Widget::TouchEventType type)
break;
}
}
//
// UIRichTextXMLBasic
//
bool UIRichTextXMLBasic::init()
{
if (UIScene::init())
{
Size widgetSize = _widget->getContentSize();
// Add the alert
Text *alert = Text::create("RichText", "fonts/Marker Felt.ttf", 30);
alert->setColor(Color3B(159, 168, 176));
alert->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f - alert->getContentSize().height * 3.125));
_widget->addChild(alert);
Button* button = Button::create("cocosui/animationbuttonnormal.png", "cocosui/animationbuttonpressed.png");
button->setTouchEnabled(true);
button->setTitleText("switch");
button->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f + button->getContentSize().height * 2.5));
button->addTouchEventListener(CC_CALLBACK_2(UIRichTextXMLBasic::touchEvent, this));
button->setLocalZOrder(10);
_widget->addChild(button);
// RichText
_richText = RichText::createWithXML("This is just a simple text. no xml tags here. testing the basics. testing word-wrapping. testing, testing, testing");
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
_richText->setPosition(Vec2(widgetSize.width / 2, widgetSize.height / 2));
_richText->setLocalZOrder(10);
_widget->addChild(_richText);
// test remove all children, this call won't effect the test
_richText->removeAllChildren();
return true;
}
return false;
}
void UIRichTextXMLBasic::touchEvent(Ref *pSender, Widget::TouchEventType type)
{
switch (type)
{
case Widget::TouchEventType::ENDED:
{
if (_richText->isIgnoreContentAdaptWithSize())
{
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
}
else
{
_richText->ignoreContentAdaptWithSize(true);
}
}
break;
default:
break;
}
}
//
// UIRichTextXMLSmallBig
//
bool UIRichTextXMLSmallBig::init()
{
if (UIScene::init())
{
Size widgetSize = _widget->getContentSize();
// Add the alert
Text *alert = Text::create("RichText", "fonts/Marker Felt.ttf", 30);
alert->setColor(Color3B(159, 168, 176));
alert->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f - alert->getContentSize().height * 3.125));
_widget->addChild(alert);
Button* button = Button::create("cocosui/animationbuttonnormal.png", "cocosui/animationbuttonpressed.png");
button->setTouchEnabled(true);
button->setTitleText("switch");
button->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f + button->getContentSize().height * 2.5));
button->addTouchEventListener(CC_CALLBACK_2(UIRichTextXMLSmallBig::touchEvent, this));
button->setLocalZOrder(10);
_widget->addChild(button);
// RichText
_richText = RichText::createWithXML("Regular size.<small>smaller size.</small><big>bigger.<small>normal.</small>bigger</big>.normal.");
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
_richText->setPosition(Vec2(widgetSize.width / 2, widgetSize.height / 2));
_richText->setLocalZOrder(10);
_widget->addChild(_richText);
// test remove all children, this call won't effect the test
_richText->removeAllChildren();
return true;
}
return false;
}
void UIRichTextXMLSmallBig::touchEvent(Ref *pSender, Widget::TouchEventType type)
{
switch (type)
{
case Widget::TouchEventType::ENDED:
{
if (_richText->isIgnoreContentAdaptWithSize())
{
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
}
else
{
_richText->ignoreContentAdaptWithSize(true);
}
}
break;
default:
break;
}
}
//
// UIRichTextXMLColor
//
bool UIRichTextXMLColor::init()
{
if (UIScene::init())
{
Size widgetSize = _widget->getContentSize();
// Add the alert
Text *alert = Text::create("RichText", "fonts/Marker Felt.ttf", 30);
alert->setColor(Color3B(159, 168, 176));
alert->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f - alert->getContentSize().height * 3.125));
_widget->addChild(alert);
Button* button = Button::create("cocosui/animationbuttonnormal.png", "cocosui/animationbuttonpressed.png");
button->setTouchEnabled(true);
button->setTitleText("switch");
button->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f + button->getContentSize().height * 2.5));
button->addTouchEventListener(CC_CALLBACK_2(UIRichTextXMLColor::touchEvent, this));
button->setLocalZOrder(10);
_widget->addChild(button);
// RichText
_richText = RichText::createWithXML("Defaul color.<font color='#ff0000'>red.<font color='#00ff00'>green</font>red again.</font>default again");
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
_richText->setPosition(Vec2(widgetSize.width / 2, widgetSize.height / 2));
_richText->setLocalZOrder(10);
_widget->addChild(_richText);
// test remove all children, this call won't effect the test
_richText->removeAllChildren();
return true;
}
return false;
}
void UIRichTextXMLColor::touchEvent(Ref *pSender, Widget::TouchEventType type)
{
switch (type)
{
case Widget::TouchEventType::ENDED:
{
if (_richText->isIgnoreContentAdaptWithSize())
{
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
}
else
{
_richText->ignoreContentAdaptWithSize(true);
}
}
break;
default:
break;
}
}
//
// UIRichTextXMLSUIB
//
bool UIRichTextXMLSUIB::init()
{
if (UIScene::init())
{
Size widgetSize = _widget->getContentSize();
// Add the alert
Text *alert = Text::create("RichText", "fonts/Marker Felt.ttf", 30);
alert->setColor(Color3B(159, 168, 176));
alert->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f - alert->getContentSize().height * 3.125));
_widget->addChild(alert);
Button* button = Button::create("cocosui/animationbuttonnormal.png", "cocosui/animationbuttonpressed.png");
button->setTouchEnabled(true);
button->setTitleText("switch");
button->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f + button->getContentSize().height * 2.5));
button->addTouchEventListener(CC_CALLBACK_2(UIRichTextXMLSUIB::touchEvent, this));
button->setLocalZOrder(10);
_widget->addChild(button);
// RichText
_richText = RichText::createWithXML("system font: <u>underline</u><i>italics</i><b>bold</b><del>strike-through</del>");
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
_richText->setPosition(Vec2(widgetSize.width / 2, widgetSize.height / 2));
_richText->setLocalZOrder(10);
_widget->addChild(_richText);
// test remove all children, this call won't effect the test
_richText->removeAllChildren();
return true;
}
return false;
}
void UIRichTextXMLSUIB::touchEvent(Ref *pSender, Widget::TouchEventType type)
{
switch (type)
{
case Widget::TouchEventType::ENDED:
{
if (_richText->isIgnoreContentAdaptWithSize())
{
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
}
else
{
_richText->ignoreContentAdaptWithSize(true);
}
}
break;
default:
break;
}
}
//
// UIRichTextXMLSUIB2
//
bool UIRichTextXMLSUIB2::init()
{
if (UIScene::init())
{
Size widgetSize = _widget->getContentSize();
// Add the alert
Text *alert = Text::create("RichText", "fonts/Marker Felt.ttf", 30);
alert->setColor(Color3B(159, 168, 176));
alert->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f - alert->getContentSize().height * 3.125));
_widget->addChild(alert);
Button* button = Button::create("cocosui/animationbuttonnormal.png", "cocosui/animationbuttonpressed.png");
button->setTouchEnabled(true);
button->setTitleText("switch");
button->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f + button->getContentSize().height * 2.5));
button->addTouchEventListener(CC_CALLBACK_2(UIRichTextXMLSUIB2::touchEvent, this));
button->setLocalZOrder(10);
_widget->addChild(button);
// RichText
_richText = RichText::createWithXML("<font face='fonts/Marker Felt.ttf' size='24'>ttf font: <u>underline</u><i>italics</i><b>bold</b><del>strike-through</del></font>");
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
_richText->setPosition(Vec2(widgetSize.width / 2, widgetSize.height / 2));
_richText->setLocalZOrder(10);
_widget->addChild(_richText);
// test remove all children, this call won't effect the test
_richText->removeAllChildren();
return true;
}
return false;
}
void UIRichTextXMLSUIB2::touchEvent(Ref *pSender, Widget::TouchEventType type)
{
switch (type)
{
case Widget::TouchEventType::ENDED:
{
if (_richText->isIgnoreContentAdaptWithSize())
{
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
}
else
{
_richText->ignoreContentAdaptWithSize(true);
}
}
break;
default:
break;
}
}
//
// UIRichTextXMLSUIB3
//
bool UIRichTextXMLSUIB3::init()
{
if (UIScene::init())
{
Size widgetSize = _widget->getContentSize();
// Add the alert
Text *alert = Text::create("RichText", "fonts/Marker Felt.ttf", 30);
alert->setColor(Color3B(159, 168, 176));
alert->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f - alert->getContentSize().height * 3.125));
_widget->addChild(alert);
Button* button = Button::create("cocosui/animationbuttonnormal.png", "cocosui/animationbuttonpressed.png");
button->setTouchEnabled(true);
button->setTitleText("switch");
button->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f + button->getContentSize().height * 2.5));
button->addTouchEventListener(CC_CALLBACK_2(UIRichTextXMLSUIB3::touchEvent, this));
button->setLocalZOrder(10);
_widget->addChild(button);
// RichText
_richText = RichText::createWithXML("<font face='fonts/Marker Felt.ttf' size='20'>ttf font: <i><u>italics and underline</u></i><del><b>bold and strike-through</b></del></font>");
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
_richText->setPosition(Vec2(widgetSize.width / 2, widgetSize.height / 2));
_richText->setLocalZOrder(10);
_widget->addChild(_richText);
// test remove all children, this call won't effect the test
_richText->removeAllChildren();
return true;
}
return false;
}
void UIRichTextXMLSUIB3::touchEvent(Ref *pSender, Widget::TouchEventType type)
{
switch (type)
{
case Widget::TouchEventType::ENDED:
{
if (_richText->isIgnoreContentAdaptWithSize())
{
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
}
else
{
_richText->ignoreContentAdaptWithSize(true);
}
}
break;
default:
break;
}
}
//
// UIRichTextXMLImg
//
bool UIRichTextXMLImg::init()
{
if (UIScene::init())
{
Size widgetSize = _widget->getContentSize();
// Add the alert
Text *alert = Text::create("RichText", "fonts/Marker Felt.ttf", 30);
alert->setColor(Color3B(159, 168, 176));
alert->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f - alert->getContentSize().height * 3.125));
_widget->addChild(alert);
Button* button = Button::create("cocosui/animationbuttonnormal.png", "cocosui/animationbuttonpressed.png");
button->setTouchEnabled(true);
button->setTitleText("switch");
button->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f + button->getContentSize().height * 2.5));
button->addTouchEventListener(CC_CALLBACK_2(UIRichTextXMLImg::touchEvent, this));
button->setLocalZOrder(10);
_widget->addChild(button);
// RichText
_richText = RichText::createWithXML("you should see an image here: <img src='cocosui/sliderballnormal.png'/> and this is text again. and this is the same image, but bigger: <img src='cocosui/sliderballnormal.png' width='30' height='30' /> and here goes text again");
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
_richText->setPosition(Vec2(widgetSize.width / 2, widgetSize.height / 2));
_richText->setLocalZOrder(10);
_widget->addChild(_richText);
// test remove all children, this call won't effect the test
_richText->removeAllChildren();
return true;
}
return false;
}
void UIRichTextXMLImg::touchEvent(Ref *pSender, Widget::TouchEventType type)
{
switch (type)
{
case Widget::TouchEventType::ENDED:
{
if (_richText->isIgnoreContentAdaptWithSize())
{
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
}
else
{
_richText->ignoreContentAdaptWithSize(true);
}
}
break;
default:
break;
}
}
//
// UIRichTextXMLUrl
//
bool UIRichTextXMLUrl::init()
{
if (UIScene::init())
{
Size widgetSize = _widget->getContentSize();
// Add the alert
Text *alert = Text::create("RichText", "fonts/Marker Felt.ttf", 30);
alert->setColor(Color3B(159, 168, 176));
alert->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f - alert->getContentSize().height * 3.125));
_widget->addChild(alert);
Button* button = Button::create("cocosui/animationbuttonnormal.png", "cocosui/animationbuttonpressed.png");
button->setTouchEnabled(true);
button->setTitleText("switch");
button->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f + button->getContentSize().height * 2.5));
button->addTouchEventListener(CC_CALLBACK_2(UIRichTextXMLUrl::touchEvent, this));
button->setLocalZOrder(10);
_widget->addChild(button);
// RichText
_richText = RichText::createWithXML("And this link will redirect you to google: <a href='http://www.google.com'>click me</a>");
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
_richText->setPosition(Vec2(widgetSize.width / 2, widgetSize.height / 2));
_richText->setLocalZOrder(10);
_widget->addChild(_richText);
// test remove all children, this call won't effect the test
_richText->removeAllChildren();
return true;
}
return false;
}
void UIRichTextXMLUrl::touchEvent(Ref *pSender, Widget::TouchEventType type)
{
switch (type)
{
case Widget::TouchEventType::ENDED:
{
if (_richText->isIgnoreContentAdaptWithSize())
{
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
}
else
{
_richText->ignoreContentAdaptWithSize(true);
}
}
break;
default:
break;
}
}
//
// UIRichTextXMLFace
//
bool UIRichTextXMLFace::init()
{
if (UIScene::init())
{
Size widgetSize = _widget->getContentSize();
// Add the alert
Text *alert = Text::create("RichText", "fonts/Marker Felt.ttf", 30);
alert->setColor(Color3B(159, 168, 176));
alert->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f - alert->getContentSize().height * 3.125));
_widget->addChild(alert);
Button* button = Button::create("cocosui/animationbuttonnormal.png", "cocosui/animationbuttonpressed.png");
button->setTouchEnabled(true);
button->setTitleText("switch");
button->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f + button->getContentSize().height * 2.5));
button->addTouchEventListener(CC_CALLBACK_2(UIRichTextXMLFace::touchEvent, this));
button->setLocalZOrder(10);
_widget->addChild(button);
// RichText
_richText = RichText::createWithXML("<font size='20' face='fonts/Marker Felt.ttf'>Marker Felt 20.<font face='fonts/arial.ttf'>Arial 20.</font></font><font face='font/Thonburi.ttf' size='24' color='#0000ff'>Thonburi 24 blue</font>");
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
_richText->setPosition(Vec2(widgetSize.width / 2, widgetSize.height / 2));
_richText->setLocalZOrder(10);
_widget->addChild(_richText);
// test remove all children, this call won't effect the test
_richText->removeAllChildren();
return true;
}
return false;
}
void UIRichTextXMLFace::touchEvent(Ref *pSender, Widget::TouchEventType type)
{
switch (type)
{
case Widget::TouchEventType::ENDED:
{
if (_richText->isIgnoreContentAdaptWithSize())
{
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
}
else
{
_richText->ignoreContentAdaptWithSize(true);
}
}
break;
default:
break;
}
}
//
// UIRichTextXMLBR
//
bool UIRichTextXMLBR::init()
{
if (UIScene::init())
{
Size widgetSize = _widget->getContentSize();
// Add the alert
Text *alert = Text::create("RichText", "fonts/Marker Felt.ttf", 30);
alert->setColor(Color3B(159, 168, 176));
alert->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f - alert->getContentSize().height * 3.125));
_widget->addChild(alert);
Button* button = Button::create("cocosui/animationbuttonnormal.png", "cocosui/animationbuttonpressed.png");
button->setTouchEnabled(true);
button->setTitleText("switch");
button->setPosition(Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f + button->getContentSize().height * 2.5));
button->addTouchEventListener(CC_CALLBACK_2(UIRichTextXMLBR::touchEvent, this));
button->setLocalZOrder(10);
_widget->addChild(button);
// RichText
_richText = RichText::createWithXML("this is one line.<br/>this should be in another line.<br/>and this is another line");
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
_richText->setPosition(Vec2(widgetSize.width / 2, widgetSize.height / 2));
_richText->setLocalZOrder(10);
_widget->addChild(_richText);
// test remove all children, this call won't effect the test
_richText->removeAllChildren();
return true;
}
return false;
}
void UIRichTextXMLBR::touchEvent(Ref *pSender, Widget::TouchEventType type)
{
switch (type)
{
case Widget::TouchEventType::ENDED:
{
if (_richText->isIgnoreContentAdaptWithSize())
{
_richText->ignoreContentAdaptWithSize(false);
_richText->setContentSize(Size(100, 100));
}
else
{
_richText->ignoreContentAdaptWithSize(true);
}
}
break;
default:
break;
}
}

View File

@ -12,14 +12,133 @@ class UIRichTextTest : public UIScene
public:
CREATE_FUNC(UIRichTextTest);
UIRichTextTest();
~UIRichTextTest();
virtual bool init() override;
bool init() override;
void touchEvent(cocos2d::Ref* sender, cocos2d::ui::Widget::TouchEventType type);
protected:
cocos2d::ui::RichText* _richText;
};
class UIRichTextXMLBasic : public UIScene
{
public:
CREATE_FUNC(UIRichTextXMLBasic);
bool init() override;
void touchEvent(cocos2d::Ref* sender, cocos2d::ui::Widget::TouchEventType type);
protected:
cocos2d::ui::RichText* _richText;
};
class UIRichTextXMLSmallBig : public UIScene
{
public:
CREATE_FUNC(UIRichTextXMLSmallBig);
bool init() override;
void touchEvent(cocos2d::Ref* sender, cocos2d::ui::Widget::TouchEventType type);
protected:
cocos2d::ui::RichText* _richText;
};
class UIRichTextXMLColor : public UIScene
{
public:
CREATE_FUNC(UIRichTextXMLColor);
bool init() override;
void touchEvent(cocos2d::Ref* sender, cocos2d::ui::Widget::TouchEventType type);
protected:
cocos2d::ui::RichText* _richText;
};
class UIRichTextXMLSUIB : public UIScene
{
public:
CREATE_FUNC(UIRichTextXMLSUIB);
bool init() override;
void touchEvent(cocos2d::Ref* sender, cocos2d::ui::Widget::TouchEventType type);
protected:
cocos2d::ui::RichText* _richText;
};
class UIRichTextXMLSUIB2 : public UIScene
{
public:
CREATE_FUNC(UIRichTextXMLSUIB2);
bool init() override;
void touchEvent(cocos2d::Ref* sender, cocos2d::ui::Widget::TouchEventType type);
protected:
cocos2d::ui::RichText* _richText;
};
class UIRichTextXMLSUIB3 : public UIScene
{
public:
CREATE_FUNC(UIRichTextXMLSUIB3);
bool init() override;
void touchEvent(cocos2d::Ref* sender, cocos2d::ui::Widget::TouchEventType type);
protected:
cocos2d::ui::RichText* _richText;
};
class UIRichTextXMLImg : public UIScene
{
public:
CREATE_FUNC(UIRichTextXMLImg);
bool init() override;
void touchEvent(cocos2d::Ref* sender, cocos2d::ui::Widget::TouchEventType type);
protected:
cocos2d::ui::RichText* _richText;
};
class UIRichTextXMLUrl : public UIScene
{
public:
CREATE_FUNC(UIRichTextXMLUrl);
bool init() override;
void touchEvent(cocos2d::Ref* sender, cocos2d::ui::Widget::TouchEventType type);
protected:
cocos2d::ui::RichText* _richText;
};
class UIRichTextXMLFace : public UIScene
{
public:
CREATE_FUNC(UIRichTextXMLFace);
bool init() override;
void touchEvent(cocos2d::Ref* sender, cocos2d::ui::Widget::TouchEventType type);
protected:
cocos2d::ui::RichText* _richText;
};
class UIRichTextXMLBR : public UIScene
{
public:
CREATE_FUNC(UIRichTextXMLBR);
bool init() override;
void touchEvent(cocos2d::Ref* sender, cocos2d::ui::Widget::TouchEventType type);
protected:
cocos2d::ui::RichText* _richText;
};
#endif /* defined(__TestCpp__UIRichTextTest__) */