/*
** 1998-07-12 -	Various little helper routines for building/managing GUIS.
** 1999-03-13 -	Adapted for new dialog module.
*/

#include <string.h>
#include <gtk/gtk.h>

#include "guiutil.h"
#include "dialog.h"

/* ----------------------------------------------------------------------------------------- */

#include "graphics/icon_details.xpm"

typedef struct {
	Dialog		*dlg;
	GtkWidget	*vbox;
	GtkWidget	*label;
	GtkWidget	*obj;
	GtkWidget	*bar;
	gboolean	terminate;
} PBar;

/* ----------------------------------------------------------------------------------------- */

/* 1998-07-12 -	Moved this out of the dirpane config module and into this brand new GUI
**		utilities module.
*/
GtkWidget * gui_arrow_button_new(GtkArrowType at)
{
	GtkWidget	*but, *arr;

	if((but = gtk_button_new()) != NULL)
	{
		if((arr = gtk_arrow_new(at, GTK_SHADOW_OUT)) != NULL)
		{
			gtk_container_add(GTK_CONTAINER(but), arr);
			gtk_widget_show(arr);
			return but;
		}
		gtk_widget_destroy(but);
	}
	return NULL;
}

/* 1999-04-26 -	Create a button with a "details" icon on it. This is typically a magnification
**		class. This button is a graphical replacement for a button labeled "...".
*/
GtkWidget * gui_details_button_new(GdkWindow *win)
{
	GtkWidget	*btn;
	GdkPixmap	*pix;
	GdkBitmap	*msk;

	if((btn = gtk_button_new()) != NULL)
	{
		if((pix = gdk_pixmap_create_from_xpm_d(win, &msk, NULL, icon_details_xpm)) != NULL)
		{
			GtkWidget	*pmap;

			if((pmap = gtk_pixmap_new(pix, msk)) != NULL)
			{
				gtk_container_add(GTK_CONTAINER(btn), pmap);
				gtk_widget_show(pmap);

				return btn;
			}
			gdk_pixmap_unref(pix);
			gdk_bitmap_unref(msk);
		}
	}
	return NULL;
}

/* ----------------------------------------------------------------------------------------- */

/* 1998-07-30 -	Build a group of radio buttons with the given labels.
** 1999-05-15 -	Now also sets the GTK+ object user data to the index of each button.
*/
GSList * gui_radio_group_new(guint num, const gchar *label[], GtkWidget *but[])
{
	GSList	*list = NULL;
	guint	i;

	for(i = 0; i < num; i++)
	{
		if(i != 0)
			list = gtk_radio_button_group(GTK_RADIO_BUTTON(but[i - 1]));
		but[i] = gtk_radio_button_new_with_label(list, label[i]);
		gtk_object_set_user_data(GTK_OBJECT(but[i]), GUINT_TO_POINTER(i));
	}
	return list;
}

/* ----------------------------------------------------------------------------------------- */

/* 1998-09-05 -	This gets called by the dialog module if the user hits the button. */
static void done(Dialog *dlg, guint res, void *data)
{
	PBar	*pbar = (PBar *) data;

	pbar->terminate = TRUE;
}

/* 1998-09-05 -	Initialize a user-abortable progress "session". Opens up a dialog window
**		with the given <body> text and <button>, as well as a progress bar widget
**		and a "current object name" indicator (a bare label).
**		Returns an "anchor"; a pointer to some private data. You use this pointer
**		in later calls to identify the session. Progress sessions don't nest!
**		Use calls to gui_progress_update() to make the bar move, and also to learn
**		about any button actions.
*/
gpointer gui_progress_begin(const gchar *body, const gchar *button)
{
	static PBar	pbar;

	pbar.vbox = gtk_vbox_new(FALSE, 0);
	pbar.label = gtk_label_new(body);
	gtk_box_pack_start(GTK_BOX(pbar.vbox), pbar.label, TRUE, TRUE, 0);
	gtk_widget_show(pbar.label);
	pbar.obj = gtk_label_new("");
	gtk_box_pack_start(GTK_BOX(pbar.vbox), pbar.obj, TRUE, TRUE, 0);
	gtk_widget_show(pbar.obj);
	pbar.bar = gtk_progress_bar_new();
	gtk_box_pack_start(GTK_BOX(pbar.vbox), pbar.bar, TRUE, TRUE, 5);
	gtk_widget_show(pbar.bar);
	pbar.terminate = FALSE;

	pbar.dlg = dlg_dialog(pbar.vbox, "Progress", button, done, (void *) &pbar);

	return &pbar;
}

/* 1998-09-05 -	Update the progress bar to a new value (which should be between 0.0 and 1.0).
**		Also allows you to change the indication of the current object.
**		Returns TRUE if the user has hit the button in the window, typically indicating
**		that the entire operation should be aborted ASAP.
*/
gboolean gui_progress_update(gpointer anchor, gfloat value, const gchar *obj)
{
	PBar	*pbar = (PBar *) anchor;

	if(!pbar->terminate)
	{
		gtk_progress_bar_update(GTK_PROGRESS_BAR(pbar->bar), value);
		if((obj != NULL) && (pbar->obj != NULL))
			gtk_label_set_text(GTK_LABEL(pbar->obj), obj);

		while(gtk_events_pending())
			gtk_main_iteration();
	}

	return pbar->terminate;
}

/* 1998-09-05 -	Close down the progress session, since the time-consuming operation has been
**		finished.
*/
void gui_progress_end(gpointer anchor)
{
	PBar	*pbar = (PBar *) anchor;

	if(!pbar->terminate)
		dlg_dialog_close_right(pbar->dlg);
	memset(pbar, 0, sizeof *pbar);		/* Makes sure we notice any foul play. */
}

/* ----------------------------------------------------------------------------------------- */

/* 1998-06-22 -	Just a utility function to help the config modules to their thing. This one
**		builds a menu from a NULL-terminated vector of item texts. Very simple, but
**		also very useful. Like so many other good things. :) Each menu item will
**		have the given <func> connected to it, which will be called with <data> as
**		the user data (as usual). Also, to make it possible for the callback to
**		determine which item was selected, each item will have its index (from 0)
**		set as object's user data. Not pretty, but still simple and useful.
*/
GtkWidget * gui_build_menu(const gchar *text[], GtkSignalFunc func, gpointer data)
{
	GtkWidget	*menu, *item;
	guint		i;

	if((menu = gtk_menu_new()) != NULL)
	{
		for(i = 0; text[i] != NULL; i++)
		{
			if((item = gtk_menu_item_new_with_label(text[i])) != NULL)
			{
				if(func != NULL)
				{
					gtk_object_set_user_data(GTK_OBJECT(item), GUINT_TO_POINTER(i));
					gtk_signal_connect(GTK_OBJECT(item), "activate", func, data);
				}
				gtk_menu_append(GTK_MENU(menu), item);
				gtk_widget_show(item);
			}
			else
			{
				gtk_widget_destroy(menu);
				return NULL;
			}
		}
	}
	return menu;
}
