/*
        Routines for menus using mouse
*/
#include <stdio.h>
#include <graphics.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <dir.h>
#include <conio.h>
#include <dos.h>
#include "fdestria.h"
#include "fdesequa.h"
#include "fdesfile.h"
#include "fdesmous.h"
#include "fdesplot.h"
#define CURSOR_RIGHT (77<<8)	/* cursor right key */
#define CURSOR_LEFT (75<<8)	/* cursor left key */

float area_scaled;               /* area scale factor from zooming */
typedef struct {
	int selections;		/* number of selections */
	char *item[16];		/* 16 strings that represent selections */
	} popmenu;

#define ITEM_HEIGHT 20		/* Item height in pixels */
#define CHAR_WIDTH 8		/* Item width per character in pixels */

/* ************************************************************************
	pop-up menus
************************************************************************ */
/* menu routines */
int popup(int x, int y, popmenu *menu, int foreground, int background)
				/* display a pop-up menu and wait for mouse
				   selection */
{
int i,rcode;
int left,top,right,bottom;
void *scr_save;
mouse_state m;
int maxwidth;
	maxwidth = 0;
	for (i=0; i<(*menu).selections; i++) {
		if (strlen((*menu).item[i]) > maxwidth)
			maxwidth = strlen((*menu).item[i]);
	}
	left = x;
	top = y;
	right = x + CHAR_WIDTH*maxwidth + 2;
	bottom = y + (*menu).selections*ITEM_HEIGHT;
	scr_save = malloc(imagesize(left,top,right,bottom));
        if (scr_save == NULL)
        {
                restorecrtmode();
                printf("Out of Memory, Sorry.");
                exit(0);
        }
	/* save screen portion */
	getimage(left,top,right,bottom,scr_save);
	/* display pop-up menu */
        setfillstyle(SOLID_FILL,background);
	bar(left,top,right,bottom);
        setcolor(foreground);
	for (i=0; i<(*menu).selections; i++) {
		outtextxy(left+2,top+i*ITEM_HEIGHT+6,(*menu).item[i]);
	}
	/* input selection from mouse */
	do {
		mouse_click(&m);
		rcode = (m.row - top - 2)/ITEM_HEIGHT + 1;
	} while ((rcode < 1) || (rcode > (*menu).selections)
		|| !((m.col >= left) && (m.col <= right)));

	/* restore screen portion */
	putimage(left,top,scr_save,COPY_PUT);
	free(scr_save);
	return(rcode);
}

int mleft[10],mtop[10],mright,mbottom;
void *mscr_save[10];
int mscr_sp = -1;
/*
        putmsg
        returns next pixel in X direction
*/
int putmsg(int x, int y, char *str, int colorbk, int colorfo) /* display a pop-up message */
{
        if (strlen(str) == 0) return(x);
        mscr_sp++;
	mleft[mscr_sp] = x;
        mtop[mscr_sp] = y;
	mright = x + strlen(str)*CHAR_WIDTH + 2;
	mbottom = y + ITEM_HEIGHT;
        mscr_save[mscr_sp] = malloc(imagesize(mleft[mscr_sp],mtop[mscr_sp],
                                              mright,mbottom));
        if (mscr_save[mscr_sp] == NULL)
        {
                restorecrtmode();
                printf("Out of Memory, Sorry.");
                exit(0);
        }
	/* save screen portion */
        getimage(mleft[mscr_sp],mtop[mscr_sp],mright,mbottom,mscr_save[mscr_sp]);
	/* display pop-up menu */
	setfillstyle(SOLID_FILL,colorbk);
        bar(mleft[mscr_sp],mtop[mscr_sp],mright,mbottom);
	setcolor(colorfo);
	outtextxy(mleft[mscr_sp]+2,mtop[mscr_sp]+6,str);
        return(mright+1);
}
void clrmsg(void)
{
	/* restore screen portion */
	if (mscr_sp < 0) {
                restorecrtmode();
		printf("Too many pops of message text");
		exit(0);
	}
        putimage(mleft[mscr_sp],mtop[mscr_sp],mscr_save[mscr_sp],COPY_PUT);
	free(mscr_save[mscr_sp--]);
}
/*
        putmsg destructive
*/
int putmsg_d(int x, int y, char *str, int colorbk, int colorfo) /* display a pop-up message */
{
int mleft,mright,mtop,mbottom;
        if (strlen(str) == 0) return(x);
        mleft = x;
        mtop = y;
	mright = x + strlen(str)*CHAR_WIDTH + 2;
	mbottom = y + ITEM_HEIGHT;
	/* display pop-up menu */
	setfillstyle(SOLID_FILL,colorbk);
        bar(mleft,mtop,mright,mbottom);
	setcolor(colorfo);
        outtextxy(mleft+2,mtop+6,str);
        return(mright+1);
}

