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>”效果:

因为兼容了系统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);
时间: 2024-10-01 03:04:57

cocos2d-x中,简单html富文本显示的相关文章

Javascript实现简单的富文本编辑器

<span style="font-size:14px;"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> &

Vue 中使用UEditor富文本编辑器-亲测可用-vue-ueditor-wrap

其中UEditor中也存在不少错误,再引用过程中. 但是UEditor相对还是比较好用的一个富文本编辑器. vue-ueditor-wrap说明 Vue + UEditor + v-model 双向绑定.之所以有这个 repo 的原因是: ?1.UEditor 依然是国内使用频率极高的所见即所得编辑器而 Vue 又有着广泛的使用,所以将两者结合使用,是很多 Vue 项目开发者的切实需求. ?2.目前没有发现满足这种需求,而使用又很方便的 repo.有的可能也只是简单的暴露一个 UEditor 的

在vue中使用tinymce富文本编辑器,解决tinymce在dialog对话框中层级太低的问题

1.安装 npm install tinymce -S 2.把node_modules\tinymce里面的文件 包括tinymce文件夹 全部复制到static文件夹下面,如下图 3.tinymce默认是英文界面,还需要下载一个中文语言包zh_CN.js https://www.tiny.cloud/get-tiny/language-packages/ 在tinymce文件夹下新建langs文件夹,将下载好的语言包放到langs文件夹下面如图  4.在main.js中引入tinymce  5

Django 中文乱码问题&amp;富文本显示

1.起源:从后台管理添加中文对象,正常,但是再次点击编辑的时候,抛出异常,显示编码问题. 解决:在项目的manage.py 的文件头部添加  import sys  reload(sys)  sys.setdefaultencoding('utf8') 确认有效. 2.正常富文本连着标签内容一起显示出来,需要将富文本放入如下代码中,就可以显示富文本效果了: {% autoescape off %} {{post.content}} {% endautoescape %}

ASP.NET MVC5 中百度ueditor富文本编辑器的使用

随着网站信息发布内容越来越多,越来越重视美观,富文本编辑就是不可缺少的了,众多编辑器比较后我选了百度的ueditor富文本编辑器. 百度ueditor富文本编辑器分为两种一种是完全版的ueditor,另一种是ueditor的迷你版umeditor. 一.我们先讲完全版的ueditor. 1.建立数据模型. 2.建立对应的控制器和视图. 3.访问http://ueditor.baidu.com/website/download.html 进入开发版的下载页面,下载.net UTF-8版本,现在最新

ASP.NET MVC 中使用 UEditor 富文本编辑器

在上篇<使用ASP.NET MVC+Entity Framework快速搭建博客系统>中,已经基本上可以实现博客分类和博客文章的CURD.但是,文章编辑界面实在是-- 好吧,咱得搞专业点.来个传说中的富文本编辑器,度娘了一下,发现 KISSY Editor 和 UEditor 貌似比较简单的样子,既然这样就用百度的 UEditor 吧,到这里下载最新的.NET版. 解压后,将默认目录名称改为 ueditor 然后复制到项目的 Content 目录中,大概就像下图中的样子 打开~/Views/P

在MVC中应用百度富文本编辑器

1.下载.NET版本的百度富文本编辑器,前往 下载.NET版本百度富文本框 2.解压下载的.zip压缩包,将utf8-.net文件夹名称改为:ueditor,复制到MVC根目录下面.结构如下: App_Code 上的文件是应用程序的源码 Config.cs 负责读取配置文件 Handler.cs 是请求处理器的基类,提供了一些基本对象的访问以及输出控制.如果需要增加处理器,应该从该基类继承 PathFormatter.cs 解析 PathFormat,把信息填充为运行时信息. *Handler.

在网站中使用UEditor富文本编辑器

UEditor是由百度WEB前端研发部开发的所见即所得的开源富文本编辑器,具有轻量.可定制.用户体验优秀等特点. 官网链接 进入到下载页面,选择相应的版本下载 这里我们使用ASP.NET开发,所以选择.NET版本. 将文件解压后,目录结构如下: 将外部js引入到页面中 <script src="Assets/js/ueditor/ueditor.config.js" type="text/javascript"></script> <s

在 Vue 项目中引入 tinymce 富文本编辑器

项目中原本使用的富文本编辑器是 wangEditor,这是一个很轻量.简洁编辑器 但是公司的业务升级,想要一个功能更全面的编辑器,我找了好久,目前常见的编辑器有这些: UEditor:百度前端的开源项目,功能强大,基于 jQuery,但已经没有再维护,而且限定了后端代码,修改起来比较费劲 bootstrap-wysiwyg:微型,易用,小而美,只是 Bootstrap + jQuery... kindEditor:功能强大,代码简洁,需要配置后台,而且好久没见更新了 wangEditor:轻量.