/* ------------------------------------------------------------------------- */
/* ----- Let 'em Fly!   V 1.2 ----------- (c) 1991-93 by Oliver Scheel ----- */
/* ------------------------------------------------------------------------- */
/* ----- Module: ltmf_fmd.c   new form_dial()  new form_center() ----------- */
/* ------------------------------------------------------------------------- */

#include <stdio.h>
#include <macros.h>
#include <smallaes.h>
#include <vdi.h>
#include <tos.h>
#include <portab.h>

#include <mxmalloc.h>
#include "ltmf_str.h"
#include "ltmf_def.h"

/* ------------------------------------------------------------------------- */

extern	int	vwk_handle;
extern	int	planes;

extern	GRECT	wi_max;
extern	int	gl_wchar,
		gl_hchar;

extern	DIALSAV	dsave[];
extern	int	dialno;

extern	OBJECT	*lasttree;
extern	OBJECT	*lastdone;

extern	int	initflag;

extern	int	magic;
extern	int	isalert;
extern	int	istrans;

/* ------------------------------------------------------------------------- */

VSCRINF	*vscr = NULL;

void	*alertbuf;
long	almemsize;

int	was_used;

/* ------------------------------------------------------------------------- */

int vwk_init(void);
void vwk_exit(int handle);
void obj_xywh(OBJECT *tree, int obj, GRECT *p);
void cdecl obj_clsize(OBJECT *tree, int obj, int *x, int *y, int *w, int *h);
void rc_copy(void *src, void *dest);
void rc_vtog(VRECT *src, GRECT *dest);
int ltmf_init(void);

/* ------------------------------------------------------------------------- */
/* ----- new form_dial() --------------------------------------------------- */
/* ------------------------------------------------------------------------- */

void _send_redraw(VRECT *vr, int w, int h)
{
	GRECT	gr;

	rc_vtog(vr, &gr);
	gr.g_x -= (w - gr.g_w) / 2;
	gr.g_y -= (h - gr.g_h) / 2;
	form_dial(FMD_FINISH, 0, 0, 0, 0, gr.g_x, gr.g_y, w, h);
}

/* ------------------------------------------------------------------------- */

