cocos2d-x中,简单html富文本显示

作者:HU

转载请注明,原文链接:http://www.cnblogs.com/xioapingguo/p/4037414.html 

 

虽然自从cocos2d-x更新到3.0后,使用freetype,并且增加了丰富文本,但这些文本都需要自己去设置,用起来也不方便,所以动手写了个简单html富文本

可以使用

 <size=15></size>//字体大小

 <fontname=“Arial”></fontname>//字体,这里必须有这个字体才能使用

 <outline=2 color = 0xFFFFFFFF></outline>//描边

 <shadow></shadow>//阴影

 <link=“”></link>//链接

 <img=“”>//图片

 <color=0XFFFFFFFF></color>//文字颜色

 <u=0xFF000000></u>//下划线

 

如“<fontname= \"Arial\"  ><shadow>11111</shadow></fontname><u><link=\"www.baidu.com\">abc</link></u><img=\"CloseSelected.png\"><color = 0xFF><size=50>defg</color><outline=2 color=0xFF0000FF>hijk</outline></size>”效果:

cocos2d-x中,简单html富文本显示

因为兼容了系统UIRichText的功能,所以直接把UIRichText替换了

下面是头文件UIRichText.h

#ifndef __UIRICHTEXT_H__

#define __UIRICHTEXT_H__



#include "ui/UIWidget.h"



NS_CC_BEGIN

/*

 <size=15></size>

 <fontname=“Arial”></fontname>

 <outline=2 color = 0xFFFFFFFF></outline>

 <shadow></shadow>

 <link=“”></link>

 <img=“”>

 <color=0XFFFFFFFF></color>

 <u=0xFF000000></u>

 */

namespace ui {



class RichElement : public Ref

{

public:

    enum class Type

    {

        TEXT,

        IMAGE,

        CUSTOM

    };

    RichElement(){};

    virtual ~RichElement(){};

protected:

    Type _type;

    CC_SYNTHESIZE(std::string,_tag,Tag);

    friend class RichText;

};



class RichElementText : public RichElement

{

public:

    

    RichElementText()

    {

        _type = Type::TEXT;

        _color = Color3B::WHITE;

        _opacity = 255;

        _text = "";

        _fontSize = 0;

        _fontName = "";

        _textColor = Color4B::WHITE;

        _outLine = -1;

        _outLineColor = Color4B::BLACK;

        _shadow = false;

        _linkurl =  "";

        _underLinecolor = Color4B(0,0,0,0);

        _underLinesize = -1;

        _touchCallback = nullptr;

    }

    virtual ~RichElementText(){};

    

    bool init(const std::string& text, const std::string& fontFile, float fontSize);

    static RichElementText* create(const std::string& text, const std::string& fontFile, float fontSize);

    

    void setTouchCallBack(std::function<void (std::string)> touch,std::string tag);

    void setLinkUrl(std::string linkurl);

protected:

    CC_SYNTHESIZE(Color3B,_color,Color);

    CC_SYNTHESIZE(GLubyte,_opacity,Opacity);

    CC_SYNTHESIZE(std::string,_text,Text);

    CC_SYNTHESIZE(std::string,_fontName,FontName);

    CC_SYNTHESIZE(float,_fontSize,FontSize);

    CC_SYNTHESIZE(Color4B,_textColor,TextColor);

    CC_SYNTHESIZE(int,_outLine,OutLine);

    CC_SYNTHESIZE(Color4B,_outLineColor,OutLineColor);

    CC_SYNTHESIZE(bool,_shadow,Shadow);

    CC_SYNTHESIZE_READONLY(std::string,_linkurl,LinkUrl);

    CC_SYNTHESIZE(Color4B,_underLinecolor,UnderLineColor);

    CC_SYNTHESIZE(int,_underLinesize,UnderLineSize);

    CC_SYNTHESIZE_READONLY(std::function<void (std::string)>, _touchCallback, TouchCallBack);

    //std::function<void (std::string)> _touchCallback;

    friend class RichText;

    

private:

    void linkCallback(std::string str);

};





class RichElementImage : public RichElement

{

public:

    RichElementImage()

    {

        _type = Type::IMAGE;

        _tag = -1;

        _color = Color3B::WHITE;

        _opacity = 255;

    }

    virtual ~RichElementImage(){};

    bool init(const std::string& filePath);

    static RichElementImage* create(const std::string& filePath);

protected:

    CC_SYNTHESIZE(Color3B,_color,Color);

    CC_SYNTHESIZE(GLubyte,_opacity,Opacity);

    

    std::string _filePath;

    Rect _textureRect;

    int _textureType;

    friend class RichText;

};



class RichElementCustomNode : public RichElement

{

public:

    RichElementCustomNode()

    {

        _type = Type::CUSTOM;

        _customNode = nullptr;

    };

