#include <stdlib.h>
#include <string.h>

#include <gtk/gtk.h>

#include "guiutils.h"
#include "menubutton.h"
#include "toolbar.h"


/* Callbacks */
static gint ToolbarEnterNotifyCB(
	GtkWidget *widget, GdkEventCrossing *crossing, gpointer data
);
static gint ToolbarLeaveNotifyCB(
	GtkWidget *widget, GdkEventCrossing *crossing, gpointer data
);
static void ToolbarClickedCB(GtkWidget *widget, gpointer data);


/* Tool Bar Item List */
toolbar_item_struct *ToolBarItemNew(
	toolbar_item_type type,		/* One of TOOLBAR_ITEM_* */
	const gchar *text,
	guint8 **icon_data,
	const gchar *tooltip,
	gint id,
	void (*func_cb)(toolbar_item_struct *, gint, gpointer),
	gpointer client_data,
	void (*enter_cb)(toolbar_item_struct *, gint, gpointer),
	gpointer enter_client_data,
	void (*leave_cb)(toolbar_item_struct *, gint, gpointer),
	gpointer leave_client_data
);
void ToolBarItemDelete(toolbar_item_struct *item);

void ToolBarItemListAppend(
	toolbar_item_struct ***item, gint *total_items,
	toolbar_item_struct *item_ptr
);
void ToolBarItemListDeleteAll(
	toolbar_item_struct ***item, gint *total_items 
);

toolbar_item_struct *ToolBarItemListMatchByID(
	toolbar_item_struct **item, gint total_items,
	gint id
);


/* Tool Bar */
toolbar_struct *ToolBarNew(
	toolbar_item_struct **item, gint total_items,
	GtkWidget *parent,
	toolbar_display display,
	toolbar_relief relief,
	gboolean vertical
);
void ToolBarSetDisplay(
	toolbar_struct *tb, toolbar_display display
);
void ToolBarSetRelief(
	toolbar_struct *tb, toolbar_relief relief
);
void ToolBarItemUpdateByID(
	toolbar_struct *tb, gint id,
	const gchar *text,
	guint8 **icon_data,
	const gchar *tooltip
);
void ToolBarMap(toolbar_struct *tb);
void ToolBarUnmap(toolbar_struct *tb);
void ToolBarDelete(toolbar_struct *tb);


/* Tool Bar Item */
GtkWidget *ToolBarItemGetWidgetID(toolbar_struct *tb, gint id);

void ToolBarItemSetSensitiveID(
	toolbar_struct *tb, gint id, gboolean sensitive
);

void ToolBarItemSetToggleID(
	toolbar_struct *tb, gint id, gboolean toggled
);
gboolean ToolBarItemGetToggleID(toolbar_struct *tb, gint id);

void ToolBarItemSetMenuID(
	toolbar_struct *tb, gint id, GtkWidget *menu
);
GtkWidget *ToolBarItemGetMenuID(toolbar_struct *tb, gint id);

gboolean ToolBarItemIsMappedID(toolbar_struct *tb, gint id);
void ToolBarItemMapID(toolbar_struct *tb, gint id);
void ToolBarItemUnmapID(toolbar_struct *tb, gint id);


#define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
#define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
#define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
#define STRDUP(s)       (((s) != NULL) ? g_strdup(s) : NULL)

#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define STRLEN(s)       (((s) != NULL) ? strlen(s) : 0)
#define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : TRUE)


#define TOOLBAR_BUTTON_PICTURE_AND_TEXT_WIDTH   GUI_BUTTON_VLABEL_WIDTH
#define TOOLBAR_BUTTON_PICTURE_AND_TEXT_HEIGHT  GUI_BUTTON_VLABEL_HEIGHT

#define TOOLBAR_BUTTON_PICTURE_WIDTH            30
#define TOOLBAR_BUTTON_PICTURE_HEIGHT           30

#define TOOLBAR_BUTTON_TEXT_WIDTH               -1
#define TOOLBAR_BUTTON_TEXT_HEIGHT              30


