/*
	pattern.c

	グラフィックのパターン化
*/

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <memory.h>
#include <stdlib.h>

#include "ge.h"
#include "dispman.h"
#include "imageman.h"
#include "mask.h"

typedef struct _pat
{
	struct _pat	*next;			// リスト化のためのポインタ
	char		name[41];		// パターン名(漢字で20文字まで)
	char		subname[15];	// パターンの略称(漢字で 7 文字まで)
	int			xlen, ylen;		// パターンの大きさ
	int			bufx, bufy;		// パターンバッファ内での位置
	int			patbufsize;		// パターンデータのバイト数
	char		*patbuf;		// パターンデータへのポインタ
	bool		selected;		// 選択されているなら YES
	bool		nodisp;			// パターンバッファ表示時に表示しないなら YES
	int			zoomx,zoomy;	// パターンの１ドットの縦横比率
	bool		nowdisp;		// 画面に表示されているなら YES
	char		dmy[33];		// 埋め草
} PAT;   // size = 128 bytes

#define	PATZOOM	2

#define	constPAT(p)		((p) = calloc(sizeof(PAT),1))
#define	destroyPAT(p)	{if((p)->patbuf!=NULL) free((p)->patbuf); free((p));}

// #define	SELNUM	1000			/* パターンを幾つまで選択できるか */
// static	PAT		*selpat[SELNUM];
// static	int		selnum = -1;

// static	char	*scrbuf = NULL;		// パターン編集に入る前の画面を保存するバッファ
static	PAT		*patlist = NULL;
static	PAT		*curpat = NULL;		// 右クリックされたパターンを指すポインタ


/*--------------------------------------------------------*/
/*                     メニューの定義                     */
/*--------------------------------------------------------*/


#define	itemExit			1
#define	itemPatBuf			2


static void disp_patterns_all_new();
static void disp_patmenu(),erase_patmenu();

	void	dsppatname(),dsppatsubname();
	#define	IP(n)	menu_button(&patsubmenu,n)
	static void disp_patsubmenu(), erase_patsubmenu();

#include "pattern.md"

static void disp_patmenu()
{
}

static void erase_patmenu()
{
}


/*--------------------------------------------------------*/
/*                   サブメニューの定義                   */
/*--------------------------------------------------------*/


int	cntcolor();


static	void	dsppatname()
{
	int ixlen;
	menu_getbuttonxy(&patsubmenu, SitemPatName, NULL,NULL,&ixlen,NULL);
	char strbuf[40];
	int i;
	for (i=0; i<ixlen/8; i++)
		strbuf[i] = curpat->name[i];
	strbuf[i] = '\0';
   menu_buttonputstr(menu_button(&patsubmenu,SitemPatName),1,1,strbuf,typeSTR);
}


static	void	dsppatsubname()
{
	menu_buttonputstr(IP(SitemPatSubName),1,1, curpat->subname, typeSTR);
}


static void disp_patsubmenu()
{
	char strbuf[100];
	sprintf(strbuf, "%d", curpat->xlen);
	menu_buttonputstr(IP(SitemPatXLen), 16,0, strbuf,typeSTR);
	sprintf(strbuf, "%d", curpat->ylen);
	menu_buttonputstr(IP(SitemPatYLen), 16,0, strbuf,typeSTR);
	sprintf(strbuf, "%d", cntcolor(curpat));
	menu_buttonputstr(IP(SitemColNum), 72,0, strbuf,typeSTR);
	// sprintf(strbuf, "(%2d,%2d)", curpat->zoomx, curpat->zoomy);
	// menu_buttonputstr(IP(SitemDotZoom), 88,0, strbuf,typeSTR);
}


static void erase_patsubmenu()
{
}


/*--------------------------------------------------------*/
/*                        補助処理                        */
/*--------------------------------------------------------*/


// ● ページ1の拡大率･表示位置を設定する


static int pre_zoom,pre_zoomY;
static int pre_dispX, pre_dispY;
static bool pre_lat1disp,pre_lat2disp;


static void resetPage1()
{
	DMimage_setzoomrate(pre_zoom);
	DMimage_setdispxy(pre_dispX,pre_dispY);
	DMimage_setlatticeswitch(pre_lat1disp,pre_lat2disp);
	DMimage_refresh();
}


static void setPage1()
{
	pre_zoom = DMimage_getzoomrate();
	DMimage_getdispxy(&pre_dispX, &pre_dispY);
	DMimage_getlatticeswitch(&pre_lat1disp,&pre_lat2disp);
	DMimage_setlatticeswitch(NO,NO);
	DMimage_setzoomrate(2);
	DMimage_setdispxy(0,0);
}


// ● 現在編集している画面をメモリに保存/復帰する



// ● ページ0の座標をページ1の座標に変換する


// ●パターンの特定のドットの色コードを調べる


static int get_pat_pixel(PAT *pp, int x, int y)
// (x,y) : パターン内でのオフセット
{
	if (mode == MODE32K)
		return *(short int *)(pp->patbuf + (pp->xlen*2) * y + x * 2);
	else
	{
		int c;
		c = *(pp->patbuf + ((pp->xlen+7)/8)*4 * y + x/2);
		if ((x&1) == 0)
			return c&15;
		else
			return (c>>4)&15;
	}
}


// ●パターンリストにいくつのパターンが登録されているか調べる


static int get_patallnum()
{
	PAT *pp;  int n;
	for (pp=patlist, n=0;  pp != NULL;  pp = pp->next, n++)
		;
	return n;
}


// ●パターンがリスト内で何番目かをしらべる


static int get_patnum(PAT *patp)
{
	PAT *pp;
	int n;
	for (pp=patlist, n=0;  pp != NULL;  pp = pp->next, n++) {
		if (pp == patp)
			return n;
	}
	return -1;
}


// ●パターンリストを、パターン名をキーにしてソートする


	static int cmp_patname(PAT **p1, PAT **p2)
	{
		return strcmp((*p1)->name, (*p2)->name);
	}


static void sort_patlist()
{
	int patallnum,i;   PAT **plist,*pp;
	if ((patallnum = get_patallnum()) == 0)
		return;
	if ((plist = (PAT**)malloc(sizeof(PAT *) * patallnum)) == NULL)
		return;
	for (i=0,pp=patlist; i<patallnum; i++,pp=pp->next)
		*(plist + i) = pp;

	qsort(plist, patallnum, sizeof(PAT*), cmp_patname);

	patlist = *(plist+0);
	for (i=0; i<patallnum-1; i++)
		(*(plist+i))->next = *(plist+i+1);
	(*(plist+patallnum-1))->next = NULL;
	free(plist);
}


// ● パターンバッファ内での座標を 640*480座標に変換する


static void bufp_to_page0p( int x,int y,int xlen,int ylen,
							int *dx,int *dy,int *dxlen,int *dylen )
{
	BUTTON *ip;  int zr=DMimage_getzoomrate();
	int ix,iy,ixlen,iylen;
	menu_getbuttonxy(&patternmenu,itemPatBuf,&ix,&iy,&ixlen,&iylen);
	if (dx!=NULL)
		*dx = ix  + x * zr;
	if (dy!=NULL)
		*dy = iy  + y * zr;
	if (dxlen != NULL)
		*dxlen = xlen * zr;
	if (dylen != NULL)
		*dylen = ylen * zr;
}


/*--------------------------------------------------------*/
/*               パターンの表示・消去の処理               */
/*--------------------------------------------------------*/


static char *get_pat_disp_name(PAT *pp)
/*
	パターン pp の画面上での名前を得る(最大30文字ぐらい)
	これは、関数内文字列バッファへのポインタを返す。
*/
{
	char name[15];
	static char buf[30];
	if (pp->subname[0] != '\0')
		strncpy(name,pp->subname,14);
	else
		strncpy(name,pp->name,14);
	sprintf(buf, "%d:%s", get_patnum(pp), name);
	return buf;
}


static void get_pat_name_area(PAT *pp, int *x, int *y, int *xlen, int *ylen)
/*
	パターン pp の名前表示のための領域(640*480座標内)を得る
*/
{
	int namex,namey; BUTTON *ip;  int zr=DMimage_getzoomrate();
	ip = menu_button(&patternmenu,itemPatBuf);
	int ix,iy;
	menu_getbuttonxy(&patternmenu,itemPatBuf,&ix,&iy,NULL,NULL);
	namex = ix + (pp->bufx + pp->xlen/2) * zr
			- (8 * strlen(get_pat_disp_name(pp))) / 2;
	namey = iy + (pp->bufy + pp->ylen) * zr + 2;
	if (x != NULL)
		*x = namex;
	if (y != NULL)
		*y = namey;
	if (xlen != NULL)
		*xlen = 8 * strlen(get_pat_disp_name(pp));
	if (ylen != NULL)
		*ylen = 16;
}


// ●パターンひとつを表示する


static void dispOnePattern(PAT *pp, bool frame, bool center)
// frame : 枠とパターン名を表示するかどうか
{
	BUTTON *ip;  int bx0,by0, px,py;  int menux,menuy;
	menu_getmenuxy(NULL,&menux,&menuy,NULL,NULL);
	int zr=DMimage_getzoomrate();
	ip = menu_button(&patternmenu,itemPatBuf);
	int ix,iy,ixlen,iylen;
	menu_getbuttonxy(&patternmenu,itemPatBuf,&ix,&iy,&ixlen,&iylen);
	bx0 = sx2bx(ix);
	by0 = sy2by(iy);
	if (center) {
		px = (ixlen/zr - pp->xlen*pp->zoomx)/2;
		py = (iylen/zr - pp->ylen*pp->zoomy)/2;
	} else {
		px = pp->bufx;
		py = pp->bufy;
	}

	int patxlen,patylen;
	patxlen = pp->xlen * pp->zoomx;
	patylen = pp->ylen * pp->zoomy;

	if (pp->nodisp)
		return;
	pp->nowdisp = YES;
	page_edit();
	if (pp->zoomx == 1 && pp->zoomy == 1)
		grp_putblk(bx0+px, by0+py, pp->xlen, pp->ylen, pp->patbuf, DrawNORMAL);
	else if (pp->zoomx == 1) { 
		int y,iy;
		for (y=0;  y < pp->ylen;  y++) {
			char *p;
			if (mode == MODE32K)
				p = pp->patbuf + pp->xlen*2 * y;
			else
				p = pp->patbuf + ((pp->xlen+7)/8)*4 * y;
			for (iy=0; iy<pp->zoomy; iy++)
				grp_putblk(bx0+px,by0+py+y*pp->zoomy+iy,pp->xlen,1,
						   p, DrawNORMAL);
		}
	} else {
		int x,y;
		for (y=0;  y < pp->ylen;  y++) {
			for (x=0;  x < pp->xlen;  x++) {
				int c;
				if (mode == MODE32K)
					c = *(short int *)(pp->patbuf + pp->xlen*2 * y + x*2);
				else {
					c = *(pp->patbuf + ((pp->xlen+7)/8)*4 * y + x/2);
					if ((x&1) == 0)
						c = c & 0xf;
					else
						c = (c >> 4);
				}
				grboxfill(bx0+px+x*pp->zoomx, by0+py+y*pp->zoomy,
						  pp->zoomx,pp->zoomy,c,DrawNORMAL);
			}
		}
	}
	if (pp->selected)
		grboxfill(bx0+px,by0+py,patxlen,patylen,white,DrawXOR);
	page_menu();

	if (frame) {
		int namex,namey;
		get_pat_name_area(pp,&namex,&namey,NULL,NULL);
		ART_putstr(namex,namey,get_pat_disp_name(pp),COL_menuString);
		{
			int patx,paty,patxl,patyl;
			bufp_to_page0p(px,py,pp->xlen*pp->zoomx,pp->ylen*pp->zoomy,&patx,&paty,&patxl,&patyl);
			grboxline(patx-1,paty-1, patxl+2,patyl+2, White,DrawNORMAL);
			grboxfill(patx,  paty,   patxl,  patyl,   Black0,DrawNORMAL);
		}
	}
}


// ● 画面上のパターンを１つ（と、それに重なるパターンを全て）消去する

/*

static void erase_pattern_one(PAT *pp)
{
	typedef struct {int x,y,xlen,ylen;} area_t;
	bool area_crash(int x1,int y1,int xlen1,int ylen1,int x2,int y2,int xlen2,int ylen2)
	{
		if (((a1.x<=a2.x && a2.x<a1.x+a1.xlen) || (a2.x<=a1.x && a1.x<a2.x+a2.xlen)) &&
		    ((a1.y<=a2.y && a2.y<a1.y+a1.ylen) || (a2.y<=a1.y && a1.y<a2.y+a2.ylen)))
			return NO;
	}
	area_t p0,p1,p2,p3;
	bufp_to_page0p( pp->bufx,pp->bufy,pp->xlen*pp->zoomx,pp->ylen*pp->zoomy,
					&p0.x,&p0.y,&p0.xlen,&p0.ylen );
	get_pat_name_area(pp,&p1.x,&p1.y,&p1.xlen,&p1.ylen);
	PAT *tpp;
	for (tpp=patlist; tpp!=NULL; tpp=tpp->next)
	{
		bufp_to_page0p( tpp->bufx,tpp->bufy,tpp->xlen*tpp->zoomx,tpp->ylen*tpp->zoomy,
						&p2.x,&p2.y,&p2.xlen,&p2.ylen );
		get_pat_name_area(tpp,&p3.x,&p3.y,&p3.xlen,&p3.ylen);
	}
}
*/


// ● 画面上のパターンを全部消去する


static void erase_patterns_all()
{
	BUTTON *ip;  int bx0,by0;
	PAT *pp; int menux,menuy;  menu_getmenuxy(NULL,&menux,&menuy,NULL,NULL);
	for (pp=patlist;  pp!=NULL; pp=pp->next)
		pp->nowdisp = NO;
	int ix,iy,ixlen,iylen;
	menu_getbuttonxy(&patternmenu,itemPatBuf,&ix,&iy,&ixlen,&iylen);
	bx0 = sx2bx(ix);
	by0 = sy2by(iy);
	int zr=DMimage_getzoomrate();
	page_edit();
	grboxfill(bx0,by0,ixlen/zr,iylen/zr,Black0,DrawNORMAL);
	page_menu();
	grboxfill(ix,iy,ixlen,iylen,Black0,DrawNORMAL);
}


// ● パターンリストのパターンの表示を更新する


static void disp_patterns_makeup()
{
	PAT *pp;
	for (pp = patlist;  pp != NULL;  pp = pp->next)
		dispOnePattern(pp, YES, NO);
}


// ● パターンリストのパターンを全部表示しなおす


static void disp_patterns_all_new()
{
	erase_patterns_all();
	disp_patterns_makeup();
}


// ● 画面上の座標が どのパターンに対応するかを調べる


static PAT *jdgPattern(int msx, int msy)
{
	BUTTON *ip; int menux,menuy;  menu_getmenuxy(NULL,&menux,&menuy,NULL,NULL);
	int ix,iy;
	menu_getbuttonxy(&patternmenu,itemPatBuf,&ix,&iy,NULL,NULL);
	PAT *pp,*rp;  int zr=DMimage_getzoomrate();
	rp = NULL;
	for (pp=patlist; pp!=NULL; pp=pp->next) {
		int x1,y1,x2,y2;
		x1 = ix+pp->bufx*zr;
		y1 = iy+pp->bufy*zr;
		x2 = x1 + pp->xlen * pp->zoomx * zr - 1;
		y2 = y1 + pp->ylen * pp->zoomy * zr - 1;
		if (x1<=msx && msx<=x2 && y1<=msy && msy<=y2)
			rp = pp;
	}
	return rp;
}


// ● 特定のパターンに、何色の色が使われているか調べる


static int cntcolor(PAT *pp)
{
	int i,j,cnt;
	cnt = 0;
	if (mode == MODE32K) {
		short int *p;
		p = (short int *)pp->patbuf;
		bool flgs[32768];
		memset(flgs, NO, 32768);	// 全ての「色使用フラグ」をクリアする
		for (i=0; i < pp->ylen; i++) {
			for (j=0; j < pp->xlen; j++) {
				if (!flgs[*p]) {
					cnt++;
					flgs[*p] = YES;
				}
				p++;
			}
		}
	} else {
		char *p;
		p = pp->patbuf;
		int ystep;  bool flgs[16];
		ystep = ((pp->xlen + 7)/8)*4;
		memset(flgs,NO,16);
		for (i=0; i < pp->ylen; i++,p+=ystep) {
			for (j=0; j < pp->xlen; j++) {
				int c = *(p+j/2);
				if ((j&1)==0)	c &= 15;
				else			c >>= 4;
				if (!flgs[c]) {
					cnt++;
					flgs[c] = YES;
				}
			}
		}
	}
	return cnt;
}

// ● ページ0 の座標と パターンバッファの座標を変換する

static int sx2bx(int x)
{
	return /* dispX + */ x/DMimage_getzoomrate();
}

static int sy2by(int y)
{
	return /* dispY + */ y/DMimage_getzoomrate();
}

static int sx2bufx(int x)
{
	int ix;
	menu_getbuttonxy(&patternmenu, itemPatBuf, &ix,NULL,NULL,NULL);
	int zr = DMimage_getzoomrate();
	return (x - ix) / zr;
}

static int sy2bufy(int y)
{
	int iy;
	menu_getbuttonxy(&patternmenu, itemPatBuf, NULL,&iy,NULL,NULL);
	int zr = DMimage_getzoomrate();
	return (y - iy) / zr;
}

static int bufx2sx(int x)
{
	int ix;
	menu_getbuttonxy(&patternmenu, itemPatBuf, &ix,NULL,NULL,NULL);
	int zr = DMimage_getzoomrate();
	return ix+x*zr;
}

static int bufy2sy(int y)
{
	int iy;
	menu_getbuttonxy(&patternmenu, itemPatBuf, NULL,&iy,NULL,NULL);
	int zr = DMimage_getzoomrate();
	return iy+y*zr;
}

// ● パターンデータの複製を作る

static PAT *dupPAT(PAT *pat)
{
	PAT *newpat;
	if (constPAT(newpat) == NULL)
		return NULL;
	*newpat = *pat;
	if ((newpat->patbuf = malloc(pat->patbufsize)) == NULL) {
		destroyPAT(newpat);
		return NULL;
	}
	memcpy(newpat->patbuf, pat->patbuf, pat->patbufsize);
	return newpat;
}

// ● パターンデータをパターンリストに追加する

static void add_patlist(PAT *pat)
// pat: 追加するパターンデータ。複製は作られず、そのまま追加される。
{
	if (patlist == NULL)
		patlist = pat;
	else {
		PAT *p;
		for (p = patlist;  p->next != NULL;  p = p->next)
			;
		p->next = pat;
	}
}

// ● パターンデータをパターンリストから削除する

static void del_patlist(PAT *pat)
// pat : 削除するパターンデータへのポインタ。
//       パターンリスト内にこのポインタがあれば、その部分が削除される。
{
	PAT *prepp,*pp;
	prepp = NULL;
	for (pp=patlist; pp!=NULL; ) {
		PAT *nextpp;
		nextpp = pp->next;
		if (pp == pat) {
			if (prepp != NULL)
				prepp->next = pp->next;
			else
				patlist     = pp->next;
			destroyPAT(pp);
		} else
			prepp = pp;
		pp = nextpp;
	}
}


// パターンリスト全体を消去し、メモリを解放する


static void clear_patlist()
{
	PAT *pp,*next;
	for (pp=patlist; pp!=NULL; )
	{
		next = pp->next;
		del_patlist(pp);
		pp = next;
	}
}


/*--------------------------------------------------------*/
/*    パターンを画面上で範囲指定し、バッファに登録する    */
/*--------------------------------------------------------*/


// ● ユーザーにパターンを選択(範囲指定)させる


static int selectPattern(PAT *pat)
// 返値 : 0=選択が普通に終了した  1=選択がキャンセルされた
//        -1=メモリ不足で選択できない
{
	int step;  int x1,y1,x2,y2;  int r;
	int lat2xlen,lat2ylen; DMimage_getlatticesize(&lat2xlen,&lat2ylen);
	r = 0;
	void drawcsr(int msx, int msy)
	{
		int tx = DMimage_getx(msx), ty = DMimage_gety(msy);
		if (step==1)
		{
			int p1=x1,p2=y1,p3=tx,p4=ty;
			if (p1 > p3) swap(p1,p3);
			if (p2 > p4) swap(p2,p4);
			if (areaadj)
			{
				p1-=p1%lat2xlen, p2-=p2%lat2ylen;
				p3=p3-p3%lat2xlen+lat2xlen-1, p4=p4-p4%lat2ylen+lat2ylen-1;
			}
			EIMboxline(p1,p2,p3,p4,white,DrawXOR);
		}
	}
	step = 0;
	int zr = DMimage_getzoomrate();
	for (;;)
	{
		int prex,prey;
		if (step == 0 || areaadj)
			DMdispcsr(ms.x,ms.y);
		drawcsr((prex=ms.x),(prey=ms.y));
		for (;;)
		{
			ms_get(&ms);
			if (ms.dx!=0 || ms.dy!=0 || ms.btn1!=OFF || ms.btn2!=OFF ||
				key_chk()!=0)
				break;
		}
		if (step == 0 || areaadj)
			DMerasecsr();
		drawcsr(prex,prey);		// 消去
		if (step==0 || step==1)
			scrollForCsr(1,1);
		else
			scrollForCsr((x2-x1+1)*zr,(y2-y1+1)*zr);
		if (ms.btn1 == OFFON)
		{
			if (step==0)				// 範囲指定開始
				step=1,x1=DMimage_getx(ms.x),y1=DMimage_gety(ms.y);
			else if (step==1) 		// 範囲指定完了
			{
				x2=DMimage_getx(ms.x),y2=DMimage_gety(ms.y);
				if (x1>x2)  swap(x1,x2);
				if (y1>y2)  swap(y1,y2);
				if (areaadj)
				{
					x1 = x1 - x1 % lat2xlen;
					y1 = y1 - y1 % lat2ylen;
					x2 = x2 - x2 % lat2xlen + lat2xlen - 1;
					y2 = y2 - y2 % lat2ylen + lat2ylen - 1;
				}
				int ixlen,iylen;
				menu_getbuttonxy(&patternmenu,itemPatBuf,NULL,NULL,&ixlen,&iylen);
				if (x2-x1+1 > ixlen/PATZOOM)
					x2 = x1 + ixlen/PATZOOM - 1;
				if (y2-y1+1 > iylen/PATZOOM)
					y2 = y1 + iylen/PATZOOM - 1;
				int dispx,dispy;
				DMimage_getdispxy(&dispx,&dispy);
				ms.x=(x1-dispx)*zr, ms.y=(y1-dispy)*zr;
				mous_setpos(&ms,ms.x,ms.y);
				scrollForCsr(1,1);
				pat->xlen = x2-x1+1;
				pat->ylen = y2-y1+1;
				{
					int gcd(int a, int b)
					{
						if (b == 0)	return a;
						else		return gcd(b, a%b);
					}
					int g = gcd(zr,zr);
					pat->zoomx = zr / g;
					pat->zoomy = zr / g;
				}
				{
					int xlen,ylen;
					xlen = x2-x1+1;
					ylen = y2-y1+1;
					if (mode == MODE32K)
						pat->patbufsize = 2 * xlen * ylen;
					else
						pat->patbufsize = 4 * ((xlen+7)/8) * ylen;
				}
				if ((pat->patbuf = malloc(pat->patbufsize)) != NULL)
				{
					page_edit();
					EIMgetblock(pat->patbuf, x1,y1,x2-x1+1,y2-y1+1);
					page_menu();
				}
				else
				{
					r = -1;
					break;
				}
				break;
			}
		}
		else if (ms.btn2 == OFFON)
		{
			if (step == 1)
				step = 0;
			else
			{
				r = 1;
				break;
			}
		}
	}
	return r;
}


// ● ユーザーに､ パターンをパターンバッファへ登録させる


static int do_storePattern(PAT *pat)
// pat をメモリ中で複製して、それをリストに追加する
{
	PAT *newpat;
	if ((newpat = dupPAT(pat)) != NULL)
	{
		newpat->selected = NO;
		newpat->nodisp = NO;
		newpat->next = NULL;
		BUTTON *ip;
		add_patlist(newpat);
		return 0;
	}
	else
		return -1;
}


/*--------------------------------------------------------*/
/*    パターンを編集画面からパターンバッファへ登録する    */
/*--------------------------------------------------------*/


static int storePattern_sub(PAT *pat)
{
	int r = 0;
	int step;  int x1,y1,x2,y2;
	void drawcsr(int msx, int msy)
	{
		int tx,ty;
		tx = sx2bx(msx);
		ty = sy2by(msy);
		page_edit();
		grboxline(tx,ty,pat->xlen*pat->zoomx,pat->ylen*pat->zoomy,white,DrawXOR);
		page_menu();
	}
	int zr = DMimage_getzoomrate();
	for (;;)
	{
		int prex,prey;
		DMdispcsr(ms.x,ms.y);
		drawcsr((prex=ms.x),(prey=ms.y));
		for (;;)
		{
			ms_get(&ms);
			if (ms.dx!=0 || ms.dy!=0 || ms.btn1!=OFF || ms.btn2!=OFF ||
			 key_chk()!=0)
				break;
		}
		DMerasecsr();
		drawcsr(prex,prey);		// 消去
		// カーソル移動をパターンバッファ内に制限する
		{
			int ix,iy,ixlen,iylen;
			menu_getbuttonxy(&patternmenu,itemPatBuf,&ix,&iy,&ixlen,&iylen);
			ms.x = _min(_max(ix, ms.x),
						ix+ixlen - pat->xlen*pat->zoomx*zr);
			ms.y = _min(_max(iy, ms.y),
						iy+iylen - pat->ylen*pat->zoomy*zr);
			mous_setpos(&ms,ms.x,ms.y);
			scrollForCsr(pat->xlen*pat->zoomx*zr,pat->ylen*pat->zoomy*zr);
		}
		if (ms.btn1 == OFFON)
		{
			// PAT 構造体の完全化と､ パターンリストへの追加
			PAT newpat;
			newpat = *pat;
			newpat.name[0] = '\0';
			newpat.subname[0] = '\0';
			newpat.selected = NO;
			newpat.nodisp = NO;
			int ix,iy;
			menu_getbuttonxy(&patternmenu,itemPatBuf,&ix,&iy,NULL,NULL);
			newpat.bufx = sx2bx(ms.x - ix);
			newpat.bufy = sy2by(ms.y - iy);
			if (do_storePattern(&newpat) != 0)
				r = -1;
			disp_patterns_all_new();
			if (r != 0)
				break;
		}
		if (ms.btn2 == OFFON)
			break;
	}
	return r;
}


static int storePattern()
// 返値 0=成功  -1=メモリ不足
{
	PAT pat;
	int r;
	for (;;)
	{
		menu_erase(&patternmenu);
		resetPage1();
		DMimage_refresh();
		r = selectPattern(&pat);
		setPage1();
		menu_disp(&patternmenu);
		if (r == 0) {
			int r2 = storePattern_sub(&pat);
			free(pat.patbuf);
			if (r2 < 0)
				return -1;
		} else if (r == 1)
			break;
		else if (r < 0)
			return -1;
	}
	return 0;
}


/*--------------------------------------------------------*/
/*                   パターンを複製する                   */
/*--------------------------------------------------------*/


static int duplicatePattern(PAT *pp)
{
	PAT newpat;
	newpat = *pp;
	newpat.bufx += 4;
	newpat.bufy += 4;
	return do_storePattern(&newpat);
}


/*--------------------------------------------------------*/
/*   パターンバッファをクリック･ドラックしたときの処理    */
/*--------------------------------------------------------*/


static void touchPat_1(PAT *pp)
/*
	パターンバッファ上のパターンを左クリック／左ドラッグしたときの処理
*/
{
	int zr = DMimage_getzoomrate();
	while (ms.btn1 == OFFON || ms.btn1 == ON)
	{
		DMdispcsr(ms.x, ms.y);
		do
		{
			ms_get(&ms);
		} while (ms.dx==0 && ms.dy==0 && ms.btn1==ON);
		DMerasecsr();
		if (ms.dx != 0 || ms.dy != 0)	// ドラッグされたなら
		{
			pp->nodisp = YES;
			disp_patterns_all_new();
			int rx,ry;
			rx = (ms.x-ms.dx) - bufx2sx(pp->bufx);
			ry = (ms.y-ms.dy) - bufy2sy(pp->bufy);
			ms.x-=rx,rx=0;
			ms.y-=ry,ry=0;
			mous_setpos(&ms,ms.x,ms.y);
			void drawpatcsr(int msx,int msy)
			{
				int x1,y1;
				x1 = bufx2sx(sx2bufx(msx - rx));
				y1 = bufy2sy(sy2bufy(msy - ry));
				grboxline(x1,y1,pp->xlen*pp->zoomx*zr,
						  pp->ylen*pp->zoomy*zr,White,DrawXOR);
			}
			while (ms.btn1 == ON)
			{
				int prex,prey;
				DMdispcsr(ms.x, ms.y);
				drawpatcsr((prex=ms.x),(prey=ms.y));
				do
				{
					ms_get(&ms);
				} while (ms.dx==0 && ms.dy==0 && ms.btn1==ON);
				DMerasecsr();
				drawpatcsr(prex,prey);
				// limitCsrPos();
				// カーソル移動をパターンバッファ内に制限する
				{
					int ix,iy,ixlen,iylen;
					menu_getbuttonxy(&patternmenu,itemPatBuf,&ix,&iy,&ixlen,&iylen);
					ms.x = _min(_max(ix, ms.x),
								ix+ixlen - pp->xlen*pp->zoomx*zr);
					ms.y = _min(_max(iy, ms.y),
								iy+iylen - pp->ylen*pp->zoomy*zr);
					mous_setpos(&ms,ms.x,ms.y);
					scrollForCsr(pp->xlen*pp->zoomx*zr,
								 pp->ylen*pp->zoomy*zr);
				}
			}
			pp->bufx = sx2bufx(ms.x-rx);
			pp->bufy = sy2bufy(ms.y-ry);
			pp->nodisp = NO;
		}
		else						// クリックされたなら
		{
			if (!pp->selected) {
				pp->selected = YES;
				//if (selnum < SELNUM) {
				//	selpat[selnum] = pp;
				//	pp->selected = YES;
				//	selnum++;
				//}
			} else {
				pp->selected = NO;
				//int i;
				//for (i=0; i < SELNUM; i++) {
				//	if (selpat[i] == pp) {
				//		if (i < SELNUM-1)
				//			memcpy(&selpat[i],&selpat[i+1],sizeof(PAT*) * (SELNUM-i-1));
				//		selnum--;
				//		selpat[selnum] = NULL;
				//	}
				//}
			}
		}
	}
	disp_patterns_all_new();
}


static int touchPat_2(PAT *pp)
/*
	パターンバッファ上のパターンが右クリックされたときの処理
	返値: 0=成功 -1=メモリ不足
*/
{
	int err = 0;
	curpat = pp;
	if (menu_dispxy(ms.x, ms.y, &patsubmenu) != 0)
		return -1;
	for (;;) {
		DMdispcsr(ms.x,ms.y);
		ms_get(&ms);
		DMerasecsr();
		limitCsrPos();
		if (ms.btn1 == OFFON) {
			int a; int ax,ay;
			a = menu_where(ms.x,ms.y,&patsubmenu, &ax,&ay,NULL);
			if (a == SitemPatName) {
				int r;
				int ix,iy,ixlen,iylen;
			    menu_getbuttonxy(&patsubmenu,SitemPatName,
			    				 &ix,&iy,&ixlen,&iylen);
				r = editStr(ix+1,iy+1,ixlen/8,curpat->name,41,-1);
			} else if (a == SitemPatSubName) {
				int r;
				int ix,iy,ixlen,iylen;
			    menu_getbuttonxy(&patsubmenu,SitemPatSubName,
			    				 &ix,&iy,&ixlen,&iylen);
				r = editStr(ix+1,iy+1,ixlen/8,curpat->subname,15,-1);
			} else if (a == SitemDup) {
				err = duplicatePattern(curpat);
				break;
			} else if (a == SitemDelete) {
				del_patlist(curpat);
				break;
			} else if (a == SitemPut)
			{
				MON;
				menu_erase();
				menu_erase();
				resetPage1();
				for (;;)
				{
					void drawcsr(int msx,int msy)
					{
						MOFF;
						int tx=DMimage_getx(msx),ty=DMimage_gety(msy);
						EIMrboxline(tx,ty,curpat->xlen,curpat->ylen,
									white,DrawXOR);
						MON;
					}
					int prex,prey;
					if (areaadj)
						DMdispcsr(ms.x,ms.y);
					drawcsr((prex=ms.x),(prey=ms.y));
					do
					{
						ms_get(&ms);
					} while (ms.dx==0 && ms.dy==0 &&
							 ms.btn1==OFF && ms.btn2==OFF && key_chk()==0);
					if (areaadj)
						DMerasecsr();
					drawcsr(prex,prey);
					int zr = DMimage_getzoomrate();
					scrollForCsr(curpat->xlen*zr, curpat->ylen*zr);
					if (ms.btn1 == OFFON)
					{
						int dx=DMimage_getx(ms.x),dy=DMimage_gety(ms.y);
						matte_putblock(dx,dy,curpat->xlen,curpat->ylen,
									   curpat->patbuf, blkop);
					}
					if (ms.btn2 == OFFON)
					{
						break;
					}
				}
				MOFF;
				setPage1();
				menu_disp(&patternmenu);
				goto end;
			}
		} else if (ms.btn2 == OFFON)
			break;
	}
	menu_erase();
	disp_patterns_all_new();
end:
	return err;
}


static int touchPatBuf(int btn)
// btn : 1=左ボタン 2=右ボタン
{
	PAT *pp;
	pp = jdgPattern(ms.x, ms.y);
	if (pp == NULL || pp->nodisp)
		return 0;
	if (btn == 1)
		touchPat_1(pp);
	else
		return touchPat_2(pp);
	return 0;
}


/*--------------------------------------------------------*/
/*                  パターンの保存･読込                   */
/*--------------------------------------------------------*/


static	bool	sw_savesel;		// SWitch to SAVE SELected-patterns
static	bool	sw_loadadd;		// SWitch to LOAD patterns ADDitionally


// typedef struct _pat {
// 	struct _pat	*next;			// リスト化のためのポインタ
// 	int			xlen, ylen;		// パターンの大きさ
// 	int			bufx, bufy;		// パターンバッファ内での位置
// 	int			patbufsize;		// パターンデータのバイト数
// 	char		*patbuf;		// パターンデータへのポインタ
// 	bool		selected;		// 選択されているなら YES
// 	bool		disp;			// パターンバッファ表示時に表示するかどうか
// } PAT;


static void do_savePattern(char **filelist)
{
	char pathbuf[_MAX_PATH];
	FILE *fp;
	add_fname_ext(pathbuf, filelist[0], "PAT");
	if ((fp = fopen(filelist[0], "wb")) == NULL)
		return;
	PAT *pp;
	for (pp=patlist; pp!=NULL; pp=pp->next)
	{
		if (sw_savesel)
		{
			if (pp->selected)
			{
				PAT pathead;
				pathead = *pp;
				pathead.selected = NO;	// 選択スイッチは OFF にしてセーブ
				fwrite(&pathead, sizeof(PAT), 1, fp);
				fwrite(pp->patbuf, 1, pp->patbufsize, fp);
			}
		}
		else
		{
			fwrite(pp, sizeof(PAT), 1, fp);
			fwrite(pp->patbuf, 1, pp->patbufsize, fp);
		}
	}
	fclose(fp);
}


static void do_loadPattern(char **filelist)
{
	FILE *fp;
	PAT pat, *pp, *prepp;
	if ((fp = fopen(filelist[0], "rb")) == NULL)
		return;
	if (!sw_loadadd)
	{
		// 新規読み込みの場合
		clear_patlist();
		prepp = NULL;
	}
	else
	{
		// 追加読み込みの場合
		if (patlist == NULL)
			prepp = NULL;
		else
		{
			for (pp = patlist;  pp->next != NULL;  pp = pp->next)
				;
			prepp = pp;
		}
	}
	fread(&pat, sizeof(PAT), 1, fp);
	for ( ;  !feof(fp);  prepp = pp) {
		if ((pp = malloc(sizeof(PAT))) == NULL)
			break;
		(prepp==NULL ? patlist = pp : prepp->next = pp);
		*pp = pat;
		if ((pp->patbuf = malloc(pp->patbufsize)) == NULL)
			break;
		fread(pp->patbuf, 1, pp->patbufsize, fp);
		fread(&pat, sizeof(PAT), 1, fp);
	}
	if (prepp != NULL)
		prepp->next = NULL;
	fclose(fp);
}


static void save_all_patterns()
{
	sw_savesel = NO;
	file_menu("すべてのパターンを保存する [.PAT]", do_savePattern);
}


static void save_sel_patterns()
{
	sw_savesel = YES;
	file_menu("選択中のパターンを保存する [.PAT]", do_savePattern);
}


static void load_patterns_new()
{
	sw_loadadd = NO;
	file_menu("パターンを新規に読み込む", do_loadPattern);
}


static void load_patterns_add()
{
	sw_loadadd = YES;
	file_menu("パターンを追加読み込みする", do_loadPattern);
}


/*--------------------------------------------------------*/
/*                 スプライトデータの作成                 */
/*--------------------------------------------------------*/


static void output_sprite_data_C(char *fname)
{
	FILE *fp;
	PAT *pp;
	if ((fp = fopen(fname,"w")) == NULL)
		return;
	fprintf(fp,"static char sprite_32k[][512] = {\n");
	for (pp = patlist;  pp != NULL;  pp = pp->next)
	{
		char *name = NULL;
		int px,py;
		if (!pp->selected || pp->nodisp)
			continue;
		// 出力するパターン名へのポインタを name に設定する
		if (pp->name[0] != 0)
			name = pp->name;
		else if (pp->subname[0] != 0)
			name = pp->subname;
		if (name != NULL)
			fprintf(fp, "\n\t/* %s */\n", name);
		// パターンデータを出力する
		for (py = 0;  py < (pp->ylen+15)/16;  py++)
		{
			for (px = 0;  px < (pp->xlen+15)/16;  px++)
			{
				int line,clm;
				for (line = 0;  line < 32;  line++) {
					fprintf(fp, (line==0 ? "\t{ " : "\t  "));
					for (clm = 0;  clm < 8;  clm++) {
						int ix,iy,dat;
						ix = px*16 + (line%2)*8 + clm;
						iy = py*16 + line/2;
						if (ix >= pp->xlen || iy >= pp->ylen)
							dat = 0;
						else
							dat = get_pat_pixel(pp, ix, iy);
						if (dat == 0)
							dat |= 0x8000;	// マスクビットをセット
						fprintf(fp, "%3d,%3d", dat&0xff, dat>>8);
						fprintf(fp, (clm < 8-1 ? "," : ""));
					}
					fprintf(fp, (line < 32-1 ? ",\n" : " }"));
				}
				fprintf(fp, (pp->next != NULL ? ",\n" : "\n"));
			}
		}
	}
	fprintf(fp,"};\n");
	fclose(fp);
}


