/*
 * file mi_combo.c - simple box box 
 *
 * $Id: mi_combo.c,v 1.5 2006/02/09 21:21:24 fzago Exp $
 *
 * Program XBLAST 
 * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2; or (at your option)
 * any later version
 *
 * This program is distributed in the hope that it will be entertaining,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "xblast.h"

/*
 * local macros
 */
#define FF_COMBO_TEXT_FOCUS       (FF_Medium | FF_Black | FF_Left   | FF_Outlined)
#define FF_COMBO_TEXT_NO_FOCUS    (FF_Medium | FF_White | FF_Left)
#define FF_COMBO_VALUE_SELECT     (FF_Medium | FF_Black | FF_Center | FF_Boxed )
#define FF_COMBO_VALUE_NO_SELECT  (FF_Medium | FF_White | FF_Center | FF_Boxed )

/*
 * local types
 */
/* simple combo box */
typedef struct
{
	XBMenuItem item;
	const char *text;
	int *value;
	void **data;
	XBAtom *atom;
	XBComboEntryList *table;
	int index;
	Sprite *t_sprite;
	Sprite *v_sprite;
} XBMenuComboItem;

/*
 * a combo item receives the focus
 */
static void
MenuComboFocus (XBMenuItem * ptr, XBBool flag)
{
	XBMenuComboItem *combo = (XBMenuComboItem *) ptr;

	assert (combo != NULL);
	assert (combo->t_sprite != NULL);
	SetSpriteAnime (combo->t_sprite, flag ? FF_COMBO_TEXT_FOCUS : FF_COMBO_TEXT_NO_FOCUS);
}								/* MenuComboFocus */

/*
 * Menu Combo Item
 */
static void
MenuComboPoll (XBMenuItem * ptr)
{
	int index = 0;
	XBMenuComboItem *combo = (XBMenuComboItem *) ptr;

	assert (combo != NULL);
	assert (combo->table != NULL);
	assert (combo->v_sprite != NULL);
	/* find current value in table */
	if (combo->value != NULL) {
		for (index = 0; combo->table[index].text != NULL; index++) {
			if (combo->table[index].value == *combo->value) {
				break;
			}
		}
	}
	if (combo->data != NULL) {
		for (index = 0; combo->table[index].text != NULL; index++) {
			if (combo->table[index].data == *combo->data) {
				break;
			}
		}
	}
	if (combo->atom != NULL) {
		for (index = 0; combo->table[index].text != NULL; index++) {
			if (combo->table[index].atom == *combo->atom) {
				break;
			}
		}
	}
	/* check if index has changed */
	if (index != combo->index) {
		combo->index = index;
		/* set values according entry */
		if (combo->value != NULL) {
			*combo->value = combo->table[index].value;
		}
		if (combo->data != NULL) {
			*combo->data = combo->table[index].data;
		}
		if (combo->atom != NULL) {
			*combo->atom = combo->table[index].atom;
		}
		/* change value display */
		SetSpriteText (combo->v_sprite, combo->table[index].text);
	}
}								/* MenuComboPoll */

/*
 * combo item: select new element
 */
static void
SetCombo (XBMenuComboItem * combo, XBBool next)
{
	if (next) {
		/* go forward in table */
		combo->index++;
		if (NULL == combo->table[combo->index].text) {
			/* reched end of table */
			combo->index = 0;
		}
	}
	else {
		/* go backward in table */
		if (combo->index <= 0) {
			/* search for last entry */
			for (combo->index = 0; combo->table[combo->index].text != NULL; combo->index++)
				continue;
		}
		combo->index--;
	}
	/* set new text for sprite */
	SetSpriteText (combo->v_sprite, combo->table[combo->index].text);
	/* set new value */
	if (NULL != combo->value) {
		*combo->value = combo->table[combo->index].value;
	}
	if (NULL != combo->data) {
		*combo->data = combo->table[combo->index].data;
	}
	if (NULL != combo->atom) {
		*combo->atom = combo->table[combo->index].atom;
	}
}								/* SetCombo */

/*
 *
 */
static void
MenuComboMouse (XBMenuItem * ptr, XBEventCode code)
{
	switch (code) {
	case XBE_MOUSE_1:
		SetCombo ((XBMenuComboItem *) ptr, XBTrue);
		break;
	case XBE_MOUSE_2:
		SetCombo ((XBMenuComboItem *) ptr, XBFalse);
		break;
	default:
		break;
	}
}								/* MenuComboMouse */