#define SET_BUTTON_LAYOUT(_w_,_d_)			\
{ if((_w_) != NULL) { switch(_d_) {			\
   case TOOLBAR_DISPLAY_PICTURES_AND_TEXT:		\
    GUIButtonChangeLayout((_w_), 1, 1);			\
    gtk_widget_set_usize(				\
     (_w_),						\
     TOOLBAR_BUTTON_PICTURE_AND_TEXT_WIDTH,		\
     TOOLBAR_BUTTON_PICTURE_AND_TEXT_HEIGHT		\
    );							\
    break;						\
   case TOOLBAR_DISPLAY_PICTURES:			\
    GUIButtonChangeLayout((_w_), 1, 0);			\
    gtk_widget_set_usize(				\
     (_w_),						\
     TOOLBAR_BUTTON_PICTURE_WIDTH,			\
     TOOLBAR_BUTTON_PICTURE_HEIGHT			\
    );							\
    break;						\
   case TOOLBAR_DISPLAY_TEXT:				\
    GUIButtonChangeLayout((_w_), 0, 1);			\
    gtk_widget_set_usize(				\
     (_w_),						\
     TOOLBAR_BUTTON_TEXT_WIDTH,				\
     TOOLBAR_BUTTON_TEXT_HEIGHT				\
    );							\
    break;						\
} } }


/*
 *	Tool Bar Item "enter_notify_event" signal callback.
 */
static gint ToolbarEnterNotifyCB(
	GtkWidget *widget, GdkEventCrossing *crossing, gpointer data
)
{
	toolbar_item_struct *item = TOOLBAR_ITEM(data);
	if(item == NULL)
	    return(TRUE);

	if(item->enter_cb != NULL)
	    item->enter_cb(
		item,			/* Tool Bar Item */
		item->id,		/* ID */
		item->enter_client_data	/* Data */
	    );

	return(TRUE);
}

/*
 *	Tool Bar Item "leave_notify_event" signal callback.
 */
static gint ToolbarLeaveNotifyCB(
	GtkWidget *widget, GdkEventCrossing *crossing, gpointer data
)
{
	toolbar_item_struct *item = TOOLBAR_ITEM(data);
	if(item == NULL)
	    return(TRUE);

	if(item->leave_cb != NULL)
	    item->leave_cb(
		item,			/* Tool Bar Item */
		item->id,		/* ID */
		item->leave_client_data	/* Data */
	    );

	return(TRUE);
}

/*
 *	Tool Bar Item "clicked" or "toggled" signal callback.
 */
static void ToolbarClickedCB(GtkWidget *widget, gpointer data)
{
	toolbar_item_struct *item = TOOLBAR_ITEM(data);
	if(item == NULL)
	    return;

	if(item->func_cb != NULL)
	    item->func_cb(
		item,			/* Tool Bar Item */
		item->id,		/* ID */
		item->client_data	/* Data */
	    );
}


/*
 *	Creates a new Tool Bar Item.
 *
 *	No widgets or other resources will be created.
 */
toolbar_item_struct *ToolBarItemNew(
	toolbar_item_type type,		/* One of TOOLBAR_ITEM_* */
	const gchar *text,
	guint8 **icon_data,
	const gchar *tooltip,
	gint id,
	void (*func_cb)(toolbar_item_struct *, gint, gpointer),
	gpointer client_data,
	void (*enter_cb)(toolbar_item_struct *, gint, gpointer),
	gpointer enter_client_data,
	void (*leave_cb)(toolbar_item_struct *, gint, gpointer),
	gpointer leave_client_data
)
{
	toolbar_item_struct *item = TOOLBAR_ITEM(g_malloc0(
	    sizeof(toolbar_item_struct)
	));
	if(item == NULL)
	    return(item);

	item->type = type;

	item->w = NULL;

	item->text = STRDUP(text);
	item->icon_data = icon_data;
	item->tooltip = STRDUP(tooltip);

	item->id = id;
	item->func_cb = func_cb;
	item->client_data = client_data;
	item->enter_cb = enter_cb;
	item->enter_client_data = enter_client_data;
	item->leave_cb = leave_cb;
	item->leave_client_data = leave_client_data;

	return(item);
}

/*
 *	Deletes the Tool Bar Item.
 */
void ToolBarItemDelete(toolbar_item_struct *item)
{
	if(item == NULL)
	    return;

	/* Destroy widgets */
	GTK_WIDGET_DESTROY(item->w)

	g_free(item->text);
	/* item->icon_data = NULL; */	/* Shared */
	g_free(item->tooltip);
	g_free(item);
}


/*
 *	Appends the Tool Bar Item to the specified list.
 *
 *	The specified Tool Bar Item will be transfered to the list and
 *	should not be referenced again after this call.
 */
void ToolBarItemListAppend(
	toolbar_item_struct ***item, gint *total_items,
	toolbar_item_struct *item_ptr
)
{
	gint i;

	if((item == NULL) || (total_items == NULL))
	{
	    ToolBarItemDelete(item_ptr);
	    return;
	}

	i = MAX(*total_items, 0);
	*total_items = i + 1;
	*item = (toolbar_item_struct **)g_realloc(
	    *item,
	    (*total_items) * sizeof(toolbar_item_struct *)
	);
	if(*item == NULL)
	{
	    *total_items = 0;
	    ToolBarItemDelete(item_ptr);
	    return;
	}

	(*item)[i] = item_ptr;
}

/*
 *	Deletes all Tool Bar Items in the specified list.
 */
void ToolBarItemListDeleteAll(
	toolbar_item_struct ***item, gint *total_items
)
{
	gint i, m;

	if((item == NULL) || (total_items == NULL))
	    return;

	m = *total_items;

	for(i = 0; i < m; i++)
	    ToolBarItemDelete((*item)[i]);

	g_free(*item);
	*item = NULL;
	*total_items = 0;
}


/*
 *	Returns a Tool Bar Item in the list that matches the specified
 *	id.
 */
toolbar_item_struct *ToolBarItemListMatchByID(
	toolbar_item_struct **item, gint total_items,
	gint id
)
{
	gint i;
	toolbar_item_struct *item_ptr;

	for(i = 0; i < total_items; i++)
	{
	    item_ptr = item[i];
	    if((item_ptr != NULL) ? (item_ptr->id == id) : FALSE)
		return(item_ptr);
	}

	return(NULL);
}


/*
 *	Creates a new Tool Bar.
 *
 *	The given list of Tool Bar Items will not be modified.
 */
toolbar_struct *ToolBarNew(
	toolbar_item_struct **item, gint total_items,
	GtkWidget *parent,
	toolbar_display display,
	toolbar_relief relief,
	gboolean vertical
)
{
	const gint	border_major = 5,
			border_minor = 2;
	gint i;
	GtkWidget *w, *parent2, *parent3;
	const toolbar_item_struct *src_item_ptr;
	toolbar_item_struct *item_ptr;
	toolbar_struct *tb = TOOLBAR(g_malloc0(
	    sizeof(toolbar_struct)
	));
	if(tb == NULL)
	    return(tb);

	/* Reset values */
	tb->display = display;
	tb->relief = relief;
	tb->vertical = vertical;

	tb->item = NULL;
	tb->total_items = 0;

	/* Create toplevel */
	if(vertical)
	    w = gtk_vbox_new(FALSE, 0);
	else
	    w = gtk_hbox_new(FALSE, 0);
	gtk_container_border_width(GTK_CONTAINER(w), border_minor);
	if(parent != NULL)
	{
	    if(GTK_IS_BOX(parent))
		gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	    else if(GTK_IS_CONTAINER(parent))
		gtk_container_add(GTK_CONTAINER(parent), w);
	}
	tb->toplevel = w;
	parent2 = w;


	/* Allocate pointer array for Tool Bar Items */
	tb->total_items = total_items;
	if(tb->total_items > 0)
	{
	    tb->item = (toolbar_item_struct **)g_malloc0(
		tb->total_items * sizeof(toolbar_item_struct *)
	    );
	    if(tb->item == NULL)
	    {
		tb->total_items = 0;
	    }
	}

	/* Create Tool Bar Items */
	for(i = 0; i < tb->total_items; i++)
	{
	    src_item_ptr = item[i];
	    if(src_item_ptr == NULL)
		continue;

	    /* Create a copy of the item */
	    tb->item[i] = item_ptr = ToolBarItemNew(
		src_item_ptr->type,
		src_item_ptr->text,
		src_item_ptr->icon_data,
		src_item_ptr->tooltip,
		src_item_ptr->id,
		src_item_ptr->func_cb,
		src_item_ptr->client_data,
		src_item_ptr->enter_cb,
		src_item_ptr->enter_client_data,
		src_item_ptr->leave_cb,
		src_item_ptr->leave_client_data
	    );

	    /* Create widgets based on new item */
	    if(item_ptr != NULL)
	    {
		GtkWidget *label_rtn, *menu_rtn;

		item_ptr->toolbar = tb;

		switch(item_ptr->type)
		{
		  case TOOLBAR_ITEM_SEPARATOR:
		    item_ptr->w = w = gtk_vbox_new(TRUE, 0);
		    gtk_widget_set_usize(
			w,
			vertical ? -1 : 5,
			vertical ? 5 : -1
		    );
		    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
		    gtk_widget_show(w);
		    parent3 = w;

		    if(vertical)
			w = gtk_hseparator_new();
		    else
			w = gtk_vseparator_new();
		    gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, TRUE, border_major);
		    gtk_widget_show(w);
		    break;

		  case TOOLBAR_ITEM_BUTTON:
		    item_ptr->w = w = GUIButtonPixmapLabelV(
			(guint8 **)item_ptr->icon_data,
			item_ptr->text,
			&label_rtn
		    );
		    switch(relief)
		    {
		      case TOOLBAR_RELIEF_NONE:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
			break;
		      case TOOLBAR_RELIEF_HALF:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_HALF);
			break;
		      case TOOLBAR_RELIEF_NORMAL:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NORMAL);
			break;
		    }
		    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
		    if(item_ptr->func_cb != NULL)
			gtk_signal_connect(
			    GTK_OBJECT(w), "clicked",
			    GTK_SIGNAL_FUNC(ToolbarClickedCB),
			    item_ptr
			);
		    if(item_ptr->enter_cb != NULL)
			gtk_signal_connect(
			    GTK_OBJECT(w), "enter_notify_event",
			    GTK_SIGNAL_FUNC(ToolbarEnterNotifyCB),
			    item_ptr
			);
		    if(item_ptr->leave_cb != NULL)
			gtk_signal_connect(
			    GTK_OBJECT(w), "leave_notify_event",
			    GTK_SIGNAL_FUNC(ToolbarLeaveNotifyCB),
			    item_ptr
			);
		    if(item_ptr->tooltip != NULL)
			GUISetWidgetTip(w, item_ptr->tooltip);
		    SET_BUTTON_LAYOUT(w, display)
		    gtk_widget_show(w);
		    break;

		  case TOOLBAR_ITEM_TOGGLE_BUTTON:
		    item_ptr->w = w = GUIToggleButtonPixmapLabelV(
			(guint8 **)item_ptr->icon_data,
			item_ptr->text,
			&label_rtn
		    );
		    switch(relief)
		    {
		      case TOOLBAR_RELIEF_NONE:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
			break;
		      case TOOLBAR_RELIEF_HALF:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_HALF);
			break;
		      case TOOLBAR_RELIEF_NORMAL:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NORMAL);
			break;
		    }
		    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
		    if(item_ptr->func_cb != NULL)
			gtk_signal_connect(
			    GTK_OBJECT(w), "toggled",
			    GTK_SIGNAL_FUNC(ToolbarClickedCB),
			    item_ptr
			);
		    if(item_ptr->enter_cb != NULL)
			gtk_signal_connect(
			    GTK_OBJECT(w), "enter_notify_event",
			    GTK_SIGNAL_FUNC(ToolbarEnterNotifyCB),
			    item_ptr
			);
		    if(item_ptr->leave_cb != NULL)
			gtk_signal_connect(
			    GTK_OBJECT(w), "leave_notify_event",
			    GTK_SIGNAL_FUNC(ToolbarLeaveNotifyCB),
			    item_ptr
			);
		    if(item_ptr->tooltip != NULL)
			GUISetWidgetTip(w, item_ptr->tooltip);
		    SET_BUTTON_LAYOUT(w, display)
		    gtk_widget_show(w);
		    break;

		  case TOOLBAR_ITEM_MENU_BUTTON:
		    item_ptr->w = MenuButtonNewV(
			item_ptr->text,
			(guint8 **)item_ptr->icon_data,
			&menu_rtn
		    );
		    switch(relief)
		    {
		      case TOOLBAR_RELIEF_NONE:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
			break;
		      case TOOLBAR_RELIEF_HALF:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_HALF);
			break;
		      case TOOLBAR_RELIEF_NORMAL:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NORMAL);
			break;
		    }
		    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
		    if(item_ptr->func_cb != NULL)
			gtk_signal_connect(
			    GTK_OBJECT(w), "toggled",
			    GTK_SIGNAL_FUNC(ToolbarClickedCB),
			    item_ptr
			);
		    if(item_ptr->enter_cb != NULL)
			gtk_signal_connect(
			    GTK_OBJECT(w), "enter_notify_event",
			    GTK_SIGNAL_FUNC(ToolbarEnterNotifyCB),
			    item_ptr
			);
		    if(item_ptr->leave_cb != NULL)
			gtk_signal_connect(
			    GTK_OBJECT(w), "leave_notify_event",
			    GTK_SIGNAL_FUNC(ToolbarLeaveNotifyCB),
			    item_ptr
			);
		    if(item_ptr->tooltip != NULL)
			GUISetWidgetTip(w, item_ptr->tooltip);
		    SET_BUTTON_LAYOUT(w, display)
		    gtk_widget_show(w);
		}
	    }
	}

	return(tb);
}

