/* window.c
 *   Main loop manages GEM windows, AES, mouse, menues, and drawing process.
 */
#include <obdefs.h>
#include <define.h>
#include <gemdefs.h>
#include <vdibind.h>
#include <osbind.h>
#include <stdio.h>
#include <debug.h>
#include "\t\mandlbox.h"

/*#define WI_KIND		(SIZER|MOVER|FULLER| CLOSER|NAME|VSLIDE)*/
#define WI_KIND		(CLOSER|NAME|VSLIDE)

#define MIN_WIDTH  (2*gl_wbox)
#define MIN_HEIGHT (3*gl_hbox)
int gl_hchar, gl_wchar, gl_wbox, gl_hbox;	/* system sizes */

int	ps_handle;	/* physical screen (workstation) handle */
int	vs_handle;	/* virtual screen (workstation) handle */
int	wi_handle;	/* window handle */
int	old_res;	/* initial resolution of screen */

int	xdesk,ydesk,hdesk,wdesk;	/* size of whole desktop */
int	xwork,ywork,hwork,wwork;	/* size of current working window */
int	xold,yold,hold,wold;		/* size of screen before FULL cmd */

int	msgbuff[8];	/* event message buffer */
int	keycode;	/* keycode returned by event-keyboard */
int	mx,my;		/* mouse x and y pos. */
int	butdown;	/* button state tested for, UP/DOWN */
int	ret;		/* dummy return variable */
int	clut_rotate;	/* mode */

/******* shared memory with draw.c: */
double	Vx0, Vy0, Vxw, Vyw;	/* Size of viewed area, in real numbers */
int Niter;			/* max number of iterations */
int box_invisible;

/******* shared memory with stitch.c: */
int no_check = 1;

int	contrl[12], intin[128], ptsin[128], intout[128];
int	ptsout[128];	/* storage wasted for idiotic bindings */

char str[128];

GRECT work_clip;
int draw_state;
char *p_menu;

#define c(x) 1000*(2*(x)+1)/16
int desks_clut[16][3], mandel_clut[16][3] = 
{	{c(7),c(7),c(7)},	/* white */
	{c(0),c(0),c(0)},	/* black */
	{c(7),c(1),c(1)},	/* red */
	{c(7),c(4),c(0)},
	{c(7),c(6),c(0)},
	{c(7),c(7),c(0)},	/* yellow */
	{c(6),c(7),c(0)},
	{c(0),c(7),c(0)},	/* green */
	{c(0),c(7),c(5)},
	{c(0),c(7),c(6)},	/* blue */
	{c(0),c(6),c(7)},
	{c(2),c(3),c(7)},
	{c(4),c(0),c(7)},
	{c(6),c(0),c(7)},	/* violet */
	{c(7),c(0),c(6)},
	{c(7),c(0),c(4)}
};

struct places
{	double x, y, dx, dy;
	int menue_number;
	int iter_ct;
	char name[20];
} places[] = 
	{{.651350,-.176159, .000929, .000636, MGOLUM,  1024, "Golum"},
	 {.166765,-.807549, .018935, .012964, MRIPPLE, 1024, "Ripple"},
	 {.054566,-.755330, .002208, .001512, MPINWH,  1024, "Pinwheels"},
	 {.127512,-.781265, .011749, .008044, MSWIRLS, 1024, "Swirls"},
	 {.656728,-.174796, .004559, .003122, M3ON4,   1024, "3 on 4"},
	 {.650663,-.176422, .001890, .001249, MTURTLE, 1024, "Turtle"},
	 {-1.0,  -1.85,    2.0,     2.4,      MBUDDAH,  256, "Buddah"}};

struct
{	char active, on_crt;
	int hidden;
	int want_active;
	char new0, new1;
	int x0,y0, x1,y1;
	int xyarray[10];
}  rbox = {0, 1, FALSE, 0};

char *fs_get();

