// #define	DEBUG
/*
	ARTemis (Graphic Editor for FM-TOWNS)
	(c) MATSUUCHI Ryosuke 1992,1993

	menu.c

	メニュー処理を行う関数群

		menu_init
		menu_end
	各種取得関数
		menu_plt
		menu_ifdisp
		menu_getcurmenu
		menu_getmenuxy
		menu_getbuttonxy
		menu_where				メニュー内座標の機能の判定
		menu_getifdisplay
	メニュー
		menu_disp				メニューの表示
		menu_dispxy				メニューの表示（位置指定あり）
		menu_erase				メニューの消去
		void	menu_settitle(MENU *m, char *title)
		int		menu_addbutton(MENU *m, BUTTON *b)
		int		menu_addscrollbar(MENU *m, SCROLLBAR *s)
		int		menu_addselector(MENU *m, SEL *s)
		void	menu_clearselector(MENU *m)
		menu_move
	ボタン
		BUTTON	*menu_button_new(void)
		void	menu_button_delete(BUTTON *b)
		void	menu_button_setid(BUTTON *b,int id)
		BUTTON	*menu_button(MENU *menu, int id)
		// BUTTON	*menu_button_getfirst(MENU *m);
		// BUTTON	*menu_button_getnext(MENU *m);
		void	menu_button_setxy(BUTTON *b, int x, int y)
		void	menu_button_setvar(BUTTON *b, int var)
	スクロールバー
		SBAR	*menu_scrollbar_new(void)
		void	menu_scrollbar_delete(SBAR *s)
		void	menu_scrollbar_setid(SBAR *s,int id)
		SBAR	*menu_scrollbar(MENU *m, int id)
		void	menu_scrollbar_setxy(SBAR *s,int x,int y)
		void	menu_scrollbar_getxy(SBAR *s,int*x,int*y,int*len)
		void	menu_scrollbar_setfunc(SBAR *s, void (*func)())
		menu_scrollbar_getvar
		menu_scrollbar_setvar
		menu_scrollbar_setallsize
		menu_scrollbar_setdispsize
		menu_touchscrollbar		スクロールバーをクリック／ドラッグした時の処理
		menu_drawscrollbar
		menu_makeupscrollbar	スクロールバー表示の更新
	選択子
		SEL		*menu_selector_new(void)
		void	menu_selector_delete(SEL *s)
		void	menu_selector_setid(SEL *s, int id)
		SEL		*menu_selector(MENU *m, int id)
		int		menu_selector_addelement(SEL *s, SEL_E *e)
		int		menu_selector_getvar(SEL *s)
		void	menu_selector_setvar(SEL *s, int n)
		void	menu_selector_makeup(SEL *sp)
		選択要素
			SEL_E	*menu_selector_element_new(void)
			void	menu_selector_element_delete(SEL_E *e)
			void	menu_selector_element_setid(SEL_E *e, int id)
			SEL_E	*menu_selector_element(SEL *s,int id)
			SEL_E	*menu_selector_element_getfirst(SEL *s)
			SEL_E	*menu_selector_element_getnext(SEL *s)
			void	menu_selector_element_setxy(SEL_E *e,int x,int y)
			void	menu_selector_element_setstr(SEL_E *e,char *s)
			void	menu_selector_element_setavail(SEL_E *e,bool f)
		menu_touchselector
	メニュー上の描画
		menu_putstr				メニュー内への文字列の表示
		menu_buttonputstr		ボタン内への文字列の表示
		menu_drawbox			陰影つき枠の表示
	メニューへのデータの設定・解除
		menu_setdata
		menu_getdata
		menu_cleardata
*/

#define	NEWMENU	1

#define	MODULE_MENU

#include <stdio.h>
#include <string.h>
#include <malloc.h>

#include "ge.h"
#include "dispman.h"

#define	Cwhite			DMgetmenuplt(White)
#define	Cblack			DMgetmenuplt(Black)
#define	Cgray			DMgetmenuplt(Gray)
#define	Clightgray		DMgetmenuplt(LightGray)
#define	Cdarkgray		DMgetmenuplt(DarkGray)
#define	Cyellow			DMgetmenuplt(Yellow)
#define	Cblack0			DMgetmenuplt(Black0)
#define	Ctransparent	DMgetmenuplt(Transparent)
#define	Ccolorless		DMgetmenuplt(Colorless)
#define	Clatticecolor	DMgetmenuplt(LatticeColor)
#define	Cmenu			DMgetmenuplt(COL_menu)
#define	Cmenu2			DMgetmenuplt(COL_menu2)
#define	Cmenulight		DMgetmenuplt(COL_menuLight)
#define	Cmenushade		DMgetmenuplt(COL_menuShade)
#define	Cmenustring		DMgetmenuplt(COL_menuString)
#define	Ccsrlight		DMgetmenuplt(COL_cursorLight)
#define	Ccsrdark		DMgetmenuplt(COL_cursorDark)
#define	ColM			Cmenu
#define	ColM2			Cmenu2
#define	ColL			Cmenulight
#define	ColS			Cmenushade

#define	MENUNUM	3
static	MENU	*menulist[MENUNUM];
static	MENU	*menulist_bak[MENUNUM];


/*--------------------------------------------------------*/
/*                モジュールの初期化／終了                */
/*--------------------------------------------------------*/


int menu_init()
{
	PRINT("menu_init begin\n");
	int i;
	for (i=0; i<MENUNUM; i++)
		menulist[i] = NULL;
	PRINT("menu_init end\n");
	return 0;
}