/*
 *	Sets the Tool Bar's display.
 */
void ToolBarSetDisplay(
	toolbar_struct *tb, toolbar_display display
)
{
	gint i;
	GtkWidget *w;
	toolbar_item_struct *item_ptr;

	if(tb == NULL)
	    return;

	/* Iterate through all Tool Bar Items */
	for(i = 0; i < tb->total_items; i++)
	{
	    item_ptr = tb->item[i];
	    if(item_ptr == NULL)
		continue;

	    w = item_ptr->w;
	    if(w == NULL)
		continue;

	    switch(item_ptr->type)
	    {
	      case TOOLBAR_ITEM_SEPARATOR:
		break;
	      case TOOLBAR_ITEM_BUTTON:
		SET_BUTTON_LAYOUT(w, display)
		break;
	      case TOOLBAR_ITEM_TOGGLE_BUTTON:
		SET_BUTTON_LAYOUT(w, display)
		break;
	      case TOOLBAR_ITEM_MENU_BUTTON:
		SET_BUTTON_LAYOUT(w, display)
		break;
	    }
	}

#if 0
	/* Remind tool bar that it needs to resize */
	w = tb->toplevel;
	if(w != NULL)
	    gtk_widget_queue_resize(w);
#endif
}

/*
 *	Sets the Tool Bar's relief.
 */
void ToolBarSetRelief(
	toolbar_struct *tb, toolbar_relief relief
)
{
	gint i;
	GtkWidget *w;
	toolbar_item_struct *item_ptr;

	if(tb == NULL)
	    return;

	/* Iterate through all Tool Bar Items */
	for(i = 0; i < tb->total_items; i++)
	{
	    item_ptr = tb->item[i];
	    if(item_ptr == NULL)
		continue;

	    w = item_ptr->w;
	    if(w == NULL)
		continue;

	    switch(item_ptr->type)
	    {
	      case TOOLBAR_ITEM_SEPARATOR:
		break;
	      case TOOLBAR_ITEM_BUTTON:
		if(GTK_IS_BUTTON(w))
		{
		    switch(relief)
		    {
		      case TOOLBAR_RELIEF_NONE:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
			break;
		      case TOOLBAR_RELIEF_HALF:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_HALF);
			break;
		      case TOOLBAR_RELIEF_NORMAL:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NORMAL);
			break;
		    }
		}
		break;
	      case TOOLBAR_ITEM_TOGGLE_BUTTON:
		if(GTK_IS_BUTTON(w))
		{
		    switch(relief)
		    {
		      case TOOLBAR_RELIEF_NONE:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
			break;
		      case TOOLBAR_RELIEF_HALF:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_HALF);
			break;
		      case TOOLBAR_RELIEF_NORMAL:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NORMAL);
			break;
		    }
		}
		break;
	      case TOOLBAR_ITEM_MENU_BUTTON:
		if(GTK_IS_BUTTON(w))
		{
		    switch(relief)
		    {
		      case TOOLBAR_RELIEF_NONE:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NONE);
			break;
		      case TOOLBAR_RELIEF_HALF:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_HALF);
			break;
		      case TOOLBAR_RELIEF_NORMAL:
			gtk_button_set_relief(GTK_BUTTON(w), GTK_RELIEF_NORMAL);
			break;
		    }
		}
		break;
	    }
	}

#if 0
	/* Remind tool bar that it needs to resize */
	w = tb->toplevel;
	if(w != NULL)
	    gtk_widget_queue_resize(w);