/* ************************************************************************
        A 'scanf' for graphics mode
        returns # of arguments
************************************************************************ */
int gscanf(int x, int y, char *prompt, int maxlength, char *format, ...)
{
char buf[133];
int si;                 /* string index into buf */
va_list parmlist;
unsigned int ch;
int input_x;
int i;
int rcode;
int mleft, mtop, mright, mbottom;

        input_x = putmsg(x,y,prompt,YELLOW,RED);

        for (i=0; i<maxlength; i++) buf[i]='_';
        buf[maxlength] = 0;
        putmsg(input_x, y, buf, WHITE, BLUE);

        buf[0] = 0;     /* null the string */
        si = 0;
        do {
                if ((ch = getch()) == 0) ch = getch() << 8;

                if (ch == 015) break;          /* carriage return */
                if (ch == 033)                 /* escape */
                {
                        clrmsg();
                        clrmsg();
                        return(0);
                }
                switch (ch)
                {
			case 010:      /* backspace */
                                if (si == 0) break;
                                si--;
                                buf[si] = 0;
                                break;
                        default:
                                if (si == maxlength) break;
                                buf[si++] = ch;
                                buf[si] = 0;
                                break;
                }
		mleft = input_x;
		mtop = y;
		mright = input_x + maxlength*CHAR_WIDTH + 2;
		mbottom = y + ITEM_HEIGHT;
		setfillstyle(SOLID_FILL,WHITE);
		bar(mleft,mtop,mright,mbottom);
		setcolor(BLUE);
		outtextxy(mleft+2,mtop+6,buf);
        } while (1);

	if (strlen(buf) != 0)
	{
		va_start(parmlist,format);
		rcode = vsscanf(buf,format,parmlist);
		va_end(parmlist);
	}
        else rcode = 0;
        clrmsg();
        clrmsg();
        return(rcode);
}

/***************************************************************************
        Returns filename pointed to by mouse
****************************************************************************/
int fname_cmp(char *s1,char *s2)
{
	return(strcmp(s1,s2));
}
char trn_select[15];
char *trn_directory(void)         /* returns NULL if no files */
{
struct ffblk ffblock;
int num_files,i;
mouse_state m;
char trn_files[240][9];
char fname[15];
        cleardevice();
        if (findfirst("*.TRN",&ffblock,0) == -1)
        {
                putmsg(100,100,"No .TRN files in directory",BLUE,WHITE);
                mouse_click(&m);
                clrmsg();
                return(NULL);
        }
        else {
                num_files = 0;
                /* get directory from DOS */
                do {
			strncpy(fname,ffblock.ff_name,14);
			stpcpy(trn_files[num_files],strtok(fname,". "));
			num_files++;
		} while ((findnext(&ffblock) == 0) && (num_files < 240));
		qsort(trn_files[0],num_files,9,fname_cmp);
                /* display on screen */
                cleardevice();
		setcolor(LIGHTGREEN);
                for (i=0; i<num_files; i++)
                {
			outtextxy((i/30)*80,(i%30)*10,trn_files[i]);
                }
                /* input mouse pointer */
                putmsg(0,330,"Click Left to view, Right to End",RED,WHITE);

                plot_type = 1;                 /* do a small plot while inputting */
                mouse_idle_job = doIFSrand;     /* do a small plot while inputting */
                do {
                        mouse_click(&m);
			if (m.buttons & MOUSE_LEFT)
                        {
                                i = (m.row/10)%30 + (m.col/80)*30;

                                if (i>(num_files-1))
                                {
                                        putmsg(100,100,"click on filename",WHITE,RED);
                                        delay(1000);
                                        clrmsg();
                                }
                                else
                                {
                                        stpcpy(trn_select,trn_files[i]);

                                        /* load in the file */
                                        if (trnfile_load(trn_select) != 0) {
                                                IFS_changed = 1;
                                        }
                                }
                        }
                } while (!(m.buttons & MOUSE_RIGHT));
                clrmsg();

                mouse_idle_job = mouse_idle;
		return(trn_select);
        }
        ;
}
/*****************************************************************************
        Non-destructive line drawing
******************************************************************************/
void *line_stack[10];
int left[10],top[10];

