mirror of https://github.com/axmolengine/axmol.git
Add RichText
This commit is contained in:
parent
cb5f9ad6dc
commit
5e84c15812
|
@ -1 +1 @@
|
|||
26f668df40952dacb355b81cf7f29a2f31afffcd
|
||||
b8671f5532fbc91d62fd7acbae8b054fbc9816af
|
|
@ -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<RichElementText*>(element);
|
||||
elementRenderer = LabelTTF::create(elmtText->_text.c_str(), elmtText->_fontName.c_str(), elmtText->_fontSize);
|
||||
break;
|
||||
}
|
||||
case RICH_IMAGE:
|
||||
{
|
||||
RichElementImage* elmtImage = static_cast<RichElementImage*>(element);
|
||||
elementRenderer = Sprite::create(elmtImage->_filePath.c_str());
|
||||
break;
|
||||
}
|
||||
case RICH_CUSTOM:
|
||||
{
|
||||
RichElementCustomNode* elmtCustom = static_cast<RichElementCustomNode*>(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<RichElement*>(_richElements.at(i));
|
||||
switch (element->_type)
|
||||
{
|
||||
case RICH_TEXT:
|
||||
{
|
||||
RichElementText* elmtText = static_cast<RichElementText*>(element);
|
||||
handleTextRenderer(elmtText->_text.c_str(), elmtText->_fontName.c_str(), elmtText->_fontSize, elmtText->_color, elmtText->_opacity);
|
||||
break;
|
||||
}
|
||||
case RICH_IMAGE:
|
||||
{
|
||||
RichElementImage* elmtImage = static_cast<RichElementImage*>(element);
|
||||
handleImageRenderer(elmtImage->_filePath.c_str(), elmtImage->_color, elmtImage->_opacity);
|
||||
break;
|
||||
}
|
||||
case RICH_CUSTOM:
|
||||
{
|
||||
RichElementCustomNode* elmtCustom = static_cast<RichElementCustomNode*>(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<Node*>());
|
||||
}
|
||||
|
||||
void RichText::formarRenderers()
|
||||
{
|
||||
if (_ignoreSize)
|
||||
{
|
||||
float newContentSizeWidth = 0.0f;
|
||||
float newContentSizeHeight = 0.0f;
|
||||
|
||||
Vector<Node*>* row = (_elementRenders[0]);
|
||||
float nextPosX = 0.0f;
|
||||
for (int 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, 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<Node*>* row = (_elementRenders[i]);
|
||||
float maxHeight = 0.0f;
|
||||
for (int 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 (int i=0; i<_elementRenders.size(); i++)
|
||||
{
|
||||
Vector<Node*>* row = (_elementRenders[i]);
|
||||
float nextPosX = 0.0f;
|
||||
nextPosY -= (maxHeights[i] + _verticalSpace);
|
||||
|
||||
for (int j=0; j<row->size(); 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<length; i++)
|
||||
{
|
||||
Vector<Node*>* 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
|
|
@ -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<RichElement*> _richElements;
|
||||
std::vector<Vector<Node*>*> _elementRenders;
|
||||
float _leftSpaceWidth;
|
||||
float _verticalSpace;
|
||||
Node* _elementRenderersContainer;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
NS_CC_END
|
||||
|
||||
#endif /* defined(__UIRichText__) */
|
|
@ -540,6 +540,10 @@ SizeType Widget::getSizeType() const
|
|||
|
||||
void Widget::ignoreContentAdaptWithSize(bool ignore)
|
||||
{
|
||||
if (_ignoreSize == ignore)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_ignoreSize = ignore;
|
||||
if (_ignoreSize)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue