/*
 * DDS MICRO-C IBM/PC Supplementary window functions
 *
 * Copyright 1989-2000 Dave Dunfield
 * All rights reserved.
 *
 * Permission granted for personal (non-commercial) use only.
 */
#include <8086io.h>
#include <window.h>
#define	SCREEN_WIDTH 80		/* width of IBM-PC screen */

static char wgi = 0;

/*
 * Put a string on the screen in a window
 */
w_puts(text, window)
	char *text, *window;
{
	while(*text)
		w_putc(*text++, window);
}

/*
 * Put a string on the screen in the current window
 */
wputs(text)
	char *text;
{
	while(*text)
		wputc(*text++);
}

/*
 * Put a string on the screen in a certain width field
 */
wputf(text, width)
	char *text;
	int width;
{
	while(width--)
		wputc(*text ? *text++ : ' ');
}

/*
 * Select an entry from a multiple choice menu
 */
wmenu(x, y, attrs, names, initial)
	int x, y, attrs, *initial;
	char *names[];
{
	int i, j, mawlen, mawentry;
	char c, *ptr, n, r;

/* First, determine longest selection, and open the window */
	for(mawentry=mawlen=0; ptr = names[mawentry]; ++mawentry) {
		if((i=strlen(ptr)) > mawlen)
			mawlen = i; }
	wopen(x, y, (attrs & WBOX3) ? mawlen+2 : mawlen,
				(attrs & WBOX3) ? mawentry+2 : mawentry, attrs);
	--mawentry;
	wcursor_off();

	n = *W_OPEN;
	r = ((unsigned)n>>4) | ((unsigned)n<<4 & 0xf0);
	for(i=0; i <= mawentry; ++i) {
		wgotoxy(0, i);
		wputs(names[i]); }

/* Print selection cursor, and wait for keys */
	i = *initial;
	do {
		wgotoxy(0, i);
		*W_OPEN = r;
		wputf(names[i], mawlen);
		*W_OPEN = n;
		c = toupper(wgetc());
		wgotoxy(0, i);
		wputf(names[i], mawlen);
		switch(c) {			/* handle special cases */
			case _KUA:			/* UP arrow */
				i = i ? i-1 : mawentry;
				break;
			case _KDA:			/* DOWN arrow */
				i = (i < mawentry) ? i+1 : 0;
				break;
			case _KHO:			/* HOME key */
				i = 0;
				break;
			case _KEN:			/* END key */
				i = mawentry;
				break;
			case 0x1B:			/* ESCAPE key (abort) */
				W_OPEN[1] |= 0x10;	/* Insure window clears */
				c = '\n';			/* Force exit */
				initial = -1;		/* Indicate abortion */
				break;
			case '\n':			/* RETURN key (select) */
				wgotoxy(0, i);
				*W_OPEN = r;
				wputc(*names[i]);
				*W_OPEN = n;
				*initial = i;
				initial = 0;		/* Indicate enter */
				break;
			default:
				if(c >= 0) {	/* First character lookup */
					for(j=0; j <= mawentry; ++j)
						if(*names[j] == c) {
							i = j;
							break; }
					break; }
				wputc(7); } }
	while(c != '\n');
	wclose();
	return initial;
}

/*
 * Get a string from a field in the window
 */
wgets(x, y, string, length)
	int x, y, length;
	char string[];
{
	int c, i, j, len;

	len = length & 0x7f;
	i = 0;
	for(;;) {
		wgotoxy(x, y);
		wputf(string, len);
		wgotoxy(x+i, y);
		wgi ? wcursor_block() : wcursor_line();
		switch(c = wgetc()) {
			case _KLA :		/* Backup */
				if(i)
					--i;
				break;
			case _KRA :		/* Forward */
				if(string[i] && (i < len))
					++i;
				break;
			case _KBS :		/* Backspace & delete */
				if(!i)
					break;
				--i;
			case _KDL :		/* Delete character */
				for(j=i; (j < len) && string[j]; ++j)
					string[j] = string[j+1];
				break;
			case _KIN:		/* Insert key */
				wgi = !wgi;
				break;
			case _KHO:		/* Home key */
				i = 0;
				break;
			case _KEN:		/* End key */
				for(i=0; (i < (len-1)) && string[i]; ++i);
				break;
			case _KPU:		/* Page up (clear field) */
				i = 0;
			case _KPD:		/* Page down (Clear to end) */
				string[i] = 0;
				break;
			default:		/* Normal (data) character */
				if(c >= 0) {
					if((length & 0x80) && ((c < '0') || (c > '9')))
						break;
					if(wgi) {
						for(j=len; j > i; --j) {
							string[j] = string[j-1];
						string[len] = 0; } }
					if(!string[i])
						string[i+1] = 0;
					string[i] = c;
					if(i < (len-1))
						++i;
					break; }
			case '\n':		/* Enter */
			case 0x1B:		/* Escape */
				return c; } }
}

/*
 * Handle a screen form input
 */
register wform(args)
	unsigned args;
{
	unsigned *argptr, attrs, x, y, length, pos, *nptr, *nptr1;
	char **form, *ptr, buffer[25];

	/* Extract the fixed arguments */
	argptr = nargs()*2 + &args;
	x = *--argptr;
	y = *--argptr;
	attrs = *--argptr;
	form = *--argptr;	/* Get form address */

	/* Draw the initial values */
	wopen(x, y, (int)form[0] >> 8, (int)form[0] & 255, attrs);
	for(pos=1; ptr = form[pos]; ++pos) {
		nptr = nptr1 = *(argptr - pos*2);
		wgotoxy(*ptr++, *ptr++);
		if((length = *ptr++) & 0x80)
			sprintf(nptr = buffer,"%u", *nptr1);
		wputs(ptr);
		wputc(' ');
		wputf(nptr, length & 0x7f); }

	/* Now, allow editing of the forms */
	pos = 1;
	for(;;) {
		ptr = form[pos];
		nptr1 = nptr = *(argptr - pos*2);
		x = *ptr++;
		y = *ptr++;
		if((length = *ptr++) & 0x80)
			sprintf(nptr = buffer,"%u", *nptr1);
		attrs = wgets(x+strlen(ptr)+1, y, nptr, length);
		if(length & 0x80)
			*nptr1 = atoi(buffer);
		switch(attrs) {
			case _KUA :		/* Up arrow */
				if(pos > 1)
					--pos;
				else {
					for(length=1; form[length]; ++length);
					pos = length-1; }
				break;
			case _KDA :		/* Down arrow */
				if(!form[++pos])
					pos = 1;
				break;
			case '\n' :		/* Enter key */
				if(form[++pos])
					break;
				wclose();
				return 0;
			case 0x1B :		/* Escape */
				wclose();
				return -1;
			default:
				wputc(7); } }
}