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

#include "guiutils.h"
#include "cdialog.h"
#include "csd.h"
#include "styleedit.h"
#include "stacklist.h"

#include "cfg.h"
#include "edvtypes.h"
#include "optwin.h"
#include "endeavour.h"
#include "edvcb.h"
#include "config.h"


static void OptWinFetchWidgetValueFromCFG(
	edv_core_struct *core_ptr, optwin_struct *optwin,
	optwin_wref_struct *wref
);
static void OptWinSetWidgetValueToCFG(
	edv_core_struct *core_ptr, optwin_struct *optwin,
	optwin_wref_struct *wref
);

void OptWinResetHasChanges(optwin_struct *optwin, gboolean has_changes);
void OptWinDoFetch(optwin_struct *optwin);
void OptWinDoApply(optwin_struct *optwin);


#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)


/*
 *	Nexus for fetching a value from the configruation list to the
 *	given widget.
 */
static void OptWinFetchWidgetValueFromCFG(
	edv_core_struct *core_ptr, optwin_struct *optwin,
	optwin_wref_struct *wref
)
{
	gint i, cfg_type;
	const gchar *cfg_parm = wref->cfg_parm;
	const cfg_item_struct	*cfg_list = core_ptr->cfg_list,
					*cfg_item;
	GtkWidget *w;
	if(STRISEMPTY(cfg_parm))
	    return;

#define FREEZE	optwin->freeze_count++;
#define THAW	optwin->freeze_count--;

	/* Match cfg item from the cfg list by the given parameter */
	i = CFGItemListMatchParameter(cfg_list, cfg_parm);
	if(i < 0)
	    return;

	cfg_item = &cfg_list[i];
	cfg_type = cfg_item->type;


	/* Do special handling first */

	/* Color button? */
	if(wref->color_btn != NULL)
	{
	    FREEZE
	    w = wref->color_btn;
	    if(cfg_type == CFG_ITEM_TYPE_COLOR)
	    {
		const cfg_color_struct *c = CFG_COLOR(cfg_item->value);
		if(c != NULL)
		{
		    csd_color_struct csd_color, *c2 = &csd_color;
		    c2->a = c->a;
		    c2->r = c->r;
		    c2->g = c->g;
		    c2->b = c->b;
		    CSDColorButtonSetColor(w, c2);
		}
	    }
	    THAW
	    return;	/* Do not go on to regular widget handling */
	}
	/* Style Edit? */
	else if(wref->style_edit != NULL)
	{
	    FREEZE
	    if(cfg_type == CFG_ITEM_TYPE_STYLE)
	    {
		style_edit_struct *se = wref->style_edit;
		const cfg_style_struct *src_style = CFG_STYLE(
		    cfg_item->value
		);
		GtkRcStyle *tar_style = gtk_rc_style_new();

#define STRDUP2(s)	((STRISEMPTY(s)) ? NULL : g_strdup(s))
		if(src_style != NULL)
		{
		    /* Copy values from the Cfg Item source style to
		     * the Style Edit target style
		     */
		    gint i;
		    guint src_color_flags;
		    const cfg_color_struct *src_c;
		    GdkColor *tar_c;

		    g_free(tar_style->font_name);
		    tar_style->font_name = STRDUP2(src_style->font_name);

		    for(i = 0; i < STYLE_EDIT_STATES; i++)
		    {
			src_color_flags = src_style->color_flags[i];
			if(src_color_flags & CFG_STYLE_FG)
			{
			    tar_style->color_flags[i] |= GTK_RC_FG;
			    src_c = &src_style->fg[i];
			    tar_c = &tar_style->fg[i];
			    GDK_COLOR_SET_COEFF(
				tar_c, src_c->r, src_c->g, src_c->b
			    )
			}
			if(src_color_flags & CFG_STYLE_BG)
			{
			    tar_style->color_flags[i] |= GTK_RC_BG;
			    src_c = &src_style->bg[i];
			    tar_c = &tar_style->bg[i];
			    GDK_COLOR_SET_COEFF(
				tar_c, src_c->r, src_c->g, src_c->b
			    )
			}
			if(src_color_flags & CFG_STYLE_TEXT)
			{
			    tar_style->color_flags[i] |= GTK_RC_TEXT;
			    src_c = &src_style->text[i];
			    tar_c = &tar_style->text[i];
			    GDK_COLOR_SET_COEFF(
				tar_c, src_c->r, src_c->g, src_c->b
			    )
			}
			if(src_color_flags & CFG_STYLE_BASE)
			{
			    tar_style->color_flags[i] |= GTK_RC_BASE;
			    src_c = &src_style->base[i];
			    tar_c = &tar_style->base[i];
			    GDK_COLOR_SET_COEFF(
				tar_c, src_c->r, src_c->g, src_c->b
			    )
			}

			g_free(tar_style->bg_pixmap_name[i]);
			tar_style->bg_pixmap_name[i] = STRDUP2(
			    src_style->bg_pixmap_name[i]
			);
		    }

		    /* Set style to the Style Edit */
		    StyleEditSetStyle(se, tar_style);
		}
		GTK_RC_STYLE_UNREF(tar_style)
#undef STRDUP2
	    }
	    THAW
	    return;	/* Do not go on to regular widget handling */
	}
	/* Stack List? */
	else if(wref->slist != NULL)
	{
	    FREEZE
	    if(cfg_type == CFG_ITEM_TYPE_INTLIST)
	    {
		const cfg_intlist_struct *intlist = CFG_INTLIST(
		    cfg_item->value
		);
		stack_list_struct *slist = wref->slist;
		if((intlist != NULL) && (slist != NULL))
		{
		    /* Update stack list's source list by deleting all
		     * items in its source list and then adding all
		     * items from its cache to its source list
		     */
		    StackListItemClearSrc(slist);
		    StackListItemSetAllFromCacheSrc(slist);

		    /* Remove items from the source list that are
		     * specified in the intlist (except items that
		     * allow multiple occurances)
		     */
		    for(i = 0; i < intlist->total; i++)
			StackListItemRemoveByIDSrc(
			    slist, intlist->i[i],
			    TRUE		/* Exclude allow_multiples */
			);

		    /* Delete all items in the target list and then add
		     * items to the target list that are specified in
		     * the intlist
		     */
		    StackListItemClearTar(slist);
		    for(i = 0; i < intlist->total; i++)
			StackListItemAppendTar(
			    slist, intlist->i[i]
			);
		}
	    }
	    THAW
	    return;	/* Do not go on to regular widget handling */
	}


	/* Standard widget handling, get widget that is to hold value */
	w = wref->w;
	if(w == NULL)
	    return;

	/* Handle by widget type */
	if(GTK_IS_CLIST(w))
	{
	    GtkCList *clist = GTK_CLIST(w);

	    FREEZE
	    if(cfg_type == CFG_ITEM_TYPE_STRING)
	    {
		/* Select the GtkCList row who's cell text matches the
		 * configuration value string
		 */
		const gchar *s = CFGItemListGetValueS(
		    cfg_list, cfg_parm
		);
		if(!STRISEMPTY(s) && (clist->columns > 0))
		{
		    gint row, column = 0;
		    gchar *s2;
		    guint8 spacing;
		    GdkPixmap *pixmap;
		    GdkBitmap *mask;

		    /* Iterate through rows, searching for a cell who's
		     * text matches the configuration value string
		     */
		    for(row = 0; row < clist->rows; row++)
		    {
			switch(gtk_clist_get_cell_type(clist, row, column))
			{
			  case GTK_CELL_TEXT:
			    gtk_clist_get_text(
				clist, row, column, &s2
			    );
			    break;
			  case GTK_CELL_PIXTEXT:
			    gtk_clist_get_pixtext(
				clist, row, column, &s2,
				&spacing, &pixmap, &mask
			    );
			    break;
			  case GTK_CELL_PIXMAP:
			  case GTK_CELL_WIDGET:
			  case GTK_CELL_EMPTY:
			    s2 = NULL;
			    break;
			}
			if(!STRISEMPTY(s2))
			{
			    if(!g_strcasecmp(s, s2))
			    {
				if(clist->selection != NULL)
				    gtk_clist_unselect_all(clist);
				gtk_clist_select_row(clist, row, column);
				break;
			    }
			}
		    }
		}
	    }
	    else
	    {
		/* Select the GtkCList row who's index is the 
		 * configuration value
		 */
		gint valuei = CFGItemListGetValueI(
		    cfg_list, cfg_parm
		);
		if(clist->selection != NULL)
		    gtk_clist_unselect_all(clist);
		if((valuei >= 0) && (valuei < clist->rows))
		    gtk_clist_select_row(clist, valuei, -1);
	    }
	    THAW
	}
	else if(GTK_IS_SPIN_BUTTON(w))
	{
	    GtkSpinButton *spin_button = GTK_SPIN_BUTTON(w);

	    FREEZE
	    if(cfg_type == CFG_ITEM_TYPE_STRING)
	    {
		const gchar *values = (const gchar *)cfg_item->value;
		if(values != NULL)
		    gtk_entry_set_text(GTK_ENTRY(w), values);
	    }
	    else
	    {
		gfloat valuef = CFGItemListGetValueF(
		    cfg_list, cfg_parm
		);
		gtk_spin_button_set_value(spin_button, valuef);
	    }
	    THAW
	}
	else if(GTK_IS_COMBO(w))
	{
	    GtkCombo *combo = GTK_COMBO(w);
	    GtkEntry *entry = GTK_ENTRY(combo->entry);

	    FREEZE
	    if(cfg_type == CFG_ITEM_TYPE_STRING)
	    {
		/* Set the GtkCombo's GtkEntry value to the
		 * configuration value string
		 */
		const gchar *values = (const gchar *)cfg_item->value;
		if(values != NULL)
		    gtk_entry_set_text(entry, values);
	    }
	    else
	    {
		/* Set the GtkCombo's GtkEntry value to the
		 * string value of the GtkCombo's list item index
		 * specified by the configuration value
		 */
		gint i = CFGItemListGetValueI(
		    cfg_list, cfg_parm
		);
		GList *glist = GUIComboGetList(w);
		if(glist != NULL)
		{
		    const gchar *s;

		    glist = g_list_nth(glist, i);
		    s = (const gchar *)((glist != NULL) ?
			glist->data : NULL
		    );
		    if(!STRISEMPTY(s))
			gtk_entry_set_text(entry, s);
		}
	    }
	    THAW
	}
	else if(GTK_IS_ENTRY(w))
	{
	    GtkEntry *entry = GTK_ENTRY(w);

	    FREEZE
	    if(cfg_type == CFG_ITEM_TYPE_STRING)
	    {
		const gchar *values = (const gchar *)cfg_item->value;
		if(values != NULL)
		    gtk_entry_set_text(entry, values);
	    }
	    else
	    {
		gchar num_str[80];

		*num_str = '\0';
		switch(cfg_type)
		{
		  case CFG_ITEM_TYPE_INT8:
		  case CFG_ITEM_TYPE_UINT8:
		  case CFG_ITEM_TYPE_INT16:
		  case CFG_ITEM_TYPE_UINT16:
		  case CFG_ITEM_TYPE_INT32:
		  case CFG_ITEM_TYPE_UINT32:
		    g_snprintf(
			num_str, sizeof(num_str),
			"%i",
			CFGItemListGetValueI(
			    cfg_list, cfg_parm
			)
		    );
		    break;

		  case CFG_ITEM_TYPE_INT64:
		  case CFG_ITEM_TYPE_UINT64:
		    g_snprintf(
			num_str, sizeof(num_str),
			"%ld",
			CFGItemListGetValueL(
			    cfg_list, cfg_parm
			)
		    );
		    break;

		  case CFG_ITEM_TYPE_FLOAT:
		    g_snprintf(
			num_str, sizeof(num_str),
			"%f",
			CFGItemListGetValueF(
			    cfg_list, cfg_parm
			)
		    );
		    break;

		  case CFG_ITEM_TYPE_DOUBLE:
		    g_snprintf(
			num_str, sizeof(num_str),
			"%f",
			CFGItemListGetValueD(
			    cfg_list, cfg_parm
			)
		    );
		    break;
		}
		gtk_entry_set_text(entry, num_str);
	    }
	    THAW
	}
	else if(GTK_IS_CHECK_MENU_ITEM(w))
	{
	    gboolean valueb;
	    GtkCheckMenuItem *check = GTK_CHECK_MENU_ITEM(w);

	    FREEZE
	    valueb = (gboolean)CFGItemListGetValueI(cfg_list, cfg_parm);
	    check->active = (valueb) ? TRUE : FALSE;
	    THAW
	}
	else if(GTK_IS_RADIO_BUTTON(w))
	{
	    /* Set this GtkRadioButton active if the Widget Reference's
	     * radio_value matches the configuration value
	     */
	    gint valuei;
	    GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON(w);

	    FREEZE
	    valuei = CFGItemListGetValueI(cfg_list, cfg_parm);
	    if(valuei == wref->radio_value)
		toggle_button->active = TRUE;
	    else
		toggle_button->active = FALSE;
	    THAW
	}
	else if(GTK_IS_TOGGLE_BUTTON(w))
	{
	    gboolean valueb;
	    GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON(w);

	    FREEZE
	    valueb = (gboolean)CFGItemListGetValueI(
		cfg_list, cfg_parm
	    );
	    toggle_button->active = valueb ? TRUE : FALSE;
	    THAW
	}
	else if(GTK_IS_RANGE(w))
	{
	    gfloat valuef;
	    GtkRange *range = GTK_RANGE(w);
	    GtkAdjustment *adj = range->adjustment;

	    FREEZE
	    valuef = CFGItemListGetValueF(cfg_list, cfg_parm);
	    if(adj != NULL)
	    {
		if(valuef > (adj->upper - adj->page_size))
		    valuef = adj->upper - adj->page_size;
		if(valuef < adj->lower)
		    valuef = adj->lower;
		gtk_adjustment_set_value(adj, valuef);
	    }
	    THAW
	}
	else if(GTK_IS_DRAWING_AREA(w))
	{
	    FREEZE


	    THAW
	}
	else
	{
		/* Unsupported widget */
	}

#undef THAW
#undef FREEZE
}