main()
{	int event, mouse_buttons, mmoving, fulled;
	int x0, y0, xw, yw, i, j;
	int *p_val;
/*	if ((old_res=Getrez()) != 0)	/* won't work with AES */
/*		Setscreen(-1, -1, 0);	/* make low resolution */
	appl_init();
	open_vwork();
 	open_window();
	open_rsc();
	Niter = 256;	/* inz count till black */
	inz_dialog();

	graf_mouse(ARROW,0x0L);
	fulled=FALSE;
	butdown=TRUE;
	box_invisible = 1;

	dr_iRastWindow(xwork, ywork, wwork, hwork);
	dr_iProgCoords(-1.0,-1.85, 2.0,2.4);
	dr_Vreset();
	do 
	{	if (draw_state==0 || mmoving)
		{	event = evnt_multi(
				MU_MESAG| MU_BUTTON| MU_KEYBD | MU_TIMER,
				1,1,butdown,
				0,0,0,0,0,  0,0,0,0,0,
				msgbuff,100,0,	/* 100 ms timer*/
				&mx,&my,&mouse_buttons,&ret,&keycode,&ret);
		}else
		{	event = evnt_multi(MU_MESAG| MU_BUTTON| MU_KEYBD| MU_M1,
				1,1,butdown,
				1,0,0,0,0, 	/* (always true event) */
				0,0,0,0,0,  msgbuff,0,0,
				&mx,&my,&mouse_buttons,&ret,&keycode,&ret);
		}
		if (event & MU_MESAG) switch (msgbuff[0])
		{   case WM_REDRAW:	/* set clip and draw_mode */
			start_redraw(1, msgbuff[4],msgbuff[5],msgbuff[6],
				msgbuff[7]);		/*!!!*/
			break;
		    case WM_NEWTOP:  /* unsure of what this does, so boobytrap*/
		    case WM_TOPPED:
			wind_set(wi_handle,WF_TOP,0,0,0,0);
			break;
		    case WM_SIZED:
		    case WM_MOVED:
			if (msgbuff[6]<MIN_WIDTH) msgbuff[6] = MIN_WIDTH;
			if (msgbuff[7]<MIN_HEIGHT) msgbuff[7] = MIN_HEIGHT;
			wind_set(wi_handle,WF_CURRXYWH,
				msgbuff[4],msgbuff[5],msgbuff[6],msgbuff[7]);
			wind_get(wi_handle,WF_WORKXYWH,&xwork,&ywork,&wwork,&hwork);
			dr_iRastWind(xwork,ywork, wwork,hwork);
			start_redraw(-1, xwork, ywork, wwork, hwork);
			break;
		    case WM_FULLED:
			if(fulled == 0)		/* to full: */
			{	wind_calc(WC_BORDER,WI_KIND,xwork,ywork,wwork,
					hwork, &xold,&yold,&wold,&hold);
				wind_calc(WC_WORK,WI_KIND,xdesk,ydesk,wdesk,
					hdesk,&xwork,&ywork,&wwork,&hwork);
				wind_set(wi_handle,WF_CURRXYWH,xdesk,ydesk,
					wdesk,hdesk);
			}else			/* to un-full: */
			{	wind_calc(WC_WORK,WI_KIND,xold,yold,wold,hold,
					&xwork,&ywork,&wwork,&hwork);
				wind_set(wi_handle,WF_CURRXYWH,xold,yold,
					wold,hold);
			}
			fulled ^= TRUE;
			dr_iRasterWindow(xwork, ywork, wwork, hwork);
			start_redraw(-1, xwork, ywork, wwork, hwork);
			break;
		    case MN_SELECTED:
			switch (msgbuff[4])
			{   
			    case MSAVEAS:
				write_scr(fs_get("man"));
				break;
			    case MOPEN:
				read_scr(fs_get("man"));
				draw_state = 0;
				break;
			    case MCROTATE:
				clut_rotate = 1-clut_rotate;
				break;
			    case MQUIT:
				goto quit;

			    case MBUDDAH:   case MRIPPLE:   case MPINWH:
			    case MSWIRLS:   case M3ON4:	    case MTURTLE:
			    case MGOLUM:

				for (i=0;places[i].menue_number!=msgbuff[4];i++)
					if(places[i].menue_number ==0) break;
				dr_iProgCoords(places[i].x,  places[i].y,
						 places[i].dx, places[i].dy);
				start_redraw(1, xwork, ywork, wwork, hwork);
				dr_Vreset();
				Niter = places[i].iter_ct;
				break;
			    case MZOUT4:
				dr_zoom(xwork-wwork*3/2, ywork-hwork*3/2,
					  xwork+wwork*5/2, ywork+hwork*5/2);
				start_redraw(1, -1, 0, 0, 0);
				break;
			    case MZNUMBER:
				zoom_numerically();
				break;
			    case MQPAINT:	/* patch-up area */
				printf("\nmqpaint\n");
				while (1 + (mouse_buttons & 3))
				{	fprintf(stderr,"*******");
					dr_area(mx, my, 3);
					dr_putBuf( 7*7 );
					fprintf(stderr,"!!!!!!!!\n");
					event = evnt_multi(MU_MESAG| MU_BUTTON| 
						MU_KEYBD| MU_M1,
						1,1,butdown,
						1,0,0,0,0, /* always true */
						0,0,0,0,0,  msgbuff,0,0,
						&mx,&my,&mouse_buttons,&ret,
						&keycode,&ret);
				}
			    case ABOUTMAN:
				disp_dialog(AUTHOR, 0);
				break;
			    case MUNZOOM:
				if (dr_Vpop())
					start_redraw(1, -1,0,0,0,0);
				break;
			    case CBOXES:
				box_invisible = 1-box_invisible;
				break;
			    case MAITER:
				set_iteration();
				break;
			    case MSAVENXT:
			    case MPLAYMOV:
			    case MZHELP:
			    case MZROTATE:
			    case MAZ2:
			    default:
				form_alert(0,"[1][Detour:|Function Under \
Construction!|Try again next Rev.|(Remember, it's Freeware)][Acknowlege]");
				break;
			}
			menu_tnormal(p_menu, msgbuff[3], TRUE);
			break;			
		}
		if (event & MU_KEYBD) 
		{	keycode &= 0xff;
			switch (keycode)
			{   case 'D': debug_print = 1-debug_print; break;
			    case 'C': no_check = 1-no_check; break;
		}	}

		if ((event & MU_BUTTON) /*&&(wi_handle == top_window) ???*/)
			butdown ^= 1;
		if (draw_state == 0) mouse_buttons = butdown ^ 1;
		if (mouse_moving(mx, my, mouse_buttons))
			mmoving = 10;
		if (mmoving)
		{	draw_on_screen();	/* make boxes visible */
			view_screen();
			mmoving--;
		}else
			more_redraw();		

		if (clut_rotate)
			rotate_clut(vs_handle,mandel_clut);
	} while(!((event & MU_MESAG) && (msgbuff[0] == WM_CLOSED)));
quit:
	menu_bar(p_menu, FALSE);
	load_clut(vs_handle, desks_clut, (long)0);
	wind_close(wi_handle);
	graf_shrinkbox(xwork+wwork/2,ywork+hwork/2,gl_wbox,gl_hbox,xwork,ywork,wwork,hwork);
	wind_delete(wi_handle);
	v_clsvwk(vs_handle);
	appl_exit();
/*	if (old_res != 0)		/*won't work with AES 
/*		Setscreen(-1, -1, old_res);	/* restore resolution */
}