void menu_end()
{
}


/*--------------------------------------------------------*/
/*                      各種取得関数                      */
/*--------------------------------------------------------*/


int menu_plt(int n)
{
	return DMgetmenuplt(n);
}


int menu_ifdisp()
{
	if (menulist[0] != NULL)
		return 1;
	else
		return 0;
}


MENU* menu_getcurmenu()
{
	return menulist[0];
}


void menu_getmenuxy(MENU *menu, int *x, int *y, int *xlen, int *ylen)
{
	if (menu == NULL)
		menu = menulist[0];
	KNOW(menu!=NULL);
	if (x != NULL)
		*x = menu->x;
	if (y != NULL)
		*y = menu->y;
	if (xlen != NULL)
		*xlen = menu->xlen;
	if (ylen != NULL)
		*ylen = menu->ylen;
	return;
}


void menu_getbuttonxy(MENU *menu,int btnnum,int *x,int *y,int *xlen,int *ylen)
{
	if (menu == NULL)
		menu = menulist[0];
	KNOW(menu!=NULL);
	BUTTON *bp = menu_button(menu,btnnum);
	if (x != NULL)
		*x = menu->x + bp->x;
	if (y != NULL)
		*y = menu->y + bp->y;
	if (xlen != NULL)
		*xlen = bp->xlen;
	if (ylen != NULL)
		*ylen = bp->ylen;
}


bool menu_getifdisplay(MENU *menu)
{
	if (menu == NULL)
		menu = menulist[0];
	if (menu==NULL)
		return NO;
	else
		return menu->display;
}


int menu_where(int x,int y,MENU *menu, int *ax,int *ay,SCROLLBAR **sbarp)
{
	if (menu->x <= x && x <= menu->x+menu->xlen-1
	 && menu->y <= y && y <= menu->y+menu->ylen-1)
	{
		int mx,my;
		mx = x-menu->x;
		my = y-menu->y;
		BUTTON *ip;  int an;
			// アイテムリストを逆順にたどり､ 判定していく
		for (ip = menu->buttonlist, an=0;  ip!=NULL && ip->x>=0;  ip++,an++)
			;
		for (an--,ip--;  an>=0;  an--,ip--)
		{
			if (!ip->noselect&&ip->x <= mx && mx < ip->x+ip->xlen &&
			 ip->y <= my && my < ip->y+ip->ylen)
			{
				if(ax!=NULL) *ax = mx - ip->x;
				if(ay!=NULL) *ay = my - ip->y;
				return ip->id;
			}
		}
		SCROLLBAR *sp;
		for (sp = menu->sbarlist;  sp!=NULL && sp->x>=0;  sp++)
		{
			if (sp->type == barHORI)
			{
				if (sp->x <= mx && mx < sp->x + sp->len &&
				 sp->y <= my && my < sp->y + 14)
				{
					if (ax!=NULL) *ax = mx - sp->x;
					if (ay!=NULL) *ay = my - sp->y;
					if(sbarp!=NULL)
						*sbarp=sp;
					return itemScrollBar;
				}
			}
			else
			{
				if (sp->x <= mx && mx < sp->x + 14 &&
				 sp->y <= my && my < sp->y + sp->len)
				{
					if(ax!=NULL) *ax = mx - sp->x;
					if(ay!=NULL) *ay = my - sp->y;
					if(sbarp!=NULL)
						*sbarp=sp;
					return itemScrollBar;
				}
			}
		}
		SELECTOR *sel;
		for (sel = menu->sellist;  sel != NULL && sel->var >= 0;  sel++)
		{
			SELECTOR_ELEMENT *seli;
			for (seli=sel->elist; seli!=NULL&&seli->x>=0; seli++)
			{
				if (seli->x <= mx && mx <= seli->x + 14 + 6*strlen(seli->str) &&
				    seli->y <= my && my <= seli->y + 11)
				{
					return itemSelector;
				}
			}
		}
		for (sel = menu->d_sellist;  sel != NULL;  sel=sel->next)
		{
			SELECTOR_ELEMENT *seli;
			for (seli=sel->d_elist; seli!=NULL; seli=seli->next)
			{
				if (seli->x<=mx&&mx <= seli->x + 14 + 6*strlen(seli->str) &&
				    seli->y<=my&&my<= seli->y + 11)
				{
					return itemSelector;
				}
			}
		}
		if (my<16)
		{
			if(ax!=NULL) *ax = mx;
			if(ay!=NULL) *ay = my;
			return itemMoveMenu;
		}
		return itemOther;
	}
	else
		return OutOfMenu;
}


/*--------------------------------------------------------*/
/*                         ボタン                         */
/*--------------------------------------------------------*/


BUTTON	*menu_button_new(void)
{
	BUTTON *b;
	b = malloc(sizeof(BUTTON));
	if (b==NULL) return NULL;
	memset(b,0,sizeof(BUTTON));
	return b;
}


void	menu_button_delete(BUTTON *b)
{
	free(b);
}


void	menu_button_setid(BUTTON *b,int id)
{
	b->id = id;
}


BUTTON	*menu_button(MENU *menu, int id)
{
	BUTTON *bp;
	for (bp=menu->buttonlist; bp!=NULL && bp->x>=0; bp++)
		if (bp->id == id)
			return bp;
	for (bp=menu->d_buttonlist; bp!=NULL; bp=bp->next)
		if (bp->id == id)
			return bp;
	return NULL;
}


