/* $Id: Choicemenu.c,v 1.4 1997/05/01 15:22:06 archer Exp $
 *	CHOICEMENU.C - Choice button managing container
 *
 * A choice menu is a special-looking Menu whose title changes to match the
 * selected item among the attached menu.
 */
#include <Widget/ChoiceMenuP.h>
#include <Widget/MenuButton.h>
#include <Widget/Menu.h>
#include <Widget/MenuItemP.h>
#include <Widget/drawP.h>


/**
 ** Internal: SET_CHOICE
 **	A choice was selected in the associated menu
 **/
static void set_choice(X11_widget item, void *wdg)
{
char	*s;
/*
 * Change the choice
 */
	s = X11_LabelGetString(item);
	X11_MenuButtonSetString(wdg, s);
/*
 * User call back
 */
	if (W_CHOICEMENU->callback)
		(*W_CHOICEMENU->callback)(wdg, W_BUTTON->userdata,
						x11__menu_index(item));
}


/**
 ** Internal: CHOICE_MENU_EXPOSE
 **	Draw a shadow beneath the menu button
 **/
static void choicemenu_expose(X11_widget wdg, XEvent *dummy)
{
/*
 * Start drawing
 */
	x11__draw_start(wdg);
	x11__shadows_gc();
/*
 * Button
 */
	x11__draw_upshadow(wdg->shadow_thickness);
	x11__draw_nothing(wdg->margin_inside);
/*
 * ChoiceMenu indicator
 */
	x11__draw_push();
	x11__draw_fit_h(4);
	x11__x_w = 6;
	x11__x_left = x11__x_right - 5;
	x11__draw_upshadow(1);
/*
 * Label
 */
	x11__draw_pop();
	x11__x_w = 0;
	x11__label_draw(W_LABEL, wdg->background, wdg->foreground);
}


/**
 ** Internal: CHOICEMENU_GEOMETRY
 **	Final setting of the geometry
 **/
static void choicemenu_geometry(X11_widget wdg, int w, int h)
{
int	b;
/*
 * Adjust
 */
	w += wdg->margin_inside + 6;
	if (h < 4)
		h = 4;
	b = wdg->border2 + 2 * (wdg->shadow_thickness + wdg->margin_inside);
	wdg->w_min = w + b;
	wdg->h_min = h + b;
	x11__widget_grow(wdg);
}


/**
 ** X11_CHOICE_MENU_NEW
 **	Sub-tended menu changes
 **/
void X11_ChoiceMenuNew(X11_widget wdg, char **titles, int fallback)
{
X11_widget	menu;
X11_widget	item;
char		**new_title;
char		*old_choice;
int		i;
int		w, h;
char		n[16];
/*
 * Find out the menu
 */
	menu = W_CHOICEMENU->menu;
	w = 0;
	h = 0;
	i = 1;
	item = menu->child;
	old_choice = W_LABEL->string;
	for (new_title = titles; *new_title; new_title++) {
		if (!item) {
			snprintf(n, sizeof(n), "choice%d", i);
			item = X11_MenuItem(menu, n, *new_title, 0, set_choice,
								(void *)wdg);
		} else
			X11_MenuItemSetString(item, *new_title);
/*
 * Fake geometry computation
 */
		W_LABEL->string = *new_title;
		x11__label_size(W_LABEL);
		if (w < W_LABEL->w_str)
			w = W_LABEL->w_str;
		if (h < W_LABEL->h_str)
			h = W_LABEL->h_str;
/*
 * Next item
 */
		item = item->sibling;
		i++;
	}
/*
 * Need to truncate the menu?
 */
	if (item)
		X11_MenuTruncate(menu, item);
	i--;
	if (fallback < 0)
		fallback = 0;
	else
		if (fallback >= i)
			fallback = i-1;
/*
 * The selection can be kept?
 */
	for (i = 0; titles[i]; i++)
		if (strcmp(old_choice, titles[i]) == 0)
			break;
	if (titles[i] == 0)
		i = fallback;
	W_LABEL->string = strdup(titles[i]);
	x11__label_size(W_LABEL);
	choicemenu_geometry(wdg, w, h);
/*
 * Make sur callback was called
 */
	if (strcmp(old_choice, titles[i]) && W_CHOICEMENU->callback)
		(*W_CHOICEMENU->callback)(wdg, W_BUTTON->userdata,
							x11__menu_index(wdg));
	free(old_choice);
	if (wdg->id)
		XClearArea(x11__screen, wdg->id, 0, 0, 0, 0, True);
}


/**
 ** X11_CHOICE_MENU
 **	Group widget holder
 **/
X11_widget X11_ChoiceMenu(X11_widget parent, char *name, char **titles,
				int initial, X11_int_call call, void *data)
{
x11__choicemenu	*object;
X11_widget	menu;
int		i;
int		choices;
int		w, h;
char		n[16];
/*
 * Get resource
 */
	object = allocator(x11__choicemenu);
	x11__core_setup(&object->menub.button.label.core, parent, "ChoiceMenu", name);
/*
 * Initialize fields
 */
	object->menub.button.label.core.on_expose = choicemenu_expose;
/*
 * How many resources?
 */
	for (choices = 0; titles[choices]; choices++)
		;
	if (initial < 0)
		initial = 0;
	if (initial >= choices)
		initial = choices-1;
/*
 * Properties as specified by resources
 */
	x11__menub_init(&object->menub, 0);
/*
 * Specials
 */
	object->callback              = call;
	object->menub.button.userdata = data;
/*
 * Create sub-objects
 */
	object->menu = menu = X11_Menu(OBJECT_P, 0);
	w = 0;
	h = 0;
	X11_MenuTitle(menu, "");
	for (i = 0; i < choices; i++) {
		snprintf(n, sizeof(n), "choice%d", i+1);
		X11_MenuItem(menu, n, titles[i], 0, set_choice, (void *)object);
/*
 * Fake geometry computation
 */
		object->menub.button.label.string = titles[i];
		x11__label_size(&object->menub.button.label);
		if (w < object->menub.button.label.w_str)
			w = object->menub.button.label.w_str;
		if (h < object->menub.button.label.h_str)
			h = object->menub.button.label.h_str;
	}
	object->menub.button.label.string = 0;
/*
 * Final geometry
 */
	choicemenu_geometry(&object->menub.button.label.core, w, h);
/*
 * Done
 */
	X11_MenuButtonSetString(OBJECT_P, titles[initial]);
	return OBJECT_P;
}