zoom_numerically()
{	struct object *p_object;

	if (rsrc_gaddr(R_TREE, NUMERIC, &p_object)==0) 
		panic ("AES/rsrc_gaddr() error",0L,0L);

	fill_dialog_field(Vx0, "%f", p_object+VALX);
	fill_dialog_field(Vy0, "%f", p_object+VALY);
	fill_dialog_field(Vxw, "%f", p_object+VALDX);
	fill_dialog_field(Vyw, "%f", p_object+VALDY);

	if (disp_dialog(NUMERIC, VALY) == NUMOK)
	{	dr_Vpush();
		get_dialog_field(p_object+VALX, "Imag. Corner", "%f%s", &Vx0);
		get_dialog_field(p_object+VALY, "Real Corner", "%f%s", &Vy0);
		get_dialog_field(p_object+VALDX, "Imag. Width", "%f%s", &Vxw);
		get_dialog_field(p_object+VALDY, "Real Width", "%f%s", &Vyw);

		dr_iProgCoords(Vx0, Vy0,  Vxw, Vyw);
		start_redraw(1, -1,0,0,0,0);
}	}

set_iteration()
{	struct object *p_object;
	float i;

	if (rsrc_gaddr(R_TREE, ITERATN, &p_object)==0) 
		panic ("AES/rsrc_gaddr() error",0L,0L);
	fill_dialog_field((long)Niter, "%ld", p_object+NITER);
	if (disp_dialog(ITERATN, NITER) == DRAWHERE)
		get_dialog_field(p_object+NITER, "Iteration Max", "%d%s",
				 &Niter);
}

