/*
	ARTemis (Graphic Editor for FM-TOWNS)
	(c) MATSUUCHI Ryosuke 1992,1993

	filemenu.c
*/

// #define	DEBUG

#include <stdio.h>
#include <string.h>
#include <dos.h>
#include <malloc.h>
#include <ctype.h>

#include "ge.h"
#include <direct.h>
#include "dispman.h"


#define	GETITEMXY(n)	menu_getbuttonxy(NULL,(n),&ix,&iy,NULL,NULL)
#define	GETITEMXYS(n)	menu_getbuttonxy(NULL,(n),&ix,&iy,&ixlen,&iylen)


#define	CHARWID	6
#define	CHARHT	12

/*--------------------------------------------------------*/
/*                     メニューの定義                     */
/*--------------------------------------------------------*/


#define	FLISTX		168
#define	FLISTY		57
#define	FLISTYLEN	12*10
#define	FLISTXLEN	6*24
#define	FNAMEX		16
#define	FNAMEY		184
#define	FNAMEXLEN	(6*46+2)
#define	PATHX		74
#define	PATHY		22
#define	PATHXLEN	(6*37+2)
#define	MASKX		74
#define	MASKY		38
#define	MASKXLEN	(6*37+2)
#define	EXTX		12
#define	EXTY		76
#define	DRVX		(16+12)
#define	DRVY		38
#define	DRVXW		30
#define	DRVYW		16

/*
#define	itemFName	2
#define	itemFList	3
#define	itemPath	5
#define	itemMask	7
#define	itemExec	8
#define	itemCancel	9
#define	itemDiskF	11
#define	itemDriveInc	14
#define	itemDriveDec	13
#define	itemDrive	15
#define	itemX		16
*/
#define	itemX_num	16

#define	itemFormat	10
#define	itemFCTiff	11
#define	itemFTiff	12
#define	itemFBeTa	13


static void disp_fname(),disp_now_path(),disp_mask_name();

static void dspNameList(int pos);
#define	XITEMMAX	10
static SELECTOR_ELEMENT filemenu_selx[XITEMMAX];
#define	SELPARA(n)		(setup_sel[n].var)
static void disp_filemenu(), erase_filemenu();

#include "filemenu.md"

/*--------------------------------------------------------*/
/*                     内部変数の宣言                     */
/*--------------------------------------------------------*/


#define	DIRMA	1	/* 0=ディレクトリバッファをいちいち確保  1=まとめて確保 */

typedef struct
{
#if (DIRMA==1)
	char	name[15];
#else
	char	*name;
#endif
	bool	subdir;	// ディレクトリ属性付きのエントリなら YES
	long	size;
} DIR;


#define	MAXWILD	300
#if (DIRMA==1)
static	DIR		*namelist = NULL;
#else
static	bool	list_inited = NO;
static	DIR		namelist[MAXWILD];
#endif
static	int		namenum;

static	char	fname[128] = {0};
static	char	nowpath[128] = "ARTemis_non_initialized";
static	char	mask[128] = "*.*";
static	int		csrx = 0;				// ファイル名編集カーソルの位置
static	int		nowdrive = -1;			// 現在表示しているドライブ
// ドライブ選択状態 3 とおり
#define	DISPLAY		0
#define	SELECTING	1
#define	INVALID		2
static	int		drive_selecting = DISPLAY;
static	int		cur_diskfree = -1;		// 選択ドライブの残り容量

static unsigned _curdrive;
static char _curpath[128];


/*--------------------------------------------------------*/
/*                        補助処理                        */
/*--------------------------------------------------------*/


// ■ ディスクの残り容量を得る
//---------------------------------------------------------------------------

static int diskfree(int drive)
// drive: 0=デフォルト 1=A 2=B ...
// 返値: -1=ドライブ指定が無効、0以上=残りバイト数
{
	struct diskfree_t info;
	if (_dos_getdiskfree(drive,&info) != 0)
		return -1;
	unsigned long ac,spc,bps;
	ac = info.avail_clusters;
	spc = info.sectors_per_cluster;
	bps = info.bytes_per_sector;
	return ac*spc*bps;
}


// ■ ディスクの残り容量を表示する
//---------------------------------------------------------------------------