int lsp = -1;
void line_ovly(int x1,int y1,int x2,int y2)
{
int right,bottom;
        lsp++;
        if (x1 <= x2)
        {
                left[lsp] = max(0,x1 - 2);
                right = min(x2 + 2,maxx);
        }
        else
        {
                left[lsp] = max(0,x2 - 2);
                right = min(x1 + 2,maxx);
        }
        if (y1 <= y2)
        {
                top[lsp] = max(0,y1 - 2);
                bottom = min(y2 + 2,maxy);
        }
        else
        {
                top[lsp] = max(0,y2 - 2);
                bottom = min(y1 + 2,maxy);
        }
        line_stack[lsp] = malloc(imagesize(left[lsp],top[lsp],right,bottom));
	getimage(left[lsp],top[lsp],right,bottom,line_stack[lsp]);
        setcolor(WHITE);
        line(x1,y1,x2,y2);
}
void line_clear(void)
{
	putimage(left[lsp],top[lsp],line_stack[lsp],COPY_PUT);
        free(line_stack[lsp]);
        lsp--;
}
/******************************************************************************
        Mouse input of a zoom box
******************************************************************************/
void box_new(int *x1, int *y1, int *x2, int *y2)
{
mouse_state m;
float widthx,widthy;
float centerx,centery;
int oldcol,oldrow;
float oldwidthx,oldwidthy;
float oldcenterx,oldcentery;

	widthx = 300.0;
        widthy = widthx*3.0/4.0;
        centerx = maxx/2.0;
	centery = maxy/2.0;
        m.row = maxy/2.0;
        m.col = maxx/2.0;
	mouse_put(&m);
	*x1 = centerx - widthx/2.0;
        *x2 = centerx + widthx/2.0;
        *y1 = centery - widthy/2.0;
	*y2 = centery + widthy/2.0;
	while (mouse_get(&m) != 0x00) ;
        putmsg(10,10,"Press any key to accept",YELLOW,BLACK);
	setlinestyle(DASHED_LINE,0,NORM_WIDTH);
        line_ovly(*x1,*y1,*x1,*y2);
        line_ovly(*x2,*y1,*x2,*y2);
        line_ovly(*x1,*y1,*x2,*y1);
        line_ovly(*x1,*y2,*x2,*y2);
        oldrow = m.row;
        oldcol = m.col;
        do
        {
                mouse_get(&m);
                oldwidthx = widthx;
                oldwidthy = widthy;
                oldcenterx = centerx;
                oldcentery = centery;
                if ((m.col != oldcol) || (m.row != oldrow))
                {
			if (m.buttons&MOUSE_LEFT)
                        {
				widthx *= (1.0 + (m.row-oldrow)/100.0);
				if (widthx < 20.0) widthx = 20.0;
                                widthy = widthx*3.0/4.0;
                        }
                        else
                        {
				centerx += (m.col-oldcol);
				centery += (m.row-oldrow);
                        }
                        m.row = maxy/2.0;
                        m.col = maxx/2.0;
                        mouse_put(&m);
                        *x1 = centerx - widthx/2.0;
                        *x2 = centerx + widthx/2.0;
                        *y1 = centery - widthy/2.0;
			*y2 = centery + widthy/2.0;
			if ((*x1 <= 2.0) || (*x2 >maxx-2.0) || (*y1 <= 2.0)
				|| (*y2 >= (maxy-2.0)))
                        {
                                widthx = oldwidthx;
                                widthy = oldwidthy;
                                centerx = oldcenterx;
                                centery = oldcentery;
                                *x1 = centerx - widthx/2.0;
                                *x2 = centerx + widthx/2.0;
                                *y1 = centery - widthy/2.0;
                                *y2 = centery + widthy/2.0;
                        }
                        line_clear();
                        line_clear();
                        line_clear();
			line_clear();
			line_ovly(*x1,*y1,*x1,*y2);
                        line_ovly(*x2,*y1,*x2,*y2);
                        line_ovly(*x1,*y1,*x2,*y1);
                        line_ovly(*x1,*y2,*x2,*y2);
                        oldcol = m.col;
                        oldrow = m.row;
                }
	} while (!kbhit());
	if (getch() == 0) getch();
        line_clear();
        line_clear();
        line_clear();
        line_clear();
        clrmsg();
}
/******************************************************************************
        Zooming on plot
        This code really belongs somewhere else.
******************************************************************************/
void zoom_in(void)
{
int x1,y1,x2,y2;
float xscale,xoffset,yscale,yoffset;

        putmsg(0,0,"Zoom Box",BLUE,WHITE);
        box_new(&x1,&y1,&x2,&y2);
        clrmsg();

        if (x1 == x2) return;
        if (y1 == y2) return;
        xscale = maxx/(x2-x1);
        yscale = maxy/(y2-y1);
        if (xscale > yscale) xscale = yscale;
        else yscale = xscale;
        xoffset = -((x1+x2)/2.0)*xscale + maxx/2.0;
        yoffset = -((y1+y2)/2.0)*yscale + maxy/2.0;

        /* scale relative to already scaled triangles */
        IFS_rescale(xscale,xoffset,yscale,yoffset,1);
        area_scaled *= xscale;
        area_scaled *= yscale;
}
void zoom_out(void)
{
        area_scaled = 1.0;
        IFS_changed = 1;
	cleardevice();
	doIFSrand();
}


