zoukankan      html  css  js  c++  java
  • 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("
    ");

            while (pos != std::string::npos)
            {
              std::string s1 = tempStr.substr(0, pos).c_str();
              if (!s1.empty())
              {
                pushBackElement(createWithSet(s1));
              }
              pushBackElement(createWithSet(""));

              tempStr = tempStr.substr(pos + 1).c_str();
              pos = tempStr.find(" ");
            }

            if (!tempStr.empty())
            {
              pushBackElement(createWithSet(tempStr));
            }

    
    

    // 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);
  • 相关阅读:
    spring注解-事务
    docker 安装
    docker 简单介绍
    jupyter配置
    docker 桌面镜像内安装gui程序启动报错
    Linux下安装matlab
    拉取cmake镜像并测试
    桌面镜像安装gui程序
    docker + pycharm 运行
    docker + vscode 运行
  • 原文地址:https://www.cnblogs.com/xioapingguo/p/4037414.html
Copyright © 2011-2022 走看看