diff --git a/build/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id b/build/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id index 6b7b8bb99a..8f1f1fd4dc 100644 --- a/build/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/build/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -26f668df40952dacb355b81cf7f29a2f31afffcd \ No newline at end of file +b8671f5532fbc91d62fd7acbae8b054fbc9816af \ No newline at end of file diff --git a/cocos/gui/UIRichText.cpp b/cocos/gui/UIRichText.cpp new file mode 100644 index 0000000000..8e153ec123 --- /dev/null +++ b/cocos/gui/UIRichText.cpp @@ -0,0 +1,442 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#include "UIRichText.h" + + +NS_CC_BEGIN + +namespace ui { + +bool RichElement::init(int tag, const Color3B &color, GLubyte opacity) +{ + _tag = tag; + _color = color; + _opacity = opacity; + return true; +} + + +RichElementText* RichElementText::create(int tag, const Color3B &color, GLubyte opacity, const char *text, const char *fontName, float fontSize) +{ + RichElementText* element = new RichElementText(); + if (element && element->init(tag, color, opacity, text, fontName, fontSize)) + { + element->autorelease(); + return element; + } + CC_SAFE_DELETE(element); + return NULL; +} + +bool RichElementText::init(int tag, const Color3B &color, GLubyte opacity, const char *text, const char *fontName, float fontSize) +{ + if (RichElement::init(tag, color, opacity)) + { + _text = text; + _fontName = fontName; + _fontSize = fontSize; + return true; + } + return false; +} + +RichElementImage* RichElementImage::create(int tag, const Color3B &color, GLubyte opacity, const char *filePath) +{ + RichElementImage* element = new RichElementImage(); + if (element && element->init(tag, color, opacity, filePath)) + { + element->autorelease(); + return element; + } + CC_SAFE_DELETE(element); + return NULL; +} + +bool RichElementImage::init(int tag, const Color3B &color, GLubyte opacity, const char *filePath) +{ + if (RichElement::init(tag, color, opacity)) + { + _filePath = filePath; + return true; + } + return false; +} + +RichElementCustomNode* RichElementCustomNode::create(int tag, const Color3B &color, GLubyte opacity, cocos2d::Node *customNode) +{ + RichElementCustomNode* element = new RichElementCustomNode(); + if (element && element->init(tag, color, opacity, customNode)) + { + element->autorelease(); + return element; + } + CC_SAFE_DELETE(element); + return NULL; +} + +bool RichElementCustomNode::init(int tag, const Color3B &color, GLubyte opacity, cocos2d::Node *customNode) +{ + if (RichElement::init(tag, color, opacity)) + { + _customNode = customNode; + _customNode->retain(); + return true; + } + return false; +} + +RichText::RichText(): +_formatTextDirty(true), +_richElements(NULL), +_elementRenders(NULL), +_leftSpaceWidth(0.0f), +_verticalSpace(0.0f), +_elementRenderersContainer(NULL) +{ + +} + +RichText::~RichText() +{ + _richElements.clear(); +} + +RichText* RichText::create() +{ + RichText* widget = new RichText(); + if (widget && widget->init()) + { + widget->autorelease(); + return widget; + } + CC_SAFE_DELETE(widget); + return NULL; +} + +bool RichText::init() +{ + if (Widget::init()) + { + return true; + } + return false; +} + +void RichText::initRenderer() +{ + _elementRenderersContainer = Node::create(); + _elementRenderersContainer->setAnchorPoint(Point(0.5f, 0.5f)); + Node::addChild(_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 (int i=0; i<_richElements.size(); i++) + { + RichElement* element = _richElements.at(i); + Node* elementRenderer = NULL; + switch (element->_type) + { + case RICH_TEXT: + { + RichElementText* elmtText = static_cast(element); + elementRenderer = LabelTTF::create(elmtText->_text.c_str(), elmtText->_fontName.c_str(), elmtText->_fontSize); + break; + } + case RICH_IMAGE: + { + RichElementImage* elmtImage = static_cast(element); + elementRenderer = Sprite::create(elmtImage->_filePath.c_str()); + break; + } + case RICH_CUSTOM: + { + RichElementCustomNode* elmtCustom = static_cast(element); + elementRenderer = elmtCustom->_customNode; + break; + } + default: + break; + } + elementRenderer->setColor(element->_color); + elementRenderer->setOpacity(element->_opacity); + pushToContainer(elementRenderer); + } + } + else + { + addNewLine(); + for (int i=0; i<_richElements.size(); i++) + { + + RichElement* element = static_cast(_richElements.at(i)); + switch (element->_type) + { + case RICH_TEXT: + { + RichElementText* elmtText = static_cast(element); + handleTextRenderer(elmtText->_text.c_str(), elmtText->_fontName.c_str(), elmtText->_fontSize, elmtText->_color, elmtText->_opacity); + break; + } + case RICH_IMAGE: + { + RichElementImage* elmtImage = static_cast(element); + handleImageRenderer(elmtImage->_filePath.c_str(), elmtImage->_color, elmtImage->_opacity); + break; + } + case RICH_CUSTOM: + { + RichElementCustomNode* elmtCustom = static_cast(element); + handleCustomRenderer(elmtCustom->_customNode); + break; + } + default: + break; + } + } + } + formarRenderers(); + _formatTextDirty = false; + } +} + +void RichText::handleTextRenderer(const char *text, const char *fontName, float fontSize, const Color3B &color, GLubyte opacity) +{ + LabelTTF* textRenderer = LabelTTF::create(text, fontName, fontSize); + float textRendererWidth = textRenderer->getContentSize().width; + _leftSpaceWidth -= textRendererWidth; + if (_leftSpaceWidth < 0.0f) + { + float overstepPercent = (-_leftSpaceWidth) / textRendererWidth; + std::string curText = text; + int stringLength = curText.length(); + int leftLength = stringLength * (1.0f - overstepPercent); + std::string leftWords = curText.substr(0, leftLength); + std::string cutWords = curText.substr(leftLength, curText.length()-1); + if (leftLength > 0) + { + LabelTTF* leftRenderer = LabelTTF::create(leftWords.substr(0, leftLength).c_str(), fontName, fontSize); + leftRenderer->setColor(color); + leftRenderer->setOpacity(opacity); + pushToContainer(leftRenderer); + } + + addNewLine(); + handleTextRenderer(cutWords.c_str(), fontName, fontSize, color, opacity); + } + else + { + textRenderer->setColor(color); + textRenderer->setOpacity(opacity); + pushToContainer(textRenderer); + } +} + +void RichText::handleImageRenderer(const char *fileParh, const Color3B &color, GLubyte opacity) +{ + Sprite* imageRenderer = Sprite::create(fileParh); + 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()); +} + +void RichText::formarRenderers() +{ + if (_ignoreSize) + { + float newContentSizeWidth = 0.0f; + float newContentSizeHeight = 0.0f; + + Vector* row = (_elementRenders[0]); + float nextPosX = 0.0f; + for (int j=0; jsize(); j++) + { + Node* l = row->at(j); + l->setAnchorPoint(Point::ZERO); + l->setPosition(Point(nextPosX, 0.0f)); + _elementRenderersContainer->addChild(l, 1, j); + 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 (int i=0; i<_elementRenders.size(); i++) + { + Vector* row = (_elementRenders[i]); + float maxHeight = 0.0f; + for (int j=0; jsize(); j++) + { + Node* l = row->at(j); + maxHeight = MAX(l->getContentSize().height, maxHeight); + } + maxHeights[i] = maxHeight; + newContentSizeHeight += maxHeights[i]; + } + + + float nextPosY = _customSize.height; + for (int i=0; i<_elementRenders.size(); i++) + { + Vector* row = (_elementRenders[i]); + float nextPosX = 0.0f; + nextPosY -= (maxHeights[i] + _verticalSpace); + + for (int j=0; jsize(); j++) + { + Node* l = row->at(j); + l->setAnchorPoint(Point::ZERO); + l->setPosition(Point(nextPosX, nextPosY)); + _elementRenderersContainer->addChild(l, 1, i*10 + j); + nextPosX += l->getContentSize().width; + } + } + _elementRenderersContainer->setContentSize(_size); + delete [] maxHeights; + } + + int length = _elementRenders.size(); + for (size_t i = 0; i* l = _elementRenders[i]; + l->clear(); + delete l; + } + _elementRenders.clear(); + + if (_ignoreSize) + { + Size s = getContentSize(); + _size = s; + } + else + { + _size = _customSize; + } +} + +void RichText::pushToContainer(cocos2d::Node *renderer) +{ + if (_elementRenders.size() <= 0) + { + return; + } + _elementRenders[_elementRenders.size()-1]->pushBack(renderer); +} + +void RichText::visit(cocos2d::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::getContentSize() const +{ + return _elementRenderersContainer->getContentSize(); +} + +void RichText::ignoreContentAdaptWithSize(bool ignore) +{ + if (_ignoreSize != ignore) + { + _formatTextDirty = true; + Widget::ignoreContentAdaptWithSize(ignore); + } +} + +} + +NS_CC_END \ No newline at end of file diff --git a/cocos/gui/UIRichText.h b/cocos/gui/UIRichText.h new file mode 100644 index 0000000000..444c8fd03a --- /dev/null +++ b/cocos/gui/UIRichText.h @@ -0,0 +1,133 @@ +/**************************************************************************** + Copyright (c) 2013 cocos2d-x.org + + http://www.cocos2d-x.org + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + ****************************************************************************/ + +#ifndef __UIRICHTEXT_H__ +#define __UIRICHTEXT_H__ + +#include "gui/UIWidget.h" + +NS_CC_BEGIN + +namespace ui { + +typedef enum { + RICH_TEXT, + RICH_IMAGE, + RICH_CUSTOM +}RichElementType; + +class RichElement : public Ref +{ +public: + RichElement(){}; + virtual ~RichElement(){}; + bool init(int tag, const Color3B& color, GLubyte opacity); +protected: + RichElementType _type; + int _tag; + Color3B _color; + GLubyte _opacity; + friend class RichText; +}; + +class RichElementText : public RichElement +{ +public: + RichElementText(){_type = RICH_TEXT;}; + virtual ~RichElementText(){}; + bool init(int tag, const Color3B& color, GLubyte opacity, const char* text, const char* fontName, float fontSize); + static RichElementText* create(int tag, const Color3B& color, GLubyte opacity, const char* text, const char* fontName, float fontSize); +protected: + std::string _text; + std::string _fontName; + float _fontSize; + friend class RichText; + +}; + +class RichElementImage : public RichElement +{ +public: + RichElementImage(){_type = RICH_IMAGE;}; + virtual ~RichElementImage(){}; + bool init(int tag, const Color3B& color, GLubyte opacity, const char* filePath); + static RichElementImage* create(int tag, const Color3B& color, GLubyte opacity, const char* filePath); +protected: + std::string _filePath; + Rect _textureRect; + int _textureType; + friend class RichText; +}; + +class RichElementCustomNode : public RichElement +{ +public: + RichElementCustomNode(){_type = RICH_CUSTOM;}; + virtual ~RichElementCustomNode(){CC_SAFE_RELEASE(_customNode);}; + bool init(int tag, const Color3B& color, GLubyte opacity, Node* customNode); + static RichElementCustomNode* create(int tag, const Color3B& color, GLubyte opacity, Node* customNode); +protected: + Node* _customNode; + friend class RichText; +}; + +class RichText : public Widget +{ +public: + RichText(); + virtual ~RichText(); + static RichText* create(); + void insertElement(RichElement* element, int index); + void pushBackElement(RichElement* element); + void removeElement(int index); + void removeElement(RichElement* element); + virtual void visit(cocos2d::Renderer *renderer, const kmMat4 &parentTransform, bool parentTransformUpdated) override; + void setVerticalSpace(float space); + virtual void setAnchorPoint(const Point &pt); + virtual const Size& getContentSize() const; + void formatText(); + virtual void ignoreContentAdaptWithSize(bool ignore); +protected: + virtual bool init(); + virtual void initRenderer(); + void pushToContainer(Node* renderer); + void handleTextRenderer(const char* text, const char* fontName, float fontSize, const Color3B& color, GLubyte opacity); + void handleImageRenderer(const char* fileParh, const Color3B& color, GLubyte opacity); + void handleCustomRenderer(Node* renderer); + void formarRenderers(); + void addNewLine(); +protected: + bool _formatTextDirty; + Vector _richElements; + std::vector*> _elementRenders; + float _leftSpaceWidth; + float _verticalSpace; + Node* _elementRenderersContainer; +}; + +} + +NS_CC_END + +#endif /* defined(__UIRichText__) */ diff --git a/cocos/gui/UIWidget.cpp b/cocos/gui/UIWidget.cpp index 4c90e1f700..08717622ea 100644 --- a/cocos/gui/UIWidget.cpp +++ b/cocos/gui/UIWidget.cpp @@ -540,6 +540,10 @@ SizeType Widget::getSizeType() const void Widget::ignoreContentAdaptWithSize(bool ignore) { + if (_ignoreSize == ignore) + { + return; + } _ignoreSize = ignore; if (_ignoreSize) {