
#include "intern.h"

static int valid_item(OBJECT *tree, int obj)
{
	int	type;
	int	ret = 0;
	
	type = get_obtype(tree, obj, NULL);
	if (type == G_STRING || type == G_SHORTCUT)
	{
		if (!get_state(tree, obj, DISABLED) && get_flag(tree, obj, SELECTABLE))
			ret = 1;
	}
	return ret;
}

/*
 * Emulation/Erweiterung von menu_popup().
 * Falls Button = 0 und das System menu_popup() hat, wird dieses aufgerufen.
 * Ist Button = 1/2 (linke/rechte Maustaste), wird das Popup selbst verwaltet.
 * Es geht dann z.B. sofort auf (nicht wie bei menu_popup() erst beim Loslassen
 * der Taste).
 * offset gibt den Offset zwischen Root und dem ersten Popup-String an (i.d.R.
 * ist offset 0, bei einem Farb-Popup aber z.B. nicht).
*/
int cf_menu_popup(MENU *m1, int x, int y, MENU *m2, int button, int offset)
{
	int	i, d;
	
	if ((button == 0) && appl_xgetinfo(9, &d, &i, &d, &d) && (i == 1))	/* gibts menu_popup? */
		return menu_popup(m1, x, y, m2);
	else
	{
		OBJECT	*tree;
		int		root, m_x, m_y, event, item, but,
					msg[8], olditem, kstate;
		GRECT		box, r;
		MFDB		save;
#ifdef __MTAES__
		EVNTDATA	ev;
		GRECT		n = {0,0,0,0};
#endif

		tree = m1->mn_tree;
		root = m1->mn_menu;
		item = m1->mn_item;
		
		tree[root].ob_x = x;
		tree[root].ob_y = y - ((item - offset - root - 1) * tree[item].ob_height);

		/* bei RSM liegt der das Popup enthaltende Dialog nicht unbedingt bei (0,0)!! */
		if (root != 0 && tree[0].ob_x > 0)
			tree[0].ob_x = 0;
		if (root != 0 && tree[0].ob_y > 0)
			tree[0].ob_y = 0;
		
		box.g_x = tree[root].ob_x - 1;
		box.g_y = tree[root].ob_y - 1;
		box.g_w = tree[root].ob_width + 4;
		box.g_h = tree[root].ob_height + 4;

		wind_update(BEG_MCTRL);
		save_background(&box, &save);
		graf_mouse(ARROW, NULL);

		if (button == 0)
			button = 1;
#ifdef __MTAES__
		graf_mkstate(&ev);
		m_x = ev.x;
		m_y = ev.y;
		but = ev.bstate;
#else
		graf_mkstate(&m_x, &m_y, &but, &d);
#endif

		if (but & button)		/* Taste noch gedrckt? */
			but = 0;				/* -> evnt_multi wartet auf Loslassen */
		else
			but = 1;				/*	->  							 Drcken */

#ifdef __MTAES__
		objc_draw(tree, root, MAX_DEPTH, &box);
#else
		objc_draw(tree, root, MAX_DEPTH, box.g_x, box.g_y, box.g_w, box.g_h);
#endif
		olditem = -1;
		do
		{
			item = objc_find(tree, root, MAX_DEPTH, m_x, m_y);
			if ((item == root) || !valid_item(tree, item))
				item = -1;

			if (item != olditem)
			{
				if (olditem != -1)
#ifdef __MTAES__
					objc_change(tree, olditem, 0, &box, tree[olditem].ob_state & (~SELECTED), TRUE);
#else
					objc_change(tree, olditem, 0, box.g_x, box.g_y, box.g_w, box.g_h, tree[olditem].ob_state & (~SELECTED), TRUE);
#endif
				if (item != -1)
#ifdef __MTAES__
					objc_change(tree, item, 0, &box, tree[item].ob_state|SELECTED, TRUE);
#else
					objc_change(tree, item, 0, box.g_x, box.g_y, box.g_w, box.g_h, tree[item].ob_state|SELECTED, TRUE);
#endif
			}
			if (item != -1)
			{
				objc_offset(tree, item, &r.g_x, &r.g_y);
				r.g_w = tree[item].ob_width;
				r.g_h = tree[item].ob_height;
			}
			else
			{
				r.g_x = m_x;	
				r.g_y = m_y;
				r.g_w = 1; 	
				r.g_h = 1;
			}
			
#ifdef __MTAES__
			event = evnt_multi((MU_BUTTON | MU_M1),
									  1, button, but,		/* ein Klick, links, s.o. */
									  1, &r, 0, &n,
									  msg, 
									  0L,
									  &ev,
									  &d, &d);
			m_x = ev.x;
			m_y = ev.y;
			kstate = ev.kstate;

			/* warten, bis die Taste wieder losgelassen wird */
			if (but == 1)
				evnt_button(1, button, 0, &ev);
#else
			event = evnt_multi((MU_BUTTON | MU_M1),
									  1, button, but,		/* ein Klick, links, s.o. */
									  1, r.g_x, r.g_y, r.g_w, r.g_h,
									  0, 0, 0, 0, 0,
									  msg, 
									  0L,
									  &m_x, &m_y,
									  &d, &kstate,
									  &d, &d);

			/* warten, bis die Taste wieder losgelassen wird */
			if (but == 1)
				evnt_button(1, button, 0, &d, &d, &d, &d);
#endif

			olditem = item;
		}
		while (!(event&MU_BUTTON));
	
		restore_background(&box, &save);
		wind_update(END_MCTRL);
	
		if (item == -1)
			item = 0;
		else
			tree[item].ob_state &= ~SELECTED;
	
		if (m2 != NULL)
		{
			if (m1 != m2)
				memcpy(m2, m1, sizeof(MENU));
			m2->mn_item = item;
			m2->mn_keystate = kstate;
		}
		return (item != 0);
	}
}