static void output_sprite_data_BASIC(char *fname)
{
	FILE *fp;
	PAT *pp;
	if ((fp = fopen(fname,"w")) == NULL)
		return;
	int lnum=10000;
	fprintf(fp,"%d ' 32768色 スプライトパターンデータ\n", lnum);
	lnum += 10;
	for (pp = patlist;  pp != NULL;  pp = pp->next)
	{
		char *name = NULL;
		int px,py;
		if (!pp->selected || pp->nodisp)
			continue;
		// 出力するパターン名へのポインタを name に設定する
		if (pp->name[0] != 0)
			name = pp->name;
		else if (pp->subname[0] != 0)
			name = pp->subname;
		fprintf(fp, "%d '  %s\n", lnum, (name!=NULL?name:""));
		lnum += 10;
		// パターンデータを出力する
		int xpatn,ypatn;
		xpatn = (pp->xlen+15)/16;
		ypatn = (pp->ylen+15)/16;
		for (py = 0;  py < ypatn;  py++)
		{
			for (px = 0;  px < xpatn;  px++)
			{
				int line,clm;
				for (line = 0;  line < 32;  line++) {
					if (xpatn > 1 || ypatn > 1)
					{
						fprintf(fp,"%d '    (%d,%d)\n", lnum, px,py);
						lnum += 10;
					}
					fprintf(fp,"%d DATA ",lnum);
					lnum += 10;
					for (clm = 0;  clm < 8;  clm++) {
						int ix,iy,dat;
						ix = px*16 + (line%2)*8 + clm;
						iy = py*16 + line/2;
						if (ix >= pp->xlen || iy >= pp->ylen)
							dat = 0;
						else
							dat = get_pat_pixel(pp, ix, iy);
						if (dat == 0)
							dat |= 0x8000;	// マスクビットをセット
						fprintf(fp, "%04x", dat);
						if (clm < 8-1)
							fprintf(fp, ",");
					}
					fprintf(fp,"\n");
				}
			}
		}
	}
	fclose(fp);
}


static void output_sprite_data_binary(char *fname, int info)
/*
	info :
		スプライト情報ファイル(番号とスプライト名の対応)を出力するか
		0 = 出力しない  1 = 出力する
*/
{
	FILE *fp, *fp_info;  PAT *pp;  int patn;
	if ((fp = fopen(fname,"wb")) == NULL)
		return;
	if (info)
	{
		if ((fp_info = fopen(trans_fname_ext(fname,"SPI"), "w")) == NULL)
			{ fclose(fp);  return; }
	}
	for (pp = patlist, patn=0;  pp != NULL;  pp = pp->next, patn++)
	{
		int px,py;
		if (!pp->selected || pp->nodisp)
			continue;
		if (info)
		{
			char *name = NULL;
			// 出力するパターン名へのポインタを name に設定する
			if (pp->name[0] != 0)
				name = pp->name;
			else if (pp->subname[0] != 0)
				name = pp->subname;
			fprintf(fp_info, "%3d: %s\n", patn, (name==NULL ? "###" : name));
		}
		// パターンデータを出力する
		for (py = 0;  py < (pp->ylen+15)/16;  py++)
		{
			for (px = 0;  px < (pp->xlen+15)/16;  px++)
			{
				int xx,yy;
				for (yy=0; yy<16; yy++)
				{
					int tdat;
					for (xx=0; xx<16; xx++)
					{
						int ix,iy,dat;
						ix = px*16 + xx;
						iy = py*16 + yy;
						if (ix >= pp->xlen || iy >= pp->ylen)
							dat = 0;
						else
							dat = get_pat_pixel(pp, ix, iy);
						if (mode == MODE32K)
						{
							if (dat == 0)
								dat |= 0x8000;	// マスクビットをセット
							putc(dat & 0xff, fp);
							putc((dat >> 8) & 0xff, fp);
						}
						else
						{
							if (xx%2 == 0)
								tdat = dat & 0xf;
							else
								putc((tdat<<4)|(dat&0xf), fp);
						}
					}
				}
			}
		}
	}
	if (info)
		fclose(fp_info);
	fclose(fp);
}


static	void	do_makesprite(char **filelist, int format)
{
	char pathbuf[_MAX_PATH];
	switch (format)
	{
	case 0:
		add_fname_ext(pathbuf, filelist[0], "C");
		output_sprite_data_C(pathbuf);
		break;
	case 1:
		add_fname_ext(pathbuf, filelist[0], "BAS");
		output_sprite_data_BASIC(pathbuf);
		break;
	case 2:
		add_fname_ext(pathbuf, filelist[0], "SPB");
		output_sprite_data_binary(pathbuf, 0);
		break;
	case 3:
		add_fname_ext(pathbuf, filelist[0], "SPB");
		output_sprite_data_binary(pathbuf, 1);
		break;
	}
}


static	void	conv_to_sprite()
{
	char *xi[] = {
		"ファイル形式",
		"[.C  ] Ｃ言語の配列",
		"[.BAS] BASICのDATA",
		"[.SPB] ベタ(情報なし)",
		"[.SPB] ベタ(情報あり)",
		NULL
	};
	file_menu_exp("選択中のパターンをスプライトデータに変換する",
				  do_makesprite, xi);
}


/*--------------------------------------------------------*/
/*                パターンを文字列になおす                */
/*--------------------------------------------------------*/


static void do_characterize(char **filelist)
{
	char pathbuf[_MAX_PATH];
	FILE *fp;
	PAT *pp;
	add_fname_ext(pathbuf, filelist[0], "PTS");
	if ((fp = fopen(pathbuf,"w")) == NULL)
		return;
	for (pp=patlist; pp!=NULL; pp=pp->next)
	{
		if (!pp->selected || pp->nodisp)
			continue;
		char *name = NULL;
		if (pp->name[0] != 0)
			name = pp->name;
		else if (pp->subname[0] != 0)
			name = pp->subname;
		if (name != NULL)
			fprintf(fp, "%s\n", pp->name);
		int ix,iy;
		for (iy=0; iy < pp->ylen; iy++)
		{
			for (ix=0; ix < pp->xlen; ix++)
			{
				if (mode == MODE32K)
				{
					fprintf(fp, "%04x", get_pat_pixel(pp,ix,iy));
					if (ix+1 < pp->xlen)
						fprintf(fp, " ");
				}
				else
					fprintf(fp, "%01x", get_pat_pixel(pp,ix,iy));
			}
			fprintf(fp, "\n");
		}
		fprintf(fp, "\n");
	}
	fclose(fp);
}