int nfm_dial(flag, xs, ys, ws, hs, x, y, w, h)
int	flag,
	xs, ys, ws, hs,
	x, y, w, h;
{
	VRECT	vr[2];
	DIALSAV	*dsav;
	int	wbufladr, wbufhadr,
		wbufllen, wbufhlen;
	long	msize;

	if(!initflag)
		ltmf_init();
	switch(flag)
	{
		case FMD_GROW :
		case FMD_SHRINK :
			return((letemfly.conf & C_F_GROW) ? form_dial(flag, xs, ys, ws, hs, x, y, w, h) : 1);
		case FMD_START :
/*			if(!istrans)
				lastdone = NULL;
*/			if(++dialno < MAXDIAL)
			{
				if(!istrans)
					was_used = FALSE;
				dsav = &dsave[dialno];
				wind_get(0, WF_WORKXYWH, &wi_max.g_x, &wi_max.g_y, &wi_max.g_w, &wi_max.g_h);
				x = max(x, wi_max.g_x);
				y = max(y, wi_max.g_y);
				w = min(w, wi_max.g_w);
				h = min(h, wi_max.g_h);
				vr[0].v_x1 = x;
				vr[0].v_y1 = y;
				vr[0].v_x2 = x + w - 1;
				vr[0].v_y2 = y + h - 1;
				rc_copy(&vr[0], &dsav->dpos);
				if(((letemfly.conf & C_FLY) || isalert) && (h > 0) && (w > 0))
				{
					vwk_handle = vwk_init();
					dsav->mem.fd_wdwidth = (w + 32) / 16;
					dsav->mem.fd_w = dsav->mem.fd_wdwidth * 16;
					dsav->mem.fd_h = h + 1;
					dsav->msize = ((long)dsav->mem.fd_wdwidth * (long)dsav->mem.fd_h * (long)planes * 2l);
					msize = isalert ? 8192l : (long)MxMalloc(-1l);
					if((dsav->msize < msize) || isalert)
					{
						if(isalert)
						{
							wind_get(0, WF_SCREEN, &wbufhadr, &wbufladr, &wbufhlen, &wbufllen);
							alertbuf = (void *)((wbufladr & 0x0000ffff) + ((long)wbufhadr << 16));
							dsav->mem.fd_addr = alertbuf;
						}
						else
							dsav->mem.fd_addr = MxMalloc(dsav->msize);
						dsav->mem.fd_nplanes = planes;
						dsav->mem.fd_stand = 0;
						dsav->dial.fd_addr = NULL;	
						vr[1].v_x1 = vr[0].v_x1 & 0x0f;
						vr[1].v_y1 = 0;
						vr[1].v_x2 = vr[1].v_x1 + w - 1;
						vr[1].v_y2 = h - 1;
						rc_copy(&vr[1], &dsav->mpos);
						graf_mouse(M_OFF, 0l);
						wind_update(BEG_UPDATE);
						vs_clip(vwk_handle, 0, &dsav->dpos);
						vro_cpyfm(vwk_handle, S_ONLY, vr,
							&dsav->dial, &dsav->mem);
						wind_update(END_UPDATE);
						graf_mouse(M_ON, 0l);
						vwk_exit(vwk_handle);
						if(letemfly.conf & C_REDRAW)
							return(form_dial(flag, xs, ys, ws, hs, x, y, w, h));
						else
							return(1);
					}
					vwk_exit(vwk_handle);
				}
				else
					dsav->mem.fd_addr = NULL;
			}
			return(form_dial(flag, xs, ys, ws, hs, x, y, w, h));
		case FMD_FINISH :
			if(!istrans)
				lastdone = NULL;
			if(dialno == -1)
				break;
			if(dialno < MAXDIAL)
			{
				dsav = &dsave[dialno--];
				if(dsav->mem.fd_addr == NULL)
				{
					_send_redraw(&dsav->dpos, w, h);
					return(1);
				}
				else if(lasttree)
				{
					Mfree(dsav->mem.fd_addr);
					dsav->mem.fd_addr = NULL;
					break;
				}
				else
				{
					rc_copy(&dsav->mpos, &vr[0]);
					rc_copy(&dsav->dpos, &vr[1]);
					vwk_handle = vwk_init();
					graf_mouse(M_OFF, 0l);
					wind_update(BEG_UPDATE);
					vs_clip(vwk_handle, 0, &dsav->dpos);
					vro_cpyfm(vwk_handle, S_ONLY, vr,
						&dsav->mem, &dsav->dial);
					wind_update(END_UPDATE);
					graf_mouse(M_ON, 0l);
					vwk_exit(vwk_handle);
#ifndef LIGHT
					if(!isalert)
#endif
						Mfree(dsav->mem.fd_addr);
					dsav->mem.fd_addr = NULL;
					if(!isalert && !istrans && ((letemfly.conf & C_REDRAW) || !was_used))
						_send_redraw(&dsav->dpos, w, h);
					return(1);
				}
			}
	}
	return(form_dial(flag, xs, ys, ws, hs, x, y, w, h));
}

/* ------------------------------------------------------------------------- */
/* ----- new form_center() ------------------------------------------------- */
/* ------------------------------------------------------------------------- */