static void disp_diskfree()
{
	int x,y;
	// int drive;
	// if (nowpath[1] == ':')
	// 	drive = toupper(nowpath[0]) - 'A' + 1;
	// else
	// 	drive = 0;
	int ix,iy;
	GETITEMXY(itemDiskF);
	x = ix,  y = iy;
	grboxfill(x,y,CHARWID*6,CHARHT,DMgetmenuplt(COL_menu),DrawNORMAL);
	if (drive_selecting == DISPLAY)
	{
		char msgbuf[10];
		sprintf(msgbuf, "%6d", cur_diskfree/1024);
		ARTputstr12(x,y,msgbuf,DMgetmenuplt(White),DMgetmenuplt(COL_menu));
	}
}


// ■ ディレクトリ上のファイル名一覧を得る
//---------------------------------------------------------------------------


#define	attrSUBDIR	0x10


static int getdir()
// 返値 0=成功  -1=メモリ不足
{
	struct find_t dirbuf;
	char pathbuf[128], pathbuf2[128];
	int r;
	DEBUG_MSG("getdir begin");
	namenum = 0;
	r = 0;
	//
	// ディレクトリ内容を記憶するバッファを確保する
#if (DIRMA==1)
	if (namelist == NULL)
	{
		if ((namelist = calloc(sizeof(DIR), MAXWILD)) == NULL)
			{ r = -1;  goto getdir_end; }
	}
#else
	if (!list_inited)
	{
		int i;
		for (i=0; i<MAXWILD; i++)
			namelist[i].name = NULL;
		list_inited = YES;
	}
#endif
	//
	// 読み込むディレクトリのフルパス名を作る
	strcpy(pathbuf,nowpath);
	if (strlen(pathbuf) > 0)
	{
		if (pathbuf[strlen(pathbuf)-1] != '\\')
			strcat(pathbuf,"\\");
	}
	//
	if (strcmp(mask, "*.*") == 0)
	{
		//
		// ファイル名マスクが "*.*" である場合は、全ディレクトリ要素を
		// 一度に読む
		strcat(pathbuf,mask);
		if (_dos_findfirst(pathbuf, _A_SUBDIR, &dirbuf) == 0)
		{
			do
			{
				DIR *dp = namelist + namenum;
				if (strcmp(dirbuf.name,".") == 0)
					continue;
#if (DIRMA==0)
				if (dp->name != NULL)
					free(dp->name);
				if ((dp->name = malloc(strlen(dirbuf.name)+1)) == NULL)
					{ r = -1;  goto getdir_end; }
#endif
				if (strcmp(dirbuf.name,"..") == 0)
					strcpy(dp->name, "親ディレクトリ");
				else
					strcpy(dp->name, dirbuf.name);
				dp->subdir = ((dirbuf.attrib & attrSUBDIR)!=0 ? YES : NO);
				dp->size = dirbuf.size;
				namenum++;
			} while (_dos_findnext(&dirbuf) == 0 && namenum < MAXWILD);
		}
	}
	else
	{
		//
		// ファイル名マスクが "*.*" でない場合は、まずサブディレクトリ名を
		// しらべ、次にファイル名を調べる
		strcpy(pathbuf2, pathbuf);
		strcat(pathbuf, "*.*");
		if (_dos_findfirst(pathbuf, _A_SUBDIR, &dirbuf) == 0)
		{
			do
			{
				if ((dirbuf.attrib & attrSUBDIR) == 0 || strcmp(dirbuf.name,".") == 0)
					continue;
				DIR *dp = namelist + namenum;
#if (DIRMA==0)
				if (dp->name != NULL)
					free(dp->name);
				if ((dp->name = malloc(strlen(dirbuf.name)+1)) == NULL)
					{ r = -1;  goto getdir_end; }
#endif
				if (strcmp(dirbuf.name,"..") == 0)
					strcpy(dp->name, "親ディレクトリ");
				else
					strcpy(dp->name, dirbuf.name);
				dp->subdir = ((dirbuf.attrib & attrSUBDIR)!=0 ? YES : NO);
				dp->size = dirbuf.size;
				namenum++;
			} while (_dos_findnext(&dirbuf) == 0 && namenum < MAXWILD);
		}
		strcpy(pathbuf, pathbuf2);
		strcat(pathbuf, mask);
		if (_dos_findfirst(pathbuf, _A_RDONLY, &dirbuf) == 0)
		{
			do
			{
				DIR *dp;
				dp = namelist + namenum;
#if (DIRMA==0)
				if (dp->name != NULL)
					free(dp->name);
				if ((dp->name = malloc(strlen(dirbuf.name)+1)) == NULL)
					{ r = -1;  goto getdir_end; }
#endif
				strcpy(dp->name, dirbuf.name);
				dp->subdir = ((dirbuf.attrib & attrSUBDIR)!=0 ? YES : NO);
				dp->size = dirbuf.size;
				namenum++;
			} while (_dos_findnext(&dirbuf) == 0 && namenum < MAXWILD);
		}
	}
getdir_end:
	sprintf(debugmsg,"getdir end(%d)",r);
	DEBUG_MSG(debugmsg);
	return r;
}


