首页 > 代码库 > 【Cocos2d-x】源代码分析之 2d/ui/Widget

【Cocos2d-x】源代码分析之 2d/ui/Widget

从今天開始 咱也模仿 红孩儿这些大牛分析源代码 ,因为水平有限 不正确之处欢迎狂喷。哈哈。

#ifndef __UIWIDGET_H__
#define __UIWIDGET_H__

#include "ui/CCProtectedNode.h"
#include "ui/UILayoutDefine.h"
#include "ui/UILayoutParameter.h"
#include "ui/GUIDefine.h"

NS_CC_BEGIN

namespace ui {

typedef enum
{
    BRIGHT_NONE = -1,
    BRIGHT_NORMAL,//正常
    BRIGHT_HIGHLIGHT//高亮 按钮点击之后
}BrightStyle;//明亮的风格

typedef enum
{
    WidgetTypeWidget, //control 基本 UIWidget 默认
    WidgetTypeContainer //container 容器 layout 实例化
}WidgetType;//ui 类型

typedef enum
{
    UI_TEX_TYPE_LOCAL = 0,//means local file
    UI_TEX_TYPE_PLIST = 1// means sprite frame
}TextureResType;//贴图类型

 enum class TouchEventType
{
    TOUCH_EVENT_BEGAN,//開始
    TOUCH_EVENT_MOVED,//移动
    TOUCH_EVENT_ENDED,//结束
    TOUCH_EVENT_CANCELED//取消
};//触摸事件类型

typedef enum
{
    SIZE_ABSOLUTE,//绝对值
    SIZE_PERCENT//百分比值
}SizeType;//size值类型

typedef enum
{
    POSITION_ABSOLUTE,//绝对 真实位置
    POSITION_PERCENT//相对父节点位置百分比
}PositionType;//位置类型
    
typedef enum
{
    WIDGET_SIZE,//size
    WIDGET_POSITION//position
    
}WidgetInfoType;//位置类型
//哦 这里说明一下 回调函数被我改动了下 主要是这样改动之后能够用到C++11的lambda表达式 
//不必在使用的时候多声明一个回调函数了 比較方便 希望引擎组能够採用这样的方式。   
typedef std::function<void(Ref*,TouchEventType)> SEL_TouchEvent;
    
//函数指针 指向 返回值 void 參数列表(Ref*,TouchEventType) 类型的函数
//typedef void (Ref::*SEL_TouchEvent)(Ref*,TouchEventType);
//宏定义 给函数指针SEL_TouchEvent取别名为toucheventselector
#define toucheventselector(_SELECTOR) (SEL_TouchEvent)(&_SELECTOR)

class Widget : public ProtectedNode
{
public:
    Widget(void);
    virtual ~Widget();
    static Widget* create();
    /**设置 是否 触摸&&可见 默认true*/
    virtual void setEnabled(bool enabled);
    bool isEnabled() const;
    /**设置是否明亮 默认true*/
    void setBright(bool bright);
    /**是否明亮*/
    bool isBright() const;
    /**能否够触摸(响应事件)默认true*/
    virtual void setTouchEnabled(bool enabled);
    /**设置明亮风格 正常 or 明亮 默认正常*/
    void setBrightStyle(BrightStyle style);
    /**能否够触摸*/
    bool isTouchEnabled() const;
    /**是否被选中 默认false*/
    bool isFocused() const;
    /**是否被选中 默认false*/
    void setFocused(bool fucosed);
    /**获取此控件距离左节点的下边界长度*/
    float getLeftInParent();
    /**获取此控件距离父节点的下边界长度*/
    float getBottomInParent();
    /**获取此控件距离父节点的右边界长度*/
    float getRightInParent();
    /**获取此控件距离父节点的上边界长度*/
    float getTopInParent();

    /**获取一个孩子从容器依据它的名字*/
    virtual Widget* getChildByName(const char* name);
    /**渲染重载*/
    virtual void visit(cocos2d::Renderer *renderer, const kmMat4 &parentTransform, bool parentTransformUpdated) override;

    /**加入回调事件*/
    void addTouchEventListener(SEL_TouchEvent selector);
    /**打印属性 debug*/
    virtual void logInfo(WidgetInfoType _type);

    //cocos2d 属性
    /**
     基类有的函数为virtual 有的不是
     不带virtual 的是全部子类都拥有这个函数的功能。
     带virtual 的是拥有上述功能之外 重载父类的函数 想拓展功能用的。
     带virtual 的函数能够使用多态 即父类指针指向子类成员
     */

    /**
     *更改在OpenGL坐标系中widget的位置(X,Y)
     *原来的点(0,0)是在屏幕的左下角。
     *@參数位置在OpenGL坐标widget的位置(X,Y)
     */
    virtual void setPosition(const Point &pos) override;
    /**同上绝对位置变为百分比*/
    void setPositionPercent(const Point &percent);
    /**得到在OpenGL坐标系中widget的百分比位置(X,Y)*/
    const Point& getPositionPercent();

