/*
 * form_do.c
 *
 * Ein eigener form_do(), der einige Sondertastentasten kann:
 *		HELP				Button mit Flag11
 *		UNDO				Button mit Flag12
 * 	^C^V^X			Klemmbrett in Editfeldern
 *		ALT-X				MagiC-Shortcut
 *
 */
#include <ctype.h>

#ifdef __MINT__
#include <macros.h>
#include <osbind.h>
#endif

#include "intern.h"


static KEYTAB	*keytab = NULL;
static KEY_CB	key_cb = NULL;

/*
 * Editfeld suchen. Die Suche beginnt bei <obj>. Ist <obj> das erste oder 
 * letzte wird ge'wrapped, also das letzte oder das erste geliefert.
*/
int edit_valid(OBJECT *tree, int obj)
{
	return ((tree[obj].ob_flags & EDITABLE) && 
	        !((tree[obj].ob_flags & HIDETREE) || 
	          (tree[obj].ob_state & DISABLED)));
}

int find_edit(OBJECT *tree, int obj, int mode)
{
	int	ret = 0, i = 0;
	int	prev = 0, next = 0;
	int	first = 0, last = 0;
		
	do
	{
		i++;
		if (edit_valid(tree, i))
		{
			/* ersten merken */
			if (first == 0)
				first = i;
				
			if (i < obj)
				prev = i;
			if ((next == 0) && (i > obj))
				next = i;

			/* enthlt beim while-Ende den letzen */
			last = i;				
		}
	} 
	while (!(tree[i].ob_flags & LASTOB));

	if (prev == 0)
		prev = last;

	if (next == 0)
		next = first;

	switch (mode)
	{
		case FMD_FORWARD:
			ret = next;
			break;
		
		case FMD_BACKWARD:
			ret = prev;
			break;

		default:
			debug("\find_edit: unbekannter Modus %d.\n", mode);
	}

	return ret;
}

/*
 * Liefert das Objekt an (x,y), wenn es nicht DISABLED oder HIDETREE ist,
 * sonst -1.
*/
int cf_objc_find(OBJECT *tree, int start, int depth, int x, int y)
{
	int	obj;
	
	obj = objc_find(tree, start, depth, x, y);
	if ((obj != -1) && ((tree[obj].ob_flags & HIDETREE) || (tree[obj].ob_state & DISABLED)))
		obj = -1;
	return obj;
}

int find_shortcut(OBJECT *tree, int kstate, int kreturn)
{
	int	ret = -1;
	int	scan;
	
	if (keytab == NULL)
		keytab = (KEYTAB *)Keytbl((void*)-1, (void*)-1, (void*)-1);

	scan = (kreturn & 0xFF00) >> 8;

	if (scan == 0x62)													/* HELP */
		ret = find_flag(tree, FLAG12);

	else if (scan == 0x61)											/* UNDO */
		ret = find_flag(tree, FLAG11);

	else if (kstate & K_ALT)										/* Shortcut */
	{
		int	pos, obj;
		char	c;
		char	ascii;

		obj = -1;
		do
		{
			obj++;
			pos = get_magx_shortcut(tree, obj, &c);
			if (pos != -1)
			{
				if ((scan >= 0x78) && (scan < 0x80))
					ascii = keytab->capslock[scan - 0x76];
				else
					ascii = keytab->capslock[scan];
				if (toupper(c) == ascii)
				{
					ret = obj;
					break;
				}
			}
		}
		while (!(tree[obj].ob_flags & LASTOB));
	}
	if ((tree[ret].ob_flags & HIDETREE) || (tree[ret].ob_state & DISABLED))
		ret = -1;
	return ret;
}

int cf_form_keybd(OBJECT *tree, int edit_obj, int kstate, int *kreturn, int *next_obj)
{
	int	cont = TRUE, obj;
	int	scan;

	if (key_cb != NULL)
	{
		cont = (*key_cb)(tree, edit_obj, kstate, kreturn, next_obj);
		if (!cont || *kreturn == 0)
			return cont;
		else
			cont = TRUE;
	}
	
	obj = find_shortcut(tree, kstate, *kreturn);
	if (obj != -1)
	{
		*kreturn = 0;
		cont = form_button(tree, obj, 1, next_obj);
		return cont;
	}

	scan = (*kreturn & 0xFF00) >> 8;

	cont = form_keybd(tree, edit_obj, *next_obj, *kreturn, next_obj, kreturn);

	/*
	 * Den eventuellen Wechsel des Editfelds mit Cursor/TAB bernehmen wir
	 * selbst, da das AES auch HIDDEN oder DISABLE Felder anspringt!
	 * Auerdem werten wir dann gleich noch Shift-TAB mit aus.
	*/	
	if ((scan == 0x48) || ((kstate & K_SHIFT) && scan == 0x0F))		/* UP, TAB */
		*next_obj = find_edit(tree, edit_obj, FMD_BACKWARD);
	else if ((scan == 0x50) || (scan == 0x0F))							/* DOWN, TAB */
		*next_obj = find_edit(tree, edit_obj, FMD_FORWARD);

	return cont;
}