void menu_button_setxy(BUTTON *b, int x, int y)
{
	b->x = x;
	b->y = y;
}


void menu_button_setvar(BUTTON *b, int var)
{
	b->var = var;
}


/*--------------------------------------------------------*/
/*                     スクロールバー                     */
/*--------------------------------------------------------*/


#define	BARH	12
#define	SWW		12


static void menu_dispbarvar(SCROLLBAR *sp)
{
	int bx,by,blen;
	menu_getmenuxy(NULL, &bx, &by, NULL, NULL);
	bx += sp->x, by += sp->y, blen = sp->len;
	char nbuf[10];
	int l = sp->numofs + sp->allsize - sp->dspsize;
	if (l < 10)
		sprintf(nbuf,"%1d",sp->numofs + sp->dsppos);
	else if (10 <= l && l < 100)
		sprintf(nbuf,"%2d",sp->numofs + sp->dsppos);
	else if (100 <= l && l < 1000)
		sprintf(nbuf,"%3d",sp->numofs + sp->dsppos);
	else
		sprintf(nbuf,"%4d",sp->numofs + sp->dsppos);
	if (sp->type == barHORI)
	{
		if (sp->dispnum)
		{
		 grboxfill(bx-4-6*strlen(nbuf),by,6*strlen(nbuf),12,Cmenu,DrawNORMAL);
		 ARTputstr12(bx-4-6*strlen(nbuf), by, nbuf, Cmenustring, Cmenu);
		}
	}
	else
	{
		if (sp->dispnum)
		{
		 grboxfill(bx+(BARH-6*strlen(nbuf))/2,by+sp->len+1,6*strlen(nbuf),12,
		 		   Cmenu,DrawNORMAL);
		 ARTputstr12(bx+(BARH-6*strlen(nbuf))/2,by+sp->len+1,nbuf,
		 			 Cmenustring, Cmenu);
		}
	}
}


static void _menu_makeupscrollbar(SCROLLBAR *sp, bool barnormal)
{
	if (sp->len <= 0)
		return;
	int bx,by,blen;
	void drawbox(int x,int y,int xlen,int ylen)
	{
		if (barnormal)
		{
			ghline(x, x+xlen-1, y, Cmenulight, DrawNORMAL);
			gvline(x, y, y+ylen-1, Cmenulight, DrawNORMAL);
			ghline(x+1, x+xlen-1, y+ylen-1, Cmenushade, DrawNORMAL);
			gvline(x+xlen-1, y+1, y+ylen-1, Cmenushade, DrawNORMAL);
		}
		else
			grboxline(x,y,xlen,ylen,Cblack,DrawNORMAL);
	}
	menu_getmenuxy(NULL, &bx, &by, NULL, NULL);
	bx += sp->x;
	by += sp->y;
	blen = sp->len;
	int p,len;
	if (sp->dspsize < sp->allsize)
	{
		if (!sp->inv)
			p=((blen-SWW*2)*sp->dsppos)/sp->allsize;
		else
			p=((blen-SWW*2)*(sp->allsize-sp->dspsize-sp->dsppos))/sp->allsize;
		len = ((blen-SWW*2) * sp->dspsize) / sp->allsize;
	}
	else
	{
		p = 0;
		len = blen-SWW*2;
	}
	if (sp->type == barHORI)
	{
		grboxfill(bx+SWW,by+1,blen-SWW*2,BARH-2,Cmenu,DrawNORMAL);
		drawbox(bx+SWW+p,by+1,len,BARH-2);
		menu_dispbarvar(sp);
	}
	else
	{
		grboxfill(bx+1,by+SWW,SWW-2,blen-SWW*2,Cmenu,DrawNORMAL);
		drawbox(bx+1,by+SWW+p,BARH-2,len);
		menu_dispbarvar(sp);
	}
}


void menu_makeupscrollbar(SCROLLBAR *sp)
{
	if (menu_getifdisplay(NULL))
		_menu_makeupscrollbar(sp, YES);
}


SCROLLBAR *menu_scrollbar(MENU *menu, int id)
{
	SCROLLBAR *sp;
	for (sp=menu->sbarlist; sp!=NULL&&sp->x>=0; sp++)
		if(sp->id == id) return sp;
	for (sp=menu->d_sbarlist; sp!=NULL; sp=sp->next)
		if(sp->id == id) return sp;
	return NULL;
}


void	menu_scrollbar_setxy(SBAR *s,int x,int y)
{
	s->x = x;
	s->y = y;
}


void	menu_scrollbar_getxy(SBAR *s,int*x,int*y,int*len)
{
	if (x!=NULL) *x=menuX+s->x;
	if (y!=NULL) *y=menuY+s->y;
	if (len!=NULL) *len=s->len;
}


void	menu_scrollbar_setfunc(SBAR *s, void (*func)())
{
	s->dspfunc = func;
}


int menu_scrollbar_getvar(SCROLLBAR *sp)
{
	return sp->numofs + sp->dsppos;
}


void menu_scrollbar_setvar(SCROLLBAR *sp, int dsppos)
{
	sp->dsppos = _lim(dsppos-sp->numofs, 0, sp->allsize - sp->dspsize);
	menu_makeupscrollbar(sp);
}


void menu_scrollbar_setallsize(SCROLLBAR *sp, int allsize)
{
	sp->allsize = allsize;
	sp->dsppos = _lim(sp->dsppos, 0, sp->allsize - sp->dspsize);
	if(sp->dspsize!=0)
		menu_makeupscrollbar(sp);
}


