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

#include "guiutils.h"
#include "cdialog.h"
#include "csd.h"
#include "style_edit.h"
#include "stacklist.h"
#include "keymap_list.h"

#include "cfg.h"
#include "edv_types.h"
#include "edv_generic_options_win.h"
#include "endeavour2.h"
#include "edv_cb.h"

#include "config.h"
#include "edv_cfg_list.h"


static void OptWinFetchWidgetValueFromCFG(
	edv_core_struct *core, edv_gen_opt_win_struct *optwin,
	edv_gen_opt_wref_struct *wref
);
static void OptWinSetWidgetValueToCFG(
	edv_core_struct *core, edv_gen_opt_win_struct *optwin,
	edv_gen_opt_wref_struct *wref
);

void EDVGenOptWinResetHasChanges(
	edv_gen_opt_win_struct *optwin, const gboolean has_changes
);
void EDVGenOptWinGetValues(edv_gen_opt_win_struct *optwin);
void EDVGenOptWinSetValues(edv_gen_opt_win_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
 *	specified widget.
 */
static void OptWinFetchWidgetValueFromCFG(
	edv_core_struct *core, edv_gen_opt_win_struct *optwin,
	edv_gen_opt_wref_struct *wref
)
{
	gint i, cfg_type;
	const gchar *cfg_parm = wref->cfg_parm;
	const cfg_item_struct	*cfg_list = core->cfg_list,
					*cfg_item;
	gpointer 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;
	w = wref->w;

	/* Set the configuration value to the widget based on the
	 * widget's type
	 */
	switch(wref->type)
	{
	  case EDV_GEN_OPT_WIDGET_UNKNOWN:
	    break;

	  case EDV_GEN_OPT_WIDGET_DRAWING_AREA:
	    break;
	  case EDV_GEN_OPT_WIDGET_BUTTON:
	    break;
	  case EDV_GEN_OPT_WIDGET_TOGGLE_BUTTON:
	    if(w != NULL)
	    {
		gboolean b;
		GtkToggleButton *tb = (GtkToggleButton *)w;
		FREEZE
		b = EDV_GET_B(cfg_parm);
		tb->active = b ? TRUE : FALSE;
		THAW
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_RADIO_BUTTON:
	    if(w != NULL)
	    {
		/* Set this GtkRadioButton active if the Widget Reference's
		 * radio_value matches the configuration value
		 */
		gint i;
		GtkToggleButton *tb = (GtkToggleButton *)w;
		FREEZE
		i = EDV_GET_I(cfg_parm);
		tb->active = (i == wref->radio_value) ? TRUE : FALSE;
		THAW
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_RANGE:
	    if(w != NULL)
	    {
		gfloat f;
		GtkRange *range = (GtkRange *)w;
		GtkAdjustment *adj = range->adjustment;
		FREEZE
		f = EDV_GET_F(cfg_parm);
		if(adj != NULL)
		{
		    if(f > (adj->upper - adj->page_size))
			f = adj->upper - adj->page_size;
		    if(f < adj->lower)
			f = adj->lower;
		    gtk_adjustment_set_value(adj, f);
		}
		THAW
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_EDITABLE:
	    if(w != NULL)
	    {
	        GtkEntry *entry = (GtkEntry *)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",
			    EDV_GET_I(cfg_parm)
		        );
		        break;

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

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

		      case CFG_ITEM_TYPE_DOUBLE:
		        g_snprintf(
			    num_str, sizeof(num_str),
			    "%f",
			    EDV_GET_D(cfg_parm)
		        );
		        break;
		    }
		    gtk_entry_set_text(entry, num_str);
	        }
	        THAW
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_SPIN_BUTTON:
	    if(w != NULL)
	    {
		GtkSpinButton *spin_button = (GtkSpinButton *)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 = EDV_GET_F(cfg_parm);
		    gtk_spin_button_set_value(spin_button, valuef);
	        }
	        THAW
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_COMBO:
	    if(w != NULL)
	    {
	        GtkCombo *combo = (GtkCombo *)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
		     */
		    const gint i = EDV_GET_I(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
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_CLIST:
	    if(w != NULL)
	    {
		GtkCList *clist = (GtkCList *)w;
		FREEZE
	        if(cfg_type == CFG_ITEM_TYPE_STRING)
	        {
		    /* Select the GtkCList row who's cell text matches the
		     * cfg value
		     */
		    const gchar *s = EDV_GET_S(cfg_parm);
		    if(!STRISEMPTY(s) && (clist->columns > 0))
		    {
		        const gint rows = clist->rows;
		        gint row, column = 0;
		        gchar *s2;
		        guint8 spacing;
		        GdkPixmap *pixmap;
		        GdkBitmap *mask;
		        for(row = 0; row < 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))
			        {
				    gtk_clist_unselect_all(clist);
				    gtk_clist_select_row(clist, row, column);
				    break;
			        }
			    }
		        }
		    }
	        }
	        else if((cfg_type == CFG_ITEM_TYPE_INT8) ||
		        (cfg_type == CFG_ITEM_TYPE_UINT8) ||
		        (cfg_type == CFG_ITEM_TYPE_INT16) ||
		        (cfg_type == CFG_ITEM_TYPE_UINT16) ||
		        (cfg_type == CFG_ITEM_TYPE_INT32) ||
		        (cfg_type == CFG_ITEM_TYPE_UINT32)
	        )
	        {
		    /* Select the GtkCList row who's index is the cfg
		     * value
		     */
		    gint valuei = EDV_GET_I(cfg_parm);
		    const gint rows = clist->rows;
		    gtk_clist_unselect_all(clist);
		    if((valuei >= 0) && (valuei < rows))
		        gtk_clist_select_row(clist, valuei, -1);
	        }
	        THAW
	    }
	    break;

	  case EDV_GEN_OPT_WIDGET_COLOR_BUTTON:
	    if(w != NULL)
	    {
		FREEZE
		if(cfg_type == CFG_ITEM_TYPE_COLOR)
		{
		    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((GtkWidget *)w, c2);
		    }
		}
		THAW
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_POPUP_LIST_BOX:
	    if(w != NULL)
	    {
		pulistbox_struct *pulistbox = PULISTBOX(w);
		FREEZE
		if(cfg_type == CFG_ITEM_TYPE_STRING)
		{
		    pulist_struct *pulist = PUListBoxGetPUList(pulistbox);
		    const gint m = PUListGetTotalItems(pulist);
		    const gchar *s = EDV_GET_S(cfg_parm);
		    if((s != NULL) && (m > 0))
		    {
			gint i;
			gchar *s2;
			for(i = 0; i < m; i++)
			{
			    PUListGetItemText(pulist, i, &s2);
			    if(s2 != NULL)
			    {
				if(!g_strcasecmp(s, s2))
				{
				    PUListSelect(pulist, i);
				    break;
				}
			    }
			}
		    }
		}
	        else if((cfg_type == CFG_ITEM_TYPE_INT8) ||
		        (cfg_type == CFG_ITEM_TYPE_UINT8) ||
		        (cfg_type == CFG_ITEM_TYPE_INT16) ||
		        (cfg_type == CFG_ITEM_TYPE_UINT16) ||
		        (cfg_type == CFG_ITEM_TYPE_INT32) ||
		        (cfg_type == CFG_ITEM_TYPE_UINT32)
	        )
		{
		    const gint i = EDV_GET_I(cfg_parm);
		    PUListBoxSelect(pulistbox, i);
		}
		THAW
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_STYLE_EDIT:
	    if(w != NULL)
	    {
		style_edit_struct *se = STYLE_EDIT(w);
		FREEZE
		if(cfg_type == CFG_ITEM_TYPE_STYLE)
		{
		    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
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_STACK_LIST:
	    if(w != NULL)
	    {
		stack_list_struct *slist = STACK_LIST(w);
	        FREEZE
	        if(cfg_type == CFG_ITEM_TYPE_INTLIST)
	        {
		    cfg_intlist_struct *intlist = CFG_INTLIST(
		        cfg_item->value
		    );
		    if(intlist != NULL)
		    {
		        GList *glist;

		        /* 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(glist = intlist->list;
		            glist != NULL;
		            glist = g_list_next(glist)
		        )
			    StackListItemRemoveByIDSrc(
			        slist, (gint)glist->data,
			        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(glist = intlist->list;
			    glist != NULL;
			    glist = g_list_next(glist)
		        )
			    StackListItemAppendTar(
			        slist, (gint)glist->data
			    );
		    }
	        }
	        THAW
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_KEYMAP_LIST:
	    if(w != NULL)
	    {
		keymap_list_struct *kmlist = KEYMAP_LIST(w);
	        FREEZE
	        if(cfg_type == CFG_ITEM_TYPE_ACCELKEY_LIST)
	        {
		    cfg_accelkey_struct *ak;
		    cfg_accelkey_list_struct *ak_list = CFG_ACCELKEY_LIST(
		        cfg_item->value
		    );
		    if(ak_list != NULL)
		    {
		        gint row;
		        GList *glist;
		        keymap_key_struct *km;

		        /* Iterate through Accelkey list and set them to
		         * the Keymap List
		         */
		        for(glist = ak_list->list, row = 0;
			    glist != NULL;
			    glist = g_list_next(glist), row++
		        )
		        {
			    ak = CFG_ACCELKEY(glist->data);
			    if(ak == NULL)
			        continue;

			    km = KeymapKeyNew(
			        ak->key,			/* Keyval */
			        ak->modifiers,		/* State */
			        (gpointer)ak->opid		/* Data */
			    );
			    KeymapListSetKey(
			        kmlist, row, km
			    );
			    KeymapKeyDelete(km);
		        }
		    }
	        }
		THAW
	    }
	    break;
	}

#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, edv_gen_opt_win_struct *optwin,
	edv_gen_opt_wref_struct *wref
)
{
	gint i, cfg_type;
	const gchar *cfg_parm = wref->cfg_parm;
	cfg_item_struct	*cfg_list = core->cfg_list,
				*cfg_item;
	gpointer w;
	if(STRISEMPTY(cfg_parm))
	    return;


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

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

	/* Get the configuration value from the widget based on the
	 * widget's type
	 */
	switch(wref->type)
	{
	  case EDV_GEN_OPT_WIDGET_UNKNOWN:
	    break;

          case EDV_GEN_OPT_WIDGET_DRAWING_AREA:
            break;
	  case EDV_GEN_OPT_WIDGET_BUTTON:
	    break;
	  case EDV_GEN_OPT_WIDGET_TOGGLE_BUTTON:
	    if(w != NULL)
	    {
		gint i = GTK_TOGGLE_BUTTON_GET_ACTIVE((GtkWidget *)w);
		EDV_SET_I(cfg_parm, i);
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_RADIO_BUTTON:
	    if(w != NULL)
	    {
		/* Set the configuration value to the Widget
		 * Reference's specified radio_value if this
		 * GtkRadioButton is active
		 */
		if(GTK_TOGGLE_BUTTON_GET_ACTIVE((GtkWidget *)w))
		    EDV_SET_I(cfg_parm, wref->radio_value);
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_RANGE:
	    if(w != NULL)
	    {
		GtkRange *range = (GtkRange *)w;
		GtkAdjustment *adj = range->adjustment;
		switch(cfg_type)
	        {
	          case CFG_ITEM_TYPE_FLOAT:
	          case CFG_ITEM_TYPE_DOUBLE:
		    EDV_SET_F(cfg_parm, adj->value);
		    break;
	          default:
		    EDV_SET_I(cfg_parm, (gint)adj->value);
		    break;
	        }
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_EDITABLE:
	    if(w != NULL)
	    {
		GtkEntry *entry = (GtkEntry *)w;
	        if(cfg_type == CFG_ITEM_TYPE_STRING)
	        {
		    const gchar *values = gtk_entry_get_text(entry);
		    if(values != NULL)
		        EDV_SET_S(cfg_parm, values);
	        }
	        else
	        {
		    const gchar *values = gtk_entry_get_text(entry);
		    if(values != NULL)
		    {
		        /* Decimal in the string? */
		        if(strchr(values, '.'))
			    EDV_SET_F(cfg_parm, ATOF(values));
		        else
			    EDV_SET_I(cfg_parm, ATOI(values));
		    }
	        }
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_SPIN_BUTTON:
	    if(w != NULL)
	    {
		GtkSpinButton *spin_button = (GtkSpinButton *)w;

	        if(cfg_type == CFG_ITEM_TYPE_STRING)
	        {
		    const gchar *values = gtk_entry_get_text(GTK_ENTRY(w));
		    if(values != NULL)
		        EDV_SET_S(cfg_parm, values);
	        }
	        else
	        {
		    if(spin_button->digits > 0)
		    {
		        gfloat valuef = gtk_spin_button_get_value_as_float(
			    spin_button
		        );
		        EDV_SET_F(cfg_parm, valuef);
		    }
		    else
		    {
		        gfloat valuei = gtk_spin_button_get_value_as_int(
			    spin_button
		        );
		        EDV_SET_I(cfg_parm, valuei);
		    }
	        }
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_COMBO:
	    if(w != NULL)
	    {
		GtkCombo *combo = (GtkCombo *)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)
		        EDV_SET_S(cfg_parm, values);
	        }
	        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)
			    EDV_SET_I(cfg_parm, valuei);
		    }
	        }
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_CLIST:
	    if(w != NULL)
	    {
		GtkCList *clist = (GtkCList *)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))
		    {
		        const gint	row = (gint)glist->data,
					column = 0;
			gchar *s;
			guint8 spacing;
			GdkPixmap *pixmap;
			GdkBitmap *mask;

		        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))
			    EDV_SET_S(cfg_parm, s);
		    }
	        }
	        else if((cfg_type == CFG_ITEM_TYPE_INT8) ||
		        (cfg_type == CFG_ITEM_TYPE_UINT8) ||
		        (cfg_type == CFG_ITEM_TYPE_INT16) ||
		        (cfg_type == CFG_ITEM_TYPE_UINT16) ||
		        (cfg_type == CFG_ITEM_TYPE_INT32) ||
		        (cfg_type == CFG_ITEM_TYPE_UINT32)
	        )
	        {
		    /* Set configuration value as the selected row index */
		    const GList *glist = clist->selection_end;
		    if(glist != NULL)
		    {
		        const gint valuei = (gint)glist->data;
		        EDV_SET_I(cfg_parm, valuei);
		    }
	        }
	    }
	    break;

	  case EDV_GEN_OPT_WIDGET_COLOR_BUTTON:
	    if((w != NULL) && (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((GtkWidget *)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
		);
		EDV_SET_COLOR(cfg_parm, c_tar);
		CFGColorDelete(c_tar);
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_POPUP_LIST_BOX:
	    if(w != NULL)
	    {
		pulistbox_struct *pulistbox = PULISTBOX(w);
		const gint i = PUListBoxGetSelected(pulistbox);

		if(cfg_type == CFG_ITEM_TYPE_STRING)
		{
		    gchar *s;
		    pulist_struct *pulist = PUListBoxGetPUList(pulistbox);
		    PUListGetItemText(pulist, i, &s);
		    if(!STRISEMPTY(s))
			EDV_SET_S(cfg_parm, s);
		}
		else if((cfg_type == CFG_ITEM_TYPE_INT8) ||
			(cfg_type == CFG_ITEM_TYPE_UINT8) ||
			(cfg_type == CFG_ITEM_TYPE_INT16) ||
			(cfg_type == CFG_ITEM_TYPE_UINT16) ||
			(cfg_type == CFG_ITEM_TYPE_INT32) ||
			(cfg_type == CFG_ITEM_TYPE_UINT32)
		)
		{
		    EDV_SET_I(cfg_parm, i);
		}
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_STYLE_EDIT:
	    if((w != NULL) && (cfg_type == CFG_ITEM_TYPE_STYLE))
	    {
		gint i;
		cfg_style_struct *tar_style = CFGStyleNew();
		style_edit_struct *se = STYLE_EDIT(w);
		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 */
		    EDV_SET_STYLE(cfg_parm, tar_style);

#undef STRDUP2
		}

		/* Delete the Cfg Style */
		CFGStyleDelete(tar_style);
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_STACK_LIST:
	    if((w != NULL) && (cfg_type == CFG_ITEM_TYPE_INTLIST))
	    {
		cfg_intlist_struct *intlist = CFGIntListNew(NULL);
		stack_list_struct *slist = STACK_LIST(w);
		if(intlist != 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)
		    {
			gint i;

			/* Add ids to the new intlist */
			for(i = 0; i < nids; i++)
			    intlist->list = g_list_append(
				intlist->list,
				(gpointer)id[i]
			    );

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

		    /* Set/copy intlist to cfg item */
		    EDV_SET_INTLIST(cfg_parm, intlist);
		}

		CFGIntListDelete(intlist);
	    }
	    break;
	  case EDV_GEN_OPT_WIDGET_KEYMAP_LIST:
	    if((w != NULL) && (cfg_type == CFG_ITEM_TYPE_ACCELKEY_LIST))
	    {
		gint row;
		GList *glist = NULL;
		cfg_accelkey_list_struct *ak_list;
		keymap_key_struct *km;
		keymap_list_struct *kmlist = KEYMAP_LIST(w);

		/* Iterate through each row on the Keymap List and
		 * append/copy each key to the glist
		 */
		for(row = 0; TRUE; row++)
		{
		    km = KeymapListGet(kmlist, row);
		    if(km == NULL)
			break;

		    glist = g_list_append(
			glist,
			CFGAccelkeyNew(
			    (gint)km->data,	/* OPID */
			    km->keyval,		/* Key */
			    km->state		/* Modifiers */
			)
		    );
		}

		/* Create a new Accelkey List and then delete the glist
		 * containing the Accelkeys
		 */
		ak_list = CFGAccelkeyListNew(glist);
		g_list_foreach(glist, (GFunc)CFGAccelkeyDelete, NULL);
		g_list_free(glist);

		/* Set/copy the Accelkey List to cfg item */
		EDV_SET_ACCELKEY_LIST(cfg_parm, ak_list);

		CFGAccelkeyListDelete(ak_list);
	    }
	    break;
	}
}


/*
 *	Resets all has_changes markers on all of the Option Window's
 *	Widget References and on the Options Window itself.
 */
void EDVGenOptWinResetHasChanges(
	edv_gen_opt_win_struct *optwin, const gboolean has_changes
)
{
	GList *glist;
	edv_gen_opt_wref_struct *wref;

	if(optwin == NULL)
	    return;

	/* Iterate through the widget references list and reset each
	 * has_changes marker
	 */
	for(glist = optwin->wrefs_list;
	    glist != NULL;
	    glist = g_list_next(glist)
	)
	{
	    wref = EDV_GEN_OPT_WREF(glist->data);
	    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 EDVGenOptWinGetValues(edv_gen_opt_win_struct *optwin)
{
	GList *glist;
	edv_gen_opt_wref_struct *wref;
	edv_core_struct *core;

	if(optwin == NULL)
	    return;

	core = optwin->core;
	if(core == NULL)
	    return;

	/* Iterate through the widget references list and get the
	 * configuration values for each widget
	 */
	for(glist = optwin->wrefs_list;
	    glist != NULL;
	    glist = g_list_next(glist)
	)
	{
	    wref = EDV_GEN_OPT_WREF(glist->data);
	    if(wref == NULL)
		continue;

	    OptWinFetchWidgetValueFromCFG(core, optwin, wref);
	}
}

/*
 *	Applies values from the widgets specified by the Option Window's
 *	Widget References to the cfg list.
 */
void EDVGenOptWinSetValues(edv_gen_opt_win_struct *optwin)
{
	GList *glist;
	edv_gen_opt_wref_struct *wref;
	edv_core_struct *core;

	if(optwin == NULL)
	    return;

	core = optwin->core;
	if(core == NULL)
	    return;

	/* Iterate through the widget references list and set the
	 * configuration values from each widget's value
	 */
	for(glist = optwin->wrefs_list;
	    glist != NULL;
	    glist = g_list_next(glist)
	)
	{
	    wref = EDV_GEN_OPT_WREF(glist->data);
	    if(wref == NULL)
		continue;

	    OptWinSetWidgetValueToCFG(core, optwin, wref);
	}

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