    virtual ~RichElementCustomNode()

    {

        CC_SAFE_RELEASE(_customNode);

    };

    bool init(Node* customNode);

    static RichElementCustomNode* create(Node* customNode);

protected:

    CC_SYNTHESIZE(Color3B,_color,Color);

    CC_SYNTHESIZE(GLubyte,_opacity,Opacity);

    

    Node* _customNode;

    friend class RichText;

};





class RichText : public Widget

{

public:

    RichText();

    virtual ~RichText();

    static RichText* create();

    static RichText* create(std::string str,const std::string& fontFile, float fontSize,const Size& size);

    bool initWithStr(std::string str,const std::string& fontFile, float fontSize,const Size& size);

    void insertElement(RichElement* element, int index);

    void pushBackElement(RichElement* element);

    void removeElement(int index);

    void removeElement(RichElement* element);

    virtual void visit(Renderer* renderer, const kmMat4 &parentTransform, bool parentTransformUpdated) override;

    void setVerticalSpace(float space);

    virtual void setAnchorPoint(const Point& pt);

    virtual const Size& getVirtualRendererSize() const override;

    void formatText();

    virtual void ignoreContentAdaptWithSize(bool ignore);

    virtual std::string getDescription() const override;

    

CC_CONSTRUCTOR_ACCESS:

    virtual bool init() override;

    virtual void onEnter() override;

    virtual void onExit() override;

protected:

    virtual void initRenderer();

    void pushToContainer(Node* renderer);

    void handleTextRenderer(const RichElementText& textInfo);

    //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 handleCustomRenderer(Node* renderer);

    void formarRenderers();

    void addNewLine();

    

    bool onTouchBegan(Touch *touch, Event *unusedEvent);

    void onTouchEnded(Touch *touch, Event *unusedEvent);

    

    CC_SYNTHESIZE(int, _touchPriority, TouchPriority);

protected:

    bool _formatTextDirty;

    Vector<RichElement*> _richElements;

    std::vector<Vector<Node*>*> _elementRenders;

    std::map<Node*,std::function<void(std::string)> > _touchDelegate;

    float _leftSpaceWidth;

    float _verticalSpace;

    Node* _elementRenderersContainer;

private:

    static float _set_fontSize;

    static std::string _set_fontFile;

    static int _set_outline;

    static Color4B _set_outline_color;

    static bool _set_shadow;

    static std::string _set_link;

    static Color4B _set_textColor;

    static bool _set_underline;

    static Color4B _set_underline_color;

    

    RichElement* createWithSet(const std::string& text);

};



}



NS_CC_END



#endif /* defined(__UIRichText__) */

下面是Cpp,UIRichText.cpp, 由于3.0对UTF8文本有点问题,下面有几个方法自己实现的,如果3.2下直接使用后面注释掉的就可以了。具体区别对照下原版本的UIRichText.cpp就可以了。

#include "UIRichText.h"



NS_CC_BEGIN