void _mouse_center(OBJECT *tree, GRECT *gr, int *mx, int *my)
{
	int	snap;

	snap = (magic && (tree->ob_flags & SNAPIN)) ? TRUE : FALSE;
	*mx -= gr->g_w / 2;
	if(*mx < (wi_max.g_x + gl_wchar/2))
		*mx = wi_max.g_x + gl_wchar/2;
	else if((*mx + gr->g_w) > (wi_max.g_w - gl_wchar /* /2 */))	/* !!!! */
		*mx = wi_max.g_w - gl_wchar /* /2 */ - gr->g_w;
	*my -= gr->g_h / 2;
	if(*my < (wi_max.g_y + 4))
		*my = wi_max.g_y + 4;
	else if((*my + gr->g_h) > (wi_max.g_y + wi_max.g_h - gl_hchar/2))
		*my = (wi_max.g_y + wi_max.g_h - gl_hchar/2) - gr->g_h;
	if(snap)
	{
		*mx = (*mx & 0xfff8) | (gr->g_x & 0x07);
		if((*mx + gr->g_w) > (wi_max.g_x + wi_max.g_w))
			*mx -= 8;
	}
}

/* ------------------------------------------------------------------------- */

int nfm_center(tree, x, y, w, h)
OBJECT	*tree;
int	*x, *y,
	*w, *h;
{
	int	xsav, ysav,
		obtyp,
		obflag,
		d, ks;
	int	mx, my;
	GRECT	gr;

	graf_mkstate(&mx, &my, &d, &ks);
	obtyp = tree->ob_type & 0xff00;
	obflag = tree->ob_flags;
	magic = ((unsigned int)obtyp == MAGIC) ? TRUE : FALSE;
	if(!initflag)
		ltmf_init();
	wind_get(0, WF_WORKXYWH, &wi_max.g_x, &wi_max.g_y, &wi_max.g_w, &wi_max.g_h);
	if((letemfly.conf & C_MOUSE) && (lasttree != tree))
	{
/*		obj_xywh(tree, ROOT, &gr);
*/		obj_clsize(tree, ROOT, &gr.g_x, &gr.g_y, &gr.g_w, &gr.g_h);
		_mouse_center(tree, &gr, &mx, &my);
		tree->ob_x = (mx + 8) & 0xfff8;
		tree->ob_y = (my + 8) & 0xfff8;
	}
	xsav = tree->ob_x;
	ysav = tree->ob_y;
	form_center(tree, x, y, w, h);
	if((letemfly.conf & (C_CENTER|C_MOUSE)) && !(obtyp == GLOBOFF)
		&& !(magic && (obflag & FRCCENT)))
	{
		if(((obflag & CENTER) || (letemfly.conf & C_MOUSE)) && (ks ^ (K_ALT|K_CTRL)))
		{
			if((xsav > wi_max.g_x) && (ysav > wi_max.g_y)
				&& ((xsav + tree->ob_width) < (wi_max.g_x + wi_max.g_w))
				&& ((ysav + tree->ob_height) < (wi_max.g_y + wi_max.g_h)))
			{
				*x += xsav - tree->ob_x;
				*y += ysav - tree->ob_y;
				tree->ob_x = xsav;
				tree->ob_y = ysav;
				return(1);
			}
		}
		else
			tree->ob_flags |= CENTER;
	}
	if(vscr && ((letemfly.conf & C_VSCR) || isalert))
	{
		if(vscr->cookie == 'VSCR')
		{
			xsav = tree->ob_x;
			ysav = tree->ob_y;
			tree->ob_x = vscr->x + (vscr->w - tree->ob_width) / 2;
			tree->ob_y = vscr->y + (vscr->h - tree->ob_height) / 2;
/*			tree->ob_x = max(vscr->x, wi_max.g_x) + (vscr->w - tree->ob_width) / 2;
			tree->ob_y = max(vscr->y, wi_max.g_y) + (vscr->h - tree->ob_height) / 2;
*/			*x += tree->ob_x - xsav;
			*y += tree->ob_y - ysav;
			if(*x < wi_max.g_x)
			{
				*w -= wi_max.g_x - *x;
				*x = wi_max.g_x;
			}
			if(*y < wi_max.g_y)
			{
				*h -= wi_max.g_y - *y;
				*y = wi_max.g_y;
			}
		}
	}
	return(1);
}
