#ifndef __LAYOUT_H__
#define __LAYOUT_H__
#include "ui/UIWidget.h"
NS_CC_BEGIN
namespace ui {
typedef enum
{
LAYOUT_COLOR_NONE,//空
LAYOUT_COLOR_SOLID,//单一固定颜色的
LAYOUT_COLOR_GRADIENT//有梯度变化的
}LayoutBackGroundColorType;//容器背景颜色类型
typedef enum
{
LAYOUT_ABSOLUTE,//绝对
LAYOUT_LINEAR_VERTICAL,//线性 垂直
LAYOUT_LINEAR_HORIZONTAL,//线性 水平
LAYOUT_RELATIVE// 平面
}LayoutType;//容器类型
typedef enum {
LAYOUT_CLIPPING_STENCIL,//模板
LAYOUT_CLIPPING_SCISSOR//镂空
}LayoutClippingType;//容器裁切类型
/**
* @js NA
* @lua NA
*/
class LayoutExecutant;
class Layout : public Widget
{
DECLARE_CLASS_GUI_INFO
public:
Layout();
virtual ~Layout();
static Layout* create();
//background
/**设置背景图
* @param fileName 图片路径
* @param texType @see TextureResType.
*/
void setBackGroundImage(const std::string& fileName,TextureResType texType = UI_TEX_TYPE_LOCAL);
/**如果背景图是9宫格 设置拉伸尺度
* @param capinsets of background image.
*/
void setBackGroundImageCapInsets(const Rect& capInsets);
const Rect& getBackGroundImageCapInsets();
/**设置背景颜色类型*/
void setBackGroundColorType(LayoutBackGroundColorType type);
LayoutBackGroundColorType getBackGroundColorType();
/**设置背景是否使用9宫格 默认不使用*/
void setBackGroundImageScale9Enabled(bool enabled);
bool isBackGroundImageScale9Enabled();
/**设置背景颜色, 如果颜色类型是固定的*/
void setBackGroundColor(const Color3B &color);
const Color3B& getBackGroundColor();
/**设置背景颜色, 如果颜色类型是 渐变的
* @param start color
* @param end color
*/
void setBackGroundColor(const Color3B &startColor, const Color3B &endColor);
const Color3B& getBackGroundStartColor();
const Color3B& getBackGroundEndColor();
/** 设置透明度.*/
void setBackGroundColorOpacity(GLubyte opacity);
GLubyte getBackGroundColorOpacity();
/** 如果背景颜色是渐变的 设置背景颜色渐变的向量
* @param vector
*/
void setBackGroundColorVector(const Point &vector);
const Point& getBackGroundColorVector();
void setBackGroundImageColor(const Color3B& color);
void setBackGroundImageOpacity(GLubyte opacity);
const Color3B& getBackGroundImageColor();
GLubyte getBackGroundImageOpacity();
/**
* 移除背景img
*/
void removeBackGroundImage();
/**得到背景img size*/
const Size& getBackGroundImageTextureSize() const;
/**
* 设置布局可以裁切他的内荣和孩子 默认不裁切
*如果你真的需要这个,请启用该功能。但它会降低渲染效率。
* @param clipping enabled.
*/
virtual void setClippingEnabled(bool enabled);
/**设置裁切类型*/
void setClippingType(LayoutClippingType type);
LayoutClippingType getClippingType();
/**是否可以裁切*/
virtual bool isClippingEnabled();
/**
* Returns the "class name" of widget.
*/
virtual std::string getDescription() const override;
/**设置容器类型*/
virtual void setLayoutType(LayoutType type);
/**得到容器类型*/
virtual LayoutType getLayoutType() const;
virtual void addChild(Node * child) override;
virtual void addChild(Node * child, int zOrder) override;
virtual void addChild(Node* child, int zOrder, int tag) override;
virtual void visit(Renderer *renderer, const kmMat4 &parentTransform, bool parentTransformUpdated) override;
virtual void removeChild(Node* child, bool cleanup = true) override;
virtual void removeAllChildren() override;
/**
* Removes all children from the container,并做了清理所有正在运行的动作
*/
virtual void removeAllChildrenWithCleanup(bool cleanup) override;
virtual void sortAllChildren() override;
void requestDoLayout();
virtual void onEnter() override;
virtual void onExit() override;
CC_CONSTRUCTOR_ACCESS:
//override "init" method of widget.
virtual bool init() override;
protected:
//override "onSizeChanged" method of widget.
virtual void onSizeChanged() override;
//init background image renderer.
void addBackGroundImage();
void supplyTheLayoutParameterLackToChild(Widget* child);
virtual Widget* createCloneInstance() override;
virtual void copySpecialProperties(Widget* model) override;
virtual void copyClonedWidgetChildren(Widget* model) override;
/**模板类型的裁切渲染*/
void stencilClippingVisit(Renderer *renderer, const kmMat4& parentTransform, bool parentTransformUpdated);
/**镂空类型的裁切渲染*/
void scissorClippingVisit(Renderer *renderer, const kmMat4& parentTransform, bool parentTransformUpdated);
/**设置裁切模板size*/
void setStencilClippingSize(const Size& size);
const Rect& getClippingRect();
virtual void doLayout();
//clipping
void onBeforeVisitStencil();
void onAfterDrawStencil();
void onAfterVisitStencil();
void onBeforeVisitScissor();
void onAfterVisitScissor();
void updateBackGroundImageColor();
void updateBackGroundImageOpacity();
void updateBackGroundImageRGBA();
LayoutExecutant* createCurrentLayoutExecutant();
protected:
bool _clippingEnabled;//是否裁切
//background
bool _backGroundScale9Enabled;//是否开启9宫格
Node* _backGroundImage;//背景图
std::string _backGroundImageFileName;//背景name
Rect _backGroundImageCapInsets;//拉伸区域
LayoutBackGroundColorType _colorType;//背景颜色类型
TextureResType _bgImageTexType;//贴图类型
LayerColor* _colorRender;//正常渲染层 当前只用一个 由类型决定
LayerGradient* _gradientRender;//渐变渲染层
Color3B _cColor;//正常模式颜色值
Color3B _gStartColor;//渐变模式颜色的开始值
Color3B _gEndColor;//渐变模式颜色的结束值
Point _alongVector;//渐变颜色方向
GLubyte _cOpacity;//透明度
Size _backGroundImageTextureSize;//背景贴图size
LayoutType _layoutType;//容器类型
LayoutClippingType _clippingType;//裁切类型
DrawNode* _clippingStencil;//绘制几何裁切区域
bool _scissorRectDirty;//多余的变量
Rect _clippingRect;//裁切的区域
Layout* _clippingParent;//裁切布局
bool _doLayoutDirty;//是否开启布局
bool _clippingRectDirty;//是否计算裁切区域 默认true 由于计算裁切区域逻辑较复杂
//所以计算一次之后就不计算了 _clippingRectDirty = false;
//clipping
GLboolean _currentStencilEnabled;
GLuint _currentStencilWriteMask;
GLenum _currentStencilFunc;
GLint _currentStencilRef;
GLuint _currentStencilValueMask;
GLenum _currentStencilFail;
GLenum _currentStencilPassDepthFail;
GLenum _currentStencilPassDepthPass;
GLboolean _currentDepthWriteMask;
GLboolean _currentAlphaTestEnabled;
GLenum _currentAlphaTestFunc;
GLclampf _currentAlphaTestRef;
Color3B _backGroundImageColor;
GLubyte _backGroundImageOpacity;
LayoutExecutant* _curLayoutExecutant;//布局执行者
GLint _mask_layer_le;
GroupCommand _groupCommand;
CustomCommand _beforeVisitCmdStencil;
CustomCommand _afterDrawStencilCmd;
CustomCommand _afterVisitCmdStencil;
CustomCommand _beforeVisitCmdScissor;
CustomCommand _afterVisitCmdScissor;
};
}
NS_CC_END
#endif /* defined(__Layout__) */
#include "ui/UILayout.h"
#include "ui/UIHelper.h"
#include "extensions/GUI/CCControlExtension/CCScale9Sprite.h"
#include "kazmath/GL/matrix.h"
#include "CCGLProgram.h"
#include "CCShaderCache.h"
#include "CCDirector.h"
#include "CCDrawingPrimitives.h"
#include "renderer/CCRenderer.h"
#include "renderer/CCGroupCommand.h"
#include "renderer/CCCustomCommand.h"
NS_CC_BEGIN
namespace ui {
//布局执行者
class LayoutExecutant : public Ref
{
public:
LayoutExecutant(){};
virtual ~LayoutExecutant(){};
static LayoutExecutant* create();
virtual void doLayout(const Size& layoutSize, Vector<Node*> container){};
};
//线性垂直 布局执行者
class LinearVerticalLayoutExecutant : public LayoutExecutant
{
public:
LinearVerticalLayoutExecutant(){};
virtual ~LinearVerticalLayoutExecutant(){};
static LinearVerticalLayoutExecutant* create();
virtual void doLayout(const Size& layoutSize, Vector<Node*> container);
};
//线性水平 布局执行者
class LinearHorizontalLayoutExecutant : public LayoutExecutant
{
public:
LinearHorizontalLayoutExecutant(){};
virtual ~LinearHorizontalLayoutExecutant(){};
static LinearHorizontalLayoutExecutant* create();
virtual void doLayout(const Size& layoutSize, Vector<Node*> container);
};
//相对 布局执行者
class RelativeLayoutExecutant : public LayoutExecutant
{
public:
RelativeLayoutExecutant(){};
virtual ~RelativeLayoutExecutant(){};
static RelativeLayoutExecutant* create();
virtual void doLayout(const Size& layoutSize, Vector<Node*> container);
};
LayoutExecutant* LayoutExecutant::create()
{
LayoutExecutant* exe = new LayoutExecutant();
if (exe)
{
exe->autorelease();
return exe;
}
CC_SAFE_DELETE(exe);
return nullptr;
}
LinearVerticalLayoutExecutant* LinearVerticalLayoutExecutant::create()
{
LinearVerticalLayoutExecutant* exe = new LinearVerticalLayoutExecutant();
if (exe)
{
exe->autorelease();
return exe;
}
CC_SAFE_DELETE(exe);
return nullptr;
}
LinearHorizontalLayoutExecutant* LinearHorizontalLayoutExecutant::create()
{
LinearHorizontalLayoutExecutant* exe = new LinearHorizontalLayoutExecutant();
if (exe)
{
exe->autorelease();
return exe;
}
CC_SAFE_DELETE(exe);
return nullptr;
}
RelativeLayoutExecutant* RelativeLayoutExecutant::create()
{
RelativeLayoutExecutant* exe = new RelativeLayoutExecutant();
if (exe)
{
exe->autorelease();
return exe;
}
CC_SAFE_DELETE(exe);
return nullptr;
}
//线性垂直 布局执行者
void LinearVerticalLayoutExecutant::doLayout(const cocos2d::Size &layoutSize, Vector<cocos2d::Node *> container)
{
float topBoundary = layoutSize.height;//布局高度
for (auto& subWidget : container)//遍历所有容器
{
Widget* child = dynamic_cast<Widget*>(subWidget);
if (child)//是widget类型
{
LinearLayoutParameter* layoutParameter = dynamic_cast<LinearLayoutParameter*>(child->getLayoutParameter(LAYOUT_PARAMETER_LINEAR));
if (layoutParameter)//是线性布局参数
{
LinearGravity childGravity = layoutParameter->getGravity();//重力类型
Point ap = child->getAnchorPoint();//锚点
Size cs = child->getSize();//大小
float finalPosX = ap.x * cs.width;//最终X位置
float finalPosY = topBoundary - ((1.0f-ap.y) * cs.height);//最终Y位置
switch (childGravity)
{
case LINEAR_GRAVITY_NONE:
case LINEAR_GRAVITY_LEFT:
break;
case LINEAR_GRAVITY_RIGHT:
finalPosX = layoutSize.width - ((1.0f - ap.x) * cs.width);//最终X位置
break;
case LINEAR_GRAVITY_CENTER_HORIZONTAL:
finalPosX = layoutSize.width / 2.0f - cs.width * (0.5f-ap.x);//最终Y位置
break;
default:
break;
}
Margin mg = layoutParameter->getMargin();//得到间距
finalPosX += mg.left;//加上左间距 右移
finalPosY -= mg.top;//减去上间距 下移
child->setPosition(Point(finalPosX, finalPosY));
topBoundary = child->getBottomInParent() - mg.bottom;
}
}
}
}
//线性水平 布局执行者 类似上
void LinearHorizontalLayoutExecutant::doLayout(const cocos2d::Size &layoutSize, Vector<cocos2d::Node *> container)
{
float leftBoundary = 0.0f;
for (auto& subWidget : container)
{
Widget* child = dynamic_cast<Widget*>(subWidget);
if (child)
{
LinearLayoutParameter* layoutParameter = dynamic_cast<LinearLayoutParameter*>(child->getLayoutParameter(LAYOUT_PARAMETER_LINEAR));
if (layoutParameter)
{
LinearGravity childGravity = layoutParameter->getGravity();
Point ap = child->getAnchorPoint();
Size cs = child->getSize();
float finalPosX = leftBoundary + (ap.x * cs.width);
float finalPosY = layoutSize.height - (1.0f - ap.y) * cs.height;
switch (childGravity)
{
case LINEAR_GRAVITY_NONE:
case LINEAR_GRAVITY_TOP:
break;
case LINEAR_GRAVITY_BOTTOM:
finalPosY = ap.y * cs.height;
break;
case LINEAR_GRAVITY_CENTER_VERTICAL:
finalPosY = layoutSize.height / 2.0f - cs.height * (0.5f - ap.y);
break;
default:
break;
}
Margin mg = layoutParameter->getMargin();
finalPosX += mg.left;
finalPosY -= mg.top;
child->setPosition(Point(finalPosX, finalPosY));
leftBoundary = child->getRightInParent() + mg.right;
}
}
}
}
//相对 布局执行者
void RelativeLayoutExecutant::doLayout(const cocos2d::Size &layoutSize, Vector<cocos2d::Node *> container)
{
ssize_t unlayoutChildCount = 0;
Vector<Widget*> widgetChildren;
for (auto& subWidget : container)
{
Widget* child = dynamic_cast<Widget*>(subWidget);
if (child)
{
RelativeLayoutParameter* layoutParameter = dynamic_cast<RelativeLayoutParameter*>(child->getLayoutParameter(LAYOUT_PARAMETER_RELATIVE));
layoutParameter->_put = false;
unlayoutChildCount++;
widgetChildren.pushBack(child);
}
}
while (unlayoutChildCount > 0)
{
for (auto& subWidget : widgetChildren)
{
Widget* child = static_cast<Widget*>(subWidget);
RelativeLayoutParameter* layoutParameter = dynamic_cast<RelativeLayoutParameter*>(child->getLayoutParameter(LAYOUT_PARAMETER_RELATIVE));
if (layoutParameter)
{
if (layoutParameter->_put)
{
continue;
}
Point ap = child->getAnchorPoint();
Size cs = child->getSize();
RelativeAlign align = layoutParameter->getAlign();
const char* relativeName = layoutParameter->getRelativeToWidgetName();
Widget* relativeWidget = nullptr;
RelativeLayoutParameter* relativeWidgetLP = nullptr;
float finalPosX = 0.0f;
float finalPosY = 0.0f;
if (relativeName && strcmp(relativeName, ""))
{
for (auto& sWidget : widgetChildren)
{
if (sWidget)
{
RelativeLayoutParameter* rlayoutParameter = dynamic_cast<RelativeLayoutParameter*>(sWidget->getLayoutParameter(LAYOUT_PARAMETER_RELATIVE));
if (rlayoutParameter && strcmp(rlayoutParameter->getRelativeName(), relativeName) == 0)
{
relativeWidget = sWidget;
relativeWidgetLP = rlayoutParameter;
break;
}
}
}
}
switch (align)
{
case RELATIVE_ALIGN_NONE:
case RELATIVE_ALIGN_PARENT_TOP_LEFT:
finalPosX = ap.x * cs.width;
finalPosY = layoutSize.height - ((1.0f - ap.y) * cs.height);
break;
case RELATIVE_ALIGN_PARENT_TOP_CENTER_HORIZONTAL:
finalPosX = layoutSize.width * 0.5f - cs.width * (0.5f - ap.x);
finalPosY = layoutSize.height - ((1.0f - ap.y) * cs.height);
break;
case RELATIVE_ALIGN_PARENT_TOP_RIGHT:
finalPosX = layoutSize.width - ((1.0f - ap.x) * cs.width);
finalPosY = layoutSize.height - ((1.0f - ap.y) * cs.height);
break;
case RELATIVE_ALIGN_PARENT_LEFT_CENTER_VERTICAL:
finalPosX = ap.x * cs.width;
finalPosY = layoutSize.height * 0.5f - cs.height * (0.5f - ap.y);
break;
case RELATIVE_CENTER_IN_PARENT:
finalPosX = layoutSize.width * 0.5f - cs.width * (0.5f - ap.x);
finalPosY = layoutSize.height * 0.5f - cs.height * (0.5f - ap.y);
break;
case RELATIVE_ALIGN_PARENT_RIGHT_CENTER_VERTICAL:
finalPosX = layoutSize.width - ((1.0f - ap.x) * cs.width);
finalPosY = layoutSize.height * 0.5f - cs.height * (0.5f - ap.y);
break;
case RELATIVE_ALIGN_PARENT_LEFT_BOTTOM:
finalPosX = ap.x * cs.width;
finalPosY = ap.y * cs.height;
break;
case RELATIVE_ALIGN_PARENT_BOTTOM_CENTER_HORIZONTAL:
finalPosX = layoutSize.width * 0.5f - cs.width * (0.5f - ap.x);
finalPosY = ap.y * cs.height;
break;
case RELATIVE_ALIGN_PARENT_RIGHT_BOTTOM:
finalPosX = layoutSize.width - ((1.0f - ap.x) * cs.width);
finalPosY = ap.y * cs.height;
break;
case RELATIVE_LOCATION_ABOVE_LEFTALIGN:
if (relativeWidget)
{
if (relativeWidgetLP && !relativeWidgetLP->_put)
{
continue;
}
float locationBottom = relativeWidget->getTopInParent();
float locationLeft = relativeWidget->getLeftInParent();
finalPosY = locationBottom + ap.y * cs.height;
finalPosX = locationLeft + ap.x * cs.width;
}
break;
case RELATIVE_LOCATION_ABOVE_CENTER:
if (relativeWidget)
{
if (relativeWidgetLP && !relativeWidgetLP->_put)
{
continue;
}
Size rbs = relativeWidget->getSize();
float locationBottom = relativeWidget->getTopInParent();
finalPosY = locationBottom + ap.y * cs.height;
finalPosX = relativeWidget->getLeftInParent() + rbs.width * 0.5f + ap.x * cs.width - cs.width * 0.5f;
}
break;
case RELATIVE_LOCATION_ABOVE_RIGHTALIGN:
if (relativeWidget)
{
if (relativeWidgetLP && !relativeWidgetLP->_put)
{
continue;
}
float locationBottom = relativeWidget->getTopInParent();
float locationRight = relativeWidget->getRightInParent();
finalPosY = locationBottom + ap.y * cs.height;
finalPosX = locationRight - (1.0f - ap.x) * cs.width;
}
break;
case RELATIVE_LOCATION_LEFT_OF_TOPALIGN:
if (relativeWidget)
{
if (relativeWidgetLP && !relativeWidgetLP->_put)
{
continue;
}
float locationTop = relativeWidget->getTopInParent();
float locationRight = relativeWidget->getLeftInParent();
finalPosY = locationTop - (1.0f - ap.y) * cs.height;
finalPosX = locationRight - (1.0f - ap.x) * cs.width;
}
break;
case RELATIVE_LOCATION_LEFT_OF_CENTER:
if (relativeWidget)
{
if (relativeWidgetLP && !relativeWidgetLP->_put)
{
continue;
}
Size rbs = relativeWidget->getSize();
float locationRight = relativeWidget->getLeftInParent();
finalPosX = locationRight - (1.0f - ap.x) * cs.width;
finalPosY = relativeWidget->getBottomInParent() + rbs.height * 0.5f + ap.y * cs.height - cs.height * 0.5f;
}
break;
case RELATIVE_LOCATION_LEFT_OF_BOTTOMALIGN:
if (relativeWidget)
{
if (relativeWidgetLP && !relativeWidgetLP->_put)
{
continue;
}
float locationBottom = relativeWidget->getBottomInParent();
float locationRight = relativeWidget->getLeftInParent();
finalPosY = locationBottom + ap.y * cs.height;
finalPosX = locationRight - (1.0f - ap.x) * cs.width;
}
break;
case RELATIVE_LOCATION_RIGHT_OF_TOPALIGN:
if (relativeWidget)
{
if (relativeWidgetLP && !relativeWidgetLP->_put)
{
continue;
}
float locationTop = relativeWidget->getTopInParent();
float locationLeft = relativeWidget->getRightInParent();
finalPosY = locationTop - (1.0f - ap.y) * cs.height;
finalPosX = locationLeft + ap.x * cs.width;
}
break;
case RELATIVE_LOCATION_RIGHT_OF_CENTER:
if (relativeWidget)
{
if (relativeWidgetLP && !relativeWidgetLP->_put)
{
continue;
}
Size rbs = relativeWidget->getSize();
float locationLeft = relativeWidget->getRightInParent();
finalPosX = locationLeft + ap.x * cs.width;
finalPosY = relativeWidget->getBottomInParent() + rbs.height * 0.5f + ap.y * cs.height - cs.height * 0.5f;
}
break;
case RELATIVE_LOCATION_RIGHT_OF_BOTTOMALIGN:
if (relativeWidget)
{
if (relativeWidgetLP && !relativeWidgetLP->_put)
{
continue;
}
float locationBottom = relativeWidget->getBottomInParent();
float locationLeft = relativeWidget->getRightInParent();
finalPosY = locationBottom + ap.y * cs.height;
finalPosX = locationLeft + ap.x * cs.width;
}
break;
case RELATIVE_LOCATION_BELOW_LEFTALIGN:
if (relativeWidget)
{
if (relativeWidgetLP && !relativeWidgetLP->_put)
{
continue;
}
float locationTop = relativeWidget->getBottomInParent();
float locationLeft = relativeWidget->getLeftInParent();
finalPosY = locationTop - (1.0f - ap.y) * cs.height;
finalPosX = locationLeft + ap.x * cs.width;
}
break;
case RELATIVE_LOCATION_BELOW_CENTER:
if (relativeWidget)
{
if (relativeWidgetLP && !relativeWidgetLP->_put)
{
continue;
}
Size rbs = relativeWidget->getSize();
float locationTop = relativeWidget->getBottomInParent();
finalPosY = locationTop - (1.0f - ap.y) * cs.height;
finalPosX = relativeWidget->getLeftInParent() + rbs.width * 0.5f + ap.x * cs.width - cs.width * 0.5f;
}
break;
case RELATIVE_LOCATION_BELOW_RIGHTALIGN:
if (relativeWidget)
{
if (relativeWidgetLP && !relativeWidgetLP->_put)
{
continue;
}
float locationTop = relativeWidget->getBottomInParent();
float locationRight = relativeWidget->getRightInParent();
finalPosY = locationTop - (1.0f - ap.y) * cs.height;
finalPosX = locationRight - (1.0f - ap.x) * cs.width;
}
break;
default:
break;
}
Margin relativeWidgetMargin;
Margin mg = layoutParameter->getMargin();
if (relativeWidgetLP)
{
relativeWidgetMargin = relativeWidgetLP->getMargin();
}
//handle margin
switch (align)
{
case RELATIVE_ALIGN_NONE:
case RELATIVE_ALIGN_PARENT_TOP_LEFT:
finalPosX += mg.left;
finalPosY -= mg.top;
break;
case RELATIVE_ALIGN_PARENT_TOP_CENTER_HORIZONTAL:
finalPosY -= mg.top;
break;
case RELATIVE_ALIGN_PARENT_TOP_RIGHT:
finalPosX -= mg.right;
finalPosY -= mg.top;
break;
case RELATIVE_ALIGN_PARENT_LEFT_CENTER_VERTICAL:
finalPosX += mg.left;
break;
case RELATIVE_CENTER_IN_PARENT:
break;
case RELATIVE_ALIGN_PARENT_RIGHT_CENTER_VERTICAL:
finalPosX -= mg.right;
break;
case RELATIVE_ALIGN_PARENT_LEFT_BOTTOM:
finalPosX += mg.left;
finalPosY += mg.bottom;
break;
case RELATIVE_ALIGN_PARENT_BOTTOM_CENTER_HORIZONTAL:
finalPosY += mg.bottom;
break;
case RELATIVE_ALIGN_PARENT_RIGHT_BOTTOM:
finalPosX -= mg.right;
finalPosY += mg.bottom;
break;
case RELATIVE_LOCATION_ABOVE_LEFTALIGN:
finalPosY += mg.bottom;
finalPosX += mg.left;
break;
case RELATIVE_LOCATION_ABOVE_RIGHTALIGN:
finalPosY += mg.bottom;
finalPosX -= mg.right;
break;
case RELATIVE_LOCATION_ABOVE_CENTER:
finalPosY += mg.bottom;
break;
case RELATIVE_LOCATION_LEFT_OF_TOPALIGN:
finalPosX -= mg.right;
finalPosY -= mg.top;
break;
case RELATIVE_LOCATION_LEFT_OF_BOTTOMALIGN:
finalPosX -= mg.right;
finalPosY += mg.bottom;
break;
case RELATIVE_LOCATION_LEFT_OF_CENTER:
finalPosX -= mg.right;
break;
case RELATIVE_LOCATION_RIGHT_OF_TOPALIGN:
finalPosX += mg.left;
finalPosY -= mg.top;
break;
case RELATIVE_LOCATION_RIGHT_OF_BOTTOMALIGN:
finalPosX += mg.left;
finalPosY += mg.bottom;
break;
case RELATIVE_LOCATION_RIGHT_OF_CENTER:
finalPosX += mg.left;
break;
case RELATIVE_LOCATION_BELOW_LEFTALIGN:
finalPosY -= mg.top;
finalPosX += mg.left;
break;
case RELATIVE_LOCATION_BELOW_RIGHTALIGN:
finalPosY -= mg.top;
finalPosX -= mg.right;
break;
case RELATIVE_LOCATION_BELOW_CENTER:
finalPosY -= mg.top;
break;
default:
break;
}
child->setPosition(Point(finalPosX, finalPosY));
layoutParameter->_put = true;
unlayoutChildCount--;
}
}
}
widgetChildren.clear();
}
//渲染层Zorder
static const int BACKGROUNDIMAGE_Z = (-1);
static const int BCAKGROUNDCOLORRENDERER_Z = (-2);
static GLint g_sStencilBits = -1;
static GLint s_layer = -1;
IMPLEMENT_CLASS_GUI_INFO(Layout)
Layout::Layout():
_clippingEnabled(false),
_backGroundScale9Enabled(false),
_backGroundImage(nullptr),
_backGroundImageFileName(""),
_backGroundImageCapInsets(Rect::ZERO),
_colorType(LAYOUT_COLOR_NONE),
_bgImageTexType(UI_TEX_TYPE_LOCAL),
_colorRender(nullptr),
_gradientRender(nullptr),
_cColor(Color3B::WHITE),
_gStartColor(Color3B::WHITE),
_gEndColor(Color3B::WHITE),
_alongVector(Point(0.0f, -1.0f)),
_cOpacity(255),
_backGroundImageTextureSize(Size::ZERO),
_layoutType(LAYOUT_ABSOLUTE),
_clippingType(LAYOUT_CLIPPING_STENCIL),
_clippingStencil(nullptr),
_scissorRectDirty(false),
_clippingRect(Rect::ZERO),
_clippingParent(nullptr),
_doLayoutDirty(true),
_clippingRectDirty(true),
_currentStencilEnabled(GL_FALSE),
_currentStencilWriteMask(~0),
_currentStencilFunc(GL_ALWAYS),
_currentStencilRef(0),
_currentStencilValueMask(~0),
_currentStencilFail(GL_KEEP),
_currentStencilPassDepthFail(GL_KEEP),
_currentStencilPassDepthPass(GL_KEEP),
_currentDepthWriteMask(GL_TRUE),
_currentAlphaTestEnabled(GL_FALSE),
_currentAlphaTestFunc(GL_ALWAYS),
_currentAlphaTestRef(1),
_backGroundImageColor(Color3B::WHITE),
_backGroundImageOpacity(255),
_curLayoutExecutant(nullptr)
{
_widgetType = WidgetTypeContainer;//默认 为容器类型
}
Layout::~Layout()
{
CC_SAFE_RELEASE(_clippingStencil);
CC_SAFE_RELEASE(_curLayoutExecutant);
}
void Layout::onEnter()
{
Widget::onEnter();
if (_clippingStencil)
{
_clippingStencil->onEnter();
}
_doLayoutDirty = true;//可以布局
_clippingRectDirty = true;//可以计算裁切矩形
}
void Layout::onExit()
{
Widget::onExit();
if (_clippingStencil)
{
_clippingStencil->onExit();
}
}
Layout* Layout::create()
{
Layout* layout = new Layout();
if (layout && layout->init())
{
layout->autorelease();
return layout;
}
CC_SAFE_DELETE(layout);
return nullptr;
}
bool Layout::init()
{
if (ProtectedNode::init())
{
initRenderer();
setBright(true);
ignoreContentAdaptWithSize(false);
setSize(Size::ZERO);
setAnchorPoint(Point::ZERO);//锚点左下
return true;
}
return false;
}
void Layout::addChild(Node *child)
{
Widget::addChild(child);
}
void Layout::addChild(Node * child, int zOrder)
{
Widget::addChild(child, zOrder);
}
void Layout::addChild(Node *child, int zOrder, int tag)
{
supplyTheLayoutParameterLackToChild(static_cast<Widget*>(child));//设置布局参数
Widget::addChild(child, zOrder, tag);//添加child
_doLayoutDirty = true;
}
void Layout::removeChild(Node *child, bool cleanup)
{
Widget::removeChild(child, cleanup);
_doLayoutDirty = true;
}
void Layout::removeAllChildren()
{
Widget::removeAllChildren();
}
void Layout::removeAllChildrenWithCleanup(bool cleanup)
{
Widget::removeAllChildrenWithCleanup(cleanup);
_doLayoutDirty = true;
}
bool Layout::isClippingEnabled()
{
return _clippingEnabled;
}
void Layout::visit(Renderer *renderer, const kmMat4 &parentTransform, bool parentTransformUpdated)
{
if (!_enabled)//不可用就直接return
{
return;
}
adaptRenderers();//对应各自的逻辑处理
if (_clippingEnabled)//可以裁切
{
switch (_clippingType)//裁切类型
{
case LAYOUT_CLIPPING_STENCIL://模板
stencilClippingVisit(renderer, parentTransform, parentTransformUpdated);//专属自己的visit
break;
case LAYOUT_CLIPPING_SCISSOR://镂空
scissorClippingVisit(renderer, parentTransform, parentTransformUpdated);//专属自己的visit
break;
default:
break;
}
}
else//不可以裁切 基本的visit
{
ProtectedNode::visit(renderer, parentTransform, parentTransformUpdated);
}
}
void Layout::sortAllChildren()
{
Widget::sortAllChildren();//排序子节点
doLayout();//布局
}
//模板类型裁切
void Layout::stencilClippingVisit(Renderer *renderer, const kmMat4 &parentTransform, bool parentTransformUpdated)
{
if(!_visible)
return;
bool dirty = parentTransformUpdated || _transformUpdated;
if(dirty)
_modelViewTransform = transform(parentTransform);
_transformUpdated = false;
// IMPORTANT:
// To ease the migration to v3.0, we still support the kmGL stack,
// but it is deprecated and your code should not rely on it
kmGLPushMatrix();
kmGLLoadMatrix(&_modelViewTransform);
//Add group command
_groupCommand.init(_globalZOrder);
renderer->addCommand(&_groupCommand);
renderer->pushGroup(_groupCommand.getRenderQueueID());
_beforeVisitCmdStencil.init(_globalZOrder);
_beforeVisitCmdStencil.func = CC_CALLBACK_0(Layout::onBeforeVisitStencil, this);
renderer->addCommand(&_beforeVisitCmdStencil);
_clippingStencil->visit(renderer, _modelViewTransform, dirty);
_afterDrawStencilCmd.init(_globalZOrder);
_afterDrawStencilCmd.func = CC_CALLBACK_0(Layout::onAfterDrawStencil, this);
renderer->addCommand(&_afterDrawStencilCmd);
int i = 0; // used by _children
int j = 0; // used by _protectedChildren
sortAllChildren();
sortAllProtectedChildren();
//
// draw children and protectedChildren zOrder < 0
//
for( ; i < _children.size(); i++ )
{
auto node = _children.at(i);
if ( node && node->getLocalZOrder() < 0 )
node->visit(renderer, _modelViewTransform, dirty);
else
break;
}
for( ; j < _protectedChildren.size(); j++ )
{
auto node = _protectedChildren.at(j);
if ( node && node->getLocalZOrder() < 0 )
node->visit(renderer, _modelViewTransform, dirty);
else
break;
}
//
// draw self
//
this->draw(renderer, _modelViewTransform, dirty);
//
// draw children and protectedChildren zOrder >= 0
//
for(auto it=_protectedChildren.cbegin()+j; it != _protectedChildren.cend(); ++it)
(*it)->visit(renderer, _modelViewTransform, dirty);
for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
(*it)->visit(renderer, _modelViewTransform, dirty);
_afterVisitCmdStencil.init(_globalZOrder);
_afterVisitCmdStencil.func = CC_CALLBACK_0(Layout::onAfterVisitStencil, this);
renderer->addCommand(&_afterVisitCmdStencil);
renderer->popGroup();
kmGLPopMatrix();
}
void Layout::onBeforeVisitStencil()
{
s_layer++;
GLint mask_layer = 0x1 << s_layer;
GLint mask_layer_l = mask_layer - 1;
_mask_layer_le = mask_layer | mask_layer_l;
_currentStencilEnabled = glIsEnabled(GL_STENCIL_TEST);
glGetIntegerv(GL_STENCIL_WRITEMASK, (GLint *)&_currentStencilWriteMask);
glGetIntegerv(GL_STENCIL_FUNC, (GLint *)&_currentStencilFunc);
glGetIntegerv(GL_STENCIL_REF, &_currentStencilRef);
glGetIntegerv(GL_STENCIL_VALUE_MASK, (GLint *)&_currentStencilValueMask);
glGetIntegerv(GL_STENCIL_FAIL, (GLint *)&_currentStencilFail);
glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, (GLint *)&_currentStencilPassDepthFail);
glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, (GLint *)&_currentStencilPassDepthPass);
glEnable(GL_STENCIL_TEST);
CHECK_GL_ERROR_DEBUG();
glStencilMask(mask_layer);
glGetBooleanv(GL_DEPTH_WRITEMASK, &_currentDepthWriteMask);
glDepthMask(GL_FALSE);
glStencilFunc(GL_NEVER, mask_layer, mask_layer);
glStencilOp(GL_ZERO, GL_KEEP, GL_KEEP);
kmGLMatrixMode(KM_GL_MODELVIEW);
kmGLPushMatrix();
kmGLLoadIdentity();
kmGLMatrixMode(KM_GL_PROJECTION);
kmGLPushMatrix();
kmGLLoadIdentity();
DrawPrimitives::drawSolidRect(Point(-1,-1), Point(1,1), Color4F(1, 1, 1, 1));
kmGLMatrixMode(KM_GL_PROJECTION);
kmGLPopMatrix();
kmGLMatrixMode(KM_GL_MODELVIEW);
kmGLPopMatrix();
glStencilFunc(GL_NEVER, mask_layer, mask_layer);
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);
}
void Layout::onAfterDrawStencil()
{
glDepthMask(_currentDepthWriteMask);
glStencilFunc(GL_EQUAL, _mask_layer_le, _mask_layer_le);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
}
void Layout::onAfterVisitStencil()
{
glStencilFunc(_currentStencilFunc, _currentStencilRef, _currentStencilValueMask);
glStencilOp(_currentStencilFail, _currentStencilPassDepthFail, _currentStencilPassDepthPass);
glStencilMask(_currentStencilWriteMask);
if (!_currentStencilEnabled)
{
glDisable(GL_STENCIL_TEST);
}
s_layer--;
}
void Layout::onBeforeVisitScissor()
{
Rect clippingRect = getClippingRect();
glEnable(GL_SCISSOR_TEST);//裁切开始
auto glview = Director::getInstance()->getOpenGLView();//得到OpenGL 窗口
glview->setScissorInPoints(clippingRect.origin.x, clippingRect.origin.y, clippingRect.size.width, clippingRect.size.height);//根据裁切范围进行裁切
}
void Layout::onAfterVisitScissor()
{
glDisable(GL_SCISSOR_TEST);//裁切终止
}
void Layout::scissorClippingVisit(Renderer *renderer, const kmMat4& parentTransform, bool parentTransformUpdated)
{//模板裁切渲染
_beforeVisitCmdScissor.init(_globalZOrder);
_beforeVisitCmdScissor.func = CC_CALLBACK_0(Layout::onBeforeVisitScissor, this);
renderer->addCommand(&_beforeVisitCmdScissor);
ProtectedNode::visit(renderer, parentTransform, parentTransformUpdated);
_afterVisitCmdScissor.init(_globalZOrder);
_afterVisitCmdScissor.func = CC_CALLBACK_0(Layout::onAfterVisitScissor, this);
renderer->addCommand(&_afterVisitCmdScissor);
}
void Layout::setClippingEnabled(bool able)
{
if (able == _clippingEnabled)//默认不能裁切 若和当前值相同 说明设置过 不必再详加判断 防止外部调用多次出现 不必要的重复逻辑
{
return;
}
_clippingEnabled = able;//是否可以裁切
switch (_clippingType)
{
case LAYOUT_CLIPPING_STENCIL://裁切类型为 模板
if (able)//若能裁切
{
static bool once = true;
if (once)
{
glGetIntegerv(GL_STENCIL_BITS, &g_sStencilBits);//裁切
if (g_sStencilBits <= 0)
{
CCLOG("Stencil buffer is not enabled.");
}
once = false;
}
_clippingStencil = DrawNode::create();//创建 绘制对象
if (_running)//若该节点在运行
{
_clippingStencil->onEnter();//初始化绘制对象
}
_clippingStencil->retain();//绘制对象引用次数++
setStencilClippingSize(_size);//设置裁切区域
}
else//若不能裁切
{
if (_running)//若该节点在运行
{
_clippingStencil->onExit();//绘制对象 退出
}
_clippingStencil->release();//计数--
_clippingStencil = nullptr;//置空
}
break;
default:
break;
}
}
void Layout::setClippingType(LayoutClippingType type)
{
if (type == _clippingType)
{
return;
}
bool clippingEnabled = isClippingEnabled();
setClippingEnabled(false);
_clippingType = type;//设置裁切类型
setClippingEnabled(clippingEnabled);
}
LayoutClippingType Layout::getClippingType()
{
return _clippingType;
}
void Layout::setStencilClippingSize(const Size &size)
{
if (_clippingEnabled && _clippingType == LAYOUT_CLIPPING_STENCIL)
{//若可以裁切 裁切类型为 模板
Point rect[4];//设置裁切范围
rect[0] = Point::ZERO;
rect[1] = Point(_size.width, 0);
rect[2] = Point(_size.width, _size.height);
rect[3] = Point(0, _size.height);
Color4F green(0, 1, 0, 1);
_clippingStencil->clear();
_clippingStencil->drawPolygon(rect, 4, green, 0, green);//花多边形
}
}
//得到裁切的矩形
const Rect& Layout::getClippingRect()
{
if (_clippingRectDirty)
{
Point worldPos = convertToWorldSpace(Point::ZERO);//世界坐标
AffineTransform t = getNodeToWorldAffineTransform();//仿射旋转
float scissorWidth = _size.width*t.a;//裁切宽度
float scissorHeight = _size.height*t.d;//裁切高度
Rect parentClippingRect;//父节点裁切矩形
Layout* parent = this;//从自己开始
while (parent)
{
parent = dynamic_cast<Layout*>(parent->getParent());
if(parent)//存在layout的父节点
{
if (parent->isClippingEnabled())//若该节点可以裁切
{
_clippingParent = parent;//保存裁切节点
break;
}
}
}
if (_clippingParent)//如果找到裁切父节点
{
parentClippingRect = _clippingParent->getClippingRect();//得到裁切矩形范围
float finalX = worldPos.x - (scissorWidth * _anchorPoint.x);
float finalY = worldPos.y - (scissorHeight * _anchorPoint.y);
float finalWidth = scissorWidth;
float finalHeight = scissorHeight;//计算得出裁切范围
float leftOffset = worldPos.x - parentClippingRect.origin.x;
if (leftOffset < 0.0f)
{
finalX = parentClippingRect.origin.x;
finalWidth += leftOffset;
}
float rightOffset = (worldPos.x + scissorWidth) - (parentClippingRect.origin.x + parentClippingRect.size.width);
if (rightOffset > 0.0f)
{
finalWidth -= rightOffset;
}
float topOffset = (worldPos.y + scissorHeight) - (parentClippingRect.origin.y + parentClippingRect.size.height);
if (topOffset > 0.0f)
{
finalHeight -= topOffset;
}
float bottomOffset = worldPos.y - parentClippingRect.origin.y;
if (bottomOffset < 0.0f)
{
finalY = parentClippingRect.origin.x;
finalHeight += bottomOffset;
}
if (finalWidth < 0.0f)
{
finalWidth = 0.0f;
}
if (finalHeight < 0.0f)
{
finalHeight = 0.0f;
}
_clippingRect.origin.x = finalX;
_clippingRect.origin.y = finalY;
_clippingRect.size.width = finalWidth;
_clippingRect.size.height = finalHeight;
}
else
{
_clippingRect.origin.x = worldPos.x - (scissorWidth * _anchorPoint.x);
_clippingRect.origin.y = worldPos.y - (scissorHeight * _anchorPoint.y);
_clippingRect.size.width = scissorWidth;
_clippingRect.size.height = scissorHeight;
}
_clippingRectDirty = false;//置为不可裁切
}
return _clippingRect;
}
void Layout::onSizeChanged()
{
Widget::onSizeChanged();
setStencilClippingSize(_size);//设置裁切范围
_doLayoutDirty = true;//开启布局
_clippingRectDirty = true;//允许计算裁切区域
if (_backGroundImage)//若背景存在
{//设置背景位置居中
_backGroundImage->setPosition(Point(_size.width/2.0f, _size.height/2.0f));
if (_backGroundScale9Enabled && _backGroundImage)
{//若使用九宫格 设置透明度
static_cast<extension::Scale9Sprite*>(_backGroundImage)->setPreferredSize(_size);
}
}
//设置渲染器的渲染区域大小
if (_colorRender)
{
_colorRender->setContentSize(_size);
}
if (_gradientRender)
{
_gradientRender->setContentSize(_size);
}
}
void Layout::setBackGroundImageScale9Enabled(bool able)
{
if (_backGroundScale9Enabled == able)
{
return;
}
removeProtectedChild(_backGroundImage);
_backGroundImage = nullptr;//置空背景
_backGroundScale9Enabled = able;
addBackGroundImage();//添加背景 设置背景属性
setBackGroundImage(_backGroundImageFileName,_bgImageTexType);
setBackGroundImageCapInsets(_backGroundImageCapInsets);
}
bool Layout::isBackGroundImageScale9Enabled()
{
return _backGroundScale9Enabled;
}
void Layout::setBackGroundImage(const std::string& fileName,TextureResType texType)
{
if (fileName.empty())
{
return;
}
if (_backGroundImage == nullptr)
{
addBackGroundImage();
}
_backGroundImageFileName = fileName;
_bgImageTexType = texType;
if (_backGroundScale9Enabled)
{//若使用九宫格 加载资源
extension::Scale9Sprite* bgiScale9 = static_cast<extension::Scale9Sprite*>(_backGroundImage);
switch (_bgImageTexType)
{
case UI_TEX_TYPE_LOCAL:
bgiScale9->initWithFile(fileName);
break;
case UI_TEX_TYPE_PLIST:
bgiScale9->initWithSpriteFrameName(fileName);
break;
default:
break;
}
bgiScale9->setPreferredSize(_size);
}
else
{//若没有使用九宫格 加载资源
switch (_bgImageTexType)
{
case UI_TEX_TYPE_LOCAL:
static_cast<Sprite*>(_backGroundImage)->setTexture(fileName);
break;
case UI_TEX_TYPE_PLIST:
static_cast<Sprite*>(_backGroundImage)->setSpriteFrame(fileName);
break;
default:
break;
}
}
//保存贴图size
_backGroundImageTextureSize = _backGroundImage->getContentSize();
//设置贴图位置居中
_backGroundImage->setPosition(Point(_size.width/2.0f, _size.height/2.0f));
updateBackGroundImageRGBA();//更新贴图颜色
}
void Layout::setBackGroundImageCapInsets(const Rect &capInsets)
{
_backGroundImageCapInsets = capInsets;
if (_backGroundScale9Enabled && _backGroundImage)
{//若使用九宫格 设置区域
static_cast<extension::Scale9Sprite*>(_backGroundImage)->setCapInsets(capInsets);
}
}
const Rect& Layout::getBackGroundImageCapInsets()
{
return _backGroundImageCapInsets;
}
void Layout::supplyTheLayoutParameterLackToChild(Widget *child)
{
if (!child)
{
return;
}
switch (_layoutType)
{
case LAYOUT_ABSOLUTE://绝对位置
break;
case LAYOUT_LINEAR_HORIZONTAL:
case LAYOUT_LINEAR_VERTICAL://线性
{
LinearLayoutParameter* layoutParameter = dynamic_cast<LinearLayoutParameter*>(child->getLayoutParameter(LAYOUT_PARAMETER_LINEAR));
if (!layoutParameter)
{
child->setLayoutParameter(LinearLayoutParameter::create());//设置线性布局参数
}
break;
}
case LAYOUT_RELATIVE://平面
{
RelativeLayoutParameter* layoutParameter = dynamic_cast<RelativeLayoutParameter*>(child->getLayoutParameter(LAYOUT_PARAMETER_RELATIVE));
if (!layoutParameter)
{
child->setLayoutParameter(RelativeLayoutParameter::create());//设置平面 布局参数
}
break;
}
default:
break;
}
}
void Layout::addBackGroundImage()
{//背景图添加到节点树上
if (_backGroundScale9Enabled)
{
_backGroundImage = extension::Scale9Sprite::create();
addProtectedChild(_backGroundImage, BACKGROUNDIMAGE_Z, -1);
static_cast<extension::Scale9Sprite*>(_backGroundImage)->setPreferredSize(_size);
}
else
{
_backGroundImage = Sprite::create();
addProtectedChild(_backGroundImage, BACKGROUNDIMAGE_Z, -1);
}
//位置居中
_backGroundImage->setPosition(Point(_size.width/2.0f, _size.height/2.0f));
}
void Layout::removeBackGroundImage()
{
if (!_backGroundImage)
{
return;
}//移除背景图 置空背景图及相关属性
removeProtectedChild(_backGroundImage);
_backGroundImage = nullptr;
_backGroundImageFileName = "";
_backGroundImageTextureSize = Size::ZERO;
}
void Layout::setBackGroundColorType(LayoutBackGroundColorType type)
{
if (_colorType == type)
{
return;
}
switch (_colorType)//移除渲染层
{
case LAYOUT_COLOR_NONE:
if (_colorRender)
{
removeProtectedChild(_colorRender);
_colorRender = nullptr;
}
if (_gradientRender)
{
removeProtectedChild(_gradientRender);
_gradientRender = nullptr;
}
break;
case LAYOUT_COLOR_SOLID:
if (_colorRender)
{
removeProtectedChild(_colorRender);
_colorRender = nullptr;
}
break;
case LAYOUT_COLOR_GRADIENT:
if (_gradientRender)
{
removeProtectedChild(_gradientRender);
_gradientRender = nullptr;
}
break;
default:
break;
}
_colorType = type;//重置渲染层
switch (_colorType)
{
case LAYOUT_COLOR_NONE:
break;
case LAYOUT_COLOR_SOLID:
_colorRender = LayerColor::create();
_colorRender->setContentSize(_size);
_colorRender->setOpacity(_cOpacity);
_colorRender->setColor(_cColor);
addProtectedChild(_colorRender, BCAKGROUNDCOLORRENDERER_Z, -1);
break;
case LAYOUT_COLOR_GRADIENT:
_gradientRender = LayerGradient::create();
_gradientRender->setContentSize(_size);
_gradientRender->setOpacity(_cOpacity);
_gradientRender->setStartColor(_gStartColor);
_gradientRender->setEndColor(_gEndColor);
_gradientRender->setVector(_alongVector);
addProtectedChild(_gradientRender, BCAKGROUNDCOLORRENDERER_Z, -1);
break;
default:
break;
}
}
LayoutBackGroundColorType Layout::getBackGroundColorType()
{
return _colorType;
}
void Layout::setBackGroundColor(const Color3B &color)
{
_cColor = color;
if (_colorRender)
{
_colorRender->setColor(color);
}
}
const Color3B& Layout::getBackGroundColor()
{
return _cColor;
}
void Layout::setBackGroundColor(const Color3B &startColor, const Color3B &endColor)
{
_gStartColor = startColor;
if (_gradientRender)
{
_gradientRender->setStartColor(startColor);//开始颜色
}
_gEndColor = endColor;
if (_gradientRender)
{
_gradientRender->setEndColor(endColor);//结束颜色
}
}
const Color3B& Layout::getBackGroundStartColor()
{
return _gStartColor;
}
const Color3B& Layout::getBackGroundEndColor()
{
return _gEndColor;
}
void Layout::setBackGroundColorOpacity(GLubyte opacity)
{
_cOpacity = opacity;
switch (_colorType)
{
case LAYOUT_COLOR_NONE:
break;
case LAYOUT_COLOR_SOLID://单一的颜色透明度
_colorRender->setOpacity(opacity);
break;
case LAYOUT_COLOR_GRADIENT:
_gradientRender->setOpacity(opacity);//渐变的颜色透明度
break;
default:
break;
}
}
GLubyte Layout::getBackGroundColorOpacity()
{
return _cOpacity;
}
void Layout::setBackGroundColorVector(const Point &vector)
{
_alongVector = vector;
if (_gradientRender)
{
_gradientRender->setVector(vector);//设置渐变方向
}
}
const Point& Layout::getBackGroundColorVector()
{
return _alongVector;
}
void Layout::setBackGroundImageColor(const Color3B &color)
{
_backGroundImageColor = color;
updateBackGroundImageColor();
}
void Layout::setBackGroundImageOpacity(GLubyte opacity)
{
_backGroundImageOpacity = opacity;
updateBackGroundImageOpacity();
}
const Color3B& Layout::getBackGroundImageColor()
{
return _backGroundImageColor;
}
GLubyte Layout::getBackGroundImageOpacity()
{
return _backGroundImageOpacity;
}
void Layout::updateBackGroundImageColor()
{
if (_backGroundImage)
{
_backGroundImage->setColor(_backGroundImageColor);
}
}
void Layout::updateBackGroundImageOpacity()
{
if (_backGroundImage)
{
_backGroundImage->setOpacity(_backGroundImageOpacity);
}
}
void Layout::updateBackGroundImageRGBA()
{
if (_backGroundImage)
{//设置背景color opacity
_backGroundImage->setColor(_backGroundImageColor);
_backGroundImage->setOpacity(_backGroundImageOpacity);
}
}
const Size& Layout::getBackGroundImageTextureSize() const
{
return _backGroundImageTextureSize;//背景资源size
}
void Layout::setLayoutType(LayoutType type)
{
_layoutType = type;//设置布局类型
CC_SAFE_RELEASE_NULL(_curLayoutExecutant);//释放布局执行者
_curLayoutExecutant = createCurrentLayoutExecutant();//新建当前布局执行者
CC_SAFE_RETAIN(_curLayoutExecutant);//引用次数++
for (auto& child : _children)//遍历所有孩子
{
Widget* widgetChild = dynamic_cast<Widget*>(child);
if (widgetChild)
{
//提供布局参数
supplyTheLayoutParameterLackToChild(static_cast<Widget*>(child));
}
}
_doLayoutDirty = true;//开启布局
}
LayoutExecutant* Layout::createCurrentLayoutExecutant()
{
LayoutExecutant* exe = nullptr;
switch (_layoutType)
{
case LAYOUT_LINEAR_VERTICAL://线性垂直
exe = LinearVerticalLayoutExecutant::create();
break;
case LAYOUT_LINEAR_HORIZONTAL://线性水平
exe = LinearHorizontalLayoutExecutant::create();
break;
case LAYOUT_RELATIVE://平面
exe = RelativeLayoutExecutant::create();
break;
default:
break;
}
return exe;
}
LayoutType Layout::getLayoutType() const
{
return _layoutType;//返回布局类型
}
//请求布局
void Layout::requestDoLayout()
{
_doLayoutDirty = true;//开启布局
}
void Layout::doLayout()
{
if (!_doLayoutDirty)//没开启布局 直接return
{
return;
}
if (_curLayoutExecutant)//开启布局 有了布局数据
{
//布局吧
_curLayoutExecutant->doLayout(getSize(), getChildren());
}
_doLayoutDirty = false;//布局完成
}
std::string Layout::getDescription() const
{
return "Layout";
}
Widget* Layout::createCloneInstance()
{
return Layout::create();
}
void Layout::copyClonedWidgetChildren(Widget* model)
{
Widget::copyClonedWidgetChildren(model);
}
//克隆属性
void Layout::copySpecialProperties(Widget *widget)
{
Layout* layout = dynamic_cast<Layout*>(widget);
if (layout)
{
setBackGroundImageScale9Enabled(layout->_backGroundScale9Enabled);
setBackGroundImage(layout->_backGroundImageFileName,layout->_bgImageTexType);
setBackGroundImageCapInsets(layout->_backGroundImageCapInsets);
setBackGroundColorType(layout->_colorType);
setBackGroundColor(layout->_cColor);
setBackGroundColor(layout->_gStartColor, layout->_gEndColor);
setBackGroundColorOpacity(layout->_cOpacity);
setBackGroundColorVector(layout->_alongVector);
setLayoutType(layout->_layoutType);
setClippingEnabled(layout->_clippingEnabled);
setClippingType(layout->_clippingType);
}
}
}
NS_CC_END