namespace ui {



#define DEFAULT_OUTLINE -1

#define DEFAULT_OUTLINE_COLOR (Color4B(0, 0, 0, 0))

#define DEFAULT_COLOR Color4B::WHITE

#define DEFAULT_UNDERLINE false

#define DEFAULT_UNDERLINE_COLOR (Color4B(0, 0, 0, 0))



int RichText::_set_outline = DEFAULT_OUTLINE;

Color4B RichText::_set_outline_color = DEFAULT_OUTLINE_COLOR;

bool RichText::_set_shadow = false;

bool RichText::_set_underline = DEFAULT_UNDERLINE;

Color4B RichText::_set_underline_color = DEFAULT_UNDERLINE_COLOR;

Color4B RichText::_set_textColor = DEFAULT_COLOR;

std::string RichText::_set_fontFile;

float RichText::_set_fontSize;

std::string RichText::_set_link;



static std::string utf8_substr(const std::string& str, unsigned long start, unsigned long leng)

{

    if (leng==0)

    {

        return "";

    }

    unsigned long c, i, ix, q, min=std::string::npos, max=std::string::npos;

    for (q=0, i=0, ix=str.length(); i < ix; i++, q++)

    {

        if (q==start)

        {

            min = i;

        }

        if (q <= start+leng || leng==std::string::npos)

        {

            max = i;

        }

        

        c = (unsigned char) str[i];

        

        if      (c<=127) i+=0;

        else if ((c & 0xE0) == 0xC0) i+=1;

        else if ((c & 0xF0) == 0xE0) i+=2;

        else if ((c & 0xF8) == 0xF0) i+=3;

        else return "";//invalid utf8

    }

    if (q <= start+leng || leng == std::string::npos)

    {

        max = i;

    }

    if (min==std::string::npos || max==std::string::npos)

    {

        return "";

    }

    return str.substr(min,max);

}



bool RichElementText::init(const std::string& text, const std::string& fontFile, float fontSize)

{

    _text = text;

    _fontName = fontFile;

    _fontSize = fontSize;

    

    return true;

}



RichElementText* RichElementText::create(const std::string& text, const std::string& fontFile, float fontSize)

{

    RichElementText* htmlElementText = new RichElementText();

    if (htmlElementText && htmlElementText->init(text, fontFile, fontSize))

    {

        htmlElementText->autorelease();

        return htmlElementText;

    }

    CC_SAFE_DELETE(htmlElementText);

    return nullptr;

}



void RichElementText::setTouchCallBack(std::function<void (std::string)> touch,std::string tag)

{

    _touchCallback = touch;

    _tag = tag;

}



void RichElementText::setLinkUrl(std::string linkurl)

{

    _linkurl = linkurl;

    setTouchCallBack(std::bind(&RichElementText::linkCallback, this,std::placeholders::_1),linkurl);

}



void RichElementText::linkCallback(std::string str)

{

    CCLOG("call open url %s",str.c_str());

}

                     

bool RichElementImage::init(const std::string& filePath)

{

    _filePath = filePath;

    return true;

}



RichElementImage* RichElementImage::create(const std::string& filePath)

{

    RichElementImage* htmlElementImage = new RichElementImage();

    if (htmlElementImage && htmlElementImage->init(filePath))

    {

        htmlElementImage->autorelease();

        return htmlElementImage;

    }

    CC_SAFE_DELETE(htmlElementImage);

    return nullptr;

}



bool RichElementCustomNode::init(cocos2d::Node *customNode)

{

    _customNode = customNode;

    _customNode->retain();

    return true;

}



RichElementCustomNode* RichElementCustomNode::create(cocos2d::Node *customNode)

{

    RichElementCustomNode* element = new RichElementCustomNode();

    if (element && element->init(customNode))

    {

        element->autorelease();

        return element;

    }

    CC_SAFE_DELETE(element);

    return nullptr;

}







RichText::RichText():

_formatTextDirty(true),

_leftSpaceWidth(0.0f),

_verticalSpace(0.0f),

_touchPriority(-1),

_elementRenderersContainer(nullptr)

{

    _touchDelegate.clear();

}



RichText::~RichText()

{

    _richElements.clear();

    std::map<Node*,std::function<void(std::string)> >::const_iterator it =  _touchDelegate.begin();

    while (it != _touchDelegate.end())

    {

        Node* node = it->first;

        if (node->getUserData()!=nullptr)

        {

            delete (std::string*)(node->getUserData());

            node->setUserData(nullptr);

        }

        ++it;

    }

    

    _touchDelegate.clear();

}



RichText* RichText::create()

{

    RichText* widget = new RichText();

    if (widget && widget->init())

    {

        widget->autorelease();

        return widget;

    }

    CC_SAFE_DELETE(widget);

    return nullptr;

}



RichText* RichText::create(std::string str,const std::string& fontFile, float fontSize,const Size& size)

{

    RichText* widget = new RichText();

    if (widget && widget->initWithStr(str,fontFile,fontSize,size))

    {

        widget->autorelease();

        return widget;

    }

    CC_SAFE_DELETE(widget);

    return nullptr;

}



bool RichText::init()

{

    if (!Widget::init())

    {

        return false;

    }

    



    return true;

}

static const char* keywords[] = {"size","fontname","outline","shadow","link","img","color","u"};



static Color4B int2ccc3(unsigned long color)

{

    Color4B ret;

    ret.r = (color&0xffffffff)>>24;

    ret.g = (color&0xffffff)>>16;

    ret.b = (color&0xffff)>>8;

    ret.a = color&0xff;

    return ret;

}



RichElement* RichText::createWithSet(const std::string& text)

{

    if (text.empty())

    {

        Node* node = Node::create();

        node->setContentSize(Size(getContentSize().width, 1));

        return RichElementCustomNode::create(node);

    }

    RichElementText* ret = RichElementText::create(text, _set_fontFile, _set_fontSize);

    if (_set_outline>0)

    {

        ret->setOutLine(_set_outline);

        ret->setOutLineColor(_set_outline_color);

    }



    ret->setShadow(_set_shadow);

    if (!_set_link.empty())

    {

        ret->setLinkUrl(_set_link);

    }

    

    CCLOG("%d,%d,%d,%d",_set_textColor.r,_set_textColor.g,_set_textColor.b,_set_textColor.a);

    ret->setTextColor(_set_textColor);

    if (_set_underline)

    {

        ret->setUnderLineSize(2);

        if (_set_underline_color.a == 0)

        {

            ret->setUnderLineColor(_set_textColor);

        }

        else

        {

            ret->setUnderLineColor(_set_underline_color);

        }

    }

    

    

    return  ret;

}



bool RichText::initWithStr(std::string str,const std::string& fontFile, float fontSize,const Size& size)

{

    if (!Widget::init())

    {

        return false;

    }

    ignoreContentAdaptWithSize(false);

    //setContentSize(size);

    setSize(size);



    _set_fontSize = fontSize;

    _set_fontFile = fontFile;

    _set_textColor = DEFAULT_COLOR;

    

    std::string s = str;

    unsigned long posStart = 0;

    unsigned long posEnd = 0;

    

    while (posStart<s.length())

    {

        bool isEnd = false;

        posEnd = s.find("<",posStart);

        

        if (posStart!=posEnd)

        {

            std::string tempStr = s.substr(posStart,posEnd-posStart);

            std::string::value_type pos = tempStr.find("\n");

            if (pos!=std::string::npos)

            {

                std::string s1 = tempStr.substr(0,pos).c_str();

                if (!s1.empty())

                {

                    pushBackElement(createWithSet(s1));

                }

                

                pushBackElement(createWithSet(""));

                std::string s2 = tempStr.substr(pos+1).c_str();

                if (!s2.empty())

                {

                    pushBackElement(createWithSet(s2));

                }



            }

            else

            {

                CCLOG("%s",tempStr.c_str());

                pushBackElement(createWithSet(tempStr));

            }

            

            if (posEnd==std::string::npos)

            {

                break;

            }

            

        }

        

        posStart = posEnd+1;

        CCLOG("%c",s.at(posStart));

        if (s.at(posStart)=='/')

        {

            isEnd = true;

            posStart++;

        }

        

        int keyIndex = 0;

        for (keyIndex=0; keyIndex<8; keyIndex++)

        {

            if(s.compare(posStart, strlen(keywords[keyIndex]), keywords[keyIndex])==0)

            {

                break;

            }

        }

        

        if (keyIndex<8)

        {

            switch (keyIndex)

            {

                case 0:

                {

                    posEnd = s.find(">",posStart);

                    if (isEnd)

                    {

                        CCLOG("size end");

                        _set_fontSize = fontSize;

                    }

                    else

                    {

                        posStart = s.find("=",posStart)+1;

                        int size = atoi(s.substr(posStart,posEnd-posStart).c_str());

                        _set_fontSize = size;

                        CCLOG("%d",size);

                    }

                }

                    break;

                case 1:

                {

                    posEnd = s.find(">",posStart);

                    if (isEnd)

                    {

                        _set_fontFile = fontFile;

                        CCLOG("fontname end");

                    }

                    else

                    {

                        posStart = s.find("=",posStart)+1;

                        std::string temp = s.substr(posStart,posEnd-posStart);

                        std::string::value_type p1,p2;

                        p1 = temp.find("\"")+1;

                        p2 = temp.find("\"",p1);

                        std::string fontname = temp.substr(p1,p2-p1);

                        _set_fontFile = fontname;

                        CCLOG("fontname = %s",fontname.c_str());

                    }

                }

                    break;

                case 2:

                {

                    posEnd = s.find(">",posStart+1);

                    if (isEnd)

                    {

                        CCLOG("outline end");

                        _set_outline = DEFAULT_OUTLINE;

                        _set_outline_color = DEFAULT_OUTLINE_COLOR;

                    }

                    else

                    {

                        posStart = s.find("=",posStart)+1;

                        std::string temp = s.substr(posStart,posEnd-posStart);

                        int size = atoi(temp.c_str());

                        _set_outline = size;

                        CCLOG("outline %d",size);

                        unsigned long p1 = temp.find("=");

                        if (p1!=std::string::npos)

                        {

                            Color4B c = int2ccc3(strtoul(temp.substr(p1+1).c_str(), NULL, 16));

                            _set_outline_color = c;

                            CCLOG("outline color = %d,%d,%d,%d",c.r,c.g,c.b,c.a);

                        }

                    }

                }

                    break;

                case 3:

                {

                    posEnd = s.find(">",posStart);

                    if (isEnd)

                    {

                        CCLOG("shadow end");

                        _set_shadow = false;

                    }

                    else

                    {

                        _set_shadow = true;

                        CCLOG("shadow start");

                    }

                }

                    break;

                case 4:

                {

                    posEnd = s.find(">",posStart);

                    if (isEnd)

                    {

                        _set_link = "";

                        CCLOG("link end");

                    }

                    else

                    {

                        posStart = s.find("=",posStart)+1;

                        std::string temp = s.substr(posStart,posEnd-posStart);

                        std::string::value_type p1,p2;

                        p1 = temp.find("\"")+1;

                        p2 = temp.find("\"",p1);

                        std::string linkstr = temp.substr(p1,p2-p1);

                        _set_link = linkstr;

                        CCLOG("link = %s",linkstr.c_str());

                    }

                }

                    break;

                case 5:

                {

                    posEnd = s.find(">",posStart);

                    

                    posStart = s.find("=",posStart)+1;

                    

                    std::string temp = s.substr(posStart,posEnd-posStart);

                    std::string::value_type p1,p2;

                    p1 = temp.find("\"")+1;

                    p2 = temp.find("\"",p1);

                    std::string img = temp.substr(p1,p2-p1);

                    Sprite* s = Sprite::create(img);

                    if (s)

                    {

                        pushBackElement(RichElementCustomNode::create(s));

                    }

                    

                    CCLOG("img = %s",img.c_str());

                    

                }

                    break;

                case 6:

                {

                    posEnd = s.find(">",posStart);

                    if (isEnd)

                    {

                        _set_textColor = DEFAULT_COLOR;

                        CCLOG("color end");

                    }

                    else

                    {

                        posStart = s.find("=",posStart)+1;

                        Color4B c = int2ccc3(strtoul(s.substr(posStart,posEnd-posStart).c_str(), NULL, 16));

                        _set_textColor = c;

                        CCLOG("%d,%d,%d,%d",c.r,c.g,c.b,c.a);

                    }

                    

                }

                    break;

                case 7:

                {

                    posEnd = s.find(">",posStart);

                    if (isEnd)

                    {

                        _set_underline = false;

                        _set_underline_color = DEFAULT_UNDERLINE_COLOR;

                        CCLOG("underline end");

                    }

                    else

                    {

                        _set_underline = true;

                        if (s.substr(posStart,posEnd-posStart).find("=")!=std::string::npos)

                        {

                            posStart = s.find("=",posStart)+1;

                            Color4B c = int2ccc3(strtoul(s.substr(posStart,posEnd-posStart).c_str(), NULL, 16));

                            _set_underline_color = c;

                            CCLOG("%d,%d,%d,%d",c.r,c.g,c.b,c.a);

                        }

                        else

                        {

                            CCLOG("underline no color");

                        }

                        

                    }

                }

                    break;

                default:

                    break;

            }

        }

        

        posStart = posEnd+1;

    }

    

    return true;

}



void RichText::onEnter()

{

    Widget::onEnter();

    

    EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();

    listener->setSwallowTouches(true);

    listener->onTouchBegan = CC_CALLBACK_2(RichText::onTouchBegan, this);

    listener->onTouchEnded = CC_CALLBACK_2(RichText::onTouchEnded, this);

    _eventDispatcher->addEventListenerWithFixedPriority(listener, _touchPriority);

}



void RichText::onExit()

{

    Widget::onExit();

    _eventDispatcher->removeAllEventListeners();

}



bool RichText::onTouchBegan(Touch *touch, Event *unusedEvent)

{

    std::map<Node*,std::function<void(std::string)> >::const_iterator it =  _touchDelegate.begin();

    while (it != _touchDelegate.end())

    {

        Node* node = it->first;

        if (node->getBoundingBox().containsPoint(node->getParent()->convertTouchToNodeSpace(touch)))

        {

            return true;

        }

        ++it;

    }

    return false;

}



void RichText::onTouchEnded(Touch *touch, Event *unusedEvent)

{

    std::map<Node*,std::function<void(std::string)> >::const_iterator it =  _touchDelegate.begin();

    while (it != _touchDelegate.end())

    {

        Node* node = it->first;

        if (node->getBoundingBox().containsPoint(node->getParent()->convertTouchToNodeSpace(touch)))

        {

            if (node->getUserData()!=nullptr)

            {

                (it->second)(*((std::string*)node->getUserData()));

            }

            

            return;

        }

        ++it;

    }

}



void RichText::initRenderer()

{

    _elementRenderersContainer = Node::create();

    _elementRenderersContainer->setAnchorPoint(Point(0.5f, 0.5f));

    addProtectedChild(_elementRenderersContainer, 0, -1);

}



void RichText::insertElement(RichElement *element, int index)

{

    _richElements.insert(index, element);

    _formatTextDirty = true;

}



void RichText::pushBackElement(RichElement *element)

{

    _richElements.pushBack(element);

    _formatTextDirty = true;

}



void RichText::removeElement(int index)

{

    _richElements.erase(index);

    _formatTextDirty = true;

}



void RichText::removeElement(RichElement *element)

{

    _richElements.eraseObject(element);

    _formatTextDirty = true;

}



void RichText::formatText()

{

    if (_formatTextDirty)

    {

        _elementRenderersContainer->removeAllChildren();

        _elementRenders.clear();

        if (_ignoreSize)

        {

            addNewLine();

            for (ssize_t i=0; i<_richElements.size(); i++)

            {

                RichElement* element = _richElements.at(i);

                Node* elementRenderer = nullptr;

                switch (element->_type)

                {

                    case RichElement::Type::TEXT:

                    {

                        Label* elementLabel = nullptr;

                        RichElementText* elmtText = static_cast<RichElementText*>(element);

                        if (FileUtils::getInstance()->isFileExist(elmtText->_fontName))

                        {

                            elementLabel = Label::createWithTTF(elmtText->_text.c_str(), elmtText->_fontName, elmtText->_fontSize);

                        }

                        else

                        {

                            elementLabel = Label::createWithSystemFont(elmtText->_text.c_str(), elmtText->_fontName, elmtText->_fontSize);

                        }

                        if (elmtText->getOutLine()>0)

                        {

                            elementLabel->enableOutline(elmtText->getOutLineColor(),elmtText->getOutLine());

                        }

                        if (elmtText->getShadow())

                        {

                            elementLabel->enableShadow();

                        }

                        elementLabel->setTextColor(/*elmtText->getTextColor()*/Color4B::RED);

                        if (elmtText->getUnderLineSize()>0)

                        {

                            LayerColor* l = nullptr;

                            if (elmtText->getUnderLineColor().a == 0)

                            {

                                l =  LayerColor::create(elmtText->getTextColor(), elementLabel->getContentSize().width, elmtText->getUnderLineSize());

                            }

                            else

                            {

                                l = LayerColor::create(elmtText->getUnderLineColor(), elementLabel->getContentSize().width, elmtText->getUnderLineSize());

                            }

                            elementLabel->setUserObject(l);

                        }

                        if (elmtText->getTouchCallBack())

                        {

                            std::string* tag = new std::string(elmtText->getTag());

                            elementLabel->setUserData(tag);

                            _touchDelegate[elementLabel] = elmtText->getTouchCallBack();

                        }

                        elementRenderer = elementLabel;

                        elementRenderer->setColor(elmtText->_color);

                        elementRenderer->setOpacity(elmtText->_opacity);

                        break;

                    }

                    case RichElement::Type::IMAGE:

                    {

                        RichElementImage* elmtImage = static_cast<RichElementImage*>(element);

                        elementRenderer = Sprite::create(elmtImage->_filePath.c_str());

                        elementRenderer->setColor(elmtImage->_color);

                        elementRenderer->setOpacity(elmtImage->_opacity);

                        break;

                    }

                    case RichElement::Type::CUSTOM:

                    {

                        RichElementCustomNode* elmtCustom = static_cast<RichElementCustomNode*>(element);

                        elementRenderer = elmtCustom->_customNode;

                        elementRenderer->setColor(elmtCustom->_color);

                        elementRenderer->setOpacity(elmtCustom->_opacity);

                        break;

                    }

                    default:

                        break;

                }

                

                pushToContainer(elementRenderer);

            }

        }

        else

        {

            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);

                        break;

                    }

                    case RichElement::Type::IMAGE:

                    {

                        RichElementImage* elmtImage = static_cast<RichElementImage*>(element);

                        handleImageRenderer(elmtImage->_filePath.c_str(), elmtImage->_color, elmtImage->_opacity);

                        break;

                    }

                    case RichElement::Type::CUSTOM:

                    {

                        RichElementCustomNode* elmtCustom = static_cast<RichElementCustomNode*>(element);

                        handleCustomRenderer(elmtCustom->_customNode);

                        break;

                    }

                    default:

                        break;

                }

            }

        }

        formarRenderers();

        _formatTextDirty = false;

    }

}

#define UTF8_ASCII(byte) (((unsigned char)(byte)>=0x00)&&((unsigned char)(byte)<=0x7F))  

#define UTF8_FIRST(byte) (((unsigned char)(byte)>=0xC0)&&((unsigned char)(byte)<=0xFD))  

#define UTF8_OTHER(byte) (((unsigned char)(byte)>=0x80)&&((unsigned char)(byte)<=0xBF))  

static int _calcCharCount(const char * pszText,int len)

{

    char *p = 0;  

    long count = 0;  



    if (!pszText || len <= 0) {  

        return 0;  

    }  



    for(p=(char*)pszText; p<pszText+len; p++) {  

        if (UTF8_ASCII(*p) || (UTF8_FIRST(*p))) {  

            count++;  

        }  

    }  



    return count;

}



void RichText::handleTextRenderer(const RichElementText& textInfo)

{

    auto fileExist = FileUtils::getInstance()->isFileExist(textInfo.getFontName());

    Label* textRenderer = nullptr;

    if (fileExist)

    {

        textRenderer = Label::createWithTTF(textInfo.getText(), textInfo.getFontName(), textInfo.getFontSize());

    }

    else

    {

        textRenderer = Label::createWithSystemFont(textInfo.getText(), textInfo.getFontName(), textInfo.getFontSize());

    }

    if (textInfo.getOutLine()>0)

    {

        textRenderer->enableOutline(textInfo.getOutLineColor(),textInfo.getOutLine());

    }

    if (textInfo.getShadow())

    {

        textRenderer->enableShadow();

    }

    

    float textRendererWidth = textRenderer->getContentSize().width;

    _leftSpaceWidth -= textRendererWidth;

    if (_leftSpaceWidth < 0.0f)

    {

        float overstepPercent = (-_leftSpaceWidth) / textRendererWidth;

        std::string curText = textInfo.getText();

        size_t stringLength = _calcCharCount(textInfo.getText().c_str(),textInfo.getText().length());//StringUtils::getCharacterCountInUTF8String(textInfo.getText());

        int leftLength = stringLength * (1.0f - overstepPercent);

        std::string leftWords = utf8_substr(curText,0,leftLength);

        std::string cutWords = utf8_substr(curText, leftLength, curText.length() - leftLength);

        if (leftLength > 0)

        {

            Label* leftRenderer = nullptr;

            if (fileExist)

            {

                leftRenderer = Label::createWithTTF(utf8_substr(leftWords, 0, leftLength), textInfo.getFontName(), textInfo.getFontSize());

            }

            else

            {

                leftRenderer = Label::createWithSystemFont(utf8_substr(leftWords, 0, leftLength), textInfo.getFontName(), textInfo.getFontSize());

            }

            if (leftRenderer)

            {

                leftRenderer->setColor(textInfo.getColor());

                leftRenderer->setOpacity(textInfo.getOpacity());

                

                if (textInfo.getOutLine()>0)

                {

                    leftRenderer->enableOutline(textInfo.getOutLineColor(),textInfo.getOutLine());

                }

                if (textInfo.getShadow())

                {

                    leftRenderer->enableShadow();

                }

                leftRenderer->setTextColor(textInfo.getTextColor());

                if (textInfo.getUnderLineSize()>0)

                {

                    LayerColor* l = nullptr;

                    if (textInfo.getUnderLineColor().a==0)

                    {

                        l =  LayerColor::create(textInfo.getTextColor(), leftRenderer->getContentSize().width, textInfo.getUnderLineSize());

                    }

                    else

                    {

                        l = LayerColor::create(textInfo.getUnderLineColor(), leftRenderer->getContentSize().width, textInfo.getUnderLineSize());

                    }

                    leftRenderer->setUserObject(l);

                }

                if (textInfo.getTouchCallBack())

                {

                    std::string* tag = new std::string(textInfo.getTag());

                    leftRenderer->setUserData(tag);

                    _touchDelegate[leftRenderer] = textInfo.getTouchCallBack();

                }

                pushToContainer(leftRenderer);

            }

        }

        

        addNewLine();

        RichElementText cutRich = textInfo;

        cutRich.setText(cutWords);

        handleTextRenderer(cutRich);

    }

    else

    {

        textRenderer->setColor(textInfo.getColor());

        textRenderer->setOpacity(textInfo.getOpacity());

        

        if (textInfo.getOutLine()>0)

        {

            textRenderer->enableOutline(textInfo.getOutLineColor(),textInfo.getOutLine());

        }

        if (textInfo.getShadow())

        {

            textRenderer->enableShadow();

        }

        textRenderer->setTextColor(textInfo.getTextColor());

        if (textInfo.getUnderLineSize()>0)

        {

            LayerColor* l = nullptr;

            if (textInfo.getUnderLineColor().a==0)

            {

                l =  LayerColor::create(textInfo.getTextColor(), textRenderer->getContentSize().width, textInfo.getUnderLineSize());

            }

            else

            {

                l = LayerColor::create(textInfo.getUnderLineColor(), textRenderer->getContentSize().width, textInfo.getUnderLineSize());

            }

            textRenderer->setUserObject(l);

        }

        if (textInfo.getTouchCallBack())

        {

            std::string* tag = new std::string(textInfo.getTag());

            textRenderer->setUserData(tag);

            _touchDelegate[textRenderer] = textInfo.getTouchCallBack();

        }

        pushToContainer(textRenderer);

    }

}