// ■ メニューにファイル名リストを表示する
//---------------------------------------------------------------------------


static char dspFnameList_reset = YES;


static void disp_onefname(int pos, int ofs) // ファイルネーム１つを表示する
{
	int ix,iy,ixlen,iylen;
	GETITEMXYS(itemFList);
	DIR *dp;
	char strbuf[80];
	dp = namelist + pos + ofs;
	if (dp->subdir)
		sprintf(strbuf,"<%s>",dp->name);
	else
		sprintf(strbuf,"%-14s%10d",dp->name,dp->size);
	ARTputstr12(ix,iy+ofs*CHARHT,strbuf,DMgetmenuplt(White),DMgetmenuplt(Black));
}


static void dspNameList_new(int pos)
{
	int i,ix,iy,ixlen,iylen;
	GETITEMXYS(itemFList);
	grboxfill(ix-1,iy-1,ixlen+2,iylen+2,DMgetmenuplt(Black),DrawNORMAL);
	if (drive_selecting == DISPLAY)
	{
		for (i = 0;  i < iylen/CHARHT && pos+i < namenum;  i++)
			disp_onefname(pos,i);
	}
	else if (drive_selecting == SELECTING)
		putmsg_width(ix,iy+(iylen-CHARHT*2)/2, ixlen-2,
					 "ドライブ名を左クリックしてください",DMgetmenuplt(White));
	else if (drive_selecting == INVALID)
		putmsg_width(ix,iy+(iylen-CHARHT*2)/2, ixlen-2,
					 "ドライブの準備ができていません",DMgetmenuplt(White));
	dspFnameList_reset = FALSE;
}


static void dspNameList(int pos)
{
	static int prepos = -1;
	int ix,iy,ixlen,iylen;
	GETITEMXYS(itemFList);
	// grboxfill(ix,iy,ixlen,iylen,DMgetmenuplt(Black),DrawNORMAL);
	// for (i = 0;  i < iylen/CHARHT && pos+i < namenum;  i++)
	if (   drive_selecting != DISPLAY || dspFnameList_reset
	    || _abs(pos-prepos) >= iylen/CHARHT)
		dspNameList_new(pos);
	else if (pos == prepos)
		;
	else
	{
		char gbuf[FLISTXLEN*CHARHT*2];
		if (pos > prepos)	// 上へのスクロール
		{
			int i,mov,ynum;
			mov = pos - prepos;
			ynum = iylen/CHARHT;
			for (i=0; i < ynum-mov; i++)
			{
				grp_getblk(gbuf, ix,iy+CHARHT*(i+mov), ixlen,CHARHT);
				grp_putblk(ix,iy+CHARHT*i,ixlen,CHARHT, gbuf, DrawNORMAL);
			}
			grboxfill(ix,iy+(ynum-mov)*CHARHT,ixlen,CHARHT*mov,DMgetmenuplt(Black),DrawNORMAL);
			for (i=0; i<mov; i++)
				disp_onefname(pos,ynum-mov+i);
		}
		else // 下へのスクロール
		{
			int i,mov,ynum;
			mov = prepos - pos;
			ynum = iylen/CHARHT;
			for (i=ynum-1-mov; i >= 0; i--)
			{
				grp_getblk(gbuf, ix,iy+CHARHT*i, ixlen,CHARHT);
				grp_putblk(ix,iy+CHARHT*(i+mov),ixlen,CHARHT, gbuf, DrawNORMAL);
			}
			grboxfill(ix,iy,ixlen,CHARHT*mov,DMgetmenuplt(Black),DrawNORMAL);
			for (i=0; i<mov; i++)
			{
				disp_onefname(pos,i);
			}
		}
	}
	dspFnameList_reset = FALSE;
	prepos = pos;
}