    /**设置位置类型*/
    void setPositionType(PositionType type);

    /**得到位置类型*/
    PositionType getPositionType() const;

    /**设置该widget是否水平翻转*/
    virtual void setFlippedX(bool flippedX);

    /**该widget是否水平翻转*/
    virtual bool isFlippedX(){return _flippedX;};

    /**该widget是否垂直翻转*/
    virtual void setFlippedY(bool flippedY);

    /**该widget是否垂直翻转*/
    virtual bool isFlippedY(){return _flippedY;};
    /**设置颜色*/
    virtual void setColor(const Color3B& color) override;
    /**设置透明度*/
    virtual void setOpacity(GLubyte opacity) override;
    /**得到颜色值*/
    const Color3B& getColor() const override {return _color;};
    /**得到透明度*/
    GLubyte getOpacity() const override {return _opacity;};
    /**弃用的属性*/
    /** @deprecated Use isFlippedX() instead */
    CC_DEPRECATED_ATTRIBUTE bool isFlipX() { return isFlippedX(); };
    /** @deprecated Use setFlippedX() instead */
    CC_DEPRECATED_ATTRIBUTE void setFlipX(bool flipX) { setFlippedX(flipX); };
    /** @deprecated Use isFlippedY() instead */
    CC_DEPRECATED_ATTRIBUTE bool isFlipY() { return isFlippedY(); };
    /** @deprecated Use setFlippedY() instead */
    CC_DEPRECATED_ATTRIBUTE void setFlipY(bool flipY) { setFlippedY(flipY); };

    /**当该widget失去焦点会调用*/
    void didNotSelectSelf();

    /**检查一个点是否在父节点区域*/
    bool clippingParentAreaContainPoint(const Point &pt);

    /** 发送触摸事件到widget的父节点*/
    virtual void checkChildInfo(int handleState,Widget* sender,const Point &touchPoint);

    /** Gets the touch began point of widget when widget is selected.*/
    const Point& getTouchStartPos();

    /** Gets the touch move point of widget when widget is selected*/
    const Point& getTouchMovePos();

    /** Gets the touch end point of widget when widget is selected.*/
    const Point& getTouchEndPos();

    /**设置name*/
    void setName(const char* name);

    /**得到name*/
    const char* getName() const;

    /**得到控件类型*/
    WidgetType getWidgetType() const;

    /**设置控件大小*/
    virtual void setSize(const Size &size);
    virtual void setSizeW(const int &sizeW);
    virtual void setSizeH(const int &sizeH);
    /**设置size百分比*/
    virtual void setSizePercent(const Point &percent);

    /**size类型*/
    void setSizeType(SizeType type);

    /**得到size类型*/
    SizeType getSizeType() const;

    /**得到size*/
    const Size& getSize() const;
    
    /**得到Customsize*/
    const Size& getCustomSize() const;
    /**得到layout size*/
    virtual const Size& getLayoutSize() {return _size;};//虚函数 供子类重写?

    /**得到size百分比*/
    const Point& getSizePercent() const;

    /***/
    virtual bool hitTest(const Point &pt);
    /**触摸事件*/
    virtual bool onTouchBegan(Touch *touch, Event *unusedEvent);
    virtual void onTouchMoved(Touch *touch, Event *unusedEvent);
    virtual void onTouchEnded(Touch *touch, Event *unusedEvent);
    virtual void onTouchCancelled(Touch *touch, Event *unusedEvent);

    /**设置布局參数*/
    void setLayoutParameter(LayoutParameter* parameter);

    /**得到布局參数*/
    LayoutParameter* getLayoutParameter(LayoutParameterType type);

    /**是否忽略size使用texture size 默认true*/
    virtual void ignoreContentAdaptWithSize(bool ignore);

    /**是否忽略size使用texture size*/
    bool isIgnoreContentAdaptWithSize() const;

    /**得到世界位置*/
    Point getWorldPosition();

    /**得到虚拟渲染器 比如 一个button的虚拟渲染器是他的 texture renderer 贴图渲染器*/
    virtual Node* getVirtualRenderer();

    /**得到虚拟渲染器的size 默认是_contentSize 不同的子类有自己的重载*/
    virtual const Size& getVirtualRendererSize() const;
    
    

    /**
     * 得到改控件相应的"class name".
     */
    virtual std::string getDescription() const override;
    /**克隆替身*/
    Widget* clone();

    virtual void onEnter() override;
    virtual void onExit() override;
    /**更新size和position*/
    void updateSizeAndPosition();

    void updateSizeAndPosition(const Size& parentSize);
    