fill_dialog_field(val, fmt, p_object)
struct object *p_object;
char *fmt;
long val;	/* 32-bits of stuff for sprintf, interpreted in type fmt */
{	char *edit_string;
	edit_string = (struct text_edinfo *) (p_object->ob_spec) -> te_ptext;
	sprintf(edit_string, fmt, val);
}

get_dialog_field(p_window, w_name, fmt, val)
struct object *p_window;
char *w_name, *fmt;
char *val;	/* untyped pointer, actually */
{	char *edit_string, alert_string[128], sc_str[128];
	edit_string = (struct text_edinfo *) (p_window->ob_spec) -> te_ptext;
	sc_str[0] = 0;
	sscanf(edit_string, fmt, val, sc_str);
	if (sc_str[0]!=0)
	{	if (strlen(edit_string) > 30) edit_string[30] = 0;
		sprintf(alert_string, 
		    "[1][Cannot figure out how | %s | can be put into %s.\
][Got It?]", edit_string, w_name);
		form_alert(0, alert_string);
}	}

long *save_screen;
int Nsave_screen;

disp_dialog(tree_index, start_edit)
int tree_index, start_edit;
{	struct object *p_object;
	int x0, y0, xw, yw;
	int exit_obj;

	if (rsrc_gaddr(R_TREE, tree_index, &p_object)==0) 
		panic ("AES/rsrc_gaddr() error",0L,0L);
	form_center(p_object, &x0, &y0, &xw, &yw); 
	form_dial(FMD_START, x0, y0, xw, yw);

	draw_on_screen();	/* don't save mouse */
	rast_save(x0, y0, xw, yw, save_screen, Nsave_screen);
	view_screen();

	objc_draw(p_object, 0, 2, x0, y0, xw, yw);
	exit_obj = form_do(p_object, start_edit);

	objc_change(p_object, exit_obj, 0, x0,y0,xw,yw, 0,1);
	draw_on_screen();	/* unsave with mouse gone */
	rast_restore();
	view_screen();

	form_dial(FMD_FINISH,  x0, y0, xw, yw);
	return (exit_obj);
}

int ind[] = {NUMERIC, AUTHOR, ITERATN, -1};
inz_dialog()		/* reserve a buffer to hide the screen under
			/* dialog boxes listed in ind[]*/
{	struct object *p_object;
	int x0, y0, xw, yw, obj, size;
	char *pointer;
			/* find size of biggest dialog box: */
	for (Nsave_screen=0, obj=0; ind[obj]>=0;)
	{	if (rsrc_gaddr(R_TREE, ind[obj++], &p_object)==0) 
			panic ("AES/rsrc_gaddr() error",0L,0L);
		form_center(p_object, &x0, &y0, &xw, &yw); 
		size = rastSize(x0, y0,  xw, yw);
		Nsave_screen = (size>Nsave_screen)? size: Nsave_screen;
	}
	pointer = Malloc((long) (Nsave_screen));
	if (pointer == 0)
		panic("inz_dialog: Malloc out of memory\n", 0L, 0L);
	save_screen = (long *) pointer;	
}