void menu_scrollbar_setdispsize(SCROLLBAR *sp, int dispsize)
{
	sp->dspsize = dispsize;
	sp->dsppos = _lim(sp->dsppos, 0, sp->allsize - sp->dspsize);
	if(sp->allsize!=0)
		menu_makeupscrollbar(sp);
}


void menu_drawscrollbar(SCROLLBAR *sp)
{
	if (sp->len <= 0)
		return;
	int bx,by,blen;
	menu_getmenuxy(NULL, &bx, &by, NULL, NULL);
	bx += sp->x;
	by += sp->y;
	blen = sp->len;
	if (sp->type == barHORI)
	{
		putpict(bx,by,Pleftsw);
		putpict(bx+blen-SWW,by,Prightsw);
		ghline(bx+SWW,bx+blen-SWW-1,by,Cmenushade,DrawNORMAL);
		ghline(bx+SWW,bx+blen-SWW-1,by+BARH-1,Cmenulight,DrawNORMAL);
	}
	else
	{
		putpict(bx,by,Pupsw);
		putpict(bx,by+blen-SWW,Pdownsw);
		gvline(bx,by+SWW,by+blen-SWW-1,Cmenushade,DrawNORMAL);
		gvline(bx+BARH-1,by+SWW,by+blen-SWW-1,Cmenulight,DrawNORMAL);
	}
	_menu_makeupscrollbar(sp,YES);
	if (sp->dspfunc != NOFNC)
		(*sp->dspfunc)(sp->dsppos);
}