/*
 *      Nexus for setting a value from the given widget to the configuration
 *	list.
 *
 *      Inputs assumed valid.
 */
static void OptWinSetWidgetValueToCFG(
	edv_core_struct *core_ptr, optwin_struct *optwin,
	optwin_wref_struct *wref
)
{
	gint i, cfg_type;
	const gchar *cfg_parm = wref->cfg_parm;
	cfg_item_struct	*cfg_list = core_ptr->cfg_list,
				*cfg_item;
	GtkWidget *w;
	if(STRISEMPTY(cfg_parm))
	    return;


	/* Match cfg item from the cfg list by the given parameter */
	i = CFGItemListMatchParameter(
	    cfg_list, cfg_parm
	);
	if(i < 0)
	    return;

	cfg_item = &cfg_list[i];
	cfg_type = cfg_item->type;


	/* Do special handling first */

	/* Color button? */
	if(wref->color_btn != NULL)
	{
	    w = wref->color_btn;
	    if(cfg_type == CFG_ITEM_TYPE_COLOR)
	    {
		cfg_color_struct *c_tar;
		csd_color_struct csd_color, *c_src = &csd_color;

		/* Get color value from the Color Button */
		CSDColorButtonGetColor(w, c_src);

		/* Create a new Cfg Color and set the new value */
		c_tar = CFGColorNew(
		    c_src->r,
		    c_src->g,
		    c_src->b,
		    c_src->a
		);
		CFGItemListSetValueColor(
		    cfg_list, cfg_parm,
		    c_tar, FALSE
		);
		CFGColorDelete(c_tar);
	    }
	    return;	/* Do not go on to regular widget handling */
	}
	/* Style Edit? */
	else if(wref->style_edit != NULL)
	{
	    if(cfg_type == CFG_ITEM_TYPE_STYLE)
	    {
		gint i;
		cfg_style_struct *tar_style = CFGStyleNew();
		style_edit_struct *se = wref->style_edit;
		const GtkRcStyle *src_style = StyleEditGetStyle(se);

		if(src_style != NULL)
		{
		    /* Copy values from the Style Edit source style to
		     * the Cfg Item target style
		     */
		    GtkRcFlags src_color_flags;
		    cfg_color_struct *tar_c;
		    const GdkColor *src_c;

#define STRDUP2(s)	((STRISEMPTY(s)) ? NULL : g_strdup(s))

		    tar_style->font_name = STRDUP2(src_style->font_name);

		    for(i = 0; i < CFG_STYLE_STATES; i++)
		    {
			src_color_flags = src_style->color_flags[i];
			if(src_color_flags & GTK_RC_FG)
			{
			    tar_style->color_flags[i] |= CFG_STYLE_FG;
			    src_c = &src_style->fg[i];
			    tar_c = &tar_style->fg[i];
			    tar_c->a = 1.0f;
			    tar_c->r = (gfloat)src_c->red   / (gfloat)((gushort)-1);
			    tar_c->g = (gfloat)src_c->green / (gfloat)((gushort)-1);
			    tar_c->b = (gfloat)src_c->blue  / (gfloat)((gushort)-1);
			}
			if(src_color_flags & GTK_RC_BG)
			{
			    tar_style->color_flags[i] |= CFG_STYLE_BG;
			    src_c = &src_style->bg[i];
			    tar_c = &tar_style->bg[i];
			    tar_c->a = 1.0f;
			    tar_c->r = (gfloat)src_c->red   / (gfloat)((gushort)-1);
			    tar_c->g = (gfloat)src_c->green / (gfloat)((gushort)-1);
			    tar_c->b = (gfloat)src_c->blue  / (gfloat)((gushort)-1);
			}
			if(src_color_flags & GTK_RC_TEXT)
			{
			    tar_style->color_flags[i] |= CFG_STYLE_TEXT;
			    src_c = &src_style->text[i];
			    tar_c = &tar_style->text[i];
			    tar_c->a = 1.0f;
			    tar_c->r = (gfloat)src_c->red   / (gfloat)((gushort)-1);
			    tar_c->g = (gfloat)src_c->green / (gfloat)((gushort)-1);
			    tar_c->b = (gfloat)src_c->blue  / (gfloat)((gushort)-1);
			}
			if(src_color_flags & GTK_RC_BASE)
			{
			    tar_style->color_flags[i] |= CFG_STYLE_BASE;
			    src_c = &src_style->base[i];
			    tar_c = &tar_style->base[i];
			    tar_c->a = 1.0f;
			    tar_c->r = (gfloat)src_c->red   / (gfloat)((gushort)-1);
			    tar_c->g = (gfloat)src_c->green / (gfloat)((gushort)-1);
			    tar_c->b = (gfloat)src_c->blue  / (gfloat)((gushort)-1);
			}

			tar_style->bg_pixmap_name[i] = STRDUP2(
			    src_style->bg_pixmap_name[i]
			);
		    }

		    /* Set target style to cfg item */
		    CFGItemListSetValueStyle(
			cfg_list, cfg_parm,
			tar_style, FALSE
		    );

#undef STRDUP2
		}

		/* Delete the Cfg Style */
		CFGStyleDelete(tar_style);
	    }
	    return;	/* Do not go on to regular widget handling */
	}
	/* Stack List? */
	else if(wref->slist != NULL)
	{
	    if(cfg_type == CFG_ITEM_TYPE_INTLIST)
	    {
		cfg_intlist_struct *intlist = CFGIntListNew(NULL, 0);
		stack_list_struct *slist = wref->slist;
		if((intlist != NULL) && (slist != NULL))
		{
		    /* Get the target list's list of IDs and add each
		     * ID to the intlist
		     */
		    gint nids;
		    gint *id = StackListItemGetTar(slist, &nids);
		    if(id != NULL)
		    {
			intlist->total = nids;
			if(nids > 0)
			{
			    intlist->i = (gint *)g_malloc(
				nids * sizeof(gint)
			    );
			    if(intlist->i != NULL)
				memcpy(
				    intlist->i, id,
				    nids * sizeof(gint)
				);
			    else
				intlist->total = 0;
			}
			else
			{
			    intlist->i = NULL;
			    intlist->total = 0;
			}

			/* Delete target list ids */
			g_free(id);
		    }

		    /* Set/copy intlist to cfg item */
		    CFGItemListSetValueIntList(
			cfg_list, cfg_parm,
			intlist, FALSE
		    );
		}

		/* Delete the Cfg Intlist */
		CFGIntListDelete(intlist);
	    }
	    return;	/* Do not go on to regular widget handling */
	}



	/* Standard widget handling, get widget that is to hold value */
	w = wref->w;
	if(w == NULL)
	    return;

	/* Handle by widget type */
	if(GTK_IS_CLIST(w))
	{
	    GtkCList *clist = GTK_CLIST(w);

	    if(cfg_type == CFG_ITEM_TYPE_STRING)
	    {
		/* Set configuration value as the string value of the
		 * selected cell
		 */
		const GList *glist = clist->selection_end;
		if((glist != NULL) && (clist->columns > 0))
		{
		    gchar *s;
		    guint8 spacing;
		    GdkPixmap *pixmap;
		    GdkBitmap *mask;
		    gint	row = (gint)glist->data,
				column = 0;

		    switch(gtk_clist_get_cell_type(clist, row, column))
		    {
		      case GTK_CELL_TEXT:
			gtk_clist_get_text(
			    clist, row, column, &s
			);
			break;
		      case GTK_CELL_PIXTEXT:
			gtk_clist_get_pixtext(
			    clist, row, column, &s,
			    &spacing, &pixmap, &mask
			);
			break;
		      case GTK_CELL_PIXMAP:
		      case GTK_CELL_WIDGET:
		      case GTK_CELL_EMPTY:
			s = NULL;
			break;
		    }
		    if(!STRISEMPTY(s))
			CFGItemListSetValueS(
			    cfg_list, cfg_parm,
			    s, FALSE
			);
		}
	    }
	    else
	    {
		/* Set configuration value as the selected row index */
		const GList *glist = clist->selection_end;
		if(glist != NULL)
		{
		    gint valuei = (gint)glist->data;
		    CFGItemListSetValueI(
			cfg_list, cfg_parm,
			valuei, FALSE
		    );
		}
	    }
	}
	else if(GTK_IS_SPIN_BUTTON(w))
	{
	    GtkSpinButton *spin_button = GTK_SPIN_BUTTON(w);

	    if(cfg_type == CFG_ITEM_TYPE_STRING)
	    {
		const gchar *values = gtk_entry_get_text(GTK_ENTRY(w));
		if(values != NULL)
		    CFGItemListSetValueS(
			cfg_list, cfg_parm,
			values, FALSE
		    );
	    }
	    else
	    {
		if(spin_button->digits > 0)
		{
		    gfloat valuef = gtk_spin_button_get_value_as_float(
			spin_button
		    );
		    CFGItemListSetValueF(
			cfg_list, cfg_parm,
			valuef, FALSE
		    );
		}
		else
		{
		    gfloat valuei = gtk_spin_button_get_value_as_int(
			spin_button
		    );
		    CFGItemListSetValueI(
			cfg_list, cfg_parm,
			valuei, FALSE
		    );
		}
	    }
	}
	else if(GTK_IS_COMBO(w))
	{
	    GtkCombo *combo = GTK_COMBO(w);
	    GtkEntry *entry = GTK_ENTRY(combo->entry);

	    if(cfg_type == CFG_ITEM_TYPE_STRING)
	    {
		/* Set the configuration value string to the value of
		 * GtkCombo's GtkEntry
		 */
		const gchar *values = gtk_entry_get_text(entry);
		if(values != NULL)
		    CFGItemListSetValueS(
			cfg_list, cfg_parm,
			values, FALSE
		    );
	    }
	    else
	    {
		/* Set the configuration value to the index of the
		 * GtkCombo's list item who's string value matches the
		 * GtkCombo's GtkEntry value
		 */
		const gchar *s = gtk_entry_get_text(entry);
		if(!STRISEMPTY(s))
		{
		    const gchar *s2;
		    gint valuei = 0;
		    GList *glist = GUIComboGetList(w);
		    while(glist != NULL)
		    {
			s2 = (const gchar *)glist->data;
			if(!STRISEMPTY(s2))
			{
			    if(!g_strcasecmp(s, s2))
				break;
			}
			valuei++;
			glist = g_list_next(glist);
		    }
		    if(glist != NULL)
			CFGItemListSetValueI(
			    cfg_list, cfg_parm,
			    valuei, FALSE
			);
		}
	    }
	}
	else if(GTK_IS_ENTRY(w))
	{
	    GtkEntry *entry = GTK_ENTRY(w);

	    if(cfg_type == CFG_ITEM_TYPE_STRING)
	    {
		const gchar *values = gtk_entry_get_text(entry);
		if(values != NULL)
		    CFGItemListSetValueS(
			cfg_list, cfg_parm,
			values, FALSE
		    );
	    }
	    else
	    {
		const gchar *values = gtk_entry_get_text(entry);
		if(values != NULL)
		{
		    /* Decimal in the string? */
		    if(strchr(values, '.'))
			CFGItemListSetValueF(
			    cfg_list, cfg_parm,
			    ATOF(values), FALSE
			);
		    else
			CFGItemListSetValueI(
			    cfg_list, cfg_parm,
			    ATOI(values), FALSE
			);
		}
	    }
	}
	else if(GTK_IS_CHECK_MENU_ITEM(w))
	{
	    CFGItemListSetValueI(
		cfg_list, cfg_parm,
		GTK_CHECK_MENU_ITEM_GET_ACTIVE(w), FALSE
	    );
	}
	else if(GTK_IS_RADIO_BUTTON(w))
	{
	    /* Set the configuration value to the Widget Reference's
	     * specified radio_value if this GtkRadioButton is active
	     */
	    if(GTK_TOGGLE_BUTTON_GET_ACTIVE(w))
		CFGItemListSetValueI(
		    cfg_list, cfg_parm,
		    wref->radio_value, FALSE
		);
	}
	else if(GTK_IS_TOGGLE_BUTTON(w))
	{
	    CFGItemListSetValueI(
		cfg_list, cfg_parm,
		GTK_TOGGLE_BUTTON_GET_ACTIVE(w), FALSE
	    );
	}
	else if(GTK_IS_RANGE(w))
	{
	    GtkRange *range = GTK_RANGE(w);
	    GtkAdjustment *adj = range->adjustment;
	    switch(cfg_type)
	    {
	      case CFG_ITEM_TYPE_FLOAT:
	      case CFG_ITEM_TYPE_DOUBLE:
		CFGItemListSetValueF(
		    cfg_list, cfg_parm,
		    adj->value, FALSE
		);
		break;
	      default:
		CFGItemListSetValueI(
		    cfg_list, cfg_parm,
		    (gint)adj->value, FALSE
		);
		break;
	    }
	}
	else if(GTK_IS_DRAWING_AREA(w))
	{



	}
	else
	{
	    /* Unsupported widget */
	}
}