    /*temp action*/
    void setActionTag(int tag);
	int getActionTag();
    
CC_CONSTRUCTOR_ACCESS:
    //initializes state of widget.
    virtual bool init() override;
    
protected:
    //call back function called when size changed.
    virtual void onSizeChanged();

    //initializes renderer of widget.
    virtual void initRenderer();

    //回复正常调用.
    virtual void onPressStateChangedToNormal();

    //选中会调用
    virtual void onPressStateChangedToPressed();

    //变暗会调用
    virtual void onPressStateChangedToDisabled();
    //不同的事件
    void pushDownEvent();
    void moveEvent();
    void releaseUpEvent();
    void cancelUpEvent();
    //空的虚函数为了多态
    virtual void updateTextureColor(){};
    virtual void updateTextureOpacity(){};
    virtual void updateTextureRGBA(){};
    virtual void updateFlippedX(){};
    virtual void updateFlippedY(){};
    
    void updateColorToRenderer(Node* renderer);
    void updateOpacityToRenderer(Node* renderer);
    void updateRGBAToRenderer(Node* renderer);
    void copyProperties(Widget* model);
    
    virtual Widget* createCloneInstance();
    virtual void copySpecialProperties(Widget* model);
    virtual void copyClonedWidgetChildren(Widget* model);
    Widget* getWidgetParent();
    void updateContentSizeWithTextureSize(const Size& size);
    /**多态 适用于全部的子类重载 实现自己的逻辑*/
    virtual void adaptRenderers(){};
protected:
    bool _enabled;            ///< 是否可见&&可触摸 最高属性 
    bool _bright;             ///< 是否光亮
    bool _touchEnabled;       ///< 是否响应触摸
    bool _touchPassedEnabled; ///< 触摸时间是不是按下
    bool _focus;              ///< 是不是焦点
    BrightStyle _brightStyle; ///< 明亮风格
    Point _touchStartPos;    ///< touch began point
    Point _touchMovePos;     ///< touch moved point
    Point _touchEndPos;      ///< touch ended point
   
    SEL_TouchEvent    _touchEventSelector;///回调函数类型
    std::string _name;///类名
    WidgetType _widgetType;///控件类型
	int _actionTag;///运行动作的tag
    Size _size;///untransformed size
    Size _customSize;///自己定义size
    bool _ignoreSize;///是否忽略自己定义的大小 而取资源原本的大小 untransformed img size 默认_size = _customSize
    bool _affectByClipping;
    SizeType _sizeType;///size 类型
    Point _sizePercent;///相对父节点size百分比
    PositionType _positionType;///位置类型
    Point _positionPercent;///相对父节点的位置百分比
    bool _reorderWidgetChildDirty;
    bool _hitted;
    EventListenerTouchOneByOne* _touchListener;///单点触摸
    Color3B _color;///颜色值
    GLubyte _opacity;///透明度
    bool _flippedX;//是否镜像X轴
    bool _flippedY;//是否镜像Y轴
    Map<int, LayoutParameter*> _layoutParameterDictionary;//布局參数Map

};
}

NS_CC_END

#endif /* defined(__Widget__) */

