/*****************************************************************************/
/* Mini Data Viewer for X68000 V1.10 for Copyright (C) 1994 by AIG-Soft      */
/*****************************************************************************/

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

#define	SX	0		/* 今はx=0から */
#define	WX	DISPX		/* 横全画面のみ */
#define	BF	2		/* 反転時前後表示行数 */

static	int	fdisp=0;	/* 情報表示フラグ */
static	void	(*ViewStat)();	/* 表示関数 */

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

void SetViewStat(void (*VS)())
/* 情報表示関数設定 */
{
	/* 状態表示が不要なときは呼び出さなくてもいい */
	if (VS==NULL) fdisp=0;
	else {
		ViewStat=VS;
		fdisp=1;
	}
}

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

static void revline(int y)
/* 指定行反転 */
{
	/* ここはそれぞれのプレーンを反転するので同時アクセスにしない */
	txrev(0,SX*8,y*16,WX*8,16);
	txrev(1,SX*8,y*16,WX*8,16);
}

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

int MiniDataViewer(y,wy,all,page,stp,top,p,frmk,pr_line,getchs,exit)
int y,wy,all,page,stp,*top,*p,frmk,(*getchs)(),(*pr_line)(),exit[];
/* 引数の意味
	y	スクロールエリアは(SX,y)-(SX+WX-1,y+wy-1)
	wy	スクロール範囲行数
	all	全行数
	page	１ページ行数(<wy)
	stp	高速スクロール行数(<page)
	top	先頭行番号(0〜all-wy)
	p	反転ポイント : 0〜all-1 , <0で無効
		初期ガイドライン制御にも使われる
	frmk	画面を再表示するかどうか（枠内も消す）
	pr_line	１行表示関数
		pr_line(no)で、no行目の１行の表示を行う。
		カーソルは設定されているのでそのまま表示すれば良い。
		ただし、１行はWXの幅で納めること。
	getchs	キー入力関数
		キーバッファークリア付き
		コード変換をキー入力関数側に持たせることで、
		この関数内部でのコードを単純化する。
	exit	緊急脱出キー
		[0]=その数
		[1〜]=スキャンコード
*/
{
int c,i,len,topl,cur,fgp=0,gp=0; /* gp : ｶﾞｲﾄﾞﾗｲﾝﾎﾟｲﾝﾀｰ 0〜wy-1 */
	cur=curmode(0); /* cursor off */
	
	topl=*top;
	if (all<=wy) { /* １画面内に納まるときはtopl無効 */
		topl=0;
		wy=all;
	}
	
	if (*p>=0) { /* この指定はtoplの指定に優先する */
		/* 特定ライン反転 */
		if (all<=wy||(*p>=topl+BF && *p<=topl+wy-1-BF && wy>BF*2)) {
			/* 画面内移動 : topl不変 */
			/* 最低でも前後各２ライン(=BF)は入れる */
			gp=*p-topl;
		} else { /* 画面外移動 : topl変更 */
			gp=wy/2; /* 画面中央に置こうとする */
			topl=*p-gp;
			if (topl<0) {
				topl=0;
				gp=*p;
			}
		}
		fgp=1; /* guide line on */
		if (frmk==0) frmk=1; /* frmk=-1のときはあえてonにしない */
	}
	
	if (frmk>0) { /* 全表示付きスタート（一番最初は必ずこれにすること）*/
		/* 枠内クリアをする */
		for (i=0;i<wy;i++) {
			B_LOCATE(SX,y+i);
			eline();
		}
		goto REDISP2;
	} /* そのままスタート */
	
	/* キー操作 */
	while (c=getchs(1),c!=SKesc) {
		for (i=1;i<=exit[0];i++) { /* 緊急脱出キー */
			if (keycmp(c,exit[i])) goto END;
		}
		
		len=1; /* 通常のスクロール行数 */
		switch (c) {
		    default:
			continue;
		
		    case SKspc: /* ガイドライン on/off */
			if (fgp) revline(y+gp); /* 現在反転している所を消す */
			fgp^=1;
			break;
		
		    case SKdown|SKctrl: /* CTRL+↓:guide line down */
		    	if (topl+gp>=all-1) continue;
			if (fgp) revline(y+gp); /* 前の行の反転解除 */
			else { /* 出てないときは最上行に出す */
				gp=-1; /* 後で++されるから */
				fgp=1;
			}
			if (gp<wy-1) {
				gp++;
				break;
			}
			/* 一番下にあるときはスクロールアップと同じにする */
			text_scroll(SX,y,WX-1,y+wy-1,1,BIT5);
			B_LOCATE(SX,y+wy-1);
			pr_line(topl+wy);
			topl++;
			break;
		
		    case SKright: /* →:fast next */
			len=stp;
		    case SKdown: /* ↓:next */
		    	if (topl+wy>=all) continue;
			if (topl+wy+len>=all) len=all-topl-wy;
			text_scroll(SX,y,WX-1,y+wy-1,len,BIT5);
			for (i=0;i<len;i++) {
				B_LOCATE(SX,y+wy-len+i);
				pr_line(topl+wy);
				topl++;
			}
			if (fgp) {
				gp-=len;
				if (gp<0) gp=0;
				else fgp=-1;
			}
			break;
		
		    case SKup|SKctrl: /* CTRL+↑:guide line up */
			if (topl+gp==0) continue;
			if (fgp) revline(y+gp); /* 前の行の反転解除 */
			else { /* 出てないときは最下行に出る */
				gp=wy; /* 後で--されるから */
				fgp=1;
			}
			if (gp>0) {
				gp--;
				break;
			}
			/* 一番上にあるときはスクロールダウンと同じにする */
			text_scroll(SX,y,WX-1,y+wy-1,1,BIT0|BIT5);
			B_LOCATE(SX,y);
			pr_line(--topl);
			break;
		
		    case SKleft: /* ←:fast back */
			len=stp;
		    case SKup: /* ↑:back */
			if (topl==0) continue;
			if (topl-len<=0) len=topl;
			text_scroll(SX,y,WX-1,y+wy-1,len,BIT0|BIT5);
			topl-=len;
			for (i=0;i<len;i++) {
				B_LOCATE(SX,y+i);
				pr_line(topl+i);
			}
			if (fgp) {
				gp+=len;
				if (gp>wy-1) gp=wy-1;
				else fgp=-1;
			}
			break;
		
		    case SKdel: /* END:DEL */
		    case SKrup: /* ROLL-UP */
		    	if (topl+wy>=all) continue;
			topl+=page;
			if (c==SKdel||topl+wy>all) topl=all-wy;
			fgp=0;
			goto REDISP;
			
		    case SKhome:  /* HOME */
		    case SKrdown: /* ROLL-DOWN */
		    	if (topl==0) continue;
			topl-=page;
			if (c==SKhome||topl<0) topl=0;
			fgp=0;
		      REDISP:;
			/* エリア内再表示 */
			if (fgp) revline(y+gp); /* 現在反転している所を消す */
		      REDISP2:;
			for (i=0;i<wy;i++) {
				B_LOCATE(SX,y+i);
				pr_line(topl+i);
			}
			break;
		}
		/* ガイドライン表示 */
		if (fgp) {
			if (fgp<0) fgp=1;
			else revline(y+gp);
		}
		/* スクロールシンボルなど表示 */
		if (fdisp) ViewStat(topl,all,wy);
	}
    END:;
	curmode(cur);
	*top=topl;
	*p=(fgp? topl+gp:-1);
	return(c);
}

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