/*****************************************************************************/
/* エリアセレクト ｂｙ　マウス ＆ キー */
/* V2.0 : '92/07/08 : テキスト対応他大幅改良 */
/* V2.1 : '92/07/11 : 座標情報表示９６桁以外大幅変更 */
/* V2.2 : '94/02/25 : 枠点滅クロック依存無し化 */
/*****************************************************************************/

#include <stdio.h>
#include <iocslib.h>
#include "defines.h"
#include "amouse.h"
#include "amacro.h"
#include "amouse.h"
#include "skey.h"

/*****************************************************************************/
/* グローバル変数：引数渡しの時間をなくし高速化するため */

static int dvx,dvy,dvx1,dvy1;
static int tx,ty;
static int x=0,y=0,sx,sy;
static int dy;
static int zdx,sdx,hdx,wdx; /* 座標表示座標 */

/*****************************************************************************/

#define disp_now_xy()	disp_xy(zdx,x,y)   /* 現在座標表示 */
#define disp_sxy()	disp_xy(sdx,sx,sy) /* 始点表示 */
#define disp_one_wxy()	disp_xy(wdx,wxy[sxy],wxy[sxy+1]) /* ワンタッチ幅表示 */

/*****************************************************************************/

static void mswaku(int sx,int sy,int ex,int ey,int style)
/* 枠表示 */
{
int c;
	/* 座標修正：終点と始点の位置はどっちが大きいか判らないから */
	if (sx>ex) {c=ex; ex=sx; sx=c;}
	if (sy>ey) {c=ey; ey=sy; sy=c;}
	ex-=sx;
	ey-=sy;
	/* ボックス表示 */
	if (dvx==1) { /* グラフィック */
		ex++;
		ey++;
	} else { /* テキスト */
		ex*=8;  if (ex==0) ex=1;
		ey*=16; if (ey==0) ey=1;
		sx=sx*8+4;
		sy=sy*16+8;
	}
	/* ここでのex,eyは幅を表わしている */
	txbox(1,sx+1,sy+1,ex-2,ey-2,style);
	txbox(1,sx,sy,ex,ey,style);
}

/*****************************************************************************/

static void disp_xy(int dx,int x,int y)
/* 座標／幅表示 */
{
	B_LOCATE(dx,dy);
	if (x<0) {
		B_PRINT("---,---");
	} else {
		B_PRINT_DEC(x,' ',3);
		B_PUTC(',');
		B_PRINT_DEC(y,' ',3);
	}
}

/*****************************************************************************/

static void disp_wxy()
/* 幅表示 */
{
int wx,wy;
	if (sx==-1) wx=-1;
	else {
		wx=x-sx+1; if (wx<0) wx=sx-x+1;
		wy=y-sy+1; if (wy<0) wy=sy-y+1;
	}
	disp_xy(hdx,wx,wy);
}

/*****************************************************************************/

static void disp_line(int xys,int wxy[],int sxy,int area[])
/* 初期情報ライン表示 */
{
int adx1=-1,adx2;
	B_LOCATE(0,dy);
	switch (tx) {
	    case 96:
	    case 768:
		/*       0         1         2         3          */
		/*       0123456789012345678901234567890123456789 */
		B_PRINT("[座標:---,---][始点:---,---][幅:---,---]");
		zdx=6; sdx=20; hdx=32;
		if (xys>0) {
			B_LOCATE(40,dy);
			/*       4         5     */
			/*       012345678901234 */
			B_PRINT("[ﾜﾝﾀｯﾁ:---,---]");
			wdx=47;
		}
		if (area!=NULL) {
			B_LOCATE(55,dy);
			/*       5    6         7         */
			/*       567890123456789012345678 */
			B_PRINT("[範囲:---,--- - ---,---]");
			adx1=61; adx2=71;
		}
		break;
		
	    case 64:
	    case 512:
		/*       0         1         2       */
		/*       012345678901234567890123456 */
		B_PRINT("[---,---][---,---][---,---]");
		zdx=1; sdx=10; hdx=19;
		if (xys>0) {
			B_LOCATE(27,dy);
			/*       2  3      */
			/*       789012345 */
			B_PRINT("[---,---]");
			wdx=28;
		}
		if (area!=NULL) {
			B_LOCATE(36,dy);
			/*       3   4         5     */
			/*       6789012345678901234 */
			B_PRINT("[---,--- - ---,---]");
			adx1=37; adx2=47;
		}
		break;
		
	    case 32:
	    case 256:
		/*       0         1         2   */
		/*       01234567890123456789012 */
		B_PRINT("---,---:---,---:---,---");
		zdx=0; sdx=8; hdx=16;
		if (xys>0) {
			B_LOCATE(23,dy);
			/*       2      3 */
			/*       34567890 */
			B_PRINT(":---,---");
			wdx=24;
		}
		/* 選択可能領域は表示できない */
		break;
	}
	/* 初期表示 */
	disp_now_xy();
	disp_sxy();
	disp_wxy();
	if (xys>0) disp_one_wxy(); /* ワンタッチ幅 */
	if (adx1>=0) { /* 選択可能領域（これは最初だけ表示：途中で変わらないから）*/
		disp_xy(adx1,area[0],area[1]);
		disp_xy(adx2,area[2],area[3]);
	}
}