void cf_objc_edit(OBJECT *tree, int obj, int kreturn, int *idx, int mode, int kstate, int *ctrl)
{
	if (!(tree[obj].ob_flags & EDITABLE))
		return;

	if (mode == ED_CHAR)
	{
		int		scan, i;
		long		l;
		TEDINFO	*ted;
		char		*ptext;
		char		buf[80];
				
		*ctrl = FALSE;

		ted = (TEDINFO *)get_obspec(tree, obj);
		ptext	= ted->te_ptext;

		scan = (kreturn & 0xff00) >> 8;
		if (kstate & K_CTRL)
		{
			switch (scan)
			{
				case 0x2D:							/* ^X -> Cut */
					scrap_wtxt(ptext);
					objc_edit(tree, obj, 0x11B, idx, ED_CHAR);		/* ESC: lschen */
					*ctrl = TRUE;
					break;
				
				case 0x2E:							/* ^C -> Copy */
					scrap_wtxt(ptext);
					*ctrl = TRUE;
					break;
					
				case 0x2F:							/* ^V -> Paste */
					objc_edit(tree, obj, 0x11B, idx, ED_CHAR);		/* ESC: lschen */
					scrap_rtxt(buf, &l, 80);
					for (i = 0; i < min(l, ted->te_txtlen-1); i++)
						objc_edit(tree, obj, buf[i], idx, ED_CHAR);
					*ctrl = TRUE;
					break;
			}
		}
		else
		{
			switch (scan)
			{
				case 0x52:							/* INS -> ASCII-Tabelle */
/*					i = ascii_table(1, 13);*/
					i = ascii_table(sys_big_id, sys_big_pts);
					if (i > 0)
						kreturn = i & 0xff;
					break;
			}
		}
	}
	if (!(kstate & K_CTRL))					/* keine Ctrl-Codes durchlassen */
		objc_edit(tree, obj, kreturn, idx, mode);
}


int cf_form_do(OBJECT *tree, int *ed_start)
{
	int	edit_obj, cont, idx, next_obj;
	int	m_x, m_y, m_button, breturn,
			kstate, kreturn, which,	msg[8];
	int	b, doppel = FALSE;
#ifdef __MTAES__
	EVNTDATA	ev;
	GRECT		null = {0,0,0,0};
#endif

	wind_update(BEG_MCTRL);
	if ((ed_start == NULL) || (*ed_start == 0) || !edit_valid(tree, *ed_start))
		next_obj = find_edit(tree, 0, FMD_FORWARD);
	else
		next_obj = *ed_start;
	edit_obj = 0;
	cont = TRUE;
	while (cont)
	{
		if (next_obj && (edit_obj != next_obj))
		{
			edit_obj = next_obj;
			next_obj = 0;
			objc_edit(tree, edit_obj, 0, &idx, ED_INIT);
		}
#ifdef __MTAES__
		which = evnt_multi(MU_KEYBD|MU_BUTTON,
								2, 1, 1,
								0, &null, 0, &null,
								msg,
								0L,
								&ev, &kreturn, &breturn);
		m_x = ev.x;
		m_y = ev.y;
		m_button = ev.bstate;
		kstate = ev.kstate;
#else
		which = evnt_multi(MU_KEYBD|MU_BUTTON,
								2, 1, 1,
								0,0,0,0,0,0,0,0,0,0,
								msg,
								0L,
								&m_x, &m_y,
								&m_button, &kstate,
								&kreturn, &breturn);
#endif

		if (which & MU_KEYBD)
		{
			cont = cf_form_keybd(tree, edit_obj, kstate, &kreturn, &next_obj);
			if (kreturn)
				cf_objc_edit(tree, edit_obj, kreturn, &idx, ED_CHAR, kstate, &b);
		}
		if (which & MU_BUTTON)
		{
			next_obj = cf_objc_find(tree, ROOT, MAX_DEPTH, m_x, m_y);
			if (next_obj == -1)
			{
				Bconout(2, 7);		/* beep */
				next_obj = 0;
			}
			else
			{
				doppel = (breturn == 2);
				cont = form_button(tree, next_obj, breturn, &next_obj);
			}
		}
		if (!cont || (next_obj && (next_obj != edit_obj)))
			objc_edit(tree, edit_obj, 0, &idx, ED_END);
	}

	if (ed_start != NULL)
		*ed_start = edit_obj;
	wind_update(END_MCTRL);

	if (doppel)
		next_obj |= 0x8000;			/* bit 15 fr Doppelklick */

	return next_obj;
}

/* --------------------------------------------------------------------------- */
int simple_dial(OBJECT *tree, int start_edit)
{
  	int	exit_obj;
	GRECT	r;
#ifdef __MTAES__
	GRECT	n = {0,0,0,0};
#endif

	graf_mouse(ARROW, NULL);
	wind_update(BEG_UPDATE);
#ifdef __MTAES__
	form_center(tree, &r);
	form_dial(FMD_START, &n, &r);
	graf_mouse(M_OFF, NULL);
	objc_draw(tree, ROOT, MAX_DEPTH, &r); 
	graf_mouse(M_ON, NULL);
	exit_obj = cf_form_do(tree, &start_edit) & 0x7FFF;
	form_dial(FMD_FINISH, &n, &r);
#else
	form_center(tree, &r.g_x, &r.g_y, &r.g_w, &r.g_h);
	form_dial(FMD_START, 0, 0, 0, 0, r.g_x, r.g_y, r.g_w, r.g_h);
	graf_mouse(M_OFF, NULL);
	objc_draw(tree, ROOT, MAX_DEPTH, r.g_x, r.g_y, r.g_w, r.g_h); 
	graf_mouse(M_ON, NULL);
	exit_obj = cf_form_do(tree, &start_edit) & 0x7FFF;
	form_dial(FMD_FINISH, 0, 0, 0, 0, r.g_x, r.g_y, r.g_w, r.g_h);
#endif
	wind_update(END_UPDATE);
	set_state(tree, exit_obj, SELECTED, FALSE);
	return exit_obj;
}

KEY_CB set_formdo_keycb(KEY_CB new)
{
	KEY_CB	old;
	
	old = key_cb;
	key_cb = new;
	return old;
}