#endif
}


/*
 *	Updates the Tool Bar Item specified by id with the given
 *	text, icon, and tooltip.
 */
void ToolBarItemUpdateByID(
	toolbar_struct *tb, gint id,
	const gchar *text,
	guint8 **icon_data,
	const gchar *tooltip
)
{
	gint i;
	toolbar_item_struct *item;

	if(tb == NULL)
	    return;

	/* Iterate through all Tool Bar Items */
	for(i = 0; i < tb->total_items; i++)
	{
	    item = tb->item[i];
	    if(item == NULL)
		continue;

	    /* Id of current item matches the given id? */
	    if(item->id == id)
	    {
		GtkWidget *w = item->w;

		/* Update text, icon data, and tool tip message */
		if(text != NULL)
		{
		    g_free(item->text);
		    item->text = STRDUP(text);
		}

		if(icon_data != NULL)
		{
		    item->icon_data = icon_data;
		}

		if(tooltip != NULL)
		{
		    g_free(item->tooltip);
		    item->tooltip = STRDUP(tooltip);
		}

		/* Update widget, handle by item type */
		switch(item->type)
		{
		  case TOOLBAR_ITEM_SEPARATOR:
		    break;
		  case TOOLBAR_ITEM_BUTTON:
		    if(w != NULL)
			GUIButtonPixmapUpdate(
			    w, icon_data, text
			);
		    break;
		  case TOOLBAR_ITEM_TOGGLE_BUTTON:
		    if(w != NULL)
			GUIButtonPixmapUpdate(
			    w, icon_data, text
			);
		    break;
		  case TOOLBAR_ITEM_MENU_BUTTON:
		    if(w != NULL)
			GUIButtonPixmapUpdate(
			    w, icon_data, text
			);  
		    break;
		}

		/* Do not break after matching this item, there may
		 * be other items with the same ID that need to be
		 * updated
		 */
	    }
	}
}

/*
 *	Maps the Tool Bar.
 */
void ToolBarMap(toolbar_struct *tb)
{
	GtkWidget *w = (tb != NULL) ? tb->toplevel : NULL; 
	if(w == NULL)    
	    return;

	gtk_widget_show(w);
}

/*
 *	Unmaps the Tool Bar.
 */
void ToolBarUnmap(toolbar_struct *tb)
{
	GtkWidget *w = (tb != NULL) ? tb->toplevel : NULL;
	if(w == NULL)
	    return;

	gtk_widget_hide(w);
}

/*
 *	Deletes the Tool Bar.
 */
void ToolBarDelete(toolbar_struct *tb)
{
	if(tb == NULL)
	    return;

	/* Delete all Tool Bar Items */
	ToolBarItemListDeleteAll(
	    &tb->item, &tb->total_items
	);

	/* Destroy Tool Bar widgets */
	GTK_WIDGET_DESTROY(tb->toplevel)

	g_free(tb);
}


/*
 *	Gets the Tool Bar Item's toplevel GtkWidget specified by id.
 */
GtkWidget *ToolBarItemGetWidgetID(toolbar_struct *tb, gint id)
{
	toolbar_item_struct *item_ptr = (tb != NULL) ?
	    ToolBarItemListMatchByID(tb->item, tb->total_items, id) : NULL;
	return((item_ptr != NULL) ? item_ptr->w : NULL);
}


/*
 *	Sets the Tool Bar Item specified by id as sensitive or
 *	insensitive.
 */
void ToolBarItemSetSensitiveID(
	toolbar_struct *tb, gint id, gboolean sensitive
)
{
	toolbar_item_struct *item_ptr = (tb != NULL) ?
	    ToolBarItemListMatchByID(tb->item, tb->total_items, id) : NULL;
	GTK_WIDGET_SET_SENSITIVE(
	    (item_ptr != NULL) ? item_ptr->w : NULL, sensitive
	)
}


/*
 *	Sets the Tool Bar Item specified by id as toggled or untoggled.
 *
 *	The Tool Bar Item must be of type TOOLBAR_ITEM_TOGGLE_BUTTON.
 *
 *	No signal will be emitted.
 */