void RichText::handleImageRenderer(const std::string& fileParh, const Color3B &color, GLubyte opacity)

{

    Sprite* imageRenderer = Sprite::create(fileParh);

    if (imageRenderer==nullptr)

    {

        return;

    }

    

    imageRenderer->setColor(color);

    imageRenderer->setOpacity(opacity);

    handleCustomRenderer(imageRenderer);

}



void RichText::handleCustomRenderer(cocos2d::Node *renderer)

{

    Size imgSize = renderer->getContentSize();

    _leftSpaceWidth -= imgSize.width;

    if (_leftSpaceWidth < 0.0f)

    {

        addNewLine();

        pushToContainer(renderer);

        _leftSpaceWidth -= imgSize.width;

    }

    else

    {

        pushToContainer(renderer);

    }

}



void RichText::addNewLine()

{

    _leftSpaceWidth = _customSize.width;

    _elementRenders.push_back(new Vector<Node*>());

}



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++)

        {

            Node* l = row->at(j);

            l->setAnchorPoint(Point::ZERO);

            l->setPosition(Point(nextPosX, 0.0f));

            _elementRenderersContainer->addChild(l, 1);

            

            Node* under = dynamic_cast<Node*>(l->getUserObject());

            if (under)

            {

                under->setPosition(Point(nextPosX,-1));

                _elementRenderersContainer->addChild(under);

                l->setUserObject(nullptr);

            }

            

            Size iSize = l->getContentSize();

            newContentSizeWidth += iSize.width;

            newContentSizeHeight = MAX(newContentSizeHeight, iSize.height);

            nextPosX += iSize.width;

        }

        _elementRenderersContainer->setContentSize(Size(newContentSizeWidth, newContentSizeHeight));

    }

    else

    {

        float newContentSizeHeight = 0.0f;

        float *maxHeights = new float[_elementRenders.size()];

        

        for (size_t i=0; i<_elementRenders.size(); i++)

        {

            Vector<Node*>* row = (_elementRenders[i]);

            float maxHeight = 0.0f;

            for (ssize_t j=0; j<row->size(); j++)

            {

                Node* l = row->at(j);

                maxHeight = MAX(l->getContentSize().height, maxHeight);

            }

            maxHeights[i] = maxHeight;

            newContentSizeHeight += maxHeights[i];

        }

        

        

        float nextPosY = _customSize.height;

        for (size_t i=0; i<_elementRenders.size(); i++)

        {

            Vector<Node*>* row = (_elementRenders[i]);

            float nextPosX = 0.0f;

            nextPosY -= (maxHeights[i] + _verticalSpace);

            

            for (ssize_t j=0; j<row->size(); j++)

            {

                Node* l = row->at(j);

                l->setAnchorPoint(Point::ZERO);

                l->setPosition(Point(nextPosX, nextPosY));

                _elementRenderersContainer->addChild(l, 1);

                Node* under = dynamic_cast<Node*>(l->getUserObject());

                if (under)

                {

                    under->setPosition(Point(nextPosX,nextPosY-1));

                    _elementRenderersContainer->addChild(under);

                    l->setUserObject(nullptr);

                }

                nextPosX += l->getContentSize().width;

            }

        }

        _elementRenderersContainer->setContentSize(_contentSize);

        delete [] maxHeights;

    }

    

    size_t length = _elementRenders.size();

    for (size_t i = 0; i<length; i++)

    {

        Vector<Node*>* l = _elementRenders[i];

        l->clear();

        delete l;

    }

    _elementRenders.clear();

    

    if (_ignoreSize)

    {

        Size s = getVirtualRendererSize();

        this->setContentSize(s);

    }

    else

    {

        this->setContentSize(_customSize);

    }

    updateContentSizeWithTextureSize(_contentSize);

    _elementRenderersContainer->setPosition(_contentSize.width / 2.0f, _contentSize.height / 2.0f);

}



