axmol/extensions/GUI/CCControlExtension/CCControlSwitch.cpp

451 lines
13 KiB
C++

/*
* Copyright (c) 2012 cocos2d-x.org
* http://www.cocos2d-x.org
*
* Copyright 2012 Yannick Loriot. All rights reserved.
* 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.
*
*/
#include "CCControlSwitch.h"
#include "cocos2d.h"
NS_CC_EXT_BEGIN
// ControlSwitchSprite
class ControlSwitchSprite : public Sprite, public ActionTweenDelegate
{
public:
ControlSwitchSprite();
virtual ~ControlSwitchSprite();
bool initWithMaskSprite(
Sprite *maskSprite,
Sprite *onSprite,
Sprite *offSprite,
Sprite *thumbSprite,
LabelTTF* onLabel,
LabelTTF* offLabel);
void draw();
void needsLayout();
void setSliderXPosition(float sliderXPosition);
float getSliderXPosition() {return _sliderXPosition;}
float onSideWidth();
float offSideWidth();
virtual void updateTweenAction(float value, const char* key);
/** Contains the position (in x-axis) of the slider inside the receiver. */
float _sliderXPosition;
CC_SYNTHESIZE(float, _onPosition, OnPosition)
CC_SYNTHESIZE(float, _offPosition, OffPosition)
CC_SYNTHESIZE_RETAIN(Texture2D*, _maskTexture, MaskTexture)
CC_SYNTHESIZE(GLuint, _textureLocation, TextureLocation)
CC_SYNTHESIZE(GLuint, _maskLocation, MaskLocation)
CC_SYNTHESIZE_RETAIN(Sprite*, _onSprite, OnSprite)
CC_SYNTHESIZE_RETAIN(Sprite*, _offSprite, OffSprite)
CC_SYNTHESIZE_RETAIN(Sprite*, _thumbSprite, ThumbSprite)
CC_SYNTHESIZE_RETAIN(LabelTTF*, _onLabel, OnLabel)
CC_SYNTHESIZE_RETAIN(LabelTTF*, _offLabel, OffLabel)
};
ControlSwitchSprite::ControlSwitchSprite()
: _sliderXPosition(0.0f)
, _onPosition(0.0f)
, _offPosition(0.0f)
, _maskTexture(NULL)
, _textureLocation(0)
, _maskLocation(0)
, _onSprite(NULL)
, _offSprite(NULL)
, _thumbSprite(NULL)
, _onLabel(NULL)
, _offLabel(NULL)
{
}
ControlSwitchSprite::~ControlSwitchSprite()
{
CC_SAFE_RELEASE(_onSprite);
CC_SAFE_RELEASE(_offSprite);
CC_SAFE_RELEASE(_thumbSprite);
CC_SAFE_RELEASE(_onLabel);
CC_SAFE_RELEASE(_offLabel);
CC_SAFE_RELEASE(_maskTexture);
}
bool ControlSwitchSprite::initWithMaskSprite(
Sprite *maskSprite,
Sprite *onSprite,
Sprite *offSprite,
Sprite *thumbSprite,
LabelTTF* onLabel,
LabelTTF* offLabel)
{
if (Sprite::initWithTexture(maskSprite->getTexture()))
{
// Sets the default values
_onPosition = 0;
_offPosition = -onSprite->getContentSize().width + thumbSprite->getContentSize().width / 2;
_sliderXPosition = _onPosition;
setOnSprite(onSprite);
setOffSprite(offSprite);
setThumbSprite(thumbSprite);
setOnLabel(onLabel);
setOffLabel(offLabel);
addChild(_thumbSprite);
// Set up the mask with the Mask shader
setMaskTexture(maskSprite->getTexture());
GLProgram* pProgram = new GLProgram();
pProgram->initWithVertexShaderByteArray(ccPositionTextureColor_vert, ccExSwitchMask_frag);
setShaderProgram(pProgram);
pProgram->release();
CHECK_GL_ERROR_DEBUG();
getShaderProgram()->addAttribute(kAttributeNamePosition, kVertexAttrib_Position);
getShaderProgram()->addAttribute(kAttributeNameColor, kVertexAttrib_Color);
getShaderProgram()->addAttribute(kAttributeNameTexCoord, kVertexAttrib_TexCoords);
CHECK_GL_ERROR_DEBUG();
getShaderProgram()->link();
CHECK_GL_ERROR_DEBUG();
getShaderProgram()->updateUniforms();
CHECK_GL_ERROR_DEBUG();
_textureLocation = glGetUniformLocation( getShaderProgram()->getProgram(), "u_texture");
_maskLocation = glGetUniformLocation( getShaderProgram()->getProgram(), "u_mask");
CHECK_GL_ERROR_DEBUG();
setContentSize(_maskTexture->getContentSize());
needsLayout();
return true;
}
return false;
}
void ControlSwitchSprite::updateTweenAction(float value, const char* key)
{
CCLOG("key = %s, value = %f", key, value);
setSliderXPosition(value);
}
void ControlSwitchSprite::draw()
{
CC_NODE_DRAW_SETUP();
ccGLEnableVertexAttribs(kVertexAttribFlag_PosColorTex);
ccGLBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
getShaderProgram()->setUniformsForBuiltins();
glActiveTexture(GL_TEXTURE0);
glBindTexture( GL_TEXTURE_2D, getTexture()->getName());
glUniform1i(_textureLocation, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture( GL_TEXTURE_2D, _maskTexture->getName() );
glUniform1i(_maskLocation, 1);
#define kQuadSize sizeof(_quad.bl)
#ifdef EMSCRIPTEN
long offset = 0;
setGLBufferData(&_quad, 4 * kQuadSize, 0);
#else
long offset = (long)&_quad;
#endif // EMSCRIPTEN
// vertex
int diff = offsetof( ccV3F_C4B_T2F, vertices);
glVertexAttribPointer(kVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff));
// texCoods
diff = offsetof( ccV3F_C4B_T2F, texCoords);
glVertexAttribPointer(kVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));
// color
diff = offsetof( ccV3F_C4B_T2F, colors);
glVertexAttribPointer(kVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glActiveTexture(GL_TEXTURE0);
}
void ControlSwitchSprite::needsLayout()
{
_onSprite->setPosition(ccp(_onSprite->getContentSize().width / 2 + _sliderXPosition,
_onSprite->getContentSize().height / 2));
_offSprite->setPosition(ccp(_onSprite->getContentSize().width + _offSprite->getContentSize().width / 2 + _sliderXPosition,
_offSprite->getContentSize().height / 2));
_thumbSprite->setPosition(ccp(_onSprite->getContentSize().width + _sliderXPosition,
_maskTexture->getContentSize().height / 2));
if (_onLabel)
{
_onLabel->setPosition(ccp(_onSprite->getPosition().x - _thumbSprite->getContentSize().width / 6,
_onSprite->getContentSize().height / 2));
}
if (_offLabel)
{
_offLabel->setPosition(ccp(_offSprite->getPosition().x + _thumbSprite->getContentSize().width / 6,
_offSprite->getContentSize().height / 2));
}
RenderTexture *rt = RenderTexture::create((int)_maskTexture->getContentSize().width, (int)_maskTexture->getContentSize().height);
rt->begin();
_onSprite->visit();
_offSprite->visit();
if (_onLabel)
{
_onLabel->visit();
}
if (_offLabel)
{
_offLabel->visit();
}
rt->end();
setTexture(rt->getSprite()->getTexture());
setFlipY(true);
}
void ControlSwitchSprite::setSliderXPosition(float sliderXPosition)
{
if (sliderXPosition <= _offPosition)
{
// Off
sliderXPosition = _offPosition;
} else if (sliderXPosition >= _onPosition)
{
// On
sliderXPosition = _onPosition;
}
_sliderXPosition = sliderXPosition;
needsLayout();
}
float ControlSwitchSprite::onSideWidth()
{
return _onSprite->getContentSize().width;
}
float ControlSwitchSprite::offSideWidth()
{
return _offSprite->getContentSize().height;
}
// ControlSwitch
ControlSwitch::ControlSwitch()
: _switchSprite(NULL)
, _initialTouchXPosition(0.0f)
, _moved(false)
, _on(false)
{
}
ControlSwitch::~ControlSwitch()
{
CC_SAFE_RELEASE(_switchSprite);
}
bool ControlSwitch::initWithMaskSprite(Sprite *maskSprite, Sprite * onSprite, Sprite * offSprite, Sprite * thumbSprite)
{
return initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, NULL, NULL);
}
ControlSwitch* ControlSwitch::create(Sprite *maskSprite, Sprite * onSprite, Sprite * offSprite, Sprite * thumbSprite)
{
ControlSwitch* pRet = new ControlSwitch();
if (pRet && pRet->initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, NULL, NULL))
{
pRet->autorelease();
}
else
{
CC_SAFE_DELETE(pRet);
}
return pRet;
}
bool ControlSwitch::initWithMaskSprite(Sprite *maskSprite, Sprite * onSprite, Sprite * offSprite, Sprite * thumbSprite, LabelTTF* onLabel, LabelTTF* offLabel)
{
if (Control::init())
{
CCAssert(maskSprite, "Mask must not be nil.");
CCAssert(onSprite, "onSprite must not be nil.");
CCAssert(offSprite, "offSprite must not be nil.");
CCAssert(thumbSprite, "thumbSprite must not be nil.");
setTouchEnabled(true);
_on = true;
_switchSprite = new ControlSwitchSprite();
_switchSprite->initWithMaskSprite(maskSprite,
onSprite,
offSprite,
thumbSprite,
onLabel,
offLabel);
_switchSprite->setPosition(ccp (_switchSprite->getContentSize().width / 2, _switchSprite->getContentSize().height / 2));
addChild(_switchSprite);
ignoreAnchorPointForPosition(false);
setAnchorPoint(ccp (0.5f, 0.5f));
setContentSize(_switchSprite->getContentSize());
return true;
}
return false;
}
ControlSwitch* ControlSwitch::create(Sprite *maskSprite, Sprite * onSprite, Sprite * offSprite, Sprite * thumbSprite, LabelTTF* onLabel, LabelTTF* offLabel)
{
ControlSwitch* pRet = new ControlSwitch();
if (pRet && pRet->initWithMaskSprite(maskSprite, onSprite, offSprite, thumbSprite, onLabel, offLabel))
{
pRet->autorelease();
}
else
{
CC_SAFE_DELETE(pRet);
}
return pRet;
}
void ControlSwitch::setOn(bool isOn)
{
setOn(isOn, false);
}
void ControlSwitch::setOn(bool isOn, bool animated)
{
_on = isOn;
if (animated) {
_switchSprite->runAction
(
ActionTween::create
(
0.2f,
"sliderXPosition",
_switchSprite->getSliderXPosition(),
(_on) ? _switchSprite->getOnPosition() : _switchSprite->getOffPosition()
)
);
}
else {
_switchSprite->setSliderXPosition((_on) ? _switchSprite->getOnPosition() : _switchSprite->getOffPosition());
}
sendActionsForControlEvents(ControlEventValueChanged);
}
void ControlSwitch::setEnabled(bool enabled)
{
_enabled = enabled;
if (_switchSprite != NULL)
{
_switchSprite->setOpacity((enabled) ? 255 : 128);
}
}
Point ControlSwitch::locationFromTouch(Touch* pTouch)
{
Point touchLocation = pTouch->getLocation(); // Get the touch position
touchLocation = this->convertToNodeSpace(touchLocation); // Convert to the node space of this class
return touchLocation;
}
bool ControlSwitch::ccTouchBegan(Touch *pTouch, Event *pEvent)
{
if (!isTouchInside(pTouch) || !isEnabled() || !isVisible())
{
return false;
}
_moved = false;
Point location = this->locationFromTouch(pTouch);
_initialTouchXPosition = location.x - _switchSprite->getSliderXPosition();
_switchSprite->getThumbSprite()->setColor(ccGRAY);
_switchSprite->needsLayout();
return true;
}
void ControlSwitch::ccTouchMoved(Touch *pTouch, Event *pEvent)
{
Point location = this->locationFromTouch(pTouch);
location = ccp (location.x - _initialTouchXPosition, 0);
_moved = true;
_switchSprite->setSliderXPosition(location.x);
}
void ControlSwitch::ccTouchEnded(Touch *pTouch, Event *pEvent)
{
Point location = this->locationFromTouch(pTouch);
_switchSprite->getThumbSprite()->setColor(ccWHITE);
if (hasMoved())
{
setOn(!(location.x < _switchSprite->getContentSize().width / 2), true);
}
else
{
setOn(!_on, true);
}
}
void ControlSwitch::ccTouchCancelled(Touch *pTouch, Event *pEvent)
{
Point location = this->locationFromTouch(pTouch);
_switchSprite->getThumbSprite()->setColor(ccWHITE);
if (hasMoved())
{
setOn(!(location.x < _switchSprite->getContentSize().width / 2), true);
} else
{
setOn(!_on, true);
}
}
NS_CC_EXT_END