static void conv_to_string()
{
	file_menu("選択中のパターンを文字列データ [.PTS] に変換",
			  do_characterize);
}


/*--------------------------------------------------------*/
/*                  順表示アニメーション                  */
/*--------------------------------------------------------*/


static void animation()
{
	if (patlist == NULL)
		return;
	erase_patterns_all();
	PAT *pp;
	for (;;) {
		for (pp=patlist; pp!=NULL; pp=pp->next) {
			ms_get(&ms);
			limitCsrPos();
			if (ms.btn1 == OFFON || ms.btn2 == OFFON)
				goto _end;
			if (pp->selected) {
				pp->selected = NO;
				if (ryosuke_pat)	// 作者オプション２がオンなら消す
					erase_patterns_all();
				dispOnePattern(pp, NO, YES);
				int i;
				for (i=0; i<5; i++) {
					wait_vsync();
				}
				pp->selected = YES;
			}
		}
	}
_end:
	disp_patterns_all_new();
}


/*--------------------------------------------------------*/
/*                選択／表示スイッチの操作                */
/*--------------------------------------------------------*/


static void switch_select_and_disp(int itemnum)
// itemnum : クリックされたメニューアイテムの番号
{
	PAT *pp;
	switch (itemnum)
	{
	case itemSelectAll:
		for (pp = patlist;  pp != NULL;  pp = pp->next)
			if (!pp->nodisp)	pp->selected = YES;
		break;
	case itemSelectNothing:
		for (pp = patlist;  pp != NULL;  pp = pp->next)
			if (!pp->nodisp)	pp->selected = NO;
		break;
	case itemSelectReverse:
		for (pp = patlist;  pp != NULL;  pp = pp->next)
			if (!pp->nodisp)	pp->selected = !pp->selected;
		break;
	case itemDispAll:
		for (pp = patlist;  pp != NULL;  pp = pp->next)
			pp->nodisp = NO;
		break;
	case itemDispNothing:
		for (pp = patlist;  pp != NULL;  pp = pp->next)
			pp->nodisp = YES, pp->selected = NO;
		break;
	case itemDispReverce:
		for (pp = patlist;  pp != NULL;  pp = pp->next)
		{
			if (pp->nodisp)
				pp->nodisp = NO;
			else
				pp->nodisp = YES, pp->selected = NO;
		}
	}
	disp_patterns_all_new();
}


/*--------------------------------------------------------*/
/*             ｢パターン編集｣コマンド 主処理              */
/*--------------------------------------------------------*/


void commandPattern()
{
	MOFF;
	// EIMbackup();   // 編集画面を保存
	// if (selnum == -1) {
	// 	memset(selpat, 0, sizeof(PAT*) * SELNUM);
	// 	selnum = 0;
	// }
	setPage1();
	menu_disp(&patternmenu);
	for (;;)
	{
		DMdispcsr(ms.x, ms.y);
		do
		{
			ms_get(&ms);
		} while (ms.dx==0 && ms.dy==0 && ms.btn1==OFF && ms.btn2==OFF && key_chk()==0);
		DMerasecsr();
		// scrollForCsr(1,1);
		limitCsrPos();
		if (ms.btn1 == OFFON)
		{
			int a;  int ax,ay;  SCROLLBAR *sbarp;
			a = menu_where(ms.x,ms.y,&patternmenu, &ax,&ay,&sbarp);
			switch (a)
			{
			int r;
			PAT *pp;
			case itemScrollBar:
				menu_touchscrollbar(sbarp, ax,ay);
				break;
			case itemExit:
				goto _end;
			case itemPatBuf:
				touchPatBuf(1);
				break;
			case itemStorePattern:
				if (storePattern() != 0)
					goto nomem;
				break;
			case itemDeleteSelPat:
				if (check_yes_no("選択中のパターンを抹消します。\nよろしいですか？")
					== 0)
				{
					for (pp=patlist; pp!=NULL; )
					{
						PAT *next = pp->next;
						if (pp->selected)
							del_patlist(pp);
						pp = next;
					}
					disp_patterns_all_new();
				}
				break;
			case itemDupSelPat:
				for (pp=patlist; pp!=NULL; pp=pp->next)
					if (pp->selected)
						duplicatePattern(pp);
				disp_patterns_all_new();
				break;
			case itemDispOffSelPat:
				for (pp=patlist; pp!=NULL; pp=pp->next)
					if (pp->selected)
						pp->selected = NO, pp->nodisp = YES;
				disp_patterns_all_new();
				break;
			case itemSaveAllPattern:
				save_all_patterns();
				break;
			case itemNewLoadPattern:
				load_patterns_new();
				disp_patterns_all_new();
				break;
			case itemSaveSelPattern:
				save_sel_patterns();
				break;
			case itemAddLoadPattern:
				load_patterns_add();
				disp_patterns_all_new();
				break;
			case itemConvToSprite:
				conv_to_sprite();
				break;
			case itemSelectAll:
			case itemSelectNothing:
			case itemSelectReverse:
			case itemDispAll:
			case itemDispNothing:
			case itemDispReverce:
				switch_select_and_disp(a);
				break;
			case itemSort:
				sort_patlist();
				disp_patterns_all_new();
				break;
			case itemAnimation:
				animation();
				break;
			case itemConvToString:
				conv_to_string();
			}
		}
		else if (ms.btn2 == OFFON)
		{
			int a;  int ax,ay;
			a = menu_where(ms.x,ms.y,&patternmenu, &ax,&ay,NULL);
			if (a == itemPatBuf)
			{
				if (touchPatBuf(2) != 0)
					goto nomem;
			} else
				break;
		}
	}
_end:
	menu_erase(&patternmenu);
	resetPage1();
	DMimage_refresh();	// 編集画面を復帰
	MON;
	return;
nomem:
	menu_erase(&patternmenu);
	resetPage1();
	DMimage_refresh();	// 編集画面を復帰
	dispAttentionMsg("記憶容量不足のため、パターンの編集に支障があります");
	MON;
}



/* end of pattern.c */