start_redraw(ds, xc, yc, wc, hc)
int ds, xc, yc, wc, hc;
{	int i;
	if (ds == 1)
	{	draw_state = 1;
		rbox.want_active = 0;
	}
	clip_current();
	if (xc >=0)
	{	work_clip.g_x=xc;
		work_clip.g_y=yc;
		work_clip.g_w=wc;
		work_clip.g_h=hc;
}	}

GRECT t1;		/*current working rectangle*/

more_redraw()
{	int i, flag;

	flag = WF_NEXTXYWH;
	switch (draw_state)
	{   case 0:
		draw_on_screen();	/* make boxes visible */
		view_screen();
		return;
	    case 1:
		flag = WF_FIRSTXYWH;
	    case 2:	
		wind_get(wi_handle, flag, &t1.g_x,&t1.g_y,&t1.g_w,&t1.g_h);
		if (t1.g_w==0 || t1.g_h==0)
		{	draw_state = 0;
			return;
		}
		if (draw_state == 2)
			panic("must currently be top window only\n", 0L, 0L);
		if (!rc_intersect(&work_clip,&t1)) return;
		draw_state = 3;
		clip_current();
		dr_sBox();	/*???t1.g_x,t1.g_y,t1.g_w,t1.g_h);*/
	    default:	
		if (i=dr_compute())
			dr_putBuf(i);
		else	draw_state = 2;
}	}	


int	last_button, last_x, last_y; /* mouse on previous scan*/

mouse_moving(mx, my, mouse_buttons)
int mx, my, mouse_buttons;
{	int moving;
	mouse_buttons &= 1;
	if (mouse_buttons && last_button==0)
	{	if (!rbox_redraw(mx,my)) /*down of left button*/
		{	rbox_set(0, mx, my);
			rbox_set(1, mx, my);
			rbox.want_active=1;
	}	}
	if (last_button)
		rbox_set(1, mx, my);	/*drag of left button*/
	moving = (mx!=last_x || my!=last_y);
	last_x = mx; last_y = my;
	last_button = mouse_buttons;
	return (moving);
}

rbox_redraw(x,y)
int x,y;
{	if ( (x > rbox.xyarray[0]) ^ (x > rbox.xyarray[4]) &&
	     (y > rbox.xyarray[1]) ^ (y > rbox.xyarray[5]) )
	{	dr_zoom(rbox.xyarray[0],rbox.xyarray[1], 
			  rbox.xyarray[4],rbox.xyarray[5]);
		start_redraw(1, xwork,ywork,wwork,hwork);
/*		rbox.want_active = 0;/**/
		return (1);
	}
	else return (0);
}
rbox_set(index, x, y)
int index, x, y;
{	int dx, dy;
	double f1, f2;
	if (index==0)
	{	rbox.x0=x; rbox.y0=y; rbox.new0=1;
	}else
	{	if ((dx=x-rbox.x0) && (dy=y-rbox.y0))	/* keep ratio correct */
		{	f1 = (double)dy/(double)dx;
			f2 = (double)hwork/(double)( (1-2*(f1<0))*wwork);
			if (f1<f2)
				y = rbox.y0 + (int)((double) dx * f2);
			else
				x = rbox.x0 +  (int)((double)dy / f2);
		}else
		{	x = rbox.x0;
			y = rbox.y0;
		}
		rbox.x1=x; rbox.y1=y; rbox.new1=1;
}	}