/****************************************************************************
Copyright (c) 2013-2014 Chukong Technologies Inc.

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 "ui/UIWidget.h"
#include "ui/UILayout.h"
#include "ui/UIHelper.h"

NS_CC_BEGIN

namespace ui {

Widget::Widget():
_enabled(true),
_bright(true),
_touchEnabled(false),
_touchPassedEnabled(false),
_focus(false),
_brightStyle(BRIGHT_NONE),
_touchStartPos(Point::ZERO),
_touchMovePos(Point::ZERO),
_touchEndPos(Point::ZERO),
_touchEventSelector(nullptr),
_name("default"),
_widgetType(WidgetTypeWidget),
_actionTag(0),
_size(Size::ZERO),
_customSize(Size::ZERO),
_ignoreSize(false),
_affectByClipping(false),
_sizeType(SIZE_ABSOLUTE),
_sizePercent(Point::ZERO),
_positionType(POSITION_ABSOLUTE),
_positionPercent(Point::ZERO),
_reorderWidgetChildDirty(true),
_hitted(false),
_touchListener(nullptr),
_color(Color3B::WHITE),
_opacity(255),
_flippedX(false),
_flippedY(false)
{

}

Widget::~Widget()
{
    _touchEventSelector = nullptr;
    setTouchEnabled(false);
}

Widget* Widget::create()
{
    Widget* widget = new Widget();
    if (widget && widget->init())
    {
        widget->autorelease();
        return widget;
    }
    CC_SAFE_DELETE(widget);
    return nullptr;
}

bool Widget::init()
{
    if (ProtectedNode::init())
    {
        initRenderer();//初始化渲染器 多态
        setBright(true);//设置明亮
        ignoreContentAdaptWithSize(true);//默认 内容不适应size大小
        setAnchorPoint(Point(0.5f, 0.5f));//默认 锚点在中心
        return true;
    }
    return false;
}

void Widget::onEnter()
{
    updateSizeAndPosition();
    ProtectedNode::onEnter();
}

void Widget::onExit()
{
    unscheduleUpdate();
    ProtectedNode::onExit();
}

void Widget::visit(Renderer *renderer, const kmMat4 &parentTransform, bool parentTransformUpdated)
{
    if (_enabled)
    {
        adaptRenderers();
        ProtectedNode::visit(renderer, parentTransform, parentTransformUpdated);
    }
}

Widget* Widget::getWidgetParent()
{
    //得到父节点
    return dynamic_cast<Widget*>(getParent());
}

void Widget::setEnabled(bool enabled)
{
    _enabled = enabled;
    for (auto& child : _children)
    {
        if (child)
        {
            Widget* widgetChild = dynamic_cast<Widget*>(child);
            if (widgetChild)
            {
                widgetChild->setEnabled(enabled);
            }
        }
    }
    
    for (auto& child : _protectedChildren)
    {
        if (child)
        {
            Widget* widgetChild = dynamic_cast<Widget*>(child);
            if (widgetChild)
            {
                widgetChild->setEnabled(enabled);
            }
        }
    }
}

Widget* Widget::getChildByName(const char *name)
{
    for (auto& child : _children)
    {
        if (child)
        {
            Widget* widgetChild = dynamic_cast<Widget*>(child);
            if (widgetChild)
            {
                if (strcmp(widgetChild->getName(), name) == 0)
                {
                    return widgetChild;
                }
            }
        }
    }
    return nullptr;
}
    
void Widget::initRenderer()
{
    //多态 不同的控件有自己的初始化渲染方式
    
}

void Widget::setSizeW(const int &sizeW)
{
    _customSize.width = sizeW;
    if (_ignoreSize)
    {
        _size = getVirtualRendererSize();
    }
    else
    {
        _size.width = sizeW;
    }
    if (_running)
    {
        Widget* widgetParent = getWidgetParent();
        Size pSize;
        if (widgetParent)
        {
            pSize = widgetParent->getSize();
        }
        else
        {
            pSize = _parent->getContentSize();
        }
        float spx = 0.0f;
        float spy = 0.0f;
        if (pSize.width > 0.0f)
        {
            spx = _customSize.width / pSize.width;
        }
        if (pSize.height > 0.0f)
        {
            spy = _customSize.height / pSize.height;
        }
        _sizePercent = Point(spx, spy);
    }
    onSizeChanged();
}
void Widget::setSizeH(const int &sizeH)
{
    _customSize.height = sizeH;
    if (_ignoreSize)
    {
        _size = getVirtualRendererSize();
    }
    else
    {
        _size.height = sizeH;
    }
    if (_running)
    {
        Widget* widgetParent = getWidgetParent();
        Size pSize;
        if (widgetParent)
        {
            pSize = widgetParent->getSize();
        }
        else
        {
            pSize = _parent->getContentSize();
        }
        float spx = 0.0f;
        float spy = 0.0f;
        if (pSize.width > 0.0f)
        {
            spx = _customSize.width / pSize.width;
        }
        if (pSize.height > 0.0f)
        {
            spy = _customSize.height / pSize.height;
        }
        _sizePercent = Point(spx, spy);
    }
    onSizeChanged();
}
void Widget::setSize(const Size &size)
{
    _customSize = size;
    if (_ignoreSize)
    {
        _size = getVirtualRendererSize();
    }
    else
    {
        _size = size;
    }
    if (_running)
    {
        Widget* widgetParent = getWidgetParent();
        Size pSize;
        if (widgetParent)
        {
            pSize = widgetParent->getSize();
        }
        else
        {
            pSize = _parent->getContentSize();
        }
        float spx = 0.0f;
        float spy = 0.0f;
        if (pSize.width > 0.0f)
        {
            spx = _customSize.width / pSize.width;
        }
        if (pSize.height > 0.0f)
        {
            spy = _customSize.height / pSize.height;
        }
        _sizePercent = Point(spx, spy);
    }
    onSizeChanged();
}

void Widget::setSizePercent(const Point &percent)
{
    _sizePercent = percent;
    Size cSize = _customSize;
    if (_running)
    {
        Widget* widgetParent = getWidgetParent();
        if (widgetParent)
        {
            cSize = Size(widgetParent->getSize().width * percent.x , widgetParent->getSize().height * percent.y);
        }
        else
        {
            cSize = Size(_parent->getContentSize().width * percent.x , _parent->getContentSize().height * percent.y);
        }
    }
    if (_ignoreSize)
    {
        _size = getVirtualRendererSize();
    }
    else
    {
        _size = cSize;
    }
    _customSize = cSize;
    onSizeChanged();
}

void Widget::updateSizeAndPosition()
{
    Widget* widgetParent = getWidgetParent();
    Size pSize;
    if (widgetParent)
    {//假设有父节点是控件基类widget 保存父节点的容器大小
        pSize = widgetParent->getLayoutSize();
    }
    else
    {//假设父节点不是控件基类widget 得到绑定贴图大小
        pSize = _parent->getContentSize();
    }
    updateSizeAndPosition(pSize);
}
    
void Widget::updateSizeAndPosition(const cocos2d::Size &parentSize)
{
    switch (_sizeType)
    {
        case SIZE_ABSOLUTE://绝对大小 真实大小
        {
            if (_ignoreSize)//忽略设置的大小
            {
                _size = getVirtualRendererSize();//size取untransformed img size
            }
            else//不忽略自己定义大小
            {
                _size = _customSize;//size 取自己定义大小
            }
            float spx = 0.0f;
            float spy = 0.0f;
            if (parentSize.width > 0.0f)
            {
                spx = _customSize.width / parentSize.width;
            }
            if (parentSize.height > 0.0f)
            {
                spy = _customSize.height / parentSize.height;
            }
            _sizePercent = Point(spx, spy);//计算得到相对父节点的size百分比
            break;
        }
        case SIZE_PERCENT://百分比size
        {
            Size cSize = Size(parentSize.width * _sizePercent.x , parentSize.height * _sizePercent.y);//计算得到自己定义大小
            if (_ignoreSize)//忽略设置的大小
            {
                _size = getVirtualRendererSize();//size取untransformed img size
            }
            else//不忽略自己定义大小
            {
                _size = cSize;//size 取 计算得到自己定义大小
            }
            _customSize = cSize;//计算得到自己定义大小
            break;
        }
        default:
            break;
    }
    onSizeChanged();
    Point absPos = getPosition();
    switch (_positionType)
    {
        case POSITION_ABSOLUTE://真实位置
        {
            if (parentSize.width <= 0.0f || parentSize.height <= 0.0f)
            {//父节点size=0
                _positionPercent = Point::ZERO;//相对父节点的位置百分比为0
            }
            else
            {
                _positionPercent = Point(absPos.x / parentSize.width, absPos.y / parentSize.height);//相对父节点的位置百分比
            }
            break;
        }
        case POSITION_PERCENT://相对位置
        {
            absPos = Point(parentSize.width * _positionPercent.x, parentSize.height * _positionPercent.y);//得到真实位置
            break;
        }
        default:
            break;
    }
    setPosition(absPos);//更新真实位置
}

void Widget::setSizeType(SizeType type)
{
    _sizeType = type;//设置size类型
}

SizeType Widget::getSizeType() const//返回值不可改
{
    return _sizeType;//得到size type 返回值不可改
}

void Widget::ignoreContentAdaptWithSize(bool ignore)
{
    if (_ignoreSize == ignore)
    {
        return;//和当前值一样 不是必需更新处理了 直接返回
    }
    _ignoreSize = ignore;
    if (_ignoreSize)//忽略自己定义size
    {
        Size s = getVirtualRendererSize();//取原本大小的size
        _size = s;
    }
    else//不忽略自己定义size
    {
        _size = _customSize;//取自己定义size
    }
    onSizeChanged();//更新size
}

bool Widget::isIgnoreContentAdaptWithSize() const
{
    return _ignoreSize;
}

const Size& Widget::getSize() const
{
    return _size;
}
    
const Size& Widget::getCustomSize() const
{
    return _customSize;
}

const Point& Widget::getSizePercent() const
{
    return _sizePercent;
}

Point Widget::getWorldPosition()
{
    return convertToWorldSpace(Point(_anchorPoint.x * _contentSize.width, _anchorPoint.y * _contentSize.height));//得到世界坐标
}

Node* Widget::getVirtualRenderer()
{
    return this;//得到虚拟渲染器 默认是自己 不同的子类有自己的重载
}

void Widget::onSizeChanged()
{
    setContentSize(_size);//设置 untransformed size
    for (auto& child : getChildren())
    {
        Widget* widgetChild = dynamic_cast<Widget*>(child);
        if (widgetChild)
        {
            widgetChild->updateSizeAndPosition();//递归更新全部子节点size position
        }
    }
}

const Size& Widget::getVirtualRendererSize() const
{
    return _contentSize;//得到虚拟渲染器zise 默认是_contentSize 不同的子类有自己的重载
}
    
void Widget::updateContentSizeWithTextureSize(const cocos2d::Size &size)
{
    if (_ignoreSize)
    {
        _size = size;
    }
    else
    {
        _size = _customSize;
    }
    onSizeChanged();
}

void Widget::setTouchEnabled(bool enable)
{
    if (enable == _touchEnabled)
    {
        return;
    }
    _touchEnabled = enable;
    if (_touchEnabled)//假设开启触摸
    {
        _touchListener = EventListenerTouchOneByOne::create();
        CC_SAFE_RETAIN(_touchListener);//创建单点触摸
        _touchListener->setSwallowTouches(true);//不向下触摸,简单点来说,比方有两个sprite ,A 和B,A在上B在下(位置重叠),触摸A的时候,B不会受到影响
        //绑定四个回调函数
        _touchListener->onTouchBegan = CC_CALLBACK_2(Widget::onTouchBegan, this);
        _touchListener->onTouchMoved = CC_CALLBACK_2(Widget::onTouchMoved, this);
        _touchListener->onTouchEnded = CC_CALLBACK_2(Widget::onTouchEnded, this);
        _touchListener->onTouchCancelled = CC_CALLBACK_2(Widget::onTouchCancelled, this);
        _eventDispatcher->addEventListenerWithSceneGraphPriority(_touchListener, this);
    }
    else //假设不开启触摸
    {
        _eventDispatcher->removeEventListener(_touchListener);//移除
        CC_SAFE_RELEASE_NULL(_touchListener);//释放
    }
}

bool Widget::isTouchEnabled() const
{
    return _touchEnabled;
}

bool Widget::isFocused() const
{
    return _focus;
}

void Widget::setFocused(bool fucos)
{
    if (fucos == _focus)
    {
        return;
    }
    _focus = fucos;
    if (_bright)//假设亮
    {
        if (_focus)//假设选中
        {
            setBrightStyle(BRIGHT_HIGHLIGHT);//高亮
        }
        else//假设没有选中
        {
            setBrightStyle(BRIGHT_NORMAL);//正常
        }
    }
    else//假设不亮
    {
        onPressStateChangedToDisabled();//变暗
    }
}

void Widget::setBright(bool bright)
{
    _bright = bright;
    if (_bright)//假设亮
    {
        _brightStyle = BRIGHT_NONE;
        setBrightStyle(BRIGHT_NORMAL);//正常亮
    }
    else//假设不亮
    {
        onPressStateChangedToDisabled();//变暗
    }
}

void Widget::setBrightStyle(BrightStyle style)
{
    if (_brightStyle == style)
    {
        return;
    }
    _brightStyle = style;
    switch (_brightStyle)
    {
        case BRIGHT_NORMAL:
            onPressStateChangedToNormal();
            break;
        case BRIGHT_HIGHLIGHT:
            onPressStateChangedToPressed();
            break;
        default:
            break;
    }
}

void Widget::onPressStateChangedToNormal()
{

}

void Widget::onPressStateChangedToPressed()
{

}

void Widget::onPressStateChangedToDisabled()
{

}

void Widget::didNotSelectSelf()
{

}
void Widget::logInfo(WidgetInfoType _type)
{
    log("widget anchor x = %f,y = %f",getAnchorPoint().x,getAnchorPoint().y);
    if (_type == WIDGET_SIZE) {
        log("widget size width = %f,height = %f",_size.width,_size.height);
    }
    if (_type == WIDGET_POSITION) {
        log("widget position x = %f,y = %f",getPositionX(),getPositionY());
    }
}
bool Widget::onTouchBegan(Touch *touch, Event *unusedEvent)
{
    _hitted = false;//刚開始触摸 没有碰到
    if (isEnabled() && isTouchEnabled())//节点能够使用 能够点击
    {
        _touchStartPos = touch->getLocation();//得到点击位置
        //触摸点在到图像区域 而且 触摸点在裁切区域
        if(hitTest(_touchStartPos) && clippingParentAreaContainPoint(_touchStartPos))
        {
            _hitted = true;//触摸到了
        }
    }
    if (!_hitted)//没有触摸到
    {
        return false;//停止
    }
    setFocused(true);//得到焦点
    Widget* widgetParent = getWidgetParent();
    if (widgetParent)//有父节点
    {
        widgetParent->checkChildInfo(0,this,_touchStartPos);//检查孩子属性
    }
    pushDownEvent();//按下回调响应
    return !_touchPassedEnabled;
}

void Widget::onTouchMoved(Touch *touch, Event *unusedEvent)
{
    _touchMovePos = touch->getLocation();
    setFocused(hitTest(_touchMovePos));
    Widget* widgetParent = getWidgetParent();
    if (widgetParent)
    {
        widgetParent->checkChildInfo(1,this,_touchMovePos);
    }
    moveEvent();
}

void Widget::onTouchEnded(Touch *touch, Event *unusedEvent)
{
    _touchEndPos = touch->getLocation();
    bool focus = _focus;
    setFocused(false);
    Widget* widgetParent = getWidgetParent();
    if (widgetParent)
    {
        widgetParent->checkChildInfo(2,this,_touchEndPos);
    }
    if (focus)
    {
        releaseUpEvent();
    }
    else
    {
        cancelUpEvent();
    }
}

void Widget::onTouchCancelled(Touch *touch, Event *unusedEvent)
{
    setFocused(false);
    cancelUpEvent();
}

void Widget::pushDownEvent()
{
    if (  _touchEventSelector)
    {
//        ( ->*_touchEventSelector)(this,TouchEventType::TOUCH_EVENT_BEGAN);//响应開始按下的回调
        _touchEventSelector(this,TouchEventType::TOUCH_EVENT_BEGAN);//响应開始按下的回调
    }
}

void Widget::moveEvent()
{
    if (  _touchEventSelector)
    {
//        ( ->*_touchEventSelector)(this,TouchEventType::TOUCH_EVENT_MOVED);//响应移动的回调
        _touchEventSelector(this,TouchEventType::TOUCH_EVENT_MOVED);//响应移动的回调
    }
}

void Widget::releaseUpEvent()
{
    if (  _touchEventSelector)
    {
//        ( ->*_touchEventSelector)(this,TouchEventType::TOUCH_EVENT_ENDED);//响应结束的回调
        _touchEventSelector(this,TouchEventType::TOUCH_EVENT_ENDED);//响应结束的回调
    }
}

void Widget::cancelUpEvent()
{
    if (  _touchEventSelector)
    {
        _touchEventSelector(this,TouchEventType::TOUCH_EVENT_CANCELED);//响应取消按下的回调
//        ( ->*_touchEventSelector)(this,TouchEventType::TOUCH_EVENT_CANCELED);//响应取消按下的回调
    }
}
//共外部注冊回调
void Widget::addTouchEventListener( SEL_TouchEvent selector)
{
    _touchEventSelector = selector;
}

bool Widget::hitTest(const Point &pt)
{
    Point nsp = convertToNodeSpace(pt);//相对this的点
    Rect bb;
    bb.size = _contentSize;
    if (bb.containsPoint(nsp))
    {
        return true;//点在size内 hit ~!
    }
    return false;
}

bool Widget::clippingParentAreaContainPoint(const Point &pt)
{
    _affectByClipping = false;
    Widget* parent = getWidgetParent();
    Widget* clippingParent = nullptr;
    while (parent)//有父节点
    {
        Layout* layoutParent = dynamic_cast<Layout*>(parent);
        if (layoutParent)//父节点是层容器
        {
            if (layoutParent->isClippingEnabled())//父节点是能够裁切的
            {
                _affectByClipping = true;//受裁切的影响
                clippingParent = layoutParent;//取到已经裁切的父节点
                break;//跳出循环
            }
        }
        parent = parent->getWidgetParent();//向上遍历父节点
    }

    if (!_affectByClipping)//没有能够裁切的层容器
    {
        return true;
    }


    if (clippingParent)//存在裁切的父节点
    {
        bool bRet = false;
        if (clippingParent->hitTest(pt))//点在裁切裁切范围内
        {
            bRet = true;
        }
        if (bRet)
        {
            return clippingParent->clippingParentAreaContainPoint(pt);//递归裁切父节点
        }
        return false;
    }
    return true;
}

void Widget::checkChildInfo(int handleState, Widget *sender, const Point &touchPoint)
{
    Widget* widgetParent = getWidgetParent();
    if (widgetParent)
    {
        widgetParent->checkChildInfo(handleState,sender,touchPoint);//递归检查孩子的info
    }
}

void Widget::setPosition(const Point &pos)
{
    if (_running)//若在执行状态
    {
        Widget* widgetParent = getWidgetParent();
        if (widgetParent)//若有父节点
        {
            Size pSize = widgetParent->getSize();//父节点大小
            if (pSize.width <= 0.0f || pSize.height <= 0.0f)
            {
                _positionPercent = Point::ZERO;//百分比为0
            }
            else
            {//计算相对父节点百分比
                _positionPercent = Point(pos.x / pSize.width, pos.y / pSize.height);
            }
        }
    }
    //由于widget对于position的表示除了 世界坐标之外 还新加了百分比坐标
    //所以须要额外处理计算百分比坐标
    ProtectedNode::setPosition(pos);
}

void Widget::setPositionPercent(const Point &percent)
{
    _positionPercent = percent;
    if (_running)
    {
        Widget* widgetParent = getWidgetParent();
        if (widgetParent)
        {
            Size parentSize = widgetParent->getSize();
            Point absPos = Point(parentSize.width * _positionPercent.x, parentSize.height * _positionPercent.y);//绝对坐标
            setPosition(absPos);
        }
    }
}

const Point& Widget::getPositionPercent()
{
    return _positionPercent;
}

void Widget::setPositionType(PositionType type)
{
    _positionType = type;
}

PositionType Widget::getPositionType() const
{
    return _positionType;
}

bool Widget::isBright() const
{
    return _bright;
}

bool Widget::isEnabled() const
{
    return _enabled;
}

float Widget::getLeftInParent()
{
    return getPosition().x - getAnchorPoint().x * _size.width;;
}
//得到距离父节点底部的距离
float Widget::getBottomInParent()
{
    return getPosition().y - getAnchorPoint().y * _size.height;;
}

float Widget::getRightInParent()
{
    return getLeftInParent() + _size.width;
}

float Widget::getTopInParent()
{
    return getBottomInParent() + _size.height;
}

const Point& Widget::getTouchStartPos()
{
    return _touchStartPos;
}

const Point& Widget::getTouchMovePos()
{
    return _touchMovePos;
}

const Point& Widget::getTouchEndPos()
{
    return _touchEndPos;
}

void Widget::setName(const char* name)
{
    _name = name;
}

const char* Widget::getName() const
{
    return _name.c_str();
}

WidgetType Widget::getWidgetType() const
{
    return _widgetType;
}
//设置布局參数
void Widget::setLayoutParameter(LayoutParameter *parameter)
{
    if (!parameter)
    {
        return;
    }
    _layoutParameterDictionary.insert(parameter->getLayoutType(), parameter);
}
//得到全部布局參数
LayoutParameter* Widget::getLayoutParameter(LayoutParameterType type)
{
    return dynamic_cast<LayoutParameter*>(_layoutParameterDictionary.at(type));
}

std::string Widget::getDescription() const
{
    return "Widget";
}
//克隆
Widget* Widget::clone()
{
    Widget* clonedWidget = createCloneInstance();
    clonedWidget->copyProperties(this);//拷贝基础属性
    clonedWidget->copyClonedWidgetChildren(this);//拷贝全部孩子
    return clonedWidget;
}

Widget* Widget::createCloneInstance()
{
    return Widget::create();
}

void Widget::copyClonedWidgetChildren(Widget* model)
{
    //引用类型auto&
    auto& modelChildren = model->getChildren();

    for (auto& subWidget : modelChildren)
    {
        Widget* child = dynamic_cast<Widget*>(subWidget);
        if (child)
        {
            addChild(child->clone());
        }
    }
}

void Widget::copySpecialProperties(Widget* model)
{

}
//拷贝属性
void Widget::copyProperties(Widget *widget)
{
    setEnabled(widget->isEnabled());
    setVisible(widget->isVisible());
    setBright(widget->isBright());
    setTouchEnabled(widget->isTouchEnabled());
    _touchPassedEnabled = false;
    setLocalZOrder(widget->getLocalZOrder());
    setTag(widget->getTag());
    setName(widget->getName());
    setActionTag(widget->getActionTag());
    _ignoreSize = widget->_ignoreSize;
    _size = widget->_size;
    _customSize = widget->_customSize;
    copySpecialProperties(widget);
    _sizeType = widget->getSizeType();
    _sizePercent = widget->_sizePercent;
    _positionType = widget->_positionType;
    _positionPercent = widget->_positionPercent;
    setPosition(widget->getPosition());
    setAnchorPoint(widget->getAnchorPoint());
    setScaleX(widget->getScaleX());
    setScaleY(widget->getScaleY());
    setRotation(widget->getRotation());
    setRotationSkewX(widget->getRotationSkewX());
    setRotationSkewY(widget->getRotationSkewY());
    setFlippedX(widget->isFlippedX());
    setFlippedY(widget->isFlippedY());
    setColor(widget->getColor());
    setOpacity(widget->getOpacity());
    //遍历布局參数 容器 拷贝
    Map<int, LayoutParameter*>& layoutParameterDic = widget->_layoutParameterDictionary;
    for (auto iter = layoutParameterDic.begin(); iter != layoutParameterDic.end(); ++iter)
    {
        setLayoutParameter(iter->second->clone());
    }
    onSizeChanged();
}
    
void Widget::setColor(const Color3B& color)
{
    _color = color;
    updateTextureColor();
}

void Widget::setOpacity(GLubyte opacity)
{
    _opacity = opacity;
    updateTextureOpacity();
}
    
void Widget::setFlippedX(bool flippedX)
{
    _flippedX = flippedX;
    updateFlippedX();
}

void Widget::setFlippedY(bool flippedY)
{
    _flippedY = flippedY;
    updateFlippedY();
}

void Widget::updateColorToRenderer(Node* renderer)
{
    renderer->setColor(_color);
}

void Widget::updateOpacityToRenderer(Node* renderer)
{
    renderer->setOpacity(_opacity);
}

void Widget::updateRGBAToRenderer(Node* renderer)
{
    renderer->setColor(_color);
    renderer->setOpacity(_opacity);
}

/*temp action*/
void Widget::setActionTag(int tag)
{
	_actionTag = tag;
}

int Widget::getActionTag()
{
	return _actionTag;
}

}

NS_CC_END


【Cocos2d-x】源代码分析之 2d/ui/Widget