ccgui
Version:
656 lines (569 loc) • 24.1 kB
JavaScript
/**
* CCControlButton.m
*
* Copyright (c) 2010-2012 cocos2d-x.org
* 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.
*/
cc.CONTROL_ZOOM_ACTION_TAG = 0xCCCB0001;
/** @class CCControlButton Button control for Cocos2D. */
cc.ControlButton = cc.Control.extend({
_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,
ctor:function () {
cc.Control.prototype.ctor.call(this);
this._preferredSize = new cc.Size(0, 0);
this._labelAnchorPoint = new cc.Point(0, 0);
this._currentTitle = "";
this._currentTitleColor = cc.white();
this._titleDispatchTable = {};
this._titleColorDispatchTable = {};
this._titleLabelDispatchTable = {};
this._backgroundSpriteDispatchTable = {};
},
init:function () {
return this.initWithLabelAndBackgroundSprite(cc.LabelTTF.create("", "Arial", 12), cc.Scale9Sprite.create());
},
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.RGBAProtocol)
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 = label ? label.getBoundingBox()._size : cc.size(0, 0);
// 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 || !label.RGBAProtocol)
throw "cc.ControlButton.initWithLabelAndBackgroundSprite(): label should be non-null";
if(!backgroundSprite)
throw "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.setTouchEnabled(true);
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 = new cc.Point(0.5, 0.5);
this.setPreferredSize(cc.SizeZero());
// Layout update
this.needsLayout();
return true;
}//couldn't init the CCControl
else
return false;
},
initWithTitleAndFontNameAndFontSize:function (title, fontName, fontSize) {
var label = cc.LabelTTF.create(title, fontName, fontSize);
return this.initWithLabelAndBackgroundSprite(label, cc.Scale9Sprite.create());
},
initWithBackgroundSprite:function (sprite) {
var label = cc.LabelTTF.create("", "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 prefered 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 prefered 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.RGBAProtocol)
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(){
return this._realColor;
},
/** 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();
if (this._zoomOnTouchDown) {
var scaleValue = (this.isHighlighted() && this.isEnabled() && !this.isSelected()) ? 1.1 : 1.0;
var zoomAction = cc.ScaleTo.create(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.Color3B} 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.white();
},
/**
* Sets the color of the title to use for the specified state.
*
* @param {cc.Color3B} 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.hasOwnProperty(state) && 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.hasOwnProperty(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(cc.LabelTTF.create(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(cc.LabelBMFont.create(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.hasOwnProperty(state) && 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.hasOwnProperty(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);
}
});
cc.ControlButton.create = function(label, backgroundSprite) {
var controlButton;
if (arguments.length == 0) {
controlButton = new cc.ControlButton();
if (controlButton && controlButton.init()) {
return controlButton;
}
return null;
} else if (arguments.length == 1) {
controlButton = new cc.ControlButton();
controlButton.initWithBackgroundSprite(arguments[0]);
} else if (arguments.length == 2) {
controlButton = new cc.ControlButton();
controlButton.initWithLabelAndBackgroundSprite(label, backgroundSprite);
} else if (arguments.length == 3) {
controlButton = new cc.ControlButton();
controlButton.initWithTitleAndFontNameAndFontSize(arguments[0], arguments[1], arguments[2]);
}
return controlButton;
};