// ■ メニューに現在（選択／入力中）のファイル名を表示する
//---------------------------------------------------------------------------


static void disp_fname()
{
	int ix,iy,ixlen,iylen;
	GETITEMXYS(itemFName);
	int x,y;
	x = ix, y = iy;
	grboxfill(x,y,ixlen,iylen,DMgetmenuplt(Black),DrawNORMAL);
	ARTputstr12(x+1,y+1,fname,DMgetmenuplt(White),DMgetmenuplt(Black));
	if (csrx > strlen(fname))
		csrx = strlen(fname);
	// grboxfill(x+1+csrx*8,y+1,8,16,White,DrawXOR);
}


// ■ メニューに現在のパス名を表示する
//---------------------------------------------------------------------------


static void disp_now_path()
{
	int ix,iy,ixlen,iylen;
	GETITEMXYS(itemPath);
	int x,y;
	x = ix, y = iy;
	grboxfill(x,y,ixlen,iylen,DMgetmenuplt(COL_menu),DrawNORMAL);
	ARTputstr12(x+1,y+1,nowpath,DMgetmenuplt(White),DMgetmenuplt(COL_menu));
}


// ■ メニューに現在のマスク文字列を表示する
//---------------------------------------------------------------------------


static void disp_mask_name()
{
	int ix,iy,ixlen,iylen;
	GETITEMXYS(itemMask);
	int x,y;
	x = ix,  y = iy;
	grboxfill(x,y,ixlen,iylen,DMgetmenuplt(Black),DrawNORMAL);
	ARTputstr12(x+1,y+1,mask,DMgetmenuplt(White),DMgetmenuplt(Black));
}


// ■ 文字列を編集する
//---------------------------------------------------------------------------


int	editStr(int x,int y,int clmnum, char *buf,int buflen, int csrx)
// 返値:  0=RETURNキー終了   1=ESCキー終了
{
	char dspbuf[200];
	int msx,msy;
	msx = ms.x;
	msy = ms.y;
	if (csrx == -1)
		csrx = strlen(buf);
	else if (csrx > strlen(buf))
		csrx = strlen(buf);
	bool abort;
	int dspofs;	// 文字列を何文字目から表示するか
	abort = NO;
	dspofs = 0;
	for (;;)
	{
		// 文字列の表示 (表示位置の調節も行う)
		grboxfill(x,y,clmnum*CHARWID,CHARHT,DMgetmenuplt(Black),DrawNORMAL);
		if ((csrx-dspofs) > (clmnum-1))
			dspofs = csrx-(clmnum-1);
		else if ((csrx-dspofs) < 0)
			dspofs = csrx;
		{int t; for(t=0;t<clmnum;t++) dspbuf[t]=buf[dspofs+t]; dspbuf[t]=0;}
		// strncpy(dspbuf,buf+dspofs,clmnum);
		ARTputstr12(x,y,dspbuf,DMgetmenuplt(White),DMgetmenuplt(Black));
		grboxfill(x+(csrx-dspofs)*CHARWID,y,CHARWID,CHARHT,DMgetmenuplt(White),DrawXOR);
		// ユーザーのアクション待ち
		do
			{ ms_get(&ms); ms.x = msx; ms.y = msy; }
		while (ms.btn1==OFF && ms.btn2==OFF && key_chk()==0);
		if (ms.btn1 == OFFON)
			goto _endloop;
		if (ms.btn2 == OFFON)
		{
			abort = YES;
			goto _endloop;
		}
		// 入力文字に対応する処理
		int c;
		c = key_read();
		switch (c)
		{
		case 13:								// RETURN キー
			goto _endloop;
		case 27:								// ESC キー
			abort = YES;
			goto _endloop;
		case 8:									// BS キー
			if (csrx > 0)
			{
				memcpy(buf+csrx-1,buf+csrx,strlen(buf+csrx)+1);
				csrx--;
			}
			break;
		case 127:								// DEL キー
			if (strlen(buf+csrx) > 0)
				memcpy(buf+csrx,buf+csrx+1,strlen(buf+csrx+1)+1);
			break;
		case 28:								// 右カーソルキー
			if (strlen(buf+csrx) > 0)
				csrx++;
			break;
		case 29:								// 左    〃
			if (csrx > 0)
				csrx--;
			break;
		case 30:		 						// 上    〃
			csrx = 0;
			break;
		case 31:								// 下    〃
			csrx = strlen(buf);
			break;
		default:
			if (' '<=c && c!=127) 				// 通常文字
			{
				if (strlen(buf)+1 < buflen)
				{
					_rmemcpy(buf+csrx+1,buf+csrx,strlen(buf+csrx)+1);
					*(buf+csrx) = c;
					csrx++;
				}
			}
		}
	}
_endloop:
	// 文字列の表示
	grboxfill(x,y,clmnum*CHARWID,CHARHT,DMgetmenuplt(Black),DrawNORMAL);
	strncpy(dspbuf, buf, clmnum);
	ARTputstr12(x,y,dspbuf,DMgetmenuplt(White),DMgetmenuplt(Black));
	//
	return (abort ? 1 : 0);
}


// ■ ドライブ名の表示
//---------------------------------------------------------------------------


static void disp_drivename(void)
{
	int ix,iy,ixlen,iylen;
	GETITEMXYS(itemDrive);
	char *str = "A:";
	*str = 'A' + (nowdrive-1);
	grboxfill(ix,iy, ixlen,iylen, DMgetmenuplt(COL_menu),DrawNORMAL);
	menu_drawbox(ix,iy,ixlen,iylen);
	ARTputstr12(ix+3,iy+2,str,DMgetmenuplt(COL_menuString),DMgetmenuplt(COL_menu));
}


/*--------------------------------------------------------*/
/*              ファイルメニューの描画･消去               */
/*--------------------------------------------------------*/


static void disp_filemenu( /* int x, int y */ )
{
	disp_diskfree();
	disp_drivename();
}


static void erase_filemenu( /* int x, int y */ )
{
	dspFnameList_reset = YES;
}


/*--------------------------------------------------------*/
/*       ファイルメニューモジュールの初期化／後処理       */
/*--------------------------------------------------------*/


int filemenu_init()
{
	if (namelist == NULL)
	{
		if ((namelist = calloc(sizeof(DIR), MAXWILD)) == NULL)
			return -1;
	}
	_dos_getdrive(&_curdrive);
	_getcwd(_curpath,128);
	return 0;
}


void filemenu_end(void)
{
	unsigned dmy;
	_dos_setdrive(_curdrive, &dmy);
	_chdir(_curpath);
}


/*--------------------------------------------------------*/
/*                    ファイルメニュー                    */
/*--------------------------------------------------------*/

#define	XSEL	2000

#if 0
static int check_drive(char drivename)
{
	struct diskfree_t dinfo;
	return _dos_getdiskfree(toupper(drivename) - 'A' + 1, &dinfo);
}
#endif


void file_menu_exp(char *title, void (*exec_func)(char **filelist, int x),
				   char **xitem)
/*
	xitem : 文字列の配列へのポインタ(or NULL)
			xitem[0] = タイトル(太字で表示)
			xitem[1..] = 各アイテム(NULLでエンドマーク)
*/
{
	PRINT("file_menu_exp begin\n");
	char FNAME[50];  int r;
	{
		PRINT("拡張アイテム設定...");
		static SELECTOR_ELEMENT buf;
		#define	TITLEX	EXTX
		#define	MEMBERX	(EXTX+6)
		int i;
		BUTTON *bp = menu_button(&filemenu, itemX);
		KNOW(bp!=NULL);
		for (i=0; i<itemX_num; i++,bp++)
		{
			*bp = btnpart[0];
			menu_button_setid(bp,itemX+i);
		}
		TRACE;
		if (xitem != NULL)
		{
			int y = EXTY, n = 0;
			for (i = 0;  xitem[i] != NULL; )
			{
				TRACE;
				SEL *sel = menu_selector_new();
				if (sel == NULL) break;
				int j = 0;
				while (xitem[i+j] != NULL && *xitem[i+j] != '\0')
				{
					TRACE;
					if (j == 0)
					{
						BUTTON *bp = menu_button(&filemenu, itemX /* +n */  );
						KNOW(bp!=NULL);
						*bp = btnpart[1];
						menu_button_setid(bp,itemX);
						menu_button_setxy(bp,TITLEX,y);
						menu_button_setvar(bp,(int)xitem[i+j]);
					}
					else
					{
						/* j>=1 */
						SEL_E *ep = menu_selector_element_new();
						if(ep==NULL) goto ENDLOOP;
						menu_selector_element_setxy(ep,j==0?TITLEX:MEMBERX,y);
						menu_selector_element_setstr(ep,xitem[i+j]);
						menu_selector_addelement(sel,ep);
					}
					TRACE;
					y += CHARHT + 4;
					j++;
				}
				i += j;
				if (xitem[i] != NULL)
					i++;
				y += 4;
				n++;
				menu_selector_setid(sel,XSEL);
				menu_addselector(&filemenu, sel);
			}
			ENDLOOP:
			;
		}
		PRINT("拡張アイテム設定終了");
	}

	PRINT("file_menu_exp ディレクトリ読み込み\n");
	if (strcmp(nowpath, "ARTemis_non_initialized") == 0)
	{
		if (_getcwd(nowpath,128) == NULL)
			return;
	}
	nowdrive = toupper(nowpath[0]) - 'A' + 1;
	if ((cur_diskfree = diskfree(nowdrive)) >= 0)
	{
		drive_selecting = DISPLAY;
		PRINT("file_menu_exp ディレクトリ読み込み a\n");
		if (getdir() != 0)
		{
			dispAttentionMsg("ディレクトリ内容を記憶するための"
							 "メモリが不足しています");
			goto file_menu_end;
		}
	}
	else
	{
		drive_selecting = INVALID;
	}
	PRINT("file_menu_exp ディレクトリ読み込み b\n");
	menu_settitle(&filemenu, title);
	FNAME[0] = 0;  r=2;
	//
	DEBUG_MSG("file_menu_exp メニュー表示");
	if (!menu_ifdisp())			// 通常メニューとして表示する
		menu_disp(&filemenu);
	else						// サブメニューとして表示する
		menu_dispxy(-2, -2, &filemenu);
	SCROLLBAR *bp;
	bp = menu_scrollbar(&filemenu,barFLIST);
	menu_scrollbar_setallsize(bp,_max(FLISTYLEN/CHARHT, namenum));
	menu_scrollbar_setdispsize(bp,FLISTYLEN/CHARHT);
	#define LISTPOS	menu_scrollbar_getvar(bp)
	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);
		if (ms.btn1 == OFFON)
		{
			int a, ix,iy,ixlen,iylen;
			int fnum; int ax,ay; SCROLLBAR *sbarp;
			a = menu_where(ms.x,ms.y,&filemenu, &ax,&ay,&sbarp);
			switch (a)
			{
			case itemScrollBar:
				menu_touchscrollbar(sbarp, ax,ay);
				break;
			case itemDriveInc:
				if (drive_selecting != SELECTING)
				{
					drive_selecting = SELECTING;
					dspNameList_new(LISTPOS);
				}
				nowdrive++;
				if ('A'+nowdrive-1 > 'Q')
					nowdrive = 1;
				disp_drivename();
				break;
			case itemDriveDec:
				if (drive_selecting != SELECTING)
				{
					drive_selecting = SELECTING;
					dspNameList_new(LISTPOS);
				}
				nowdrive--;
				if (nowdrive < 1)
					nowdrive = 'Q'-'A'+1;
				disp_drivename();
				break;
			case itemDrive:
				if ((cur_diskfree = diskfree(nowdrive)) >= 0)
				{
					drive_selecting = DISPLAY;
					unsigned dmy;
					_dos_setdrive(nowdrive, &dmy);
					_getcwd(nowpath,128);
					getdir();
					menu_scrollbar_setallsize
						(bp,_max(FLISTYLEN/CHARHT,namenum));
					menu_scrollbar_setvar(bp,0);
				}
				else
				{
					drive_selecting = INVALID;
					namenum = 0;
					menu_scrollbar_setallsize
						(bp,_max(FLISTYLEN/CHARHT, namenum));
					menu_scrollbar_setvar(bp,0);
					strcpy(nowpath, "A:");
					nowpath[0] = 'A' + nowdrive - 1;
				}
				dspNameList_new(LISTPOS);
				menu_makeupscrollbar(bp);
				disp_now_path();
				disp_diskfree();
				break;
			case itemFList:
				fnum = LISTPOS + ay/CHARHT;
				if (fnum < namenum)
				{
					DIR *namep;
					namep = namelist + fnum;
					if (namep->subdir)
					{
						if (strcmp(namep->name,"親ディレクトリ") == 0)
						{
							char *p;
							if ((p = strrchr(nowpath,'\\')) != NULL)
								*p = 0;	// そこを文字列の終端にする
						}
						else if (strcmp(namep->name,".") != 0)
						{
							if (nowpath[strlen(nowpath)-1] != '\\')
								strcat(nowpath,"\\");
							strcat(nowpath,namep->name);
						}
						_chdir(nowpath);
						getdir();
						menu_scrollbar_setallsize
							(bp,_max(FLISTYLEN/CHARHT, namenum));
						menu_scrollbar_setvar(bp,0);
						dspNameList_new(LISTPOS);
						menu_makeupscrollbar(bp);
						disp_now_path();
					}
					else
					{
						strcpy(fname, namep->name);
						disp_fname();
					}
				}
				break;
			case itemFName:
				GETITEMXYS(itemFName);
				r = (editStr(ix+1,iy+1,ixlen/6,fname,128,-1)==0? 1: 2);
				// goto _endloop;
				continue;
			#if 0
			case itemPath:
				GETITEMXYS(itemPath);
				editStr(ix+1,iy+1,ixlen/6, nowpath,128, -1);
				getdir();
				menu_scrollbar_setallsize
					(bp,_max(FLISTYLEN/CHARHT, namenum));
				menu_scrollbar_setvar(bp,0);
				dspNameList_new(LISTPOS);
				menu_makeupscrollbar(bp);
				disp_diskfree();
				break;
			#endif
			case itemMask:
				DEBUG_MSG("filemenu mask-1");
				GETITEMXYS(itemMask);
				editStr(ix+1,iy+1,ixlen/6, mask,128, -1);
				getdir();
				DEBUG_MSG("filemenu mask-2");
				menu_scrollbar_setallsize
					(bp,_max(FLISTYLEN/CHARHT, namenum));
				menu_scrollbar_setvar(bp,0);
				dspNameList_new(LISTPOS);
				DEBUG_MSG("filemenu mask-3");
				menu_makeupscrollbar(bp);
				DEBUG_MSG("filemenu mask-4");
				break;
			case itemMoveMenu:
MOVEMENU:
				menu_move();
				break;
			case itemExec:
				if (drive_selecting == DISPLAY)
				{
					r = 1;
					goto _endloop;
				}
				else
					goto MOVEMENU;
			case itemCancel:
				r = 2;
				goto _endloop;
			case itemSelector:
				menu_touchselector(&filemenu);
				break;
			}
		}
		else if (ms.btn2 == OFFON)
			{ r=2; break; }
	}
_endloop:
	menu_erase();
	PRINT("メニュー消去完了");
	if (r==1 && fname[0]!=0)
	{
		char fnbuf[128]; char *fnlist[200];
		if (strchr(fname, '\\') == NULL)
		{
			strcpy(fnbuf,nowpath);
			if (fnbuf[strlen(fnbuf)-1] != '\\')
				strcat(fnbuf,"\\");
			strcat(fnbuf,fname);
		}
		else
			strcpy(fnbuf,fname);
		fnlist[0] = fnbuf;
		fnlist[1] = NULL;
		SEL *sel = menu_selector(&filemenu,XSEL);
		(*exec_func)(fnlist,(sel!=NULL?menu_selector_getvar(sel):0));
	}
	menu_clearselector(&filemenu);
file_menu_end:
	PRINT("file_menu_exp end\n");
}


void file_menu(char *title, void (*exec_func)(char **filelist))
{
	file_menu_exp(title, (void(*)(char **filelist,int x))exec_func, NULL);
}


/* end of filemenu.c */