/*
 * Popup zur Laufzeit erzeugen.
*/
int create_popup(POPUP *p, int anz, int maxlen, char *item)
{
	char	*text;
	int	i;
					
	p->tree = (OBJECT *) cf_malloc((anz + 1) * sizeof(OBJECT), "create_popup", FALSE);
	if (p->tree == NULL)
		return FALSE;

	p->max_item = anz;
	if (maxlen == -1)
		p->item_len = (int)strlen(item);
	else
		p->item_len = maxlen;
	
	/* Box */
	p->tree[0].ob_next   = -1;
	p->tree[0].ob_head   = 1;
	p->tree[0].ob_tail   = 1;
	p->tree[0].ob_type   = G_BOX;
	p->tree[0].ob_flags  = FL3DBAK;
	p->tree[0].ob_state  = SHADOWED;
	p->tree[0].ob_spec.index  = 0x00ff1100L;	/* Rahmen, Farbe ... */
	p->tree[0].ob_x	   = 0;
	p->tree[0].ob_y	   = 0;
	p->tree[0].ob_width  = p->item_len;
	p->tree[0].ob_height = 1;
	
	/* Speicher fr String holen */
	text = strdup(item);
	if (text == NULL)
		return FALSE;

	/* 1. Eintrag */
	p->tree[1].ob_next   = 0;
	p->tree[1].ob_head   = -1;
	p->tree[1].ob_tail   = -1;
	p->tree[1].ob_type   = G_STRING;
	p->tree[1].ob_flags  = (SELECTABLE|LASTOB);
	p->tree[1].ob_state  = 0;
	p->tree[1].ob_spec.free_string = text;
	p->tree[1].ob_x	   = 0;
	p->tree[1].ob_y	   = 0;
	p->tree[1].ob_width  = p->item_len;
	p->tree[1].ob_height = 1;
	
	p->akt_item = 1;

	for(i = 0; i <= p->akt_item; i++)
		rsrc_obfix(p->tree, i);
	
	return TRUE;
}


int free_popup(POPUP *p)
{
	int	i;
	
	if (p->tree == NULL)
		return FALSE;
	else
	{
		i = -1;
		do
		{
			i++;
			if (get_obtype(p->tree, i, NULL) == G_STRING)
				Mfree((char *)get_obspec(p->tree, i));	/* free_string freigeben */
		}
		while (!(p->tree[i].ob_flags & LASTOB));
		Mfree(p->tree);
		return TRUE;
	}
}


int append_popup(POPUP *p, char *item)
{
	char	*text;
	int	i, state;

	if (p->tree == NULL)
		return FALSE;

	if (p->akt_item >= p->max_item)
		return FALSE;
	
	/* letztes wird vorletztes */
	p->tree[p->akt_item].ob_next  = p->akt_item + 1;
	p->tree[p->akt_item].ob_flags = SELECTABLE;

	p->akt_item++;

	if (item[0] == '-')
		state = 0x0008;
	else
		state = 0x0000;
		
	/* Speicher fr String holen */
	text = strdup(item);
	if (text == NULL)
		return FALSE;

	/* neues */
	p->tree[p->akt_item].ob_next	= 0;
	p->tree[p->akt_item].ob_head	= -1;
	p->tree[p->akt_item].ob_tail	= -1;
	p->tree[p->akt_item].ob_type	= G_STRING;
	p->tree[p->akt_item].ob_flags	= (SELECTABLE|LASTOB);
	p->tree[p->akt_item].ob_state	= state;
	p->tree[p->akt_item].ob_spec.free_string = text;
	p->tree[p->akt_item].ob_x	= 0;
	p->tree[p->akt_item].ob_y	= (p->akt_item - 1) * gl_hchar;
	p->tree[p->akt_item].ob_width	= (p->item_len) * gl_wchar;
	p->tree[p->akt_item].ob_height	= 1 * gl_hchar;

	/* Box */
	p->tree[0].ob_tail	= p->akt_item;
	p->tree[0].ob_height	= (p->akt_item) * gl_hchar;

	for(i = 0; i <= p->akt_item; i++)
	{
		/* zurck auf Zeichenkoor., damit der obfix klappt! */
		p->tree[i].ob_y      /= gl_hchar;
		p->tree[i].ob_width  /= gl_wchar;
		p->tree[i].ob_height /= gl_hchar;
		rsrc_obfix(p->tree, i);
	}
	return TRUE;
}


int do_popup(POPUP *p, int button)
{
	int	flag, p_x, p_y, d;
	MENU	Menu,
			MData;

	Menu.mn_tree   = p->tree;
	Menu.mn_menu   = ROOT;		
	Menu.mn_item   = 0;			
	Menu.mn_scroll = FALSE;		

#ifdef __MTAES__
{
	EVNTDATA	ev;
	graf_mkstate(&ev);
	p_x = ev.x;
	p_y = ev.y;
}
#else
	graf_mkstate(&p_x, &p_y, &d, &d);
#endif

	flag = cf_menu_popup( &Menu, p_x, p_y, &MData, button, 0);
	return (flag ? MData.mn_item : 0);
}


int handle_popup(OBJECT *dial, int dial_obj, OBJECT *pop, int pop_obj, int mode)
{
	char	active_str[50] = "", s[50];
	int	first, last, item, i, first_offset;
	int	x, y;
	MENU	m1, m2;
	GRECT	r;
	int	down_pop;
	
	if (pop == NULL)	
		return -1;

	first = pop[pop_obj].ob_head;
	while (!valid_item(pop, first))
		first++;

	last = pop[pop_obj].ob_tail;
	while (!valid_item(pop, last))
		last--;

	/* falls erste Spalte z.B. Farbmarke */
	first_offset = first - pop[pop_obj].ob_head;

	item = first;
	down_pop = FALSE;

	if (dial != NULL)
	{
		/* Popup-Typ ermitteln */
		down_pop = (get_obtype(dial, dial_obj, NULL) == G_BOXCHAR);

		if (!down_pop)
		{
			/* Zunchst das aktuelle, im Dialog eingetragene Popup-Item suchen */
			get_string(dial, dial_obj, active_str);
			item = first;
			while (item <= last)
			{
				get_string(pop, item, s);
				if (strcmp(active_str, s) == 0)
					break;
				item++;
			}
			if (item > last)		/* nicht gefunden */
				item = first;
		}
	}
	
	switch (mode)
	{
		case POP_OPEN:
			/* Position des Popups ermitteln */
			if (dial != NULL)
			{
				objc_offset(dial, dial_obj, &x, &y);
				if (down_pop)
					x -= (pop[1].ob_width - dial[dial_obj].ob_width);
				else
				{
					/* mehrspaltiges Popups? */
					if (pop[pop_obj].ob_height <= ((item - first) * gl_hchar))
					{
						get_objframe(pop, item, &r);
						x -= r.g_w;
						item -= (pop[pop_obj].ob_height / gl_hchar);
					}
				}

				/* auerhalb des Bildschirms? */
				get_objframe(pop, pop_obj, &r);

				if (x < gl_desk.g_x)
					x = gl_desk.g_x;
				if ((x + r.g_w) > (gl_desk.g_x + gl_desk.g_w))
					x = (gl_desk.g_x + gl_desk.g_w) - r.g_w;

				i = (last - item + 1) * gl_hchar;
				if ((y + i) > (gl_desk.g_y + gl_desk.g_h))
					y = (gl_desk.g_y + gl_desk.g_h) - i;

				i = (item - first) * gl_hchar;
				if (y - i < gl_desk.g_y)
					y = gl_desk.g_y + i;

			}
			else
			{
#ifdef __MTAES__
				EVNTDATA	ev;
				graf_mkstate(&ev);
				x = ev.x;
				y = ev.y;
#else
				graf_mkstate(&x, &y, &i, &i);
#endif
				get_objframe(pop, item, &r);
				x -= r.g_w / 2;
				y -= r.g_h / 2;
				if (first_offset > 0)
					y -= (first_offset * gl_hchar);
			}
			m1.mn_tree = pop;
			m1.mn_menu = pop_obj;
			m1.mn_item = item;
			i = cf_menu_popup(&m1, x, y, &m2, 1, first_offset);
			if (i != 0)
				item = m2.mn_item;
			else
				item = 0;
			break;
			
		case POP_CYCLE:
			i = 0;
			do
			{
				item++;
				i++;
				if (item > last)
					item = first;
			}
			while(((pop[item].ob_state & DISABLED) || 
					!(pop[item].ob_flags & SELECTABLE)) && 
					i <= last - first);
		
			if (i > last - first) 
				item = 0;
			break;
		
		default:
			debug("\ahandle_popup: unbekannter Modus %d.\n", mode);
	}
	
	/* Text des neuen Popup-Items in den Dialog eintragen und neu zeichnen */
	if ((!down_pop) && (item > 0) && (dial != NULL))
	{
		get_string(pop, item, s);
		set_string(dial, dial_obj, s);
		get_objframe(dial, dial_obj, &r);
#ifdef __MTAES__
		objc_draw(dial, dial_obj, 1, &r);
#else
		objc_draw(dial, dial_obj, 1, r.g_x, r.g_y, r.g_w, r.g_h);
#endif
	}
	
	return item;
}