/*
 * event handling whiule combo is selected
 */
static void
ComboEventLoop (XBMenuItem * ptr)
{
	XBEventCode event;
	XBEventData data;
	XBMenuComboItem *combo = (XBMenuComboItem *) ptr;

	assert (combo != NULL);
	assert (combo->v_sprite != NULL);

	SetSpriteAnime (combo->v_sprite, FF_COMBO_VALUE_SELECT);
	/* event loop */
	while (1) {
		/* update window contents */
		MenuUpdateWindow ();
		/* get event from gui */
		while (XBE_TIMER != (event = GUI_WaitEvent (&data))) {
			if (event == XBE_MENU) {
				switch (data.value) {
				case XBMK_PREV:
				case XBMK_UP:
					SetCombo (combo, XBFalse);
					break;
				case XBMK_NEXT:
				case XBMK_DOWN:
					SetCombo (combo, XBTrue);
					break;
				case XBMK_SELECT:
				case XBMK_ABORT:
					SetSpriteAnime (combo->v_sprite, FF_COMBO_VALUE_NO_SELECT);
					return;
				default:
					break;
				}
			}
		}
	}
}								/* ComboEventLoop */

/*
 *
 */
XBMenuItem *
MenuCreateCombo (int x, int y, int w, const char *text, int w_val,
				 int *value, void **data, XBAtom * atom, XBComboEntryList * table)
{
	XBMenuComboItem *combo;

	assert (w - w_val > 0);
	combo = calloc (1, sizeof (*combo));
	assert (combo != NULL);
	MenuSetItem (&combo->item, MIT_Combo, x, y, w, CELL_H, MenuComboFocus, ComboEventLoop,
				 MenuComboMouse, MenuComboPoll);
	/* set label */
	combo->text = text;
	combo->t_sprite =
		CreateTextSprite (text, (x + 1) * BASE_X, (y + 1) * BASE_Y, (w - w_val - 2) * BASE_X,
						  (CELL_H - 2) * BASE_Y, FF_COMBO_TEXT_NO_FOCUS, SPM_MAPPED);
	/* find index of value in table */
	combo->value = value;
	combo->data = data;
	combo->atom = atom;
	combo->table = table;
	combo->index = 0;
	/* find valid entry in table */
	if (combo->value != NULL) {
		for (combo->index = 0; table[combo->index].text != NULL; combo->index++) {
			if (table[combo->index].value == *value) {
				break;
			}
		}
	}
	if (combo->data != NULL) {
		for (combo->index = 0; table[combo->index].text != NULL; combo->index++) {
			if (table[combo->index].data == *data) {
				break;
			}
		}
	}
	if (combo->atom != NULL) {
		for (combo->index = 0; table[combo->index].text != NULL; combo->index++) {
			if (table[combo->index].atom == *atom) {
				break;
			}
		}
	}
	if (NULL == table[combo->index].text) {
		combo->index = 0;
	}
	/* set values according entry */
	if (combo->value != NULL) {
		*combo->value = table[combo->index].value;
	}
	if (combo->data != NULL) {
		*combo->data = table[combo->index].data;
	}
	if (combo->atom != NULL) {
		*combo->atom = table[combo->index].atom;
	}
	/* create sprite */
	combo->v_sprite
		=
		CreateTextSprite (table[combo->index].text, (x + w - w_val + 1) * BASE_X, (y + 2) * BASE_Y,
						  (w_val - 2) * BASE_X, (CELL_H - 4) * BASE_Y, FF_COMBO_VALUE_NO_SELECT,
						  SPM_MAPPED);
	/* graphics */
	MenuAddLargeFrame ((x - CELL_W / 2) / CELL_W, (x + w + CELL_W / 2 - 1) / CELL_W, y / CELL_H);
	return &combo->item;
}

/*
 * delete a combo 
 */
void
MenuDeleteCombo (XBMenuItem * item)
{
	XBMenuComboItem *combo = (XBMenuComboItem *) item;

	assert (combo != NULL);
	assert (combo->t_sprite != NULL);
	assert (combo->v_sprite != NULL);
	DeleteSprite (combo->t_sprite);
	DeleteSprite (combo->v_sprite);
}								/* DeleteComboItem */

/*
 * end of file mi_bombo.c
 */