/*
 *	Resets all has_changes markers on all of the Option Window's
 *	Widget References and on the Options Window itself.
 */
void OptWinResetHasChanges(optwin_struct *optwin, gboolean has_changes)
{
	gint i;
	optwin_wref_struct *wref;

	if(optwin == NULL)
	    return;

	/* Reset all has_changes markers on all Widget References */
	for(i = 0; i < optwin->total_wrefs; i++)
	{
	    wref = optwin->wref[i];
	    if(wref == NULL)
		continue;

	    wref->has_changes = FALSE;
	}

	/* Reset has_changes on the Options Window */
	optwin->has_changes = FALSE;
}

/*
 *	Fetches values from the cfg list to the widgets specified
 *	by the Option Window's Widget References.
 */
void OptWinDoFetch(optwin_struct *optwin)
{
	gint i;
	edv_core_struct *core_ptr;
	optwin_wref_struct *wref;

	if(optwin == NULL)
	    return;

	core_ptr = EDV_CORE(optwin->core_ptr);
	if(core_ptr == NULL)
	    return;

	/* Iterate through all wrefs */
	for(i = 0; i < optwin->total_wrefs; i++)
	{
	    wref = optwin->wref[i];
	    if(wref == NULL)
		continue;

	    OptWinFetchWidgetValueFromCFG(core_ptr, optwin, wref);
	}
}

/*
 *	Applies values from the widgets specified by the Option Window's
 *	Widget References to the cfg list.
 */
void OptWinDoApply(optwin_struct *optwin)
{
	gint i;
	edv_core_struct *core_ptr;
	optwin_wref_struct *wref;


	if(optwin == NULL)
	    return;

	core_ptr = EDV_CORE(optwin->core_ptr);
	if(core_ptr == NULL)
	    return;

	/* Iterate through all wrefs */
	for(i = 0; i < optwin->total_wrefs; i++)
	{
	    wref = optwin->wref[i];
	    if(wref == NULL)
		continue;

	    OptWinSetWidgetValueToCFG(core_ptr, optwin, wref);
	}

	/* Send out reconfigured signal to all resources */
	EDVReconfiguredEmit(core_ptr);
}
