プログラム編の続きで、内部関数編です。
●winmng_SetItemList
メニューかリストのウィンドウの設定をします。
項目数はここで数えておきます。項目のラストは項目名がNULLで判定です。
初期選択番号は0で固定してます。
//----------------------------------------------------------------------
// (内部)リストを設定する。
//----------------------------------------------------------------------
static void winmng_SetItemList(char **itemlist,int mode)
{
// アクティブなウィンドウがあるなら
if( s_winData.ActiveNo != -1 ) {
int winno = s_winData.ActiveNo;
// 処理モード
s_winData.win[winno].mode = mode; // 現在のモード
// リストを設定します。
s_winData.win[winno].itemList = itemlist;
// 項目数を数えます。(最大値は適当です)
s_winData.win[winno].listNums = 0;
for( int m=0 ; m 0 ) {
bNewLine = TRUE;
src+= NewLineCodeSize;
} else {
// 全角文字をチェックする。
if( SjisZenkaku(src) ) {
// 2バイトコード(全角)
dst[0] = src[0];
dst[1] = src[1];
dst++;src++;
dst++;src++;
} else {
// 1バイトコード(半角)
dst[0] = src[0];
dst++;src++;
}
}
dst[0] = '\0';//仮の文字列終端。
// 出来上がった文字列長が一行をオーバーしていたら、改行処理。
int fontsizex = winmng_DrawString(0,0,strbuf,FONT_TYPE_MSG,0,FALSE);
if( fontsizex >= (sizex-s_FontData[FONT_TYPE_MSG].size-(WINDOW_SPACE*2)) ) {
// 禁則処理判定で句読点かチェック
if( ProhibitionCheck(src) ) {
// 句読点用のサイズでチェックする。
if( fontsizex >= (sizex-WINDOW_SPACE) ) {
// ここで改行する。
bNewLine = TRUE;
}
} else {
// ここで改行する。
bNewLine = TRUE;
}
}
// 改行なら描画する。
if( bNewLine ) {
// 描画
winmng_DrawString(px+WINDOW_SPACE,posy,strbuf,
FONT_TYPE_MSG,GetColor(255,255,255),TRUE );
// 改行
posy += (s_FontData[FONT_TYPE_MSG].size + 1);
// 文字列バッファを先頭に
dst = strbuf;
dst[0] = '\0';//仮の文字列終端。
// ウィンドウの下段に達したか?
if( posy >= (topy+sizey-(WINDOW_SPACE*2)-s_FontData[FONT_TYPE_MSG].size) ) {
// 一時中断ポイント
rtnCode = DRAWMSG_RTN_WINEND; //ウィンドウの終端
break;
}
}
}
// 最後の位置を保存する。
s_winData.win[winno].msgEnd = src;
// 残った文字の処理。
if( strlen(strbuf) > 0 ) {
winmng_DrawString(px+WINDOW_SPACE,posy,strbuf,
FONT_TYPE_MSG,GetColor(255,255,255),TRUE );
}
// 持ち帰る。
return rtnCode;
}
初回なら、必要な全種類の文字フォントハンドルを作成します。
もし描画が有効なら、指定された位置に指定された文字列を指定フォントで描画します。
描画なしなら、文字列を描画したときのドット幅を持ち帰ります。
//----------------------------------------------------------------------
// (内部)文字列描画処理
//----------------------------------------------------------------------
static int winmng_DrawString(int px,int py,char *str,int fonttype,int color,int bDraw)
{
// 文字フォント
static int bInit = FALSE; // 初期化済み
static int FontHandles[FONT_TYPE_MAX]; // フォントハンドル
// 未初期化ならフォントハンドルを作成。
if( bInit==FALSE ) {
bInit = TRUE;
// フォントのハンドルを作成。
for( int f=0 ; f (PAUSE_BLINK_CYCLE/2) ) {
int x1 = px + ( sizex / 2 );
int y1 = py + sizey + WINDOW_SPACE;
int x2 = x1 - PAUSE_MARK_SIZE;
int y2 = y1 - PAUSE_MARK_SIZE;
int x3 = x1 + PAUSE_MARK_SIZE;
int y3 = y1 - PAUSE_MARK_SIZE;
// 三角形を描く
DrawTriangle(x1,y1,x2,y2,x3,y3,GetColor(255,255,255),TRUE);
}
}
ウィンドウに設定されたリストを描画します。
選択カーソルが有効なら、その位置に選択カーソルも描画します。
ちなみにspy,spyで位置や行間も制御されています。
//----------------------------------------------------------------------
// (内部)リストを描画する。
//----------------------------------------------------------------------
static void winmng_DrawItemList(int winno,int spx,int spy,int fonttype,int bCursor)
{
// ウィンドウ情報。
int px = s_winData.win[winno].px; // ウィンドウのピクセル位置X
int py = s_winData.win[winno].py; // ウィンドウのピクセル位置Y
int sizex = s_winData.win[winno].sizex; // ウィンドウのピクセルサイズX
int sizey = s_winData.win[winno].sizey; // ウィンドウのピクセルサイズY
char *winName = s_winData.win[winno].winName; // ウィンドウ名
// 選択情報
char **itemlist = s_winData.win[winno].itemList; // リスト
MACRO_ASSERT( itemlist!=NULL );
int listNums = s_winData.win[winno].listNums; // リスト項目数
int itemNo = s_winData.win[winno].itemNo; // 選択番号
// 表示開始座標。タイトルを避ける。
int topx = px + spx;
int topy = py + spy;
if( winName ) {
topy += WINNAME_OFFSET_Y + s_FontData[FONT_TYPE_TITLE].size + 1;
}
// リストを表示する。
for( int sn=0 ; sn<listNums ; sn++ ) {
// リスト項目を表示する。
winmng_DrawString(topx,topy,itemlist[sn],
FONT_TYPE_MENU,GetColor(255,255,255),TRUE );
// 選択カーソル?
if( bCursor ) {
// 選択項目ならカーソルを表示する。
if( sn == itemNo ) {
int x1 = topx - s_FontData[fonttype].size;
int y1 = topy;
int x2 = x1;
int y2 = topy + s_FontData[fonttype].size;
int x3 = x1 + PAUSE_MARK_SIZE;
int y3 = topy + (s_FontData[fonttype].size/2);
// 三角形を描く
DrawTriangle(x1,y1,x2,y2,x3,y3,GetColor(255,255,255),TRUE);
}
}
// 次の位置
topy += s_FontData[fonttype].size + spy;
}
}
序章で説明したとおり、全角(2バイト文字)かどうかを判断する関数です。
2バイト文字ならTRUE、それ以外はFALSEを返します。
//----------------------------------------------------------------------
// シフトJIS全角文字判定
//----------------------------------------------------------------------
static int SjisZenkaku(char *str)
{
BYTE *bstr = (BYTE*)str;
// SJIS全角文字判定
if( ( (BYTE)0x81<=bstr[0] && bstr[0]<=(BYTE)0x9F ) ||
( (BYTE)0xE0<=bstr[0] && bstr[0]<=(BYTE)0xFF ) ) {
return TRUE;//全角
} else {
return FALSE;//半角
}
}
これも序章で説明したとおり、改行コードを判定します。
今回の判定は0x0d,0x0aの組みと0x0a単体の改行コードの2種類に対応させました。
//----------------------------------------------------------------------
// 改行コード判定
//----------------------------------------------------------------------
static int NewLineCheck(char *str)
{
// 0x0d,0x0aの並びなら改行。
if( str[0] != '\0' ) {
if( str[0] == 0x0d ) {
if( str[1] != '\0' ) {
if( str[1] == 0x0a ) {
// 2文字改行
return 2;
}
}
}
}
// 0x0aだけでも改行。
if( str[0] != '\0' ) {
if( str[0] == 0x0a ) {
// 1文字改行
return 1;
}
}
// 改行ではない。
return 0;
}
これも序章で説明したとおり、禁則文字か判定しています。
2バイト文字と1バイト文字で二重にチェックしています。
禁則文字も不十分だと思いますので必要の合わせて増やす必要があります。
//----------------------------------------------------------------------
// 禁則処理文字チェック
//----------------------------------------------------------------------
static int ProhibitionCheck(char *str)
{
// 全角?
if( SjisZenkaku(str) ) {
// 禁則文字か?
if( 0 == strncmp(str,"、",2) ||
0 == strncmp(str,",",2) ||
0 == strncmp(str,"。",2) ||
0 == strncmp(str,".",2) ||
0 == strncmp(str,")",2) ||
0 == strncmp(str,"」",2) ) {
// 禁則文字
return TRUE;
}
} else {
// 禁則文字か?
if( 0 == strncmp(str,"、",1) ||
0 == strncmp(str,",",1) ||
0 == strncmp(str,"。",1) ||
0 == strncmp(str,".",1) ||
0 == strncmp(str,")",1) ||
0 == strncmp(str,"」",1) ) {
// 禁則文字
return TRUE;
}
}
// 禁則文字ではない。
return FALSE;
}
いよいよ次はゲーム本編に組み込んでみましょう。