mirror of https://github.com/axmolengine/axmol.git
Merge branch 'master' into 608
This commit is contained in:
commit
5f08bb24fe
|
@ -24,8 +24,8 @@ function btnTouchMove(e)
|
|||
local v = e[1]
|
||||
local pointMove = v:locationInView(v:view())
|
||||
pointMove = cocos2d.CCDirector:sharedDirector():convertToGL(pointMove)
|
||||
local positionCurrent = layerFarm.__CCNode__:getPosition()
|
||||
layerFarm.__CCNode__:setPosition(cocos2d.CCPoint(positionCurrent.x + pointMove.x - pointBegin.x, positionCurrent.y + pointMove.y - pointBegin.y))
|
||||
local positionCurrent = layerFarm:getPosition()
|
||||
layerFarm:setPosition(cocos2d.CCPoint(positionCurrent.x + pointMove.x - pointBegin.x, positionCurrent.y + pointMove.y - pointBegin.y))
|
||||
pointBegin = pointMove
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
using namespace cocos2d;
|
||||
|
||||
#define IMG_PATH "assets"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
|
@ -23,8 +21,6 @@ void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thi
|
|||
view->create(480, 320);
|
||||
cocos2d::CCDirector::sharedDirector()->setOpenGLView(view);
|
||||
|
||||
CCFileUtils::setRelativePath(IMG_PATH);
|
||||
|
||||
AppDelegate *pAppDelegate = new AppDelegate();
|
||||
cocos2d::CCApplication::sharedApplication().run();
|
||||
}
|
||||
|
|
|
@ -83,6 +83,9 @@ public class Cocos2dxActivity extends Activity{
|
|||
backgroundMusicPlayer = new Cocos2dxMusic(this);
|
||||
soundPlayer = new Cocos2dxSound(this);
|
||||
|
||||
// init bitmap context
|
||||
Cocos2dxBitmap.setContext(this);
|
||||
|
||||
handler = new Handler(){
|
||||
public void handleMessage(Message msg){
|
||||
switch(msg.what){
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.ByteOrder;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
|
@ -11,6 +12,7 @@ import android.graphics.Paint;
|
|||
import android.graphics.Typeface;
|
||||
import android.graphics.Paint.Align;
|
||||
import android.graphics.Paint.FontMetricsInt;
|
||||
import android.util.Log;
|
||||
|
||||
public class Cocos2dxBitmap{
|
||||
/*
|
||||
|
@ -21,6 +23,12 @@ public class Cocos2dxBitmap{
|
|||
private static final int ALIGNLEFT = 0x31;
|
||||
private static final int ALIGNRIGHT = 0x32;
|
||||
|
||||
private static Context context;
|
||||
|
||||
public static void setContext(Context context){
|
||||
Cocos2dxBitmap.context = context;
|
||||
}
|
||||
|
||||
/*
|
||||
* @width: the width to draw, it can be 0
|
||||
* @height: the height to draw, it can be 0
|
||||
|
@ -31,7 +39,7 @@ public class Cocos2dxBitmap{
|
|||
content = refactorString(content);
|
||||
Paint paint = newPaint(fontName, fontSize, alignment);
|
||||
|
||||
TextProperty textProperty = getTextWidthAndHeight(content, paint, width, height);
|
||||
TextProperty textProperty = computeTextProperty(content, paint, width, height);
|
||||
|
||||
// Draw text to bitmap
|
||||
Bitmap bitmap = Bitmap.createBitmap(textProperty.maxWidth,
|
||||
|
@ -95,7 +103,7 @@ public class Cocos2dxBitmap{
|
|||
}
|
||||
}
|
||||
|
||||
private static TextProperty getTextWidthAndHeight(String content, Paint paint,
|
||||
private static TextProperty computeTextProperty(String content, Paint paint,
|
||||
int maxWidth, int maxHeight){
|
||||
FontMetricsInt fm = paint.getFontMetricsInt();
|
||||
int h = (int)Math.ceil(fm.descent - fm.ascent);
|
||||
|
@ -119,7 +127,6 @@ public class Cocos2dxBitmap{
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return new TextProperty(maxContentWidth, h, lines);
|
||||
}
|
||||
|
||||
|
@ -231,10 +238,10 @@ public class Cocos2dxBitmap{
|
|||
}
|
||||
|
||||
/*
|
||||
* Add the last char
|
||||
* Add the last chars
|
||||
*/
|
||||
if (start == charLength - 1){
|
||||
strList.add(content.substring(charLength-1));
|
||||
if (start < charLength){
|
||||
strList.add(content.substring(start));
|
||||
}
|
||||
|
||||
return strList;
|
||||
|
@ -244,9 +251,29 @@ public class Cocos2dxBitmap{
|
|||
Paint paint = new Paint();
|
||||
paint.setColor(Color.WHITE);
|
||||
paint.setTextSize(fontSize);
|
||||
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
/*
|
||||
* Set type face for paint, now it support .ttf file.
|
||||
*/
|
||||
if (fontName.endsWith(".ttf")){
|
||||
try {
|
||||
Typeface typeFace = Typeface.createFromAsset(context.getAssets(), fontName);
|
||||
paint.setTypeface(typeFace);
|
||||
} catch (Exception e){
|
||||
Log.e("Cocos2dxBitmap",
|
||||
"error to create ttf type face: " + fontName);
|
||||
|
||||
/*
|
||||
* The file may not find, use system font
|
||||
*/
|
||||
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
|
||||
}
|
||||
}
|
||||
else {
|
||||
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
|
||||
}
|
||||
|
||||
switch (alignment){
|
||||
case ALIGNCENTER:
|
||||
paint.setTextAlign(Align.CENTER);
|
||||
|
|
|
@ -40,6 +40,9 @@ bool AppDelegate::initInstance()
|
|||
// OpenGLView initialized in HelloWorld/android/jni/helloworld/main.cpp
|
||||
// the default setting is to create a fullscreen view
|
||||
// if you want to use auto-scale, please enable view->create(320,480) in main.cpp
|
||||
// if the resources under '/sdcard" or other writeable path, set it.
|
||||
// warning: the audio source should in assets/
|
||||
// cocos2d::CCFileUtils::setResourcePath("/sdcard");
|
||||
|
||||
#endif // CC_PLATFORM_ANDROID
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
using namespace cocos2d;
|
||||
|
||||
#define IMG_PATH "assets"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
|
@ -23,8 +21,6 @@ void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thi
|
|||
// view->create(480, 320);
|
||||
cocos2d::CCDirector::sharedDirector()->setOpenGLView(view);
|
||||
|
||||
CCFileUtils::setRelativePath(IMG_PATH);
|
||||
|
||||
AppDelegate *pAppDelegate = new AppDelegate();
|
||||
cocos2d::CCApplication::sharedApplication().run();
|
||||
}
|
||||
|
|
|
@ -83,6 +83,9 @@ public class Cocos2dxActivity extends Activity{
|
|||
backgroundMusicPlayer = new Cocos2dxMusic(this);
|
||||
soundPlayer = new Cocos2dxSound(this);
|
||||
|
||||
// init bitmap context
|
||||
Cocos2dxBitmap.setContext(this);
|
||||
|
||||
handler = new Handler(){
|
||||
public void handleMessage(Message msg){
|
||||
switch(msg.what){
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.ByteOrder;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
|
@ -11,6 +12,7 @@ import android.graphics.Paint;
|
|||
import android.graphics.Typeface;
|
||||
import android.graphics.Paint.Align;
|
||||
import android.graphics.Paint.FontMetricsInt;
|
||||
import android.util.Log;
|
||||
|
||||
public class Cocos2dxBitmap{
|
||||
/*
|
||||
|
@ -21,6 +23,12 @@ public class Cocos2dxBitmap{
|
|||
private static final int ALIGNLEFT = 0x31;
|
||||
private static final int ALIGNRIGHT = 0x32;
|
||||
|
||||
private static Context context;
|
||||
|
||||
public static void setContext(Context context){
|
||||
Cocos2dxBitmap.context = context;
|
||||
}
|
||||
|
||||
/*
|
||||
* @width: the width to draw, it can be 0
|
||||
* @height: the height to draw, it can be 0
|
||||
|
@ -31,7 +39,7 @@ public class Cocos2dxBitmap{
|
|||
content = refactorString(content);
|
||||
Paint paint = newPaint(fontName, fontSize, alignment);
|
||||
|
||||
TextProperty textProperty = getTextWidthAndHeight(content, paint, width, height);
|
||||
TextProperty textProperty = computeTextProperty(content, paint, width, height);
|
||||
|
||||
// Draw text to bitmap
|
||||
Bitmap bitmap = Bitmap.createBitmap(textProperty.maxWidth,
|
||||
|
@ -95,7 +103,7 @@ public class Cocos2dxBitmap{
|
|||
}
|
||||
}
|
||||
|
||||
private static TextProperty getTextWidthAndHeight(String content, Paint paint,
|
||||
private static TextProperty computeTextProperty(String content, Paint paint,
|
||||
int maxWidth, int maxHeight){
|
||||
FontMetricsInt fm = paint.getFontMetricsInt();
|
||||
int h = (int)Math.ceil(fm.descent - fm.ascent);
|
||||
|
@ -119,7 +127,6 @@ public class Cocos2dxBitmap{
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return new TextProperty(maxContentWidth, h, lines);
|
||||
}
|
||||
|
||||
|
@ -231,10 +238,10 @@ public class Cocos2dxBitmap{
|
|||
}
|
||||
|
||||
/*
|
||||
* Add the last char
|
||||
* Add the last chars
|
||||
*/
|
||||
if (start == charLength - 1){
|
||||
strList.add(content.substring(charLength-1));
|
||||
if (start < charLength){
|
||||
strList.add(content.substring(start));
|
||||
}
|
||||
|
||||
return strList;
|
||||
|
@ -244,9 +251,29 @@ public class Cocos2dxBitmap{
|
|||
Paint paint = new Paint();
|
||||
paint.setColor(Color.WHITE);
|
||||
paint.setTextSize(fontSize);
|
||||
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
/*
|
||||
* Set type face for paint, now it support .ttf file.
|
||||
*/
|
||||
if (fontName.endsWith(".ttf")){
|
||||
try {
|
||||
Typeface typeFace = Typeface.createFromAsset(context.getAssets(), fontName);
|
||||
paint.setTypeface(typeFace);
|
||||
} catch (Exception e){
|
||||
Log.e("Cocos2dxBitmap",
|
||||
"error to create ttf type face: " + fontName);
|
||||
|
||||
/*
|
||||
* The file may not find, use system font
|
||||
*/
|
||||
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
|
||||
}
|
||||
}
|
||||
else {
|
||||
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
|
||||
}
|
||||
|
||||
switch (alignment){
|
||||
case ALIGNCENTER:
|
||||
paint.setTextAlign(Align.CENTER);
|
||||
|
|
|
@ -1 +1 @@
|
|||
9fb28c61f00c78e9def984ba0b22cf9fae814b94
|
||||
a94593d95f2fff9766c611a35a6593a87d490698
|
|
@ -25,7 +25,7 @@ echo.
|
|||
|
||||
call %VSVARS%
|
||||
if %VC_VER%==90 (
|
||||
vcbuild cocos2d-win32.vc2008.sln $ALL
|
||||
vcbuild /MP /M10 cocos2d-win32.vc2008.sln $ALL
|
||||
) else if %VC_VER%==100 (
|
||||
msbuild cocos2d-win32.vc2010.sln /p:Configuration="Debug"
|
||||
msbuild cocos2d-win32.vc2010.sln /p:Configuration="Release"
|
||||
|
|
|
@ -102,7 +102,7 @@ bool CCDirector::init(void)
|
|||
|
||||
// FPS
|
||||
m_bDisplayFPS = false;
|
||||
m_nFrames = 0;
|
||||
m_uTotalFrames = m_uFrames = 0;
|
||||
m_pszFPS = new char[10];
|
||||
m_pLastUpdate = new struct cc_timeval();
|
||||
|
||||
|
@ -227,6 +227,8 @@ void CCDirector::drawScene(void)
|
|||
|
||||
glPopMatrix();
|
||||
|
||||
m_uTotalFrames++;
|
||||
|
||||
// swap buffers
|
||||
if (m_pobOpenGLView)
|
||||
{
|
||||
|
@ -669,13 +671,13 @@ void CCDirector::resume(void)
|
|||
// updates the FPS every frame
|
||||
void CCDirector::showFPS(void)
|
||||
{
|
||||
m_nFrames++;
|
||||
m_uFrames++;
|
||||
m_fAccumDt += m_fDeltaTime;
|
||||
|
||||
if (m_fAccumDt > CC_DIRECTOR_FPS_INTERVAL)
|
||||
{
|
||||
m_fFrameRate = m_nFrames / m_fAccumDt;
|
||||
m_nFrames = 0;
|
||||
m_fFrameRate = m_uFrames / m_fAccumDt;
|
||||
m_uFrames = 0;
|
||||
m_fAccumDt = 0;
|
||||
|
||||
sprintf(m_pszFPS, "%.1f", m_fFrameRate);
|
||||
|
|
|
@ -75,7 +75,7 @@ typedef struct _hashScriptFuncEntry
|
|||
{
|
||||
CCTimer *timer;
|
||||
bool paused;
|
||||
string *funcName;
|
||||
const char *funcName;
|
||||
UT_hash_handle hh;
|
||||
} tHashScriptFuncEntry;
|
||||
|
||||
|
@ -306,7 +306,7 @@ void CCScheduler::scheduleScriptFunc(const char *pszFuncName, ccTime fInterval,
|
|||
if (! pElement)
|
||||
{
|
||||
pElement = (tHashScriptFuncEntry *)calloc(sizeof(*pElement), 1);
|
||||
pElement->funcName = new string(pszFuncName);
|
||||
pElement->funcName = pszFuncName;
|
||||
pElement->timer = new CCTimer();
|
||||
pElement->timer->initWithScriptFuncName(pszFuncName, fInterval);
|
||||
pElement->paused = bPaused;
|
||||
|
@ -373,23 +373,22 @@ void CCScheduler::unscheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol
|
|||
}
|
||||
}
|
||||
|
||||
void CCScheduler::unscheduleScriptFunc(const char *pfzFuncName)
|
||||
void CCScheduler::unscheduleScriptFunc(const char *pszFuncName)
|
||||
{
|
||||
// explicity handle nil arguments when removing an object
|
||||
if (pfzFuncName == 0)
|
||||
if (pszFuncName == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tHashScriptFuncEntry *pElement = NULL;
|
||||
HASH_FIND_INT(m_pHashForScriptFunctions, &pfzFuncName, pElement);
|
||||
HASH_FIND_INT(m_pHashForScriptFunctions, &pszFuncName, pElement);
|
||||
|
||||
if (pElement)
|
||||
{
|
||||
pElement->timer->release();
|
||||
delete pElement->funcName;
|
||||
|
||||
HASH_DEL(m_pHashForSelectors, pElement);
|
||||
HASH_DEL(m_pHashForScriptFunctions, pElement);
|
||||
free(pElement);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2180,8 +2180,7 @@ CCActionInterval* CCAnimate::reverse(void)
|
|||
}
|
||||
}
|
||||
|
||||
CCAnimation *pNewAnim = CCAnimation::animationWithName(m_pAnimation->getName(),
|
||||
m_pAnimation->getDelay(), pNewArray);
|
||||
CCAnimation *pNewAnim = CCAnimation::animationWithFrames(pNewArray, m_pAnimation->getDelay());
|
||||
|
||||
pNewArray->release();
|
||||
|
||||
|
|
|
@ -166,7 +166,7 @@ void CCNode::setZOrder(int z)
|
|||
/// ertexZ getter
|
||||
float CCNode::getVertexZ()
|
||||
{
|
||||
return m_fVertexZ;
|
||||
return m_fVertexZ / CC_CONTENT_SCALE_FACTOR();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace cocos2d {
|
|||
|
||||
const char* cocos2dVersion()
|
||||
{
|
||||
return "cocos2d v1.0.0";
|
||||
return "cocos2d v1.0.1";
|
||||
}
|
||||
|
||||
}//namespace cocos2d
|
||||
|
|
|
@ -86,28 +86,6 @@ namespace cocos2d {
|
|||
*/
|
||||
bool initWithFrames(CCMutableArray<CCSpriteFrame*> *pFrames, float delay);
|
||||
|
||||
/** Initializes a CCAnimation with a name
|
||||
@since v0.99.3
|
||||
@deprecated Will be removed in 1.0.1. Use "init" instead.
|
||||
*/
|
||||
bool initWithName(const char *pszName);
|
||||
|
||||
/** Initializes a CCAnimation with a name and frames
|
||||
@since v0.99.3
|
||||
@deprecated Will be removed in 1.0.1. Use "initWithFrames" instead.
|
||||
*/
|
||||
bool initWithName(const char *pszName, CCMutableArray<CCSpriteFrame*> *pFrames);
|
||||
|
||||
/** Initializes a CCAnimation with a name and delay between frames.
|
||||
@deprecated Will be removed in 1.0.1. Use "initWithFrames:nil delay:delay" instead.
|
||||
*/
|
||||
bool initWithName(const char *pszName, float fDelay);
|
||||
|
||||
/** Initializes a CCAnimation with a name, delay and an array of CCSpriteFrames.
|
||||
@deprecated Will be removed in 1.0.1. Use "initWithFrames:frames delay:delay" instead.
|
||||
*/
|
||||
bool initWithName(const char *pszName, float fDelay, CCMutableArray<CCSpriteFrame*> *pFrames);
|
||||
|
||||
/** adds a frame to a CCAnimation */
|
||||
void addFrame(CCSpriteFrame *pFrame);
|
||||
|
||||
|
@ -138,24 +116,6 @@ namespace cocos2d {
|
|||
@since v0.99.5
|
||||
*/
|
||||
static CCAnimation* animationWithFrames(CCMutableArray<CCSpriteFrame*> *frames, float delay);
|
||||
|
||||
/** Creates a CCAnimation with a name
|
||||
@since v0.99.3
|
||||
@deprecated Will be removed in 1.0.1. Use "animation" instead.
|
||||
*/
|
||||
static CCAnimation* animationWithName(const char *pszName);
|
||||
|
||||
/** Creates a CCAnimation with a name and frames
|
||||
@since v0.99.3
|
||||
@deprecated Will be removed in 1.0.1. Use "animationWithFrames" instead.
|
||||
*/
|
||||
static CCAnimation* animationWithName(const char *pszName, CCMutableArray<CCSpriteFrame*> *pFrames);
|
||||
|
||||
/** Creates a CCAnimation with a name and delay between frames. */
|
||||
static CCAnimation* animationWithName(const char *pszName, float fDelay);
|
||||
|
||||
/** Creates a CCAnimation with a name, delay and an array of CCSpriteFrames. */
|
||||
static CCAnimation* animationWithName(const char *pszName, float fDelay, CCMutableArray<CCSpriteFrame*> *pFrames);
|
||||
};
|
||||
} // end of name sapce cocos2d
|
||||
|
||||
|
|
|
@ -404,7 +404,6 @@ protected:
|
|||
bool m_bLandscape;
|
||||
|
||||
bool m_bDisplayFPS;
|
||||
int m_nFrames;
|
||||
ccTime m_fAccumDt;
|
||||
ccTime m_fFrameRate;
|
||||
#if CC_DIRECTOR_FAST_FPS
|
||||
|
@ -415,6 +414,7 @@ protected:
|
|||
bool m_bPaused;
|
||||
|
||||
/* How many frames were called since the director started */
|
||||
unsigned int m_uTotalFrames;
|
||||
unsigned int m_uFrames;
|
||||
|
||||
/* The running scene */
|
||||
|
|
|
@ -52,12 +52,6 @@ namespace cocos2d{
|
|||
/** creates the CCLabelAtlas with a string, a char map file(the atlas), the width and height of each element and the starting char of the atlas */
|
||||
static CCLabelAtlas * labelWithString(const char *label, const char *charMapFile, unsigned int itemWidth, unsigned int itemHeight, unsigned char startCharMap);
|
||||
|
||||
|
||||
/** creates the CCLabelAtlas with a string, a char map file(the atlas), the width and height of each element in points and the starting char of the atlas.
|
||||
@deprecated Will be removed in 1.0.1. Use "labelWithString:" instead
|
||||
*/
|
||||
static CCLabelAtlas * labelAtlasWithString(const char *label, const char *charMapFile, unsigned int itemWidth, unsigned int itemHeight, unsigned char startCharMap);
|
||||
|
||||
/** initializes the CCLabelAtlas with a string, a char map file(the atlas), the width and height of each element and the starting char of the atlas */
|
||||
bool initWithString(const char *label, const char *charMapFile, unsigned int itemWidth, unsigned int itemHeight, unsigned char startCharMap);
|
||||
// super methods
|
||||
|
|
|
@ -171,12 +171,6 @@ namespace cocos2d{
|
|||
/** creates a bitmap font altas with an initial string and the FNT file */
|
||||
static CCLabelBMFont * labelWithString(const char *str, const char *fntFile);
|
||||
|
||||
/** creates a BMFont label with an initial string and the FNT file
|
||||
@deprecated Will be removed in 1.0.1. Use "labelWithString" instead.
|
||||
@since v0.99.5
|
||||
*/
|
||||
static CCLabelBMFont * bitmapFontAtlasWithString(const char *str, const char *fntFile);
|
||||
|
||||
/** init a bitmap font altas with an initial string and the FNT file */
|
||||
bool initWithString(const char *str, const char *fntFile);
|
||||
/** updates the font chars based on the string to render */
|
||||
|
@ -203,14 +197,6 @@ namespace cocos2d{
|
|||
/** Purges the FNT config cache
|
||||
*/
|
||||
CC_DLL void FNTConfigRemoveCache( void );
|
||||
|
||||
/** CCBitmapFontAtlas
|
||||
@deprecated Use CCLabelBMFont instead. Will be removed 1.0.1
|
||||
*/
|
||||
class CCBitmapFontAtlas : public CCLabelBMFont
|
||||
{
|
||||
};
|
||||
|
||||
}// namespace cocos2d
|
||||
|
||||
#endif //__CCBITMAP_FONT_ATLAS_H__
|
||||
|
|
|
@ -121,6 +121,25 @@ return NULL; \
|
|||
} \
|
||||
};
|
||||
|
||||
#define LAYER_NODE_FUNC_PARAM(layer,__PARAMTYPE__,__PARAM__) \
|
||||
static layer* node(__PARAMTYPE__ __PARAM__) \
|
||||
{ \
|
||||
layer *pRet = new layer(); \
|
||||
if (pRet && pRet->init(__PARAM__)) \
|
||||
{ \
|
||||
pRet->autorelease(); \
|
||||
return pRet; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
delete pRet; \
|
||||
pRet = NULL; \
|
||||
return NULL; \
|
||||
} \
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// CCLayerColor
|
||||
//
|
||||
|
@ -177,18 +196,6 @@ protected:
|
|||
virtual void updateColor();
|
||||
};
|
||||
|
||||
/** CCColorLayer
|
||||
It is the same as CCLayerColor.
|
||||
|
||||
@deprecated Use CCLayerColor instead. This class will be removed in v1.0.1
|
||||
*/
|
||||
class CC_DLL CCColorLayer : public CCLayerColor
|
||||
{
|
||||
public:
|
||||
static CCColorLayer * layerWithColorWidthHeight(ccColor4B color, GLfloat width, GLfloat height);
|
||||
static CCColorLayer * layerWithColor(ccColor4B color);
|
||||
};
|
||||
|
||||
//
|
||||
// CCLayerGradient
|
||||
//
|
||||
|
@ -283,14 +290,6 @@ public:
|
|||
LAYER_NODE_FUNC(CCLayerMultiplex);
|
||||
};
|
||||
|
||||
/** CCMultiplexLayer
|
||||
It is the same as CCLayerMultiplex.
|
||||
|
||||
@deprecated Use CCLayerMultiplex instead. This class will be removed in v1.0.1
|
||||
*/
|
||||
class CCMultiplexLayer : public CCLayerMultiplex
|
||||
{
|
||||
};
|
||||
}//namespace cocos2d
|
||||
|
||||
#endif // __CCLAYER_H__
|
||||
|
|
|
@ -55,6 +55,10 @@ namespace cocos2d{
|
|||
, m_pSelectedItem(NULL)
|
||||
{}
|
||||
virtual ~CCMenu(){}
|
||||
|
||||
/** creates an empty CCMenu */
|
||||
static CCMenu* node();
|
||||
|
||||
/** creates a CCMenu with it's items */
|
||||
static CCMenu* menuWithItems(CCMenuItem* item, ...);
|
||||
|
||||
|
@ -64,6 +68,8 @@ namespace cocos2d{
|
|||
*/
|
||||
static CCMenu*menuWithItem(CCMenuItem* item);
|
||||
|
||||
/** initializes an empty CCMenu */
|
||||
bool init();
|
||||
/** initializes a CCMenu with it's items */
|
||||
bool initWithItems(CCMenuItem* item, va_list args);
|
||||
|
||||
|
@ -118,10 +124,8 @@ namespace cocos2d{
|
|||
|
||||
virtual CCRGBAProtocol* convertToRGBAProtocol() { return (CCRGBAProtocol*)this; }
|
||||
|
||||
private:
|
||||
CCMenuItem* itemForTouch(CCTouch * touch);
|
||||
|
||||
protected:
|
||||
CCMenuItem* itemForTouch(CCTouch * touch);
|
||||
tCCMenuState m_eState;
|
||||
GLubyte m_cOpacity;
|
||||
CCMenuItem *m_pSelectedItem;
|
||||
|
|
|
@ -90,14 +90,29 @@ public:
|
|||
void clear(float r, float g, float b, float a);
|
||||
|
||||
/** saves the texture into a file */
|
||||
bool saveBuffer(const char *name);
|
||||
/** saves the texture into a file. The format can be JPG or PNG */
|
||||
bool saveBuffer(const char *name, int format);
|
||||
// para szFilePath the absolute path to save
|
||||
// para x,y the lower left corner coordinates of the buffer to save
|
||||
// pare nWidth,nHeight the size of the buffer to save
|
||||
// when nWidth = 0 and nHeight = 0, the image size to save equals to buffer texture size
|
||||
bool saveBuffer(const char *szFilePath, int x = 0, int y = 0, int nWidth = 0, int nHeight = 0);
|
||||
|
||||
/** saves the texture into a file.
|
||||
// para name the file name to save
|
||||
// para format the image format to save, here it supports kCCImageFormatPNG and kCCImageFormatJPG */
|
||||
// para x,y the lower left corner coordinates of the buffer to save
|
||||
// pare nWidth,nHeight the size of the buffer to save
|
||||
// when nWidth = 0 and nHeight = 0, the image size to save equals to buffer texture size
|
||||
bool saveBuffer(int format, const char *name, int x = 0, int y = 0, int nWidth = 0, int nHeight = 0);
|
||||
|
||||
/* get buffer as UIImage, can only save a render buffer which has a RGBA8888 pixel format */
|
||||
CCData *getUIImageAsDataFromBuffer(int format);
|
||||
|
||||
bool getUIImageFromBuffer(CCImage *pImage);
|
||||
/** save the buffer data to a CCImage */
|
||||
// para pImage the CCImage to save
|
||||
// para x,y the lower left corner coordinates of the buffer to save
|
||||
// pare nWidth,nHeight the size of the buffer to save
|
||||
// when nWidth = 0 and nHeight = 0, the image size to save equals to buffer texture size
|
||||
bool getUIImageFromBuffer(CCImage *pImage, int x = 0, int y = 0, int nWidth = 0, int nHeight = 0);
|
||||
|
||||
protected:
|
||||
GLuint m_uFBO;
|
||||
|
|
|
@ -79,4 +79,21 @@ static scene* node() \
|
|||
} \
|
||||
};
|
||||
|
||||
#define SCENE_FUNC_PARAM(__TYPE__,__PARAMTYPE__,__PARAM__) \
|
||||
static cocos2d::CCScene* node(__PARAMTYPE__ __PARAM__) \
|
||||
{ \
|
||||
cocos2d::CCScene * scene = NULL; \
|
||||
do \
|
||||
{ \
|
||||
scene = cocos2d::CCScene::node(); \
|
||||
CC_BREAK_IF(! scene); \
|
||||
__TYPE__ *layer = __TYPE__::node(__PARAM__); \
|
||||
CC_BREAK_IF(! layer); \
|
||||
scene->addChild(layer); \
|
||||
} while (0); \
|
||||
return scene; \
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // __CCSCENE_H__
|
||||
|
|
|
@ -143,7 +143,7 @@ public:
|
|||
void unscheduleSelector(SEL_SCHEDULE pfnSelector, SelectorProtocol *pTarget);
|
||||
/** Unschedule the script function
|
||||
*/
|
||||
void unscheduleScriptFunc(const char *pfzFuncName);
|
||||
void unscheduleScriptFunc(const char *pszFuncName);
|
||||
|
||||
/** Unschedules the update selector for a given target
|
||||
@since v0.99.3
|
||||
|
|
|
@ -327,25 +327,8 @@ public:
|
|||
/** returns the current displayed frame. */
|
||||
CCSpriteFrame* displayedFrame(void);
|
||||
|
||||
/** adds an Animation to the Sprite.
|
||||
|
||||
@deprecated Use CCAnimationCache instead. Will be removed in 1.0.1
|
||||
*/
|
||||
void addAnimation(CCAnimation *pAnimation);
|
||||
|
||||
/** returns an Animation given it's name.
|
||||
|
||||
@deprecated Use CCAnimationCache instead. Will be removed in 1.0.1
|
||||
*/
|
||||
CCAnimation* animationByName(const char *pszAnimationName);
|
||||
|
||||
// Animation
|
||||
|
||||
/** changes the display frame based on an animation and an index.
|
||||
@deprecated Will be removed in 1.0.1. Use setDisplayFrameWithAnimationName:index instead
|
||||
*/
|
||||
void setDisplayFrame(const char *pszAnimationName, int nFrameIndex);
|
||||
|
||||
/** changes the display frame with animation name and index.
|
||||
The animation name will be get from the CCAnimationCache
|
||||
@since v0.99.5
|
||||
|
@ -355,7 +338,6 @@ public:
|
|||
protected:
|
||||
void updateTextureCoords(CCRect rect);
|
||||
void updateBlendFunc(void);
|
||||
void initAnimationDictionary(void);
|
||||
void getTransformValues(struct transformValues_ *tv); // optimization
|
||||
|
||||
protected:
|
||||
|
@ -404,9 +386,6 @@ protected:
|
|||
// image is flipped
|
||||
bool m_bFlipX;
|
||||
bool m_bFlipY;
|
||||
|
||||
// Animations that belong to the sprite
|
||||
CCMutableDictionary<std::string, CCAnimation*> *m_pAnimations;
|
||||
};
|
||||
}//namespace cocos2d
|
||||
|
||||
|
|
|
@ -78,27 +78,23 @@ namespace cocos2d
|
|||
The capacity will be increased in 33% in runtime if it run out of space.
|
||||
*/
|
||||
static CCSpriteBatchNode* batchNodeWithTexture(CCTexture2D *tex);
|
||||
static CCSpriteBatchNode* spriteSheetWithTexture(CCTexture2D *tex); // deprecated
|
||||
|
||||
/** creates a CCSpriteBatchNode with a texture2d and capacity of children.
|
||||
The capacity will be increased in 33% in runtime if it run out of space.
|
||||
*/
|
||||
static CCSpriteBatchNode* batchNodeWithTexture(CCTexture2D* tex, unsigned int capacity);
|
||||
static CCSpriteBatchNode* spriteSheetWithTexture(CCTexture2D *tex, unsigned int capacity); // deprecated
|
||||
|
||||
/** creates a CCSpriteBatchNode with a file image (.png, .jpeg, .pvr, etc) with a default capacity of 29 children.
|
||||
The capacity will be increased in 33% in runtime if it run out of space.
|
||||
The file will be loaded using the TextureMgr.
|
||||
*/
|
||||
static CCSpriteBatchNode* batchNodeWithFile(const char* fileImage);
|
||||
static CCSpriteBatchNode* spriteSheetWithFile(const char* fileImage); // deprecated
|
||||
|
||||
/** creates a CCSpriteBatchNode with a file image (.png, .jpeg, .pvr, etc) and capacity of children.
|
||||
The capacity will be increased in 33% in runtime if it run out of space.
|
||||
The file will be loaded using the TextureMgr.
|
||||
*/
|
||||
static CCSpriteBatchNode* batchNodeWithFile(const char* fileImage, unsigned int capacity);
|
||||
static CCSpriteBatchNode* spriteSheetWithFile(const char* fileImage, unsigned int capacity); // deprecated
|
||||
|
||||
/** initializes a CCSpriteBatchNode with a texture2d and capacity of children.
|
||||
The capacity will be increased in 33% in runtime if it run out of space.
|
||||
|
@ -112,25 +108,6 @@ namespace cocos2d
|
|||
|
||||
void increaseAtlasCapacity();
|
||||
|
||||
/** creates an sprite with a rect in the CCSpriteBatchNode.
|
||||
It's the same as:
|
||||
- create an standard CCSsprite
|
||||
- set the usingSpriteSheet = YES
|
||||
- set the textureAtlas to the same texture Atlas as the CCSpriteBatchNode
|
||||
@deprecated Use [CCSprite spriteWithBatchNode:rect:] instead;
|
||||
*/
|
||||
CCSprite* createSpriteWithRect(CCRect rect);
|
||||
|
||||
/** initializes a previously created sprite with a rect. This sprite will have the same texture as the CCSpriteBatchNode.
|
||||
It's the same as:
|
||||
- initialize an standard CCSsprite
|
||||
- set the usingBatchNode = YES
|
||||
- set the textureAtlas to the same texture Atlas as the CCSpriteBatchNode
|
||||
@since v0.99.0
|
||||
@deprecated Use [CCSprite initWithBatchNode:rect:] instead;
|
||||
*/
|
||||
void initSprite(CCSprite *sprite, CCRect rect);
|
||||
|
||||
/** removes a child given a certain index. It will also cleanup the running actions depending on the cleanup parameter.
|
||||
@warning Removing a child from a CCSpriteBatchNode is very slow
|
||||
*/
|
||||
|
|
|
@ -117,13 +117,6 @@ public:
|
|||
*/
|
||||
CCSpriteFrame* spriteFrameByName(const char *pszName);
|
||||
|
||||
/** Creates an sprite with the name of an sprite frame.
|
||||
The created sprite will contain the texture, rect and offset of the sprite frame.
|
||||
It returns an autorelease object.
|
||||
@deprecated use CCSprite::spriteWithSpriteFrameName(name). This method will be removed on final v0.9
|
||||
*/
|
||||
CCSprite* createSpriteWithFrameName(const char *pszName);
|
||||
|
||||
public:
|
||||
/** Returns the shared instance of the Sprite Frame cache */
|
||||
static CCSpriteFrameCache* sharedSpriteFrameCache(void);
|
||||
|
|
|
@ -128,11 +128,6 @@ namespace cocos2d {
|
|||
/** return the TMXObjectGroup for the secific group */
|
||||
CCTMXObjectGroup* objectGroupNamed(const char *groupName);
|
||||
|
||||
/** return the TMXObjectGroup for the secific group
|
||||
@deprecated Use map#objectGroupNamed instead
|
||||
*/
|
||||
CCTMXObjectGroup* groupNamed(const char *groupName);
|
||||
|
||||
/** return the value for the specific property name */
|
||||
CCString *propertyNamed(const char *propertyName);
|
||||
|
||||
|
|
|
@ -142,13 +142,13 @@ public:
|
|||
public:
|
||||
/** singleton of the CCTouchDispatcher */
|
||||
static CCTouchDispatcher* sharedDispatcher();
|
||||
CCTouchHandler* findHandler(CCTouchDelegate *pDelegate);
|
||||
|
||||
protected:
|
||||
void forceRemoveDelegate(CCTouchDelegate *pDelegate);
|
||||
void forceAddHandler(CCTouchHandler *pHandler, CCMutableArray<CCTouchHandler*> *pArray);
|
||||
void forceRemoveAllDelegates(void);
|
||||
void rearrangeHandlers(CCMutableArray<CCTouchHandler*> *pArray);
|
||||
CCTouchHandler* findHandler(CCTouchDelegate *pDelegate);
|
||||
|
||||
protected:
|
||||
CCMutableArray<CCTouchHandler*> *m_pTargetedHandlers;
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace cocos2d {
|
|||
CCTouchHandler
|
||||
Object than contains the delegate and priority of the event handler.
|
||||
*/
|
||||
class CCTouchHandler : public CCObject
|
||||
class CC_DLL CCTouchHandler : public CCObject
|
||||
{
|
||||
public:
|
||||
virtual ~CCTouchHandler(void);
|
||||
|
@ -69,7 +69,7 @@ protected:
|
|||
/** CCStandardTouchHandler
|
||||
It forwardes each event to the delegate.
|
||||
*/
|
||||
class CCStandardTouchHandler : public CCTouchHandler
|
||||
class CC_DLL CCStandardTouchHandler : public CCTouchHandler
|
||||
{
|
||||
public:
|
||||
/** initializes a TouchHandler with a delegate and a priority */
|
||||
|
@ -85,7 +85,7 @@ public:
|
|||
Object than contains the claimed touches and if it swallos touches.
|
||||
Used internally by TouchDispatcher
|
||||
*/
|
||||
class CCTargetedTouchHandler : public CCTouchHandler
|
||||
class CC_DLL CCTargetedTouchHandler : public CCTouchHandler
|
||||
{
|
||||
public:
|
||||
~CCTargetedTouchHandler(void);
|
|
@ -38,18 +38,18 @@ public:
|
|||
~CCUserDefault();
|
||||
|
||||
// get value methods
|
||||
bool getBoolForKey(const char* pKey);
|
||||
int getIntegerForKey(const char* pKey);
|
||||
float getFloatForKey(const char* pKey);
|
||||
double getDoubleForKey(const char* pKey);
|
||||
std::string getStringForKey(const char* pKey);
|
||||
bool getBoolForKey(const char* pKey, bool defaultValue = false);
|
||||
int getIntegerForKey(const char* pKey, int defaultValue = 0);
|
||||
float getFloatForKey(const char* pKey, float defaultValue=0.0f);
|
||||
double getDoubleForKey(const char* pKey, double defaultValue=0.0);
|
||||
std::string getStringForKey(const char* pKey, const std::string & defaultValue = "");
|
||||
|
||||
// set value methods
|
||||
void setBoolForKey(const char* pKey, bool value);
|
||||
void setIntegerForKey(const char* pKey, int value);
|
||||
void setFloatForKey(const char* pKey, float value);
|
||||
void setDoubleForKey(const char* pKey, double value);
|
||||
void setStringForKey(const char* pKey, std::string value);
|
||||
void setStringForKey(const char* pKey, const std::string & value);
|
||||
|
||||
static CCUserDefault* sharedUserDefault();
|
||||
static void purgeSharedUserDefault();
|
||||
|
|
|
@ -28,6 +28,10 @@ THE SOFTWARE.
|
|||
#ifndef __COCOS2D_H__
|
||||
#define __COCOS2D_H__
|
||||
|
||||
// 0x00 HI ME LO
|
||||
// 00 01 00 01
|
||||
#define COCOS2D_VERSION 0x00010001
|
||||
|
||||
//
|
||||
// all cocos2d include files
|
||||
//
|
||||
|
@ -80,6 +84,7 @@ THE SOFTWARE.
|
|||
#include "CCTexturePVR.h"
|
||||
#include "CCTransitionRadial.h"
|
||||
#include "CCActionProgressTimer.h"
|
||||
#include "CCTouchHandler.h"
|
||||
#include "CCTouchDispatcher.h"
|
||||
#include "CCDrawingPrimitives.h"
|
||||
#include "CCScheduler.h"
|
||||
|
|
|
@ -44,11 +44,6 @@ namespace cocos2d{
|
|||
return NULL;
|
||||
}
|
||||
|
||||
CCLabelAtlas * CCLabelAtlas::labelAtlasWithString(const char *label, const char *charMapFile, unsigned int itemWidth, unsigned int itemHeight, unsigned char startCharMap)
|
||||
{
|
||||
return labelWithString(label, charMapFile, itemWidth, itemHeight, startCharMap);
|
||||
}
|
||||
|
||||
bool CCLabelAtlas::initWithString(const char *label, const char *charMapFile, unsigned int itemWidth, unsigned int itemHeight, unsigned char startCharMap)
|
||||
{
|
||||
assert(label != NULL);
|
||||
|
|
|
@ -392,11 +392,6 @@ namespace cocos2d{
|
|||
return NULL;
|
||||
}
|
||||
|
||||
CCLabelBMFont * CCLabelBMFont::bitmapFontAtlasWithString(const char *str, const char *fntFile)
|
||||
{
|
||||
return labelWithString(str, fntFile);
|
||||
}
|
||||
|
||||
bool CCLabelBMFont::initWithString(const char *theString, const char *fntFile)
|
||||
{
|
||||
assert(theString != NULL);
|
||||
|
@ -411,7 +406,7 @@ namespace cocos2d{
|
|||
m_tColor = ccWHITE;
|
||||
m_tContentSize = CCSizeZero;
|
||||
m_bIsOpacityModifyRGB = m_pobTextureAtlas->getTexture()->getHasPremultipliedAlpha();
|
||||
m_tAnchorPoint = ccp(0.5f, 0.5f);
|
||||
setAnchorPoint(ccp(0.5f, 0.5f));
|
||||
this->setString(theString);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ CCLayer::CCLayer()
|
|||
,m_bIsKeypadEnabled(false)
|
||||
{
|
||||
m_eTouchDelegateType = ccTouchDelegateAllBit;
|
||||
m_tAnchorPoint = ccp(0.5f, 0.5f);
|
||||
setAnchorPoint(ccp(0.5f, 0.5f));
|
||||
m_bIsRelativeAnchorPoint = false;
|
||||
}
|
||||
|
||||
|
@ -469,33 +469,6 @@ void CCLayerColor::draw()
|
|||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
//
|
||||
// CCColorLayer
|
||||
//
|
||||
CCColorLayer* CCColorLayer::layerWithColorWidthHeight(ccColor4B color, GLfloat width, GLfloat height)
|
||||
{
|
||||
CCColorLayer * pLayer = new CCColorLayer();
|
||||
if( pLayer && pLayer->initWithColorWidthHeight(color,width,height))
|
||||
{
|
||||
pLayer->autorelease();
|
||||
return pLayer;
|
||||
}
|
||||
CC_SAFE_DELETE(pLayer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CCColorLayer* CCColorLayer::layerWithColor(ccColor4B color)
|
||||
{
|
||||
CCColorLayer * pLayer = new CCColorLayer();
|
||||
if(pLayer && pLayer->initWithColor(color))
|
||||
{
|
||||
pLayer->autorelease();
|
||||
return pLayer;
|
||||
}
|
||||
CC_SAFE_DELETE(pLayer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// CCLayerGradient
|
||||
//
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace cocos2d {
|
|||
CCScene::CCScene()
|
||||
{
|
||||
m_bIsRelativeAnchorPoint = false;
|
||||
m_tAnchorPoint = ccp(0.5f, 0.5f);
|
||||
setAnchorPoint(ccp(0.5f, 0.5f));
|
||||
m_eSceneType = ccNormalScene;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ THE SOFTWARE.
|
|||
#include "CCStdC.h"
|
||||
|
||||
#include <vector>
|
||||
#include <stdarg.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -44,6 +45,18 @@ namespace cocos2d{
|
|||
//
|
||||
//CCMenu
|
||||
//
|
||||
|
||||
CCMenu* CCMenu::node()
|
||||
{
|
||||
CCMenu *menu = new CCMenu();
|
||||
if (menu && menu->init()) {
|
||||
menu->autorelease();
|
||||
return menu;
|
||||
}
|
||||
CC_SAFE_DELETE(menu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
CCMenu * CCMenu::menuWithItems(CCMenuItem* item, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
@ -65,6 +78,12 @@ namespace cocos2d{
|
|||
return menuWithItems(item, NULL);
|
||||
}
|
||||
|
||||
bool CCMenu::init()
|
||||
{
|
||||
va_list args;
|
||||
return initWithItems(0, args);
|
||||
}
|
||||
|
||||
bool CCMenu::initWithItems(CCMenuItem* item, va_list args)
|
||||
{
|
||||
if (CCLayer::init())
|
||||
|
@ -75,7 +94,7 @@ namespace cocos2d{
|
|||
CCSize s = CCDirector::sharedDirector()->getWinSize();
|
||||
|
||||
this->m_bIsRelativeAnchorPoint = false;
|
||||
m_tAnchorPoint = ccp(0.5f, 0.5f);
|
||||
setAnchorPoint(ccp(0.5f, 0.5f));
|
||||
this->setContentSize(s);
|
||||
|
||||
// XXX: in v0.7, winSize should return the visible size
|
||||
|
@ -156,6 +175,15 @@ namespace cocos2d{
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (CCNode *c = this->m_pParent; c != NULL; c = c->getParent())
|
||||
{
|
||||
if (c->getIsVisible() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_pSelectedItem = this->itemForTouch(touch);
|
||||
if (m_pSelectedItem)
|
||||
{
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace cocos2d{
|
|||
}
|
||||
bool CCMenuItem::initWithTarget(SelectorProtocol *rec, SEL_MenuHandler selector)
|
||||
{
|
||||
m_tAnchorPoint = ccp(0.5f, 0.5f);
|
||||
setAnchorPoint(ccp(0.5f, 0.5f));
|
||||
m_pListener = rec;
|
||||
m_pfnSelector = selector;
|
||||
m_bIsEnabled = true;
|
||||
|
|
|
@ -79,7 +79,7 @@ bool CCProgressTimer::initWithTexture(cocos2d::CCTexture2D *pTexture)
|
|||
m_fPercentage = 0.f;
|
||||
m_pVertexData = NULL;
|
||||
m_nVertexDataCount = 0;
|
||||
m_tAnchorPoint = ccp(0.5f, 0.5f);
|
||||
setAnchorPoint(ccp(0.5f, 0.5f));
|
||||
setContentSize(m_pSprite->getContentSize());
|
||||
m_eType = kCCProgressTimerTypeRadialCCW;
|
||||
|
||||
|
@ -108,6 +108,7 @@ void CCProgressTimer::setSprite(cocos2d::CCSprite *pSprite)
|
|||
CC_SAFE_RETAIN(pSprite);
|
||||
CC_SAFE_RELEASE(m_pSprite);
|
||||
m_pSprite = pSprite;
|
||||
setContentSize(m_pSprite->getContentSize());
|
||||
|
||||
// Everytime we set a new sprite, we free the current vertex data
|
||||
if (m_pVertexData)
|
||||
|
@ -148,9 +149,17 @@ ccVertex2F CCProgressTimer::vertexFromTexCoord(cocos2d::CCPoint texCoord)
|
|||
CCTexture2D *pTexture = m_pSprite->getTexture();
|
||||
if (pTexture)
|
||||
{
|
||||
CCSize texSize = pTexture->getContentSizeInPixels();
|
||||
tmp = ccp(texSize.width * texCoord.x / pTexture->getMaxS(),
|
||||
texSize.height * (1 - (texCoord.y / pTexture->getMaxT())));
|
||||
float fXMax = MAX(m_pSprite->getQuad().br.texCoords.u, m_pSprite->getQuad().bl.texCoords.u);
|
||||
float fXMin = MIN(m_pSprite->getQuad().br.texCoords.u, m_pSprite->getQuad().bl.texCoords.u);
|
||||
float fYMax = MAX(m_pSprite->getQuad().tl.texCoords.v, m_pSprite->getQuad().bl.texCoords.v);
|
||||
float fYMin = MIN(m_pSprite->getQuad().tl.texCoords.v, m_pSprite->getQuad().bl.texCoords.v);
|
||||
CCPoint tMax = ccp(fXMax, fYMax);
|
||||
CCPoint tMin = ccp(fXMin, fYMin);
|
||||
|
||||
CCSize texSize = CCSizeMake(m_pSprite->getQuad().br.vertices.x - m_pSprite->getQuad().bl.vertices.x,
|
||||
m_pSprite->getQuad().tl.vertices.y - m_pSprite->getQuad().bl.vertices.y);
|
||||
tmp = ccp(texSize.width * (texCoord.x - tMin.x) / (tMax.x - tMin.x),
|
||||
texSize.height * (1 - (texCoord.y - tMin.y) / (tMax.y - tMin.y)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -215,11 +224,15 @@ void CCProgressTimer::updateProgress(void)
|
|||
void CCProgressTimer::updateRadial(void)
|
||||
{
|
||||
// Texture Max is the actual max coordinates to deal with non-power of 2 textures
|
||||
CCPoint tMax = ccp(m_pSprite->getTexture()->getMaxS(),
|
||||
m_pSprite->getTexture()->getMaxT());
|
||||
float fXMax = MAX(m_pSprite->getQuad().br.texCoords.u, m_pSprite->getQuad().bl.texCoords.u);
|
||||
float fXMin = MIN(m_pSprite->getQuad().br.texCoords.u, m_pSprite->getQuad().bl.texCoords.u);
|
||||
float fYMax = MAX(m_pSprite->getQuad().tl.texCoords.v, m_pSprite->getQuad().bl.texCoords.v);
|
||||
float fYMin = MIN(m_pSprite->getQuad().tl.texCoords.v, m_pSprite->getQuad().bl.texCoords.v);
|
||||
CCPoint tMax = ccp(fXMax, fYMax);
|
||||
CCPoint tMin = ccp(fXMin, fYMin);
|
||||
|
||||
// Grab the midpoint
|
||||
CCPoint midpoint = ccpCompMult(m_tAnchorPoint, tMax);
|
||||
CCPoint midpoint = ccpAdd(tMin, ccpCompMult(m_tAnchorPoint, ccpSub(tMax, tMin)));
|
||||
|
||||
float alpha = m_fPercentage / 100.f;
|
||||
|
||||
|
@ -229,7 +242,7 @@ void CCProgressTimer::updateRadial(void)
|
|||
// We find the vector to do a hit detection based on the percentage
|
||||
// We know the first vector is the one @ 12 o'clock (top,mid) so we rotate
|
||||
// from that by the progress angle around the midpoint pivot
|
||||
CCPoint topMid = ccp(midpoint.x, 0.f);
|
||||
CCPoint topMid = ccp(midpoint.x, tMin.y);
|
||||
CCPoint percentagePt = ccpRotateByAngle(topMid, midpoint, angle);
|
||||
|
||||
int index = 0;
|
||||
|
@ -261,8 +274,8 @@ void CCProgressTimer::updateRadial(void)
|
|||
{
|
||||
int pIndex = (i + (kProgressTextureCoordsCount - 1)) % kProgressTextureCoordsCount;
|
||||
|
||||
CCPoint edgePtA = ccpCompMult(boundaryTexCoord(i % kProgressTextureCoordsCount), tMax);
|
||||
CCPoint edgePtB = ccpCompMult(boundaryTexCoord(pIndex), tMax);
|
||||
CCPoint edgePtA = ccpAdd(tMin, ccpCompMult(boundaryTexCoord(i % kProgressTextureCoordsCount), ccpSub(tMax, tMin)));
|
||||
CCPoint edgePtB = ccpAdd(tMin, ccpCompMult(boundaryTexCoord(pIndex), ccpSub(tMax, tMin)));
|
||||
|
||||
// Remember that the top edge is split in half for the 12 o'clock position
|
||||
// Let's deal with that here by finding the correct endpoints
|
||||
|
@ -342,12 +355,12 @@ void CCProgressTimer::updateRadial(void)
|
|||
m_pVertexData[0].texCoords = tex2(midpoint.x, midpoint.y);
|
||||
m_pVertexData[0].vertices = vertexFromTexCoord(midpoint);
|
||||
|
||||
m_pVertexData[1].texCoords = tex2(midpoint.x, 0.f);
|
||||
m_pVertexData[1].vertices = vertexFromTexCoord(ccp(midpoint.x, 0.f));
|
||||
m_pVertexData[1].texCoords = tex2(midpoint.x, tMin.y);
|
||||
m_pVertexData[1].vertices = vertexFromTexCoord(ccp(midpoint.x, tMin.y));
|
||||
|
||||
for (int i = 0; i < index; ++i)
|
||||
{
|
||||
CCPoint texCoords = ccpCompMult(boundaryTexCoord(i), tMax);
|
||||
CCPoint texCoords = ccpAdd(tMin, ccpCompMult(boundaryTexCoord(i), ccpSub(tMax, tMin)));
|
||||
|
||||
m_pVertexData[i+2].texCoords = tex2(texCoords.x, texCoords.y);
|
||||
m_pVertexData[i+2].vertices = vertexFromTexCoord(texCoords);
|
||||
|
@ -360,12 +373,12 @@ void CCProgressTimer::updateRadial(void)
|
|||
{
|
||||
if (m_pSprite->isFlipX())
|
||||
{
|
||||
m_pVertexData[i].texCoords.u = tMax.x - m_pVertexData[i].texCoords.u;
|
||||
m_pVertexData[i].texCoords.u = tMin.x + tMax.x - m_pVertexData[i].texCoords.u;
|
||||
}
|
||||
|
||||
if (m_pSprite->isFlipY())
|
||||
{
|
||||
m_pVertexData[i].texCoords.v = tMax.y - m_pVertexData[i].texCoords.v;
|
||||
m_pVertexData[i].texCoords.v = tMin.y + tMax.y - m_pVertexData[i].texCoords.v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -379,12 +392,12 @@ void CCProgressTimer::updateRadial(void)
|
|||
{
|
||||
if (m_pSprite->isFlipX())
|
||||
{
|
||||
m_pVertexData[m_nVertexDataCount - 1].texCoords.u = tMax.x - m_pVertexData[m_nVertexDataCount - 1].texCoords.u;
|
||||
m_pVertexData[m_nVertexDataCount - 1].texCoords.u = tMin.x + tMax.x - m_pVertexData[m_nVertexDataCount - 1].texCoords.u;
|
||||
}
|
||||
|
||||
if (m_pSprite->isFlipY())
|
||||
{
|
||||
m_pVertexData[m_nVertexDataCount - 1].texCoords.v = tMax.y - m_pVertexData[m_nVertexDataCount - 1].texCoords.v;
|
||||
m_pVertexData[m_nVertexDataCount - 1].texCoords.v = tMin.y + tMax.y - m_pVertexData[m_nVertexDataCount - 1].texCoords.v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -402,7 +415,12 @@ void CCProgressTimer::updateBar(void)
|
|||
{
|
||||
float alpha = m_fPercentage / 100.f;
|
||||
|
||||
CCPoint tMax = ccp(m_pSprite->getTexture()->getMaxS(), m_pSprite->getTexture()->getMaxT());
|
||||
float fXMax = MAX(m_pSprite->getQuad().br.texCoords.u, m_pSprite->getQuad().bl.texCoords.u);
|
||||
float fXMin = MIN(m_pSprite->getQuad().br.texCoords.u, m_pSprite->getQuad().bl.texCoords.u);
|
||||
float fYMax = MAX(m_pSprite->getQuad().tl.texCoords.v, m_pSprite->getQuad().bl.texCoords.v);
|
||||
float fYMin = MIN(m_pSprite->getQuad().tl.texCoords.v, m_pSprite->getQuad().bl.texCoords.v);
|
||||
CCPoint tMax = ccp(fXMax, fYMax);
|
||||
CCPoint tMin = ccp(fXMin, fYMin);
|
||||
|
||||
unsigned char vIndexes[2] = {0, 0};
|
||||
unsigned char index = 0;
|
||||
|
@ -418,23 +436,23 @@ void CCProgressTimer::updateBar(void)
|
|||
|
||||
if (m_eType == kCCProgressTimerTypeHorizontalBarLR)
|
||||
{
|
||||
m_pVertexData[vIndexes[0] = 0].texCoords = tex2(0, 0);
|
||||
m_pVertexData[vIndexes[1] = 1].texCoords = tex2(0, tMax.y);
|
||||
m_pVertexData[vIndexes[0] = 0].texCoords = tex2(tMin.x, tMin.y);
|
||||
m_pVertexData[vIndexes[1] = 1].texCoords = tex2(tMin.x, tMax.y);
|
||||
} else
|
||||
if (m_eType == kCCProgressTimerTypeHorizontalBarRL)
|
||||
{
|
||||
m_pVertexData[vIndexes[0] = 2].texCoords = tex2(tMax.x, tMax.y);
|
||||
m_pVertexData[vIndexes[1] = 3].texCoords = tex2(tMax.x, 0.f);
|
||||
m_pVertexData[vIndexes[1] = 3].texCoords = tex2(tMax.x, tMin.y);
|
||||
} else
|
||||
if (m_eType == kCCProgressTimerTypeVerticalBarBT)
|
||||
{
|
||||
m_pVertexData[vIndexes[0] = 1].texCoords = tex2(0, tMax.y);
|
||||
m_pVertexData[vIndexes[0] = 1].texCoords = tex2(tMin.x, tMax.y);
|
||||
m_pVertexData[vIndexes[1] = 3].texCoords = tex2(tMax.x, tMax.y);
|
||||
} else
|
||||
if (m_eType == kCCProgressTimerTypeVerticalBarTB)
|
||||
{
|
||||
m_pVertexData[vIndexes[0] = 0].texCoords = tex2(0, 0);
|
||||
m_pVertexData[vIndexes[1] = 2].texCoords = tex2(tMax.x, 0);
|
||||
m_pVertexData[vIndexes[0] = 0].texCoords = tex2(tMin.x, tMin.y);
|
||||
m_pVertexData[vIndexes[1] = 2].texCoords = tex2(tMax.x, tMin.y);
|
||||
}
|
||||
|
||||
index = vIndexes[0];
|
||||
|
@ -450,17 +468,17 @@ void CCProgressTimer::updateBar(void)
|
|||
if (m_pSprite->isFlipX())
|
||||
{
|
||||
index = vIndexes[0];
|
||||
m_pVertexData[index].texCoords.u = tMax.x - m_pVertexData[index].texCoords.u;
|
||||
m_pVertexData[index].texCoords.u = tMin.x + tMax.x - m_pVertexData[index].texCoords.u;
|
||||
index = vIndexes[1];
|
||||
m_pVertexData[index].texCoords.u = tMax.x - m_pVertexData[index].texCoords.u;
|
||||
m_pVertexData[index].texCoords.u = tMin.x + tMax.x - m_pVertexData[index].texCoords.u;
|
||||
}
|
||||
|
||||
if (m_pSprite->isFlipY())
|
||||
{
|
||||
index = vIndexes[0];
|
||||
m_pVertexData[index].texCoords.v = tMax.y - m_pVertexData[index].texCoords.v;
|
||||
m_pVertexData[index].texCoords.v = tMin.y + tMax.y - m_pVertexData[index].texCoords.v;
|
||||
index = vIndexes[1];
|
||||
m_pVertexData[index].texCoords.v = tMax.y - m_pVertexData[index].texCoords.v;
|
||||
m_pVertexData[index].texCoords.v = tMin.y + tMax.y - m_pVertexData[index].texCoords.v;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -469,23 +487,23 @@ void CCProgressTimer::updateBar(void)
|
|||
|
||||
if(m_eType == kCCProgressTimerTypeHorizontalBarLR)
|
||||
{
|
||||
m_pVertexData[vIndexes[0] = 3].texCoords = tex2(tMax.x*alpha, tMax.y);
|
||||
m_pVertexData[vIndexes[1] = 2].texCoords = tex2(tMax.x*alpha, 0);
|
||||
m_pVertexData[vIndexes[0] = 3].texCoords = tex2(tMin.x + (tMax.x - tMin.x) *alpha, tMax.y);
|
||||
m_pVertexData[vIndexes[1] = 2].texCoords = tex2(tMin.x + (tMax.x - tMin.x) *alpha, tMin.y);
|
||||
} else
|
||||
if (m_eType == kCCProgressTimerTypeHorizontalBarRL)
|
||||
{
|
||||
m_pVertexData[vIndexes[0] = 1].texCoords = tex2(tMax.x*(1.f - alpha), 0);
|
||||
m_pVertexData[vIndexes[1] = 0].texCoords = tex2(tMax.x*(1.f - alpha), tMax.y);
|
||||
m_pVertexData[vIndexes[0] = 1].texCoords = tex2(tMin.x + (tMax.x - tMin.x) * (1.f - alpha), tMin.y);
|
||||
m_pVertexData[vIndexes[1] = 0].texCoords = tex2(tMin.x + (tMax.x - tMin.x) * (1.f - alpha), tMax.y);
|
||||
} else
|
||||
if (m_eType == kCCProgressTimerTypeVerticalBarBT)
|
||||
{
|
||||
m_pVertexData[vIndexes[0] = 0].texCoords = tex2(0, tMax.y*(1.f - alpha));
|
||||
m_pVertexData[vIndexes[1] = 2].texCoords = tex2(tMax.x, tMax.y*(1.f - alpha));
|
||||
m_pVertexData[vIndexes[0] = 0].texCoords = tex2(tMin.x, tMin.y + (tMax.y - tMin.y) * (1.f - alpha));
|
||||
m_pVertexData[vIndexes[1] = 2].texCoords = tex2(tMax.x, tMin.y + (tMax.y - tMin.y) * (1.f - alpha));
|
||||
} else
|
||||
if (m_eType == kCCProgressTimerTypeVerticalBarTB)
|
||||
{
|
||||
m_pVertexData[vIndexes[0] = 1].texCoords = tex2(0, tMax.y*alpha);
|
||||
m_pVertexData[vIndexes[1] = 3].texCoords = tex2(tMax.x, tMax.y*alpha);
|
||||
m_pVertexData[vIndexes[0] = 1].texCoords = tex2(tMin.x, tMin.y + (tMax.y - tMin.y) * alpha);
|
||||
m_pVertexData[vIndexes[1] = 3].texCoords = tex2(tMax.x, tMin.y + (tMax.y - tMin.y) * alpha);
|
||||
}
|
||||
|
||||
index = vIndexes[0];
|
||||
|
@ -500,17 +518,17 @@ void CCProgressTimer::updateBar(void)
|
|||
if (m_pSprite->isFlipX())
|
||||
{
|
||||
index = vIndexes[0];
|
||||
m_pVertexData[index].texCoords.u = tMax.x - m_pVertexData[index].texCoords.u;
|
||||
m_pVertexData[index].texCoords.u = tMin.x + tMax.x - m_pVertexData[index].texCoords.u;
|
||||
index = vIndexes[1];
|
||||
m_pVertexData[index].texCoords.u = tMax.x - m_pVertexData[index].texCoords.u;
|
||||
m_pVertexData[index].texCoords.u = tMin.x + tMax.x - m_pVertexData[index].texCoords.u;
|
||||
}
|
||||
|
||||
if (m_pSprite->isFlipY())
|
||||
{
|
||||
index = vIndexes[0];
|
||||
m_pVertexData[index].texCoords.v = tMax.y - m_pVertexData[index].texCoords.v;
|
||||
m_pVertexData[index].texCoords.v = tMin.y + tMax.y - m_pVertexData[index].texCoords.v;
|
||||
index = vIndexes[1];
|
||||
m_pVertexData[index].texCoords.v = tMax.y - m_pVertexData[index].texCoords.v;
|
||||
m_pVertexData[index].texCoords.v = tMin.y + tMax.y - m_pVertexData[index].texCoords.v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -254,19 +254,27 @@ void CCRenderTexture::clear(float r, float g, float b, float a)
|
|||
this->end();
|
||||
}
|
||||
|
||||
bool CCRenderTexture::saveBuffer(const char *name)
|
||||
{
|
||||
return this->saveBuffer(name, kCCImageFormatJPG);
|
||||
}
|
||||
bool CCRenderTexture::saveBuffer(const char *fileName, int format)
|
||||
bool CCRenderTexture::saveBuffer(const char *szFilePath, int x, int y, int nWidth, int nHeight)
|
||||
{
|
||||
bool bRet = false;
|
||||
|
||||
CCImage *pImage = new CCImage();
|
||||
if (pImage != NULL && getUIImageFromBuffer(pImage, x, y, nWidth, nHeight))
|
||||
{
|
||||
bRet = pImage->saveToFile(szFilePath);
|
||||
}
|
||||
|
||||
CC_SAFE_DELETE(pImage);
|
||||
return bRet;
|
||||
}
|
||||
bool CCRenderTexture::saveBuffer(int format, const char *fileName, int x, int y, int nWidth, int nHeight)
|
||||
{
|
||||
bool bRet = false;
|
||||
CCAssert(format == kCCImageFormatJPG || format == kCCImageFormatPNG,
|
||||
"the image can only be saved as JPG or PNG format");
|
||||
|
||||
CCImage *pImage = new CCImage();
|
||||
if (pImage != NULL && getUIImageFromBuffer(pImage))
|
||||
if (pImage != NULL && getUIImageFromBuffer(pImage, x, y, nWidth, nHeight))
|
||||
{
|
||||
std::string fullpath = CCFileUtils::getWriteablePath() + fileName;
|
||||
if (kCCImageFormatPNG == format)
|
||||
|
@ -287,35 +295,90 @@ bool CCRenderTexture::saveBuffer(const char *fileName, int format)
|
|||
}
|
||||
|
||||
/* get buffer as UIImage */
|
||||
bool CCRenderTexture::getUIImageFromBuffer(CCImage *pImage)
|
||||
bool CCRenderTexture::getUIImageFromBuffer(CCImage *pImage, int x, int y, int nWidth, int nHeight)
|
||||
{
|
||||
if (NULL == pImage)
|
||||
if (NULL == pImage || NULL == m_pTexture)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GLubyte * pBuffer = NULL;
|
||||
CCSize s = m_pTexture->getContentSizeInPixels();
|
||||
int tx = (int)s.width;
|
||||
int ty = (int)s.height;
|
||||
|
||||
if (x < 0 || x >= tx || y < 0 || y >= ty)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nWidth < 0
|
||||
|| nHeight < 0
|
||||
|| (0 == nWidth && 0 != nHeight)
|
||||
|| (0 == nHeight && 0 != nWidth))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// to get the image size to save
|
||||
// if the saving image domain exeeds the buffer texture domain,
|
||||
// it should be cut
|
||||
int nSavedBufferWidth = nWidth;
|
||||
int nSavedBufferHeight = nHeight;
|
||||
if (0 == nWidth)
|
||||
{
|
||||
nSavedBufferWidth = tx;
|
||||
}
|
||||
if (0 == nHeight)
|
||||
{
|
||||
nSavedBufferHeight = ty;
|
||||
}
|
||||
nSavedBufferWidth = x + nSavedBufferWidth > tx ? (tx - x): nSavedBufferWidth;
|
||||
nSavedBufferHeight = y + nSavedBufferHeight > ty ? (ty - y): nSavedBufferHeight;
|
||||
|
||||
GLubyte *pBuffer = NULL;
|
||||
GLubyte *pTempData = NULL;
|
||||
bool bRet = false;
|
||||
|
||||
do
|
||||
{
|
||||
CCAssert(m_ePixelFormat == kCCTexture2DPixelFormat_RGBA8888, "only RGBA8888 can be saved as image");
|
||||
|
||||
CCSize s = m_pTexture->getContentSizeInPixels();
|
||||
int tx = (int)s.width;
|
||||
int ty = (int)s.height;
|
||||
CC_BREAK_IF(! (pBuffer = new GLubyte[nSavedBufferWidth * nSavedBufferHeight * 4]));
|
||||
|
||||
CC_BREAK_IF(! (pBuffer = new GLubyte[tx * ty * 4]));
|
||||
// On some machines, like Samsung i9000, Motorola Defy,
|
||||
// the dimension need to be a power of 2
|
||||
int nReadBufferWidth = 0;
|
||||
int nReadBufferHeight = 0;
|
||||
int nMaxTextureSize = 0;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &nMaxTextureSize);
|
||||
|
||||
nReadBufferWidth = ccNextPOT(tx);
|
||||
nReadBufferHeight = ccNextPOT(ty);
|
||||
|
||||
CC_BREAK_IF(0 == nReadBufferWidth || 0 == nReadBufferHeight);
|
||||
CC_BREAK_IF(nReadBufferWidth > nMaxTextureSize || nReadBufferHeight > nMaxTextureSize);
|
||||
|
||||
CC_BREAK_IF(! (pTempData = new GLubyte[nReadBufferWidth * nReadBufferHeight * 4]));
|
||||
|
||||
this->begin();
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glReadPixels(0,0,tx,ty,GL_RGBA,GL_UNSIGNED_BYTE, pBuffer);
|
||||
glReadPixels(0,0,nReadBufferWidth,nReadBufferHeight,GL_RGBA,GL_UNSIGNED_BYTE, pTempData);
|
||||
this->end();
|
||||
|
||||
bRet = pImage->initWithImageData(pBuffer, tx * ty * 4, CCImage::kFmtRawData, tx, ty, 8);
|
||||
// to get the actual texture data
|
||||
// #640 the image read from rendertexture is upseted
|
||||
for (int i = 0; i < nSavedBufferHeight; ++i)
|
||||
{
|
||||
memcpy(&pBuffer[i * nSavedBufferWidth * 4],
|
||||
&pTempData[(y + nSavedBufferHeight - i - 1) * nReadBufferWidth * 4 + x * 4],
|
||||
nSavedBufferWidth * 4);
|
||||
}
|
||||
|
||||
bRet = pImage->initWithImageData(pBuffer, nSavedBufferWidth * nSavedBufferHeight * 4, CCImage::kFmtRawData, nSavedBufferWidth, nSavedBufferHeight, 8);
|
||||
} while (0);
|
||||
|
||||
CC_SAFE_DELETE_ARRAY(pBuffer);
|
||||
CC_SAFE_DELETE_ARRAY(pTempData);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ bool CCParticleFire::initWithTotalParticles(unsigned int numberOfParticles)
|
|||
|
||||
// emitter position
|
||||
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
this->m_tPosition = ccp(winSize.width/2, 60);
|
||||
this->setPosition(ccp(winSize.width/2, 60));
|
||||
this->m_tPosVar = ccp(40, 20);
|
||||
|
||||
// life of particles
|
||||
|
@ -124,7 +124,7 @@ bool CCParticleFireworks::initWithTotalParticles(unsigned int numberOfParticles)
|
|||
|
||||
// emitter position
|
||||
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
m_tPosition = ccp(winSize.width/2, winSize.height/2);
|
||||
this->setPosition(ccp(winSize.width/2, winSize.height/2));
|
||||
|
||||
// angle
|
||||
this->m_fAngle= 90;
|
||||
|
@ -200,7 +200,7 @@ bool CCParticleSun::initWithTotalParticles(unsigned int numberOfParticles)
|
|||
|
||||
// emitter position
|
||||
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
m_tPosition = ccp(winSize.width/2, winSize.height/2);
|
||||
this->setPosition(ccp(winSize.width/2, winSize.height/2));
|
||||
m_tPosVar = CCPointZero;
|
||||
|
||||
// life of particles
|
||||
|
@ -272,7 +272,7 @@ bool CCParticleGalaxy::initWithTotalParticles(unsigned int numberOfParticles)
|
|||
|
||||
// emitter position
|
||||
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
m_tPosition = ccp(winSize.width/2, winSize.height/2);
|
||||
this->setPosition(ccp(winSize.width/2, winSize.height/2));
|
||||
m_tPosVar = CCPointZero;
|
||||
|
||||
// life of particles
|
||||
|
@ -346,7 +346,7 @@ bool CCParticleFlower::initWithTotalParticles(unsigned int numberOfParticles)
|
|||
|
||||
// emitter position
|
||||
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
m_tPosition = ccp(winSize.width/2, winSize.height/2);
|
||||
this->setPosition(ccp(winSize.width/2, winSize.height/2));
|
||||
m_tPosVar = CCPointZero;
|
||||
|
||||
// life of particles
|
||||
|
@ -419,7 +419,7 @@ bool CCParticleMeteor::initWithTotalParticles(unsigned int numberOfParticles)
|
|||
|
||||
// emitter position
|
||||
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
m_tPosition = ccp(winSize.width/2, winSize.height/2);
|
||||
this->setPosition(ccp(winSize.width/2, winSize.height/2));
|
||||
m_tPosVar = CCPointZero;
|
||||
|
||||
// life of particles
|
||||
|
@ -493,7 +493,7 @@ bool CCParticleSpiral::initWithTotalParticles(unsigned int numberOfParticles)
|
|||
|
||||
// emitter position
|
||||
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
m_tPosition = ccp(winSize.width/2, winSize.height/2);
|
||||
this->setPosition(ccp(winSize.width/2, winSize.height/2));
|
||||
m_tPosVar = CCPointZero;
|
||||
|
||||
// life of particles
|
||||
|
@ -566,7 +566,7 @@ bool CCParticleExplosion::initWithTotalParticles(unsigned int numberOfParticles)
|
|||
|
||||
// emitter position
|
||||
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
m_tPosition = ccp(winSize.width/2, winSize.height/2);
|
||||
this->setPosition(ccp(winSize.width/2, winSize.height/2));
|
||||
m_tPosVar = CCPointZero;
|
||||
|
||||
// life of particles
|
||||
|
@ -636,7 +636,7 @@ bool CCParticleSmoke::initWithTotalParticles(unsigned int numberOfParticles)
|
|||
|
||||
// emitter position
|
||||
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
m_tPosition = ccp(winSize.width/2, 0);
|
||||
this->setPosition(ccp(winSize.width/2, 0));
|
||||
m_tPosVar = ccp(20, 0);
|
||||
|
||||
// life of particles
|
||||
|
@ -705,7 +705,7 @@ bool CCParticleSnow::initWithTotalParticles(unsigned int numberOfParticles)
|
|||
|
||||
// emitter position
|
||||
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
m_tPosition = ccp(winSize.width/2, winSize.height + 10);
|
||||
this->setPosition(ccp(winSize.width/2, winSize.height + 10));
|
||||
m_tPosVar = ccp( winSize.width/2, 0 );
|
||||
|
||||
// angle
|
||||
|
@ -782,7 +782,7 @@ bool CCParticleRain::initWithTotalParticles(unsigned int numberOfParticles)
|
|||
|
||||
// emitter position
|
||||
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
m_tPosition = ccp(winSize.width/2, winSize.height);
|
||||
this->setPosition(ccp(winSize.width/2, winSize.height));
|
||||
m_tPosVar = ccp( winSize.width/2, 0 );
|
||||
|
||||
// life of particles
|
||||
|
|
|
@ -199,8 +199,9 @@ bool CCParticleSystem::initWithDictionary(CCDictionary<std::string, CCObject*> *
|
|||
m_fEndSizeVar = (float)atof(valueForKey("finishParticleSizeVariance", dictionary));
|
||||
|
||||
// position
|
||||
m_tPosition.x = (float)atof(valueForKey("sourcePositionx", dictionary));
|
||||
m_tPosition.y = (float)atof(valueForKey("sourcePositiony", dictionary));
|
||||
float x = (float)atof(valueForKey("sourcePositionx", dictionary));
|
||||
float y = (float)atof(valueForKey("sourcePositiony", dictionary));
|
||||
this->setPosition( ccp(x,y) );
|
||||
m_tPosVar.x = (float)atof(valueForKey("sourcePositionVariancex", dictionary));
|
||||
m_tPosVar.y = (float)atof(valueForKey("sourcePositionVariancey", dictionary));
|
||||
|
||||
|
|
|
@ -107,12 +107,6 @@ public:
|
|||
*/
|
||||
static void setResource(const char* pszZipFileName);
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// interfaces on android
|
||||
///////////////////////////////////////////////////
|
||||
static const char* getResourcePath(void);
|
||||
static void setRelativePath(const char* pszRelativePath);
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// interfaces on ios
|
||||
///////////////////////////////////////////////////
|
||||
|
|
|
@ -29,6 +29,7 @@ THE SOFTWARE.
|
|||
#include "CCFileUtils.h"
|
||||
#include "png.h"
|
||||
#include <string>
|
||||
#include <ctype.h>
|
||||
|
||||
#if (CC_TARGET_PLATFORM != CC_PLATFORM_IOS)
|
||||
// on ios, we should use platform/ios/CCImage_ios.mm instead
|
||||
|
|
|
@ -65,7 +65,12 @@ bool CCImage::initWithImageFile(const char * strPath, EImageFormat eImgFmt/* = e
|
|||
return initWithImageData(data.getBuffer(), data.getSize(), eImgFmt);
|
||||
}
|
||||
|
||||
bool CCImage::initWithImageData(void * pData, int nDataLen, EImageFormat eFmt/* = eSrcFmtPng*/)
|
||||
bool CCImage::initWithImageData(void * pData,
|
||||
int nDataLen,
|
||||
EImageFormat eFmt,
|
||||
int nWidth,
|
||||
int nHeight,
|
||||
int nBitsPerComponent)
|
||||
{
|
||||
bool bRet = false;
|
||||
do
|
||||
|
@ -239,4 +244,29 @@ bool CCImage::initWithString(
|
|||
bool bRet = false;
|
||||
return bRet;
|
||||
}
|
||||
|
||||
bool CCImage::saveToFile(const char *pszFilePath, bool bIsToRGB)
|
||||
{
|
||||
// todo
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCImage::_initWithRawData(void * pData, int nDatalen, int nWidth, int nHeight, int nBitsPerComponent)
|
||||
{
|
||||
// todo
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCImage::_saveImageToPNG(const char * pszFilePath, bool bIsToRGB)
|
||||
{
|
||||
// todo
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCImage::_saveImageToJPG(const char * pszFilePath)
|
||||
{
|
||||
// todo
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_CC_END;
|
||||
|
|
|
@ -29,49 +29,49 @@ NS_CC_BEGIN;
|
|||
|
||||
#define MAX_PATH 256
|
||||
|
||||
using namespace std;
|
||||
|
||||
// record the resource path
|
||||
static std::string s_strRelativePath = "";
|
||||
static std::string s_strResourcePath = "";
|
||||
static string s_strResourcePath = "";
|
||||
|
||||
void CCFileUtils::setRelativePath(const char* pszRelativePath)
|
||||
void CCFileUtils::setResourcePath(const char* pszResourcePath)
|
||||
{
|
||||
CCAssert(pszRelativePath != NULL, "[FileUtils setRelativePath] -- wrong relative path");
|
||||
CCAssert(pszResourcePath != NULL, "[FileUtils setRelativePath] -- wrong relative path");
|
||||
|
||||
if (! pszRelativePath)
|
||||
if (! pszResourcePath)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s_strRelativePath = pszRelativePath;
|
||||
|
||||
// if the path is not ended with '/', append it
|
||||
if (s_strRelativePath.find("/") != (strlen(s_strRelativePath.c_str()) - 1))
|
||||
{
|
||||
s_strRelativePath += "/";
|
||||
}
|
||||
}
|
||||
|
||||
void CCFileUtils::setResourcePath(const char *pszResourcePath)
|
||||
{
|
||||
CCAssert(pszResourcePath != NULL, "[FileUtils setResourcePath] -- wrong resource path");
|
||||
CCAssert(strlen(pszResourcePath) <= MAX_PATH, "[FileUtils setResourcePath] -- resource path too long");
|
||||
|
||||
s_strResourcePath = pszResourcePath;
|
||||
}
|
||||
|
||||
const char* CCFileUtils::getResourcePath()
|
||||
{
|
||||
return s_strResourcePath.c_str();
|
||||
/*
|
||||
* If the path is set by user, and not end with "/", append it
|
||||
*/
|
||||
if (s_strResourcePath.find(".apk") == string::npos
|
||||
&& s_strResourcePath.find_last_of("/") != s_strResourcePath.length() - 1)
|
||||
{
|
||||
s_strResourcePath += "/";
|
||||
}
|
||||
}
|
||||
|
||||
const char* CCFileUtils::fullPathFromRelativePath(const char *pszRelativePath)
|
||||
{
|
||||
if (s_strResourcePath.find(".apk") != string::npos)
|
||||
{
|
||||
return pszRelativePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
CCString *pRet = new CCString();
|
||||
pRet->autorelease();
|
||||
pRet->m_sString = s_strResourcePath + pszRelativePath;
|
||||
return pRet->m_sString.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
const char *CCFileUtils::fullPathFromRelativeFile(const char *pszFilename, const char *pszRelativeFile)
|
||||
{
|
||||
//std::string relativeFile = fullPathFromRelativePath(pszRelativeFile);
|
||||
std::string relativeFile = pszRelativeFile;
|
||||
CCString *pRet = new CCString();
|
||||
pRet->autorelease();
|
||||
|
@ -82,13 +82,37 @@ const char *CCFileUtils::fullPathFromRelativeFile(const char *pszFilename, const
|
|||
|
||||
unsigned char* CCFileUtils::getFileData(const char* pszFileName, const char* pszMode, unsigned long * pSize)
|
||||
{
|
||||
string fullPath = s_strRelativePath + pszFileName;
|
||||
unsigned char * pData = CCFileUtils::getFileDataFromZip(s_strResourcePath.c_str(), fullPath.c_str(), pSize);
|
||||
string fullPath = pszFileName;
|
||||
unsigned char * pData = 0;
|
||||
|
||||
if (s_strResourcePath.find(".apk") != string::npos)
|
||||
{
|
||||
// read from apk
|
||||
fullPath.insert(0, "assets/");
|
||||
pData = CCFileUtils::getFileDataFromZip(s_strResourcePath.c_str(), fullPath.c_str(), pSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
// read rrom other path than user set it
|
||||
FILE *fp = fopen(pszFileName, pszMode);
|
||||
CC_BREAK_IF(!fp);
|
||||
|
||||
fseek(fp,0,SEEK_END);
|
||||
*pSize = ftell(fp);
|
||||
fseek(fp,0,SEEK_SET);
|
||||
pData = new unsigned char[*pSize];
|
||||
*pSize = fread(pData,sizeof(unsigned char), *pSize,fp);
|
||||
fclose(fp);
|
||||
} while (0);
|
||||
}
|
||||
|
||||
if (! pData && getIsPopupNotify())
|
||||
{
|
||||
std::string title = "Notification";
|
||||
std::string msg = "Get data from file(";
|
||||
msg.append(pszFileName).append(") failed!");
|
||||
msg.append(fullPath.c_str()).append(") failed!");
|
||||
CCMessageBox(msg.c_str(), title.c_str());
|
||||
}
|
||||
return pData;
|
||||
|
|
|
@ -34,6 +34,8 @@ THE SOFTWARE.
|
|||
|
||||
#define JAVAVM cocos2d::JniHelper::getJavaVM()
|
||||
|
||||
using namespace std;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
|
@ -161,34 +163,24 @@ extern "C"
|
|||
return bRet;
|
||||
}
|
||||
|
||||
static char* jstringToChar_(jstring jstr)
|
||||
static string jstring2string_(jstring jstr)
|
||||
{
|
||||
char* rtn = 0;
|
||||
JNIEnv *env = 0;
|
||||
|
||||
jboolean isCopy;
|
||||
if (! getEnv(&env))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// convert jstring to byte array
|
||||
jclass clsstring = env->FindClass("java/lang/String");
|
||||
jstring strencode = env->NewStringUTF("utf-8");
|
||||
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
|
||||
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
|
||||
jsize alen = env->GetArrayLength(barr);
|
||||
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
|
||||
|
||||
// copy byte array into char[]
|
||||
if (alen > 0)
|
||||
const char* chars = env->GetStringUTFChars(jstr, &isCopy);
|
||||
string ret(chars);
|
||||
if (isCopy)
|
||||
{
|
||||
rtn = new char[alen + 1];
|
||||
memcpy(rtn, ba, alen);
|
||||
rtn[alen] = 0;
|
||||
env->ReleaseStringUTFChars(jstr, chars);
|
||||
}
|
||||
env->ReleaseByteArrayElements(barr, ba, 0);
|
||||
|
||||
return rtn;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,8 +213,8 @@ namespace cocos2d {
|
|||
return getMethodInfo_(methodinfo, className, methodName, paramCode);
|
||||
}
|
||||
|
||||
char* JniHelper::jstringToChar(jstring str)
|
||||
string JniHelper::jstring2string(jstring str)
|
||||
{
|
||||
return jstringToChar_(str);
|
||||
return jstring2string_(str);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ THE SOFTWARE.
|
|||
#define __ANDROID_JNI_HELPER_H__
|
||||
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
#include "CCPlatformMacros.h"
|
||||
|
||||
namespace cocos2d {
|
||||
|
@ -44,7 +45,7 @@ namespace cocos2d {
|
|||
static jclass getClassID(const char *className, JNIEnv *env=0);
|
||||
static bool getStaticMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);
|
||||
static bool getMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);
|
||||
static char* jstringToChar(jstring str);
|
||||
static std::string jstring2string(jstring str);
|
||||
|
||||
private:
|
||||
static JavaVM *m_psJavaVM;
|
||||
|
|
|
@ -25,6 +25,7 @@ THE SOFTWARE.
|
|||
#include "CCDirector.h"
|
||||
#include "JniHelper.h"
|
||||
#include "CCApplication.h"
|
||||
#include "CCFileUtils.h"
|
||||
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
|
@ -111,4 +112,18 @@ extern "C"
|
|||
t.env->CallStaticObjectMethod(t.classID, t.methodID);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// set apk path
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void Java_org_cocos2dx_lib_Cocos2dxActivity_nativeSetPaths(JNIEnv* env, jobject thiz, jstring apkPath)
|
||||
{
|
||||
const char* str;
|
||||
jboolean isCopy;
|
||||
str = env->GetStringUTFChars(apkPath, &isCopy);
|
||||
if (isCopy) {
|
||||
cocos2d::CCFileUtils::setResourcePath(str);
|
||||
env->ReleaseStringUTFChars(apkPath, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ THE SOFTWARE.
|
|||
#include "CCAccelerometer.h"
|
||||
#include "platform/android/CCAccelerometer_android.h"
|
||||
#include "CCEGLView.h"
|
||||
#include "CCFileUtils.h"
|
||||
#include "JniHelper.h"
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
|
@ -59,18 +58,6 @@ extern "C"
|
|||
timeStamp);
|
||||
}
|
||||
|
||||
void Java_org_cocos2dx_lib_Cocos2dxActivity_nativeSetPaths(JNIEnv* env, jobject thiz, jstring apkPath)
|
||||
{
|
||||
const char* str;
|
||||
jboolean isCopy;
|
||||
str = env->GetStringUTFChars(apkPath, &isCopy);
|
||||
if (isCopy) {
|
||||
cocos2d::CCFileUtils::setResourcePath(str);
|
||||
env->ReleaseStringUTFChars(apkPath, str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void enableAccelerometerJNI()
|
||||
{
|
||||
JniMethodInfo t;
|
||||
|
|
|
@ -50,7 +50,7 @@ extern "C"
|
|||
"()Ljava/lang/String;"))
|
||||
{
|
||||
jstring str = (jstring)t.env->CallStaticObjectMethod(t.classID, t.methodID);
|
||||
ret = JniHelper::jstringToChar(str);
|
||||
ret = (char*)JniHelper::jstring2string(str).c_str();
|
||||
|
||||
LOGD("package name %s", ret);
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ extern "C"
|
|||
, "()Ljava/lang/String;"))
|
||||
{
|
||||
jstring str = (jstring)t.env->CallStaticObjectMethod(t.classID, t.methodID);
|
||||
ret = JniHelper::jstringToChar(str);
|
||||
ret = (char*)JniHelper::jstring2string(str).c_str();
|
||||
|
||||
LOGD("language name %s", ret);
|
||||
}
|
||||
|
|
|
@ -248,11 +248,6 @@ namespace cocos2d {
|
|||
strcpy(s_pszResourcePath, pszResourcePath);
|
||||
}
|
||||
|
||||
const char* CCFileUtils::getResourcePath()
|
||||
{
|
||||
return s_pszResourcePath;
|
||||
}
|
||||
|
||||
int CCFileUtils::ccLoadFileIntoMemory(const char *filename, unsigned char **out)
|
||||
{
|
||||
CCAssert( out, "ccLoadFileIntoMemory: invalid 'out' parameter");
|
||||
|
@ -347,10 +342,6 @@ namespace cocos2d {
|
|||
{
|
||||
CCAssert(0, "Have not implement!");
|
||||
}
|
||||
void CCFileUtils::setRelativePath(const char* pszRelativePath)
|
||||
{
|
||||
CCAssert(0, "Have not implement!");
|
||||
}
|
||||
|
||||
// notification support when getFileData from a invalid file
|
||||
static bool s_bPopupNotify = true;
|
||||
|
|
|
@ -21,11 +21,18 @@ 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 <Foundation/Foundation.h>
|
||||
#include <UIKit/UIKit.h>
|
||||
#include "CCImage.h"
|
||||
#include "CCFileUtils.h"
|
||||
#include <string>
|
||||
#import "CCImage.h"
|
||||
#import "CCFileUtils.h"
|
||||
#import <string>
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#if CC_FONT_LABEL_SUPPORT
|
||||
// FontLabel support
|
||||
#import "FontLabel/FontManager.h"
|
||||
#import "FontLabel/FontLabelStringDrawing.h"
|
||||
#endif// CC_FONT_LABEL_SUPPORT
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -335,104 +342,97 @@ static bool _initWithString(const char * pText, cocos2d::CCImage::ETextAlign eAl
|
|||
{
|
||||
CC_BREAK_IF(! pText || ! pInfo);
|
||||
|
||||
NSString * string = [NSString stringWithUTF8String:pText];
|
||||
NSString * str = [NSString stringWithUTF8String:pText];
|
||||
NSString * fntName = [NSString stringWithUTF8String:pFontName];
|
||||
CGSize dim;
|
||||
|
||||
// create the font
|
||||
NSString * fntName = _isValidFontName(pFontName) ? [NSString stringWithUTF8String:pFontName] : @"MarkerFelt-Wide";
|
||||
UIFont * font = [UIFont fontWithName:fntName size:nSize];
|
||||
id font;
|
||||
font = [UIFont fontWithName:fntName size:nSize];
|
||||
if (font)
|
||||
{
|
||||
dim = [str sizeWithFont:font];
|
||||
}
|
||||
|
||||
#if CC_FONT_LABEL_SUPPORT
|
||||
if (! font)
|
||||
{
|
||||
font = [[FontManager sharedManager] zFontWithName:fntName pointSize:nSize];
|
||||
if (font)
|
||||
{
|
||||
//dim = [str sizeWithZFont:font];
|
||||
dim = [FontLabelStringDrawingHelper sizeWithZFont:str zfont:font];
|
||||
}
|
||||
}
|
||||
#endif // CC_FONT_LABEL_SUPPORT
|
||||
|
||||
if (! font)
|
||||
{
|
||||
fntName = _isValidFontName(pFontName) ? fntName : @"MarkerFelt-Wide";
|
||||
font = [UIFont fontWithName:fntName size:nSize];
|
||||
|
||||
if (! font)
|
||||
{
|
||||
font = [UIFont systemFontOfSize:nSize];
|
||||
}
|
||||
|
||||
if (font)
|
||||
{
|
||||
dim = [str sizeWithFont:font];
|
||||
}
|
||||
}
|
||||
|
||||
if (pInfo->width != 0 || pInfo->height != 0)
|
||||
{
|
||||
dim.width = pInfo->width;
|
||||
dim.height = pInfo->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
pInfo->width = dim.width;
|
||||
pInfo->height = dim.height;
|
||||
}
|
||||
|
||||
CC_BREAK_IF(! font);
|
||||
|
||||
// measure text size with specified font and determine the rectangle to draw text in
|
||||
unsigned uHoriFlag = eAlign & 0x0f;
|
||||
unsigned uVertFlag = (eAlign & 0xf0) >> 4;
|
||||
|
||||
CGSize textSize; // the size which total text layout need
|
||||
CGSize canvasSize; // the size which malloc for drawtext
|
||||
CGRect textRect; // the rectangle which draw text in
|
||||
|
||||
if (0 >= pInfo->width)
|
||||
{
|
||||
// the content width no limit, use 0x7fffffff as a big enough bounds
|
||||
CGSize contentSize = CGSizeMake(0x7fffffff, 0x7fffffff);
|
||||
textSize = [string sizeWithFont:font constrainedToSize:contentSize];
|
||||
|
||||
canvasSize = textSize;
|
||||
pInfo->width = (size_t) textSize.width;
|
||||
pInfo->height = (size_t) textSize.height;
|
||||
|
||||
textRect = CGRectMake(0, 0, textSize.width, textSize.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the content height no limit, use 0x7fffffff as a big enough height
|
||||
CGSize contentSize = CGSizeMake(pInfo->width, 0x7fffffff);
|
||||
textSize = [string sizeWithFont:font constrainedToSize:contentSize];
|
||||
|
||||
if (0 >= pInfo->height)
|
||||
{
|
||||
canvasSize = textSize;
|
||||
pInfo->height = (size_t) textSize.height;
|
||||
pInfo->width = (size_t) textSize.width;
|
||||
|
||||
textRect = CGRectMake(0, 0, textSize.width, textSize.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
canvasSize.width = pInfo->width;
|
||||
if (textSize.height <= pInfo->height)
|
||||
{
|
||||
canvasSize.height = pInfo->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the height of text larger than the specified
|
||||
// let canvas's height larger a little,
|
||||
// make sure the last line of text in specified rectangle draw in canvas
|
||||
size_t lineHeight = (size_t)font.lineHeight;
|
||||
canvasSize.height = ((pInfo->height + lineHeight - 1) / lineHeight) * lineHeight;
|
||||
}
|
||||
|
||||
canvasSize = CGSizeMake(pInfo->width, MAX(pInfo->height, (size_t)textSize.height));
|
||||
|
||||
textRect.size = textSize;
|
||||
textRect.origin.x = (1 == uHoriFlag) ? 0 // align to left
|
||||
: (2 == uHoriFlag) ? pInfo->width - textSize.width // align to right
|
||||
: (pInfo->width - textSize.width) / 2; // align to center
|
||||
|
||||
textRect.origin.y = (1 == uVertFlag || textSize.height >= pInfo->height) ? 0 // align to top
|
||||
: (2 == uVertFlag) ? pInfo->height - textSize.height // align to bottom
|
||||
: (pInfo->height - textSize.height) / 2; // align to center
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// malloc space to store pixels data
|
||||
size_t width = (size_t)canvasSize.width;
|
||||
size_t height = (size_t)canvasSize.height;
|
||||
unsigned char* data = new unsigned char[width * height * 4];
|
||||
CC_BREAK_IF(! data);
|
||||
memset(data, 0, height * width * 4);
|
||||
unsigned char* data = new unsigned char[pInfo->width * pInfo->height * 4];
|
||||
memset(data, 0, pInfo->width * pInfo->height * 4);
|
||||
|
||||
// draw text
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
|
||||
CGContextRef context = CGBitmapContextCreate(data, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
|
||||
CGContextRef context = CGBitmapContextCreate(data, dim.width, dim.height, 8, dim.width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
CC_BREAK_IF(!context);
|
||||
|
||||
if (! context)
|
||||
{
|
||||
delete[] data;
|
||||
break;
|
||||
}
|
||||
|
||||
CGContextSetRGBFillColor(context, 1, 1, 1, 1);
|
||||
CGContextTranslateCTM(context, 0.0f, height);
|
||||
CGContextTranslateCTM(context, 0.0f, dim.height);
|
||||
CGContextScaleCTM(context, 1.0f, -1.0f); //NOTE: NSString draws in UIKit referential i.e. renders upside-down compared to CGBitmapContext referential
|
||||
UIGraphicsPushContext(context);
|
||||
|
||||
// measure text size with specified font and determine the rectangle to draw text in
|
||||
unsigned uHoriFlag = eAlign & 0x0f;
|
||||
UITextAlignment align = (2 == uHoriFlag) ? UITextAlignmentRight
|
||||
: (3 == uHoriFlag) ? UITextAlignmentCenter
|
||||
: UITextAlignmentLeft;
|
||||
[string drawInRect:textRect withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:align];
|
||||
|
||||
// normal fonts
|
||||
if( [font isKindOfClass:[UIFont class] ] )
|
||||
{
|
||||
[str drawInRect:CGRectMake(0, 0, dim.width, dim.height) withFont:font lineBreakMode:UILineBreakModeWordWrap alignment:align];
|
||||
}
|
||||
|
||||
#if CC_FONT_LABEL_SUPPORT
|
||||
else // ZFont class
|
||||
{
|
||||
//[str drawInRect:CGRectMake(0, 0, dim.width, dim.height) withZFont:font lineBreakMode:UILineBreakModeWordWrap alignment:align];
|
||||
[FontLabelStringDrawingHelper drawInRect:str rect:CGRectMake(0, 0, dim.width, dim.height) withZFont:font lineBreakMode:UILineBreakModeWordWrap alignment:align];
|
||||
}
|
||||
#endif
|
||||
|
||||
UIGraphicsPopContext();
|
||||
|
||||
|
@ -473,7 +473,12 @@ bool CCImage::initWithImageFile(const char * strPath, EImageFormat eImgFmt/* = e
|
|||
return initWithImageData(data.getBuffer(), data.getSize(), eImgFmt);
|
||||
}
|
||||
|
||||
bool CCImage::initWithImageData(void * pData, int nDataLen, EImageFormat eFmt/* = eSrcFmtPng*/)
|
||||
bool CCImage::initWithImageData(void * pData,
|
||||
int nDataLen,
|
||||
EImageFormat eFmt,
|
||||
int nWidth,
|
||||
int nHeight,
|
||||
int nBitsPerComponent)
|
||||
{
|
||||
bool bRet = false;
|
||||
tImageInfo info = {0};
|
||||
|
@ -520,5 +525,10 @@ bool CCImage::initWithString(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CCImage::saveToFile(const char *pszFilePath, bool bIsToRGB)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_CC_END;
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// FontLabel.h
|
||||
// FontLabel
|
||||
//
|
||||
// Created by Kevin Ballard on 5/8/09.
|
||||
// Copyright © 2009 Zynga Game Networks
|
||||
//
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class ZFont;
|
||||
@class ZAttributedString;
|
||||
|
||||
@interface FontLabel : UILabel {
|
||||
void *reserved; // works around a bug in UILabel
|
||||
ZFont *zFont;
|
||||
ZAttributedString *zAttributedText;
|
||||
}
|
||||
@property (nonatomic, setter=setCGFont:) CGFontRef cgFont __AVAILABILITY_INTERNAL_DEPRECATED;
|
||||
@property (nonatomic, assign) CGFloat pointSize __AVAILABILITY_INTERNAL_DEPRECATED;
|
||||
@property (nonatomic, retain, setter=setZFont:) ZFont *zFont;
|
||||
// if attributedText is nil, fall back on using the inherited UILabel properties
|
||||
// if attributedText is non-nil, the font/text/textColor
|
||||
// in addition, adjustsFontSizeToFitWidth does not work with attributed text
|
||||
@property (nonatomic, copy) ZAttributedString *zAttributedText;
|
||||
// -initWithFrame:fontName:pointSize: uses FontManager to look up the font name
|
||||
- (id)initWithFrame:(CGRect)frame fontName:(NSString *)fontName pointSize:(CGFloat)pointSize;
|
||||
- (id)initWithFrame:(CGRect)frame zFont:(ZFont *)font;
|
||||
- (id)initWithFrame:(CGRect)frame font:(CGFontRef)font pointSize:(CGFloat)pointSize __AVAILABILITY_INTERNAL_DEPRECATED;
|
||||
@end
|
|
@ -0,0 +1,195 @@
|
|||
//
|
||||
// FontLabel.m
|
||||
// FontLabel
|
||||
//
|
||||
// Created by Kevin Ballard on 5/8/09.
|
||||
// Copyright © 2009 Zynga Game Networks
|
||||
//
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "FontLabel.h"
|
||||
#import "FontManager.h"
|
||||
#import "FontLabelStringDrawing.h"
|
||||
#import "ZFont.h"
|
||||
|
||||
@interface ZFont (ZFontPrivate)
|
||||
@property (nonatomic, readonly) CGFloat ratio;
|
||||
@end
|
||||
|
||||
@implementation FontLabel
|
||||
@synthesize zFont;
|
||||
@synthesize zAttributedText;
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame fontName:(NSString *)fontName pointSize:(CGFloat)pointSize {
|
||||
return [self initWithFrame:frame zFont:[[FontManager sharedManager] zFontWithName:fontName pointSize:pointSize]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame zFont:(ZFont *)font {
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
zFont = [font retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame font:(CGFontRef)font pointSize:(CGFloat)pointSize {
|
||||
return [self initWithFrame:frame zFont:[ZFont fontWithCGFont:font size:pointSize]];
|
||||
}
|
||||
|
||||
- (CGFontRef)cgFont {
|
||||
return self.zFont.cgFont;
|
||||
}
|
||||
|
||||
- (void)setCGFont:(CGFontRef)font {
|
||||
if (self.zFont.cgFont != font) {
|
||||
self.zFont = [ZFont fontWithCGFont:font size:self.zFont.pointSize];
|
||||
}
|
||||
}
|
||||
|
||||
- (CGFloat)pointSize {
|
||||
return self.zFont.pointSize;
|
||||
}
|
||||
|
||||
- (void)setPointSize:(CGFloat)pointSize {
|
||||
if (self.zFont.pointSize != pointSize) {
|
||||
self.zFont = [ZFont fontWithCGFont:self.zFont.cgFont size:pointSize];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setZAttributedText:(ZAttributedString *)attStr {
|
||||
if (zAttributedText != attStr) {
|
||||
[zAttributedText release];
|
||||
zAttributedText = [attStr copy];
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)drawTextInRect:(CGRect)rect {
|
||||
if (self.zFont == NULL && self.zAttributedText == nil) {
|
||||
[super drawTextInRect:rect];
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.zAttributedText == nil) {
|
||||
// this method is documented as setting the text color for us, but that doesn't appear to be the case
|
||||
if (self.highlighted) {
|
||||
[(self.highlightedTextColor ?: [UIColor whiteColor]) setFill];
|
||||
} else {
|
||||
[(self.textColor ?: [UIColor blackColor]) setFill];
|
||||
}
|
||||
|
||||
ZFont *actualFont = self.zFont;
|
||||
CGSize origSize = rect.size;
|
||||
if (self.numberOfLines == 1) {
|
||||
origSize.height = actualFont.leading;
|
||||
CGPoint point = CGPointMake(rect.origin.x,
|
||||
rect.origin.y + roundf(((rect.size.height - actualFont.leading) / 2.0f)));
|
||||
CGSize size = [self.text sizeWithZFont:actualFont];
|
||||
if (self.adjustsFontSizeToFitWidth && self.minimumFontSize < actualFont.pointSize) {
|
||||
if (size.width > origSize.width) {
|
||||
CGFloat desiredRatio = (origSize.width * actualFont.ratio) / size.width;
|
||||
CGFloat desiredPointSize = desiredRatio * actualFont.pointSize / actualFont.ratio;
|
||||
actualFont = [actualFont fontWithSize:MAX(MAX(desiredPointSize, self.minimumFontSize), 1.0f)];
|
||||
size = [self.text sizeWithZFont:actualFont];
|
||||
}
|
||||
if (!CGSizeEqualToSize(origSize, size)) {
|
||||
switch (self.baselineAdjustment) {
|
||||
case UIBaselineAdjustmentAlignCenters:
|
||||
point.y += roundf((origSize.height - size.height) / 2.0f);
|
||||
break;
|
||||
case UIBaselineAdjustmentAlignBaselines:
|
||||
point.y += (self.zFont.ascender - actualFont.ascender);
|
||||
break;
|
||||
case UIBaselineAdjustmentNone:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
size.width = MIN(size.width, origSize.width);
|
||||
// adjust the point for alignment
|
||||
switch (self.textAlignment) {
|
||||
case UITextAlignmentLeft:
|
||||
break;
|
||||
case UITextAlignmentCenter:
|
||||
point.x += (origSize.width - size.width) / 2.0f;
|
||||
break;
|
||||
case UITextAlignmentRight:
|
||||
point.x += origSize.width - size.width;
|
||||
break;
|
||||
}
|
||||
[self.text drawAtPoint:point forWidth:size.width withZFont:actualFont lineBreakMode:self.lineBreakMode];
|
||||
} else {
|
||||
CGSize size = [self.text sizeWithZFont:actualFont constrainedToSize:origSize lineBreakMode:self.lineBreakMode numberOfLines:self.numberOfLines];
|
||||
CGPoint point = rect.origin;
|
||||
point.y += roundf((rect.size.height - size.height) / 2.0f);
|
||||
rect = (CGRect){point, CGSizeMake(rect.size.width, size.height)};
|
||||
[self.text drawInRect:rect withZFont:actualFont lineBreakMode:self.lineBreakMode alignment:self.textAlignment numberOfLines:self.numberOfLines];
|
||||
}
|
||||
} else {
|
||||
ZAttributedString *attStr = self.zAttributedText;
|
||||
if (self.highlighted) {
|
||||
// modify the string to change the base color
|
||||
ZMutableAttributedString *mutStr = [[attStr mutableCopy] autorelease];
|
||||
NSRange activeRange = NSMakeRange(0, attStr.length);
|
||||
while (activeRange.length > 0) {
|
||||
NSRange effective;
|
||||
UIColor *color = [attStr attribute:ZForegroundColorAttributeName atIndex:activeRange.location
|
||||
longestEffectiveRange:&effective inRange:activeRange];
|
||||
if (color == nil) {
|
||||
[mutStr addAttribute:ZForegroundColorAttributeName value:[UIColor whiteColor] range:effective];
|
||||
}
|
||||
activeRange.location += effective.length, activeRange.length -= effective.length;
|
||||
}
|
||||
attStr = mutStr;
|
||||
}
|
||||
CGSize size = [attStr sizeConstrainedToSize:rect.size lineBreakMode:self.lineBreakMode numberOfLines:self.numberOfLines];
|
||||
CGPoint point = rect.origin;
|
||||
point.y += roundf((rect.size.height - size.height) / 2.0f);
|
||||
rect = (CGRect){point, CGSizeMake(rect.size.width, size.height)};
|
||||
[attStr drawInRect:rect withLineBreakMode:self.lineBreakMode alignment:self.textAlignment numberOfLines:self.numberOfLines];
|
||||
}
|
||||
}
|
||||
|
||||
- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines {
|
||||
if (self.zFont == NULL && self.zAttributedText == nil) {
|
||||
return [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];
|
||||
}
|
||||
|
||||
if (numberOfLines == 1) {
|
||||
// if numberOfLines == 1 we need to use the version that converts spaces
|
||||
CGSize size;
|
||||
if (self.zAttributedText == nil) {
|
||||
size = [self.text sizeWithZFont:self.zFont];
|
||||
} else {
|
||||
size = [self.zAttributedText size];
|
||||
}
|
||||
bounds.size.width = MIN(bounds.size.width, size.width);
|
||||
bounds.size.height = MIN(bounds.size.height, size.height);
|
||||
} else {
|
||||
if (numberOfLines > 0) bounds.size.height = MIN(bounds.size.height, self.zFont.leading * numberOfLines);
|
||||
if (self.zAttributedText == nil) {
|
||||
bounds.size = [self.text sizeWithZFont:self.zFont constrainedToSize:bounds.size lineBreakMode:self.lineBreakMode];
|
||||
} else {
|
||||
bounds.size = [self.zAttributedText sizeConstrainedToSize:bounds.size lineBreakMode:self.lineBreakMode];
|
||||
}
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[zFont release];
|
||||
[zAttributedText release];
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,81 @@
|
|||
//
|
||||
// FontLabelStringDrawing.h
|
||||
// FontLabel
|
||||
//
|
||||
// Created by Kevin Ballard on 5/5/09.
|
||||
// Copyright © 2009 Zynga Game Networks
|
||||
// Copyright (c) 2011 cocos2d-x.org
|
||||
//
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "ZAttributedString.h"
|
||||
|
||||
@class ZFont;
|
||||
|
||||
@interface NSString (FontLabelStringDrawing)
|
||||
// CGFontRef-based methods
|
||||
- (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize __AVAILABILITY_INTERNAL_DEPRECATED;
|
||||
- (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize constrainedToSize:(CGSize)size __AVAILABILITY_INTERNAL_DEPRECATED;
|
||||
- (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize constrainedToSize:(CGSize)size
|
||||
lineBreakMode:(UILineBreakMode)lineBreakMode __AVAILABILITY_INTERNAL_DEPRECATED;
|
||||
- (CGSize)drawAtPoint:(CGPoint)point withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize __AVAILABILITY_INTERNAL_DEPRECATED;
|
||||
- (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize __AVAILABILITY_INTERNAL_DEPRECATED;
|
||||
- (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize
|
||||
lineBreakMode:(UILineBreakMode)lineBreakMode __AVAILABILITY_INTERNAL_DEPRECATED;
|
||||
- (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize
|
||||
lineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment __AVAILABILITY_INTERNAL_DEPRECATED;
|
||||
|
||||
// ZFont-based methods
|
||||
- (CGSize)sizeWithZFont:(ZFont *)font;
|
||||
- (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size;
|
||||
- (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode;
|
||||
- (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode
|
||||
numberOfLines:(NSUInteger)numberOfLines;
|
||||
- (CGSize)drawAtPoint:(CGPoint)point withZFont:(ZFont *)font;
|
||||
- (CGSize)drawAtPoint:(CGPoint)point forWidth:(CGFloat)width withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode;
|
||||
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font;
|
||||
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode;
|
||||
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode
|
||||
alignment:(UITextAlignment)alignment;
|
||||
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode
|
||||
alignment:(UITextAlignment)alignment numberOfLines:(NSUInteger)numberOfLines;
|
||||
@end
|
||||
|
||||
@interface ZAttributedString (ZAttributedStringDrawing)
|
||||
- (CGSize)size;
|
||||
- (CGSize)sizeConstrainedToSize:(CGSize)size;
|
||||
- (CGSize)sizeConstrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode;
|
||||
- (CGSize)sizeConstrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode
|
||||
numberOfLines:(NSUInteger)numberOfLines;
|
||||
- (CGSize)drawAtPoint:(CGPoint)point;
|
||||
- (CGSize)drawAtPoint:(CGPoint)point forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode;
|
||||
- (CGSize)drawInRect:(CGRect)rect;
|
||||
- (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode;
|
||||
- (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment;
|
||||
- (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment
|
||||
numberOfLines:(NSUInteger)numberOfLines;
|
||||
@end
|
||||
|
||||
// This class is used to invoke in .mm file.
|
||||
// Can not invoke FontLabelStringDrawing directly in .mm.
|
||||
// It seems that, in .mm it can not support category.
|
||||
@interface FontLabelStringDrawingHelper : NSObject {
|
||||
}
|
||||
+ (CGSize)sizeWithZFont:(NSString*)string zfont:(ZFont *)font;
|
||||
+ (CGSize)drawInRect:(NSString*)string rect:(CGRect)rect withZFont:(ZFont *)font
|
||||
lineBreakMode:(UILineBreakMode)lineBreakMode
|
||||
alignment:(UITextAlignment)alignment;
|
||||
@end
|
|
@ -0,0 +1,907 @@
|
|||
//
|
||||
// FontLabelStringDrawing.m
|
||||
// FontLabel
|
||||
//
|
||||
// Created by Kevin Ballard on 5/5/09.
|
||||
// Copyright © 2009 Zynga Game Networks
|
||||
// Copyright (c) 2011 cocos2d-x.org
|
||||
//
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "FontLabelStringDrawing.h"
|
||||
#import "ZFont.h"
|
||||
#import "ZAttributedStringPrivate.h"
|
||||
|
||||
@interface ZFont (ZFontPrivate)
|
||||
@property (nonatomic, readonly) CGFloat ratio;
|
||||
@end
|
||||
|
||||
#define kUnicodeHighSurrogateStart 0xD800
|
||||
#define kUnicodeHighSurrogateEnd 0xDBFF
|
||||
#define kUnicodeHighSurrogateMask kUnicodeHighSurrogateStart
|
||||
#define kUnicodeLowSurrogateStart 0xDC00
|
||||
#define kUnicodeLowSurrogateEnd 0xDFFF
|
||||
#define kUnicodeLowSurrogateMask kUnicodeLowSurrogateStart
|
||||
#define kUnicodeSurrogateTypeMask 0xFC00
|
||||
#define UnicharIsHighSurrogate(c) ((c & kUnicodeSurrogateTypeMask) == kUnicodeHighSurrogateMask)
|
||||
#define UnicharIsLowSurrogate(c) ((c & kUnicodeSurrogateTypeMask) == kUnicodeLowSurrogateMask)
|
||||
#define ConvertSurrogatePairToUTF32(high, low) ((UInt32)((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000))
|
||||
|
||||
typedef enum {
|
||||
kFontTableFormat4 = 4,
|
||||
kFontTableFormat12 = 12,
|
||||
} FontTableFormat;
|
||||
|
||||
typedef struct fontTable {
|
||||
NSUInteger retainCount;
|
||||
CFDataRef cmapTable;
|
||||
FontTableFormat format;
|
||||
union {
|
||||
struct {
|
||||
UInt16 segCountX2;
|
||||
UInt16 *endCodes;
|
||||
UInt16 *startCodes;
|
||||
UInt16 *idDeltas;
|
||||
UInt16 *idRangeOffsets;
|
||||
} format4;
|
||||
struct {
|
||||
UInt32 nGroups;
|
||||
struct {
|
||||
UInt32 startCharCode;
|
||||
UInt32 endCharCode;
|
||||
UInt32 startGlyphCode;
|
||||
} *groups;
|
||||
} format12;
|
||||
} cmap;
|
||||
} fontTable;
|
||||
|
||||
static FontTableFormat supportedFormats[] = { kFontTableFormat4, kFontTableFormat12 };
|
||||
static size_t supportedFormatsCount = sizeof(supportedFormats) / sizeof(FontTableFormat);
|
||||
|
||||
static fontTable *newFontTable(CFDataRef cmapTable, FontTableFormat format) {
|
||||
fontTable *table = (struct fontTable *)malloc(sizeof(struct fontTable));
|
||||
table->retainCount = 1;
|
||||
table->cmapTable = CFRetain(cmapTable);
|
||||
table->format = format;
|
||||
return table;
|
||||
}
|
||||
|
||||
static fontTable *retainFontTable(fontTable *table) {
|
||||
if (table != NULL) {
|
||||
table->retainCount++;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
static void releaseFontTable(fontTable *table) {
|
||||
if (table != NULL) {
|
||||
if (table->retainCount <= 1) {
|
||||
CFRelease(table->cmapTable);
|
||||
free(table);
|
||||
} else {
|
||||
table->retainCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const void *fontTableRetainCallback(CFAllocatorRef allocator, const void *value) {
|
||||
return retainFontTable((fontTable *)value);
|
||||
}
|
||||
|
||||
static void fontTableReleaseCallback(CFAllocatorRef allocator, const void *value) {
|
||||
releaseFontTable((fontTable *)value);
|
||||
}
|
||||
|
||||
static const CFDictionaryValueCallBacks kFontTableDictionaryValueCallBacks = {
|
||||
.version = 0,
|
||||
.retain = &fontTableRetainCallback,
|
||||
.release = &fontTableReleaseCallback,
|
||||
.copyDescription = NULL,
|
||||
.equal = NULL
|
||||
};
|
||||
|
||||
// read the cmap table from the font
|
||||
// we only know how to understand some of the table formats at the moment
|
||||
static fontTable *readFontTableFromCGFont(CGFontRef font) {
|
||||
CFDataRef cmapTable = CGFontCopyTableForTag(font, 'cmap');
|
||||
NSCAssert1(cmapTable != NULL, @"CGFontCopyTableForTag returned NULL for 'cmap' tag in font %@",
|
||||
(font ? [(id)CFCopyDescription(font) autorelease] : @"(null)"));
|
||||
const UInt8 * const bytes = CFDataGetBytePtr(cmapTable);
|
||||
NSCAssert1(OSReadBigInt16(bytes, 0) == 0, @"cmap table for font %@ has bad version number",
|
||||
(font ? [(id)CFCopyDescription(font) autorelease] : @"(null)"));
|
||||
UInt16 numberOfSubtables = OSReadBigInt16(bytes, 2);
|
||||
const UInt8 *unicodeSubtable = NULL;
|
||||
//UInt16 unicodeSubtablePlatformID;
|
||||
UInt16 unicodeSubtablePlatformSpecificID;
|
||||
FontTableFormat unicodeSubtableFormat;
|
||||
const UInt8 * const encodingSubtables = &bytes[4];
|
||||
for (UInt16 i = 0; i < numberOfSubtables; i++) {
|
||||
const UInt8 * const encodingSubtable = &encodingSubtables[8 * i];
|
||||
UInt16 platformID = OSReadBigInt16(encodingSubtable, 0);
|
||||
UInt16 platformSpecificID = OSReadBigInt16(encodingSubtable, 2);
|
||||
// find the best subtable
|
||||
// best is defined by a combination of encoding and format
|
||||
// At the moment we only support format 4, so ignore all other format tables
|
||||
// We prefer platformID == 0, but we will also accept Microsoft's unicode format
|
||||
if (platformID == 0 || (platformID == 3 && platformSpecificID == 1)) {
|
||||
BOOL preferred = NO;
|
||||
if (unicodeSubtable == NULL) {
|
||||
preferred = YES;
|
||||
} else if (platformID == 0 && platformSpecificID > unicodeSubtablePlatformSpecificID) {
|
||||
preferred = YES;
|
||||
}
|
||||
if (preferred) {
|
||||
UInt32 offset = OSReadBigInt32(encodingSubtable, 4);
|
||||
const UInt8 *subtable = &bytes[offset];
|
||||
UInt16 format = OSReadBigInt16(subtable, 0);
|
||||
for (size_t i = 0; i < supportedFormatsCount; i++) {
|
||||
if (format == supportedFormats[i]) {
|
||||
if (format >= 8) {
|
||||
// the version is a fixed-point
|
||||
UInt16 formatFrac = OSReadBigInt16(subtable, 2);
|
||||
if (formatFrac != 0) {
|
||||
// all the current formats with a Fixed version are always *.0
|
||||
continue;
|
||||
}
|
||||
}
|
||||
unicodeSubtable = subtable;
|
||||
//unicodeSubtablePlatformID = platformID;
|
||||
unicodeSubtablePlatformSpecificID = platformSpecificID;
|
||||
unicodeSubtableFormat = format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fontTable *table = NULL;
|
||||
if (unicodeSubtable != NULL) {
|
||||
table = newFontTable(cmapTable, unicodeSubtableFormat);
|
||||
switch (unicodeSubtableFormat) {
|
||||
case kFontTableFormat4:
|
||||
// subtable format 4
|
||||
//UInt16 length = OSReadBigInt16(unicodeSubtable, 2);
|
||||
//UInt16 language = OSReadBigInt16(unicodeSubtable, 4);
|
||||
table->cmap.format4.segCountX2 = OSReadBigInt16(unicodeSubtable, 6);
|
||||
//UInt16 searchRange = OSReadBigInt16(unicodeSubtable, 8);
|
||||
//UInt16 entrySelector = OSReadBigInt16(unicodeSubtable, 10);
|
||||
//UInt16 rangeShift = OSReadBigInt16(unicodeSubtable, 12);
|
||||
table->cmap.format4.endCodes = (UInt16*)&unicodeSubtable[14];
|
||||
table->cmap.format4.startCodes = (UInt16*)&((UInt8*)table->cmap.format4.endCodes)[table->cmap.format4.segCountX2+2];
|
||||
table->cmap.format4.idDeltas = (UInt16*)&((UInt8*)table->cmap.format4.startCodes)[table->cmap.format4.segCountX2];
|
||||
table->cmap.format4.idRangeOffsets = (UInt16*)&((UInt8*)table->cmap.format4.idDeltas)[table->cmap.format4.segCountX2];
|
||||
//UInt16 *glyphIndexArray = &idRangeOffsets[segCountX2];
|
||||
break;
|
||||
case kFontTableFormat12:
|
||||
table->cmap.format12.nGroups = OSReadBigInt32(unicodeSubtable, 12);
|
||||
table->cmap.format12.groups = (void *)&unicodeSubtable[16];
|
||||
break;
|
||||
default:
|
||||
releaseFontTable(table);
|
||||
table = NULL;
|
||||
}
|
||||
}
|
||||
CFRelease(cmapTable);
|
||||
return table;
|
||||
}
|
||||
|
||||
// outGlyphs must be at least size n
|
||||
static void mapCharactersToGlyphsInFont(const fontTable *table, unichar characters[], size_t charLen, CGGlyph outGlyphs[], size_t *outGlyphLen) {
|
||||
if (table != NULL) {
|
||||
NSUInteger j = 0;
|
||||
switch (table->format) {
|
||||
case kFontTableFormat4: {
|
||||
for (NSUInteger i = 0; i < charLen; i++, j++) {
|
||||
unichar c = characters[i];
|
||||
UInt16 segOffset;
|
||||
BOOL foundSegment = NO;
|
||||
for (segOffset = 0; segOffset < table->cmap.format4.segCountX2; segOffset += 2) {
|
||||
UInt16 endCode = OSReadBigInt16(table->cmap.format4.endCodes, segOffset);
|
||||
if (endCode >= c) {
|
||||
foundSegment = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundSegment) {
|
||||
// no segment
|
||||
// this is an invalid font
|
||||
outGlyphs[j] = 0;
|
||||
} else {
|
||||
UInt16 startCode = OSReadBigInt16(table->cmap.format4.startCodes, segOffset);
|
||||
if (!(startCode <= c)) {
|
||||
// the code falls in a hole between segments
|
||||
outGlyphs[j] = 0;
|
||||
} else {
|
||||
UInt16 idRangeOffset = OSReadBigInt16(table->cmap.format4.idRangeOffsets, segOffset);
|
||||
if (idRangeOffset == 0) {
|
||||
UInt16 idDelta = OSReadBigInt16(table->cmap.format4.idDeltas, segOffset);
|
||||
outGlyphs[j] = (c + idDelta) % 65536;
|
||||
} else {
|
||||
// use the glyphIndexArray
|
||||
UInt16 glyphOffset = idRangeOffset + 2 * (c - startCode);
|
||||
outGlyphs[j] = OSReadBigInt16(&((UInt8*)table->cmap.format4.idRangeOffsets)[segOffset], glyphOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kFontTableFormat12: {
|
||||
UInt32 lastSegment = UINT32_MAX;
|
||||
for (NSUInteger i = 0; i < charLen; i++, j++) {
|
||||
unichar c = characters[i];
|
||||
UInt32 c32 = c;
|
||||
if (UnicharIsHighSurrogate(c)) {
|
||||
if (i+1 < charLen) { // do we have another character after this one?
|
||||
unichar cc = characters[i+1];
|
||||
if (UnicharIsLowSurrogate(cc)) {
|
||||
c32 = ConvertSurrogatePairToUTF32(c, cc);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Start the heuristic search
|
||||
// If this is an ASCII char, just do a linear search
|
||||
// Otherwise do a hinted, modified binary search
|
||||
// Start the first pivot at the last range found
|
||||
// And when moving the pivot, limit the movement by increasing
|
||||
// powers of two. This should help with locality
|
||||
__typeof__(table->cmap.format12.groups[0]) *foundGroup = NULL;
|
||||
if (c32 <= 0x7F) {
|
||||
// ASCII
|
||||
for (UInt32 idx = 0; idx < table->cmap.format12.nGroups; idx++) {
|
||||
__typeof__(table->cmap.format12.groups[idx]) *group = &table->cmap.format12.groups[idx];
|
||||
if (c32 < OSSwapBigToHostInt32(group->startCharCode)) {
|
||||
// we've fallen into a hole
|
||||
break;
|
||||
} else if (c32 <= OSSwapBigToHostInt32(group->endCharCode)) {
|
||||
// this is the range
|
||||
foundGroup = group;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// heuristic search
|
||||
UInt32 maxJump = (lastSegment == UINT32_MAX ? UINT32_MAX / 2 : 8);
|
||||
UInt32 lowIdx = 0, highIdx = table->cmap.format12.nGroups; // highIdx is the first invalid idx
|
||||
UInt32 pivot = (lastSegment == UINT32_MAX ? lowIdx + (highIdx - lowIdx) / 2 : lastSegment);
|
||||
while (highIdx > lowIdx) {
|
||||
__typeof__(table->cmap.format12.groups[pivot]) *group = &table->cmap.format12.groups[pivot];
|
||||
if (c32 < OSSwapBigToHostInt32(group->startCharCode)) {
|
||||
highIdx = pivot;
|
||||
} else if (c32 > OSSwapBigToHostInt32(group->endCharCode)) {
|
||||
lowIdx = pivot + 1;
|
||||
} else {
|
||||
// we've hit the range
|
||||
foundGroup = group;
|
||||
break;
|
||||
}
|
||||
if (highIdx - lowIdx > maxJump * 2) {
|
||||
if (highIdx == pivot) {
|
||||
pivot -= maxJump;
|
||||
} else {
|
||||
pivot += maxJump;
|
||||
}
|
||||
maxJump *= 2;
|
||||
} else {
|
||||
pivot = lowIdx + (highIdx - lowIdx) / 2;
|
||||
}
|
||||
}
|
||||
if (foundGroup != NULL) lastSegment = pivot;
|
||||
}
|
||||
if (foundGroup == NULL) {
|
||||
outGlyphs[j] = 0;
|
||||
} else {
|
||||
outGlyphs[j] = (CGGlyph)(OSSwapBigToHostInt32(foundGroup->startGlyphCode) +
|
||||
(c32 - OSSwapBigToHostInt32(foundGroup->startCharCode)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (outGlyphLen != NULL) *outGlyphLen = j;
|
||||
} else {
|
||||
// we have no table, so just null out the glyphs
|
||||
bzero(outGlyphs, charLen*sizeof(CGGlyph));
|
||||
if (outGlyphLen != NULL) *outGlyphLen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL mapGlyphsToAdvancesInFont(ZFont *font, size_t n, CGGlyph glyphs[], CGFloat outAdvances[]) {
|
||||
int advances[n];
|
||||
if (CGFontGetGlyphAdvances(font.cgFont, glyphs, n, advances)) {
|
||||
CGFloat ratio = font.ratio;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
outAdvances[i] = advances[i]*ratio;
|
||||
}
|
||||
return YES;
|
||||
} else {
|
||||
bzero(outAdvances, n*sizeof(CGFloat));
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
static id getValueOrDefaultForRun(ZAttributeRun *run, NSString *key) {
|
||||
id value = [run.attributes objectForKey:key];
|
||||
if (value == nil) {
|
||||
static NSDictionary *defaultValues = nil;
|
||||
if (defaultValues == nil) {
|
||||
defaultValues = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
[ZFont fontWithUIFont:[UIFont systemFontOfSize:12]], ZFontAttributeName,
|
||||
[UIColor blackColor], ZForegroundColorAttributeName,
|
||||
[UIColor clearColor], ZBackgroundColorAttributeName,
|
||||
[NSNumber numberWithInt:ZUnderlineStyleNone], ZUnderlineStyleAttributeName,
|
||||
nil];
|
||||
}
|
||||
value = [defaultValues objectForKey:key];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static void readRunInformation(NSArray *attributes, NSUInteger len, CFMutableDictionaryRef fontTableMap,
|
||||
NSUInteger index, ZAttributeRun **currentRun, NSUInteger *nextRunStart,
|
||||
ZFont **currentFont, fontTable **currentTable) {
|
||||
*currentRun = [attributes objectAtIndex:index];
|
||||
*nextRunStart = ([attributes count] > index+1 ? [[attributes objectAtIndex:index+1] index] : len);
|
||||
*currentFont = getValueOrDefaultForRun(*currentRun, ZFontAttributeName);
|
||||
if (!CFDictionaryGetValueIfPresent(fontTableMap, (*currentFont).cgFont, (const void **)currentTable)) {
|
||||
*currentTable = readFontTableFromCGFont((*currentFont).cgFont);
|
||||
CFDictionarySetValue(fontTableMap, (*currentFont).cgFont, *currentTable);
|
||||
releaseFontTable(*currentTable);
|
||||
}
|
||||
}
|
||||
|
||||
static CGSize drawOrSizeTextConstrainedToSize(BOOL performDraw, NSString *string, NSArray *attributes, CGSize constrainedSize, NSUInteger maxLines,
|
||||
UILineBreakMode lineBreakMode, UITextAlignment alignment, BOOL ignoreColor) {
|
||||
NSUInteger len = [string length];
|
||||
NSUInteger idx = 0;
|
||||
CGPoint drawPoint = CGPointZero;
|
||||
CGSize retValue = CGSizeZero;
|
||||
CGContextRef ctx = (performDraw ? UIGraphicsGetCurrentContext() : NULL);
|
||||
|
||||
BOOL convertNewlines = (maxLines == 1);
|
||||
|
||||
// Extract the characters from the string
|
||||
// Convert newlines to spaces if necessary
|
||||
unichar *characters = (unichar *)malloc(sizeof(unichar) * len);
|
||||
if (convertNewlines) {
|
||||
NSCharacterSet *charset = [NSCharacterSet newlineCharacterSet];
|
||||
NSRange range = NSMakeRange(0, len);
|
||||
size_t cIdx = 0;
|
||||
while (range.length > 0) {
|
||||
NSRange newlineRange = [string rangeOfCharacterFromSet:charset options:0 range:range];
|
||||
if (newlineRange.location == NSNotFound) {
|
||||
[string getCharacters:&characters[cIdx] range:range];
|
||||
cIdx += range.length;
|
||||
break;
|
||||
} else {
|
||||
NSUInteger delta = newlineRange.location - range.location;
|
||||
if (newlineRange.location > range.location) {
|
||||
[string getCharacters:&characters[cIdx] range:NSMakeRange(range.location, delta)];
|
||||
}
|
||||
cIdx += delta;
|
||||
characters[cIdx] = (unichar)' ';
|
||||
cIdx++;
|
||||
delta += newlineRange.length;
|
||||
range.location += delta, range.length -= delta;
|
||||
if (newlineRange.length == 1 && range.length >= 1 &&
|
||||
[string characterAtIndex:newlineRange.location] == (unichar)'\r' &&
|
||||
[string characterAtIndex:range.location] == (unichar)'\n') {
|
||||
// CRLF sequence, skip the LF
|
||||
range.location += 1, range.length -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
len = cIdx;
|
||||
} else {
|
||||
[string getCharacters:characters range:NSMakeRange(0, len)];
|
||||
}
|
||||
|
||||
// Create storage for glyphs and advances
|
||||
CGGlyph *glyphs;
|
||||
CGFloat *advances;
|
||||
{
|
||||
NSUInteger maxRunLength = 0;
|
||||
ZAttributeRun *a = [attributes objectAtIndex:0];
|
||||
for (NSUInteger i = 1; i < [attributes count]; i++) {
|
||||
ZAttributeRun *b = [attributes objectAtIndex:i];
|
||||
maxRunLength = MAX(maxRunLength, b.index - a.index);
|
||||
a = b;
|
||||
}
|
||||
maxRunLength = MAX(maxRunLength, len - a.index);
|
||||
maxRunLength++; // for a potential ellipsis
|
||||
glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * maxRunLength);
|
||||
advances = (CGFloat *)malloc(sizeof(CGFloat) * maxRunLength);
|
||||
}
|
||||
|
||||
// Use this table to cache all fontTable objects
|
||||
CFMutableDictionaryRef fontTableMap = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
|
||||
&kFontTableDictionaryValueCallBacks);
|
||||
|
||||
// Fetch initial style values
|
||||
NSUInteger currentRunIdx = 0;
|
||||
ZAttributeRun *currentRun;
|
||||
NSUInteger nextRunStart;
|
||||
ZFont *currentFont;
|
||||
fontTable *currentTable;
|
||||
|
||||
#define READ_RUN() readRunInformation(attributes, len, fontTableMap, \
|
||||
currentRunIdx, ¤tRun, &nextRunStart, \
|
||||
¤tFont, ¤tTable)
|
||||
|
||||
READ_RUN();
|
||||
|
||||
// fetch the glyphs for the first run
|
||||
size_t glyphCount;
|
||||
NSUInteger glyphIdx;
|
||||
|
||||
#define READ_GLYPHS() do { \
|
||||
mapCharactersToGlyphsInFont(currentTable, &characters[currentRun.index], (nextRunStart - currentRun.index), glyphs, &glyphCount); \
|
||||
mapGlyphsToAdvancesInFont(currentFont, (nextRunStart - currentRun.index), glyphs, advances); \
|
||||
glyphIdx = 0; \
|
||||
} while (0)
|
||||
|
||||
READ_GLYPHS();
|
||||
|
||||
NSMutableCharacterSet *alphaCharset = [NSMutableCharacterSet alphanumericCharacterSet];
|
||||
[alphaCharset addCharactersInString:@"([{'\"\u2019\u02BC"];
|
||||
|
||||
// scan left-to-right looking for newlines or until we hit the width constraint
|
||||
// When we hit a wrapping point, calculate truncation as follows:
|
||||
// If we have room to draw at least one more character on the next line, no truncation
|
||||
// Otherwise apply the truncation algorithm to the current line.
|
||||
// After calculating any truncation, draw.
|
||||
// Each time we hit the end of an attribute run, calculate the new font and make sure
|
||||
// it fits (vertically) within the size constraint. If not, truncate this line.
|
||||
// When we draw, iterate over the attribute runs for this line and draw each run separately
|
||||
BOOL lastLine = NO; // used to indicate truncation and to stop the iterating
|
||||
NSUInteger lineCount = 1;
|
||||
while (idx < len && !lastLine) {
|
||||
if (maxLines > 0 && lineCount == maxLines) {
|
||||
lastLine = YES;
|
||||
}
|
||||
// scan left-to-right
|
||||
struct {
|
||||
NSUInteger index;
|
||||
NSUInteger glyphIndex;
|
||||
NSUInteger currentRunIdx;
|
||||
} indexCache = { idx, glyphIdx, currentRunIdx };
|
||||
CGSize lineSize = CGSizeMake(0, currentFont.leading);
|
||||
CGFloat lineAscender = currentFont.ascender;
|
||||
struct {
|
||||
NSUInteger index;
|
||||
NSUInteger glyphIndex;
|
||||
NSUInteger currentRunIdx;
|
||||
CGSize lineSize;
|
||||
} lastWrapCache = {0, 0, 0, CGSizeZero};
|
||||
BOOL inAlpha = NO; // used for calculating wrap points
|
||||
|
||||
BOOL finishLine = NO;
|
||||
for (;idx <= len && !finishLine;) {
|
||||
NSUInteger skipCount = 0;
|
||||
if (idx == len) {
|
||||
finishLine = YES;
|
||||
lastLine = YES;
|
||||
} else {
|
||||
if (idx >= nextRunStart) {
|
||||
// cycle the font and table and grab the next set of glyphs
|
||||
do {
|
||||
currentRunIdx++;
|
||||
READ_RUN();
|
||||
} while (idx >= nextRunStart);
|
||||
READ_GLYPHS();
|
||||
// re-scan the characters to synchronize the glyph index
|
||||
for (NSUInteger j = currentRun.index; j < idx; j++) {
|
||||
if (UnicharIsHighSurrogate(characters[j]) && j+1<len && UnicharIsLowSurrogate(characters[j+1])) {
|
||||
j++;
|
||||
}
|
||||
glyphIdx++;
|
||||
}
|
||||
if (currentFont.leading > lineSize.height) {
|
||||
lineSize.height = currentFont.leading;
|
||||
if (retValue.height + currentFont.ascender > constrainedSize.height) {
|
||||
lastLine = YES;
|
||||
finishLine = YES;
|
||||
}
|
||||
}
|
||||
lineAscender = MAX(lineAscender, currentFont.ascender);
|
||||
}
|
||||
unichar c = characters[idx];
|
||||
// Mark a wrap point before spaces and after any stretch of non-alpha characters
|
||||
BOOL markWrap = NO;
|
||||
if (c == (unichar)' ') {
|
||||
markWrap = YES;
|
||||
} else if ([alphaCharset characterIsMember:c]) {
|
||||
if (!inAlpha) {
|
||||
markWrap = YES;
|
||||
inAlpha = YES;
|
||||
}
|
||||
} else {
|
||||
inAlpha = NO;
|
||||
}
|
||||
if (markWrap) {
|
||||
lastWrapCache = (__typeof__(lastWrapCache)){
|
||||
.index = idx,
|
||||
.glyphIndex = glyphIdx,
|
||||
.currentRunIdx = currentRunIdx,
|
||||
.lineSize = lineSize
|
||||
};
|
||||
}
|
||||
// process the line
|
||||
if (c == (unichar)'\n' || c == 0x0085) { // U+0085 is the NEXT_LINE unicode character
|
||||
finishLine = YES;
|
||||
skipCount = 1;
|
||||
} else if (c == (unichar)'\r') {
|
||||
finishLine = YES;
|
||||
// check for CRLF
|
||||
if (idx+1 < len && characters[idx+1] == (unichar)'\n') {
|
||||
skipCount = 2;
|
||||
} else {
|
||||
skipCount = 1;
|
||||
}
|
||||
} else if (lineSize.width + advances[glyphIdx] > constrainedSize.width) {
|
||||
finishLine = YES;
|
||||
if (retValue.height + lineSize.height + currentFont.ascender > constrainedSize.height) {
|
||||
lastLine = YES;
|
||||
}
|
||||
// walk backwards if wrapping is necessary
|
||||
if (lastWrapCache.index > indexCache.index && lineBreakMode != UILineBreakModeCharacterWrap &&
|
||||
(!lastLine || lineBreakMode != UILineBreakModeClip)) {
|
||||
// we're doing some sort of word wrapping
|
||||
idx = lastWrapCache.index;
|
||||
lineSize = lastWrapCache.lineSize;
|
||||
if (!lastLine) {
|
||||
// re-check if this is the last line
|
||||
if (lastWrapCache.currentRunIdx != currentRunIdx) {
|
||||
currentRunIdx = lastWrapCache.currentRunIdx;
|
||||
READ_RUN();
|
||||
READ_GLYPHS();
|
||||
}
|
||||
if (retValue.height + lineSize.height + currentFont.ascender > constrainedSize.height) {
|
||||
lastLine = YES;
|
||||
}
|
||||
}
|
||||
glyphIdx = lastWrapCache.glyphIndex;
|
||||
// skip any spaces
|
||||
for (NSUInteger j = idx; j < len && characters[j] == (unichar)' '; j++) {
|
||||
skipCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (finishLine) {
|
||||
// TODO: support head/middle truncation
|
||||
if (lastLine && idx < len && lineBreakMode == UILineBreakModeTailTruncation) {
|
||||
// truncate
|
||||
unichar ellipsis = 0x2026; // ellipsis (…)
|
||||
CGGlyph ellipsisGlyph;
|
||||
mapCharactersToGlyphsInFont(currentTable, &ellipsis, 1, &ellipsisGlyph, NULL);
|
||||
CGFloat ellipsisWidth;
|
||||
mapGlyphsToAdvancesInFont(currentFont, 1, &ellipsisGlyph, &ellipsisWidth);
|
||||
while ((idx - indexCache.index) > 1 && lineSize.width + ellipsisWidth > constrainedSize.width) {
|
||||
// we have more than 1 character and we're too wide, so back up
|
||||
idx--;
|
||||
if (UnicharIsHighSurrogate(characters[idx]) && UnicharIsLowSurrogate(characters[idx+1])) {
|
||||
idx--;
|
||||
}
|
||||
if (idx < currentRun.index) {
|
||||
ZFont *oldFont = currentFont;
|
||||
do {
|
||||
currentRunIdx--;
|
||||
READ_RUN();
|
||||
} while (idx < currentRun.index);
|
||||
READ_GLYPHS();
|
||||
glyphIdx = glyphCount-1;
|
||||
if (oldFont != currentFont) {
|
||||
mapCharactersToGlyphsInFont(currentTable, &ellipsis, 1, &ellipsisGlyph, NULL);
|
||||
mapGlyphsToAdvancesInFont(currentFont, 1, &ellipsisGlyph, &ellipsisWidth);
|
||||
}
|
||||
} else {
|
||||
glyphIdx--;
|
||||
}
|
||||
lineSize.width -= advances[glyphIdx];
|
||||
}
|
||||
// skip any spaces before truncating
|
||||
while ((idx - indexCache.index) > 1 && characters[idx-1] == (unichar)' ') {
|
||||
idx--;
|
||||
if (idx < currentRun.index) {
|
||||
currentRunIdx--;
|
||||
READ_RUN();
|
||||
READ_GLYPHS();
|
||||
glyphIdx = glyphCount-1;
|
||||
} else {
|
||||
glyphIdx--;
|
||||
}
|
||||
lineSize.width -= advances[glyphIdx];
|
||||
}
|
||||
lineSize.width += ellipsisWidth;
|
||||
glyphs[glyphIdx] = ellipsisGlyph;
|
||||
idx++;
|
||||
glyphIdx++;
|
||||
}
|
||||
retValue.width = MAX(retValue.width, lineSize.width);
|
||||
retValue.height += lineSize.height;
|
||||
|
||||
// draw
|
||||
if (performDraw) {
|
||||
switch (alignment) {
|
||||
case UITextAlignmentLeft:
|
||||
drawPoint.x = 0;
|
||||
break;
|
||||
case UITextAlignmentCenter:
|
||||
drawPoint.x = (constrainedSize.width - lineSize.width) / 2.0f;
|
||||
break;
|
||||
case UITextAlignmentRight:
|
||||
drawPoint.x = constrainedSize.width - lineSize.width;
|
||||
break;
|
||||
}
|
||||
NSUInteger stopGlyphIdx = glyphIdx;
|
||||
NSUInteger lastRunIdx = currentRunIdx;
|
||||
NSUInteger stopCharIdx = idx;
|
||||
idx = indexCache.index;
|
||||
if (currentRunIdx != indexCache.currentRunIdx) {
|
||||
currentRunIdx = indexCache.currentRunIdx;
|
||||
READ_RUN();
|
||||
READ_GLYPHS();
|
||||
}
|
||||
glyphIdx = indexCache.glyphIndex;
|
||||
for (NSUInteger drawIdx = currentRunIdx; drawIdx <= lastRunIdx; drawIdx++) {
|
||||
if (drawIdx != currentRunIdx) {
|
||||
currentRunIdx = drawIdx;
|
||||
READ_RUN();
|
||||
READ_GLYPHS();
|
||||
}
|
||||
NSUInteger numGlyphs;
|
||||
if (drawIdx == lastRunIdx) {
|
||||
numGlyphs = stopGlyphIdx - glyphIdx;
|
||||
idx = stopCharIdx;
|
||||
} else {
|
||||
numGlyphs = glyphCount - glyphIdx;
|
||||
idx = nextRunStart;
|
||||
}
|
||||
CGContextSetFont(ctx, currentFont.cgFont);
|
||||
CGContextSetFontSize(ctx, currentFont.pointSize);
|
||||
// calculate the fragment size
|
||||
CGFloat fragmentWidth = 0;
|
||||
for (NSUInteger g = 0; g < numGlyphs; g++) {
|
||||
fragmentWidth += advances[glyphIdx + g];
|
||||
}
|
||||
|
||||
if (!ignoreColor) {
|
||||
UIColor *foregroundColor = getValueOrDefaultForRun(currentRun, ZForegroundColorAttributeName);
|
||||
UIColor *backgroundColor = getValueOrDefaultForRun(currentRun, ZBackgroundColorAttributeName);
|
||||
if (backgroundColor != nil && ![backgroundColor isEqual:[UIColor clearColor]]) {
|
||||
[backgroundColor setFill];
|
||||
UIRectFillUsingBlendMode((CGRect){ drawPoint, { fragmentWidth, lineSize.height } }, kCGBlendModeNormal);
|
||||
}
|
||||
[foregroundColor setFill];
|
||||
}
|
||||
|
||||
CGContextShowGlyphsAtPoint(ctx, drawPoint.x, drawPoint.y + lineAscender, &glyphs[glyphIdx], numGlyphs);
|
||||
NSNumber *underlineStyle = getValueOrDefaultForRun(currentRun, ZUnderlineStyleAttributeName);
|
||||
if ([underlineStyle integerValue] & ZUnderlineStyleMask) {
|
||||
// we only support single for the time being
|
||||
UIRectFill(CGRectMake(drawPoint.x, drawPoint.y + lineAscender, fragmentWidth, 1));
|
||||
}
|
||||
drawPoint.x += fragmentWidth;
|
||||
glyphIdx += numGlyphs;
|
||||
}
|
||||
drawPoint.y += lineSize.height;
|
||||
}
|
||||
idx += skipCount;
|
||||
glyphIdx += skipCount;
|
||||
lineCount++;
|
||||
} else {
|
||||
lineSize.width += advances[glyphIdx];
|
||||
glyphIdx++;
|
||||
idx++;
|
||||
if (idx < len && UnicharIsHighSurrogate(characters[idx-1]) && UnicharIsLowSurrogate(characters[idx])) {
|
||||
// skip the second half of the surrogate pair
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(fontTableMap);
|
||||
free(glyphs);
|
||||
free(advances);
|
||||
free(characters);
|
||||
|
||||
#undef READ_GLYPHS
|
||||
#undef READ_RUN
|
||||
|
||||
return retValue;
|
||||
}
|
||||
|
||||
static NSArray *attributeRunForFont(ZFont *font) {
|
||||
return [NSArray arrayWithObject:[ZAttributeRun attributeRunWithIndex:0
|
||||
attributes:[NSDictionary dictionaryWithObject:font
|
||||
forKey:ZFontAttributeName]]];
|
||||
}
|
||||
|
||||
static CGSize drawTextInRect(CGRect rect, NSString *text, NSArray *attributes, UILineBreakMode lineBreakMode,
|
||||
UITextAlignment alignment, NSUInteger numberOfLines, BOOL ignoreColor) {
|
||||
CGContextRef ctx = UIGraphicsGetCurrentContext();
|
||||
|
||||
CGContextSaveGState(ctx);
|
||||
|
||||
// flip it upside-down because our 0,0 is upper-left, whereas ttfs are for screens where 0,0 is lower-left
|
||||
CGAffineTransform textTransform = CGAffineTransformMake(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
|
||||
CGContextSetTextMatrix(ctx, textTransform);
|
||||
|
||||
CGContextTranslateCTM(ctx, rect.origin.x, rect.origin.y);
|
||||
|
||||
CGContextSetTextDrawingMode(ctx, kCGTextFill);
|
||||
CGSize size = drawOrSizeTextConstrainedToSize(YES, text, attributes, rect.size, numberOfLines, lineBreakMode, alignment, ignoreColor);
|
||||
|
||||
CGContextRestoreGState(ctx);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@implementation NSString (FontLabelStringDrawing)
|
||||
// CGFontRef-based methods
|
||||
- (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize {
|
||||
return [self sizeWithZFont:[ZFont fontWithCGFont:font size:pointSize]];
|
||||
}
|
||||
|
||||
- (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize constrainedToSize:(CGSize)size {
|
||||
return [self sizeWithZFont:[ZFont fontWithCGFont:font size:pointSize] constrainedToSize:size];
|
||||
}
|
||||
|
||||
- (CGSize)sizeWithCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize constrainedToSize:(CGSize)size
|
||||
lineBreakMode:(UILineBreakMode)lineBreakMode {
|
||||
return [self sizeWithZFont:[ZFont fontWithCGFont:font size:pointSize] constrainedToSize:size lineBreakMode:lineBreakMode];
|
||||
}
|
||||
|
||||
- (CGSize)drawAtPoint:(CGPoint)point withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize {
|
||||
return [self drawAtPoint:point withZFont:[ZFont fontWithCGFont:font size:pointSize]];
|
||||
}
|
||||
|
||||
- (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize {
|
||||
return [self drawInRect:rect withZFont:[ZFont fontWithCGFont:font size:pointSize]];
|
||||
}
|
||||
|
||||
- (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize lineBreakMode:(UILineBreakMode)lineBreakMode {
|
||||
return [self drawInRect:rect withZFont:[ZFont fontWithCGFont:font size:pointSize] lineBreakMode:lineBreakMode];
|
||||
}
|
||||
|
||||
- (CGSize)drawInRect:(CGRect)rect withCGFont:(CGFontRef)font pointSize:(CGFloat)pointSize
|
||||
lineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment {
|
||||
return [self drawInRect:rect withZFont:[ZFont fontWithCGFont:font size:pointSize] lineBreakMode:lineBreakMode alignment:alignment];
|
||||
}
|
||||
|
||||
// ZFont-based methods
|
||||
- (CGSize)sizeWithZFont:(ZFont *)font {
|
||||
CGSize size = drawOrSizeTextConstrainedToSize(NO, self, attributeRunForFont(font), CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX), 1,
|
||||
UILineBreakModeClip, UITextAlignmentLeft, YES);
|
||||
return CGSizeMake(ceilf(size.width), ceilf(size.height));
|
||||
}
|
||||
|
||||
- (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size {
|
||||
return [self sizeWithZFont:font constrainedToSize:size lineBreakMode:UILineBreakModeWordWrap];
|
||||
}
|
||||
|
||||
/*
|
||||
According to experimentation with UIStringDrawing, this can actually return a CGSize whose height is greater
|
||||
than the one passed in. The two cases are as follows:
|
||||
1. If the given size parameter's height is smaller than a single line, the returned value will
|
||||
be the height of one line.
|
||||
2. If the given size parameter's height falls between multiples of a line height, and the wrapped string
|
||||
actually extends past the size.height, and the difference between size.height and the previous multiple
|
||||
of a line height is >= the font's ascender, then the returned size's height is extended to the next line.
|
||||
To put it simply, if the baseline point of a given line falls in the given size, the entire line will
|
||||
be present in the output size.
|
||||
*/
|
||||
- (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode {
|
||||
size = drawOrSizeTextConstrainedToSize(NO, self, attributeRunForFont(font), size, 0, lineBreakMode, UITextAlignmentLeft, YES);
|
||||
return CGSizeMake(ceilf(size.width), ceilf(size.height));
|
||||
}
|
||||
|
||||
- (CGSize)sizeWithZFont:(ZFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode
|
||||
numberOfLines:(NSUInteger)numberOfLines {
|
||||
size = drawOrSizeTextConstrainedToSize(NO, self, attributeRunForFont(font), size, numberOfLines, lineBreakMode, UITextAlignmentLeft, YES);
|
||||
return CGSizeMake(ceilf(size.width), ceilf(size.height));
|
||||
}
|
||||
|
||||
- (CGSize)drawAtPoint:(CGPoint)point withZFont:(ZFont *)font {
|
||||
return [self drawAtPoint:point forWidth:CGFLOAT_MAX withZFont:font lineBreakMode:UILineBreakModeClip];
|
||||
}
|
||||
|
||||
- (CGSize)drawAtPoint:(CGPoint)point forWidth:(CGFloat)width withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode {
|
||||
return drawTextInRect((CGRect){ point, { width, CGFLOAT_MAX } }, self, attributeRunForFont(font), lineBreakMode, UITextAlignmentLeft, 1, YES);
|
||||
}
|
||||
|
||||
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font {
|
||||
return [self drawInRect:rect withZFont:font lineBreakMode:UILineBreakModeWordWrap];
|
||||
}
|
||||
|
||||
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode {
|
||||
return [self drawInRect:rect withZFont:font lineBreakMode:lineBreakMode alignment:UITextAlignmentLeft];
|
||||
}
|
||||
|
||||
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode
|
||||
alignment:(UITextAlignment)alignment {
|
||||
return drawTextInRect(rect, self, attributeRunForFont(font), lineBreakMode, alignment, 0, YES);
|
||||
}
|
||||
|
||||
- (CGSize)drawInRect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode
|
||||
alignment:(UITextAlignment)alignment numberOfLines:(NSUInteger)numberOfLines {
|
||||
return drawTextInRect(rect, self, attributeRunForFont(font), lineBreakMode, alignment, numberOfLines, YES);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ZAttributedString (ZAttributedStringDrawing)
|
||||
- (CGSize)size {
|
||||
CGSize size = drawOrSizeTextConstrainedToSize(NO, self.string, self.attributes, CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX), 1,
|
||||
UILineBreakModeClip, UITextAlignmentLeft, NO);
|
||||
return CGSizeMake(ceilf(size.width), ceilf(size.height));
|
||||
}
|
||||
|
||||
- (CGSize)sizeConstrainedToSize:(CGSize)size {
|
||||
return [self sizeConstrainedToSize:size lineBreakMode:UILineBreakModeWordWrap];
|
||||
}
|
||||
|
||||
- (CGSize)sizeConstrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode {
|
||||
size = drawOrSizeTextConstrainedToSize(NO, self.string, self.attributes, size, 0, lineBreakMode, UITextAlignmentLeft, NO);
|
||||
return CGSizeMake(ceilf(size.width), ceilf(size.height));
|
||||
}
|
||||
|
||||
- (CGSize)sizeConstrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode
|
||||
numberOfLines:(NSUInteger)numberOfLines {
|
||||
size = drawOrSizeTextConstrainedToSize(NO, self.string, self.attributes, size, numberOfLines, lineBreakMode, UITextAlignmentLeft, NO);
|
||||
return CGSizeMake(ceilf(size.width), ceilf(size.height));
|
||||
}
|
||||
|
||||
- (CGSize)drawAtPoint:(CGPoint)point {
|
||||
return [self drawAtPoint:point forWidth:CGFLOAT_MAX lineBreakMode:UILineBreakModeClip];
|
||||
}
|
||||
|
||||
- (CGSize)drawAtPoint:(CGPoint)point forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode {
|
||||
return drawTextInRect((CGRect){ point, { width, CGFLOAT_MAX } }, self.string, self.attributes, lineBreakMode, UITextAlignmentLeft, 1, NO);
|
||||
}
|
||||
|
||||
- (CGSize)drawInRect:(CGRect)rect {
|
||||
return [self drawInRect:rect withLineBreakMode:UILineBreakModeWordWrap];
|
||||
}
|
||||
|
||||
- (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode {
|
||||
return [self drawInRect:rect withLineBreakMode:lineBreakMode alignment:UITextAlignmentLeft];
|
||||
}
|
||||
|
||||
- (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment {
|
||||
return drawTextInRect(rect, self.string, self.attributes, lineBreakMode, alignment, 0, NO);
|
||||
}
|
||||
|
||||
- (CGSize)drawInRect:(CGRect)rect withLineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UITextAlignment)alignment
|
||||
numberOfLines:(NSUInteger)numberOfLines {
|
||||
return drawTextInRect(rect, self.string, self.attributes, lineBreakMode, alignment, numberOfLines, NO);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation FontLabelStringDrawingHelper
|
||||
+ (CGSize)sizeWithZFont:(NSString*)string zfont:(ZFont *)font {
|
||||
CGSize size = drawOrSizeTextConstrainedToSize(NO, string, attributeRunForFont(font), CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX), 1,
|
||||
UILineBreakModeClip, UITextAlignmentLeft, YES);
|
||||
return CGSizeMake(ceilf(size.width), ceilf(size.height));
|
||||
}
|
||||
|
||||
+ (CGSize)drawInRect:(NSString*)string rect:(CGRect)rect withZFont:(ZFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode
|
||||
alignment:(UITextAlignment)alignment {
|
||||
return [string drawInRect:rect withZFont:font lineBreakMode:lineBreakMode alignment:alignment];
|
||||
}
|
||||
@end
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// FontManager.h
|
||||
// FontLabel
|
||||
//
|
||||
// Created by Kevin Ballard on 5/5/09.
|
||||
// Copyright © 2009 Zynga Game Networks
|
||||
//
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
@class ZFont;
|
||||
|
||||
@interface FontManager : NSObject {
|
||||
CFMutableDictionaryRef fonts;
|
||||
NSMutableDictionary *urls;
|
||||
}
|
||||
+ (FontManager *)sharedManager;
|
||||
/*!
|
||||
@method
|
||||
@abstract Loads a TTF font from the main bundle
|
||||
@param filename The name of the font file to load (with or without extension).
|
||||
@return YES if the font was loaded, NO if an error occurred
|
||||
@discussion If the font has already been loaded, this method does nothing and returns YES.
|
||||
This method first attempts to load the font by appending .ttf to the filename.
|
||||
If that file does not exist, it tries the filename exactly as given.
|
||||
*/
|
||||
- (BOOL)loadFont:(NSString *)filename;
|
||||
/*!
|
||||
@method
|
||||
@abstract Loads a font from the given file URL
|
||||
@param url A file URL that points to a font file
|
||||
@return YES if the font was loaded, NO if an error occurred
|
||||
@discussion If the font has already been loaded, this method does nothing and returns YES.
|
||||
*/
|
||||
- (BOOL)loadFontURL:(NSURL *)url;
|
||||
/*!
|
||||
@method
|
||||
@abstract Returns the loaded font with the given filename
|
||||
@param filename The name of the font file that was given to -loadFont:
|
||||
@return A CGFontRef, or NULL if the specified font cannot be found
|
||||
@discussion If the font has not been loaded yet, -loadFont: will be
|
||||
called with the given name first.
|
||||
*/
|
||||
- (CGFontRef)fontWithName:(NSString *)filename __AVAILABILITY_INTERNAL_DEPRECATED;
|
||||
/*!
|
||||
@method
|
||||
@abstract Returns a ZFont object corresponding to the loaded font with the given filename and point size
|
||||
@param filename The name of the font file that was given to -loadFont:
|
||||
@param pointSize The point size of the font
|
||||
@return A ZFont, or NULL if the specified font cannot be found
|
||||
@discussion If the font has not been loaded yet, -loadFont: will be
|
||||
called with the given name first.
|
||||
*/
|
||||
- (ZFont *)zFontWithName:(NSString *)filename pointSize:(CGFloat)pointSize;
|
||||
/*!
|
||||
@method
|
||||
@abstract Returns a ZFont object corresponding to the loaded font with the given file URL and point size
|
||||
@param url A file URL that points to a font file
|
||||
@param pointSize The point size of the font
|
||||
@return A ZFont, or NULL if the specified font cannot be loaded
|
||||
@discussion If the font has not been loaded yet, -loadFontURL: will be called with the given URL first.
|
||||
*/
|
||||
- (ZFont *)zFontWithURL:(NSURL *)url pointSize:(CGFloat)pointSize;
|
||||
/*!
|
||||
@method
|
||||
@abstract Returns a CFArrayRef of all loaded CGFont objects
|
||||
@return A CFArrayRef of all loaded CGFont objects
|
||||
@description You are responsible for releasing the CFArrayRef
|
||||
*/
|
||||
- (CFArrayRef)copyAllFonts;
|
||||
@end
|
|
@ -0,0 +1,123 @@
|
|||
//
|
||||
// FontManager.m
|
||||
// FontLabel
|
||||
//
|
||||
// Created by Kevin Ballard on 5/5/09.
|
||||
// Copyright © 2009 Zynga Game Networks
|
||||
//
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "FontManager.h"
|
||||
#import "ZFont.h"
|
||||
|
||||
static FontManager *sharedFontManager = nil;
|
||||
|
||||
@implementation FontManager
|
||||
+ (FontManager *)sharedManager {
|
||||
@synchronized(self) {
|
||||
if (sharedFontManager == nil) {
|
||||
sharedFontManager = [[self alloc] init];
|
||||
}
|
||||
}
|
||||
return sharedFontManager;
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
fonts = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
urls = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)loadFont:(NSString *)filename {
|
||||
NSString *fontPath = [[NSBundle mainBundle] pathForResource:filename ofType:@"ttf"];
|
||||
if (fontPath == nil) {
|
||||
fontPath = [[NSBundle mainBundle] pathForResource:filename ofType:nil];
|
||||
}
|
||||
if (fontPath == nil) return NO;
|
||||
|
||||
NSURL *url = [NSURL fileURLWithPath:fontPath];
|
||||
if ([self loadFontURL:url]) {
|
||||
[urls setObject:url forKey:filename];
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)loadFontURL:(NSURL *)url {
|
||||
CGDataProviderRef fontDataProvider = CGDataProviderCreateWithURL((CFURLRef)url);
|
||||
if (fontDataProvider == NULL) return NO;
|
||||
CGFontRef newFont = CGFontCreateWithDataProvider(fontDataProvider);
|
||||
CGDataProviderRelease(fontDataProvider);
|
||||
if (newFont == NULL) return NO;
|
||||
|
||||
CFDictionarySetValue(fonts, url, newFont);
|
||||
CGFontRelease(newFont);
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CGFontRef)fontWithName:(NSString *)filename {
|
||||
CGFontRef font = NULL;
|
||||
NSURL *url = [urls objectForKey:filename];
|
||||
if (url == nil && [self loadFont:filename]) {
|
||||
url = [urls objectForKey:filename];
|
||||
}
|
||||
if (url != nil) {
|
||||
font = (CGFontRef)CFDictionaryGetValue(fonts, url);
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
- (ZFont *)zFontWithName:(NSString *)filename pointSize:(CGFloat)pointSize {
|
||||
NSURL *url = [urls objectForKey:filename];
|
||||
if (url == nil && [self loadFont:filename]) {
|
||||
url = [urls objectForKey:filename];
|
||||
}
|
||||
if (url != nil) {
|
||||
CGFontRef cgFont = (CGFontRef)CFDictionaryGetValue(fonts, url);
|
||||
if (cgFont != NULL) {
|
||||
return [ZFont fontWithCGFont:cgFont size:pointSize];
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (ZFont *)zFontWithURL:(NSURL *)url pointSize:(CGFloat)pointSize {
|
||||
CGFontRef cgFont = (CGFontRef)CFDictionaryGetValue(fonts, url);
|
||||
if (cgFont == NULL && [self loadFontURL:url]) {
|
||||
cgFont = (CGFontRef)CFDictionaryGetValue(fonts, url);
|
||||
}
|
||||
if (cgFont != NULL) {
|
||||
return [ZFont fontWithCGFont:cgFont size:pointSize];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CFArrayRef)copyAllFonts {
|
||||
CFIndex count = CFDictionaryGetCount(fonts);
|
||||
CGFontRef *values = (CGFontRef *)malloc(sizeof(CGFontRef) * count);
|
||||
CFDictionaryGetKeysAndValues(fonts, NULL, (const void **)values);
|
||||
CFArrayRef array = CFArrayCreate(NULL, (const void **)values, count, &kCFTypeArrayCallBacks);
|
||||
free(values);
|
||||
return array;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
CFRelease(fonts);
|
||||
[urls release];
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// ZAttributedString.h
|
||||
// FontLabel
|
||||
//
|
||||
// Created by Kevin Ballard on 9/22/09.
|
||||
// Copyright 2009 Zynga Game Networks. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if NS_BLOCKS_AVAILABLE
|
||||
#define Z_BLOCKS 1
|
||||
#else
|
||||
// set this to 1 if you are using PLBlocks
|
||||
#define Z_BLOCKS 0
|
||||
#endif
|
||||
|
||||
#if Z_BLOCKS
|
||||
enum {
|
||||
ZAttributedStringEnumerationReverse = (1UL << 1),
|
||||
ZAttributedStringEnumerationLongestEffectiveRangeNotRequired = (1UL << 20)
|
||||
};
|
||||
typedef NSUInteger ZAttributedStringEnumerationOptions;
|
||||
#endif
|
||||
|
||||
@interface ZAttributedString : NSObject <NSCoding, NSCopying, NSMutableCopying> {
|
||||
NSMutableString *_buffer;
|
||||
NSMutableArray *_attributes;
|
||||
}
|
||||
@property (nonatomic, readonly) NSUInteger length;
|
||||
@property (nonatomic, readonly) NSString *string;
|
||||
- (id)initWithAttributedString:(ZAttributedString *)attr;
|
||||
- (id)initWithString:(NSString *)str;
|
||||
- (id)initWithString:(NSString *)str attributes:(NSDictionary *)attributes;
|
||||
- (id)attribute:(NSString *)attributeName atIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange;
|
||||
- (id)attribute:(NSString *)attributeName atIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange inRange:(NSRange)rangeLimit;
|
||||
- (ZAttributedString *)attributedSubstringFromRange:(NSRange)aRange;
|
||||
- (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange;
|
||||
- (NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange inRange:(NSRange)rangeLimit;
|
||||
#if Z_BLOCKS
|
||||
- (void)enumerateAttribute:(NSString *)attrName inRange:(NSRange)enumerationRange options:(ZAttributedStringEnumerationOptions)opts
|
||||
usingBlock:(void (^)(id value, NSRange range, BOOL *stop))block;
|
||||
- (void)enumerateAttributesInRange:(NSRange)enumerationRange options:(ZAttributedStringEnumerationOptions)opts
|
||||
usingBlock:(void (^)(NSDictionary *attrs, NSRange range, BOOL *stop))block;
|
||||
#endif
|
||||
- (BOOL)isEqualToAttributedString:(ZAttributedString *)otherString;
|
||||
@end
|
||||
|
||||
@interface ZMutableAttributedString : ZAttributedString {
|
||||
}
|
||||
- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range;
|
||||
- (void)addAttributes:(NSDictionary *)attributes range:(NSRange)range;
|
||||
- (void)appendAttributedString:(ZAttributedString *)str;
|
||||
- (void)deleteCharactersInRange:(NSRange)range;
|
||||
- (void)insertAttributedString:(ZAttributedString *)str atIndex:(NSUInteger)idx;
|
||||
- (void)removeAttribute:(NSString *)name range:(NSRange)range;
|
||||
- (void)replaceCharactersInRange:(NSRange)range withAttributedString:(ZAttributedString *)str;
|
||||
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str;
|
||||
- (void)setAttributedString:(ZAttributedString *)str;
|
||||
- (void)setAttributes:(NSDictionary *)attributes range:(NSRange)range;
|
||||
@end
|
||||
|
||||
extern NSString * const ZFontAttributeName;
|
||||
extern NSString * const ZForegroundColorAttributeName;
|
||||
extern NSString * const ZBackgroundColorAttributeName;
|
||||
extern NSString * const ZUnderlineStyleAttributeName;
|
||||
|
||||
enum {
|
||||
ZUnderlineStyleNone = 0x00,
|
||||
ZUnderlineStyleSingle = 0x01
|
||||
};
|
||||
#define ZUnderlineStyleMask 0x00FF
|
||||
|
||||
enum {
|
||||
ZUnderlinePatternSolid = 0x0000
|
||||
};
|
||||
#define ZUnderlinePatternMask 0xFF00
|
|
@ -0,0 +1,597 @@
|
|||
//
|
||||
// ZAttributedString.m
|
||||
// FontLabel
|
||||
//
|
||||
// Created by Kevin Ballard on 9/22/09.
|
||||
// Copyright 2009 Zynga Game Networks. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ZAttributedString.h"
|
||||
#import "ZAttributedStringPrivate.h"
|
||||
|
||||
@interface ZAttributedString ()
|
||||
- (NSUInteger)indexOfEffectiveAttributeRunForIndex:(NSUInteger)index;
|
||||
- (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange uniquingOnName:(NSString *)attributeName;
|
||||
- (NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange
|
||||
inRange:(NSRange)rangeLimit uniquingOnName:(NSString *)attributeName;
|
||||
@end
|
||||
|
||||
@interface ZAttributedString ()
|
||||
@property (nonatomic, readonly) NSArray *attributes;
|
||||
@end
|
||||
|
||||
@implementation ZAttributedString
|
||||
@synthesize string = _buffer;
|
||||
@synthesize attributes = _attributes;
|
||||
|
||||
- (id)initWithAttributedString:(ZAttributedString *)attr {
|
||||
NSParameterAssert(attr != nil);
|
||||
if ((self = [super init])) {
|
||||
_buffer = [attr->_buffer mutableCopy];
|
||||
_attributes = [[NSMutableArray alloc] initWithArray:attr->_attributes copyItems:YES];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithString:(NSString *)str {
|
||||
return [self initWithString:str attributes:nil];
|
||||
}
|
||||
|
||||
- (id)initWithString:(NSString *)str attributes:(NSDictionary *)attributes {
|
||||
if ((self = [super init])) {
|
||||
_buffer = [str mutableCopy];
|
||||
_attributes = [[NSMutableArray alloc] initWithObjects:[ZAttributeRun attributeRunWithIndex:0 attributes:attributes], nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
return [self initWithString:@"" attributes:nil];
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
if ((self = [super init])) {
|
||||
_buffer = [[decoder decodeObjectForKey:@"buffer"] mutableCopy];
|
||||
_attributes = [[decoder decodeObjectForKey:@"attributes"] mutableCopy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:_buffer forKey:@"buffer"];
|
||||
[aCoder encodeObject:_attributes forKey:@"attributes"];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
return [self retain];
|
||||
}
|
||||
|
||||
- (id)mutableCopyWithZone:(NSZone *)zone {
|
||||
return [(ZMutableAttributedString *)[ZMutableAttributedString allocWithZone:zone] initWithAttributedString:self];
|
||||
}
|
||||
|
||||
- (NSUInteger)length {
|
||||
return [_buffer length];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
NSMutableArray *components = [NSMutableArray arrayWithCapacity:[_attributes count]*2];
|
||||
NSRange range = NSMakeRange(0, 0);
|
||||
for (NSUInteger i = 0; i <= [_attributes count]; i++) {
|
||||
range.location = NSMaxRange(range);
|
||||
ZAttributeRun *run;
|
||||
if (i < [_attributes count]) {
|
||||
run = [_attributes objectAtIndex:i];
|
||||
range.length = run.index - range.location;
|
||||
} else {
|
||||
run = nil;
|
||||
range.length = [_buffer length] - range.location;
|
||||
}
|
||||
if (range.length > 0) {
|
||||
[components addObject:[NSString stringWithFormat:@"\"%@\"", [_buffer substringWithRange:range]]];
|
||||
}
|
||||
if (run != nil) {
|
||||
NSMutableArray *attrDesc = [NSMutableArray arrayWithCapacity:[run.attributes count]];
|
||||
for (id key in run.attributes) {
|
||||
[attrDesc addObject:[NSString stringWithFormat:@"%@: %@", key, [run.attributes objectForKey:key]]];
|
||||
}
|
||||
[components addObject:[NSString stringWithFormat:@"{%@}", [attrDesc componentsJoinedByString:@", "]]];
|
||||
}
|
||||
}
|
||||
return [NSString stringWithFormat:@"%@", [components componentsJoinedByString:@" "]];
|
||||
}
|
||||
|
||||
- (id)attribute:(NSString *)attributeName atIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange {
|
||||
NSParameterAssert(attributeName != nil);
|
||||
return [[self attributesAtIndex:index effectiveRange:aRange uniquingOnName:attributeName] objectForKey:attributeName];
|
||||
}
|
||||
|
||||
- (id)attribute:(NSString *)attributeName atIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange inRange:(NSRange)rangeLimit {
|
||||
NSParameterAssert(attributeName != nil);
|
||||
return [[self attributesAtIndex:index longestEffectiveRange:aRange inRange:rangeLimit uniquingOnName:attributeName] objectForKey:attributeName];
|
||||
}
|
||||
|
||||
- (ZAttributedString *)attributedSubstringFromRange:(NSRange)aRange {
|
||||
if (NSMaxRange(aRange) > [_buffer length]) {
|
||||
@throw [NSException exceptionWithName:NSRangeException reason:@"range was outisde of the attributed string" userInfo:nil];
|
||||
}
|
||||
ZMutableAttributedString *newStr = [self mutableCopy];
|
||||
if (aRange.location > 0) {
|
||||
[newStr deleteCharactersInRange:NSMakeRange(0, aRange.location)];
|
||||
}
|
||||
if (NSMaxRange(aRange) < [_buffer length]) {
|
||||
[newStr deleteCharactersInRange:NSMakeRange(aRange.length, [_buffer length] - NSMaxRange(aRange))];
|
||||
}
|
||||
return [newStr autorelease];
|
||||
}
|
||||
|
||||
- (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange {
|
||||
return [NSDictionary dictionaryWithDictionary:[self attributesAtIndex:index effectiveRange:aRange uniquingOnName:nil]];
|
||||
}
|
||||
|
||||
- (NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange inRange:(NSRange)rangeLimit {
|
||||
return [NSDictionary dictionaryWithDictionary:[self attributesAtIndex:index longestEffectiveRange:aRange inRange:rangeLimit uniquingOnName:nil]];
|
||||
}
|
||||
|
||||
#if Z_BLOCKS
|
||||
// Warning: this code has not been tested. The only guarantee is that it compiles.
|
||||
- (void)enumerateAttribute:(NSString *)attrName inRange:(NSRange)enumerationRange options:(ZAttributedStringEnumerationOptions)opts
|
||||
usingBlock:(void (^)(id, NSRange, BOOL*))block {
|
||||
if (opts & ZAttributedStringEnumerationLongestEffectiveRangeNotRequired) {
|
||||
[self enumerateAttributesInRange:enumerationRange options:opts usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
|
||||
id value = [attrs objectForKey:attrName];
|
||||
if (value != nil) {
|
||||
block(value, range, stop);
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
__block id oldValue = nil;
|
||||
__block NSRange effectiveRange = NSMakeRange(0, 0);
|
||||
[self enumerateAttributesInRange:enumerationRange options:opts usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
|
||||
id value = [attrs objectForKey:attrName];
|
||||
if (oldValue == nil) {
|
||||
oldValue = value;
|
||||
effectiveRange = range;
|
||||
} else if (value != nil && [oldValue isEqual:value]) {
|
||||
// combine the attributes
|
||||
effectiveRange = NSUnionRange(effectiveRange, range);
|
||||
} else {
|
||||
BOOL innerStop = NO;
|
||||
block(oldValue, effectiveRange, &innerStop);
|
||||
if (innerStop) {
|
||||
*stop = YES;
|
||||
oldValue = nil;
|
||||
} else {
|
||||
oldValue = value;
|
||||
}
|
||||
}
|
||||
}];
|
||||
if (oldValue != nil) {
|
||||
BOOL innerStop = NO; // necessary for the block, but unused
|
||||
block(oldValue, effectiveRange, &innerStop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)enumerateAttributesInRange:(NSRange)enumerationRange options:(ZAttributedStringEnumerationOptions)opts
|
||||
usingBlock:(void (^)(NSDictionary*, NSRange, BOOL*))block {
|
||||
// copy the attributes so we can mutate the string if necessary during enumeration
|
||||
// also clip the array during copy to only the subarray of attributes that cover the requested range
|
||||
NSArray *attrs;
|
||||
if (NSEqualRanges(enumerationRange, NSMakeRange(0, 0))) {
|
||||
attrs = [NSArray arrayWithArray:_attributes];
|
||||
} else {
|
||||
// in this binary search, last is the first run after the range
|
||||
NSUInteger first = 0, last = [_attributes count];
|
||||
while (last > first+1) {
|
||||
NSUInteger pivot = (last + first) / 2;
|
||||
ZAttributeRun *run = [_attributes objectAtIndex:pivot];
|
||||
if (run.index < enumerationRange.location) {
|
||||
first = pivot;
|
||||
} else if (run.index >= NSMaxRange(enumerationRange)) {
|
||||
last = pivot;
|
||||
}
|
||||
}
|
||||
attrs = [_attributes subarrayWithRange:NSMakeRange(first, last-first)];
|
||||
}
|
||||
if (opts & ZAttributedStringEnumerationReverse) {
|
||||
NSUInteger end = [_buffer length];
|
||||
for (ZAttributeRun *run in [attrs reverseObjectEnumerator]) {
|
||||
BOOL stop = NO;
|
||||
NSUInteger start = run.index;
|
||||
// clip to enumerationRange
|
||||
start = MAX(start, enumerationRange.location);
|
||||
end = MIN(end, NSMaxRange(enumerationRange));
|
||||
block(run.attributes, NSMakeRange(start, end - start), &stop);
|
||||
if (stop) break;
|
||||
end = run.index;
|
||||
}
|
||||
} else {
|
||||
NSUInteger start = 0;
|
||||
ZAttributeRun *run = [attrs objectAtIndex:0];
|
||||
NSInteger offset = 0;
|
||||
NSInteger oldLength = [_buffer length];
|
||||
for (NSUInteger i = 1;;i++) {
|
||||
NSUInteger end;
|
||||
if (i >= [attrs count]) {
|
||||
end = oldLength;
|
||||
} else {
|
||||
end = [[attrs objectAtIndex:i] index];
|
||||
}
|
||||
BOOL stop = NO;
|
||||
NSUInteger clippedStart = MAX(start, enumerationRange.location);
|
||||
NSUInteger clippedEnd = MIN(end, NSMaxRange(enumerationRange));
|
||||
block(run.attributes, NSMakeRange(clippedStart + offset, clippedEnd - start), &stop);
|
||||
if (stop || i >= [attrs count]) break;
|
||||
start = end;
|
||||
NSUInteger newLength = [_buffer length];
|
||||
offset += (newLength - oldLength);
|
||||
oldLength = newLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
- (BOOL)isEqualToAttributedString:(ZAttributedString *)otherString {
|
||||
return ([_buffer isEqualToString:otherString->_buffer] && [_attributes isEqualToArray:otherString->_attributes]);
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
return [object isKindOfClass:[ZAttributedString class]] && [self isEqualToAttributedString:(ZAttributedString *)object];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSUInteger)indexOfEffectiveAttributeRunForIndex:(NSUInteger)index {
|
||||
NSUInteger first = 0, last = [_attributes count];
|
||||
while (last > first + 1) {
|
||||
NSUInteger pivot = (last + first) / 2;
|
||||
ZAttributeRun *run = [_attributes objectAtIndex:pivot];
|
||||
if (run.index > index) {
|
||||
last = pivot;
|
||||
} else if (run.index < index) {
|
||||
first = pivot;
|
||||
} else {
|
||||
first = pivot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
- (NSDictionary *)attributesAtIndex:(NSUInteger)index effectiveRange:(NSRangePointer)aRange uniquingOnName:(NSString *)attributeName {
|
||||
if (index >= [_buffer length]) {
|
||||
@throw [NSException exceptionWithName:NSRangeException reason:@"index beyond range of attributed string" userInfo:nil];
|
||||
}
|
||||
NSUInteger runIndex = [self indexOfEffectiveAttributeRunForIndex:index];
|
||||
ZAttributeRun *run = [_attributes objectAtIndex:runIndex];
|
||||
if (aRange != NULL) {
|
||||
aRange->location = run.index;
|
||||
runIndex++;
|
||||
if (runIndex < [_attributes count]) {
|
||||
aRange->length = [[_attributes objectAtIndex:runIndex] index] - aRange->location;
|
||||
} else {
|
||||
aRange->length = [_buffer length] - aRange->location;
|
||||
}
|
||||
}
|
||||
return run.attributes;
|
||||
}
|
||||
- (NSDictionary *)attributesAtIndex:(NSUInteger)index longestEffectiveRange:(NSRangePointer)aRange
|
||||
inRange:(NSRange)rangeLimit uniquingOnName:(NSString *)attributeName {
|
||||
if (index >= [_buffer length]) {
|
||||
@throw [NSException exceptionWithName:NSRangeException reason:@"index beyond range of attributed string" userInfo:nil];
|
||||
} else if (NSMaxRange(rangeLimit) > [_buffer length]) {
|
||||
@throw [NSException exceptionWithName:NSRangeException reason:@"rangeLimit beyond range of attributed string" userInfo:nil];
|
||||
}
|
||||
NSUInteger runIndex = [self indexOfEffectiveAttributeRunForIndex:index];
|
||||
ZAttributeRun *run = [_attributes objectAtIndex:runIndex];
|
||||
if (aRange != NULL) {
|
||||
if (attributeName != nil) {
|
||||
id value = [run.attributes objectForKey:attributeName];
|
||||
NSUInteger endRunIndex = runIndex+1;
|
||||
runIndex--;
|
||||
// search backwards
|
||||
while (1) {
|
||||
if (run.index <= rangeLimit.location) {
|
||||
break;
|
||||
}
|
||||
ZAttributeRun *prevRun = [_attributes objectAtIndex:runIndex];
|
||||
id prevValue = [prevRun.attributes objectForKey:attributeName];
|
||||
if (prevValue == value || (value != nil && [prevValue isEqual:value])) {
|
||||
runIndex--;
|
||||
run = prevRun;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// search forwards
|
||||
ZAttributeRun *endRun = nil;
|
||||
while (endRunIndex < [_attributes count]) {
|
||||
ZAttributeRun *nextRun = [_attributes objectAtIndex:endRunIndex];
|
||||
if (nextRun.index >= NSMaxRange(rangeLimit)) {
|
||||
endRun = nextRun;
|
||||
break;
|
||||
}
|
||||
id nextValue = [nextRun.attributes objectForKey:attributeName];
|
||||
if (nextValue == value || (value != nil && [nextValue isEqual:value])) {
|
||||
endRunIndex++;
|
||||
} else {
|
||||
endRun = nextRun;
|
||||
break;
|
||||
}
|
||||
}
|
||||
aRange->location = MAX(run.index, rangeLimit.location);
|
||||
aRange->length = MIN((endRun ? endRun.index : [_buffer length]), NSMaxRange(rangeLimit)) - aRange->location;
|
||||
} else {
|
||||
// with no attribute name, we don't need to do any real searching,
|
||||
// as we already guarantee each run has unique attributes.
|
||||
// just make sure to clip the range to the rangeLimit
|
||||
aRange->location = MAX(run.index, rangeLimit.location);
|
||||
ZAttributeRun *endRun = (runIndex+1 < [_attributes count] ? [_attributes objectAtIndex:runIndex+1] : nil);
|
||||
aRange->length = MIN((endRun ? endRun.index : [_buffer length]), NSMaxRange(rangeLimit)) - aRange->location;
|
||||
}
|
||||
}
|
||||
return run.attributes;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_buffer release];
|
||||
[_attributes release];
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface ZMutableAttributedString ()
|
||||
- (void)cleanupAttributesInRange:(NSRange)range;
|
||||
- (NSRange)rangeOfAttributeRunsForRange:(NSRange)range;
|
||||
- (void)offsetRunsInRange:(NSRange )range byOffset:(NSInteger)offset;
|
||||
@end
|
||||
|
||||
@implementation ZMutableAttributedString
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
return [(ZAttributedString *)[ZAttributedString allocWithZone:zone] initWithAttributedString:self];
|
||||
}
|
||||
|
||||
- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range {
|
||||
range = [self rangeOfAttributeRunsForRange:range];
|
||||
for (ZAttributeRun *run in [_attributes subarrayWithRange:range]) {
|
||||
[run.attributes setObject:value forKey:name];
|
||||
}
|
||||
[self cleanupAttributesInRange:range];
|
||||
}
|
||||
|
||||
- (void)addAttributes:(NSDictionary *)attributes range:(NSRange)range {
|
||||
range = [self rangeOfAttributeRunsForRange:range];
|
||||
for (ZAttributeRun *run in [_attributes subarrayWithRange:range]) {
|
||||
[run.attributes addEntriesFromDictionary:attributes];
|
||||
}
|
||||
[self cleanupAttributesInRange:range];
|
||||
}
|
||||
|
||||
- (void)appendAttributedString:(ZAttributedString *)str {
|
||||
[self insertAttributedString:str atIndex:[_buffer length]];
|
||||
}
|
||||
|
||||
- (void)deleteCharactersInRange:(NSRange)range {
|
||||
NSRange runRange = [self rangeOfAttributeRunsForRange:range];
|
||||
[_buffer replaceCharactersInRange:range withString:@""];
|
||||
[_attributes removeObjectsInRange:runRange];
|
||||
for (NSUInteger i = runRange.location; i < [_attributes count]; i++) {
|
||||
ZAttributeRun *run = [_attributes objectAtIndex:i];
|
||||
ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:(run.index - range.length) attributes:run.attributes];
|
||||
[_attributes replaceObjectAtIndex:i withObject:newRun];
|
||||
[newRun release];
|
||||
}
|
||||
[self cleanupAttributesInRange:NSMakeRange(runRange.location, 0)];
|
||||
}
|
||||
|
||||
- (void)insertAttributedString:(ZAttributedString *)str atIndex:(NSUInteger)idx {
|
||||
[self replaceCharactersInRange:NSMakeRange(idx, 0) withAttributedString:str];
|
||||
}
|
||||
|
||||
- (void)removeAttribute:(NSString *)name range:(NSRange)range {
|
||||
range = [self rangeOfAttributeRunsForRange:range];
|
||||
for (ZAttributeRun *run in [_attributes subarrayWithRange:range]) {
|
||||
[run.attributes removeObjectForKey:name];
|
||||
}
|
||||
[self cleanupAttributesInRange:range];
|
||||
}
|
||||
|
||||
- (void)replaceCharactersInRange:(NSRange)range withAttributedString:(ZAttributedString *)str {
|
||||
NSRange replaceRange = [self rangeOfAttributeRunsForRange:range];
|
||||
NSInteger offset = [str->_buffer length] - range.length;
|
||||
[_buffer replaceCharactersInRange:range withString:str->_buffer];
|
||||
[_attributes replaceObjectsInRange:replaceRange withObjectsFromArray:str->_attributes];
|
||||
NSRange newRange = NSMakeRange(replaceRange.location, [str->_attributes count]);
|
||||
[self offsetRunsInRange:newRange byOffset:range.location];
|
||||
[self offsetRunsInRange:NSMakeRange(NSMaxRange(newRange), [_attributes count] - NSMaxRange(newRange)) byOffset:offset];
|
||||
[self cleanupAttributesInRange:NSMakeRange(newRange.location, 0)];
|
||||
[self cleanupAttributesInRange:NSMakeRange(NSMaxRange(newRange), 0)];
|
||||
}
|
||||
|
||||
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str {
|
||||
[self replaceCharactersInRange:range withAttributedString:[[[ZAttributedString alloc] initWithString:str] autorelease]];
|
||||
}
|
||||
|
||||
- (void)setAttributedString:(ZAttributedString *)str {
|
||||
[_buffer release], _buffer = [str->_buffer mutableCopy];
|
||||
[_attributes release], _attributes = [str->_attributes mutableCopy];
|
||||
}
|
||||
|
||||
- (void)setAttributes:(NSDictionary *)attributes range:(NSRange)range {
|
||||
range = [self rangeOfAttributeRunsForRange:range];
|
||||
for (ZAttributeRun *run in [_attributes subarrayWithRange:range]) {
|
||||
[run.attributes setDictionary:attributes];
|
||||
}
|
||||
[self cleanupAttributesInRange:range];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
// splits the existing runs to provide one or more new runs for the given range
|
||||
- (NSRange)rangeOfAttributeRunsForRange:(NSRange)range {
|
||||
NSParameterAssert(NSMaxRange(range) <= [_buffer length]);
|
||||
|
||||
// find (or create) the first run
|
||||
NSUInteger first = 0;
|
||||
ZAttributeRun *lastRun = nil;
|
||||
for (;;first++) {
|
||||
if (first >= [_attributes count]) {
|
||||
// we didn't find a run
|
||||
first = [_attributes count];
|
||||
ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:range.location attributes:lastRun.attributes];
|
||||
[_attributes addObject:newRun];
|
||||
[newRun release];
|
||||
break;
|
||||
}
|
||||
ZAttributeRun *run = [_attributes objectAtIndex:first];
|
||||
if (run.index == range.location) {
|
||||
break;
|
||||
} else if (run.index > range.location) {
|
||||
ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:range.location attributes:lastRun.attributes];
|
||||
[_attributes insertObject:newRun atIndex:first];
|
||||
[newRun release];
|
||||
break;
|
||||
}
|
||||
lastRun = run;
|
||||
}
|
||||
|
||||
if (((ZAttributeRun *)[_attributes lastObject]).index < NSMaxRange(range)) {
|
||||
NSRange subrange = NSMakeRange(first, [_attributes count] - first);
|
||||
if (NSMaxRange(range) < [_buffer length]) {
|
||||
ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:NSMaxRange(range)
|
||||
attributes:(NSDictionary*)[(ZAttributeRun *)[_attributes lastObject] attributes]];
|
||||
[_attributes addObject:newRun];
|
||||
[newRun release];
|
||||
}
|
||||
return subrange;
|
||||
} else {
|
||||
// find the last run within and the first run after the range
|
||||
NSUInteger lastIn = first, firstAfter = [_attributes count]-1;
|
||||
while (firstAfter > lastIn + 1) {
|
||||
NSUInteger idx = (firstAfter + lastIn) / 2;
|
||||
ZAttributeRun *run = [_attributes objectAtIndex:idx];
|
||||
if (run.index < range.location) {
|
||||
lastIn = idx;
|
||||
} else if (run.index > range.location) {
|
||||
firstAfter = idx;
|
||||
} else {
|
||||
// this is definitively the first run after the range
|
||||
firstAfter = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ([[_attributes objectAtIndex:firstAfter] index] > NSMaxRange(range)) {
|
||||
// the first after is too far after, insert another run!
|
||||
ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:NSMaxRange(range)
|
||||
attributes:[(ZAttributeRun *)[_attributes objectAtIndex:firstAfter-1] attributes]];
|
||||
[_attributes insertObject:newRun atIndex:firstAfter];
|
||||
[newRun release];
|
||||
}
|
||||
return NSMakeRange(lastIn, firstAfter - lastIn);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cleanupAttributesInRange:(NSRange)range {
|
||||
// expand the range to include one surrounding attribute on each side
|
||||
if (range.location > 0) {
|
||||
range.location -= 1;
|
||||
range.length += 1;
|
||||
}
|
||||
if (NSMaxRange(range) < [_attributes count]) {
|
||||
range.length += 1;
|
||||
} else {
|
||||
// make sure the range is capped to the attributes count
|
||||
range.length = [_attributes count] - range.location;
|
||||
}
|
||||
if (range.length == 0) return;
|
||||
ZAttributeRun *lastRun = [_attributes objectAtIndex:range.location];
|
||||
for (NSUInteger i = range.location+1; i < NSMaxRange(range);) {
|
||||
ZAttributeRun *run = [_attributes objectAtIndex:i];
|
||||
if ([lastRun.attributes isEqualToDictionary:run.attributes]) {
|
||||
[_attributes removeObjectAtIndex:i];
|
||||
range.length -= 1;
|
||||
} else {
|
||||
lastRun = run;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)offsetRunsInRange:(NSRange)range byOffset:(NSInteger)offset {
|
||||
for (NSUInteger i = range.location; i < NSMaxRange(range); i++) {
|
||||
ZAttributeRun *run = [_attributes objectAtIndex:i];
|
||||
ZAttributeRun *newRun = [[ZAttributeRun alloc] initWithIndex:run.index + offset attributes:run.attributes];
|
||||
[_attributes replaceObjectAtIndex:i withObject:newRun];
|
||||
[newRun release];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ZAttributeRun
|
||||
@synthesize index = _index;
|
||||
@synthesize attributes = _attributes;
|
||||
|
||||
+ (id)attributeRunWithIndex:(NSUInteger)idx attributes:(NSDictionary *)attrs {
|
||||
return [[[self alloc] initWithIndex:idx attributes:attrs] autorelease];
|
||||
}
|
||||
|
||||
- (id)initWithIndex:(NSUInteger)idx attributes:(NSDictionary *)attrs {
|
||||
NSParameterAssert(idx >= 0);
|
||||
if ((self = [super init])) {
|
||||
_index = idx;
|
||||
if (attrs == nil) {
|
||||
_attributes = [[NSMutableDictionary alloc] init];
|
||||
} else {
|
||||
_attributes = [attrs mutableCopy];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
if ((self = [super init])) {
|
||||
_index = [[decoder decodeObjectForKey:@"index"] unsignedIntegerValue];
|
||||
_attributes = [[decoder decodeObjectForKey:@"attributes"] mutableCopy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
return [self initWithIndex:0 attributes:[NSDictionary dictionary]];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
return [[ZAttributeRun allocWithZone:zone] initWithIndex:_index attributes:_attributes];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:[NSNumber numberWithUnsignedInteger:_index] forKey:@"index"];
|
||||
[aCoder encodeObject:_attributes forKey:@"attributes"];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
NSMutableArray *components = [NSMutableArray arrayWithCapacity:[_attributes count]];
|
||||
for (id key in _attributes) {
|
||||
[components addObject:[NSString stringWithFormat:@"%@=%@", key, [_attributes objectForKey:key]]];
|
||||
}
|
||||
return [NSString stringWithFormat:@"<%@: %p index=%lu attributes={%@}>",
|
||||
NSStringFromClass([self class]), self, (unsigned long)_index, [components componentsJoinedByString:@" "]];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
if (![object isKindOfClass:[ZAttributeRun class]]) return NO;
|
||||
ZAttributeRun *other = (ZAttributeRun *)object;
|
||||
return _index == other->_index && [_attributes isEqualToDictionary:other->_attributes];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_attributes release];
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
||||
|
||||
NSString * const ZFontAttributeName = @"ZFontAttributeName";
|
||||
NSString * const ZForegroundColorAttributeName = @"ZForegroundColorAttributeName";
|
||||
NSString * const ZBackgroundColorAttributeName = @"ZBackgroundColorAttributeName";
|
||||
NSString * const ZUnderlineStyleAttributeName = @"ZUnderlineStyleAttributeName";
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// ZAttributedStringPrivate.h
|
||||
// FontLabel
|
||||
//
|
||||
// Created by Kevin Ballard on 9/23/09.
|
||||
// Copyright 2009 Zynga Game Networks. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ZAttributedString.h"
|
||||
|
||||
@interface ZAttributeRun : NSObject <NSCopying, NSCoding> {
|
||||
NSUInteger _index;
|
||||
NSMutableDictionary *_attributes;
|
||||
}
|
||||
@property (nonatomic, readonly) NSUInteger index;
|
||||
@property (nonatomic, readonly) NSMutableDictionary *attributes;
|
||||
+ (id)attributeRunWithIndex:(NSUInteger)idx attributes:(NSDictionary *)attrs;
|
||||
- (id)initWithIndex:(NSUInteger)idx attributes:(NSDictionary *)attrs;
|
||||
@end
|
||||
|
||||
@interface ZAttributedString (ZAttributedStringPrivate)
|
||||
@property (nonatomic, readonly) NSArray *attributes;
|
||||
@end
|
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// ZFont.h
|
||||
// FontLabel
|
||||
//
|
||||
// Created by Kevin Ballard on 7/2/09.
|
||||
// Copyright © 2009 Zynga Game Networks
|
||||
//
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface ZFont : NSObject {
|
||||
CGFontRef _cgFont;
|
||||
CGFloat _pointSize;
|
||||
CGFloat _ratio;
|
||||
NSString *_familyName;
|
||||
NSString *_fontName;
|
||||
NSString *_postScriptName;
|
||||
}
|
||||
@property (nonatomic, readonly) CGFontRef cgFont;
|
||||
@property (nonatomic, readonly) CGFloat pointSize;
|
||||
@property (nonatomic, readonly) CGFloat ascender;
|
||||
@property (nonatomic, readonly) CGFloat descender;
|
||||
@property (nonatomic, readonly) CGFloat leading;
|
||||
@property (nonatomic, readonly) CGFloat xHeight;
|
||||
@property (nonatomic, readonly) CGFloat capHeight;
|
||||
@property (nonatomic, readonly) NSString *familyName;
|
||||
@property (nonatomic, readonly) NSString *fontName;
|
||||
@property (nonatomic, readonly) NSString *postScriptName;
|
||||
+ (ZFont *)fontWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize;
|
||||
+ (ZFont *)fontWithUIFont:(UIFont *)uiFont;
|
||||
- (id)initWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize;
|
||||
- (ZFont *)fontWithSize:(CGFloat)fontSize;
|
||||
@end
|
|
@ -0,0 +1,170 @@
|
|||
//
|
||||
// ZFont.m
|
||||
// FontLabel
|
||||
//
|
||||
// Created by Kevin Ballard on 7/2/09.
|
||||
// Copyright © 2009 Zynga Game Networks
|
||||
//
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#import "ZFont.h"
|
||||
|
||||
@interface ZFont ()
|
||||
@property (nonatomic, readonly) CGFloat ratio;
|
||||
- (NSString *)copyNameTableEntryForID:(UInt16)nameID;
|
||||
@end
|
||||
|
||||
@implementation ZFont
|
||||
@synthesize cgFont=_cgFont, pointSize=_pointSize, ratio=_ratio;
|
||||
|
||||
+ (ZFont *)fontWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize {
|
||||
return [[[self alloc] initWithCGFont:cgFont size:fontSize] autorelease];
|
||||
}
|
||||
|
||||
+ (ZFont *)fontWithUIFont:(UIFont *)uiFont {
|
||||
NSParameterAssert(uiFont != nil);
|
||||
CGFontRef cgFont = CGFontCreateWithFontName((CFStringRef)uiFont.fontName);
|
||||
ZFont *zFont = [[self alloc] initWithCGFont:cgFont size:uiFont.pointSize];
|
||||
CGFontRelease(cgFont);
|
||||
return [zFont autorelease];
|
||||
}
|
||||
|
||||
- (id)initWithCGFont:(CGFontRef)cgFont size:(CGFloat)fontSize {
|
||||
if ((self = [super init])) {
|
||||
_cgFont = CGFontRetain(cgFont);
|
||||
_pointSize = fontSize;
|
||||
_ratio = fontSize/CGFontGetUnitsPerEm(cgFont);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
NSAssert(NO, @"-init is not valid for ZFont");
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CGFloat)ascender {
|
||||
return ceilf(self.ratio * CGFontGetAscent(self.cgFont));
|
||||
}
|
||||
|
||||
- (CGFloat)descender {
|
||||
return floorf(self.ratio * CGFontGetDescent(self.cgFont));
|
||||
}
|
||||
|
||||
- (CGFloat)leading {
|
||||
return (self.ascender - self.descender);
|
||||
}
|
||||
|
||||
- (CGFloat)capHeight {
|
||||
return ceilf(self.ratio * CGFontGetCapHeight(self.cgFont));
|
||||
}
|
||||
|
||||
- (CGFloat)xHeight {
|
||||
return ceilf(self.ratio * CGFontGetXHeight(self.cgFont));
|
||||
}
|
||||
|
||||
- (NSString *)familyName {
|
||||
if (_familyName == nil) {
|
||||
_familyName = [self copyNameTableEntryForID:1];
|
||||
}
|
||||
return _familyName;
|
||||
}
|
||||
|
||||
- (NSString *)fontName {
|
||||
if (_fontName == nil) {
|
||||
_fontName = [self copyNameTableEntryForID:4];
|
||||
}
|
||||
return _fontName;
|
||||
}
|
||||
|
||||
- (NSString *)postScriptName {
|
||||
if (_postScriptName == nil) {
|
||||
_postScriptName = [self copyNameTableEntryForID:6];
|
||||
}
|
||||
return _postScriptName;
|
||||
}
|
||||
|
||||
- (ZFont *)fontWithSize:(CGFloat)fontSize {
|
||||
if (fontSize == self.pointSize) return self;
|
||||
NSParameterAssert(fontSize > 0.0);
|
||||
return [[[ZFont alloc] initWithCGFont:self.cgFont size:fontSize] autorelease];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
if (![object isKindOfClass:[ZFont class]]) return NO;
|
||||
ZFont *font = (ZFont *)object;
|
||||
return (font.cgFont == self.cgFont && font.pointSize == self.pointSize);
|
||||
}
|
||||
|
||||
- (NSString *)copyNameTableEntryForID:(UInt16)aNameID {
|
||||
CFDataRef nameTable = CGFontCopyTableForTag(self.cgFont, 'name');
|
||||
NSAssert1(nameTable != NULL, @"CGFontCopyTableForTag returned NULL for 'name' tag in font %@",
|
||||
[(id)CFCopyDescription(self.cgFont) autorelease]);
|
||||
const UInt8 * const bytes = CFDataGetBytePtr(nameTable);
|
||||
NSAssert1(OSReadBigInt16(bytes, 0) == 0, @"name table for font %@ has bad version number",
|
||||
[(id)CFCopyDescription(self.cgFont) autorelease]);
|
||||
const UInt16 count = OSReadBigInt16(bytes, 2);
|
||||
const UInt16 stringOffset = OSReadBigInt16(bytes, 4);
|
||||
const UInt8 * const nameRecords = &bytes[6];
|
||||
UInt16 nameLength = 0;
|
||||
UInt16 nameOffset = 0;
|
||||
NSStringEncoding encoding = 0;
|
||||
for (UInt16 idx = 0; idx < count; idx++) {
|
||||
const uintptr_t recordOffset = 12 * idx;
|
||||
const UInt16 nameID = OSReadBigInt16(nameRecords, recordOffset + 6);
|
||||
if (nameID != aNameID) continue;
|
||||
const UInt16 platformID = OSReadBigInt16(nameRecords, recordOffset + 0);
|
||||
const UInt16 platformSpecificID = OSReadBigInt16(nameRecords, recordOffset + 2);
|
||||
encoding = 0;
|
||||
// for now, we only support a subset of encodings
|
||||
switch (platformID) {
|
||||
case 0: // Unicode
|
||||
encoding = NSUTF16StringEncoding;
|
||||
break;
|
||||
case 1: // Macintosh
|
||||
switch (platformSpecificID) {
|
||||
case 0:
|
||||
encoding = NSMacOSRomanStringEncoding;
|
||||
break;
|
||||
}
|
||||
case 3: // Microsoft
|
||||
switch (platformSpecificID) {
|
||||
case 1:
|
||||
encoding = NSUTF16StringEncoding;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (encoding == 0) continue;
|
||||
nameLength = OSReadBigInt16(nameRecords, recordOffset + 8);
|
||||
nameOffset = OSReadBigInt16(nameRecords, recordOffset + 10);
|
||||
break;
|
||||
}
|
||||
NSString *result = nil;
|
||||
if (nameOffset > 0) {
|
||||
const UInt8 *nameBytes = &bytes[stringOffset + nameOffset];
|
||||
result = [[NSString alloc] initWithBytes:nameBytes length:nameLength encoding:encoding];
|
||||
}
|
||||
CFRelease(nameTable);
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
CGFontRelease(_cgFont);
|
||||
[_familyName release];
|
||||
[_fontName release];
|
||||
[_postScriptName release];
|
||||
[super dealloc];
|
||||
}
|
||||
@end
|
|
@ -148,18 +148,6 @@ void CCFileUtils::setResource(const char* pszZipFileName)
|
|||
CCAssert(0, "Have not implement!");
|
||||
}
|
||||
|
||||
const char* CCFileUtils::getResourcePath(void)
|
||||
{
|
||||
CCAssert(0, "Have not implement!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CCFileUtils::setRelativePath(const char* pszRelativePath)
|
||||
{
|
||||
CC_UNUSED_PARAM(pszRelativePath);
|
||||
CCAssert(0, "Have not implement!");
|
||||
}
|
||||
|
||||
string CCFileUtils::getWriteablePath()
|
||||
{
|
||||
// return the path that the exe file saved in
|
||||
|
|
|
@ -34,7 +34,9 @@ public:
|
|||
: m_hDC(NULL)
|
||||
, m_hBmp(NULL)
|
||||
, m_hFont((HFONT)GetStockObject(DEFAULT_GUI_FONT))
|
||||
, m_hWnd(NULL)
|
||||
{
|
||||
m_hWnd = hWnd;
|
||||
HDC hdc = GetDC(hWnd);
|
||||
m_hDC = CreateCompatibleDC(hdc);
|
||||
ReleaseDC(hWnd, hdc);
|
||||
|
@ -53,6 +55,39 @@ public:
|
|||
DeleteObject(m_hFont);
|
||||
m_hFont = hDefFont;
|
||||
}
|
||||
// release temp font resource
|
||||
if (m_curFontPath.size() > 0)
|
||||
{
|
||||
wchar_t * pwszBuffer = utf8ToUtf16(m_curFontPath);
|
||||
if (pwszBuffer)
|
||||
{
|
||||
RemoveFontResource(pwszBuffer);
|
||||
SendMessage( m_hWnd, WM_FONTCHANGE, 0, 0);
|
||||
delete [] pwszBuffer;
|
||||
pwszBuffer = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t * utf8ToUtf16(std::string nString)
|
||||
{
|
||||
wchar_t * pwszBuffer = NULL;
|
||||
do
|
||||
{
|
||||
if (nString.size() < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// utf-8 to utf-16
|
||||
int nLen = nString.size();
|
||||
int nBufLen = nLen + 1;
|
||||
pwszBuffer = new wchar_t[nBufLen];
|
||||
CC_BREAK_IF(! pwszBuffer);
|
||||
memset(pwszBuffer,0,nBufLen);
|
||||
nLen = MultiByteToWideChar(CP_UTF8, 0, nString.c_str(), nLen, pwszBuffer, nBufLen);
|
||||
} while (0);
|
||||
return pwszBuffer;
|
||||
|
||||
}
|
||||
|
||||
bool setFont(const char * pFontName = NULL, int nSize = 0)
|
||||
|
@ -60,13 +95,27 @@ public:
|
|||
bool bRet = false;
|
||||
do
|
||||
{
|
||||
std::string fontName = pFontName;
|
||||
std::string fontPath;
|
||||
HFONT hDefFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
|
||||
LOGFONTA tNewFont = {0};
|
||||
LOGFONTA tOldFont = {0};
|
||||
GetObjectA(hDefFont, sizeof(tNewFont), &tNewFont);
|
||||
if (pFontName)
|
||||
if (fontName.c_str())
|
||||
{
|
||||
strcpy_s(tNewFont.lfFaceName, LF_FACESIZE, pFontName);
|
||||
// create font from ttf file
|
||||
int nFindttf = fontName.find(".ttf");
|
||||
int nFindTTF = fontName.find(".TTF");
|
||||
if (nFindttf >= 0 || nFindTTF >= 0)
|
||||
{
|
||||
fontPath = CCFileUtils::fullPathFromRelativePath(fontName.c_str());
|
||||
int nFindPos = fontName.rfind("/");
|
||||
fontName = &fontName[nFindPos+1];
|
||||
nFindPos = fontName.rfind(".");
|
||||
fontName = fontName.substr(0,nFindPos);
|
||||
}
|
||||
tNewFont.lfCharSet = DEFAULT_CHARSET;
|
||||
strcpy_s(tNewFont.lfFaceName, LF_FACESIZE, fontName.c_str());
|
||||
}
|
||||
if (nSize)
|
||||
{
|
||||
|
@ -86,6 +135,31 @@ public:
|
|||
if (m_hFont != hDefFont)
|
||||
{
|
||||
DeleteObject(m_hFont);
|
||||
// release old font register
|
||||
if (m_curFontPath.size() > 0)
|
||||
{
|
||||
wchar_t * pwszBuffer = utf8ToUtf16(m_curFontPath);
|
||||
if (pwszBuffer)
|
||||
{
|
||||
RemoveFontResource(pwszBuffer);
|
||||
SendMessage( m_hWnd, WM_FONTCHANGE, 0, 0);
|
||||
delete [] pwszBuffer;
|
||||
pwszBuffer = NULL;
|
||||
}
|
||||
}
|
||||
fontPath.size()>0?(m_curFontPath = fontPath):(m_curFontPath.clear());
|
||||
// register temp font
|
||||
if (m_curFontPath.size() > 0)
|
||||
{
|
||||
wchar_t * pwszBuffer = utf8ToUtf16(m_curFontPath);
|
||||
if (pwszBuffer)
|
||||
{
|
||||
AddFontResource(pwszBuffer);
|
||||
SendMessage( m_hWnd, WM_FONTCHANGE, 0, 0);
|
||||
delete [] pwszBuffer;
|
||||
pwszBuffer = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_hFont = NULL;
|
||||
|
||||
|
@ -267,6 +341,8 @@ public:
|
|||
private:
|
||||
friend class CCImage;
|
||||
HFONT m_hFont;
|
||||
HWND m_hWnd;
|
||||
std::string m_curFontPath;
|
||||
};
|
||||
|
||||
static BitmapDC& sharedBitmapDC()
|
||||
|
|
|
@ -247,17 +247,6 @@ void CCFileUtils::setResourcePath(const char *pszResourcePath)
|
|||
CCAssert(0, "Have not implement!");
|
||||
}
|
||||
|
||||
const char* CCFileUtils::getResourcePath(void)
|
||||
{
|
||||
CCAssert(0, "Have not implement!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CCFileUtils::setRelativePath(const char* pszRelativePath)
|
||||
{
|
||||
CCAssert(0, "Have not implement!");
|
||||
}
|
||||
|
||||
string CCFileUtils::getWriteablePath()
|
||||
{
|
||||
return string(CCApplication::sharedApplication().getAppWritablePath());
|
||||
|
|
|
@ -24,6 +24,7 @@ THE SOFTWARE.
|
|||
|
||||
#include "TG3.h"
|
||||
#include <string>
|
||||
#include "CCApplication.h"
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
|
@ -35,6 +36,7 @@ public:
|
|||
BitmapDC()
|
||||
: m_pBmp(NULL)
|
||||
, m_pMemWnd(NULL)
|
||||
, m_pFont(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -42,16 +44,59 @@ public:
|
|||
~BitmapDC(void)
|
||||
{
|
||||
prepareBitmap(0, 0);
|
||||
if (m_pFont)
|
||||
{
|
||||
delete m_pFont;
|
||||
m_pFont = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool setFont(const char * pFontName = NULL, int nSize = 0)
|
||||
{
|
||||
bool bRet = false;
|
||||
TFont * pNewFont = new TFont;
|
||||
do
|
||||
{
|
||||
CC_BREAK_IF(! m_hFont.Create(0, (Int32)nSize));
|
||||
if (NULL == pFontName)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
TUChar szFullPath[MAX_PATH] = {0};
|
||||
std::string fullpath;
|
||||
#ifdef _TRANZDA_VM_
|
||||
fullpath = pFontName;
|
||||
CCLog("++fullpath %s",fullpath.c_str());
|
||||
fullpath = CCFileUtils::fullPathFromRelativePath(fullpath.c_str());
|
||||
CCLog("--fullpath %s",fullpath.c_str());
|
||||
fullpath = &fullpath.c_str()[strlen("D:/Work7")];
|
||||
#else
|
||||
fullpath = CCApplication::sharedApplication().getAppDataPath();
|
||||
fullpath += pFontName;
|
||||
#endif
|
||||
TUString::StrGBToUnicode(szFullPath,(const Char*)fullpath.c_str());
|
||||
CCLog("path %s,++pNewFont->Create",fullpath.c_str());
|
||||
CC_BREAK_IF(! pNewFont->Create(szFullPath,0, (Int32)nSize,0,NULL));
|
||||
CCLog("path %s,--pNewFont->Create",fullpath.c_str());
|
||||
bRet = true;
|
||||
} while (0);
|
||||
// create default font
|
||||
if (!bRet &&
|
||||
pNewFont->Create(0, (Int32)nSize))
|
||||
{
|
||||
bRet = true;
|
||||
}
|
||||
// delete old font
|
||||
if (bRet)
|
||||
{
|
||||
if (m_pFont)
|
||||
{
|
||||
delete m_pFont;
|
||||
m_pFont = NULL;
|
||||
}
|
||||
m_pFont = pNewFont;
|
||||
}
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
|
@ -96,7 +141,7 @@ public:
|
|||
}
|
||||
|
||||
// calculate the width of current line and update the window width
|
||||
int nTempWidth = m_hFont.CharsWidth(strLine.c_str(), strLine.length() + 1);
|
||||
int nTempWidth = m_pFont->CharsWidth(strLine.c_str(), strLine.length() + 1);
|
||||
if (nTempWidth >= nWinWidth)
|
||||
{
|
||||
nWinWidth = nTempWidth;
|
||||
|
@ -115,14 +160,14 @@ public:
|
|||
int nCurPos = 0;
|
||||
do
|
||||
{
|
||||
nCurPos = m_hFont.WordWrap(strLeft.c_str(), nWinWidth);
|
||||
nCurPos = m_pFont->WordWrap(strLeft.c_str(), nWinWidth);
|
||||
strLeft = strLeft.substr(nCurPos);
|
||||
++nLineCount;
|
||||
} while (strLeft.length() > 0);
|
||||
}
|
||||
|
||||
// calculate the window height.
|
||||
tSize.SetHeight(nLineCount * m_hFont.LineHeight());
|
||||
tSize.SetHeight(nLineCount * m_pFont->LineHeight());
|
||||
tSize.SetWidth(nWinWidth);
|
||||
|
||||
bRet = true;
|
||||
|
@ -205,7 +250,7 @@ public:
|
|||
m_pMemWnd->GetMemWindowTBitmapPtr()->Fill32(RGBA(0, 0, 0, 0), 0, 0, nWidth, nHeight);
|
||||
|
||||
TRectangle rect(0, 0, nWidth, nHeight);
|
||||
dc.DrawTextInRectangleEx(pszText, 0, RGBA(255,255,255,255), RGBA(0,0,0,255), m_hFont, &rect, style);
|
||||
dc.DrawTextInRectangleEx(pszText, 0, RGBA(255,255,255,255), RGBA(0,0,0,255), *m_pFont, &rect, style);
|
||||
|
||||
dc.ReadBitmap(m_pBmp, 0, 0);
|
||||
|
||||
|
@ -217,7 +262,7 @@ public:
|
|||
CC_SYNTHESIZE_READONLY(TBitmap*, m_pBmp, Bitmap);
|
||||
|
||||
private:
|
||||
TFont m_hFont;
|
||||
TFont * m_pFont;
|
||||
TWindow * m_pMemWnd;
|
||||
};
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ OBJECTS = \
|
|||
$(OBJECTS_DIR)/CCAccelerometer_wophone.o \
|
||||
$(OBJECTS_DIR)/CCApplication_wophone.o \
|
||||
$(OBJECTS_DIR)/CCEGLView_wophone.o \
|
||||
$(OBJECTS_DIR)/CCScriptSupport.o \
|
||||
$(OBJECTS_DIR)/CCAnimation.o \
|
||||
$(OBJECTS_DIR)/CCAnimationCache.o \
|
||||
$(OBJECTS_DIR)/CCSprite.o \
|
||||
|
@ -115,6 +116,7 @@ OBJECTS = \
|
|||
$(OBJECTS_DIR)/CCTexture2D.o \
|
||||
$(OBJECTS_DIR)/CCTextureAtlas.o \
|
||||
$(OBJECTS_DIR)/CCTextureCache.o \
|
||||
$(OBJECTS_DIR)/CCTexturePVR.o \
|
||||
$(OBJECTS_DIR)/CCParallaxNode.o \
|
||||
$(OBJECTS_DIR)/CCTileMapAtlas.o \
|
||||
$(OBJECTS_DIR)/CCTMXLayer.o \
|
||||
|
@ -122,8 +124,7 @@ OBJECTS = \
|
|||
$(OBJECTS_DIR)/CCTMXTiledMap.o \
|
||||
$(OBJECTS_DIR)/CCTMXXMLParser.o \
|
||||
$(OBJECTS_DIR)/CCTouchDispatcher.o \
|
||||
$(OBJECTS_DIR)/CCTouchHandler.o \
|
||||
$(OBJECTS_DIR)/CCScriptSupport.o
|
||||
$(OBJECTS_DIR)/CCTouchHandler.o
|
||||
|
||||
ADD_OBJECTS +=
|
||||
|
||||
|
@ -325,6 +326,9 @@ $(OBJECTS_DIR)/CCApplication_wophone.o : ../platform/wophone/CCApplication_wopho
|
|||
$(OBJECTS_DIR)/CCEGLView_wophone.o : ../platform/wophone/CCEGLView_wophone.cpp
|
||||
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCEGLView_wophone.o ../platform/wophone/CCEGLView_wophone.cpp
|
||||
|
||||
$(OBJECTS_DIR)/CCScriptSupport.o : ../script_support/CCScriptSupport.cpp
|
||||
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCScriptSupport.o ../script_support/CCScriptSupport.cpp
|
||||
|
||||
$(OBJECTS_DIR)/CCAnimation.o : ../sprite_nodes/CCAnimation.cpp
|
||||
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCAnimation.o ../sprite_nodes/CCAnimation.cpp
|
||||
|
||||
|
@ -391,6 +395,9 @@ $(OBJECTS_DIR)/CCTextureAtlas.o : ../textures/CCTextureAtlas.cpp
|
|||
$(OBJECTS_DIR)/CCTextureCache.o : ../textures/CCTextureCache.cpp
|
||||
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCTextureCache.o ../textures/CCTextureCache.cpp
|
||||
|
||||
$(OBJECTS_DIR)/CCTexturePVR.o : ../textures/CCTexturePVR.cpp
|
||||
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCTexturePVR.o ../textures/CCTexturePVR.cpp
|
||||
|
||||
$(OBJECTS_DIR)/CCParallaxNode.o : ../tileMap_parallax_nodes/CCParallaxNode.cpp
|
||||
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCParallaxNode.o ../tileMap_parallax_nodes/CCParallaxNode.cpp
|
||||
|
||||
|
@ -415,5 +422,3 @@ $(OBJECTS_DIR)/CCTouchDispatcher.o : ../touch_dispatcher/CCTouchDispatcher.cpp
|
|||
$(OBJECTS_DIR)/CCTouchHandler.o : ../touch_dispatcher/CCTouchHandler.cpp
|
||||
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCTouchHandler.o ../touch_dispatcher/CCTouchHandler.cpp
|
||||
|
||||
$(OBJECTS_DIR)/CCScriptSupport.o : ../script_support/CCScriptSupport.cpp
|
||||
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCScriptSupport.o ../script_support/CCScriptSupport.cpp
|
||||
|
|
|
@ -65,42 +65,6 @@ namespace cocos2d
|
|||
return pAnimation;
|
||||
}
|
||||
|
||||
CCAnimation* CCAnimation::animationWithName(const char *pszName)
|
||||
{
|
||||
CCAnimation *pAnimation = new CCAnimation();
|
||||
pAnimation->initWithName(pszName);
|
||||
pAnimation->autorelease();
|
||||
|
||||
return pAnimation;
|
||||
}
|
||||
|
||||
CCAnimation* CCAnimation::animationWithName(const char *pszName, CCMutableArray<CCSpriteFrame*> *pFrames)
|
||||
{
|
||||
CCAnimation *pAnimation = new CCAnimation();
|
||||
pAnimation->initWithName(pszName, pFrames);
|
||||
pAnimation->autorelease();
|
||||
|
||||
return pAnimation;
|
||||
}
|
||||
|
||||
CCAnimation* CCAnimation::animationWithName(const char *pszName, float fDelay, CCMutableArray<CCSpriteFrame*> *pFrames)
|
||||
{
|
||||
CCAnimation *pAnimation = new CCAnimation();
|
||||
pAnimation->initWithName(pszName, fDelay, pFrames);
|
||||
pAnimation->autorelease();
|
||||
|
||||
return pAnimation;
|
||||
}
|
||||
|
||||
CCAnimation* CCAnimation::animationWithName(const char *pszName, float fDelay)
|
||||
{
|
||||
CCAnimation *pAnimation = new CCAnimation();
|
||||
pAnimation->initWithName(pszName, fDelay);
|
||||
pAnimation->autorelease();
|
||||
|
||||
return pAnimation;
|
||||
}
|
||||
|
||||
bool CCAnimation::initWithFrames(CCMutableArray<CCSpriteFrame*> *pFrames, float delay)
|
||||
{
|
||||
m_fDelay = delay;
|
||||
|
@ -115,31 +79,6 @@ namespace cocos2d
|
|||
return initWithFrames(pFrames, 0);
|
||||
}
|
||||
|
||||
bool CCAnimation::initWithName(const char *pszName)
|
||||
{
|
||||
return initWithName(pszName, 0, NULL);
|
||||
}
|
||||
|
||||
bool CCAnimation::initWithName(const char *pszName, float fDelay)
|
||||
{
|
||||
return initWithName(pszName, fDelay, NULL);
|
||||
}
|
||||
|
||||
bool CCAnimation::initWithName(const char *pszName, CCMutableArray<CCSpriteFrame*> *pFrames)
|
||||
{
|
||||
return initWithName(pszName, 0, pFrames);
|
||||
}
|
||||
|
||||
bool CCAnimation::initWithName(const char *pszName, float fDelay, CCMutableArray<CCSpriteFrame*> *pFrames)
|
||||
{
|
||||
m_fDelay = fDelay;
|
||||
m_nameStr = pszName;
|
||||
m_pobFrames = CCMutableArray<CCSpriteFrame*>::arrayWithArray(pFrames);
|
||||
m_pobFrames->retain();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CCAnimation::~CCAnimation(void)
|
||||
{
|
||||
CCLOGINFO("cocos2d, deallocing %p", this);
|
||||
|
|
|
@ -195,11 +195,8 @@ bool CCSprite::init(void)
|
|||
|
||||
m_bFlipX = m_bFlipY = false;
|
||||
|
||||
// lazy alloc
|
||||
m_pAnimations = NULL;
|
||||
|
||||
// default transform anchor: center
|
||||
m_tAnchorPoint = ccp(0.5f, 0.5f);
|
||||
setAnchorPoint(ccp(0.5f, 0.5f));
|
||||
|
||||
// zwoptex default values
|
||||
m_obOffsetPositionInPixels = CCPointZero;
|
||||
|
@ -332,7 +329,6 @@ CCSprite::CCSprite()
|
|||
CCSprite::~CCSprite(void)
|
||||
{
|
||||
CC_SAFE_RELEASE(m_pobTexture);
|
||||
CC_SAFE_RELEASE(m_pAnimations);
|
||||
}
|
||||
|
||||
void CCSprite::useSelfRender(void)
|
||||
|
@ -360,11 +356,6 @@ void CCSprite::useBatchNode(CCSpriteBatchNode *batchNode)
|
|||
m_pobBatchNode = batchNode;
|
||||
}
|
||||
|
||||
void CCSprite::initAnimationDictionary(void)
|
||||
{
|
||||
m_pAnimations = new CCMutableDictionary<string, CCAnimation*>();
|
||||
}
|
||||
|
||||
void CCSprite::setTextureRect(CCRect rect)
|
||||
{
|
||||
CCRect rectInPixels = CC_RECT_POINTS_TO_PIXELS(rect);
|
||||
|
@ -1039,22 +1030,6 @@ void CCSprite::setDisplayFrame(CCSpriteFrame *pNewFrame)
|
|||
setTextureRectInPixels(pNewFrame->getRectInPixels(), pNewFrame->isRotated(), pNewFrame->getOriginalSizeInPixels());
|
||||
}
|
||||
|
||||
// XXX deprecated
|
||||
void CCSprite::setDisplayFrame(const char *pszAnimationName, int nFrameIndex)
|
||||
{
|
||||
if (! m_pAnimations)
|
||||
{
|
||||
initAnimationDictionary();
|
||||
}
|
||||
|
||||
CCAnimation *pAnimation = m_pAnimations->objectForKey(std::string(pszAnimationName));
|
||||
CCSpriteFrame *pFrame = pAnimation->getFrames()->getObjectAtIndex(nFrameIndex);
|
||||
|
||||
assert(pFrame);
|
||||
|
||||
setDisplayFrame(pFrame);
|
||||
}
|
||||
|
||||
void CCSprite::setDisplayFrameWithAnimationName(const char *animationName, int frameIndex)
|
||||
{
|
||||
assert(animationName);
|
||||
|
@ -1087,24 +1062,6 @@ CCSpriteFrame* CCSprite::displayedFrame(void)
|
|||
m_tContentSizeInPixels);
|
||||
}
|
||||
|
||||
void CCSprite::addAnimation(CCAnimation *pAnimation)
|
||||
{
|
||||
// lazy alloc
|
||||
if (! m_pAnimations)
|
||||
{
|
||||
initAnimationDictionary();
|
||||
}
|
||||
|
||||
m_pAnimations->setObject(pAnimation, pAnimation->getName());
|
||||
}
|
||||
|
||||
CCAnimation* CCSprite::animationByName(const char *pszAnimationName)
|
||||
{
|
||||
assert(pszAnimationName != NULL);
|
||||
|
||||
return m_pAnimations->objectForKey(std::string(pszAnimationName));
|
||||
}
|
||||
|
||||
// Texture protocol
|
||||
|
||||
void CCSprite::updateBlendFunc(void)
|
||||
|
|
|
@ -48,11 +48,6 @@ namespace cocos2d
|
|||
return batchNode;
|
||||
}
|
||||
|
||||
CCSpriteBatchNode* CCSpriteBatchNode::spriteSheetWithTexture(cocos2d::CCTexture2D *tex)
|
||||
{
|
||||
return batchNodeWithTexture(tex);
|
||||
}
|
||||
|
||||
CCSpriteBatchNode* CCSpriteBatchNode::batchNodeWithTexture(CCTexture2D* tex, unsigned int capacity)
|
||||
{
|
||||
CCSpriteBatchNode *batchNode = new CCSpriteBatchNode();
|
||||
|
@ -62,11 +57,6 @@ namespace cocos2d
|
|||
return batchNode;
|
||||
}
|
||||
|
||||
CCSpriteBatchNode* CCSpriteBatchNode::spriteSheetWithTexture(CCTexture2D *tex, unsigned int capacity)
|
||||
{
|
||||
return batchNodeWithTexture(tex, capacity);
|
||||
}
|
||||
|
||||
/*
|
||||
* creation with File Image
|
||||
*/
|
||||
|
@ -79,11 +69,6 @@ namespace cocos2d
|
|||
return batchNode;
|
||||
}
|
||||
|
||||
CCSpriteBatchNode* CCSpriteBatchNode::spriteSheetWithFile(const char *fileImage, unsigned int capacity)
|
||||
{
|
||||
return batchNodeWithFile(fileImage, capacity);
|
||||
}
|
||||
|
||||
CCSpriteBatchNode* CCSpriteBatchNode::batchNodeWithFile(const char *fileImage)
|
||||
{
|
||||
CCSpriteBatchNode *batchNode = new CCSpriteBatchNode();
|
||||
|
@ -93,11 +78,6 @@ namespace cocos2d
|
|||
return batchNode;
|
||||
}
|
||||
|
||||
CCSpriteBatchNode* CCSpriteBatchNode::spriteSheetWithFile(const char *fileImage)
|
||||
{
|
||||
return batchNodeWithFile(fileImage);
|
||||
}
|
||||
|
||||
/*
|
||||
* init with CCTexture2D
|
||||
*/
|
||||
|
@ -170,25 +150,6 @@ namespace cocos2d
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
// xxx deprecated
|
||||
CCSprite* CCSpriteBatchNode::createSpriteWithRect(CCRect rect)
|
||||
{
|
||||
CCSprite *pSprite = CCSprite::spriteWithTexture(m_pobTextureAtlas->getTexture(), rect);
|
||||
pSprite->useBatchNode(this);
|
||||
|
||||
return pSprite;
|
||||
}
|
||||
|
||||
// XXX deprecated
|
||||
void CCSpriteBatchNode::initSprite(cocos2d::CCSprite *sprite, cocos2d::CCRect rect)
|
||||
{
|
||||
if (sprite)
|
||||
{
|
||||
sprite->initWithTexture(m_pobTextureAtlas->getTexture(), rect);
|
||||
sprite->useBatchNode(this);
|
||||
}
|
||||
}
|
||||
|
||||
void CCSpriteBatchNode::addChild(CCNode *child, int zOrder, int tag)
|
||||
{
|
||||
assert(child != NULL);
|
||||
|
@ -266,7 +227,7 @@ namespace cocos2d
|
|||
CCSprite* pChild = (CCSprite*) pObject;
|
||||
if (pChild)
|
||||
{
|
||||
pChild->useSelfRender();
|
||||
removeSpriteFromAtlas(pChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -388,11 +388,6 @@ CCSpriteFrame* CCSpriteFrameCache::spriteFrameByName(const char *pszName)
|
|||
return frame;
|
||||
}
|
||||
|
||||
CCSprite* CCSpriteFrameCache::createSpriteWithFrameName(const char *pszName)
|
||||
{
|
||||
CCSpriteFrame *frame = m_pSpriteFrames->objectForKey(std::string(pszName));
|
||||
return CCSprite::spriteWithSpriteFrame(frame);
|
||||
}
|
||||
const char * CCSpriteFrameCache::valueForKey(const char *key, CCDictionary<std::string, CCObject*> *dict)
|
||||
{
|
||||
if (dict)
|
||||
|
|
|
@ -148,26 +148,24 @@ void CCUserDefault::purgeSharedUserDefault()
|
|||
m_spUserDefault = NULL;
|
||||
}
|
||||
|
||||
bool CCUserDefault::getBoolForKey(const char* pKey)
|
||||
bool CCUserDefault::getBoolForKey(const char* pKey, bool defaultValue)
|
||||
{
|
||||
const char* value = getValueForKey(pKey);
|
||||
bool ret = false;
|
||||
bool ret = defaultValue;
|
||||
|
||||
if (value)
|
||||
{
|
||||
if (! strcmp(value, "true"))
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
ret = (! strcmp(value, "true"));
|
||||
xmlFree((void*)value);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CCUserDefault::getIntegerForKey(const char* pKey)
|
||||
int CCUserDefault::getIntegerForKey(const char* pKey, int defaultValue)
|
||||
{
|
||||
const char* value = getValueForKey(pKey);
|
||||
int ret = 0;
|
||||
int ret = defaultValue;
|
||||
|
||||
if (value)
|
||||
{
|
||||
|
@ -178,17 +176,17 @@ int CCUserDefault::getIntegerForKey(const char* pKey)
|
|||
return ret;
|
||||
}
|
||||
|
||||
float CCUserDefault::getFloatForKey(const char* pKey)
|
||||
float CCUserDefault::getFloatForKey(const char* pKey, float defaultValue)
|
||||
{
|
||||
float ret = (float)getDoubleForKey(pKey);
|
||||
float ret = (float)getDoubleForKey(pKey, (double)defaultValue);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
double CCUserDefault::getDoubleForKey(const char* pKey)
|
||||
double CCUserDefault::getDoubleForKey(const char* pKey, double defaultValue)
|
||||
{
|
||||
const char* value = getValueForKey(pKey);
|
||||
double ret = 0.0;
|
||||
double ret = defaultValue;
|
||||
|
||||
if (value)
|
||||
{
|
||||
|
@ -199,10 +197,10 @@ double CCUserDefault::getDoubleForKey(const char* pKey)
|
|||
return ret;
|
||||
}
|
||||
|
||||
string CCUserDefault::getStringForKey(const char* pKey)
|
||||
string CCUserDefault::getStringForKey(const char* pKey, const std::string & defaultValue)
|
||||
{
|
||||
const char* value = getValueForKey(pKey);
|
||||
string ret("");
|
||||
string ret = defaultValue;
|
||||
|
||||
if (value)
|
||||
{
|
||||
|
@ -264,7 +262,7 @@ void CCUserDefault::setDoubleForKey(const char* pKey, double value)
|
|||
setValueForKey(pKey, tmp);
|
||||
}
|
||||
|
||||
void CCUserDefault::setStringForKey(const char* pKey, std::string value)
|
||||
void CCUserDefault::setStringForKey(const char* pKey, const std::string & value)
|
||||
{
|
||||
// check key
|
||||
if (! pKey)
|
||||
|
|
|
@ -445,7 +445,8 @@ void CCTextureCache::removeTextureForKey(const char *textureKeyName)
|
|||
|
||||
CCTexture2D* CCTextureCache::textureForKey(const char* key)
|
||||
{
|
||||
return m_pTextures->objectForKey(string(key));
|
||||
std::string strKey = CCFileUtils::fullPathFromRelativePath(key);
|
||||
return m_pTextures->objectForKey(strKey);
|
||||
}
|
||||
|
||||
void CCTextureCache::reloadAllTextures()
|
||||
|
|
|
@ -227,11 +227,6 @@ namespace cocos2d{
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// XXX deprecated
|
||||
CCTMXObjectGroup * CCTMXTiledMap::groupNamed(const char *groupName)
|
||||
{
|
||||
return objectGroupNamed(groupName);
|
||||
}
|
||||
CCString * CCTMXTiledMap::propertyNamed(const char *propertyName)
|
||||
{
|
||||
return m_pProperties->objectForKey(std::string(propertyName));
|
||||
|
|
|
@ -19,8 +19,8 @@ fi
|
|||
|
||||
|
||||
# the bash file should not be called by cygwin
|
||||
UNIX_NAME=`uname -o`
|
||||
if [ $UNIX_NAME = "Cygwin" ];then
|
||||
KERNEL_NAME=`uname -s | grep "CYGWIN*"`
|
||||
if [ $KERNEL_NAME"hi" != "hi" ]; then
|
||||
echo "Error!!!"
|
||||
echo "Don't run in cygwin. You should run corresponding bat."
|
||||
exit
|
||||
|
|
|
@ -65,6 +65,7 @@ copy_src_and_jni(){
|
|||
copy_build_native(){
|
||||
# here should use # instead of /, why??
|
||||
sed "s#__cocos2dxroot__#$COCOS2DX_ROOT#;s#__ndkroot__#$NDK_ROOT#;s#__projectname__#$APP_NAME#" $COCOS2DX_ROOT/template/android/build_native.sh > $APP_DIR/android/build_native.sh
|
||||
chmod u+x $APP_DIR/android/build_native.sh
|
||||
}
|
||||
|
||||
# replace AndroidManifext.xml and change the activity name
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved.
|
||||
//
|
||||
|
||||
#include "___PROJECTNAMEASIDENTIFIER___AppDelegate.h"
|
||||
#include "AppDelegate.h"
|
||||
|
||||
#include "cocos2d.h"
|
||||
#include "HelloWorldScene.h"
|
|
@ -1 +1 @@
|
|||
6616770f7d0487bf12f076293d27d5ef5f11af1e
|
||||
fd240a3cf678487c690dd028abcba1a5ff1a3c6c
|
|
@ -6,7 +6,7 @@
|
|||
// Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved.
|
||||
//
|
||||
|
||||
#include "___PROJECTNAMEASIDENTIFIER___AppDelegate.h"
|
||||
#include "AppDelegate.h"
|
||||
|
||||
#include "cocos2d.h"
|
||||
#include "HelloWorldScene.h"
|
|
@ -1 +1 @@
|
|||
55a23e272c4ae52bb22a27f5bd0f4309bcb4c683
|
||||
e11ed677bce9b5ea1798fdbfff120ddba0182dd9
|
|
@ -6,7 +6,7 @@
|
|||
// Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved.
|
||||
//
|
||||
|
||||
#include "___PROJECTNAMEASIDENTIFIER___AppDelegate.h"
|
||||
#include "AppDelegate.h"
|
||||
|
||||
#include "cocos2d.h"
|
||||
#include "HelloWorldScene.h"
|
|
@ -1 +1 @@
|
|||
e927644074613ed3644c897bdb0912660335380e
|
||||
bd9603372ffc87e1e3fc5cb80030bdc28112f961
|
|
@ -1 +1 @@
|
|||
99f6132989ba063c7d343a1b0b27799df3d2f280
|
||||
4f2f642918e859dde3db5a24ebb9484634f1d2fc
|
|
@ -52,6 +52,7 @@ LOCAL_SRC_FILES := main.cpp \
|
|||
../../../tests/EaseActionsTest/EaseActionsTest.cpp \
|
||||
../../../tests/EffectsAdvancedTest/EffectsAdvancedTest.cpp \
|
||||
../../../tests/EffectsTest/EffectsTest.cpp \
|
||||
../../../tests/FontTest/FontTest.cpp \
|
||||
../../../tests/HiResTest/HiResTest.cpp \
|
||||
../../../tests/IntervalTest/IntervalTest.cpp \
|
||||
../../../tests/KeypadTest/KeypadTest.cpp \
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
using namespace cocos2d;
|
||||
|
||||
#define IMG_PATH "assets"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
|
@ -23,8 +21,6 @@ void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv* env, jobject thi
|
|||
// view->create(480, 320);
|
||||
cocos2d::CCDirector::sharedDirector()->setOpenGLView(view);
|
||||
|
||||
CCFileUtils::setRelativePath(IMG_PATH);
|
||||
|
||||
AppDelegate *pAppDelegate = new AppDelegate();
|
||||
cocos2d::CCApplication::sharedApplication().run();
|
||||
}
|
||||
|
|
|
@ -83,6 +83,9 @@ public class Cocos2dxActivity extends Activity{
|
|||
backgroundMusicPlayer = new Cocos2dxMusic(this);
|
||||
soundPlayer = new Cocos2dxSound(this);
|
||||
|
||||
// init bitmap context
|
||||
Cocos2dxBitmap.setContext(this);
|
||||
|
||||
handler = new Handler(){
|
||||
public void handleMessage(Message msg){
|
||||
switch(msg.what){
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.ByteOrder;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
|
@ -11,6 +12,7 @@ import android.graphics.Paint;
|
|||
import android.graphics.Typeface;
|
||||
import android.graphics.Paint.Align;
|
||||
import android.graphics.Paint.FontMetricsInt;
|
||||
import android.util.Log;
|
||||
|
||||
public class Cocos2dxBitmap{
|
||||
/*
|
||||
|
@ -21,6 +23,12 @@ public class Cocos2dxBitmap{
|
|||
private static final int ALIGNLEFT = 0x31;
|
||||
private static final int ALIGNRIGHT = 0x32;
|
||||
|
||||
private static Context context;
|
||||
|
||||
public static void setContext(Context context){
|
||||
Cocos2dxBitmap.context = context;
|
||||
}
|
||||
|
||||
/*
|
||||
* @width: the width to draw, it can be 0
|
||||
* @height: the height to draw, it can be 0
|
||||
|
@ -31,7 +39,7 @@ public class Cocos2dxBitmap{
|
|||
content = refactorString(content);
|
||||
Paint paint = newPaint(fontName, fontSize, alignment);
|
||||
|
||||
TextProperty textProperty = getTextWidthAndHeight(content, paint, width, height);
|
||||
TextProperty textProperty = computeTextProperty(content, paint, width, height);
|
||||
|
||||
// Draw text to bitmap
|
||||
Bitmap bitmap = Bitmap.createBitmap(textProperty.maxWidth,
|
||||
|
@ -95,7 +103,7 @@ public class Cocos2dxBitmap{
|
|||
}
|
||||
}
|
||||
|
||||
private static TextProperty getTextWidthAndHeight(String content, Paint paint,
|
||||
private static TextProperty computeTextProperty(String content, Paint paint,
|
||||
int maxWidth, int maxHeight){
|
||||
FontMetricsInt fm = paint.getFontMetricsInt();
|
||||
int h = (int)Math.ceil(fm.descent - fm.ascent);
|
||||
|
@ -119,7 +127,6 @@ public class Cocos2dxBitmap{
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return new TextProperty(maxContentWidth, h, lines);
|
||||
}
|
||||
|
||||
|
@ -231,10 +238,10 @@ public class Cocos2dxBitmap{
|
|||
}
|
||||
|
||||
/*
|
||||
* Add the last char
|
||||
* Add the last chars
|
||||
*/
|
||||
if (start == charLength - 1){
|
||||
strList.add(content.substring(charLength-1));
|
||||
if (start < charLength){
|
||||
strList.add(content.substring(start));
|
||||
}
|
||||
|
||||
return strList;
|
||||
|
@ -244,9 +251,29 @@ public class Cocos2dxBitmap{
|
|||
Paint paint = new Paint();
|
||||
paint.setColor(Color.WHITE);
|
||||
paint.setTextSize(fontSize);
|
||||
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
|
||||
paint.setAntiAlias(true);
|
||||
|
||||
/*
|
||||
* Set type face for paint, now it support .ttf file.
|
||||
*/
|
||||
if (fontName.endsWith(".ttf")){
|
||||
try {
|
||||
Typeface typeFace = Typeface.createFromAsset(context.getAssets(), fontName);
|
||||
paint.setTypeface(typeFace);
|
||||
} catch (Exception e){
|
||||
Log.e("Cocos2dxBitmap",
|
||||
"error to create ttf type face: " + fontName);
|
||||
|
||||
/*
|
||||
* The file may not find, use system font
|
||||
*/
|
||||
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
|
||||
}
|
||||
}
|
||||
else {
|
||||
paint.setTypeface(Typeface.create(fontName, Typeface.NORMAL));
|
||||
}
|
||||
|
||||
switch (alignment){
|
||||
case ALIGNCENTER:
|
||||
paint.setTextAlign(Align.CENTER);
|
||||
|
|
|
@ -1 +1 @@
|
|||
898c0f4be35b091c881554d3a75aafca0788707a
|
||||
089538e21098633ff475d29aa721c886c2eed848
|
|
@ -1083,6 +1083,18 @@
|
|||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="FontTest"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\tests\FontTest\FontTest.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\tests\FontTest\FontTest.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
</Filter>
|
||||
</Files>
|
||||
|
|
|
@ -119,7 +119,8 @@ OBJECTS = \
|
|||
$(OBJECTS_DIR)/TouchesTest.o \
|
||||
$(OBJECTS_DIR)/TransitionsTest.o \
|
||||
$(OBJECTS_DIR)/UserDefaultTest.o \
|
||||
$(OBJECTS_DIR)/ZwoptexTest.o
|
||||
$(OBJECTS_DIR)/ZwoptexTest.o \
|
||||
$(OBJECTS_DIR)/FontTest.o
|
||||
|
||||
ADD_OBJECTS +=
|
||||
|
||||
|
@ -390,3 +391,6 @@ $(OBJECTS_DIR)/UserDefaultTest.o : ../tests/UserDefaultTest/UserDefaultTest.cpp
|
|||
$(OBJECTS_DIR)/ZwoptexTest.o : ../tests/ZwoptexTest/ZwoptexTest.cpp
|
||||
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/ZwoptexTest.o ../tests/ZwoptexTest/ZwoptexTest.cpp
|
||||
|
||||
$(OBJECTS_DIR)/FontTest.o : ../tests/FontTest/FontTest.cpp
|
||||
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/FontTest.o ../tests/FontTest/FontTest.cpp
|
||||
|
||||
|
|
|
@ -1090,6 +1090,18 @@
|
|||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="FontTest"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\tests\FontTest\FontTest.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\tests\FontTest\FontTest.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
|
|
|
@ -609,7 +609,7 @@ void ActionAnimate::onEnter()
|
|||
|
||||
centerSprites(1);
|
||||
|
||||
CCAnimation* animation = CCAnimation::animationWithName("dance", 0.2f);
|
||||
CCAnimation* animation = CCAnimation::animation();
|
||||
char frameName[100] = {0};
|
||||
for( int i=1;i<15;i++)
|
||||
{
|
||||
|
@ -617,7 +617,7 @@ void ActionAnimate::onEnter()
|
|||
animation->addFrameWithFileName(frameName);
|
||||
}
|
||||
|
||||
CCActionInterval* action = CCAnimate::actionWithAnimation( animation, false);
|
||||
CCActionInterval* action = CCAnimate::actionWithDuration(3, animation, false);
|
||||
CCActionInterval* action_back = action->reverse();
|
||||
|
||||
m_grossini->runAction( CCSequence::actions( action, action_back, NULL));
|
||||
|
|
|
@ -120,7 +120,7 @@ void Box2DTestLayer::addNewSpriteWithCoords(CCPoint p)
|
|||
//just randomly picking one of the images
|
||||
int idx = (CCRANDOM_0_1() > .5 ? 0:1);
|
||||
int idy = (CCRANDOM_0_1() > .5 ? 0:1);
|
||||
CCSprite *sprite = batch->createSpriteWithRect( CCRectMake(32 * idx,32 * idy,32,32));
|
||||
CCSprite *sprite = CCSprite::spriteWithTexture(batch->getTexture(), CCRectMake(32 * idx,32 * idy,32,32));
|
||||
batch->addChild(sprite);
|
||||
|
||||
sprite->setPosition( CCPointMake( p.x, p.y) );
|
||||
|
|
|
@ -19,15 +19,16 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "cocos2d.h"
|
||||
|
||||
#include "cocos2d.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
|
||||
|
||||
using namespace cocos2d;
|
||||
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
#include "FontTest.h"
|
||||
#include "../testResource.h"
|
||||
|
||||
enum {
|
||||
kTagLabel1,
|
||||
kTagLabel2,
|
||||
kTagLabel3,
|
||||
kTagLabel4,
|
||||
};
|
||||
|
||||
static int fontIdx = 0;
|
||||
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
|
||||
static std::string fontList[] =
|
||||
{
|
||||
"American Typewriter",
|
||||
"Marker Felt",
|
||||
"A Damn Mess",
|
||||
"Abberancy",
|
||||
"Abduction",
|
||||
"Paint Boy",
|
||||
"Schwarzwald Regular",
|
||||
"Scissor Cuts",
|
||||
};
|
||||
#else
|
||||
static std::string fontList[] =
|
||||
{
|
||||
"fonts/A Damn Mess.ttf",
|
||||
"fonts/Abberancy.ttf",
|
||||
"fonts/Abduction.ttf",
|
||||
"fonts/Paint Boy.ttf",
|
||||
"fonts/Schwarzwald Regular.ttf",
|
||||
"fonts/Scissor Cuts.ttf",
|
||||
};
|
||||
#endif
|
||||
|
||||
static const char* nextAction(void)
|
||||
{
|
||||
fontIdx++;
|
||||
fontIdx = fontIdx % (sizeof(fontList) / sizeof(fontList[0]));
|
||||
return fontList[fontIdx].c_str();
|
||||
}
|
||||
|
||||
static const char* backAction(void)
|
||||
{
|
||||
fontIdx--;
|
||||
if (fontIdx < 0)
|
||||
{
|
||||
fontIdx += (sizeof(fontList) / sizeof(fontList[0]));
|
||||
}
|
||||
|
||||
return fontList[fontIdx].c_str();
|
||||
}
|
||||
|
||||
static const char* restartAction(void)
|
||||
{
|
||||
return fontList[fontIdx].c_str();
|
||||
}
|
||||
|
||||
|
||||
FontTest::FontTest()
|
||||
{
|
||||
CCSize size = CCDirector::sharedDirector()->getWinSize();
|
||||
CCMenuItemImage *item1 = CCMenuItemImage::itemFromNormalImage(s_pPathB1, s_pPathB2, this, menu_selector(FontTest::backCallback));
|
||||
CCMenuItemImage *item2 = CCMenuItemImage::itemFromNormalImage(s_pPathR1, s_pPathR2, this, menu_selector(FontTest::restartCallback));
|
||||
CCMenuItemImage *item3 = CCMenuItemImage::itemFromNormalImage(s_pPathF1, s_pPathF2, this, menu_selector(FontTest::nextCallback));
|
||||
|
||||
CCMenu *menu = CCMenu::menuWithItems(item1, item2, item3, NULL);
|
||||
menu->setPosition(CCPointZero);
|
||||
item1->setPosition(ccp(size.width/2 - 100,30));
|
||||
item2->setPosition(ccp(size.width/2, 30));
|
||||
item3->setPosition(ccp(size.width/2 + 100,30));
|
||||
addChild(menu, 1);
|
||||
|
||||
showFont(restartAction());
|
||||
}
|
||||
|
||||
void FontTest::showFont(const char *pFont)
|
||||
{
|
||||
removeChildByTag(kTagLabel1, true);
|
||||
removeChildByTag(kTagLabel2, true);
|
||||
removeChildByTag(kTagLabel3, true);
|
||||
removeChildByTag(kTagLabel4, true);
|
||||
|
||||
CCSize s = CCDirector::sharedDirector()->getWinSize();
|
||||
|
||||
CCLabelTTF *top = CCLabelTTF::labelWithString(pFont, pFont, 24);
|
||||
CCLabelTTF *left = CCLabelTTF::labelWithString("alignment left", CCSizeMake(s.width, 50), CCTextAlignmentLeft, pFont, 32);
|
||||
CCLabelTTF *center = CCLabelTTF::labelWithString("alignment center", CCSizeMake(s.width, 50), CCTextAlignmentCenter, pFont, 32);
|
||||
CCLabelTTF *right = CCLabelTTF::labelWithString("alignment right", CCSizeMake(s.width, 50), CCTextAlignmentRight, pFont, 32);
|
||||
|
||||
top->setPosition(ccp(s.width/2, 250));
|
||||
left->setPosition(ccp(s.width/2, 200));
|
||||
center->setPosition(ccp(s.width/2, 150));
|
||||
right->setPosition(ccp(s.width/2, 100));
|
||||
|
||||
addChild(left, 0, kTagLabel1);
|
||||
addChild(right, 0, kTagLabel2);
|
||||
addChild(center, 0, kTagLabel3);
|
||||
addChild(top, 0, kTagLabel4);
|
||||
}
|
||||
|
||||
void FontTest::backCallback(CCObject* pSender)
|
||||
{
|
||||
showFont(backAction());
|
||||
}
|
||||
|
||||
void FontTest::nextCallback(CCObject* pSender)
|
||||
{
|
||||
showFont(nextAction());
|
||||
}
|
||||
|
||||
std::string FontTest::title()
|
||||
{
|
||||
return "Font test";
|
||||
}
|
||||
|
||||
void FontTest::restartCallback(CCObject* pSender)
|
||||
{
|
||||
showFont(restartAction());
|
||||
}
|
||||
|
||||
///---------------------------------------
|
||||
//
|
||||
// DirectorTestScene
|
||||
//
|
||||
///---------------------------------------
|
||||
void FontTestScene::runThisTest()
|
||||
{
|
||||
CCLayer* pLayer = FontTest::node();
|
||||
addChild(pLayer);
|
||||
|
||||
CCDirector::sharedDirector()->replaceScene(this);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue