首页 > 代码库 > 【Cocos2d-x】源码分析之 2d/ui/UILayout
【Cocos2d-x】源码分析之 2d/ui/UILayout
#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
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。