void RichText::pushToContainer(cocos2d::Node *renderer)

{

    if (_elementRenders.size() <= 0)

    {

        return;

    }

    _elementRenders[_elementRenders.size()-1]->pushBack(renderer);

}



void RichText::visit(Renderer* renderer, const kmMat4 &parentTransform, bool parentTransformUpdated)

{

    if (_enabled)

    {

        formatText(); 

        Widget::visit(renderer, parentTransform, parentTransformUpdated);

    }

}



void RichText::setVerticalSpace(float space)

{

    _verticalSpace = space;

}



void RichText::setAnchorPoint(const Point& pt)

{

    Widget::setAnchorPoint(pt);

    _elementRenderersContainer->setAnchorPoint(pt);

}



const Size& RichText::getVirtualRendererSize() const

{

    return _elementRenderersContainer->getContentSize();

}



void RichText::ignoreContentAdaptWithSize(bool ignore)

{

    if (_ignoreSize != ignore)

    {

        _formatTextDirty = true;

        Widget::ignoreContentAdaptWithSize(ignore);

    }

}



std::string RichText::getDescription() const

{

    return "RichText";

}



}



NS_CC_END

使用方法,上面的str

    RichText* _richText = RichText::create(str, "fonts/Marker Felt.ttf", 30, Size(300, 300));

    _richText->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

    _richText->setLocalZOrder(10);

    

    addChild(_richText);

 

你可能感兴趣的:(cocos2d-x)