/*****************************************************************************/

static void area_set(int area[4],int fon,int finit)
/* 移動可能範囲設定／表示 ＆ 解除 */
{
int sx,sy,ex,ey;
	sx=area[0]*dvx;
	sy=area[1]*dvy;
	ex=(area[2]+1)*dvx-1;
	ey=(area[3]+1)*dvy-1;
	
	/* マウス移動可能範囲設定 */
	if (fon) {
		MS_INIT();
		SKEY_MOD(0,0,0); /* ソフトウエアキーボード消去 */
		MS_LIMIT(sx,sy,ex,ey);
	} else {
		MS_LIMIT(0,0,tx*dvx-1,ty*dvy-1);
	}
	
	/* 外枠 */
	if (!(finit&BIT16)) txbox(2,sx,sy,ex-sx+1,ey-sy+1,fon? 0x0707:0x0000);
}

/*****************************************************************************/

int areasel(asx,asy,aex,aey,fdisp,xys,wxy,area,finit,mode,inkeys)
int *asx,*asy,*aex,*aey;
int fdisp;
int xys,wxy[],area[4];
int finit;
int mode; /* 1=Graphic , 0=Text , BIT15=1:文字表示色白 */
int (*inkeys)(); /* キー入力関数 */
{
int ret,cur,col,msc,mcx,mcy,br,bl,c,ww,sxy=0;
int cx,cy;
int fclr=0,fdcut=0;
int tm0,t,wk;
int area2[4];
	/* 画面設定 */
	/* プレーン０：座標表示 */
	/* プレーン１：枠表示 */
	/* 文字表示には基本的にはプレーン０しか使えないから */
	/* しかし、areaの設定によって文字表示領域を領域選択領域外にした場合は使える */
	/* この場合、fispは<0にして固定しなければならない */
	col=B_COLOR(mode&BIT15? TWHITE:TCYAN);
	mode&=0x7fff; /* BIT15を消す */
	cur=curmode(0); /* cursor off */
	/* モード別定数設定 */
	if (mode) { /* グラフィック */
		if (finit&0x7fff) { /* 画面初期化 */
			syslineoff(); /* システム行オフ */
			cls();	      /* テキスト画面クリア */
		}
		dvx=dvy=dvx1=1;
		dvy1=16;
	} else { /* テキスト */
		dvx=8;
		dvy=16;
		dvx1=2;
		dvy1=1;
	}
	/* 画面幅 */
	ty=gxy(&tx)/dvy;
	tx/=dvx;
	
	/* 移動可能範囲設定 */
	if (area==NULL) { /* 指定なしの時は画面一杯 */
		area2[0]=area2[1]=0;
		area2[2]=tx-1;
		area2[3]=ty-1;
	} else { /* 指定有りの時 */
		/* 終点の判定だけする */
		/* それ以外の判定はしないので、必ず始点＜終点のこと */
		for (ret=0;ret<4;ret++) area2[ret]=area[ret]; /* まずはコピー */
		if (area2[2]==-1 || area2[2]>=tx) area2[2]=tx-1;
		if (area2[3]==-1 || area2[3]>=ty) area2[3]=ty-1;
	}
	
	if (xys>0) {
		if (wxy[0]==0) wxy[0]=area2[2]-area2[0]+1;
		if (wxy[1]==0) wxy[1]=area2[3]-area2[1]+1;
	}
	
	/* マウス初期座標設定 */
	if (finit&0x7fff) {
		/* 移動可能範囲ホーム */
		x=area2[0];
		y=area2[1];
	} else {
		/* 現在の位置 */
		if (mode) { /* グラフィック */
			x=MS_CURGT();
			y=(x&0xffff);
			x>>=16;
			#if 0
			if (x<area2[0]) x=area2[0];
			if (y<area2[1]) y=area2[1];
			if (x>area2[3]) x=area2[2];
			if (y>area2[4]) x=area2[3];
			#endif
		} else { /* テキスト */
			x=-1;
			y=-1;
		}
	}
	
	/* 座標表示制限 */
	if (fdisp<0) {
		fdcut=1;
		if (fdisp==-3) fdisp=0;
		else fdisp=-fdisp;
	}
	
	/* マウス初期化 */
	if (area!=NULL) area_set(area2,1,finit);
	msc=ms_set(&mcx,&mcy,x,y,0); /* マウス状態セット */
	/* マウス移動可能範囲設定 */
	
	sx=-1; /* 始点設定していないの印 */
	cx=cy=-1;
	tm0=ONTIME();
	wk=0;
	
	if (fdisp) {
		dy=(fdisp==2? 0:ty/dvy1-2); /* 座標表示Ｙ座標 */
		disp_line(xys,wxy,sxy,area==NULL? NULL:area2);
	}
	
	while (1) {
		/* 現在のマウス座標を記録（変化前座標）*/
		cx=x; cy=y;
		
		/* マウスカーソル座標 */
		x=MS_CURGT();
		y=(x&0xffff)/dvy;
		x=(x>>=16)/dvx;
		
		/* リアルタイムキー入力 */
		c=inkeys(sx,sy,x,y);
		if (c!=0) { /* キーに操作 */
		    int cx1,cy1;
			cx1=x; cy1=y; /* キーによる移動前座標 */
			ww=1; /* 増減差分 */
			if ((c&BIT0)||(c&BIT2)) ww=8/dvx1; /* +SHIFT/+OPT.1 = ±８/dvx1 */
			if (c&BIT3) ww=16/dvx1; /* +OPT.2 = ±１６/dvx1 */
			if (c&BIT1) ww=4/dvx1; /* +CTRL = ±４/dvx1 */
			switch (c&0xff00) {
			    case SKtab0: /* TAB:ワンタッチ枠幅切り替え */
				if (xys==0) break;
				/* 次ぎのデータへ */
				sxy+=2;
				if (sxy>=xys*2) sxy=0;
				if (fdisp) disp_one_wxy();
			    case SKspc0: /* SPC:ワンタッチ枠幅設定 */
				if (xys==0) break;
				if (sx==-1) { /* 始点が設定されていない時 */
					sx=x; /* まず、現在座標を始点にする */
					sy=y;
					if (fdisp) disp_sxy();
				}
				/* ポイント座標設定 */
				x=sx+wxy[sxy]-1;
				y=sy+wxy[sxy+1]-1;
				
				/* 領域外に出そうな時は画面いっぱいまで */
				if (x>area2[2]) x=area2[2];
				if (y>area2[3]) y=area2[3];
				break;
				
			    case SKclr: /* CLR */
				if (!fdcut) {
				    switch (fdisp) {
					default:
					case 2: /* ON(上) -> OFF */
						B_LOCATE(0,dy); eline();
						fdisp=0;
						break;
					case 1: /* ON(下) -> ON(上) */
						B_LOCATE(0,dy); eline();
					case 0: /* OFF -> ON(下) */
						/* 座標表示Ｙ座標 */
						fdisp++;
						dy=(fdisp==2? 0:ty/dvy1-2);
						disp_line(xys,wxy,sxy,area==NULL? area:area2);
						break;
				    }
				}
				break;
				
			    case SKleft: /* ← */
				if (x>=ww+area2[0]) x-=ww; else x=area2[0];
				break;
			    case SKup: /* ↑ */
				if (y>=ww+area2[1]) y-=ww; else y=area2[1];
				break;
			    case SKright: /* → */
				if (x<=area2[2]-ww) x+=ww; else x=area2[2];
				break;
			    case SKdown: /* ↓ */
				if (y<=area2[3]-ww) y+=ww; else y=area2[3];
				break;
			    case SKhome: /* HOME */
				if (sx<0) { /* 始点が設定されていない時 */
					x=area2[0];
					y=area2[1];
				} else { /* 設定されている時 */
					x=sx;
					y=sy;
				}
				break;
			}
			/* 座標が変わった時はマウスカーソルも設定 */
			if (cx1!=x || cy1!=y) MS_CURST(x*dvx+dvx/2,y*dvy+dvy/2);
		}
		
		/* 現在座標表示（変化のあった時のみ）*/
		if (fdisp && (cx!=x || cy!=y)) disp_now_xy();
		
		if (sx>=0) { /* 始点は設定されている＝ボックス表示中 */
			if (x!=cx || y!=cy) { /* 枠に変化が会った時 */
				mswaku(sx,sy,cx,cy,0x0000); /* 前の枠を消す */
				if (fdisp) disp_wxy();
			}
			t=ONTIME();
			if (t-tm0>17) { /* 枠点滅（1/6sec）*/
				mswaku(sx,sy,x,y,wk? 0x3333:0xcccc);
				tm0=t;
				wk^=1;
			}
		}
		
		/* マウスボタン */
		br=MS_GETDT();
		bl=br&0xff00;
		br&=0x00ff;
		
		if (c==SKbrk || (br&&bl)) {
			/* BREAK/両ボタンが同時にが押されたら強制終了 */
			ret=2;
			fclr=1; /* 枠を消す */
			break;
		}
		
		if (c==SKesc || br) { /* ESC,右ボタン：始点解除／終了 */
			if (sx==-1) { /* 始点が設定されていない時は終了 */
				ret=1;
				break;
			}
			mswaku(sx,sy,x,y,0x0000); /* 今のボックスを消す */
			MSBOFF(); /* 両ボタンが離されるまで待つ */
			sx=-1; /* 始点解除の印 */
			if (fdisp) {
				disp_sxy();
				disp_wxy();
			}
		}
		else
		if ((c&0xff)==0x0d || bl) {
			/* CR/ENTER,左ボタン：始点/終点設定 */
			if (sx==-1) { /* 始点がまだ設定されていない時 */
				/* 始点設定 */
				sx=x;
				sy=y;
				if (fdisp) {
					disp_sxy();
					disp_wxy();
				}
			} else { /* 始点が既に設定されている時 */
				/* 幅判定 */
				if (xys>0) { /* 幅が大き過ぎる時 */
					ww=x-sx+1; if (ww<0) ww=sx-x+1;
					if (ww>wxy[0]) {
						beep();
						goto BL1;
					}
					ww=y-sy+1; if (ww<0) ww=sy-y+1;
					if (ww>wxy[1]) {
						beep();
						goto BL1;
					}
				}
				/* 座標設定 */
				/* 指定は小さく、終点は大きくする */
				if (sx>x) {ww=x; x=sx; sx=ww;}
				if (sy>y) {ww=y; y=sy; sy=ww;}
				*asx=sx;
				*asy=sy;
				*aex=x;
				*aey=y;
				ret=0;
				break; /* 終了 */
			}
		    BL1:;
			MSBOFF(); /* 両ボタンが離されるまで待つ */
		}
	}
	/* 終了 */
	MSBOFF(); /* 両ボタンが離されるまで待つ */
	if (fclr||(finit&BIT15)) mswaku(sx,sy,x,y,0x0000); /* 枠消し */
	ms_reset(msc,mcx,mcy); /* マウス状態復帰 */
	if (area!=NULL) area_set(area2,0,finit); /* 選択可能領域表示枠クリア */
	B_COLOR(col); /* 表示色戻し */
	curmode(cur); /* cursor on */
	/*if (mode) syslineon();*//* システム行 on */
	return(ret);
}

/*****************************************************************************/