void menu_touchscrollbar(SCROLLBAR *sp,int ax,int ay)
{
	if (sp->len <= 0)
		return;
	int mx,my;
	menu_getmenuxy(NULL, &mx, &my, NULL, NULL);
	void makeupBar(bool normalbar)
	{
		_menu_makeupscrollbar(sp, normalbar);
		if (sp->dspfunc != NOFNC)
			(*sp->dspfunc)(sp->dsppos);
	}
	void incdecPos(int dir)
	{
		if (dir == -1)
			{ if (sp->dsppos > 0)
				sp->dsppos--; }
		else
			{ if (sp->dsppos+sp->dspsize < sp->allsize)
				sp->dsppos++; }
		makeupBar(YES);
		int iniwait;
		iniwait = 150;
		for (;;)
		{
			DMdispcsr(ms.x,ms.y);
			ms_get(&ms);
			DMerasecsr();
			if (ms.btn1!=ON)
				break;
			if (iniwait > 0)
				iniwait--;
			else
			{
				if (dir == -1)
				  { if (sp->dsppos > 0)
						{ sp->dsppos--;  makeupBar(YES); } }
				else
				  { if (sp->dsppos < sp->allsize-sp->dspsize)
						{ sp->dsppos++;  makeupBar(YES); } }
			}
		}
	}
	#define	BARLEN	(sp->len-SWW*2)
	#define	FRAC(a,f1,f2)	((2*(a)*(f1)+(f2))/((f2)*2))

#define	TOUCHBAR(_x,_y) { 												 	\
	if (0<=a##_x && a##_x<SWW && 0<=a##_y && a##_y<BARH)					\
		incdecPos((!sp->inv ? -1 : 1));										\
	else if (sp->len-SWW<=a##_x && a##_x<sp->len && 0<=a##_y && a##_y<BARH)	\
		incdecPos((!sp->inv ? 1 : -1));										\
	else																	\
	{																		\
		int p,len;															\
		void set_p_len(void)												\
		{																	\
			if (sp->dspsize < sp->allsize)									\
			  { if (!sp->inv)												\
			 		p=FRAC(BARLEN,sp->dsppos, sp->allsize);					\
			    else														\
					p=FRAC(BARLEN,sp->allsize-sp->dspsize-sp->dsppos,		\
						   sp->allsize);									\
				len = FRAC(BARLEN, sp->dspsize,sp->allsize); }				\
			else															\
			  { p = 0;														\
				len = BARLEN; }												\
		}																	\
		set_p_len();														\
		if (a##_x < SWW+p || SWW+p+len <= a##_x)							\
		{																	\
			int cx = (ms._x-len/2)-(m##_x+sp->_x+SWW);						\
			/* cx = _lim(cx, 0, BARLEN-len); */								\
			sp->dsppos = FRAC(cx, sp->allsize, BARLEN);						\
			if (sp->inv)													\
				sp->dsppos = sp->allsize - sp->dspsize - sp->dsppos;		\
			sp->dsppos = _lim(sp->dsppos,0,sp->allsize-sp->dspsize);		\
		}																	\
		set_p_len();														\
		int dx = a##_x - (SWW+p);											\
		int cx;																\
		for (;;)															\
		{																	\
			cx = (ms._x - dx) - (m##_x + SWW + sp->_x);						\
			/* cx = _lim(cx, 0, BARLEN-len); */								\
			sp->dsppos = FRAC(cx, sp->allsize, BARLEN);						\
			if (sp->inv)													\
				sp->dsppos = sp->allsize - sp->dspsize - sp->dsppos;		\
			sp->dsppos = _lim(sp->dsppos, 0, sp->allsize-sp->dspsize);		\
			makeupBar(NO);													\
			DMdispcsr(ms.x,ms.y);											\
			do {															\
				ms_get(&ms);												\
			} while (ms.dx==0 && ms.dy==0 && ms.btn1==ON &&					\
			         key_read()==0);										\
			DMerasecsr();													\
			if (ms.btn1!=ON)												\
				break;														\
		}																	\
		/* sp->dsppos = FRAC(cx, sp->allsize,BARLEN); */					\
		sp->dsppos = _lim(sp->dsppos, 0, sp->allsize - sp->dspsize);		\
		makeupBar(YES);														\
	}																		\
}
#

	if (sp->type == barHORI)
	{
		TOUCHBAR(x,y);
	}
	else
	{
		TOUCHBAR(y,x);
	}
}


/*--------------------------------------------------------*/
/*                         選択子                         */
/*--------------------------------------------------------*/


SEL		*menu_selector_new(void)
{
	SEL *s;
	s = malloc(sizeof(SEL));
	if(s==NULL) return NULL;
	s->var = 0;
	s->elist = 0;
	s->next = NULL;
	s->id = 0;
	return s;
}


void	menu_selector_delete(SEL *s)
{
	free(s);
}


void	menu_selector_setid(SEL *s, int id)
{
	s->id = id;
}


SEL		*menu_selector(MENU *m, int id)
{
	SEL *s;
	for(s=m->sellist; s!=NULL && s->var>=0; s++)
		if(s->id==id) return s;
	for(s=m->d_sellist; s!=NULL; s=s->next)
		if(s->id==id) return s;
	return NULL;
}


int		menu_selector_addelement(SEL *s, SEL_E *e)
{
	if (s->d_elist == NULL)
		{ s->d_elist = e; e->next = NULL; }
	else {
		SEL_E *ep;
		for(ep=s->d_elist;ep->next!=NULL;ep=ep->next)
			;
		ep->next = e; e->next = NULL;
	}
	return 0;
}


int		menu_selector_getvar(SEL *s)
{
	return s->var;
}


void	menu_selector_setvar(SEL *s, int n)
{
	s->var = n;
}


// 選択要素


SEL_E	*menu_selector_element_new(void)
{
	SEL_E *s;
	s = malloc(sizeof(SEL_E));
	if(s==NULL) return NULL;
	s->x = s->y = 0;
	s->str = NULL;
	s->available = YES;
	s->next = NULL;
	s->id = 0;
	return s;
}


void	menu_selector_element_delete(SEL_E *e)
{
	free(e);
}


void	menu_selector_element_setid(SEL_E *e, int id)
{
	e->id = id;
}


SEL_E	*menu_selector_element(SEL *s,int id)
{
	SEL_E *ep;
	for(ep=s->elist;ep!=NULL&&ep->x>=0;ep++)
		if(ep->id==id) return ep;
	for(ep=s->d_elist;ep!=NULL;ep=ep->next)
		if(ep->id==id) return ep;
	return NULL;
}


SEL_E	*menu_selector_element_getfirst(SEL *s)
{
	if(s==NULL) return NULL;
	if(s->elist!=NULL)
	{
		s->cur_se = s->elist;
		s->se_static = YES;
	}
	else
	{
		s->cur_se = s->d_elist;
		s->se_static = NO;
	}
	return s->cur_se;
}


SEL_E	*menu_selector_element_getnext(SEL *s)
{
	if(s==NULL) return NULL;
	if (s->cur_se == NULL)
		return NULL;
	if(s->se_static)
	{
		(s->cur_se)++; 
		if(s->cur_se->x >= 0) return s->cur_se;
		s->se_static = NO;
		s->cur_se = s->d_elist;
		return s->cur_se;
	}
	else
	{
		s->cur_se = s->cur_se->next;
		return s->cur_se;
	}
}


void	menu_selector_element_setxy(SEL_E *e,int x,int y)
{
	e->x = x,e->y=y;
}


void	menu_selector_element_setstr(SEL_E *e,char *s)
{
	e->str=s;
}


void	menu_selector_element_setavail(SEL_E *e,bool f)
{
	e->available = f;
}


static SEL_E *n2se(SEL *s, int n)
{
	SEL_E *e; int i;
	for (e=menu_selector_element_getfirst(s),i=0;
		 e!=NULL;
		 e=menu_selector_element_getnext(s),i++)
		if (i==n)
			return e;
	return NULL;
}


void menu_selector_makeup(SEL *sp)
{
	int mx,my;
	if (!menu_ifdisp())
		return;
	MENU *menu = menu_getcurmenu();
	menu_getmenuxy(menu, &mx, &my, NULL, NULL);
	SEL_E *seli;  int var;
	for (seli=menu_selector_element_getfirst(sp),var=0;
		 seli!=NULL;
		 seli=menu_selector_element_getnext(sp),var++)
	{
		if (var == sp->var)
			putpict(mx+seli->x, my+seli->y, Pselecton);
		else
			putpict(mx+seli->x, my+seli->y, Pselectoff);
	}
}


void menu_touchselector(MENU *menu)
{
	int mx,my;
	menu_getmenuxy(menu, &mx, &my, NULL, NULL);
	SELECTOR *sel;
	for (sel = menu->sellist;  sel != NULL && sel->var >= 0;  sel++)
	{
		SEL_E *pre_seli = n2se(sel,sel->var);
		SEL_E *seli;  int var;
		for (seli=menu_selector_element_getfirst(sel),var=0;
			 seli!=NULL;
			 seli=menu_selector_element_getnext(sel),var++)
		{
			if (seli->x<=ms.x-mx && ms.x-mx<=seli->x+14+6*strlen(seli->str) &&
			    seli->y<=ms.y-my && ms.y-my<=seli->y+11 && seli->available)
			{
				putpict(mx+pre_seli->x, my+pre_seli->y, Pselectoff);
				putpict(mx+seli->x, my+seli->y, Pselecton);
				sel->var = var;
			}
		}
	}
	for (sel = menu->d_sellist;  sel != NULL;  sel=sel->next)
	{
		SEL_E *pre_seli = n2se(sel,sel->var);
		SEL_E *seli;  int var;
		for (seli=menu_selector_element_getfirst(sel),var=0;
			 seli!=NULL;
			 seli=menu_selector_element_getnext(sel),var++)
		{
			if (seli->x<=ms.x-mx && ms.x-mx<=seli->x+14+6*strlen(seli->str) &&
			    seli->y<=ms.y-my && ms.y-my<=seli->y+11 && seli->available)
			{
				putpict(mx+pre_seli->x, my+pre_seli->y, Pselectoff);
				putpict(mx+seli->x, my+seli->y, Pselecton);
				sel->var = var;
			}
		}
	}
}


/*--------------------------------------------------------*/
/*                    メニュー上の描画                    */
/*--------------------------------------------------------*/


// メニュー内に文字列を描画する


void	menu_putstr(int ofsx, int ofsy, char *str, int type)
// type : typeSTR, typeSTRe のいずれか
{
	if (str == NULL)
		return;
	int sx,sy;
	menu_getmenuxy(NULL, &sx, &sy, NULL, NULL);
	sx += ofsx;
	sy += ofsy;
	ARTputstr12(sx,sy,str,Cmenustring,Cmenu);
}


void	menu_buttonputstr(BUTTON *ip, int ofsx, int ofsy, char *str, int type)
{
	menu_putstr(ip->x+ofsx, ip->y+ofsy, str, type);
}


/*--------------------------------------------------------*/
/*                  メニューの描画･消去                   */
/*--------------------------------------------------------*/


static	int		menuX_bk,menuY_bk;
static	int		menuX0_bk,menuY0_bk;
static	bool	subMenuDisp = NO;
static	MENU	*cmenu_bk;
static	char	*subm_scrbuf = NULL;
static	MENU	*pre_menu = NULL;


static void draw_shadedbox
	(int x1,int y1,int xlen,int ylen,int col, int col_light, int col_shade,
	 bool f_frameonly, bool f_inverse)
{
	if (!f_frameonly)
		grboxfill(x1,y1,xlen,ylen,col,DrawNORMAL);
	ghline(x1,x1+xlen-1,y1+ylen-1,col_shade,DrawNORMAL);
	gvline(x1+xlen-1,y1,y1+ylen-1,col_shade,DrawNORMAL);
	ghline(x1,x1+xlen-(f_inverse?2:1),y1,col_light,DrawNORMAL);
	gvline(x1,y1,y1+ylen-(f_inverse?2:1),col_light,DrawNORMAL);
}


static void draw_menubase(int x1, int y1, int xlen, int ylen, char *title)
// タイトルバーつきメニュー枠の描画
{
	draw_shadedbox(x1,y1,xlen,ylen,ColM,ColL,ColS,NO,NO);
	if (title != NULL && title[0] != '\0')
	{
		int tlen = 6 * strlen(title);
		int l1,l2,l3,sx;
		l2 = tlen+24;
		l1 = ((xlen-2)-l2)/2;
		l3 = (xlen-2)-(l1+l2);
		sx = x1 + (xlen-tlen)/2;
		draw_shadedbox(x1+1,y1+1,l1,16,ColM,ColL,ColS,YES,NO);
		draw_shadedbox(x1+1+l1,y1+1,l2,16,ColM2,ColS,ColL,NO,YES);
		draw_shadedbox(x1+1+l1+l2,y1+1,l3,16,ColM,ColL,ColS,YES,NO);
		ARTputstr12(sx+1,y1+3,title,Cwhite,Cmenu);
		ARTputstr12(sx,y1+3,title,Cmenushade,Cmenu);
	}
	else
		draw_shadedbox(x1+1,y1+1,xlen-2,16,ColM,ColL,ColS,YES,NO);
}


void menu_drawbox(int x1, int y1, int xlen, int ylen)
{
	draw_shadedbox(x1,y1,xlen,ylen,ColM,ColL,ColS,YES,NO);
}


static void menu_dispbuttons(MENU *menu, BUTTON *ip)
// list_method: 0=array  1=pointer-link-list
{
	PRINT("menu_dispbuttons begin\n");
	int mx,my,mxlen,mylen;
	menu_getmenuxy(menu, &mx, &my, &mxlen, &mylen);
	int n;
	for (n=0; ip!=NULL && ip->x>=0; ip++,n++)
	{
		PRINT("button static %d ",n);
		switch (ip->type)
		{
		case typeBUTTONS:
			PRINT("[BUTTONS]");
			menu_dispbuttons(menu, (BUTTON*)ip->var);
			break;
		case typePIC:
			PRINT("[PIC]");
			putpict(mx+ip->x, my+ip->y, ip->var);
			break;
		case typeSTR:	// 普通の文字列
		case typeSTRe:	// 太字文字列
		case typeSTRb:	// 箱入り文字列(ボタン用)
		case typeSTRc:  // センタリング立体強調文字列
			PRINT("[STR][%s]",(char*)ip->var);
			int sx,sy;
			sx = mx + ip->x;
			sy = my + ip->y;
			if (ip->type == typeSTRb)
			{
				menu_drawbox(sx,sy,ip->xlen,ip->ylen);
				sx+=4,sy+=2;
			}
			if (ip->type == typeSTRc)
			{
				int len = 6 * strlen((char*)ip->var);
				sx = mx + (mxlen - len)/2;
				ARTputstr12(sx+1,sy,(char*)ip->var,Cwhite,Cmenu);
				ARTputstr12(sx,sy,(char*)ip->var,Cmenushade,Cmenu);
			}
			else if (ip->type == typeSTRe)
			{
				// ARTputstr12(sx+1,sy,(char*)ip->var,Cmenulight,Cmenu);
				ARTputstr12(sx,sy,(char*)ip->var,Cmenustring,Cmenu);
			}
			else if ((char *)ip->var != NULL)
				ARTputstr12(sx,sy,(char*)ip->var,Cmenustring,Cmenu);
			break;
		case typeBOX:
			PRINT("[BOX]");
			grboxfill(mx+ip->x,my+ip->y,ip->xlen,ip->ylen,
					  DMgetmenuplt(ip->var), DrawNORMAL);
			break;
		}
		if (ip->dspfunc != NOFNC)
			PRINT("[callfunc]");
		if (ip->dspfunc != NOFNC)
			(*ip->dspfunc)(mx+ip->x, my+ip->y);
		PRINT("\n",n);
	}
	PRINT("menu_dispbuttons end\n");
}


static void drawMenu_prim(void)
{
	PRINT("drawMenu_prim begin\n");
	int mx,my,mxlen,mylen;  MENU *menu;
	menu = menu_getcurmenu();
	KNOW(menu!=NULL);
	menu_getmenuxy(NULL, &mx, &my, &mxlen, &mylen);
	PRINT("mx:%d my:%d mxlen:%d mylen:%d\n",mx,my,mxlen,mylen);
	draw_menubase(mx,my,mxlen,mylen,menu->title);
	menu_dispbuttons(menu,menu->buttonlist);
	PRINT("メニュー描画中: ボタンリスト描画終了\n");
	SCROLLBAR *sp;
	for (sp = menu->sbarlist;  sp!=NULL && sp->x >= 0;  sp++)
		menu_drawscrollbar(sp);
	PRINT("メニュー描画中: スクロールバー描画終了\n");
	void dspsel(SEL *sel)
	{
		SELECTOR_ELEMENT *seli;
		for (seli = menu_selector_element_getfirst(sel);
			 seli != NULL;
			 seli = menu_selector_element_getnext(sel))
		{
			putpict(mx+seli->x, my+seli->y, Pselectoff);
		   ARTputstr12(mx+seli->x+14,my+seli->y,seli->str,Cmenustring,Cmenu);
			if (! seli->available)
				mist(mx+seli->x+14, my+seli->y, 6*strlen(seli->str),12, Cmenu);
		}
		seli = n2se(sel,sel->var);
		putpict(mx+seli->x, my+seli->y, Pselecton);
	}
	SELECTOR *sel;
	for (sel = menu->sellist;  sel!=NULL && sel->var >= 0;  sel++)
		dspsel(sel);
	for (sel = menu->d_sellist;  sel!=NULL;  sel=sel->next)
		dspsel(sel);
	PRINT("メニュー描画中: 選択子描画終了\n");
	if (menu->dspfunc != NOFNC)
		(*(menu->dspfunc))();
	PRINT("drawMenu_prim end\n");
}


int menu_dispxy(int x, int y, MENU *menu)
// (x,y):
//     メニューを表示する座標：メニュー左上 (特に指定しないときは -1)
//                                          (画面の真ん中に表示したいときは -2)
//									(メインメニューを最初に表示するときは -3)
// 返値: 0=成功 -1=メモリ不足
{
	int err=0;
	key_clrbuf();

	int __menu_x0, __menu_y0;
	PRINT("menu_dispxy begin\t[%s]\n", menu->title);
	// メニューリストのシフト
	int i;
	for (i=MENUNUM-1; i>=1; i--)
		menulist[i] = menulist[i-1];
	menulist[0] = menu;
	// メニュー座標の決定
	int zr = DMimage_getzoomrate();
	if (x >= 0)
		menu->x0 = x;
	else if (x == -2)
	{
		if (pre_menu != NULL && menu != pre_menu)
			__menu_x0 = pre_menu->x0;
		else
			__menu_x0 = menu->x0;
		menu->x0 = (DMgetxsize() - menu->xlen) / 2;
	}
	else if (x == -3)
	{
		__menu_x0 = menu->x0 = (DMgetxsize() - menu->xlen) / 2;
	}
	else
		if (pre_menu != NULL && menu != pre_menu)
			menu->x0 = pre_menu->x0;
	if (y >= 0)
		menu->y0 = y;
	else if (y == -2)
	{
		if (pre_menu != NULL && menu != pre_menu)
			__menu_y0 = pre_menu->y0;
		else
			__menu_y0 = menu->y0;
		menu->y0 = (DMgetysize() - menu->ylen) / 2;
	}
	else if (y == -3)
	{
		__menu_y0 = menu->y0 = (DMgetysize() - menu->ylen) / 2;
	}
	else
		if (pre_menu != NULL && menu != pre_menu)
			menu->y0 = pre_menu->y0;
	menu->x = (menu->x0 / zr) * zr;
	menu->y = (menu->y0 / zr) * zr;
	menu->x = _min(((DMgetxsize()-menu->xlen) / zr) * zr, menu->x);
	menu->y = _min(((DMgetysize()-menu->ylen) / zr) * zr, menu->y);
	menu->nobuf = NO;
	if (DMmenu1_addbox(menu->x,menu->y,menu->xlen,menu->ylen) != 0)
	{
		PRINT("メニュー表示域画像退避バッファ　確保失敗\n");
		menu->nobuf = YES;
		// // メニューリストのシフト（もとにもどす）
		// for (i=1; i<=MENUNUM-1; i++)
		// 	menulist[i-1] = menulist[i];
		// menulist[MENUNUM-1] = NULL;
		// err = -1;
		// goto end_drawMenuTo;
	}
	else
		PRINT("メニュー表示域画像退避バッファ　確保成功\n");
	//
	drawMenu_prim();
	menu->display = YES;

end_drawMenuTo:
	if (x == -2)
		menu->x0 = __menu_x0;
	if (y == -2)
		menu->y0 = __menu_y0;
	pre_menu = menu;
	PRINT("menu_dispxy end  \t[%s]\n", menu->title);
	return err;
}


int menu_disp(MENU *menu)
{
	return menu_dispxy(-1, -1, menu);
}


void menu_erase()
{
	char menuname[100];  MENU *menu;  int i;
	menu = menulist[0];
	strcpy(menuname, menu->title);
	PRINT("menu_erase begin [%s]\n", menuname);

	menu->display = NO;
	if (menu->ersfunc != NOFNC)
		(*menu->ersfunc)();
	// menu_clearselector(menu);
	if (!menu->nobuf)
		DMmenu1_deletebox();
	// メニューリストのシフト
	for (i=1; i<=MENUNUM-1; i++)
		menulist[i-1] = menulist[i];
	menulist[MENUNUM-1] = NULL;

	PRINT("menu_erase end   [%s]\n", menuname);
}


/*--------------------------------------------------------*/
/*       メニューの描画・消去以外のメニュー関連処理       */
/*--------------------------------------------------------*/


void	menu_settitle(MENU *m, char *title)
{
	m->title = title;
}


int		menu_addselector(MENU *m, SEL *s)
{
	SEL *sp;
	s->next = NULL;
	if(m->d_sellist == NULL)
		m->d_sellist = s;
	else {
		for(sp=m->d_sellist;sp->next!=NULL;sp=sp->next)
			;
		sp->next = s;
	}
	return 0;
}


void	menu_clearselector(MENU *m)
{
	SEL *psp,*sp;
	SEL_E *pep,*ep;
	for(psp=NULL,sp=m->d_sellist;sp!=NULL;psp=sp,sp=sp->next)
	{
		if(psp!=NULL) menu_selector_delete(psp);
		for(ep=sp->d_elist,pep=NULL;ep!=NULL;pep=ep,ep=ep->next)
		{
			if(pep!=NULL) menu_selector_element_delete(pep);
		}
		if(pep!=NULL) menu_selector_element_delete(pep);
		sp->d_elist = NULL;
	}
	if(psp!=NULL) menu_selector_delete(psp);
	m->d_sellist = NULL;
}


void menu_move()
{
	int zr = DMimage_getzoomrate();
	int dx,dy;  MENU *menu;
	menu = menu_getcurmenu();
	// ● 現在表示しているメニューの消去
	menu_erase();
	// ● 移動処理
	dx = ms.x - menu->x;
	dy = ms.y - menu->y;
	void drawcsr(int x,int y)
	{
		if (!DMgetifonepage())
			grboxline(x,y,menu->xlen,menu->ylen,DMgetmenuplt(csrcol),DrawXOR);
		else
			grboxline(x,y,menu->xlen,menu->ylen,DMgetmenuplt(White),DrawXOR);
	}
	while (ms.btn1==OFFON || ms.btn1==ON)
	{
		int prex,prey;
		DMdispcsr(ms.x,ms.y);
		prex=((ms.x-dx)/zr)*zr;
		prey=((ms.y-dy)/zr)*zr;
		drawcsr(prex,prey);
		do
		{
			ms_get(&ms);
		} while ((ms.btn1==OFFON||ms.btn1==ON) && ms.dx==0 && ms.dy==0 &&
		         key_chk()==0);
		DMerasecsr();
		drawcsr(prex,prey);		// 消去
		if (ms.x-dx < 0)
			ms.x = dx;
		else if (ms.x-dx+menu->xlen >= DMgetxsize())
			ms.x = DMgetxsize()-menu->xlen + dx;
		if (ms.y-dy < 0)
			ms.y = dy;
		else if (ms.y-dy+menu->ylen >= DMgetysize())
			ms.y = DMgetysize()-menu->ylen + dy;
	}
	menu->x0 = menu->x = ((ms.x-dx)/zr)*zr;
	menu->y0 = menu->y = ((ms.y-dy)/zr)*zr;
	// ● もと表示していたメニューの表示
	menu_disp(menu);
}


/*--------------------------------------------------------*/
/*      メニューに対する任意データの設定・取得・解除      */
/*--------------------------------------------------------*/


void menu_setdata(MENU *menu, void *data)
{
	if (menu == NULL)
		menu = menu_getcurmenu();
	menu->data = data;
}


void *menu_getdata(MENU *menu)
{
	if (menu == NULL)
		menu = menu_getcurmenu();
	return menu->data;
}


void menu_cleardata(MENU *menu)
{
	if (menu == NULL)
		menu = menu_getcurmenu();
	menu->data = NULL;
}


/* end of menu.c */
