Files
2020-08-24 23:16:53 +07:00

689 lines
24 KiB
JavaScript
Vendored

/**
* CCControlButton.m
*
* Copyright (c) 2008-2010 Ricardo Quesada
* Copyright (c) 2011-2012 cocos2d-x.org
* Copyright (c) 2013-2014 Chukong Technologies Inc.
* Copyright 2011 Yannick Loriot.
* http://yannickloriot.com
*
* 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.
*/
/**
* @ignore
*/
cc.CONTROL_ZOOM_ACTION_TAG = 0xCCCB0001;
/**
* CCControlButton: Button control for Cocos2D.
* @class
* @extends cc.Control
*
* @property {Boolean} adjustBackgroundImage - Indicate whether the background image will be adjusted
* @property {Boolean} zoomOnTouchDown - Indicate whether the button will be zoomed while touch down
* @property {cc.Size} preferredSize - The preferred size of the control button
* @property {Boolean} labelAnchor - The anchor point for the label of the control button
*/
cc.ControlButton = cc.Control.extend(/** @lends cc.ControlButton# */{
_doesAdjustBackgroundImage: false,
zoomOnTouchDown: false,
_preferredSize: null,
_labelAnchorPoint: null,
_currentTitle: null,
_currentTitleColor: null,
_titleLabel: null,
_backgroundSprite: null,
_opacity: 0,
_isPushed: false,
_titleDispatchTable: null,
_titleColorDispatchTable: null,
_titleLabelDispatchTable: null,
_backgroundSpriteDispatchTable: null,
_parentInited: false,
_marginV: 0,
_marginH: 0,
_className: "ControlButton",
ctor: function (label, backgroundSprite, fontSize) {
cc.Control.prototype.ctor.call(this);
this._preferredSize = cc.size(0, 0);
this._labelAnchorPoint = cc.p(0, 0);
this._currentTitle = "";
this._currentTitleColor = cc.color.WHITE;
this._titleDispatchTable = {};
this._titleColorDispatchTable = {};
this._titleLabelDispatchTable = {};
this._backgroundSpriteDispatchTable = {};
if(fontSize != undefined)
this.initWithTitleAndFontNameAndFontSize(label, backgroundSprite, fontSize);
else if(backgroundSprite != undefined)
this.initWithLabelAndBackgroundSprite(label, backgroundSprite);
else if(label != undefined)
this.initWithBackgroundSprite(label);
else
this.init();
},
init: function () {
return this.initWithLabelAndBackgroundSprite(new cc.LabelTTF("", "Arial", 12), new cc.Scale9Sprite());
},
needsLayout: function () {
if (!this._parentInited) {
return;
}
// Hide the background and the label
if (this._titleLabel)
this._titleLabel.setVisible(false);
if (this._backgroundSprite)
this._backgroundSprite.setVisible(false);
// Update anchor of all labels
this.setLabelAnchorPoint(this._labelAnchorPoint);
// Update the label to match with the current state
//CC_SAFE_RELEASE(this._currentTitle)
var locState = this._state;
this._currentTitle = this.getTitleForState(locState);
this._currentTitleColor = this.getTitleColorForState(locState);
this._titleLabel = this.getTitleLabelForState(locState);
var label = this._titleLabel;
if (label && label.setString)
label.setString(this._currentTitle);
if (label)
label.setColor(this._currentTitleColor);
var locContentSize = this.getContentSize();
if (label)
label.setPosition(locContentSize.width / 2, locContentSize.height / 2);
// Update the background sprite
this._backgroundSprite = this.getBackgroundSpriteForState(locState);
var locBackgroundSprite = this._backgroundSprite;
if (locBackgroundSprite)
locBackgroundSprite.setPosition(locContentSize.width / 2, locContentSize.height / 2);
// Get the title label size
var titleLabelSize = cc.size(0, 0);
if (label) {
var boundingBox = label.getBoundingBox();
titleLabelSize.width = boundingBox.width;
titleLabelSize.height = boundingBox.height;
}
// Adjust the background image if necessary
if (this._doesAdjustBackgroundImage) {
// Add the margins
if (locBackgroundSprite)
locBackgroundSprite.setContentSize(titleLabelSize.width + this._marginH * 2, titleLabelSize.height + this._marginV * 2);
} else {
//TODO: should this also have margins if one of the preferred sizes is relaxed?
if (locBackgroundSprite) {
var preferredSize = locBackgroundSprite.getPreferredSize();
preferredSize = cc.size(preferredSize.width, preferredSize.height);
if (preferredSize.width <= 0)
preferredSize.width = titleLabelSize.width;
if (preferredSize.height <= 0)
preferredSize.height = titleLabelSize.height;
locBackgroundSprite.setContentSize(preferredSize);
}
}
// Set the content size
var rectTitle = label ? label.getBoundingBox() : cc.rect(0, 0, 0, 0);
var rectBackground = locBackgroundSprite ? locBackgroundSprite.getBoundingBox() : cc.rect(0, 0, 0, 0);
var maxRect = cc.rectUnion(rectTitle, rectBackground);
this.setContentSize(maxRect.width, maxRect.height);
locContentSize = this.getContentSize();
if (label) {
label.setPosition(locContentSize.width / 2, locContentSize.height / 2);
label.setVisible(true);
}
if (locBackgroundSprite) {
locBackgroundSprite.setPosition(locContentSize.width / 2, locContentSize.height / 2);
locBackgroundSprite.setVisible(true);
}
},
initWithLabelAndBackgroundSprite: function (label, backgroundSprite) {
if (!label)
throw new Error("cc.ControlButton.initWithLabelAndBackgroundSprite(): label should be non-null");
if (!backgroundSprite)
throw new Error("cc.ControlButton.initWithLabelAndBackgroundSprite(): backgroundSprite should be non-null");
if (cc.Control.prototype.init.call(this, true)) {
this._parentInited = true;
// Initialize the button state tables
this._titleDispatchTable = {};
this._titleColorDispatchTable = {};
this._titleLabelDispatchTable = {};
this._backgroundSpriteDispatchTable = {};
this._isPushed = false;
this.zoomOnTouchDown = true;
this._currentTitle = null;
// Adjust the background image by default
this.setAdjustBackgroundImage(true);
this.setPreferredSize(cc.size(0, 0));
// Zooming button by default
this.zoomOnTouchDown = true;
// Set the default anchor point
this.ignoreAnchorPointForPosition(false);
this.setAnchorPoint(0.5, 0.5);
// Set the nodes
this._titleLabel = label;
this._backgroundSprite = backgroundSprite;
// Set the default color and opacity
this.setOpacity(255);
this.setOpacityModifyRGB(true);
// Initialize the dispatch table
var tempString = label.getString();
//tempString.autorelease();
this.setTitleForState(tempString, cc.CONTROL_STATE_NORMAL);
this.setTitleColorForState(label.getColor(), cc.CONTROL_STATE_NORMAL);
this.setTitleLabelForState(label, cc.CONTROL_STATE_NORMAL);
this.setBackgroundSpriteForState(backgroundSprite, cc.CONTROL_STATE_NORMAL);
this._state = cc.CONTROL_STATE_NORMAL;
//default margins
this._marginH = 24;
this._marginV = 12;
this._labelAnchorPoint = cc.p(0.5, 0.5);
this.setPreferredSize(cc.size(0, 0));
// Layout update
this.needsLayout();
return true;
}//couldn't init the CCControl
else
return false;
},
initWithTitleAndFontNameAndFontSize: function (title, fontName, fontSize) {
var label = new cc.LabelTTF(title, fontName, fontSize);
return this.initWithLabelAndBackgroundSprite(label, new cc.Scale9Sprite());
},
initWithBackgroundSprite: function (sprite) {
var label = new cc.LabelTTF("", "Arial", 30);//
return this.initWithLabelAndBackgroundSprite(label, sprite);
},
/**
* Adjust the background image. YES by default. If the property is set to NO, the background will use the preferred size of the background image.
* @return {Boolean}
*/
doesAdjustBackgroundImage: function () {
return this._doesAdjustBackgroundImage;
},
setAdjustBackgroundImage: function (adjustBackgroundImage) {
this._doesAdjustBackgroundImage = adjustBackgroundImage;
this.needsLayout();
},
/** Adjust the button zooming on touchdown. Default value is YES. */
getZoomOnTouchDown: function () {
return this.zoomOnTouchDown;
},
setZoomOnTouchDown: function (zoomOnTouchDown) {
return this.zoomOnTouchDown = zoomOnTouchDown;
},
/** The preferred size of the button, if label is larger it will be expanded. */
getPreferredSize: function () {
return this._preferredSize;
},
setPreferredSize: function (size) {
if (size.width === 0 && size.height === 0) {
this._doesAdjustBackgroundImage = true;
} else {
this._doesAdjustBackgroundImage = false;
var locTable = this._backgroundSpriteDispatchTable;
for (var itemKey in locTable)
locTable[itemKey].setPreferredSize(size);
}
this._preferredSize = size;
this.needsLayout();
},
getLabelAnchorPoint: function () {
return this._labelAnchorPoint;
},
setLabelAnchorPoint: function (labelAnchorPoint) {
this._labelAnchorPoint = labelAnchorPoint;
if (this._titleLabel)
this._titleLabel.setAnchorPoint(labelAnchorPoint);
},
/**
* The current title that is displayed on the button.
* @return {string}
*/
_getCurrentTitle: function () {
return this._currentTitle;
},
/** The current color used to display the title. */
_getCurrentTitleColor: function () {
return this._currentTitleColor;
},
/* Override setter to affect a background sprite too */
getOpacity: function () {
return this._opacity;
},
setOpacity: function (opacity) {
// XXX fixed me if not correct
cc.Control.prototype.setOpacity.call(this, opacity);
/*this._opacity = opacity;
var controlChildren = this.getChildren();
for (var i = 0; i < controlChildren.length; i++) {
var selChild = controlChildren[i];
if (selChild)
selChild.setOpacity(opacity);
}*/
var locTable = this._backgroundSpriteDispatchTable;
for (var itemKey in locTable)
locTable[itemKey].setOpacity(opacity);
},
setColor: function (color) {
cc.Control.prototype.setColor.call(this, color);
var locTable = this._backgroundSpriteDispatchTable;
for (var key in locTable)
locTable[key].setColor(color);
},
getColor: function () {
var locRealColor = this._realColor;
return cc.color(locRealColor.r, locRealColor.g, locRealColor.b, locRealColor.a);
},
/** Flag to know if the button is currently pushed. */
isPushed: function () {
return this._isPushed;
},
/* Define the button margin for Top/Bottom edge */
_getVerticalMargin: function () {
return this._marginV;
},
/* Define the button margin for Left/Right edge */
_getHorizontalOrigin: function () {
return this._marginH;
},
/**
* set the margins at once (so we only have to do one call of needsLayout)
* @param {Number} marginH
* @param {Number} marginV
*/
setMargins: function (marginH, marginV) {
this._marginV = marginV;
this._marginH = marginH;
this.needsLayout();
},
setEnabled: function (enabled) {
cc.Control.prototype.setEnabled.call(this, enabled);
this.needsLayout();
},
setSelected: function (enabled) {
cc.Control.prototype.setSelected.call(this, enabled);
this.needsLayout();
},
setHighlighted: function (enabled) {
this._state = enabled ? cc.CONTROL_STATE_HIGHLIGHTED : cc.CONTROL_STATE_NORMAL;
cc.Control.prototype.setHighlighted.call(this, enabled);
var action = this.getActionByTag(cc.CONTROL_ZOOM_ACTION_TAG);
if (action)
this.stopAction(action);
//this.needsLayout();// needn't
if (this.zoomOnTouchDown) {
var scaleValue = (this.isHighlighted() && this.isEnabled() && !this.isSelected()) ? 1.1 : 1.0;
var zoomAction = cc.scaleTo(0.05, scaleValue);
zoomAction.setTag(cc.CONTROL_ZOOM_ACTION_TAG);
this.runAction(zoomAction);
}
},
onTouchBegan: function (touch, event) {
if (!this.isTouchInside(touch) || !this.isEnabled() || !this.isVisible() || !this.hasVisibleParents())
return false;
this._isPushed = true;
this.setHighlighted(true);
this.sendActionsForControlEvents(cc.CONTROL_EVENT_TOUCH_DOWN);
return true;
},
onTouchMoved: function (touch, event) {
if (!this._enabled || !this._isPushed || this._selected) {
if (this._highlighted)
this.setHighlighted(false);
return;
}
var isTouchMoveInside = this.isTouchInside(touch);
if (isTouchMoveInside && !this._highlighted) {
this.setHighlighted(true);
this.sendActionsForControlEvents(cc.CONTROL_EVENT_TOUCH_DRAG_ENTER);
} else if (isTouchMoveInside && this._highlighted) {
this.sendActionsForControlEvents(cc.CONTROL_EVENT_TOUCH_DRAG_INSIDE);
} else if (!isTouchMoveInside && this._highlighted) {
this.setHighlighted(false);
this.sendActionsForControlEvents(cc.CONTROL_EVENT_TOUCH_DRAG_EXIT);
} else if (!isTouchMoveInside && !this._highlighted) {
this.sendActionsForControlEvents(cc.CONTROL_EVENT_TOUCH_DRAG_OUTSIDE);
}
},
onTouchEnded: function (touch, event) {
this._isPushed = false;
this.setHighlighted(false);
if (this.isTouchInside(touch)) {
this.sendActionsForControlEvents(cc.CONTROL_EVENT_TOUCH_UP_INSIDE);
} else {
this.sendActionsForControlEvents(cc.CONTROL_EVENT_TOUCH_UP_OUTSIDE);
}
},
onTouchCancelled: function (touch, event) {
this._isPushed = false;
this.setHighlighted(false);
this.sendActionsForControlEvents(cc.CONTROL_EVENT_TOUCH_CANCEL);
},
/**
* Returns the title used for a state.
*
* @param {Number} state The state that uses the title. Possible values are described in "CCControlState".
* @return {string} The title for the specified state.
*/
getTitleForState: function (state) {
var locTable = this._titleDispatchTable;
if (locTable) {
if (locTable[state])
return locTable[state];
return locTable[cc.CONTROL_STATE_NORMAL];
}
return "";
},
/**
* <p>
* Sets the title string to use for the specified state. <br/>
* If a property is not specified for a state, the default is to use the CCButtonStateNormal value.
* </p>
* @param {string} title The title string to use for the specified state.
* @param {Number} state The state that uses the specified title. The values are described in "CCControlState".
*/
setTitleForState: function (title, state) {
this._titleDispatchTable[state] = title || "";
// If the current state if equal to the given state we update the layout
if (this.getState() === state)
this.needsLayout();
},
/**
* Returns the title color used for a state.
*
* @param {Number} state The state that uses the specified color. The values are described in "CCControlState".
* @return {cc.Color} The color of the title for the specified state.
*/
getTitleColorForState: function (state) {
var colorObject = this._titleColorDispatchTable[state];
if (colorObject)
return colorObject;
colorObject = this._titleColorDispatchTable[cc.CONTROL_STATE_NORMAL];
if (colorObject)
return colorObject;
return cc.color.WHITE;
},
/**
* Sets the color of the title to use for the specified state.
*
* @param {cc.Color} color The color of the title to use for the specified state.
* @param {Number} state The state that uses the specified color. The values are described in "CCControlState".
*/
setTitleColorForState: function (color, state) {
//ccColor3B* colorValue=&color;
this._titleColorDispatchTable[state] = color;
// If the current state if equal to the given state we update the layout
if (this.getState() === state)
this.needsLayout();
},
/**
* Returns the title label used for a state.
*
* @param state The state that uses the title label. Possible values are described in "CCControlState".
* @return {cc.Node} the title label used for a state.
*/
getTitleLabelForState: function (state) {
var locTable = this._titleLabelDispatchTable;
if (locTable[state])
return locTable[state];
return locTable[cc.CONTROL_STATE_NORMAL];
},
/**
* <p>Sets the title label to use for the specified state. <br/>
* If a property is not specified for a state, the default is to use the CCButtonStateNormal value. </p>
*
* @param {cc.Node} titleLabel The title label to use for the specified state.
* @param {Number} state The state that uses the specified title. The values are described in "CCControlState".
*/
setTitleLabelForState: function (titleLabel, state) {
var locTable = this._titleLabelDispatchTable;
if (locTable[state]) {
var previousLabel = locTable[state];
if (previousLabel)
this.removeChild(previousLabel, true);
}
locTable[state] = titleLabel;
titleLabel.setVisible(false);
titleLabel.setAnchorPoint(0.5, 0.5);
this.addChild(titleLabel, 1);
// If the current state if equal to the given state we update the layout
if (this.getState() === state)
this.needsLayout();
},
/**
* Sets the title TTF filename to use for the specified state.
* @param {string} fntFile
* @param {Number} state
*/
setTitleTTFForState: function (fntFile, state) {
var title = this.getTitleForState(state);
if (!title)
title = "";
this.setTitleLabelForState(new cc.LabelTTF(title, fntFile, 12), state);
},
/**
* return the title TTF filename to use for the specified state.
* @param {Number} state
* @returns {string}
*/
getTitleTTFForState: function (state) {
var labelTTF = this.getTitleLabelForState(state);
if ((labelTTF != null) && (labelTTF instanceof cc.LabelTTF)) {
return labelTTF.getFontName();
} else {
return "";
}
},
/**
* @param {Number} size
* @param {Number} state
*/
setTitleTTFSizeForState: function (size, state) {
var labelTTF = this.getTitleLabelForState(state);
if ((labelTTF != null) && (labelTTF instanceof cc.LabelTTF)) {
labelTTF.setFontSize(size);
}
},
/**
* return the font size of LabelTTF to use for the specified state
* @param {Number} state
* @returns {Number}
*/
getTitleTTFSizeForState: function (state) {
var labelTTF = this.getTitleLabelForState(state);
if ((labelTTF != null) && (labelTTF instanceof cc.LabelTTF)) {
return labelTTF.getFontSize();
}
return 0;
},
/**
* Sets the font of the label, changes the label to a CCLabelBMFont if necessary.
* @param {string} fntFile The name of the font to change to
* @param {Number} state The state that uses the specified fntFile. The values are described in "CCControlState".
*/
setTitleBMFontForState: function (fntFile, state) {
var title = this.getTitleForState(state);
if (!title)
title = "";
this.setTitleLabelForState(new cc.LabelBMFont(title, fntFile), state);
},
getTitleBMFontForState: function (state) {
var labelBMFont = this.getTitleLabelForState(state);
if ((labelBMFont != null) && (labelBMFont instanceof cc.LabelBMFont)) {
return labelBMFont.getFntFile();
}
return "";
},
/**
* Returns the background sprite used for a state.
*
* @param {Number} state The state that uses the background sprite. Possible values are described in "CCControlState".
*/
getBackgroundSpriteForState: function (state) {
var locTable = this._backgroundSpriteDispatchTable;
if (locTable[state]) {
return locTable[state];
}
return locTable[cc.CONTROL_STATE_NORMAL];
},
/**
* Sets the background sprite to use for the specified button state.
*
* @param {Scale9Sprite} sprite The background sprite to use for the specified state.
* @param {Number} state The state that uses the specified image. The values are described in "CCControlState".
*/
setBackgroundSpriteForState: function (sprite, state) {
var locTable = this._backgroundSpriteDispatchTable;
if (locTable[state]) {
var previousSprite = locTable[state];
if (previousSprite)
this.removeChild(previousSprite, true);
}
locTable[state] = sprite;
sprite.setVisible(false);
sprite.setAnchorPoint(0.5, 0.5);
this.addChild(sprite);
var locPreferredSize = this._preferredSize;
if (locPreferredSize.width !== 0 || locPreferredSize.height !== 0) {
sprite.setPreferredSize(locPreferredSize);
}
// If the current state if equal to the given state we update the layout
if (this._state === state)
this.needsLayout();
},
/**
* Sets the background spriteFrame to use for the specified button state.
*
* @param {SpriteFrame} spriteFrame The background spriteFrame to use for the specified state.
* @param {Number} state The state that uses the specified image. The values are described in "CCControlState".
*/
setBackgroundSpriteFrameForState: function (spriteFrame, state) {
var sprite = cc.Scale9Sprite.createWithSpriteFrame(spriteFrame);
this.setBackgroundSpriteForState(sprite, state);
}
});
var _p = cc.ControlButton.prototype;
// Extended properties
/** @expose */
_p.adjustBackground;
cc.defineGetterSetter(_p, "adjustBackground", _p.getAdjustBackgroundImage, _p.setAdjustBackgroundImage);
/** @expose */
_p.preferredSize;
cc.defineGetterSetter(_p, "preferredSize", _p.getPreferredSize, _p.setPreferredSize);
/** @expose */
_p.labelAnchor;
cc.defineGetterSetter(_p, "labelAnchor", _p.getLabelAnchorPoint, _p.setLabelAnchorPoint);
_p = null;
/**
* @deprecated
* @param label
* @param backgroundSprite
* @param fontSize
* @returns {ControlButton}
*/
cc.ControlButton.create = function (label, backgroundSprite, fontSize) {
return new cc.ControlButton(label, backgroundSprite, fontSize);
};