draw_on_screen()
{	if (rbox.on_crt==0) return;
	rbox.on_crt = 0;
	wind_update(TRUE);		/*lock window THIS HANGS*/
	if(rbox.hidden==FALSE) graf_mouse(M_OFF,0x0L);
	if (rbox.active) exor_box();	/*take off box*/
	rbox.hidden=TRUE;
}	
view_screen()
{	if (rbox.on_crt) return;
	if (rbox.new0)
	{	rbox.xyarray[0] = rbox.xyarray[6] = rbox.xyarray[8] = rbox.x0;
		rbox.xyarray[1] = rbox.xyarray[3] = rbox.xyarray[9] = rbox.y0;
		rbox.new0=0;
	}
	if (rbox.new1)
	{	rbox.xyarray[2] = rbox.xyarray[4] = rbox.x1;
		rbox.xyarray[5] = rbox.xyarray[7] = rbox.y1;
		rbox.new1=0;
	}
	if (rbox.active = rbox.want_active) exor_box();	/*draw box*/

	if(rbox.hidden==TRUE) graf_mouse(M_ON,0x0L);
	wind_update(FALSE);		/*unlock window*/
	rbox.hidden=FALSE;
	rbox.on_crt = 1;
}	

exor_box()
{	clip_current();
	vswr_mode(wi_handle, 3);	/* XOR */
	vsl_color(wi_handle, 8);	/* 180 deg around spectrum*/
	v_pline(wi_handle, 5, rbox.xyarray);
}

clip_current()
{	set_clip(xwork, ywork, wwork, hwork);
}
clip_full()
{	set_clip(xdesk, ydesk, wdesk, hdesk);
}

set_clip(x,y,w,h)
int x,y,w,h;
{	int clip[4];
	clip[0]=x;
	clip[1]=y;
	clip[2]=x+w;
	clip[3]=y+h;
	vs_clip(wi_handle,1,clip);
	dr_clip(x,y,w,h);
}


char *fs_get(type)
char *type;
{	char path[128], sel[128], *p1, *p2;
	int buttons;
	for (p1="*.dir", p2=path; *p2++ = *p1++; );
	sel[0] = 0;
	if (fsel_input(path, sel, &buttons) == 0)
		panic("fsel_input error (returned 0)");
	if (buttons == 0)
		printf("buttons==0!\n");
	fprintf(stderr, "fi() = |%s|%s|\n", path, sel);
	return ("xxx.man");
}

open_vwork()
{	int i;
	int work_in[11];	/* Input to GSX parameter array */
	int work_out[57];	/* Output from GSX parameter array */

	ps_handle=graf_handle(&gl_wchar,&gl_hchar,&gl_wbox,&gl_hbox);
	for(i=0;i<10;work_in[i++]=1);
	work_in[10]=2;
	vs_handle=ps_handle;
	v_opnvwk(work_in,&vs_handle,work_out);
	if (vs_handle == 0)
		panic("v_opnvwk couldn't open window",0L,0L);
	load_clut(vs_handle, mandel_clut, desks_clut);
}

open_window()
{	wind_get(0/*whole screen*/,WF_WORKXYWH, &xdesk, &ydesk, &wdesk, &hdesk);
	wi_handle=wind_create(WI_KIND,xdesk,ydesk,wdesk,hdesk);
	wind_set(wi_handle, WF_NAME,"Mandlbox",0,0);
	graf_growbox(xdesk+wdesk/2,ydesk+hdesk/2,gl_wbox,gl_hbox,xdesk,ydesk,wdesk,hdesk);
	wind_open(wi_handle,xdesk,ydesk,wdesk,hdesk);
	wind_get(wi_handle,WF_WORKXYWH,&xwork,&ywork,&wwork,&hwork);
	if (wdesk>500 && 2 != form_alert(1,"[3][16 Colors Required.|\
Set Preferences to Low|Resolution and Restart.][okay|ignore warning]")) exit();
}

char myname[] = "mandlbox.rsc";
open_rsc()
{	if (rsrc_load(myname)==0) panic("File %s missing!",myname,0L);
	if (rsrc_gaddr(R_TREE, MENUE, &p_menu)==0)
		panic ("AES/rsrc_gaddr() error",0L,0L);
	if (menu_bar(p_menu, TRUE)==0) panic ("AES/menu_bar() error",0L,0L);
}
panic(str,v,w)
char *str, *v, *w;
{	long i;
	fprintf(stderr,"\n\n\n***** ERROR: *****\n");
	fprintf(stderr,str,v,w);
	for (i=0; i<200000; i++);
	exit();
}