void ToolBarItemSetToggleID(
	toolbar_struct *tb, gint id, gboolean toggled
)
{
	toolbar_item_struct *item_ptr = (tb != NULL) ? 
	    ToolBarItemListMatchByID(tb->item, tb->total_items, id) : NULL;
	if(item_ptr == NULL)
	    return;

	if(item_ptr->type == TOOLBAR_ITEM_TOGGLE_BUTTON)
	{
	    GtkToggleButton *tb = (GtkToggleButton *)item_ptr->w;
	    if(tb != NULL)
	    {
		/* Check if toggle button state has changed by comparing
		 * the current value with the specified value
		 *
		 * If there is a change then first record the function
		 * callback from the item and then set it NULL
		 *
		 * Next, do the toggle, in which case the toggle
		 * callback will be called but the func_cb will not be
		 * called
		 *
		 * After the callback is made we set the func_cb back
		 * to its original value
		 */
		if((gboolean)tb->active != (gboolean)toggled)
		{
		    void (*func_cb)(toolbar_item_struct *, gint, gpointer) = item_ptr->func_cb;
		    item_ptr->func_cb = NULL;
		    gtk_toggle_button_set_active(tb, toggled);
		    item_ptr->func_cb = func_cb;
		}
	    }
	}
}

/*
 *	Gets the Tool Bar Item's toggle state.
 */
gboolean ToolBarItemGetToggleID(toolbar_struct *tb, gint id)
{
	toolbar_item_struct *item_ptr = (tb != NULL) ? 
	    ToolBarItemListMatchByID(tb->item, tb->total_items, id) : NULL;
	if(item_ptr == NULL)
	    return(FALSE);

	if(item_ptr->type == TOOLBAR_ITEM_TOGGLE_BUTTON)
	    return(GTK_TOGGLE_BUTTON_GET_ACTIVE(item_ptr->w));
	else
	    return(FALSE);
}

/*
 *	Sets the Tool Bar Item's menu.
 */
void ToolBarItemSetMenuID(
	toolbar_struct *tb, gint id, GtkWidget *menu   
)
{
	toolbar_item_struct *item_ptr = (tb != NULL) ?
	    ToolBarItemListMatchByID(tb->item, tb->total_items, id) : NULL;
	if(item_ptr == NULL)
	    return;

	if(item_ptr->type == TOOLBAR_ITEM_MENU_BUTTON)
	    MenuButtonSetMenu(item_ptr->w, GTK_MENU(menu));
}

/*
 *	Gets the Tool Bar Item's menu.
 */
GtkWidget *ToolBarItemGetMenuID(toolbar_struct *tb, gint id)
{
	toolbar_item_struct *item_ptr = (tb != NULL) ?
	    ToolBarItemListMatchByID(tb->item, tb->total_items, id) : NULL;
	if(item_ptr == NULL)
	    return(NULL);

	if(item_ptr->type == TOOLBAR_ITEM_MENU_BUTTON)
	    return(MenuButtonGetMenu(item_ptr->w));
	else
	    return(NULL);
}


/*
 *	Checks if the Tool Bar Item specified by id is mapped.
 */
gboolean ToolBarItemIsMappedID(toolbar_struct *tb, gint id)
{
	toolbar_item_struct *item_ptr = (tb != NULL) ?
	    ToolBarItemListMatchByID(tb->item, tb->total_items, id) : NULL;
	GtkWidget *w = (item_ptr != NULL) ? item_ptr->w : NULL;
	return((w != NULL) ? GTK_WIDGET_MAPPED(w) : FALSE);
}


/*
 *	Maps the Tool Bar Item specified by id.
 */
void ToolBarItemMapID(toolbar_struct *tb, gint id)
{
	GtkWidget *w;
	toolbar_item_struct *item_ptr = (tb != NULL) ? 
	    ToolBarItemListMatchByID(tb->item, tb->total_items, id) : NULL;
	if(item_ptr == NULL)
	    return;

	w = item_ptr->w;
	if(w != NULL)
	    gtk_widget_show(w);
}

/*
 *	Unmaps the Tool Bar Item specified by id.
 */
void ToolBarItemUnmapID(toolbar_struct *tb, gint id)
{
	GtkWidget *w;
	toolbar_item_struct *item_ptr = (tb != NULL) ? 
	    ToolBarItemListMatchByID(tb->item, tb->total_items, id) : NULL;
	if(item_ptr == NULL)
	    return;

	w = item_ptr->w;
	if(w != NULL)
	    gtk_widget_hide(w);
}
